1var Textline = {}; 2 3Textline.Widget = function(phone_number, user_opts) { 4 var on_doc_ready, 5 widget; 6 7 this.animating = false; 8 this.visible = false; 9 this.phone_number = phone_number.replace(/[^\d+]/gi, ''); 10 11 user_opts = user_opts || {}; 12 this.setupWidgetOpts(user_opts); 13 this.createWidget(); 14 15 if (location.search == '?textline_debug') { 16 this.generateDebugConsole(); 17 } 18 if ((!this.detectPhone() && !user_opts.force_display) && !(location.search == "?force_textline" || this.debug_console)) { 19 return; 20 } 21 22 widget = this; 23 on_doc_ready = function() { 24 document.getElementsByTagName('body')[0].appendChild(widget.widget); 25 widget.position(); 26 widget.setupScrollHandling(); 27 } 28 if (document.addEventListener) { 29 document.addEventListener('DOMContentLoaded', on_doc_ready, false); 30 } 31}; 32 33 34Textline.Widget.prototype.setupWidgetOpts = function(user_opts) { 35 this.opts = {}; 36 37 this.opts.background_color = user_opts.background_color || '#0F77BA'; 38 this.opts.font_color = user_opts.font_color || '#FFFFFF'; 39 this.opts.height = user_opts.height || 50; 40 this.opts.font_family = user_opts.font_family || 'Arial'; 41 this.opts.font_size = user_opts.font_size || '18px'; 42 this.opts.prefill = user_opts.prefill; 43 this.opts.text = user_opts.text || 'Text Us'; 44 45 this.opts.scroll_target = user_opts.scroll_target; 46 this.opts.scroll_threshold = user_opts.scroll_threshold; 47 this.opts.bottom_offset = user_opts.bottom_offset || 30; 48 49 this.opts.widget_id = user_opts.id || 'textline-widget'; 50}; 51 52 53Textline.Widget.prototype.createWidget = function() { 54 var ref, 55 tail; 56 57 this.widget = document.createElement('a'); 58 ref = 'sms:' + this.phone_number 59 if (this.opts.prefill) { 60 ref += ';?&body=' + encodeURIComponent(this.opts.prefill); 61 } 62 this.widget.setAttribute('href', ref); 63 this.widget.setAttribute('target', '_blank'); 64 this.widget.setAttribute('id', this.opts.widget_id); 65 66 this.widget.style.textDecoration = 'none' 67 this.widget.style.display = 'block' 68 this.widget.style.backgroundColor = this.opts.background_color; 69 this.widget.style.whiteSpace = 'nowrap'; 70 this.widget.style.padding = ((this.opts.height-20)/2)+'px 35px 0px 53px'; 71 this.widget.style.borderRadius = '4px'; 72 73 this.widget.style.position = 'fixed'; 74 this.widget.style.left = '25%'; 75 this.widget.style.zIndex = '1000'; 76 77 this.widget.style.transition = 'initial'; 78 79 this.content = document.createElement('div'); 80 this.content.style.height = this.opts.height - (this.opts.height - 20)/2 + 'px'; 81 this.content.style.lineHeight = 'normal'; 82 this.widget.appendChild(this.content); 83 84 tail = document.createElement('div'); 85 tail.style.borderTop = '12px solid ' + this.opts.background_color; 86 tail.style.borderLeft = tail.style.borderRight = '12px solid transparent'; 87 tail.style.position = 'absolute'; 88 tail.style.bottom = '-12px'; 89 tail.style.left = '50%'; 90 tail.style.marginLeft = '-12px'; 91 this.widget.appendChild(tail); 92 93 this.createIcon(); 94 this.createTextNode(); 95}; 96 97 98Textline.Widget.prototype.createIcon = function() { 99 var button, 100 screen; 101 102 this.icon = document.createElement('i'); 103 104 this.icon.style.display = 'inline-block'; 105 this.icon.style.border = '2px solid ' + this.opts.font_color; 106 this.icon.style.borderBottomWidth = '5px'; 107 this.icon.style.borderRadius = '2px'; 108 109 this.icon.style.position = 'absolute'; 110 this.icon.style.left = '35px'; 111 this.icon.style.top = '50%'; 112 this.icon.style.marginTop = '-10px'; 113 114 screen = document.createElement('div'); 115 screen.style.width = '8px'; 116 screen.style.height = '12px'; 117 this.icon.appendChild(screen); 118 119 button = document.createElement('div'); 120 button.style.backgroundColor = this.opts.background_color; 121 button.style.borderRadius = '2px'; 122 button.style.width = '3px'; 123 button.style.height = '3px'; 124 button.style.position = 'absolute'; 125 button.style.bottom = '-4px'; 126 button.style.left = '50%';
127 button.style.marginLeft = '-1.5px'; 128 this.icon.appendChild(button); 129 130 this.content.appendChild(this.icon); 131}; 132 133 134Textline.Widget.prototype.createTextNode = function() { 135 this.text_node = document.createElement('span'); 136 137 this.text_node.style.color = this.opts.font_color; 138 this.text_node.style.fontFamily = this.opts.font_family; 139 this.text_node.style.fontSize = this.opts.font_size; 140 141 this.text_node.appendChild(document.createTextNode(this.opts.text)); 142 143 this.content.appendChild(this.text_node); 144}; 145 146 147Textline.Widget.prototype.position = function() { 148 if (this.animating) { 149 return; 150 } 151 152 this.widget.style.marginLeft = (-1*this.widget.clientWidth/2)+'px'; 153 154 if (this.visible) { 155 this.widget.style.bottom = this.visibleBottomOffset() + 'px'; 156 } else { 157 this.widget.style.bottom = (-1*this.widget.clientHeight) + 'px'; 158 } 159}; 160 161 162Textline.Widget.prototype.show = function() { 163 var animate, 164 animation_end_pos, 165 animation_start_pos, 166 curr_pos, 167 direction, 168 final_pos, 169 num_steps, 170 overshoot, 171 step, 172 widget; 173 174 if (this.visible) { 175 return; 176 } 177 178 this.animating = true; 179 this.visible = true; 180 181 curr_pos = parseFloat(this.widget.style.bottom.slice(0,-2)); 182 final_pos = this.visibleBottomOffset(); 183 num_steps = 64; 184 overshoot = this.visibleBottomOffset(); 185 direction = -1; 186 animation_end_pos = curr_pos; 187 widget = this; 188 189 animate = function() { 190 if (isNaN(curr_pos)) { 191 return; 192 } 193 if (animation_end_pos == curr_pos) { 194 overshoot = overshoot/2; 195 if (overshoot <= 0.01) { 196 overshoot = 0; 197 } 198 direction = -1*direction 199 animation_end_pos = final_pos + direction * overshoot; 200 animation_start_pos = curr_pos; 201 202 if (animation_end_pos == final_pos) { 203 widget.animating = false; 204 widget.position(); 205 return; 206 } 207 208 num_steps = Math.ceil(num_steps/1.2); 209 step = 0; 210 } 211 212 step += 1; 213 curr_pos = animation_start_pos + widget.easeInOutQuad(step/num_steps) * direction * Math.abs(animation_start_pos - animation_end_pos); 214 widget.widget.style.bottom = curr_pos + 'px'; 215 216 setTimeout(animate, 5); 217 }; 218 219 animate(); 220}; 221 222 223Textline.Widget.prototype.setupScrollHandling = function() { 224 var scroll_evt_handler, 225 scroll_offset, 226 widget; 227 228 if (this.opts.scroll_target) { 229 if (typeof(this.opts.scroll_target) == typeof('')) { 230 this._scroll_target = document.getElementById(this.opts.scroll_target) 231 } else { 232 this._scroll_target = this.opts.scroll_target; 233 } 234 } else { 235 this._scroll_target = window; 236 } 237 if (!this._scroll_target) { 238 return; 239 } 240 241 widget = this 242 243 scroll_evt_handler = function() { 244 scroll_offset = widget._scroll_target.scrollY || widget._scroll_target.scrollTop || widget._scroll_target.pageYOffset || 0; 245 if (scroll_offset >= widget.scrollThreshold()) { 246 widget.show(); 247 } 248 }; 249 this._scroll_target.addEventListener('scroll', scroll_evt_handler, false); 250 scroll_evt_handler(); 251}; 252 253 254Textline.Widget.prototype.easeInOutQuad = function(t) { 255 return t<.5 ? 2*t*t : -1+(4-2*t)*t 256}; 257 258 259Textline.Widget.prototype.visibleBottomOffset = function() { 260 return this.opts.bottom_offset; 261}; 262 263 264Textline.Widget.prototype.scrollThreshold = function() { 265 if (typeof(this.opts.scroll_threshold) == typeof(0)) { 266 return this.opts.scroll_threshold; 267 } 268 return 100; 269}; 270 271 272Textline.Widget.prototype.detectPhone = function() { 273 var check = false; 274 // http://detectmobilebrowsers.com/ 275 (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|
275sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera); 276 return check; 277}; 278 279 280Textline.Widget.prototype.generateDebugConsole = function() { 281 this.debug_console = document.createElement('div'); 282 this.debug_console.style.position = 'fixed'; 283 this.debug_console.style.top = '0px'; 284 this.debug_console.style.left = '0px'; 285 this.debug_console.style.zIndex = '1000'; 286 this.debug_console.style.fontSize = '12px'; 287 this.debug_console.style.color = '#0F0'; 288 this.debug_console.style.background = '#000'; 289 this.debug_console.style.padding = '0px 8px'; 290 this.debug_console.innerHTML = 'debugging...'; 291 document.getElementsByTagName('body')[0].appendChild(this.debug_console); 292}; 293 294 295Textline.Widget.prototype.log = function(msg) { 296 if (this.debug_console) { 297 this.debug_console.innerHTML = '' + msg; 298 } 299}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.