jquery-dfp-rails 1.0.16

Sign up to get free protection for your applications and to get access to all the features.
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);