retreaverjs-rails 0.2.25 → 0.2.26

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/build.js +104 -0
  3. data/lib/retreaverjs/compile.rb +6 -5
  4. data/lib/retreaverjs/rails/version.rb +1 -1
  5. data/package.json +14 -27
  6. data/vendor/assets/javascripts/retreaver.js +25 -11
  7. data/vendor/assets/javascripts/retreaver.min.js +2 -2
  8. data/vendor/documentation/javascript/v1/Retreaver.Campaign.html +343 -282
  9. data/vendor/documentation/javascript/v1/Retreaver.Number.html +875 -713
  10. data/vendor/documentation/javascript/v1/Retreaver.html +161 -130
  11. data/vendor/documentation/javascript/v1/campaign.js.html +11 -87
  12. data/vendor/documentation/javascript/v1/fonts/OpenSans-Bold-webfont.eot +0 -0
  13. data/vendor/documentation/javascript/v1/fonts/OpenSans-Bold-webfont.svg +1830 -0
  14. data/vendor/documentation/javascript/v1/fonts/OpenSans-Bold-webfont.woff +0 -0
  15. data/vendor/documentation/javascript/v1/fonts/OpenSans-BoldItalic-webfont.eot +0 -0
  16. data/vendor/documentation/javascript/v1/fonts/OpenSans-BoldItalic-webfont.svg +1830 -0
  17. data/vendor/documentation/javascript/v1/fonts/OpenSans-BoldItalic-webfont.woff +0 -0
  18. data/vendor/documentation/javascript/v1/fonts/OpenSans-Italic-webfont.eot +0 -0
  19. data/vendor/documentation/javascript/v1/fonts/OpenSans-Italic-webfont.svg +1830 -0
  20. data/vendor/documentation/javascript/v1/fonts/OpenSans-Italic-webfont.woff +0 -0
  21. data/vendor/documentation/javascript/v1/fonts/OpenSans-Light-webfont.eot +0 -0
  22. data/vendor/documentation/javascript/v1/fonts/OpenSans-Light-webfont.svg +1831 -0
  23. data/vendor/documentation/javascript/v1/fonts/OpenSans-Light-webfont.woff +0 -0
  24. data/vendor/documentation/javascript/v1/fonts/OpenSans-LightItalic-webfont.eot +0 -0
  25. data/vendor/documentation/javascript/v1/fonts/OpenSans-LightItalic-webfont.svg +1835 -0
  26. data/vendor/documentation/javascript/v1/fonts/OpenSans-LightItalic-webfont.woff +0 -0
  27. data/vendor/documentation/javascript/v1/fonts/OpenSans-Regular-webfont.eot +0 -0
  28. data/vendor/documentation/javascript/v1/fonts/OpenSans-Regular-webfont.svg +1831 -0
  29. data/vendor/documentation/javascript/v1/fonts/OpenSans-Regular-webfont.woff +0 -0
  30. data/vendor/documentation/javascript/v1/global.html +123 -93
  31. data/vendor/documentation/javascript/v1/index.html +10 -8
  32. data/vendor/documentation/javascript/v1/number.js.html +1 -1
  33. data/vendor/documentation/javascript/v1/retreaver.js.html +8 -7
  34. data/vendor/documentation/javascript/v1/retreaver_campaign.js.html +400 -0
  35. data/vendor/documentation/javascript/v1/retreaver_number.js.html +275 -0
  36. data/vendor/documentation/javascript/v1/scripts/linenumber.js +20 -12
  37. data/vendor/documentation/javascript/v1/styles/jsdoc-default.css +201 -133
  38. data/vendor/documentation/javascript/v1/styles/prettify-tomorrow.css +1 -1
  39. data/vendor/documentation/javascript/{dev → v2}/Retreaver.Campaign.html +3 -3
  40. data/vendor/documentation/javascript/{dev → v2}/Retreaver.Number.html +1 -1
  41. data/vendor/documentation/javascript/{dev → v2}/Retreaver.html +2 -2
  42. data/vendor/documentation/javascript/{dev → v2}/campaign.js.html +39 -48
  43. data/vendor/documentation/javascript/{dev → v2}/global.html +2 -2
  44. data/vendor/documentation/javascript/{dev → v2}/index.html +1 -1
  45. data/vendor/documentation/javascript/{dev → v2}/number.js.html +1 -1
  46. data/vendor/documentation/javascript/{dev → v2}/retreaver.js.html +2 -2
  47. metadata +42 -24
  48. data/Gruntfile.js +0 -50
  49. /data/vendor/documentation/javascript/{dev → v2}/scripts/linenumber.js +0 -0
  50. /data/vendor/documentation/javascript/{dev → v2}/scripts/prettify/Apache-License-2.0.txt +0 -0
  51. /data/vendor/documentation/javascript/{dev → v2}/scripts/prettify/lang-css.js +0 -0
  52. /data/vendor/documentation/javascript/{dev → v2}/scripts/prettify/prettify.js +0 -0
  53. /data/vendor/documentation/javascript/{dev → v2}/styles/jsdoc-default.css +0 -0
  54. /data/vendor/documentation/javascript/{dev → v2}/styles/prettify-jsdoc.css +0 -0
  55. /data/vendor/documentation/javascript/{dev → v2}/styles/prettify-tomorrow.css +0 -0
