diff --git a/app/assets/javascripts/modeling.js.jsx b/app/assets/javascripts/modeling.js.jsx
index 142a1793..002ef774 100644
--- a/app/assets/javascripts/modeling.js.jsx
+++ b/app/assets/javascripts/modeling.js.jsx
@@ -225,11 +225,13 @@ var Neopia = (function($, I18n) {
Neopia.init();
this._createItems($);
var usersEl = $('#modeling-neopets-users');
- this._usersComponent = React.renderComponent(,
- usersEl.get(0));
- var usernames = ImpressUser.getNeopetsUsernames();
- usernames.forEach(this._registerUsername.bind(this));
- this._updateUsernames();
+ if (usersEl.length) {
+ this._usersComponent = React.renderComponent(,
+ usersEl.get(0));
+ var usernames = ImpressUser.getNeopetsUsernames();
+ usernames.forEach(this._registerUsername.bind(this));
+ this._updateUsernames();
+ }
},
model: function(neopiaPetId, itemId) {
var oldCustomization = this._customizationsByPetId[neopiaPetId];
diff --git a/app/assets/javascripts/outfits/new.js b/app/assets/javascripts/outfits/new.js
index e00aa27d..c1f4d813 100644
--- a/app/assets/javascripts/outfits/new.js
+++ b/app/assets/javascripts/outfits/new.js
@@ -1,315 +1,252 @@
-var disqus_shortname = 'dresstoimpress';
-
(function () { // don't need to export anything in here
-var preview_el = $('#pet-preview'),
- img_el = preview_el.find('img'),
- response_el = preview_el.find('span');
+ var preview_el = $('#pet-preview'),
+ img_el = preview_el.find('img'),
+ response_el = preview_el.find('span');
-var defaultPreviewUrl = img_el.attr('src');
+ var defaultPreviewUrl = img_el.attr('src');
-preview_el.click(function () {
- Preview.Job.current.visit();
-});
+ preview_el.click(function () {
+ Preview.Job.current.visit();
+ });
-var Preview = {
- clear: function () {
- if(typeof Preview.Job.fallback != 'undefined') Preview.Job.fallback.setAsCurrent();
- },
- displayLoading: function () {
- preview_el.addClass('loading');
- response_el.text('Loading...');
- },
- failed: function () {
- preview_el.addClass('hidden');
- },
- notFound: function (key, options) {
- Preview.failed();
- response_el.empty();
- $('#preview-' + key + '-template').tmpl(options).appendTo(response_el);
- },
- updateWithName: function (name_el) {
- var name = name_el.val(), job;
- if(name) {
- currentName = name;
- if(!Preview.Job.current || name != Preview.Job.current.name) {
- job = new Preview.Job.Name(name);
- job.setAsCurrent();
- Preview.displayLoading();
+ var Preview = {
+ clear: function () {
+ if(typeof Preview.Job.fallback != 'undefined') Preview.Job.fallback.setAsCurrent();
+ },
+ displayLoading: function () {
+ preview_el.addClass('loading');
+ response_el.text('Loading...');
+ },
+ failed: function () {
+ preview_el.addClass('hidden');
+ },
+ notFound: function (key, options) {
+ Preview.failed();
+ response_el.empty();
+ $('#preview-' + key + '-template').tmpl(options).appendTo(response_el);
+ },
+ updateWithName: function (name_el) {
+ var name = name_el.val(), job;
+ if(name) {
+ currentName = name;
+ if(!Preview.Job.current || name != Preview.Job.current.name) {
+ job = new Preview.Job.Name(name);
+ job.setAsCurrent();
+ Preview.displayLoading();
+ }
+ } else {
+ Preview.clear();
}
- } else {
- Preview.clear();
}
}
-}
-function loadNotable() {
- $.getJSON('http://notables.openneo.net/api/1/days/ago/1?callback=?', function (response) {
- var notables = response.notables;
- var i = Math.floor(Math.random() * notables.length);
- Preview.Job.fallback = new Preview.Job.Name(notables[i].petName);
+ function loadNotable() {
+ // TODO: add HTTPS to notables
+ // $.getJSON('http://notables.openneo.net/api/1/days/ago/1?callback=?', function (response) {
+ // var notables = response.notables;
+ // var i = Math.floor(Math.random() * notables.length);
+ // Preview.Job.fallback = new Preview.Job.Name(notables[i].petName);
+ // if(!Preview.Job.current) {
+ // Preview.Job.fallback.setAsCurrent();
+ // }
+ // });
if(!Preview.Job.current) {
Preview.Job.fallback.setAsCurrent();
}
- });
-}
+ }
-function loadFeature() {
- $.getJSON('/donations/features', function(features) {
- if (features.length > 0) {
- var feature = features[Math.floor(Math.random() * features.length)];
- Preview.Job.fallback = new Preview.Job.Feature(feature);
- if (!Preview.Job.current) {
- Preview.Job.fallback.setAsCurrent();
+ function loadFeature() {
+ $.getJSON('/donations/features', function(features) {
+ if (features.length > 0) {
+ var feature = features[Math.floor(Math.random() * features.length)];
+ Preview.Job.fallback = new Preview.Job.Feature(feature);
+ if (!Preview.Job.current) {
+ Preview.Job.fallback.setAsCurrent();
+ }
+ } else {
+ loadNotable();
}
- } else {
- loadNotable();
- }
- });
-}
-
-loadFeature();
-
-Preview.Job = function (key, base) {
- var job = this,
- quality = 2;
- job.loading = false;
-
- function getImageSrc() {
- if (key.substr(0, 3) === 'a:-') {
- // lol lazy code for prank image :P
- return "http://swfimages.impress.openneo.net" +
- "/biology/000/000/0-2/" + key.substr(2) + "/300x300.png";
- } else if (base === 'cp' || base === 'cpn') {
- return petImage(base + '/' + key, quality);
- } else if (base === 'url') {
- return key;
- } else {
- throw new Error("unrecognized image base " + base);
- }
+ });
}
-
- function load() {
- job.loading = true;
- img_el.attr('src', getImageSrc());
- }
-
- this.increaseQualityIfPossible = function () {
- if(quality == 2) {
- quality = 4;
+
+ loadFeature();
+
+ Preview.Job = function (key, base) {
+ var job = this,
+ quality = 2;
+ job.loading = false;
+
+ function getImageSrc() {
+ if (key.substr(0, 3) === 'a:-') {
+ // lol lazy code for prank image :P
+ // TODO: HTTPS?
+ return "http://swfimages.impress.openneo.net" +
+ "/biology/000/000/0-2/" + key.substr(2) + "/300x300.png";
+ } else if (base === 'cp' || base === 'cpn') {
+ return petImage(base + '/' + key, quality);
+ } else if (base === 'url') {
+ return key;
+ } else {
+ throw new Error("unrecognized image base " + base);
+ }
+ }
+
+ function load() {
+ job.loading = true;
+ img_el.attr('src', getImageSrc());
+ }
+
+ this.increaseQualityIfPossible = function () {
+ if(quality == 2) {
+ quality = 4;
+ load();
+ }
+ }
+
+ this.setAsCurrent = function () {
+ Preview.Job.current = job;
load();
}
- }
-
- this.setAsCurrent = function () {
- Preview.Job.current = job;
- load();
+
+ this.notFound = function() {
+ Preview.notFound('pet-not-found');
+ }
}
- this.notFound = function() {
- Preview.notFound('pet-not-found');
- }
-}
+ Preview.Job.Name = function (name) {
+ this.name = name;
+ Preview.Job.apply(this, [name, 'cpn']);
-Preview.Job.Name = function (name) {
- this.name = name;
- Preview.Job.apply(this, [name, 'cpn']);
-
- this.visit = function() {
- $('.main-pet-name').val(this.name).closest('form').submit();
- }
-}
-
-Preview.Job.Hash = function (hash, form) {
- Preview.Job.apply(this, [hash, 'cp']);
-
- this.visit = function() {
- window.location = "/wardrobe?color=" + form.find('.color').val() + "&species=" +
- form.find('.species').val();
- }
-}
-
-Preview.Job.Feature = function(feature) {
- Preview.Job.apply(this, [feature.outfit_image_url, 'url']);
- this.name = "Thanks for donating, " + feature.donor_name + "!"; // TODO: i18n
-
- this.visit = function() {
- window.location = '/donate';
+ this.visit = function() {
+ $('.main-pet-name').val(this.name).closest('form').submit();
+ }
}
- this.notFound = function() {
- // The outfit thumbnail hasn't generated or is missing or something.
- // Let's fall back to a boring image for now.
- var boring = new Preview.Job.Feature({
- donor_name: feature.donor_name,
- outfit_image_url: defaultPreviewUrl
+ Preview.Job.Hash = function (hash, form) {
+ Preview.Job.apply(this, [hash, 'cp']);
+
+ this.visit = function() {
+ window.location = "/wardrobe?color=" + form.find('.color').val() + "&species=" +
+ form.find('.species').val();
+ }
+ }
+
+ Preview.Job.Feature = function(feature) {
+ Preview.Job.apply(this, [feature.outfit_image_url, 'url']);
+ this.name = "Thanks for donating, " + feature.donor_name + "!"; // TODO: i18n
+
+ this.visit = function() {
+ window.location = '/donate';
+ }
+
+ this.notFound = function() {
+ // The outfit thumbnail hasn't generated or is missing or something.
+ // Let's fall back to a boring image for now.
+ var boring = new Preview.Job.Feature({
+ donor_name: feature.donor_name,
+ outfit_image_url: defaultPreviewUrl
+ });
+ boring.setAsCurrent();
+ }
+ }
+
+
+ $(function () {
+ var previewWithNameTimeout;
+
+ var name_el = $('.main-pet-name');
+ name_el.val(PetQuery.name);
+ Preview.updateWithName(name_el);
+
+ name_el.keyup(function () {
+ if(previewWithNameTimeout) {
+ clearTimeout(previewWithNameTimeout);
+ Preview.Job.current.loading = false;
+ }
+ var name_el = $(this);
+ previewWithNameTimeout = setTimeout(function() {
+ Preview.updateWithName(name_el);
+ }, 250);
});
- boring.setAsCurrent();
- }
-}
-
-
-$(function () {
- var previewWithNameTimeout;
-
- var name_el = $('.main-pet-name');
- name_el.val(PetQuery.name);
- Preview.updateWithName(name_el);
-
- name_el.keyup(function () {
- if(previewWithNameTimeout) {
- clearTimeout(previewWithNameTimeout);
- Preview.Job.current.loading = false;
- }
- var name_el = $(this);
- previewWithNameTimeout = setTimeout(function() {
- Preview.updateWithName(name_el);
- }, 250);
- });
-
- img_el.load(function () {
- if(Preview.Job.current.loading) {
- Preview.Job.loading = false;
- Preview.Job.current.increaseQualityIfPossible();
- preview_el.removeClass('loading').removeClass('hidden').addClass('loaded');
- response_el.text(Preview.Job.current.name);
- }
- }).error(function () {
- if(Preview.Job.current.loading) {
- Preview.Job.loading = false;
- Preview.Job.current.notFound();
- }
- });
-
- $('.species, .color').change(function () {
- var type = {}, nameComponents = {};
- var form = $(this).closest('form');
- form.find('select').each(function () {
- var el = $(this), selectedEl = el.children(':selected'), key = el.attr('name');
- type[key] = selectedEl.val();
- nameComponents[key] = selectedEl.text();
+
+ img_el.load(function () {
+ if(Preview.Job.current.loading) {
+ Preview.Job.loading = false;
+ Preview.Job.current.increaseQualityIfPossible();
+ preview_el.removeClass('loading').removeClass('hidden').addClass('loaded');
+ response_el.text(Preview.Job.current.name);
+ }
+ }).error(function () {
+ if(Preview.Job.current.loading) {
+ Preview.Job.loading = false;
+ Preview.Job.current.notFound();
+ }
});
- name = nameComponents.color + ' ' + nameComponents.species;
- Preview.displayLoading();
- $.ajax({
- url: '/species/' + type.species + '/color/' + type.color + '/pet_type.json',
- data: {
- 'for': 'image'
- },
- dataType: 'json',
- success: function (data) {
- var job;
- if(data) {
- job = new Preview.Job.Hash(data.image_hash, form);
- job.name = name;
- job.setAsCurrent();
- } else {
- Preview.notFound('pet-type-not-found', {
- color_name: nameComponents.color,
- species_name: nameComponents.species
- });
+
+ $('.species, .color').change(function () {
+ var type = {}, nameComponents = {};
+ var form = $(this).closest('form');
+ form.find('select').each(function () {
+ var el = $(this), selectedEl = el.children(':selected'), key = el.attr('name');
+ type[key] = selectedEl.val();
+ nameComponents[key] = selectedEl.text();
+ });
+ name = nameComponents.color + ' ' + nameComponents.species;
+ Preview.displayLoading();
+ $.ajax({
+ url: '/species/' + type.species + '/color/' + type.color + '/pet_type.json',
+ data: {
+ 'for': 'image'
+ },
+ dataType: 'json',
+ success: function (data) {
+ var job;
+ if(data) {
+ job = new Preview.Job.Hash(data.image_hash, form);
+ job.name = name;
+ job.setAsCurrent();
+ } else {
+ Preview.notFound('pet-type-not-found', {
+ color_name: nameComponents.color,
+ species_name: nameComponents.species
+ });
+ }
}
- }
- });
- });
-
- $.getJSON('http://blog.openneo.net/api/read/json?callback=?', function (data) {
- var post = data.posts[0], el = $('#blog-preview'),
- url = post['url-with-slug'], header = "Here's the latest!", body = '',
- truncate_body_at = 500, image;
- if(post.type == 'regular') {
- header = post['regular-title'];
- body = post['regular-body'];
- } else if(post.type == 'link') {
- header = post['link-text'];
- body = post['link-description'];
- } else if(post.type == 'photo') {
- body = post['photo-caption'];
- image = post['photo-url-75'];
- }
- // No truncation on this new layout
- /*body = body.replace(/(<\/?[\S][^>]*>)/gi, '');
- if(body.length > truncate_body_at) {
- body = body.substring(0, truncate_body_at);
- body = body.replace(/\s+\w+$/, '');
- body += '…';
- }*/
- el.find('h2').text(header).wrapInner($('', {href: url}));
- var contentEl = el.find('div');
- contentEl.html(body);
- $('', {'id': 'blog-preview-comments', href: url + '#disqus_thread'}).appendTo(el);
- if(image) {
- el.find('img').attr('src', image).parent().attr('href', url);
- }
-
- // Localize
- var localizedBodies = {};
- contentEl.find('.locale').each(function () {
- var localizedBody = $(this);
- var locale = localizedBody.attr('class').match(/locale-(\S+)/)[1];
- localizedBodies[locale] = localizedBody;
+ });
});
- var fallbacks = $('#locale option:selected').attr('data-fallbacks').split(',');
- var bestLocale = null;
- for(var i = 0; i < fallbacks.length; i++) {
- if(localizedBodies.hasOwnProperty(fallbacks[i])) {
- bestLocale = fallbacks[i];
- break;
+
+ var neopiaError = document.location.search.match(/neopia%5Berror%5D=([^&]+)/);
+ if (neopiaError !== null) {
+ var message = decodeURI(neopiaError[1]).replace(/\+/g, ' ');
+ if (message === "pet not found") {
+ $('#pet-not-found').show();
+ } else {
+ var el = $('#neopia-error');
+ var text = el.text().replace('%{message}', message);
+ el.text(text).show();
}
}
-
- if(bestLocale) {
- // I feel bad doing all this in JS rather than CSS, but sometimes you
- // gotta do what you gotta do if you wanna support any number of locales.
- for(var locale in localizedBodies) {
- localizedBodies[locale].hide();
+
+ $('.load-pet-to-wardrobe').submit(function(e) {
+ if ($(this).find('.main-pet-name').val() === "" && Preview.Job.current) {
+ e.preventDefault();
+ Preview.Job.current.visit();
}
-
- localizedBodies[bestLocale].show();
-
- contentEl.find('.no-locale').hide();
+ });
+
+ function setNeopiaStatus(isOnline) {
+ $('#outfit-forms').attr('data-neopia-status', isOnline ? 'online' : 'offline');
}
-
- el.fadeIn('medium');
- addDisqusCount();
+
+ Neopia.Status.get().then(function(r) {
+ setNeopiaStatus(!!r.status);
+ }).fail(function() {
+ setNeopiaStatus(false);
+ });
});
- var neopiaError = document.location.search.match(/neopia%5Berror%5D=([^&]+)/);
- if (neopiaError !== null) {
- var message = decodeURI(neopiaError[1]).replace(/\+/g, ' ');
- if (message === "pet not found") {
- $('#pet-not-found').show();
- } else {
- var el = $('#neopia-error');
- var text = el.text().replace('%{message}', message);
- el.text(text).show();
- }
- }
+ $('#latest-contribution-created-at').timeago();
- $('.load-pet-to-wardrobe').submit(function(e) {
- if ($(this).find('.main-pet-name').val() === "" && Preview.Job.current) {
- e.preventDefault();
- Preview.Job.current.visit();
- }
- });
-
- function setNeopiaStatus(isOnline) {
- $('#outfit-forms').attr('data-neopia-status', isOnline ? 'online' : 'offline');
- }
-
- Neopia.Status.get().then(function(r) {
- setNeopiaStatus(!!r.status);
- }).fail(function() {
- setNeopiaStatus(false);
- });
-});
-
-function addDisqusCount() {
- var s = document.createElement('script'); s.async = true;
- s.type = 'text/javascript';
- s.src = 'http://' + disqus_shortname + '.disqus.com/count.js';
- (document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);}
})();
-
-$('#latest-contribution-created-at').timeago();
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 817cbd4f..812bc8ba 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -216,17 +216,7 @@ module ApplicationHelper
end
def camo_image_url(image_url)
- if CAMO_KEY
- hexdigest = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), CAMO_KEY, image_url)
- uri = Addressable::URI.parse("#{CAMO_HOST}/#{hexdigest}")
- uri.query_values = { 'url' => image_url, 'repo' => '', 'path' => '' }
- uri.to_s
- else
- uri = Addressable::URI.parse(image_url)
- query_values = uri.query_values || {}
- uri.query_values = query_values.merge(NO_CAMO_CONFIG: nil)
- uri.to_s
- end
+ Image.from_insecure_url(image_url).secure_url
end
end
diff --git a/app/helpers/contribution_helper.rb b/app/helpers/contribution_helper.rb
index d4baa595..894066d7 100644
--- a/app/helpers/contribution_helper.rb
+++ b/app/helpers/contribution_helper.rb
@@ -19,7 +19,7 @@ module ContributionHelper
:item_link => link)
output = translate("contributions.contributed_description.main.#{main_key}_html",
:item_description => description)
- output << image_tag(item.thumbnail_url) if show_image
+ output << image_tag(item.thumbnail.secure_url) if show_image
output
else
translate('contributions.contributed_description.parents.item.blank')
diff --git a/app/models/image.rb b/app/models/image.rb
new file mode 100644
index 00000000..2cbc6dac
--- /dev/null
+++ b/app/models/image.rb
@@ -0,0 +1,28 @@
+class Image
+ attr_reader :insecure_url, :secure_url
+
+ def initialize(insecure_url, secure_url)
+ @insecure_url = insecure_url
+ @secure_url = secure_url
+ end
+
+ def self.from_insecure_url(insecure_url)
+ Image.new insecure_url, proxy_insecure_url(insecure_url)
+ end
+
+ private
+
+ def self.proxy_insecure_url(insecure_url)
+ if CAMO_HOST && CAMO_KEY
+ hexdigest = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), CAMO_KEY, insecure_url)
+ uri = Addressable::URI.parse("#{CAMO_HOST}/#{hexdigest}")
+ uri.query_values = { url: insecure_url }
+ uri.to_s
+ else
+ uri = Addressable::URI.parse(insecure_url)
+ query_values = uri.query_values || {}
+ uri.query_values = query_values.merge(NO_CAMO_CONFIG: nil)
+ uri.to_s
+ end
+ end
+end
diff --git a/app/models/item.rb b/app/models/item.rb
index 8581b971..da951a1c 100644
--- a/app/models/item.rb
+++ b/app/models/item.rb
@@ -327,12 +327,16 @@ class Item < ActiveRecord::Base
modeled_body_ids.size.to_f / predicted_body_ids.size
end
+ def thumbnail
+ @thumbnail ||= Image.from_insecure_url(thumbnail_url)
+ end
+
def as_json(options={})
json = {
:description => description,
:id => id,
:name => name,
- :thumbnail_url => thumbnail_url,
+ :thumbnail_url => thumbnail.secure_url,
:zones_restrict => zones_restrict,
:rarity_index => rarity_index,
:nc => nc?
diff --git a/app/models/item/proxy.rb b/app/models/item/proxy.rb
index 18e2eafe..465d96c6 100644
--- a/app/models/item/proxy.rb
+++ b/app/models/item/proxy.rb
@@ -5,7 +5,7 @@ class Item
attr_reader :id
attr_writer :item, :owned, :wanted
- delegate :description, :name, :nc?, :thumbnail_url, :to_param, to: :item
+ delegate :description, :name, :nc?, :thumbnail_url, :thumbnail, :to_param, to: :item
def self.model_name
Item.model_name
diff --git a/app/views/items/_item_link.html.haml b/app/views/items/_item_link.html.haml
index e50aafd3..27fb65ef 100644
--- a/app/views/items/_item_link.html.haml
+++ b/app/views/items/_item_link.html.haml
@@ -1,4 +1,4 @@
= link_to item_path(item) do
- = image_tag item.thumbnail_url, :alt => item.description, :title => item.description
+ = image_tag item.thumbnail.secure_url, :alt => item.description, :title => item.description
%span.name= item.name
= nc_icon_for(item)
diff --git a/app/views/items/show.html.haml b/app/views/items/show.html.haml
index df098abd..0bade545 100644
--- a/app/views/items/show.html.haml
+++ b/app/views/items/show.html.haml
@@ -3,7 +3,7 @@
- localized_cache "items/#{@item.id} header" do
%header#item-header
- = image_tag @item.thumbnail_url, :id => 'item-thumbnail'
+ = image_tag @item.thumbnail.secure_url, :id => 'item-thumbnail'
%div
%h2#item-name= @item.name
= nc_icon_for(@item)
diff --git a/app/views/outfits/new.html.haml b/app/views/outfits/new.html.haml
index 911f86fc..4128b649 100644
--- a/app/views/outfits/new.html.haml
+++ b/app/views/outfits/new.html.haml
@@ -80,7 +80,7 @@
%li
= link_to bulk_pets_path do
- = image_tag 'http://images.neopets.com/items/mall_ac_garland_spotlight.gif'
+ = image_tag camo_image_url('http://images.neopets.com/items/mall_ac_garland_spotlight.gif')
%h3= link_to t('modeling_hub'), bulk_pets_path
%div
%h4= t '.modeling_hub.tagline'
@@ -108,7 +108,7 @@
- @newest_unmodeled_items.each do |item|
- localized_cache "items/#{item.id} modeling_progress updated_at=#{item.updated_at.to_i}" do
%li{'data-item-id' => item.id}
- = link_to image_tag(item.thumbnail_url), item, :class => 'image-link'
+ = link_to image_tag(item.thumbnail.secure_url), item, :class => 'image-link'
= link_to item, :class => 'header' do
%h2= item.name
%span.meter{style: "width: #{@newest_unmodeled_items_predicted_modeled_ratio[item]*100}%"}
@@ -121,7 +121,7 @@
- @newest_modeled_items.each do |item|
%li.object
= link_to item, title: item.name, alt: item.name do
- = image_tag item.thumbnail_url
+ = image_tag item.thumbnail.secure_url
= nc_icon_for(item)