Easy Table of Contents - Version 1.0

Version Description

09/08/2015 = * Initial release. - Complete refactor and restructure of the original code for better design and separation of function to make code base much easier to maintain and extend. - Update all third party libraries. - Make much better use of the WordPress Settings API. - Minified CSS and JS files are used by default. Using SCRIPT_DEBUG will use the un-minified versions. - Add substantial amounts of phpDoc for developers. - Add many hooks to permit third party integrations. - Widget can be affixed/stuck to the page so it is always visible. - Widget will highlight the table of content sections that are currently visible in the browser viewport. - Widget will now generate table of contents using output from third party shortcodes. - Use wpColorPicker instead of farbtastic. - Remove all shortcodes. - Per post options are saved in post meta instead of set by shortcode.

=

Download this release

Release Info

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

Version 1.0

README.txt ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Easy Table of Contents ===
2
+ Contributors: shazahm1@hotmail.com
3
+ Donate link: http://connections-pro.com/
4
+ Tags: table of contents, toc
5
+ Requires at least: 3.2
6
+ Tested up to: 4.4
7
+ Stable tag: 1.0
8
+ License: GPLv2 or later
9
+ License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
+
11
+ Adds a user friendly and fully automatic way to create and display a table of contents generated from the page content.
12
+
13
+ == Description ==
14
+
15
+ A user friendly, featured focused plugin which allows you to insert a table of contents into your posts, pages and custom post types.
16
+
17
+ = Features =
18
+ * Automatically generate a table of contents for your posts, pages and custom post types by parsing its contents for headers.
19
+ * Optionally enable for pages and/or posts. Custom post types are supported, as long as their content is output with the `the_content()` template tag.
20
+ * Optionally auto insert the table of contents into the page, selectable by enabled post type.
21
+ * Provides many easy to understand options to configure when and where to insert the table of contents.
22
+ * Many options are available to configure how the inserted table of contents appears which include several builtin themes. If the supplied themes do no meet you needs, you can create your own by choosing you own colors for the border, background and link color.
23
+ * Multiple counter bullet formats to choose from; none, decimal, numeric and roman.
24
+ * Choose to display the table of contents hierarchical or not. This means headings of lower priority will be nested under headings of higher priority.
25
+ * User can optionally hide the table of contents. You full control of this feature. It can be disabled and you can choose to have it hidden by default.
26
+ * Supports smooth scrolling.
27
+ * Selectively enable or disabled the table of contents on a post by post basis.
28
+ * Choose which headings are used to generate the table of contents. This too can be set on a post by post basis.
29
+ * Easily exclude headers globally and on a post by post basis.
30
+ * If you rather not insert the table of contents in the post content, you can use the supplied widget and place the table of contents in your theme's sidebar.
31
+ * The widgets supports being affixed or stuck on the page so it is always visible as you scroll down the page. NOTE: this is an advanced option since every theme is different, you might need support from your theme developer to learn what the correct item selector to use in the settings to enable this feature.
32
+ * The widget auto highlights the sections currently visible on the page. The highlight color is configurable.
33
+ * Developer friendly with many action hooks and filters available. More can be added by request on [Github](https://github.com/shazahm1/Easy-Table-of-Contents). Pull requests are welcomed.
34
+
35
+ = Live Examples =
36
+
37
+ Here are links to documentation pages for several of the premium templates for the [Connections Business Directory plugin](https://wordpress.org/plugins/connections/) which utilize the widget included with this plugin:
38
+
39
+ * [cMap Template Docs](http://connections-pro.com/documentation/cmap/)
40
+ * [Circled Template Docs](http://connections-pro.com/documentation/circled/)
41
+ * [Gridder Template Docs](http://connections-pro.com/documentation/gridder/)
42
+
43
+ = Roadmap =
44
+ * Fragment caching for improved performance.
45
+ * Support for `<!--nextpage-->`.
46
+ * Customizer support.
47
+
48
+ = Requirements =
49
+
50
+ * **WordPress version:** >= 3.2
51
+ * **PHP version:** >= 5.2.4
52
+
53
+ = Credit =
54
+
55
+ Easy Table Contents is a fork of the excellent [Table of Contents Plus](https://wordpress.org/plugins/table-of-contents-plus/) plugin by [Michael Tran](http://dublue.com/plugins/toc/).
56
+
57
+ == Screenshots ==
58
+
59
+ 1. The General section of the settings.
60
+ 2. The Appearance section of the settings.
61
+ 3. The Advanced section of the settings.
62
+
63
+ == Installation ==
64
+
65
+ = Using the WordPress Plugin Search =
66
+
67
+ 1. Navigate to the `Add New` sub-page under the Plugins admin page.
68
+ 2. Search for `easy table of contents`.
69
+ 3. The plugin should be listed first in the search results.
70
+ 4. Click the `Install Now` link.
71
+ 5. Lastly click the `Activate Plugin` link to activate the plugin.
72
+
73
+ = Uploading in WordPress Admin =
74
+
75
+ 1. [Download the plugin zip file](http://wordpress.org/plugins/easy-table-of-contents/) and save it to your computer.
76
+ 2. Navigate to the `Add New` sub-page under the Plugins admin page.
77
+ 3. Click the `Upload` link.
78
+ 4. Select Easy Table of Contents zip file from where you saved the zip file on your computer.
79
+ 5. Click the `Install Now` button.
80
+ 6. Lastly click the `Activate Plugin` link to activate the plugin.
81
+
82
+ = Using FTP =
83
+
84
+ 1. [Download the plugin zip file](http://wordpress.org/plugins/easy-table-of-contents/) and save it to your computer.
85
+ 2. Extract the Easy Table of Contents zip file.
86
+ 3. Create a new directory named `easy-table-of-contents` directory in the `../wp-content/plugins/` directory.
87
+ 4. Upload the files from the folder extracted in Step 2.
88
+ 4. Activate the plugin on the Plugins admin page.
89
+
90
+ == Changelog ==
91
+
92
+ = 1.0 09/08/2015 =
93
+ * Initial release.
94
+ - Complete refactor and restructure of the original code for better design and separation of function to make code base much easier to maintain and extend.
95
+ - Update all third party libraries.
96
+ - Make much better use of the WordPress Settings API.
97
+ - Minified CSS and JS files are used by default. Using SCRIPT_DEBUG will use the un-minified versions.
98
+ - Add substantial amounts of phpDoc for developers.
99
+ - Add many hooks to permit third party integrations.
100
+ - Widget can be affixed/stuck to the page so it is always visible.
101
+ - Widget will highlight the table of content sections that are currently visible in the browser viewport.
102
+ - Widget will now generate table of contents using output from third party shortcodes.
103
+ - Use wpColorPicker instead of farbtastic.
104
+ - Remove all shortcodes.
105
+ - Per post options are saved in post meta instead of set by shortcode.
106
+
107
+ == Frequently Asked Questions ==
108
+
109
+ = Ok, I've installed this... what do I do next? =
110
+
111
+ You first stop should be the Table of Contents settings admin page. You can find this under the Settings menu item.
112
+
113
+ You first and only required decision is you need to decide which post types you want to enable Table of Contents support for. By default it is the Pages post type. If on Pages is the only place you plan on using Table of Contents, you have nothing to do on the Settings page. To keep things simple, I recommend not changing any of the other settings at this point. Many of the other settings control when and where the table of contents is inserted and changing these settings could cause it not to display making getting started a bit more difficult. After you get comfortable with how this works... then tweak away :)
114
+
115
+ With that out of the way make sure to read the **How are the tables of contents created?** FAQ so you know how the Table of Contents is automatically generated. After you have the page headers setup, or before, either way... Scroll down on the page you'll see a metabox named "*Table of Contents*", enable the *Insert table of contents.* option and Update and/or Publish you page. The table of contents should automatically be shown at the top of the page.
116
+
117
+ = How are the tables of contents created? =
118
+
119
+ The table of contents is generated by the headers found on a page. Headers are the [`<h1>,<h2>,<h3>,<h4>,<h5>,<h6>` HTML tags](http://www.w3schools.com/tags/tag_hn.asp). If you are using the WordPres Visual Post Editor, these header tags are used and inserted into the post when you select one of the [*Heading n* options from the formatting drop down](http://torquemag.io/wordpress-heading-tags/). Each header that is found on the page will create a table of content item. Here's an example which will create a table of contents containing the six items.
120
+
121
+ `<h1>Item 1</h1>
122
+ <h1>Item 2</h1>
123
+ <h1>Item 3</h1>
124
+ <h1>Item 4</h1>
125
+ <h1>Item 5</h1>
126
+ <h1>Item 6</h1>`
127
+
128
+ You can also create "nested" table of contents. This is difficult to explain so I'll illustrate building on the previous example. In this example a table of contents will be created with the same six items but now the first three will each an child item nested underneath it. The indentation is not necessary, it was only added for illustration purposes.
129
+
130
+ `<h1>Item 1</h1>
131
+ <h2>Item 1.1 -- Level 2</h2>
132
+ <h1>Item 2</h1>
133
+ <h2>Item 2.1 -- Level 2</h2>
134
+ <h1>Item 3</h1>
135
+ <h2>Item 3.1 -- Level 2</h2>
136
+ <h1>Item 4</h1>
137
+ <h1>Item 5</h1>
138
+ <h1>Item 6</h1>`
139
+
140
+ You are not limited to a single a single nested item either. You can add as many as you need. You can even create multiple nested levels...
141
+
142
+ `<h1>Item 1</h1>
143
+ <h2>Item 1.1 -- Level 2</h2>
144
+ <h3>Item 1.1.1 -- Level 3</h3>
145
+ <h3>Item 1.1.2 -- Level 3</h3>
146
+ <h3>Item 1.1.3 -- Level 3</h3>
147
+ <h2>Item 1.2 -- Level 2</h2>
148
+ <h3>Item 1.2.1 -- Level 3</h3>
149
+ <h3>Item 1.2.2 -- Level 3</h3>
150
+ <h3>Item 1.2.3 -- Level 3</h3>
151
+ <h2>Item 1.3 -- Level 2</h2>
152
+ <h1>Item 2</h1>
153
+ <h2>Item 2.1 -- Level 2</h2>
154
+ <h2>Item 2.2 -- Level 2</h2>
155
+ <h1>Item 3</h1>
156
+ <h2>Item 3.1 -- Level 2</h2>
157
+ <h2>Item 3.2 -- Level 2</h2>
158
+ <h1>Item 4</h1>
159
+ <h1>Item 5</h1>
160
+ <h1>Item 6</h1>`
161
+
162
+ You can nest up 6 levels deep if needed. I hope this helps you understand how to create and build your own auto generated table of contents on your sites!
163
+
164
+ == Upgrade Notice ==
165
+
166
+ = 1.0 =
167
+ Initial release.
assets/css/admin.css ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ div.tab_content table {
2
+ margin-bottom: 1em;
3
+ }
4
+ table.more_toc_options_table th, table.more_toc_options_table td {
5
+ padding: 0;
6
+ margin: 0;
7
+ }
8
+ table.more_toc_options_table th {
9
+ width: auto;
10
+ padding-right: 4px;
11
+ padding-top: 2px;
12
+ }
13
+ div.tab_content ul li {
14
+ margin-left: 2em;
15
+ list-style-type: disc;
16
+ }
17
+ div.tab_content ol li {
18
+ list-style: inherit;
19
+ }
20
+ div.tab_content pre {
21
+ margin-left: 2em;
22
+ }
23
+ ul#tabbed-nav {
24
+ margin-top: 1em;
25
+ }
26
+ #tabbed-nav {
27
+ margin: 0;
28
+ padding: 0;
29
+ float: left;
30
+ list-style: none;
31
+ height: 32px;
32
+ border-bottom: 1px solid #DFDFDF;
33
+ border-left: 1px solid #DFDFDF;
34
+ width: 100%;
35
+ }
36
+ #tabbed-nav li {
37
+ float: left;
38
+ margin: 0;
39
+ padding: 0;
40
+ height: 31px;
41
+ line-height: 31px;
42
+ border: 1px solid #DFDFDF;
43
+ border-left: none;
44
+ margin-bottom: -1px;
45
+ overflow: hidden;
46
+ position: relative;
47
+ background: #F5F5F5;
48
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#F5F5F5));
49
+ background-image: -webkit-linear-gradient(center top, #fff, #F5F5F5);
50
+ background-image: -moz-linear-gradient(center top, #fff, #F5F5F5);
51
+ background-image: -ms-linear-gradient(center top, #fff, #F5F5F5);
52
+ background-image: -o-linear-gradient(center top, #fff, #F5F5F5);
53
+ background-image: linear-gradient(center top, #fff, #F5F5F5);
54
+ }
55
+ #tabbed-nav li a {
56
+ text-decoration: none;
57
+ color: #000;
58
+ display: block;
59
+ font-size: 1.2em;
60
+ padding: 0 20px;
61
+ border: 1px solid #fff;
62
+ outline: none;
63
+ }
64
+ #tabbed-nav li a:hover {
65
+ background: #ECECEC;
66
+ }
67
+ html #tabbed-nav li.active, html #tabbed-nav li.active a:hover {
68
+ background: #fff;
69
+ border-bottom: 1px solid #fff;
70
+ }
71
+ div.tab_container {
72
+ border: 1px solid #DFDFDF;
73
+ border-top: none;
74
+ overflow: hidden;
75
+ clear: both;
76
+ float: left; width: 100%;
77
+ background: #fff;
78
+ margin-bottom: 2em;
79
+ padding-bottom: 2em;
80
+ }
81
+ div.tab_content {
82
+ padding: 10px;
83
+ padding-bottom: 0;
84
+ font-size: 1em;
85
+ }
86
+ h3 span.show_hide {
87
+ font-size: 0.85em;
88
+ font-weight: normal;
89
+ }
90
+ div.more_toc_options {
91
+ margin-top: 4px;
92
+ margin-left: 2em;
93
+ }
94
+ div.toc_theme_option {
95
+ width: 200px;
96
+ float: left;
97
+ margin-right: 5px;
98
+ }
99
+ #wpcontent select optgroup option {
100
+ padding-left: 15px;
101
+ }
102
+ input#width_custom,
103
+ input#font_size,
104
+ input#smooth_scroll_offset {
105
+ width: 50px;
106
+ text-align: center;
107
+ }
108
+ input.custom_colour_option {
109
+ width: 75px;
110
+ }
111
+ table#theme_custom, div#farbtastic_colour_wheel {
112
+ float: left;
113
+ }
114
+ table#theme_custom {
115
+ margin-top: 30px;
116
+ }
117
+ table#theme_custom img {
118
+ vertical-align: middle;
119
+ opacity: 0.4;
120
+ }
121
+ table#theme_custom img:hover {
122
+ cursor: pointer;
123
+ opacity: 1;
124
+ }
125
+ div#farbtastic_colour_wheel {
126
+ margin-left: 20px;
127
+ }
128
+ #tab3 h3:not(:first-child) {
129
+ margin-top: 2em;
130
+ }
131
+
132
+ /* My styles */
133
+ #toc input.small-text {
134
+ width: 50px;
135
+ padding: 2px;
136
+ height: 28px;
137
+ line-height: 28px;
138
+ vertical-align: bottom;
139
+ }
140
+
141
+ #toc .form-table tr > th > strong {
142
+ font-size: 18px;
143
+ font-style: italic;
144
+ }
assets/css/admin.min.css ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ div.tab_content table{margin-bottom:1em}table.more_toc_options_table th,table.more_toc_options_table td{padding:0;margin:0}table.more_toc_options_table th{width:auto;padding-right:4px;padding-top:2px}
2
+ div.tab_content ul li{margin-left:2em;list-style-type:disc}div.tab_content ol li{list-style:inherit}div.tab_content pre{margin-left:2em}ul#tabbed-nav{margin-top:1em}
3
+ #tabbed-nav{margin:0;padding:0;float:left;list-style:none;height:32px;border-bottom:1px solid #dfdfdf;border-left:1px solid #dfdfdf;width:100%}#tabbed-nav li{float:left;margin:0;padding:0;height:31px;line-height:31px;border:1px solid #dfdfdf;border-left:none;margin-bottom:-1px;overflow:hidden;position:relative;background:#f5f5f5;background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f5f5f5));background-image:-webkit-linear-gradient(center top,#fff,#f5f5f5);background-image:-moz-linear-gradient(center top,#fff,#f5f5f5);background-image:-ms-linear-gradient(center top,#fff,#f5f5f5);background-image:-o-linear-gradient(center top,#fff,#f5f5f5);background-image:linear-gradient(center top,#fff,#f5f5f5)}
4
+ #tabbed-nav li a{text-decoration:none;color:#000;display:block;font-size:1.2em;padding:0 20px;border:1px solid #fff;outline:0}#tabbed-nav li a:hover{background:#ececec}
5
+ html #tabbed-nav li.active,html #tabbed-nav li.active a:hover{background:#fff;border-bottom:1px solid #fff}div.tab_container{border:1px solid #dfdfdf;border-top:0;overflow:hidden;clear:both;float:left;width:100%;background:#fff;margin-bottom:2em;padding-bottom:2em}
6
+ div.tab_content{padding:10px;padding-bottom:0;font-size:1em}h3 span.show_hide{font-size:.85em;font-weight:normal}div.more_toc_options{margin-top:4px;margin-left:2em}
7
+ div.toc_theme_option{width:200px;float:left;margin-right:5px}#wpcontent select optgroup option{padding-left:15px}input#width_custom,input#font_size,input#smooth_scroll_offset{width:50px;text-align:center}
8
+ input.custom_colour_option{width:75px}table#theme_custom,div#farbtastic_colour_wheel{float:left}table#theme_custom{margin-top:30px}table#theme_custom img{vertical-align:middle;opacity:.4}
9
+ table#theme_custom img:hover{cursor:pointer;opacity:1}div#farbtastic_colour_wheel{margin-left:20px}#tab3 h3:not(:first-child){margin-top:2em}#toc input.small-text{width:50px;padding:2px;height:28px;line-height:28px;vertical-align:bottom}
10
+ #toc .form-table tr>th>strong{font-size:18px;font-style:italic}
assets/css/screen.css ADDED
@@ -0,0 +1,337 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #ez-toc-container {
2
+ background: #F9F9F9;
3
+ border: 1px solid #AAAAAA;
4
+ border-radius: 4px;
5
+ -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
6
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
7
+ display: table;
8
+ /*font-size: 95%;*/
9
+ margin-bottom: 1em;
10
+ padding: 10px;
11
+ position: relative;
12
+ width: auto;
13
+ }
14
+
15
+ .ez-toc-widget-container {
16
+ /*padding: 0 10px;*/
17
+ position: relative;
18
+ white-space: nowrap;
19
+ }
20
+
21
+ #ez-toc-container.ez-toc-light-blue {
22
+ background: #EDF6FF;
23
+ }
24
+
25
+ #ez-toc-container.ez-toc-white {
26
+ background: #FFFFFF;
27
+ }
28
+
29
+ #ez-toc-container.ez-toc-black {
30
+ background: #000000;
31
+ }
32
+
33
+ #ez-toc-container.ez-toc-transparent {
34
+ background: none transparent;
35
+ }
36
+
37
+ .ez-toc-widget-container ul.ez-toc-list {
38
+ padding: 0 10px;
39
+ }
40
+
41
+ #ez-toc-container ul ul,
42
+ .ez-toc div.ez-toc-widget-container ul ul {
43
+ margin-left: 1.5em;
44
+ }
45
+
46
+ #ez-toc-container ul,
47
+ #ez-toc-container li {
48
+ margin: 0;
49
+ padding: 0;
50
+ }
51
+
52
+ #ez-toc-container ul,
53
+ #ez-toc-container li,
54
+ #ez-toc-container ul li,
55
+ .ez-toc-widget-container,
56
+ .ez-toc-widget-container li {
57
+ background: none;
58
+ list-style-type: none;
59
+ list-style: none;
60
+ line-height: 1.6;
61
+ margin: 0;
62
+ overflow: hidden;
63
+ z-index: 1;
64
+ }
65
+
66
+ /*#ez-toc-container.have_bullets li {*/
67
+ /*padding-left: 12px;*/
68
+ /*}*/
69
+
70
+ #ez-toc-container p.ez-toc-title {
71
+ text-align: left;
72
+ font-family: "Arial Narrow", sans-serif;
73
+ font-size: 18px;
74
+ font-weight: 500;
75
+ line-height: 1.45;
76
+ margin: 0;
77
+ padding: 0;
78
+ }
79
+
80
+ .ez-toc-title-container {
81
+ display: table;
82
+ width: 100%;
83
+ }
84
+
85
+ .ez-toc-title,
86
+ .ez-toc-title-toggle {
87
+ display: table-cell;
88
+ text-align: left;
89
+ vertical-align: middle;
90
+ }
91
+
92
+ #ez-toc-container.ez-toc-black p.ez-toc-title {
93
+ color: #FFF;
94
+ }
95
+
96
+ /*#ez-toc-container span.ez-toc-toggle {*/
97
+ /*font-weight: 400;*/
98
+ /*font-size: 90%;*/
99
+ /*}*/
100
+
101
+ #ez-toc-container p.ez-toc-title + ul.ez-toc-list {
102
+ margin-top: 1em;
103
+ }
104
+
105
+ .ez-toc-wrap-left {
106
+ float: left;
107
+ margin-right: 10px;
108
+ }
109
+
110
+ .ez-toc-wrap-right {
111
+ float: right;
112
+ margin-left: 10px;
113
+ }
114
+
115
+ #ez-toc-container a {
116
+ color: #444444;
117
+ text-decoration: none;
118
+ text-shadow: none;
119
+ }
120
+
121
+ #ez-toc-container a:visited {
122
+ color: #9f9f9f;
123
+ }
124
+
125
+ #ez-toc-container a:hover {
126
+ text-decoration: underline;
127
+ }
128
+
129
+ #ez-toc-container.ez-toc-black a {
130
+ color: #FFF;
131
+ }
132
+
133
+ #ez-toc-container.ez-toc-black a:visited {
134
+ color: #FFF;
135
+ }
136
+
137
+ #ez-toc-container a.ez-toc-toggle {
138
+ color: #444444;
139
+ }
140
+
141
+ #ez-toc-container.counter-hierarchy ul,
142
+ .ez-toc-widget-container.counter-hierarchy ul,
143
+ #ez-toc-container.counter-flat ul,
144
+ .ez-toc-widget-container.counter-flat ul {
145
+ counter-reset: item;
146
+ }
147
+
148
+ #ez-toc-container.counter-numeric li,
149
+ .ez-toc-widget-container.counter-numeric li {
150
+ list-style-type: decimal;
151
+ list-style-position: inside;
152
+ }
153
+
154
+ #ez-toc-container.counter-decimal ul.ez-toc-list li a::before,
155
+ .ez-toc-widget-container.counter-decimal ul.ez-toc-list li a::before {
156
+ content: counters(item, ".") ". ";
157
+ counter-increment: item;
158
+ }
159
+
160
+ #ez-toc-container.counter-roman li a::before,
161
+ .ez-toc-widget-container.counter-roman ul.ez-toc-list li a::before {
162
+ content: counters(item, ".", upper-roman) ". ";
163
+ counter-increment: item;
164
+ }
165
+
166
+ .ez-toc-widget-container ul.ez-toc-list li::before {
167
+ content: ' ';
168
+ position: absolute;
169
+ left: 0;
170
+ right: 0;
171
+ height: 30px;
172
+ line-height: 30px;
173
+ z-index: -1;
174
+ }
175
+
176
+ .ez-toc-widget-container ul.ez-toc-list li.active::before {
177
+ background-color: #EDEDED;
178
+ }
179
+
180
+ .ez-toc-widget-container li.active > a {
181
+ font-weight: 900;
182
+ }
183
+
184
+ .btn {
185
+ display: inline-block;
186
+ padding: 6px 12px;
187
+ margin-bottom: 0;
188
+ font-size: 14px;
189
+ font-weight: normal;
190
+ line-height: 1.428571429;
191
+ text-align: center;
192
+ white-space: nowrap;
193
+ vertical-align: middle;
194
+ cursor: pointer;
195
+ background-image: none;
196
+ border: 1px solid transparent;
197
+ border-radius: 4px;
198
+ -webkit-user-select: none;
199
+ -moz-user-select: none;
200
+ -ms-user-select: none;
201
+ -o-user-select: none;
202
+ user-select: none
203
+ }
204
+
205
+ .btn:focus {
206
+ outline: thin dotted #333;
207
+ outline: 5px auto -webkit-focus-ring-color;
208
+ outline-offset: -2px
209
+ }
210
+
211
+ .btn:hover,.btn:focus {
212
+ color: #333;
213
+ text-decoration: none
214
+ }
215
+
216
+ .btn:active,.btn.active {
217
+ background-image: none;
218
+ outline: 0;
219
+ -webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);
220
+ box-shadow: inset 0 3px 5px rgba(0,0,0,0.125)
221
+ }
222
+
223
+ .btn-default {
224
+ color: #333;
225
+ background-color: #fff;
226
+ border-color: #ccc
227
+ }
228
+
229
+ .btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active {
230
+ color: #333;
231
+ background-color: #ebebeb;
232
+ border-color: #adadad
233
+ }
234
+
235
+ .btn-default:active,.btn-default.active {
236
+ background-image: none
237
+ }
238
+
239
+ /*.btn-lg {*/
240
+ /*padding: 10px 16px;*/
241
+ /*font-size: 18px;*/
242
+ /*line-height: 1.33;*/
243
+ /*border-radius: 6px*/
244
+ /*}*/
245
+
246
+ .btn-sm,.btn-xs {
247
+ padding: 5px 10px;
248
+ font-size: 12px;
249
+ line-height: 1.5;
250
+ border-radius: 3px
251
+ }
252
+
253
+ .btn-xs {
254
+ padding: 1px 5px
255
+ }
256
+
257
+ .btn-default {
258
+ text-shadow: 0 -1px 0 rgba(0,0,0,0.2);
259
+ -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);
260
+ box-shadow: inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075)
261
+ }
262
+
263
+ .btn-default:active {
264
+ -webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);
265
+ box-shadow: inset 0 3px 5px rgba(0,0,0,0.125)
266
+ }
267
+
268
+ .btn:active,.btn.active {
269
+ background-image: none
270
+ }
271
+
272
+ .btn-default {
273
+ text-shadow: 0 1px 0 #fff;
274
+ background-image: -webkit-gradient(linear,left 0,left 100%,from(#fff),to(#e0e0e0));
275
+ background-image: -webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);
276
+ background-image: -moz-linear-gradient(top,#fff 0,#e0e0e0 100%);
277
+ background-image: linear-gradient(to bottom,#fff 0,#e0e0e0 100%);
278
+ background-repeat: repeat-x;
279
+ border-color: #dbdbdb;
280
+ border-color: #ccc;
281
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe0e0e0',GradientType=0);
282
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false)
283
+ }
284
+
285
+ .btn-default:hover,.btn-default:focus {
286
+ background-color: #e0e0e0;
287
+ background-position: 0 -15px
288
+ }
289
+
290
+ .btn-default:active,.btn-default.active {
291
+ background-color: #e0e0e0;
292
+ border-color: #dbdbdb
293
+ }
294
+
295
+ .pull-right {
296
+ float: right !important;
297
+ margin-left: 10px;
298
+ }
299
+
300
+ .glyphicon {
301
+ position: relative;
302
+ top: 1px;
303
+ display: inline-block;
304
+ font-family: 'Glyphicons Halflings';
305
+ -webkit-font-smoothing: antialiased;
306
+ font-style: normal;
307
+ font-weight: normal;
308
+ line-height: 1;
309
+ -moz-osx-font-smoothing: grayscale
310
+ }
311
+
312
+ .glyphicon:empty {
313
+ width: 1em
314
+ }
315
+
316
+ .ez-toc-toggle i.glyphicon {
317
+ font-size: 16px;
318
+ margin-left: 2px;
319
+ }
320
+
321
+ [class*="ez-toc-icon-"] {
322
+ font-family: 'ez-toc-icomoon' !important; /* For better glyphicon compatibility */
323
+ speak: none;
324
+ font-style: normal;
325
+ font-weight: normal;
326
+ font-variant: normal;
327
+ text-transform: none;
328
+ line-height: 1;
329
+
330
+ /* Better Font Rendering =========== */
331
+ -webkit-font-smoothing: antialiased;
332
+ -moz-osx-font-smoothing: grayscale;
333
+ }
334
+
335
+ .ez-toc-icon-toggle:before {
336
+ content: "\e87a";
337
+ }
assets/css/screen.min.css ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #ez-toc-container{background:#f9f9f9;border:1px solid #aaa;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05);display:table;margin-bottom:1em;padding:10px;position:relative;width:auto}
2
+ .ez-toc-widget-container{position:relative;white-space:nowrap}#ez-toc-container.ez-toc-light-blue{background:#edf6ff}#ez-toc-container.ez-toc-white{background:#fff}
3
+ #ez-toc-container.ez-toc-black{background:#000}#ez-toc-container.ez-toc-transparent{background:none transparent}.ez-toc-widget-container ul.ez-toc-list{padding:0 10px}
4
+ #ez-toc-container ul ul,.ez-toc div.ez-toc-widget-container ul ul{margin-left:1.5em}#ez-toc-container ul,#ez-toc-container li{margin:0;padding:0}#ez-toc-container ul,#ez-toc-container li,#ez-toc-container ul li,.ez-toc-widget-container,.ez-toc-widget-container li{background:0;list-style-type:none;list-style:none;line-height:1.6;margin:0;overflow:hidden;z-index:1}
5
+ #ez-toc-container p.ez-toc-title{text-align:left;font-family:"Arial Narrow",sans-serif;font-size:18px;font-weight:500;line-height:1.45;margin:0;padding:0}
6
+ .ez-toc-title-container{display:table;width:100%}.ez-toc-title,.ez-toc-title-toggle{display:table-cell;text-align:left;vertical-align:middle}#ez-toc-container.ez-toc-black p.ez-toc-title{color:#FFF}
7
+ #ez-toc-container p.ez-toc-title+ul.ez-toc-list{margin-top:1em}.ez-toc-wrap-left{float:left;margin-right:10px}.ez-toc-wrap-right{float:right;margin-left:10px}
8
+ #ez-toc-container a{color:#444;text-decoration:none;text-shadow:none}#ez-toc-container a:visited{color:#9f9f9f}#ez-toc-container a:hover{text-decoration:underline}
9
+ #ez-toc-container.ez-toc-black a{color:#FFF}#ez-toc-container.ez-toc-black a:visited{color:#FFF}#ez-toc-container a.ez-toc-toggle{color:#444}#ez-toc-container.counter-hierarchy ul,.ez-toc-widget-container.counter-hierarchy ul,#ez-toc-container.counter-flat ul,.ez-toc-widget-container.counter-flat ul{counter-reset:item}
10
+ #ez-toc-container.counter-numeric li,.ez-toc-widget-container.counter-numeric li{list-style-type:decimal;list-style-position:inside}#ez-toc-container.counter-decimal ul.ez-toc-list li a::before,.ez-toc-widget-container.counter-decimal ul.ez-toc-list li a::before{content:counters(item,".") ". ";counter-increment:item}
11
+ #ez-toc-container.counter-roman li a::before,.ez-toc-widget-container.counter-roman ul.ez-toc-list li a::before{content:counters(item,".",upper-roman) ". ";counter-increment:item}
12
+ .ez-toc-widget-container ul.ez-toc-list li::before{content:' ';position:absolute;left:0;right:0;height:30px;line-height:30px;z-index:-1}
13
+ .ez-toc-widget-container ul.ez-toc-list li.active::before{background-color:#ededed}.ez-toc-widget-container li.active>a{font-weight:900}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:normal;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}
14
+ .btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}
15
+ .btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}
16
+ .btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active{color:#333;background-color:#ebebeb;border-color:#adadad}
17
+ .btn-default:active,.btn-default.active{background-image:none}.btn-sm,.btn-xs{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px}
18
+ .btn-default{text-shadow:0 -1px 0 rgba(0,0,0,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075)}
19
+ .btn-default:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn:active,.btn.active{background-image:none}
20
+ .btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left 0,left 100%,from(#fff),to(#e0e0e0));background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-moz-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe0e0e0',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}
21
+ .btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}
22
+ .pull-right{float:right!important;margin-left:10px}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';-webkit-font-smoothing:antialiased;font-style:normal;font-weight:normal;line-height:1;-moz-osx-font-smoothing:grayscale}
23
+ .glyphicon:empty{width:1em}.ez-toc-toggle i.glyphicon{font-size:16px;margin-left:2px}[class*="ez-toc-icon-"]{font-family:'ez-toc-icomoon'!important;speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
24
+ .ez-toc-icon-toggle:before{content:"\e87a"}
assets/js/admin.js ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function($) {
2
+
3
+ var ez_toc_color_picker = $( '.ez-toc-color-picker' );
4
+
5
+ if ( ez_toc_color_picker.length ) {
6
+ ez_toc_color_picker.wpColorPicker();
7
+ }
8
+ });
assets/js/admin.min.js ADDED
@@ -0,0 +1 @@
 
1
+ jQuery(document).ready(function(b){var a=b(".ez-toc-color-picker");if(a.length){a.wpColorPicker();}});
assets/js/front.js ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery( document ).ready( function( $ ) {
2
+
3
+ if ( typeof ezTOC != 'undefined' ) {
4
+
5
+ var affix = $( '.ez-toc-widget-container.ez-toc-affix' );
6
+
7
+ if ( 0 !== affix.length ) {
8
+
9
+ $( ezTOC.affixSelector ).stick_in_parent({
10
+ inner_scrolling : false,
11
+ offset_top : 30
12
+ });
13
+ }
14
+
15
+ $.fn.shrinkTOCWidth = function() {
16
+
17
+ $( this ).css( {
18
+ width: 'auto',
19
+ display: 'table'
20
+ });
21
+
22
+ if ( /MSIE 7\./.test( navigator.userAgent ) )
23
+ $( this ).css( 'width', '' );
24
+ };
25
+
26
+ if ( ezTOC.smooth_scroll == 1 ) {
27
+
28
+ var target = hostname = pathname = qs = hash = null;
29
+
30
+ $( 'body a' ).click( function( event ) {
31
+
32
+ hostname = $( this ).prop( 'hostname' );
33
+ pathname = $( this ).prop( 'pathname' );
34
+ qs = $( this ).prop( 'search' );
35
+ hash = $( this ).prop( 'hash' );
36
+
37
+ // ie strips out the preceding / from pathname
38
+ if ( pathname.length > 0 ) {
39
+ if ( pathname.charAt( 0 ) != '/' ) {
40
+ pathname = '/' + pathname;
41
+ }
42
+ }
43
+
44
+ if ( (window.location.hostname == hostname) && (window.location.pathname == pathname) && (window.location.search == qs) && (hash !== '') ) {
45
+
46
+ // escape jquery selector chars, but keep the #
47
+ var hash_selector = hash.replace( /([ !"$%&'()*+,.\/:;<=>?@[\]^`{|}~])/g, '\\$1' );
48
+
49
+ // check if element exists with id=__
50
+ if ( $( hash_selector ).length > 0 )
51
+ target = hash;
52
+ else {
53
+ // must be an anchor (a name=__)
54
+ anchor = hash;
55
+ anchor = anchor.replace( '#', '' );
56
+ target = 'a[name="' + anchor + '"]';
57
+ // verify it exists
58
+ if ( $( target ).length == 0 )
59
+ target = '';
60
+ }
61
+
62
+ // check offset setting
63
+ if ( typeof ezTOC.scroll_offset != 'undefined' ) {
64
+
65
+ var offset = -1 * ezTOC.scroll_offset;
66
+
67
+ } else {
68
+
69
+ var adminbar = $( '#wpadminbar' );
70
+
71
+ if ( adminbar.length > 0 ) {
72
+
73
+ if ( adminbar.is( ':visible' ) )
74
+ offset = -30; // admin bar exists, give it the default
75
+ else
76
+ offset = 0; // there is an admin bar but it's hidden, so no offset!
77
+
78
+ } else {
79
+
80
+ // no admin bar, so no offset!
81
+ offset = 0;
82
+ }
83
+ }
84
+
85
+ if ( target ) {
86
+ $.smoothScroll( {
87
+ scrollTarget: target,
88
+ offset: offset
89
+ } );
90
+ }
91
+ }
92
+ } );
93
+ }
94
+
95
+ if ( typeof ezTOC.visibility_hide_by_default != 'undefined' ) {
96
+
97
+ var toggle = $( 'a.ez-toc-toggle' );
98
+ var invert = ezTOC.visibility_hide_by_default;
99
+
100
+ if ( Cookies ) {
101
+
102
+ Cookies.get( 'ezTOC_hidetoc' ) == 1 ? toggle.data( 'visible', false ) : toggle.data( 'visible', true );
103
+
104
+ } else {
105
+
106
+ toggle.data( 'visible', true );
107
+ }
108
+
109
+ if ( invert ) {
110
+
111
+ toggle.data( 'visible', false )
112
+ }
113
+
114
+ if ( ! toggle.data( 'visible' ) ) {
115
+
116
+ $( 'ul.ez-toc-list' ).hide();
117
+ }
118
+
119
+ toggle.click( function( event ) {
120
+
121
+ event.preventDefault();
122
+
123
+ if ( $( this ).data( 'visible' ) ) {
124
+
125
+ $( this ).data( 'visible', false );
126
+
127
+ if ( Cookies ) {
128
+
129
+ if ( invert )
130
+ Cookies.set( 'ezTOC_hidetoc', null, { path: '/' } );
131
+ else
132
+ Cookies.set( 'ezTOC_hidetoc', '1', { expires: 30, path: '/' } );
133
+ }
134
+
135
+ $( 'ul.ez-toc-list' ).hide( 'fast' );
136
+
137
+ } else {
138
+
139
+ $( this ).data( 'visible', true );
140
+
141
+ if ( Cookies ) {
142
+
143
+ if ( invert )
144
+ Cookies.set( 'ezTOC_hidetoc', '1', { expires: 30, path: '/' } );
145
+ else
146
+ Cookies.set( 'ezTOC_hidetoc', null, { path: '/' } );
147
+ }
148
+
149
+ $( 'ul.ez-toc-list' ).show( 'fast' );
150
+
151
+ }
152
+
153
+ } );
154
+ }
155
+
156
+ // ======================================
157
+ // Waypoints helper functions
158
+ // ======================================
159
+
160
+ // Get link by section or article id
161
+ function getRelatedNavigation( element ) {
162
+ return $( '.ez-toc-widget-container .ez-toc-list a[href=#' + $( element ).attr( 'id' ) + ']' );
163
+ }
164
+
165
+ function getScrollOffset( element ) {
166
+
167
+ var scrollOffset = ( typeof ezTOC.scroll_offset != 'undefined' ) ? parseInt( ezTOC.scroll_offset ) : 30;
168
+ var offset = $( element ).height() + scrollOffset;
169
+
170
+ var adminbar = $( '#wpadminbar' );
171
+
172
+ if ( 0 === adminbar.length ) {
173
+
174
+ offset = offset-30;
175
+ }
176
+
177
+ return parseInt( offset );
178
+ }
179
+
180
+ // ======================================
181
+ // Waypoints
182
+ // ======================================
183
+
184
+ $('span.ez-toc-section')
185
+ .waypoint( function( direction ) {
186
+ // Highlight element when related content is 10% percent from the bottom - remove if below.
187
+ var item = getRelatedNavigation( this.element ).toggleClass( 'active', direction === 'down' );
188
+ item.toggleClass( 'active', direction === 'down' ).parent().toggleClass( 'active', direction === 'down' );
189
+ }, {
190
+ offset: '90%' //
191
+ });
192
+ $('span.ez-toc-section')
193
+ .waypoint( function( direction ) {
194
+ // Highlight element when bottom of related content is 30px from the top - remove if less.
195
+ var item = getRelatedNavigation( this.element ).toggleClass( 'active', direction === 'up' );
196
+ item.toggleClass( 'active', direction === 'up' ).parent().toggleClass( 'active', direction === 'up' );
197
+ }, {
198
+ offset: getScrollOffset( this.element )
199
+ });
200
+
201
+
202
+ var div_height = $('.ez-toc-widget-container ul.ez-toc-list li').css('line-height');
203
+
204
+ $('<style>.ez-toc-widget-container ul.ez-toc-list li::before{line-height:' + div_height + ';height:' + div_height + '}</style>').appendTo('head');
205
+ }
206
+ } );
assets/js/front.min.js ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function(e){if(typeof ezTOC!="undefined"){var b=e(".ez-toc-widget-container.ez-toc-affix");if(0!==b.length){e(ezTOC.affixSelector).stick_in_parent({inner_scrolling:false,offset_top:30});
2
+ }e.fn.shrinkTOCWidth=function(){e(this).css({width:"auto",display:"table"});if(/MSIE 7\./.test(navigator.userAgent)){e(this).css("width","");}};if(ezTOC.smooth_scroll==1){var f=hostname=pathname=qs=hash=null;
3
+ e("body a").click(function(k){hostname=e(this).prop("hostname");pathname=e(this).prop("pathname");qs=e(this).prop("search");hash=e(this).prop("hash");if(pathname.length>0){if(pathname.charAt(0)!="/"){pathname="/"+pathname;
4
+ }}if((window.location.hostname==hostname)&&(window.location.pathname==pathname)&&(window.location.search==qs)&&(hash!=="")){var j=hash.replace(/([ !"$%&'()*+,.\/:;<=>?@[\]^`{|}~])/g,"\\$1");
5
+ if(e(j).length>0){f=hash;}else{anchor=hash;anchor=anchor.replace("#","");f='a[name="'+anchor+'"]';if(e(f).length==0){f="";}}if(typeof ezTOC.scroll_offset!="undefined"){var l=-1*ezTOC.scroll_offset;
6
+ }else{var i=e("#wpadminbar");if(i.length>0){if(i.is(":visible")){l=-30;}else{l=0;}}else{l=0;}}if(f){e.smoothScroll({scrollTarget:f,offset:l});}}});}if(typeof ezTOC.visibility_hide_by_default!="undefined"){var a=e("a.ez-toc-toggle");
7
+ var g=ezTOC.visibility_hide_by_default;if(Cookies){Cookies.get("ezTOC_hidetoc")==1?a.data("visible",false):a.data("visible",true);}else{a.data("visible",true);
8
+ }if(g){a.data("visible",false);}if(!a.data("visible")){e("ul.ez-toc-list").hide();}a.click(function(i){i.preventDefault();if(e(this).data("visible")){e(this).data("visible",false);
9
+ if(Cookies){if(g){Cookies.set("ezTOC_hidetoc",null,{path:"/"});}else{Cookies.set("ezTOC_hidetoc","1",{expires:30,path:"/"});}}e("ul.ez-toc-list").hide("fast");
10
+ }else{e(this).data("visible",true);if(Cookies){if(g){Cookies.set("ezTOC_hidetoc","1",{expires:30,path:"/"});}else{Cookies.set("ezTOC_hidetoc",null,{path:"/"});
11
+ }}e("ul.ez-toc-list").show("fast");}});}function h(i){return e(".ez-toc-widget-container .ez-toc-list a[href=#"+e(i).attr("id")+"]");}function d(j){var i=(typeof ezTOC.scroll_offset!="undefined")?parseInt(ezTOC.scroll_offset):30;
12
+ var l=e(j).height()+i;var k=e("#wpadminbar");if(0===k.length){l=l-30;}return parseInt(l);}e("span.ez-toc-section").waypoint(function(j){var i=h(this.element).toggleClass("active",j==="down");
13
+ i.toggleClass("active",j==="down").parent().toggleClass("active",j==="down");},{offset:"90%"});e("span.ez-toc-section").waypoint(function(j){var i=h(this.element).toggleClass("active",j==="up");
14
+ i.toggleClass("active",j==="up").parent().toggleClass("active",j==="up");},{offset:d(this.element)});var c=e(".ez-toc-widget-container ul.ez-toc-list li").css("line-height");
15
+ e("<style>.ez-toc-widget-container ul.ez-toc-list li::before{line-height:"+c+";height:"+c+"}</style>").appendTo("head");}});
easy-table-of-contents.php ADDED
@@ -0,0 +1,1071 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
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: 1.0
7
+ * Author: Steven A. Zahm
8
+ * Author URI: http://connections-pro.com/
9
+ * Text Domain: ez_toc
10
+ * Domain Path: languages
11
+ *
12
+ * Copyright 2015 Steven A. Zahm ( email : helpdesk@connections-pro.com )
13
+ *
14
+ * Easy Table of Contents is free software; you can redistribute it and/or modify
15
+ * it under the terms of the GNU General Public License, version 2, as
16
+ * published by the Free Software Foundation.
17
+ *
18
+ * This program is distributed in the hope that it will be useful,
19
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
+ * GNU General Public License for more details.
22
+ *
23
+ * You should have received a copy of the GNU General Public License
24
+ * along with Easy Table of Contents; if not, see <http://www.gnu.org/licenses/>.
25
+ *
26
+ * @package Easy Table of Contents
27
+ * @category Plugin
28
+ * @author Steven A. Zahm
29
+ * @version 1.0
30
+ */
31
+
32
+ // Exit if accessed directly
33
+ if ( ! defined( 'ABSPATH' ) ) exit;
34
+
35
+ if ( ! class_exists( 'ezTOC' ) ) {
36
+
37
+ /**
38
+ * Class ezTOC
39
+ */
40
+ final class ezTOC {
41
+
42
+ /**
43
+ * Current version.
44
+ *
45
+ * @since 1.0
46
+ * @var string
47
+ */
48
+ const VERSION = '1.0';
49
+
50
+ /**
51
+ * Stores the instance of this class.
52
+ *
53
+ * @access private
54
+ * @since 1.0
55
+ * @static
56
+ *
57
+ * @var ezTOC
58
+ */
59
+ private static $instance;
60
+
61
+ /**
62
+ * Keeps a track of used anchors for collision detecting.
63
+ *
64
+ * @access private
65
+ * @since 1.0
66
+ * @static
67
+ *
68
+ * @var array
69
+ */
70
+ private static $collision_collector = array();
71
+
72
+ /**
73
+ * A dummy constructor to prevent the class from being loaded more than once.
74
+ *
75
+ * @access public
76
+ * @since 1.0
77
+ */
78
+ public function __construct() { /* Do nothing here */ }
79
+
80
+ /**
81
+ * @access private
82
+ * @since 1.0
83
+ * @static
84
+ *
85
+ * @return ezTOC
86
+ */
87
+ public static function instance() {
88
+
89
+ if ( ! isset( self::$instance ) && ! ( self::$instance instanceof ezTOC ) ) {
90
+
91
+ self::$instance = new ezTOC();
92
+
93
+ self::defineConstants();
94
+ self::includes();
95
+ self::hooks();
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Define the plugin constants.
101
+ *
102
+ * @access private
103
+ * @since 1.0
104
+ * @static
105
+ */
106
+ private static function defineConstants() {
107
+
108
+ define( 'EZ_TOC_DIR_NAME', plugin_basename( dirname( __FILE__ ) ) );
109
+ define( 'EZ_TOC_BASE_NAME', plugin_basename( __FILE__ ) );
110
+ define( 'EZ_TOC_PATH', plugin_dir_path( __FILE__ ) );
111
+ define( 'EZ_TOC_URL', plugin_dir_url( __FILE__ ) );
112
+ }
113
+
114
+ /**
115
+ * Includes the plugin dependency files.
116
+ *
117
+ * @access private
118
+ * @since 1.0
119
+ * @static
120
+ */
121
+ private static function includes() {
122
+
123
+ require_once( EZ_TOC_PATH . 'includes/class.options.php' );
124
+
125
+ if ( is_admin() ) {
126
+
127
+ // This must be included after `class.options.php` because it depends on it methods.
128
+ require_once( EZ_TOC_PATH . 'includes/class.admin.php' );
129
+ }
130
+
131
+ require_once( EZ_TOC_PATH . 'includes/class.widget-toc.php' );
132
+ }
133
+
134
+ /**
135
+ * Add the core action filter hook.
136
+ *
137
+ * @access private
138
+ * @since 1.0
139
+ * @static
140
+ */
141
+ private static function hooks() {
142
+
143
+ add_action( 'plugins_loaded', array( __CLASS__, 'loadTextdomain' ) );
144
+ add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueueScripts' ) );
145
+
146
+ // Run after shortcodes are interpreted (priority 10).
147
+ add_filter( 'the_content', array( __CLASS__, 'the_content' ), 100 );
148
+ }
149
+
150
+ /**
151
+ * Load the plugin translation.
152
+ *
153
+ * Credit: Adapted from Ninja Forms / Easy Digital Downloads.
154
+ *
155
+ * @access private
156
+ * @since 1.0
157
+ * @static
158
+ *
159
+ * @uses apply_filters()
160
+ * @uses get_locale()
161
+ * @uses load_textdomain()
162
+ * @uses load_plugin_textdomain()
163
+ *
164
+ * @return void
165
+ */
166
+ public static function loadTextdomain() {
167
+
168
+ // Plugin textdomain. This should match the one set in the plugin header.
169
+ $domain = 'ez_toc';
170
+
171
+ // Set filter for plugin's languages directory
172
+ $languagesDirectory = apply_filters( "ez_{$domain}_languages_directory", EZ_TOC_DIR_NAME . '/languages/' );
173
+
174
+ // Traditional WordPress plugin locale filter
175
+ $locale = apply_filters( 'plugin_locale', get_locale(), $domain );
176
+ $fileName = sprintf( '%1$s-%2$s.mo', $domain, $locale );
177
+
178
+ // Setup paths to current locale file
179
+ $local = $languagesDirectory . $fileName;
180
+ $global = WP_LANG_DIR . "/{$domain}/" . $fileName;
181
+
182
+ if ( file_exists( $global ) ) {
183
+
184
+ // Look in global `../wp-content/languages/{$domain}/` folder.
185
+ load_textdomain( $domain, $global );
186
+
187
+ } elseif ( file_exists( $local ) ) {
188
+
189
+ // Look in local `../wp-content/plugins/{plugin-directory}/languages/` folder.
190
+ load_textdomain( $domain, $local );
191
+
192
+ } else {
193
+
194
+ // Load the default language files
195
+ load_plugin_textdomain( $domain, FALSE, $languagesDirectory );
196
+ }
197
+ }
198
+
199
+ /**
200
+ * Register and enqueue CSS and javascript files for frontend.
201
+ *
202
+ * @access private
203
+ * @since 1.0
204
+ * @static
205
+ */
206
+ public static function enqueueScripts() {
207
+
208
+ // If SCRIPT_DEBUG is set and TRUE load the non-minified JS files, otherwise, load the minified files.
209
+ $min = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';
210
+
211
+ $js_vars = array();
212
+
213
+ wp_register_style( 'ez-icomoon', EZ_TOC_URL . "vendor/icomoon/style$min.css", array(), ezTOC::VERSION );
214
+ wp_register_style( 'ez-toc', EZ_TOC_URL . "assets/css/screen$min.css", array( 'ez-icomoon' ), ezTOC::VERSION );
215
+
216
+ wp_register_script( 'js-cookie', EZ_TOC_URL . "vendor/js-cookie/js.cookie$min.js", array(), '2.0.3', TRUE );
217
+ wp_register_script( 'jquery-smooth-scroll', EZ_TOC_URL . "vendor/smooth-scroll/jquery.smooth-scroll$min.js", array( 'jquery' ), '1.5.5', TRUE );
218
+ wp_register_script( 'jquery-sticky-kit', EZ_TOC_URL . "vendor/sticky-kit/jquery.sticky-kit$min.js", array( 'jquery' ), '1.9.2', TRUE );
219
+ wp_register_script( 'jquery-waypoints', EZ_TOC_URL . "vendor/waypoints/jquery.waypoints$min.js", array( 'jquery' ), '1.9.2', TRUE );
220
+ wp_register_script( 'ez-toc-js', EZ_TOC_URL . "assets/js/front$min.js", array( 'jquery-smooth-scroll', 'js-cookie', 'jquery-sticky-kit', 'jquery-waypoints' ), ezTOC::VERSION, TRUE );
221
+
222
+ if ( ! ezTOC_Option::get( 'exclude_css' ) ) {
223
+
224
+ wp_enqueue_style( 'ez-toc' );
225
+ self::inlineCSS();
226
+ }
227
+
228
+ if ( ezTOC_Option::get( 'smooth_scroll' ) ) {
229
+
230
+ $js_vars['smooth_scroll'] = TRUE;
231
+ }
232
+
233
+ //wp_enqueue_script( 'ez-toc-js' );
234
+
235
+ if ( ezTOC_Option::get( 'show_heading_text' ) && ezTOC_Option::get( 'visibility' ) ) {
236
+
237
+ $width = ezTOC_Option::get( 'width' ) != 'custom' ? ezTOC_Option::get( 'width' ) : ezTOC_Option::get( 'width_custom' ) . ezTOC_Option::get( 'width_custom_units' );
238
+
239
+ $js_vars['visibility_hide_by_default'] = ezTOC_Option::get( 'visibility_hide_by_default' ) ? TRUE : FALSE;
240
+
241
+ $js_vars['width'] = esc_js( $width );
242
+ }
243
+
244
+ $js_vars['scroll_offset'] = esc_js( ezTOC_Option::get( 'smooth_scroll_offset' ) );
245
+
246
+ if ( ezTOC_Option::get( 'widget_affix_selector' ) ) {
247
+
248
+ $js_vars['affixSelector'] = ezTOC_Option::get( 'widget_affix_selector' );
249
+ }
250
+
251
+ if ( 0 < count( $js_vars ) ) {
252
+
253
+ wp_localize_script( 'ez-toc-js', 'ezTOC', $js_vars );
254
+ }
255
+ }
256
+
257
+ /**
258
+ * Prints out inline CSS after the core CSS file to allow overriding core styles via options.
259
+ *
260
+ * @access private
261
+ * @since 1.0
262
+ * @static
263
+ */
264
+ public static function inlineCSS() {
265
+
266
+ $css = '';
267
+
268
+ if ( ! ezTOC_Option::get( 'exclude_css' ) ) {
269
+
270
+ $css .= 'div#ez-toc-container ul li {font-size: ' . ezTOC_Option::get( 'font_size' ) . ezTOC_Option::get( 'font_size_units' ) . ';}';
271
+
272
+ if ( ezTOC_Option::get( 'theme' ) == 'custom' || ezTOC_Option::get( 'width' ) != 'auto' ) {
273
+
274
+ $css .= 'div#ez-toc-container {';
275
+
276
+ if ( ezTOC_Option::get( 'theme' ) == 'custom' ) {
277
+
278
+ $css .= 'background: ' . ezTOC_Option::get( 'custom_background_colour' ) . ';border: 1px solid ' . ezTOC_Option::get( 'custom_border_colour' ) . ';';
279
+ }
280
+
281
+ if ( 'auto' != ezTOC_Option::get( 'width' ) ) {
282
+
283
+ $css .= 'width: ';
284
+
285
+ if ( 'custom' != ezTOC_Option::get( 'width' ) ) {
286
+
287
+ $css .= ezTOC_Option::get( 'width' );
288
+
289
+ } else {
290
+
291
+ $css .= ezTOC_Option::get( 'width_custom' ) . ezTOC_Option::get( 'width_custom_units' );
292
+ }
293
+
294
+ $css .= ';';
295
+ }
296
+
297
+ $css .= '}';
298
+ }
299
+
300
+ if ( 'custom' == ezTOC_Option::get( 'theme' ) ) {
301
+
302
+ $css .= 'div#ez-toc-container p.ez-toc-title {color: ' . ezTOC_Option::get( 'custom_title_colour' ) . ';}';
303
+ //$css .= 'div#ez-toc-container p.ez-toc-title a,div#ez-toc-container ul.ez-toc-list a {color: ' . ezTOC_Option::get( 'custom_link_colour' ) . ';}';
304
+ $css .= 'div#ez-toc-container ul.ez-toc-list a:hover {color: ' . ezTOC_Option::get( 'custom_link_hover_colour' ) . ';}';
305
+ $css .= 'div#ez-toc-container ul.ez-toc-list a:hover {color: ' . ezTOC_Option::get( 'custom_link_hover_colour' ) . ';}';
306
+ $css .= 'div#ez-toc-container ul.ez-toc-list a:visited {color: ' . ezTOC_Option::get( 'custom_link_visited_colour' ) . ';}';
307
+ }
308
+ }
309
+
310
+ if ( $css ) {
311
+
312
+ wp_add_inline_style( 'ez-toc', $css );
313
+ }
314
+ }
315
+
316
+ /**
317
+ * Returns a URL to be used as the destination anchor target.
318
+ *
319
+ * @access private
320
+ * @since 1.0
321
+ * @static
322
+ *
323
+ * @param string $title
324
+ *
325
+ * @return bool|string
326
+ */
327
+ private static function url_anchor_target( $title ) {
328
+
329
+ $return = FALSE;
330
+
331
+ if ( $title ) {
332
+
333
+ $return = trim( strip_tags( $title ) );
334
+
335
+ // Convert accented characters to ASCII.
336
+ $return = remove_accents( $return );
337
+
338
+ // replace newlines with spaces (eg when headings are split over multiple lines)
339
+ $return = str_replace( array( "\r", "\n", "\n\r", "\r\n" ), ' ', $return );
340
+
341
+ // remove &amp;
342
+ $return = str_replace( '&amp;', '', $return );
343
+
344
+ // remove non alphanumeric chars
345
+ $return = preg_replace( '/[^a-zA-Z0-9 \-_]*/', '', $return );
346
+
347
+ // convert spaces to _
348
+ $return = str_replace(
349
+ array( ' ', ' ' ),
350
+ '_',
351
+ $return
352
+ );
353
+
354
+ // remove trailing - and _
355
+ $return = rtrim( $return, '-_' );
356
+
357
+ // lowercase everything?
358
+ if ( ezTOC_Option::get( 'lowercase' ) ) {
359
+
360
+ $return = strtolower( $return );
361
+ }
362
+
363
+ // if blank, then prepend with the fragment prefix
364
+ // blank anchors normally appear on sites that don't use the latin charset
365
+ if ( ! $return ) {
366
+
367
+ $return = ( ezTOC_Option::get( 'fragment_prefix' ) ) ? ezTOC_Option::get( 'fragment_prefix' ) : '_';
368
+ }
369
+
370
+ // hyphenate?
371
+ if ( ezTOC_Option::get( 'hyphenate' ) ) {
372
+
373
+ $return = str_replace( '_', '-', $return );
374
+ $return = str_replace( '--', '-', $return );
375
+ }
376
+ }
377
+
378
+ if ( array_key_exists( $return, self::$collision_collector ) ) {
379
+
380
+ self::$collision_collector[ $return ] ++;
381
+ $return .= '-' . self::$collision_collector[ $return ];
382
+
383
+ } else {
384
+
385
+ self::$collision_collector[ $return ] = 1;
386
+ }
387
+
388
+ return apply_filters( 'ez_toc_url_anchor_target', $return );
389
+ }
390
+
391
+ /**
392
+ * Generates a nested unordered list for the table of contents.
393
+ *
394
+ * @access private
395
+ * @since 1.0
396
+ * @static
397
+ *
398
+ * @param array $matches
399
+ *
400
+ * @return string
401
+ */
402
+ private static function build_hierarchy( &$matches ) {
403
+
404
+ $current_depth = 100; // headings can't be larger than h6 but 100 as a default to be sure
405
+ $html = '';
406
+ $numbered_items = array();
407
+ $numbered_items_min = NULL;
408
+
409
+ // reset the internal collision collection
410
+ self::$collision_collector = array();
411
+
412
+ // find the minimum heading to establish our baseline
413
+ for ( $i = 0; $i < count( $matches ); $i ++ ) {
414
+ if ( $current_depth > $matches[ $i ][2] ) {
415
+ $current_depth = (int) $matches[ $i ][2];
416
+ }
417
+ }
418
+
419
+ $numbered_items[ $current_depth ] = 0;
420
+ $numbered_items_min = $current_depth;
421
+
422
+ for ( $i = 0; $i < count( $matches ); $i ++ ) {
423
+
424
+ if ( $current_depth == (int) $matches[ $i ][2] ) {
425
+
426
+ $html .= '<li>';
427
+ }
428
+
429
+ // start lists
430
+ if ( $current_depth != (int) $matches[ $i ][2] ) {
431
+
432
+ for ( $current_depth; $current_depth < (int) $matches[ $i ][2]; $current_depth ++ ) {
433
+
434
+ $numbered_items[ $current_depth + 1 ] = 0;
435
+ $html .= '<ul><li>';
436
+ }
437
+ }
438
+
439
+ // list item
440
+ if ( in_array( $matches[ $i ][2], ezTOC_Option::get( 'heading_levels' ) ) ) {
441
+
442
+ //$html .= '<a href="#' . self::url_anchor_target( $matches[ $i ][0] ) . '">';
443
+ $html .= sprintf(
444
+ '<a href="#%1$s" title="%2$s">',
445
+ self::url_anchor_target( $matches[ $i ][0] ),
446
+ esc_attr( strip_tags( $matches[ $i ][0] ) )
447
+ );
448
+
449
+ //if ( 'decimal' == ezTOC_Option::get( 'counter' ) ) {
450
+ //
451
+ // // attach leading numbers when lower in hierarchy
452
+ // $html .= '<span class="ez-toc-number ez-toc-depth_' . ( $current_depth - $numbered_items_min + 1 ) . '">';
453
+ //
454
+ // for ( $j = $numbered_items_min; $j < $current_depth; $j ++ ) {
455
+ //
456
+ // $number = ( $numbered_items[ $j ] ) ? $numbered_items[ $j ] : 0;
457
+ // $html .= $number . '.';
458
+ // }
459
+ //
460
+ // $html .= ( $numbered_items[ $current_depth ] + 1 ) . '</span> ';
461
+ // $numbered_items[ $current_depth ] ++;
462
+ //}
463
+
464
+ $html .= strip_tags( $matches[ $i ][0] ) . '</a>';
465
+ }
466
+
467
+ // end lists
468
+ if ( $i != count( $matches ) - 1 ) {
469
+
470
+ if ( $current_depth > (int) $matches[ $i + 1 ][2] ) {
471
+
472
+ for ( $current_depth; $current_depth > (int) $matches[ $i + 1 ][2]; $current_depth -- ) {
473
+
474
+ $html .= '</li></ul>';
475
+ $numbered_items[ $current_depth ] = 0;
476
+ }
477
+ }
478
+
479
+ if ( $current_depth == (int) @$matches[ $i + 1 ][2] ) {
480
+
481
+ $html .= '</li>';
482
+ }
483
+
484
+ } else {
485
+
486
+ // this is the last item, make sure we close off all tags
487
+ for ( $current_depth; $current_depth >= $numbered_items_min; $current_depth -- ) {
488
+
489
+ $html .= '</li>';
490
+
491
+ if ( $current_depth != $numbered_items_min ) {
492
+ $html .= '</ul>';
493
+ }
494
+ }
495
+ }
496
+ }
497
+
498
+ return $html;
499
+ }
500
+
501
+ /**
502
+ * Returns a string with all items from the $find array replaced with their matching
503
+ * items in the $replace array. This does a one to one replacement (rather than globally).
504
+ *
505
+ * This function is multibyte safe.
506
+ *
507
+ * $find and $replace are arrays, $string is the haystack. All variables are
508
+ * passed by reference.
509
+ *
510
+ * @access private
511
+ * @since 1.0
512
+ * @static
513
+ *
514
+ * @param bool $find
515
+ * @param bool $replace
516
+ * @param string $string
517
+ *
518
+ * @return mixed|string
519
+ */
520
+ private static function mb_find_replace( &$find = FALSE, &$replace = FALSE, &$string = '' ) {
521
+
522
+ if ( is_array( $find ) && is_array( $replace ) && $string ) {
523
+
524
+ // check if multibyte strings are supported
525
+ if ( function_exists( 'mb_strpos' ) ) {
526
+
527
+ for ( $i = 0; $i < count( $find ); $i ++ ) {
528
+
529
+ $string = mb_substr(
530
+ $string,
531
+ 0,
532
+ mb_strpos( $string, $find[ $i ] )
533
+ ) . // everything before $find
534
+ $replace[ $i ] . // its replacement
535
+ mb_substr(
536
+ $string,
537
+ mb_strpos( $string, $find[ $i ] ) + mb_strlen( $find[ $i ] )
538
+ ) // everything after $find
539
+ ;
540
+ }
541
+
542
+ } else {
543
+
544
+ for ( $i = 0; $i < count( $find ); $i ++ ) {
545
+
546
+ $string = substr_replace(
547
+ $string,
548
+ $replace[ $i ],
549
+ strpos( $string, $find[ $i ] ),
550
+ strlen( $find[ $i ] )
551
+ );
552
+ }
553
+ }
554
+ }
555
+
556
+ return $string;
557
+ }
558
+
559
+ /**
560
+ * This function extracts headings from the html formatted $content. It will pull out
561
+ * only the required headings as specified in the options. For all qualifying headings,
562
+ * this function populates the $find and $replace arrays (both passed by reference)
563
+ * with what to search and replace with.
564
+ *
565
+ * Returns a HTML formatted string of list items for each qualifying heading. This
566
+ * is everything between and NOT including <ul> and </ul>
567
+ *
568
+ * @access private
569
+ * @since 1.0
570
+ * @static
571
+ *
572
+ * @param array $find
573
+ * @param array $replace
574
+ * @param string $content
575
+ *
576
+ * @return bool|string
577
+ */
578
+ public static function extract_headings( &$find, &$replace, $content = '' ) {
579
+
580
+ global $wp_query;
581
+
582
+ $post = $wp_query->post;
583
+
584
+ $matches = array();
585
+ $anchor = '';
586
+ $items = '';
587
+
588
+ $headings = get_post_meta( $post->ID, '_ez-toc-heading-levels', TRUE );
589
+ $exclude = get_post_meta( $post->ID, '_ez-toc-exclude', TRUE );
590
+
591
+ if ( ! is_array( $headings ) ) {
592
+
593
+ $headings = array();
594
+ }
595
+
596
+ if ( empty( $headings ) ) {
597
+
598
+ $headings = ezTOC_Option::get( 'heading_levels', array() );
599
+ }
600
+
601
+ if ( empty( $exclude ) ) {
602
+
603
+ $exclude = ezTOC_Option::get( 'exclude' );
604
+ }
605
+
606
+ // reset the internal collision collection as the_content may have been triggered elsewhere
607
+ // eg by themes or other plugins that need to read in content such as metadata fields in
608
+ // the head html tag, or to provide descriptions to twitter/facebook
609
+ self::$collision_collector = array();
610
+
611
+ if ( is_array( $find ) && is_array( $replace ) && $content ) {
612
+
613
+ // get all headings
614
+ // the html spec allows for a maximum of 6 heading depths
615
+ if ( preg_match_all( '/(<h([1-6]{1})[^>]*>).*<\/h\2>/msuU', $content, $matches, PREG_SET_ORDER ) ) {
616
+
617
+ // remove undesired headings (if any) as defined by heading_levels
618
+ if ( count( $headings ) != 6 ) {
619
+
620
+ $new_matches = array();
621
+
622
+ for ( $i = 0; $i < count( $matches ); $i ++ ) {
623
+
624
+ if ( in_array( $matches[ $i ][2], $headings ) ) {
625
+
626
+ $new_matches[] = $matches[ $i ];
627
+ }
628
+ }
629
+ $matches = $new_matches;
630
+ }
631
+
632
+ // remove specific headings if provided via the 'exclude' property
633
+ if ( $exclude ) {
634
+
635
+ $excluded_headings = explode( '|', $exclude );
636
+
637
+ if ( count( $excluded_headings ) > 0 ) {
638
+
639
+ for ( $j = 0; $j < count( $excluded_headings ); $j++ ) {
640
+
641
+ $excluded_headings[ $j ] = preg_quote( $excluded_headings[ $j ] );
642
+
643
+ // escape some regular expression characters
644
+ // others: http://www.php.net/manual/en/regexp.reference.meta.php
645
+ $excluded_headings[ $j ] = str_replace(
646
+ array( '\*' ),
647
+ array( '.*' ),
648
+ trim( $excluded_headings[ $j ] )
649
+ );
650
+ }
651
+
652
+ $new_matches = array();
653
+
654
+ for ( $i = 0; $i < count( $matches ); $i++ ) {
655
+
656
+ $found = FALSE;
657
+
658
+ for ( $j = 0; $j < count( $excluded_headings ); $j++ ) {
659
+
660
+ if ( @preg_match( '/^' . $excluded_headings[ $j ] . '$/imU', strip_tags( $matches[ $i ][0] ) ) ) {
661
+
662
+ $found = TRUE;
663
+ break;
664
+ }
665
+ }
666
+
667
+ if ( ! $found ) {
668
+
669
+ $new_matches[] = $matches[ $i ];
670
+ }
671
+ }
672
+
673
+ if ( count( $matches ) != count( $new_matches ) ) {
674
+
675
+ $matches = $new_matches;
676
+ }
677
+ }
678
+ }
679
+
680
+ // remove empty headings
681
+ $new_matches = array();
682
+
683
+ for ( $i = 0; $i < count( $matches ); $i ++ ) {
684
+
685
+ if ( trim( strip_tags( $matches[ $i ][0] ) ) != FALSE ) {
686
+
687
+ $new_matches[] = $matches[ $i ];
688
+ }
689
+ }
690
+
691
+ if ( count( $matches ) != count( $new_matches ) ) {
692
+
693
+ $matches = $new_matches;
694
+ }
695
+
696
+ // check minimum number of headings
697
+ if ( count( $matches ) >= ezTOC_Option::get( 'start' ) ) {
698
+
699
+ for ( $i = 0; $i < count( $matches ); $i ++ ) {
700
+
701
+ // get anchor and add to find and replace arrays
702
+ $anchor = self::url_anchor_target( $matches[ $i ][0] );
703
+ $find[] = $matches[ $i ][0];
704
+ $replace[] = str_replace(
705
+ array(
706
+ $matches[ $i ][1], // start of heading
707
+ '</h' . $matches[ $i ][2] . '>' // end of heading
708
+ ),
709
+ array(
710
+ $matches[ $i ][1] . '<span class="ez-toc-section" id="' . $anchor . '">',
711
+ '</span></h' . $matches[ $i ][2] . '>'
712
+ ),
713
+ $matches[ $i ][0]
714
+ );
715
+
716
+ // assemble flat list
717
+ if ( ! ezTOC_Option::get( 'show_hierarchy' ) ) {
718
+
719
+ $items .= '<li><a href="#' . $anchor . '">';
720
+
721
+ //if ( 'decimal' == ezTOC_Option::get( 'counter' ) ) {
722
+ //
723
+ // $items .= count( $replace ) . ' ';
724
+ //}
725
+
726
+ $items .= strip_tags( $matches[ $i ][0] ) . '</a></li>';
727
+ }
728
+ }
729
+
730
+ // build a hierarchical toc?
731
+ // we could have tested for $items but that var can be quite large in some cases
732
+ if ( ezTOC_Option::get( 'show_hierarchy' ) ) {
733
+
734
+ $items = self::build_hierarchy( $matches );
735
+ }
736
+
737
+ }
738
+ }
739
+ }
740
+
741
+ return $items;
742
+ }
743
+
744
+ /**
745
+ * Returns true if the table of contents is eligible to be printed, false otherwise.
746
+ *
747
+ * @access public
748
+ * @since 1.0
749
+ * @static
750
+ *
751
+ * @return bool
752
+ */
753
+ public static function is_eligible() {
754
+
755
+ global $wp_query;
756
+
757
+ $post = $wp_query->post;
758
+ $type = get_post_type( $post->ID );
759
+
760
+ // do not trigger the TOC when displaying an XML/RSS feed
761
+ if ( is_feed() ) {
762
+
763
+ return FALSE;
764
+ }
765
+
766
+ $enabled = in_array( $type, ezTOC_Option::get( 'enabled_post_types', array() ) );
767
+ $insert = in_array( $type, ezTOC_Option::get( 'auto_insert_post_types', array() ) );
768
+
769
+ if ( ( ( $insert || $enabled ) &&
770
+ ! is_search() && ! is_archive() && ! is_front_page() ) ||
771
+ ( ezTOC_Option::get( 'include_homepage' ) && is_front_page() ) ) {
772
+
773
+ if ( ezTOC_Option::get( 'restrict_path' ) ) {
774
+
775
+ if ( strpos( $_SERVER['REQUEST_URI'], ezTOC_Option::get( 'restrict_path' ) ) === 0 ) {
776
+
777
+ return TRUE;
778
+
779
+ } else {
780
+
781
+ return FALSE;
782
+ }
783
+
784
+ } else {
785
+
786
+ if ( $insert && 1 == get_post_meta( $post->ID, '_ez-toc-disabled', TRUE ) ) {
787
+
788
+ return FALSE;
789
+
790
+ } elseif ( $insert && 0 == get_post_meta( $post->ID, '_ez-toc-disabled', TRUE ) ) {
791
+
792
+ return TRUE;
793
+
794
+ } elseif ( $enabled && 1 == get_post_meta( $post->ID, '_ez-toc-insert', TRUE ) ) {
795
+
796
+ return TRUE;
797
+ }
798
+
799
+ return FALSE;
800
+ //return TRUE;
801
+ }
802
+
803
+ } else {
804
+
805
+ return FALSE;
806
+ }
807
+ }
808
+
809
+ /**
810
+ * Callback for the `the_content` filter.
811
+ *
812
+ * This will add the inline table of contents page anchors to the post content. It will also insert the
813
+ * table of contents inline with the post content as defined by the user defined preference.
814
+ *
815
+ * @access private
816
+ * @since 1.0
817
+ * @static
818
+ *
819
+ * @param string $content
820
+ *
821
+ * @return string
822
+ */
823
+ public static function the_content( $content ) {
824
+
825
+ $css_classes = '';
826
+
827
+ $html = '';
828
+ $find = array();
829
+ $replace = array();
830
+ $items = self::extract_headings( $find, $replace, $content );
831
+
832
+ if ( $items ) {
833
+
834
+ if ( self::is_eligible() ) {
835
+
836
+ // wrapping css classes
837
+ switch ( ezTOC_Option::get( 'wrapping' ) ) {
838
+
839
+ case 'left':
840
+ $css_classes .= ' ez-toc-wrap-left';
841
+ break;
842
+
843
+ case 'right':
844
+ $css_classes .= ' ez-toc-wrap-right';
845
+ break;
846
+
847
+ case 'none':
848
+ default:
849
+ // do nothing
850
+ }
851
+
852
+ if ( ezTOC_Option::get( 'show_hierarchy' ) ) {
853
+
854
+ $css_classes .= ' counter-hierarchy';
855
+
856
+ } else {
857
+
858
+ $css_classes .= ' counter-flat';
859
+ }
860
+
861
+ switch ( ezTOC_Option::get( 'counter' ) ) {
862
+
863
+ case 'numeric':
864
+ $css_classes .= ' counter-numeric';
865
+ break;
866
+
867
+ case 'roman':
868
+ $css_classes .= ' counter-roman';
869
+ break;
870
+
871
+ case 'decimal':
872
+ $css_classes .= ' counter-decimal';
873
+ break;
874
+ }
875
+
876
+ // colour themes
877
+ switch ( ezTOC_Option::get( 'theme' ) ) {
878
+
879
+ case 'light-blue':
880
+ $css_classes .= ' ez-toc-light-blue';
881
+ break;
882
+
883
+ case 'white':
884
+ $css_classes .= ' ez-toc-white';
885
+ break;
886
+
887
+ case 'black':
888
+ $css_classes .= ' ez-toc-black';
889
+ break;
890
+
891
+ case 'transparent':
892
+ $css_classes .= ' ez-toc-transparent';
893
+ break;
894
+
895
+ case 'grey':
896
+ $css_classes .= ' ez-toc-grey';
897
+ break;
898
+
899
+ default:
900
+ // do nothing
901
+ }
902
+
903
+ // bullets?
904
+ //if ( ezTOC_Option::get( 'bullet_spacing' ) ) {
905
+ //
906
+ // $css_classes .= ' have_bullets';
907
+ //
908
+ //} else {
909
+ //
910
+ // $css_classes .= ' no_bullets';
911
+ //}
912
+
913
+ if ( ezTOC_Option::get( 'css_container_class' ) ) {
914
+
915
+ $css_classes .= ' ' . ezTOC_Option::get( 'css_container_class' );
916
+ }
917
+
918
+ $css_classes = trim( $css_classes );
919
+
920
+ // an empty class="" is invalid markup!
921
+ if ( ! $css_classes ) {
922
+
923
+ $css_classes = ' ';
924
+ }
925
+
926
+ // add container, toc title and list items
927
+ $html .= '<div id="ez-toc-container" class="' . $css_classes . '">' . PHP_EOL;
928
+
929
+ if ( ezTOC_Option::get( 'show_heading_text' ) ) {
930
+
931
+ $toc_title = ezTOC_Option::get( 'heading_text' );
932
+
933
+ if ( strpos( $toc_title, '%PAGE_TITLE%' ) !== FALSE ) {
934
+
935
+ $toc_title = str_replace( '%PAGE_TITLE%', get_the_title(), $toc_title );
936
+ }
937
+
938
+ if ( strpos( $toc_title, '%PAGE_NAME%' ) !== FALSE ) {
939
+
940
+ $toc_title = str_replace( '%PAGE_NAME%', get_the_title(), $toc_title );
941
+ }
942
+
943
+ $html .= '<div class="ez-toc-title-container">' . PHP_EOL;
944
+
945
+ $html .= '<p class="ez-toc-title">' . htmlentities( $toc_title, ENT_COMPAT, 'UTF-8' ) . '</p>' . PHP_EOL;
946
+
947
+ $html .= '<span class="ez-toc-title-toggle">';
948
+
949
+ if ( ezTOC_Option::get( 'visibility' ) ) {
950
+
951
+ $html .= '<a class="pull-right btn btn-xs btn-default ez-toc-toggle"><i class="glyphicon ez-toc-icon-toggle"></i></a>';
952
+ }
953
+
954
+ $html .= '</span>';
955
+
956
+ $html .= '</div>' . PHP_EOL;
957
+ }
958
+
959
+ ob_start();
960
+ do_action( 'ez_toc_before' );
961
+ $html .= ob_get_clean();
962
+
963
+ $html .= '<ul class="ez-toc-list">' . $items . '</ul>';
964
+
965
+ ob_start();
966
+ do_action( 'ez_toc_after' );
967
+ $html .= ob_get_clean();
968
+
969
+ $html .= '</div>' . PHP_EOL;
970
+ }
971
+
972
+ if ( count( $find ) > 0 ) {
973
+
974
+ switch ( ezTOC_Option::get( 'position' ) ) {
975
+
976
+ case 'top':
977
+ $content = $html . self::mb_find_replace( $find, $replace, $content );
978
+ break;
979
+
980
+ case 'bottom':
981
+ $content = self::mb_find_replace( $find, $replace, $content ) . $html;
982
+ break;
983
+
984
+ case 'after':
985
+ $replace[0] = $replace[0] . $html;
986
+ $content = self::mb_find_replace( $find, $replace, $content );
987
+ break;
988
+
989
+ case 'before':
990
+ default:
991
+ $replace[0] = $html . $replace[0];
992
+ $content = self::mb_find_replace( $find, $replace, $content );
993
+ }
994
+ }
995
+
996
+ // Enqueue the script.
997
+ wp_enqueue_script( 'ez-toc-js' );
998
+ }
999
+
1000
+ return $content;
1001
+ }
1002
+
1003
+ } // end class
1004
+
1005
+ /**
1006
+ * The main function responsible for returning the Easy Table of Contents instance to functions everywhere.
1007
+ *
1008
+ * Use this function like you would a global variable, except without needing to declare the global.
1009
+ *
1010
+ * Example: <?php $instance = ezTOC(); ?>
1011
+ *
1012
+ * @access public
1013
+ * @since 1.0
1014
+ *
1015
+ * @return ezTOC
1016
+ */
1017
+ function ezTOC() {
1018
+
1019
+ return ezTOC::instance();
1020
+ }
1021
+
1022
+ // Start Easy Table of Contents.
1023
+ ezTOC();
1024
+ }
1025
+
1026
+
1027
+ /**
1028
+ * Returns a HTML formatted string of the table of contents without the surrounding UL or OL
1029
+ * tags to enable the theme editor to supply their own ID and/or classes to the outer list.
1030
+ *
1031
+ * There are three optional parameters you can feed this function with:
1032
+ *
1033
+ * - $content is the entire content with headings. If blank, will default to the current $post
1034
+ *
1035
+ * - $link is the URL to prefix the anchor with. If provided a string, will use it as the prefix.
1036
+ * If set to true then will try to obtain the permalink from the $post object.
1037
+ *
1038
+ * - $apply_eligibility bool, defaults to false. When set to true, will apply the check to
1039
+ * see if bit of content has the prerequisites needed for a TOC, eg minimum number of headings
1040
+ * enabled post type, etc.
1041
+ */
1042
+ //function toc_get_index( $content = '', $prefix_url = '', $apply_eligibility = FALSE ) {
1043
+ //
1044
+ // global $wp_query, $tic;
1045
+ //
1046
+ // $return = '';
1047
+ // $find = $replace = array();
1048
+ // $proceed = TRUE;
1049
+ //
1050
+ // if ( ! $content ) {
1051
+ // $post = get_post( $wp_query->post->ID );
1052
+ // $content = wptexturize( $post->post_content );
1053
+ // }
1054
+ //
1055
+ // if ( $apply_eligibility ) {
1056
+ // if ( ! $tic->is_eligible() ) {
1057
+ // $proceed = FALSE;
1058
+ // }
1059
+ // } else {
1060
+ // $tic->set_option( array( 'start' => 0 ) );
1061
+ // }
1062
+ //
1063
+ // if ( $proceed ) {
1064
+ // $return = $tic->extract_headings( $find, $replace, $content );
1065
+ // if ( $prefix_url ) {
1066
+ // $return = str_replace( 'href="#', 'href="' . $prefix_url . '#', $return );
1067
+ // }
1068
+ // }
1069
+ //
1070
+ // return $return;
1071
+ //}
includes/class.admin.php ADDED
@@ -0,0 +1,377 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Exit if accessed directly
4
+ if ( ! defined( 'ABSPATH' ) ) exit;
5
+
6
+ if ( ! class_exists( 'ezTOC_Admin' ) ) {
7
+
8
+ /**
9
+ * Class ezTOC_Admin
10
+ */
11
+ final class ezTOC_Admin {
12
+
13
+ /**
14
+ * Setup plugin for admin use.
15
+ *
16
+ * @access private
17
+ * @since 1.0
18
+ * @static
19
+ */
20
+ public function __construct() {
21
+
22
+ $this->hooks();
23
+ //$this->registerMetaboxes();
24
+ }
25
+
26
+ /**
27
+ * Add the core admin hooks.
28
+ *
29
+ * @access private
30
+ * @since 1.0
31
+ * @static
32
+ */
33
+ private function hooks() {
34
+
35
+ add_action( 'admin_init', array( $this, 'registerScripts' ) );
36
+ add_action( 'admin_menu', array( $this, 'menu' ) );
37
+ add_action( 'init', array( $this, 'registerMetaboxes' ), 99 );
38
+ add_filter( 'plugin_action_links_' . EZ_TOC_BASE_NAME, array( $this, 'pluginActionLinks' ), 10, 2 );
39
+ }
40
+
41
+ /**
42
+ * Callback to add the Settings link to the plugin action links.
43
+ *
44
+ * @access private
45
+ * @since 1.0
46
+ * @static
47
+ */
48
+ public function pluginActionLinks( $links, $file ) {
49
+
50
+ $action = array();
51
+
52
+ $action[] = sprintf(
53
+ '<a href="%1$s">%2$s</a>',
54
+ esc_url( add_query_arg( 'page', 'table-of-contents', self_admin_url( 'options-general.php' ) ) ),
55
+ esc_html( __( 'Settings', 'ez_toc' ) )
56
+ );
57
+
58
+ return array_merge( $action, $links );
59
+ }
60
+
61
+ /**
62
+ * Register the scripts used in the admin.
63
+ *
64
+ * @access private
65
+ * @since 1.0
66
+ * @static
67
+ */
68
+ public function registerScripts() {
69
+
70
+ wp_register_script( 'cn_toc_admin_script', EZ_TOC_URL . 'assets/js/admin.js', array( 'jquery', 'wp-color-picker' ), ezTOC::VERSION, TRUE );
71
+ wp_register_style( 'cn_toc_admin_style', EZ_TOC_URL . 'assets/css/admin.css', array( 'wp-color-picker' ), ezTOC::VERSION );
72
+ }
73
+
74
+ /**
75
+ * Callback to add plugin as a submenu page of the Options page.
76
+ *
77
+ * This also adds the action to enqueue the scripts to be loaded on plugin's admin pages only.
78
+ *
79
+ * @access private
80
+ * @since 1.0
81
+ * @static
82
+ */
83
+ public function menu() {
84
+
85
+ $page = add_submenu_page(
86
+ 'options-general.php',
87
+ __( 'Table of Contents', 'ez_toc' ),
88
+ __( 'Table of Contents', 'ez_toc' ),
89
+ 'manage_options',
90
+ 'table-of-contents',
91
+ array( $this, 'page' )
92
+ );
93
+
94
+ add_action( 'admin_print_styles-' . $page, array( $this, 'enqueueScripts' ) );
95
+ }
96
+
97
+ /**
98
+ * Enqueue the scripts.
99
+ *
100
+ * @access private
101
+ * @since 1.0
102
+ * @static
103
+ */
104
+ public function enqueueScripts() {
105
+
106
+ wp_enqueue_script( 'cn_toc_admin_script' );
107
+ wp_enqueue_style( 'cn_toc_admin_style' );
108
+ }
109
+
110
+ /**
111
+ * Callback to add the action which will register the table of contents post metaboxes.
112
+ *
113
+ * Metaboxes will only be registered for the post types per user preferences.
114
+ *
115
+ * @access private
116
+ * @since 1.0
117
+ * @static
118
+ */
119
+ public function registerMetaboxes() {
120
+
121
+ foreach ( get_post_types() as $type ) {
122
+
123
+ if ( in_array( $type, ezTOC_Option::get( 'enabled_post_types', array() ) ) ) {
124
+
125
+ add_action( "add_meta_boxes_$type", array( $this, 'metabox' ) );
126
+ add_action( "save_post_$type", array( $this, 'save' ), 10, 3 );
127
+ }
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Callback to register the table of contents metaboxes.
133
+ *
134
+ * @access private
135
+ * @since 1.0
136
+ * @static
137
+ */
138
+ public function metabox() {
139
+
140
+ add_meta_box( 'ez-toc', __( 'Table of Contents', 'ez-toc' ), array( $this, 'displayMetabox' ) );
141
+ }
142
+
143
+ /**
144
+ * Callback to render the content of the table of contents metaboxes.
145
+ *
146
+ * @access private
147
+ * @since 1.0
148
+ * @static
149
+ *
150
+ * @param object $post The post object.
151
+ * @param $atts
152
+ */
153
+ public function displayMetabox( $post, $atts ) {
154
+
155
+ // Add an nonce field so we can check for it on save.
156
+ wp_nonce_field( 'ez_toc_save', '_ez_toc_nonce' );
157
+
158
+ $suppress = get_post_meta( $post->ID, '_ez-toc-disabled', TRUE ) == 1 ? TRUE : FALSE;
159
+ $insert = get_post_meta( $post->ID, '_ez-toc-insert', TRUE ) == 1 ? TRUE : FALSE;
160
+ $headings = get_post_meta( $post->ID, '_ez-toc-heading-levels', TRUE );
161
+ $exclude = get_post_meta( $post->ID, '_ez-toc-exclude', TRUE );
162
+
163
+ if ( ! is_array( $headings ) ) {
164
+
165
+ $headings = array();
166
+ }
167
+ ?>
168
+
169
+ <table class="form-table">
170
+
171
+ <tbody>
172
+
173
+ <tr>
174
+ <th scope="row"></th>
175
+ <td>
176
+
177
+ <?php if ( in_array( get_post_type( $post ), ezTOC_Option::get( 'auto_insert_post_types', array() ) ) ) :
178
+
179
+ ezTOC_Option::checkbox(
180
+ array(
181
+ 'id' => 'disabled-toc',
182
+ 'desc' => __( 'Disable the automatic insertion of the table of contents.', 'ez_toc' ),
183
+ 'default' => $suppress,
184
+ ),
185
+ $suppress
186
+ );
187
+
188
+ elseif( in_array( get_post_type( $post ), ezTOC_Option::get( 'enabled_post_types', array() ) ) ):
189
+
190
+ ezTOC_Option::checkbox(
191
+ array(
192
+ 'id' => 'insert-toc',
193
+ 'desc' => __( 'Insert table of contents.', 'ez_toc' ),
194
+ 'default' => $insert,
195
+ ),
196
+ $insert
197
+ );
198
+
199
+ endif; ?>
200
+
201
+ </td>
202
+ </tr>
203
+
204
+ <tr>
205
+ <th scope="row"><?php _e( 'Advanced:', 'ez_toc' ); ?></th>
206
+ <td>
207
+ <?php
208
+ ezTOC_Option::descriptive_text(
209
+ array(
210
+ 'id' => 'exclude-desc',
211
+ 'name' => '',
212
+ 'desc' => '<p><strong>' . __( 'NOTE:', 'ez_toc' ) . '</strong></p>' .
213
+ '<ul>' .
214
+ '<li>' . __( 'Using the advanced options below will override the global advanced settings.', 'ez_toc' ) . '</li>' .
215
+ '</ul>',
216
+ )
217
+ );
218
+ ?>
219
+ </td>
220
+ </tr>
221
+
222
+ <tr>
223
+ <th scope="row"><?php _e( 'Headings:', 'ez_toc' ); ?></th>
224
+ <td>
225
+ <?php
226
+ ezTOC_Option::checkboxgroup(
227
+ array(
228
+ 'id' => 'heading-levels',
229
+ 'desc' => __( 'Select the heading to consider when generating the table of contents. Deselecting a heading will exclude it.', 'ez_toc' ),
230
+ 'options' => array(
231
+ '1' => __( 'Heading 1 (h1)', 'ez_toc' ),
232
+ '2' => __( 'Heading 2 (h2)', 'ez_toc' ),
233
+ '3' => __( 'Heading 3 (h3)', 'ez_toc' ),
234
+ '4' => __( 'Heading 4 (h4)', 'ez_toc' ),
235
+ '5' => __( 'Heading 5 (h5)', 'ez_toc' ),
236
+ '6' => __( 'Heading 6 (h6)', 'ez_toc' ),
237
+ ),
238
+ 'default' => array(),
239
+ ),
240
+ array_map( 'absint', $headings )
241
+ );
242
+ ?>
243
+ </td>
244
+ </tr>
245
+ <tr>
246
+ <th scope="row"><?php _e( 'Exclude Headings', 'ez_toc' ); ?></th>
247
+ <td>
248
+ <?php
249
+ ezTOC_Option::text(
250
+ array(
251
+ 'id' => 'exclude',
252
+ 'desc' => __( 'Specify headings to be excluded from appearing in the table of contents. Separate multiple headings with a pipe <code>|</code>. Use an asterisk <code>*</code> as a wildcard to match other text.', 'ez_toc' ),
253
+ 'size' => 'large',
254
+ 'default' => '',
255
+ ),
256
+ esc_textarea( $exclude )
257
+ );
258
+ ?>
259
+ </td>
260
+ </tr>
261
+ <tr>
262
+ <th scope="row"></th>
263
+ <td>
264
+ <?php
265
+ ezTOC_Option::descriptive_text(
266
+ array(
267
+ 'id' => 'exclude-desc',
268
+ 'name' => '',
269
+ 'desc' => '<p><strong>' . __( 'Examples:', 'ez_toc' ) . '</strong></p>' .
270
+ '<ul>' .
271
+ '<li>' . __( '<code>Fruit*</code> Ignore headings starting with "Fruit".', 'ez_toc' ) . '</li>' .
272
+ '<li>' . __( '<code>*Fruit Diet*</code> Ignore headings with "Fruit Diet" somewhere in the heading.', 'ez_toc' ) . '</li>' .
273
+ '<li>' . __( '<code>Apple Tree|Oranges|Yellow Bananas</code> Ignore headings that are exactly "Apple Tree", "Oranges" or "Yellow Bananas".', 'ez_toc' ) . '</li>' .
274
+ '</ul>' .
275
+ '<p>' . __( '<strong>Note:</strong> This is not case sensitive.', 'ez_toc' ) . '</p>',
276
+ )
277
+ );
278
+ ?>
279
+ </td>
280
+ </tr>
281
+ </tbody>
282
+ </table>
283
+
284
+ <?php
285
+ }
286
+
287
+ /**
288
+ * Callback which saves the user preferences from the table of contents metaboxes.
289
+ *
290
+ * @access private
291
+ * @since 1.0
292
+ * @static
293
+ *
294
+ * @param int $post_id The post ID.
295
+ * @param object $post The post object.
296
+ * @param bool $update Whether this is an existing post being updated or not.
297
+ */
298
+ public function save( $post_id, $post, $update ) {
299
+
300
+ if ( current_user_can( 'edit_post', $post_id ) && wp_verify_nonce( $_REQUEST['_ez_toc_nonce'], 'ez_toc_save' ) ) {
301
+
302
+ // Checkboxes are present if checked, absent if not.
303
+ if ( isset( $_REQUEST['ez-toc-settings']['disabled-toc'] ) ) {
304
+
305
+ update_post_meta( $post_id, '_ez-toc-disabled', TRUE );
306
+
307
+ } else {
308
+
309
+ update_post_meta( $post_id, '_ez-toc-disabled', FALSE );
310
+
311
+ }
312
+
313
+ if ( isset( $_REQUEST['ez-toc-settings']['insert-toc'] ) ) {
314
+
315
+ update_post_meta( $post_id, '_ez-toc-insert', TRUE );
316
+
317
+ } else {
318
+
319
+ update_post_meta( $post_id, '_ez-toc-insert', FALSE );
320
+ }
321
+
322
+ if ( isset( $_REQUEST['ez-toc-settings']['heading-levels'] ) && ! empty( $_REQUEST['ez-toc-settings']['heading-levels'] ) ) {
323
+
324
+ if ( is_array( $_REQUEST['ez-toc-settings']['heading-levels'] ) ) {
325
+
326
+ $headings = array_map( 'absint', $_REQUEST['ez-toc-settings']['heading-levels'] );
327
+
328
+ } else {
329
+
330
+ $headings = array();
331
+ }
332
+
333
+ update_post_meta( $post_id, '_ez-toc-heading-levels', $headings );
334
+
335
+ } else {
336
+
337
+ update_post_meta( $post_id, '_ez-toc-heading-levels', array() );
338
+ }
339
+
340
+ if ( isset( $_REQUEST['ez-toc-settings']['exclude'] ) && ! empty( $_REQUEST['ez-toc-settings']['exclude'] ) ) {
341
+
342
+ if ( is_string( $_REQUEST['ez-toc-settings']['exclude'] ) ) {
343
+
344
+ $exclude = stripslashes( trim( $_REQUEST['ez-toc-settings']['exclude'] ) );
345
+
346
+ } else {
347
+
348
+ $exclude = '';
349
+ }
350
+
351
+ update_post_meta( $post_id, '_ez-toc-exclude', $exclude );
352
+
353
+ } else {
354
+
355
+ update_post_meta( $post_id, '_ez-toc-exclude', '' );
356
+ }
357
+
358
+ }
359
+
360
+ }
361
+
362
+ /**
363
+ * Callback used to render the admin options page.
364
+ *
365
+ * @access private
366
+ * @since 1.0
367
+ * @static
368
+ */
369
+ public function page() {
370
+
371
+ include EZ_TOC_PATH . 'includes/inc.admin-options-page.php';
372
+ }
373
+ }
374
+
375
+ new ezTOC_Admin();
376
+
377
+ }
includes/class.options.php ADDED
@@ -0,0 +1,1197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Exit if accessed directly
4
+ if ( ! defined( 'ABSPATH' ) ) exit;
5
+
6
+ if ( ! class_exists( 'ezTOC_Option' ) ) {
7
+
8
+ /**
9
+ * Class ezTOC_Option
10
+ *
11
+ * Credit: Adapted from Easy Digital Downloads.
12
+ */
13
+ final class ezTOC_Option {
14
+
15
+ /**
16
+ * Register the plugins core settings and options.
17
+ *
18
+ * @access private
19
+ * @since 1.0
20
+ * @static
21
+ */
22
+ public static function register() {
23
+
24
+ if ( FALSE === get_option( 'ez-toc-settings' ) ) {
25
+
26
+ add_option( 'ez-toc-settings', self::getDefaults() );
27
+ }
28
+
29
+ foreach ( self::getRegistered() as $section => $settings ) {
30
+
31
+ add_settings_section(
32
+ 'ez_toc_settings_' . $section,
33
+ __return_null(),
34
+ '__return_false',
35
+ 'ez_toc_settings_' . $section
36
+ );
37
+
38
+ foreach ( $settings as $option ) {
39
+
40
+ $name = isset( $option['name'] ) ? $option['name'] : '';
41
+
42
+ add_settings_field(
43
+ 'ez-toc-settings[' . $option['id'] . ']',
44
+ $name,
45
+ method_exists( __CLASS__, $option['type'] ) ? array( __CLASS__, $option['type'] ) : array( __CLASS__, 'missingCallback' ),
46
+ 'ez_toc_settings_' . $section,
47
+ 'ez_toc_settings_' . $section,
48
+ array(
49
+ 'section' => $section,
50
+ 'id' => isset( $option['id'] ) ? $option['id'] : NULL,
51
+ 'desc' => ! empty( $option['desc'] ) ? $option['desc'] : '',
52
+ 'name' => isset( $option['name'] ) ? $option['name'] : NULL,
53
+ 'size' => isset( $option['size'] ) ? $option['size'] : NULL,
54
+ 'options' => isset( $option['options'] ) ? $option['options'] : '',
55
+ 'default' => isset( $option['default'] ) ? $option['default'] : '',
56
+ 'min' => isset( $option['min'] ) ? $option['min'] : NULL,
57
+ 'max' => isset( $option['max'] ) ? $option['max'] : NULL,
58
+ 'step' => isset( $option['step'] ) ? $option['step'] : NULL,
59
+ 'chosen' => isset( $option['chosen'] ) ? $option['chosen'] : NULL,
60
+ 'placeholder' => isset( $option['placeholder'] ) ? $option['placeholder'] : NULL,
61
+ 'allow_blank' => isset( $option['allow_blank'] ) ? $option['allow_blank'] : TRUE,
62
+ 'readonly' => isset( $option['readonly'] ) ? $option['readonly'] : FALSE,
63
+ 'faux' => isset( $option['faux'] ) ? $option['faux'] : FALSE,
64
+ )
65
+ );
66
+ }
67
+
68
+ }
69
+
70
+ // Creates our settings in the options table
71
+ register_setting( 'ez-toc-settings', 'ez-toc-settings', array( __CLASS__, 'sanitize' ) );
72
+ }
73
+
74
+ /**
75
+ * Callback for settings sanitization.
76
+ *
77
+ * @access private
78
+ * @since 1.0
79
+ * @static
80
+ *
81
+ * @param array $input The value inputted in the field.
82
+ *
83
+ * @return string $input Sanitized value.
84
+ */
85
+ public static function sanitize( $input = array() ) {
86
+
87
+ $options = self::getOptions();
88
+
89
+ if ( empty( $_POST['_wp_http_referer'] ) ) {
90
+
91
+ return $input;
92
+ }
93
+
94
+ $registered = self::getRegistered();
95
+
96
+ foreach ( $registered as $sectionID => $sectionOptions ) {
97
+
98
+ $input = $input ? $input : array();
99
+ $input = apply_filters( 'ez_toc_settings_' . $sectionID . '_sanitize', $input );
100
+
101
+ // Loop through each setting being saved and pass it through a sanitization filter
102
+ foreach ( $input as $key => $value ) {
103
+
104
+ // Get the setting type (checkbox, select, etc)
105
+ $type = isset( $registered[ $sectionID ][ $key ]['type'] ) ? $registered[ $sectionID ][ $key ]['type'] : FALSE;
106
+
107
+ if ( $type ) {
108
+
109
+ // Field type specific filter
110
+ $input[ $key ] = apply_filters( 'ez_toc_settings_sanitize_' . $type, $value, $key );
111
+ }
112
+
113
+ // General filter
114
+ $input[ $key ] = apply_filters( 'ez_toc_settings_sanitize', $input[ $key ], $key );
115
+ }
116
+
117
+ // Loop through the registered options.
118
+ foreach ( $sectionOptions as $optionID => $optionProperties ) {
119
+
120
+ // Unset any that are empty for the section being saved.
121
+ if ( empty( $input[ $optionID ] ) ) {
122
+
123
+ unset( $options[ $optionID ] );
124
+ }
125
+
126
+ // Check for the checkbox option type.
127
+ if ( array_key_exists( 'type', $optionProperties ) && 'checkbox' == $optionProperties['type'] ) {
128
+
129
+ // If it does not exist in the options values being saved, add the option ID and set its value to `0`.
130
+ // This matches WP core behavior for saving checkbox option values.
131
+ if ( ! array_key_exists( $optionID, $input ) ) {
132
+
133
+ $input[ $optionID ] = '0';
134
+ }
135
+ }
136
+ }
137
+
138
+ }
139
+
140
+ // Merge our new settings with the existing
141
+ $output = array_merge( $options, $input );
142
+
143
+ return $output;
144
+ }
145
+
146
+ /**
147
+ * The core registered settings and options.
148
+ *
149
+ * @access private
150
+ * @since 1.0
151
+ * @static
152
+ *
153
+ * @return array
154
+ */
155
+ private static function getRegistered() {
156
+
157
+ $options = array(
158
+ 'general' => apply_filters(
159
+ 'ez_toc_settings_general',
160
+ array(
161
+ 'enabled_post_types' => array(
162
+ 'id' => 'enabled_post_types',
163
+ 'name' => __( 'Enable Support', 'ez_toc' ),
164
+ 'desc' => __( 'Select the post types to enable the support for table of contents.', 'ez_toc' ),
165
+ 'type' => 'checkboxgroup',
166
+ 'options' => self::getPostTypes(),
167
+ 'default' => array(),
168
+ ),
169
+ 'auto_insert_post_types' => array(
170
+ 'id' => 'auto_insert_post_types',
171
+ 'name' => __( 'Auto Insert', 'ez_toc' ),
172
+ 'desc' => __( 'Select the post types which will have the table of contents automatically inserted.', 'ez_toc' ) .
173
+ '<br><span class="description">' . __( 'NOTE: The table of contents will only be automatically inserted on post types for which it has been enabled.', 'ez_toc' ) . '<span>',
174
+ 'type' => 'checkboxgroup',
175
+ 'options' => self::getPostTypes(),
176
+ 'default' => array(),
177
+ ),
178
+ 'position' => array(
179
+ 'id' => 'position',
180
+ 'name' => __( 'Position', 'ez_toc' ),
181
+ 'desc' => __( 'Choose where where you want to display the table of contents.', 'ez_toc' ),
182
+ 'type' => 'select',
183
+ 'options' => array(
184
+ 'before' => __( 'Before first heading (default)', 'ez_toc' ),
185
+ 'after' => __( 'After first heading', 'ez_toc' ),
186
+ 'top' => __( 'Top', 'ez_toc' ),
187
+ 'bottom' => __( 'Bottom', 'ez_toc' ),
188
+ ),
189
+ 'default' => 1,
190
+ ),
191
+ 'start' => array(
192
+ 'id' => 'start',
193
+ 'name' => __( 'Show when', 'ez_toc' ),
194
+ 'desc' => __( 'or more headings are present', 'ez_toc' ),
195
+ 'type' => 'select',
196
+ 'options' => array_combine( range( 2, 10 ), range( 2, 10 ) ),
197
+ 'default' => 4,
198
+ ),
199
+ 'show_heading_text' => array(
200
+ 'id' => 'show_heading_text',
201
+ 'name' => __( 'Display Header Label', 'ez_toc' ),
202
+ 'desc' => __( 'Show header text above the table of contents.', 'ez_toc' ),
203
+ 'type' => 'checkbox',
204
+ 'default' => TRUE,
205
+ ),
206
+ 'heading_text' => array(
207
+ 'id' => 'heading_text',
208
+ 'name' => __( 'Header Label', 'ez_toc' ),
209
+ 'desc' => __( 'Eg: Contents, Table of Contents, Page Contents', 'ez_toc' ),
210
+ 'type' => 'text',
211
+ 'default' => __( 'Contents', 'ez_toc' ),
212
+ ),
213
+ 'visibility' => array(
214
+ 'id' => 'visibility',
215
+ 'name' => __( 'Toggle View', 'ez_toc' ),
216
+ 'desc' => __( 'Allow the user to toggle the visibility of the table of contents.', 'connection_toc' ),
217
+ 'type' => 'checkbox',
218
+ 'default' => TRUE,
219
+ ),
220
+ //'visibility_show' => array(
221
+ // 'id' => 'visibility_show',
222
+ // 'name' => __( 'Show Label', 'ez_toc' ),
223
+ // 'desc' => __( 'Eg: show', 'ez_toc' ),
224
+ // 'type' => 'text',
225
+ // 'default' => __( 'show', 'ez_toc' ),
226
+ //),
227
+ //'visibility_hide' => array(
228
+ // 'id' => 'visibility_hide',
229
+ // 'name' => __( 'Hide Label', 'ez_toc' ),
230
+ // 'desc' => __( 'Eg: hide', 'ez_toc' ),
231
+ // 'type' => 'text',
232
+ // 'default' => __( 'hide', 'ez_toc' ),
233
+ //),
234
+ 'visibility_hide_by_default' => array(
235
+ 'id' => 'visibility_hide_by_default',
236
+ 'name' => __( 'Initial View', 'ez_toc' ),
237
+ 'desc' => __( 'Initially hide the table of contents.', 'connection_toc' ),
238
+ 'type' => 'checkbox',
239
+ 'default' => FALSE,
240
+ ),
241
+ 'show_hierarchy' => array(
242
+ 'id' => 'show_hierarchy',
243
+ 'name' => __( 'Show as Hierarchy', 'ez_toc' ),
244
+ 'desc' => '',
245
+ 'type' => 'checkbox',
246
+ 'default' => TRUE,
247
+ ),
248
+ 'counter' => array(
249
+ 'id' => 'counter',
250
+ 'name' => __( 'Counter', 'ez_toc' ),
251
+ 'desc' => '',
252
+ 'type' => 'select',
253
+ 'options' => array(
254
+ 'decimal' => __( 'Decimal (default)', 'ez_toc' ),
255
+ 'numeric' => __( 'Numeric', 'ez_toc' ),
256
+ 'roman' => __( 'Roman', 'ez_toc' ),
257
+ 'none' => __( 'None', 'ez_toc' ),
258
+ ),
259
+ 'default' => 'decimal',
260
+ ),
261
+ 'smooth_scroll' => array(
262
+ 'id' => 'smooth_scroll',
263
+ 'name' => __( 'Smooth Scroll', 'ez_toc' ),
264
+ 'desc' => '',
265
+ 'type' => 'checkbox',
266
+ 'default' => TRUE,
267
+ ),
268
+ )
269
+ ),
270
+ 'appearance' => apply_filters(
271
+ 'ez_toc_settings_appearance',
272
+ array(
273
+ 'width' => array(
274
+ 'id' => 'width',
275
+ 'name' => __( 'Width', 'ez_toc' ),
276
+ 'desc' => '',
277
+ 'type' => 'selectgroup',
278
+ 'options' => array(
279
+ 'fixed' => array(
280
+ 'name' => __( 'Fixed', 'ez_toc' ),
281
+ 'options' => array(
282
+ '200px' => '200px',
283
+ '225px' => '225px',
284
+ '250px' => '250px',
285
+ '275px' => '275px',
286
+ '300px' => '300px',
287
+ '325px' => '325px',
288
+ '350px' => '350px',
289
+ '375px' => '375px',
290
+ '400px' => '400px',
291
+ ),
292
+ ),
293
+ 'relative' => array(
294
+ 'name' => __( 'Relative', 'ez_toc' ),
295
+ 'options' => array(
296
+ 'auto' => 'Auto',
297
+ '25%' => '25%',
298
+ '33%' => '33%',
299
+ '50%' => '50%',
300
+ '66%' => '66%',
301
+ '75%' => '75%',
302
+ '100%' => '100%',
303
+ ),
304
+ ),
305
+ 'other' => array(
306
+ 'name' => __( 'Custom', 'ez_toc' ),
307
+ 'options' => array(
308
+ 'custom' => __( 'User Defined', 'ez_toc' ),
309
+ ),
310
+ ),
311
+ ),
312
+ 'default' => 'auto',
313
+ ),
314
+ 'width_custom' => array(
315
+ 'id' => 'width_custom',
316
+ 'name' => __( 'Custom Width', 'ez_toc' ),
317
+ 'desc' => __( 'Select the User Defined option from the Width option to utilitze the custom width.', 'ez_toc' ),
318
+ 'type' => 'custom_width',
319
+ 'default' => 275,
320
+ ),
321
+ 'wrapping' => array(
322
+ 'id' => 'wrapping',
323
+ 'name' => __( 'Float', 'ez_toc' ),
324
+ 'desc' => '',
325
+ 'type' => 'select',
326
+ 'options' => array(
327
+ 'none' => __( 'None (Default)', 'ez_toc' ),
328
+ 'left' => __( 'Left', 'ez_toc' ),
329
+ 'right' => __( 'Right', 'ez_toc' ),
330
+ ),
331
+ 'default' => 'none',
332
+ ),
333
+ 'font_size' => array(
334
+ 'id' => 'font_size',
335
+ 'name' => __( 'Font Size', 'ez_toc' ),
336
+ 'desc' => '',
337
+ 'type' => 'font_size',
338
+ 'default' => 95,
339
+ ),
340
+ 'theme' => array(
341
+ 'id' => 'theme',
342
+ 'name' => __( 'Theme', 'ez_toc' ),
343
+ 'desc' => __( 'The theme is only applied to the table of contents which is auto inserted into the post. The Table of Contents widget will inherit the theme widget styles.', 'ez_toc' ),
344
+ 'type' => 'radio',
345
+ 'options' => array(
346
+ 'grey' => __( 'Grey', 'ez_toc' ),
347
+ 'light-blue' => __( 'Light Blue', 'ez_toc' ),
348
+ 'white' => __( 'White', 'ez_toc' ),
349
+ 'black' => __( 'Black', 'ez_toc' ),
350
+ 'transparent' => __( 'Transparent', 'ez_toc' ),
351
+ 'custom' => __( 'Custom', 'ez_toc' ),
352
+ ),
353
+ 'default' => 'grey',
354
+ ),
355
+ 'custom_theme_header' => array(
356
+ 'id' => 'custom_theme_header',
357
+ 'name' => '<strong>' . __( 'Custom Theme', 'ez_toc' ) . '</strong>',
358
+ 'desc' => __( 'For the following settings to apply, select the Custom Theme option.', 'ez_toc' ),
359
+ 'type' => 'header',
360
+ ),
361
+ 'custom_background_colour' => array(
362
+ 'id' => 'custom_background_colour',
363
+ 'name' => __( 'Background Color', 'ez_toc' ),
364
+ 'desc' => '',
365
+ 'type' => 'color',
366
+ 'default' => '#fff',
367
+ ),
368
+ 'custom_border_colour' => array(
369
+ 'id' => 'custom_border_colour',
370
+ 'name' => __( 'Border Color', 'ez_toc' ),
371
+ 'desc' => '',
372
+ 'type' => 'color',
373
+ 'default' => '#ddd',
374
+ ),
375
+ 'custom_title_colour' => array(
376
+ 'id' => 'custom_title_colour',
377
+ 'name' => __( 'Title Color', 'ez_toc' ),
378
+ 'desc' => '',
379
+ 'type' => 'color',
380
+ 'default' => '#999',
381
+ ),
382
+ 'custom_link_colour' => array(
383
+ 'id' => 'custom_link_colour',
384
+ 'name' => __( 'Link Color', 'ez_toc' ),
385
+ 'desc' => '',
386
+ 'type' => 'color',
387
+ 'default' => '#428bca',
388
+ ),
389
+ 'custom_link_hover_colour' => array(
390
+ 'id' => 'custom_link_hover_colour',
391
+ 'name' => __( 'Link Hover Color', 'ez_toc' ),
392
+ 'desc' => '',
393
+ 'type' => 'color',
394
+ 'default' => '#2a6496',
395
+ ),
396
+ 'custom_link_visited_colour' => array(
397
+ 'id' => 'custom_link_visited_colour',
398
+ 'name' => __( 'Link Visited Color', 'ez_toc' ),
399
+ 'desc' => '',
400
+ 'type' => 'color',
401
+ 'default' => '#428bca',
402
+ ),
403
+ )
404
+ ),
405
+ 'advanced' => apply_filters(
406
+ 'ez_toc_settings_advanced',
407
+ array(
408
+ 'lowercase' => array(
409
+ 'id' => 'lowercase',
410
+ 'name' => __( 'Lowercase', 'ez_toc' ),
411
+ 'desc' => __( 'Ensure anchors are in lowercase.', 'ez_toc' ),
412
+ 'type' => 'checkbox',
413
+ 'default' => FALSE,
414
+ ),
415
+ 'hyphenate' => array(
416
+ 'id' => 'hyphenate',
417
+ 'name' => __( 'Hyphenate', 'ez_toc' ),
418
+ 'desc' => __( 'Use - rather than _ in anchors.', 'ez_toc' ),
419
+ 'type' => 'checkbox',
420
+ 'default' => FALSE,
421
+ ),
422
+ 'include_homepage' => array(
423
+ 'id' => 'include_homepage',
424
+ 'name' => __( 'Homepage', 'ez_toc' ),
425
+ 'desc' => __( 'Show the table of contents for qualifying items on the homepage.', 'ez_toc' ),
426
+ 'type' => 'checkbox',
427
+ 'default' => FALSE,
428
+ ),
429
+ 'exclude_css' => array(
430
+ 'id' => 'exclude_css',
431
+ 'name' => __( 'CSS', 'ez_toc' ),
432
+ 'desc' => __( "Prevent the loading the core CSS styles. When selected, the appearance options from above will be ignored.", 'ez_toc' ),
433
+ 'type' => 'checkbox',
434
+ 'default' => FALSE,
435
+ ),
436
+ //'bullet_spacing' => array(
437
+ // 'id' => 'bullet_spacing',
438
+ // 'name' => __( 'Theme Bullets', 'ez_toc' ),
439
+ // 'desc' => __( 'If your theme includes background images for unordered list elements, enable this option to support them.', 'ez_toc' ),
440
+ // 'type' => 'checkbox',
441
+ // 'default' => FALSE,
442
+ //),
443
+ 'heading_levels' => array(
444
+ 'id' => 'heading_levels',
445
+ 'name' => __( 'Headings:', 'ez_toc' ),
446
+ 'desc' => __( 'Select the heading to consider when generating the table of contents. Deselecting a heading will exclude it.', 'ez_toc' ),
447
+ 'type' => 'checkboxgroup',
448
+ 'options' => array(
449
+ '1' => __( 'Heading 1 (h1)', 'ez_toc' ),
450
+ '2' => __( 'Heading 2 (h2)', 'ez_toc' ),
451
+ '3' => __( 'Heading 3 (h3)', 'ez_toc' ),
452
+ '4' => __( 'Heading 4 (h4)', 'ez_toc' ),
453
+ '5' => __( 'Heading 5 (h5)', 'ez_toc' ),
454
+ '6' => __( 'Heading 6 (h6)', 'ez_toc' ),
455
+ ),
456
+ 'default' => array( '1', '2', '3', '4', '5', '6' ),
457
+ ),
458
+ 'exclude' => array(
459
+ 'id' => 'exclude',
460
+ 'name' => __( 'Exclude Headings', 'ez_toc' ),
461
+ 'desc' => __( 'Specify headings to be excluded from appearing in the table of contents. Separate multiple headings with a pipe <code>|</code>. Use an asterisk <code>*</code> as a wildcard to match other text.', 'ez_toc' ),
462
+ 'type' => 'text',
463
+ 'size' => 'large',
464
+ 'default' => '',
465
+ ),
466
+ 'exclude_desc' => array(
467
+ 'id' => 'exclude_desc',
468
+ 'name' => '',
469
+ 'desc' => '<p><strong>' . __( 'Examples:', 'ez_toc' ) . '</strong></p>' .
470
+ '<ul>' .
471
+ '<li>' . __( '<code>Fruit*</code> Ignore headings starting with "Fruit".', 'ez_toc' ) . '</li>' .
472
+ '<li>' . __( '<code>*Fruit Diet*</code> Ignore headings with "Fruit Diet" somewhere in the heading.', 'ez_toc' ) . '</li>' .
473
+ '<li>' . __( '<code>Apple Tree|Oranges|Yellow Bananas</code> Ignore headings that are exactly "Apple Tree", "Oranges" or "Yellow Bananas".', 'ez_toc' ) . '</li>' .
474
+ '</ul>' .
475
+ '<p>' . __( '<strong>Note:</strong> This is not case sensitive.', 'ez_toc' ) . '</p>',
476
+ 'type' => 'descriptive_text',
477
+ ),
478
+ 'smooth_scroll_offset' => array(
479
+ 'id' => 'smooth_scroll_offset',
480
+ 'name' => __( 'Smooth Scroll Offset', 'ez_toc' ),
481
+ 'desc' => 'px<br/>' . __( 'If you have a consistent menu across the top of your site, you can adjust the top offset to stop the headings from appearing underneath the top menu. A setting of 30 accommodates the WordPress admin bar. This setting only has an effect after you have enabled Smooth Scroll option.', 'ez_toc' ),
482
+ 'type' => 'number',
483
+ 'size' => 'small',
484
+ 'default' => 30
485
+ ),
486
+ 'restrict_path' => array(
487
+ 'id' => 'restrict_path',
488
+ 'name' => __( 'Limit Path', 'ez_toc' ),
489
+ 'desc' => '<br/>' . __( 'Restrict generation of the table of contents to pages that match the required path. This path is from the root of your site and always begins with a forward slash.', 'ez_toc' ) .
490
+ '<br/><span class="description">' . __( 'Eg: /wiki/, /corporate/annual-reports/', 'ez_toc' ) . '</span>',
491
+ 'type' => 'text',
492
+ ),
493
+ 'fragment_prefix' => array(
494
+ 'id' => 'fragment_prefix',
495
+ 'name' => __( 'Default Anchor Prefix', 'ez_toc' ),
496
+ 'desc' => '<br/>' . __( 'Anchor targets are restricted to alphanumeric characters as per HTML specification (see readme for more detail). The default anchor prefix will be used when no characters qualify. When left blank, a number will be used instead.', 'ez_toc' ) .
497
+ '<br/>' . __( 'This option normally applies to content written in character sets other than ASCII.', 'ez_toc' ) .
498
+ '<br/><span class="description">' . __( 'Eg: i, toc_index, index, _', 'ez_toc' ) . '</span>',
499
+ 'type' => 'text',
500
+ 'default' => 'i',
501
+ ),
502
+ 'widget_affix_selector' => array(
503
+ 'id' => 'widget_affix_selector',
504
+ 'name' => __( 'Widget Affix Selector', 'ez_toc' ),
505
+ 'desc' => '<br/>' . __( 'To enable the option to affix or pin the Table of Contents widget enter the theme\'s sidebar class or id.', 'ez_toc' ) .
506
+ '<br/>' . __( 'Since every theme is different, this can not be determined automatically. If you are unsure how to find the sidebar\'s class or id, please ask the theme\'s support persons.', 'ez_toc' ) .
507
+ '<br/><span class="description">' . __( 'Eg: .widget-area or #sidebar', 'ez_toc' ) . '</span>',
508
+ 'type' => 'text',
509
+ 'default' => '',
510
+ ),
511
+ )
512
+ ),
513
+ );
514
+
515
+ return apply_filters( 'ez_toc_registered_settings', $options );
516
+ }
517
+
518
+ /**
519
+ * The default values for the registered settings and options.
520
+ *
521
+ * @access private
522
+ * @since 1.0
523
+ * @static
524
+ *
525
+ * @return array
526
+ */
527
+ private static function getDefaults() {
528
+
529
+ $defaults = array(
530
+ 'fragment_prefix' => 'i',
531
+ 'position' => 'before',
532
+ 'start' => 4,
533
+ 'show_heading_text' => TRUE,
534
+ 'heading_text' => 'Table of Contents',
535
+ 'enabled_post_types' => array( 'page' ),
536
+ 'auto_insert_post_types' => array(),
537
+ 'show_hierarchy' => TRUE,
538
+ 'counter' => 'decimal',
539
+ 'smooth_scroll' => TRUE,
540
+ 'smooth_scroll_offset' => 30,
541
+ 'visibility' => TRUE,
542
+ //'visibility_show' => 'show',
543
+ //'visibility_hide' => 'hide',
544
+ 'visibility_hide_by_default' => FALSE,
545
+ 'width' => 'auto',
546
+ 'width_custom' => 275,
547
+ 'width_custom_units' => 'px',
548
+ 'wrapping' => 'none',
549
+ 'font_size' => 95,
550
+ 'font_size_units' => '%',
551
+ 'theme' => 'grey',
552
+ 'custom_background_colour' => '#fff',
553
+ 'custom_border_colour' => '#ddd',
554
+ 'custom_title_colour' => '#999',
555
+ 'custom_link_colour' => '#428bca',
556
+ 'custom_link_hover_colour' => '#2a6496',
557
+ 'custom_link_visited_colour' => '#428bca',
558
+ 'lowercase' => FALSE,
559
+ 'hyphenate' => FALSE,
560
+ //'bullet_spacing' => FALSE,
561
+ 'include_homepage' => FALSE,
562
+ 'exclude_css' => FALSE,
563
+ 'exclude' => '',
564
+ 'heading_levels' => array( '1', '2', '3', '4', '5', '6' ),
565
+ 'restrict_path' => '',
566
+ 'css_container_class' => '',
567
+ //'show_toc_in_widget_only' => FALSE,
568
+ //'show_toc_in_widget_only_post_types' => array(),
569
+ 'widget_affix_selector' => '',
570
+ );
571
+
572
+ return apply_filters( 'ez_toc_get_default_options', $defaults );
573
+ }
574
+
575
+ /**
576
+ * Get the default options array.
577
+ *
578
+ * @access private
579
+ * @since 1.0
580
+ * @static
581
+ *
582
+ * @return array
583
+ */
584
+ private static function getOptions() {
585
+
586
+ $defaults = self::getDefaults();
587
+ $options = get_option( 'ez-toc-settings', $defaults );
588
+
589
+ //return apply_filters( 'ez_toc_get_options', wp_parse_args( $options, $defaults ) );
590
+ return apply_filters( 'ez_toc_get_options', $options );
591
+ }
592
+
593
+ /**
594
+ * Get option value by key name.
595
+ *
596
+ * @access public
597
+ * @since 1.0
598
+ * @static
599
+ *
600
+ * @param string $key
601
+ * @param bool|FALSE $default
602
+ *
603
+ * @return mixed|void
604
+ */
605
+ public static function get( $key, $default = FALSE ) {
606
+
607
+ $options = self::getOptions();
608
+
609
+ $value = array_key_exists( $key, $options ) ? $options[ $key ] : $default;
610
+ $value = apply_filters( 'ez_toc_get_option', $value, $key, $default );
611
+
612
+ return apply_filters( 'ez_toc_get_option_' . $key, $value, $key, $default );
613
+ }
614
+
615
+ /**
616
+ * Set an option value by key name.
617
+ *
618
+ * @access public
619
+ * @since 1.0
620
+ * @static
621
+ *
622
+ * @param string $key
623
+ * @param bool|FALSE $value
624
+ *
625
+ * @return bool
626
+ */
627
+ public static function set( $key, $value = FALSE ) {
628
+
629
+ if ( empty( $value ) ) {
630
+
631
+ $remove_option = self::delete( $key );
632
+
633
+ return $remove_option;
634
+ }
635
+
636
+ $options = self::getOptions();
637
+
638
+ $options[ $key ] = apply_filters( 'ez_toc_update_option', $value, $key );
639
+
640
+ return update_option( 'ez-toc-settings', $options );
641
+ }
642
+
643
+ /**
644
+ * Delete an option from the options table by option key name.
645
+ *
646
+ * @access public
647
+ * @since 1.0
648
+ * @static
649
+ *
650
+ * @param string $key
651
+ *
652
+ * @return bool
653
+ */
654
+ public static function delete( $key ) {
655
+
656
+ // First let's grab the current settings
657
+ $options = get_option( 'ez-toc-settings' );
658
+
659
+ // Next let's try to update the value
660
+ if ( array_key_exists( $key, $options ) ) {
661
+
662
+ unset( $options[ $key ] );
663
+ }
664
+
665
+ return update_option( 'ez-toc-settings', $options );
666
+ }
667
+
668
+ /**
669
+ * Sanitize a hex color from user input.
670
+ *
671
+ * Tries to convert $string into a valid hex colour.
672
+ * Returns $default if $string is not a hex value, otherwise returns verified hex.
673
+ *
674
+ * @access private
675
+ * @since 1.0
676
+ * @static
677
+ *
678
+ * @param string $string
679
+ * @param string $default
680
+ *
681
+ * @return mixed|string
682
+ */
683
+ private static function hex_value( $string = '', $default = '#' ) {
684
+
685
+ $return = $default;
686
+
687
+ if ( $string ) {
688
+ // strip out non hex chars
689
+ $return = preg_replace( '/[^a-fA-F0-9]*/', '', $string );
690
+
691
+ switch ( strlen( $return ) ) {
692
+ case 3: // do next
693
+ case 6:
694
+ $return = '#' . $return;
695
+ break;
696
+
697
+ default:
698
+ if ( strlen( $return ) > 6 ) {
699
+ $return = '#' . substr( $return, 0, 6 );
700
+ } // if > 6 chars, then take the first 6
701
+ elseif ( strlen( $return ) > 3 && strlen( $return ) < 6 ) {
702
+ $return = '#' . substr( $return, 0, 3 );
703
+ } // if between 3 and 6, then take first 3
704
+ else {
705
+ $return = $default;
706
+ } // not valid, return $default
707
+ }
708
+ }
709
+
710
+ return $return;
711
+ }
712
+
713
+ /**
714
+ * Get the registered post types minus excluded core types.
715
+ *
716
+ * @access public
717
+ * @since 1.0
718
+ * @static
719
+ *
720
+ * @return array
721
+ */
722
+ public static function getPostTypes() {
723
+
724
+ $exclude = apply_filters( 'ez_toc_exclude_post_types', array( 'attachment', 'revision', 'nav_menu_item', 'safecss' ) );
725
+ $registered = get_post_types( array(), 'objects' );
726
+ $types = array();
727
+
728
+ foreach ( $registered as $post ) {
729
+
730
+ if ( in_array( $post->name, $exclude ) ) {
731
+
732
+ continue;
733
+ }
734
+
735
+ $types[ $post->name ] = $post->label;
736
+ }
737
+
738
+ return $types;
739
+ }
740
+
741
+ /**
742
+ * Missing Callback
743
+ *
744
+ * If a settings field type callback is not callable, alert the user.
745
+ *
746
+ * @access public
747
+ * @since 1.0
748
+ * @static
749
+ *
750
+ * @param array $args Arguments passed by the setting
751
+ */
752
+ public static function missingCallback( $args ) {
753
+
754
+ printf(
755
+ __( 'The callback function used for the <strong>%s</strong> setting is missing.', 'ez_toc' ),
756
+ $args['id']
757
+ );
758
+ }
759
+
760
+ /**
761
+ * Text Callback
762
+ *
763
+ * Renders text fields.
764
+ *
765
+ * @access public
766
+ * @since 1.0
767
+ * @static
768
+ *
769
+ * @param array $args Arguments passed by the setting
770
+ * @param null $value
771
+ */
772
+ public static function text( $args, $value = NULL ) {
773
+
774
+ if ( is_null( $value ) ) {
775
+
776
+ $value = self::get( $args['id'], $args['default'] );
777
+ }
778
+
779
+ if ( isset( $args['faux'] ) && TRUE === $args['faux'] ) {
780
+
781
+ $args['readonly'] = TRUE;
782
+ $value = isset( $args['default'] ) ? $args['default'] : '';
783
+ $name = '';
784
+
785
+ } else {
786
+
787
+ $name = 'name="ez-toc-settings[' . $args['id'] . ']"';
788
+ }
789
+
790
+ $readonly = isset( $args['readonly'] ) && $args['readonly'] === TRUE ? ' readonly="readonly"' : '';
791
+ $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
792
+
793
+ $html = '<input type="text" class="' . $size . '-text" id="ez-toc-settings[' . $args['id'] . ']"' . $name . ' value="' . esc_attr( stripslashes( $value ) ) . '"' . $readonly . '/>';
794
+
795
+ if ( 0 < strlen( $args['desc'] ) ) {
796
+
797
+ $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
798
+ }
799
+
800
+ echo $html;
801
+ }
802
+
803
+ /**
804
+ * Number Callback
805
+ *
806
+ * Renders number fields.
807
+ *
808
+ * @access public
809
+ * @since 1.0
810
+ * @static
811
+ *
812
+ * @param array $args Arguments passed by the setting
813
+ */
814
+ public static function number( $args ) {
815
+
816
+ $value = self::get( $args['id'], $args['default'] );
817
+
818
+ if ( isset( $args['faux'] ) && TRUE === $args['faux'] ) {
819
+
820
+ $args['readonly'] = TRUE;
821
+ $value = isset( $args['default'] ) ? $args['default'] : '';
822
+ $name = '';
823
+
824
+ } else {
825
+
826
+ $name = 'name="ez-toc-settings[' . $args['id'] . ']"';
827
+ }
828
+
829
+ $readonly = isset( $args['readonly'] ) && $args['readonly'] === TRUE ? ' readonly="readonly"' : '';
830
+ $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
831
+
832
+ $html = '<input type="number" class="' . $size . '-text" id="ez-toc-settings[' . $args['id'] . ']"' . $name . ' value="' . esc_attr( stripslashes( $value ) ) . '"' . $readonly . '/>';
833
+
834
+ if ( 0 < strlen( $args['desc'] ) ) {
835
+
836
+ $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
837
+ }
838
+
839
+ echo $html;
840
+ }
841
+
842
+ /**
843
+ * Checkbox Callback
844
+ *
845
+ * Renders checkboxes.
846
+ *
847
+ * @access public
848
+ * @since 1.0
849
+ * @static
850
+ *
851
+ * @param array $args Arguments passed by the setting
852
+ * @param null $value
853
+ */
854
+ public static function checkbox( $args, $value = NULL ) {
855
+
856
+ if ( is_null( $value ) ) {
857
+
858
+ $value = self::get( $args['id'], $args['default'] );
859
+ }
860
+
861
+ if ( isset( $args['faux'] ) && TRUE === $args['faux'] ) {
862
+
863
+ $name = '';
864
+
865
+ } else {
866
+
867
+ $name = 'name="ez-toc-settings[' . $args['id'] . ']"';
868
+ }
869
+
870
+ $checked = $value ? checked( 1, $value, FALSE ) : '';
871
+
872
+ $html = '<input type="checkbox" id="ez-toc-settings[' . $args['id'] . ']"' . $name . ' value="1" ' . $checked . '/>';
873
+
874
+ if ( 0 < strlen( $args['desc'] ) ) {
875
+
876
+ $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
877
+ }
878
+
879
+ echo $html;
880
+ }
881
+
882
+ /**
883
+ * Multicheck Callback
884
+ *
885
+ * Renders multiple checkboxes.
886
+ *
887
+ * @access public
888
+ * @since 1.0
889
+ * @static
890
+ *
891
+ * @param array $args Arguments passed by the setting
892
+ * @param null $value
893
+ */
894
+ public static function checkboxgroup( $args, $value = NULL ) {
895
+
896
+ if ( is_null( $value ) ) {
897
+
898
+ $value = self::get( $args['id'], $args['default'] );
899
+ }
900
+
901
+ if ( ! empty( $args['options'] ) ) {
902
+
903
+ foreach ( $args['options'] as $key => $option ):
904
+
905
+ if ( in_array( $key, $value ) ) {
906
+
907
+ $enabled = $option;
908
+
909
+ } else {
910
+
911
+ $enabled = NULL;
912
+ }
913
+
914
+ echo '<input name="ez-toc-settings[' . $args['id'] . '][' . $key . ']" id="ez-toc-settings[' . $args['id'] . '][' . $key . ']" type="checkbox" value="' . $key . '" ' . checked( $option, $enabled, FALSE ) . '/>&nbsp;';
915
+ echo '<label for="ez-toc-settings[' . $args['id'] . '][' . $key . ']">' . $option . '</label><br/>';
916
+
917
+ endforeach;
918
+
919
+ if ( 0 < strlen( $args['desc'] ) ) {
920
+
921
+ echo '<p class="description">' . $args['desc'] . '</p>';
922
+ }
923
+ }
924
+ }
925
+
926
+ /**
927
+ * Radio Callback
928
+ *
929
+ * Renders radio groups.
930
+ *
931
+ * @access public
932
+ * @since 1.0
933
+ * @static
934
+ *
935
+ * @param array $args Arguments passed by the setting
936
+ */
937
+ public static function radio( $args ) {
938
+
939
+ $value = self::get( $args['id'], $args['default'] );
940
+
941
+ foreach ( $args['options'] as $key => $option ) {
942
+
943
+ echo '<input name="ez-toc-settings[' . $args['id'] . ']"" id="ez-toc-settings[' . $args['id'] . '][' . $key . ']" type="radio" value="' . $key . '" ' . checked( $key, $value, FALSE ) . '/>&nbsp;';
944
+ echo '<label for="ez-toc-settings[' . $args['id'] . '][' . $key . ']">' . $option . '</label><br/>';
945
+ }
946
+
947
+ if ( 0 < strlen( $args['desc'] ) ) {
948
+
949
+ echo '<p class="description">' . $args['desc'] . '</p>';
950
+ }
951
+ }
952
+
953
+ /**
954
+ * Select Callback
955
+ *
956
+ * Renders select fields.
957
+ *
958
+ * @access public
959
+ * @since 1.0
960
+ * @static
961
+ *
962
+ * @param array $args Arguments passed by the setting.
963
+ */
964
+ public static function select( $args ) {
965
+
966
+ $value = self::get( $args['id'], $args['default'] );
967
+
968
+ if ( isset( $args['placeholder'] ) ) {
969
+ $placeholder = $args['placeholder'];
970
+ } else {
971
+ $placeholder = '';
972
+ }
973
+
974
+ if ( isset( $args['chosen'] ) ) {
975
+ $chosen = 'class="enhanced"';
976
+ } else {
977
+ $chosen = '';
978
+ }
979
+
980
+ $html = '<select id="ez-toc-settings[' . $args['id'] . ']" name="ez-toc-settings[' . $args['id'] . ']" ' . $chosen . 'data-placeholder="' . $placeholder . '" />';
981
+
982
+ foreach ( $args['options'] as $option => $name ) {
983
+ $selected = selected( $option, $value, FALSE );
984
+ $html .= '<option value="' . $option . '" ' . $selected . '>' . $name . '</option>';
985
+ }
986
+
987
+ $html .= '</select>';
988
+
989
+ if ( 0 < strlen( $args['desc'] ) ) {
990
+
991
+ $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
992
+ }
993
+
994
+ echo $html;
995
+ }
996
+
997
+ /**
998
+ * Select Drop Down Callback
999
+ *
1000
+ * Renders select with option group fields.
1001
+ *
1002
+ * @access public
1003
+ * @since 1.0
1004
+ * @static
1005
+ *
1006
+ * @param array $args Arguments passed by the setting.
1007
+ */
1008
+ public static function selectgroup( $args ) {
1009
+
1010
+ $value = self::get( $args['id'], $args['default'] );
1011
+
1012
+ if ( isset( $args['placeholder'] ) ) {
1013
+ $placeholder = $args['placeholder'];
1014
+ } else {
1015
+ $placeholder = '';
1016
+ }
1017
+
1018
+ if ( isset( $args['chosen'] ) ) {
1019
+ $chosen = 'class="enhanced"';
1020
+ } else {
1021
+ $chosen = '';
1022
+ }
1023
+
1024
+ $html = '<select id="ez-toc-settings[' . $args['id'] . ']" name="ez-toc-settings[' . $args['id'] . ']" ' . $chosen . 'data-placeholder="' . $placeholder . '" />';
1025
+
1026
+ foreach ( $args['options'] as $group ) {
1027
+
1028
+ $html .= sprintf( '<optgroup label="%1$s">', $group['name'] );
1029
+
1030
+ foreach ( $group['options'] as $option => $name ) {
1031
+
1032
+ $selected = selected( $option, $value, FALSE );
1033
+ $html .= '<option value="' . $option . '" ' . $selected . '>' . $name . '</option>';
1034
+ }
1035
+
1036
+ $html .= '</optgroup>';
1037
+ }
1038
+
1039
+ $html .= '</select>';
1040
+
1041
+ if ( 0 < strlen( $args['desc'] ) ) {
1042
+
1043
+ $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1044
+ }
1045
+
1046
+ echo $html;
1047
+ }
1048
+
1049
+ /**
1050
+ * Header Callback
1051
+ *
1052
+ * Renders the header.
1053
+ *
1054
+ * @access public
1055
+ * @since 1.0
1056
+ * @static
1057
+ *
1058
+ * @param array $args Arguments passed by the setting
1059
+ */
1060
+ public static function header( $args ) {
1061
+
1062
+ echo '<hr/>';
1063
+
1064
+ if ( 0 < strlen( $args['desc'] ) ) {
1065
+
1066
+ echo '<p>' . wp_kses_post( $args['desc'] ) . '</p>';
1067
+ }
1068
+ }
1069
+
1070
+ /**
1071
+ * Descriptive text callback.
1072
+ *
1073
+ * Renders descriptive text onto the settings field.
1074
+ *
1075
+ * @access public
1076
+ * @since 1.0
1077
+ * @static
1078
+ *
1079
+ * @param array $args Arguments passed by the setting
1080
+ */
1081
+ public static function descriptive_text( $args ) {
1082
+
1083
+ echo wp_kses_post( $args['desc'] );
1084
+ }
1085
+
1086
+ /**
1087
+ * Color picker Callback
1088
+ *
1089
+ * Renders color picker fields.
1090
+ *
1091
+ * @access public
1092
+ * @since 1.0
1093
+ * @static
1094
+ *
1095
+ * @param array $args Arguments passed by the setting
1096
+ */
1097
+ public static function color( $args ) {
1098
+
1099
+ $value = self::get( $args['id'], $args['default'] );
1100
+
1101
+ $default = isset( $args['default'] ) ? $args['default'] : '';
1102
+
1103
+ $html = '<input type="text" class="ez-toc-color-picker" id="ez-toc-settings[' . $args['id'] . ']" name="ez-toc-settings[' . $args['id'] . ']" value="' . esc_attr( $value ) . '" data-default-color="' . esc_attr( $default ) . '" />';
1104
+
1105
+ if ( 0 < strlen( $args['desc'] ) ) {
1106
+
1107
+ echo '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1108
+ }
1109
+
1110
+ echo $html;
1111
+ }
1112
+
1113
+ /**
1114
+ * Custom table of contents width.
1115
+ *
1116
+ * @access public
1117
+ * @since 1.0
1118
+ * @static
1119
+ *
1120
+ * @param array $args
1121
+ */
1122
+ public static function custom_width( $args ) {
1123
+
1124
+ //$value = self::get( $args['id'], $args['default'] );
1125
+
1126
+ self::text(
1127
+ array(
1128
+ 'id' => $args['id'],
1129
+ 'desc' => '',
1130
+ 'size' => 'small',
1131
+ 'default' => $args['default'],
1132
+ )
1133
+ );
1134
+
1135
+ self::select(
1136
+ array(
1137
+ 'id' => $args['id'] . '_units',
1138
+ 'desc' => '',
1139
+ 'options' => array(
1140
+ 'px' => 'px',
1141
+ '%' => '%',
1142
+ 'em' => 'em',
1143
+ ),
1144
+ 'default' => 'px',
1145
+ )
1146
+ );
1147
+
1148
+ if ( 0 < strlen( $args['desc'] ) ) {
1149
+
1150
+ echo '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1151
+ }
1152
+ }
1153
+
1154
+ /**
1155
+ * Custom font size callback.
1156
+ *
1157
+ * @access public
1158
+ * @since 1.0
1159
+ * @static
1160
+ *
1161
+ * @param array $args
1162
+ */
1163
+ public static function font_size( $args ) {
1164
+
1165
+ //$value = self::get( $args['id'], $args['default'] );
1166
+
1167
+ self::text(
1168
+ array(
1169
+ 'id' => $args['id'],
1170
+ 'desc' => '',
1171
+ 'size' => 'small',
1172
+ 'default' => $args['default'],
1173
+ )
1174
+ );
1175
+
1176
+ self::select(
1177
+ array(
1178
+ 'id' => $args['id'] . '_units',
1179
+ 'desc' => '',
1180
+ 'options' => array(
1181
+ 'pt' => 'pt',
1182
+ '%' => '%',
1183
+ 'em' => 'em',
1184
+ ),
1185
+ 'default' => 'px',
1186
+ )
1187
+ );
1188
+
1189
+ if ( 0 < strlen( $args['desc'] ) ) {
1190
+
1191
+ echo '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1192
+ }
1193
+ }
1194
+ }
1195
+
1196
+ add_action( 'admin_init', array( 'ezTOC_Option', 'register' ) );
1197
+ }
includes/class.widget-toc.php ADDED
@@ -0,0 +1,345 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // Exit if accessed directly
3
+ if ( ! defined( 'ABSPATH' ) ) exit;
4
+
5
+ if ( ! class_exists( 'ezTOC_Widget' ) ) {
6
+
7
+ /**
8
+ * Class ezTOC_Widget
9
+ */
10
+ class ezTOC_Widget extends WP_Widget {
11
+
12
+ /**
13
+ * Setup and register the table of contents widget.
14
+ *
15
+ * @access public
16
+ * @since 1.0
17
+ */
18
+ public function __construct() {
19
+
20
+ $options = array(
21
+ 'classname' => 'ez-toc',
22
+ 'description' => __( 'Display the table of contents.', 'ez_toc' )
23
+ );
24
+
25
+ parent::__construct(
26
+ 'ezw_tco',
27
+ __( 'Table of Contents', 'ez_toc' ),
28
+ $options
29
+ );
30
+
31
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueueScripts' ) );
32
+ add_action( 'admin_footer-widgets.php', array( $this, 'printScripts' ), 9999 );
33
+ }
34
+
35
+ /**
36
+ * Callback which registers the widget with the Widget API.
37
+ *
38
+ * @access public
39
+ * @since 1.0
40
+ * @static
41
+ *
42
+ * @return void
43
+ */
44
+ public static function register() {
45
+
46
+ register_widget( __CLASS__ );
47
+ }
48
+
49
+ /**
50
+ * Callback to enqueue scripts on the Widgets admin page.
51
+ *
52
+ * @access private
53
+ * @since 1.0
54
+ *
55
+ * @param string $hook_suffix
56
+ */
57
+ public function enqueueScripts( $hook_suffix ) {
58
+
59
+ if ( 'widgets.php' !== $hook_suffix ) {
60
+ return;
61
+ }
62
+
63
+ wp_enqueue_style( 'wp-color-picker' );
64
+ wp_enqueue_script( 'wp-color-picker' );
65
+ wp_enqueue_script( 'underscore' );
66
+ }
67
+
68
+ /**
69
+ * Callback to print the scripts to the Widgets admin page footer.
70
+ *
71
+ * @access private
72
+ * @since 1.0
73
+ */
74
+ public function printScripts() {
75
+ ?>
76
+ <script>
77
+ ( function( $ ){
78
+ function initColorPicker( widget ) {
79
+ widget.find( '.color-picker' ).wpColorPicker( {
80
+ change: _.throttle( function() { // For Customizer
81
+ $(this).trigger( 'change' );
82
+ }, 3000 )
83
+ });
84
+ }
85
+
86
+ function onFormUpdate( event, widget ) {
87
+ initColorPicker( widget );
88
+ }
89
+
90
+ $( document ).on( 'widget-added widget-updated', onFormUpdate );
91
+
92
+ $( document ).ready( function() {
93
+ $( '#widgets-right .widget:has(.color-picker)' ).each( function () {
94
+ initColorPicker( $( this ) );
95
+ } );
96
+ } );
97
+ }( jQuery ) );
98
+ </script>
99
+ <?php
100
+ }
101
+
102
+ /**
103
+ * Display the post content. Optionally allows post ID to be passed
104
+ *
105
+ * @link http://stephenharris.info/get-post-content-by-id/
106
+ * @link http://wordpress.stackexchange.com/a/143316
107
+ *
108
+ * @access public
109
+ * @since 1.0
110
+ *
111
+ * @param int $post_id Optional. Post ID.
112
+ *
113
+ * @return string
114
+ */
115
+ public function the_content( $post_id = 0 ) {
116
+
117
+ global $post;
118
+ $post = get_post( $post_id );
119
+ setup_postdata( $post );
120
+ ob_start();
121
+ the_content();
122
+ $content = ob_get_clean();
123
+ wp_reset_postdata();
124
+
125
+ return $content;
126
+ }
127
+
128
+ /**
129
+ * Renders the widgets.
130
+ *
131
+ * @access private
132
+ * @since 1.0
133
+ *
134
+ * @param array $args
135
+ * @param array $instance
136
+ */
137
+ public function widget( $args, $instance ) {
138
+
139
+ global $wp_query;
140
+
141
+ $css_classes = '';
142
+
143
+ $find = $replace = array();
144
+ $post = get_post( $wp_query->post->ID );
145
+ $content = apply_filters( 'the_content', $post->post_content );
146
+
147
+ /**
148
+ * @var string $before_widget
149
+ * @var string $after_widget
150
+ * @var string $before_title
151
+ * @var string $after_title
152
+ */
153
+ extract( $args );
154
+
155
+ $title = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
156
+ $items = ezTOC::extract_headings( $find, $replace, $content );
157
+
158
+ if ( FALSE !== strpos( $title, '%PAGE_TITLE%' ) || FALSE !== strpos( $title, '%PAGE_NAME%' ) ) {
159
+
160
+ $title = str_replace( '%PAGE_TITLE%', get_the_title(), $title );
161
+ }
162
+
163
+ if ( ezTOC_Option::get( 'show_hierarchy' ) ) {
164
+
165
+ $css_classes = ' counter-hierarchy';
166
+
167
+ } else {
168
+
169
+ $css_classes .= ' counter-flat';
170
+ }
171
+
172
+ switch ( ezTOC_Option::get( 'counter' ) ) {
173
+
174
+ case 'numeric':
175
+ $css_classes .= ' counter-numeric';
176
+ break;
177
+
178
+ case 'roman':
179
+ $css_classes .= ' counter-roman';
180
+ break;
181
+
182
+ case 'decimal':
183
+ $css_classes .= ' counter-decimal';
184
+ break;
185
+ }
186
+
187
+ if ( $instance['affix'] ) {
188
+
189
+ $css_classes .= ' ez-toc-affix';
190
+ }
191
+
192
+ // bullets?
193
+ //if ( ezTOC_Option::get( 'bullet_spacing' ) ) {
194
+ //
195
+ // $css_classes = ' have_bullets';
196
+ //
197
+ //} else {
198
+ //
199
+ // $css_classes = ' no_bullets';
200
+ //}
201
+
202
+ $css_classes = trim( $css_classes );
203
+
204
+ // an empty class="" is invalid markup!
205
+ if ( ! $css_classes ) {
206
+
207
+ $css_classes = ' ';
208
+ }
209
+
210
+ if ( $items ) {
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
+
218
+ if ( 0 < strlen( $title ) ) {
219
+
220
+ ?>
221
+
222
+ <?php echo $before_title; ?>
223
+
224
+ <span class="ez-toc-title-container">
225
+
226
+ <style type="text/css">
227
+ #<?php echo $this->id ?> .ez-toc-widget-container ul.ez-toc-list li.active::before {
228
+ background-color: <?php echo esc_attr( $instance['highlight_color'] ); ?>;
229
+ }
230
+ </style>
231
+
232
+ <span class="ez-toc-title"><?php echo $title; ?></span>
233
+
234
+ <span class="ez-toc-title-toggle">
235
+
236
+ <?php
237
+ if ( ezTOC_Option::get( 'visibility' ) ) {
238
+
239
+ echo '<a class="pull-right btn btn-xs btn-default ez-toc-toggle"><i class="glyphicon ez-toc-icon-toggle"></i></a>';
240
+ }
241
+ ?>
242
+
243
+ </span>
244
+
245
+ </span>
246
+
247
+ <?php echo $after_title; ?>
248
+
249
+ <?php
250
+ }
251
+
252
+ echo '<ul class="ez-toc-list">'. PHP_EOL . $items . '</ul>' . PHP_EOL;
253
+
254
+ do_action( 'ez_toc_after_widget' );
255
+
256
+ echo '</div>' . PHP_EOL;
257
+
258
+ echo $after_widget;
259
+
260
+ // Enqueue the script.
261
+ wp_enqueue_script( 'ez-toc-js' );
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Update the widget settings.
267
+ *
268
+ * @access private
269
+ * @since 1.0
270
+ *
271
+ * @param array $new_instance
272
+ * @param array $old_instance
273
+ *
274
+ * @return array
275
+ */
276
+ public function update( $new_instance, $old_instance ) {
277
+
278
+ $instance = $old_instance;
279
+
280
+ $instance['title'] = strip_tags( $new_instance['title'] );
281
+
282
+ $instance['affix'] = array_key_exists( 'affix', $new_instance ) ? $new_instance['affix'] : '0';
283
+
284
+ $instance['highlight_color'] = strip_tags( $new_instance['highlight_color'] );
285
+
286
+ $instance['hide_inline'] = array_key_exists( 'hide_inline', $new_instance ) ? $new_instance['hide_inline'] : '0';
287
+
288
+ //ezTOC_Option::set( 'show_toc_in_widget_only', $instance['hide_inline'] );
289
+ //ezTOC_Option::set( 'show_toc_in_widget_only_post_types', $new_instance['show_toc_in_widget_only_post_types'] );
290
+
291
+ return $instance;
292
+ }
293
+
294
+ /**
295
+ * Displays the widget settings on the Widgets admin page.
296
+ *
297
+ * @access private
298
+ * @since 1.0
299
+ *
300
+ * @param array $instance
301
+ *
302
+ * @return string|void
303
+ */
304
+ public function form( $instance ) {
305
+
306
+ $defaults = array(
307
+ 'affix' => '0',
308
+ 'highlight_color' => '#ededed',
309
+ 'title' => '',
310
+ );
311
+
312
+ $instance = wp_parse_args( (array) $instance, $defaults );
313
+
314
+ $highlight_color = esc_attr( $instance[ 'highlight_color' ] );
315
+
316
+ ?>
317
+ <p>
318
+ <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title', 'ez_toc' ); ?>:</label>
319
+ <input type="text" id="<?php echo $this->get_field_id( 'title' ); ?>"
320
+ name="<?php echo $this->get_field_name( 'title' ); ?>" value="<?php echo $instance['title']; ?>"
321
+ style="width:100%;"/>
322
+ </p>
323
+
324
+ <p>
325
+ <label for="<?php echo $this->get_field_id( 'highlight_color' ); ?>"><?php _e( 'Active Section Highlight Color:', 'ez_toc' ); ?></label><br>
326
+ <input type="text" name="<?php echo $this->get_field_name( 'highlight_color' ); ?>" class="color-picker" id="<?php echo $this->get_field_id( 'highlight_color' ); ?>" value="<?php echo $highlight_color; ?>" data-default-color="<?php echo $defaults['highlight_color']; ?>" />
327
+ </p>
328
+
329
+ <p style="display: <?php echo ezTOC_Option::get( 'widget_affix_selector' ) ? 'block' : 'none'; ?>;">
330
+ <input class="checkbox" type="checkbox" <?php checked( $instance['affix'], 1 ); ?>
331
+ id="<?php echo $this->get_field_id( 'affix' ); ?>"
332
+ name="<?php echo $this->get_field_name( 'affix' ); ?>" value="1"/>
333
+ <label for="<?php echo $this->get_field_id( 'affix' ); ?>"> <?php _e( 'Affix or pin the widget.', 'ez_toc' ); ?></label>
334
+ </p>
335
+
336
+ <p class="description" style="display: <?php echo ezTOC_Option::get( 'widget_affix_selector' ) ? 'block' : 'none'; ?>;">
337
+ <?php _e( 'If you choose to affix the widget, do not add any other widgets on the sidebar. Also, make sure you have only one instance Table of Contents widget on the page.', 'ez_toc' ); ?>
338
+ </p>
339
+ <?php
340
+ }
341
+
342
+ } // end class
343
+
344
+ add_action( 'widgets_init', array( 'ezTOC_Widget', 'register' ) );
345
+ }
includes/inc.admin-options-page.php ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div id='toc' class='wrap'>
2
+ <h1><?php _e( 'Table of Contents', 'ez_toc' ); ?></h1>
3
+
4
+ <form method="post" action="<?php echo esc_url( self_admin_url( 'options.php' ) ); ?>">
5
+
6
+ <div class="metabox-holder">
7
+
8
+ <div class="postbox">
9
+ <h3><span><?php _e( 'General', 'ez_toc' ); ?></span></h3>
10
+
11
+ <div class="inside">
12
+
13
+ <table class="form-table">
14
+
15
+ <?php do_settings_fields( 'ez_toc_settings_general', 'ez_toc_settings_general' ); ?>
16
+
17
+ </table>
18
+
19
+ </div><!-- /.inside -->
20
+ </div><!-- /.postbox -->
21
+
22
+ </div><!-- /.metabox-holder -->
23
+
24
+ <div class="metabox-holder">
25
+
26
+ <div class="postbox">
27
+ <h3><span><?php _e( 'Appearance', 'ez_toc' ); ?></span></h3>
28
+
29
+ <div class="inside">
30
+
31
+ <table class="form-table">
32
+
33
+ <?php do_settings_fields( 'ez_toc_settings_appearance', 'ez_toc_settings_appearance' ); ?>
34
+
35
+ </table>
36
+
37
+ </div><!-- /.inside -->
38
+ </div><!-- /.postbox -->
39
+
40
+ </div><!-- /.metabox-holder -->
41
+
42
+ <div class="metabox-holder">
43
+
44
+ <div class="postbox">
45
+ <h3><span><?php _e( 'Advanced', 'ez_toc' ); ?></span></h3>
46
+
47
+ <div class="inside">
48
+
49
+ <table class="form-table">
50
+
51
+ <?php do_settings_fields( 'ez_toc_settings_advanced', 'ez_toc_settings_advanced' ); ?>
52
+
53
+ </table>
54
+
55
+ </div><!-- /.inside -->
56
+ </div><!-- /.postbox -->
57
+
58
+ </div><!-- /.metabox-holder -->
59
+
60
+ <?php settings_fields( 'ez-toc-settings' ); ?>
61
+ <?php submit_button( __( 'Save Changes', 'ez_toc' ) ); ?>
62
+ </form>
63
+ </div>
vendor/icomoon/fonts/ez-toc-icomoon.eot ADDED
Binary file
vendor/icomoon/fonts/ez-toc-icomoon.svg ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
3
+ <svg xmlns="http://www.w3.org/2000/svg">
4
+ <metadata>Generated by IcoMoon</metadata>
5
+ <defs>
6
+ <font id="ez-toc-icomoon" horiz-adv-x="1024">
7
+ <font-face units-per-em="1024" ascent="960" descent="-64" />
8
+ <missing-glyph horiz-adv-x="1024" />
9
+ <glyph unicode="&#x20;" horiz-adv-x="512" d="" />
10
+ <glyph unicode="&#xe87a;" glyph-name="menu" d="M0 576h704v-128h-704v128zM0 768h704v-128h-704v128zM0 384h704v-128h-704v128zM0 192h704v-128h-704v128zM768 384l128-192 128 192h-256zM1024 448l-128 192-128-192h256z" />
11
+ </font></defs></svg>
vendor/icomoon/fonts/ez-toc-icomoon.ttf ADDED
Binary file
vendor/icomoon/fonts/ez-toc-icomoon.woff ADDED
Binary file
vendor/icomoon/selection.json ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "IcoMoonType": "selection",
3
+ "icons": [
4
+ {
5
+ "icon": {
6
+ "paths": [
7
+ "M0 384h704v128h-704v-128zM0 192h704v128h-704v-128zM0 576h704v128h-704v-128zM0 768h704v128h-704v-128zM768 576l128 192 128-192h-256zM1024 512l-128-192-128 192h256z"
8
+ ],
9
+ "attrs": [],
10
+ "isMulticolor": false,
11
+ "tags": [
12
+ "menu",
13
+ "options"
14
+ ],
15
+ "grid": 16
16
+ },
17
+ "attrs": [],
18
+ "properties": {
19
+ "order": 6,
20
+ "id": 184,
21
+ "prevSize": 32,
22
+ "code": 59514,
23
+ "name": "menu",
24
+ "ligatures": ""
25
+ },
26
+ "setIdx": 0,
27
+ "setId": 4,
28
+ "iconIdx": 183
29
+ }
30
+ ],
31
+ "height": 1024,
32
+ "metadata": {
33
+ "name": "ez-toc-icomoon"
34
+ },
35
+ "preferences": {
36
+ "showGlyphs": true,
37
+ "showQuickUse": true,
38
+ "showQuickUse2": true,
39
+ "showSVGs": true,
40
+ "fontPref": {
41
+ "prefix": "icon-",
42
+ "metadata": {
43
+ "fontFamily": "ez-toc-icomoon",
44
+ "majorVersion": 1,
45
+ "minorVersion": 0
46
+ },
47
+ "metrics": {
48
+ "emSize": 1024,
49
+ "baseline": 6.25,
50
+ "whitespace": 50
51
+ },
52
+ "embed": false,
53
+ "showVersion": true,
54
+ "showMetadata": false,
55
+ "showMetrics": false,
56
+ "showSelector": true,
57
+ "selector": "i",
58
+ "autoHost": true
59
+ },
60
+ "imagePref": {
61
+ "prefix": "icon-",
62
+ "png": true,
63
+ "useClassSelector": true,
64
+ "color": 4473924,
65
+ "bgColor": 16777215
66
+ },
67
+ "historySize": 100,
68
+ "showCodes": false,
69
+ "quickUsageToken": {
70
+ "UntitledProject": "MmZiZGU0YzgwOTdlM2VkNTRjNzYwNDE0OTQ5MTA5MzkjMSMxNDQxMDMwMjM1IyMj"
71
+ },
72
+ "fontHostingName": false,
73
+ "gridSize": 16
74
+ }
75
+ }
vendor/icomoon/style.css ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @font-face {
2
+ font-family: 'ez-toc-icomoon';
3
+ src:url('fonts/ez-toc-icomoon.eot?-5j7dhv');
4
+ src:url('fonts/ez-toc-icomoon.eot?#iefix-5j7dhv') format('embedded-opentype'),
5
+ url('fonts/ez-toc-icomoon.ttf?-5j7dhv') format('truetype'),
6
+ url('fonts/ez-toc-icomoon.woff?-5j7dhv') format('woff'),
7
+ url('fonts/ez-toc-icomoon.svg?-5j7dhv#ez-toc-icomoon') format('svg');
8
+ font-weight: normal;
9
+ font-style: normal;
10
+ }
11
+
12
+ i {
13
+ font-family: 'ez-toc-icomoon';
14
+ speak: none;
15
+ font-style: normal;
16
+ font-weight: normal;
17
+ font-variant: normal;
18
+ text-transform: none;
19
+ line-height: 1;
20
+
21
+ /* Better Font Rendering =========== */
22
+ -webkit-font-smoothing: antialiased;
23
+ -moz-osx-font-smoothing: grayscale;
24
+ }
25
+
26
+ .icon-menu:before {
27
+ content: "\e87a";
28
+ }
vendor/icomoon/style.min.css ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ @font-face{font-family:'ez-toc-icomoon';src:url('fonts/ez-toc-icomoon.eot?-5j7dhv');src:url('fonts/ez-toc-icomoon.eot?#iefix-5j7dhv') format('embedded-opentype'),url('fonts/ez-toc-icomoon.ttf?-5j7dhv') format('truetype'),url('fonts/ez-toc-icomoon.woff?-5j7dhv') format('woff'),url('fonts/ez-toc-icomoon.svg?-5j7dhv#ez-toc-icomoon') format('svg');font-weight:normal;font-style:normal}
2
+ i{font-family:'ez-toc-icomoon';speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
3
+ .icon-menu:before{content:"\e87a"}
vendor/js-cookie/js.cookie.js ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * JavaScript Cookie v2.0.3
3
+ * https://github.com/js-cookie/js-cookie
4
+ *
5
+ * Copyright 2006, 2015 Klaus Hartl & Fagner Brack
6
+ * Released under the MIT license
7
+ */
8
+ (function (factory) {
9
+ if (typeof define === 'function' && define.amd) {
10
+ define(factory);
11
+ } else if (typeof exports === 'object') {
12
+ module.exports = factory();
13
+ } else {
14
+ var _OldCookies = window.Cookies;
15
+ var api = window.Cookies = factory();
16
+ api.noConflict = function () {
17
+ window.Cookies = _OldCookies;
18
+ return api;
19
+ };
20
+ }
21
+ }(function () {
22
+ function extend () {
23
+ var i = 0;
24
+ var result = {};
25
+ for (; i < arguments.length; i++) {
26
+ var attributes = arguments[ i ];
27
+ for (var key in attributes) {
28
+ result[key] = attributes[key];
29
+ }
30
+ }
31
+ return result;
32
+ }
33
+
34
+ function init (converter) {
35
+ function api (key, value, attributes) {
36
+ var result;
37
+
38
+ // Write
39
+
40
+ if (arguments.length > 1) {
41
+ attributes = extend({
42
+ path: '/'
43
+ }, api.defaults, attributes);
44
+
45
+ if (typeof attributes.expires === 'number') {
46
+ var expires = new Date();
47
+ expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5);
48
+ attributes.expires = expires;
49
+ }
50
+
51
+ try {
52
+ result = JSON.stringify(value);
53
+ if (/^[\{\[]/.test(result)) {
54
+ value = result;
55
+ }
56
+ } catch (e) {}
57
+
58
+ value = encodeURIComponent(String(value));
59
+ value = value.replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
60
+
61
+ key = encodeURIComponent(String(key));
62
+ key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent);
63
+ key = key.replace(/[\(\)]/g, escape);
64
+
65
+ return (document.cookie = [
66
+ key, '=', value,
67
+ attributes.expires && '; expires=' + attributes.expires.toUTCString(), // use expires attribute, max-age is not supported by IE
68
+ attributes.path && '; path=' + attributes.path,
69
+ attributes.domain && '; domain=' + attributes.domain,
70
+ attributes.secure ? '; secure' : ''
71
+ ].join(''));
72
+ }
73
+
74
+ // Read
75
+
76
+ if (!key) {
77
+ result = {};
78
+ }
79
+
80
+ // To prevent the for loop in the first place assign an empty array
81
+ // in case there are no cookies at all. Also prevents odd result when
82
+ // calling "get()"
83
+ var cookies = document.cookie ? document.cookie.split('; ') : [];
84
+ var rdecode = /(%[0-9A-Z]{2})+/g;
85
+ var i = 0;
86
+
87
+ for (; i < cookies.length; i++) {
88
+ var parts = cookies[i].split('=');
89
+ var name = parts[0].replace(rdecode, decodeURIComponent);
90
+ var cookie = parts.slice(1).join('=');
91
+
92
+ if (cookie.charAt(0) === '"') {
93
+ cookie = cookie.slice(1, -1);
94
+ }
95
+
96
+ try {
97
+ cookie = converter && converter(cookie, name) || cookie.replace(rdecode, decodeURIComponent);
98
+
99
+ if (this.json) {
100
+ try {
101
+ cookie = JSON.parse(cookie);
102
+ } catch (e) {}
103
+ }
104
+
105
+ if (key === name) {
106
+ result = cookie;
107
+ break;
108
+ }
109
+
110
+ if (!key) {
111
+ result[name] = cookie;
112
+ }
113
+ } catch (e) {}
114
+ }
115
+
116
+ return result;
117
+ }
118
+
119
+ api.get = api.set = api;
120
+ api.getJSON = function () {
121
+ return api.apply({
122
+ json: true
123
+ }, [].slice.call(arguments));
124
+ };
125
+ api.defaults = {};
126
+
127
+ api.remove = function (key, attributes) {
128
+ api(key, '', extend(attributes, {
129
+ expires: -1
130
+ }));
131
+ };
132
+
133
+ api.withConverter = init;
134
+
135
+ return api;
136
+ }
137
+
138
+ return init();
139
+ }));
vendor/js-cookie/js.cookie.min.js ADDED
@@ -0,0 +1,2 @@
 
 
1
+ /*! js-cookie v2.0.3 | MIT */
2
+ !function(a){if("function"==typeof define&&define.amd)define(a);else if("object"==typeof exports)module.exports=a();else{var b=window.Cookies,c=window.Cookies=a(window.jQuery);c.noConflict=function(){return window.Cookies=b,c}}}(function(){function a(){for(var a=0,b={};a<arguments.length;a++){var c=arguments[a];for(var d in c)b[d]=c[d]}return b}function b(c){function d(b,e,f){var g;if(arguments.length>1){if(f=a({path:"/"},d.defaults,f),"number"==typeof f.expires){var h=new Date;h.setMilliseconds(h.getMilliseconds()+864e5*f.expires),f.expires=h}try{g=JSON.stringify(e),/^[\{\[]/.test(g)&&(e=g)}catch(i){}return e=encodeURIComponent(String(e)),e=e.replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent),b=encodeURIComponent(String(b)),b=b.replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent),b=b.replace(/[\(\)]/g,escape),document.cookie=[b,"=",e,f.expires&&"; expires="+f.expires.toUTCString(),f.path&&"; path="+f.path,f.domain&&"; domain="+f.domain,f.secure?"; secure":""].join("")}b||(g={});for(var j=document.cookie?document.cookie.split("; "):[],k=/(%[0-9A-Z]{2})+/g,l=0;l<j.length;l++){var m=j[l].split("="),n=m[0].replace(k,decodeURIComponent),o=m.slice(1).join("=");'"'===o.charAt(0)&&(o=o.slice(1,-1));try{if(o=c&&c(o,n)||o.replace(k,decodeURIComponent),this.json)try{o=JSON.parse(o)}catch(i){}if(b===n){g=o;break}b||(g[n]=o)}catch(i){}}return g}return d.get=d.set=d,d.getJSON=function(){return d.apply({json:!0},[].slice.call(arguments))},d.defaults={},d.remove=function(b,c){d(b,"",a(c,{expires:-1}))},d.withConverter=b,d}return b()});
vendor/smooth-scroll/jquery.smooth-scroll.js ADDED
@@ -0,0 +1,272 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * jQuery Smooth Scroll - v1.5.5 - 2015-02-19
3
+ * https://github.com/kswedberg/jquery-smooth-scroll
4
+ * Copyright (c) 2015 Karl Swedberg
5
+ * Licensed MIT (https://github.com/kswedberg/jquery-smooth-scroll/blob/master/LICENSE-MIT)
6
+ */
7
+
8
+ (function (factory) {
9
+ if (typeof define === 'function' && define.amd) {
10
+ // AMD. Register as an anonymous module.
11
+ define(['jquery'], factory);
12
+ } else if (typeof module === 'object' && module.exports) {
13
+ // CommonJS
14
+ factory(require('jquery'));
15
+ } else {
16
+ // Browser globals
17
+ factory(jQuery);
18
+ }
19
+ }(function ($) {
20
+
21
+ var version = '1.5.5',
22
+ optionOverrides = {},
23
+ defaults = {
24
+ exclude: [],
25
+ excludeWithin:[],
26
+ offset: 0,
27
+
28
+ // one of 'top' or 'left'
29
+ direction: 'top',
30
+
31
+ // jQuery set of elements you wish to scroll (for $.smoothScroll).
32
+ // if null (default), $('html, body').firstScrollable() is used.
33
+ scrollElement: null,
34
+
35
+ // only use if you want to override default behavior
36
+ scrollTarget: null,
37
+
38
+ // fn(opts) function to be called before scrolling occurs.
39
+ // `this` is the element(s) being scrolled
40
+ beforeScroll: function() {},
41
+
42
+ // fn(opts) function to be called after scrolling occurs.
43
+ // `this` is the triggering element
44
+ afterScroll: function() {},
45
+ easing: 'swing',
46
+ speed: 400,
47
+
48
+ // coefficient for "auto" speed
49
+ autoCoefficient: 2,
50
+
51
+ // $.fn.smoothScroll only: whether to prevent the default click action
52
+ preventDefault: true
53
+ },
54
+
55
+ getScrollable = function(opts) {
56
+ var scrollable = [],
57
+ scrolled = false,
58
+ dir = opts.dir && opts.dir === 'left' ? 'scrollLeft' : 'scrollTop';
59
+
60
+ this.each(function() {
61
+
62
+ if (this === document || this === window) { return; }
63
+ var el = $(this);
64
+ if ( el[dir]() > 0 ) {
65
+ scrollable.push(this);
66
+ } else {
67
+ // if scroll(Top|Left) === 0, nudge the element 1px and see if it moves
68
+ el[dir](1);
69
+ scrolled = el[dir]() > 0;
70
+ if ( scrolled ) {
71
+ scrollable.push(this);
72
+ }
73
+ // then put it back, of course
74
+ el[dir](0);
75
+ }
76
+ });
77
+
78
+ // If no scrollable elements, fall back to <body>,
79
+ // if it's in the jQuery collection
80
+ // (doing this because Safari sets scrollTop async,
81
+ // so can't set it to 1 and immediately get the value.)
82
+ if (!scrollable.length) {
83
+ this.each(function() {
84
+ if (this.nodeName === 'BODY') {
85
+ scrollable = [this];
86
+ }
87
+ });
88
+ }
89
+
90
+ // Use the first scrollable element if we're calling firstScrollable()
91
+ if ( opts.el === 'first' && scrollable.length > 1 ) {
92
+ scrollable = [ scrollable[0] ];
93
+ }
94
+
95
+ return scrollable;
96
+ };
97
+
98
+ $.fn.extend({
99
+ scrollable: function(dir) {
100
+ var scrl = getScrollable.call(this, {dir: dir});
101
+ return this.pushStack(scrl);
102
+ },
103
+ firstScrollable: function(dir) {
104
+ var scrl = getScrollable.call(this, {el: 'first', dir: dir});
105
+ return this.pushStack(scrl);
106
+ },
107
+
108
+ smoothScroll: function(options, extra) {
109
+ options = options || {};
110
+
111
+ if ( options === 'options' ) {
112
+ if ( !extra ) {
113
+ return this.first().data('ssOpts');
114
+ }
115
+ return this.each(function() {
116
+ var $this = $(this),
117
+ opts = $.extend($this.data('ssOpts') || {}, extra);
118
+
119
+ $(this).data('ssOpts', opts);
120
+ });
121
+ }
122
+
123
+ var opts = $.extend({}, $.fn.smoothScroll.defaults, options),
124
+ locationPath = $.smoothScroll.filterPath(location.pathname);
125
+
126
+ this
127
+ .unbind('click.smoothscroll')
128
+ .bind('click.smoothscroll', function(event) {
129
+ var link = this,
130
+ $link = $(this),
131
+ thisOpts = $.extend({}, opts, $link.data('ssOpts') || {}),
132
+ exclude = opts.exclude,
133
+ excludeWithin = thisOpts.excludeWithin,
134
+ elCounter = 0, ewlCounter = 0,
135
+ include = true,
136
+ clickOpts = {},
137
+ hostMatch = ((location.hostname === link.hostname) || !link.hostname),
138
+ pathMatch = thisOpts.scrollTarget || ( $.smoothScroll.filterPath(link.pathname) === locationPath ),
139
+ thisHash = escapeSelector(link.hash);
140
+
141
+ if ( !thisOpts.scrollTarget && (!hostMatch || !pathMatch || !thisHash) ) {
142
+ include = false;
143
+ } else {
144
+ while (include && elCounter < exclude.length) {
145
+ if ($link.is(escapeSelector(exclude[elCounter++]))) {
146
+ include = false;
147
+ }
148
+ }
149
+ while ( include && ewlCounter < excludeWithin.length ) {
150
+ if ($link.closest(excludeWithin[ewlCounter++]).length) {
151
+ include = false;
152
+ }
153
+ }
154
+ }
155
+
156
+ if ( include ) {
157
+
158
+ if ( thisOpts.preventDefault ) {
159
+ event.preventDefault();
160
+ }
161
+
162
+ $.extend( clickOpts, thisOpts, {
163
+ scrollTarget: thisOpts.scrollTarget || thisHash,
164
+ link: link
165
+ });
166
+
167
+ $.smoothScroll( clickOpts );
168
+ }
169
+ });
170
+
171
+ return this;
172
+ }
173
+ });
174
+
175
+ $.smoothScroll = function(options, px) {
176
+ if ( options === 'options' && typeof px === 'object' ) {
177
+ return $.extend(optionOverrides, px);
178
+ }
179
+ var opts, $scroller, scrollTargetOffset, speed, delta,
180
+ scrollerOffset = 0,
181
+ offPos = 'offset',
182
+ scrollDir = 'scrollTop',
183
+ aniProps = {},
184
+ aniOpts = {};
185
+
186
+ if (typeof options === 'number') {
187
+ opts = $.extend({link: null}, $.fn.smoothScroll.defaults, optionOverrides);
188
+ scrollTargetOffset = options;
189
+ } else {
190
+ opts = $.extend({link: null}, $.fn.smoothScroll.defaults, options || {}, optionOverrides);
191
+ if (opts.scrollElement) {
192
+ offPos = 'position';
193
+ if (opts.scrollElement.css('position') === 'static') {
194
+ opts.scrollElement.css('position', 'relative');
195
+ }
196
+ }
197
+ }
198
+
199
+ scrollDir = opts.direction === 'left' ? 'scrollLeft' : scrollDir;
200
+
201
+ if ( opts.scrollElement ) {
202
+ $scroller = opts.scrollElement;
203
+ if ( !(/^(?:HTML|BODY)$/).test($scroller[0].nodeName) ) {
204
+ scrollerOffset = $scroller[scrollDir]();
205
+ }
206
+ } else {
207
+ $scroller = $('html, body').firstScrollable(opts.direction);
208
+ }
209
+
210
+ // beforeScroll callback function must fire before calculating offset
211
+ opts.beforeScroll.call($scroller, opts);
212
+
213
+ scrollTargetOffset = (typeof options === 'number') ? options :
214
+ px ||
215
+ ( $(opts.scrollTarget)[offPos]() &&
216
+ $(opts.scrollTarget)[offPos]()[opts.direction] ) ||
217
+ 0;
218
+
219
+ aniProps[scrollDir] = scrollTargetOffset + scrollerOffset + opts.offset;
220
+ speed = opts.speed;
221
+
222
+ // automatically calculate the speed of the scroll based on distance / coefficient
223
+ if (speed === 'auto') {
224
+
225
+ // $scroller.scrollTop() is position before scroll, aniProps[scrollDir] is position after
226
+ // When delta is greater, speed will be greater.
227
+ delta = aniProps[scrollDir] - $scroller.scrollTop();
228
+ if(delta < 0) {
229
+ delta *= -1;
230
+ }
231
+
232
+ // Divide the delta by the coefficient
233
+ speed = delta / opts.autoCoefficient;
234
+ }
235
+
236
+ aniOpts = {
237
+ duration: speed,
238
+ easing: opts.easing,
239
+ complete: function() {
240
+ opts.afterScroll.call(opts.link, opts);
241
+ }
242
+ };
243
+
244
+ if (opts.step) {
245
+ aniOpts.step = opts.step;
246
+ }
247
+
248
+ if ($scroller.length) {
249
+ $scroller.stop().animate(aniProps, aniOpts);
250
+ } else {
251
+ opts.afterScroll.call(opts.link, opts);
252
+ }
253
+ };
254
+
255
+ $.smoothScroll.version = version;
256
+ $.smoothScroll.filterPath = function(string) {
257
+ string = string || '';
258
+ return string
259
+ .replace(/^\//,'')
260
+ .replace(/(?:index|default).[a-zA-Z]{3,4}$/,'')
261
+ .replace(/\/$/,'');
262
+ };
263
+
264
+ // default options
265
+ $.fn.smoothScroll.defaults = defaults;
266
+
267
+ function escapeSelector (str) {
268
+ return str.replace(/(:|\.|\/)/g,'\\$1');
269
+ }
270
+
271
+ }));
272
+
vendor/smooth-scroll/jquery.smooth-scroll.min.js ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * jQuery Smooth Scroll - v1.5.5 - 2015-02-19
3
+ * https://github.com/kswedberg/jquery-smooth-scroll
4
+ * Copyright (c) 2015 Karl Swedberg
5
+ * Licensed MIT (https://github.com/kswedberg/jquery-smooth-scroll/blob/master/LICENSE-MIT)
6
+ */
7
+ (function(a){if(typeof define==="function"&&define.amd){define(["jquery"],a);
8
+ }else{if(typeof module==="object"&&module.exports){a(require("jquery"));}else{a(jQuery);}}}(function(d){var b="1.5.5",f={},e={exclude:[],excludeWithin:[],offset:0,direction:"top",scrollElement:null,scrollTarget:null,beforeScroll:function(){},afterScroll:function(){},easing:"swing",speed:400,autoCoefficient:2,preventDefault:true},a=function(i){var j=[],h=false,g=i.dir&&i.dir==="left"?"scrollLeft":"scrollTop";
9
+ this.each(function(){if(this===document||this===window){return;}var k=d(this);if(k[g]()>0){j.push(this);}else{k[g](1);h=k[g]()>0;if(h){j.push(this);}k[g](0);
10
+ }});if(!j.length){this.each(function(){if(this.nodeName==="BODY"){j=[this];}});}if(i.el==="first"&&j.length>1){j=[j[0]];}return j;};d.fn.extend({scrollable:function(g){var h=a.call(this,{dir:g});
11
+ return this.pushStack(h);},firstScrollable:function(g){var h=a.call(this,{el:"first",dir:g});return this.pushStack(h);},smoothScroll:function(h,g){h=h||{};
12
+ if(h==="options"){if(!g){return this.first().data("ssOpts");}return this.each(function(){var l=d(this),k=d.extend(l.data("ssOpts")||{},g);d(this).data("ssOpts",k);
13
+ });}var i=d.extend({},d.fn.smoothScroll.defaults,h),j=d.smoothScroll.filterPath(location.pathname);this.unbind("click.smoothscroll").bind("click.smoothscroll",function(m){var u=this,t=d(this),o=d.extend({},i,t.data("ssOpts")||{}),n=i.exclude,r=o.excludeWithin,v=0,q=0,l=true,w={},p=((location.hostname===u.hostname)||!u.hostname),k=o.scrollTarget||(d.smoothScroll.filterPath(u.pathname)===j),s=c(u.hash);
14
+ if(!o.scrollTarget&&(!p||!k||!s)){l=false;}else{while(l&&v<n.length){if(t.is(c(n[v++]))){l=false;}}while(l&&q<r.length){if(t.closest(r[q++]).length){l=false;
15
+ }}}if(l){if(o.preventDefault){m.preventDefault();}d.extend(w,o,{scrollTarget:o.scrollTarget||s,link:u});d.smoothScroll(w);}});return this;}});d.smoothScroll=function(r,m){if(r==="options"&&typeof m==="object"){return d.extend(f,m);
16
+ }var g,h,q,i,n,p=0,j="offset",l="scrollTop",o={},k={};if(typeof r==="number"){g=d.extend({link:null},d.fn.smoothScroll.defaults,f);q=r;}else{g=d.extend({link:null},d.fn.smoothScroll.defaults,r||{},f);
17
+ if(g.scrollElement){j="position";if(g.scrollElement.css("position")==="static"){g.scrollElement.css("position","relative");}}}l=g.direction==="left"?"scrollLeft":l;
18
+ if(g.scrollElement){h=g.scrollElement;if(!(/^(?:HTML|BODY)$/).test(h[0].nodeName)){p=h[l]();}}else{h=d("html, body").firstScrollable(g.direction);}g.beforeScroll.call(h,g);
19
+ q=(typeof r==="number")?r:m||(d(g.scrollTarget)[j]()&&d(g.scrollTarget)[j]()[g.direction])||0;o[l]=q+p+g.offset;i=g.speed;if(i==="auto"){n=o[l]-h.scrollTop();
20
+ if(n<0){n*=-1;}i=n/g.autoCoefficient;}k={duration:i,easing:g.easing,complete:function(){g.afterScroll.call(g.link,g);}};if(g.step){k.step=g.step;}if(h.length){h.stop().animate(o,k);
21
+ }else{g.afterScroll.call(g.link,g);}};d.smoothScroll.version=b;d.smoothScroll.filterPath=function(g){g=g||"";return g.replace(/^\//,"").replace(/(?:index|default).[a-zA-Z]{3,4}$/,"").replace(/\/$/,"");
22
+ };d.fn.smoothScroll.defaults=e;function c(g){return g.replace(/(:|\.|\/)/g,"\\$1");}}));
vendor/sticky-kit/jquery.sticky-kit.js ADDED
@@ -0,0 +1,251 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Generated by CoffeeScript 1.9.2
2
+
3
+ /**
4
+ @license Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net
5
+ */
6
+
7
+ (function() {
8
+ var $, win;
9
+
10
+ $ = this.jQuery || window.jQuery;
11
+
12
+ win = $(window);
13
+
14
+ $.fn.stick_in_parent = function(opts) {
15
+ var doc, elm, enable_bottoming, fn, i, inner_scrolling, len, manual_spacer, offset_top, parent_selector, recalc_every, sticky_class;
16
+ if (opts == null) {
17
+ opts = {};
18
+ }
19
+ sticky_class = opts.sticky_class, inner_scrolling = opts.inner_scrolling, recalc_every = opts.recalc_every, parent_selector = opts.parent, offset_top = opts.offset_top, manual_spacer = opts.spacer, enable_bottoming = opts.bottoming;
20
+ if (offset_top == null) {
21
+ offset_top = 0;
22
+ }
23
+ if (parent_selector == null) {
24
+ parent_selector = void 0;
25
+ }
26
+ if (inner_scrolling == null) {
27
+ inner_scrolling = true;
28
+ }
29
+ if (sticky_class == null) {
30
+ sticky_class = "is_stuck";
31
+ }
32
+ doc = $(document);
33
+ if (enable_bottoming == null) {
34
+ enable_bottoming = true;
35
+ }
36
+ fn = function(elm, padding_bottom, parent_top, parent_height, top, height, el_float, detached) {
37
+ var bottomed, detach, fixed, last_pos, last_scroll_height, offset, parent, recalc, recalc_and_tick, recalc_counter, spacer, tick;
38
+ if (elm.data("sticky_kit")) {
39
+ return;
40
+ }
41
+ elm.data("sticky_kit", true);
42
+ last_scroll_height = doc.height();
43
+ parent = elm.parent();
44
+ if (parent_selector != null) {
45
+ parent = parent.closest(parent_selector);
46
+ }
47
+ if (!parent.length) {
48
+ throw "failed to find stick parent";
49
+ }
50
+ fixed = false;
51
+ bottomed = false;
52
+ spacer = manual_spacer != null ? manual_spacer && elm.closest(manual_spacer) : $("<div />");
53
+ //if (spacer) {
54
+ // spacer.css('position', elm.css('position'));
55
+ //}
56
+ recalc = function() {
57
+ var border_top, padding_top, restore;
58
+ if (detached) {
59
+ return;
60
+ }
61
+ last_scroll_height = doc.height();
62
+ border_top = parseInt(parent.css("border-top-width"), 10);
63
+ padding_top = parseInt(parent.css("padding-top"), 10);
64
+ padding_bottom = parseInt(parent.css("padding-bottom"), 10);
65
+ parent_top = parent.offset().top + border_top + padding_top;
66
+ parent_height = parent.height();
67
+ if (fixed) {
68
+ fixed = false;
69
+ bottomed = false;
70
+ if (manual_spacer == null) {
71
+ elm.insertAfter(spacer);
72
+ spacer.detach();
73
+ }
74
+ elm.css({
75
+ position: "",
76
+ top: "",
77
+ width: "",
78
+ bottom: ""
79
+ }).removeClass(sticky_class);
80
+ restore = true;
81
+ }
82
+ top = elm.offset().top - (parseInt(elm.css("margin-top"), 10) || 0) - offset_top;
83
+ height = elm.outerHeight(true);
84
+ el_float = elm.css("float");
85
+ if (spacer) {
86
+ spacer.css({
87
+ width: elm.outerWidth(true),
88
+ height: height,
89
+ display: elm.css("display"),
90
+ "vertical-align": elm.css("vertical-align"),
91
+ "float": el_float
92
+ });
93
+ }
94
+ if (restore) {
95
+ return tick();
96
+ }
97
+ };
98
+ recalc();
99
+ if (height === parent_height) {
100
+ return;
101
+ }
102
+ last_pos = void 0;
103
+ offset = offset_top;
104
+ recalc_counter = recalc_every;
105
+ tick = function() {
106
+ var css, delta, recalced, scroll, will_bottom, win_height;
107
+ if (detached) {
108
+ return;
109
+ }
110
+ recalced = false;
111
+ if (recalc_counter != null) {
112
+ recalc_counter -= 1;
113
+ if (recalc_counter <= 0) {
114
+ recalc_counter = recalc_every;
115
+ recalc();
116
+ recalced = true;
117
+ }
118
+ }
119
+ if (!recalced && doc.height() !== last_scroll_height) {
120
+ recalc();
121
+ recalced = true;
122
+ }
123
+ scroll = win.scrollTop();
124
+ if (last_pos != null) {
125
+ delta = scroll - last_pos;
126
+ }
127
+ last_pos = scroll;
128
+ if (fixed) {
129
+ if (enable_bottoming) {
130
+ will_bottom = scroll + height + offset > parent_height + parent_top;
131
+ if (bottomed && !will_bottom) {
132
+ bottomed = false;
133
+ elm.css({
134
+ position: "fixed",
135
+ bottom: "",
136
+ top: offset
137
+ }).trigger("sticky_kit:unbottom");
138
+ }
139
+ }
140
+ if (scroll < top) {
141
+ fixed = false;
142
+ offset = offset_top;
143
+ if (manual_spacer == null) {
144
+ if (el_float === "left" || el_float === "right") {
145
+ elm.insertAfter(spacer);
146
+ }
147
+ spacer.detach();
148
+ }
149
+ css = {
150
+ position: "",
151
+ width: "",
152
+ top: ""
153
+ };
154
+ elm.css(css).removeClass(sticky_class).trigger("sticky_kit:unstick");
155
+ }
156
+ if (inner_scrolling) {
157
+ win_height = win.height();
158
+ if (height + offset_top > win_height) {
159
+ if (!bottomed) {
160
+ offset -= delta;
161
+ offset = Math.max(win_height - height, offset);
162
+ offset = Math.min(offset_top, offset);
163
+ if (fixed) {
164
+ elm.css({
165
+ top: offset + "px"
166
+ });
167
+ }
168
+ }
169
+ }
170
+ }
171
+ } else {
172
+ if (scroll > top) {
173
+ fixed = true;
174
+ css = {
175
+ position: "fixed",
176
+ top: offset
177
+ };
178
+ css.width = elm.css("box-sizing") === "border-box" ? elm.outerWidth() + "px" : elm.width() + "px";
179
+ elm.css(css).addClass(sticky_class);
180
+ if (manual_spacer == null) {
181
+ elm.after(spacer);
182
+ if (el_float === "left" || el_float === "right") {
183
+ spacer.append(elm);
184
+ }
185
+ }
186
+ elm.trigger("sticky_kit:stick");
187
+ }
188
+ }
189
+ if (fixed && enable_bottoming) {
190
+ if (will_bottom == null) {
191
+ will_bottom = scroll + height + offset > parent_height + parent_top;
192
+ }
193
+ if (!bottomed && will_bottom) {
194
+ bottomed = true;
195
+ if (parent.css("position") === "static") {
196
+ parent.css({
197
+ position: "relative"
198
+ });
199
+ }
200
+ return elm.css({
201
+ position: "absolute",
202
+ bottom: padding_bottom,
203
+ top: "auto"
204
+ }).trigger("sticky_kit:bottom");
205
+ }
206
+ }
207
+ };
208
+ recalc_and_tick = function() {
209
+ recalc();
210
+ return tick();
211
+ };
212
+ detach = function() {
213
+ detached = true;
214
+ win.off("touchmove", tick);
215
+ win.off("scroll", tick);
216
+ win.off("resize", recalc_and_tick);
217
+ $(document.body).off("sticky_kit:recalc", recalc_and_tick);
218
+ elm.off("sticky_kit:detach", detach);
219
+ elm.removeData("sticky_kit");
220
+ elm.css({
221
+ position: "",
222
+ bottom: "",
223
+ top: "",
224
+ width: ""
225
+ });
226
+ parent.position("position", "");
227
+ if (fixed) {
228
+ if (manual_spacer == null) {
229
+ if (el_float === "left" || el_float === "right") {
230
+ elm.insertAfter(spacer);
231
+ }
232
+ spacer.remove();
233
+ }
234
+ return elm.removeClass(sticky_class);
235
+ }
236
+ };
237
+ win.on("touchmove", tick);
238
+ win.on("scroll", tick);
239
+ win.on("resize", recalc_and_tick);
240
+ $(document.body).on("sticky_kit:recalc", recalc_and_tick);
241
+ elm.on("sticky_kit:detach", detach);
242
+ return setTimeout(tick, 0);
243
+ };
244
+ for (i = 0, len = this.length; i < len; i++) {
245
+ elm = this[i];
246
+ fn($(elm));
247
+ }
248
+ return this;
249
+ };
250
+
251
+ }).call(this);
vendor/sticky-kit/jquery.sticky-kit.min.js ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function(){var a,b;a=this.jQuery||window.jQuery;b=a(window);a.fn.stick_in_parent=function(d){var p,m,o,n,j,h,k,f,l,e,c,g;if(d==null){d={};}g=d.sticky_class,h=d.inner_scrolling,c=d.recalc_every,e=d.parent,l=d.offset_top,f=d.spacer,o=d.bottoming;
2
+ if(l==null){l=0;}if(e==null){e=void 0;}if(h==null){h=true;}if(g==null){g="is_stuck";}p=a(document);if(o==null){o=true;}n=function(t,G,q,i,B,C,y,z){var D,H,r,F,I,s,w,u,x,A,v,E;
3
+ if(t.data("sticky_kit")){return;}t.data("sticky_kit",true);I=p.height();w=t.parent();if(e!=null){w=w.closest(e);}if(!w.length){throw"failed to find stick parent";
4
+ }r=false;D=false;v=f!=null?f&&t.closest(f):a("<div />");u=function(){var J,L,K;if(z){return;}I=p.height();J=parseInt(w.css("border-top-width"),10);L=parseInt(w.css("padding-top"),10);
5
+ G=parseInt(w.css("padding-bottom"),10);q=w.offset().top+J+L;i=w.height();if(r){r=false;D=false;if(f==null){t.insertAfter(v);v.detach();}t.css({position:"",top:"",width:"",bottom:""}).removeClass(g);
6
+ K=true;}B=t.offset().top-(parseInt(t.css("margin-top"),10)||0)-l;C=t.outerHeight(true);y=t.css("float");if(v){v.css({width:t.outerWidth(true),height:C,display:t.css("display"),"vertical-align":t.css("vertical-align"),"float":y});
7
+ }if(K){return E();}};u();if(C===i){return;}F=void 0;s=l;A=c;E=function(){var L,O,M,K,J,N;if(z){return;}M=false;if(A!=null){A-=1;if(A<=0){A=c;u();M=true;
8
+ }}if(!M&&p.height()!==I){u();M=true;}K=b.scrollTop();if(F!=null){O=K-F;}F=K;if(r){if(o){J=K+C+s>i+q;if(D&&!J){D=false;t.css({position:"fixed",bottom:"",top:s}).trigger("sticky_kit:unbottom");
9
+ }}if(K<B){r=false;s=l;if(f==null){if(y==="left"||y==="right"){t.insertAfter(v);}v.detach();}L={position:"",width:"",top:""};t.css(L).removeClass(g).trigger("sticky_kit:unstick");
10
+ }if(h){N=b.height();if(C+l>N){if(!D){s-=O;s=Math.max(N-C,s);s=Math.min(l,s);if(r){t.css({top:s+"px"});}}}}}else{if(K>B){r=true;L={position:"fixed",top:s};
11
+ L.width=t.css("box-sizing")==="border-box"?t.outerWidth()+"px":t.width()+"px";t.css(L).addClass(g);if(f==null){t.after(v);if(y==="left"||y==="right"){v.append(t);
12
+ }}t.trigger("sticky_kit:stick");}}if(r&&o){if(J==null){J=K+C+s>i+q;}if(!D&&J){D=true;if(w.css("position")==="static"){w.css({position:"relative"});}return t.css({position:"absolute",bottom:G,top:"auto"}).trigger("sticky_kit:bottom");
13
+ }}};x=function(){u();return E();};H=function(){z=true;b.off("touchmove",E);b.off("scroll",E);b.off("resize",x);a(document.body).off("sticky_kit:recalc",x);
14
+ t.off("sticky_kit:detach",H);t.removeData("sticky_kit");t.css({position:"",bottom:"",top:"",width:""});w.position("position","");if(r){if(f==null){if(y==="left"||y==="right"){t.insertAfter(v);
15
+ }v.remove();}return t.removeClass(g);}};b.on("touchmove",E);b.on("scroll",E);b.on("resize",x);a(document.body).on("sticky_kit:recalc",x);t.on("sticky_kit:detach",H);
16
+ return setTimeout(E,0);};for(j=0,k=this.length;j<k;j++){m=this[j];n(a(m));}return this;};}).call(this);
vendor/waypoints/jquery.waypoints.js ADDED
@@ -0,0 +1,649 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ Waypoints - 4.0.0
3
+ Copyright © 2011-2015 Caleb Troughton
4
+ Licensed under the MIT license.
5
+ https://github.com/imakewebthings/waypoints/blog/master/licenses.txt
6
+ */
7
+ (function() {
8
+ 'use strict'
9
+
10
+ var keyCounter = 0
11
+ var allWaypoints = {}
12
+
13
+ /* http://imakewebthings.com/waypoints/api/waypoint */
14
+ function Waypoint(options) {
15
+ if (!options) {
16
+ throw new Error('No options passed to Waypoint constructor')
17
+ }
18
+ if (!options.element) {
19
+ throw new Error('No element option passed to Waypoint constructor')
20
+ }
21
+ if (!options.handler) {
22
+ throw new Error('No handler option passed to Waypoint constructor')
23
+ }
24
+
25
+ this.key = 'waypoint-' + keyCounter
26
+ this.options = Waypoint.Adapter.extend({}, Waypoint.defaults, options)
27
+ this.element = this.options.element
28
+ this.adapter = new Waypoint.Adapter(this.element)
29
+ this.callback = options.handler
30
+ this.axis = this.options.horizontal ? 'horizontal' : 'vertical'
31
+ this.enabled = this.options.enabled
32
+ this.triggerPoint = null
33
+ this.group = Waypoint.Group.findOrCreate({
34
+ name: this.options.group,
35
+ axis: this.axis
36
+ })
37
+ this.context = Waypoint.Context.findOrCreateByElement(this.options.context)
38
+
39
+ if (Waypoint.offsetAliases[this.options.offset]) {
40
+ this.options.offset = Waypoint.offsetAliases[this.options.offset]
41
+ }
42
+ this.group.add(this)
43
+ this.context.add(this)
44
+ allWaypoints[this.key] = this
45
+ keyCounter += 1
46
+ }
47
+
48
+ /* Private */
49
+ Waypoint.prototype.queueTrigger = function(direction) {
50
+ this.group.queueTrigger(this, direction)
51
+ }
52
+
53
+ /* Private */
54
+ Waypoint.prototype.trigger = function(args) {
55
+ if (!this.enabled) {
56
+ return
57
+ }
58
+ if (this.callback) {
59
+ this.callback.apply(this, args)
60
+ }
61
+ }
62
+
63
+ /* Public */
64
+ /* http://imakewebthings.com/waypoints/api/destroy */
65
+ Waypoint.prototype.destroy = function() {
66
+ this.context.remove(this)
67
+ this.group.remove(this)
68
+ delete allWaypoints[this.key]
69
+ }
70
+
71
+ /* Public */
72
+ /* http://imakewebthings.com/waypoints/api/disable */
73
+ Waypoint.prototype.disable = function() {
74
+ this.enabled = false
75
+ return this
76
+ }
77
+
78
+ /* Public */
79
+ /* http://imakewebthings.com/waypoints/api/enable */
80
+ Waypoint.prototype.enable = function() {
81
+ this.context.refresh()
82
+ this.enabled = true
83
+ return this
84
+ }
85
+
86
+ /* Public */
87
+ /* http://imakewebthings.com/waypoints/api/next */
88
+ Waypoint.prototype.next = function() {
89
+ return this.group.next(this)
90
+ }
91
+
92
+ /* Public */
93
+ /* http://imakewebthings.com/waypoints/api/previous */
94
+ Waypoint.prototype.previous = function() {
95
+ return this.group.previous(this)
96
+ }
97
+
98
+ /* Private */
99
+ Waypoint.invokeAll = function(method) {
100
+ var allWaypointsArray = []
101
+ for (var waypointKey in allWaypoints) {
102
+ allWaypointsArray.push(allWaypoints[waypointKey])
103
+ }
104
+ for (var i = 0, end = allWaypointsArray.length; i < end; i++) {
105
+ allWaypointsArray[i][method]()
106
+ }
107
+ }
108
+
109
+ /* Public */
110
+ /* http://imakewebthings.com/waypoints/api/destroy-all */
111
+ Waypoint.destroyAll = function() {
112
+ Waypoint.invokeAll('destroy')
113
+ }
114
+
115
+ /* Public */
116
+ /* http://imakewebthings.com/waypoints/api/disable-all */
117
+ Waypoint.disableAll = function() {
118
+ Waypoint.invokeAll('disable')
119
+ }
120
+
121
+ /* Public */
122
+ /* http://imakewebthings.com/waypoints/api/enable-all */
123
+ Waypoint.enableAll = function() {
124
+ Waypoint.invokeAll('enable')
125
+ }
126
+
127
+ /* Public */
128
+ /* http://imakewebthings.com/waypoints/api/refresh-all */
129
+ Waypoint.refreshAll = function() {
130
+ Waypoint.Context.refreshAll()
131
+ }
132
+
133
+ /* Public */
134
+ /* http://imakewebthings.com/waypoints/api/viewport-height */
135
+ Waypoint.viewportHeight = function() {
136
+ return window.innerHeight || document.documentElement.clientHeight
137
+ }
138
+
139
+ /* Public */
140
+ /* http://imakewebthings.com/waypoints/api/viewport-width */
141
+ Waypoint.viewportWidth = function() {
142
+ return document.documentElement.clientWidth
143
+ }
144
+
145
+ Waypoint.adapters = []
146
+
147
+ Waypoint.defaults = {
148
+ context: window,
149
+ continuous: true,
150
+ enabled: true,
151
+ group: 'default',
152
+ horizontal: false,
153
+ offset: 0
154
+ }
155
+
156
+ Waypoint.offsetAliases = {
157
+ 'bottom-in-view': function() {
158
+ return this.context.innerHeight() - this.adapter.outerHeight()
159
+ },
160
+ 'right-in-view': function() {
161
+ return this.context.innerWidth() - this.adapter.outerWidth()
162
+ }
163
+ }
164
+
165
+ window.Waypoint = Waypoint
166
+ }())
167
+ ;(function() {
168
+ 'use strict'
169
+
170
+ function requestAnimationFrameShim(callback) {
171
+ window.setTimeout(callback, 1000 / 60)
172
+ }
173
+
174
+ var keyCounter = 0
175
+ var contexts = {}
176
+ var Waypoint = window.Waypoint
177
+ var oldWindowLoad = window.onload
178
+
179
+ /* http://imakewebthings.com/waypoints/api/context */
180
+ function Context(element) {
181
+ this.element = element
182
+ this.Adapter = Waypoint.Adapter
183
+ this.adapter = new this.Adapter(element)
184
+ this.key = 'waypoint-context-' + keyCounter
185
+ this.didScroll = false
186
+ this.didResize = false
187
+ this.oldScroll = {
188
+ x: this.adapter.scrollLeft(),
189
+ y: this.adapter.scrollTop()
190
+ }
191
+ this.waypoints = {
192
+ vertical: {},
193
+ horizontal: {}
194
+ }
195
+
196
+ element.waypointContextKey = this.key
197
+ contexts[element.waypointContextKey] = this
198
+ keyCounter += 1
199
+
200
+ this.createThrottledScrollHandler()
201
+ this.createThrottledResizeHandler()
202
+ }
203
+
204
+ /* Private */
205
+ Context.prototype.add = function(waypoint) {
206
+ var axis = waypoint.options.horizontal ? 'horizontal' : 'vertical'
207
+ this.waypoints[axis][waypoint.key] = waypoint
208
+ this.refresh()
209
+ }
210
+
211
+ /* Private */
212
+ Context.prototype.checkEmpty = function() {
213
+ var horizontalEmpty = this.Adapter.isEmptyObject(this.waypoints.horizontal)
214
+ var verticalEmpty = this.Adapter.isEmptyObject(this.waypoints.vertical)
215
+ if (horizontalEmpty && verticalEmpty) {
216
+ this.adapter.off('.waypoints')
217
+ delete contexts[this.key]
218
+ }
219
+ }
220
+
221
+ /* Private */
222
+ Context.prototype.createThrottledResizeHandler = function() {
223
+ var self = this
224
+
225
+ function resizeHandler() {
226
+ self.handleResize()
227
+ self.didResize = false
228
+ }
229
+
230
+ this.adapter.on('resize.waypoints', function() {
231
+ if (!self.didResize) {
232
+ self.didResize = true
233
+ Waypoint.requestAnimationFrame(resizeHandler)
234
+ }
235
+ })
236
+ }
237
+
238
+ /* Private */
239
+ Context.prototype.createThrottledScrollHandler = function() {
240
+ var self = this
241
+ function scrollHandler() {
242
+ self.handleScroll()
243
+ self.didScroll = false
244
+ }
245
+
246
+ this.adapter.on('scroll.waypoints', function() {
247
+ if (!self.didScroll || Waypoint.isTouch) {
248
+ self.didScroll = true
249
+ Waypoint.requestAnimationFrame(scrollHandler)
250
+ }
251
+ })
252
+ }
253
+
254
+ /* Private */
255
+ Context.prototype.handleResize = function() {
256
+ Waypoint.Context.refreshAll()
257
+ }
258
+
259
+ /* Private */
260
+ Context.prototype.handleScroll = function() {
261
+ var triggeredGroups = {}
262
+ var axes = {
263
+ horizontal: {
264
+ newScroll: this.adapter.scrollLeft(),
265
+ oldScroll: this.oldScroll.x,
266
+ forward: 'right',
267
+ backward: 'left'
268
+ },
269
+ vertical: {
270
+ newScroll: this.adapter.scrollTop(),
271
+ oldScroll: this.oldScroll.y,
272
+ forward: 'down',
273
+ backward: 'up'
274
+ }
275
+ }
276
+
277
+ for (var axisKey in axes) {
278
+ var axis = axes[axisKey]
279
+ var isForward = axis.newScroll > axis.oldScroll
280
+ var direction = isForward ? axis.forward : axis.backward
281
+
282
+ for (var waypointKey in this.waypoints[axisKey]) {
283
+ var waypoint = this.waypoints[axisKey][waypointKey]
284
+ var wasBeforeTriggerPoint = axis.oldScroll < waypoint.triggerPoint
285
+ var nowAfterTriggerPoint = axis.newScroll >= waypoint.triggerPoint
286
+ var crossedForward = wasBeforeTriggerPoint && nowAfterTriggerPoint
287
+ var crossedBackward = !wasBeforeTriggerPoint && !nowAfterTriggerPoint
288
+ if (crossedForward || crossedBackward) {
289
+ waypoint.queueTrigger(direction)
290
+ triggeredGroups[waypoint.group.id] = waypoint.group
291
+ }
292
+ }
293
+ }
294
+
295
+ for (var groupKey in triggeredGroups) {
296
+ triggeredGroups[groupKey].flushTriggers()
297
+ }
298
+
299
+ this.oldScroll = {
300
+ x: axes.horizontal.newScroll,
301
+ y: axes.vertical.newScroll
302
+ }
303
+ }
304
+
305
+ /* Private */
306
+ Context.prototype.innerHeight = function() {
307
+ /*eslint-disable eqeqeq */
308
+ if (this.element == this.element.window) {
309
+ return Waypoint.viewportHeight()
310
+ }
311
+ /*eslint-enable eqeqeq */
312
+ return this.adapter.innerHeight()
313
+ }
314
+
315
+ /* Private */
316
+ Context.prototype.remove = function(waypoint) {
317
+ delete this.waypoints[waypoint.axis][waypoint.key]
318
+ this.checkEmpty()
319
+ }
320
+
321
+ /* Private */
322
+ Context.prototype.innerWidth = function() {
323
+ /*eslint-disable eqeqeq */
324
+ if (this.element == this.element.window) {
325
+ return Waypoint.viewportWidth()
326
+ }
327
+ /*eslint-enable eqeqeq */
328
+ return this.adapter.innerWidth()
329
+ }
330
+
331
+ /* Public */
332
+ /* http://imakewebthings.com/waypoints/api/context-destroy */
333
+ Context.prototype.destroy = function() {
334
+ var allWaypoints = []
335
+ for (var axis in this.waypoints) {
336
+ for (var waypointKey in this.waypoints[axis]) {
337
+ allWaypoints.push(this.waypoints[axis][waypointKey])
338
+ }
339
+ }
340
+ for (var i = 0, end = allWaypoints.length; i < end; i++) {
341
+ allWaypoints[i].destroy()
342
+ }
343
+ }
344
+
345
+ /* Public */
346
+ /* http://imakewebthings.com/waypoints/api/context-refresh */
347
+ Context.prototype.refresh = function() {
348
+ /*eslint-disable eqeqeq */
349
+ var isWindow = this.element == this.element.window
350
+ /*eslint-enable eqeqeq */
351
+ var contextOffset = isWindow ? undefined : this.adapter.offset()
352
+ var triggeredGroups = {}
353
+ var axes
354
+
355
+ this.handleScroll()
356
+ axes = {
357
+ horizontal: {
358
+ contextOffset: isWindow ? 0 : contextOffset.left,
359
+ contextScroll: isWindow ? 0 : this.oldScroll.x,
360
+ contextDimension: this.innerWidth(),
361
+ oldScroll: this.oldScroll.x,
362
+ forward: 'right',
363
+ backward: 'left',
364
+ offsetProp: 'left'
365
+ },
366
+ vertical: {
367
+ contextOffset: isWindow ? 0 : contextOffset.top,
368
+ contextScroll: isWindow ? 0 : this.oldScroll.y,
369
+ contextDimension: this.innerHeight(),
370
+ oldScroll: this.oldScroll.y,
371
+ forward: 'down',
372
+ backward: 'up',
373
+ offsetProp: 'top'
374
+ }
375
+ }
376
+
377
+ for (var axisKey in axes) {
378
+ var axis = axes[axisKey]
379
+ for (var waypointKey in this.waypoints[axisKey]) {
380
+ var waypoint = this.waypoints[axisKey][waypointKey]
381
+ var adjustment = waypoint.options.offset
382
+ var oldTriggerPoint = waypoint.triggerPoint
383
+ var elementOffset = 0
384
+ var freshWaypoint = oldTriggerPoint == null
385
+ var contextModifier, wasBeforeScroll, nowAfterScroll
386
+ var triggeredBackward, triggeredForward
387
+
388
+ if (waypoint.element !== waypoint.element.window) {
389
+ elementOffset = waypoint.adapter.offset()[axis.offsetProp]
390
+ }
391
+
392
+ if (typeof adjustment === 'function') {
393
+ adjustment = adjustment.apply(waypoint)
394
+ }
395
+ else if (typeof adjustment === 'string') {
396
+ adjustment = parseFloat(adjustment)
397
+ if (waypoint.options.offset.indexOf('%') > - 1) {
398
+ adjustment = Math.ceil(axis.contextDimension * adjustment / 100)
399
+ }
400
+ }
401
+
402
+ contextModifier = axis.contextScroll - axis.contextOffset
403
+ waypoint.triggerPoint = elementOffset + contextModifier - adjustment
404
+ wasBeforeScroll = oldTriggerPoint < axis.oldScroll
405
+ nowAfterScroll = waypoint.triggerPoint >= axis.oldScroll
406
+ triggeredBackward = wasBeforeScroll && nowAfterScroll
407
+ triggeredForward = !wasBeforeScroll && !nowAfterScroll
408
+
409
+ if (!freshWaypoint && triggeredBackward) {
410
+ waypoint.queueTrigger(axis.backward)
411
+ triggeredGroups[waypoint.group.id] = waypoint.group
412
+ }
413
+ else if (!freshWaypoint && triggeredForward) {
414
+ waypoint.queueTrigger(axis.forward)
415
+ triggeredGroups[waypoint.group.id] = waypoint.group
416
+ }
417
+ else if (freshWaypoint && axis.oldScroll >= waypoint.triggerPoint) {
418
+ waypoint.queueTrigger(axis.forward)
419
+ triggeredGroups[waypoint.group.id] = waypoint.group
420
+ }
421
+ }
422
+ }
423
+
424
+ Waypoint.requestAnimationFrame(function() {
425
+ for (var groupKey in triggeredGroups) {
426
+ triggeredGroups[groupKey].flushTriggers()
427
+ }
428
+ })
429
+
430
+ return this
431
+ }
432
+
433
+ /* Private */
434
+ Context.findOrCreateByElement = function(element) {
435
+ return Context.findByElement(element) || new Context(element)
436
+ }
437
+
438
+ /* Private */
439
+ Context.refreshAll = function() {
440
+ for (var contextId in contexts) {
441
+ contexts[contextId].refresh()
442
+ }
443
+ }
444
+
445
+ /* Public */
446
+ /* http://imakewebthings.com/waypoints/api/context-find-by-element */
447
+ Context.findByElement = function(element) {
448
+ return contexts[element.waypointContextKey]
449
+ }
450
+
451
+ window.onload = function() {
452
+ if (oldWindowLoad) {
453
+ oldWindowLoad()
454
+ }
455
+ Context.refreshAll()
456
+ }
457
+
458
+ Waypoint.requestAnimationFrame = function(callback) {
459
+ var requestFn = window.requestAnimationFrame ||
460
+ window.mozRequestAnimationFrame ||
461
+ window.webkitRequestAnimationFrame ||
462
+ requestAnimationFrameShim
463
+ requestFn.call(window, callback)
464
+ }
465
+ Waypoint.Context = Context
466
+ }())
467
+ ;(function() {
468
+ 'use strict'
469
+
470
+ function byTriggerPoint(a, b) {
471
+ return a.triggerPoint - b.triggerPoint
472
+ }
473
+
474
+ function byReverseTriggerPoint(a, b) {
475
+ return b.triggerPoint - a.triggerPoint
476
+ }
477
+
478
+ var groups = {
479
+ vertical: {},
480
+ horizontal: {}
481
+ }
482
+ var Waypoint = window.Waypoint
483
+
484
+ /* http://imakewebthings.com/waypoints/api/group */
485
+ function Group(options) {
486
+ this.name = options.name
487
+ this.axis = options.axis
488
+ this.id = this.name + '-' + this.axis
489
+ this.waypoints = []
490
+ this.clearTriggerQueues()
491
+ groups[this.axis][this.name] = this
492
+ }
493
+
494
+ /* Private */
495
+ Group.prototype.add = function(waypoint) {
496
+ this.waypoints.push(waypoint)
497
+ }
498
+
499
+ /* Private */
500
+ Group.prototype.clearTriggerQueues = function() {
501
+ this.triggerQueues = {
502
+ up: [],
503
+ down: [],
504
+ left: [],
505
+ right: []
506
+ }
507
+ }
508
+
509
+ /* Private */
510
+ Group.prototype.flushTriggers = function() {
511
+ for (var direction in this.triggerQueues) {
512
+ var waypoints = this.triggerQueues[direction]
513
+ var reverse = direction === 'up' || direction === 'left'
514
+ waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint)
515
+ for (var i = 0, end = waypoints.length; i < end; i += 1) {
516
+ var waypoint = waypoints[i]
517
+ if (waypoint.options.continuous || i === waypoints.length - 1) {
518
+ waypoint.trigger([direction])
519
+ }
520
+ }
521
+ }
522
+ this.clearTriggerQueues()
523
+ }
524
+
525
+ /* Private */
526
+ Group.prototype.next = function(waypoint) {
527
+ this.waypoints.sort(byTriggerPoint)
528
+ var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
529
+ var isLast = index === this.waypoints.length - 1
530
+ return isLast ? null : this.waypoints[index + 1]
531
+ }
532
+
533
+ /* Private */
534
+ Group.prototype.previous = function(waypoint) {
535
+ this.waypoints.sort(byTriggerPoint)
536
+ var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
537
+ return index ? this.waypoints[index - 1] : null
538
+ }
539
+
540
+ /* Private */
541
+ Group.prototype.queueTrigger = function(waypoint, direction) {
542
+ this.triggerQueues[direction].push(waypoint)
543
+ }
544
+
545
+ /* Private */
546
+ Group.prototype.remove = function(waypoint) {
547
+ var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
548
+ if (index > -1) {
549
+ this.waypoints.splice(index, 1)
550
+ }
551
+ }
552
+
553
+ /* Public */
554
+ /* http://imakewebthings.com/waypoints/api/first */
555
+ Group.prototype.first = function() {
556
+ return this.waypoints[0]
557
+ }
558
+
559
+ /* Public */
560
+ /* http://imakewebthings.com/waypoints/api/last */
561
+ Group.prototype.last = function() {
562
+ return this.waypoints[this.waypoints.length - 1]
563
+ }
564
+
565
+ /* Private */
566
+ Group.findOrCreate = function(options) {
567
+ return groups[options.axis][options.name] || new Group(options)
568
+ }
569
+
570
+ Waypoint.Group = Group
571
+ }())
572
+ ;(function() {
573
+ 'use strict'
574
+
575
+ var $ = window.jQuery
576
+ var Waypoint = window.Waypoint
577
+
578
+ function JQueryAdapter(element) {
579
+ this.$element = $(element)
580
+ }
581
+
582
+ $.each([
583
+ 'innerHeight',
584
+ 'innerWidth',
585
+ 'off',
586
+ 'offset',
587
+ 'on',
588
+ 'outerHeight',
589
+ 'outerWidth',
590
+ 'scrollLeft',
591
+ 'scrollTop'
592
+ ], function(i, method) {
593
+ JQueryAdapter.prototype[method] = function() {
594
+ var args = Array.prototype.slice.call(arguments)
595
+ return this.$element[method].apply(this.$element, args)
596
+ }
597
+ })
598
+
599
+ $.each([
600
+ 'extend',
601
+ 'inArray',
602
+ 'isEmptyObject'
603
+ ], function(i, method) {
604
+ JQueryAdapter[method] = $[method]
605
+ })
606
+
607
+ Waypoint.adapters.push({
608
+ name: 'jquery',
609
+ Adapter: JQueryAdapter
610
+ })
611
+ Waypoint.Adapter = JQueryAdapter
612
+ }())
613
+ ;(function() {
614
+ 'use strict'
615
+
616
+ var Waypoint = window.Waypoint
617
+
618
+ function createExtension(framework) {
619
+ return function() {
620
+ var waypoints = []
621
+ var overrides = arguments[0]
622
+
623
+ if (framework.isFunction(arguments[0])) {
624
+ overrides = framework.extend({}, arguments[1])
625
+ overrides.handler = arguments[0]
626
+ }
627
+
628
+ this.each(function() {
629
+ var options = framework.extend({}, overrides, {
630
+ element: this
631
+ })
632
+ if (typeof options.context === 'string') {
633
+ options.context = framework(this).closest(options.context)[0]
634
+ }
635
+ waypoints.push(new Waypoint(options))
636
+ })
637
+
638
+ return waypoints
639
+ }
640
+ }
641
+
642
+ if (window.jQuery) {
643
+ window.jQuery.fn.waypoint = createExtension(window.jQuery)
644
+ }
645
+ if (window.Zepto) {
646
+ window.Zepto.fn.waypoint = createExtension(window.Zepto)
647
+ }
648
+ }())
649
+ ;
vendor/waypoints/jquery.waypoints.min.js ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ /*!
2
+ Waypoints - 4.0.0
3
+ Copyright © 2011-2015 Caleb Troughton
4
+ Licensed under the MIT license.
5
+ https://github.com/imakewebthings/waypoints/blog/master/licenses.txt
6
+ */
7
+ !function(){"use strict";function t(o){if(!o)throw new Error("No options passed to Waypoint constructor");if(!o.element)throw new Error("No element option passed to Waypoint constructor");if(!o.handler)throw new Error("No handler option passed to Waypoint constructor");this.key="waypoint-"+e,this.options=t.Adapter.extend({},t.defaults,o),this.element=this.options.element,this.adapter=new t.Adapter(this.element),this.callback=o.handler,this.axis=this.options.horizontal?"horizontal":"vertical",this.enabled=this.options.enabled,this.triggerPoint=null,this.group=t.Group.findOrCreate({name:this.options.group,axis:this.axis}),this.context=t.Context.findOrCreateByElement(this.options.context),t.offsetAliases[this.options.offset]&&(this.options.offset=t.offsetAliases[this.options.offset]),this.group.add(this),this.context.add(this),i[this.key]=this,e+=1}var e=0,i={};t.prototype.queueTrigger=function(t){this.group.queueTrigger(this,t)},t.prototype.trigger=function(t){this.enabled&&this.callback&&this.callback.apply(this,t)},t.prototype.destroy=function(){this.context.remove(this),this.group.remove(this),delete i[this.key]},t.prototype.disable=function(){return this.enabled=!1,this},t.prototype.enable=function(){return this.context.refresh(),this.enabled=!0,this},t.prototype.next=function(){return this.group.next(this)},t.prototype.previous=function(){return this.group.previous(this)},t.invokeAll=function(t){var e=[];for(var o in i)e.push(i[o]);for(var n=0,r=e.length;r>n;n++)e[n][t]()},t.destroyAll=function(){t.invokeAll("destroy")},t.disableAll=function(){t.invokeAll("disable")},t.enableAll=function(){t.invokeAll("enable")},t.refreshAll=function(){t.Context.refreshAll()},t.viewportHeight=function(){return window.innerHeight||document.documentElement.clientHeight},t.viewportWidth=function(){return document.documentElement.clientWidth},t.adapters=[],t.defaults={context:window,continuous:!0,enabled:!0,group:"default",horizontal:!1,offset:0},t.offsetAliases={"bottom-in-view":function(){return this.context.innerHeight()-this.adapter.outerHeight()},"right-in-view":function(){return this.context.innerWidth()-this.adapter.outerWidth()}},window.Waypoint=t}(),function(){"use strict";function t(t){window.setTimeout(t,1e3/60)}function e(t){this.element=t,this.Adapter=n.Adapter,this.adapter=new this.Adapter(t),this.key="waypoint-context-"+i,this.didScroll=!1,this.didResize=!1,this.oldScroll={x:this.adapter.scrollLeft(),y:this.adapter.scrollTop()},this.waypoints={vertical:{},horizontal:{}},t.waypointContextKey=this.key,o[t.waypointContextKey]=this,i+=1,this.createThrottledScrollHandler(),this.createThrottledResizeHandler()}var i=0,o={},n=window.Waypoint,r=window.onload;e.prototype.add=function(t){var e=t.options.horizontal?"horizontal":"vertical";this.waypoints[e][t.key]=t,this.refresh()},e.prototype.checkEmpty=function(){var t=this.Adapter.isEmptyObject(this.waypoints.horizontal),e=this.Adapter.isEmptyObject(this.waypoints.vertical);t&&e&&(this.adapter.off(".waypoints"),delete o[this.key])},e.prototype.createThrottledResizeHandler=function(){function t(){e.handleResize(),e.didResize=!1}var e=this;this.adapter.on("resize.waypoints",function(){e.didResize||(e.didResize=!0,n.requestAnimationFrame(t))})},e.prototype.createThrottledScrollHandler=function(){function t(){e.handleScroll(),e.didScroll=!1}var e=this;this.adapter.on("scroll.waypoints",function(){(!e.didScroll||n.isTouch)&&(e.didScroll=!0,n.requestAnimationFrame(t))})},e.prototype.handleResize=function(){n.Context.refreshAll()},e.prototype.handleScroll=function(){var t={},e={horizontal:{newScroll:this.adapter.scrollLeft(),oldScroll:this.oldScroll.x,forward:"right",backward:"left"},vertical:{newScroll:this.adapter.scrollTop(),oldScroll:this.oldScroll.y,forward:"down",backward:"up"}};for(var i in e){var o=e[i],n=o.newScroll>o.oldScroll,r=n?o.forward:o.backward;for(var s in this.waypoints[i]){var a=this.waypoints[i][s],l=o.oldScroll<a.triggerPoint,h=o.newScroll>=a.triggerPoint,p=l&&h,u=!l&&!h;(p||u)&&(a.queueTrigger(r),t[a.group.id]=a.group)}}for(var c in t)t[c].flushTriggers();this.oldScroll={x:e.horizontal.newScroll,y:e.vertical.newScroll}},e.prototype.innerHeight=function(){return this.element==this.element.window?n.viewportHeight():this.adapter.innerHeight()},e.prototype.remove=function(t){delete this.waypoints[t.axis][t.key],this.checkEmpty()},e.prototype.innerWidth=function(){return this.element==this.element.window?n.viewportWidth():this.adapter.innerWidth()},e.prototype.destroy=function(){var t=[];for(var e in this.waypoints)for(var i in this.waypoints[e])t.push(this.waypoints[e][i]);for(var o=0,n=t.length;n>o;o++)t[o].destroy()},e.prototype.refresh=function(){var t,e=this.element==this.element.window,i=e?void 0:this.adapter.offset(),o={};this.handleScroll(),t={horizontal:{contextOffset:e?0:i.left,contextScroll:e?0:this.oldScroll.x,contextDimension:this.innerWidth(),oldScroll:this.oldScroll.x,forward:"right",backward:"left",offsetProp:"left"},vertical:{contextOffset:e?0:i.top,contextScroll:e?0:this.oldScroll.y,contextDimension:this.innerHeight(),oldScroll:this.oldScroll.y,forward:"down",backward:"up",offsetProp:"top"}};for(var r in t){var s=t[r];for(var a in this.waypoints[r]){var l,h,p,u,c,d=this.waypoints[r][a],f=d.options.offset,w=d.triggerPoint,y=0,g=null==w;d.element!==d.element.window&&(y=d.adapter.offset()[s.offsetProp]),"function"==typeof f?f=f.apply(d):"string"==typeof f&&(f=parseFloat(f),d.options.offset.indexOf("%")>-1&&(f=Math.ceil(s.contextDimension*f/100))),l=s.contextScroll-s.contextOffset,d.triggerPoint=y+l-f,h=w<s.oldScroll,p=d.triggerPoint>=s.oldScroll,u=h&&p,c=!h&&!p,!g&&u?(d.queueTrigger(s.backward),o[d.group.id]=d.group):!g&&c?(d.queueTrigger(s.forward),o[d.group.id]=d.group):g&&s.oldScroll>=d.triggerPoint&&(d.queueTrigger(s.forward),o[d.group.id]=d.group)}}return n.requestAnimationFrame(function(){for(var t in o)o[t].flushTriggers()}),this},e.findOrCreateByElement=function(t){return e.findByElement(t)||new e(t)},e.refreshAll=function(){for(var t in o)o[t].refresh()},e.findByElement=function(t){return o[t.waypointContextKey]},window.onload=function(){r&&r(),e.refreshAll()},n.requestAnimationFrame=function(e){var i=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||t;i.call(window,e)},n.Context=e}(),function(){"use strict";function t(t,e){return t.triggerPoint-e.triggerPoint}function e(t,e){return e.triggerPoint-t.triggerPoint}function i(t){this.name=t.name,this.axis=t.axis,this.id=this.name+"-"+this.axis,this.waypoints=[],this.clearTriggerQueues(),o[this.axis][this.name]=this}var o={vertical:{},horizontal:{}},n=window.Waypoint;i.prototype.add=function(t){this.waypoints.push(t)},i.prototype.clearTriggerQueues=function(){this.triggerQueues={up:[],down:[],left:[],right:[]}},i.prototype.flushTriggers=function(){for(var i in this.triggerQueues){var o=this.triggerQueues[i],n="up"===i||"left"===i;o.sort(n?e:t);for(var r=0,s=o.length;s>r;r+=1){var a=o[r];(a.options.continuous||r===o.length-1)&&a.trigger([i])}}this.clearTriggerQueues()},i.prototype.next=function(e){this.waypoints.sort(t);var i=n.Adapter.inArray(e,this.waypoints),o=i===this.waypoints.length-1;return o?null:this.waypoints[i+1]},i.prototype.previous=function(e){this.waypoints.sort(t);var i=n.Adapter.inArray(e,this.waypoints);return i?this.waypoints[i-1]:null},i.prototype.queueTrigger=function(t,e){this.triggerQueues[e].push(t)},i.prototype.remove=function(t){var e=n.Adapter.inArray(t,this.waypoints);e>-1&&this.waypoints.splice(e,1)},i.prototype.first=function(){return this.waypoints[0]},i.prototype.last=function(){return this.waypoints[this.waypoints.length-1]},i.findOrCreate=function(t){return o[t.axis][t.name]||new i(t)},n.Group=i}(),function(){"use strict";function t(t){this.$element=e(t)}var e=window.jQuery,i=window.Waypoint;e.each(["innerHeight","innerWidth","off","offset","on","outerHeight","outerWidth","scrollLeft","scrollTop"],function(e,i){t.prototype[i]=function(){var t=Array.prototype.slice.call(arguments);return this.$element[i].apply(this.$element,t)}}),e.each(["extend","inArray","isEmptyObject"],function(i,o){t[o]=e[o]}),i.adapters.push({name:"jquery",Adapter:t}),i.Adapter=t}(),function(){"use strict";function t(t){return function(){var i=[],o=arguments[0];return t.isFunction(arguments[0])&&(o=t.extend({},arguments[1]),o.handler=arguments[0]),this.each(function(){var n=t.extend({},o,{element:this});"string"==typeof n.context&&(n.context=t(this).closest(n.context)[0]),i.push(new e(n))}),i}}var e=window.Waypoint;window.jQuery&&(window.jQuery.fn.waypoint=t(window.jQuery)),window.Zepto&&(window.Zepto.fn.waypoint=t(window.Zepto))}();