retreaverjs-rails 0.0.12 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/Gruntfile.js +1 -0
  3. data/config/README +1 -1
  4. data/config/jsdocs.json +1 -0
  5. data/lib/retreaverjs/compile.rb +5 -5
  6. data/lib/retreaverjs/rails/version.rb +1 -1
  7. data/src/retreaver/base/model.js +1 -1
  8. data/src/retreaver/campaign.js +1 -1
  9. data/src/retreaver.js +28 -0
  10. data/vendor/assets/javascripts/retreaver.js +1179 -0
  11. data/vendor/assets/javascripts/retreaver.min.js +2 -0
  12. data/vendor/documentation/javascript/v1/Retreaver.Campaign.html +425 -0
  13. data/vendor/documentation/javascript/v1/Retreaver.Number.html +1415 -0
  14. data/vendor/documentation/javascript/v1/Retreaver.Retreaver.html +146 -0
  15. data/vendor/documentation/javascript/v1/Retreaver.context.Retreaver.html +146 -0
  16. data/vendor/documentation/javascript/v1/Retreaver.html +304 -0
  17. data/vendor/documentation/javascript/v1/campaign.js.html +157 -0
  18. data/vendor/documentation/javascript/v1/global.html +232 -0
  19. data/vendor/documentation/javascript/v1/index.html +67 -0
  20. data/vendor/documentation/javascript/v1/number.js.html +255 -0
  21. data/vendor/documentation/javascript/v1/retreaver.js.html +78 -0
  22. data/vendor/documentation/javascript/v1/scripts/linenumber.js +17 -0
  23. data/vendor/documentation/javascript/v1/scripts/prettify/Apache-License-2.0.txt +202 -0
  24. data/vendor/documentation/javascript/v1/scripts/prettify/lang-css.js +2 -0
  25. data/vendor/documentation/javascript/v1/scripts/prettify/prettify.js +28 -0
  26. data/vendor/documentation/javascript/v1/styles/jsdoc-default.css +290 -0
  27. data/vendor/documentation/javascript/v1/styles/prettify-jsdoc.css +111 -0
  28. data/vendor/documentation/javascript/v1/styles/prettify-tomorrow.css +132 -0
  29. metadata +22 -2