@@ -0,0 +1,400 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>JSDoc: Source: retreaver/campaign.js</title>
6
+
7
+ <script src="scripts/prettify/prettify.js"> </script>
8
+ <script src="scripts/prettify/lang-css.js"> </script>
9
+ <!--[if lt IE 9]>
10
+ <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
11
+ <![endif]-->
12
+ <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
13
+ <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
14
+ </head>
15
+
16
+ <body>
17
+
18
+ <div id="main">
19
+
20
+ <h1 class="page-title">Source: retreaver/campaign.js</h1>
21
+
22
+
23
+
24
+
25
+
26
+
27
+ <section>
28
+ <article>
29
+ <pre class="prettyprint source linenums"><code>(function() {
30
+ // Dependencies
31
+ var RequestNumber = Retreaver.Base.RequestNumber;
32
+ /**
33
+ * @constructor
34
+ * @memberOf Retreaver
35
+ * @param {Object} options
36
+ * @param {String} options.campaign_key - Campaign key
37
+ * @example
38
+ * var campaign = new Retreaver.Campaign({ campaign_key: '67d9fb1917ae8f4eaff36831b41788c3' });
39
+ */
40
+ var Campaign = function(options) {
41
+
42
+ function initialize(data) {
43
+ // initialize data store
44
+ self.store(data);
45
+ }
46
+
47
+ function find_and_replace_number(replacement_numbers) {
48
+ for (var i = 0; i &lt; replacement_numbers.length; i++) {
49
+ var rn = replacement_numbers[i];
50
+
51
+ Retreaver.Vendor.findAndReplaceDOMText(document.getElementsByTagName('body')[0], {
52
+ find: rn['find'],
53
+ replace: rn['replace_with']
54
+ });
55
+
56
+ var links = document.getElementsByTagName('a');
57
+ for (var j = 0; j &lt; links.length; j++) {
58
+ var link = links[j];
59
+ var href = link.getAttribute('href');
60
+
61
+ if (href !== null) {
62
+ var match = href.match(/^(tel:|clk[a-z]\/tel\/)(.*)/);
63
+ if (match &amp;&amp; match[2] === rn['find']) {
64
+ link.setAttribute('href', match[1] + rn['replace_with']);
65
+ }
66
+ }
67
+ }
68
+ }
69
+ }
70
+
71
+ function get_integration_config(number, integration) {
72
+ const integrations = number.get("integrations");
73
+
74
+ if (typeof(integrations) != 'object') {
75
+ return;
76
+ }
77
+
78
+ const integrationConfig = integrations[integration];
79
+ if (typeof(integrationConfig) == 'undefined') {
80
+ return;
81
+ }
82
+
83
+ return integrationConfig;
84
+ }
85
+
86
+ function handle_google_analytics_integration(number) {
87
+ googleAnalyticsConfig = get_integration_config(number, "google_analytics");
88
+ if (typeof(googleAnalyticsConfig) == "undefined") {
89
+ return;
90
+ }
91
+
92
+ const obtainGoogleAnalyticsCookies = new Promise(function(resolve) {
93
+ const googleAnalyticsInterval = setInterval(function() {
94
+ const gaSessionIdPattern = /_ga_[^=]+=([^;]*)/;
95
+ const gaSessionMatch = document.cookie.match(gaSessionIdPattern);
96
+ const gaSessionMatched = gaSessionMatch &amp;&amp; gaSessionMatch[1];
97
+
98
+ const gaClientIdPattern = /_ga=([^;]*)/;
99
+ const gaClientMatch = document.cookie.match(gaClientIdPattern);
100
+ const gaClientMatched = gaClientMatch &amp;&amp; gaClientMatch[1];
101
+
102
+ if (gaSessionMatched &amp;&amp; gaClientMatched) {
103
+ resolve({
104
+ gaSessionId: gaSessionMatched,
105
+ gaClientId: gaClientMatched,
106
+ });
107
+
108
+ clearInterval(googleAnalyticsInterval);
109
+ }
110
+ }, googleAnalyticsConfig["checkIntervalMs"]); // Try to get the Google Analytics session data every X milliseconds
111
+ })
112
+
113
+ obtainGoogleAnalyticsCookies.then(function (sessionData) {
114
+ number.replace_tags({
115
+ ga_session_id: sessionData.gaSessionId,
116
+ ga_client_id: sessionData.gaClientId,
117
+ });
118
+ });
119
+ }
120
+
121
+ function handle_true_call_integration(number) {
122
+ const trueCallConfig = get_integration_config(number, "truecall.com");
123
+
124
+ if (typeof(trueCallConfig) == "undefined") {
125
+ return;
126
+ }
127
+
128
+ // Load the trueCall script into the page it it's missing
129
+ if(!document.getElementById("__tc_script") || !window.TrueCall) {
130
+ (function () {
131
+ const trueCallScriptTag = document.createElement('script');
132
+ trueCallScriptTag.type = 'text/javascript';
133
+ trueCallScriptTag.async = true;
134
+ trueCallScriptTag.defer = true;
135
+ trueCallScriptTag.dataset.campaign_uuid = trueCallConfig["tcCampaignUuid"];
136
+ trueCallScriptTag.dataset.use_set_did = "1";
137
+ trueCallScriptTag.id = "__tc_script"
138
+ trueCallScriptTag.src = trueCallConfig["scriptSrc"];
139
+ (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(trueCallScriptTag);
140
+ })();
141
+ }
142
+
143
+ const trueCallInterval = setInterval(function() {
144
+ if (window.TrueCall) {
145
+ window.TrueCall.setDID(number.get("number")).then(function() {
146
+ clearInterval(trueCallInterval);
147
+ return window.TrueCall.getIdAsync();
148
+ }).then(function(trueCallId) {
149
+ const tags = {};
150
+ tags[trueCallConfig["tagName"]] = trueCallId;
151
+ number.replace_tags(tags);
152
+ });
153
+ }
154
+ }, trueCallConfig["checkIntervalMs"]);
155
+ }
156
+
157
+ function handle_red_track_integration(number) {
158
+ const redTrackConfig = get_integration_config(number, "red_track");
159
+
160
+ if (typeof(redTrackConfig) == "undefined") {
161
+ return;
162
+ }
163
+
164
+ function getRedTrackClickID(name) {
165
+ const value = '; ' + document.cookie;
166
+ const parts = value.split('; ' + name + '=');
167
+ if (parts.length == 2) return parts.pop().split(';').shift();
168
+ }
169
+
170
+ const obtainRedTrackClickID = new Promise( function (resolve) {
171
+ const myInterval = setInterval(function () {
172
+ const redTrackClickID = getRedTrackClickID('rtkclickid-store');
173
+ if (redTrackClickID) {
174
+ resolve(redTrackClickID);
175
+ clearInterval(myInterval);
176
+ }
177
+ }, redTrackConfig["checkIntervalMs"]);
178
+ });
179
+
180
+ obtainRedTrackClickID.then(function (redTrackClickID) {
181
+ const tags = {};
182
+ tags[redTrackConfig["tagName"]] = redTrackClickID;
183
+ number.replace_tags(tags);
184
+ });
185
+
186
+ }
187
+
188
+ function handle_click_flare_integration(number) {
189
+ const clickFlareConfig = get_integration_config(number, "click_flare");
190
+
191
+ if (typeof(clickFlareConfig) == "undefined") {
192
+ return;
193
+ }
194
+
195
+ const getClickFlareClickID = function() {
196
+ if (window.clickflare &amp;&amp; window.clickflare.data &amp;&amp; window.clickflare.data.event_tokens) {
197
+ // ClickFlare has this cv_click_id which is an id that when present tracks the user better and takes
198
+ // precedent over cf_click_id.
199
+ return (window.clickflare.data.event_tokens.cv_click_id || window.clickflare.data.event_tokens.cf_click_id);
200
+ }
201
+ };
202
+
203
+ const obtainClickFlareClickID = new Promise(function (resolve) {
204
+ const myInterval = setInterval(function () {
205
+ const clickFlareClickID = getClickFlareClickID();
206
+ if (clickFlareClickID) {
207
+ resolve(clickFlareClickID);
208
+ clearInterval(myInterval);
209
+ }
210
+ }, clickFlareConfig["checkIntervalMs"]);
211
+ });
212
+
213
+ obtainClickFlareClickID.then(function (clickFlareClickID) {
214
+ const tags = {};
215
+ tags[clickFlareConfig["tagName"]] = clickFlareClickID;
216
+ number.replace_tags(tags);
217
+ });
218
+
219
+ }
220
+
221
+ var self = this;
222
+ self.type = 'campaigns';
223
+ self.primary_key('campaign_key');
224
+ self.numbers = [];
225
+
226
+ /**
227
+ * Fetch a campaign number.
228
+ * @memberOf Retreaver.Campaign
229
+ * @function request_number
230
+ * @instance
231
+ * @param {Object} [tags] - A collection of tags as key-value pairs. The number returned will match these tags.
232
+ * @param {getNumberCallback} callback - Callback fired if the request completes successfully.
233
+ * @param {Function} error_callback - Callback fired if the request raises an error.
234
+ * @example
235
+ * campaign.request_number({calling_about: 'support'}, function (number) {
236
+ * alert(number.get('number'))
237
+ * }, function(response){
238
+ * alert('something went wrong: ' + response);
239
+ * };
240
+ */
241
+ self.request_number = function(tags, callback, error_callback) {
242
+ // if the first argument is a function, the user has decided to skip passing tags
243
+ // therefore cascade the arguments upwards so that everything works as expected
244
+ if (typeof(tags) === 'function') {
245
+ // argument 3 becomes argument 2
246
+ error_callback = callback;
247
+ // argument 2 becomes argument 1
248
+ callback = tags;
249
+ // argument 1 becomes an empty tags object
250
+ tags = {};
251
+ }
252
+
253
+ if (typeof callback === 'undefined') {
254
+ callback = function () {
255
+ };
256
+ }
257
+
258
+ if (typeof tags === 'undefined') {
259
+ tags = {};
260
+ }
261
+
262
+ // assign the tags (this is important since it runs it through set_number_matching_tags)
263
+ self.set('number_matching_tags', tags);
264
+ // request the number
265
+ new RequestNumber(self.get('campaign_key', 'number_matching_tags')).perform(function(data) {
266
+ // did retreaver return a valid number?
267
+ if (typeof(data) !== 'undefined' &amp;&amp; typeof(data.number) !== 'undefined' &amp;&amp; data.number !== '') {
268
+ // initialize number
269
+ var number = new Retreaver.Number(data.number);
270
+
271
+ try {
272
+ handle_true_call_integration(number);
273
+ } catch (e) {
274
+ console.error("Could not integrate with truecall.com, ", e);
275
+ }
276
+
277
+ try {
278
+ handle_red_track_integration(number);
279
+ } catch (e) {
280
+ console.error("Could not integrate with Red Track, ", e);
281
+ }
282
+
283
+ try {
284
+ handle_google_analytics_integration(number);
285
+ } catch (e) {
286
+ console.error("Could not integrate with google analytics, ", e);
287
+ }
288
+
289
+ try {
290
+ handle_click_flare_integration(number);
291
+ } catch (e) {
292
+ console.error("Could not integrate with click flare, ", e);
293
+ }
294
+
295
+ // if there is a replacement in the response, replace all occurrences
296
+ // of that number on the page with the retreaver number
297
+ if (typeof(data.number.replacement_numbers) !== 'undefined') {
298
+ find_and_replace_number(data.number.replacement_numbers);
299
+ }
300
+ // call callback
301
+ callback.apply(self, [number]);
302
+ }
303
+ // otherwise fire the error callback
304
+ else if (typeof(error_callback) === 'function') {
305
+ error_callback.apply(self, [data]);
306
+ }
307
+ });
308
+ };
309
+
310
+ /**
311
+ * Auto replace all numbers on page according to campaign settings
312
+ * Calls campaign.request_number
313
+ * @memberOf Retreaver.Campaign
314
+ * @function auto_replace_numbers
315
+ * @instance
316
+ * @param {Object} [tags] - A collection of tags as key-value pairs. The number returned will match these tags.
317
+ * @param {getNumberCallback} callback - Callback fired if the request completes successfully.
318
+ * @param {Function} error_callback - Callback fired if the request raises an error.
319
+ * @example
320
+ * campaign.auto_replace_numbers({calling_about: 'support'}, function (number) {
321
+ * alert(number.get('number'))
322
+ * }, function(response){
323
+ * alert('something went wrong: ' + response);
324
+ * };
325
+ */
326
+ self.auto_replace_numbers = function(tags, callback, error_callback) {
327
+ if (typeof callback === 'undefined') {
328
+ callback = function() {};
329
+ }
330
+
331
+ if (typeof error_callback === 'undefined') {
332
+ error_callback = function() {};
333
+ }
334
+ self.request_number(tags, callback, error_callback);
335
+ };
336
+
337
+ /**
338
+ * Retreaver.Campaign#request_number callback fired after the request completes.
339
+ * @callback getNumberCallback
340
+ * @param {Retreaver.Number} - The number that was returned
341
+ */
342
+
343
+ self.numbers = function() {
344
+ var output = [];
345
+ if (typeof(Retreaver.Base.Data._store) !== 'undefined') {
346
+ // get numbers
347
+ var numbers = Retreaver.Base.Data._store['numbers'];
348
+ // present?
349
+ if (typeof(numbers) !== 'undefined') {
350
+ // collect numbers matching this campaign
351
+ for (var primary_key in numbers) {
352
+ var number = numbers[primary_key];
353
+ if (self.get('campaign_key') == number.campaign_key) {
354
+ output.push(new Retreaver.Number(number));
355
+ }
356
+ }
357
+ }
358
+ }
359
+ return output;
360
+ };
361
+
362
+ self.set_number_matching_tags = function(tags) {
363
+ if (typeof(tags) === 'string') {
364
+ tags = Retreaver.Number.extract_tags_from_string(tags);
365
+ }
366
+ if (tags &amp;&amp; (typeof tags === "object") &amp;&amp; !(tags instanceof Array)) {
367
+ return tags
368
+ } else {
369
+ throw "ArgumentError: Expected number_matching_tags to be an object. eg: {tag: 'value'}";
370
+ }
371
+ };
372
+
373
+ initialize(options);
374
+ };
375
+ Campaign.prototype = new Retreaver.Base.Model();
376
+ Retreaver.Campaign = Campaign;
377
+ })();
378
+ </code></pre>
379
+ </article>
380
+ </section>
381
+
382
+
383
+
384
+
385
+ </div>
386
+
387
+ <nav>
388
+ <h2><a href="index.html">Home</a></h2><h3>Namespaces</h3><ul><li><a href="Retreaver.html">Retreaver</a></li></ul><h3>Classes</h3><ul><li><a href="Retreaver.Campaign.html">Campaign</a></li><li><a href="Retreaver.Number.html">Number</a></li></ul><h3><a href="global.html">Global</a></h3>
389
+ </nav>
390
+
391
+ <br class="clear">
392
+
393
+ <footer>
394
+ Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Aug 23 2025 21:55:04 GMT+0300 (Eastern European Summer Time)
395
+ </footer>
396
+
397
+ <script> prettyPrint(); </script>
398
+ <script src="scripts/linenumber.js"> </script>
399
+ </body>
400
+ </html>
@@ -0,0 +1,275 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>JSDoc: Source: retreaver/number.js</title>
6
+
7
+ <script src="scripts/prettify/prettify.js"> </script>
8
+ <script src="scripts/prettify/lang-css.js"> </script>
9
+ <!--[if lt IE 9]>
10
+ <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
11
+ <![endif]-->
12
+ <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
13
+ <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
14
+ </head>
15
+
16
+ <body>
17
+
18
+ <div id="main">
19
+
20
+ <h1 class="page-title">Source: retreaver/number.js</h1>
21
+
22
+
23
+
24
+
25
+
26
+
27
+ <section>
28
+ <article>
29
+ <pre class="prettyprint source linenums"><code>(function () {
30
+ // Dependencies
31
+ var Base = Retreaver.Base;
32
+ /**
33
+ * @constructor
34
+ * @memberOf Retreaver
35
+ * @param {Object} attributes - Attributes
36
+ * @property {Object} attributes
37
+ * @property {Number} attributes.id - The CallPixels internal number ID.
38
+ * @property {String} attributes.formatted_number - Nationally formatted phone number.
39
+ * @property {String} attributes.number - E.164 formatted phone number.
40
+ * @property {String} attributes.extension - The extension number.
41
+ * @property {String} attributes.plain_number - The unformatted phone number digits.
42
+ * @property {String} attributes.number_extension - The phone number digits with extension.
43
+ * @property {Boolean} attributes.target_open - Whether there is an open, available target.
44
+
45
+ */
46
+ Retreaver.Number = function (options) {
47
+
48
+ var self = this;
49
+ self.type = 'numbers';
50
+
51
+ function initialize(data) {
52
+ self.store(data);
53
+ self.set('is_active', 'true');
54
+ }
55
+
56
+ /**
57
+ * Add tags to a number.
58
+ * @memberOf Retreaver.Number
59
+ * @function add_tags
60
+ * @instance
61
+ * @param {Object} tags - A collection of tags {key: 'value', tag2: 'value2'}
62
+ * @param {Function} callback - Callback that will be fired after request.
63
+ * @throws Will throw an error if attempting to modify tags on a number that doesn't belong to a number pool
64
+ * with per-visitor numbers enabled.
65
+ */
66
+ self.add_tags = function (tags, callback) {
67
+ ensure_is_per_visitor();
68
+ self.post_data('numbers/tag', tags_payload(tags), callback);
69
+ };
70
+
71
+ /**
72
+ * Replace tags on a number. Any tags that already exist on the number that match the given keys will be
73
+ * removed. This can be used instead of calling remove_tags and then add_tags.
74
+ * @memberOf Retreaver.Number
75
+ * @function replace_tags
76
+ * @instance
77
+ * @param {Object} tags - A collection of tags {key: 'value', tag2: 'value2'}
78
+ * @param {Function} callback - Callback that will be fired after request.
79
+ * @throws Will throw an error if attempting to modify tags on a number that doesn't belong to a number pool
80
+ * with per-visitor numbers enabled.
81
+ */
82
+ self.replace_tags = function (tags, callback) {
83
+ ensure_is_per_visitor();
84
+ self.post_data('numbers/replace_tags', tags_payload(tags), callback);
85
+ };
86
+
87
+ /**
88
+ * Remove tags from a number.
89
+ * @memberOf Retreaver.Number
90
+ * @function remove_tags
91
+ * @instance
92
+ * @param {Object} tags - A collection of tags {key: 'value', tag2: 'value2'}
93
+ * @param {Function} callback - Callback that will be fired after request.
94
+ * @throws Will throw an error if attempting to modify tags on a number that doesn't belong to a number pool
95
+ * with per-visitor numbers enabled.
96
+ */
97
+ self.remove_tags = function (tags, callback) {
98
+ ensure_is_per_visitor();
99
+ self.post_data('numbers/untag', tags_payload(tags), callback);
100
+ };
101
+
102
+ /**
103
+ * Removes all tags with given keys from a number.
104
+ * @memberOf Retreaver.Number
105
+ * @function remove_tags_by_keys
106
+ * @instance
107
+ * @param {Array} keys - An array of keys to remove. eg: ['key1', 'key2']
108
+ * @param {Function} callback - Callback that will be fired after request.
109
+ * @throws Will throw an error if attempting to modify tags on a number that doesn't belong to a number pool
110
+ * with per-visitor numbers enabled.
111
+ */
112
+ self.remove_tags_by_keys = function (keys, callback) {
113
+ ensure_is_per_visitor();
114
+ if (typeof(keys) === 'string') keys = keys.split(',');
115
+ var payload = {
116
+ tag_keys: keys,
117
+ ids: [ get('id') ],
118
+ campaign_key: get('campaign_key')
119
+ };
120
+ self.post_data('numbers/untag/keys', payload, callback);
121
+ };
122
+
123
+ /**
124
+ * Clear all tags from a number.
125
+ * @memberOf Retreaver.Number
126
+ * @function clear_tags
127
+ * @instance
128
+ * @param {Function} callback - Callback that will be fired after request.
129
+ * @throws Will throw an error if attempting to modify tags on a number that doesn't belong to a number pool
130
+ * with per-visitor numbers enabled.
131
+ */
132
+ self.clear_tags = function (callback) {
133
+ ensure_is_per_visitor();
134
+ var payload = {
135
+ ids: [ get('id') ],
136
+ campaign_key: get('campaign_key'),
137
+ all: 'true'
138
+ };
139
+ self.post_data('numbers/untag', payload, callback);
140
+ };
141
+
142
+ /**
143
+ * Release number back to pool.
144
+ * @memberOf Retreaver.Number
145
+ * @function release
146
+ * @instance
147
+ */
148
+ self.release = function () {
149
+ self.set('is_active', 'false');
150
+ };
151
+
152
+ /**
153
+ * Start a call immediately by having a campaign target dial the visitor.
154
+ * @memberOf Retreaver.Number
155
+ * @function initiate_call
156
+ * @instance
157
+ * @param {String} dial - The number to call.
158
+ * @param {Object} payload - A collection of tags as key-value pairs and optional secure override properties.
159
+ * @param {string} [payload.target_map] - A string mapping a placeholder number to a phone number.
160
+ * @param {string} [payload.target_map_cs] - A SHA1 checksum of the target_map concatenated with your CallPixels API
161
+ * key.
162
+ * @param {number} [payload.timer_offset] - Number of seconds to offset the "connect" duration timers by.
163
+ * @param {string} [payload.timer_offset_cs] - An SHA1 checksum of the timer_offset concatenated with your
164
+ * CallPixels API key.
165
+ * @param {(string|number)} [payload.*] - Key value pairs treated as tags.
166
+ * @param {Function} callback - Callback that will be fired after request.
167
+ * @example
168
+ * number.initiate_call('4166686980', {company_name: 'CallPixels'}, function (call) {
169
+ * alert('Call started with UUID ' + call.uuid)
170
+ * });
171
+ */
172
+ self.initiate_call = function (dial, payload, callback) {
173
+ if (typeof(payload) === 'undefined') payload = {};
174
+ // assign dial to payload
175
+ payload.dial = dial;
176
+ // merge payload into payload
177
+ payload = Base.merge(self.get('id', 'campaign_key'), payload);
178
+ // post the payload
179
+ self.post_data('numbers/initiate_call', payload, callback);
180
+ };
181
+
182
+ function tags_payload(tags) {
183
+ if (typeof(tags) === 'string') tags = Retreaver.Number.extract_tags_from_string(tags);
184
+ return {
185
+ tag_values: tags,
186
+ ids: [ get('id') ],
187
+ campaign_key: get('campaign_key')
188
+ };
189
+ }
190
+
191
+ function get(key) {
192
+ return self.get(key);
193
+ }
194
+
195
+ function ensure_is_per_visitor() {
196
+ if (self.get('is_per_visitor') === false) {
197
+ throw "Error: Tried to add tags to non per-visitor number.";
198
+ }
199
+ }
200
+
201
+ initialize(options);
202
+ };
203
+
204
+ Retreaver.Number.extract_tags_from_string = function (tags) {
205
+ var output = {};
206
+ var tags = tags.split(",");
207
+ for (var i = 0; i &lt; tags.length; i++) {
208
+ var tag = tags[i].split(":");
209
+ output[tag[0]] = tag[1]
210
+ }
211
+ return output;
212
+ };
213
+
214
+ Retreaver.Number.prototype = new Retreaver.Base.Model();
215
+
216
+ function ping_active_numbers(callback) {
217
+ if (typeof(Retreaver.Base.Data._store) !== 'undefined') {
218
+ // get numbers
219
+ var numbers = Retreaver.Base.Data._store['numbers'];
220
+ // for each number
221
+ if (typeof(numbers) !== 'undefined') {
222
+ // group number_ids by campaign_key
223
+ var grouped = {};
224
+ for (var primary_key in numbers) {
225
+ var number = numbers[primary_key];
226
+ if (number.is_active === 'true') {
227
+ if (typeof(grouped[number.campaign_key]) === 'undefined') {
228
+ grouped[number.campaign_key] = [];
229
+ grouped[number.campaign_key]['ids'] = [];
230
+ grouped[number.campaign_key]['hashes'] = [];
231
+ }
232
+ grouped[number.campaign_key]['ids'].push(number.id);
233
+ grouped[number.campaign_key]['hashes'].push(number.id_checksum);
234
+ }
235
+ }
236
+ // ping each group of number_ids
237
+ for (var campaign_key in grouped) {
238
+ var payload = {
239
+ ids: grouped[campaign_key].ids,
240
+ hashes: grouped[campaign_key].hashes
241
+ };
242
+ Retreaver.Base.Request.connection().postJSON('/api/v1/numbers/ping', payload, [Retreaver.Base.Model.update, callback], this);
243
+ }
244
+ }
245
+ }
246
+ // call recursively
247
+ setTimeout(ping_active_numbers, 15000);
248
+ }
249
+
250
+ // always ping active numbers
251
+ ping_active_numbers();
252
+
253
+ })();</code></pre>
254
+ </article>
255
+ </section>
256
+
257
+
258
+
259
+
260
+ </div>
261
+
262
+ <nav>
263
+ <h2><a href="index.html">Home</a></h2><h3>Namespaces</h3><ul><li><a href="Retreaver.html">Retreaver</a></li></ul><h3>Classes</h3><ul><li><a href="Retreaver.Campaign.html">Campaign</a></li><li><a href="Retreaver.Number.html">Number</a></li></ul><h3><a href="global.html">Global</a></h3>
264
+ </nav>
265
+
266
+ <br class="clear">
267
+
268
+ <footer>
269
+ Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Aug 23 2025 21:55:04 GMT+0300 (Eastern European Summer Time)
270
+ </footer>
271
+
272
+ <script> prettyPrint(); </script>
273
+ <script src="scripts/linenumber.js"> </script>
274
+ </body>
275
+ </html>