f8cede4d2278100144f910a3de13eb02f960b40d
[wolnelektury.git] / src / wolnelektury / static / js / contrib / jquery.shorten.js
1 /*
2  * jQuery Shorten plugin 1.1.0
3  *
4  * Copyright (c) 2014 Viral Patel
5  * http://viralpatel.net
6  *
7  * Licensed under the MIT license:
8  *   http://www.opensource.org/licenses/mit-license.php
9  */
10
11 /*
12 ** updated by Jeff Richardson
13 ** Updated to use strict,
14 ** IE 7 has a "bug" It is returning undefined when trying to reference string characters in this format
15 ** content[i]. IE 7 allows content.charAt(i) This works fine in all modern browsers.
16 ** I've also added brackets where they weren't added just for readability (mostly for me).
17 */
18
19 (function($) {
20     $.fn.shorten = function(settings) {
21         "use strict";
22
23         var config = {
24             showChars: 100,
25             minHideChars: 10,
26             ellipsesText: "...",
27             moreText: "more",
28             lessText: "less",
29             onLess: function() {},
30             onMore: function() {},
31             errMsg: null,
32             force: false
33         };
34
35         if (settings) {
36             $.extend(config, settings);
37         }
38
39         if ($(this).data('jquery.shorten') && !config.force) {
40             return false;
41         }
42         $(this).data('jquery.shorten', true);
43
44         $(document).off("click", '.morelink');
45
46         $(document).on({
47             click: function() {
48
49                 var $this = $(this);
50                 if ($this.hasClass('less')) {
51                     $this.removeClass('less');
52                     $this.html(config.moreText);
53                     $this.parent().prev().hide();
54                     $this.parent().prev().prev().show();
55                     config.onLess();
56                 } else {
57                     $this.addClass('less');
58                     $this.html(config.lessText);
59                     $this.parent().prev().show();
60                     $this.parent().prev().prev().hide();
61                     config.onMore();
62                 }
63                 return false;
64             }
65         }, '.morelink');
66
67         return this.each(function() {
68             var $this = $(this);
69
70             var content = $this.html();
71             var contentlen = $this.text().length;
72             if (contentlen > config.showChars + config.minHideChars) {
73                 var c = content.substr(0, config.showChars);
74                 if (c.indexOf('<') >= 0) // If there's HTML don't want to cut it
75                 {
76                     var inTag = false; // I'm in a tag?
77                     var bag = ''; // Put the characters to be shown here
78                     var countChars = 0; // Current bag size
79                     var openTags = []; // Stack for opened tags, so I can close them later
80                     var tagName = null;
81
82                     for (var i = 0, r = 0; r <= config.showChars; i++) {
83                         if (content[i] == '<' && !inTag) {
84                             inTag = true;
85
86                             // This could be "tag" or "/tag"
87                             tagName = content.substring(i + 1, content.indexOf('>', i));
88
89                             // If its a closing tag
90                             if (tagName[0] == '/') {
91
92
93                                 if (tagName != '/' + openTags[0]) {
94                                     config.errMsg = 'ERROR en HTML: the top of the stack should be the tag that closes';
95                                 } else {
96                                     openTags.shift(); // Pops the last tag from the open tag stack (the tag is closed in the retult HTML!)
97                                 }
98
99                             } else {
100                                 // There are some nasty tags that don't have a close tag like <br/>
101                                 if (tagName.toLowerCase() != 'br') {
102                                     openTags.unshift(tagName); // Add to start the name of the tag that opens
103                                 }
104                             }
105                         }
106                         if (inTag && content[i] == '>') {
107                             inTag = false;
108                         }
109
110                         if (inTag) { bag += content.charAt(i); } // Add tag name chars to the result
111                         else {
112                             r++;
113                             if (countChars <= config.showChars) {
114                                 bag += content.charAt(i); // Fix to ie 7 not allowing you to reference string characters using the []
115                                 countChars++;
116                             } else // Now I have the characters needed
117                             {
118                                 if (openTags.length > 0) // I have unclosed tags
119                                 {
120                                     //console.log('They were open tags');
121                                     //console.log(openTags);
122                                     for (j = 0; j < openTags.length; j++) {
123                                         //console.log('Cierro tag ' + openTags[j]);
124                                         bag += '</' + openTags[j] + '>'; // Close all tags that were opened
125
126                                         // You could shift the tag from the stack to check if you end with an empty stack, that means you have closed all open tags
127                                     }
128                                     break;
129                                 }
130                             }
131                         }
132                     }
133                     c = $('<div/>').html(bag + '<span class="ellip">' + config.ellipsesText + '</span>').html();
134                 }else{
135                     c+=config.ellipsesText;
136                 }
137
138                 var html = '<div class="shortcontent">' + c +
139                     '</div><div class="allcontent">' + content +
140                     '</div><span><a href="javascript://nop/" class="morelink">' + config.moreText + '</a></span>';
141
142                 $this.html(html);
143                 $this.find(".allcontent").hide(); // Hide all text
144                 $('.shortcontent p:last', $this).css('margin-bottom', 0); //Remove bottom margin on last paragraph as it's likely shortened
145             }
146         });
147
148     };
149
150 })(jQuery);