From eebeb2476fa36bf85d173f54f84ea427286f2306 Mon Sep 17 00:00:00 2001 From: eric Date: Tue, 28 Feb 2012 17:28:33 -0500 Subject: [PATCH] finish committing all changes --- ..._field_waswork_moved__add_field_waswork.py | 238 +++++++ core/tests.py | 10 +- frontend/forms.py | 71 +- frontend/templates/book_panel.html | 19 +- frontend/templates/work.html | 53 +- frontend/views.py | 41 +- static/css/campaign.css | 605 +++--------------- 7 files changed, 440 insertions(+), 597 deletions(-) create mode 100644 core/migrations/0026_auto__add_field_ebook_user__add_field_waswork_moved__add_field_waswork.py diff --git a/core/migrations/0026_auto__add_field_ebook_user__add_field_waswork_moved__add_field_waswork.py b/core/migrations/0026_auto__add_field_ebook_user__add_field_waswork_moved__add_field_waswork.py new file mode 100644 index 00000000..3d867f08 --- /dev/null +++ b/core/migrations/0026_auto__add_field_ebook_user__add_field_waswork_moved__add_field_waswork.py @@ -0,0 +1,238 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + no_dry_run = True + def forwards(self, orm): + + # Adding field 'Ebook.user' + db.add_column('core_ebook', 'user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True), keep_default=False) + + # Adding field 'WasWork.moved' + db.add_column('core_waswork', 'moved', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, default=datetime.date(2012, 2, 25), blank=True), keep_default=False) + + # Adding field 'WasWork.user' + db.add_column('core_waswork', 'user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True), keep_default=False) + + # change value of ebook.provider + for ebook in orm.Ebook.objects.filter(provider = 'google'): + ebook.provider ='Google Books' + ebook.rights = 'PD-US' + ebook.save() + for ebook in orm.Ebook.objects.filter(provider = 'gutenberg'): + ebook.provider ='Project Gutenberg' + ebook.rights = 'PD-US' + ebook.save() + + + + def backwards(self, orm): + + # Deleting field 'Ebook.user' + db.delete_column('core_ebook', 'user_id') + + # Deleting field 'WasWork.moved' + db.delete_column('core_waswork', 'moved') + + # Deleting field 'WasWork.user' + db.delete_column('core_waswork', 'user_id') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'core.author': { + 'Meta': {'object_name': 'Author'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'editions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'authors'", 'symmetrical': 'False', 'to': "orm['core.Edition']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '500'}) + }, + 'core.campaign': { + 'Meta': {'object_name': 'Campaign'}, + 'activated': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'amazon_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'deadline': ('django.db.models.fields.DateTimeField', [], {}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'details': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'left': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '14', 'decimal_places': '2'}), + 'managers': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'campaigns'", 'symmetrical': 'False', 'to': "orm['auth.User']"}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True'}), + 'paypal_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'status': ('django.db.models.fields.CharField', [], {'default': "'INITIALIZED'", 'max_length': '15', 'null': 'True'}), + 'target': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '14', 'decimal_places': '2'}), + 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'campaigns'", 'to': "orm['core.Work']"}) + }, + 'core.campaignaction': { + 'Meta': {'object_name': 'CampaignAction'}, + 'campaign': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['core.Campaign']"}), + 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '15'}) + }, + 'core.celerytask': { + 'Meta': {'object_name': 'CeleryTask'}, + 'active': ('django.db.models.fields.NullBooleanField', [], {'default': 'True', 'null': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 2, 25, 11, 41, 50, 264275)', 'auto_now_add': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.CharField', [], {'max_length': '2048', 'null': 'True'}), + 'function_args': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'function_name': ('django.db.models.fields.CharField', [], {'max_length': '1024'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'task_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tasks'", 'null': 'True', 'to': "orm['auth.User']"}) + }, + 'core.claim': { + 'Meta': {'object_name': 'Claim'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'rights_holder': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'claim'", 'to': "orm['core.RightsHolder']"}), + 'status': ('django.db.models.fields.CharField', [], {'default': "'pending'", 'max_length': '7'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'claim'", 'to': "orm['auth.User']"}), + 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'claim'", 'to': "orm['core.Work']"}) + }, + 'core.ebook': { + 'Meta': {'object_name': 'Ebook'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'edition': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ebooks'", 'to': "orm['core.Edition']"}), + 'format': ('django.db.models.fields.CharField', [], {'max_length': '25'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'provider': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'rights': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'url': ('django.db.models.fields.CharField', [], {'max_length': '1024'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}) + }, + 'core.edition': { + 'Meta': {'object_name': 'Edition'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'public_domain': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'publication_date': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}), + 'publisher': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'}), + 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'editions'", 'null': 'True', 'to': "orm['core.Work']"}) + }, + 'core.identifier': { + 'Meta': {'unique_together': "(('type', 'value'),)", 'object_name': 'Identifier'}, + 'edition': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'identifiers'", 'null': 'True', 'to': "orm['core.Edition']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '4'}), + 'value': ('django.db.models.fields.CharField', [], {'max_length': '31'}), + 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'identifiers'", 'to': "orm['core.Work']"}) + }, + 'core.premium': { + 'Meta': {'object_name': 'Premium'}, + 'amount': ('django.db.models.fields.DecimalField', [], {'max_digits': '10', 'decimal_places': '0'}), + 'campaign': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'premiums'", 'null': 'True', 'to': "orm['core.Campaign']"}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '2'}) + }, + 'core.rightsholder': { + 'Meta': {'object_name': 'RightsHolder'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'email': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rights_holder'", 'to': "orm['auth.User']"}), + 'rights_holder_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}) + }, + 'core.subject': { + 'Meta': {'ordering': "['name']", 'object_name': 'Subject'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'}), + 'works': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subjects'", 'symmetrical': 'False', 'to': "orm['core.Work']"}) + }, + 'core.userprofile': { + 'Meta': {'object_name': 'UserProfile'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'facebook_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'goodreads_auth_secret': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'goodreads_auth_token': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'goodreads_user_id': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'goodreads_user_link': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'goodreads_user_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'home_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'librarything_id': ('django.db.models.fields.CharField', [], {'max_length': '31', 'blank': 'True'}), + 'pic_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}), + 'tagline': ('django.db.models.fields.CharField', [], {'max_length': '140', 'blank': 'True'}), + 'twitter_id': ('django.db.models.fields.CharField', [], {'max_length': '15', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': "orm['auth.User']"}) + }, + 'core.waswork': { + 'Meta': {'object_name': 'WasWork'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'moved': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), + 'was': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}), + 'work': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Work']"}) + }, + 'core.wishes': { + 'Meta': {'object_name': 'Wishes', 'db_table': "'core_wishlist_works'"}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'source': ('django.db.models.fields.CharField', [], {'max_length': '15', 'blank': 'True'}), + 'wishlist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Wishlist']"}), + 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'wishes'", 'to': "orm['core.Work']"}) + }, + 'core.wishlist': { + 'Meta': {'object_name': 'Wishlist'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'wishlist'", 'unique': 'True', 'to': "orm['auth.User']"}), + 'works': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'wishlists'", 'symmetrical': 'False', 'through': "orm['core.Wishes']", 'to': "orm['core.Work']"}) + }, + 'core.work': { + 'Meta': {'ordering': "['title']", 'object_name': 'Work'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'language': ('django.db.models.fields.CharField', [], {'default': "'en'", 'max_length': '2'}), + 'num_wishes': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'openlibrary_lookup': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'}) + } + } + + complete_apps = ['core'] diff --git a/core/tests.py b/core/tests.py index e66e9c89..055cfc41 100755 --- a/core/tests.py +++ b/core/tests.py @@ -227,14 +227,15 @@ class BookLoaderTests(TestCase): #self.assertEqual(ebook_epub.url, 'http://books.google.com/books/download/The_Latin_language.epub?id=U3FXAAAAYAAJ&ie=ISO-8859-1&output=epub&source=gbs_api') self.assertEqual(parse_qs(urlparse(ebook_epub.url).query).get("id"), ['U3FXAAAAYAAJ']) self.assertEqual(parse_qs(urlparse(ebook_epub.url).query).get("output"), ['epub']) - self.assertEqual(ebook_epub.provider, 'google') + self.assertEqual(ebook_epub.provider, 'Google Books') + self.assertEqual(ebook_epub.set_provider(), 'Google Books') ebook_pdf = edition.ebooks.filter(format='pdf')[0] self.assertEqual(ebook_pdf.format, 'pdf') #self.assertEqual(ebook_pdf.url, 'http://books.google.com/books/download/The_Latin_language.pdf?id=U3FXAAAAYAAJ&ie=ISO-8859-1&output=pdf&sig=ACfU3U2yLt3nmTncB8ozxOWUc4iHKUznCA&source=gbs_api') self.assertEqual(parse_qs(urlparse(ebook_pdf.url).query).get("id"), ['U3FXAAAAYAAJ']) self.assertEqual(parse_qs(urlparse(ebook_pdf.url).query).get("output"), ['pdf']) - self.assertEqual(ebook_pdf.provider, 'google') - self.assertEqual(edition.public_domain, True) + self.assertEqual(ebook_pdf.provider, 'Google Books') + self.assertEqual(edition.public_domain, True) w = edition.work self.assertEqual(w.first_epub().url, ebook_epub.url) @@ -242,6 +243,9 @@ class BookLoaderTests(TestCase): self.assertEqual(w.first_epub_url(), ebook_epub.url) self.assertEqual(w.first_pdf_url(), ebook_pdf.url) + ebook_pdf.url='http://en.wikisource.org/wiki/Frankenstein' + self.assertEqual(ebook_pdf.set_provider(), 'Wikisource') + def test_add_no_ebook(self): # this edition lacks an ebook, but we should still be able to load it e = bookloader.add_by_isbn('0465019358') diff --git a/frontend/forms.py b/frontend/forms.py index 574a1c8a..1a6b063d 100644 --- a/frontend/forms.py +++ b/frontend/forms.py @@ -11,14 +11,29 @@ from decimal import Decimal as D from selectable.forms import AutoCompleteSelectMultipleWidget,AutoCompleteSelectMultipleField from selectable.forms import AutoCompleteSelectWidget,AutoCompleteSelectField -from regluit.core.models import UserProfile, RightsHolder, Claim, Campaign, Premium +from regluit.core.models import UserProfile, RightsHolder, Claim, Campaign, Premium, Ebook from regluit.core.lookups import OwnerLookup import logging logger = logging.getLogger(__name__) - +class EbookForm(forms.ModelForm): + class Meta: + model = Ebook + exclude = 'created' + widgets = { + 'edition': forms.HiddenInput, + 'user': forms.HiddenInput, + 'provider': forms.HiddenInput, + 'url': forms.TextInput(attrs={'size' : 60}), + } + def clean_provider(self): + new_provider= Ebook.infer_provider(self.data['url']) + if not new_provider: + raise forms.ValidationError(_("At this time, ebook URLs must point at Internet Archive, Wikisources, Hathitrust, Project Gutenberg, or Google Books.")) + return new_provider + def UserClaimForm ( user_instance, *args, **kwargs ): class ClaimForm(forms.ModelForm): i_agree=forms.BooleanField() @@ -194,30 +209,30 @@ class CampaignAdminForm(forms.Form): pass class EmailShareForm(forms.Form): - recipient = forms.EmailField() - sender = forms.EmailField(widget=forms.HiddenInput()) - subject = forms.CharField(max_length=100) - message = forms.CharField(widget=forms.Textarea()) - # allows us to return user to original page by passing it as hidden form input - # we can't rely on POST or GET since the emailshare view handles both - # and may iterate several times as it catches user errors, losing URL info - next = forms.CharField(widget=forms.HiddenInput()) - + recipient = forms.EmailField() + sender = forms.EmailField(widget=forms.HiddenInput()) + subject = forms.CharField(max_length=100) + message = forms.CharField(widget=forms.Textarea()) + # allows us to return user to original page by passing it as hidden form input + # we can't rely on POST or GET since the emailshare view handles both + # and may iterate several times as it catches user errors, losing URL info + next = forms.CharField(widget=forms.HiddenInput()) + class FeedbackForm(forms.Form): - sender = forms.EmailField(widget=forms.TextInput(attrs={'size':50}), label="Your email") - subject = forms.CharField(max_length=500, widget=forms.TextInput(attrs={'size':50})) - message = forms.CharField(widget=forms.Textarea()) - page = forms.CharField(widget=forms.HiddenInput()) - notarobot = forms.IntegerField(label="Please prove you're not a robot") - answer = forms.IntegerField(widget=forms.HiddenInput()) - num1 = forms.IntegerField(widget=forms.HiddenInput()) - num2 = forms.IntegerField(widget=forms.HiddenInput()) - - def clean(self): - cleaned_data = self.cleaned_data - notarobot = str(cleaned_data.get("notarobot")) - answer = str(cleaned_data.get("answer")) - if notarobot!=answer: - raise forms.ValidationError(_("Whoops, try that sum again.")) - - return cleaned_data + sender = forms.EmailField(widget=forms.TextInput(attrs={'size':50}), label="Your email") + subject = forms.CharField(max_length=500, widget=forms.TextInput(attrs={'size':50})) + message = forms.CharField(widget=forms.Textarea()) + page = forms.CharField(widget=forms.HiddenInput()) + notarobot = forms.IntegerField(label="Please prove you're not a robot") + answer = forms.IntegerField(widget=forms.HiddenInput()) + num1 = forms.IntegerField(widget=forms.HiddenInput()) + num2 = forms.IntegerField(widget=forms.HiddenInput()) + + def clean(self): + cleaned_data = self.cleaned_data + notarobot = str(cleaned_data.get("notarobot")) + answer = str(cleaned_data.get("answer")) + if notarobot!=answer: + raise forms.ValidationError(_("Whoops, try that sum again.")) + + return cleaned_data diff --git a/frontend/templates/book_panel.html b/frontend/templates/book_panel.html index e3b41665..c91ae9df 100644 --- a/frontend/templates/book_panel.html +++ b/frontend/templates/book_panel.html @@ -1,4 +1,4 @@ -
+
@@ -6,17 +6,17 @@
{% comment %}top section: campaign info + optional action button. Varies by campaign status.{% endcomment %} - {% if work.first_pdf_url or work.first_epub_url %} + {% if work.first_ebook %} AVAILABLE!
-
{% if work.first_epub_url %}{% else %}{% endif %}Read it Now
+
{% if work.first_ebook %}{% endif %}Read it Now
{% else %}{% if status == 'SUCCESSFUL' %} UNGLUED!

