jquery-dfp-rails 1.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +18 -0
  3. data/Rakefile +38 -0
  4. data/lib/jquery-dfp-rails.rb +3 -0
  5. data/lib/jquery-dfp-rails/engine.rb +7 -0
  6. data/lib/jquery-dfp-rails/version.rb +3 -0
  7. data/lib/tasks/jquery-dfp-rails_tasks.rake +4 -0
  8. data/test/dummy/README.rdoc +261 -0
  9. data/test/dummy/Rakefile +7 -0
  10. data/test/dummy/app/assets/javascripts/application.js +15 -0
  11. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  12. data/test/dummy/app/controllers/application_controller.rb +3 -0
  13. data/test/dummy/app/helpers/application_helper.rb +2 -0
  14. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  15. data/test/dummy/config.ru +4 -0
  16. data/test/dummy/config/application.rb +59 -0
  17. data/test/dummy/config/boot.rb +10 -0
  18. data/test/dummy/config/database.yml +25 -0
  19. data/test/dummy/config/environment.rb +5 -0
  20. data/test/dummy/config/environments/development.rb +37 -0
  21. data/test/dummy/config/environments/production.rb +67 -0
  22. data/test/dummy/config/environments/test.rb +37 -0
  23. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  24. data/test/dummy/config/initializers/inflections.rb +15 -0
  25. data/test/dummy/config/initializers/mime_types.rb +5 -0
  26. data/test/dummy/config/initializers/secret_token.rb +7 -0
  27. data/test/dummy/config/initializers/session_store.rb +8 -0
  28. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  29. data/test/dummy/config/locales/en.yml +5 -0
  30. data/test/dummy/config/routes.rb +58 -0
  31. data/test/dummy/db/test.sqlite3 +0 -0
  32. data/test/dummy/log/test.log +20 -0
  33. data/test/dummy/public/404.html +26 -0
  34. data/test/dummy/public/422.html +26 -0
  35. data/test/dummy/public/500.html +25 -0
  36. data/test/dummy/public/favicon.ico +0 -0
  37. data/test/dummy/script/rails +6 -0
  38. data/test/dummy/tmp/cache/assets/C84/B70/sprockets%2F6e805e2b7ded241647252d728507664a +0 -0
  39. data/test/dummy/tmp/cache/assets/CB7/9D0/sprockets%2F61f25fb2725e79b6751b94537b6c108c +0 -0
  40. data/test/dummy/tmp/cache/assets/CCC/8D0/sprockets%2F97c8600121af14792a256cde0a7c0c14 +0 -0
  41. data/test/dummy/tmp/cache/assets/D3C/9F0/sprockets%2F9217cd553aff02a8506d6ee670a9a34c +0 -0
  42. data/test/dummy/tmp/cache/assets/D72/5F0/sprockets%2Fa3e67d4b155d4c6f8420b8fb41c9cd66 +0 -0
  43. data/test/dummy/tmp/cache/assets/DA4/F00/sprockets%2Faed9f5c95662c19b5c653ebd2d4026ed +0 -0
  44. data/test/jquery-dfp-rails_test.rb +8 -0
  45. data/test/test_helper.rb +13 -0
  46. data/vendor/assets/javascripts/jquery.dfp.js +495 -0
  47. metadata +194 -0
