Easy Table of Contents - Version 2.0.7

Version Description

Requires WordPress >

Download this release

Release Info

Developer shazahm1@hotmail.com
Plugin Icon 128x128 Easy Table of Contents
Version 2.0.7
Comparing to
See all releases

Code changes from version 2.0.6 to 2.0.7

README.txt CHANGED
@@ -5,7 +5,7 @@ Tags: table of contents, toc
5
  Requires at least: 5.2
6
  Tested up to: 5.4
7
  Requires PHP: 5.6.20
8
- Stable tag: 2.0.6
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -89,6 +89,21 @@ Easy Table Contents is a fork of the excellent [Table of Contents Plus](https://
89
 
90
  == Changelog ==
91
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  = 2.0.6 03/30/2020 =
93
  * BUG: Ensure minified files are current.
94
 
@@ -358,3 +373,6 @@ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
358
 
359
  = 2.0.6 =
360
  Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
 
 
 
5
  Requires at least: 5.2
6
  Tested up to: 5.4
7
  Requires PHP: 5.6.20
8
+ Stable tag: 2.0.7
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
89
 
90
  == Changelog ==
91
 
92
+ = 2.0.7 04/02/2020 =
93
+ * NEW: Exclude any HTML nodes with the class of `.ez-toc-exclude-headings`.
94
+ * TWEAK: Change smooth scroll selector from `'body a'` to `'a.ez-toc-link'`.
95
+ * TWEAK: Declare JS variables.
96
+ * TWEAK: Support unicode characters for the `id` attribute. Permitted by HTML5.
97
+ * TWEAK: Move the in-page anchor/span to before the heading text to account for long headings where it line wraps.
98
+ * TWEAK: Slight rework to ezTOC widget container classes logic.
99
+ * TWEAK: Cache bust the JS to make dev easier.
100
+ * TWEAK: JavaScript cleanup.
101
+ * TWEAK: URI Encode the id attribute to deal with reserved characters in JavaScript. Technically not necessary for the id attribute but needed to work with the jQuery smoothScroll library.
102
+ * COMPATIBILITY: Reintroduce filter to exclude Ultimate Addons for VC Composer Tabs from heading eligibility.
103
+ * BUG: Correct array iteration logic when processing headings.
104
+ * BUG: Tighten matching for headings in excluded HTML nodes. The loose matching was excluding far too many headings.
105
+ * BUG: Use `esc_attr()` instead of `esc_url()` for the anchor href because valid id attribute characters would cause it to return an empty href which cause a nonworking link.
106
+
107
  = 2.0.6 03/30/2020 =
108
  * BUG: Ensure minified files are current.
109
 
373
 
374
  = 2.0.6 =
375
  Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
376
+
377
+ = 2.0.7 =
378
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
assets/js/front.js CHANGED
@@ -1,5 +1,14 @@
1
  jQuery( function( $ ) {
2
 
 
 
 
 
 
 
 
 
 
3
  if ( typeof ezTOC != 'undefined' ) {
4
 
5
  var affix = $( '.ez-toc-widget-container.ez-toc-affix' );
@@ -17,13 +26,13 @@ jQuery( function( $ ) {
17
  // check offset setting
18
  if ( typeof ezTOC.scroll_offset != 'undefined' ) {
19
 
20
- affixOffset = ezTOC.scroll_offset;
21
  }
22
 
23
- $( ezTOC.affixSelector ).stick_in_parent({
24
- inner_scrolling : false,
25
- offset_top : parseInt( affixOffset )
26
- });
27
  }
28
 
29
  $.fn.shrinkTOCWidth = function() {
@@ -37,40 +46,40 @@ jQuery( function( $ ) {
37
  $( this ).css( 'width', '' );
38
  };
39
 
40
- if ( ezTOC.smooth_scroll == 1 ) {
 
 
41
 
42
- var target = hostname = pathname = qs = hash = null;
43
 
44
- $( 'body a' ).click( function( event ) {
45
 
46
- hostname = $( this ).prop( 'hostname' );
47
- pathname = $( this ).prop( 'pathname' );
48
- qs = $( this ).prop( 'search' );
49
- hash = $( this ).prop( 'hash' );
 
50
 
51
  // ie strips out the preceding / from pathname
52
  if ( pathname.length > 0 ) {
53
- if ( pathname.charAt( 0 ) != '/' ) {
54
  pathname = '/' + pathname;
55
  }
56
  }
57
 
58
- if ( (window.location.hostname == hostname) && (window.location.pathname == pathname) && (window.location.search == qs) && (hash !== '') ) {
59
-
60
- // escape jquery selector chars, but keep the #
61
- var hash_selector = hash.replace( /([ !"$%&'()*+,.\/:;<=>?@[\]^`{|}~])/g, '\\$1' );
62
-
63
- // check if element exists with id=__
64
- if ( $( hash_selector ).length > 0 )
65
- target = hash;
66
- else {
67
- // must be an anchor (a name=__)
68
- anchor = hash;
69
- anchor = anchor.replace( '#', '' );
70
- target = 'a[name="' + anchor + '"]';
71
- // verify it exists
72
- if ( $( target ).length == 0 )
73
- target = '';
74
  }
75
 
76
  // check offset setting
@@ -111,6 +120,7 @@ jQuery( function( $ ) {
111
 
112
  if ( typeof ezTOC.visibility_hide_by_default != 'undefined' ) {
113
 
 
114
  var toggle = $( 'a.ez-toc-toggle' );
115
  var invert = ezTOC.visibility_hide_by_default;
116
 
@@ -130,10 +140,10 @@ jQuery( function( $ ) {
130
 
131
  if ( ! toggle.data( 'visible' ) ) {
132
 
133
- $( 'ul.ez-toc-list' ).hide();
134
  }
135
 
136
- toggle.click( function( event ) {
137
 
138
  event.preventDefault();
139
 
@@ -149,7 +159,7 @@ jQuery( function( $ ) {
149
  Cookies.set( 'ezTOC_hidetoc', '1', { expires: 30, path: '/' } );
150
  }
151
 
152
- $( 'ul.ez-toc-list' ).hide( 'fast' );
153
 
154
  } else {
155
 
@@ -163,7 +173,7 @@ jQuery( function( $ ) {
163
  Cookies.set( 'ezTOC_hidetoc', null, { path: '/' } );
164
  }
165
 
166
- $( 'ul.ez-toc-list' ).show( 'fast' );
167
 
168
  }
169
 
@@ -191,7 +201,7 @@ jQuery( function( $ ) {
191
  removeStyleFromNonActiveListElement( activeListElementLink, listElementLinks );
192
  setStyleForActiveListElementElement( activeListElementLink );
193
  }
194
- };
195
 
196
  function activateSetActiveEzTocListElement() {
197
  if ( headings.length > 0 && $('.ez-toc-widget-container').length) {
@@ -267,8 +277,9 @@ jQuery( function( $ ) {
267
  // But because it get's directly removed afterwards it never will be rendered by the browser
268
  // (at least in my tests in FF, Chrome, IE11 and Edge)
269
  $listElement.parent().append( '<li id="ez-toc-height-test" class="active">' + content + '</li>' );
270
- var height = jQuery( '#ez-toc-height-test' ).height();
271
- jQuery( '#ez-toc-height-test' ).remove();
 
272
  return height - $listElement.children( 'ul' ).first().height();
273
  }
274
 
1
  jQuery( function( $ ) {
2
 
3
+ /**
4
+ * @typedef ezTOC
5
+ * @type {Object} ezTOC
6
+ * @property {string} affixSelector
7
+ * @property {string} scroll_offset
8
+ * @property {string} smooth_scroll
9
+ * @property {string} visibility_hide_by_default
10
+ */
11
+
12
  if ( typeof ezTOC != 'undefined' ) {
13
 
14
  var affix = $( '.ez-toc-widget-container.ez-toc-affix' );
26
  // check offset setting
27
  if ( typeof ezTOC.scroll_offset != 'undefined' ) {
28
 
29
+ affixOffset = parseInt( ezTOC.scroll_offset );
30
  }
31
 
32
+ $( ezTOC.affixSelector ).stick_in_parent( {
33
+ inner_scrolling: false,
34
+ offset_top: affixOffset
35
+ } )
36
  }
37
 
38
  $.fn.shrinkTOCWidth = function() {
46
  $( this ).css( 'width', '' );
47
  };
48
 
49
+ var smoothScroll = parseInt( ezTOC.smooth_scroll );
50
+
51
+ if ( 1 === smoothScroll ) {
52
 
53
+ $( 'a.ez-toc-link' ).on( 'click', function() {
54
 
55
+ var self = $( this );
56
 
57
+ var target = '';
58
+ var hostname = self.prop( 'hostname' );
59
+ var pathname = self.prop( 'pathname' );
60
+ var qs = self.prop( 'search' );
61
+ var hash = self.prop( 'hash' );
62
 
63
  // ie strips out the preceding / from pathname
64
  if ( pathname.length > 0 ) {
65
+ if ( pathname.charAt( 0 ) !== '/' ) {
66
  pathname = '/' + pathname;
67
  }
68
  }
69
 
70
+ if ( ( window.location.hostname === hostname ) &&
71
+ ( window.location.pathname === pathname ) &&
72
+ ( window.location.search === qs ) &&
73
+ ( hash !== '' )
74
+ ) {
75
+
76
+ // var id = decodeURIComponent( hash.replace( '#', '' ) );
77
+ target = '[id="' + hash.replace( '#', '' ) + '"]';
78
+
79
+ // verify it exists
80
+ if ( $( target ).length === 0 ) {
81
+ console.log( 'ezTOC scrollTarget Not Found: ' + target );
82
+ target = '';
 
 
 
83
  }
84
 
85
  // check offset setting
120
 
121
  if ( typeof ezTOC.visibility_hide_by_default != 'undefined' ) {
122
 
123
+ var toc = $( 'ul.ez-toc-list' );
124
  var toggle = $( 'a.ez-toc-toggle' );
125
  var invert = ezTOC.visibility_hide_by_default;
126
 
140
 
141
  if ( ! toggle.data( 'visible' ) ) {
142
 
143
+ toc.hide();
144
  }
145
 
146
+ toggle.on( 'click', function( event ) {
147
 
148
  event.preventDefault();
149
 
159
  Cookies.set( 'ezTOC_hidetoc', '1', { expires: 30, path: '/' } );
160
  }
161
 
162
+ toc.hide( 'fast' );
163
 
164
  } else {
165
 
173
  Cookies.set( 'ezTOC_hidetoc', null, { path: '/' } );
174
  }
175
 
176
+ toc.show( 'fast' );
177
 
178
  }
179
 
201
  removeStyleFromNonActiveListElement( activeListElementLink, listElementLinks );
202
  setStyleForActiveListElementElement( activeListElementLink );
203
  }
204
+ }
205
 
206
  function activateSetActiveEzTocListElement() {
207
  if ( headings.length > 0 && $('.ez-toc-widget-container').length) {
277
  // But because it get's directly removed afterwards it never will be rendered by the browser
278
  // (at least in my tests in FF, Chrome, IE11 and Edge)
279
  $listElement.parent().append( '<li id="ez-toc-height-test" class="active">' + content + '</li>' );
280
+ var listItem = $( '#ez-toc-height-test' );
281
+ var height = listItem.height();
282
+ listItem.remove();
283
  return height - $listElement.children( 'ul' ).first().height();
284
  }
285
 
assets/js/front.min.js CHANGED
@@ -1 +1 @@
1
- jQuery((function($){if("undefined"!=typeof ezTOC){var affix;if(0!==$(".ez-toc-widget-container.ez-toc-affix").length){var affixOffset=30;void 0!==ezTOC.scroll_offset&&(affixOffset=ezTOC.scroll_offset),$(ezTOC.affixSelector).stick_in_parent({inner_scrolling:!1,offset_top:parseInt(affixOffset)})}if($.fn.shrinkTOCWidth=function(){$(this).css({width:"auto",display:"table"}),/MSIE 7\./.test(navigator.userAgent)&&$(this).css("width","")},1==ezTOC.smooth_scroll){var target=hostname=pathname=qs=hash=null;$("body a").click((function(event){if(hostname=$(this).prop("hostname"),pathname=$(this).prop("pathname"),qs=$(this).prop("search"),hash=$(this).prop("hash"),pathname.length>0&&"/"!=pathname.charAt(0)&&(pathname="/"+pathname),window.location.hostname==hostname&&window.location.pathname==pathname&&window.location.search==qs&&""!==hash){var hash_selector=hash.replace(/([ !"$%&'()*+,.\/:;<=>?@[\]^`{|}~])/g,"\\$1");if($(hash_selector).length>0?target=hash:(anchor=hash,anchor=anchor.replace("#",""),target='a[name="'+anchor+'"]',0==$(target).length&&(target="")),void 0!==ezTOC.scroll_offset)var offset=-1*ezTOC.scroll_offset;else{var adminbar=$("#wpadminbar");offset=adminbar.length>0&&adminbar.is(":visible")?-30:0}target&&$.smoothScroll({scrollTarget:target,offset:offset,beforeScroll:deactivateSetActiveEzTocListElement,afterScroll:function(){setActiveEzTocListElement(),activateSetActiveEzTocListElement()}})}}))}if(void 0!==ezTOC.visibility_hide_by_default){var toggle=$("a.ez-toc-toggle"),invert=ezTOC.visibility_hide_by_default;Cookies&&1==Cookies.get("ezTOC_hidetoc")?toggle.data("visible",!1):toggle.data("visible",!0),invert&&toggle.data("visible",!1),toggle.data("visible")||$("ul.ez-toc-list").hide(),toggle.click((function(event){event.preventDefault(),$(this).data("visible")?($(this).data("visible",!1),Cookies&&(invert?Cookies.set("ezTOC_hidetoc",null,{path:"/"}):Cookies.set("ezTOC_hidetoc","1",{expires:30,path:"/"})),$("ul.ez-toc-list").hide("fast")):($(this).data("visible",!0),Cookies&&(invert?Cookies.set("ezTOC_hidetoc","1",{expires:30,path:"/"}):Cookies.set("ezTOC_hidetoc",null,{path:"/"})),$("ul.ez-toc-list").show("fast"))}))}var headings=$("span.ez-toc-section").toArray(),headingToListElementLinkMap=getHeadingToListElementLinkMap(headings),listElementLinks=$.map(headingToListElementLinkMap,(function(value,key){return value})),scrollOffset=getScrollOffset();function setActiveEzTocListElement(){var activeHeading=getActiveHeading(scrollOffset,headings);if(activeHeading){var activeListElementLink=headingToListElementLinkMap[activeHeading.id];removeStyleFromNonActiveListElement(activeListElementLink,listElementLinks),setStyleForActiveListElementElement(activeListElementLink)}}function activateSetActiveEzTocListElement(){headings.length>0&&$(".ez-toc-widget-container").length&&$(window).on("load resize scroll",setActiveEzTocListElement)}function deactivateSetActiveEzTocListElement(){$(window).off("load resize scroll",setActiveEzTocListElement)}function getEzTocListElementLinkByHeading(heading){return $('.ez-toc-widget-container .ez-toc-list a[href="#'+$(heading).attr("id")+'"]')}function getHeadingToListElementLinkMap(headings){return headings.reduce((function(map,heading){return map[heading.id]=getEzTocListElementLinkByHeading(heading),map}),{})}function getScrollOffset(){var scrollOffset=5;void 0!==ezTOC.smooth_scroll&&1===parseInt(ezTOC.smooth_scroll)&&(scrollOffset=void 0!==ezTOC.scroll_offset?parseInt(ezTOC.scroll_offset):30);var adminbar=$("#wpadminbar");return adminbar.length&&(scrollOffset+=adminbar.height()),scrollOffset}function getActiveHeading(topOffset,headings){var scrollTop,relevantOffset=$(window).scrollTop()+topOffset+1,activeHeading=headings[0],closestHeadingAboveOffset=relevantOffset-$(activeHeading).offset().top;return headings.forEach((function(section){var topOffset=relevantOffset-$(section).offset().top;topOffset>0&&topOffset<closestHeadingAboveOffset&&(closestHeadingAboveOffset=topOffset,activeHeading=section)})),activeHeading}function removeStyleFromNonActiveListElement(activeListElementLink,listElementLinks){listElementLinks.forEach((function(listElementLink){activeListElementLink!==listElementLink&&listElementLink.parent().hasClass("active")&&listElementLink.parent().removeClass("active")}))}function correctActiveListElementBackgroundColorHeight(activeListElement){var listElementHeight;addListElementBackgroundColorHeightStyleToHead(getListElementHeightWithoutUlChildren(activeListElement))}function getListElementHeightWithoutUlChildren(listElement){var $listElement=$(listElement),content=$listElement.html();$listElement.parent().append('<li id="ez-toc-height-test" class="active">'+content+"</li>");var height=jQuery("#ez-toc-height-test").height();return jQuery("#ez-toc-height-test").remove(),height-$listElement.children("ul").first().height()}function addListElementBackgroundColorHeightStyleToHead(listElementHeight){$("#ez-toc-active-height").remove(),$('<style id="ez-toc-active-height">.ez-toc-widget-container ul.ez-toc-list li.active::before {height:'+listElementHeight+"px;} </style>").appendTo("head")}function setStyleForActiveListElementElement(activeListElementLink){var activeListElement=activeListElementLink.parent();activeListElement.hasClass("active")||activeListElement.addClass("active"),correctActiveListElementBackgroundColorHeight(activeListElement)}activateSetActiveEzTocListElement()}}));
1
+ jQuery((function($){if("undefined"!=typeof ezTOC){var affix,smoothScroll;if(0!==$(".ez-toc-widget-container.ez-toc-affix").length){var affixOffset=30;void 0!==ezTOC.scroll_offset&&(affixOffset=parseInt(ezTOC.scroll_offset)),$(ezTOC.affixSelector).stick_in_parent({inner_scrolling:!1,offset_top:affixOffset})}if($.fn.shrinkTOCWidth=function(){$(this).css({width:"auto",display:"table"}),/MSIE 7\./.test(navigator.userAgent)&&$(this).css("width","")},1===parseInt(ezTOC.smooth_scroll)&&$("a.ez-toc-link").on("click",(function(){var self=$(this),target="",hostname=self.prop("hostname"),pathname=self.prop("pathname"),qs=self.prop("search"),hash=self.prop("hash");if(pathname.length>0&&"/"!==pathname.charAt(0)&&(pathname="/"+pathname),window.location.hostname===hostname&&window.location.pathname===pathname&&window.location.search===qs&&""!==hash){if(target='[id="'+hash.replace("#","")+'"]',0===$(target).length&&(console.log("ezTOC scrollTarget Not Found: "+target),target=""),void 0!==ezTOC.scroll_offset)var offset=-1*ezTOC.scroll_offset;else{var adminbar=$("#wpadminbar");offset=adminbar.length>0&&adminbar.is(":visible")?-30:0}target&&$.smoothScroll({scrollTarget:target,offset:offset,beforeScroll:deactivateSetActiveEzTocListElement,afterScroll:function(){setActiveEzTocListElement(),activateSetActiveEzTocListElement()}})}})),void 0!==ezTOC.visibility_hide_by_default){var toc=$("ul.ez-toc-list"),toggle=$("a.ez-toc-toggle"),invert=ezTOC.visibility_hide_by_default;Cookies&&1==Cookies.get("ezTOC_hidetoc")?toggle.data("visible",!1):toggle.data("visible",!0),invert&&toggle.data("visible",!1),toggle.data("visible")||toc.hide(),toggle.on("click",(function(event){event.preventDefault(),$(this).data("visible")?($(this).data("visible",!1),Cookies&&(invert?Cookies.set("ezTOC_hidetoc",null,{path:"/"}):Cookies.set("ezTOC_hidetoc","1",{expires:30,path:"/"})),toc.hide("fast")):($(this).data("visible",!0),Cookies&&(invert?Cookies.set("ezTOC_hidetoc","1",{expires:30,path:"/"}):Cookies.set("ezTOC_hidetoc",null,{path:"/"})),toc.show("fast"))}))}var headings=$("span.ez-toc-section").toArray(),headingToListElementLinkMap=getHeadingToListElementLinkMap(headings),listElementLinks=$.map(headingToListElementLinkMap,(function(value,key){return value})),scrollOffset=getScrollOffset();function setActiveEzTocListElement(){var activeHeading=getActiveHeading(scrollOffset,headings);if(activeHeading){var activeListElementLink=headingToListElementLinkMap[activeHeading.id];removeStyleFromNonActiveListElement(activeListElementLink,listElementLinks),setStyleForActiveListElementElement(activeListElementLink)}}function activateSetActiveEzTocListElement(){headings.length>0&&$(".ez-toc-widget-container").length&&$(window).on("load resize scroll",setActiveEzTocListElement)}function deactivateSetActiveEzTocListElement(){$(window).off("load resize scroll",setActiveEzTocListElement)}function getEzTocListElementLinkByHeading(heading){return $('.ez-toc-widget-container .ez-toc-list a[href="#'+$(heading).attr("id")+'"]')}function getHeadingToListElementLinkMap(headings){return headings.reduce((function(map,heading){return map[heading.id]=getEzTocListElementLinkByHeading(heading),map}),{})}function getScrollOffset(){var scrollOffset=5;void 0!==ezTOC.smooth_scroll&&1===parseInt(ezTOC.smooth_scroll)&&(scrollOffset=void 0!==ezTOC.scroll_offset?parseInt(ezTOC.scroll_offset):30);var adminbar=$("#wpadminbar");return adminbar.length&&(scrollOffset+=adminbar.height()),scrollOffset}function getActiveHeading(topOffset,headings){var scrollTop,relevantOffset=$(window).scrollTop()+topOffset+1,activeHeading=headings[0],closestHeadingAboveOffset=relevantOffset-$(activeHeading).offset().top;return headings.forEach((function(section){var topOffset=relevantOffset-$(section).offset().top;topOffset>0&&topOffset<closestHeadingAboveOffset&&(closestHeadingAboveOffset=topOffset,activeHeading=section)})),activeHeading}function removeStyleFromNonActiveListElement(activeListElementLink,listElementLinks){listElementLinks.forEach((function(listElementLink){activeListElementLink!==listElementLink&&listElementLink.parent().hasClass("active")&&listElementLink.parent().removeClass("active")}))}function correctActiveListElementBackgroundColorHeight(activeListElement){var listElementHeight;addListElementBackgroundColorHeightStyleToHead(getListElementHeightWithoutUlChildren(activeListElement))}function getListElementHeightWithoutUlChildren(listElement){var $listElement=$(listElement),content=$listElement.html();$listElement.parent().append('<li id="ez-toc-height-test" class="active">'+content+"</li>");var listItem=$("#ez-toc-height-test"),height=listItem.height();return listItem.remove(),height-$listElement.children("ul").first().height()}function addListElementBackgroundColorHeightStyleToHead(listElementHeight){$("#ez-toc-active-height").remove(),$('<style id="ez-toc-active-height">.ez-toc-widget-container ul.ez-toc-list li.active::before {height:'+listElementHeight+"px;} </style>").appendTo("head")}function setStyleForActiveListElementElement(activeListElementLink){var activeListElement=activeListElementLink.parent();activeListElement.hasClass("active")||activeListElement.addClass("active"),correctActiveListElementBackgroundColorHeight(activeListElement)}activateSetActiveEzTocListElement()}}));
easy-table-of-contents.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Easy Table of Contents
4
  * Plugin URI: http://connections-pro.com/
5
  * Description: Adds a user friendly and fully automatic way to create and display a table of contents generated from the page content.
6
- * Version: 2.0.6
7
  * Author: Steven A. Zahm
8
  * Author URI: http://connections-pro.com/
9
  * Text Domain: easy-table-of-contents
@@ -26,7 +26,7 @@
26
  * @package Easy Table of Contents
27
  * @category Plugin
28
  * @author Steven A. Zahm
29
- * @version 2.0.6
30
  */
31
 
32
  use function Easy_Plugins\Table_Of_Contents\String\mb_find_replace;
@@ -47,7 +47,7 @@ if ( ! class_exists( 'ezTOC' ) ) {
47
  * @since 1.0
48
  * @var string
49
  */
50
- const VERSION = '2.0.6';
51
 
52
  /**
53
  * Stores the instance of this class.
@@ -226,7 +226,14 @@ if ( ! class_exists( 'ezTOC' ) ) {
226
  wp_register_script( 'js-cookie', EZ_TOC_URL . "vendor/js-cookie/js.cookie$min.js", array(), '2.2.1', TRUE );
227
  wp_register_script( 'jquery-smooth-scroll', EZ_TOC_URL . "vendor/smooth-scroll/jquery.smooth-scroll$min.js", array( 'jquery' ), '2.2.0', TRUE );
228
  wp_register_script( 'jquery-sticky-kit', EZ_TOC_URL . "vendor/sticky-kit/jquery.sticky-kit$min.js", array( 'jquery' ), '1.9.2', TRUE );
229
- wp_register_script( 'ez-toc-js', EZ_TOC_URL . "assets/js/front$min.js", array( 'jquery-smooth-scroll', 'js-cookie', 'jquery-sticky-kit'), ezTOC::VERSION, TRUE );
 
 
 
 
 
 
 
230
 
231
  if ( ! ezTOC_Option::get( 'exclude_css' ) ) {
232
 
3
  * Plugin Name: Easy Table of Contents
4
  * Plugin URI: http://connections-pro.com/
5
  * Description: Adds a user friendly and fully automatic way to create and display a table of contents generated from the page content.
6
+ * Version: 2.0.7
7
  * Author: Steven A. Zahm
8
  * Author URI: http://connections-pro.com/
9
  * Text Domain: easy-table-of-contents
26
  * @package Easy Table of Contents
27
  * @category Plugin
28
  * @author Steven A. Zahm
29
+ * @version 2.0.7
30
  */
31
 
32
  use function Easy_Plugins\Table_Of_Contents\String\mb_find_replace;
47
  * @since 1.0
48
  * @var string
49
  */
50
+ const VERSION = '2.0.7';
51
 
52
  /**
53
  * Stores the instance of this class.
226
  wp_register_script( 'js-cookie', EZ_TOC_URL . "vendor/js-cookie/js.cookie$min.js", array(), '2.2.1', TRUE );
227
  wp_register_script( 'jquery-smooth-scroll', EZ_TOC_URL . "vendor/smooth-scroll/jquery.smooth-scroll$min.js", array( 'jquery' ), '2.2.0', TRUE );
228
  wp_register_script( 'jquery-sticky-kit', EZ_TOC_URL . "vendor/sticky-kit/jquery.sticky-kit$min.js", array( 'jquery' ), '1.9.2', TRUE );
229
+
230
+ wp_register_script(
231
+ 'ez-toc-js',
232
+ EZ_TOC_URL . "assets/js/front$min.js",
233
+ array( 'jquery-smooth-scroll', 'js-cookie', 'jquery-sticky-kit' ),
234
+ ezTOC::VERSION . '-' . filemtime( EZ_TOC_PATH . "assets/js/front$min.js" ),
235
+ true
236
+ );
237
 
238
  if ( ! ezTOC_Option::get( 'exclude_css' ) ) {
239
 
includes/class.post.php CHANGED
@@ -359,7 +359,7 @@ class ezTOC_Post {
359
  * @param $selectors array Array of classes/id selector to exclude from TOC.
360
  * @param $content string Post content.
361
  */
362
- $selectors = apply_filters( 'ez_toc_exclude_by_selector', array(), $content );
363
 
364
  $nodes = $html->Find( implode( ',', $selectors ) );
365
 
@@ -426,7 +426,7 @@ class ezTOC_Post {
426
 
427
  }
428
 
429
- return $matches;
430
  }
431
 
432
  /**
@@ -469,7 +469,7 @@ class ezTOC_Post {
469
 
470
  foreach ( $matches as $i => $match ) {
471
 
472
- if ( $this->inExcludedNode( $match[3] ) ) {
473
 
474
  unset( $matches[ $i ] );
475
  }
@@ -524,13 +524,14 @@ class ezTOC_Post {
524
  if ( count( $levels ) != 6 ) {
525
 
526
  $new_matches = array();
527
- $count = count( $matches );
528
 
529
- for ( $i = 0; $i < $count; $i++ ) {
 
530
 
531
  if ( in_array( $matches[ $i ][2], $levels ) ) {
532
 
533
- $new_matches[] = $matches[ $i ];
534
  }
535
  }
536
 
@@ -582,9 +583,10 @@ class ezTOC_Post {
582
  }
583
 
584
  $new_matches = array();
585
- $count = count( $matches );
586
 
587
- for ( $i = 0; $i < $count; $i++ ) {
 
588
 
589
  $found = false;
590
 
@@ -613,14 +615,14 @@ class ezTOC_Post {
613
 
614
  if ( ! $found ) {
615
 
616
- $new_matches[] = $matches[ $i ];
617
  }
618
  }
619
 
620
- if ( count( $matches ) != count( $new_matches ) ) {
621
-
622
- $matches = $new_matches;
623
- }
624
  }
625
  }
626
 
@@ -682,11 +684,12 @@ class ezTOC_Post {
682
  private function alternateHeadings( &$matches ) {
683
 
684
  $alt_headings = $this->getAlternateHeadings();
685
- $count = count( $matches );
686
 
687
  if ( 0 < count( $alt_headings ) ) {
688
 
689
- for ( $i = 0; $i < $count; $i++ ) {
 
690
 
691
  foreach ( $alt_headings as $original_heading => $alt_heading ) {
692
 
@@ -745,9 +748,10 @@ class ezTOC_Post {
745
  */
746
  private function headingIDs( &$matches ) {
747
 
748
- $count = count( $matches );
749
 
750
- for ( $i = 0; $i < $count; $i++ ) {
 
751
 
752
  $matches[ $i ]['id'] = $this->generateHeadingIDFromTitle( $matches[ $i ][0] );
753
  }
@@ -790,7 +794,8 @@ class ezTOC_Post {
790
  $return = html_entity_decode( $return, ENT_QUOTES, get_option( 'blog_charset' ) );
791
 
792
  // remove non alphanumeric chars
793
- $return = preg_replace( '/[^a-zA-Z0-9 \-_]*/', '', $return );
 
794
 
795
  // convert spaces to _
796
  $return = preg_replace( '/\s+/', '_', $return );
@@ -798,6 +803,23 @@ class ezTOC_Post {
798
  // remove trailing - and _
799
  $return = rtrim( $return, '-_' );
800
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
801
  // lowercase everything?
802
  if ( ezTOC_Option::get( 'lowercase' ) ) {
803
 
@@ -845,20 +867,21 @@ class ezTOC_Post {
845
  private function removeEmptyHeadings( &$matches ) {
846
 
847
  $new_matches = array();
848
- $count = count( $matches );
849
 
850
- for ( $i = 0; $i < $count; $i ++ ) {
 
851
 
852
  if ( trim( strip_tags( $matches[ $i ][0] ) ) != false ) {
853
 
854
- $new_matches[] = $matches[ $i ];
855
  }
856
  }
857
 
858
- if ( count( $matches ) != count( $new_matches ) ) {
859
-
860
- $matches = $new_matches;
861
- }
862
 
863
  return $matches;
864
  }
@@ -902,9 +925,10 @@ class ezTOC_Post {
902
  //$headings = wp_list_pluck( $this->pages[ $page ]['headings'], 0 );
903
 
904
  $matches = $this->pages[ $page ]['headings'];
905
- $count = count( $matches );
906
 
907
- for ( $i = 0; $i < $count; $i++ ) {
 
908
 
909
  //$anchor = $matches[ $i ]['id'];
910
  $headings[] = str_replace(
@@ -946,9 +970,10 @@ class ezTOC_Post {
946
  if ( isset( $this->pages[ $page ] ) ) {
947
 
948
  $matches = $this->pages[ $page ]['headings'];
949
- $count = count( $matches );
950
 
951
- for ( $i = 0; $i < $count; $i++ ) {
 
952
 
953
  $anchor = $matches[ $i ]['id'];
954
  $headings[] = str_replace(
@@ -957,8 +982,8 @@ class ezTOC_Post {
957
  '</h' . $matches[ $i ][2] . '>' // end of heading
958
  ),
959
  array(
960
- '>',
961
- '<span class="ez-toc-section" id="' . $anchor . '"></span></h' . $matches[ $i ][2] . '>'
962
  ),
963
  $matches[ $i ][0]
964
  );
@@ -1179,7 +1204,8 @@ class ezTOC_Post {
1179
  //self::$collision_collector = array();
1180
 
1181
  // find the minimum heading to establish our baseline
1182
- for ( $i = 0; $i < count( $matches ); $i ++ ) {
 
1183
  if ( $current_depth > $matches[ $i ][2] ) {
1184
  $current_depth = (int) $matches[ $i ][2];
1185
  }
@@ -1188,7 +1214,8 @@ class ezTOC_Post {
1188
  $numbered_items[ $current_depth ] = 0;
1189
  $numbered_items_min = $current_depth;
1190
 
1191
- for ( $i = 0; $i < count( $matches ); $i ++ ) {
 
1192
 
1193
  $level = $matches[ $i ][2];
1194
  $count = $i + 1;
@@ -1246,7 +1273,8 @@ class ezTOC_Post {
1246
 
1247
  } else {
1248
 
1249
- for ( $i = 0; $i < count( $matches ); $i++ ) {
 
1250
 
1251
  $count = $i + 1;
1252
 
@@ -1279,7 +1307,7 @@ class ezTOC_Post {
1279
 
1280
  return sprintf(
1281
  '<a class="ez-toc-link ez-toc-heading-' . $count . '" href="%1$s" title="%2$s">%3$s</a>',
1282
- esc_url( $this->createTOCItemURL( $id, $page ) ),
1283
  esc_attr( strip_tags( $title ) ),
1284
  $title
1285
  );
359
  * @param $selectors array Array of classes/id selector to exclude from TOC.
360
  * @param $content string Post content.
361
  */
362
+ $selectors = apply_filters( 'ez_toc_exclude_by_selector', array( '.ez-toc-exclude-headings' ), $content );
363
 
364
  $nodes = $html->Find( implode( ',', $selectors ) );
365
 
426
 
427
  }
428
 
429
+ return array_values( $matches ); // Rest the array index.
430
  }
431
 
432
  /**
469
 
470
  foreach ( $matches as $i => $match ) {
471
 
472
+ if ( $this->inExcludedNode( "{$match[3]}</h$match[2]>" ) ) {
473
 
474
  unset( $matches[ $i ] );
475
  }
524
  if ( count( $levels ) != 6 ) {
525
 
526
  $new_matches = array();
527
+ //$count = count( $matches );
528
 
529
+ //for ( $i = 0; $i < $count; $i++ ) {
530
+ foreach ( $matches as $i => $match ) {
531
 
532
  if ( in_array( $matches[ $i ][2], $levels ) ) {
533
 
534
+ $new_matches[ $i ] = $matches[ $i ];
535
  }
536
  }
537
 
583
  }
584
 
585
  $new_matches = array();
586
+ //$count = count( $matches );
587
 
588
+ //for ( $i = 0; $i < $count; $i++ ) {
589
+ foreach ( $matches as $i => $match ) {
590
 
591
  $found = false;
592
 
615
 
616
  if ( ! $found ) {
617
 
618
+ $new_matches[ $i ] = $matches[ $i ];
619
  }
620
  }
621
 
622
+ //if ( count( $matches ) != count( $new_matches ) ) {
623
+ //
624
+ // $matches = $new_matches;
625
+ //}
626
  }
627
  }
628
 
684
  private function alternateHeadings( &$matches ) {
685
 
686
  $alt_headings = $this->getAlternateHeadings();
687
+ //$count = count( $matches );
688
 
689
  if ( 0 < count( $alt_headings ) ) {
690
 
691
+ //for ( $i = 0; $i < $count; $i++ ) {
692
+ foreach ( $matches as $i => $match ) {
693
 
694
  foreach ( $alt_headings as $original_heading => $alt_heading ) {
695
 
748
  */
749
  private function headingIDs( &$matches ) {
750
 
751
+ //$count = count( $matches );
752
 
753
+ //for ( $i = 0; $i < $count; $i++ ) {
754
+ foreach ( $matches as $i => $match ) {
755
 
756
  $matches[ $i ]['id'] = $this->generateHeadingIDFromTitle( $matches[ $i ][0] );
757
  }
794
  $return = html_entity_decode( $return, ENT_QUOTES, get_option( 'blog_charset' ) );
795
 
796
  // remove non alphanumeric chars
797
+ //$return = preg_replace( '/[^a-zA-Z0-9 \-_]*/', '', $return );
798
+ $return = preg_replace( '/[\x00-\x1F\x7F\-_]*/u', '', $return );
799
 
800
  // convert spaces to _
801
  $return = preg_replace( '/\s+/', '_', $return );
803
  // remove trailing - and _
804
  $return = rtrim( $return, '-_' );
805
 
806
+ /*
807
+ * Encode URI based on ECMA-262.
808
+ *
809
+ * Only required to support the jQuery smoothScroll library.
810
+ *
811
+ * @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI#Description
812
+ * @link https://stackoverflow.com/a/19858404/5351316
813
+ */
814
+ $return = preg_replace_callback(
815
+ "{[^0-9a-z_.!~*'();,/?:@&=+$#-]}i",
816
+ function( $m ) {
817
+
818
+ return sprintf( '%%%02X', ord( $m[0] ) );
819
+ },
820
+ $return
821
+ );
822
+
823
  // lowercase everything?
824
  if ( ezTOC_Option::get( 'lowercase' ) ) {
825
 
867
  private function removeEmptyHeadings( &$matches ) {
868
 
869
  $new_matches = array();
870
+ //$count = count( $matches );
871
 
872
+ //for ( $i = 0; $i < $count; $i ++ ) {
873
+ foreach ( $matches as $i => $match ) {
874
 
875
  if ( trim( strip_tags( $matches[ $i ][0] ) ) != false ) {
876
 
877
+ $new_matches[ $i ] = $matches[ $i ];
878
  }
879
  }
880
 
881
+ //if ( count( $matches ) != count( $new_matches ) ) {
882
+ //
883
+ // $matches = $new_matches;
884
+ //}
885
 
886
  return $matches;
887
  }
925
  //$headings = wp_list_pluck( $this->pages[ $page ]['headings'], 0 );
926
 
927
  $matches = $this->pages[ $page ]['headings'];
928
+ //$count = count( $matches );
929
 
930
+ //for ( $i = 0; $i < $count; $i++ ) {
931
+ foreach ( $matches as $i => $match ) {
932
 
933
  //$anchor = $matches[ $i ]['id'];
934
  $headings[] = str_replace(
970
  if ( isset( $this->pages[ $page ] ) ) {
971
 
972
  $matches = $this->pages[ $page ]['headings'];
973
+ //$count = count( $matches );
974
 
975
+ //for ( $i = 0; $i < $count; $i++ ) {
976
+ foreach ( $matches as $i => $match ) {
977
 
978
  $anchor = $matches[ $i ]['id'];
979
  $headings[] = str_replace(
982
  '</h' . $matches[ $i ][2] . '>' // end of heading
983
  ),
984
  array(
985
+ '><span class="ez-toc-section" id="' . $anchor . '"></span>',
986
+ '</h' . $matches[ $i ][2] . '>'
987
  ),
988
  $matches[ $i ][0]
989
  );
1204
  //self::$collision_collector = array();
1205
 
1206
  // find the minimum heading to establish our baseline
1207
+ //for ( $i = 0; $i < count( $matches ); $i ++ ) {
1208
+ foreach ( $matches as $i => $match ) {
1209
  if ( $current_depth > $matches[ $i ][2] ) {
1210
  $current_depth = (int) $matches[ $i ][2];
1211
  }
1214
  $numbered_items[ $current_depth ] = 0;
1215
  $numbered_items_min = $current_depth;
1216
 
1217
+ //for ( $i = 0; $i < count( $matches ); $i ++ ) {
1218
+ foreach ( $matches as $i => $match ) {
1219
 
1220
  $level = $matches[ $i ][2];
1221
  $count = $i + 1;
1273
 
1274
  } else {
1275
 
1276
+ //for ( $i = 0; $i < count( $matches ); $i++ ) {
1277
+ foreach ( $matches as $i => $match ) {
1278
 
1279
  $count = $i + 1;
1280
 
1307
 
1308
  return sprintf(
1309
  '<a class="ez-toc-link ez-toc-heading-' . $count . '" href="%1$s" title="%2$s">%3$s</a>',
1310
+ esc_attr( $this->createTOCItemURL( $id, $page ) ),
1311
  esc_attr( strip_tags( $title ) ),
1312
  $title
1313
  );
includes/class.widget-toc.php CHANGED
@@ -154,8 +154,6 @@ if ( ! class_exists( 'ezTOC_Widget' ) ) {
154
 
155
  if ( $post->hasTOCItems() ) {
156
 
157
- $css_classes = '';
158
-
159
  /**
160
  * @var string $before_widget
161
  * @var string $after_widget
@@ -164,6 +162,7 @@ if ( ! class_exists( 'ezTOC_Widget' ) ) {
164
  */
165
  extract( $args );
166
 
 
167
  $title = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
168
  //$items = ezTOC::extract_headings( $find, $replace, $post );
169
 
@@ -174,44 +173,53 @@ if ( ! class_exists( 'ezTOC_Widget' ) ) {
174
 
175
  if ( ezTOC_Option::get( 'show_hierarchy' ) ) {
176
 
177
- $css_classes = ' counter-hierarchy';
178
 
179
  } else {
180
 
181
- $css_classes .= ' counter-flat';
182
  }
183
 
184
  switch ( ezTOC_Option::get( 'counter' ) ) {
185
 
186
  case 'numeric':
187
- $css_classes .= ' counter-numeric';
188
  break;
189
 
190
  case 'roman':
191
- $css_classes .= ' counter-roman';
192
  break;
193
 
194
  case 'decimal':
195
- $css_classes .= ' counter-decimal';
196
  break;
197
  }
198
 
199
  if ( $instance['affix'] ) {
200
 
201
- $css_classes .= ' ez-toc-affix';
202
  }
203
 
204
- $css_classes = trim( $css_classes );
 
 
 
 
 
205
 
206
- // an empty class="" is invalid markup!
207
- if ( ! $css_classes ) {
208
 
209
- $css_classes = ' ';
 
210
  }
211
 
 
 
 
 
212
  echo $before_widget;
213
 
214
- echo '<div class="ez-toc-widget-container ' . $css_classes . '">' . PHP_EOL;
215
 
216
  do_action( 'ez_toc_before_widget' );
217
 
154
 
155
  if ( $post->hasTOCItems() ) {
156
 
 
 
157
  /**
158
  * @var string $before_widget
159
  * @var string $after_widget
162
  */
163
  extract( $args );
164
 
165
+ $class = array( 'ez-toc-v' . str_replace( '.', '_', ezTOC::VERSION ) );
166
  $title = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
167
  //$items = ezTOC::extract_headings( $find, $replace, $post );
168
 
173
 
174
  if ( ezTOC_Option::get( 'show_hierarchy' ) ) {
175
 
176
+ $class[] = 'counter-hierarchy';
177
 
178
  } else {
179
 
180
+ $class[] = 'counter-flat';
181
  }
182
 
183
  switch ( ezTOC_Option::get( 'counter' ) ) {
184
 
185
  case 'numeric':
186
+ $class[] = 'counter-numeric';
187
  break;
188
 
189
  case 'roman':
190
+ $class[] = 'counter-roman';
191
  break;
192
 
193
  case 'decimal':
194
+ $class[] = 'counter-decimal';
195
  break;
196
  }
197
 
198
  if ( $instance['affix'] ) {
199
 
200
+ $class[] = 'ez-toc-affix';
201
  }
202
 
203
+ $custom_classes = ezTOC_Option::get( 'css_container_class', '' );
204
+
205
+ if ( 0 < strlen( $custom_classes ) ) {
206
+
207
+ $custom_classes = explode( ' ', $custom_classes );
208
+ $custom_classes = apply_filters( 'ez_toc_container_class', $custom_classes, $this );
209
 
210
+ if ( is_array( $custom_classes ) ) {
 
211
 
212
+ $class = array_merge( $class, $custom_classes );
213
+ }
214
  }
215
 
216
+ $class = array_filter( $class );
217
+ $class = array_map( 'trim', $class );
218
+ $class = array_map( 'sanitize_html_class', $class );
219
+
220
  echo $before_widget;
221
 
222
+ echo '<div class="ez-toc-widget-container ' . implode( ' ', $class ) . '">' . PHP_EOL;
223
 
224
  do_action( 'ez_toc_before_widget' );
225
 
includes/inc.plugin-compatibility.php CHANGED
@@ -289,7 +289,7 @@ add_filter(
289
  'ez_toc_exclude_by_selector',
290
  function( $selectors ) {
291
 
292
- //$selectors['ultimate-addons-for-vc-composer'] = '.ult_tabs';
293
 
294
  return $selectors;
295
  }
289
  'ez_toc_exclude_by_selector',
290
  function( $selectors ) {
291
 
292
+ $selectors['ultimate-addons-for-vc-composer'] = '.ult_tabs';
293
 
294
  return $selectors;
295
  }