callpixelsjs-rails 0.0.1

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