@@ -0,0 +1,1179 @@
1
+ (function (context) {
2
+ /**
3
+ * @namespace Retreaver
4
+ */
5
+ var Retreaver = {
6
+
7
+ /**
8
+ * Configure the retreaver client library.
9
+ * @function configure
10
+ * @memberof Retreaver
11
+ * @param {Object} options
12
+ * @param {String} options.host - Retreaver API Host
13
+ * @example
14
+ * Retreaver.configure({host: 'api.retreaver.com'});
15
+ *
16
+ */
17
+ configure: function (options) {
18
+ var params = {
19
+ addr: options.host,
20
+ http_prefix: 'http',
21
+ urlregex: "/\\/\\/[^\\/]*\\/(.*)/"
22
+ };
23
+ window.Retreaver._connection = new Retreaver.Base.Request(params);
24
+ }
25
+ };
26
+ context.Retreaver = Retreaver;
27
+
28
+ })(window);
29
+ ;(function () {
30
+ // ensure namespace is present
31
+ if (typeof window.Retreaver === 'undefined') window.Retreaver = {};
32
+ var Base = {};
33
+ // define helpers
34
+ Base.assert_required_keys = function () {
35
+ var args = Array.prototype.slice.call(arguments);
36
+ var object = args.shift();
37
+ for (var i = 0; i < args.length; i++) {
38
+ var key = args[i];
39
+ if (typeof object === 'undefined' || typeof object[key] === 'undefined') {
40
+ throw "ArgumentError: Required keys are not defined: " + args.join(', ');
41
+ }
42
+ }
43
+ return object;
44
+ };
45
+ Base.merge = function (obj1, obj2) {
46
+ for (var p in obj2) {
47
+ try {
48
+ if (obj2[p].constructor == Object) {
49
+ obj1[p] = Base.merge(obj1[p], obj2[p]);
50
+ } else {
51
+ obj1[p] = obj2[p];
52
+ }
53
+ } catch (e) {
54
+ obj1[p] = obj2[p];
55
+ }
56
+ }
57
+ return obj1;
58
+ };
59
+ Base.isArray = function (arg) {
60
+ return Object.prototype.toString.call(arg) === '[object Array]';
61
+ };
62
+ Base.ieVersion = function () {
63
+ if (Base._ieVersion == null) {
64
+ Base._ieVersion = (function () {
65
+ var v = 3,
66
+ div = document.createElement('div'),
67
+ all = div.getElementsByTagName('i');
68
+
69
+ while (
70
+ div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
71
+ all[0]
72
+ ) {
73
+ }
74
+ return v > 4 ? v : false;
75
+ }());
76
+ }
77
+ if (Base._ieVersion == 6 || Base._ieVersion == 7) {
78
+ if (Retreaver['easyxdm_loaded'] == null) Retreaver['easyxdm_loaded'] = false;
79
+ }
80
+ return Base._ieVersion;
81
+ };
82
+ Retreaver.Base = Base;
83
+ })();;// https://github.com/evertton/cookiejs
84
+ (function (f) {
85
+ var a = function (b, c, d) {
86
+ return 1 === arguments.length ? a.get(b) : a.set(b, c, d)
87
+ };
88
+ a._document = document;
89
+ a._navigator = navigator;
90
+ a.defaults = {path: "/"};
91
+ a.get = function (b) {
92
+ a._cachedDocumentCookie !== a._document.cookie && a._renewCache();
93
+ return a._cache[b]
94
+ };
95
+ a.set = function (b, c, d) {
96
+ d = a._getExtendedOptions(d);
97
+ a._document.cookie = a._generateCookieString(b, c, d);
98
+ return a
99
+ };
100
+ a._getExtendedOptions = function (b) {
101
+ return{path: b && b.path || a.defaults.path, domain: b && b.domain || a.defaults.domain, secure: b && b.secure !== f ? b.secure :
102
+ a.defaults.secure}
103
+ };
104
+ a._isValidDate = function (a) {
105
+ return"[object Date]" === Object.prototype.toString.call(a) && !isNaN(a.getTime())
106
+ };
107
+ a._generateCookieString = function (a, c, d) {
108
+ a = encodeURIComponent(a);
109
+ c = (c + "").replace(/[^!#$&-+\--:<-\[\]-~]/g, encodeURIComponent);
110
+ d = d || {};
111
+ a = a + "=" + c + (d.path ? ";path=" + d.path : "");
112
+ a += d.domain ? ";domain=" + d.domain : "";
113
+ return a += d.secure ? ";secure" : ""
114
+ };
115
+ a._getCookieObjectFromString = function (b) {
116
+ var c = {};
117
+ b = b ? b.split("; ") : [];
118
+ for (var d = 0; d < b.length; d++) {
119
+ var e = a._getKeyValuePairFromCookieString(b[d]);
120
+ c[e.key] === f && (c[e.key] = e.value)
121
+ }
122
+ return c
123
+ };
124
+ a._getKeyValuePairFromCookieString = function (a) {
125
+ var c = a.indexOf("="), c = 0 > c ? a.length : c;
126
+ return{key: decodeURIComponent(a.substr(0, c)), value: decodeURIComponent(a.substr(c + 1))}
127
+ };
128
+ a._renewCache = function () {
129
+ a._cache = a._getCookieObjectFromString(a._document.cookie);
130
+ a._cachedDocumentCookie = a._document.cookie
131
+ };
132
+ a._areEnabled = function () {
133
+ return a._navigator.cookieEnabled || "1" === a.set("cookies.js", 1).get("cookies.js")
134
+ };
135
+ a.enabled = a._areEnabled();
136
+ "function" === typeof define &&
137
+ define.amd ? define(function () {
138
+ return a
139
+ }) : "undefined" !== typeof exports ? ("undefined" !== typeof module && module.exports && (exports = module.exports = a), exports.Cookies = a) : a;
140
+ Retreaver.Base.Cookies = a;
141
+ })();;// http://www.webtoolkit.info/javascript-base64.html#.U-qwzYBdUwQ
142
+ (function () {
143
+ var Base64 = {
144
+ _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
145
+ };
146
+ // public method for encoding
147
+ Base64.encode = function (input) {
148
+ var output = "";
149
+ var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
150
+ var i = 0;
151
+
152
+ input = Base64._utf8_encode(input);
153
+
154
+ while (i < input.length) {
155
+
156
+ chr1 = input.charCodeAt(i++);
157
+ chr2 = input.charCodeAt(i++);
158
+ chr3 = input.charCodeAt(i++);
159
+
160
+ enc1 = chr1 >> 2;
161
+ enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
162
+ enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
163
+ enc4 = chr3 & 63;
164
+
165
+ if (isNaN(chr2)) {
166
+ enc3 = enc4 = 64;
167
+ } else if (isNaN(chr3)) {
168
+ enc4 = 64;
169
+ }
170
+ output = output +
171
+ Base64._keyStr.charAt(enc1) + Base64._keyStr.charAt(enc2) +
172
+ Base64._keyStr.charAt(enc3) + Base64._keyStr.charAt(enc4);
173
+
174
+ }
175
+ return output;
176
+ };
177
+ Base64.decode = function (input) {
178
+ var output = "";
179
+ var chr1, chr2, chr3;
180
+ var enc1, enc2, enc3, enc4;
181
+ var i = 0;
182
+
183
+ input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
184
+
185
+ while (i < input.length) {
186
+
187
+ enc1 = Base64._keyStr.indexOf(input.charAt(i++));
188
+ enc2 = Base64._keyStr.indexOf(input.charAt(i++));
189
+ enc3 = Base64._keyStr.indexOf(input.charAt(i++));
190
+ enc4 = Base64._keyStr.indexOf(input.charAt(i++));
191
+
192
+ chr1 = (enc1 << 2) | (enc2 >> 4);
193
+ chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
194
+ chr3 = ((enc3 & 3) << 6) | enc4;
195
+
196
+ output = output + String.fromCharCode(chr1);
197
+
198
+ if (enc3 != 64) {
199
+ output = output + String.fromCharCode(chr2);
200
+ }
201
+ if (enc4 != 64) {
202
+ output = output + String.fromCharCode(chr3);
203
+ }
204
+
205
+ }
206
+
207
+ output = Base64._utf8_decode(output);
208
+
209
+ return output;
210
+ };
211
+ Base64._utf8_encode = function (string) {
212
+ //REGEX_2: /\r\n/g NEWLINE: "\n"
213
+ string = string.replace(eval("/\\r\\n/g"),eval("String('\\n')"));
214
+ var utftext = "";
215
+
216
+ for (var n = 0; n < string.length; n++) {
217
+
218
+ var c = string.charCodeAt(n);
219
+
220
+ if (c < 128) {
221
+ utftext += String.fromCharCode(c);
222
+ }
223
+ else if ((c > 127) && (c < 2048)) {
224
+ utftext += String.fromCharCode((c >> 6) | 192);
225
+ utftext += String.fromCharCode((c & 63) | 128);
226
+ }
227
+ else {
228
+ utftext += String.fromCharCode((c >> 12) | 224);
229
+ utftext += String.fromCharCode(((c >> 6) & 63) | 128);
230
+ utftext += String.fromCharCode((c & 63) | 128);
231
+ }
232
+
233
+ }
234
+
235
+ return utftext;
236
+ };
237
+ Base64._utf8_decode = function (utftext) {
238
+ var string = "";
239
+ var i = 0;
240
+ var c = c1 = c2 = 0;
241
+
242
+ while (i < utftext.length) {
243
+
244
+ c = utftext.charCodeAt(i);
245
+
246
+ if (c < 128) {
247
+ string += String.fromCharCode(c);
248
+ i++;
249
+ }
250
+ else if ((c > 191) && (c < 224)) {
251
+ c2 = utftext.charCodeAt(i + 1);
252
+ string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
253
+ i += 2;
254
+ }
255
+ else {
256
+ c2 = utftext.charCodeAt(i + 1);
257
+ c3 = utftext.charCodeAt(i + 2);
258
+ string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
259
+ i += 3;
260
+ }
261
+
262
+ }
263
+ return string;
264
+ };
265
+ Retreaver.Base.Base64 = Base64;
266
+ })();;(function () {
267
+ // Dependencies
268
+ var Base = Retreaver.Base;
269
+ /**
270
+ * @constructor
271
+ * @memberof Retreaver.Base
272
+ * @param {Object} config - Configuration hash
273
+ * @param {String} config.type - The data type
274
+ * @param {Numeric} config.primary_key - The primary_key
275
+ */
276
+ var Data = function (config) {
277
+
278
+ function initialize() {
279
+ Base.assert_required_keys(config, 'type', 'primary_key');
280
+ if (typeof Retreaver.Base.Data._store[config.type] === 'undefined') {
281
+ Retreaver.Base.Data._store[config.type] = {};
282
+ }
283
+ if (typeof Retreaver.Base.Data._store[config.type][config.primary_key] === 'undefined') {
284
+ Retreaver.Base.Data._store[config.type][config.primary_key] = {};
285
+ }
286
+ }
287
+
288
+ var self = this;
289
+
290
+ /**
291
+ * Request data from the host
292
+ * @memberOf Retreaver.Base.Data
293
+ * @function get
294
+ * @instance
295
+ * @param {String} key - The key to retrieve
296
+ * @returns {*}
297
+ */
298
+ self.get = function () {
299
+ var output = {};
300
+ if (typeof arguments[0] === 'undefined') {
301
+ output = Retreaver.Base.Data._store[config.type][config.primary_key];
302
+ } else if (arguments.length === 1) {
303
+ output = Retreaver.Base.Data._store[config.type][config.primary_key][arguments[0]];
304
+ } else {
305
+ for (var i = 0; i < arguments.length; i++) {
306
+ var key = arguments[i];
307
+ output[key] = Retreaver.Base.Data._store[config.type][config.primary_key][key];
308
+ }
309
+ }
310
+ return output;
311
+ };
312
+
313
+ /**
314
+ * Request data from the host
315
+ * @memberOf Retreaver.Base.Data
316
+ * @function set
317
+ * @instance
318
+ * @param {String} key - The key to retrieve
319
+ * @param {String} value - The value to assign
320
+ * @returns {*}
321
+ */
322
+ self.set = function (key, value) {
323
+ Retreaver.Base.Data._store[config.type][config.primary_key][key] = value;
324
+ return value;
325
+ };
326
+
327
+ /**
328
+ * Merge data
329
+ * @memberOf Retreaver.Base.Data
330
+ * @function set
331
+ * @instance
332
+ * @param {String} object - The object to merge
333
+ * @returns {*}
334
+ */
335
+ self.merge = function (object) {
336
+ for (var key in object) {
337
+ Retreaver.Base.Data._store[config.type][config.primary_key][key] = object[key];
338
+ }
339
+ return object;
340
+ };
341
+
342
+ initialize();
343
+ };
344
+ Data._store = {};
345
+ Retreaver.Base.Data = Data;
346
+ })();;(function () {
347
+ // Dependencies
348
+ var Base = Retreaver.Base;
349
+ var Data = Retreaver.Base.Data;
350
+
351
+ /**
352
+ * @constructor
353
+ * @memberof Retreaver.Base
354
+ */
355
+ var Model = function () {
356
+
357
+ this.api_host_uri = '/api/v1/';
358
+ this.type = 'model';
359
+
360
+ this.primary_key = function (primary_key) {
361
+ return Model.primary_key(this.type, primary_key);
362
+ };
363
+
364
+ this.store = function (data) {
365
+ // do we have data to store?
366
+ if (typeof(data) !== 'undefined') {
367
+ // does the data contain the required primary_key?
368
+ var key = this.primary_key();
369
+ if (typeof(data[key]) === 'undefined') {
370
+ throw("ArgumentError: Expected to receive primary_key " + key);
371
+ }
372
+ // has a store been initialized?
373
+ else if (typeof(this._store) === 'undefined') {
374
+ this._store = new Retreaver.Base.Data({type: this.type, primary_key: data[key] });
375
+ }
376
+ // merge the data
377
+ this._store.merge(data);
378
+ // update visitor is token present
379
+ Model.update_visitor_id(data);
380
+ }
381
+ return this._store;
382
+ };
383
+
384
+ this.get_data = function (path, callback) {
385
+ return this.connection().getJSON(this.api_host_uri + path, null, [Model.update, callback], this);
386
+ };
387
+
388
+ this.post_data = function (path, data, callback) {
389
+ return this.connection().postJSON(this.api_host_uri + path, data, [Model.update, callback], this);
390
+ };
391
+
392
+ this.set = function () {
393
+ if (typeof(this["set_" + arguments[0]]) === 'function') {
394
+ arguments[1] = this["set_" + arguments[0]].apply(this, [arguments[1]]);
395
+ }
396
+ return this._store.set.apply(this, arguments);
397
+ };
398
+ this.get = function () {
399
+ return this._store.get.apply(this, arguments);
400
+ };
401
+ this.connection = function () {
402
+ return Retreaver.Base.Request.connection();
403
+ };
404
+ };
405
+ Model.inflections = {
406
+ 'number': 'numbers',
407
+ 'campaign': 'campaigns'
408
+ };
409
+ Model.update = function (data) {
410
+ for (var key in data) {
411
+ var type = key;
412
+ var value = data[key];
413
+ if (typeof Model.inflections[key] !== 'undefined') {
414
+ type = Model.inflections[key];
415
+ }
416
+ if (typeof Data._store[type] !== 'undefined') {
417
+ if (Base.isArray(value)) {
418
+ for (var i = 0; i < value.length; i++) {
419
+ Model.update_record(type, value[i]);
420
+ }
421
+ } else {
422
+ Model.update_record(type, value[i]);
423
+ }
424
+ }
425
+ }
426
+ return data;
427
+ };
428
+ Model.update_record = function (type, record) {
429
+ // update visitor is token present
430
+ Model.update_visitor_id(record);
431
+ // update data store
432
+ if (typeof record.id !== 'undefined') {
433
+ var primary_key = Model.primary_key(type);
434
+ for (var key in record) {
435
+ Retreaver.Base.Data._store[type][record[primary_key]][key] = record[key];
436
+ }
437
+ return true
438
+ } else {
439
+ return false
440
+ }
441
+ return record;
442
+ };
443
+ Model.update_visitor_id = function (record) {
444
+ if (typeof(record) !== 'undefined' && typeof(record.visitor_id) !== 'undefined') {
445
+ Retreaver.Base.Cookies.set('CallPixels-vid', record.visitor_id);
446
+ }
447
+ };
448
+ Model.primary_key = function (type, primary_key) {
449
+ if (typeof(Model.primary_keys) === 'undefined') Model.primary_keys = {};
450
+ // default key
451
+ if (typeof(Model.primary_keys[type]) === 'undefined') Model.primary_keys[type] = 'id';
452
+ // assign key if passed
453
+ if (typeof(primary_key) !== 'undefined') Model.primary_keys[type] = primary_key;
454
+ // return value
455
+ return Model.primary_keys[type];
456
+ };
457
+ Retreaver.Base.Model = Model;
458
+ })();;(function () {
459
+ // Dependencies
460
+ var Base = window.Retreaver.Base;
461
+ var Cookies = window.Retreaver.Base.Cookies;
462
+ /**
463
+ * @constructor
464
+ * @memberof Retreaver.Base
465
+ * @param {String} options.http_prefix - The http type (http || https).
466
+ * @param {String} options.addr - The api hostname.
467
+ * @param {String} options.urlregex - The url regex validator.
468
+ */
469
+ var Request = function (options) {
470
+
471
+ function initialize(options) {
472
+ // assert required keys and assign if valid
473
+ config = Base.assert_required_keys(options, 'http_prefix', 'addr', 'urlregex');
474
+ }
475
+
476
+ // INIT
477
+ var self = this;
478
+ var config = {};
479
+
480
+ /**
481
+ * Request data from the host
482
+ * @memberOf Retreaver.Base.Request
483
+ * @function getJSON
484
+ * @instance
485
+ * @param {String} request_url - The request uri
486
+ * @param {Object} payload - Post object
487
+ * @param {*} [callbacks] - Array or Function to be called after request
488
+ * @param {*} [context] - Context applied to callback
489
+ * @returns {Object} json
490
+ */
491
+ self.getJSON = function (request_url, payload, callbacks, context) {
492
+ // ensure callbacks are an array
493
+ if (typeof(callbacks) == "function") callbacks = [callbacks];
494
+ if (typeof(context) === 'undefined') context = self;
495
+ // request
496
+ var request = function () {
497
+ self.apiRequest(request_url, function (data) {
498
+ // parse
499
+ response = JSON.parse(data);
500
+ // fire callbacks
501
+ for (var i in callbacks) {
502
+ if (typeof callbacks[i] == "function") callbacks[i].apply(context, [response]);
503
+ }
504
+ }, payload)
505
+ };
506
+ if (Base.ieVersion() == 6 || Base.ieVersion() == 7) {
507
+ with_ie_scripts(request);
508
+ } else {
509
+ request();
510
+ }
511
+ };
512
+
513
+ // This is an alias for now to show intent
514
+ self.postJSON = function () {
515
+ return self.getJSON.apply(this, arguments);
516
+ };
517
+
518
+ /**
519
+ * Request data from the host
520
+ * @memberOf Retreaver.Base.Request
521
+ * @function apiRequest
522
+ * @instance
523
+ * @param {String} request_url - The request uri
524
+ * @param {Array} callbackFunctions - Array of callback functions
525
+ * @param {Object} payload - Post object
526
+ * @returns {String} string
527
+ */
528
+ self.apiRequest = function (request_uri, callbackFunctions, payload) {
529
+ // configure
530
+ var http_prefix = config['http_prefix'];
531
+ var addr = config['addr'];
532
+ var urlregex = eval(config['urlregex']);
533
+ var request_url = http_prefix + '://' + addr + request_uri;
534
+ // configure
535
+
536
+ if (payload && typeof(Cookies.get('CallPixels-vid')) !== 'undefined' && Cookies.get('CallPixels-vid') !== 'null') {
537
+ payload['visitor_id'] = Cookies.get('CallPixels-vid');
538
+ }
539
+
540
+ if (typeof(callbackFunctions) == "function") {
541
+ callbackFunctions = [callbackFunctions];
542
+ }
543
+
544
+ function ignored() {
545
+ }
546
+
547
+ function runCallbacks(response) {
548
+ for (var i in callbackFunctions) {
549
+ if (typeof callbackFunctions[i] == "function") callbackFunctions[i](response);
550
+ }
551
+ }
552
+
553
+ function forwardResponse() {
554
+ runCallbacks(xdr.responseText);
555
+ }
556
+
557
+ function sendXdm() {
558
+ // create the rpc request
559
+ var remote = http_prefix + '://' + addr + '/ie_provider';
560
+ var swf = http_prefix + '://' + addr + "/easyxdm.swf";
561
+ var rpc = eval('new window.easyXDM.Rpc({ remote: "' + remote + '", swf: "' + swf + '"},{remote: {request: {}}});');
562
+
563
+ rpc['request']({
564
+ url: ('/' + request_url.match(urlregex)[1]),
565
+ method: "POST",
566
+ data: payload
567
+ }, function (response) {
568
+ runCallbacks(response.data);
569
+ });
570
+ }
571
+
572
+ if (window.XDomainRequest) {
573
+ // IE >= 8
574
+ // 1. Create XDR object
575
+ var xdr = new XDomainRequest();
576
+
577
+ xdr.onload = forwardResponse; //alertLoaded;
578
+ xdr.onprogress = ignored;
579
+ xdr.onerror = ignored;
580
+ xdr.ontimeout = ignored;
581
+ xdr.timeout = 30000;
582
+
583
+ // 2. Open connection with server using GET method
584
+ if (payload) {
585
+ xdr.open("post", request_url);
586
+ xdr.send(self.buildPost(payload));
587
+ } else {
588
+ xdr.open("get", request_url);
589
+ xdr.send();
590
+ }
591
+
592
+ // 3. Send string data to server
593
+
594
+ } else if (Base.ieVersion() == 6 || Base.ieVersion() == 7) {
595
+ with_ie_scripts(sendXdm);
596
+ } else {
597
+ var request = new XMLHttpRequest;
598
+
599
+ if (payload) {
600
+ request.open("POST", request_url, false);
601
+ request.setRequestHeader("Content-Type", "application/json");
602
+ request.send(JSON.stringify(payload));
603
+ } else {
604
+ request.open("GET", request_url, false);
605
+ request.send();
606
+ }
607
+
608
+ runCallbacks(request.responseText);
609
+ }
610
+ };
611
+
612
+ function with_ie_scripts(callback) {
613
+ if (Retreaver['easyxdm_loaded']) {
614
+ callback();
615
+ } else {
616
+ self.loadScript(http_prefix + '://cdn.jsdelivr.net/easyxdm/2.4.17.1/easyXDM.min.js', function () {
617
+ self.loadScript(http_prefix + '://cdn.jsdelivr.net/easyxdm/2.4.17.1/json2.js', function () {
618
+ Retreaver['easyxdm_loaded'] = true;
619
+ callback();
620
+ });
621
+ });
622
+ }
623
+ };
624
+
625
+ self.buildPost = function (obj) {
626
+ var post_vars = '';
627
+ for (var k in obj) {
628
+ post_vars += k + "=" + obj[k] + '&';
629
+ }
630
+ return post_vars;
631
+ };
632
+
633
+ self.loadScript = function (scriptUrl, afterCallback) {
634
+ var firstScriptElement = document.getElementsByTagName('script')[0];
635
+ var scriptElement = document.createElement('script');
636
+ scriptElement.type = 'text/javascript';
637
+ scriptElement.async = false;
638
+ scriptElement.src = scriptUrl;
639
+
640
+ var ieLoadBugFix = function (scriptElement, callback) {
641
+ if (scriptElement.readyState == 'loaded' || scriptElement.readyState == 'complete') {
642
+ callback();
643
+ } else {
644
+ setTimeout(function () {
645
+ ieLoadBugFix(scriptElement, callback);
646
+ }, 100);
647
+ }
648
+ };
649
+
650
+ if (typeof afterCallback === "function") {
651
+ if (typeof scriptElement.addEventListener !== "undefined") {
652
+ scriptElement.addEventListener("load", afterCallback, false)
653
+ } else {
654
+ scriptElement.onreadystatechange = function () {
655
+ scriptElement.onreadystatechange = null;
656
+ ieLoadBugFix(scriptElement, afterCallback);
657
+ }
658
+ }
659
+ }
660
+ firstScriptElement.parentNode.insertBefore(scriptElement, firstScriptElement);
661
+ };
662
+ initialize(options);
663
+ self.config = config;
664
+ };
665
+ Request.connection = function () {
666
+ if (typeof window.Retreaver._connection === 'undefined') {
667
+ window.Retreaver._connection = new Retreaver.Base.Request({addr: 'api.retreaver.com', http_prefix: 'http', urlregex: "/\\/\\/[^\\/]*\\/(.*)/" });
668
+ }
669
+ return window.Retreaver._connection;
670
+ };
671
+ Retreaver.Base.Request = Request;
672
+ })();;(function () {
673
+ // Dependencies
674
+ var Base = Retreaver.Base;
675
+ var Cookies = Retreaver.Base.Cookies;
676
+ var Base64 = Retreaver.Base.Base64;
677
+ var Request = Retreaver.Base.Request;
678
+ /**
679
+ * @constructor
680
+ * @memberof Retreaver.Base
681
+ * @param {Object} options
682
+ * @param {String} options.campaign_key - The campaign uuid.
683
+ * @param {Object} options.tags - The tags to search for.
684
+ * @param {String} [options.default_number_replacement]
685
+ * @param {String} [options.message_replacement]
686
+ * @param {Array} [options.target_map]
687
+ * @param {Array} [options.target_map_cs]
688
+ * @param {String} [options.timer_offset]
689
+ * @param {String} [options.timer_offset_cs]
690
+ */
691
+ var RequestNumber = function (options) {
692
+
693
+ function initialize(options) {
694
+ // assert required keys and assign if valid
695
+ config = Base.assert_required_keys(options, 'campaign_key');
696
+ }
697
+
698
+ // INIT
699
+ var self = this;
700
+ var config = {};
701
+ var resource_url = '/api/v1/numbers?';
702
+
703
+ /**
704
+ * Request the number
705
+ * @memberOf Retreaver.Base.RequestNumber
706
+ * @function perform
707
+ * @instance
708
+ * @param {Function} callback - Callback to fire after request
709
+ */
710
+ self.perform = function (callback) {
711
+ if (typeof callback !== 'function') {
712
+ throw "ArgumentError: Expected to receive a callback function"
713
+ }
714
+ var request_url = resource_url + '&campaign_key=' + config['campaign_key'];
715
+
716
+ // append configs to url if provided
717
+ if (config['default_number_replacement']) {
718
+ request_url = request_url + "&default_number=" + config['default_number_replacement'];
719
+ }
720
+ if (config['message_replacement']) {
721
+ request_url = request_url + "&message=" + config['message_replacement'];
722
+ }
723
+
724
+ var body = new Object();
725
+
726
+ var uri = document.location.href;
727
+
728
+ body['u'] = Base64.encode(uri);
729
+ body['st'] = Base64.encode(tags_to_script_tags(config.number_matching_tags));
730
+
731
+ var ou = Cookies.get('CallPixels-ou');
732
+ if (getParts([document.location.href])['cpreset'] || !ou) {
733
+ Cookies.set('CallPixels-ou', body['u']);
734
+ } else {
735
+ body['ou'] = ou;
736
+ }
737
+
738
+ function sendGARequest(ga_acct, ga_cookies) {
739
+ body['ga'] = Base64.encode(ga_acct);
740
+ body['c'] = Base64.encode(JSON.stringify(ga_cookies));
741
+ Request.connection().getJSON(request_url, body, callback);
742
+ }
743
+
744
+
745
+ var ga_acct = 'FAILED';
746
+
747
+ try {
748
+ _gaq.push(function () {
749
+ ga_acct = eval('_gat._getTrackerByName()._getAccount()');
750
+
751
+ sendGARequest(ga_acct, getGACookies());
752
+ });
753
+
754
+ } catch (e) {
755
+
756
+ try {
757
+ ga(function (tracker) {
758
+ var clientId = tracker.get('clientId');
759
+ var allTrackers = eval('ga.getAll()');
760
+ ga_acct = allTrackers[0].get('trackingId');
761
+
762
+ var ga_cookies = {};
763
+ ga_cookies['__utma'] = clientId;
764
+ ga_cookies['mp'] = 'yes';
765
+ sendGARequest(ga_acct, ga_cookies);
766
+ });
767
+
768
+ } catch (f) {
769
+ // Post back with failed ga_acct.
770
+ Request.connection().getJSON(request_url, body, callback);
771
+ }
772
+ }
773
+
774
+ };
775
+
776
+ function getParts(urls) {
777
+ var all_parts = {};
778
+ for (var i = 0; i < urls.length; i++) {
779
+ var url_parts = getUrlParts(urls[i]);
780
+ for (var attrname in url_parts) {
781
+ all_parts[attrname] = url_parts[attrname];
782
+ }
783
+ }
784
+ return all_parts;
785
+ }
786
+
787
+ function getUrlParts(url) {
788
+ // url contains your data.
789
+ var objURL = new Object();
790
+ try {
791
+ //REGEX_1: /\?(.*)/
792
+ url = url.match(eval("/\\?(.*)/"))[0];
793
+ } catch (e) {
794
+ return objURL;
795
+ //Ignored
796
+ }
797
+
798
+ // Use the String::replace method to iterate over each
799
+ // name-value pair in the query string. Location.search
800
+ // gives us the query string (if it exists).
801
+ url.replace(
802
+ new RegExp("([^?=&]+)(=([^&]*))?", "g"),
803
+
804
+ // For each matched query string pair, add that
805
+ // pair to the URL struct using the pre-equals
806
+ // value as the key.
807
+ function ($0, $1, $2, $3) {
808
+ objURL[ $1.toLowerCase() ] = $3;
809
+ }
810
+ );
811
+
812
+ return objURL;
813
+ }
814
+
815
+ function getGACookies() {
816
+ var ga_cookies = ['__utma', '__utmb', '__utmc', '__utmz', '__utmv'];
817
+ var cookies = new Object();
818
+ for (var i in ga_cookies) {
819
+ var cookie_val = extractCookie(ga_cookies[i]);
820
+
821
+ if (cookie_val || i > 0) {
822
+ if (cookie_val) cookies[ga_cookies[i]] = cookie_val;
823
+ } else {
824
+ break;
825
+ }
826
+ }
827
+ return cookies;
828
+ }
829
+
830
+ function extractCookie(name) {
831
+ var regex = new RegExp(name + '=([^;]*)', 'g');
832
+ try {
833
+ return regex.exec(document.cookie)[1];
834
+ } catch (e) {
835
+ return false;
836
+ }
837
+ }
838
+
839
+ function findOne(all_parts, var_arr) {
840
+ for (var look_for in var_arr) {
841
+ for (var attrname in all_parts) {
842
+ if (attrname == var_arr[look_for]) {
843
+ return all_parts[attrname];
844
+ }
845
+ }
846
+ }
847
+ return false
848
+ }
849
+
850
+ initialize(options);
851
+ };
852
+
853
+ function tags_to_script_tags(tags) {
854
+ var script_tags = '';
855
+ for (var key in tags) {
856
+ var value = tags[key];
857
+ script_tags = script_tags + '&' + key + '=' + value
858
+ }
859
+ return script_tags;
860
+ }
861
+
862
+ Retreaver.Base.RequestNumber = RequestNumber;
863
+ })();
864
+
865
+ ;window.Retreaver.Cache = {};;(function () {
866
+ // Dependencies
867
+ var Base = Retreaver.Base;
868
+ /**
869
+ * @constructor
870
+ * @memberOf Retreaver
871
+ * @param {Object} attributes - Attributes
872
+ * @property {Object} attributes
873
+ * @property {Number} attributes.id - The CallPixels internal number ID.
874
+ * @property {String} attributes.formatted_number - Nationally formatted phone number.
875
+ * @property {String} attributes.number - E.164 formatted phone number.
876
+ * @property {String} attributes.plain_number - The unformatted phone number digits.
877
+ * @property {Boolean} attributes.target_open - Whether there is an open, available target.
878
+ */
879
+ Retreaver.Number = function (options) {
880
+
881
+ var self = this;
882
+ self.type = 'numbers';
883
+
884
+ function initialize(data) {
885
+ self.store(data);
886
+ self.set('is_active', 'true');
887
+ }
888
+
889
+ /**
890
+ * Add tags to a number.
891
+ * @memberOf Retreaver.Number
892
+ * @function add_tags
893
+ * @instance
894
+ * @param {Object} tags - A collection of tags {key: 'value', tag2: 'value2'}
895
+ * @param {Function} callback - Callback that will be fired after request.
896
+ * @throws Will throw an error if attempting to modify tags on a number that doesn't belong to a number pool
897
+ * with per-visitor numbers enabled.
898
+ */
899
+ self.add_tags = function (tags, callback) {
900
+ ensure_is_per_visitor();
901
+ self.post_data('numbers/tag', tags_payload(tags), callback);
902
+ };
903
+
904
+ /**
905
+ * Remove tags from a number.
906
+ * @memberOf Retreaver.Number
907
+ * @function remove_tags
908
+ * @instance
909
+ * @param {Object} tags - A collection of tags {key: 'value', tag2: 'value2'}
910
+ * @param {Function} callback - Callback that will be fired after request.
911
+ * @throws Will throw an error if attempting to modify tags on a number that doesn't belong to a number pool
912
+ * with per-visitor numbers enabled.
913
+ */
914
+ self.remove_tags = function (tags, callback) {
915
+ ensure_is_per_visitor();
916
+ self.post_data('numbers/untag', tags_payload(tags), callback);
917
+ };
918
+
919
+ /**
920
+ * Removes all tags with given keys from a number.
921
+ * @memberOf Retreaver.Number
922
+ * @function remove_tags_by_keys
923
+ * @instance
924
+ * @param {Array} keys - An array of keys to remove. eg: ['key1', 'key2']
925
+ * @param {Function} callback - Callback that will be fired after request.
926
+ * @throws Will throw an error if attempting to modify tags on a number that doesn't belong to a number pool
927
+ * with per-visitor numbers enabled.
928
+ */
929
+ self.remove_tags_by_keys = function (keys, callback) {
930
+ ensure_is_per_visitor();
931
+ if (typeof(keys) === 'string') keys = keys.split(',');
932
+ var payload = {
933
+ tag_keys: keys,
934
+ ids: [ get('id') ],
935
+ campaign_key: get('campaign_key')
936
+ };
937
+ self.post_data('numbers/untag/keys', payload, callback);
938
+ };
939
+
940
+ /**
941
+ * Clear all tags from a number.
942
+ * @memberOf Retreaver.Number
943
+ * @function clear_tags
944
+ * @instance
945
+ * @param {Function} callback - Callback that will be fired after request.
946
+ * @throws Will throw an error if attempting to modify tags on a number that doesn't belong to a number pool
947
+ * with per-visitor numbers enabled.
948
+ */
949
+ self.clear_tags = function (callback) {
950
+ ensure_is_per_visitor();
951
+ var payload = {
952
+ ids: [ get('id') ],
953
+ campaign_key: get('campaign_key'),
954
+ all: 'true'
955
+ };
956
+ self.post_data('numbers/untag', payload, callback);
957
+ };
958
+
959
+ /**
960
+ * Release number back to pool.
961
+ * @memberOf Retreaver.Number
962
+ * @function release
963
+ * @instance
964
+ */
965
+ self.release = function () {
966
+ self.set('is_active', 'false');
967
+ };
968
+
969
+ /**
970
+ * Start a call immediately by having a campaign target dial the visitor.
971
+ * @memberOf Retreaver.Number
972
+ * @function initiate_call
973
+ * @instance
974
+ * @param {String} dial - The number to call.
975
+ * @param {Object} payload - A collection of tags as key-value pairs and optional secure override properties.
976
+ * @param {string} [payload.target_map] - A string mapping a placeholder number to a phone number.
977
+ * @param {string} [payload.target_map_cs] - A SHA1 checksum of the target_map concatenated with your CallPixels API
978
+ * key.
979
+ * @param {number} [payload.timer_offset] - Number of seconds to offset the "connect" duration timers by.
980
+ * @param {string} [payload.timer_offset_cs] - An SHA1 checksum of the timer_offset concatenated with your
981
+ * CallPixels API key.
982
+ * @param {(string|number)} [payload.*] - Key value pairs treated as tags.
983
+ * @param {Function} callback - Callback that will be fired after request.
984
+ * @example
985
+ * number.initiate_call('4166686980', {company_name: 'CallPixels'}, function (call) {
986
+ * alert('Call started with UUID ' + call.uuid)
987
+ * });
988
+ */
989
+ self.initiate_call = function (dial, payload, callback) {
990
+ if (typeof(payload) === 'undefined') payload = {};
991
+ // assign dial to payload
992
+ payload.dial = dial;
993
+ // merge payload into payload
994
+ payload = Base.merge(self.get('id', 'campaign_key'), payload);
995
+ // post the payload
996
+ self.post_data('numbers/initiate_call', payload, callback);
997
+ };
998
+
999
+ function tags_payload(tags) {
1000
+ if (typeof(tags) === 'string') tags = Retreaver.Number.extract_tags_from_string(tags);
1001
+ return {
1002
+ tag_values: tags,
1003
+ ids: [ get('id') ],
1004
+ campaign_key: get('campaign_key')
1005
+ };
1006
+ }
1007
+
1008
+ function get(key) {
1009
+ return self.get(key);
1010
+ }
1011
+
1012
+ function ensure_is_per_visitor() {
1013
+ if (self.get('is_per_visitor') === false) {
1014
+ throw "Error: Tried to add tags to non per-visitor number.";
1015
+ }
1016
+ }
1017
+
1018
+ initialize(options);
1019
+ };
1020
+
1021
+ Retreaver.Number.extract_tags_from_string = function (tags) {
1022
+ var output = {};
1023
+ var tags = tags.split(",");
1024
+ for (var i = 0; i < tags.length; i++) {
1025
+ var tag = tags[i].split(":");
1026
+ output[tag[0]] = tag[1]
1027
+ }
1028
+ return output;
1029
+ };
1030
+
1031
+ Retreaver.Number.prototype = new Retreaver.Base.Model();
1032
+
1033
+ function ping_active_numbers(callback) {
1034
+ if (typeof(Retreaver.Base.Data._store) !== 'undefined') {
1035
+ // get numbers
1036
+ var numbers = Retreaver.Base.Data._store['numbers'];
1037
+ // for each number
1038
+ if (typeof(numbers) !== 'undefined') {
1039
+ // group number_ids by campaign_key
1040
+ var grouped = {};
1041
+ for (var primary_key in numbers) {
1042
+ var number = numbers[primary_key];
1043
+ if (number.is_active === 'true') {
1044
+ if (typeof(grouped[number.campaign_key]) === 'undefined') {
1045
+ grouped[number.campaign_key] = [];
1046
+ grouped[number.campaign_key]['ids'] = [];
1047
+ grouped[number.campaign_key]['hashes'] = [];
1048
+ }
1049
+ grouped[number.campaign_key]['ids'].push(number.id);
1050
+ grouped[number.campaign_key]['hashes'].push(number.id_checksum);
1051
+ }
1052
+ }
1053
+ // ping each group of number_ids
1054
+ for (var campaign_key in grouped) {
1055
+ var payload = {
1056
+ ids: grouped[campaign_key].ids,
1057
+ hashes: grouped[campaign_key].hashes
1058
+ };
1059
+ Retreaver.Base.Request.connection().postJSON('/api/v1/numbers/ping', payload, [Retreaver.Base.Model.update, callback], this);
1060
+ }
1061
+ }
1062
+ }
1063
+ // call recursively
1064
+ setTimeout(ping_active_numbers, 15000);
1065
+ }
1066
+
1067
+ // always ping active numbers
1068
+ ping_active_numbers();
1069
+
1070
+ })();;(function () {
1071
+ // Dependencies
1072
+ var RequestNumber = Retreaver.Base.RequestNumber;
1073
+ /**
1074
+ * @constructor
1075
+ * @memberOf Retreaver
1076
+ * @param {Object} options
1077
+ * @param {String} options.campaign_key - Campaign key
1078
+ * @example
1079
+ * var campaign = new Retreaver.Campaign({ campaign_key: '67d9fb1917ae8f4eaff36831b41788c3' });
1080
+ */
1081
+ var Campaign = function (options) {
1082
+
1083
+ function initialize(data) {
1084
+ // initialize data store
1085
+ self.store(data);
1086
+ }
1087
+
1088
+ var self = this;
1089
+ self.type = 'campaigns';
1090
+ self.primary_key('campaign_key');
1091
+ self.numbers = [];
1092
+
1093
+ /**
1094
+ * Fetch a campaign number.
1095
+ * @memberOf Retreaver.Campaign
1096
+ * @function request_number
1097
+ * @instance
1098
+ * @param {Object} tags - A collection of tags as key-value pairs. The number returned will match these tags.
1099
+ * @param {getNumberCallback} callback - Callback fired if the request completes successfully.
1100
+ * @param {Function} error_callback - Callback fired if the request raises an error.
1101
+ * @example
1102
+ * campaign.request_number({calling_about: 'support'}, function (number) {
1103
+ * alert(number.get('number'))
1104
+ * }, function(response){
1105
+ * alert('something went wrong: ' + response);
1106
+ * };
1107
+ */
1108
+ self.request_number = function (tags, callback, error_callback) {
1109
+ // if the first argument is a function, the user has decided to skip passing tags
1110
+ // therefore cascade the arguments upwards so that everything works as expected
1111
+ if (typeof(tags) === 'function') {
1112
+ // argument 3 becomes argument 2
1113
+ error_callback = callback;
1114
+ // argument 2 becomes argument 1
1115
+ callback = tags;
1116
+ // argument 1 becomes an empty tags object
1117
+ tags = {};
1118
+ }
1119
+ // assign the tags (this is important since it runs it through set_number_matching_tags)
1120
+ self.set('number_matching_tags', tags);
1121
+ // request the number
1122
+ new RequestNumber(self.get('campaign_key', 'number_matching_tags')).perform(function (data) {
1123
+ // did retreaver return a valid number?
1124
+ if (typeof(data) !== 'undefined' && typeof(data.number) !== 'undefined' && data.number !== '') {
1125
+ // initialize number
1126
+ var number = new Retreaver.Number(data.number);
1127
+ // call callback
1128
+ callback.apply(self, [number]);
1129
+ }
1130
+ // otherwise fire the error callback
1131
+ else if (typeof(error_callback) === 'function') {
1132
+ error_callback.apply(self, [data]);
1133
+ }
1134
+ });
1135
+ };
1136
+ /**
1137
+ * Retreaver.Campaign#request_number callback fired after the request completes.
1138
+ * @callback getNumberCallback
1139
+ * @param {Retreaver.Number} - The number that was returned
1140
+ */
1141
+
1142
+ self.numbers = function () {
1143
+ var output = [];
1144
+ if (typeof(Retreaver.Base.Data._store) !== 'undefined') {
1145
+ // get numbers
1146
+ var numbers = Retreaver.Base.Data._store['numbers'];
1147
+ // present?
1148
+ if (typeof(numbers) !== 'undefined') {
1149
+ // collect numbers matching this campaign
1150
+ for (var primary_key in numbers) {
1151
+ var number = numbers[primary_key];
1152
+ if (self.get('campaign_key') == number.campaign_key) {
1153
+ output.push(new Retreaver.Number(number));
1154
+ }
1155
+ }
1156
+ }
1157
+ }
1158
+ return output;
1159
+ };
1160
+
1161
+ self.set_number_matching_tags = function (tags) {
1162
+ if (typeof(tags) === 'string') {
1163
+ tags = Retreaver.Number.extract_tags_from_string(tags);
1164
+ }
1165
+ if (tags && (typeof tags === "object") && !(tags instanceof Array)) {
1166
+ return tags
1167
+ }
1168
+ else {
1169
+ throw "ArgumentError: Expected number_matching_tags to be an object. eg: {tag: 'value'}";
1170
+ }
1171
+ };
1172
+
1173
+ initialize(options);
1174
+ };
1175
+ Campaign.prototype = new Retreaver.Base.Model();
1176
+ Retreaver.Campaign = Campaign;
1177
+ })();;(function (context) {
1178
+ context.Callpixels = window.Retreaver;
1179
+ })(window);