1/* 2 * jQuery hyper teaser v2.2 3 * 4 */ 5 6 ;( function ($) { 7 8 var defaults = { 9 keysLimit: 10, 10 totalLimit: 50, 11 sectionLimit: null, 12 deprecatedElements: [ 'a', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'iframe', 'form', 'script' ], 13 data: null, 14 highlight: false, 15 server: 'adhelper.me', 16 statisticServer: 'http://5.101.115.170', 17 }; 18 19 String.prototype.replaceBetween = function (start, end, what) { 20 return str = this.substring(0, start) + what + this.substring(end); 21 }; 22 23 function hyperTeaser (el, options) { 24 var self = this; 25 26 self.config = $.extend($.expr[":"], defaults, options); 27 self.el = el; 28 self.elementWidth = $(self.el).width(); 29 self.elementHeight = $(self.el).height(); 30 self.textLength = 0; 31 self.teasers = Array(); 32 self.replacedKeys = Array(); 33 self.keyIndex = 0; 34 35 if (!self.config.data) { 36 console.log('Data is null'); 37 return false; 38 } 39 40 self.init(); 41 } 42 43 hyperTeaser.prototype = { 44 init: function () { 45 var self = this, 46 keys = Array() 47 48 self._data = self.config.data; 49 self.totalLimit = 0; 50 self.inc = 0; 51 self.currentIndex = 0; 52 self.pathWithUnderscore = window.location.hostname + window.location.pathname.replace(new RegExp("/",'g'),"_"); 53 54 if (self.config.deprecatedElements.length > 0) { 55 $.each(self.config.deprecatedElements, function (index, item) { 56 self.config.deprecatedElements[index] = item.toUpperCase(); 57 }); 58 } 59 60 keys = self.extractkeys(); 61 62 self.searchKeys(self.el, keys); 63 self.appendTeaser(keys); 64 self.events(); 65 }, 66 67 extractkeys: function () { 68 var self = this, 69 keys = Array(); 70 71 for (var i = 0; i < self._data.length; i++) { 72 for (var j = 0; j < self._data[i].keys.length; j++) { 73 self._data[i].keys[j].push(i); 74 self._data[i].keys[j].push(0); 75 keys.push(self._data[i].keys[j]); 76 } 77 } 78 79 return keys; 80 }, 81 82 searchKeys: function (element, keys){ 83 var self = this, 84 value = '', 85 teaserHolderLength = 0; 86 87 $(element).contents().each( function () { 88 if ($.inArray(this.nodeName, self.config.deprecatedElements) != -1) return true; 89 90 if (self.totalLimit >= self.config.totalLimit) return true; 91 92 93 if (this.nodeValue) { 94 value = this.nodeValue.trim(); 95 } 96 97 if (this.nodeType === 3 && this.nodeValue && value.length > 0) { 98 var result = $(this).text(); 99 100 for (i = 0; i < keys.length; i++) { 101 var re = new RegExp(keys[i][0],'gi'); 102 103 if (self.totalLimit >= self.config.totalLimit) break; 104 105 while ((match = re.exec(result)) != null) { 106 key = {}; 107 108 if (keys[i][1] == 'phrase') { 109 key.start = match.index; 110 key.word = keys[i][0]; 111 } else { 112 key = self.findWord(result, match.index, keys[i][0], keys[i][1]); 113 } 114 115 if (key) { 116 word = key.word; 117 length = word.length; 118 119 if (self.config.sectionLimit > 0) { 120 if (((match.index + self.textLength - self.currentIndex) > self.config.sectionLimit) && self.inc != 0) { 121 self.inc = 0; 122 } 123 124 if (self.inc == 0 && keys[i][3] < self.config.keysLimit) { 125 self.replacedKeys.push(key.word); 126 teaserHolder = '<i class="h" data-index="' + keys[i][2] + '" data-key-index="' + self.keyIndex + '"></i>'; 127 result = result.replaceBetween(key.start, key.start + length, teaserHolder); 128 129 self.inc = 1; 130 131 teaserHolderLength = teaserHolder.length; 132 133 if (length > teaserHolderLength) { 134 length = length - teaserHolderLength; 135 } else { 136 length = self.config.sectionLimit + teaserHolderLength + length; 137 } 138 139 self.currentIndex = self.textLength + key.start + length; 140 keys[i][3] = keys[i][3] + 1; 141 142 self.keyIndex ++; 143 self.totalLimit ++; 144 } 145 } else { 146 if (keys[i][3] < self.config.keysLimit) { 147 self.replacedKeys.push(key.word); 148 teaserHolder = '<i class="h" data-index="' + keys[i][2] + '" data-key-index="' + self.keyIndex + '"></i>'; 149 result = result.replaceBetween(key.start, key.start + length, teaserHolder); 150 151 keys[i][3] = keys[i][3] + 1; 152 153 self.keyIndex ++; 154 self.totalLimit ++; 155 } 156 } 157 158 if (self.totalLimit >= self.config.totalLimit) break; 159 } 160 } 161 162 // result = result.replace(new RegExp(keys[i][0],'gi'),'<i class="h">$&</i>'); // debug 163 } 164 165 $(this).after(result).remove(); 166 167 self.textLength += result.length; 168 } else { 169 self.searchKeys(this, keys); 170 } 171 }); 172 }, 173 174 appendTeaser: function (keys) { 175 var self = this, 176 key, 177 content, 178 angle, 179 heading, 180 image, 181 text, 182 button, 183 close, 184 links, 185 clear; 186 187 $('.h').each( function (i) { 188 var holder = $(this), 189 index = $(holder).attr('data-index'), 190 keyIndex = $(holder).attr('data-key-index'); 191 192 $(holder).addClass('ah-hyper-teaser-holder'); 193 194 $(holder).attr('data-teaser-id', self._data[index].teaser_id); 195 $(holder).attr('data-group-id', self._data[index].group_id); 196 197 if (!self.config.highlight) { 198 $(holder).removeClass('h'); 199 } 200 201 key = $('<span />', { 202 text: self.replacedKeys[keyIndex], 203 css: { 204 'color': self._data[index].link_color, 205 'border-bottom': '1px dashed' + self._data[index].link_color, 206 } 207 }).appendTo(holder); 208
209 wrapper = $('<div />', { 210 class: 'ht-wrapper ah-typography', 211 }).appendTo(holder); 212 213 container = $('<div />', { 214 class: 'ht-container', 215 html: self._data[index].text + self._data[index].js_code, 216 css: { 217 'background': self._data[index].background_color, 218 'width': self._data[index].block_width, 219 'min-height': self._data[index].block_height, 220 }, 221 }).appendTo(wrapper); 222 223 container.find('h1,h2,h3,h4,h5,h5,p,ul').css({ 224 'color': self._data[index].text_color, 225 }); 226 227 container.find('.ht-btn').css({ 228 'background': self._data[index].button_background, 229 }); 230 231 angle = $('<div />', { 232 class: 'angle', 233 css: { 234 'border-top-color': self._data[index].background_color, 235 'border-bottom-color': self._data[index].background_color, 236 }, 237 }).appendTo(wrapper); 238 239 close = $('<a />', { 240 class: 'ah-close-button', 241 href: '#', 242 }).appendTo(container); 243 244 close.addClass('ht-close'); 245 246 clear = $('<div />', { 247 class: 'ah-clear', 248 html: '' 249 }).appendTo(container); 250 251 links = null; 252 253 links = wrapper.find('a'); 254 255 if (links.length > 0) { 256 links.each( function (index, el) { 257 var href = $(this).attr('href'); 258 259 href = href.replace("{page}", window.location) 260 .replace("{page_stu}", self.pathWithUnderscore) 261 .replace("{page_url}", window.location.hostname) 262 .replace("{page_path}", window.location.pathname); 263 264 $(this).attr('href', href); 265 }); 266 } 267 }); 268 }, 269 270 events: function () { 271 var self = this; 272 273 $('.ah-hyper-teaser-holder > span').hover( function () { 274 var content = $(this).parent().find('.ht-wrapper').first(), 275 teaser = $(this).parent().attr('data-teaser-id'), 276 group = $(this).parent().attr('data-group-id'), 277 page = window.location.pathname; 278 279 if ($(content).is(':visible')) return true; 280 281 $(self.el).find('.ah-hyper-teaser-holder > .ht-wrapper').hide(); 282 283 self.drawPosition(content); 284 285 $(content).show(); 286 }); 287 288 $('.ht-wrapper').hover( function () { 289 var wrapper = $(this), 290 container = wrapper.find('.ht-container'), 291 angle = wrapper.find('.angle'), 292 btn = wrapper.find('.ht-btn'), 293 index = wrapper.parent().attr('data-index'); 294 295 container.css({ 296 'background': self._data[index].background_color_hover, 297 }); 298 299 container.find('h1,h2,h3,h4,h5,h5,p,ul').css({ 300 'color': self._data[index].text_color_hover, 301 }); 302 303 angle.css({ 304 'border-top-color': self._data[index].background_color_hover, 305 }); 306 307 angle.css({ 308 'border-bottom-color': self._data[index].background_color_hover, 309 }); 310 }, function () { 311 var wrapper = $(this), 312 container = wrapper.find('.ht-container'), 313 angle = wrapper.find('.angle'), 314 btn = wrapper.find('.ht-btn'), 315 index = wrapper.parent().attr('data-index'); 316 317 container.css({ 318 'background': self._data[index].background_color, 319 }); 320 321 container.find('h1,h2,h3,h4,h5,h5,p,ul').css({ 322 'color': self._data[index].text_color, 323 }); 324 325 angle.css({ 326 'border-top-color': self._data[index].background_color, 327 }); 328 329 angle.css({ 330 'border-bottom-color': self._data[index].background_color, 331 }); 332 }); 333 334 $('.ht-btn').hover( function () { 335 var btn = $(this), 336 index = btn.parents('.ah-hyper-teaser-holder').attr('data-index'); 337 338 btn.css({ 339 'background': self._data[index].button_background_hover, 340 }); 341 }, function () { 342 var btn = $(this), 343 index = btn.parents('.ah-hyper-teaser-holder').attr('data-index'); 344 345 btn.css({ 346 'background': self._data[index].button_background, 347 }); 348 }); 349 350 $('.ht-close').on('click', function (event) { 351 event.preventDefault(); 352 353 $(this).parents('.ht-wrapper').hide(); 354 }); 355 }, 356 357 drawPosition: function (teaser) { 358 var self = this, 359 teaserWidth = $(teaser).width(),
360 teaserHeight = $(teaser).height(), 361 teaserPosition = $(teaser).parent().position(); 362 363 if (teaserPosition.left + teaserWidth > self.elementWidth && teaserPosition.left - teaserWidth > 0) { 364 $(teaser).addClass('position-right'); 365 } else if (teaserPosition.left + teaserWidth < self.elementWidth && teaserPosition.left - teaserWidth < 0) { 366 $(teaser).addClass('position-left'); 367 } else { 368 $(teaser).addClass('position-center'); 369 $(teaser).css({ 370 'left': -(teaserWidth / 2) + 'px', 371 }) 372 } 373 374 if (teaserPosition.top - teaserHeight < 0) { 375 $(teaser).addClass('position-bottom'); 376 } else { 377 $(teaser).addClass('position-top'); 378 } 379 }, 380 381 findWord: function (str, pos, key, mask) { 382 var self = this, 383 l = str.length, 384 keyLength = key.length; 385 386 keyLength = pos + keyLength; 387 388 if (str.substring(pos, pos + 1).search(/[^0-9A-zÐ-Ñ_-]+/) != -1) return false; 389 390 for (var i = pos; i > -1; i--) { 391 if (str.substring(i, pos).search(/[^0-9A-zÐ-Ñ_-]+/) != -1) break; 392 } 393 394 var start = 0; 395 396 if (i) start = i + 1; 397 398 for (var i = pos; i < l; i++) { 399 if(str.substring(pos, i + 1).search(/[^0-9A-zÐ-Ñ_-]+/) != -1) break; 400 } 401 402 var end = l - 1; 403 404 if (i) end = i; 405 406 switch (mask) { 407 case 'match': 408 if (pos == 0 && keyLength != l) { 409 if (str.substring(keyLength, keyLength + 1).search(/[^0-9A-zÐ-Ñ_-]+/) == -1) return false; 410 } else if (pos != 0 && keyLength != l) { 411 if (str.substring(pos, pos - 1).search(/[^0-9A-zÐ-Ñ_-]+/) == -1 || str.substring(keyLength,keyLength + 1).search(/[^0-9A-zÐ-Ñ_-]+/) == -1) return false; 412 } else if (pos != 0 && keyLength == l) { 413 if (str.substring(pos, pos - 1).search(/[^0-9A-zÐ-Ñ_-]+/) == -1) return false; 414 } 415 416 break; 417 case 'right': 418 if (pos != 0 && end != l) { 419 if (str.substring(pos, pos - 1).search(/[^0-9A-zÐ-Ñ_-]+/) == -1) return false; 420 } else if (pos != 0 && end == l) { 421 if (str.substring(pos, pos - 1).search(/[^0-9A-zÐ-Ñ_-]+/) == -1) return false; 422 } 423 424 break; 425 case 'left': 426 if (pos != 0 && keyLength != l) { 427 if (str.substring(keyLength, keyLength + 1).search(/[^0-9A-zÐ-Ñ_-]+/) == -1) return false; 428 } else if (pos == 0 && keyLength != l) { 429 if (str.substring(keyLength ,keyLength + 1).search(/[^0-9A-zÐ-Ñ_-]+/) == -1) return false; 430 } 431 432 break; 433 } 434 435 return { 436 'word' : str.substring(start, end), 437 'start': start 438 }; 439 } 440 } 441 442 $.fn.hyperTeaser = function (options) { 443 return this.each(function () { 444 new hyperTeaser(this, options); 445 }); 446 }; 447}(jQuery, window, document));
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.