On: {{ deadline|date:"M d, Y" }}

Raised: {{ work.last_campaign.current_total }}

-
{% if work.first_epub_url %}{% else %}{% endif %}Read it Now
+
{% if work.first_ebook %}{% endif %}Read it Now
{% else %}{% if status == 'ACTIVE' %} UNGLUE IT! @@ -123,14 +123,11 @@
{% if status == 'No campaign yet' or status == 'INITIALIZED' %} Wished by {{ work.num_wishes }} - {% else %}{% if work.first_pdf_url or work.first_epub_url %} + {% else %}{% if work.first_ebook %} - {% if work.first_epub_url %} - EPUB - {% endif %} - {% if work.first_pdf_url %} - PDF - {% endif %} + {% for ebook in work.ebooks|slice:":3" %} + {{ ebook.format }} + {% endfor %} {% else %} diff --git a/frontend/templates/work.html b/frontend/templates/work.html index 5f1b55ee..f8bef7a9 100644 --- a/frontend/templates/work.html +++ b/frontend/templates/work.html @@ -19,7 +19,14 @@ jQuery(document).ready(function(){ jQuery('#embed').click(function(){ jQuery('div#widgetcode').toggle(); }); + jQuery('.show_more_edition').click(function(){ + jQuery(this).html('less...'); + jQuery(this).next().toggle(); + }); }); + + + {% endblock %} @@ -31,7 +38,7 @@ jQuery(document).ready(function(){
- {% if work.first_epub_url or work.first_pdf_url %} + {% if work.first_ebook %} AVAILABLE! {% else %}{% if work.last_campaign %} {% if status == 'ACTIVE' %} @@ -106,7 +113,7 @@ jQuery(document).ready(function(){
- {% if work.first_epub_url or work.first_pdf_url %} + {% if work.first_ebook %} {% if wishers == 1 %} 1 Ungluer is {% else %} @@ -127,17 +134,14 @@ jQuery(document).ready(function(){ {% endif %} wished for this Work {% endif %}{% endif %}
-
+
- {% if work.first_epub_url or work.first_pdf_url %} + {% if work.first_ebook %} - {% if work.first_epub_url %} - EPUB - {% endif %} - {% if work.first_pdf_url %} - PDF - {% endif %} + {% for ebook in work.ebooks %} + {{ ebook.format }} {{ebook.rights}} at {{ebook.provider}}
+ {% endfor %}
{% endif %} {% if request.user.is_anonymous %} @@ -154,7 +158,7 @@ jQuery(document).ready(function(){
{% else %}
- Add to {% if work.first_epub_url or work.first_pdf_url %}Enjoying{% else %}Wishlist{% endif %} + Add to {% if work.first_ebook %}Enjoying{% else %}Wishlist{% endif %}
{% endif %}{% endif %}{% endif %}
@@ -224,7 +228,7 @@ jQuery(document).ready(function(){

Last campaign details

{{ work.last_campaign.details|safe }} {% endif %} - +

Rights Information

{% if work.claim.count %}

This work has been claimed by:

@@ -271,10 +275,11 @@ jQuery(document).ready(function(){ {% endif %}

Editions

+ {% if alert %}
Ebook Contribution:
{{ alert }}
{% endif %} {% for edition in editions %}
- + {% if edition.ebook_form %} +
more...
+
+ {% if edition.ebooks %} +
eBooks for this Edition
+ {% for ebook in edition.ebooks.all %} + {{ ebook.format }} {{ebook.rights}} at {{ebook.provider}}
+ {% endfor %} + {% endif %} +
Add an eBook for this Edition
+ If you know that this edition is available as a public domain or Creative Commons ebook, you can enter the link here and "unglue" it. Right now, we're only accepting URLs that point to Internet Archive, Wikisources, Hathitrust, Project Gutenberg, or Google Books. +
+ {% csrf_token %}{{ edition.ebook_form.edition }}{{ edition.ebook_form.user }}{{ edition.ebook_form.provider }} + URL: {{ edition.ebook_form.url }}
+ File Format: {{ edition.ebook_form.format }}    + License: {{ edition.ebook_form.rights }}
+ +
+
+ {% endif %} {% endfor %}
diff --git a/frontend/views.py b/frontend/views.py index da297ee7..38556e4d 100755 --- a/frontend/views.py +++ b/frontend/views.py @@ -42,6 +42,7 @@ from regluit.core.goodreads import GoodreadsClient from regluit.frontend.forms import UserData, ProfileForm, CampaignPledgeForm, GoodreadsShelfLoadingForm from regluit.frontend.forms import RightsHolderForm, UserClaimForm, LibraryThingForm, OpenCampaignForm from regluit.frontend.forms import ManageCampaignForm, DonateForm, CampaignAdminForm, EmailShareForm, FeedbackForm +from regluit.frontend.forms import EbookForm from regluit.payment.manager import PaymentManager from regluit.payment.models import Transaction from regluit.payment.parameters import TARGET_TYPE_CAMPAIGN, TARGET_TYPE_DONATION, PAYMENT_TYPE_AUTHORIZATION @@ -90,13 +91,29 @@ def stub(request): def work(request, work_id, action='display'): try: - work = models.Work.objects.get(id = work_id) + work = models.Work.objects.get(id = work_id) except models.Work.DoesNotExist: - try: - work = models.WasWork.objects.get(was = work_id).work - except models.WasWork.DoesNotExist: - raise Http404 + try: + work = models.WasWork.objects.get(was = work_id).work + except models.WasWork.DoesNotExist: + raise Http404 + if request.method == 'POST' and not request.user.is_anonymous(): + activetab = '4' + ebook_form= EbookForm( data = request.POST) + if ebook_form.is_valid(): + ebook_form.save() + alert = 'Thanks for adding an ebook to unglue.it!' + else: + alert = ebook_form.errors + else: + alert='' + try: + activetab = request.GET['tab'] + if activetab not in ['1', '2', '3', '4']: + activetab = '1'; + except: + activetab = '1'; editions = work.editions.all().order_by('-publication_date') campaign = work.last_campaign() try: @@ -109,6 +126,9 @@ def work(request, work_id, action='display'): pubdate = 'unknown' if not request.user.is_anonymous(): claimform = UserClaimForm( request.user, data={'work':work.pk, 'user': request.user.id}) + for edition in editions: + #edition.ebook_form = EbookForm( data = {'user':request.user.id, 'edition':edition.pk }) + edition.ebook_form = EbookForm( instance= models.Ebook(user = request.user, edition = edition, provider = 'x' ) ) else: claimform = None if campaign: @@ -120,12 +140,6 @@ def work(request, work_id, action='display'): wishers = work.num_wishes base_url = request.build_absolute_uri("/")[:-1] - try: - activetab = request.GET['tab'] - if activetab not in ['1', '2', '3', '4']: - activetab = '1'; - except: - activetab = '1'; #may want to deprecate the following if action == 'setup_campaign': @@ -142,6 +156,7 @@ def work(request, work_id, action='display'): 'pubdate': pubdate, 'pledged':pledged, 'activetab': activetab, + 'alert':alert }) def manage_campaign(request, id): @@ -729,8 +744,8 @@ def supporter(request, supporter_username, template_name): wishlist = supporter.wishlist fromsupport = 1 - # querysets for tabs - # unglued tab is anything for which there has been a successful campaign OR anything with an existing ebook + # querysets for tabs + # unglued tab is anything for which there has been a successful campaign OR anything with an existing ebook works_unglued = wishlist.works.all().filter(Q(campaigns__status='SUCCESSFUL') | Q(editions__ebooks__isnull=False)).order_by('-num_wishes') # take the set complement of the unglued tab and filter it for active works to get middle tab diff --git a/static/css/campaign.css b/static/css/campaign.css index 9c665b3b..c72e4b0d 100755 --- a/static/css/campaign.css +++ b/static/css/campaign.css @@ -1,528 +1,77 @@ -/* variables and mixins used in multiple less files go here */ -.header-text { - height: 36px; - line-height: 36px; - display: block; - text-decoration: none; - font-weight: bold; - font-size: 13px; - letter-spacing: -0.05em; -} -.panelborders { - border-width: 1px 0px; - border-style: solid none; - border-color: #FFFFFF; -} -.roundedspan { - border: 1px solid #d4d4d4; - -moz-border-radius: 7px; - -webkit-border-radius: 7px; - border-radius: 7px; - padding: 1px; - color: #fff; - margin: 0 8px 0 0; - display: inline-block; -} -.roundedspan > span { - padding: 7px 7px; - min-width: 15px; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; - border-radius: 5px; - text-align: center; - display: inline-block; -} -.roundedspan > span .hovertext { - display: none; -} -.roundedspan > span:hover .hovertext { - display: inline; -} -.mediaborder { - padding: 5px; - border: solid 5px #EDF3F4; -} -.google_signup_div { - padding: 14px 0; -} -.google_signup_div div { - height: 24px; - line-height: 24px; - float: left; - padding-left: 5px; -} -.google_signup_div img { - float: left; - height: 24px; - width: 24px; -} -.actionbuttons { - width: auto; - height: 36px; - line-height: 36px; - background: #8dc63f; - -moz-border-radius: 32px; - -webkit-border-radius: 32px; - border-radius: 32px; - color: white; - cursor: pointer; - font-size: 13px; - font-weight: bold; - padding: 0 15px; - border: none; - margin: 5px 0; -} -#js-page-wrap { - overflow: hidden; -} -#main-container { - margin-top: 20px; -} -#js-leftcol .jsmodule, .pledge.jsmodule { - margin-bottom: 10px; -} -#js-leftcol .jsmodule.rounded .jsmod-content, .pledge.jsmodule.rounded .jsmod-content { - -moz-border-radius: 20px; - -webkit-border-radius: 20px; - border-radius: 20px; - background: #edf3f4; - color: #3d4e53; - padding: 10px 20px; - font-weight: bold; - border: none; - margin: 0; -} -#js-leftcol .jsmodule.rounded .jsmod-content.active0, -.pledge.jsmodule.rounded .jsmod-content.active0, -#js-leftcol .jsmodule.rounded .jsmod-content.active1, -.pledge.jsmodule.rounded .jsmod-content.active1 { - background: #e35351; -} -#js-leftcol .jsmodule.rounded .jsmod-content.active2, .pledge.jsmodule.rounded .jsmod-content.active2 { - background: #e18551; -} -#js-leftcol .jsmodule.rounded .jsmod-content.active3, .pledge.jsmodule.rounded .jsmod-content.active3 { - background: #e5a956; -} -#js-leftcol .jsmodule.rounded .jsmod-content.active4, .pledge.jsmodule.rounded .jsmod-content.active4 { - background: #efd45e; -} -#js-leftcol .jsmodule.rounded .jsmod-content.active5, .pledge.jsmodule.rounded .jsmod-content.active5 { - background: #bbcf67; -} -#js-leftcol .jsmodule.rounded .jsmod-content.active6, .pledge.jsmodule.rounded .jsmod-content.active6 { - background: #8dc63f; -} -#js-leftcol .jsmodule.rounded .jsmod-content span, .pledge.jsmodule.rounded .jsmod-content span { - display: inline-block; - vertical-align: middle; -} -#js-leftcol .jsmodule.rounded .jsmod-content span.spacer, .pledge.jsmodule.rounded .jsmod-content span.spacer { - visibility: none; -} -#js-leftcol .jsmodule.rounded .jsmod-content span.findtheungluers, .pledge.jsmodule.rounded .jsmod-content span.findtheungluers { - cursor: pointer; -} -.jsmodule.pledge { - float: left; - margin-left: 10px; -} -.book-detail { - float: left; - width: 100%; - clear: both; - display: block; -} -.book-detail-img { - float: left; - margin-right: 10px; - width: 151px; -} -.book-detail-img img { - padding: 5px; - border: solid 5px #EDF3F4; -} -.book-detail-info { - float: left; - /* if we want to nix the explore bar, width should be 544ish */ - - width: 309px; -} -.book-detail-info h2.book-name, .book-detail-info h3.book-author, .book-detail-info h3.book-year { - padding: 0; - margin: 0; - line-height: normal; -} -.book-detail-info h2.book-name { - font-size: 18px; - text-transform: capitalize; - font-weight: bold; - color: #3d4e53; -} -.book-detail-info h3.book-author, .book-detail-info h3.book-year { - font-size: 12px; - font-weight: normal; - color: #6994a3; -} -.book-detail-info > div { - width: 100%; - clear: both; - display: block; - overflow: hidden; - border-top: 1px solid #edf3f4; - padding: 10px 0; -} -.book-detail-info > div.layout { - border: none; - padding: 0; -} -.book-detail-info > div.layout div.pubinfo { - float: left; - width: auto; -} -.book-detail-info > div.layout div.btn_support { - float: right; -} -.book-detail-info > div.layout div.btn_support input { - background: url("/static/images/btn_bg.png") 0 0 no-repeat; - width: 104px; - height: 41px; - display: block; - color: #fff; - font-weight: bold; - text-align: center; - border: none; - padding: 0; - cursor: pointer; -} -.book-detail-info > div.layout div.btn_support.modify input { - background: url("/static/images/btn_bg_grey.png") 0 0 no-repeat; -} -.book-detail-info .btn_wishlist span { - text-align: right; -} -.book-detail-info .find-book { - margin-top: 15px; -} -.book-detail-info .find-book label { - float: left; - line-height: 31px; -} -.book-detail-info .find-link { - float: right; -} -.book-detail-info .find-link a { - padding: 0 0 0 4px; -} -.book-detail-info .pledged-info { - padding: 0; - position: relative; -} -.book-detail-info .pledged-group { - padding: 10px 40px 10px 0; - float: left; -} -.book-detail-info .status { - position: absolute; - top: 50%; - right: 0%; - height: 25px; - margin-top: -12px; -} -#tabs { - border-bottom: 4px solid #6994a3; - clear: both; - float: left; - margin-top: 10px; - width: 100%; -} -#tabs ul.book-list-view { - margin-bottom: 4px !important; -} -#tabs-1, -#tabs-2, -#tabs-3, -#tabs-4 { - display: none; -} -#tabs-1.active, -#tabs-2.active, -#tabs-3.active, -#tabs-4.active { - display: inherit; -} -#tabs-2 textarea { - width: 95%; -} -ul.tabs { - float: left; - padding: 0; - margin: 0; - list-style: none; - width: 100%; -} -ul.tabs li { - float: left; - height: 46px; - line-height: 46px; - padding-right: 2px; - width: 116px; -} -ul.tabs li.tabs4 { - padding-right: 0px; -} -ul.tabs li a { - height: 46px; - line-height: 46px; - display: block; - text-align: center; - padding: 0 10px; - min-width: 80px; - -moz-border-radius: 7px 7px 0 0; - -webkit-border-radius: 7px 7px 0 0; - border-radius: 7px 7px 0 0; - background: #d6dde0; - color: #3d4e53; -} -ul.tabs li a:hover { - text-decoration: none; -} -ul.tabs li a:hover, ul.tabs li.active a { - background: #6994a3; - color: #fff; -} -#js-rightcol { - float: right; - width: 235px; - margin-bottom: 20px; -} -#js-rightcol h3.jsmod-title { - background: #a7c1ca; - -moz-border-radius: 10px; - -webkit-border-radius: 10px; - border-radius: 10px; - padding: 10px; - height: auto; - font-style: normal; - font-size: 14px; - margin: 0 0 10px 0; - color: white; -} -#js-rightcol h3.jsmod-title span { - padding: 0; - color: #fff; - font-style: normal; -} -#js-rightcol .jsmodule { - margin-bottom: 10px; -} -.js-rightcol-pad { - border: 1px solid #d6dde0; - -moz-border-radius: 10px; - -webkit-border-radius: 10px; - border-radius: 10px; - padding: 10px; -} -#js-maincol { - float: left; - /* If we want to nuke the explore column, width should be 705ish */ - - width: 470px; - margin: 0 10px; -} -#js-maincol div#content-block { - background: none; - padding: 0; -} -div#content-block-content { - padding-left: 5px; -} -.tabs-content { - padding-right: 5px; -} -.tabs-content iframe { - padding: 5px; - border: solid 5px #EDF3F4; -} -.tabs-content form { - margin-left: -5px; -} -ul.social a:hover { - text-decoration: none; -} -ul.social li { - padding: 5px 0 5px 30px; - height: 28px; - line-height: 28px; -} -ul.social li.facebook { - background: url("/static/images/icons/facebook.png") 10px center no-repeat; - cursor: pointer; -} -ul.social li.facebook span { - padding-left: 10px; -} -ul.social li.facebook:hover { - background: #8dc63f url("/static/images/icons/facebook-hover.png") 10px center no-repeat; -} -ul.social li.facebook:hover span { - color: #fff; -} -ul.social li.twitter { - background: url("/static/images/icons/twitter.png") 10px center no-repeat; - cursor: pointer; -} -ul.social li.twitter span { - padding-left: 10px; -} -ul.social li.twitter:hover { - background: #8dc63f url("/static/images/icons/twitter-hover.png") 10px center no-repeat; -} -ul.social li.twitter:hover span { - color: #fff; -} -ul.social li.email { - background: url("/static/images/icons/email.png") 10px center no-repeat; - cursor: pointer; -} -ul.social li.email span { - padding-left: 10px; -} -ul.social li.email:hover { - background: #8dc63f url("/static/images/icons/email-hover.png") 10px center no-repeat; -} -ul.social li.email:hover span { - color: #fff; -} -ul.social li.embed { - background: url("/static/images/icons/embed.png") 10px center no-repeat; - cursor: pointer; -} -ul.social li.embed span { - padding-left: 10px; -} -ul.social li.embed:hover { - background: #8dc63f url("/static/images/icons/embed-hover.png") 10px center no-repeat; -} -ul.social li.embed:hover span { - color: #fff; -} -#widgetcode { - display: none; - border: 1px solid #d6dde0; - -moz-border-radius: 10px; - -webkit-border-radius: 10px; - border-radius: 10px; - padding: 10px; -} -ul.support li { - border-bottom: 1px solid #d6dde0; - padding: 10px 5px 10px 10px; - background: url("/static/images/icons/pledgearrow.png") 98% center no-repeat; -} -ul.support li span { - display: block; - padding-right: 10px; -} -ul.support li span.menu-item-price { - font-size: 18px; -} -ul.support li:hover { - color: #fff; - background: #8dc63f url("/static/images/icons/pledgearrow-hover.png") 98% center no-repeat; -} -ul.support li:hover a { - color: #fff; - text-decoration: none; -} -.work_supporter_nocomment { - height: 50px; - margin-top: 5px; - vertical-align: middle; - margin-left: -5px; -} -.work_supporter_avatar { - float: left; -} -.work_supporter_name { - height: 50px; - line-height: 50px; - float: left; -} -/* this line differs from sitewide.css. should it? */ -a { - color: #3d4e53; - font-size: 12px; -} -.add-wishlist, -.add-wishlist-workpage, -.remove-wishlist-workpage, -.remove-wishlist, -.on-wishlist, -.create-account { - float: right; - cursor: pointer; -} -.add-wishlist span, -.add-wishlist-workpage span, -.remove-wishlist-workpage span, -.remove-wishlist span, -.on-wishlist span, -.create-account span { - font-weight: normal; - color: #3d4e53; - text-transform: none; - padding-left: 20px; -} -.add-wishlist span.on-wishlist, -.add-wishlist-workpage span.on-wishlist, -.remove-wishlist-workpage span.on-wishlist, -.remove-wishlist span.on-wishlist, -.on-wishlist span.on-wishlist, -.create-account span.on-wishlist { - background: url("/static/images/checkmark_small.png") left center no-repeat; - cursor: default; -} -.add-wishlist span, .add-wishlist-workpage span, .create-account span { - background: url("/static/images/booklist/add-wishlist.png") left center no-repeat; -} -.remove-wishlist-workpage span, .remove-wishlist span { - background: url("/static/images/booklist/remove-wishlist-blue.png") left center no-repeat; -} -.editions { - clear: both; -} -.editions div { - float: left; - padding-bottom: 5px; -} -.editions .image { - width: 60px; - overflow: hidden; -} -.editions .metadata { - display: block; - overflow: hidden; - margin-left: 5px; -} -.editions a:hover { - text-decoration: underline; -} -.thank-you { - font-size: 20px; -} -.work_supporter { - height: auto; - min-height: 50px; - margin-top: 5px; - vertical-align: middle; - margin-left: -5px; -} -.work_supporter_avatar { - margin-right: 5px; -} -.work_supporter_avatar img { - -moz-border-radius: 5px; - -webkit-border-radius: 5px; - border-radius: 5px; -} +.header-text{height:36px;line-height:36px;display:block;text-decoration:none;font-weight:bold;font-size:13px;letter-spacing:-0.05em;} +.panelborders{border-width:1px 0px;border-style:solid none;border-color:#FFFFFF;} +.roundedspan{border:1px solid #d4d4d4;-moz-border-radius:7px;-webkit-border-radius:7px;border-radius:7px;padding:1px;color:#fff;margin:0 8px 0 0;display:inline-block;}.roundedspan>span{padding:7px 7px;min-width:15px;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;text-align:center;display:inline-block;}.roundedspan>span .hovertext{display:none;} +.roundedspan>span:hover .hovertext{display:inline;} +.mediaborder{padding:5px;border:solid 5px #EDF3F4;} +.google_signup_div{padding:14px 0;}.google_signup_div div{height:24px;line-height:24px;float:left;padding-left:5px;} +.google_signup_div img{float:left;height:24px;width:24px;} +.actionbuttons{width:auto;height:36px;line-height:36px;background:#8dc63f;-moz-border-radius:32px;-webkit-border-radius:32px;border-radius:32px;color:white;cursor:pointer;font-size:13px;font-weight:bold;padding:0 15px;border:none;margin:5px 0;} +#js-page-wrap{overflow:hidden;} +#main-container{margin-top:20px;} +#js-leftcol .jsmodule,.pledge.jsmodule{margin-bottom:10px;}#js-leftcol .jsmodule.rounded .jsmod-content,.pledge.jsmodule.rounded .jsmod-content{-moz-border-radius:20px;-webkit-border-radius:20px;border-radius:20px;background:#edf3f4;color:#3d4e53;padding:10px 20px;font-weight:bold;border:none;margin:0;}#js-leftcol .jsmodule.rounded .jsmod-content.active0,.pledge.jsmodule.rounded .jsmod-content.active0,#js-leftcol .jsmodule.rounded .jsmod-content.active1,.pledge.jsmodule.rounded .jsmod-content.active1{background:#e35351;} +#js-leftcol .jsmodule.rounded .jsmod-content.active2,.pledge.jsmodule.rounded .jsmod-content.active2{background:#e18551;} +#js-leftcol .jsmodule.rounded .jsmod-content.active3,.pledge.jsmodule.rounded .jsmod-content.active3{background:#e5a956;} +#js-leftcol .jsmodule.rounded .jsmod-content.active4,.pledge.jsmodule.rounded .jsmod-content.active4{background:#efd45e;} +#js-leftcol .jsmodule.rounded .jsmod-content.active5,.pledge.jsmodule.rounded .jsmod-content.active5{background:#bbcf67;} +#js-leftcol .jsmodule.rounded .jsmod-content.active6,.pledge.jsmodule.rounded .jsmod-content.active6{background:#8dc63f;} +#js-leftcol .jsmodule.rounded .jsmod-content span,.pledge.jsmodule.rounded .jsmod-content span{display:inline-block;vertical-align:middle;}#js-leftcol .jsmodule.rounded .jsmod-content span.spacer,.pledge.jsmodule.rounded .jsmod-content span.spacer{visibility:none;} +#js-leftcol .jsmodule.rounded .jsmod-content span.findtheungluers,.pledge.jsmodule.rounded .jsmod-content span.findtheungluers{cursor:pointer;} +.jsmodule.pledge{float:left;margin-left:10px;} +.book-detail{float:left;width:100%;clear:both;display:block;} +.book-detail-img{float:left;margin-right:10px;width:151px;}.book-detail-img img{padding:5px;border:solid 5px #EDF3F4;} +.book-detail-info{float:left;width:309px;}.book-detail-info h2.book-name,.book-detail-info h3.book-author,.book-detail-info h3.book-year{padding:0;margin:0;line-height:normal;} +.book-detail-info h2.book-name{font-size:18px;text-transform:capitalize;font-weight:bold;color:#3d4e53;} +.book-detail-info h3.book-author,.book-detail-info h3.book-year{font-size:12px;font-weight:normal;color:#6994a3;} +.book-detail-info>div{width:100%;clear:both;display:block;overflow:hidden;border-top:1px solid #edf3f4;padding:10px 0;} +.book-detail-info>div.layout{border:none;padding:0;}.book-detail-info>div.layout div.pubinfo{float:left;width:auto;} +.book-detail-info>div.layout div.btn_support{float:right;}.book-detail-info>div.layout div.btn_support input{background:url("/static/images/btn_bg.png") 0 0 no-repeat;width:104px;height:41px;display:block;color:#fff;font-weight:bold;text-align:center;border:none;padding:0;cursor:pointer;} +.book-detail-info>div.layout div.btn_support.modify input{background:url("/static/images/btn_bg_grey.png") 0 0 no-repeat;} +.book-detail-info .btn_wishlist span{text-align:right;} +.book-detail-info .find-book{margin-top:15px;}.book-detail-info .find-book label{float:left;line-height:31px;} +.book-detail-info .find-link{float:right;}.book-detail-info .find-link a{padding:0 0 0 4px;} +.book-detail-info .pledged-info{padding:0;position:relative;} +.book-detail-info .pledged-group{padding:10px 40px 10px 0;float:left;} +.book-detail-info .status{position:absolute;top:50%;right:0%;height:25px;margin-top:-12px;} +#tabs{border-bottom:4px solid #6994a3;clear:both;float:left;margin-top:10px;width:100%;}#tabs ul.book-list-view{margin-bottom:4px !important;} +#tabs-1,#tabs-2,#tabs-3,#tabs-4{display:none;} +#tabs-1.active,#tabs-2.active,#tabs-3.active,#tabs-4.active{display:inherit;} +#tabs-2 textarea{width:95%;} +ul.tabs{float:left;padding:0;margin:0;list-style:none;width:100%;}ul.tabs li{float:left;height:46px;line-height:46px;padding-right:2px;width:116px;}ul.tabs li.tabs4{padding-right:0px;} +ul.tabs li a{height:46px;line-height:46px;display:block;text-align:center;padding:0 10px;min-width:80px;-moz-border-radius:7px 7px 0 0;-webkit-border-radius:7px 7px 0 0;border-radius:7px 7px 0 0;background:#d6dde0;color:#3d4e53;}ul.tabs li a:hover{text-decoration:none;} +ul.tabs li a:hover,ul.tabs li.active a{background:#6994a3;color:#fff;} +#js-rightcol{float:right;width:235px;margin-bottom:20px;}#js-rightcol h3.jsmod-title{background:#a7c1ca;-moz-border-radius:10px;-webkit-border-radius:10px;border-radius:10px;padding:10px;height:auto;font-style:normal;font-size:14px;margin:0 0 10px 0;color:white;}#js-rightcol h3.jsmod-title span{padding:0;color:#fff;font-style:normal;} +#js-rightcol .jsmodule{margin-bottom:10px;} +.js-rightcol-pad{border:1px solid #d6dde0;-moz-border-radius:10px;-webkit-border-radius:10px;border-radius:10px;padding:10px;} +#js-maincol{float:left;width:470px;margin:0 10px;}#js-maincol div#content-block{background:none;padding:0;} +div#content-block-content{padding-left:5px;} +.tabs-content{padding-right:5px;}.tabs-content iframe{padding:5px;border:solid 5px #EDF3F4;} +.tabs-content form{margin-left:-5px;} +ul.social a:hover{text-decoration:none;} +ul.social li{padding:5px 0 5px 30px;height:28px;line-height:28px;}ul.social li.facebook{background:url("/static/images/icons/facebook.png") 10px center no-repeat;cursor:pointer;}ul.social li.facebook span{padding-left:10px;} +ul.social li.facebook:hover{background:#8dc63f url("/static/images/icons/facebook-hover.png") 10px center no-repeat;}ul.social li.facebook:hover span{color:#fff;} +ul.social li.twitter{background:url("/static/images/icons/twitter.png") 10px center no-repeat;cursor:pointer;}ul.social li.twitter span{padding-left:10px;} +ul.social li.twitter:hover{background:#8dc63f url("/static/images/icons/twitter-hover.png") 10px center no-repeat;}ul.social li.twitter:hover span{color:#fff;} +ul.social li.email{background:url("/static/images/icons/email.png") 10px center no-repeat;cursor:pointer;}ul.social li.email span{padding-left:10px;} +ul.social li.email:hover{background:#8dc63f url("/static/images/icons/email-hover.png") 10px center no-repeat;}ul.social li.email:hover span{color:#fff;} +ul.social li.embed{background:url("/static/images/icons/embed.png") 10px center no-repeat;cursor:pointer;}ul.social li.embed span{padding-left:10px;} +ul.social li.embed:hover{background:#8dc63f url("/static/images/icons/embed-hover.png") 10px center no-repeat;}ul.social li.embed:hover span{color:#fff;} +#widgetcode{display:none;border:1px solid #d6dde0;-moz-border-radius:10px;-webkit-border-radius:10px;border-radius:10px;padding:10px;} +ul.support li{border-bottom:1px solid #d6dde0;padding:10px 5px 10px 10px;background:url("/static/images/icons/pledgearrow.png") 98% center no-repeat;}ul.support li span{display:block;padding-right:10px;}ul.support li span.menu-item-price{font-size:18px;} +ul.support li:hover{color:#fff;background:#8dc63f url("/static/images/icons/pledgearrow-hover.png") 98% center no-repeat;}ul.support li:hover a{color:#fff;text-decoration:none;} +.work_supporter_nocomment{height:50px;margin-top:5px;vertical-align:middle;margin-left:-5px;} +.work_supporter_avatar{float:left;} +.work_supporter_name{height:50px;line-height:50px;float:left;} +a{color:#3d4e53;font-size:12px;} +.add-wishlist,.add-wishlist-workpage,.remove-wishlist-workpage,.remove-wishlist,.on-wishlist,.create-account{float:right;cursor:pointer;}.add-wishlist span,.add-wishlist-workpage span,.remove-wishlist-workpage span,.remove-wishlist span,.on-wishlist span,.create-account span{font-weight:normal;color:#3d4e53;text-transform:none;padding-left:20px;}.add-wishlist span.on-wishlist,.add-wishlist-workpage span.on-wishlist,.remove-wishlist-workpage span.on-wishlist,.remove-wishlist span.on-wishlist,.on-wishlist span.on-wishlist,.create-account span.on-wishlist{background:url("/static/images/checkmark_small.png") left center no-repeat;cursor:default;} +.add-wishlist span,.add-wishlist-workpage span,.create-account span{background:url("/static/images/booklist/add-wishlist.png") left center no-repeat;} +.remove-wishlist-workpage span,.remove-wishlist span{background:url("/static/images/booklist/remove-wishlist-blue.png") left center no-repeat;} +.editions{clear:both;}.editions div{float:left;padding-bottom:5px;} +.editions .image{width:60px;overflow:hidden;} +.editions .metadata{display:block;overflow:hidden;margin-left:5px;} +.editions a:hover{text-decoration:underline;} +.thank-you{font-size:20px;} +.work_supporter{height:auto;min-height:50px;margin-top:5px;vertical-align:middle;margin-left:-5px;} +.work_supporter_avatar{margin-right:5px;}.work_supporter_avatar img{-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;} +.more_edition{display:none;clear:both;padding-bottom:10px;padding-left:60px;} +.show_more_edition:hover{text-decoration:underline;} +.show_more_edition{text-align:right;}