retreaverjs-rails 0.0.12 → 0.1.0

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 (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);