@@ -0,0 +1,8 @@
1
+ require 'test_helper'
2
+
3
+ describe "jquery.dfp integration" do
4
+ it "provides jquery.dfp.js on the asset pipeline" do
5
+ visit '/assets/jquery.dfp.js'
6
+ page.text.must_include 'jQuery DFP v1.0.16'
7
+ end
8
+ end
@@ -0,0 +1,13 @@
1
+ # Configure Rails Environment
2
+ ENV["RAILS_ENV"] = "test"
3
+
4
+ require File.expand_path("../dummy/config/environment.rb", __FILE__)
5
+ require 'minitest/autorun'
6
+ require "capybara/rails"
7
+
8
+ Rails.backtrace_cleaner.remove_silencers!
9
+
10
+ class IntegrationTest < MiniTest::Spec
11
+ include Capybara::DSL
12
+ register_spec_type(/integration$/, self)
13
+ end
@@ -0,0 +1,495 @@
1
+ /**
2
+ * jQuery DFP v1.0.16
3
+ * http://github.com/coop182/jquery.dfp.js
4
+ *
5
+ * Copyright 2013 Matt Cooper
6
+ * Released under the MIT license
7
+ */
8
+ (function ($, window, undefined) {
9
+
10
+ "use strict";
11
+
12
+ var
13
+
14
+ // Save Scope
15
+ dfpScript = this,
16
+
17
+ // DFP account ID
18
+ dfpID = '',
19
+
20
+ // Count of ads
21
+ count = 0,
22
+
23
+ // Count of rendered ads
24
+ rendered = 0,
25
+
26
+ // Default DFP selector
27
+ dfpSelector = '.adunit',
28
+
29
+ // DFP options object
30
+ dfpOptions = {},
31
+
32
+ // Keep track of if we've already tried to load gpt.js before
33
+ dfpIsLoaded = false,
34
+
35
+ // Collection of ads
36
+ $adCollection,
37
+
38
+ // Store adunit on div as:
39
+ storeAs = 'googleAdUnit',
40
+
41
+ /**
42
+ * Init function sets required params and loads Google's DFP script
43
+ * @param String id The DFP account ID
44
+ * @param String selector The adunit selector
45
+ * @param Object options Custom options to apply
46
+ */
47
+ init = function (id, selector, options) {
48
+
49
+ dfpID = id;
50
+ $adCollection = $(selector);
51
+
52
+ dfpLoader();
53
+ setOptions(options);
54
+
55
+ $(function () {
56
+ createAds();
57
+ displayAds();
58
+ });
59
+
60
+ },
61
+
62
+ /**
63
+ * Set the options for DFP
64
+ * @param Object options Custom options to apply
65
+ */
66
+ setOptions = function (options) {
67
+
68
+ // Get URL Targeting
69
+ var URLTargets = getURLTargets();
70
+
71
+ // Set default options
72
+ dfpOptions = {
73
+ setTargeting: {
74
+ inURL: URLTargets.inURL,
75
+ URLIs: URLTargets.URLIs,
76
+ Query: URLTargets.Query,
77
+ Domain: window.location.host
78
+ },
79
+ setCategoryExclusion: '',
80
+ enableSingleRequest: true,
81
+ collapseEmptyDivs: 'original',
82
+ targetPlatform: 'web',
83
+ enableSyncRendering: false,
84
+ refreshExisting: true
85
+ };
86
+
87
+ // Merge options objects
88
+ $.extend(true, dfpOptions, options);
89
+
90
+ // If a custom googletag is specified, use it.
91
+ if (dfpOptions.googletag) {
92
+ window.googletag.cmd.push(function () {
93
+ $.extend(true, window.googletag, dfpOptions.googletag);
94
+ });
95
+ }
96
+
97
+ },
98
+
99
+ /**
100
+ * Find and create all Ads
101
+ * @return Array an array of ad units that have been created.
102
+ */
103
+ createAds = function () {
104
+
105
+ // Loops through on page Ad units and gets ads for them.
106
+ $adCollection.each(function () {
107
+
108
+ var $adUnit = $(this);
109
+
110
+ count++;
111
+
112
+ // adUnit name
113
+ var adUnitName = getName($adUnit);
114
+
115
+ // adUnit id - this will use an existing id or an auto generated one.
116
+ var adUnitID = getID($adUnit, adUnitName, count);
117
+
118
+ // get dimensions of the adUnit
119
+ var dimensions = getDimensions($adUnit);
120
+
121
+ // get existing content
122
+ var $existingContent = $adUnit.html();
123
+
124
+ // wipe html clean ready for ad and set the default display class.
125
+ $adUnit.html('').addClass('display-none');
126
+
127
+ // Push commands to DFP to create ads
128
+ window.googletag.cmd.push(function () {
129
+
130
+ var googleAdUnit,
131
+ $adUnitData = $adUnit.data(storeAs);
132
+
133
+ if ($adUnitData) {
134
+
135
+ // Get existing ad unit
136
+ googleAdUnit = $adUnitData;
137
+
138
+ } else {
139
+
140
+ // Create the ad - out of page or normal
141
+ if ($adUnit.data('outofpage')) {
142
+ googleAdUnit = window.googletag.defineOutOfPageSlot('/' + dfpID + '/' + adUnitName, adUnitID).addService(window.googletag.pubads());
143
+ } else {
144
+ googleAdUnit = window.googletag.defineSlot('/' + dfpID + '/' + adUnitName, dimensions, adUnitID).addService(window.googletag.pubads());
145
+ }
146
+
147
+ }
148
+
149
+ // Sets custom targeting for just THIS ad unit if it has been specified
150
+ var targeting = $adUnit.data("targeting");
151
+ if (targeting) {
152
+ $.each(targeting, function (k, v) {
153
+ googleAdUnit.setTargeting(k, v);
154
+ });
155
+ }
156
+
157
+ // Sets custom exclusions for just THIS ad unit if it has been specified
158
+ var exclusions = $adUnit.data("exclusions");
159
+ if (exclusions) {
160
+ var exclusionsGroup = exclusions.split(',');
161
+ var valueTrimmed;
162
+ $.each(exclusionsGroup, function (k, v) {
163
+ valueTrimmed = $.trim(v);
164
+ if (valueTrimmed.length > 0) {
165
+ googleAdUnit.setCategoryExclusion(valueTrimmed);
166
+ }
167
+ });
168
+ }
169
+
170
+ // The following hijacks an internal google method to check if the div has been
171
+ // collapsed after the ad has been attempted to be loaded.
172
+ googleAdUnit.oldRenderEnded = googleAdUnit.oldRenderEnded || googleAdUnit.renderEnded;
173
+ googleAdUnit.renderEnded = function () {
174
+
175
+ rendered++;
176
+
177
+ var display = $adUnit.css('display');
178
+
179
+ // if the div has been collapsed but there was existing content expand the
180
+ // div and reinsert the existing content.
181
+ if (display === 'none' && $.trim($existingContent).length > 0 && dfpOptions.collapseEmptyDivs === 'original') {
182
+ $adUnit.show().html($existingContent);
183
+ display = 'block display-original';
184
+ }
185
+
186
+ $adUnit.removeClass('display-none').addClass('display-' + display);
187
+
188
+ googleAdUnit.oldRenderEnded();
189
+
190
+ // Excute afterEachAdLoaded callback if provided
191
+ if (typeof dfpOptions.afterEachAdLoaded === 'function') {
192
+ dfpOptions.afterEachAdLoaded.call(this, $adUnit);
193
+ }
194
+
195
+ // Excute afterAllAdsLoaded callback if provided
196
+ if (typeof dfpOptions.afterAllAdsLoaded === 'function' && rendered === count) {
197
+ dfpOptions.afterAllAdsLoaded.call(this, $adCollection);
198
+ }
199
+
200
+ };
201
+
202
+ // Store googleAdUnit reference
203
+ $adUnit.data(storeAs, googleAdUnit);
204
+
205
+ });
206
+
207
+ });
208
+
209
+ // Push DFP config options
210
+ window.googletag.cmd.push(function () {
211
+
212
+ if (dfpOptions.enableSingleRequest === true) {
213
+ window.googletag.pubads().enableSingleRequest();
214
+ }
215
+ $.each(dfpOptions.setTargeting, function (k, v) {
216
+ window.googletag.pubads().setTargeting(k, v);
217
+ });
218
+ if (dfpOptions.setCategoryExclusion.length > 0) {
219
+ var exclusionsGroup = dfpOptions.setCategoryExclusion.split(',');
220
+ var valueTrimmed;
221
+ $.each(exclusionsGroup, function (k, v) {
222
+ valueTrimmed = $.trim(v);
223
+ if (valueTrimmed.length > 0) {
224
+ window.googletag.pubads().setCategoryExclusion(valueTrimmed);
225
+ }
226
+ });
227
+ }
228
+ if (dfpOptions.collapseEmptyDivs === true || dfpOptions.collapseEmptyDivs === 'original') {
229
+ window.googletag.pubads().collapseEmptyDivs();
230
+ }
231
+ window.googletag.enableServices();
232
+
233
+ });
234
+
235
+ },
236
+
237
+ /**
238
+ * Display all created Ads
239
+ */
240
+ displayAds = function () {
241
+
242
+ // Display each ad
243
+ $adCollection.each(function () {
244
+
245
+ var $adUnit = $(this),
246
+ $adUnitData = $adUnit.data(storeAs);
247
+
248
+ if (dfpOptions.refreshExisting && $adUnitData && $adUnit.hasClass('display-block')) {
249
+
250
+ window.googletag.cmd.push(function () { window.googletag.pubads().refresh([$adUnitData]); });
251
+
252
+ } else {
253
+
254
+ window.googletag.cmd.push(function () { window.googletag.display($adUnit.attr('id')); });
255
+
256
+ }
257
+
258
+ });
259
+
260
+ },
261
+
262
+ /**
263
+ * Create an array of paths so that we can target DFP ads to Page URI's
264
+ * @return Array an array of URL parts that can be targeted.
265
+ */
266
+ getURLTargets = function () {
267
+
268
+ // Get the paths for targeting against
269
+ var paths = window.location.pathname.replace(/\/$/, ''),
270
+ patt = new RegExp('\/([^\/]*)', 'ig'),
271
+ pathsMatches = paths.match(patt),
272
+ targetPaths = ['/'],
273
+ longestpath = '';
274
+
275
+ if (pathsMatches && paths !== '/') {
276
+ var target = '',
277
+ size = pathsMatches.length;
278
+ if (size > 0) {
279
+ for (var i = 0; i < size; i++) {
280
+ target = pathsMatches[i];
281
+ targetPaths.push(target);
282
+ for (var j = i + 1; j < size; j++) {
283
+ target += pathsMatches[j];
284
+ targetPaths.push(target);
285
+ }
286
+ if (i === 0) {
287
+ targetPaths.splice(-1, 1);
288
+ longestpath = target;
289
+ }
290
+ }
291
+ }
292
+ targetPaths.push(longestpath);
293
+ }
294
+
295
+ targetPaths = targetPaths.reverse();
296
+
297
+ // Get the query params for targeting against
298
+ var url = window.location.toString().replace(/\=/ig, ':').match(/\?(.+)$/),
299
+ params = RegExp.$1.split("&");
300
+
301
+ return {
302
+ inURL: targetPaths,
303
+ URLIs: targetPaths[0],
304
+ Query: params
305
+ };
306
+
307
+ },
308
+
309
+ /**
310
+ * Get the id of the adUnit div or generate a unique one.
311
+ * @param Object $adUnit The adunit to work with
312
+ * @param String adUnitName The name of the adunit
313
+ * @param Integer count The current count of adunit, for uniqueness
314
+ * @return String The ID of the adunit or a unique autogenerated ID
315
+ */
316
+ getID = function ($adUnit, adUnitName, count) {
317
+
318
+ return $adUnit.attr('id') || $adUnit.attr('id', adUnitName + '-auto-gen-id-' + count).attr('id');
319
+
320
+ },
321
+
322
+ /**
323
+ * Get the name of the Ad unit, either use the div id or
324
+ * check for the optional attribute data-adunit
325
+ * @param Object $adUnit The adunit to work with
326
+ * @return String The name of the adunit, will be the same as inside DFP
327
+ */
328
+ getName = function ($adUnit) {
329
+
330
+ return $adUnit.data('adunit') || $adUnit.attr('id');
331
+
332
+ },
333
+
334
+ /**
335
+ * Get the dimensions of the ad unit using the container div dimensions or
336
+ * check for the optional attribute data-dimensions
337
+ * @param Object $adUnit The adunit to work with
338
+ * @return Array The dimensions of the adunit (width, height)
339
+ */
340
+ getDimensions = function ($adUnit) {
341
+
342
+ var dimensions = [],
343
+ dimensionsData = $adUnit.data('dimensions');
344
+
345
+ // Check if data-dimensions are specified. If they aren't, use the dimensions of the ad unit div.
346
+ if (dimensionsData) {
347
+
348
+ var dimensionGroups = dimensionsData.split(',');
349
+
350
+ $.each(dimensionGroups, function (k, v) {
351
+
352
+ var dimensionSet = v.split('x');
353
+ dimensions.push([parseInt(dimensionSet[0], 10), parseInt(dimensionSet[1], 10)]);
354
+
355
+ });
356
+
357
+ } else {
358
+
359
+ dimensions.push([$adUnit.width(), $adUnit.height()]);
360
+
361
+ }
362
+
363
+ return dimensions;
364
+
365
+ },
366
+
367
+ /**
368
+ * Call the google DFP script - there is a little bit of error detection in here to detect
369
+ * if the dfp script has failed to load either through an error or it being blocked by an ad
370
+ * blocker... if it does not load we execute a dummy script to replace the real DFP.
371
+ */
372
+ dfpLoader = function () {
373
+
374
+ // make sure we don't load gpt.js multiple times
375
+ dfpIsLoaded = dfpIsLoaded || $('script[src*="googletagservices.com/tag/js/gpt.js"]').length;
376
+ if (dfpIsLoaded) {
377
+ return;
378
+ }
379
+
380
+ window.googletag = window.googletag || {};
381
+ window.googletag.cmd = window.googletag.cmd || [];
382
+
383
+ var gads = document.createElement('script');
384
+ gads.async = true;
385
+ gads.type = 'text/javascript';
386
+
387
+ // Adblock blocks the load of Ad scripts... so we check for that
388
+ gads.onerror = function () {
389
+ dfpBlocked();
390
+ };
391
+
392
+ var useSSL = 'https:' === document.location.protocol;
393
+ gads.src = (useSSL ? 'https:' : 'http:') +
394
+ '//www.googletagservices.com/tag/js/gpt.js';
395
+ var node = document.getElementsByTagName('script')[0];
396
+ node.parentNode.insertBefore(gads, node);
397
+
398
+ // Adblock plus seems to hide blocked scripts... so we check for that
399
+ if (gads.style.display === 'none') {
400
+ dfpBlocked();
401
+ }
402
+
403
+ },
404
+
405
+ /**
406
+ * This function gets called if DFP has been blocked by an adblocker
407
+ * it implements a dummy version of the dfp object and allows the script to excute its callbacks
408
+ * regardless of whether DFP is actually loaded or not... it is basically only useful for situations
409
+ * where you are laying DFP over existing content and need to init things like slide shows after the loading
410
+ * is completed.
411
+ */
412
+ dfpBlocked = function () {
413
+
414
+ // Get the stored dfp commands
415
+ var commands = window.googletag.cmd;
416
+
417
+ // SetTimeout is a bit dirty but the script does not execute in the correct order without it
418
+ setTimeout(function () {
419
+
420
+ // overwrite the dfp object - replacing the command array with a function and defining missing functions
421
+ window.googletag = {
422
+ cmd: {
423
+ push: function (callback) {
424
+ callback.call(dfpScript);
425
+ }
426
+ },
427
+ ads: [],
428
+ pubads: function () { return this; },
429
+ enableSingleRequest: function () { return this; },
430
+ setTargeting: function () { return this; },
431
+ collapseEmptyDivs: function () { return this; },
432
+ enableServices: function () { return this; },
433
+ defineSlot: function (name, dimensions, id) {
434
+ window.googletag.ads.push(id);
435
+ window.googletag.ads[id] = {
436
+ renderEnded: function () {},
437
+ addService: function () { return this; }
438
+ };
439
+ return window.googletag.ads[id];
440
+ },
441
+ defineOutOfPageSlot: function (name, id) {
442
+ window.googletag.ads.push(id);
443
+ window.googletag.ads[id] = {
444
+ renderEnded: function () {},
445
+ addService: function () { return this; }
446
+ };
447
+ return window.googletag.ads[id];
448
+ },
449
+ display: function (id) {
450
+ window.googletag.ads[id].renderEnded.call(dfpScript);
451
+ return this;
452
+ }
453
+
454
+ };
455
+
456
+ // Execute any stored commands
457
+ $.each(commands, function (k, v) {
458
+ window.googletag.cmd.push(v);
459
+ });
460
+
461
+ }, 50);
462
+
463
+ };
464
+
465
+ /**
466
+ * Add function to the jQuery / Zepto / tire namespace
467
+ * @param String id (Optional) The DFP account ID
468
+ * @param Object options (Optional) Custom options to apply
469
+ */
470
+ $.dfp = $.fn.dfp = function (id, options) {
471
+
472
+ options = options || {};
473
+
474
+ if (id === undefined) {
475
+ id = dfpID;
476
+ }
477
+
478
+ if (typeof id === 'object') {
479
+ options = id;
480
+ id = options.dfpID || dfpID;
481
+ }
482
+
483
+ var selector = this;
484
+
485
+ if (typeof this === 'function') {
486
+ selector = dfpSelector;
487
+ }
488
+
489
+ init(id, selector, options);
490
+
491
+ return this;
492
+
493
+ };
494
+
495
+ })(window.jQuery || window.Zepto || window.tire, window);