Author SHA1 Message Date
Neil Lalonde d3025a0e56 test widget in post-bottom placement 2019-05-10 15:08:28 -04:00
190 changed files with 3357 additions and 8776 deletions
+103 -1
View File
@@ -1,3 +1,105 @@
{
"extends": "eslint-config-discourse"
"env": {
"jasmine": true,
"node": true,
"mocha": true,
"browser": true,
"builtin": true
},
"parserOptions": {
"ecmaVersion": 7,
"sourceType": "module"
},
"globals":
{"Ember":true,
"jQuery":true,
"$":true,
"RSVP":true,
"Discourse":true,
"Em":true,
"PreloadStore":true,
"Handlebars":true,
"I18n":true,
"bootbox":true,
"module":true,
"moduleFor":true,
"moduleForComponent":true,
"Pretender":true,
"sandbox":true,
"controllerFor":true,
"test":true,
"ok":true,
"not":true,
"expect":true,
"equal":true,
"visit":true,
"andThen":true,
"click":true,
"currentPath":true,
"currentRouteName":true,
"currentURL":true,
"fillIn":true,
"keyEvent":true,
"triggerEvent":true,
"count":true,
"exists":true,
"visible":true,
"invisible":true,
"asyncRender":true,
"selectDropdown":true,
"asyncTestDiscourse":true,
"fixture":true,
"find":true,
"sinon":true,
"moment":true,
"start":true,
"_":true,
"alert":true,
"containsInstance":true,
"deepEqual":true,
"notEqual":true,
"define":true,
"require":true,
"requirejs":true,
"hasModule":true,
"Blob":true,
"File":true},
"rules": {
"block-scoped-var": 2,
"dot-notation": 0,
"eqeqeq": [
2,
"allow-null"
],
"guard-for-in": 2,
"no-bitwise": 2,
"no-caller": 2,
"no-cond-assign": 0,
"no-debugger": 2,
"no-empty": 0,
"no-eval": 2,
"no-extend-native": 2,
"no-extra-parens": 0,
"no-irregular-whitespace": 2,
"no-iterator": 2,
"no-loop-func": 2,
"no-multi-str": 2,
"no-new": 2,
"no-plusplus": 0,
"no-proto": 2,
"no-script-url": 2,
"no-sequences": 2,
"no-shadow": 2,
"no-undef": 2,
"no-unused-vars": 2,
"no-with": 2,
"semi": 2,
"strict": 0,
"valid-typeof": 2,
"wrap-iife": [
2,
"inside"
]
},
"parser": "babel-eslint"
}
-11
View File
@@ -1,11 +0,0 @@
name: Discourse Plugin
on:
push:
branches:
- main
pull_request:
jobs:
ci:
uses: discourse/.github/.github/workflows/discourse-plugin.yml@v1
+2 -3
View File
@@ -2,8 +2,7 @@
log/*.log
pkg/
auto_generated
Gemfile.lock
.DS_Store
*.swp
node_modules
yarn-error.log
.rubocop-https---raw-githubusercontent-com-discourse-*
.rubocop-https---raw-githubusercontent-com-discourse-discourse-master--rubocop-yml
-1
View File
@@ -1 +0,0 @@
{}
+1 -2
View File
@@ -1,2 +1 @@
inherit_gem:
rubocop-discourse: stree-compat.yml
inherit_from: https://raw.githubusercontent.com/discourse/discourse/master/.rubocop.yml
-2
View File
@@ -1,2 +0,0 @@
--print-width=100
--plugins=plugin/trailing_comma
-4
View File
@@ -1,4 +0,0 @@
module.exports = {
plugins: ["ember-template-lint-plugin-discourse"],
extends: "discourse:recommended",
};
+15
View File
@@ -0,0 +1,15 @@
[main]
host = https://www.transifex.com
lang_map = el_GR: el, es_ES: es, fr_FR: fr, hu_HU: hu, ko_KR: ko, pt_PT: pt, sk_SK: sk, vi_VN: vi
[discourse-org.discourse-adpluginclientenyml]
file_filter = config/locales/client.<lang>.yml
source_file = config/locales/client.en.yml
source_lang = en
type = YML
[discourse-org.discourse-adpluginserverenyml]
file_filter = config/locales/server.<lang>.yml
source_file = config/locales/server.en.yml
source_lang = en
type = YML
+2 -5
View File
@@ -1,8 +1,5 @@
# frozen_string_literal: true
source "https://rubygems.org"
source 'https://rubygems.org'
group :development do
gem "rubocop-discourse"
gem "syntax_tree"
gem 'translations-manager', git: 'https://github.com/discourse/translations-manager.git'
end
-43
View File
@@ -1,43 +0,0 @@
GEM
remote: https://rubygems.org/
specs:
ast (2.4.2)
json (2.6.2)
parallel (1.22.1)
parser (3.1.2.1)
ast (~> 2.4.1)
prettier_print (1.2.0)
rainbow (3.1.1)
regexp_parser (2.6.0)
rexml (3.2.5)
rubocop (1.36.0)
json (~> 2.3)
parallel (~> 1.10)
parser (>= 3.1.2.1)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.20.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 3.0)
rubocop-ast (1.21.0)
parser (>= 3.1.1.0)
rubocop-discourse (3.0)
rubocop (>= 1.1.0)
rubocop-rspec (>= 2.0.0)
rubocop-rspec (2.13.2)
rubocop (~> 1.33)
ruby-progressbar (1.11.0)
syntax_tree (5.1.0)
prettier_print (>= 1.2.0)
unicode-display_width (2.3.0)
PLATFORMS
ruby
DEPENDENCIES
rubocop-discourse
syntax_tree
BUNDLED WITH
2.1.4
+39 -58
View File
@@ -1,12 +1,10 @@
# Official Discourse Advertising Plugin
Official Plugin Topic & Documentation: https://meta.discourse.org/t/official-advertising-ad-plugin-for-discourse/33734
This is the official Discourse advertising plugin. It allows advertisements to be served by supported advertising platforms for users with a Discourse forum.
**Authors**: [Sarah Ni](https://github.com/cyberkoi) & [Vi Nguyen](https://github.com/ladydanger)
**Version**: 1.2.5
**Version**: 1.2.0
**Contributors**: See [credits section](#credits) below
@@ -19,8 +17,8 @@ This is the official Discourse advertising plugin. It allows advertisements to
* [Google Adsense](http://www.google.com.au/adsense/start/why-adsense.html)
* [Google Double Click for Publishers](https://www.google.com/dfp)
* [Amazon Affiliates](http://affiliate-program.amazon.com) - Banner and Product Link Ads
* [CodeFund](https://codefund.io) - Ethical Ad Platform for Developers
* [Carbon Ads](https://www.carbonads.net/)
* [AdButler](https://www.adbutler.com/)
## Quick Start in 3 Steps
@@ -36,7 +34,7 @@ For non-docker or local development installation (those with programming experie
### Step 1 - Install the Official Discourse Advertising Plugin
As seen in a [how-to on meta.discourse.org](https://meta.discourse.org/t/install-plugins-in-discourse/19157), simply **add the plugin's repository url to your container's app.yml file**:
As seen in a [how-to on meta.discourse.org](https://meta.discourse.org/t/advanced-troubleshooting-with-docker/15927#Example:%20Install%20a%20plugin), simply **add the plugin's repository url to your container's app.yml file**:
```yml
hooks:
@@ -81,8 +79,8 @@ the ad slots. The ads will start showing as soon as you add them to slots.
<li>House Ads - if you want to create and serve ads from your Discourse instance.</li>
<li>Adsense - if using Adsense as your advertisement platform.</li>
<li>DFP - if using the DoubleClick for Publishers advertisement platform.</li>
<li>CodeFund - if using the CodeFund ethical advertisement platform.</li>
<li>Carbon Ads - if using the Carbon Ads advertisement platform.</li>
<li>AdButler - if using the AdButler advertisement platform.</li>
</ul>
</ul>
@@ -96,49 +94,24 @@ the ad slots. The ads will start showing as soon as you add them to slots.
##### Adsense Advertisement Tag to Discourse's Site Settings
![image](https://user-images.githubusercontent.com/5862206/214489271-32ce230f-9f79-441e-9d7a-c5488ebb8c8a.png)
![](https://www.dropbox.com/sc/pguxq17zo2rovyd/AAD--LTH_IIgVhgczoaY1Ljva?dl=1)
##### DoubleClick for Publishers' Advertisement Tag to Discourse's Site Settings
![image](https://user-images.githubusercontent.com/5862206/214489324-8554a996-1876-432b-a686-e1add3b96ec4.png)
![](https://www.dropbox.com/sc/0inoc1iduux0gsf/AADi8tfKX9S6Tx9S8RndcUE8a?dl=1)
##### Amazon Affiliates' Advertisement Tag to Discourse's Site Settings
Only for Product Link and Banner Ads.
![image](https://user-images.githubusercontent.com/5862206/214489360-8829291b-8571-4deb-a867-139e823ebdea.png)
![](https://www.dropbox.com/sc/l67fb5c3tl8bq3d/AAAAMmccMW3kkIeBR7cBdWoFa?dl=1)
##### CodeFund Embed Tag to Discourse's Site Settings
![CodeFund Instructions](https://s3-us-west-2.amazonaws.com/codesponsor/discourse-codefund-instructions.png)
##### Carbon Ads Script Tag to Discourse's Site Settings
![adpluginexample](https://user-images.githubusercontent.com/5862206/214489455-234a3812-3606-47bf-9e49-cdaa3d1e3b9c.png)
##### AdButler Ads Zone URL to Discourse's Site Settings
This plugin only support AdButler "Standard Zones". Text and VAST are not supported.
If you browse to a zone in the AdButler admin, then you can find the Publisher ID (PPPPPP) and the Zone ID (ZZZZZZ) in the URL of your browser's address bar:
`https://admin.adbutler.com/?ID=PPPPPP&p=textadzone.view&zoneID=ZZZZZZ`
Configure the ads in Admin > Settings > AdButler.
Enter the publisher id in the "adbutler publisher id" setting, and enter the Zone IDs in the different
zone id settings as desired.
By default, ads are assumed to be size 728 x 90, or 320 x 50 in mobile view.
To use different size ads, customize using CSS in your site's theme. Override the following CSS:
```css
.adbutler-ad {
width: 728px;
height: 90px;
}
.adbutler-mobile-ad {
width: 320px;
height: 50px;
}
```
![Carbon Ads](https://d11a6trkgmumsb.cloudfront.net/original/3X/3/a/3acc7488db2b53733cdd427d3cb1b76361c786e1.png)
### Step 3 - See Your Ad
@@ -149,11 +122,9 @@ Once you've configured your settings and your advertising platform has ads that
In this section, we go into more detail on:
* Available Locations for Ad Display
* Ad Sizes Supported
* Trust Levels
* Personal messages
* Groups
* Categories
* Tags
* Languages Supported
### Available Locations for Ad Display
@@ -166,7 +137,26 @@ The following are available locations along with a description and an image show
| Topic Above Suggested | Ad will appear in the footer above suggested topics of all Discourse forum topics |
| Post Bottom & Nth Post | Ad will appear on the stipulated nth post within a topic. So if you have 5 posts in a topic and you want the ad to display after on the 2nd post, put 2 in ```ad_platform_nth_post_code```. |
![adplugin2](https://user-images.githubusercontent.com/5862206/214489128-2e0a9520-ffa5-47a9-81f8-27609b2c9975.jpeg)
![](https://www.dropbox.com/sc/rm5bcn8c85niul1/AAAUVW-hn56XtCl_XTNlE19Ra?dl=1)
### Advertisement Sizes Supported
This plugin supports the following ad sizes for the following locations.
All locations except post bottom | Post bottom location | Mobile
--- | --- | ---
728 x 90 | 728 x 90 | 320 x 50
336 x 280 | 336 x 280 |
300 x 250 | 300 x 250 |
970 x 90 | 970 x 90 |
468 x 60 | 468 x 60 |
234 x 60 | 234 x 60 |
125 x 125 | |
180 x 150 | |
200 x 200 | |
250 x 250 | |
### Trust Levels
@@ -180,21 +170,12 @@ You can use the ```ad_platform_through_trust_level``` dropdown to disable ads fo
To find more about trust levels in Discourse, refer to [Discourse's posts on trust levels](https://meta.discourse.org/t/what-do-user-trust-levels-do/4924)
### Personal messages
### Languages Supported
By default, ads won't be shown in personal messages. To enable ads in personal messages, use the "no ads for personal messages" setting.
### Groups
To give some users an ad-free experience, put the users in groups and add those groups to the "no ads for groups" setting.
### Categories
To disable ads in certain categories, add them to the "no ads for categories" setting. Also consider using the "no ads for restricted categories" to disable ads in all categories that have read access restrictions.
### Tags
Individual topics can have ads disabled by using tags, and entering those tags in the "no ads for tags" setting. This is useful if some topics violate ad network policies.
* Chinese (Simplified)
* English
* French
* Spanish
## Other Installation
@@ -1,5 +1,3 @@
# frozen_string_literal: true
module ::AdPlugin
class HouseAdSettingsController < ::ApplicationController
requires_plugin AdPlugin.plugin_name
+15 -6
View File
@@ -1,11 +1,12 @@
# frozen_string_literal: true
module ::AdPlugin
class HouseAdsController < ::ApplicationController
requires_plugin AdPlugin.plugin_name
def index
render_json_dump(house_ads: HouseAd.all.map(&:to_hash), settings: HouseAdSetting.all)
render_json_dump(
house_ads: HouseAd.all.map(&:to_hash),
settings: HouseAdSetting.all
)
end
def show
@@ -14,7 +15,11 @@ module ::AdPlugin
def create
ad = HouseAd.create(house_ad_params)
ad.valid? ? render_json_dump(house_ad: ad.to_hash) : render_json_error(ad)
if ad.valid?
render_json_dump(house_ad: ad.to_hash)
else
render_json_error(ad)
end
end
def update
@@ -24,14 +29,18 @@ module ::AdPlugin
ad = HouseAd.create(house_ad_params.except(:id))
end
ad.valid? ? render_json_dump(house_ad: ad.to_hash) : render_json_error(ad)
if ad.valid?
render_json_dump(house_ad: ad.to_hash)
else
render_json_error(ad)
end
end
def destroy
if ad = HouseAd.find(house_ad_params[:id])
ad.destroy
else
render_json_error(I18n.t("not_found"), status: 404)
render_json_error(I18n.t('not_found'), status: 404)
end
end
+14 -11
View File
@@ -1,5 +1,3 @@
# frozen_string_literal: true
module ::AdPlugin
class HouseAd
include ActiveModel::Validations
@@ -37,7 +35,7 @@ module ::AdPlugin
end
def self.alloc_id
DistributedMutex.synchronize("adplugin-house-ad-id") do
DistributedMutex.synchronize('adplugin-house-ad-id') do
max_id = AdPlugin.pstore_get("ad:_id")
max_id = 1 unless max_id
AdPlugin.pstore_set("ad:_id", max_id + 1)
@@ -46,7 +44,7 @@ module ::AdPlugin
end
def self.find(id)
if r = AdPlugin.pstore_get("ad:#{id}")
if r = AdPlugin::pstore_get("ad:#{id}")
from_hash(r)
else
nil
@@ -54,18 +52,18 @@ module ::AdPlugin
end
def self.all
PluginStoreRow
.where(plugin_name: AdPlugin.plugin_name)
PluginStoreRow.where(plugin_name: AdPlugin.plugin_name)
.where("key LIKE 'ad:%'")
.where("key != 'ad:_id'")
.map { |psr| from_hash(PluginStore.cast_value(psr.type_name, psr.value)) }
.sort_by { |ad| ad.id }
.map do |psr|
from_hash(PluginStore.cast_value(psr.type_name, psr.value))
end.sort_by { |ad| ad.id }
end
def save
if self.valid?
self.id = self.class.alloc_id if self.id.to_i <= 0
AdPlugin.pstore_set("ad:#{id}", to_hash)
AdPlugin::pstore_set("ad:#{id}", to_hash)
self.class.publish_if_ads_enabled
true
else
@@ -80,11 +78,15 @@ module ::AdPlugin
end
def to_hash
{ id: @id, name: @name, html: @html }
{
id: @id,
name: @name,
html: @html
}
end
def destroy
AdPlugin.pstore_delete("ad:#{id}")
AdPlugin::pstore_delete("ad:#{id}")
self.class.publish_if_ads_enabled
end
@@ -93,5 +95,6 @@ module ::AdPlugin
AdPlugin::HouseAdSetting.publish_settings
end
end
end
end
+28 -30
View File
@@ -1,67 +1,65 @@
# frozen_string_literal: true
module ::AdPlugin
class HouseAdSetting
DEFAULTS = {
topic_list_top: "",
topic_above_post_stream: "",
topic_above_suggested: "",
post_bottom: "",
topic_list_between: "",
topic_list_top: '',
topic_above_post_stream: '',
topic_above_suggested: '',
post_bottom: ''
}
def self.all
settings = DEFAULTS.dup
PluginStoreRow
.where(plugin_name: AdPlugin.plugin_name)
PluginStoreRow.where(plugin_name: AdPlugin.plugin_name)
.where("key LIKE 'ad-setting:%'")
.each { |psr| settings[psr.key[11..-1].to_sym] = psr.value }
.each do |psr|
settings[psr.key[11..-1].to_sym] = psr.value
end
settings
end
def self.settings_and_ads
settings = AdPlugin::HouseAdSetting.all
ad_names = settings.values.map { |v| v.split("|") }.flatten.uniq
ad_names = settings.values.map { |v| v.split('|') }.flatten.uniq
ads = AdPlugin::HouseAd.all.select { |ad| ad_names.include?(ad.name) }
{
settings:
settings.merge(
after_nth_post: SiteSetting.house_ads_after_nth_post,
after_nth_topic: SiteSetting.house_ads_after_nth_topic,
house_ads_frequency: SiteSetting.house_ads_frequency,
),
creatives:
ads.inject({}) do |h, ad|
h[ad.name] = ad.html
h
end,
settings: settings.merge(
after_nth_post: SiteSetting.house_ads_after_nth_post,
house_ads_frequency: SiteSetting.house_ads_frequency
),
creatives: ads.inject({}) { |h, ad| h[ad.name] = ad.html; h }
}
end
def self.update(setting_name, value)
raise Discourse::NotFound unless DEFAULTS.keys.include?(setting_name.to_sym)
unless DEFAULTS.keys.include?(setting_name.to_sym)
raise Discourse::NotFound
end
ad_names = value&.split("|") || []
ad_names = value&.split('|') || []
raise Discourse::InvalidParameters if value && ad_names.any? { |v| v !~ HouseAd::NAME_REGEX }
if value && ad_names.any? { |v| v !~ HouseAd::NAME_REGEX }
raise Discourse::InvalidParameters
end
ad_names = (HouseAd.all.map(&:name) & ad_names) unless ad_names.empty?
unless ad_names.empty?
ad_names = (HouseAd.all.map(&:name) & ad_names)
end
new_value = ad_names.join("|")
new_value = ad_names.join('|')
if value.nil? || new_value == DEFAULTS[setting_name.to_sym]
AdPlugin.pstore_delete("ad-setting:#{setting_name}")
AdPlugin::pstore_delete("ad-setting:#{setting_name}")
else
AdPlugin.pstore_set("ad-setting:#{setting_name}", new_value)
AdPlugin::pstore_set("ad-setting:#{setting_name}", new_value)
end
publish_settings
end
def self.publish_settings
MessageBus.publish("/site/house-creatives", settings_and_ads)
MessageBus.publish('/site/house-creatives', settings_and_ads)
end
end
end
@@ -2,9 +2,9 @@ export default {
resource: "admin.adminPlugins",
path: "/plugins",
map() {
this.route("houseAds", { path: "/pluginad/house_creatives" }, function () {
this.route("houseAds", { path: "/adplugin/house_ads" }, function() {
this.route("index", { path: "/" });
this.route("show", { path: "/:ad_id" });
});
},
}
};
@@ -1,106 +0,0 @@
import Component from "@ember/component";
import { inject as service } from "@ember/service";
import { alias, or } from "@ember/object/computed";
import discourseComputed from "discourse-common/utils/decorators";
import {
isNthPost,
isNthTopicListItem,
} from "discourse/plugins/discourse-adplugin/discourse/helpers/slot-position";
export default Component.extend({
router: service(),
currentCategoryId: or(
"router.currentRoute.attributes.category.id",
"router.currentRoute.parent.attributes.category_id"
),
currentCategorySlug: or(
"router.currentRoute.attributes.category.slug",
"router.currentRoute.parent.attributes.category.slug"
),
// Server needs to compute this in case hidden tags are being used.
topicTagsDisableAds: alias(
"router.currentRoute.parent.attributes.tags_disable_ads"
),
isRestrictedCategory: or(
"router.currentRoute.attributes.category.read_restricted",
"router.currentRoute.parent.attributes.category.read_restricted"
),
@discourseComputed(
"router.currentRoute.attributes.__type",
"router.currentRoute.attributes.id"
)
topicListTag(type, tag) {
if (type === "tag" && tag) {
return tag;
}
},
@discourseComputed("router.currentRoute.parent.attributes.archetype")
isPersonalMessage(topicType) {
return topicType === "private_message";
},
@discourseComputed("currentUser.groups")
showToGroups(groups) {
const currentUser = this.currentUser;
if (
!currentUser ||
!groups ||
!this.siteSettings.no_ads_for_groups ||
this.siteSettings.no_ads_for_groups.length === 0
) {
return true;
}
let noAdsGroups = this.siteSettings.no_ads_for_groups
.split("|")
.filter(Boolean);
let currentGroups = groups.map((g) => g.id.toString());
return !currentGroups.any((g) => noAdsGroups.includes(g));
},
@discourseComputed(
"currentCategoryId",
"topicTagsDisableAds",
"topicListTag",
"isPersonalMessage",
"isRestrictedCategory"
)
showOnCurrentPage(
categoryId,
topicTagsDisableAds,
topicListTag,
isPersonalMessage,
isRestrictedCategory
) {
return (
!topicTagsDisableAds &&
(!categoryId ||
!this.siteSettings.no_ads_for_categories ||
!this.siteSettings.no_ads_for_categories
.split("|")
.includes(categoryId.toString())) &&
(!topicListTag ||
!this.siteSettings.no_ads_for_tags ||
!this.siteSettings.no_ads_for_tags.split("|").includes(topicListTag)) &&
(!isPersonalMessage || !this.siteSettings.no_ads_for_personal_messages) &&
(!isRestrictedCategory ||
!this.siteSettings.no_ads_for_restricted_categories)
);
},
isNthPost(n) {
return isNthPost(n, this.get("postNumber"));
},
isNthTopicListItem(n) {
return isNthTopicListItem(n, this.get("indexNumber"));
},
});
@@ -0,0 +1,32 @@
import computed from "ember-addons/ember-computed-decorators";
export default Ember.Component.extend({
@computed("currentUser.groups")
showToGroups(groups) {
const currentUser = Discourse.User.current();
if (
!currentUser ||
!groups ||
!this.siteSettings.no_ads_for_groups ||
this.siteSettings.no_ads_for_groups.length === 0
) {
return true;
}
const groupNames = groups.map(g => g.name.toLowerCase());
const noAdsGroupNames = this.siteSettings.no_ads_for_groups
.split("|")
.map(g => g.toLowerCase());
return !groupNames.any(g => noAdsGroupNames.includes(g));
},
isNthPost(n) {
if (n && n > 0) {
return this.get("postNumber") % n === 0;
} else {
return false;
}
}
});
@@ -1,254 +0,0 @@
import EmberObject from "@ember/object";
import AdComponent from "discourse/plugins/discourse-adplugin/discourse/components/ad-component";
import discourseComputed, { observes } from "discourse-common/utils/decorators";
import { isBlank } from "@ember/utils";
import {
isNthPost,
isNthTopicListItem,
} from "discourse/plugins/discourse-adplugin/discourse/helpers/slot-position";
const adConfig = EmberObject.create({
"google-adsense": {
settingPrefix: "adsense", // settings follow naming convention
enabledSetting: "adsense_publisher_code",
nthPost: "adsense_nth_post_code",
},
"google-dfp-ad": {
settingPrefix: "dfp", // settings follow naming convention
enabledSetting: "dfp_publisher_id",
nthPost: "dfp_nth_post_code",
},
"amazon-product-links": {
settingPrefix: "amazon",
enabledSetting: false,
nthPost: "amazon_nth_post_code",
desktop: {
"topic-list-top": "amazon_topic_list_top_src_code",
"post-bottom": "amazon_post_bottom_src_code",
"topic-above-post-stream": "amazon_topic_above_post_stream_src_code",
"topic-above-suggested": "amazon_topic_above_suggested_src_code",
},
mobile: {
"topic-list-top": "amazon_mobile_topic_list_top_src_code",
"post-bottom": "amazon_mobile_post_bottom_src_code",
"topic-above-post-stream":
"amazon_mobile_topic_above_post_stream_src_code",
"topic-above-suggested": "amazon_mobile_topic_above_suggested_src_code",
},
},
"carbonads-ad": {
settingPrefix: "carbonads",
enabledSetting: "carbonads_serve_id",
desktop: {
"topic-list-top": "carbonads_topic_list_top_enabled",
"post-bottom": false,
"topic-above-post-stream": "carbonads_above_post_stream_enabled",
"topic-above-suggested": false,
},
},
"adbutler-ad": {
settingPrefix: "adbutler",
enabledSetting: "adbutler_publisher_id",
desktop: {
"topic-list-top": "adbutler_topic_list_top_zone_id",
"post-bottom": "adbutler_post_bottom_zone_id",
"topic-above-post-stream": "adbutler_topic_above_post_stream_zone_id",
"topic-above-suggested": "adbutler_topic_above_suggested_zone_id",
},
mobile: {
"topic-list-top": "adbutler_mobile_topic_list_top_zone_id",
"post-bottom": "adbutler_mobile_post_bottom_zone_id",
"topic-above-post-stream":
"adbutler_mobile_topic_above_post_stream_zone_id",
"topic-above-suggested": "adbutler_mobile_topic_above_suggested_zone_id",
},
},
});
const displayCounts = {
houseAds: 0,
allAds: 0,
};
function _isNetworkAvailable(siteSettings, enabledNetworkSettingName) {
// False means there's no setting to enable or disable this ad network.
// Assume it's always enabled.
if (enabledNetworkSettingName === false) {
return true;
} else {
return (
enabledNetworkSettingName &&
!isBlank(siteSettings[enabledNetworkSettingName])
);
}
}
function _shouldPlaceAdInSlot(
siteSettings,
currentPostNumber,
positionToPlace
) {
return (
!currentPostNumber ||
!positionToPlace ||
isNthPost(parseInt(siteSettings[positionToPlace], 10), currentPostNumber)
);
}
export function slotContenders(
site,
siteSettings,
placement,
indexNumber,
postNumber
) {
let types = [];
const houseAds = site.get("house_creatives"),
placeUnderscored = placement.replace(/-/g, "_");
if (houseAds && houseAds.settings) {
const adsForSlot = houseAds.settings[placeUnderscored];
const adAvailable =
Object.keys(houseAds.creatives).length > 0 && !isBlank(adsForSlot);
// postNumber and indexNumber are both null for topic-list-top, topic-above-post-stream,
// and topic-above-suggested placements. Assume we want to place an ad outside the topic list.
const notPlacingBetweenTopics = !postNumber && !indexNumber;
const canBePlacedInBetweenTopics =
placeUnderscored === "topic_list_between" &&
isNthTopicListItem(
parseInt(houseAds.settings.after_nth_topic, 10),
indexNumber
);
if (
adAvailable &&
(notPlacingBetweenTopics ||
canBePlacedInBetweenTopics ||
isNthPost(parseInt(houseAds.settings.after_nth_post, 10), postNumber))
) {
types.push("house-ad");
}
}
Object.keys(adConfig).forEach((adNetwork) => {
const config = adConfig[adNetwork];
let settingNames = null,
name;
if (
_isNetworkAvailable(siteSettings, config.enabledSetting) &&
_shouldPlaceAdInSlot(siteSettings, postNumber, config.nthPost)
) {
if (site.mobileView) {
settingNames = config.mobile || config.desktop;
} else {
settingNames = config.desktop;
}
if (settingNames) {
name = settingNames[placement];
}
if (name === undefined) {
// follows naming convention: prefix_(mobile_)_{placement}_code
name = `${config.settingPrefix}_${
site.mobileView ? "mobile_" : ""
}${placeUnderscored}_code`;
}
if (
name !== false &&
siteSettings[name] !== false &&
!isBlank(siteSettings[name])
) {
types.push(adNetwork);
}
}
});
return types;
}
export default AdComponent.extend({
needsUpdate: false,
tagName: "",
/**
* For a given ad placement and optionally a post number if in between posts,
* list all ad network names that are configured to show there.
*/
@discourseComputed("placement", "postNumber", "indexNumber")
availableAdTypes(placement, postNumber, indexNumber) {
return slotContenders(
this.site,
this.siteSettings,
placement,
indexNumber,
postNumber
);
},
/**
* When house ads are configured to alternate with other ad networks, we
* need to trigger an update of which ad component is shown after
* navigating between topic lists or topics.
*/
@observes("refreshOnChange")
changed() {
if (this.get("listLoading")) {
return;
}
// force adComponents to be recomputed
this.notifyPropertyChange("needsUpdate");
},
/**
* Returns a list of the names of ad components that should be rendered
* in the given ad placement. It handles alternating between house ads
* and other ad networks.
*/
@discourseComputed("placement", "availableAdTypes", "needsUpdate")
adComponents(placement, availableAdTypes) {
if (
!availableAdTypes.includes("house-ad") ||
availableAdTypes.length === 1
) {
// Current behaviour is to allow multiple ads from different networks
// to show in the same place. We could change this to choose one somehow.
return availableAdTypes;
}
const houseAds = this.site.get("house_creatives");
let houseAdsSkipped = false;
if (houseAds.settings.house_ads_frequency === 100) {
// house always wins
return ["house-ad"];
} else if (houseAds.settings.house_ads_frequency > 0) {
// show house ads the given percent of the time
if (
displayCounts.allAds === 0 ||
(100 * displayCounts.houseAds) / displayCounts.allAds <
houseAds.settings.house_ads_frequency
) {
displayCounts.houseAds += 1;
displayCounts.allAds += 1;
return ["house-ad"];
} else {
houseAdsSkipped = true;
}
}
const networkNames = availableAdTypes.filter((x) => x !== "house-ad");
if (houseAdsSkipped) {
displayCounts.allAds += networkNames.length;
}
return networkNames;
},
});
@@ -0,0 +1,188 @@
import AdComponent from "discourse/plugins/discourse-adplugin/discourse/components/ad-component";
import {
default as computed,
observes
} from "ember-addons/ember-computed-decorators";
const adConfig = Ember.Object.create({
"google-adsense": {
settingPrefix: "adsense", // settings follow naming convention
enabledSetting: "adsense_publisher_code",
nthPost: "adsense_nth_post_code"
},
"google-dfp-ad": {
settingPrefix: "dfp", // settings follow naming convention
enabledSetting: "dfp_publisher_id",
nthPost: "dfp_nth_post_code"
},
"amazon-product-links": {
settingPrefix: "amazon",
enabledSetting: false,
nthPost: "amazon_nth_post_code",
desktop: {
"topic-list-top": "amazon_topic_list_top_src_code",
"post-bottom": "amazon_post_bottom_src_code",
"topic-above-post-stream": "amazon_topic_above_post_stream_src_code",
"topic-above-suggested": "amazon_topic_above_suggested_src_code"
},
mobile: {
"topic-list-top": "amazon_mobile_topic_list_top_src_code",
"post-bottom": "amazon_mobile_post_bottom_src_code",
"topic-above-post-stream":
"amazon_mobile_topic_above_post_stream_src_code",
"topic-above-suggested": "amazon_mobile_topic_above_suggested_src_code"
}
},
"codefund-ad": {
settingPrefix: "codefund",
enabledSetting: "codefund_property_id",
nthPost: "codefund_nth_post",
desktop: {
"topic-list-top": "codefund_top_of_topic_list_enabled",
"post-bottom": "codefund_below_post_enabled",
"topic-above-post-stream": "codefund_above_post_stream_enabled",
"topic-above-suggested": "codefund_above_suggested_enabled"
}
},
"carbonads-ad": {
settingPrefix: "carbonads",
enabledSetting: "carbonads_serve_id",
desktop: {
"topic-list-top": "carbonads_topic_list_top_enabled",
"post-bottom": false,
"topic-above-post-stream": "carbonads_above_post_stream_enabled",
"topic-above-suggested": false
}
}
});
const displayCounts = {
houseAds: 0,
allAds: 0
};
export default AdComponent.extend({
needsUpdate: false,
/**
* For a given ad placement and optionally a post number if in between posts,
* list all ad network names that are configured to show there.
*/
@computed("placement", "postNumber")
availableAdTypes(placement, postNumber) {
let types = [];
const houseAds = this.site.get("house_creatives"),
placeUnderscored = placement.replace(/-/g, "_");
if (houseAds && houseAds.settings) {
const adsForSlot = houseAds.settings[placeUnderscored];
if (
Object.keys(houseAds.creatives).length > 0 &&
!Ember.isBlank(adsForSlot) &&
(!postNumber ||
this.isNthPost(parseInt(houseAds.settings.after_nth_post, 10)))
) {
types.push("house-ad");
}
}
Object.keys(adConfig).forEach(adNetwork => {
const config = adConfig[adNetwork];
let settingNames = null,
name;
if (
config.enabledSetting &&
!Ember.isBlank(this.siteSettings[config.enabledSetting]) &&
(!postNumber ||
!config.nthPost ||
this.isNthPost(parseInt(this.siteSettings[config.nthPost], 10)))
) {
if (this.site.mobileView) {
settingNames = config.mobile || config.desktop;
} else {
settingNames = config.desktop;
}
if (settingNames) {
name = settingNames[placement];
}
if (name === undefined) {
// follows naming convention: prefix_(mobile_)_{placement}_code
name = `${config.settingPrefix}_${
this.site.mobileView ? "mobile_" : ""
}${placeUnderscored}_code`;
}
if (name !== false && !Ember.isBlank(this.siteSettings[name])) {
types.push(adNetwork);
}
}
});
return types;
},
/**
* When house ads are configured to alternate with other ad networks, we
* need to trigger an update of which ad component is shown after
* navigating between topic lists or topics.
*/
@observes("refreshOnChange")
changed() {
if (this.get("listLoading")) {
return;
}
// force adComponents to be recomputed
this.notifyPropertyChange("needsUpdate");
},
/**
* Returns a list of the names of ad components that should be rendered
* in the given ad placement. It handles alternating between house ads
* and other ad networks.
*/
@computed("placement", "availableAdTypes", "needsUpdate")
adComponents(placement, availableAdTypes) {
if (
!availableAdTypes.includes("house-ad") ||
availableAdTypes.length === 1
) {
// Current behaviour is to allow multiple ads from different networks
// to show in the same place. We could change this to choose one somehow.
return availableAdTypes;
}
const houseAds = this.site.get("house_creatives");
let houseAdsSkipped = false;
if (houseAds.settings.house_ads_frequency === 100) {
// house always wins
return ["house-ad"];
} else if (houseAds.settings.house_ads_frequency > 0) {
// show house ads the given percent of the time
if (
displayCounts.allAds === 0 ||
(100 * displayCounts.houseAds) / displayCounts.allAds <
houseAds.settings.house_ads_frequency
) {
displayCounts.houseAds += 1;
displayCounts.allAds += 1;
return ["house-ad"];
} else {
houseAdsSkipped = true;
}
}
const networkNames = availableAdTypes.filter(x => x !== "house-ad");
if (houseAdsSkipped) {
displayCounts.allAds += networkNames.length;
}
return networkNames;
}
});
@@ -1,161 +0,0 @@
import AdComponent from "discourse/plugins/discourse-adplugin/discourse/components/ad-component";
import discourseComputed, { observes } from "discourse-common/utils/decorators";
import loadScript from "discourse/lib/load-script";
import RSVP from "rsvp";
import { scheduleOnce } from "@ember/runloop";
import { isTesting } from "discourse-common/config/environment";
let _loaded = false,
_promise = null,
_c = 0;
function loadAdbutler(adserverHostname) {
if (_loaded) {
return RSVP.resolve();
}
if (_promise) {
return _promise;
}
_promise = loadScript("https://" + adserverHostname + "/app.js", {
scriptTag: true,
}).then(function () {
_loaded = true;
});
return _promise;
}
export default AdComponent.extend({
divs: null,
publisherId: null,
init() {
let dimensions = [728, 90];
let configKey = "adbutler_";
let className = "adbutler-";
let dimClassName = "adbutler-ad";
this.set("divs", []);
if (this.site.mobileView) {
dimensions = [320, 50];
configKey += "mobile_";
className += "mobile-";
dimClassName = "adbutler-mobile-ad";
}
configKey += this.get("placement").replace(/-/g, "_") + "_zone_id";
this.set("configKey", configKey);
className += this.get("placement");
this.set("className", className + " " + dimClassName);
let zoneId = this.siteSettings[configKey];
this.set("zoneId", zoneId);
let divId = "placement-" + zoneId + "-" + _c;
this.set("divId", divId);
let publisherId = this.siteSettings.adbutler_publisher_id;
this.set("publisherId", publisherId);
_c++;
this.divs.push({
divId,
publisherId,
zoneId,
dimensions,
});
this._super();
},
_triggerAds() {
if (isTesting()) {
return; // Don't load external JS during tests
}
const adserverHostname = this.siteSettings.adbutler_adserver_hostname;
loadAdbutler(adserverHostname).then(
function () {
if (this.divs.length > 0) {
let abkw = window.abkw || "";
window.AdButler.ads.push({
handler: function (opt) {
window.AdButler.register(
opt.place.publisherId,
opt.place.zoneId,
opt.place.dimensions,
opt.place.divId,
opt
);
},
opt: {
place: this.divs.pop(),
keywords: abkw,
domain: adserverHostname,
click: "CLICK_MACRO_PLACEHOLDER",
},
});
}
}.bind(this)
);
},
didInsertElement() {
this._super();
scheduleOnce("afterRender", this, this._triggerAds);
},
@observes("listLoading")
waitForLoad() {
if (this.get("adRequested")) {
return;
} // already requested that this ad unit be populated
if (!this.get("listLoading")) {
scheduleOnce("afterRender", this, this._triggerAds);
}
},
@discourseComputed("currentUser.trust_level")
showToTrustLevel(trustLevel) {
return !(
trustLevel && trustLevel > this.siteSettings.adbutler_through_trust_level
);
},
@discourseComputed(
"publisherId",
"showToTrustLevel",
"showToGroups",
"showAfterPost",
"showOnCurrentPage"
)
showAd(
publisherId,
showToTrustLevel,
showToGroups,
showAfterPost,
showOnCurrentPage
) {
return (
publisherId &&
showToTrustLevel &&
showToGroups &&
showAfterPost &&
showOnCurrentPage
);
},
@discourseComputed("postNumber")
showAfterPost(postNumber) {
if (!postNumber) {
return true;
}
return this.isNthPost(parseInt(this.siteSettings.adbutler_nth_post, 10));
},
});
@@ -1,191 +0,0 @@
import AdComponent from "discourse/plugins/discourse-adplugin/discourse/components/ad-component";
import discourseComputed from "discourse-common/utils/decorators";
import { and } from "@ember/object/computed";
import { htmlSafe } from "@ember/template";
export default AdComponent.extend({
classNames: ["amazon-product-links"],
showAd: and(
"showToTrustLevel",
"showToGroups",
"showAfterPost",
"showOnCurrentPage"
),
init() {
const data = {
"topic-list-top": {},
"topic-above-post-stream": {},
"topic-above-suggested": {},
"post-bottom": {},
};
const mobileView = this.site.get("mobileView");
const placement = this.get("placement");
if (!mobileView && this.siteSettings.amazon_topic_list_top_src_code) {
data["topic-list-top"]["user_input"] =
this.siteSettings.amazon_topic_list_top_src_code;
data["topic-list-top"]["amazon_width"] = parseInt(
this.siteSettings.amazon_topic_list_top_ad_width_code,
10
);
data["topic-list-top"]["amazon_height"] = parseInt(
this.siteSettings.amazon_topic_list_top_ad_height_code,
10
);
}
if (mobileView && this.siteSettings.amazon_mobile_topic_list_top_src_code) {
data["topic-list-top"]["user_input_mobile"] =
this.siteSettings.amazon_mobile_topic_list_top_src_code;
data["topic-list-top"]["mobile_amazon_width"] = parseInt(
this.siteSettings.amazon_mobile_topic_list_top_ad_width_code,
10
);
data["topic-list-top"]["mobile_amazon_height"] = parseInt(
this.siteSettings.amazon_mobile_topic_list_top_ad_height_code,
10
);
}
if (
!mobileView &&
this.siteSettings.amazon_topic_above_post_stream_src_code
) {
data["topic-above-post-stream"]["user_input"] =
this.siteSettings.amazon_topic_above_post_stream_src_code;
data["topic-above-post-stream"]["amazon_width"] = parseInt(
this.siteSettings.amazon_topic_above_post_stream_ad_width_code,
10
);
data["topic-above-post-stream"]["amazon_height"] = parseInt(
this.siteSettings.amazon_topic_above_post_stream_ad_height_code,
10
);
}
if (
mobileView &&
this.siteSettings.amazon_mobile_topic_above_post_stream_src_code
) {
data["topic-above-post-stream"]["user_input_mobile"] =
this.siteSettings.amazon_mobile_topic_above_post_stream_src_code;
data["topic-above-post-stream"]["mobile_amazon_width"] = parseInt(
this.siteSettings.amazon_mobile_topic_above_post_stream_ad_width_code,
10
);
data["topic-above-post-stream"]["mobile_amazon_height"] = parseInt(
this.siteSettings.amazon_mobile_topic_above_post_stream_ad_height_code,
10
);
}
if (
!mobileView &&
this.siteSettings.amazon_topic_above_suggested_src_code
) {
data["topic-above-suggested"]["user_input"] =
this.siteSettings.amazon_topic_above_suggested_src_code;
data["topic-above-suggested"]["amazon_width"] = parseInt(
this.siteSettings.amazon_topic_above_suggested_ad_width_code,
10
);
data["topic-above-suggested"]["amazon_height"] = parseInt(
this.siteSettings.amazon_topic_above_suggested_ad_height_code,
10
);
}
if (
mobileView &&
this.siteSettings.amazon_mobile_topic_above_suggested_src_code
) {
data["topic-above-suggested"]["user_input_mobile"] =
this.siteSettings.amazon_mobile_topic_above_suggested_src_code;
data["topic-above-suggested"]["mobile_amazon_width"] = parseInt(
this.siteSettings.amazon_mobile_topic_above_suggested_ad_width_code,
10
);
data["topic-above-suggested"]["mobile_amazon_height"] = parseInt(
this.siteSettings.amazon_mobile_topic_above_suggested_ad_height_code,
10
);
}
if (!mobileView && this.siteSettings.amazon_post_bottom_src_code) {
data["post-bottom"]["user_input"] =
this.siteSettings.amazon_post_bottom_src_code;
data["post-bottom"]["amazon_width"] = parseInt(
this.siteSettings.amazon_post_bottom_ad_width_code,
10
);
data["post-bottom"]["amazon_height"] = parseInt(
this.siteSettings.amazon_post_bottom_ad_height_code,
10
);
}
if (mobileView && this.siteSettings.amazon_mobile_post_bottom_src_code) {
data["post-bottom"]["user_input_mobile"] =
this.siteSettings.amazon_mobile_post_bottom_src_code;
data["post-bottom"]["mobile_amazon_width"] = parseInt(
this.siteSettings.amazon_mobile_post_bottom_ad_width_code,
10
);
data["post-bottom"]["mobile_amazon_height"] = parseInt(
this.siteSettings.amazon_mobile_post_bottom_ad_height_code,
10
);
}
this.set("user_input", data[placement]["user_input"]);
this.set("amazon_width", data[placement]["amazon_width"]);
this.set("amazon_height", data[placement]["amazon_height"]);
this.set("user_input_mobile", data[placement]["user_input_mobile"]);
this.set("mobile_amazon_height", data[placement]["mobile_amazon_height"]);
this.set("mobile_amazon_width", data[placement]["mobile_amazon_width"]);
this._super();
},
@discourseComputed("amazon_width", "amazon_height")
adWrapperStyle(w, h) {
return htmlSafe(`width: ${w}px; height: ${h}px;`);
},
@discourseComputed("mobile_amazon_width", "mobile_amazon_height")
adWrapperStyleMobile(w, h) {
return htmlSafe(`width: ${w}px; height: ${h}px;`);
},
@discourseComputed("mobile_amazon_width")
adTitleStyleMobile(w) {
return htmlSafe(`width: ${w}px;`);
},
@discourseComputed("user_input")
userInput(userInput) {
return htmlSafe(`${userInput}`);
},
@discourseComputed("user_input_mobile")
userInputMobile(userInput) {
return htmlSafe(`${userInput}`);
},
@discourseComputed("currentUser.trust_level")
showToTrustLevel(trustLevel) {
return !(
trustLevel && trustLevel > this.siteSettings.amazon_through_trust_level
);
},
@discourseComputed("postNumber")
showAfterPost(postNumber) {
if (!postNumber) {
return true;
}
return this.isNthPost(parseInt(this.siteSettings.amazon_nth_post_code, 10));
},
});
@@ -0,0 +1,186 @@
import AdComponent from "discourse/plugins/discourse-adplugin/discourse/components/ad-component";
import computed from "ember-addons/ember-computed-decorators";
const currentUser = Discourse.User.current();
const data = {
"topic-list-top": {},
"topic-above-post-stream": {},
"topic-above-suggested": {},
"post-bottom": {}
};
if (
!Discourse.Mobile.mobileView &&
Discourse.SiteSettings.amazon_topic_list_top_src_code
) {
data["topic-list-top"]["user_input"] =
Discourse.SiteSettings.amazon_topic_list_top_src_code;
data["topic-list-top"]["amazon_width"] = parseInt(
Discourse.SiteSettings.amazon_topic_list_top_ad_width_code
);
data["topic-list-top"]["amazon_height"] = parseInt(
Discourse.SiteSettings.amazon_topic_list_top_ad_height_code
);
}
if (
Discourse.Mobile.mobileView &&
Discourse.SiteSettings.amazon_mobile_topic_list_top_src_code
) {
data["topic-list-top"]["user_input_mobile"] =
Discourse.SiteSettings.amazon_mobile_topic_list_top_src_code;
data["topic-list-top"]["mobile_amazon_width"] = parseInt(
Discourse.SiteSettings.amazon_mobile_topic_list_top_ad_width_code
);
data["topic-list-top"]["mobile_amazon_height"] = parseInt(
Discourse.SiteSettings.amazon_mobile_topic_list_top_ad_height_code
);
}
if (
!Discourse.Mobile.mobileView &&
Discourse.SiteSettings.amazon_topic_above_post_stream_src_code
) {
data["topic-above-post-stream"]["user_input"] =
Discourse.SiteSettings.amazon_topic_above_post_stream_src_code;
data["topic-above-post-stream"]["amazon_width"] = parseInt(
Discourse.SiteSettings.amazon_topic_above_post_stream_ad_width_code
);
data["topic-above-post-stream"]["amazon_height"] = parseInt(
Discourse.SiteSettings.amazon_topic_above_post_stream_ad_height_code
);
}
if (
Discourse.Mobile.mobileView &&
Discourse.SiteSettings.amazon_mobile_topic_above_post_stream_src_code
) {
data["topic-above-post-stream"]["user_input_mobile"] =
Discourse.SiteSettings.amazon_mobile_topic_above_post_stream_src_code;
data["topic-above-post-stream"]["mobile_amazon_width"] = parseInt(
Discourse.SiteSettings.amazon_mobile_topic_above_post_stream_ad_width_code
);
data["topic-above-post-stream"]["mobile_amazon_height"] = parseInt(
Discourse.SiteSettings.amazon_mobile_topic_above_post_stream_ad_height_code
);
}
if (
!Discourse.Mobile.mobileView &&
Discourse.SiteSettings.amazon_topic_above_suggested_src_code
) {
data["topic-above-suggested"]["user_input"] =
Discourse.SiteSettings.amazon_topic_above_suggested_src_code;
data["topic-above-suggested"]["amazon_width"] = parseInt(
Discourse.SiteSettings.amazon_topic_above_suggested_ad_width_code
);
data["topic-above-suggested"]["amazon_height"] = parseInt(
Discourse.SiteSettings.amazon_topic_above_suggested_ad_height_code
);
}
if (
Discourse.Mobile.mobileView &&
Discourse.SiteSettings.amazon_mobile_topic_above_suggested_src_code
) {
data["topic-above-suggested"]["user_input_mobile"] =
Discourse.SiteSettings.amazon_mobile_topic_above_suggested_src_code;
data["topic-above-suggested"]["mobile_amazon_width"] = parseInt(
Discourse.SiteSettings.amazon_mobile_topic_above_suggested_ad_width_code
);
data["topic-above-suggested"]["mobile_amazon_height"] = parseInt(
Discourse.SiteSettings.amazon_mobile_topic_above_suggested_ad_height_code
);
}
if (
!Discourse.Mobile.mobileView &&
Discourse.SiteSettings.amazon_post_bottom_src_code
) {
data["post-bottom"]["user_input"] =
Discourse.SiteSettings.amazon_post_bottom_src_code;
data["post-bottom"]["amazon_width"] = parseInt(
Discourse.SiteSettings.amazon_post_bottom_ad_width_code
);
data["post-bottom"]["amazon_height"] = parseInt(
Discourse.SiteSettings.amazon_post_bottom_ad_height_code
);
}
if (
Discourse.Mobile.mobileView &&
Discourse.SiteSettings.amazon_mobile_post_bottom_src_code
) {
data["post-bottom"]["user_input_mobile"] =
Discourse.SiteSettings.amazon_mobile_post_bottom_src_code;
data["post-bottom"]["mobile_amazon_width"] = parseInt(
Discourse.SiteSettings.amazon_mobile_post_bottom_ad_width_code
);
data["post-bottom"]["mobile_amazon_height"] = parseInt(
Discourse.SiteSettings.amazon_mobile_post_bottom_ad_height_code
);
}
export default AdComponent.extend({
classNames: ["amazon-product-links"],
showAd: Ember.computed.and(
"showToTrustLevel",
"showToGroups",
"showAfterPost"
),
init() {
let placement = this.get("placement");
this.set("user_input", data[placement]["user_input"]);
this.set("amazon_width", data[placement]["amazon_width"]);
this.set("amazon_height", data[placement]["amazon_height"]);
this.set("user_input_mobile", data[placement]["user_input_mobile"]);
this.set("mobile_amazon_height", data[placement]["mobile_amazon_height"]);
this.set("mobile_amazon_width", data[placement]["mobile_amazon_width"]);
this._super();
},
@computed("amazon_width", "amazon_height")
adWrapperStyle(w, h) {
return `width: ${w}px; height: ${h}px;`.htmlSafe();
},
@computed("mobile_amazon_width", "mobile_amazon_height")
adWrapperStyleMobile(w, h) {
return `width: ${w}px; height: ${h}px;`.htmlSafe();
},
@computed("mobile_amazon_width")
adTitleStyleMobile(w) {
return `width: ${w}px;`.htmlSafe();
},
@computed("user_input")
userInput(userInput) {
return `${userInput}`.htmlSafe();
},
@computed("user_input_mobile")
userInputMobile(userInput) {
return `${userInput}`.htmlSafe();
},
@computed("currentUser.trust_level")
showToTrustLevel(trustLevel) {
return !(
trustLevel &&
trustLevel > Discourse.SiteSettings.amazon_through_trust_level
);
},
@computed("postNumber")
showAfterPost(postNumber) {
if (!postNumber) {
return true;
}
return this.isNthPost(parseInt(this.siteSettings.amazon_nth_post_code));
}
});
@@ -1,51 +0,0 @@
import AdComponent from "discourse/plugins/discourse-adplugin/discourse/components/ad-component";
import discourseComputed from "discourse-common/utils/decorators";
import { htmlSafe } from "@ember/template";
export default AdComponent.extend({
serve_id: null,
placement: null,
init() {
this.set("serve_id", this.siteSettings.carbonads_serve_id);
this.set("placement", this.siteSettings.carbonads_placement);
this._super();
},
@discourseComputed("serve_id", "placement")
url(serveId, placement) {
return htmlSafe(
`//cdn.carbonads.com/carbon.js?serve=${serveId}&placement=${placement}`
);
},
@discourseComputed("currentUser.trust_level")
showToTrustLevel(trustLevel) {
return !(
trustLevel && trustLevel > this.siteSettings.carbonads_through_trust_level
);
},
@discourseComputed(
"placement",
"serve_id",
"showToTrustLevel",
"showToGroups",
"showOnCurrentPage"
)
showAd(
placement,
serveId,
showToTrustLevel,
showToGroups,
showOnCurrentPage
) {
return (
placement &&
serveId &&
showToTrustLevel &&
showToGroups &&
showOnCurrentPage
);
},
});
@@ -0,0 +1,35 @@
import AdComponent from "discourse/plugins/discourse-adplugin/discourse/components/ad-component";
import {
default as computed,
observes
} from "ember-addons/ember-computed-decorators";
const currentUser = Discourse.User.current(),
serve_id = Discourse.SiteSettings.carbonads_serve_id,
placement = Discourse.SiteSettings.carbonads_placement;
export default AdComponent.extend({
init() {
this.set("serve_id", serve_id);
this.set("placement", placement);
this._super();
},
@computed("serve_id", "placement")
url(serveId, placement) {
return `//cdn.carbonads.com/carbon.js?serve=${serveId}&placement=${placement}`.htmlSafe();
},
@computed("currentUser.trust_level")
showToTrustLevel(trustLevel) {
return !(
trustLevel &&
trustLevel > Discourse.SiteSettings.carbonads_through_trust_level
);
},
@computed("showToTrustLevel", "showToGroups")
showAd(showToTrustLevel, showToGroups) {
return placement && serve_id && showToTrustLevel && showToGroups;
}
});
@@ -0,0 +1,133 @@
import AdComponent from "discourse/plugins/discourse-adplugin/discourse/components/ad-component";
import {
default as computed,
observes
} from "ember-addons/ember-computed-decorators";
let _loaded = false,
_promise = null;
const currentUser = Discourse.User.current(),
propertyId = Discourse.SiteSettings.codefund_property_id;
function loadCodeFund() {
if (_loaded) {
return Ember.RSVP.resolve();
}
if (_promise) {
return _promise;
}
const url = "https://codefund.app/properties/" + propertyId + "/funder.json";
_promise = new Promise(function(resolve, reject) {
let xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onreadystatechange = handler;
xhr.responseType = "json";
xhr.setRequestHeader("Accept", "application/json");
xhr.send();
function handler() {
if (this.readyState === this.DONE) {
_loaded = true;
if (this.status === 200) {
resolve(this.response);
} else {
reject(
new Error(
"getJSON: `" + url + "` failed with status: [" + this.status + "]"
)
);
}
}
}
});
return _promise;
}
export default AdComponent.extend({
classNameBindings: [":codefund-ad"],
propertyId: propertyId,
adRequested: false,
adDetails: {},
displayPostBottom: Ember.computed.equal("placement", "post-bottom"),
displayTopicAbovePostStream: Ember.computed.equal(
"placement",
"topic-above-post-stream"
),
displayTopicAboveSuggested: Ember.computed.equal(
"placement",
"topic-above-suggested"
),
displayTopicListTop: Ember.computed.equal("placement", "topic-list-top"),
_triggerAds() {
if (!propertyId) return;
this.set("adRequested", true);
loadCodeFund()
.then(data => {
_loaded = false;
_promise = null;
this.set("adDetails", data);
this.set("adRequested", false);
})
.catch(error => console.log(error));
},
didInsertElement() {
this._super();
if (!this.get("showAd")) {
return;
}
if (this.get("listLoading")) {
return;
}
Ember.run.scheduleOnce("afterRender", this, this._triggerAds);
},
@observes("listLoading")
waitForLoad() {
if (this.get("adRequested")) {
return;
} // already requested that this ad unit be populated
if (!this.get("listLoading")) {
Ember.run.scheduleOnce("afterRender", this, this._triggerAds);
}
},
@computed("currentUser.trust_level")
showToTrustLevel(trustLevel) {
return !(
trustLevel && trustLevel > this.siteSettings.codefund_through_trust_level
);
},
@computed("showToTrustLevel", "showToGroups", "showAfterPost")
showAd(showToTrustLevel, showToGroups, showAfterPost) {
return (
this.siteSettings.codefund_property_id &&
showToTrustLevel &&
showToGroups &&
showAfterPost
);
},
@computed("postNumber")
showAfterPost(postNumber) {
if (!postNumber) {
return true;
}
return this.isNthPost(parseInt(this.siteSettings.codefund_nth_post));
}
});
@@ -1,255 +0,0 @@
import AdComponent from "discourse/plugins/discourse-adplugin/discourse/components/ad-component";
import discourseComputed, { observes } from "discourse-common/utils/decorators";
import loadScript from "discourse/lib/load-script";
import RSVP from "rsvp";
import { scheduleOnce } from "@ember/runloop";
import { isTesting } from "discourse-common/config/environment";
import { htmlSafe } from "@ember/template";
let _loaded = false,
_promise = null,
renderCounts = {};
function parseAdWidth(value) {
if (value === "responsive") {
return "auto";
}
if (value.startsWith("fluid")) {
return "fluid";
}
const w = parseInt(value.substring(0, 3).trim(), 10);
if (isNaN(w)) {
return "auto";
} else {
return `${w}px`;
}
}
function parseAdHeight(value) {
if (value === "responsive") {
return "auto";
}
if (value.startsWith("fluid")) {
return "fluid";
}
const h = parseInt(value.substring(4, 7).trim(), 10);
if (isNaN(h)) {
return "auto";
} else {
return `${h}px`;
}
}
function loadAdsense() {
if (_loaded) {
return RSVP.resolve();
}
if (_promise) {
return _promise;
}
const adsenseSrc =
("https:" === document.location.protocol ? "https:" : "http:") +
"//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js";
_promise = loadScript(adsenseSrc, { scriptTag: true }).then(function () {
_loaded = true;
});
return _promise;
}
const DESKTOP_SETTINGS = {
"topic-list-top": {
code: "adsense_topic_list_top_code",
sizes: "adsense_topic_list_top_ad_sizes",
},
"topic-above-post-stream": {
code: "adsense_topic_above_post_stream_code",
sizes: "adsense_topic_above_post_stream_ad_sizes",
},
"topic-above-suggested": {
code: "adsense_topic_above_suggested_code",
sizes: "adsense_topic_above_suggested_ad_sizes",
},
"post-bottom": {
code: "adsense_post_bottom_code",
sizes: "adsense_post_bottom_ad_sizes",
},
};
const MOBILE_SETTINGS = {
"topic-list-top": {
code: "adsense_mobile_topic_list_top_code",
sizes: "adsense_mobile_topic_list_top_ad_size",
},
"topic-above-post-stream": {
code: "adsense_mobile_topic_above_post_stream_code",
sizes: "adsense_mobile_topic_above_post_stream_ad_size",
},
"topic-above-suggested": {
code: "adsense_mobile_topic_above_suggested_code",
sizes: "adsense_mobile_topic_above_suggested_ad_size",
},
"post-bottom": {
code: "adsense_mobile_post_bottom_code",
sizes: "adsense_mobile_post_bottom_ad_size",
},
};
export default AdComponent.extend({
classNameBindings: [
":google-adsense",
"classForSlot",
"isResponsive:adsense-responsive",
],
loadedGoogletag: false,
publisher_id: null,
ad_width: null,
ad_height: null,
adRequested: false,
init() {
let config, size;
const placement = this.get("placement");
if (this.site.mobileView) {
config = MOBILE_SETTINGS[placement];
} else {
config = DESKTOP_SETTINGS[placement];
}
if (!renderCounts[placement]) {
renderCounts[placement] = 0;
}
const sizes = (this.siteSettings[config.sizes] || "").split("|");
if (sizes.length === 1) {
size = sizes[0];
} else {
size = sizes[renderCounts[placement] % sizes.length];
renderCounts[placement] += 1;
}
this.set("ad_width", parseAdWidth(size));
this.set("ad_height", parseAdHeight(size));
this.set("ad_code", this.siteSettings[config.code]);
this.set("publisher_id", this.siteSettings.adsense_publisher_code);
this._super();
},
_triggerAds() {
if (isTesting()) {
return; // Don't load external JS during tests
}
this.set("adRequested", true);
loadAdsense().then(function () {
const adsbygoogle = window.adsbygoogle || [];
try {
adsbygoogle.push({}); // ask AdSense to fill one ad unit
} catch (ex) {}
});
},
didInsertElement() {
this._super();
if (!this.get("showAd")) {
return;
}
if (this.get("listLoading")) {
return;
}
scheduleOnce("afterRender", this, this._triggerAds);
},
@observes("listLoading")
waitForLoad() {
if (this.get("adRequested")) {
return;
} // already requested that this ad unit be populated
if (!this.get("listLoading")) {
scheduleOnce("afterRender", this, this._triggerAds);
}
},
@discourseComputed("ad_width")
isResponsive(adWidth) {
return ["auto", "fluid"].includes(adWidth);
},
@discourseComputed("ad_width")
isFluid(adWidth) {
return adWidth === "fluid";
},
@discourseComputed("placement", "showAd")
classForSlot(placement, showAd) {
return showAd ? htmlSafe(`adsense-${placement}`) : "";
},
@discourseComputed("isResponsive", "isFluid")
autoAdFormat(isResponsive, isFluid) {
return isResponsive ? htmlSafe(isFluid ? "fluid" : "auto") : false;
},
@discourseComputed("ad_width", "ad_height", "isResponsive")
adWrapperStyle(w, h, isResponsive) {
return htmlSafe(isResponsive ? "" : `width: ${w}; height: ${h};`);
},
@discourseComputed("adWrapperStyle", "isResponsive")
adInsStyle(adWrapperStyle, isResponsive) {
return htmlSafe(
`display: ${isResponsive ? "block" : "inline-block"}; ${adWrapperStyle}`
);
},
@discourseComputed("currentUser.trust_level")
showToTrustLevel(trustLevel) {
return !(
trustLevel && trustLevel > this.siteSettings.adsense_through_trust_level
);
},
@discourseComputed(
"publisher_id",
"showToTrustLevel",
"showToGroups",
"showAfterPost",
"showOnCurrentPage"
)
showAd(
publisherId,
showToTrustLevel,
showToGroups,
showAfterPost,
showOnCurrentPage
) {
return (
publisherId &&
showToTrustLevel &&
showToGroups &&
showAfterPost &&
showOnCurrentPage
);
},
@discourseComputed("postNumber")
showAfterPost(postNumber) {
if (!postNumber) {
return true;
}
return this.isNthPost(
parseInt(this.siteSettings.adsense_nth_post_code, 10)
);
},
});
@@ -0,0 +1,258 @@
import AdComponent from "discourse/plugins/discourse-adplugin/discourse/components/ad-component";
import {
default as computed,
observes
} from "ember-addons/ember-computed-decorators";
import loadScript from "discourse/lib/load-script";
let _loaded = false,
_promise = null,
currentUser = Discourse.User.current(),
publisher_id = Discourse.SiteSettings.adsense_publisher_code;
const mobileView = Discourse.Site.currentProp("mobileView");
function parseAdWidth(value) {
if (value === "responsive") {
return "auto";
}
return `${parseInt(value.substring(0, 3).trim())}px`;
}
function parseAdHeight(value) {
if (value === "responsive") {
return "auto";
}
return `${parseInt(value.substring(4, 7).trim())}px`;
}
function loadAdsense() {
if (_loaded) {
return Ember.RSVP.resolve();
}
if (_promise) {
return _promise;
}
const adsenseSrc =
("https:" === document.location.protocol ? "https:" : "http:") +
"//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js";
_promise = loadScript(adsenseSrc, { scriptTag: true }).then(function() {
_loaded = true;
});
return _promise;
}
let data = {
"topic-list-top": {},
"topic-above-post-stream": {},
"topic-above-suggested": {},
"post-bottom": {}
};
if (Discourse.SiteSettings.adsense_publisher_code) {
if (!mobileView && Discourse.SiteSettings.adsense_topic_list_top_code) {
data["topic-list-top"]["ad_code"] =
Discourse.SiteSettings.adsense_topic_list_top_code;
data["topic-list-top"]["ad_width"] = parseAdWidth(
Discourse.SiteSettings.adsense_topic_list_top_ad_sizes
);
data["topic-list-top"]["ad_height"] = parseAdHeight(
Discourse.SiteSettings.adsense_topic_list_top_ad_sizes
);
}
if (mobileView && Discourse.SiteSettings.adsense_mobile_topic_list_top_code) {
data["topic-list-top"]["ad_code"] =
Discourse.SiteSettings.adsense_mobile_topic_list_top_code;
data["topic-list-top"]["ad_width"] = parseAdWidth(
Discourse.SiteSettings.adsense_mobile_topic_list_top_ad_size
);
data["topic-list-top"]["ad_height"] = parseAdHeight(
Discourse.SiteSettings.adsense_mobile_topic_list_top_ad_size
);
}
if (
!mobileView &&
Discourse.SiteSettings.adsense_topic_above_post_stream_code
) {
data["topic-above-post-stream"]["ad_code"] =
Discourse.SiteSettings.adsense_topic_above_post_stream_code;
data["topic-above-post-stream"]["ad_width"] = parseAdWidth(
Discourse.SiteSettings.adsense_topic_above_post_stream_ad_sizes
);
data["topic-above-post-stream"]["ad_height"] = parseAdHeight(
Discourse.SiteSettings.adsense_topic_above_post_stream_ad_sizes
);
}
if (
mobileView &&
Discourse.SiteSettings.adsense_mobile_topic_above_post_stream_code
) {
data["topic-above-post-stream"]["ad_code"] =
Discourse.SiteSettings.adsense_mobile_topic_above_post_stream_code;
data["topic-above-post-stream"]["ad_width"] = parseAdWidth(
Discourse.SiteSettings.adsense_mobile_topic_above_post_stream_ad_size
);
data["topic-above-post-stream"]["ad_height"] = parseAdHeight(
Discourse.SiteSettings.adsense_mobile_topic_above_post_stream_ad_size
);
}
if (
!mobileView &&
Discourse.SiteSettings.adsense_topic_above_suggested_code
) {
data["topic-above-suggested"]["ad_code"] =
Discourse.SiteSettings.adsense_topic_above_suggested_code;
data["topic-above-suggested"]["ad_width"] = parseAdWidth(
Discourse.SiteSettings.adsense_topic_above_suggested_ad_sizes
);
data["topic-above-suggested"]["ad_height"] = parseAdHeight(
Discourse.SiteSettings.adsense_topic_above_suggested_ad_sizes
);
}
if (
mobileView &&
Discourse.SiteSettings.adsense_mobile_topic_above_suggested_code
) {
data["topic-above-suggested"]["ad_code"] =
Discourse.SiteSettings.adsense_mobile_topic_above_suggested_code;
data["topic-above-suggested"]["ad_width"] = parseAdWidth(
Discourse.SiteSettings.adsense_mobile_topic_above_suggested_ad_size
);
data["topic-above-suggested"]["ad_height"] = parseAdHeight(
Discourse.SiteSettings.adsense_mobile_topic_above_suggested_ad_size
);
}
if (!mobileView && Discourse.SiteSettings.adsense_post_bottom_code) {
data["post-bottom"]["ad_code"] =
Discourse.SiteSettings.adsense_post_bottom_code;
data["post-bottom"]["ad_width"] = parseAdWidth(
Discourse.SiteSettings.adsense_post_bottom_ad_sizes
);
data["post-bottom"]["ad_height"] = parseAdHeight(
Discourse.SiteSettings.adsense_post_bottom_ad_sizes
);
}
if (mobileView && Discourse.SiteSettings.adsense_mobile_post_bottom_code) {
data["post-bottom"]["ad_code"] =
Discourse.SiteSettings.adsense_mobile_post_bottom_code;
data["post-bottom"]["ad_width"] = parseAdWidth(
Discourse.SiteSettings.adsense_mobile_post_bottom_ad_size
);
data["post-bottom"]["ad_height"] = parseAdHeight(
Discourse.SiteSettings.adsense_mobile_post_bottom_ad_size
);
}
}
export default AdComponent.extend({
classNameBindings: [
":google-adsense",
"classForSlot",
"isResponsive:adsense-responsive"
],
loadedGoogletag: false,
publisher_id: publisher_id,
ad_width: null,
ad_height: null,
adRequested: false,
init() {
this.set("ad_width", data[this.placement]["ad_width"]);
this.set("ad_height", data[this.placement]["ad_height"]);
this.set("ad_code", data[this.placement]["ad_code"]);
this._super();
},
_triggerAds() {
this.set("adRequested", true);
loadAdsense().then(function() {
const adsbygoogle = window.adsbygoogle || [];
try {
adsbygoogle.push({}); // ask AdSense to fill one ad unit
} catch (ex) {}
});
},
didInsertElement() {
this._super();
if (!this.get("showAd")) {
return;
}
if (this.get("listLoading")) {
return;
}
Ember.run.scheduleOnce("afterRender", this, this._triggerAds);
},
@observes("listLoading")
waitForLoad() {
if (this.get("adRequested")) {
return;
} // already requested that this ad unit be populated
if (!this.get("listLoading")) {
Ember.run.scheduleOnce("afterRender", this, this._triggerAds);
}
},
@computed("ad_width")
isResponsive(adWidth) {
return adWidth === "auto";
},
@computed("placement", "showAd")
classForSlot(placement, showAd) {
return showAd ? `adsense-${placement}`.htmlSafe() : "";
},
@computed("isResponsive")
autoAdFormat(isResponsive) {
return isResponsive ? "auto".htmlSafe() : false;
},
@computed("ad_width", "ad_height", "isResponsive")
adWrapperStyle(w, h, isResponsive) {
return (isResponsive ? "" : `width: ${w}; height: ${h};`).htmlSafe();
},
@computed("adWrapperStyle", "isResponsive")
adInsStyle(adWrapperStyle, isResponsive) {
return `display: ${
isResponsive ? "block" : "inline-block"
}; ${adWrapperStyle}`.htmlSafe();
},
@computed("currentUser.trust_level")
showToTrustLevel(trustLevel) {
return !(
trustLevel && trustLevel > this.siteSettings.adsense_through_trust_level
);
},
@computed("showToTrustLevel", "showToGroups", "showAfterPost")
showAd(showToTrustLevel, showToGroups, showAfterPost) {
return (
this.siteSettings.adsense_publisher_code &&
showToTrustLevel &&
showToGroups &&
showAfterPost
);
},
@computed("postNumber")
showAfterPost(postNumber) {
if (!postNumber) {
return true;
}
return this.isNthPost(parseInt(this.siteSettings.adsense_nth_post_code));
}
});
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More