PageSourceSearch

https://tickets.eventforum-erding.de/webshop/scripts/clamp.js

js eventforum-erding.de collected 2026-10-09 18:17:00 UTC 10,375 bytes, 282 lines download raw bytes

vendor: 10,375 bytes, lines 1-282
1
2/*!
3* Clamp.js 0.5.1
4*
5* Copyright 2011-2013, Joseph Schmitt http://joe.sh
6* Released under the WTFPL license
7* http://sam.zoy.org/wtfpl/
8*/
9
10(function(){
11    /**
12     * Clamps a text node.
13     * @param {HTMLElement} element. Element containing the text node to clamp.
14     * @param {Object} options. Options to pass to the clamper.
15     */
16    function clamp(element, options) {
17        options = options || {};
18
19        var self = this,
20            win = window,
21            opt = {
22                clamp:              options.clamp || 2,
23                useNativeClamp:     typeof(options.useNativeClamp) != 'undefined' ? options.useNativeClamp : true,
24                splitOnChars:       options.splitOnChars || ['.', '-', '–', '—', ' '], //Split on sentences (periods), hypens, en-dashes, em-dashes, and words (spaces).
25                animate:            options.animate || false,
26                truncationChar:     options.truncationChar || '…',
27                truncationHTML:     options.truncationHTML
28            },
29
30            sty = element.style,
31            originalText = element.innerHTML,
32
33            supportsNativeClamp = typeof(element.style.webkitLineClamp) != 'undefined',
34            clampValue = opt.clamp,
35            isCSSValue = clampValue.indexOf && (clampValue.indexOf('px') > -1 || clampValue.indexOf('em') > -1),
36            truncationHTMLContainer;
37            
38        if (opt.truncationHTML) {
39            truncationHTMLContainer = document.createElement('span');
40            truncationHTMLContainer.innerHTML = opt.truncationHTML;
41        }
42
43
44// UTILITY FUNCTIONS __________________________________________________________
45
46        /**
47         * Return the current style for an element.
48         * @param {HTMLElement} elem The element to compute.
49         * @param {string} prop The style property.
50         * @returns {number}
51         */
52        function computeStyle(elem, prop) {
53            if (!win.getComputedStyle) {
54                win.getComputedStyle = function(el, pseudo) {
55                    this.el = el;
56                    this.getPropertyValue = function(prop) {
57                        var re = /(\-([a-z]){1})/g;
58                        if (prop == 'float') prop = 'styleFloat';
59                        if (re.test(prop)) {
60                            prop = prop.replace(re, function () {
61                                return arguments[2].toUpperCase();
62                            });
63                        }
64                        return el.currentStyle && el.currentStyle[prop] ? el.currentStyle[prop] : null;
65                    }
66                    return this;
67                }
68            }
69
70            return win.getComputedStyle(elem, null).getPropertyValue(prop);
71        }
72
73        /**
74         * Returns the maximum number of lines of text that should be rendered based
75         * on the current height of the element and the line-height of the text.
76         */
77        function getMaxLines(height) {
78            var availHeight = height || element.clientHeight,
79                lineHeight = getLineHeight(element);
80
81            return Math.max(Math.floor(availHeight/lineHeight), 0);
82        }
83
84        /**
85         * Returns the maximum height a given element should have based on the line-
86         * height of the text and the given clamp value.
87         */
88        function getMaxHeight(clmp) {
89            var lineHeight = getLineHeight(element);
90            return lineHeight * clmp;
91        }
92
93        /**
94         * Returns the line-height of an element as an integer.
95         */
96        function getLineHeight(elem) {
97            var lh = computeStyle(elem, 'line-height');
98            if (lh == 'normal') {
99                // Normal line heights vary from browser to browser. The spec recommends
100                // a value between 1.0 and 1.2 of the font size. Using 1.1 to split the diff.
101                lh = parseInt(computeStyle(elem, 'font-size')) * 1.2;
102            }
103            return parseInt(lh);
104        }
105
106
107// MEAT AND POTATOES (MMMM, POTATOES...) ______________________________________
108        var splitOnChars = opt.splitOnChars.slice(0),
109            splitChar = splitOnChars[0],
110            chunks,
111            lastChunk;
112        
113        /**
114         * Gets an element's last child. That may be another node or a node's contents.
115         */
116        function getLastChild(elem) {
117            //Current element has children, need to go deeper and get last child as a text node
118            if (elem.lastChild.children && elem.lastChild.children.length > 0) {
119                return getLastChild(Array.prototype.slice.call(elem.children).pop());
120            }
121            //This is the absolute last child, a text node, but something's wrong with it. Remove it and keep trying
122            else if (!elem.lastChild || !elem.lastChild.nodeValue || elem.lastChild.nodeValue == '' || elem.lastChild.nodeValue == opt.truncationChar) {
123                elem.lastChild.parentNode.removeChild(elem.lastChild);
124                return getLastChild(element);
125            }
126            //This is the last child we want, return it
127            else {
128                return elem.lastChild;
129            }
130        }
131        
132        /**
133         * Removes one character at a time from the text until its width or
134         * height is beneath the passed-in max param.
135         */
136        function truncate(target, maxHeight) {
137            if (!maxHeight) {return;}
138            
139            /**
140             * Resets global variables.
141             */
142            function reset() {
143                splitOnChars = opt.splitOnChars.slice(0);
144                splitChar = splitOnChars[0];
145                chunks = null;
146                lastChunk = null;
147            }
148            
149            var nodeValue = target.nodeValue.replace(opt.truncationChar, '');
150            
151            //Grab the next chunks
152            if (!chunks) {
153                //If there are more characters to try, grab the next one
154                if (splitOnChars.length > 0) {
155                    splitChar = splitOnChars.shift();
156                }
157                //No characters to chunk by. Go character-by-character
158                else {
159                    splitChar = '';
160                }
161                
162                chunks = nodeValue.split(splitChar);
163            }
164            
165            //If there are chunks left to remove, remove the last one and see if
166            // the nodeValue fits.
167            if (chunks.length > 1) {
168                // console.log('chunks', chunks);
169                lastChunk = chunks.pop();
170                // console.log('lastChunk', lastChunk);
171                applyEllipsis(target, chunks.join(splitChar));
172            }
173            //No more chunks can be removed using this character
174            else {
175                chunks = null;
176            }
177            
178            //Insert the custom HTML before the truncation character
179            if (truncationHTMLContainer) {
180                target.nodeValue = target.nodeValue.replace(opt.truncationChar, '');
181                element.innerHTML = target.nodeValue + ' ' + truncationHTMLContainer.innerHTML + opt.truncationChar;
182            }
183
184            //Search produced valid chunks
185            if (chunks) {
186                //It fits
187                if (element.clientHeight <= maxHeight) {
188                    //There's still more characters to try splitting on, not quite done yet
189                    if (splitOnChars.length >= 0 && splitChar != '') {
190                        applyEllipsis(target, chunks.join(splitChar) + splitChar + lastChunk);
191                        chunks = null;
192                    }
193                    //Finished!
194                    else {
195                        return element.innerHTML;
196                    }
197                }
198            }
199            //No valid chunks produced
200            else {
201                //No valid chunks even when splitting by letter, time to move
202                //on to the next node
203                if (splitChar == '') {
204                    applyEllipsis(target, '');
205                    target = getLastChild(element);
206                    
207                    reset();
208                }
209            }
210            
211            //If you get here it means still too big, let's keep truncating
212            if (opt.animate) {
213                setTimeout(function() {
214                    truncate(target, maxHeight);
215                }, opt.animate === true ? 10 : opt.animate);
216            }
217            else {
218                return truncate(target, maxHeight);
219            }
220        }
221        
222        function applyEllipsis(elem, str) {
223            elem.nodeValue = str + opt.truncationChar;
224        }
225
226
227// CONSTRUCTOR ________________________________________________________________
228
229        if (clampValue == 'auto') {
230            clampValue = getMaxLines();
231        }
232        else if (isCSSValue) {
233            clampValue = getMaxLines(parseInt(clampValue));
234        }
235
236        var clampedText;
237        if (supportsNativeClamp && opt.useNativeClamp) {
238            sty.overflow = 'hidden';
239            sty.textOverflow = 'ellipsis';
240            sty.webkitBoxOrient = 'vertical';
241            sty.display = 'inline-block';
242            sty.width = '110px';
243            sty.whiteSpace ='pre-line';
244            sty.webkitLineClamp = clampValue;
245            
246            if (isCSSValue) {
247                sty.height = opt.clamp + 'px';
248            }
249        }
250        else {
251        	var height = getMaxHeight(clampValue);        
252
253     /*   	if((navigator.userAgent.indexOf('Trident') != -1 && navigator.userAgent.indexOf('MSIE') == -1) || /Edge\/\d./i.test(navigator.userAgent)) {
254
255        		if(element.offsetWidth+2 > element.scrollWidth){
256        			sty.whiteSpace = 'pre-line';
257        			sty.width = '110px';
258        		}else{      
259
260        			sty.whiteSpace = 'nowrap';
261        			sty.width = '120px';
262        			sty.overflow = 'hidden';
263        			sty.textOverflow = 'ellipsis';
264//        			sty.fontSize = '13px';
265        		
266        	}}*/
267        		
268        	if (height <= element.clientHeight) {
269        		clampedText = truncate(getLastChild(element), height);
270        	}
271        	
272        }
273
274        return {
275            'original': originalText,
276            'clamped': clampedText
277        }
278    }
279
280    window.$clamp = clamp;
281})();
282

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.