callpixelsjs-rails 0.0.1

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