PageSourceSearch

https://traumadissociation.com/javascripts/jquery.glossarize.js

js traumadissociation.com collected 2026-09-24 09:29:42 UTC 7,388 bytes, 378 lines download raw bytes

1/**
2 * Plugin Name: Glossarizer
3 * Author : Vinay @Pebbleroad
4 * Date: 02/04/2013
5 * Description: Takes glossary terms from a JSON object -> Searches for terms in your html -> Wraps a abbr tag around the matched word
6 * 1. Fixed IE8 bug where whitespace get removed - Had to change `abbr` tag to a block element `div`
7 */
8
9;(function($){
10
11	/**
12	 * Defaults
13	 */
14	
15	var pluginName = 'glossarizer',
16		defaults = {
17			sourceURL     : '', /* URL of the JSON file with format {"term": "", "description": ""} */	
18			replaceTag    : 'abbr', /* Matching words will be wrapped with abbr tags by default */
19			lookupTagName : 'p, ul, li, ol, dd, dl, div', /* Lookup in either paragraphs or lists. Do not replace in headings */ 
20			callback      : null, /* Callback once all tags are replaced: Call or tooltip or anything you like */
21			replaceOnce   : true /* Replace only once in a TextNode */,
22			replaceClass: 'glossarizer_replaced'			
23		}
24
25	/**
26	 * Constructor
27	 */
28	
29	function Glossarizer(el, options){
30
31		var base = this
32
33		base.el = el;
34
35		/* Element */
36		base.$el = $(el)
37
38		/* Extend options */
39
40		base.options = $.extend({}, defaults, options)
41
42		/* Terms */
43		
44		base.terms = [];
45
46		/* Excludes array */
47
48		base.excludes = [];
49
50		/* Replaced words array */
51
52		base.replaced = [];
53		
54
55		/* Regex Tags */
56		
57		base.regexOption = base.options.replaceOnce? 'i': 'ig';
58		
59		
60		/* Fetch glossary JSON */
61
62		$.getJSON(this.options.sourceURL).then(function(data){
63
64			base.glossary = data;
65			
66			if(!base.glossary.length || base.glossary.length == 0) return;			
67			
68			/**
69			 * Get all terms
70			 */
71			
72			for(var i =0; i< base.glossary.length; i++){
73				
74				var terms = base.glossary[i].term.split(',');
75
76				for(var j = 0; j < terms.length; j++){
77
78					/* Trim */
79
80					var trimmed = terms[j].replace(/^\s+|\s+$/g, ''),
81						isExclusion = trimmed.indexOf('!');
82					
83					if(isExclusion == -1 || isExclusion != 0){
84
85						/* Glossary terms array */
86						
87						base.terms.push(trimmed)
88
89					}else{
90
91						/* Excluded terms array */
92						
93						base.excludes.push(trimmed.substr(1));
94					}
95				}
96				
97				
98			}
99			
100
101			/**
102			 * Wrap terms
103			 */
104			
105			base.wrapTerms();
106
107
108		})
109
110		
111
112	}
113
114	/**
115	 * Prototypes
116	 */
117	Glossarizer.prototype = {		
118
119		getDescription: function(term){			
120
121			var regex = new RegExp('(^\s*)'+this.clean(term)+'\\s*|\\,$', 'i');
122
123			/**
124			 * Matches
125			 * 1. Starts with \s* (zero or more spaces)			 
126			 * 2. Ends with zero or more spaces
127			 * 3. Ends with comma
128			 */
129
130			for(var i =0; i< this.glossary.length; i++){				
131
132				if(this.glossary[i].term.match(regex)){										
133					return this.glossary[i].description.replace(/\"/gi, '&quot;')
134				}				
135			}				
136
137		},
138		clean: function(text){
139
140			var reEscape = new RegExp('(\\' + ['/', '.', '*', '+', '?', '(', ')', '[', ']', '{', '}', '\\'].join('|\\') + ')', 'g')
141			
142			return text.replace(reEscape, '\\$1')
143
144		},
145		
146		/**
147		 * Wraps the matched terms by calling traverser     
148		 */
149		wrapTerms: function(){
150
151			this.cleanedTerms = this.clean(this.terms.join('|'))
152			this.excludedTerms = this.clean(this.excludes.join('|'))
153			
154			var nodes = this.el.querySelectorAll(this.options.lookupTagName)					
155
156			for(var i =0; i < nodes.length; i++){
157				this.traverser(nodes[i])
158			}      
159
160			/**
161			 * Callback
162			 */
163			
164			if(this.options.callback) this.options.callback.call(this.$el)
165
166		},
167
168		/**
169		 * Traverses through nodes to find the matching terms in TEXTNODES
170		 */
171
172		traverser: function(node){      
173			
174			var next,
175				base = this;
176
177			if (node.nodeType === 1) {
178
179				/*
180				 Element Node
181				 */
182				
183				if (node = node.firstChild) {
184						do {
185							// Recursively call traverseChildNodes
186							// on each child node
187							next = node.nextSibling
188
189							/**
190							 * Check if the node is not glossarized
191							 */
192
193							if(	node.className != this.options.replaceClass)
194							{
195								
196								this.traverser(node)
197
198							}
199
200						} while(node = next)
201				}
202
203			} else if (node.nodeType === 3) {
204
205				/*
206				 Text Node
207				 */
208
209				var temp = document.createElement('div'),
210					data = node.data;
211
212				var re = new RegExp('(?:^|\\b)('+this.cleanedTerms+ ')(?!\\w)', base.regexOption),
213					reEx = new RegExp('(?:^|\\b)('+this.excludedTerms+ ')(?!\\w)', base.regexOption);
214				
215				
216				if(re.test(data)){      
217					
218					var excl = reEx.exec(data);    
219					
220					data = data.replace(re,function(match, item , offset, string){
221						
222
223						if(base.options.replaceOnce && inArrayIn(match, base.replaced) >= 0){
224
225							return match;
226						}
227						
228						base.replaced.push(match);
229						
230						var ir = new RegExp('(?:^|\\b)'+base.clean(match)+'(?!\\w)'),
231							result = ir.exec(data)
232						
233						
234						if(result){
235
236							if(excl && base.excludes.length){
237								
238								var id = offset,
239									exid = excl.index,
240									exl = excl.index + excl[0].length;
241								
242								if(exid <= id && id <= exl){
243
244									return match;
245									
246								}else{
247
248									return '<'+base.options.replaceTag+' class="'+base.options.replaceClass+'" title="'+base.getDescription(match)+'">'+ match + '</'+base.options.replaceTag+'>'
249
250								}
251							}
252							else{
253
254								return '<'+base.options.replaceTag+' class="'+base.options.replaceClass+'" title="'+base.getDescription(match)+'">'+ match + '</'+base.options.replaceTag+'>'
255							}
256						}
257						
258
259					});
260
261					/**
262					 * Only replace when a match is found					 
263					 * Resorting to jQuery html() because of IE8 whitespace issue.
264					 * IE 8 removes leading whitespace from Text Nodes. Hence innerhtml doesnt work.
265					 * 
266					 */
267					
268					$(temp).html(data)
269
270					
271				
272					while (temp.firstChild) {          
273						node.parentNode.insertBefore(temp.firstChild, node)
274					}
275
276					node.parentNode.removeChild(node)
277
278				}
279
280			}
281
282		},
283
284	};
285
286
287	/**
288	 * Public Methods
289	 */
290	
291	var methods = {
292
293		destroy: function(){			
294
295			this.$el.removeData('plugin_' + pluginName);
296
297			/* Remove abbr tag */
298			this.$el.find('.' + this.options.replaceClass).each(function(){
299
300				var $this = $(this),
301					text = $this.text();
302
303
304				$this.replaceWith(text)
305
306			})
307			
308		}
309	}
310
311
312	/**
313	 * Extend Prototype
314	 */
315	
316	Glossarizer.prototype = $.extend({}, Glossarizer.prototype, methods)
317
318	/**
319	 * Plugin
320	 * @param  {[type]} options   
321	 */
322	$.fn[pluginName] =function(options){
323
324		return this.each(function(){
325
326
327			var $this = $(this),
328				glossarizer = $this.data('plugin_' + pluginName);
329
330			/*
331			Check if its a method
332			 */
333			
334			if(typeof options == "string" && glossarizer  && methods.hasOwnProperty(options) ){
335
336				glossarizer[options].apply(glossarizer)
337
338			}else{
339
340				/* Destroy if exists */
341
342				if(glossarizer) glossarizer['destroy'].apply(glossarizer);
343
344
345				/* Initialize */
346			
347				$.data(this, 'plugin_' + pluginName, new Glossarizer(this, options))
348			}
349		});
350
351	}
352
353
354	/**
355	 * In Array
356	 */
357	
358	function inArrayIn(elem, arr, i){            
359        
360        if (typeof elem !== 'string'){
361			return $.inArray.apply(this, arguments);
362        }
363
364        if (arr){
365            var len = arr.length;
366                i = i ? (i < 0 ? Math.max(0, len + i) : i) : 0;
367            elem = elem.toLowerCase();
368            for (; i < len; i++){
369                if (i in arr && arr[i].toLowerCase() == elem){
370                    return i;
371                }
372            }
373        }            
374        return -1;
375    }
376
377
378})(jQuery);

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.