Skip to content

Commit

Permalink
Merge pull request #728 from readthedocs/davidfischer/live-ad-preview
Browse files Browse the repository at this point in the history
Display a live ad preview when editing or adding ads
  • Loading branch information
davidfischer committed Apr 11, 2023
2 parents e061762 + ae71d9b commit 03f2216
Show file tree
Hide file tree
Showing 11 changed files with 74 additions and 19 deletions.
15 changes: 12 additions & 3 deletions adserver/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from django.db.models.constraints import UniqueConstraint
from django.template import engines
from django.template.loader import get_template
from django.templatetags.static import static
from django.urls import reverse
from django.utils import timezone
from django.utils.crypto import get_random_string
Expand Down Expand Up @@ -1769,7 +1770,7 @@ def country_click_breakdown(self, start_date, end_date=None):

return report

def render_links(self, link=None):
def render_links(self, link=None, preview=False):
"""
Include the link in the html text.
Expand All @@ -1781,6 +1782,7 @@ def render_links(self, link=None):
ad_html = template.render(
{
"ad": self,
"preview": preview,
}
).strip()
else:
Expand All @@ -1800,6 +1802,7 @@ def render_ad(
publisher=None,
keywords=None,
topics=None,
preview=False,
):
"""Render the ad as HTML including any proxy links for collecting view/click metrics."""
if not ad_type:
Expand All @@ -1815,14 +1818,20 @@ def render_ad(
# Don't do this by default as searching for a template is expensive
template = get_template("adserver/advertisement.html")

image_preview_url = None
if preview:
# When previewing an ad (typically in the advertiser dashboard)
# we want to display a simple placeholder image.
image_preview_url = static("image-placeholder.png")

return template.render(
{
"ad": self,
"publisher": publisher,
"image_url": self.image.url if self.image else None,
"image_url": self.image.url if self.image else image_preview_url,
"link_url": click_url or self.link,
"view_url": view_url,
"text_as_html": self.render_links(link=click_url),
"text_as_html": self.render_links(link=click_url, preview=preview),
# Pass keywords and topics so we can be smart with what landing page
# to link the `Ads by EthicalAds` to.
"keywords": keywords,
Expand Down
6 changes: 3 additions & 3 deletions adserver/templates/adserver/advertisement-body.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{% spaceless %}
<a>
{% if ad.headline %}<strong>{{ ad.headline }} </strong>{% endif %}
<span>{{ ad.content|default:"" }}</span>
{% if ad.cta %}<strong> {{ ad.cta }}</strong>{% endif %}
{% if ad.headline or preview %}<strong class="ea-headline">{{ ad.headline|default:"" }} </strong>{% endif %}
<span class="ea-body">{{ ad.content|default:"" }}</span>
{% if ad.cta or preview %}<strong class="ea-cta"> {{ ad.cta|default:"" }}</strong>{% endif %}
</a>
{% endspaceless %}
22 changes: 17 additions & 5 deletions adserver/templates/adserver/advertiser/advertisement-create.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,27 @@ <h1>{% block heading %}{% trans 'Create advertisement' %}{% endblock heading %}<
</div>

<div class="col-md ml-md-5">
<div class="mb-5">
{% if ad_types %}
<h5>{% trans 'Ad types' %}</h5>

{% for ad_type in ad_types %}
<div class="mt-4">
<h6>{{ ad_type.name }}</h6>
<p class="small">{{ ad_type.description }}</p>
</div>
{% endfor %}
{% endif %}
</div>

{% if ad_types %}
<h5>{% trans 'Ad types' %}</h5>
<div class="ad-previews" data-bind="visible: totalLength() > 10">
<h5>{% trans 'Preview' %}</h5>

{% for ad_type in ad_types %}
<div class="mt-4">
<h6>{{ ad_type.name }}</h6>
<p class="small">{{ ad_type.description }}</p>
</div>
{% include "adserver/includes/ad-preview.html" %}
{% endfor %}
</div>
{% endif %}
</div>

Expand Down
11 changes: 7 additions & 4 deletions adserver/templates/adserver/advertiser/advertisement-update.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@ <h1>{% block heading %}{% trans 'Advertisement: ' %}{{ advertisement.name }}{% e

{# Preview the ad in all its ad types #}
<div class="col-md ml-md-5">
<h5>{% trans 'Preview' %}</h5>

{% for ad_type in advertisement.ad_types.all %}
{% include "adserver/includes/ad-preview.html" %}
{% endfor %}
<div class="ad-previews" data-bind="visible: totalLength() > 10">
<h5>{% trans 'Preview' %}</h5>

{% for ad_type in advertisement.ad_types.all %}
{% include "adserver/includes/ad-preview.html" %}
{% endfor %}
</div>
</div>

</div>
Expand Down
2 changes: 1 addition & 1 deletion adserver/templatetags/ad_extras.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ def advertisement_preview(ad, ad_type=None):
if not ad_type:
ad_type = ad.ad_types.first()

return mark_safe(ad.render_ad(ad_type))
return mark_safe(ad.render_ad(ad_type, preview=True))
2 changes: 1 addition & 1 deletion adserver/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ def test_ad_response_fields(self):
self.assertTrue("</a>" in resp_json["text"])
self.assertTrue(
resp_json["text"].endswith(
"<strong>Test headline </strong><span>Test ad body</span><strong> Test CTA</strong></a>"
'<strong class="ea-headline">Test headline </strong><span class="ea-body">Test ad body</span><strong class="ea-cta"> Test CTA</strong></a>'
),
resp_json["text"],
)
Expand Down
8 changes: 7 additions & 1 deletion adserver/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,11 @@ def form_valid(self, form):

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({"advertiser": self.advertiser})
context.update(
{
"advertiser": self.advertiser,
}
)
return context

def get_form_kwargs(self):
Expand Down Expand Up @@ -551,6 +555,8 @@ def get_context_data(self, **kwargs):
"ad_types": self.flight.campaign.allowed_ad_types(
exclude_deprecated=True
)[:5],
# This dummy ad is used for previews only
"advertisement": Advertisement(),
}
)
return context
Expand Down
Binary file added assets/img/image-placeholder.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions assets/src/scss/_theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ body {
}
}

.ad-previews {
position: sticky;
top: 0;
}


/* Preview an advertisement - most of this custom CSS comes from Read the Docs' existing ad settings */
.advertisement-preview {
Expand Down
17 changes: 17 additions & 0 deletions assets/src/views/advertisement-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,22 @@ const ko = require('knockout');


function AdvertisementFormViewModel(method) {
const MAX_PREVIEW_LENGTH = 100;

this.headline = ko.observable($("#id_headline").val());
this.content = ko.observable($("#id_content").val());
this.cta = ko.observable($("#id_cta").val());

this.getHeadlinePreview = function () {
return (this.headline() || "").slice(0, MAX_PREVIEW_LENGTH) + " ";
};
this.getBodyPreview = function () {
return (this.content() || "").slice(0, MAX_PREVIEW_LENGTH);
};
this.getCTAPreview = function () {
return " " + (this.cta() || "").slice(0, MAX_PREVIEW_LENGTH);
};

this.totalLength = function () {
let headline = this.headline() || "";
let content = this.content() || "";
Expand All @@ -19,5 +31,10 @@ function AdvertisementFormViewModel(method) {
}

if ($('form#advertisement-update').length > 0) {
// Setup bindings on the preview
$(".ea-headline").attr("data-bind", "text: getHeadlinePreview()");
$(".ea-body").attr("data-bind", "text: getBodyPreview()");
$(".ea-cta").attr("data-bind", "text: getCTAPreview()");

ko.applyBindings(new AdvertisementFormViewModel());
}
5 changes: 4 additions & 1 deletion config/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,10 @@
STATIC_ROOT = os.path.join(BASE_DIR, "static")
STATIC_URL = "/static/"
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
STATICFILES_DIRS = [os.path.join(BASE_DIR, "assets", "dist")]
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "assets", "dist"),
os.path.join(BASE_DIR, "assets", "img"),
]


# User-uploaded files (ad images)
Expand Down

0 comments on commit 03f2216

Please sign in to comment.