Easy Table of Contents - Version 2.0.33

Version Description

08/06/2022 = * BUG: Sticky Toggle JS issue when disabled Auto Insert & not added manual Shortcode #272 * BUG: Ad Invalid Click Protector plugin is having conflicted #267 * TWEAK: Trailing equal signs in changelog area of readme.txt are missing #264 * TWEAK: Need to make the functionality numbers for the heading start from a right side. #262 * NEW: Need to add compatibility with the plugin "Multiple Page Generator MPG" #261 * TWEAK: Need to improve the help page #259 * BUG: Other plugins admin notices are appearing on our settings page #257 * NEW: Need to add a shortcode tab in settings page #256

Download this release

Release Info

Developer magazine3
Plugin Icon 128x128 Easy Table of Contents
Version 2.0.33
Comparing to
See all releases

Code changes from version 2.0.32 to 2.0.33

README.txt CHANGED
@@ -5,7 +5,7 @@ Tags: table of contents, toc
5
  Requires at least: 5.3
6
  Tested up to: 6.0
7
  Requires PHP: 5.6.20
8
- Stable tag: 2.0.32
9
  License: GPLv2 or later
10
  License URI: https://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -106,7 +106,17 @@ Easy Table Contents is a fork of the excellent [Table of Contents Plus](https://
106
 
107
  == Changelog ==
108
 
109
- = 2.0.32 08/16/2022
 
 
 
 
 
 
 
 
 
 
110
  * NEW: Added Sticky Table of Content #241
111
  * TWEAK: Improved admin UI & UX #245
112
  * TWEAK: Audit onboarding as a first time user #243
@@ -114,7 +124,7 @@ Easy Table Contents is a fork of the excellent [Table of Contents Plus](https://
114
  * BUG: Capitalizing the first letter of each title in the table of content #252
115
  * BUG: Need to fix the sidebar position #251
116
 
117
- = 2.0.31.1 08/03/2022
118
  * BUG: TOC not working with the SEOWP theme #230
119
  * BUG: TOC rendering area’s height is always changing in sidebar #244
120
  * BUG: The colon is getting removed from anchor links #248
@@ -124,7 +134,7 @@ Easy Table Contents is a fork of the excellent [Table of Contents Plus](https://
124
  * BUG: TOC showing issue with video implemented posts/pages. #236
125
  * BUG: When using TOC with Elementor then the animation content is not showing #237
126
 
127
- = 2.0.31 07/29/2022
128
  BUG: Elementor editor is not accessible after latest update. #235
129
 
130
  = 2.0.30 07/28/2022 =
5
  Requires at least: 5.3
6
  Tested up to: 6.0
7
  Requires PHP: 5.6.20
8
+ Stable tag: 2.0.33
9
  License: GPLv2 or later
10
  License URI: https://www.gnu.org/licenses/gpl-2.0.html
11
 
106
 
107
  == Changelog ==
108
 
109
+ = 2.0.33 08/06/2022 =
110
+ * BUG: Sticky Toggle JS issue when disabled Auto Insert & not added manual Shortcode #272
111
+ * BUG: Ad Invalid Click Protector plugin is having conflicted #267
112
+ * TWEAK: Trailing equal signs in changelog area of readme.txt are missing #264
113
+ * TWEAK: Need to make the functionality numbers for the heading start from a right side. #262
114
+ * NEW: Need to add compatibility with the plugin "Multiple Page Generator – MPG" #261
115
+ * TWEAK: Need to improve the help page #259
116
+ * BUG: Other plugins admin notices are appearing on our settings page #257
117
+ * NEW: Need to add a shortcode tab in settings page #256
118
+
119
+ = 2.0.32 08/16/2022 =
120
  * NEW: Added Sticky Table of Content #241
121
  * TWEAK: Improved admin UI & UX #245
122
  * TWEAK: Audit onboarding as a first time user #243
124
  * BUG: Capitalizing the first letter of each title in the table of content #252
125
  * BUG: Need to fix the sidebar position #251
126
 
127
+ = 2.0.31.1 08/03/2022 =
128
  * BUG: TOC not working with the SEOWP theme #230
129
  * BUG: TOC rendering area’s height is always changing in sidebar #244
130
  * BUG: The colon is getting removed from anchor links #248
134
  * BUG: TOC showing issue with video implemented posts/pages. #236
135
  * BUG: When using TOC with Elementor then the animation content is not showing #237
136
 
137
+ = 2.0.31 07/29/2022 =
138
  BUG: Elementor editor is not accessible after latest update. #235
139
 
140
  = 2.0.30 07/28/2022 =
assets/css/admin.css CHANGED
@@ -1,314 +1,372 @@
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#child_font_size,
105
  input#smooth_scroll_offset {
106
- width: 50px;
107
- text-align: center;
108
  }
 
109
  input.custom_colour_option {
110
- width: 75px;
111
  }
 
112
  table#theme_custom, div#farbtastic_colour_wheel {
113
- float: left;
114
  }
 
115
  table#theme_custom {
116
- margin-top: 30px;
117
  }
 
118
  table#theme_custom img {
119
- vertical-align: middle;
120
- opacity: 0.4;
121
  }
 
122
  table#theme_custom img:hover {
123
- cursor: pointer;
124
- opacity: 1;
125
  }
 
126
  div#farbtastic_colour_wheel {
127
- margin-left: 20px;
128
  }
 
129
  #tab3 h3:not(:first-child) {
130
- margin-top: 2em;
131
  }
132
 
133
  /* My styles */
134
  #toc input.small-text {
135
- width: 50px;
136
- padding: 2px;
137
- height: 28px;
138
- line-height: 28px;
139
- vertical-align: bottom;
140
  }
141
 
142
  #toc .form-table tr > th > strong {
143
- font-size: 18px;
144
- font-style: italic;
145
  }
 
146
  /* Tab panel styles */
147
- .postbox{
148
- padding: 10px;
149
  }
 
150
  html {
151
- scroll-behavior: smooth;
152
  }
 
153
  .toc-tab-panel {
154
- overflow: hidden;
155
- border: 1px solid #ccc;
156
- background-color: #fff;
157
- margin-top: 15px;}
 
 
158
  .toc-tab-panel a {
159
- background-color: inherit;
160
- text-decoration: none;
161
- float: left;
162
- border: none;
163
- outline: none;
164
- cursor: pointer;
165
- padding: 14px 16px;
166
- transition: 0s;
167
- font-size: 15px;
168
- color: #2271b1;
169
- font-weight: 500;
170
- }
 
171
  .toc-tab-panel a:hover {
172
- color: #0a4b78;
173
- }
 
174
  .toc-tab-panel a.active {
175
- box-shadow: none;
176
- border-bottom: 4px solid #646970;
177
- color: #1d2327;
178
- }
 
179
  .toc-tab-panel a:focus {
180
- box-shadow: none;
181
- outline: none;
182
  }
 
183
  .eztoc-tabcontent {
184
- display: none;
185
- border-top: none;
186
- animation: fadeEffect 1s;
187
- }
188
- #technical .eztoc-form-page-ui{
189
- display:flex;
190
- background: #fff;
191
- width: auto;
192
- height: auto;
193
- }
194
- #technical .eztoc-left-side{
195
- width: 70%;
196
-
197
- }
198
- .eztoc-right-side{
199
- width: 31%;
200
- margin-top: auto;
201
- margin-bottom: auto;
202
- text-align: center;
203
-
204
  }
 
 
 
 
 
 
 
 
 
205
  .eztoc-tabcontent {
206
- display: none;
207
- border-top: none;
208
- }
209
- #technical {
210
- background: #fff;
211
- margin-top: 10px;
212
- padding: 28px;
213
- padding: 15px 28px 28px 28px;
214
- min-width: 255px;
215
- box-shadow: 0 1px 1px rgb(0 0 0 / 4%);
216
- }
 
 
217
  /* #technical p{
218
  line-height: 0.5rem;
219
  } */
220
- #technical-form{
221
-
222
- width: 60%;
223
- }
 
224
  .support-label {
225
- margin-top: 4px;
226
- float: left;
227
- width: 70px;
228
 
229
- font-size: 14px;
230
  }
231
 
232
- .star-mark{
233
- color: red;
234
- margin-left: 4px;
235
- font-family: bold;
236
  }
 
237
  #technical li {
238
- margin:25px 0px 20px 0px;
239
- margin:10px 0px 10px 0px;
240
- list-style: none;
241
- }
242
- .eztoc_support_div_form{
243
- margin-top: 23px;
244
- }
245
- .eztoc-customer-type{
246
- display: block;
247
- }
248
- .support-input select{
249
- border-radius: 4px;
250
- margin-top: -7px;
251
- }
252
- .eztoc_dev-bio{
253
- display: block;
254
- }
255
- .ezoc-bio-wrap{
256
- float: left;
257
- text-align: center;
258
- width: 33.33%;
259
- text-transform: uppercase;
260
- }
261
- .ezoc-bio-wrap p{
262
- width: auto;
263
- font-size: 10px;
264
- color: #555;
265
- margin: 0px 0 20px 0;
266
- }
267
- .ezoc-bio-wrap img{
268
- margin: 25px 0 0 0;
269
- border-radius: 50%;
270
- }
271
- .eztoc-bio-box{
272
- background: #fff;
273
- border: 1px solid #ccc;
274
- padding: 15px 20px;
275
- border-radius: 4px;
276
- margin: 15px 15px 15px 0;
277
- /* height: 22rem; */
278
- padding: 0px 20px;
279
- }
280
- .eztoc-bio-box:hover{
281
- box-shadow: 5px 5px 8px #888888;
282
- }
283
- .eztoc-p{
284
- font-size: 15px;
285
- margin: 20px auto 0px auto;
286
- text-align: center;
287
- }
288
- .eztoc-p{
289
- line-height: 1.5rem;
290
- padding: 0 25px;
291
- margin-top: 10px;
292
- font-size: 16px;
293
- }
294
- .eztoc-bio-box h1{
295
- margin: 8px auto 0px auto;
296
- text-align: center;
297
- font-weight: bolder;
298
- }
299
- .eztoc_boxdesk{
300
- clear: left;
301
- font-size: 15px;
302
- text-align: center;
303
- margin: 20px 0 0 0;
304
-
305
- }
306
- .company-link{
307
- font-weight: 500;
308
- margin: 20px 0 0 0;
309
- }
310
- .company-link a{
311
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312
  display: table;
313
  background: #e91e63;
314
  width: auto;
@@ -317,49 +375,62 @@ html {
317
  color: #fff;
318
  text-decoration: none;
319
  margin-top: 10px;
320
- margin-bottom: 15px;
321
  border-radius: 6px;
322
  border: 0;
323
  /* text-transform: uppercase; */
324
  font-size: 16px;
325
 
326
  }
327
- .eztoc-send-query{
328
- background: #2271b1;
 
329
  border-color: #2271b1;
330
- color:#fff;
331
  text-decoration: none;
332
  text-shadow: none;
333
- margin-left: 70px !important;;
334
- }
335
-
336
- @media screen and (min-width: 870px) and (max-width: 1300px ){
337
- .eztoc-bio-box{
338
- padding-top: 20px;
339
- height: 29.1rem;;
340
- }
341
- .eztoc-bio-box h1{
342
- font-size: 20px;
343
- }
344
- .eztoc-bio-box p{
345
- font-size: 13px;
346
- margin: 20px auto 0px auto;
347
- }
348
- .ezoc-bio-wrap img{
349
- width: 30px;
350
- height: 30px;
351
- }
352
- .ezoc-bio-wrap p{
353
- width: 55px;
354
- font-size: 12px;
355
- margin-bottom: 10px;
356
- }
357
-
358
- }
359
- @keyframes fadeEffect { from {opacity: 0;} to {opacity: 1;} }
360
-
361
-
362
- .eztoc-wrapper{
 
 
 
 
 
 
 
 
 
 
 
 
363
  max-width: 100%;
364
  width: 100%;
365
  display: flex;
@@ -367,7 +438,7 @@ html {
367
  margin: auto;
368
  }
369
 
370
- .eztoc-wrapper .table{
371
  margin: 0 auto;
372
  background: #fff;
373
  width: calc(30%);
@@ -376,12 +447,12 @@ html {
376
  box-shadow: 0 5px 10px rgb(0 0 0 / 10%);
377
  }
378
 
379
- .table .price-section{
380
- display: flex;
381
- justify-content: center;
382
  }
383
 
384
- .price-section .price-area{
385
  height: 120px;
386
  width: 120px;
387
  background: #ffd861;
@@ -389,7 +460,7 @@ html {
389
  padding: 2px;
390
  }
391
 
392
- .price-section .price-area .inner-area{
393
  height: 100%;
394
  width: 100%;
395
  border-radius: 50%;
@@ -400,7 +471,7 @@ html {
400
  position: relative;
401
  }
402
 
403
- .price-area .inner-area .text{
404
  font-size: 25px;
405
  font-weight: 400;
406
  position: absolute;
@@ -408,12 +479,12 @@ html {
408
  left: 17px;
409
  }
410
 
411
- .price-area .inner-area .price{
412
  font-size: 55px;
413
  font-weight: 500;
414
  }
415
 
416
- .table .package-name{
417
  width: 100%;
418
  height: 2px;
419
  background: #ffecb3;
@@ -421,7 +492,7 @@ html {
421
  position: relative;
422
  }
423
 
424
- .table .package-name::before{
425
  position: absolute;
426
  content: "Basic";
427
  top: 50%;
@@ -433,37 +504,37 @@ html {
433
  font-weight: bolder;
434
  }
435
 
436
- .table .features li{
437
  list-style: none;
438
  display: flex;
439
  justify-content: space-between;
440
  margin-bottom: 15px;
441
  }
442
 
443
- .features li .list-name{
444
  font-size: 17px;
445
  font-weight: 400;
446
  }
447
 
448
- .features li .icon{
449
  font-size: 15px;
450
  }
451
 
452
- .features li .icon.check{
453
  color: #2db94d;
454
  }
455
 
456
- .features li .icon.cross{
457
  color: #cd3241;
458
  }
459
 
460
- .table .btn{
461
  display: flex;
462
  justify-content: center;
463
  margin-top: 35px;
464
  }
465
 
466
- .table .btn button{
467
  width: 80%;
468
  height: 50px;
469
  font-weight: 700;
@@ -477,116 +548,118 @@ html {
477
  }
478
 
479
  .basic .price-area,
480
- .basic .inner-area{
481
  background: #ffd861;
482
  }
483
 
484
- .basic .btn button{
485
  background: #fff;
486
  color: #ffd861;
487
  border: 2px solid #ffd861;
488
  }
489
 
490
- .basic .btn button:hover{
491
  border-radius: 6px;
492
  background: #ffd861;
493
  color: #fff;
494
  }
495
 
496
  .Premium .price-area,
497
- .Premium .inner-area{
498
  background: #a26bfa;
499
  }
500
 
501
- .Premium .btn button{
502
  background: #fff;
503
  color: #a26bfa;
504
  border: 2px solid #a26bfa;
505
  }
506
 
507
- .Premium .btn button:hover{
508
  border-radius: 6px;
509
  background: #a26bfa;
510
  color: #fff;
511
  }
512
-
513
 
514
- .basic .package-name{
 
515
  background: #ffecb3;
516
  }
517
 
518
- .Premium .package-name{
519
  background: #a26bfa;
520
  }
521
 
522
-
523
 
524
- .basic .package-name::before{
525
  content: "Free";
526
  }
527
 
528
- .Premium .package-name::before{
529
  content: "PRO";
530
  }
531
 
532
-
533
 
534
  .basic ::selection,
535
  .basic .price-area,
536
- .basic .inner-area{
537
  background: #ffd861;
538
  }
539
 
540
  .Premium ::selection,
541
  .Premium .price-area,
542
- .Premium .inner-area{
543
  background: #a26bfa;
544
  }
545
 
546
  div#eztoc-tabs a {
547
  text-decoration: none;
548
- }
 
549
  div#eztoc-tabs a:first-child {
550
  color: #000;
551
  }
552
 
553
- #the-list{position: relative;}
 
 
 
554
  .eztoc-wr {
555
- width: 100%;
556
- margin: 0 auto;
557
- position: relative
558
  }
559
 
560
  .etoc-eztoc-img {
561
- width: 100%;
562
- margin: 0 auto;
563
- text-align: center;
564
- position: relative;
565
- line-height: 0;
566
- height: 300px;
567
  }
568
 
569
  .eztoc-img img {
570
- position: relative
571
  }
572
 
573
  .sp_ov {
574
- background: rgba(234, 76, 137, 1);
575
- bottom: 0;
576
- left: 0;
577
- position: absolute;
578
- right: 0;
579
- top: 0;
580
  }
581
 
582
  .etoc-eztoc-cnt {
583
- position: absolute;
584
- top: 40px;
585
- bottom: 0;
586
- left: 40px;
587
- right: 40px;
588
- margin: 0 auto;
589
- text-align: center
590
  }
591
 
592
  .etoc-eztoc-cnt h1 {
@@ -596,7 +669,7 @@ div#eztoc-tabs a:first-child {
596
  }
597
 
598
  .etoc-eztoc-cnt p {
599
- margin-top: 0px;
600
  color: #371b24;
601
  font-size: 18px;
602
  padding: 0 100px;
@@ -605,563 +678,579 @@ div#eztoc-tabs a:first-child {
605
  }
606
 
607
  .etoc-eztoc-cnt .buy {
608
- border-width: 0px !important;
609
- font-size: 1.25rem;
610
- line-height: 2;
611
- text-decoration: none;
612
- background: white !important;
613
  border-radius: 8px !important;
614
  font-size: 16px !important;
615
  padding: 12px 18px;
616
  color: rgba(234, 76, 137, 1) !important;
617
  font-weight: 500;
618
  }
619
- .etoc-eztoc-cnt .buy:hover{
620
- box-shadow: 0px 2px 2px #999;
621
- background: linear-gradient(to left, #fdfc35, #ffe258) !important;
 
622
  }
 
623
  .pvf {
624
- position: relative;
625
- top: -16px;
626
- border: 1px solid #eee;
627
- padding-bottom: 40px
628
  }
629
 
630
  .ext {
631
- display: grid;
632
- grid-template-columns: 1fr 1fr 1fr;
633
- background: #f9f9f9;
634
- padding: 45px 0 45px 25px
635
  }
636
 
637
  .ex-1 {
638
- width: 80%;
639
  }
640
 
641
  .ex-1 h4 {
642
- margin: 15px 0 12px 0;
643
- font-weight: 600;
644
- font-size: 20px;
645
  color: rgba(234, 76, 137, 1);
646
  }
647
 
648
  .ex-1 p {
649
- font-size: 14px;
650
- font-weight: 400;
651
- margin: 0;
652
  color: #000;
653
  }
654
 
655
  .e-1 img {
656
- width: 65px!important
657
  }
658
 
659
  .e-2 img {
660
- width: 45px!important
661
  }
662
 
663
  .e-3 img {
664
- width: 49px!important
665
  }
666
 
667
  .pvf-cnt {
668
- width: 100%;
669
- display: inline-block
670
  }
671
 
672
  .pvf-tlt {
673
- text-align: center;
674
- width: 100%;
675
- margin: 70px 0 60px 0
676
  }
677
 
678
  .pvf-tlt h2 {
679
- font-size: 36px;
680
- line-height: 1.4;
681
- color: #000;
682
- font-weight: 500;
683
- margin: 0
684
  }
685
 
686
  .pvf-tlt span {
687
- font-size: 16px;
688
- color: #000;
689
- margin-top: 15px;
690
- display: inline-block;
691
- position: relative;
692
- top: 4px
693
  }
694
 
695
  .pvf-cmp {
696
- display: grid;
697
- grid-template-columns: 1fr 2fr
698
  }
699
 
700
  .fr {
701
- border-right: 1px solid #eee
702
  }
703
 
704
  .fr h1,
705
  .pr h1 {
706
- font-size: 36px;
707
- font-weight: 700;
708
- line-height: 1.5;
709
- border-bottom: 1px solid #efefef;
710
- padding: 0 0 20px 35px;
711
  }
712
 
713
  .pr h1 {
714
- padding-left: 50px;
715
- color: rgba(234, 76, 137, 1);
716
  }
717
 
718
  .fr-fe {
719
- color: #222;
720
- padding-top: 10px
721
  }
722
 
723
  .fe-1 {
724
- padding: 22px 35px 35px 35px
725
  }
726
 
727
  .fe-1 h4 {
728
- margin: 0 0 10px 0;
729
- font-size: 20px;
730
- line-height: 1.4;
731
- font-weight: 400;
732
- color: #000
733
  }
734
 
735
  .fe-1 p {
736
- font-size: 15px;
737
- line-height: 1.4;
738
- margin: 0;
739
- color: #333
740
  }
741
 
742
  .pr-fe {
743
- padding: 34px 35px 35px 35px
744
  }
745
 
746
  .pr-fe span {
747
- font-family: georgia;
748
- font-size: 16px;
749
- font-weight: 700;
750
- color: #000;
751
- font-style: italic;
752
- line-height: 1.3
753
  }
754
 
755
  .fet {
756
- width: 100%;
757
- display: grid;
758
- grid-template-columns: 1fr 1fr;
759
- grid-gap: 25px;
760
- margin-top: 40px
761
  }
762
 
763
  .fe-2 {
764
- color: #222
765
  }
766
 
767
  .fe-t img {
768
- width: 22px!important;
769
- display: inline-block;
770
- vertical-align: middle
771
  }
772
 
773
  .fe-t h4 {
774
- margin: 0;
775
- display: inline-block;
776
- vertical-align: middle;
777
- font-size: 19px;
778
- color: #000;
779
- font-weight: 400;
780
- line-height: 1.4;
781
- padding-left: 8px;
782
- margin-top: -5px;
783
  }
784
 
785
  .fe-2 p {
786
- font-size: 15px;
787
- line-height: 1.4;
788
- margin: 0;
789
- color: #555;
790
- padding-top: 8px
791
  }
792
 
793
  .pr-btn {
794
- width: 100%;
795
- display: inline-block;
796
- text-align: center;
797
- margin: 50px 0 25px 0
798
  }
799
 
800
  .pr-btn a {
801
- text-decoration: none;
802
- color: #fff;
803
- padding: 12px 35px 17px 35px;
804
- display: inline-block;
805
- border-radius: 5px;
806
- font-size: 28px;
807
- font-weight: 500;
808
- line-height: 1.2;
809
- background: -webkit-linear-gradient(to right, #e35796, #fc789f);
810
- font-weight: 600;
811
- background: linear-gradient(to right, #e35796, rgba(234, 76, 137, 1));
812
- margin-top: 0;
813
- box-shadow: 0 .15em .65em 0 rgba(0, 0, 0, .25);
814
  }
815
 
816
  .amp-upg {
817
- background: #f5f5f5;
818
- padding: 60px 10px 0 10px
819
  }
820
 
821
  .upg-t {
822
- text-align: center;
823
- color: #222
824
  }
825
 
826
  .upg-t h2 {
827
- margin: 0;
828
- font-size: 35px;
829
- color: #060606;
830
- line-height: 1.3;
831
- font-weight: 500
832
  }
833
 
834
- .upg-t>span {
835
- font-size: 14px;
836
- line-height: 1.2;
837
- margin-top: 15px;
838
- display: inline-block;
839
- color: #666
840
  }
841
 
842
  .etoc-pri-lst {
843
- width: 100%;
844
- display: grid;
845
- grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
846
- margin-top: 70px;
847
- grid-gap: 1px;
848
- box-shadow: 0 10px 15px 1px #ddd
849
  }
850
 
851
  .pri-tb {
852
- background: #fff;
853
- text-align: center;
854
- border: 1px solid #f9f9f9;
855
- position: relative
856
  }
857
 
858
  .pri-tb:hover {
859
- border: 1px solid #e04371;
860
  }
861
 
862
  .pri-tb a:hover .pri-by {
863
- background: #e04371;
864
  }
 
865
  .pri-tb a:hover .amt {
866
- color: #7241a7;
867
  }
868
 
869
  .pri-tb a {
870
- display: inline-block;
871
- text-decoration: none;
872
- color: #222;
873
- padding: 20px 12px;
874
  }
875
 
876
  .pri-tb h5 {
877
- margin: 0 0 20px 0;
878
- font-size: 13px;
879
- line-height: 1.2;
880
- letter-spacing: 2px;
881
- font-weight: 400;
882
- color: #000
883
  }
884
 
885
  .pri-tb span {
886
- display: inline-block
887
  }
888
 
889
  .pri-tb .amt {
890
- font-size: 40px;
891
- color: #e04371;
892
- font-weight: 500;
893
- margin-bottom: 20px;
894
- display: block;
895
  }
896
 
897
  .pri-tb .d-amt {
898
- font-size: 24px;
899
- color: #666;
900
- font-weight: 500;
901
- margin-bottom: 15px;
902
- display: none;
903
- text-decoration: line-through
904
  }
905
 
906
  .d-amt sup {
907
- line-height: 0;
908
- position: relative;
909
- top: 7px
910
  }
911
 
912
  .pri-tb .s-amt {
913
- font-size: 13px;
914
- color: #4caf50;
915
- font-weight: 500;
916
- margin-bottom: 10px;
917
- display: none
918
  }
919
 
920
  .pri-tb .amt sup {
921
- font-size: 22px;
922
- padding: 0 4px 0 0;
923
- position: relative;
924
- top: 7px
925
  }
926
 
927
  .pri-tb .bil {
928
- color: #aaa;
929
- font-size: 12px;
930
- margin-bottom: 20px
931
  }
932
 
933
  .pri-tb .e,
934
  .pri-tb .f,
935
  .pri-tb .s {
936
- font-size: 14px;
937
- margin-bottom: 15px;
938
- color: #3b4750;
939
- display: block;
940
  }
941
 
942
  .pri-tb .etoc-sv {
943
- display: none;
944
- font-size: 12px;
945
- color: #fff;
946
- background: #4caf50;
947
- margin: 0 auto;
948
- padding: 1px 7px 2px 7px;
949
- border-radius: 45px
950
  }
951
 
952
  .pri-by {
953
- font-size: 15px;
954
- line-height: 1.2;
955
- background: #333;
956
- border-radius: 2px;
957
- padding: 9px 18px 10px 18px;
958
- display: inline-block;
959
- color: #fff;
960
- margin-top: 29px;
961
- font-weight: 500
962
  }
963
 
964
  .etoc-pri-lst .rec {
965
- box-shadow: 0 1px 40px 0 #ccc;
966
- background: #fff;
967
- z-index: 9;
968
- margin-top: -20px;
969
- position: relative
970
  }
971
 
972
  .etoc-pri-lst .rec:hover .etoc-rcm {
973
- background: #000;
974
- color: #fff;
975
  }
976
 
977
  .etoc-pri-lst .rec .pri-by {
978
- background: #e04371;
979
  }
980
 
981
  .etoc-rcm {
982
- background: linear-gradient(to right, #e35796, #fc789f);
983
  color: #fff;
984
- position: absolute;
985
- top: -20px;
986
- left: 0;
987
- right: -1px;
988
- bottom: auto;
989
- padding: 2px 0;
990
- font-size: 11px;
991
- letter-spacing: 2px
992
  }
993
 
994
  .tru-us {
995
- text-align: center;
996
- padding: 60px 0;
997
- margin: 0 auto;
998
- font-size: 16px;
999
- color: #222
1000
  }
1001
 
1002
  .tru-us h2 {
1003
- margin: 20px 0 0 0;
1004
- font-size: 28px;
1005
- font-weight: 500
1006
  }
1007
 
1008
  .tru-us p {
1009
- font-size: 17px;
1010
- margin: 19px 15% 18px 15%;
1011
- color: #666;
1012
- line-height: 29px
1013
  }
1014
 
1015
  .tru-us a {
1016
- font-size: 18px;
1017
- color: #489bff;
1018
- text-decoration: none;
1019
- font-weight: 400
1020
  }
1021
 
1022
  .ampfaq {
1023
- width: 100%;
1024
- margin: 25px 0
1025
  }
1026
 
1027
  .ampfaq h4 {
1028
- margin: 0;
1029
- text-align: center;
1030
- font-size: 20px;
1031
- font-weight: 500;
1032
- color: #333
1033
  }
1034
 
1035
  .faq-lst {
1036
- margin-top: 50px;
1037
- display: grid;
1038
- grid-template-columns: 1fr 1fr
1039
  }
1040
 
1041
  .lt {
1042
- padding-left: 50px
1043
  }
1044
 
1045
  .lt,
1046
  .rt {
1047
- width: 70%
1048
  }
1049
 
1050
  .lt ul,
1051
  .rt ul {
1052
- margin: 0
1053
  }
1054
 
1055
  .lt ul li,
1056
  .rt ul li {
1057
- color: #222;
1058
- margin-bottom: 30px!important
1059
  }
1060
 
1061
  .lt span,
1062
  .rt span {
1063
- font-size: 17px;
1064
- font-weight: 500;
1065
- margin-bottom: 6px;
1066
- display: inline-block
1067
  }
1068
 
1069
  .lt p,
1070
  .rt p {
1071
- font-size: 15px;
1072
- margin: 0
1073
  }
1074
 
1075
  .f-cnt {
1076
- text-align: center;
1077
- margin-top: 20px;
1078
- color: #222
1079
  }
1080
 
1081
  .f-cnt span {
1082
- font-size: 17px;
1083
- margin: 8px 0;
1084
- font-weight: 500
1085
  }
1086
 
1087
  .f-cnt p {
1088
- font-size: 15px;
1089
- margin: 6px 0
1090
  }
1091
 
1092
  .f-cnt a {
1093
- background: #333;
1094
- color: #fff;
1095
- padding: 15px 30px;
1096
- text-decoration: none;
1097
- font-size: 18px;
1098
- font-weight: 500;
1099
- display: inline-block;
1100
- margin-top: 15px
1101
- }
1102
-
1103
- @media(max-width:1366px) {
1104
- .amp-upg {
1105
- padding: 60px 0 0 0
1106
- }
1107
- .etoc-eztoc-cnt p {
 
1108
 
1109
  line-height: 35px;
1110
  font-size: 18px;
1111
 
1112
- }
1113
- }
1114
-
1115
- @media(max-width:1280px) {
1116
- .etoc-eztoc-cnt {
1117
- top: 1.3%
1118
- }
1119
- }
1120
-
1121
- @media(max-width:768px) {
1122
- .ext {
1123
- grid-template-columns: 1fr;
1124
- grid-gap: 30px 0;
1125
- padding: 30px
1126
- }
1127
- .pvf-tlt h2 {
1128
- font-size: 26px
1129
- }
1130
- .pvf-cmp {
1131
- grid-template-columns: 1fr
1132
- }
1133
- .pr-btn a {
1134
- font-size: 22px
1135
- }
1136
- .etoc-pri-lst {
1137
- grid-template-columns: 1fr 1fr 1fr
1138
- }
1139
- .etoc-eztoc-cnt p {
1140
- line-height: 1.5;
1141
- font-size: 16px;
1142
- margin-top: 15px;
1143
- padding: 0 20px
1144
- }
1145
- .etoc-eztoc-cnt .buy {
1146
- font-size: 16px;
1147
- padding: 8px 30px
1148
- }
1149
- .etoc-eztoc-cnt {
1150
- top: 15px
1151
- }
1152
- .etoc-eztoc-cnt h1 {
1153
- font-size: 30px
1154
- }
1155
- .ex-1 {
1156
- width: 100%
1157
- }
1158
- .faq-lst {
1159
- grid-template-columns: 1fr
1160
- }
1161
- .rt {
1162
- padding-left: 50px
1163
- }
1164
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1165
  div#freevspro {
1166
  padding: 0;
1167
  }
@@ -1172,18 +1261,22 @@ div#freevspro {
1172
  font-weight: 500;
1173
  text-align: center;
1174
  }
 
1175
  a#eztoc-upgrade {
1176
  color: #ffffff;
1177
  background: rgba(234, 76, 137, 1);
1178
  padding: 16px;
1179
  }
 
1180
  div#welcome {
1181
  text-align: center;
1182
  }
 
1183
  a#eztoc-welcome {
1184
  display: none;
1185
  }
1186
- .button-toc{
 
1187
  text-align: center;
1188
  cursor: pointer;
1189
  font-size: 16px;
@@ -1196,48 +1289,120 @@ a#eztoc-welcome {
1196
  transition: all 0.5s;
1197
  font-weight: 600;
1198
  }
 
1199
  .button-toc span {
1200
- cursor: pointer;
1201
- display: inline-block;
1202
- position: relative;
1203
- transition: 0.5s;
1204
  }
1205
 
1206
  .button-toc span:after {
1207
- content: '»';
1208
- position: absolute;
1209
- opacity: 0;
1210
- top: 0;
1211
- right: -20px;
1212
- transition: 0.5s;
1213
  }
1214
 
1215
  .button-toc:hover span {
1216
- padding-right: 25px;
1217
  }
1218
 
1219
  .button-toc:hover span:after {
1220
- opacity: 1;
1221
- right: 0;
1222
  }
1223
 
1224
- .eztoc-query-success{
1225
- color: green;
1226
- }
1227
- .eztoc-query-error{
1228
- color: red;
1229
- }
1230
- .eztoc_hide{
1231
- display: none;
1232
- }
1233
- .eztoc-result{
1234
- margin-left: 70px;
1235
- }
1236
-
1237
- div#wp-pointer-0{
1238
- position: absolute;
 
 
 
1239
  width: 320px;
1240
- top: 515px!important;
1241
- left: 146px!important;
1242
  z-index: 9999;
1243
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  div.tab_content table {
2
+ margin-bottom: 1em;
3
  }
4
+
5
  table.more_toc_options_table th, table.more_toc_options_table td {
6
+ padding: 0;
7
+ margin: 0;
8
  }
9
+
10
  table.more_toc_options_table th {
11
+ width: auto;
12
+ padding-right: 4px;
13
+ padding-top: 2px;
14
  }
15
+
16
  div.tab_content ul li {
17
+ margin-left: 2em;
18
+ list-style-type: disc;
19
  }
20
+
21
  div.tab_content ol li {
22
+ list-style: inherit;
23
  }
24
+
25
  div.tab_content pre {
26
+ margin-left: 2em;
27
  }
28
+
29
  ul#tabbed-nav {
30
+ margin-top: 1em;
31
  }
32
+
33
  #tabbed-nav {
34
+ margin: 0;
35
+ padding: 0;
36
+ float: left;
37
+ list-style: none;
38
+ height: 32px;
39
+ border-bottom: 1px solid #DFDFDF;
40
+ border-left: 1px solid #DFDFDF;
41
+ width: 100%;
42
  }
43
+
44
  #tabbed-nav li {
45
+ float: left;
46
+ margin: 0;
47
+ padding: 0;
48
+ height: 31px;
49
+ line-height: 31px;
50
+ border: 1px solid #DFDFDF;
51
+ border-left: none;
52
+ margin-bottom: -1px;
53
+ overflow: hidden;
54
+ position: relative;
55
+ background: #F5F5F5;
56
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#F5F5F5));
57
+ background-image: -webkit-linear-gradient(center top, #fff, #F5F5F5);
58
+ background-image: -moz-linear-gradient(center top, #fff, #F5F5F5);
59
+ background-image: -ms-linear-gradient(center top, #fff, #F5F5F5);
60
+ background-image: -o-linear-gradient(center top, #fff, #F5F5F5);
61
+ background-image: linear-gradient(center top, #fff, #F5F5F5);
62
  }
63
+
64
  #tabbed-nav li a {
65
+ text-decoration: none;
66
+ color: #000;
67
+ display: block;
68
+ font-size: 1.2em;
69
+ padding: 0 20px;
70
+ border: 1px solid #fff;
71
+ outline: none;
72
  }
73
+
74
  #tabbed-nav li a:hover {
75
+ background: #ECECEC;
76
  }
77
+
78
+ html #tabbed-nav li.active, html #tabbed-nav li.active a:hover {
79
+ background: #fff;
80
+ border-bottom: 1px solid #fff;
81
  }
82
+
83
  div.tab_container {
84
+ border: 1px solid #DFDFDF;
85
+ border-top: none;
86
+ overflow: hidden;
87
+ clear: both;
88
+ float: left;
89
+ width: 100%;
90
+ background: #fff;
91
+ margin-bottom: 2em;
92
+ padding-bottom: 2em;
93
  }
94
+
95
  div.tab_content {
96
+ padding: 10px;
97
+ padding-bottom: 0;
98
+ font-size: 1em;
99
  }
100
+
101
  h3 span.show_hide {
102
+ font-size: 0.85em;
103
+ font-weight: normal;
104
  }
105
+
106
  div.more_toc_options {
107
+ margin-top: 4px;
108
+ margin-left: 2em;
109
  }
110
+
111
  div.toc_theme_option {
112
+ width: 200px;
113
+ float: left;
114
+ margin-right: 5px;
115
  }
116
+
117
  #wpcontent select optgroup option {
118
+ padding-left: 15px;
119
  }
120
+
121
  input#width_custom,
122
  input#font_size,
123
  input#child_font_size,
124
  input#smooth_scroll_offset {
125
+ width: 50px;
126
+ text-align: center;
127
  }
128
+
129
  input.custom_colour_option {
130
+ width: 75px;
131
  }
132
+
133
  table#theme_custom, div#farbtastic_colour_wheel {
134
+ float: left;
135
  }
136
+
137
  table#theme_custom {
138
+ margin-top: 30px;
139
  }
140
+
141
  table#theme_custom img {
142
+ vertical-align: middle;
143
+ opacity: 0.4;
144
  }
145
+
146
  table#theme_custom img:hover {
147
+ cursor: pointer;
148
+ opacity: 1;
149
  }
150
+
151
  div#farbtastic_colour_wheel {
152
+ margin-left: 20px;
153
  }
154
+
155
  #tab3 h3:not(:first-child) {
156
+ margin-top: 2em;
157
  }
158
 
159
  /* My styles */
160
  #toc input.small-text {
161
+ width: 50px;
162
+ padding: 2px;
163
+ height: 28px;
164
+ line-height: 28px;
165
+ vertical-align: bottom;
166
  }
167
 
168
  #toc .form-table tr > th > strong {
169
+ font-size: 18px;
170
+ font-style: italic;
171
  }
172
+
173
  /* Tab panel styles */
174
+ .postbox {
175
+ padding: 10px;
176
  }
177
+
178
  html {
179
+ scroll-behavior: smooth;
180
  }
181
+
182
  .toc-tab-panel {
183
+ overflow: hidden;
184
+ border: 1px solid #ccc;
185
+ background-color: #fff;
186
+ margin-top: 15px;
187
+ }
188
+
189
  .toc-tab-panel a {
190
+ background-color: inherit;
191
+ text-decoration: none;
192
+ float: left;
193
+ border: none;
194
+ outline: none;
195
+ cursor: pointer;
196
+ padding: 14px 16px;
197
+ transition: 0s;
198
+ font-size: 15px;
199
+ color: #2271b1;
200
+ font-weight: 500;
201
+ }
202
+
203
  .toc-tab-panel a:hover {
204
+ color: #0a4b78;
205
+ }
206
+
207
  .toc-tab-panel a.active {
208
+ box-shadow: none;
209
+ border-bottom: 4px solid #646970;
210
+ color: #1d2327;
211
+ }
212
+
213
  .toc-tab-panel a:focus {
214
+ box-shadow: none;
215
+ outline: none;
216
  }
217
+
218
  .eztoc-tabcontent {
219
+ display: none;
220
+ border-top: none;
221
+ animation: fadeEffect 1s;
222
+ }
223
+
224
+ #technical .eztoc-form-page-ui {
225
+ display: flex;
226
+ background: #fff;
227
+ width: auto;
228
+ height: auto;
229
+ }
230
+
231
+ #technical .eztoc-left-side {
232
+ width: 70%;
233
+
 
 
 
 
 
234
  }
235
+
236
+ .eztoc-right-side {
237
+ width: 31%;
238
+ margin-top: 0;
239
+ margin-bottom: auto;
240
+ text-align: center;
241
+
242
+ }
243
+
244
  .eztoc-tabcontent {
245
+ display: none;
246
+ border-top: none;
247
+ }
248
+
249
+ #technical .eztoc-form-page-ui {
250
+ background: #fff;
251
+ margin-top: 10px;
252
+ padding: 28px;
253
+ padding: 15px 28px 28px 28px;
254
+ min-width: 255px;
255
+ box-shadow: 0 1px 1px rgb(0 0 0 / 4%);
256
+ }
257
+
258
  /* #technical p{
259
  line-height: 0.5rem;
260
  } */
261
+ #technical-form {
262
+
263
+ width: 60%;
264
+ }
265
+
266
  .support-label {
267
+ margin-top: 4px;
268
+ float: left;
269
+ width: 70px;
270
 
271
+ font-size: 14px;
272
  }
273
 
274
+ .star-mark {
275
+ color: red;
276
+ margin-left: 4px;
277
+ font-family: bold;
278
  }
279
+
280
  #technical li {
281
+ margin: 25px 0px 20px 0px;
282
+ margin: 10px 0px 10px 0px;
283
+ list-style: none;
284
+ }
285
+
286
+ .eztoc_support_div_form {
287
+ margin-top: 23px;
288
+ }
289
+
290
+ .eztoc-customer-type {
291
+ display: block;
292
+ }
293
+
294
+ .support-input select {
295
+ border-radius: 4px;
296
+ margin-top: -7px;
297
+ }
298
+
299
+ .eztoc_dev-bio {
300
+ display: block;
301
+ }
302
+
303
+ .ezoc-bio-wrap {
304
+ float: left;
305
+ text-align: center;
306
+ width: 33.33%;
307
+ text-transform: uppercase;
308
+ }
309
+
310
+ .ezoc-bio-wrap p {
311
+ width: auto;
312
+ font-size: 10px;
313
+ color: #555;
314
+ margin: 0px 0 20px 0;
315
+ }
316
+
317
+ .ezoc-bio-wrap img {
318
+ margin: 25px 0 0 0;
319
+ border-radius: 50%;
320
+ }
321
+
322
+ .eztoc-bio-box {
323
+ background: #fff;
324
+ border: 1px solid #ccc;
325
+ padding: 15px 20px;
326
+ border-radius: 4px;
327
+ margin: 15px 15px 15px 0;
328
+ /* height: 22rem; */
329
+ padding: 0px 20px;
330
+ }
331
+
332
+ .eztoc-bio-box:hover {
333
+ box-shadow: 5px 5px 8px #888888;
334
+ }
335
+
336
+ .eztoc-p {
337
+ font-size: 15px;
338
+ margin: 20px auto 0px auto;
339
+ text-align: center;
340
+ }
341
+
342
+ .eztoc-p {
343
+ line-height: 1.5rem;
344
+ padding: 0 25px;
345
+ margin-top: 10px;
346
+ font-size: 16px;
347
+ }
348
+
349
+ .eztoc-bio-box h1 {
350
+ margin: 8px auto 0px auto;
351
+ text-align: center;
352
+ font-weight: bolder;
353
+ }
354
+
355
+ .eztoc_boxdesk {
356
+ clear: left;
357
+ font-size: 15px;
358
+ text-align: center;
359
+ margin: 20px 0 0 0;
360
+
361
+ }
362
+
363
+ .company-link {
364
+ font-weight: 500;
365
+ margin: 20px 0 0 0;
366
+ }
367
+
368
+ .company-link a {
369
+
370
  display: table;
371
  background: #e91e63;
372
  width: auto;
375
  color: #fff;
376
  text-decoration: none;
377
  margin-top: 10px;
378
+ margin-bottom: 15px;
379
  border-radius: 6px;
380
  border: 0;
381
  /* text-transform: uppercase; */
382
  font-size: 16px;
383
 
384
  }
385
+
386
+ .eztoc-send-query {
387
+ background: #2271b1;
388
  border-color: #2271b1;
389
+ color: #fff;
390
  text-decoration: none;
391
  text-shadow: none;
392
+ margin-left: 70px !important;;
393
+ }
394
+
395
+ @media screen and (min-width: 870px) and (max-width: 1300px ) {
396
+ .eztoc-bio-box {
397
+ padding-top: 20px;
398
+ height: 29.1rem;;
399
+ }
400
+
401
+ .eztoc-bio-box h1 {
402
+ font-size: 20px;
403
+ }
404
+
405
+ .eztoc-bio-box p {
406
+ font-size: 13px;
407
+ margin: 20px auto 0px auto;
408
+ }
409
+
410
+ .ezoc-bio-wrap img {
411
+ width: 30px;
412
+ height: 30px;
413
+ }
414
+
415
+ .ezoc-bio-wrap p {
416
+ width: 55px;
417
+ font-size: 12px;
418
+ margin-bottom: 10px;
419
+ }
420
+
421
+ }
422
+
423
+ @keyframes fadeEffect {
424
+ from {
425
+ opacity: 0;
426
+ }
427
+ to {
428
+ opacity: 1;
429
+ }
430
+ }
431
+
432
+
433
+ .eztoc-wrapper {
434
  max-width: 100%;
435
  width: 100%;
436
  display: flex;
438
  margin: auto;
439
  }
440
 
441
+ .eztoc-wrapper .table {
442
  margin: 0 auto;
443
  background: #fff;
444
  width: calc(30%);
447
  box-shadow: 0 5px 10px rgb(0 0 0 / 10%);
448
  }
449
 
450
+ .table .price-section {
451
+ display: flex;
452
+ justify-content: center;
453
  }
454
 
455
+ .price-section .price-area {
456
  height: 120px;
457
  width: 120px;
458
  background: #ffd861;
460
  padding: 2px;
461
  }
462
 
463
+ .price-section .price-area .inner-area {
464
  height: 100%;
465
  width: 100%;
466
  border-radius: 50%;
471
  position: relative;
472
  }
473
 
474
+ .price-area .inner-area .text {
475
  font-size: 25px;
476
  font-weight: 400;
477
  position: absolute;
479
  left: 17px;
480
  }
481
 
482
+ .price-area .inner-area .price {
483
  font-size: 55px;
484
  font-weight: 500;
485
  }
486
 
487
+ .table .package-name {
488
  width: 100%;
489
  height: 2px;
490
  background: #ffecb3;
492
  position: relative;
493
  }
494
 
495
+ .table .package-name::before {
496
  position: absolute;
497
  content: "Basic";
498
  top: 50%;
504
  font-weight: bolder;
505
  }
506
 
507
+ .table .features li {
508
  list-style: none;
509
  display: flex;
510
  justify-content: space-between;
511
  margin-bottom: 15px;
512
  }
513
 
514
+ .features li .list-name {
515
  font-size: 17px;
516
  font-weight: 400;
517
  }
518
 
519
+ .features li .icon {
520
  font-size: 15px;
521
  }
522
 
523
+ .features li .icon.check {
524
  color: #2db94d;
525
  }
526
 
527
+ .features li .icon.cross {
528
  color: #cd3241;
529
  }
530
 
531
+ .table .btn {
532
  display: flex;
533
  justify-content: center;
534
  margin-top: 35px;
535
  }
536
 
537
+ .table .btn button {
538
  width: 80%;
539
  height: 50px;
540
  font-weight: 700;
548
  }
549
 
550
  .basic .price-area,
551
+ .basic .inner-area {
552
  background: #ffd861;
553
  }
554
 
555
+ .basic .btn button {
556
  background: #fff;
557
  color: #ffd861;
558
  border: 2px solid #ffd861;
559
  }
560
 
561
+ .basic .btn button:hover {
562
  border-radius: 6px;
563
  background: #ffd861;
564
  color: #fff;
565
  }
566
 
567
  .Premium .price-area,
568
+ .Premium .inner-area {
569
  background: #a26bfa;
570
  }
571
 
572
+ .Premium .btn button {
573
  background: #fff;
574
  color: #a26bfa;
575
  border: 2px solid #a26bfa;
576
  }
577
 
578
+ .Premium .btn button:hover {
579
  border-radius: 6px;
580
  background: #a26bfa;
581
  color: #fff;
582
  }
 
583
 
584
+
585
+ .basic .package-name {
586
  background: #ffecb3;
587
  }
588
 
589
+ .Premium .package-name {
590
  background: #a26bfa;
591
  }
592
 
 
593
 
594
+ .basic .package-name::before {
595
  content: "Free";
596
  }
597
 
598
+ .Premium .package-name::before {
599
  content: "PRO";
600
  }
601
 
 
602
 
603
  .basic ::selection,
604
  .basic .price-area,
605
+ .basic .inner-area {
606
  background: #ffd861;
607
  }
608
 
609
  .Premium ::selection,
610
  .Premium .price-area,
611
+ .Premium .inner-area {
612
  background: #a26bfa;
613
  }
614
 
615
  div#eztoc-tabs a {
616
  text-decoration: none;
617
+ }
618
+
619
  div#eztoc-tabs a:first-child {
620
  color: #000;
621
  }
622
 
623
+ #the-list {
624
+ position: relative;
625
+ }
626
+
627
  .eztoc-wr {
628
+ width: 100%;
629
+ margin: 0 auto;
630
+ position: relative
631
  }
632
 
633
  .etoc-eztoc-img {
634
+ width: 100%;
635
+ margin: 0 auto;
636
+ text-align: center;
637
+ position: relative;
638
+ line-height: 0;
639
+ height: 300px;
640
  }
641
 
642
  .eztoc-img img {
643
+ position: relative
644
  }
645
 
646
  .sp_ov {
647
+ background: rgba(234, 76, 137, 1);
648
+ bottom: 0;
649
+ left: 0;
650
+ position: absolute;
651
+ right: 0;
652
+ top: 0;
653
  }
654
 
655
  .etoc-eztoc-cnt {
656
+ position: absolute;
657
+ top: 40px;
658
+ bottom: 0;
659
+ left: 40px;
660
+ right: 40px;
661
+ margin: 0 auto;
662
+ text-align: center
663
  }
664
 
665
  .etoc-eztoc-cnt h1 {
669
  }
670
 
671
  .etoc-eztoc-cnt p {
672
+ margin-top: 0px;
673
  color: #371b24;
674
  font-size: 18px;
675
  padding: 0 100px;
678
  }
679
 
680
  .etoc-eztoc-cnt .buy {
681
+ border-width: 0px !important;
682
+ font-size: 1.25rem;
683
+ line-height: 2;
684
+ text-decoration: none;
685
+ background: white !important;
686
  border-radius: 8px !important;
687
  font-size: 16px !important;
688
  padding: 12px 18px;
689
  color: rgba(234, 76, 137, 1) !important;
690
  font-weight: 500;
691
  }
692
+
693
+ .etoc-eztoc-cnt .buy:hover {
694
+ box-shadow: 0px 2px 2px #999;
695
+ background: linear-gradient(to left, #fdfc35, #ffe258) !important;
696
  }
697
+
698
  .pvf {
699
+ position: relative;
700
+ top: -16px;
701
+ border: 1px solid #eee;
702
+ padding-bottom: 40px
703
  }
704
 
705
  .ext {
706
+ display: grid;
707
+ grid-template-columns: 1fr 1fr 1fr;
708
+ background: #f9f9f9;
709
+ padding: 45px 0 45px 25px
710
  }
711
 
712
  .ex-1 {
713
+ width: 80%;
714
  }
715
 
716
  .ex-1 h4 {
717
+ margin: 15px 0 12px 0;
718
+ font-weight: 600;
719
+ font-size: 20px;
720
  color: rgba(234, 76, 137, 1);
721
  }
722
 
723
  .ex-1 p {
724
+ font-size: 14px;
725
+ font-weight: 400;
726
+ margin: 0;
727
  color: #000;
728
  }
729
 
730
  .e-1 img {
731
+ width: 65px !important
732
  }
733
 
734
  .e-2 img {
735
+ width: 45px !important
736
  }
737
 
738
  .e-3 img {
739
+ width: 49px !important
740
  }
741
 
742
  .pvf-cnt {
743
+ width: 100%;
744
+ display: inline-block
745
  }
746
 
747
  .pvf-tlt {
748
+ text-align: center;
749
+ width: 100%;
750
+ margin: 70px 0 60px 0
751
  }
752
 
753
  .pvf-tlt h2 {
754
+ font-size: 36px;
755
+ line-height: 1.4;
756
+ color: #000;
757
+ font-weight: 500;
758
+ margin: 0
759
  }
760
 
761
  .pvf-tlt span {
762
+ font-size: 16px;
763
+ color: #000;
764
+ margin-top: 15px;
765
+ display: inline-block;
766
+ position: relative;
767
+ top: 4px
768
  }
769
 
770
  .pvf-cmp {
771
+ display: grid;
772
+ grid-template-columns: 1fr 2fr
773
  }
774
 
775
  .fr {
776
+ border-right: 1px solid #eee
777
  }
778
 
779
  .fr h1,
780
  .pr h1 {
781
+ font-size: 36px;
782
+ font-weight: 700;
783
+ line-height: 1.5;
784
+ border-bottom: 1px solid #efefef;
785
+ padding: 0 0 20px 35px;
786
  }
787
 
788
  .pr h1 {
789
+ padding-left: 50px;
790
+ color: rgba(234, 76, 137, 1);
791
  }
792
 
793
  .fr-fe {
794
+ color: #222;
795
+ padding-top: 10px
796
  }
797
 
798
  .fe-1 {
799
+ padding: 22px 35px 35px 35px
800
  }
801
 
802
  .fe-1 h4 {
803
+ margin: 0 0 10px 0;
804
+ font-size: 20px;
805
+ line-height: 1.4;
806
+ font-weight: 400;
807
+ color: #000
808
  }
809
 
810
  .fe-1 p {
811
+ font-size: 15px;
812
+ line-height: 1.4;
813
+ margin: 0;
814
+ color: #333
815
  }
816
 
817
  .pr-fe {
818
+ padding: 34px 35px 35px 35px
819
  }
820
 
821
  .pr-fe span {
822
+ font-family: georgia;
823
+ font-size: 16px;
824
+ font-weight: 700;
825
+ color: #000;
826
+ font-style: italic;
827
+ line-height: 1.3
828
  }
829
 
830
  .fet {
831
+ width: 100%;
832
+ display: grid;
833
+ grid-template-columns: 1fr 1fr;
834
+ grid-gap: 25px;
835
+ margin-top: 40px
836
  }
837
 
838
  .fe-2 {
839
+ color: #222
840
  }
841
 
842
  .fe-t img {
843
+ width: 22px !important;
844
+ display: inline-block;
845
+ vertical-align: middle
846
  }
847
 
848
  .fe-t h4 {
849
+ margin: 0;
850
+ display: inline-block;
851
+ vertical-align: middle;
852
+ font-size: 19px;
853
+ color: #000;
854
+ font-weight: 400;
855
+ line-height: 1.4;
856
+ padding-left: 8px;
857
+ margin-top: -5px;
858
  }
859
 
860
  .fe-2 p {
861
+ font-size: 15px;
862
+ line-height: 1.4;
863
+ margin: 0;
864
+ color: #555;
865
+ padding-top: 8px
866
  }
867
 
868
  .pr-btn {
869
+ width: 100%;
870
+ display: inline-block;
871
+ text-align: center;
872
+ margin: 50px 0 25px 0
873
  }
874
 
875
  .pr-btn a {
876
+ text-decoration: none;
877
+ color: #fff;
878
+ padding: 12px 35px 17px 35px;
879
+ display: inline-block;
880
+ border-radius: 5px;
881
+ font-size: 28px;
882
+ font-weight: 500;
883
+ line-height: 1.2;
884
+ background: -webkit-linear-gradient(to right, #e35796, #fc789f);
885
+ font-weight: 600;
886
+ background: linear-gradient(to right, #e35796, rgba(234, 76, 137, 1));
887
+ margin-top: 0;
888
+ box-shadow: 0 .15em .65em 0 rgba(0, 0, 0, .25);
889
  }
890
 
891
  .amp-upg {
892
+ background: #f5f5f5;
893
+ padding: 60px 10px 0 10px
894
  }
895
 
896
  .upg-t {
897
+ text-align: center;
898
+ color: #222
899
  }
900
 
901
  .upg-t h2 {
902
+ margin: 0;
903
+ font-size: 35px;
904
+ color: #060606;
905
+ line-height: 1.3;
906
+ font-weight: 500
907
  }
908
 
909
+ .upg-t > span {
910
+ font-size: 14px;
911
+ line-height: 1.2;
912
+ margin-top: 15px;
913
+ display: inline-block;
914
+ color: #666
915
  }
916
 
917
  .etoc-pri-lst {
918
+ width: 100%;
919
+ display: grid;
920
+ grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
921
+ margin-top: 70px;
922
+ grid-gap: 1px;
923
+ box-shadow: 0 10px 15px 1px #ddd
924
  }
925
 
926
  .pri-tb {
927
+ background: #fff;
928
+ text-align: center;
929
+ border: 1px solid #f9f9f9;
930
+ position: relative
931
  }
932
 
933
  .pri-tb:hover {
934
+ border: 1px solid #e04371;
935
  }
936
 
937
  .pri-tb a:hover .pri-by {
938
+ background: #e04371;
939
  }
940
+
941
  .pri-tb a:hover .amt {
942
+ color: #7241a7;
943
  }
944
 
945
  .pri-tb a {
946
+ display: inline-block;
947
+ text-decoration: none;
948
+ color: #222;
949
+ padding: 20px 12px;
950
  }
951
 
952
  .pri-tb h5 {
953
+ margin: 0 0 20px 0;
954
+ font-size: 13px;
955
+ line-height: 1.2;
956
+ letter-spacing: 2px;
957
+ font-weight: 400;
958
+ color: #000
959
  }
960
 
961
  .pri-tb span {
962
+ display: inline-block
963
  }
964
 
965
  .pri-tb .amt {
966
+ font-size: 40px;
967
+ color: #e04371;
968
+ font-weight: 500;
969
+ margin-bottom: 20px;
970
+ display: block;
971
  }
972
 
973
  .pri-tb .d-amt {
974
+ font-size: 24px;
975
+ color: #666;
976
+ font-weight: 500;
977
+ margin-bottom: 15px;
978
+ display: none;
979
+ text-decoration: line-through
980
  }
981
 
982
  .d-amt sup {
983
+ line-height: 0;
984
+ position: relative;
985
+ top: 7px
986
  }
987
 
988
  .pri-tb .s-amt {
989
+ font-size: 13px;
990
+ color: #4caf50;
991
+ font-weight: 500;
992
+ margin-bottom: 10px;
993
+ display: none
994
  }
995
 
996
  .pri-tb .amt sup {
997
+ font-size: 22px;
998
+ padding: 0 4px 0 0;
999
+ position: relative;
1000
+ top: 7px
1001
  }
1002
 
1003
  .pri-tb .bil {
1004
+ color: #aaa;
1005
+ font-size: 12px;
1006
+ margin-bottom: 20px
1007
  }
1008
 
1009
  .pri-tb .e,
1010
  .pri-tb .f,
1011
  .pri-tb .s {
1012
+ font-size: 14px;
1013
+ margin-bottom: 15px;
1014
+ color: #3b4750;
1015
+ display: block;
1016
  }
1017
 
1018
  .pri-tb .etoc-sv {
1019
+ display: none;
1020
+ font-size: 12px;
1021
+ color: #fff;
1022
+ background: #4caf50;
1023
+ margin: 0 auto;
1024
+ padding: 1px 7px 2px 7px;
1025
+ border-radius: 45px
1026
  }
1027
 
1028
  .pri-by {
1029
+ font-size: 15px;
1030
+ line-height: 1.2;
1031
+ background: #333;
1032
+ border-radius: 2px;
1033
+ padding: 9px 18px 10px 18px;
1034
+ display: inline-block;
1035
+ color: #fff;
1036
+ margin-top: 29px;
1037
+ font-weight: 500
1038
  }
1039
 
1040
  .etoc-pri-lst .rec {
1041
+ box-shadow: 0 1px 40px 0 #ccc;
1042
+ background: #fff;
1043
+ z-index: 9;
1044
+ margin-top: -20px;
1045
+ position: relative
1046
  }
1047
 
1048
  .etoc-pri-lst .rec:hover .etoc-rcm {
1049
+ background: #000;
1050
+ color: #fff;
1051
  }
1052
 
1053
  .etoc-pri-lst .rec .pri-by {
1054
+ background: #e04371;
1055
  }
1056
 
1057
  .etoc-rcm {
1058
+ background: linear-gradient(to right, #e35796, #fc789f);
1059
  color: #fff;
1060
+ position: absolute;
1061
+ top: -20px;
1062
+ left: 0;
1063
+ right: -1px;
1064
+ bottom: auto;
1065
+ padding: 2px 0;
1066
+ font-size: 11px;
1067
+ letter-spacing: 2px
1068
  }
1069
 
1070
  .tru-us {
1071
+ text-align: center;
1072
+ padding: 60px 0;
1073
+ margin: 0 auto;
1074
+ font-size: 16px;
1075
+ color: #222
1076
  }
1077
 
1078
  .tru-us h2 {
1079
+ margin: 20px 0 0 0;
1080
+ font-size: 28px;
1081
+ font-weight: 500
1082
  }
1083
 
1084
  .tru-us p {
1085
+ font-size: 17px;
1086
+ margin: 19px 15% 18px 15%;
1087
+ color: #666;
1088
+ line-height: 29px
1089
  }
1090
 
1091
  .tru-us a {
1092
+ font-size: 18px;
1093
+ color: #489bff;
1094
+ text-decoration: none;
1095
+ font-weight: 400
1096
  }
1097
 
1098
  .ampfaq {
1099
+ width: 100%;
1100
+ margin: 25px 0
1101
  }
1102
 
1103
  .ampfaq h4 {
1104
+ margin: 0;
1105
+ text-align: center;
1106
+ font-size: 20px;
1107
+ font-weight: 500;
1108
+ color: #333
1109
  }
1110
 
1111
  .faq-lst {
1112
+ margin-top: 50px;
1113
+ display: grid;
1114
+ grid-template-columns: 1fr 1fr
1115
  }
1116
 
1117
  .lt {
1118
+ padding-left: 50px
1119
  }
1120
 
1121
  .lt,
1122
  .rt {
1123
+ width: 70%
1124
  }
1125
 
1126
  .lt ul,
1127
  .rt ul {
1128
+ margin: 0
1129
  }
1130
 
1131
  .lt ul li,
1132
  .rt ul li {
1133
+ color: #222;
1134
+ margin-bottom: 30px !important
1135
  }
1136
 
1137
  .lt span,
1138
  .rt span {
1139
+ font-size: 17px;
1140
+ font-weight: 500;
1141
+ margin-bottom: 6px;
1142
+ display: inline-block
1143
  }
1144
 
1145
  .lt p,
1146
  .rt p {
1147
+ font-size: 15px;
1148
+ margin: 0
1149
  }
1150
 
1151
  .f-cnt {
1152
+ text-align: center;
1153
+ margin-top: 20px;
1154
+ color: #222
1155
  }
1156
 
1157
  .f-cnt span {
1158
+ font-size: 17px;
1159
+ margin: 8px 0;
1160
+ font-weight: 500
1161
  }
1162
 
1163
  .f-cnt p {
1164
+ font-size: 15px;
1165
+ margin: 6px 0
1166
  }
1167
 
1168
  .f-cnt a {
1169
+ background: #333;
1170
+ color: #fff;
1171
+ padding: 15px 30px;
1172
+ text-decoration: none;
1173
+ font-size: 18px;
1174
+ font-weight: 500;
1175
+ display: inline-block;
1176
+ margin-top: 15px
1177
+ }
1178
+
1179
+ @media (max-width: 1366px) {
1180
+ .amp-upg {
1181
+ padding: 60px 0 0 0
1182
+ }
1183
+
1184
+ .etoc-eztoc-cnt p {
1185
 
1186
  line-height: 35px;
1187
  font-size: 18px;
1188
 
1189
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1190
  }
1191
+
1192
+ @media (max-width: 1280px) {
1193
+ .etoc-eztoc-cnt {
1194
+ top: 1.3%
1195
+ }
1196
+ }
1197
+
1198
+ @media (max-width: 768px) {
1199
+ .ext {
1200
+ grid-template-columns: 1fr;
1201
+ grid-gap: 30px 0;
1202
+ padding: 30px
1203
+ }
1204
+
1205
+ .pvf-tlt h2 {
1206
+ font-size: 26px
1207
+ }
1208
+
1209
+ .pvf-cmp {
1210
+ grid-template-columns: 1fr
1211
+ }
1212
+
1213
+ .pr-btn a {
1214
+ font-size: 22px
1215
+ }
1216
+
1217
+ .etoc-pri-lst {
1218
+ grid-template-columns: 1fr 1fr 1fr
1219
+ }
1220
+
1221
+ .etoc-eztoc-cnt p {
1222
+ line-height: 1.5;
1223
+ font-size: 16px;
1224
+ margin-top: 15px;
1225
+ padding: 0 20px
1226
+ }
1227
+
1228
+ .etoc-eztoc-cnt .buy {
1229
+ font-size: 16px;
1230
+ padding: 8px 30px
1231
+ }
1232
+
1233
+ .etoc-eztoc-cnt {
1234
+ top: 15px
1235
+ }
1236
+
1237
+ .etoc-eztoc-cnt h1 {
1238
+ font-size: 30px
1239
+ }
1240
+
1241
+ .ex-1 {
1242
+ width: 100%
1243
+ }
1244
+
1245
+ .faq-lst {
1246
+ grid-template-columns: 1fr
1247
+ }
1248
+
1249
+ .rt {
1250
+ padding-left: 50px
1251
+ }
1252
+ }
1253
+
1254
  div#freevspro {
1255
  padding: 0;
1256
  }
1261
  font-weight: 500;
1262
  text-align: center;
1263
  }
1264
+
1265
  a#eztoc-upgrade {
1266
  color: #ffffff;
1267
  background: rgba(234, 76, 137, 1);
1268
  padding: 16px;
1269
  }
1270
+
1271
  div#welcome {
1272
  text-align: center;
1273
  }
1274
+
1275
  a#eztoc-welcome {
1276
  display: none;
1277
  }
1278
+
1279
+ .button-toc {
1280
  text-align: center;
1281
  cursor: pointer;
1282
  font-size: 16px;
1289
  transition: all 0.5s;
1290
  font-weight: 600;
1291
  }
1292
+
1293
  .button-toc span {
1294
+ cursor: pointer;
1295
+ display: inline-block;
1296
+ position: relative;
1297
+ transition: 0.5s;
1298
  }
1299
 
1300
  .button-toc span:after {
1301
+ content: '»';
1302
+ position: absolute;
1303
+ opacity: 0;
1304
+ top: 0;
1305
+ right: -20px;
1306
+ transition: 0.5s;
1307
  }
1308
 
1309
  .button-toc:hover span {
1310
+ padding-right: 25px;
1311
  }
1312
 
1313
  .button-toc:hover span:after {
1314
+ opacity: 1;
1315
+ right: 0;
1316
  }
1317
 
1318
+ .eztoc-query-success {
1319
+ color: green;
1320
+ }
1321
+
1322
+ .eztoc-query-error {
1323
+ color: red;
1324
+ }
1325
+
1326
+ .eztoc_hide {
1327
+ display: none;
1328
+ }
1329
+
1330
+ .eztoc-result {
1331
+ margin-left: 70px;
1332
+ }
1333
+
1334
+ div#wp-pointer-0 {
1335
+ position: absolute;
1336
  width: 320px;
1337
+ top: 515px !important;
1338
+ left: 146px !important;
1339
  z-index: 9999;
1340
+ }
1341
+
1342
+ /**
1343
+ * Clipboard CSS
1344
+ * @since 2.0.33
1345
+ */
1346
+ .ez-toc-tooltip {
1347
+ position: relative;
1348
+ display: inline-block;
1349
+ }
1350
+
1351
+ .ez-toc-tooltip .ez-toc-tooltiptext {
1352
+ visibility: hidden;
1353
+ width: 140px;
1354
+ background-color: #555;
1355
+ color: #fff;
1356
+ text-align: center;
1357
+ border-radius: 6px;
1358
+ padding: 5px;
1359
+ position: absolute;
1360
+ z-index: 1;
1361
+ bottom: 150%;
1362
+ left: 50%;
1363
+ margin-left: -75px;
1364
+ opacity: 0;
1365
+ transition: opacity 0.3s;
1366
+ }
1367
+
1368
+ .ez-toc-tooltip .ez-toc-tooltiptext::after {
1369
+ content: "";
1370
+ position: absolute;
1371
+ top: 100%;
1372
+ left: 50%;
1373
+ margin-left: -5px;
1374
+ border-width: 5px;
1375
+ border-style: solid;
1376
+ border-color: #555 transparent transparent transparent;
1377
+ }
1378
+
1379
+ .ez-toc-tooltip:hover .ez-toc-tooltiptext {
1380
+ visibility: visible;
1381
+ opacity: 1;
1382
+ }
1383
+
1384
+ #eztoc-tabs-technical {
1385
+ margin-top: 10px;
1386
+ }
1387
+
1388
+ #eztoc-tabs-technical a.eztoc-tablinks-technical, #eztoc-tabs-technical a:first-child.eztoc-tablinks-technical {
1389
+ color: #000000;
1390
+ text-decoration: none;
1391
+ }
1392
+
1393
+ #eztoc-tabs-technical a.eztoc-tablinks-technical.active {
1394
+ color: #ea4c89;
1395
+ }
1396
+
1397
+ .ez-toc-pull-technical-img {
1398
+ float: left !important;
1399
+ margin-right: 10px;
1400
+ width: 100%;
1401
+ }
1402
+ .eztoc-tabcontent-technical p.ez-toc-tabcontent-technical-title-content {
1403
+ margin-top: -5px;
1404
+ }
1405
+
1406
+ #eztoc-technical-how-to-use li{
1407
+ list-style: auto !important;
1408
+ }
assets/css/admin.min.css CHANGED
@@ -1,8 +1 @@
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;}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;}#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);}#tabbed-nav li a {text-decoration: none;color: #000;display: block;font-size: 1.2em;padding: 0 20px;border: 1px solid #fff;outline: none;}#tabbed-nav li a:hover {background: #ECECEC;}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: none;overflow: hidden;clear: both;float: left;width: 100%;background: #fff;margin-bottom: 2em;padding-bottom: 2em;}div.tab_content {padding: 10px;padding-bottom: 0;font-size: 1em;}h3 span.show_hide {font-size: 0.85em;font-weight: normal;}div.more_toc_options {margin-top: 4px;margin-left: 2em;}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#child_font_size, input#smooth_scroll_offset {width: 50px;text-align: center;}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: 0.4;}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;}#toc .form-table tr > th > strong {font-size: 18px;font-style: italic;}.postbox{padding: 10px;}html {scroll-behavior: smooth;}.toc-tab-panel {overflow: hidden;border: 1px solid #ccc;background-color: #fff;margin-top: 15px;}.toc-tab-panel a {background-color: inherit;text-decoration: none;float: left;border: none;outline: none;cursor: pointer;padding: 14px 16px;transition: 0s;font-size: 15px;color: #2271b1;font-weight: 500;}.toc-tab-panel a:hover {color: #0a4b78;}.toc-tab-panel a.active {box-shadow: none;border-bottom: 4px solid #646970;color: #1d2327;}.toc-tab-panel a:focus {box-shadow: none;outline: none;}.eztoc-tabcontent {display: none;border-top: none;animation: fadeEffect 1s;}.eztoc_support_div {background: #fff;margin-top: 10px;padding: 28px;min-width: 255px;border: 1px solid #c3c4c7;box-shadow: 0 1px 1px rgb(0 0 0 / 4%);}.support-label {float: left;width: 70px;font-size: 14px;}.star-mark{color: red;margin-left: 4px;font-family:bold;}.eztoc_support_div li {margin:25px 0px 20px 0px;}.eztoc-query-success{color: green;}.eztoc-query-error{color: red;}.eztoc_hide{display: none;}.eztoc-result{margin-left: 70px;}.eztoc-send-query{margin-left: 70px !important;;}@keyframes fadeEffect {from {opacity: 0;}to {opacity: 1;}}.eztoc-wrapper{max-width: 1090px;width: 100%;display: flex;flex-wrap: wrap;margin: auto;}.eztoc-wrapper .table{margin: 0 auto;background: #fff;width: calc(30%);padding: 30px 20px;position: relative;box-shadow: 0 5px 10px rgb(0 0 0 / 10%);}.table .price-section{display: flex;justify-content: center;}.price-section .price-area{height: 120px;width: 120px;background: #ffd861;border-radius: 50%;padding: 2px;}.price-section .price-area .inner-area{height: 100%;width: 100%;border-radius: 50%;border: 3px solid #fff;color: #fff;line-height: 117px;text-align: center;position: relative;}.price-area .inner-area .text{font-size: 25px;font-weight: 400;position: absolute;top: -10px;left: 17px;}.price-area .inner-area .price{font-size: 55px;font-weight: 500;}.table .package-name{width: 100%;height: 2px;background: #ffecb3;margin: 35px 0;position: relative;}.table .package-name::before{position: absolute;content: "Basic";top: 50%;left: 50%;transform: translate(-50%, -50%);background: #fff;font-size: 25px;padding: 0 10px;font-weight: bolder;}.table .features li{list-style: none;display: flex;justify-content: space-between;margin-bottom: 15px;}.features li .list-name{font-size: 17px;font-weight: 400;}.features li .icon{font-size: 15px;}.features li .icon.check{color: #2db94d;}.features li .icon.cross{color: #cd3241;}.table .btn{display: flex;justify-content: center;margin-top: 35px;}.table .btn button{width: 80%;height: 50px;font-weight: 700;color: #fff;font-size: 20px;border: none;outline: none;border-radius: 25px;cursor: pointer;transition: all 0.3s ease;}.basic .price-area, .basic .inner-area{background: #ffd861;}.basic .btn button{background: #fff;color: #ffd861;border: 2px solid #ffd861;}.basic .btn button:hover{border-radius: 6px;background: #ffd861;color: #fff;}.Premium .price-area, .Premium .inner-area{background: #a26bfa;}.Premium .btn button{background: #fff;color: #a26bfa;border: 2px solid #a26bfa;}.Premium .btn button:hover{border-radius: 6px;background: #a26bfa;color: #fff;}.basic .package-name{background: #ffecb3;}.Premium .package-name{background: #a26bfa;}.basic .package-name::before{content: "Free";}.Premium .package-name::before{content: "PRO";}.basic ::selection, .basic .price-area, .basic .inner-area{background: #ffd861;}.Premium ::selection, .Premium .price-area, .Premium .inner-area{background: #a26bfa;}div#eztoc-tabs a {text-decoration: none;}div#eztoc-tabs a:first-child {color: #000;}a#eztoc-upgrade {color: #b8ef0e;background: #000;padding: 16px;}
2
- div#wp-pointer-0{
3
- position: absolute;
4
- width: 320px;
5
- top: 630px!important;
6
- left: 146px!important;
7
- z-index: 9999;
8
- }
1
+ #tabbed-nav li,div.tab_container{border:1px solid #dfdfdf;overflow:hidden;float:left}.fe-t h4,.fe-t img{vertical-align:middle}.etoc-eztoc-cnt,.etoc-eztoc-img,.ezoc-bio-wrap,.eztoc-bio-box h1,.eztoc-p,.eztoc-right-side,.eztoc_boxdesk,.pr-btn,.pri-tb,.price-section .price-area .inner-area,.pvf-tlt,.upg-t{text-align:center}#tabbed-nav li a,.company-link a,.etoc-eztoc-cnt .buy,.eztoc-send-query,.f-cnt a,.pr-btn a,.pri-tb a,.toc-tab-panel a,.tru-us a,div#eztoc-tabs a{text-decoration:none}div.tab_content table{margin-bottom:1em}#tabbed-nav,table.more_toc_options_table td,table.more_toc_options_table th{margin:0;padding:0}table.more_toc_options_table th{width:auto;padding-right:4px;padding-top:2px}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}#tabbed-nav{float:left;list-style:none;height:32px;border-bottom:1px solid #dfdfdf;border-left:1px solid #dfdfdf;width:100%}#tabbed-nav li{margin:0 0 -1px;padding:0;height:31px;line-height:31px;border-left:none;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)}#tabbed-nav li a{color:#000;display:block;font-size:1.2em;padding:0 20px;border:1px solid #fff;outline:0}#tabbed-nav li a:hover{background:#ececec}html #tabbed-nav li.active,html #tabbed-nav li.active a:hover{background:#fff;border-bottom:1px solid #fff}div.tab_container{border-top:none;clear:both;width:100%;background:#fff;margin-bottom:2em;padding-bottom:2em}div.tab_content{padding:10px 10px 0;font-size:1em}h3 span.show_hide{font-size:.85em;font-weight:400}div.more_toc_options{margin-top:4px;margin-left:2em}div.toc_theme_option{width:200px;float:left;margin-right:5px}#wpcontent select optgroup option{padding-left:15px}input#child_font_size,input#font_size,input#smooth_scroll_offset,input#width_custom{width:50px;text-align:center}input.custom_colour_option{width:75px}div#farbtastic_colour_wheel,table#theme_custom{float:left}table#theme_custom{margin-top:30px}table#theme_custom img{vertical-align:middle;opacity:.4}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}#toc .form-table tr>th>strong{font-size:18px;font-style:italic}.postbox{padding:10px}html{scroll-behavior:smooth}.toc-tab-panel{overflow:hidden;border:1px solid #ccc;background-color:#fff;margin-top:15px}.toc-tab-panel a{background-color:inherit;float:left;border:none;outline:0;cursor:pointer;padding:14px 16px;transition:none;font-size:15px;color:#2271b1;font-weight:500}.toc-tab-panel a:hover{color:#0a4b78}.toc-tab-panel a.active{box-shadow:none;border-bottom:4px solid #646970;color:#1d2327}.toc-tab-panel a:focus{box-shadow:none;outline:0}.eztoc-tabcontent{animation:1s fadeEffect;display:none;border-top:none}#technical .eztoc-form-page-ui{display:flex;width:auto;height:auto;background:#fff;margin-top:10px;padding:15px 28px 28px;min-width:255px;box-shadow:0 1px 1px rgb(0 0 0 / 4%)}#technical .eztoc-left-side,.lt,.rt{width:70%}.eztoc-right-side{width:31%;margin-top:0;margin-bottom:auto}#technical-form{width:60%}.support-label{margin-top:4px;float:left;width:70px;font-size:14px}.star-mark{color:red;margin-left:4px;font-family:bold}#technical li{margin:10px 0;list-style:none}.eztoc_support_div_form{margin-top:23px}.eztoc-customer-type,.eztoc_dev-bio{display:block}.support-input select{border-radius:4px;margin-top:-7px}.ezoc-bio-wrap{float:left;width:33.33%;text-transform:uppercase}.ezoc-bio-wrap p{width:auto;font-size:10px;color:#555;margin:0 0 20px}.ezoc-bio-wrap img{margin:25px 0 0;border-radius:50%}.eztoc-bio-box{background:#fff;border:1px solid #ccc;padding:0 20px;border-radius:4px;margin:15px 15px 15px 0}.eztoc-bio-box:hover{box-shadow:5px 5px 8px #888}.eztoc-p{margin:10px auto 0;line-height:1.5rem;padding:0 25px;font-size:16px}.eztoc-bio-box h1{margin:8px auto 0;font-weight:bolder}.eztoc_boxdesk{clear:left;font-size:15px;margin:20px 0 0}.company-link{font-weight:500;margin:20px 0 0}.company-link a{display:table;background:#e91e63;width:auto;margin:10px auto 15px;padding:7px 25px;color:#fff;border-radius:6px;border:0;font-size:16px}.eztoc-send-query{background:#2271b1;border-color:#2271b1;color:#fff;text-shadow:none;margin-left:70px!important}.fe-2,.fr-fe,.upg-t{color:#222}@media screen and (min-width:870px) and (max-width:1300px){.eztoc-bio-box{padding-top:20px;height:29.1rem}.eztoc-bio-box h1{font-size:20px}.eztoc-bio-box p{font-size:13px;margin:20px auto 0}.ezoc-bio-wrap img{width:30px;height:30px}.ezoc-bio-wrap p{width:55px;font-size:12px;margin-bottom:10px}}@keyframes fadeEffect{from{opacity:0}to{opacity:1}}.eztoc-wrapper{max-width:100%;width:100%;display:flex;flex-wrap:wrap;margin:auto}.eztoc-wrapper .table{margin:0 auto;background:#fff;width:calc(30%);padding:30px 20px;position:relative;box-shadow:0 5px 10px rgb(0 0 0 / 10%)}.table .price-section{display:flex;justify-content:center}.price-section .price-area{height:120px;width:120px;background:#ffd861;border-radius:50%;padding:2px}.etoc-eztoc-img,.eztoc-wr,.table .package-name{width:100%;position:relative}.price-section .price-area .inner-area{height:100%;width:100%;border-radius:50%;border:3px solid #fff;color:#fff;line-height:117px;position:relative}.price-area .inner-area .text{font-size:25px;font-weight:400;position:absolute;top:-10px;left:17px}.price-area .inner-area .price{font-size:55px;font-weight:500}.table .package-name{height:2px;background:#ffecb3;margin:35px 0}.table .package-name::before{position:absolute;content:"Basic";top:50%;left:50%;transform:translate(-50%,-50%);background:#fff;font-size:25px;padding:0 10px;font-weight:bolder}.table .features li{list-style:none;display:flex;justify-content:space-between;margin-bottom:15px}.features li .list-name{font-size:17px;font-weight:400}.features li .icon{font-size:15px}.features li .icon.check{color:#2db94d}.features li .icon.cross{color:#cd3241}.table .btn{display:flex;justify-content:center;margin-top:35px}.table .btn button{width:80%;height:50px;font-weight:700;color:#fff;font-size:20px;border:none;outline:0;border-radius:25px;cursor:pointer;transition:.3s}.basic .inner-area,.basic .price-area{background:#ffd861}.basic .btn button{background:#fff;color:#ffd861;border:2px solid #ffd861}.basic .btn button:hover{border-radius:6px;background:#ffd861;color:#fff}.Premium .inner-area,.Premium .package-name,.Premium .price-area{background:#a26bfa}.Premium .btn button{background:#fff;color:#a26bfa;border:2px solid #a26bfa}.Premium .btn button:hover{border-radius:6px;background:#a26bfa;color:#fff}.basic .package-name{background:#ffecb3}.basic .package-name::before{content:"Free"}.Premium .package-name::before{content:"PRO"}.basic .inner-area,.basic .price-area,.basic ::selection{background:#ffd861}.Premium .inner-area,.Premium .price-area,.Premium ::selection{background:#a26bfa}div#eztoc-tabs a:first-child{color:#000}#the-list,.eztoc-img img{position:relative}.eztoc-wr{margin:0 auto}.etoc-eztoc-img{margin:0 auto;line-height:0;height:300px}.etoc-eztoc-cnt,.sp_ov{position:absolute;bottom:0}.sp_ov{background:#ea4c89;left:0;right:0;top:0}.etoc-eztoc-cnt{top:40px;left:40px;right:40px;margin:0 auto}.d-amt sup,.pri-tb,.pri-tb .amt sup,.pvf,.pvf-tlt span{position:relative}.etoc-eztoc-cnt h1{font-size:60px;color:#fff;font-weight:600}.etoc-eztoc-cnt p{margin-top:0;color:#371b24;font-size:18px;padding:0 100px;line-height:1.4;font-weight:500}.etoc-eztoc-cnt .buy{border-width:0!important;line-height:2;background:#fff!important;border-radius:8px!important;font-size:16px!important;padding:12px 18px;color:#ea4c89!important;font-weight:500}.etoc-eztoc-cnt .buy:hover{box-shadow:0 2px 2px #999;background:linear-gradient(to left,#fdfc35,#ffe258)!important}.pvf{top:-16px;border:1px solid #eee;padding-bottom:40px}.ext{display:grid;grid-template-columns:1fr 1fr 1fr;background:#f9f9f9;padding:45px 0 45px 25px}.pvf-cnt,.pvf-tlt span{display:inline-block}.ex-1{width:80%}.ampfaq,.etoc-pri-lst,.fet,.pr-btn,.pvf-cnt,.pvf-tlt{width:100%}.ex-1 h4{margin:15px 0 12px;font-weight:600;font-size:20px;color:#ea4c89}.ex-1 p,.pvf-tlt h2{margin:0;color:#000}.ex-1 p{font-size:14px;font-weight:400}.e-1 img{width:65px!important}.e-2 img{width:45px!important}.e-3 img{width:49px!important}.pvf-tlt{margin:70px 0 60px}.pvf-tlt h2{font-size:36px;line-height:1.4;font-weight:500}.pvf-tlt span{font-size:16px;color:#000;margin-top:15px;top:4px}.pvf-cmp{display:grid;grid-template-columns:1fr 2fr}.fr{border-right:1px solid #eee}.fr h1,.pr h1{font-size:36px;font-weight:700;line-height:1.5;border-bottom:1px solid #efefef;padding:0 0 20px 35px}.pr h1{padding-left:50px;color:#ea4c89}.fr-fe{padding-top:10px}.fe-1{padding:22px 35px 35px}.fe-1 h4{margin:0 0 10px;font-size:20px;line-height:1.4;font-weight:400;color:#000}.fe-1 p{font-size:15px;line-height:1.4;margin:0;color:#333}.pr-fe{padding:34px 35px 35px}.pr-fe span{font-family:georgia;font-size:16px;font-weight:700;color:#000;font-style:italic;line-height:1.3}.fet{display:grid;grid-template-columns:1fr 1fr;grid-gap:25px;margin-top:40px}.fe-t h4,.fe-t img,.pr-btn,.pr-btn a,.upg-t>span{display:inline-block}.fe-t img{width:22px!important}.fe-t h4{margin:-5px 0 0;font-size:19px;color:#000;font-weight:400;line-height:1.4;padding-left:8px}.fe-2 p{font-size:15px;line-height:1.4;margin:0;color:#555;padding-top:8px}.pr-btn{margin:50px 0 25px}.pr-btn a{color:#fff;padding:12px 35px 17px;border-radius:5px;font-size:28px;line-height:1.2;background:-webkit-linear-gradient(to right,#e35796,#fc789f);font-weight:600;background:linear-gradient(to right,#e35796,#ea4c89);margin-top:0;box-shadow:0 .15em .65em 0 rgba(0,0,0,.25)}.amp-upg{background:#f5f5f5;padding:60px 10px 0}.upg-t h2{margin:0;font-size:35px;color:#060606;line-height:1.3;font-weight:500}.pri-by,.pri-tb h5,.upg-t>span{line-height:1.2}.upg-t>span{font-size:14px;margin-top:15px;color:#666}.etoc-pri-lst{display:grid;grid-template-columns:1fr 1fr 1fr 1fr 1fr 1fr;margin-top:70px;grid-gap:1px;box-shadow:0 10px 15px 1px #ddd}.pri-tb{background:#fff;border:1px solid #f9f9f9}.f-cnt a,.pri-by{background:#333;display:inline-block}.pri-tb:hover{border:1px solid #e04371}.etoc-pri-lst .rec .pri-by,.pri-tb a:hover .pri-by{background:#e04371}.pri-tb a:hover .amt{color:#7241a7}.pri-tb a{display:inline-block;color:#222;padding:20px 12px}.pri-tb h5{margin:0 0 20px;font-size:13px;letter-spacing:2px;font-weight:400;color:#000}.pri-by,.pri-tb .amt,.pri-tb .d-amt,.pri-tb .s-amt,.tru-us h2{font-weight:500}.pri-tb span{display:inline-block}.pri-tb .amt{font-size:40px;color:#e04371;margin-bottom:20px;display:block}.pri-tb .d-amt{font-size:24px;color:#666;margin-bottom:15px;display:none;text-decoration:line-through}.d-amt sup{line-height:0;top:7px}.pri-tb .s-amt{font-size:13px;color:#4caf50;margin-bottom:10px;display:none}.pri-tb .amt sup{font-size:22px;padding:0 4px 0 0;top:7px}.pri-tb .bil{color:#aaa;font-size:12px;margin-bottom:20px}.pri-tb .e,.pri-tb .f,.pri-tb .s{font-size:14px;margin-bottom:15px;color:#3b4750;display:block}.pri-tb .etoc-sv{display:none;font-size:12px;color:#fff;background:#4caf50;margin:0 auto;padding:1px 7px 2px;border-radius:45px}.pri-by{font-size:15px;border-radius:2px;padding:9px 18px 10px;color:#fff;margin-top:29px}.etoc-pri-lst .rec{box-shadow:0 1px 40px 0 #ccc;background:#fff;z-index:9;margin-top:-20px;position:relative}.etoc-pri-lst .rec:hover .etoc-rcm{background:#000;color:#fff}.etoc-rcm{background:linear-gradient(to right,#e35796,#fc789f);color:#fff;position:absolute;top:-20px;left:0;right:-1px;bottom:auto;padding:2px 0;font-size:11px;letter-spacing:2px}.button-toc,.tru-us{font-size:16px;text-align:center}.tru-us{padding:60px 0;margin:0 auto;color:#222}.tru-us h2{margin:20px 0 0;font-size:28px}.tru-us p{font-size:17px;margin:19px 15% 18px;color:#666;line-height:29px}.tru-us a{font-size:18px;color:#489bff;font-weight:400}.ampfaq h2,.ampfaq h4,.f-cnt a,.f-cnt span{font-weight:500}.ampfaq{margin:25px 0}.ampfaq h4{margin:0;text-align:center;font-size:20px;color:#333}.faq-lst{margin-top:50px;display:grid;grid-template-columns:1fr 1fr}.lt{padding-left:50px}.lt ul,.rt ul{margin:0}.lt ul li,.rt ul li{color:#222;margin-bottom:30px!important}.lt span,.rt span{font-size:17px;font-weight:500;margin-bottom:6px;display:inline-block}.lt p,.rt p{font-size:15px;margin:0}.f-cnt{text-align:center;margin-top:20px;color:#222}.f-cnt span{font-size:17px;margin:8px 0}.f-cnt p{font-size:15px;margin:6px 0}.f-cnt a{color:#fff;padding:15px 30px;font-size:18px;margin-top:15px}@media (max-width:1366px){.amp-upg{padding:60px 0 0}.etoc-eztoc-cnt p{line-height:35px;font-size:18px}}@media (max-width:1280px){.etoc-eztoc-cnt{top:1.3%}}@media (max-width:768px){.ext,.faq-lst,.pvf-cmp{grid-template-columns:1fr}.ext{grid-gap:30px 0;padding:30px}.pvf-tlt h2{font-size:26px}.pr-btn a{font-size:22px}.etoc-pri-lst{grid-template-columns:1fr 1fr 1fr}.etoc-eztoc-cnt p{line-height:1.5;font-size:16px;margin-top:15px;padding:0 20px}.etoc-eztoc-cnt .buy{font-size:16px;padding:8px 30px}.etoc-eztoc-cnt{top:15px}.etoc-eztoc-cnt h1{font-size:30px}.ex-1{width:100%}.rt{padding-left:50px}}div#freevspro{padding:0}.ampfaq h2{margin:40px 0 0;font-size:30px;text-align:center}a#eztoc-upgrade{color:#fff;background:#ea4c89;padding:16px}div#welcome{text-align:center}.eztoc_hide,a#eztoc-welcome{display:none}.button-toc span,.ez-toc-tooltip{position:relative;display:inline-block}.button-toc{cursor:pointer;margin:20px;color:#fff;border-radius:4px;background-color:#ec407a;border:none;padding:20px;transition:.5s;font-weight:600}.button-toc span{cursor:pointer;transition:.5s}.button-toc span:after{content:'»';position:absolute;opacity:0;top:0;right:-20px;transition:.5s}.button-toc:hover span{padding-right:25px}.button-toc:hover span:after{opacity:1;right:0}.eztoc-query-success{color:green}.eztoc-query-error{color:red}.eztoc-result{margin-left:70px}div#wp-pointer-0{position:absolute;width:320px;top:515px!important;left:146px!important;z-index:9999}.ez-toc-tooltip .ez-toc-tooltiptext{visibility:hidden;width:140px;background-color:#555;color:#fff;text-align:center;border-radius:6px;padding:5px;position:absolute;z-index:1;bottom:150%;left:50%;margin-left:-75px;opacity:0;transition:opacity .3s}.ez-toc-tooltip .ez-toc-tooltiptext::after{content:"";position:absolute;top:100%;left:50%;margin-left:-5px;border-width:5px;border-style:solid;border-color:#555 transparent transparent}.ez-toc-tooltip:hover .ez-toc-tooltiptext{visibility:visible;opacity:1}#eztoc-tabs-technical{margin-top:10px}#eztoc-tabs-technical a.eztoc-tablinks-technical,#eztoc-tabs-technical a:first-child.eztoc-tablinks-technical{color:#000;text-decoration:none}#eztoc-tabs-technical a.eztoc-tablinks-technical.active{color:#ea4c89}.ez-toc-pull-technical-img{float:left!important;margin-right:10px;width:100%}.eztoc-tabcontent-technical p.ez-toc-tabcontent-technical-title-content{margin-top:-5px}#eztoc-technical-how-to-use li{list-style:auto!important}
 
 
 
 
 
 
 
assets/css/ez-toc-sticky.css CHANGED
@@ -150,46 +150,6 @@ div.ez-toc-sticky-widget-container li {
150
  color: #444444;
151
  }
152
 
153
- #ez-toc-sticky-container.counter-hierarchy ul,
154
- .ez-toc-sticky-widget-container.counter-hierarchy ul,
155
- #ez-toc-sticky-container.counter-flat ul,
156
- .ez-toc-sticky-widget-container.counter-flat ul {
157
- counter-reset: item;
158
- }
159
-
160
- #ez-toc-sticky-container.counter-numeric li,
161
- .ez-toc-sticky-widget-container.counter-numeric li {
162
- list-style-type: decimal;
163
- list-style-position: inside;
164
- }
165
-
166
- #ez-toc-sticky-container.counter-disc li,
167
- .ez-toc-sticky-widget-container.counter-disc li {
168
- list-style-type: disc;
169
- list-style-position: inside;
170
- }
171
-
172
- #ez-toc-sticky-container.counter-hyphen li,
173
- .ez-toc-sticky-widget-container.counter-hyphen li {
174
- list-style-type: '-';
175
- list-style-position: inside;
176
- }
177
-
178
-
179
- #ez-toc-sticky-container.counter-decimal ul.ez-toc-sticky-list li a::before,
180
- .ez-toc-sticky-widget-container.counter-decimal ul.ez-toc-sticky-list li a::before {
181
- content: counters(item, ".") ". ";
182
- display: inline-block;
183
- counter-increment: item;
184
- margin-right: .2em;
185
- }
186
-
187
- #ez-toc-sticky-container.counter-roman li a::before,
188
- .ez-toc-sticky-widget-container.counter-roman ul.ez-toc-sticky-list li a::before {
189
- content: counters(item, ".", upper-roman) ". ";
190
- counter-increment: item;
191
- }
192
-
193
  .ez-toc-sticky-widget-container ul.ez-toc-sticky-list li::before {
194
  content: ' ';
195
  position: absolute;
150
  color: #444444;
151
  }
152
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  .ez-toc-sticky-widget-container ul.ez-toc-sticky-list li::before {
154
  content: ' ';
155
  position: absolute;
assets/css/ez-toc-sticky.min.css CHANGED
@@ -1 +1 @@
1
- #ez-toc-sticky-container{background:#fff;border:1px solid #aaa;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05);display:table;margin-bottom:1em;padding:10px;position:relative;width:auto}div.ez-toc-sticky-widget-container{padding:0;position:relative}#ez-toc-sticky-container.ez-toc-sticky-light-blue{background:#edf6ff}#ez-toc-sticky-container.ez-toc-sticky-white{background:#fff}#ez-toc-sticky-container.ez-toc-sticky-black{background:#000}#ez-toc-sticky-container.ez-toc-sticky-transparent{background:none}div.ez-toc-sticky-widget-container ul{display:block}div.ez-toc-sticky-widget-container li{border:none;padding:0}div.ez-toc-sticky-widget-container ul.ez-toc-sticky-list{padding:10px}#ez-toc-sticky-container ul ul,.ez-toc div.ez-toc-sticky-widget-container ul ul{margin-left:1.5em}#ez-toc-sticky-container li,#ez-toc-sticky-container ul{padding:0}#ez-toc-sticky-container li,#ez-toc-sticky-container ul,#ez-toc-sticky-container ul li,div.ez-toc-sticky-widget-container,div.ez-toc-sticky-widget-container li{background:0 0;list-style:none;line-height:1.6;margin:0;overflow:hidden;z-index:1}#ez-toc-sticky-container p.ez-toc-sticky-title{text-align:left;line-height:1.45;margin:0;padding:0}.ez-toc-sticky-title-container{display:table;width:100%}.ez-toc-sticky-title,.ez-toc-sticky-title-toggle{display:table-cell;text-align:left;vertical-align:middle}#ez-toc-sticky-container.ez-toc-sticky-black a,#ez-toc-sticky-container.ez-toc-sticky-black a:visited,#ez-toc-sticky-container.ez-toc-sticky-black p.ez-toc-sticky-title{color:#fff}#ez-toc-sticky-container div.ez-toc-sticky-title-container+ul.ez-toc-sticky-list{margin-top:1em}.ez-toc-sticky-wrap-left{float:left;margin-right:10px}.ez-toc-sticky-wrap-right{float:right;margin-left:10px}.ez-toc-sticky-wrap-center{margin:0 auto}#ez-toc-sticky-container a{color:#444;box-shadow:none;text-decoration:none;text-shadow:none}#ez-toc-sticky-container a:visited{color:#9f9f9f}#ez-toc-sticky-container a:hover{text-decoration:underline}#ez-toc-sticky-container a.ez-toc-sticky-toggle{color:#444}#ez-toc-sticky-container.counter-flat ul,#ez-toc-sticky-container.counter-hierarchy ul,.ez-toc-sticky-widget-container.counter-flat ul,.ez-toc-sticky-widget-container.counter-hierarchy ul{counter-reset:item}#ez-toc-sticky-container.counter-numeric li,.ez-toc-sticky-widget-container.counter-numeric li{list-style-type:decimal;list-style-position:inside}#ez-toc-sticky-container.counter-disc li,.ez-toc-sticky-widget-container.counter-disc li{list-style-type:disc;list-style-position:inside}#ez-toc-sticky-container.counter-hyphen li,.ez-toc-sticky-widget-container.counter-hyphen li{list-style-type:'-';list-style-position:inside}#ez-toc-sticky-container.counter-decimal ul.ez-toc-sticky-list li a::before,.ez-toc-sticky-widget-container.counter-decimal ul.ez-toc-sticky-list li a::before{content:counters(item, ".") ". ";display:inline-block;counter-increment:item;margin-right:.2em}#ez-toc-sticky-container.counter-roman li a::before,.ez-toc-sticky-widget-container.counter-roman ul.ez-toc-sticky-list li a::before{content:counters(item, ".", upper-roman) ". ";counter-increment:item}.ez-toc-sticky-widget-container ul.ez-toc-sticky-list li::before{content:' ';position:absolute;left:0;right:0;height:30px;line-height:30px;z-index:-1}.ez-toc-sticky-widget-container ul.ez-toc-sticky-list li.active{background-color:#ededed;height:auto!important}.ez-toc-sticky-widget-container li.active>a{font-weight:900}.ez-toc-sticky-btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;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}.ez-toc-sticky-btn:focus{outline:#333 dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}.ez-toc-sticky-btn:focus,.ez-toc-sticky-btn:hover{color:#333;text-decoration:none}.ez-toc-sticky-btn.active,.ez-toc-sticky-btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.ez-toc-sticky-btn-default{color:#333;background-color:#fff;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);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:#ccc}.ez-toc-sticky-btn-default.active,.ez-toc-sticky-btn-default:active,.ez-toc-sticky-btn-default:focus,.ez-toc-sticky-btn-default:hover{color:#333;background-color:#ebebeb;border-color:#adadad}.ez-toc-sticky-btn-default.active,.ez-toc-sticky-btn-default:active{background-image:none;background-color:#e0e0e0;border-color:#dbdbdb}.ez-toc-sticky-btn-sm,.ez-toc-sticky-btn-xs{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.ez-toc-sticky-glyphicon,[class*=ez-toc-sticky-icon-]{font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.ez-toc-sticky-btn-xs{padding:1px 5px}.ez-toc-sticky-btn-default:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.active,.ez-toc-sticky-btn:active{background-image:none}.ez-toc-sticky-btn-default:focus,.ez-toc-sticky-btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.ez-toc-sticky-pull-right{float:right!important;margin-left:10px}.ez-toc-sticky-glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings'}.ez-toc-sticky-glyphicon:empty{width:1em}.ez-toc-sticky-toggle i.ez-toc-sticky-glyphicon,label.cssicon .ez-toc-sticky-glyphicon:empty{font-size:16px;margin-left:2px}[class*=ez-toc-sticky-icon-]{font-family:ez-toc-sticky-icomoon!important;speak:none;font-variant:normal;text-transform:none}.ez-toc-sticky-icon-toggle:before{content:"\e87a"}#ez-toc-sticky-container input{position:absolute;left:-999em}#ez-toc-sticky-container input[type=checkbox]:checked+nav{opacity:0;max-height:0;border:none;display:none}#ez-toc-sticky-container label{float:right;position:relative;left:10px;font-size:16px;background:#f9efef;padding:0 4px 0 5px;border:1px solid #999191;border-radius:5px;cursor:pointer}div#ez-toc-sticky-container p.ez-toc-sticky-title{display:contents}div#ez-toc-sticky-container{padding-right:20px}div#ez-toc-sticky-container.afterpara+p,label.cssiconcheckbox{display:none}.ez-toc-sticky-widget-container ul li a{padding-left:10px}
1
+ #ez-toc-sticky-container{background:#fff;border:1px solid #aaa;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05);display:table;margin-bottom:1em;padding:10px;position:relative;width:auto}div.ez-toc-sticky-widget-container{padding:0;position:relative}#ez-toc-sticky-container.ez-toc-sticky-light-blue{background:#edf6ff}#ez-toc-sticky-container.ez-toc-sticky-white{background:#fff}#ez-toc-sticky-container.ez-toc-sticky-black{background:#000}#ez-toc-sticky-container.ez-toc-sticky-transparent{background:none}div.ez-toc-sticky-widget-container ul{display:block}div.ez-toc-sticky-widget-container li{border:none;padding:0}div.ez-toc-sticky-widget-container ul.ez-toc-sticky-list{padding:10px}#ez-toc-sticky-container ul ul,.ez-toc div.ez-toc-sticky-widget-container ul ul{margin-left:1.5em}#ez-toc-sticky-container li,#ez-toc-sticky-container ul{padding:0}#ez-toc-sticky-container li,#ez-toc-sticky-container ul,#ez-toc-sticky-container ul li,div.ez-toc-sticky-widget-container,div.ez-toc-sticky-widget-container li{background:0 0;list-style:none;line-height:1.6;margin:0;overflow:hidden;z-index:1}#ez-toc-sticky-container p.ez-toc-sticky-title{text-align:left;line-height:1.45;margin:0;padding:0}.ez-toc-sticky-title-container{display:table;width:100%}.ez-toc-sticky-title,.ez-toc-sticky-title-toggle{display:table-cell;text-align:left;vertical-align:middle}#ez-toc-sticky-container.ez-toc-sticky-black a,#ez-toc-sticky-container.ez-toc-sticky-black a:visited,#ez-toc-sticky-container.ez-toc-sticky-black p.ez-toc-sticky-title{color:#fff}#ez-toc-sticky-container div.ez-toc-sticky-title-container+ul.ez-toc-sticky-list{margin-top:1em}.ez-toc-sticky-wrap-left{float:left;margin-right:10px}.ez-toc-sticky-wrap-right{float:right;margin-left:10px}.ez-toc-sticky-wrap-center{margin:0 auto}#ez-toc-sticky-container a{color:#444;box-shadow:none;text-decoration:none;text-shadow:none}#ez-toc-sticky-container a:visited{color:#9f9f9f}#ez-toc-sticky-container a:hover{text-decoration:underline}#ez-toc-sticky-container a.ez-toc-sticky-toggle{color:#444}.ez-toc-sticky-widget-container ul.ez-toc-sticky-list li::before{content:' ';position:absolute;left:0;right:0;height:30px;line-height:30px;z-index:-1}.ez-toc-sticky-widget-container ul.ez-toc-sticky-list li.active{background-color:#ededed;height:auto!important}.ez-toc-sticky-widget-container li.active>a{font-weight:900}.ez-toc-sticky-btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;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}.ez-toc-sticky-btn:focus{outline:#333 dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}.ez-toc-sticky-btn:focus,.ez-toc-sticky-btn:hover{color:#333;text-decoration:none}.ez-toc-sticky-btn.active,.ez-toc-sticky-btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.ez-toc-sticky-btn-default{color:#333;background-color:#fff;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);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:#ccc}.ez-toc-sticky-btn-default.active,.ez-toc-sticky-btn-default:active,.ez-toc-sticky-btn-default:focus,.ez-toc-sticky-btn-default:hover{color:#333;background-color:#ebebeb;border-color:#adadad}.ez-toc-sticky-btn-default.active,.ez-toc-sticky-btn-default:active{background-image:none;background-color:#e0e0e0;border-color:#dbdbdb}.ez-toc-sticky-btn-sm,.ez-toc-sticky-btn-xs{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.ez-toc-sticky-glyphicon,[class*=ez-toc-sticky-icon-]{font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.ez-toc-sticky-btn-xs{padding:1px 5px}.ez-toc-sticky-btn-default:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.active,.ez-toc-sticky-btn:active{background-image:none}.ez-toc-sticky-btn-default:focus,.ez-toc-sticky-btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.ez-toc-sticky-pull-right{float:right!important;margin-left:10px}.ez-toc-sticky-glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings'}.ez-toc-sticky-glyphicon:empty{width:1em}.ez-toc-sticky-toggle i.ez-toc-sticky-glyphicon,label.cssicon .ez-toc-sticky-glyphicon:empty{font-size:16px;margin-left:2px}[class*=ez-toc-sticky-icon-]{font-family:ez-toc-sticky-icomoon!important;speak:none;font-variant:normal;text-transform:none}.ez-toc-sticky-icon-toggle:before{content:"\e87a"}#ez-toc-sticky-container input{position:absolute;left:-999em}#ez-toc-sticky-container input[type=checkbox]:checked+nav{opacity:0;max-height:0;border:none;display:none}#ez-toc-sticky-container label{float:right;position:relative;left:10px;font-size:16px;background:#f9efef;padding:0 4px 0 5px;border:1px solid #999191;border-radius:5px;cursor:pointer}div#ez-toc-sticky-container p.ez-toc-sticky-title{display:contents}div#ez-toc-sticky-container{padding-right:20px}div#ez-toc-sticky-container.afterpara+p,label.cssiconcheckbox{display:none}.ez-toc-sticky-widget-container ul li a{padding-left:10px}
assets/css/screen.css CHANGED
@@ -1,60 +1,59 @@
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
  div.ez-toc-widget-container {
16
- padding: 0;
17
- position: relative;
18
  }
19
 
20
  #ez-toc-container.ez-toc-light-blue {
21
- background: #EDF6FF;
22
  }
23
 
24
  #ez-toc-container.ez-toc-white {
25
- background: #FFFFFF;
26
  }
27
 
28
  #ez-toc-container.ez-toc-black {
29
- background: #000000;
30
  }
31
 
32
  #ez-toc-container.ez-toc-transparent {
33
- background: none transparent;
34
  }
35
 
36
  div.ez-toc-widget-container ul {
37
- display: block;
38
  }
39
 
40
  div.ez-toc-widget-container li {
41
- border: none;
42
- padding: 0;
43
  }
44
 
45
  div.ez-toc-widget-container ul.ez-toc-list {
46
- padding: 10px;
47
  }
48
 
49
  #ez-toc-container ul ul,
50
  .ez-toc div.ez-toc-widget-container ul ul {
51
- margin-left: 1.5em;
52
  }
53
 
54
  #ez-toc-container ul,
55
  #ez-toc-container li {
56
- margin: 0;
57
- padding: 0;
58
  }
59
 
60
  #ez-toc-container ul,
@@ -62,335 +61,303 @@ div.ez-toc-widget-container ul.ez-toc-list {
62
  #ez-toc-container ul li,
63
  div.ez-toc-widget-container,
64
  div.ez-toc-widget-container li {
65
- background: none;
66
- list-style: none none;
67
- line-height: 1.6;
68
- margin: 0;
69
- overflow: hidden;
70
- z-index: 1;
71
  }
72
 
73
- /*#ez-toc-container.have_bullets li {*/
74
- /*padding-left: 12px;*/
75
- /*}*/
76
-
77
  #ez-toc-container p.ez-toc-title {
78
- text-align: left;
79
- /*font-family: "Arial Narrow", sans-serif;*/
80
- /*font-size: 120%;*/
81
- /*font-weight: 500;*/
82
- line-height: 1.45;
83
- margin: 0;
84
- padding: 0;
85
  }
86
 
87
  .ez-toc-title-container {
88
- display: table;
89
- width: 100%;
90
  }
91
 
92
  .ez-toc-title,
93
  .ez-toc-title-toggle {
94
- display: table-cell;
95
- text-align: left;
96
- vertical-align: middle;
97
  }
98
 
99
  #ez-toc-container.ez-toc-black p.ez-toc-title {
100
- color: #FFF;
101
  }
102
 
103
- /*#ez-toc-container span.ez-toc-toggle {*/
104
- /*font-weight: 400;*/
105
- /*font-size: 90%;*/
106
- /*}*/
107
-
108
  #ez-toc-container div.ez-toc-title-container + ul.ez-toc-list {
109
- margin-top: 1em;
110
  }
111
 
112
  .ez-toc-wrap-left {
113
- float: left;
114
- margin-right: 10px;
115
  }
116
 
117
  .ez-toc-wrap-right {
118
- float: right;
119
- margin-left: 10px;
120
- }
121
- .ez-toc-wrap-center {
122
- margin: 0 auto;
123
  }
 
124
  #ez-toc-container a {
125
- color: #444444;
126
- box-shadow: none;
127
- text-decoration: none;
128
- text-shadow: none;
129
  }
130
 
131
  #ez-toc-container a:visited {
132
- color: #9f9f9f;
133
  }
134
 
135
  #ez-toc-container a:hover {
136
- text-decoration: underline;
137
  }
138
 
139
  #ez-toc-container.ez-toc-black a {
140
- color: #FFF;
141
  }
142
 
143
  #ez-toc-container.ez-toc-black a:visited {
144
- color: #FFF;
145
  }
146
 
147
  #ez-toc-container a.ez-toc-toggle {
148
- color: #444444;
149
- }
150
-
151
- #ez-toc-container.counter-hierarchy ul,
152
- .ez-toc-widget-container.counter-hierarchy ul,
153
- #ez-toc-container.counter-flat ul,
154
- .ez-toc-widget-container.counter-flat ul {
155
- counter-reset: item;
156
- }
157
-
158
- #ez-toc-container.counter-numeric li,
159
- .ez-toc-widget-container.counter-numeric li {
160
- list-style-type: decimal;
161
- list-style-position: inside;
162
- }
163
-
164
- #ez-toc-container.counter-disc li,
165
- .ez-toc-widget-container.counter-disc li {
166
- list-style-type: disc;
167
- list-style-position: inside;
168
- }
169
-
170
- #ez-toc-container.counter-hyphen li,
171
- .ez-toc-widget-container.counter-hyphen li {
172
- list-style-type: '-';
173
- list-style-position: inside;
174
- }
175
-
176
-
177
-
178
-
179
- #ez-toc-container.counter-decimal ul.ez-toc-list li a::before,
180
- .ez-toc-widget-container.counter-decimal ul.ez-toc-list li a::before {
181
- content: counters(item, ".") ". ";
182
- display: inline-block;
183
- counter-increment: item;
184
- margin-right: .2em;
185
- }
186
-
187
- #ez-toc-container.counter-roman li a::before,
188
- .ez-toc-widget-container.counter-roman ul.ez-toc-list li a::before {
189
- content: counters(item, ".", upper-roman) ". ";
190
- counter-increment: item;
191
  }
192
 
193
  .ez-toc-widget-container ul.ez-toc-list li::before {
194
- content: ' ';
195
- position: absolute;
196
- left: 0;
197
- right: 0;
198
- height: 30px;
199
- line-height: 30px;
200
- z-index: -1;
201
  }
202
 
203
  .ez-toc-widget-container ul.ez-toc-list li.active {
204
- background-color: #EDEDED;
205
  }
206
 
207
  .ez-toc-widget-container li.active > a {
208
- font-weight: 900;
209
  }
210
 
211
  .ez-toc-btn {
212
- display: inline-block;
213
- padding: 6px 12px;
214
- margin-bottom: 0;
215
- font-size: 14px;
216
- font-weight: normal;
217
- line-height: 1.428571429;
218
- text-align: center;
219
- white-space: nowrap;
220
- vertical-align: middle;
221
- cursor: pointer;
222
- background-image: none;
223
- border: 1px solid transparent;
224
- border-radius: 4px;
225
- -webkit-user-select: none;
226
- -moz-user-select: none;
227
- -ms-user-select: none;
228
- -o-user-select: none;
229
- user-select: none
230
  }
231
 
232
  .ez-toc-btn:focus {
233
- outline: thin dotted #333;
234
- outline: 5px auto -webkit-focus-ring-color;
235
- outline-offset: -2px
236
  }
237
 
238
- .ez-toc-btn:hover,.ez-toc-btn:focus {
239
- color: #333;
240
- text-decoration: none
 
241
  }
242
 
243
- .ez-toc-btn:active,.ez-toc-btn.active {
244
- background-image: none;
245
- outline: 0;
246
- -webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);
247
- box-shadow: inset 0 3px 5px rgba(0,0,0,0.125)
 
248
  }
249
 
250
  .ez-toc-btn-default {
251
- color: #333;
252
- background-color: #fff;
253
- border-color: #ccc
254
  }
255
 
256
- .ez-toc-btn-default:hover,.ez-toc-btn-default:focus,.ez-toc-btn-default:active,.ez-toc-btn-default.active {
257
- color: #333;
258
- background-color: #ebebeb;
259
- border-color: #adadad
 
 
 
260
  }
261
 
262
- .ez-toc-btn-default:active,.ez-toc-btn-default.active {
263
- background-image: none
 
264
  }
265
 
266
- /*.btn-lg {*/
267
- /*padding: 10px 16px;*/
268
- /*font-size: 18px;*/
269
- /*line-height: 1.33;*/
270
- /*border-radius: 6px*/
271
- /*}*/
272
-
273
- .ez-toc-btn-sm,.ez-toc-btn-xs {
274
- padding: 5px 10px;
275
- font-size: 12px;
276
- line-height: 1.5;
277
- border-radius: 3px
278
  }
279
 
280
  .ez-toc-btn-xs {
281
- padding: 1px 5px
282
  }
283
 
284
  .ez-toc-btn-default {
285
- text-shadow: 0 -1px 0 rgba(0,0,0,0.2);
286
- -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);
287
- box-shadow: inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075)
288
  }
289
 
290
  .ez-toc-btn-default:active {
291
- -webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);
292
- box-shadow: inset 0 3px 5px rgba(0,0,0,0.125)
293
  }
294
 
295
- .ez-toc-btn:active,.btn.active {
296
- background-image: none
 
297
  }
298
 
299
  .ez-toc-btn-default {
300
- text-shadow: 0 1px 0 #fff;
301
- background-image: -webkit-gradient(linear,left 0,left 100%,from(#fff),to(#e0e0e0));
302
- background-image: -webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);
303
- background-image: -moz-linear-gradient(top,#fff 0,#e0e0e0 100%);
304
- background-image: linear-gradient(to bottom,#fff 0,#e0e0e0 100%);
305
- background-repeat: repeat-x;
306
- border-color: #dbdbdb;
307
- border-color: #ccc;
308
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe0e0e0',GradientType=0);
309
- filter: progid:DXImageTransform.Microsoft.gradient(enabled=false)
310
  }
311
 
312
- .ez-toc-btn-default:hover,.ez-toc-btn-default:focus {
313
- background-color: #e0e0e0;
314
- background-position: 0 -15px
 
315
  }
316
 
317
- .ez-toc-btn-default:active,.ez-toc-btn-default.active {
318
- background-color: #e0e0e0;
319
- border-color: #dbdbdb
 
320
  }
321
 
322
  .ez-toc-pull-right {
323
- float: right !important;
324
- margin-left: 10px;
325
  }
326
 
327
  .ez-toc-glyphicon {
328
- position: relative;
329
- top: 1px;
330
- display: inline-block;
331
- font-family: 'Glyphicons Halflings';
332
- -webkit-font-smoothing: antialiased;
333
- font-style: normal;
334
- font-weight: normal;
335
- line-height: 1;
336
- -moz-osx-font-smoothing: grayscale
337
  }
338
 
339
  .ez-toc-glyphicon:empty {
340
- width: 1em
341
  }
342
 
343
  .ez-toc-toggle i.ez-toc-glyphicon {
344
- font-size: 16px;
345
- margin-left: 2px;
346
  }
347
 
348
  [class*="ez-toc-icon-"] {
349
- font-family: 'ez-toc-icomoon' !important; /* For better glyphicon compatibility */
350
- speak: none;
351
- font-style: normal;
352
- font-weight: normal;
353
- font-variant: normal;
354
- text-transform: none;
355
- line-height: 1;
356
-
357
- /* Better Font Rendering =========== */
358
- -webkit-font-smoothing: antialiased;
359
- -moz-osx-font-smoothing: grayscale;
360
  }
361
 
362
  .ez-toc-icon-toggle:before {
363
- content: "\e87a";
364
  }
 
365
  #ez-toc-container input {
366
- position: absolute;
367
- left: -999em;
368
  }
 
369
  #ez-toc-container input[type="checkbox"]:checked + nav {
370
- opacity: 0;
371
- max-height: 0;
372
- border: none;
373
- display: none;
374
  }
375
 
376
  #ez-toc-container label {
377
  float: right;
378
  position: relative;
379
- left: 10px;
380
  font-size: 16px;
381
- background: #f9efef;
382
  padding: 0px 4px 0px 5px;
383
  border: 1px solid #999191;
384
  border-radius: 5px;
385
  cursor: pointer;
386
  }
387
- div#ez-toc-container p.ez-toc-title {
 
388
  display: contents;
389
  }
 
390
  div#ez-toc-container {
391
  padding-right: 20px;
392
  }
393
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
394
  label.cssicon .ez-toc-glyphicon:empty {
395
  font-size: 16px;
396
  margin-left: 2px;
@@ -403,9 +370,11 @@ label.cssiconcheckbox {
403
  div#ez-toc-container.afterpara + p {
404
  display: none;
405
  }
 
406
  .ez-toc-widget-container ul li a {
407
- padding-left: 10px;
408
  }
 
409
  .ez-toc-widget-container ul.ez-toc-list li.active {
410
- height: auto!important;
411
  }
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
+ margin-bottom: 1em;
9
+ padding: 10px;
10
+ position: relative;
11
+ width: auto;
 
12
  }
13
 
14
  div.ez-toc-widget-container {
15
+ padding: 0;
16
+ position: relative;
17
  }
18
 
19
  #ez-toc-container.ez-toc-light-blue {
20
+ background: #EDF6FF;
21
  }
22
 
23
  #ez-toc-container.ez-toc-white {
24
+ background: #FFFFFF;
25
  }
26
 
27
  #ez-toc-container.ez-toc-black {
28
+ background: #000000;
29
  }
30
 
31
  #ez-toc-container.ez-toc-transparent {
32
+ background: none transparent;
33
  }
34
 
35
  div.ez-toc-widget-container ul {
36
+ display: block;
37
  }
38
 
39
  div.ez-toc-widget-container li {
40
+ border: none;
41
+ padding: 0;
42
  }
43
 
44
  div.ez-toc-widget-container ul.ez-toc-list {
45
+ padding: 10px;
46
  }
47
 
48
  #ez-toc-container ul ul,
49
  .ez-toc div.ez-toc-widget-container ul ul {
50
+ margin-left: 1.5em;
51
  }
52
 
53
  #ez-toc-container ul,
54
  #ez-toc-container li {
55
+ margin: 0;
56
+ padding: 0;
57
  }
58
 
59
  #ez-toc-container ul,
61
  #ez-toc-container ul li,
62
  div.ez-toc-widget-container,
63
  div.ez-toc-widget-container li {
64
+ background: none;
65
+ list-style: none none;
66
+ line-height: 1.6;
67
+ margin: 0;
68
+ overflow: hidden;
69
+ z-index: 1;
70
  }
71
 
 
 
 
 
72
  #ez-toc-container p.ez-toc-title {
73
+ text-align: left;
74
+ line-height: 1.45;
75
+ margin: 0;
76
+ padding: 0;
 
 
 
77
  }
78
 
79
  .ez-toc-title-container {
80
+ display: table;
81
+ width: 100%;
82
  }
83
 
84
  .ez-toc-title,
85
  .ez-toc-title-toggle {
86
+ display: inline;
87
+ text-align: left;
88
+ vertical-align: middle;
89
  }
90
 
91
  #ez-toc-container.ez-toc-black p.ez-toc-title {
92
+ color: #FFF;
93
  }
94
 
 
 
 
 
 
95
  #ez-toc-container div.ez-toc-title-container + ul.ez-toc-list {
96
+ margin-top: 1em;
97
  }
98
 
99
  .ez-toc-wrap-left {
100
+ float: left;
101
+ margin-right: 10px;
102
  }
103
 
104
  .ez-toc-wrap-right {
105
+ float: right;
106
+ margin-left: 10px;
 
 
 
107
  }
108
+
109
  #ez-toc-container a {
110
+ color: #444444;
111
+ box-shadow: none;
112
+ text-decoration: none;
113
+ text-shadow: none;
114
  }
115
 
116
  #ez-toc-container a:visited {
117
+ color: #9f9f9f;
118
  }
119
 
120
  #ez-toc-container a:hover {
121
+ text-decoration: underline;
122
  }
123
 
124
  #ez-toc-container.ez-toc-black a {
125
+ color: #FFF;
126
  }
127
 
128
  #ez-toc-container.ez-toc-black a:visited {
129
+ color: #FFF;
130
  }
131
 
132
  #ez-toc-container a.ez-toc-toggle {
133
+ color: #444444;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  }
135
 
136
  .ez-toc-widget-container ul.ez-toc-list li::before {
137
+ content: ' ';
138
+ position: absolute;
139
+ left: 0;
140
+ right: 0;
141
+ height: 30px;
142
+ line-height: 30px;
143
+ z-index: -1;
144
  }
145
 
146
  .ez-toc-widget-container ul.ez-toc-list li.active {
147
+ background-color: #EDEDED;
148
  }
149
 
150
  .ez-toc-widget-container li.active > a {
151
+ font-weight: 900;
152
  }
153
 
154
  .ez-toc-btn {
155
+ display: inline-block;
156
+ padding: 6px 12px;
157
+ margin-bottom: 0;
158
+ font-size: 14px;
159
+ font-weight: normal;
160
+ line-height: 1.428571429;
161
+ text-align: center;
162
+ white-space: nowrap;
163
+ vertical-align: middle;
164
+ cursor: pointer;
165
+ background-image: none;
166
+ border: 1px solid transparent;
167
+ border-radius: 4px;
168
+ -webkit-user-select: none;
169
+ -moz-user-select: none;
170
+ -ms-user-select: none;
171
+ -o-user-select: none;
172
+ user-select: none
173
  }
174
 
175
  .ez-toc-btn:focus {
176
+ outline: thin dotted #333;
177
+ outline: 5px auto -webkit-focus-ring-color;
178
+ outline-offset: -2px
179
  }
180
 
181
+ .ez-toc-btn:hover,
182
+ .ez-toc-btn:focus {
183
+ color: #333;
184
+ text-decoration: none
185
  }
186
 
187
+ .ez-toc-btn:active,
188
+ .ez-toc-btn.active {
189
+ background-image: none;
190
+ outline: 0;
191
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
192
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125)
193
  }
194
 
195
  .ez-toc-btn-default {
196
+ color: #333;
197
+ background-color: #fff;
198
+ border-color: #ccc
199
  }
200
 
201
+ .ez-toc-btn-default:hover,
202
+ .ez-toc-btn-default:focus,
203
+ .ez-toc-btn-default:active,
204
+ .ez-toc-btn-default.active {
205
+ color: #333;
206
+ background-color: #ebebeb;
207
+ border-color: #adadad
208
  }
209
 
210
+ .ez-toc-btn-default:active,
211
+ .ez-toc-btn-default.active {
212
+ background-image: none
213
  }
214
 
215
+ .ez-toc-btn-sm,
216
+ .ez-toc-btn-xs {
217
+ padding: 5px 10px;
218
+ font-size: 12px;
219
+ line-height: 1.5;
220
+ border-radius: 3px
 
 
 
 
 
 
221
  }
222
 
223
  .ez-toc-btn-xs {
224
+ padding: 1px 5px
225
  }
226
 
227
  .ez-toc-btn-default {
228
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
229
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
230
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075)
231
  }
232
 
233
  .ez-toc-btn-default:active {
234
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
235
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125)
236
  }
237
 
238
+ .ez-toc-btn:active,
239
+ .btn.active {
240
+ background-image: none
241
  }
242
 
243
  .ez-toc-btn-default {
244
+ text-shadow: 0 1px 0 #fff;
245
+ background-image: -webkit-gradient(linear, left 0, left 100%, from(#fff), to(#e0e0e0));
246
+ background-image: -webkit-linear-gradient(top, #fff 0, #e0e0e0 100%);
247
+ background-image: -moz-linear-gradient(top, #fff 0, #e0e0e0 100%);
248
+ background-image: linear-gradient(to bottom, #fff 0, #e0e0e0 100%);
249
+ background-repeat: repeat-x;
250
+ border-color: #dbdbdb;
251
+ border-color: #ccc;
252
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
253
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false)
254
  }
255
 
256
+ .ez-toc-btn-default:hover,
257
+ .ez-toc-btn-default:focus {
258
+ background-color: #e0e0e0;
259
+ background-position: 0 -15px
260
  }
261
 
262
+ .ez-toc-btn-default:active,
263
+ .ez-toc-btn-default.active {
264
+ background-color: #e0e0e0;
265
+ border-color: #dbdbdb
266
  }
267
 
268
  .ez-toc-pull-right {
269
+ float: right !important;
270
+ margin-left: 10px;
271
  }
272
 
273
  .ez-toc-glyphicon {
274
+ position: relative;
275
+ top: 1px;
276
+ display: inline-block;
277
+ font-family: 'Glyphicons Halflings';
278
+ -webkit-font-smoothing: antialiased;
279
+ font-style: normal;
280
+ font-weight: normal;
281
+ line-height: 1;
282
+ -moz-osx-font-smoothing: grayscale
283
  }
284
 
285
  .ez-toc-glyphicon:empty {
286
+ width: 1em
287
  }
288
 
289
  .ez-toc-toggle i.ez-toc-glyphicon {
290
+ font-size: 16px;
291
+ margin-left: 2px;
292
  }
293
 
294
  [class*="ez-toc-icon-"] {
295
+ font-family: 'ez-toc-icomoon' !important;
296
+ speak: none;
297
+ font-style: normal;
298
+ font-weight: normal;
299
+ font-variant: normal;
300
+ text-transform: none;
301
+ line-height: 1;
302
+ -webkit-font-smoothing: antialiased;
303
+ -moz-osx-font-smoothing: grayscale;
 
 
304
  }
305
 
306
  .ez-toc-icon-toggle:before {
307
+ content: "\e87a";
308
  }
309
+
310
  #ez-toc-container input {
311
+ position: absolute;
312
+ left: -999em;
313
  }
314
+
315
  #ez-toc-container input[type="checkbox"]:checked + nav {
316
+ opacity: 0;
317
+ max-height: 0;
318
+ border: none;
319
+ display: none;
320
  }
321
 
322
  #ez-toc-container label {
323
  float: right;
324
  position: relative;
325
+ left: 3px;
326
  font-size: 16px;
327
+ /* background: #f9efef; */
328
  padding: 0px 4px 0px 5px;
329
  border: 1px solid #999191;
330
  border-radius: 5px;
331
  cursor: pointer;
332
  }
333
+
334
+ div#ez-toc-container p.ez-toc-title {
335
  display: contents;
336
  }
337
+
338
  div#ez-toc-container {
339
  padding-right: 20px;
340
  }
341
 
342
+ #ez-toc-container label {
343
+ left: 10px;
344
+ }
345
+
346
+ .ez-toc-wrap-center {
347
+ margin: 0 auto;
348
+ }
349
+
350
+ #ez-toc-container a.ez-toc-toggle {
351
+ color: #444444;
352
+ background: inherit;
353
+ border: inherit;
354
+ }
355
+
356
+ .ez-toc-toggle #item {
357
+ position: absolute;
358
+ left: -999em;
359
+ }
360
+
361
  label.cssicon .ez-toc-glyphicon:empty {
362
  font-size: 16px;
363
  margin-left: 2px;
370
  div#ez-toc-container.afterpara + p {
371
  display: none;
372
  }
373
+
374
  .ez-toc-widget-container ul li a {
375
+ padding-left: 10px
376
  }
377
+
378
  .ez-toc-widget-container ul.ez-toc-list li.active {
379
+ height: auto !important;
380
  }
assets/css/screen.min.css CHANGED
@@ -1,37 +1 @@
1
- #ez-toc-container {background: #F9F9F9;border: 1px solid #AAAAAA;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;}div.ez-toc-widget-container {padding: 0;position: relative;}#ez-toc-container.ez-toc-light-blue {background: #EDF6FF;}#ez-toc-container.ez-toc-white {background: #FFFFFF;}#ez-toc-container.ez-toc-black {background: #000000;}#ez-toc-container.ez-toc-transparent {background: none transparent;}div.ez-toc-widget-container ul {display: block;}div.ez-toc-widget-container li {border: none;padding: 0;}div.ez-toc-widget-container ul.ez-toc-list {padding: 10px;}#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, div.ez-toc-widget-container, div.ez-toc-widget-container li {background: none;list-style: none none;line-height: 1.6;margin: 0;overflow: hidden;z-index: 1;}#ez-toc-container p.ez-toc-title {text-align: left;line-height: 1.45;margin: 0;padding: 0;}.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;}#ez-toc-container div.ez-toc-title-container + 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;}#ez-toc-container a {color: #444444;box-shadow: none;text-decoration: none;text-shadow: none;}#ez-toc-container a:visited {color: #9f9f9f;}#ez-toc-container a:hover {text-decoration: underline;}#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: #444444;}#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;}#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, ".") ". ";display: inline-block;counter-increment: item;margin-right: .2em;}#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;}.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;}.ez-toc-widget-container ul.ez-toc-list li.active {background-color: #EDEDED;}.ez-toc-widget-container li.active > a {font-weight: 900;}.ez-toc-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 }.ez-toc-btn:focus {outline: thin dotted #333;outline: 5px auto -webkit-focus-ring-color;outline-offset: -2px }.ez-toc-btn:hover,.ez-toc-btn:focus {color: #333;text-decoration: none }.ez-toc-btn:active,.ez-toc-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) }.ez-toc-btn-default {color: #333;background-color: #fff;border-color: #ccc }.ez-toc-btn-default:hover,.ez-toc-btn-default:focus,.ez-toc-btn-default:active,.ez-toc-btn-default.active {color: #333;background-color: #ebebeb;border-color: #adadad }.ez-toc-btn-default:active,.ez-toc-btn-default.active {background-image: none }.ez-toc-btn-sm,.ez-toc-btn-xs {padding: 5px 10px;font-size: 12px;line-height: 1.5;border-radius: 3px }.ez-toc-btn-xs {padding: 1px 5px }.ez-toc-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) }.ez-toc-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) }.ez-toc-btn:active,.btn.active {background-image: none }.ez-toc-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) }.ez-toc-btn-default:hover,.ez-toc-btn-default:focus {background-color: #e0e0e0;background-position: 0 -15px }.ez-toc-btn-default:active,.ez-toc-btn-default.active {background-color: #e0e0e0;border-color: #dbdbdb }.ez-toc-pull-right {float: right !important;margin-left: 10px;}.ez-toc-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 }.ez-toc-glyphicon:empty {width: 1em }.ez-toc-toggle i.ez-toc-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;}.ez-toc-icon-toggle:before {content: "\e87a";}#ez-toc-container input {position: absolute;left: -999em;}#ez-toc-container input[type="checkbox"]:checked + nav {opacity: 0;max-height: 0;border: none;display: none;}#ez-toc-container label {float: right;position: relative;left: 3px;font-size: 16px;/* background: #f9efef; */padding: 0px 4px 0px 5px;border: 1px solid #999191;border-radius: 5px;cursor: pointer;}div#ez-toc-container p.ez-toc-title {display: contents;}div#ez-toc-container {padding-right: 20px;}#ez-toc-container label {left: 10px;}.ez-toc-wrap-center {margin: 0 auto;}
2
- #ez-toc-container.counter-hyphen ul.ez-toc-list li a::before,
3
-
4
- #ez-toc-container.counter-disc li,
5
- .ez-toc-widget-container.counter-disc li {
6
- list-style-type: disc;
7
- list-style-position: inside;
8
- }
9
-
10
- #ez-toc-container.counter-hyphen li,
11
- .ez-toc-widget-container.counter-hyphen li {
12
- list-style-type: '- ';
13
- list-style-position: inside;
14
-
15
- }
16
-
17
- #ez-toc-container a.ez-toc-toggle {
18
- color: #444444;
19
- background: inherit;
20
- border: inherit;
21
- }
22
- .ez-toc-toggle #item{position: absolute;left: -999em;}
23
-
24
- label.cssicon .ez-toc-glyphicon:empty {
25
- font-size: 16px;
26
- margin-left: 2px;
27
- }
28
- label.cssiconcheckbox {
29
- display: none;
30
- }
31
- div#ez-toc-container.afterpara + p {
32
- display: none;
33
- }
34
- .ez-toc-widget-container ul li a{padding-left:10px}
35
- .ez-toc-widget-container ul.ez-toc-list li.active {
36
- height: auto!important;
37
- }
1
+ #ez-toc-container{background:#f9f9f9;border:1px solid #aaa;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05);display:table;margin-bottom:1em;padding:10px;position:relative;width:auto}div.ez-toc-widget-container{padding:0;position:relative}#ez-toc-container.ez-toc-light-blue{background:#edf6ff}#ez-toc-container.ez-toc-white{background:#fff}#ez-toc-container.ez-toc-black{background:#000}#ez-toc-container.ez-toc-transparent{background:none}div.ez-toc-widget-container ul{display:block}div.ez-toc-widget-container li{border:none;padding:0}div.ez-toc-widget-container ul.ez-toc-list{padding:10px}#ez-toc-container ul ul,.ez-toc div.ez-toc-widget-container ul ul{margin-left:1.5em}#ez-toc-container li,#ez-toc-container ul{padding:0}#ez-toc-container li,#ez-toc-container ul,#ez-toc-container ul li,div.ez-toc-widget-container,div.ez-toc-widget-container li{background:0 0;list-style:none;line-height:1.6;margin:0;overflow:hidden;z-index:1}#ez-toc-container p.ez-toc-title{text-align:left;line-height:1.45;margin:0;padding:0}.ez-toc-title-container{display:table;width:100%}.ez-toc-title,.ez-toc-title-toggle{display:inline;text-align:left;vertical-align:middle}#ez-toc-container.ez-toc-black a,#ez-toc-container.ez-toc-black a:visited,#ez-toc-container.ez-toc-black p.ez-toc-title{color:#fff}#ez-toc-container div.ez-toc-title-container+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}#ez-toc-container a{color:#444;box-shadow:none;text-decoration:none;text-shadow:none}#ez-toc-container a:visited{color:#9f9f9f}#ez-toc-container a:hover{text-decoration:underline}.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}.ez-toc-widget-container ul.ez-toc-list li.active{background-color:#ededed;height:auto!important}.ez-toc-widget-container li.active>a{font-weight:900}.ez-toc-btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;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}.ez-toc-btn:focus{outline:#333 dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}.ez-toc-btn:focus,.ez-toc-btn:hover{color:#333;text-decoration:none}.ez-toc-btn.active,.ez-toc-btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.ez-toc-btn-default{color:#333;background-color:#fff;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);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:#ccc}.ez-toc-btn-default.active,.ez-toc-btn-default:active,.ez-toc-btn-default:focus,.ez-toc-btn-default:hover{color:#333;background-color:#ebebeb;border-color:#adadad}.ez-toc-btn-default.active,.ez-toc-btn-default:active{background-image:none;background-color:#e0e0e0;border-color:#dbdbdb}.ez-toc-btn-sm,.ez-toc-btn-xs{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.ez-toc-glyphicon,[class*=ez-toc-icon-]{font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.ez-toc-btn-xs{padding:1px 5px}.ez-toc-btn-default:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.active,.ez-toc-btn:active{background-image:none}.ez-toc-btn-default:focus,.ez-toc-btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.ez-toc-pull-right{float:right!important;margin-left:10px}.ez-toc-glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings'}.ez-toc-glyphicon:empty{width:1em}.ez-toc-toggle i.ez-toc-glyphicon,label.cssicon .ez-toc-glyphicon:empty{font-size:16px;margin-left:2px}[class*=ez-toc-icon-]{font-family:ez-toc-icomoon!important;speak:none;font-variant:normal;text-transform:none}.ez-toc-icon-toggle:before{content:"\e87a"}#ez-toc-container input,.ez-toc-toggle #item{position:absolute;left:-999em}#ez-toc-container input[type=checkbox]:checked+nav{opacity:0;max-height:0;border:none;display:none}#ez-toc-container label{float:right;position:relative;font-size:16px;padding:0 4px 0 5px;border:1px solid #999191;border-radius:5px;cursor:pointer;left:10px}div#ez-toc-container p.ez-toc-title{display:contents}div#ez-toc-container{padding-right:20px}.ez-toc-wrap-center{margin:0 auto}#ez-toc-container a.ez-toc-toggle{color:#444;background:inherit;border:inherit}div#ez-toc-container.afterpara+p,label.cssiconcheckbox{display:none}.ez-toc-widget-container ul li a{padding-left:10px}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/js/admin.js CHANGED
@@ -1,29 +1,97 @@
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
- var tableBody = document.getElementById('eztoc-appearance');
9
- var tableRows = tableBody.getElementsByTagName('tr');
10
- var targetElement = tableRows[1];
11
- targetElement.style.display = "none";
12
- document.getElementById('ez-toc-settings[width]').addEventListener('change', function () {
13
- if(document.getElementById('ez-toc-settings[width]').value == 'custom'){
14
- targetElement.style.display = "revert";
15
- }else{
16
- targetElement.style.display = "none";
17
- }
18
- });
19
- $("#subscribe-newsletter-form").on('submit',function(e){
20
  e.preventDefault();
21
  var $form = $("#subscribe-newsletter-form");
22
  var name = $form.find('input[name="name"]').val();
23
  var email = $form.find('input[name="email"]').val();
24
  var website = $form.find('input[name="company"]').val();
25
- $.post(ajaxurl, {action:'eztoc_subscribe_newsletter',name:name, email:email,website:website},
26
- function(data) {}
 
27
  );
28
  });
29
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ var tableBody = document.getElementById('eztoc-appearance');
9
+ var tableRows = tableBody.getElementsByTagName('tr');
10
+ var targetElement = tableRows[1];
11
+ targetElement.style.display = "none";
12
+ document.getElementById('ez-toc-settings[width]').addEventListener('change', function () {
13
+ if (document.getElementById('ez-toc-settings[width]').value == 'custom') {
14
+ targetElement.style.display = "revert";
15
+ } else {
16
+ targetElement.style.display = "none";
17
+ }
18
+ });
19
+ $("#subscribe-newsletter-form").on('submit', function (e) {
20
  e.preventDefault();
21
  var $form = $("#subscribe-newsletter-form");
22
  var name = $form.find('input[name="name"]').val();
23
  var email = $form.find('input[name="email"]').val();
24
  var website = $form.find('input[name="company"]').val();
25
+ $.post(ajaxurl, {action: 'eztoc_subscribe_newsletter', name: name, email: email, website: website, eztoc_security_nonce: cn_toc_admin_data.eztoc_security_nonce},
26
+ function (data) {
27
+ }
28
  );
29
  });
30
  });
31
+
32
+ /**
33
+ * DisableScrolling Function
34
+ * @since 2.0.33
35
+ */
36
+ function disableScrolling() {
37
+ var x=window.scrollX;
38
+ var y=window.scrollY;
39
+ window.onscroll=function(){window.scrollTo(x, y);};
40
+ }
41
+ /**
42
+ * EnableScrolling Function
43
+ * @since 2.0.33
44
+ */
45
+ function enableScrolling(){
46
+ window.onscroll=function(){};
47
+ }
48
+
49
+ /**
50
+ * unsecuredCopyToClipboard Function
51
+ * Clipboard JS
52
+ * @since 2.0.33
53
+ */
54
+ const unsecuredCopyToClipboard = (text) => {
55
+ const textArea = document.createElement("textarea");
56
+ textArea.value = text;
57
+ document.body.appendChild(textArea);
58
+ textArea.focus();
59
+ textArea.select();
60
+ try {
61
+ document.execCommand('copy')
62
+ } catch (err) {
63
+ console.error('Unable to copy to clipboard', err)
64
+ }
65
+ document.body.removeChild(textArea)
66
+ };
67
+ /**
68
+ * ez_toc_clipboard Function
69
+ * Clipboard JS
70
+ * @since 2.0.33
71
+ */
72
+ function ez_toc_clipboard(id, tooltipId, $this, event) {
73
+ event.preventDefault();
74
+ disableScrolling();
75
+ var copyText = $this.parentNode.parentNode.querySelectorAll("#" + id)[0];
76
+ copyText.select();
77
+ copyText.setSelectionRange(0, 99999);
78
+ // if (window.isSecureContext && navigator.clipboard) {
79
+ // navigator.clipboard.writeText(content);
80
+ // } else {
81
+ unsecuredCopyToClipboard(copyText.value);
82
+ // }
83
+
84
+ var tooltip = $this.querySelectorAll('span.' + tooltipId)[0];
85
+ tooltip.innerHTML = "Copied: " + copyText.value;
86
+ }
87
+ /**
88
+ * ez_toc_outFunc Function
89
+ * Clipboard JS
90
+ * @since 2.0.33
91
+ */
92
+ function ez_toc_outFunc(tooltipId, $this, event) {
93
+ event.preventDefault();
94
+ var tooltip = $this.querySelectorAll('span.' + tooltipId)[0];
95
+ tooltip.innerHTML = "Copy to clipboard";
96
+ enableScrolling();
97
+ }
assets/js/admin.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(document).ready((function(e){var t=e(".ez-toc-color-picker");t.length&&t.wpColorPicker();var n=document.getElementById("eztoc-appearance").getElementsByTagName("tr")[1];n.style.display="none",document.getElementById("ez-toc-settings[width]").addEventListener("change",(function(){"custom"==document.getElementById("ez-toc-settings[width]").value?n.style.display="revert":n.style.display="none"})),e("#subscribe-newsletter-form").on("submit",(function(t){t.preventDefault();var n=e("#subscribe-newsletter-form"),a=n.find('input[name="name"]').val(),i=n.find('input[name="email"]').val(),o=n.find('input[name="company"]').val();e.post(ajaxurl,{action:"eztoc_subscribe_newsletter",name:a,email:i,website:o},(function(e){}))}))}));
1
+ function disableScrolling(){var e=window.scrollX,n=window.scrollY;window.onscroll=function(){window.scrollTo(e,n)}}function enableScrolling(){window.onscroll=function(){}}jQuery(document).ready((function(e){var n=e(".ez-toc-color-picker");n.length&&n.wpColorPicker();var t=document.getElementById("eztoc-appearance").getElementsByTagName("tr")[1];t.style.display="none",document.getElementById("ez-toc-settings[width]").addEventListener("change",(function(){"custom"==document.getElementById("ez-toc-settings[width]").value?t.style.display="revert":t.style.display="none"})),e("#subscribe-newsletter-form").on("submit",(function(n){n.preventDefault();var t=e("#subscribe-newsletter-form"),o=t.find('input[name="name"]').val(),c=t.find('input[name="email"]').val(),l=t.find('input[name="company"]').val();e.post(ajaxurl,{action:"eztoc_subscribe_newsletter",name:o,email:c,website:l,eztoc_security_nonce:cn_toc_admin_data.eztoc_security_nonce},(function(e){}))}))}));const unsecuredCopyToClipboard=e=>{const n=document.createElement("textarea");n.value=e,document.body.appendChild(n),n.focus(),n.select();try{document.execCommand("copy")}catch(e){console.error("Unable to copy to clipboard",e)}document.body.removeChild(n)};function ez_toc_clipboard(e,n,t,o){o.preventDefault(),disableScrolling();var c=t.parentNode.parentNode.querySelectorAll("#"+e)[0];c.select(),c.setSelectionRange(0,99999),unsecuredCopyToClipboard(c.value),t.querySelectorAll("span."+n)[0].innerHTML="Copied: "+c.value}function ez_toc_outFunc(e,n,t){t.preventDefault(),n.querySelectorAll("span."+e)[0].innerHTML="Copy to clipboard",enableScrolling()}
assets/js/eztoc-admin.js CHANGED
@@ -1,94 +1,99 @@
1
- function tabToggle(evt, idname) {
2
- var i, tabcontent, tablinks;tabcontent = document.getElementsByClassName("eztoc-tabcontent");
3
- for (i = 0; i < tabcontent.length; i++) {
4
- tabcontent[i].style.display = "none";
5
- }
6
- tablinks = document.getElementsByClassName("eztoc-tablinks");
7
- for (i = 0; i < tablinks.length; i++) {
8
- tablinks[i].className = tablinks[i].className.replace(" active", "");
9
- }
10
- document.getElementById(idname).style.display = "block";
 
11
 
12
- evt.target.className += " active";
13
  }
14
 
15
  function eztocIsEmail(email) {
16
- var regex = /^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/;
17
- return regex.test(email);
18
  }
19
-
20
 
21
- //query form send starts here
22
- jQuery(document).ready(function($) {
23
 
24
- var url = window.location.href;
25
- if(url.indexOf('#technical-support') > -1){
26
- $("#eztoc-technical").click();
27
- }else if(url.indexOf('#freevspro-support') > -1){
28
- $("#eztoc-freevspro").click();
29
- }
30
- else if(url.indexOf('#welcome') > -1){
31
- $("#eztoc-welcome").click();
32
- }
33
- else{
34
- $("#eztoc-default").click();
35
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
- $(".eztoc-send-query").on("click", function(e){
38
- e.preventDefault();
39
- var message = $("#eztoc_query_message").val();
40
- var email = $("#eztoc_query_email").val();
41
- var premium_cus = $("#saswp_query_premium_cus").val();
42
-
43
- if($.trim(message) !='' && $.trim(email) !='' && eztocIsEmail(email) == true){
44
- $.ajax({
45
- type: "POST",
46
- url:ajaxurl,
47
- dataType: "json",
48
- data:{action:"eztoc_send_query_message",message:message,email:email, eztoc_security_nonce:eztoc_admin_data.eztoc_security_nonce},
49
- success:function(response){
50
- if(response['status'] =='t'){
51
- $(".eztoc-query-success").show();
52
- $(".eztoc-query-error").hide();
53
- }else{
54
- $(".eztoc-query-success").hide();
55
- $(".eztoc-query-error").show();
56
- }
57
- },
58
- error: function(response){
59
- console.log(response);
60
- }
61
- });
62
- }else{
63
-
64
- if($.trim(message) =='' && $.trim(email) ==''){
65
- alert('Please enter the message, email and select customer type');
66
- }else{
67
-
68
- if($.trim(message) == ''){
69
  alert('Please enter the message');
70
  }
71
- if($.trim(email) == ''){
72
  alert('Please enter the email');
73
  }
74
- if(eztocIsEmail(email) == false){
75
  alert('Please enter a valid email');
76
  }
77
-
78
- }
79
-
80
- }
81
 
82
- });
 
 
 
 
83
 
84
- $("#subscribe-newsletter-form").on('submit',function(e){
85
  e.preventDefault();
86
  var $form = $("#subscribe-newsletter-form");
87
  var name = $form.find('input[name="name"]').val();
88
  var email = $form.find('input[name="email"]').val();
89
  var website = $form.find('input[name="company"]').val();
90
- $.post(ajaxurl, {action:'eztoc_subscribe_newsletter',name:name, email:email,website:website},
91
- function(data) {}
 
92
  );
93
  });
94
- });
1
+ function ezTocTabToggle(evt, idname, tabContentClass = 'eztoc-tabcontent', tabLinksClass = 'eztoc-tablinks') {
2
+ var i, tabcontent, tablinks;
3
+ tabcontent = document.getElementsByClassName(tabContentClass);
4
+ for (i = 0; i < tabcontent.length; i++) {
5
+ tabcontent[i].style.display = "none";
6
+ }
7
+ tablinks = document.getElementsByClassName(tabLinksClass);
8
+ for (i = 0; i < tablinks.length; i++) {
9
+ tablinks[i].className = tablinks[i].className.replace(" active", "");
10
+ }
11
+ document.getElementById(idname).style.display = "block";
12
 
13
+ evt.target.className += " active";
14
  }
15
 
16
  function eztocIsEmail(email) {
17
+ var regex = /^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/;
18
+ return regex.test(email);
19
  }
 
20
 
 
 
21
 
22
+ //query form send starts here
23
+ jQuery(document).ready(function ($) {
24
+
25
+ var url = window.location.href;
26
+ if (url.indexOf('#technical-support') > -1) {
27
+ $("#eztoc-technical").click();
28
+ } else if (url.indexOf('#freevspro-support') > -1) {
29
+ $("#eztoc-freevspro").click();
30
+ } else if (url.indexOf('#welcome') > -1) {
31
+ $("#eztoc-welcome").click();
32
+ } else {
33
+ $("#eztoc-default").click();
34
+ }
35
+
36
+ $(".eztoc-send-query").on("click", function (e) {
37
+ e.preventDefault();
38
+ var message = $("#eztoc_query_message").val();
39
+ var email = $("#eztoc_query_email").val();
40
+ var premium_cus = $("#saswp_query_premium_cus").val();
41
+
42
+ if ($.trim(message) != '' && $.trim(email) != '' && eztocIsEmail(email) == true) {
43
+ $.ajax({
44
+ type: "POST",
45
+ url: ajaxurl,
46
+ dataType: "json",
47
+ data: {
48
+ action: "eztoc_send_query_message",
49
+ message: message,
50
+ email: email,
51
+ eztoc_security_nonce: eztoc_admin_data.eztoc_security_nonce
52
+ },
53
+ success: function (response) {
54
+ if (response['status'] == 't') {
55
+ $(".eztoc-query-success").show();
56
+ $(".eztoc-query-error").hide();
57
+ } else {
58
+ $(".eztoc-query-success").hide();
59
+ $(".eztoc-query-error").show();
60
+ }
61
+ },
62
+ error: function (response) {
63
+ console.log(response);
64
+ }
65
+ });
66
+ } else {
67
 
68
+ if ($.trim(message) == '' && $.trim(email) == '') {
69
+ alert('Please enter the message, email and select customer type');
70
+ } else {
71
+
72
+ if ($.trim(message) == '') {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  alert('Please enter the message');
74
  }
75
+ if ($.trim(email) == '') {
76
  alert('Please enter the email');
77
  }
78
+ if (eztocIsEmail(email) == false) {
79
  alert('Please enter a valid email');
80
  }
 
 
 
 
81
 
82
+ }
83
+
84
+ }
85
+
86
+ });
87
 
88
+ $("#subscribe-newsletter-form").on('submit', function (e) {
89
  e.preventDefault();
90
  var $form = $("#subscribe-newsletter-form");
91
  var name = $form.find('input[name="name"]').val();
92
  var email = $form.find('input[name="email"]').val();
93
  var website = $form.find('input[name="company"]').val();
94
+ $.post(ajaxurl, {action: 'eztoc_subscribe_newsletter', name: name, email: email, website: website, eztoc_security_nonce: eztoc_admin_data.eztoc_security_nonce},
95
+ function (data) {
96
+ }
97
  );
98
  });
99
+ });
assets/js/eztoc-admin.min.js ADDED
@@ -0,0 +1 @@
 
1
+ function ezTocTabToggle(e,t,a="eztoc-tabcontent",c="eztoc-tablinks"){var n,s,o;for(s=document.getElementsByClassName(a),n=0;n<s.length;n++)s[n].style.display="none";for(o=document.getElementsByClassName(c),n=0;n<o.length;n++)o[n].className=o[n].className.replace(" active","");document.getElementById(t).style.display="block",e.target.className+=" active"}function eztocIsEmail(e){return/^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/.test(e)}jQuery(document).ready((function(e){var t=window.location.href;t.indexOf("#technical-support")>-1?e("#eztoc-technical").click():t.indexOf("#freevspro-support")>-1?e("#eztoc-freevspro").click():t.indexOf("#welcome")>-1?e("#eztoc-welcome").click():e("#eztoc-default").click(),e(".eztoc-send-query").on("click",(function(t){t.preventDefault();var a=e("#eztoc_query_message").val(),c=e("#eztoc_query_email").val();e("#saswp_query_premium_cus").val();""!=e.trim(a)&&""!=e.trim(c)&&1==eztocIsEmail(c)?e.ajax({type:"POST",url:ajaxurl,dataType:"json",data:{action:"eztoc_send_query_message",message:a,email:c,eztoc_security_nonce:eztoc_admin_data.eztoc_security_nonce},success:function(t){"t"==t.status?(e(".eztoc-query-success").show(),e(".eztoc-query-error").hide()):(e(".eztoc-query-success").hide(),e(".eztoc-query-error").show())},error:function(e){console.log(e)}}):""==e.trim(a)&&""==e.trim(c)?alert("Please enter the message, email and select customer type"):(""==e.trim(a)&&alert("Please enter the message"),""==e.trim(c)&&alert("Please enter the email"),0==eztocIsEmail(c)&&alert("Please enter a valid email"))})),e("#subscribe-newsletter-form").on("submit",(function(t){t.preventDefault();var a=e("#subscribe-newsletter-form"),c=a.find('input[name="name"]').val(),n=a.find('input[name="email"]').val(),s=a.find('input[name="company"]').val();e.post(ajaxurl,{action:"eztoc_subscribe_newsletter",name:c,email:n,website:s,eztoc_security_nonce:eztoc_admin_data.eztoc_security_nonce},(function(e){}))}))}));
assets/js/front.js CHANGED
@@ -139,7 +139,8 @@ jQuery( function( $ ) {
139
  } else {
140
 
141
  toggle.data( 'visible', true );
142
- Cookies.remove('ezTOC_hidetoc')
 
143
  }
144
 
145
  if ( invert ) {
@@ -333,4 +334,10 @@ jQuery( function( $ ) {
333
  // Start EZ TOC on page load.
334
  ezTOCInit();
335
  }
 
 
 
 
 
 
336
  } );
139
  } else {
140
 
141
  toggle.data( 'visible', true );
142
+ // Cookies.remove('ezTOC_hidetoc');
143
+ delete_cookie('ezTOC_hidetoc');
144
  }
145
 
146
  if ( invert ) {
334
  // Start EZ TOC on page load.
335
  ezTOCInit();
336
  }
337
+ function set_cookie(name, value) {
338
+ document.cookie = name +'='+ value +'; Path=/;';
339
+ }
340
+ function delete_cookie(name) {
341
+ document.cookie = name +'=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
342
+ }
343
  } );
assets/js/front.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(function($){if("undefined"!=typeof ezTOC){function a(){if(0!==$(".ez-toc-widget-container.ez-toc-affix").length){var c=30;void 0!==ezTOC.scroll_offset&&(c=parseInt(ezTOC.scroll_offset)),$(ezTOC.affixSelector).stick_in_parent({inner_scrolling:!1,offset_top:c})}if($.fn.shrinkTOCWidth=function(){$(this).css({width:"auto",display:"table"}),/MSIE 7\./.test(navigator.userAgent)&&$(this).css("width","")},1===parseInt(ezTOC.smooth_scroll)&&$("a.ez-toc-link").on("click",function(){var c=$(this),a="",g=c.prop("hostname"),b=c.prop("pathname"),h=c.prop("search"),d=c.prop("hash");if(b.length>0&&"/"!==b.charAt(0)&&(b="/"+b),window.location.hostname===g&&window.location.pathname===b&&window.location.search===h&&""!==d){if(0===$(a='[id="'+d.replace("#","")+'"]').length&&(console.log("ezTOC scrollTarget Not Found: "+a),a=""),void 0!==ezTOC.scroll_offset)var e=-1*ezTOC.scroll_offset;else{var f=$("#wpadminbar");e=f.length>0&&f.is(":visible")?-30:0}a&&$.smoothScroll({scrollTarget:a,offset:e,beforeScroll:n,afterScroll:function(){m(),j()}})}}),void 0!==ezTOC.visibility_hide_by_default){var e=$("ul.ez-toc-list"),a=$("a.ez-toc-toggle"),f=ezTOC.visibility_hide_by_default;a.css("display","inline"),Cookies?(1==Cookies.get("ezTOC_hidetoc")?a.data("visible",!1):a.data("visible",!0),Cookies.remove("ezTOC_hidetoc")):(a.data("visible",!0),Cookies.remove("ezTOC_hidetoc")),f&&a.data("visible",!1),a.data("visible")||e.hide(),a.on("click",function(b){b.preventDefault();let a=document.querySelector("#ez-toc-container");if(a)a.classList.toggle("toc_close");else{let c=document.querySelector(".ez-toc-widget-container");c.classList.toggle("toc_close")}$(this).data("visible")?($(this).data("visible",!1),Cookies&&(f?Cookies.set("ezTOC_hidetoc",null,{path:"/"}):Cookies.set("ezTOC_hidetoc","1",{expires:30,path:"/"})),e.hide("fast")):($(this).data("visible",!0),Cookies&&(f?Cookies.set("ezTOC_hidetoc","1",{expires:30,path:"/"}):Cookies.set("ezTOC_hidetoc",null,{path:"/"})),e.show("fast"))})}var g,b,d,h=$("span.ez-toc-section").toArray(),i=(g=h).reduce(function(a,b){var c;return a[b.id]=$('.ez-toc-widget-container .ez-toc-list a[href="#'+$(b).attr("id")+'"]'),a},{}),k=$.map(i,function(a,b){return a}),l=(b=5,void 0!==ezTOC.smooth_scroll&&1===parseInt(ezTOC.smooth_scroll)&&(b=void 0!==ezTOC.scroll_offset?parseInt(ezTOC.scroll_offset):30),(d=$("#wpadminbar")).length&&(b+=d.height()),b);function m(){var a=o(l,h);if(a){var b=i[a.id];p(b,k),q(b)}}function j(){h.length>0&&$(".ez-toc-widget-container").length&&$(window).on("load resize scroll",m)}function n(){$(window).off("load resize scroll",m)}function o(c,a){var d=$(window).scrollTop()+c+1,b=a[0],e=d-$(b).offset().top;return a.forEach(function(c){var a=d-$(c).offset().top;a>0&&a<e&&(e=a,b=c)}),b}function p(b,a){a.forEach(function(a){b!==a&&a.parent().hasClass("active")&&a.parent().removeClass("active")})}function q(g){var i,h,a,d,b,e,f,c=g.parent();c.hasClass("active")||c.addClass("active"),f=(d=(a=$(h=c)).html(),a.parent().append('<li id="ez-toc-height-test" class="active">'+d+"</li>"),b=$("#ez-toc-height-test"),e=b.height(),b.remove(),e-a.children("ul").first().height()),$("#ez-toc-active-height").remove(),$('<style id="ez-toc-active-height">.ez-toc-widget-container ul.ez-toc-list li.active {height:'+f+"px;} </style>").appendTo("head")}j()}ezTOC.init=function(){a()},a()}})
1
+ jQuery((function(e){if("undefined"!=typeof ezTOC){function t(){var t;if(0!==e(".ez-toc-widget-container.ez-toc-affix").length){var o=30;void 0!==ezTOC.scroll_offset&&(o=parseInt(ezTOC.scroll_offset)),e(ezTOC.affixSelector).stick_in_parent({inner_scrolling:!1,offset_top:o})}if(e.fn.shrinkTOCWidth=function(){e(this).css({width:"auto",display:"table"}),/MSIE 7\./.test(navigator.userAgent)&&e(this).css("width","")},1===parseInt(ezTOC.smooth_scroll)&&e("a.ez-toc-link").on("click",(function(){var t=e(this),o="",i=t.prop("hostname"),n=t.prop("pathname"),s=t.prop("search"),a=t.prop("hash");if(n.length>0&&"/"!==n.charAt(0)&&(n="/"+n),window.location.hostname===i&&window.location.pathname===n&&window.location.search===s&&""!==a){if(o='[id="'+a.replace("#","")+'"]',0===e(o).length&&(console.log("ezTOC scrollTarget Not Found: "+o),o=""),void 0!==ezTOC.scroll_offset)var c=-1*ezTOC.scroll_offset;else{var l=e("#wpadminbar");c=l.length>0&&l.is(":visible")?-30:0}o&&e.smoothScroll({scrollTarget:o,offset:c,beforeScroll:d,afterScroll:function(){h(),f()}})}})),void 0!==ezTOC.visibility_hide_by_default){var i=e("ul.ez-toc-list"),n=e("a.ez-toc-toggle"),s=ezTOC.visibility_hide_by_default;n.css("display","inline"),Cookies?(1==Cookies.get("ezTOC_hidetoc")?n.data("visible",!1):n.data("visible",!0),Cookies.remove("ezTOC_hidetoc")):(n.data("visible",!0),t="ezTOC_hidetoc",document.cookie=t+"=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;"),s&&n.data("visible",!1),n.data("visible")||i.hide(),n.on("click",(function(t){t.preventDefault();const o=document.querySelector("#ez-toc-container");if(o)o.classList.toggle("toc_close");else{document.querySelector(".ez-toc-widget-container").classList.toggle("toc_close")}e(this).data("visible")?(e(this).data("visible",!1),Cookies&&(s?Cookies.set("ezTOC_hidetoc",null,{path:"/"}):Cookies.set("ezTOC_hidetoc","1",{expires:30,path:"/"})),i.hide("fast")):(e(this).data("visible",!0),Cookies&&(s?Cookies.set("ezTOC_hidetoc","1",{expires:30,path:"/"}):Cookies.set("ezTOC_hidetoc",null,{path:"/"})),i.show("fast"))}))}var a=e("span.ez-toc-section").toArray(),c=function(t){return t.reduce((function(t,o){return t[o.id]=function(t){return e('.ez-toc-widget-container .ez-toc-list a[href="#'+e(t).attr("id")+'"]')}(o),t}),{})}(a),l=e.map(c,(function(e,t){return e})),r=function(){var t=5;void 0!==ezTOC.smooth_scroll&&1===parseInt(ezTOC.smooth_scroll)&&(t=void 0!==ezTOC.scroll_offset?parseInt(ezTOC.scroll_offset):30);var o=e("#wpadminbar");o.length&&(t+=o.height());return t}();function h(){var t=function(t,o){var i=e(window).scrollTop()+t+1,n=o[0],s=i-e(n).offset().top;return o.forEach((function(t){var o=i-e(t).offset().top;o>0&&o<s&&(s=o,n=t)})),n}(r,a);if(t){var o=c[t.id];!function(e,t){t.forEach((function(t){e!==t&&t.parent().hasClass("active")&&t.parent().removeClass("active")}))}(o,l),function(t){var o=t.parent();o.hasClass("active")||o.addClass("active");!function(t){!function(t){e("#ez-toc-active-height").remove(),e('<style id="ez-toc-active-height">.ez-toc-widget-container ul.ez-toc-list li.active {height:'+t+"px;} </style>").appendTo("head")}(function(t){var o=e(t),i=o.html();o.parent().append('<li id="ez-toc-height-test" class="active">'+i+"</li>");var n=e("#ez-toc-height-test"),s=n.height();return n.remove(),s-o.children("ul").first().height()}(t))}(o)}(o)}}function f(){a.length>0&&e(".ez-toc-widget-container").length&&e(window).on("load resize scroll",h)}function d(){e(window).off("load resize scroll",h)}f()}ezTOC.init=function(){t()},t()}}));
easy-table-of-contents.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Easy Table of Contents
4
  * Plugin URI: https://magazine3.company/
5
  * Description: Adds a user friendly and fully automatic way to create and display a table of contents generated from the page content.
6
- * Version: 2.0.32
7
  * Author: Magazine3
8
  * Author URI: https://magazine3.company/
9
  * Text Domain: easy-table-of-contents
@@ -26,7 +26,7 @@
26
  * @package Easy Table of Contents
27
  * @category Plugin
28
  * @author Magazine3
29
- * @version 2.0.32
30
  */
31
 
32
  use Easy_Plugins\Table_Of_Contents\Debug;
@@ -48,7 +48,7 @@ if ( ! class_exists( 'ezTOC' ) ) {
48
  * @since 1.0
49
  * @var string
50
  */
51
- const VERSION = '2.0.32';
52
 
53
  /**
54
  * Stores the instance of this class.
@@ -235,15 +235,15 @@ if ( ! class_exists( 'ezTOC' ) ) {
235
  if (!ezTOC_Option::get( 'inline_css' )) {
236
  wp_register_style( 'ez-toc', EZ_TOC_URL . "assets/css/screen$min.css", array( 'ez-icomoon' ), ezTOC::VERSION );
237
  }
238
- wp_register_script( 'js-cookie', EZ_TOC_URL . "vendor/js-cookie/js.cookie$min.js", array(), '2.2.1', TRUE );
239
- wp_register_script( 'jquery-smooth-scroll', EZ_TOC_URL . "vendor/smooth-scroll/jquery.smooth-scroll$min.js", array( 'jquery' ), '2.2.0', TRUE );
240
- wp_register_script( 'jquery-sticky-kit', EZ_TOC_URL . "vendor/sticky-kit/jquery.sticky-kit$min.js", array( 'jquery' ), '1.9.2', TRUE );
241
 
242
  if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
243
  wp_register_script(
244
  'ez-toc-js',
245
  EZ_TOC_URL . "assets/js/front{$min}.js",
246
- array( 'jquery-smooth-scroll', 'js-cookie', 'jquery-sticky-kit' ),
247
  ezTOC::VERSION . '-' . filemtime( EZ_TOC_PATH . "/assets/js/front{$min}.js" ),
248
  true
249
  );
@@ -364,31 +364,215 @@ if ( ! class_exists( 'ezTOC' ) ) {
364
 
365
  wp_add_inline_style( 'ez-toc', $css );
366
  }
 
 
 
 
 
 
 
 
 
 
 
 
367
  }
368
 
369
- /**
370
- * inlineStickyToggleCSS Method
371
- * Prints out inline Sticky Toggle CSS after the core CSS file to allow overriding core styles via options.
372
- *
373
- * @since 2.0.32
374
- * @static
375
- */
376
- private static function inlineStickyToggleCSS() {
377
- $custom_width = 'max-width: auto;';
378
- if ( null !== ezTOC_Option::get( 'sticky-toggle-width-custom' ) && ! empty( ezTOC_Option::get(
379
- 'sticky-toggle-width-custom'
380
- ) ) ) {
381
- $custom_width = 'max-width: ' . ezTOC_Option::get( 'sticky-toggle-width-custom' ) . ';' . PHP_EOL;
382
- $custom_width .= 'min-width: ' . ezTOC_Option::get( 'sticky-toggle-width-custom' ) . ';' . PHP_EOL;
383
- }
384
- $custom_height = 'max-height: 100vh;';
385
- if ( null !== ezTOC_Option::get( 'sticky-toggle-height-custom' ) && ! empty( ezTOC_Option::get(
386
- 'sticky-toggle-height-custom'
387
- ) ) ) {
388
- $custom_height = 'max-height: ' . ezTOC_Option::get( 'sticky-toggle-height-custom' ) . ';' . PHP_EOL;
389
- $custom_height .= 'min-height: ' . ezTOC_Option::get( 'sticky-toggle-height-custom' ) . ';' . PHP_EOL;
390
- }
391
- $inlineStickyToggleCSS = <<<INLINESTICKYTOGGLECSS
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
392
  /**
393
  * Ez Toc Sidebar Sticky CSS
394
  */
@@ -543,15 +727,18 @@ function showBar(e) {
543
  }, 200);
544
  }
545
  (function() {
546
- document.body.addEventListener("click", function (evt) {
547
- hideBar(event);
548
- });
549
- document.querySelector('div.ez-toc-sticky-fixed').addEventListener('click', function(event) {
550
- event.stopPropagation();
551
- });
552
- document.querySelector('.ez-toc-open-icon').addEventListener('click', function(event) {
553
- event.stopPropagation();
554
- });
 
 
 
555
  })();
556
  INLINESTICKYTOGGLEJS;
557
  wp_add_inline_script( 'ez-toc-sticky', $inlineStickyToggleJS );
@@ -754,6 +941,11 @@ INLINESTICKYTOGGLEJS;
754
  $html = preg_replace('/class="ez-toc-list ez-toc-list-level-1"/', 'class="ez-toc-list ez-toc-list-level-1" style="display:none"', $html);
755
  }
756
 
 
 
 
 
 
757
  return $html;
758
  }
759
 
@@ -935,10 +1127,12 @@ INLINESTICKYTOGGLEJS;
935
  }
936
  }
937
 
938
- // @since 2.0.32
939
- if ( ezTOC_Option::get( 'sticky-toggle' ) ) {
940
- add_action( 'wp_footer', [ __CLASS__, 'stickyToggleContent' ] );
941
- }
 
 
942
 
943
  return Debug::log()->appendTo( $content );
944
  }
@@ -950,7 +1144,7 @@ INLINESTICKYTOGGLEJS;
950
  * @since 2.0.32
951
  * @static
952
  */
953
- public static function stickyToggleContent(): void {
954
  $post = self::get( get_the_ID() );
955
  if ( null !== $post ) {
956
  $stickyToggleTOC = $post->getStickyToggleTOC();
3
  * Plugin Name: Easy Table of Contents
4
  * Plugin URI: https://magazine3.company/
5
  * Description: Adds a user friendly and fully automatic way to create and display a table of contents generated from the page content.
6
+ * Version: 2.0.33
7
  * Author: Magazine3
8
  * Author URI: https://magazine3.company/
9
  * Text Domain: easy-table-of-contents
26
  * @package Easy Table of Contents
27
  * @category Plugin
28
  * @author Magazine3
29
+ * @version 2.0.33
30
  */
31
 
32
  use Easy_Plugins\Table_Of_Contents\Debug;
48
  * @since 1.0
49
  * @var string
50
  */
51
+ const VERSION = '2.0.33';
52
 
53
  /**
54
  * Stores the instance of this class.
235
  if (!ezTOC_Option::get( 'inline_css' )) {
236
  wp_register_style( 'ez-toc', EZ_TOC_URL . "assets/css/screen$min.css", array( 'ez-icomoon' ), ezTOC::VERSION );
237
  }
238
+ wp_register_script( 'ez-toc-js-cookie', EZ_TOC_URL . "vendor/js-cookie/js.cookie$min.js", array(), '2.2.1', TRUE );
239
+ wp_register_script( 'ez-toc-jquery-smooth-scroll', EZ_TOC_URL . "vendor/smooth-scroll/jquery.smooth-scroll$min.js", array( 'jquery' ), '2.2.0', TRUE );
240
+ wp_register_script( 'ez-toc-jquery-sticky-kit', EZ_TOC_URL . "vendor/sticky-kit/jquery.sticky-kit$min.js", array( 'jquery' ), '1.9.2', TRUE );
241
 
242
  if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
243
  wp_register_script(
244
  'ez-toc-js',
245
  EZ_TOC_URL . "assets/js/front{$min}.js",
246
+ array( 'ez-toc-jquery-smooth-scroll', 'ez-toc-js-cookie', 'ez-toc-jquery-sticky-kit' ),
247
  ezTOC::VERSION . '-' . filemtime( EZ_TOC_PATH . "/assets/js/front{$min}.js" ),
248
  true
249
  );
364
 
365
  wp_add_inline_style( 'ez-toc', $css );
366
  }
367
+
368
+ /**
369
+ * RTL Direction
370
+ * @since 2.0.33
371
+ */
372
+ self::InlineCountingCSS( ezTOC_Option::get( 'heading-text-direction' ) );
373
+ self::InlineCountingCSS( ezTOC_Option::get( 'heading-text-direction' ),'ez-toc-widget-direction','ez-toc-widget-container' );
374
+
375
+ if( ezTOC_Option::get( 'sticky-toggle' ) ) {
376
+ self::InlineCountingCSS( ezTOC_Option::get( 'heading-text-direction' ), 'ez-toc-sticky-toggle-direction', 'ez-toc-sticky-toggle-counter' );
377
+ }
378
+ /* End rtl direction */
379
  }
380
 
381
+ /**
382
+ * InlineCountingCSS Method
383
+ * @since 2.0.33
384
+ * @scope private
385
+ * @static
386
+ * @param string $direction
387
+ * @param string $directionClass
388
+ * @param string $class
389
+ * @param string $counter
390
+ * @return void
391
+ */
392
+ private static function InlineCountingCSS( $direction = 'ltr', $directionClass = 'ez-toc-container-direction', $class = 'ez-toc-counter', $counter = 'counter' )
393
+ {
394
+ $list_type = ezTOC_Option::get( $counter );
395
+ wp_enqueue_style('ez-toc');
396
+ $inlineCSS = '';
397
+ $counterListAll = array_merge(ezTOC_Option::getCounterListDecimal(), ezTOC_Option::getCounterList_i18n());
398
+ $listTypesForCounting = array_keys($counterListAll);
399
+ $inlineCSS .= <<<INLINECSS
400
+ .$directionClass {
401
+ direction: $direction;
402
+ }
403
+ INLINECSS;
404
+ if( in_array($list_type, $listTypesForCounting) ) {
405
+ if( $direction == 'rtl' ) {
406
+ $class .= '-rtl';
407
+ $directionClass .= '-rtl';
408
+ $length = 6;
409
+ $counterRTLCSS = self::rtlCounterResetCSS( $length, $class );
410
+ $counterRTLCSS .= self::rtlCounterIncrementCSS( $length, $class );
411
+ $counterRTLCSS .= self::rtlCounterContentCSS( $length, $list_type, $class );
412
+ $inlineCSS .= <<<INLINECSS
413
+ $counterRTLCSS
414
+ INLINECSS;
415
+ }
416
+ if( $direction == 'ltr' ) {
417
+ $inlineCSS .= <<<INLINECSS
418
+ .$class ul {
419
+ counter-reset: item;
420
+ }
421
+
422
+ .$class nav ul li a::before {
423
+ content: counters(item, ".", $list_type) ". ";
424
+ display: inline-block;
425
+ counter-increment: item;
426
+ margin-right: .2em;
427
+ }
428
+ INLINECSS;
429
+ }
430
+ } else {
431
+ $inlineCSS .= <<<INLINECSS
432
+ .$class ul {
433
+ counter-reset: item;
434
+ }
435
+ .$class nav ul li a::before {
436
+ content: counter(item, $list_type) " ";
437
+ margin-right: .2em;
438
+ }
439
+ INLINECSS;
440
+
441
+ }
442
+ wp_add_inline_style('ez-toc', $inlineCSS);
443
+ }
444
+
445
+ /**
446
+ * rtlCounterResetCSS Method
447
+ * @since 2.0.33
448
+ * @scope private
449
+ * @static
450
+ * @param int $length
451
+ * @param string $class
452
+ * @return string
453
+ */
454
+ private static function rtlCounterResetCSS( $length = 6, $class = 'ez-toc-counter-rtl' )
455
+ {
456
+ if ($length < 6) {
457
+ $length = 6;
458
+ }
459
+ $counterResetCSS = "";
460
+ for ($i = 1; $i <= $length; $i++) {
461
+ $ul = [];
462
+ for ($j = 1; $j <= $i; $j++) {
463
+ $ul[$j] = "ul";
464
+ }
465
+ $ul = implode(" ", $ul);
466
+ $items = [];
467
+ for ($j = $i; $j <= $length; $j++) {
468
+ $items[$j] = "item-level$j";
469
+ }
470
+ $items = implode(", ", $items);
471
+ $counterResetCSS .= <<<COUNTERRESETCSS
472
+ .$class $ul {
473
+ direction: rtl;
474
+ counter-reset: $items;
475
+ }\n\n
476
+ COUNTERRESETCSS;
477
+ }
478
+ return $counterResetCSS;
479
+ }
480
+
481
+ /**
482
+ * rtlCounterIncrementCSS Method
483
+ * @since 2.0.33
484
+ * @scope private
485
+ * @static
486
+ * @param int $length
487
+ * @param string $class
488
+ * @return string
489
+ */
490
+ private static function rtlCounterIncrementCSS( $length = 6, $class = 'ez-toc-counter-rtl' )
491
+ {
492
+ if ($length < 6) {
493
+ $length = 6;
494
+ }
495
+ $counterIncrementCSS = "";
496
+ for ($i = 1; $i <= $length; $i++) {
497
+ $ul = [];
498
+ for ($j = 1; $j <= $i; $j++) {
499
+ $ul[$j] = "ul";
500
+ }
501
+ $ul = implode(" ", $ul);
502
+ $item = "item-level$i";
503
+ $counterIncrementCSS .= <<<COUNTERINCREMENTCSS
504
+ .$class $ul li {
505
+ counter-increment: $item;
506
+ }\n\n
507
+ COUNTERINCREMENTCSS;
508
+ }
509
+ return $counterIncrementCSS;
510
+ }
511
+
512
+ /**
513
+ * rtlCounterContentCSS Method
514
+ * @since 2.0.33
515
+ * @scope private
516
+ * @static
517
+ * @param int $length
518
+ * @param string $list_type
519
+ * @param string $class
520
+ * @return string
521
+ */
522
+ private static function rtlCounterContentCSS( $length = 6, $list_type = 'decimal', $class = 'ez-toc-counter-rtl' )
523
+ {
524
+ if ($length < 6) {
525
+ $length = 6;
526
+ }
527
+ $counterContentCSS = "";
528
+ for ($i = 1; $i <= $length; $i++) {
529
+ $ul = [];
530
+ for ($j = 1; $j <= $i; $j++) {
531
+ $ul[$j] = "ul";
532
+ }
533
+ $ul = implode(" ", $ul);
534
+ $items = [];
535
+
536
+ $cnt = $i;
537
+ for ($j = 1; $j <= $i; $j++) {
538
+ $items[$cnt] = "counter(item-level$cnt, $list_type)";
539
+ $cnt--;
540
+ }
541
+ $items = implode(' "." ', $items);
542
+ $counterContentCSS .= <<<COUNTERINCREMENTCSS
543
+ .$class nav $ul li a::before {
544
+ content: $items " ";
545
+ }\n\n
546
+ COUNTERINCREMENTCSS;
547
+ }
548
+ return $counterContentCSS;
549
+ }
550
+
551
+
552
+ /**
553
+ * inlineStickyToggleCSS Method
554
+ * Prints out inline Sticky Toggle CSS after the core CSS file to allow overriding core styles via options.
555
+ *
556
+ * @since 2.0.32
557
+ * @static
558
+ */
559
+ private static function inlineStickyToggleCSS()
560
+ {
561
+ $custom_width = 'max-width: auto;';
562
+ if (null !== ezTOC_Option::get('sticky-toggle-width-custom') && !empty(ezTOC_Option::get(
563
+ 'sticky-toggle-width-custom'
564
+ ))) {
565
+ $custom_width = 'max-width: ' . ezTOC_Option::get('sticky-toggle-width-custom') . ';' . PHP_EOL;
566
+ $custom_width .= 'min-width: ' . ezTOC_Option::get('sticky-toggle-width-custom') . ';' . PHP_EOL;
567
+ }
568
+ $custom_height = 'max-height: 100vh;';
569
+ if (null !== ezTOC_Option::get('sticky-toggle-height-custom') && !empty(ezTOC_Option::get(
570
+ 'sticky-toggle-height-custom'
571
+ ))) {
572
+ $custom_height = 'max-height: ' . ezTOC_Option::get('sticky-toggle-height-custom') . ';' . PHP_EOL;
573
+ $custom_height .= 'min-height: ' . ezTOC_Option::get('sticky-toggle-height-custom') . ';' . PHP_EOL;
574
+ }
575
+ $inlineStickyToggleCSS = <<<INLINESTICKYTOGGLECSS
576
  /**
577
  * Ez Toc Sidebar Sticky CSS
578
  */
727
  }, 200);
728
  }
729
  (function() {
730
+ let ez_toc_sticky_fixed_container = document.querySelector('div.ez-toc-sticky-fixed');
731
+ if(ez_toc_sticky_fixed_container) {
732
+ document.body.addEventListener("click", function (evt) {
733
+ hideBar(event);
734
+ });
735
+ ez_toc_sticky_fixed_container.addEventListener('click', function(event) {
736
+ event.stopPropagation();
737
+ });
738
+ document.querySelector('.ez-toc-open-icon').addEventListener('click', function(event) {
739
+ event.stopPropagation();
740
+ });
741
+ }
742
  })();
743
  INLINESTICKYTOGGLEJS;
744
  wp_add_inline_script( 'ez-toc-sticky', $inlineStickyToggleJS );
941
  $html = preg_replace('/class="ez-toc-list ez-toc-list-level-1"/', 'class="ez-toc-list ez-toc-list-level-1" style="display:none"', $html);
942
  }
943
 
944
+ if( !is_home() ) {
945
+ if ( ezTOC_Option::get('sticky-toggle') ) {
946
+ add_action('wp_footer', array(__CLASS__, 'stickyToggleContent'));
947
+ }
948
+ }
949
  return $html;
950
  }
951
 
1127
  }
1128
  }
1129
 
1130
+ /**
1131
+ * @since 2.0.32
1132
+ */
1133
+ if ( ezTOC_Option::get('sticky-toggle') && !is_home() ) {
1134
+ add_action('wp_footer', array(__CLASS__, 'stickyToggleContent'));
1135
+ }
1136
 
1137
  return Debug::log()->appendTo( $content );
1138
  }
1144
  * @since 2.0.32
1145
  * @static
1146
  */
1147
+ public static function stickyToggleContent() {
1148
  $post = self::get( get_the_ID() );
1149
  if ( null !== $post ) {
1150
  $stickyToggleTOC = $post->getStickyToggleTOC();
includes/class.admin.php CHANGED
@@ -31,7 +31,12 @@ if ( ! class_exists( 'ezTOC_Admin' ) ) {
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 );
@@ -40,7 +45,23 @@ if ( ! class_exists( 'ezTOC_Admin' ) ) {
40
  add_action('wp_ajax_eztoc_send_query_message', array( $this, 'eztoc_send_query_message'));
41
  }
42
 
43
- /**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  * Callback to add the Settings link to the plugin action links.
45
  *
46
  * @access private
@@ -79,6 +100,14 @@ if ( ! class_exists( 'ezTOC_Admin' ) ) {
79
  // wp_enqueue_style( 'ez-toc' );
80
  // self::inlineStickyToggleCSS();
81
  wp_enqueue_script( 'cn_toc_admin_script' );
 
 
 
 
 
 
 
 
82
  self::inlineAdminStickyToggleJS();
83
 
84
  }
@@ -103,11 +132,12 @@ if ( ! class_exists( 'ezTOC_Admin' ) ) {
103
  */
104
  jQuery(function($) {
105
 
106
- var stickyToggleCheckbox = $('#eztoc-general').find("input[name='ez-toc-settings[sticky-toggle]']");
107
- var stickyToggleWidth = $('#eztoc-general').find("select[name='ez-toc-settings[sticky-toggle-width]']");
108
- var stickyToggleWidthCustom = $('#eztoc-general').find("input[name='ez-toc-settings[sticky-toggle-width-custom]']");
109
- var stickyToggleHeight = $('#eztoc-general').find("select[name='ez-toc-settings[sticky-toggle-height]']");
110
- var stickyToggleHeightCustom = $('#eztoc-general').find("input[name='ez-toc-settings[sticky-toggle-height-custom]']");
 
111
 
112
 
113
  $stickyToggleOpenButtonTextJS
@@ -537,7 +567,7 @@ INLINESTICKYTOGGLEJS;
537
 
538
  }
539
 
540
-
541
  /**
542
  * Enqueue Admin js scripts
543
  *
31
  * @static
32
  */
33
  private function hooks() {
34
+ global $pagenow;
35
 
36
+ if($pagenow == 'options-general.php' && isset($_REQUEST['page']) && !empty($_REQUEST['page']) &&
37
+ $_REQUEST['page'] == 'table-of-contents') {
38
+ add_action( 'admin_head', array( $this,'_clean_other_plugins_stuff' ) );
39
+ }
40
  add_action( 'admin_init', array( $this, 'registerScripts' ) );
41
  add_action( 'admin_menu', array( $this, 'menu' ) );
42
  add_action( 'init', array( $this, 'registerMetaboxes' ), 99 );
45
  add_action('wp_ajax_eztoc_send_query_message', array( $this, 'eztoc_send_query_message'));
46
  }
47
 
48
+ /**
49
+ * Attach to admin_head hook to hide all admin notices.
50
+ *
51
+ * @scope public
52
+ * @since 2.0.33
53
+ * @return void
54
+ * @uses remove_all_actions()
55
+ */
56
+ public function _clean_other_plugins_stuff()
57
+ {
58
+ remove_all_actions('admin_notices');
59
+ remove_all_actions('network_admin_notices');
60
+ remove_all_actions('all_admin_notices');
61
+ remove_all_actions('user_admin_notices');
62
+ }
63
+
64
+ /**
65
  * Callback to add the Settings link to the plugin action links.
66
  *
67
  * @access private
100
  // wp_enqueue_style( 'ez-toc' );
101
  // self::inlineStickyToggleCSS();
102
  wp_enqueue_script( 'cn_toc_admin_script' );
103
+ $data = array(
104
+ 'ajax_url' => admin_url( 'admin-ajax.php' ),
105
+ 'eztoc_security_nonce' => wp_create_nonce('eztoc_ajax_check_nonce'),
106
+ );
107
+
108
+ $data = apply_filters( 'eztoc_localize_filter', $data, 'eztoc_admin_data' );
109
+
110
+ wp_localize_script( 'cn_toc_admin_script', 'cn_toc_admin_data', $data );
111
  self::inlineAdminStickyToggleJS();
112
 
113
  }
132
  */
133
  jQuery(function($) {
134
 
135
+ let stickyToggleCheckbox = $('#eztoc-general').find("input[name='ez-toc-settings[sticky-toggle]']");
136
+ let stickyToggleWidth = $('#eztoc-general').find("select[name='ez-toc-settings[sticky-toggle-width]']");
137
+ let stickyToggleWidthCustom = $('#eztoc-general').find("input[name='ez-toc-settings[sticky-toggle-width-custom]']");
138
+ let stickyToggleHeight = $('#eztoc-general').find("select[name='ez-toc-settings[sticky-toggle-height]']");
139
+ let stickyToggleHeightCustom = $('#eztoc-general').find("input[name='ez-toc-settings[sticky-toggle-height-custom]']");
140
+
141
 
142
 
143
  $stickyToggleOpenButtonTextJS
567
 
568
  }
569
 
570
+
571
  /**
572
  * Enqueue Admin js scripts
573
  *
includes/class.options.php CHANGED
@@ -61,6 +61,8 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
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
  }
@@ -252,14 +254,7 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
252
  'name' => __( 'Counter', 'easy-table-of-contents' ),
253
  'desc' => '',
254
  'type' => 'select',
255
- 'options' => array(
256
- 'decimal' => __( 'Decimal (default)', 'easy-table-of-contents' ),
257
- 'disc' => __( 'Disc', 'easy-table-of-contents' ),
258
- 'hyphen' => __( 'Hyphen', 'easy-table-of-contents' ),
259
- 'numeric' => __( 'Numeric', 'easy-table-of-contents' ),
260
- 'roman' => __( 'Roman', 'easy-table-of-contents' ),
261
- 'none' => __( 'None', 'easy-table-of-contents' ),
262
- ),
263
  'default' => 'decimal',
264
  ),
265
  'smooth_scroll' => array(
@@ -535,6 +530,17 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
535
  'type' => 'color',
536
  'default' => '#428bca',
537
  ),
 
 
 
 
 
 
 
 
 
 
 
538
  )
539
  ),
540
  'advanced' => apply_filters(
@@ -668,6 +674,52 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
668
 
669
  )
670
  ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
671
  'prosettings' => apply_filters(
672
  'ez_toc_settings_prosettings',
673
  array(
@@ -706,6 +758,111 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
706
  return apply_filters( 'ez_toc_registered_settings', $options );
707
  }
708
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
709
  /**
710
  * The default values for the registered settings and options.
711
  *
@@ -1333,7 +1490,8 @@ HR_TAG;
1333
  */
1334
  public static function header( $args ) {
1335
 
1336
- echo '<hr/>';
 
1337
 
1338
  if ( 0 < strlen( $args['desc'] ) ) {
1339
 
@@ -1341,6 +1499,30 @@ HR_TAG;
1341
  }
1342
  }
1343
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1344
  /**
1345
  * Descriptive text callback.
1346
  *
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
+ 'without_hr' => isset( $option['without_hr'] ) ? $option['without_hr'] : true,
65
+ 'allowedHtml' => isset( $option['allowedHtml'] ) ? $option['allowedHtml'] : [],
66
  )
67
  );
68
  }
254
  'name' => __( 'Counter', 'easy-table-of-contents' ),
255
  'desc' => '',
256
  'type' => 'select',
257
+ 'options' => self::getCounterList(),
 
 
 
 
 
 
 
258
  'default' => 'decimal',
259
  ),
260
  'smooth_scroll' => array(
530
  'type' => 'color',
531
  'default' => '#428bca',
532
  ),
533
+ 'heading-text-direction' => array(
534
+ 'id' => 'heading-text-direction',
535
+ 'name' => __( 'Heading Text Direction', 'easy-table-of-contents' ),
536
+ 'desc' => '',
537
+ 'type' => 'radio',
538
+ 'options' => array(
539
+ 'ltr' => __( 'Left to Right (LTR)', 'easy-table-of-contents' ),
540
+ 'rtl' => __( 'Right to Left (RTL)', 'easy-table-of-contents' ),
541
+ ),
542
+ 'default' => 'ltr',
543
+ ),
544
  )
545
  ),
546
  'advanced' => apply_filters(
674
 
675
  )
676
  ),
677
+ 'shortcode' => apply_filters(
678
+ 'ez_toc_settings_shortcode',
679
+ array(
680
+ // 'shortcode-heading-paragraph' => array(
681
+ // 'id' => 'shortcode-heading-paragraph',
682
+ // 'name' => '',
683
+ // 'desc' => __( 'There are several ways to have the easy table of contents display on your website.', 'easy-table-of-contents' ),
684
+ // 'type' => 'paragraph',
685
+ // ),
686
+ 'shortcode-first-paragraph' => array(
687
+ 'id' => 'shortcode-first-paragraph',
688
+ 'name' => __( 'Manual Adding the shortcode', 'easy-table-of-contents' ),
689
+ 'desc' => __( 'You can use the following shortcode to `Easy Table of Contents` display in your particular post or page:<br/><input type="text" id="ez-toc-clipboard-apply" value="[ez-toc]" disabled />&nbsp;<span class="ez-toc-tooltip"><button type="button" onclick="ez_toc_clipboard(\'ez-toc-clipboard-apply\', \'ez-toc-myTooltip\', this, event)" onmouseout="ez_toc_outFunc(\'ez-toc-myTooltip\', this, event)"><span class="ez-toc-tooltiptext ez-toc-myTooltip">Copy to clipboard</span>Copy shortcode </button></span>', 'easy-table-of-contents' ),
690
+ 'type' => 'paragraph',
691
+ 'allowedHtml' => array(
692
+ 'br' => array(),
693
+ 'input' => array(
694
+ 'type' => true,
695
+ 'id' => true,
696
+ 'value' => true,
697
+ 'readonly' => true,
698
+ 'disabled' => true,
699
+ 'class' => true,
700
+ ),
701
+ '&nbsp;' => array(),
702
+ 'span' => array(
703
+ 'class' => true,
704
+ 'id' => true,
705
+ ),
706
+ 'button' => array(
707
+ 'type' => true,
708
+ 'onclick' => true,
709
+ 'onmouseout' => true,
710
+ 'id' => true,
711
+ 'class' => true,
712
+ ),
713
+ ),
714
+ ),
715
+ 'shortcode-second-paragraph' => array(
716
+ 'id' => 'shortcode-second-paragraph',
717
+ 'name' => __( 'Auto Insert', 'easy-table-of-contents' ),
718
+ 'desc' => __( 'You can add `Easy Table of Contents` without using shortcode from `Auto Insert` option in General Setting so then there is no need to add shortcode while post, page or any post type editing.', 'easy-table-of-contents' ),
719
+ 'type' => 'paragraph',
720
+ ),
721
+ )
722
+ ),
723
  'prosettings' => apply_filters(
724
  'ez_toc_settings_prosettings',
725
  array(
758
  return apply_filters( 'ez_toc_registered_settings', $options );
759
  }
760
 
761
+ /**
762
+ * getCounterListBasic Method
763
+ * @since 2.0.33
764
+ * @scope protected
765
+ * @static
766
+ * @return array
767
+ */
768
+ protected static function getCounterList() {
769
+ return array_merge( self::getCounterListBasic(), self::getCounterListDecimal(), self::getCounterList_i18n() );
770
+ }
771
+
772
+ /**
773
+ * getCounterListBasic Method
774
+ * @since 2.0.33
775
+ * @scope public
776
+ * @static
777
+ * @return array
778
+ */
779
+ public static function getCounterListBasic() {
780
+ return array(
781
+ 'none' => __( 'None', 'easy-table-of-contents' ),
782
+ 'disc' => __( 'Disc', 'easy-table-of-contents' ),
783
+ 'circle' => __( 'Circle', 'easy-table-of-contents' ),
784
+ 'square' => __( 'Square', 'easy-table-of-contents' ),
785
+ '- ' => __( 'Hyphen', 'easy-table-of-contents' ),
786
+ 'cjk-earthly-branch' => __( 'Earthly Branch', 'easy-table-of-contents' ),
787
+ 'disclosure-open' => __( 'Disclosure Open', 'easy-table-of-contents' ),
788
+ 'disclosure-closed' => __( 'Disclosure Closed', 'easy-table-of-contents' ),
789
+ 'numeric' => __( 'Numeric', 'easy-table-of-contents' ),
790
+ );
791
+ }
792
+
793
+ /**
794
+ * getCounterListDecimal Method
795
+ * @since 2.0.33
796
+ * @scope public
797
+ * @static
798
+ * @return array
799
+ */
800
+ public static function getCounterListDecimal() {
801
+ return array(
802
+ 'decimal' => __( 'Decimal (default)', 'easy-table-of-contents' ),
803
+ 'decimal-leading-zero' => __( 'Decimal Leading Zero', 'easy-table-of-contents' ),
804
+ 'cjk-decimal' => __( 'CJK Decimal', 'easy-table-of-contents' ),
805
+ );
806
+ }
807
+
808
+ /**
809
+ * getCounterList_i18n Method
810
+ * @since 2.0.33
811
+ * @scope public
812
+ * @static
813
+ * @return array
814
+ */
815
+ public static function getCounterList_i18n() {
816
+ return array(
817
+ 'upper-roman' => __( 'Upper Roman', 'easy-table-of-contents' ),
818
+ 'lower-roman' => __( 'Lower Roman', 'easy-table-of-contents' ),
819
+ 'upper-greek' => __( 'Upper Greek', 'easy-table-of-contents' ),
820
+ 'lower-greek' => __( 'Lower Greek', 'easy-table-of-contents' ),
821
+ 'upper-alpha' => __( 'Upper Alpha/Latin', 'easy-table-of-contents' ),
822
+ 'lower-alpha' => __( 'Lower Alpha/Latin', 'easy-table-of-contents' ),
823
+ 'armenian' => __( 'Armenian', 'easy-table-of-contents' ),
824
+ 'lower-armenian' => __( 'Lower Armenian', 'easy-table-of-contents' ),
825
+ 'arabic-indic' => __( 'Arabic', 'easy-table-of-contents' ),
826
+ 'bengali' => __( 'Bengali', 'easy-table-of-contents' ),
827
+ 'cambodian' => __( 'Cambodian/Khmer', 'easy-table-of-contents' ),
828
+ 'cjk-heavenly-stem' => __( 'Heavenly Stem', 'easy-table-of-contents' ),
829
+ 'cjk-ideographic' => __( 'CJK Ideographic/trad-chinese-informal', 'easy-table-of-contents' ),
830
+ 'devanagari' => __( 'Hindi (Devanagari)', 'easy-table-of-contents' ),
831
+ 'ethiopic-numeric' => __( 'Ethiopic', 'easy-table-of-contents' ),
832
+ 'georgian' => __( 'Georgian', 'easy-table-of-contents' ),
833
+ 'gujarati' => __( 'Gujarati', 'easy-table-of-contents' ),
834
+ 'gurmukhi' => __( 'Gurmukhi', 'easy-table-of-contents' ),
835
+ 'hebrew' => __( 'Hebrew', 'easy-table-of-contents' ),
836
+ 'hiragana' => __( 'Hiragana', 'easy-table-of-contents' ),
837
+ 'hiragana-iroha' => __( 'Hiragana-Iroha', 'easy-table-of-contents' ),
838
+ 'japanese-formal' => __( 'Japanese Formal', 'easy-table-of-contents' ),
839
+ 'japanese-informal' => __( 'Japanese Informal', 'easy-table-of-contents' ),
840
+ 'kannada' => __( 'Kannada', 'easy-table-of-contents' ),
841
+ 'katakana' => __( 'Katakana', 'easy-table-of-contents' ),
842
+ 'katakana-iroha' => __( 'Katakana-Iroha', 'easy-table-of-contents' ),
843
+ 'korean-hangul-formal' => __( 'Korean Hangul Formal', 'easy-table-of-contents' ),
844
+ 'korean-hanja-formal' => __( 'Korean Hanja Formal', 'easy-table-of-contents' ),
845
+ 'korean-hanja-informal' => __( 'Korean Hanja Informal', 'easy-table-of-contents' ),
846
+ 'lao' => __( 'Laotian', 'easy-table-of-contents' ),
847
+ 'malayalam' => __( 'Malayalam', 'easy-table-of-contents' ),
848
+ 'mongolian' => __( 'Mongolian', 'easy-table-of-contents' ),
849
+ 'myanmar' => __( 'Myanmar', 'easy-table-of-contents' ),
850
+ 'oriya' => __( 'Oriya', 'easy-table-of-contents' ),
851
+ 'persian' => __( 'Persian', 'easy-table-of-contents' ),
852
+ 'simp-chinese-formal' => __( 'Simplified Chinese Formal', 'easy-table-of-contents' ),
853
+ 'simp-chinese-informal' => __( 'Simplified Chinese Informal', 'easy-table-of-contents' ),
854
+ 'tamil' => __( 'Tamil', 'easy-table-of-contents' ),
855
+ 'telugu' => __( 'Telugu', 'easy-table-of-contents' ),
856
+ 'thai' => __( 'Thai', 'easy-table-of-contents' ),
857
+ 'tibetan' => __( 'Tibetan', 'easy-table-of-contents' ),
858
+ 'trad-chinese-formal' => __( 'Traditional Chinese Formal', 'easy-table-of-contents' ),
859
+ 'trad-chinese-informal' => __( 'Traditional Chinese Informal', 'easy-table-of-contents' ),
860
+ 'hangul' => __( 'Hangul', 'easy-table-of-contents' ),
861
+ 'hangul-consonant' => __( 'Hangul Consonant', 'easy-table-of-contents' ),
862
+ 'urdu' => __( 'Urdu', 'easy-table-of-contents' ),
863
+ );
864
+ }
865
+
866
  /**
867
  * The default values for the registered settings and options.
868
  *
1490
  */
1491
  public static function header( $args ) {
1492
 
1493
+ if( !isset( $args['without_hr'] ) || ( isset( $args['without_hr'] ) && $args['without_hr']) )
1494
+ echo '<hr/>';
1495
 
1496
  if ( 0 < strlen( $args['desc'] ) ) {
1497
 
1499
  }
1500
  }
1501
 
1502
+ /**
1503
+ * Paragraph Callback
1504
+ *
1505
+ * Renders the paragraph.
1506
+ *
1507
+ * @access public
1508
+ * @since 2.0.33
1509
+ * @static
1510
+ *
1511
+ * @param array $args Arguments passed by the setting
1512
+ * @return void
1513
+ */
1514
+ public static function paragraph( $args ) {
1515
+
1516
+ if ( 0 < strlen( $args['desc'] ) ) {
1517
+
1518
+ $allowed_html = [];
1519
+ if( is_array( $args['allowedHtml'] ) && count( $args['allowedHtml'] ) > 0 ) {
1520
+ $allowed_html = $args['allowedHtml'];
1521
+ }
1522
+ echo '<p>' . wp_kses( $args['desc'] , $allowed_html ) . '</p>';
1523
+ }
1524
+ }
1525
+
1526
  /**
1527
  * Descriptive text callback.
1528
  *
includes/class.post.php CHANGED
@@ -1097,33 +1097,22 @@ class ezTOC_Post {
1097
  $htmlSticky = '';
1098
  if ( $this->hasTOCItems() ) {
1099
  $classSticky[] = 'counter-flat';
1100
- switch ( ezTOC_Option::get( 'counter' ) ) {
1101
-
1102
- case 'numeric':
1103
- $classSticky[] .= 'counter-numeric';
1104
- break;
1105
-
1106
- case 'roman':
1107
- $classSticky[] = 'counter-roman';
1108
- break;
1109
 
1110
- case 'decimal':
1111
- $classSticky[] = 'counter-decimal';
1112
- break;
1113
 
1114
- case 'hyphen':
1115
- $classSticky[] = 'counter-hyphen';
1116
- break;
1117
 
1118
- case 'disc':
1119
- $classSticky[] = 'counter-disc';
1120
- break;
1121
- }
1122
  $classSticky = array_filter( $classSticky );
1123
  $classSticky = array_map( 'trim', $classSticky );
1124
  $classSticky = array_map( 'sanitize_html_class', $classSticky );
1125
 
1126
 
 
 
1127
  if ( ezTOC_Option::get( 'show_heading_text' ) ) {
1128
  $toc_title = ezTOC_Option::get( 'heading_text' );
1129
  if ( strpos( $toc_title, '%PAGE_TITLE%' ) !== false ) {
@@ -1147,11 +1136,11 @@ class ezTOC_Post {
1147
  }
1148
  $htmlSticky .= '<div id="ez-toc-sticky-container" class="' . implode( ' ', $classSticky ) . '">' . PHP_EOL;
1149
  ob_start();
1150
- do_action( 'ez_toc_before' );
1151
  $htmlSticky .= ob_get_clean();
1152
- $htmlSticky .= '<nav>' . $this->getTOCList( "ez-toc-sticky" ) . '</nav>';
1153
  ob_start();
1154
- do_action( 'ez_toc_after' );
1155
  $htmlSticky .= ob_get_clean();
1156
  $htmlSticky .= '</div>' . PHP_EOL;
1157
  // Enqueue the script.
@@ -1203,29 +1192,12 @@ class ezTOC_Post {
1203
  $class[] .= 'counter-flat';
1204
  }
1205
 
1206
- switch ( ezTOC_Option::get( 'counter' ) ) {
1207
-
1208
- case 'numeric':
1209
- $class[] .= 'counter-numeric';
1210
- break;
1211
-
1212
- case 'roman':
1213
- $class[] = 'counter-roman';
1214
- break;
1215
-
1216
- case 'decimal':
1217
- $class[] = 'counter-decimal';
1218
- break;
1219
-
1220
- case 'hyphen':
1221
- $class[] = 'counter-hyphen';
1222
- break;
1223
-
1224
- case 'disc':
1225
- $class[] = 'counter-disc';
1226
- break;
1227
- }
1228
-
1229
  // colour themes
1230
  switch ( ezTOC_Option::get( 'theme' ) ) {
1231
 
@@ -1256,6 +1228,8 @@ class ezTOC_Post {
1256
  if($position == 'afterpara'){
1257
  $custom_classes .= "afterpara";
1258
  }
 
 
1259
 
1260
  if ( 0 < strlen( $custom_classes ) ) {
1261
 
@@ -1271,6 +1245,7 @@ class ezTOC_Post {
1271
  $class = array_filter( $class );
1272
  $class = array_map( 'trim', $class );
1273
  $class = array_map( 'sanitize_html_class', $class );
 
1274
  $html .= '<div id="ez-toc-container" class="' . implode( ' ', $class ) . '">' . PHP_EOL;
1275
 
1276
  if ( ezTOC_Option::get( 'show_heading_text' ) ) {
1097
  $htmlSticky = '';
1098
  if ( $this->hasTOCItems() ) {
1099
  $classSticky[] = 'counter-flat';
1100
+ if( ezTOC_Option::get( 'heading-text-direction' ) == 'ltr' ) {
1101
+ $classSticky[] = 'ez-toc-sticky-toggle-counter';
1102
+ }
1103
+ if( ezTOC_Option::get( 'heading-text-direction' ) == 'rtl' ) {
1104
+ $classSticky[] = 'ez-toc-sticky-toggle-counter-rtl';
1105
+ }
 
 
 
1106
 
 
 
 
1107
 
 
 
 
1108
 
 
 
 
 
1109
  $classSticky = array_filter( $classSticky );
1110
  $classSticky = array_map( 'trim', $classSticky );
1111
  $classSticky = array_map( 'sanitize_html_class', $classSticky );
1112
 
1113
 
1114
+ $ezTocStickyToggleDirection = 'ez-toc-sticky-toggle-direction';
1115
+
1116
  if ( ezTOC_Option::get( 'show_heading_text' ) ) {
1117
  $toc_title = ezTOC_Option::get( 'heading_text' );
1118
  if ( strpos( $toc_title, '%PAGE_TITLE%' ) !== false ) {
1136
  }
1137
  $htmlSticky .= '<div id="ez-toc-sticky-container" class="' . implode( ' ', $classSticky ) . '">' . PHP_EOL;
1138
  ob_start();
1139
+ do_action( 'ez_toc_sticky_toggle_before' );
1140
  $htmlSticky .= ob_get_clean();
1141
+ $htmlSticky .= "<nav class='$ezTocStickyToggleDirection'>" . $this->getTOCList( "ez-toc-sticky" ) . "</nav>";
1142
  ob_start();
1143
+ do_action( 'ez_toc_sticky_toggle_after' );
1144
  $htmlSticky .= ob_get_clean();
1145
  $htmlSticky .= '</div>' . PHP_EOL;
1146
  // Enqueue the script.
1192
  $class[] .= 'counter-flat';
1193
  }
1194
 
1195
+ if( ezTOC_Option::get( 'heading-text-direction' ) == 'ltr' ) {
1196
+ $class[] = 'ez-toc-counter';
1197
+ }
1198
+ if( ezTOC_Option::get( 'heading-text-direction' ) == 'rtl' ) {
1199
+ $class[] = 'ez-toc-counter-rtl';
1200
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1201
  // colour themes
1202
  switch ( ezTOC_Option::get( 'theme' ) ) {
1203
 
1228
  if($position == 'afterpara'){
1229
  $custom_classes .= "afterpara";
1230
  }
1231
+
1232
+ $class[] = 'ez-toc-container-direction';
1233
 
1234
  if ( 0 < strlen( $custom_classes ) ) {
1235
 
1245
  $class = array_filter( $class );
1246
  $class = array_map( 'trim', $class );
1247
  $class = array_map( 'sanitize_html_class', $class );
1248
+
1249
  $html .= '<div id="ez-toc-container" class="' . implode( ' ', $class ) . '">' . PHP_EOL;
1250
 
1251
  if ( ezTOC_Option::get( 'show_heading_text' ) ) {
includes/class.widget-toc.php CHANGED
@@ -189,35 +189,21 @@ if ( ! class_exists( 'ezTOC_Widget' ) ) {
189
  $class[] = 'counter-flat';
190
  }
191
 
192
- switch ( ezTOC_Option::get( 'counter' ) ) {
193
-
194
- case 'numeric':
195
- $class[] = 'counter-numeric';
196
- break;
197
-
198
- case 'roman':
199
- $class[] = 'counter-roman';
200
- break;
201
-
202
- case 'decimal':
203
- $class[] = 'counter-decimal';
204
- break;
205
-
206
- case 'hyphen':
207
- $class[] = 'counter-hyphen';
208
- break;
209
-
210
- case 'disc':
211
- $class[] = 'counter-disc';
212
- break;
213
-
214
- }
215
 
216
  if ( $instance['affix'] ) {
217
 
218
  $class[] = 'ez-toc-affix';
219
  }
220
 
 
 
 
221
  $custom_classes = ezTOC_Option::get( 'css_container_class', '' );
222
 
223
  if ( 0 < strlen( $custom_classes ) ) {
189
  $class[] = 'counter-flat';
190
  }
191
 
192
+ if( ezTOC_Option::get( 'heading-text-direction' ) == 'ltr' ) {
193
+ $class[] = 'ez-toc-widget-container';
194
+ }
195
+ if( ezTOC_Option::get( 'heading-text-direction' ) == 'rtl' ) {
196
+ $class[] = 'ez-toc-widget-container-rtl';
197
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
198
 
199
  if ( $instance['affix'] ) {
200
 
201
  $class[] = 'ez-toc-affix';
202
  }
203
 
204
+
205
+ $class[] = 'ez-toc-widget-direction';
206
+
207
  $custom_classes = ezTOC_Option::get( 'css_container_class', '' );
208
 
209
  if ( 0 < strlen( $custom_classes ) ) {
includes/deactivate-feedback.php CHANGED
@@ -1,37 +1,37 @@
1
- <?php
2
- $reasons = array(
3
- 1 => '<li><label><input type="radio" name="eztoc_disable_reason" value="temporary"/>' . __('It is only temporary', 'easy-table-of-contents') . '</label></li>',
4
- 2 => '<li><label><input type="radio" name="eztoc_disable_reason" value="stopped showing toc"/>' . __('I stopped showing TOC on my site', 'easy-table-of-contents') . '</label></li>',
5
- 3 => '<li><label><input type="radio" name="eztoc_disable_reason" value="missing feature"/>' . __('I miss a feature', 'easy-table-of-contents') . '</label></li>
6
- <li><input type="text" name="eztoc_disable_text[]" value="" placeholder="Please describe the feature"/></li>',
7
- 4 => '<li><label><input type="radio" name="eztoc_disable_reason" value="technical issue"/>' . __('Technical Issue', 'easy-table-of-contents') . '</label></li>
8
- <li><textarea name="eztoc_disable_text[]" placeholder="' . __('Can we help? Please describe your problem', 'easy-table-of-contents') . '"></textarea></li>',
9
- 5 => '<li><label><input type="radio" name="eztoc_disable_reason" value="other plugin"/>' . __('I switched to another plugin', 'easy-table-of-contents') . '</label></li>
10
- <li><input type="text" name="eztoc_disable_text[]" value="" placeholder="Name of the plugin"/></li>',
11
- 6 => '<li><label><input type="radio" name="eztoc_disable_reason" value="other"/>' . __('Other reason', 'easy-table-of-contents') . '</label></li>
12
- <li><textarea name="eztoc_disable_text[]" placeholder="' . __('Please specify, if possible', 'easy-table-of-contents') . '"></textarea></li>',
13
- );
14
- shuffle($reasons);
15
- ?>
16
-
17
-
18
- <div id="eztoc-reloaded-feedback-overlay" style="display: none;">
19
- <div id="eztoc-reloaded-feedback-content">
20
- <form action="" method="post">
21
- <h3><strong><?php _e('If you have a moment, please let us know why you are deactivating:', 'easy-table-of-contents'); ?></strong></h3>
22
- <ul>
23
- <?php
24
- foreach ($reasons as $reason){
25
- echo $reason;
26
- }
27
- ?>
28
- </ul>
29
- <?php if ($email) : ?>
30
- <input type="hidden" name="eztoc_disable_from" value="<?php echo $email; ?>"/>
31
- <?php endif; ?>
32
- <input id="eztoc-reloaded-feedback-submit" class="button button-primary" type="submit" name="eztoc_disable_submit" value="<?php _e('Submit & Deactivate', 'easy-table-of-contents'); ?>"/>
33
- <a class="button"><?php _e('Only Deactivate', 'easy-table-of-contents'); ?></a>
34
- <a class="eztoc-feedback-not-deactivate" href="#"><?php _e('Don\'t deactivate', 'easy-table-of-contents'); ?></a>
35
- </form>
36
- </div>
37
  </div>
1
+ <?php
2
+ $reasons = array(
3
+ 1 => '<li><label><input type="radio" name="eztoc_disable_reason" value="temporary"/>' . __('It is only temporary', 'easy-table-of-contents') . '</label></li>',
4
+ 2 => '<li><label><input type="radio" name="eztoc_disable_reason" value="stopped showing toc"/>' . __('I stopped showing TOC on my site', 'easy-table-of-contents') . '</label></li>',
5
+ 3 => '<li><label><input type="radio" name="eztoc_disable_reason" value="missing feature"/>' . __('I miss a feature', 'easy-table-of-contents') . '</label></li>
6
+ <li><input type="text" name="eztoc_disable_text[]" value="" placeholder="Please describe the feature"/></li>',
7
+ 4 => '<li><label><input type="radio" name="eztoc_disable_reason" value="technical issue"/>' . __('Technical Issue', 'easy-table-of-contents') . '</label></li>
8
+ <li><textarea name="eztoc_disable_text[]" placeholder="' . __('Can we help? Please describe your problem', 'easy-table-of-contents') . '"></textarea></li>',
9
+ 5 => '<li><label><input type="radio" name="eztoc_disable_reason" value="other plugin"/>' . __('I switched to another plugin', 'easy-table-of-contents') . '</label></li>
10
+ <li><input type="text" name="eztoc_disable_text[]" value="" placeholder="Name of the plugin"/></li>',
11
+ 6 => '<li><label><input type="radio" name="eztoc_disable_reason" value="other"/>' . __('Other reason', 'easy-table-of-contents') . '</label></li>
12
+ <li><textarea name="eztoc_disable_text[]" placeholder="' . __('Please specify, if possible', 'easy-table-of-contents') . '"></textarea></li>',
13
+ );
14
+ shuffle($reasons);
15
+ ?>
16
+
17
+
18
+ <div id="eztoc-reloaded-feedback-overlay" style="display: none;">
19
+ <div id="eztoc-reloaded-feedback-content">
20
+ <form action="" method="post">
21
+ <h3><strong><?php _e('If you have a moment, please let us know why you are deactivating:', 'easy-table-of-contents'); ?></strong></h3>
22
+ <ul>
23
+ <?php
24
+ foreach ($reasons as $reason){
25
+ echo $reason;
26
+ }
27
+ ?>
28
+ </ul>
29
+ <?php if ($email) : ?>
30
+ <input type="hidden" name="eztoc_disable_from" value="<?php echo $email; ?>"/>
31
+ <?php endif; ?>
32
+ <input id="eztoc-reloaded-feedback-submit" class="button button-primary" type="submit" name="eztoc_disable_submit" value="<?php _e('Submit & Deactivate', 'easy-table-of-contents'); ?>"/>
33
+ <a class="button"><?php _e('Only Deactivate', 'easy-table-of-contents'); ?></a>
34
+ <a class="eztoc-feedback-not-deactivate" href="#"><?php _e('Don\'t deactivate', 'easy-table-of-contents'); ?></a>
35
+ </form>
36
+ </div>
37
  </div>
includes/feedback.css CHANGED
@@ -1,42 +1,42 @@
1
- /* makebetter admin css*/
2
-
3
- /**
4
- PLUGINS ADMIN PAGE
5
- */
6
- #eztoc-reloaded-feedback-overlay {
7
- /* Height & width depends on how you want to reveal the overlay (see JS below) */
8
- height: 100%;
9
- width: 100%;
10
- position: fixed; /* Stay in place */
11
- z-index: 10000; /* Sit on top */
12
- left: 0;
13
- top: 0;
14
- background-color: rgb(120,120,120); /* Black fallback color */
15
- background-color: rgba(0,0,0, 0.5); /* Black w/opacity */
16
- }
17
- #eztoc-reloaded-feedback-content {
18
- position: relative;
19
- top: 25%; /* 25% from the top */
20
- width: 500px;
21
- max-width: 100%;
22
- margin: auto;
23
- margin-top: 30px; /* 30px top margin to avoid conflict with the close button on smaller screens */
24
- max-height: 50%;
25
- padding: 20px;
26
- background-color: #fff;
27
- overflow-y: auto;
28
- }
29
- #eztoc-reloaded-feedback-content textarea,
30
- #eztoc-reloaded-feedback-content input[type="text"] { display:none;width:100%; }
31
- .eztoc-feedback-not-deactivate { display: block; text-align: right; }
32
-
33
- #eztoc-reloaded-feedback-content h3{
34
- margin:5px;
35
- }
36
-
37
- @media screen and (max-width:400px){
38
- #eztoc-reloaded-feedback-content {
39
- padding:0px;
40
- padding-bottom:50px;
41
- }
42
  }
1
+ /* makebetter admin css*/
2
+
3
+ /**
4
+ PLUGINS ADMIN PAGE
5
+ */
6
+ #eztoc-reloaded-feedback-overlay {
7
+ /* Height & width depends on how you want to reveal the overlay (see JS below) */
8
+ height: 100%;
9
+ width: 100%;
10
+ position: fixed; /* Stay in place */
11
+ z-index: 10000; /* Sit on top */
12
+ left: 0;
13
+ top: 0;
14
+ background-color: rgb(120,120,120); /* Black fallback color */
15
+ background-color: rgba(0,0,0, 0.5); /* Black w/opacity */
16
+ }
17
+ #eztoc-reloaded-feedback-content {
18
+ position: relative;
19
+ top: 25%; /* 25% from the top */
20
+ width: 500px;
21
+ max-width: 100%;
22
+ margin: auto;
23
+ margin-top: 30px; /* 30px top margin to avoid conflict with the close button on smaller screens */
24
+ max-height: 50%;
25
+ padding: 20px;
26
+ background-color: #fff;
27
+ overflow-y: auto;
28
+ }
29
+ #eztoc-reloaded-feedback-content textarea,
30
+ #eztoc-reloaded-feedback-content input[type="text"] { display:none;width:100%; }
31
+ .eztoc-feedback-not-deactivate { display: block; text-align: right; }
32
+
33
+ #eztoc-reloaded-feedback-content h3{
34
+ margin:5px;
35
+ }
36
+
37
+ @media screen and (max-width:400px){
38
+ #eztoc-reloaded-feedback-content {
39
+ padding:0px;
40
+ padding-bottom:50px;
41
+ }
42
  }
includes/feedback.js CHANGED
@@ -1,79 +1,79 @@
1
- var strict;
2
-
3
- jQuery(document).ready(function ($) {
4
- /**
5
- * DEACTIVATION FEEDBACK FORM
6
- */
7
- // show overlay when clicked on "deactivate"
8
- eztoc_deactivate_link = $('.wp-admin.plugins-php tr[data-slug="easy-table-of-contents"] .row-actions .deactivate a');
9
- eztoc_deactivate_link_url = eztoc_deactivate_link.attr('href');
10
-
11
- eztoc_deactivate_link.click(function (e) {
12
- e.preventDefault();
13
-
14
- // only show feedback form once per 30 days
15
- var c_value = eztoc_admin_get_cookie("eztoc_hide_deactivate_feedback");
16
-
17
- if (c_value === undefined) {
18
- $('#eztoc-reloaded-feedback-overlay').show();
19
- } else {
20
- // click on the link
21
- window.location.href = eztoc_deactivate_link_url;
22
- }
23
- });
24
- // show text fields
25
- $('#eztoc-reloaded-feedback-content input[type="radio"]').click(function () {
26
- // show text field if there is one
27
- $(this).parents('li').next('li').children('input[type="text"], textarea').show();
28
- });
29
- // send form or close it
30
- $('#eztoc-reloaded-feedback-content .button').click(function (e) {
31
- e.preventDefault();
32
- // set cookie for 30 days
33
- var exdate = new Date();
34
- exdate.setSeconds(exdate.getSeconds() + 2592000);
35
- document.cookie = "eztoc_hide_deactivate_feedback=1; expires=" + exdate.toUTCString() + "; path=/";
36
-
37
- $('#eztoc-reloaded-feedback-overlay').hide();
38
- if ('eztoc-reloaded-feedback-submit' === this.id) {
39
- // Send form data
40
- $.ajax({
41
- type: 'POST',
42
- url: ajaxurl,
43
- dataType: 'json',
44
- data: {
45
- action: 'eztoc_send_feedback',
46
- data: $('#eztoc-reloaded-feedback-content form').serialize()
47
- },
48
- complete: function (MLHttpRequest, textStatus, errorThrown) {
49
- // deactivate the plugin and close the popup
50
- $('#eztoc-reloaded-feedback-overlay').remove();
51
- window.location.href = eztoc_deactivate_link_url;
52
-
53
- }
54
- });
55
- } else {
56
- $('#eztoc-reloaded-feedback-overlay').remove();
57
- window.location.href = eztoc_deactivate_link_url;
58
- }
59
- });
60
- // close form without doing anything
61
- $('.eztoc-feedback-not-deactivate').click(function (e) {
62
- $('#eztoc-reloaded-feedback-overlay').hide();
63
- });
64
-
65
- function eztoc_admin_get_cookie (name) {
66
- var i, x, y, eztoc_cookies = document.cookie.split( ";" );
67
- for (i = 0; i < eztoc_cookies.length; i++)
68
- {
69
- x = eztoc_cookies[i].substr( 0, eztoc_cookies[i].indexOf( "=" ) );
70
- y = eztoc_cookies[i].substr( eztoc_cookies[i].indexOf( "=" ) + 1 );
71
- x = x.replace( /^\s+|\s+$/g, "" );
72
- if (x === name)
73
- {
74
- return unescape( y );
75
- }
76
- }
77
- }
78
-
79
  }); // document ready
1
+ var strict;
2
+
3
+ jQuery(document).ready(function ($) {
4
+ /**
5
+ * DEACTIVATION FEEDBACK FORM
6
+ */
7
+ // show overlay when clicked on "deactivate"
8
+ eztoc_deactivate_link = $('.wp-admin.plugins-php tr[data-slug="easy-table-of-contents"] .row-actions .deactivate a');
9
+ eztoc_deactivate_link_url = eztoc_deactivate_link.attr('href');
10
+
11
+ eztoc_deactivate_link.click(function (e) {
12
+ e.preventDefault();
13
+
14
+ // only show feedback form once per 30 days
15
+ var c_value = eztoc_admin_get_cookie("eztoc_hide_deactivate_feedback");
16
+
17
+ if (c_value === undefined) {
18
+ $('#eztoc-reloaded-feedback-overlay').show();
19
+ } else {
20
+ // click on the link
21
+ window.location.href = eztoc_deactivate_link_url;
22
+ }
23
+ });
24
+ // show text fields
25
+ $('#eztoc-reloaded-feedback-content input[type="radio"]').click(function () {
26
+ // show text field if there is one
27
+ $(this).parents('li').next('li').children('input[type="text"], textarea').show();
28
+ });
29
+ // send form or close it
30
+ $('#eztoc-reloaded-feedback-content .button').click(function (e) {
31
+ e.preventDefault();
32
+ // set cookie for 30 days
33
+ var exdate = new Date();
34
+ exdate.setSeconds(exdate.getSeconds() + 2592000);
35
+ document.cookie = "eztoc_hide_deactivate_feedback=1; expires=" + exdate.toUTCString() + "; path=/";
36
+
37
+ $('#eztoc-reloaded-feedback-overlay').hide();
38
+ if ('eztoc-reloaded-feedback-submit' === this.id) {
39
+ // Send form data
40
+ $.ajax({
41
+ type: 'POST',
42
+ url: ajaxurl,
43
+ dataType: 'json',
44
+ data: {
45
+ action: 'eztoc_send_feedback',
46
+ data: $('#eztoc-reloaded-feedback-content form').serialize()
47
+ },
48
+ complete: function (MLHttpRequest, textStatus, errorThrown) {
49
+ // deactivate the plugin and close the popup
50
+ $('#eztoc-reloaded-feedback-overlay').remove();
51
+ window.location.href = eztoc_deactivate_link_url;
52
+
53
+ }
54
+ });
55
+ } else {
56
+ $('#eztoc-reloaded-feedback-overlay').remove();
57
+ window.location.href = eztoc_deactivate_link_url;
58
+ }
59
+ });
60
+ // close form without doing anything
61
+ $('.eztoc-feedback-not-deactivate').click(function (e) {
62
+ $('#eztoc-reloaded-feedback-overlay').hide();
63
+ });
64
+
65
+ function eztoc_admin_get_cookie (name) {
66
+ var i, x, y, eztoc_cookies = document.cookie.split( ";" );
67
+ for (i = 0; i < eztoc_cookies.length; i++)
68
+ {
69
+ x = eztoc_cookies[i].substr( 0, eztoc_cookies[i].indexOf( "=" ) );
70
+ y = eztoc_cookies[i].substr( eztoc_cookies[i].indexOf( "=" ) + 1 );
71
+ x = x.replace( /^\s+|\s+$/g, "" );
72
+ if (x === name)
73
+ {
74
+ return unescape( y );
75
+ }
76
+ }
77
+ }
78
+
79
  }); // document ready
includes/helper-function.php CHANGED
@@ -107,6 +107,9 @@ add_action( 'admin_enqueue_scripts', 'eztoc_enqueue_makebetter_email_js' );
107
  add_action('wp_ajax_eztoc_subscribe_newsletter','eztoc_subscribe_for_newsletter');
108
  add_action('wp_ajax_nopriv_eztoc_subscribe_newsletter','eztoc_subscribe_for_newsletter');
109
  function eztoc_subscribe_for_newsletter(){
 
 
 
110
  $api_url = 'http://magazine3.company/wp-json/api/central/email/subscribe';
111
  $api_params = array(
112
  'name' => sanitize_text_field($_POST['name']),
107
  add_action('wp_ajax_eztoc_subscribe_newsletter','eztoc_subscribe_for_newsletter');
108
  add_action('wp_ajax_nopriv_eztoc_subscribe_newsletter','eztoc_subscribe_for_newsletter');
109
  function eztoc_subscribe_for_newsletter(){
110
+ if( !wp_verify_nonce( $_POST['eztoc_security_nonce'], 'eztoc_security_nonce')){
111
+ return 'nonce not verified';
112
+ }
113
  $api_url = 'http://magazine3.company/wp-json/api/central/email/subscribe';
114
  $api_params = array(
115
  'name' => sanitize_text_field($_POST['name']),
includes/inc.admin-options-page.php CHANGED
@@ -1,466 +1,655 @@
1
  <div id='toc' class='wrap'>
2
- <a href="https://tocwp.com/" target="_blank" >
3
- <img src="<?php echo plugins_url( 'assets/eztoc-logo.png', dirname(__FILE__) ) ?>" alt="tocwp" srcset="<?php echo plugins_url( 'assets/eztoc-logo.png', dirname(__FILE__) ) ?> 1x, <?php echo plugins_url( 'assets/eztoc-logo.png', dirname(__FILE__) ) ?> 2x" >
4
- </a>
5
- <div class="toc-tab-panel">
6
- <a id="eztoc-welcome" class="eztoc-tablinks" data-href="no" href="#welcome" onclick="tabToggle(event, 'welcome')">Welcome</a>
7
- <a id="eztoc-default" class="eztoc-tablinks" data-href="no" href="#general-settings" onclick="tabToggle(event, 'general')">Settings</a>
8
- <?php
9
- $pro = '';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
- if (function_exists('ez_toc_pro_activation_link')) {
12
- $pro = '<a id="eztoc-default" class="eztoc-tablinks" data-href="no" href="#eztoc-prosettings" onclick="tabToggle(event, "prosettings")">PRO Settings</a>';
13
- }?>
14
- <?php echo $pro; ?>
15
-
16
- <?php
17
- if (!function_exists('ez_toc_pro_activation_link')) {?>
18
- <a class="eztoc-tablinks" id="eztoc-freevspro" href="#freevspro-support" onclick="tabToggle(event, 'freevspro')" data-href="no">Free vs PRO</a>
19
- <?php }
20
- ?>
21
- <a class="eztoc-tablinks" id="eztoc-technical" href="#technical-support" onclick="tabToggle(event, 'technical')" data-href="no">Help & Support</a>
22
- <a class="eztoc-tablinks" id="eztoc-upgrade" href="https://tocwp.com/pricing/" target="_blank" >UPGRADE to PRO</a>
23
- <?php
24
-
25
- if (function_exists('ez_toc_pro_activation_link')) {
26
- $license_info = get_option("easytoc_pro_upgrade_license");
27
- $license_exp = date('Y-m-d', strtotime($license_info['pro']['license_key_expires']));
28
- $today = date('Y-m-d');
29
- $exp_date = $license_exp;
30
- $date1 = date_create($today);
31
- $date2 = date_create($exp_date);
32
- $diff = date_diff($date1,$date2);
33
- $days = $diff->format("%a");
34
- $days = intval($days);?>
35
- <a class="eztoc-tablinks" id="eztoc-license" href="#license" onclick="tabToggle(event, 'license')" data-href="no">License</a>
36
- <?php
37
- if( $days < 30 ){?>
38
- <span class="dashicons dashicons-warning" style="color: #ffb229;position: relative;top: 15px;left: -10px;"></span>
39
- <?php } }?>
40
- </div><!-- /.Tab panel -->
41
- <div class="eztoc_support_div eztoc-tabcontent" id="welcome" style="display: block;">
42
- <p style="font-weight: bold;font-size: 30px;color: #000;">Thank YOU for using Easy Table of Content. </p>
43
- <p style="font-size: 18px;padding: 0 10%;line-height: 1.7;color: #000;">We strive to create the best TOC solution in WordPress. Our dedicated development team does continious development and innoviation to make sure we are able to meet your demand.</p>
44
- <p style="font-size: 16px;font-weight: 600;color: #000;">Please support us by Upgrading to Premium verison.</p>
45
- <a target="_blank" href="https://tocwp.com/pricing/"><button class="button-toc" style="display: inline-block;font-size: 20px;">
46
- <span>YES! I want to Support by UPGRADING.</span></button></a>
47
- <a href="<?php echo add_query_arg( 'page', 'table-of-contents', admin_url( 'options-general.php' ) ); ?>" style="text-decoration: none;"><button class="button-toc1" style="display: block;text-align: center;border: 0;margin: 0 auto;background: none;">
48
- <span style="cursor: pointer;">No Thanks, I will stick with FREE version for now.</span></button></a>
49
- </div><!-- /.Welcome ended -->
50
- <div class="eztoc-tabcontent" id="general">
51
- <div id="eztoc-tabs" style="margin-top: 10px;"><a href="#eztoc-general">General</a> | <a href="#eztoc-appearance" >Appearance</a> | <a href="#eztoc-advanced" >Advanced</a></div>
52
- <form method="post" action="<?php echo esc_url( self_admin_url( 'options.php' ) ); ?>">
53
-
54
- <div class="metabox-holder">
55
-
56
- <div class="postbox" id="eztoc-general">
57
- <h3><span><?php _e( 'General', 'easy-table-of-contents' ); ?></span></h3>
58
-
59
- <div class="inside">
60
-
61
- <table class="form-table">
62
-
63
- <?php do_settings_fields( 'ez_toc_settings_general', 'ez_toc_settings_general' ); ?>
64
-
65
- </table>
66
-
67
- </div><!-- /.inside -->
68
- </div><!-- /.postbox -->
69
-
70
- </div><!-- /.metabox-holder -->
71
-
72
- <div class="metabox-holder">
73
-
74
- <div class="postbox" id="eztoc-appearance">
75
- <h3><span><?php _e( 'Appearance', 'easy-table-of-contents' ); ?></span></h3>
76
-
77
- <div class="inside">
78
-
79
- <table class="form-table">
80
-
81
- <?php do_settings_fields( 'ez_toc_settings_appearance', 'ez_toc_settings_appearance' ); ?>
82
-
83
- </table>
84
-
85
- </div><!-- /.inside -->
86
- </div><!-- /.postbox -->
87
-
88
- </div><!-- /.metabox-holder -->
89
-
90
- <div class="metabox-holder">
91
-
92
- <div class="postbox" id="eztoc-advanced">
93
- <h3><span><?php _e( 'Advanced', 'easy-table-of-contents' ); ?></span></h3>
94
-
95
- <div class="inside">
96
-
97
- <table class="form-table">
98
-
99
- <?php do_settings_fields( 'ez_toc_settings_advanced', 'ez_toc_settings_advanced' ); ?>
100
-
101
- </table>
102
-
103
- </div><!-- /.inside -->
104
- </div><!-- /.postbox -->
105
 
106
- </div><!-- /.metabox-holder -->
107
- <?php if (function_exists('ez_toc_pro_activation_link')) {?>
108
- <div class="metabox-holder">
109
 
110
- <div class="postbox" id="eztoc-prosettings">
111
- <h3><span><?php _e( 'PRO Settings', 'easy-table-of-contents' ); ?></span></h3>
112
- <div class="inside">
113
-
114
- <table class="form-table">
115
- <?php do_settings_fields( 'ez_toc_settings_prosettings', 'ez_toc_settings_prosettings' ); ?>
116
 
117
- </table>
 
118
 
119
- </div><!-- /.inside -->
120
- </div><!-- /.postbox -->
121
 
122
- </div><!-- /.metabox-holder -->
123
- <?php } ?>
124
- <?php settings_fields( 'ez-toc-settings' ); ?>
125
- <?php submit_button( __( 'Save Changes', 'easy-table-of-contents' ) ); ?>
126
- </form>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  </div><!-- /.General Settings ended -->
128
 
129
-
130
-
131
-
132
- <div class="eztoc_support_div eztoc-tabcontent" id="technical">
133
- <div class="eztoc-form-page-ui">
134
- <div class="eztoc-left-side">
135
- <p><?php echo esc_html__('We are dedicated to provide Technical support & Help to our users. Use the below form for sending your questions.','easy-table-of-contents') ?> </p>
136
- <p><?php echo esc_html__('You can also contact us from ','easy-table-of-contents') ?><a href="https://tocwp.com/contact/">https://tocwp.com/contact/</a>.</p>
137
-
138
- <div class="eztoc_support_div_form" id="technical-form">
139
- <ul>
140
- <li>
141
- <label class="support-label">Email<span class="star-mark">*</span></label>
142
- <div class="support-input">
143
-
144
- <input type="text" id="eztoc_query_email" name="eztoc_query_email" placeholder="Enter your Email" required>
145
- </div>
146
- </li>
147
-
148
- <li>
149
- <label class="support-label">Query<span class="star-mark">*</span></label>
150
-
151
- <div class="support-input"><textarea rows="5" cols="50" id="eztoc_query_message" name="eztoc_query_message" placeholder="Write your query"></textarea>
152
- </div>
153
-
154
-
155
- </li>
156
-
157
- </ul>
158
- <li>
159
- <div class="eztoc-customer-type">
160
- <label class="support-label">Type</label>
161
- <div class="support-input">
162
- <select name="eztoc_customer_type" id="eztoc_customer_type">
163
- <option value="select">Select Customer Type</option>
164
- <option value="paid">Paid<span> (Response within 24 hrs)</span></option>
165
- <option value="free">Free<span> ( Avg Response within 48-72 hrs)</span></option>
166
- </select>
167
- </div>
168
- </div>
169
- </li>
170
- <li><button class="button button-primary eztoc-send-query"><?php echo esc_html__('Send Support Request','easy-table-of-contents'); ?></button></li>
171
- </ul>
172
- <div class="clear"> </div>
173
- <span class="eztoc-query-success eztoc-result eztoc_hide"><?php echo esc_html__('Message sent successfully, Please wait we will get back to you shortly','easy-table-of-contents'); ?></span>
174
- <span class="eztoc-query-error eztoc-result eztoc_hide"><?php echo esc_html__('Message not sent. please check your network connection','easy-table-of-contents'); ?></span>
175
- </div>
176
- </div>
177
- <div class="eztoc-right-side">
178
- <div class="eztoc-bio-box" id="ez_Bio">
179
- <h1>Vision & Mission</h1>
180
- <p class="eztoc-p">We strive to provide the best TOC in the world.</p>
181
- <section class="eztoc_dev-bio">
182
- <div class="ezoc-bio-wrap">
183
- <img width="50px" height="50px" src="<?php echo plugins_url( 'assets/ahmed-kaludi.jpg', dirname(__FILE__) ) ?>">
184
- <p>Lead Dev</p>
185
- </div>
186
- <div class="ezoc-bio-wrap">
187
- <img width="50px" height="50px" src="<?php echo plugins_url( 'assets/Mohammed-kaludi.jpeg', dirname(__FILE__) ) ?>">
188
- <p>Developer</p>
189
- </div>
190
- <div class="ezoc-bio-wrap">
191
- <img width="50px" height="50px" src="<?php echo plugins_url( 'assets/zabi.jpg', dirname(__FILE__) ) ?>">
192
- <p>Developer</p>
193
- </div>
194
- </section>
195
- <p class="eztoc_boxdesk"> Delivering a good user experience means a lot to us, so we try our best to reply each and every question.</p>
196
- <p class="company-link"> Support the innovation & development by upgrading to PRO <a href="https://tocwp.com/pricing/">I Want To Upgrade!</a></p>
197
- </div>
198
- </div> </div> </div> <!-- /.Technical support div ended -->
199
-
200
- <div class="eztoc_support_div eztoc-tabcontent" id="freevspro">
201
- <div class="eztoc-wrapper">
202
- <div class="eztoc-wr">
203
- <div class="etoc-eztoc-img">
204
- <span class="sp_ov"></span>
205
- </div>
206
- <div class="etoc-eztoc-cnt">
207
- <h1><?php _e( 'UPGRADE to PRO Version'); ?></h1>
208
- <p><?php _e( 'Take your Table of Contents to the NEXT Level!', 'easy-table-of-contents' ); ?></p>
209
- <a class="buy" href="#upgrade"><?php _e( 'Purchase Now', 'easy-table-of-contents' ); ?></a>
210
- </div>
211
- <div class="pvf">
212
- <div class="ext">
213
- <div class="ex-1 e-1">
214
- <h4><?php _e( 'Premium Features', 'easy-table-of-contents' ); ?></h4>
215
- <p><?php _e( 'Easy TOC Pro will enhances your website table of contents and takes it to a next level to help you reach more engagement and personalization with your users.', 'easy-table-of-contents' ); ?></p>
216
- </div>
217
- <div class="ex-1 e-2">
218
- <h4><?php _e( 'Continuous Innovation', 'easy-table-of-contents' ); ?></h4>
219
- <p><?php _e( 'We are planning to continiously build premium features and release them. We have a roadmap and we listen to our customers to turn their feedback into reality.', 'easy-table-of-contents' ); ?></p>
220
- </div>
221
- <div class="ex-1 e-3">
222
- <h4><?php _e( 'Tech Support', 'easy-table-of-contents' ); ?></h4>
223
- <p><?php _e( 'Get private ticketing help from our full-time technical staff & developers who helps you with the technical issues.', 'easy-table-of-contents' ); ?></p>
224
- </div>
225
- </div><!-- /. ext -->
226
- <div class="pvf-cnt">
227
- <div class="pvf-tlt">
228
- <h2><?php _e( 'Compare Pro vs. Free Version', 'easy-table-of-contents' ); ?></h2>
229
- <span><?php _e( 'See what you\'ll get with the professional version', 'easy-table-of-contents' ); ?></span>
230
- </div>
231
- <div class="pvf-cmp">
232
- <div class="fr">
233
- <h1>FREE</h1>
234
- <div class="fr-fe">
235
- <div class="fe-1">
236
- <h4><?php _e( 'Continious Development', 'easy-table-of-contents' ); ?></h4>
237
- <p><?php _e( 'We take bug reports and feature requests seriously. We’re continiously developing &amp; improve this product for last 2 years with passion and love.', 'easy-table-of-contents' ); ?></p>
238
  </div>
239
- <div class="fe-1">
240
- <h4><?php _e( '50+ Features', 'easy-table-of-contents' ); ?></h4>
241
- <p><?php _e( 'We\'re constantly expanding the plugin and make it more useful. We have wide variety of features which will fit any use-case.', 'easy-table-of-contents' ); ?></p>
 
 
 
 
 
 
 
242
  </div>
243
- </div><!-- /. fr-fe -->
244
- </div><!-- /. fr -->
245
- <div class="pr">
246
- <h1>PRO</h1>
247
- <div class="pr-fe">
248
- <span><?php _e( 'Everything in Free, and:', 'easy-table-of-contents' ); ?></span>
249
- <div class="fet">
250
- <div class="fe-2">
251
- <div class="fe-t">
252
- <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
253
- <h4><?php _e( 'Gutenberg Block', 'easy-table-of-contents' ); ?></h4>
254
- </div>
255
- <p><?php _e( 'Easily create TOC in Gutenberg block without the need any coding or shortcode.', 'easy-table-of-contents' ); ?></p>
256
- </div>
257
- <div class="fe-2">
258
- <div class="fe-t">
259
- <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
260
- <h4><?php _e( 'Elementor Widget', 'easy-table-of-contents' ); ?></h4>
261
- </div>
262
- <p><?php _e( 'Easily create TOC in Elementor with the widget without the need any coding or shortcode.', 'easy-table-of-contents' ); ?></p>
263
- </div>
264
 
265
- <div class="fe-2">
266
- <div class="fe-t">
267
- <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
268
- <h4>Fixed/Sticky TOC</h4>
269
- </div>
270
- <p>Users can faster find the content they want with sticky</p>
271
- </div>
272
 
273
-
274
- <div class="fe-2">
275
- <div class="fe-t">
276
- <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
277
- <h4>Full AMP Support</h4>
278
- </div>
279
- <p>Generates a table of contents with your existing setup and makes them AMP automatically.</p>
280
- </div>
281
- <div class="fe-2">
282
- <div class="fe-t">
283
- <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
284
- <h4>Continious Updates</h4>
285
- </div>
286
- <p>We're continiously updating our premium features and releasing them.</p>
287
- </div>
288
- <div class="fe-2">
289
- <div class="fe-t">
290
- <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
291
- <h4>Documentation</h4>
292
- </div>
293
- <p>We create tutorials for every possible feature and keep it updated for you.</p>
294
  </div>
295
- </div><!-- /. fet -->
296
- <div class="pr-btn">
297
- <a href="#upgrade">Upgrade to Pro</a>
298
- </div><!-- /. pr-btn -->
299
- </div><!-- /. pr-fe -->
300
- </div><!-- /.pr -->
301
- </div><!-- /. pvf-cmp -->
302
- </div><!-- /. pvf-cnt -->
303
- <div id="upgrade" class="amp-upg">
304
- <div class="upg-t">
305
- <h2>Let's Upgrade Your Easy Table of Contents</h2>
306
- <span>Choose your plan and upgrade in minutes!</span>
307
  </div>
308
- <div class="etoc-pri-lst">
309
- <div class="pri-tb">
310
- <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=1" target="_blank">
311
- <h5>PERSONAL</h5>
312
- <span class="d-amt"><sup>$</sup>49</span>
313
- <span class="amt"><sup>$</sup>49</span>
314
- <span class="s-amt">(Save $59)</span>
315
- <span class="bil">Billed Annually</span>
316
- <span class="s">1 Site License</span>
317
- <span class="e">Tech Support</span>
318
- <span class="f">1 year Updates </span>
319
- <span class="etoc-sv">Pro Features </span>
320
- <span class="pri-by">Buy Now</span>
321
- </a>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322
  </div>
323
- <div class="pri-tb rec">
324
- <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=2" target="_blank">
325
- <h5>MULTIPLE</h5>
326
- <span class="d-amt"><sup>$</sup>69</span>
327
- <span class="amt"><sup>$</sup>69</span>
328
- <span class="s-amt">(Save $79)</span>
329
- <span class="bil">Billed Annually</span>
330
- <span class="s">3 Site License</span>
331
- <span class="e">Tech Support</span>
332
- <span class="f">1 year Updates</span>
333
- <span class="etoc-sv">Save 78%</span>
334
- <span class="pri-by">Buy Now</span>
335
- <span class="etoc-rcm">RECOMMENDED</span>
336
- </a>
337
  </div>
338
- <div class="pri-tb">
339
- <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=3" target="_blank">
340
- <h5>WEBMASTER</h5>
341
- <span class="d-amt"><sup>$</sup>79</span>
342
- <span class="amt"><sup>$</sup>79</span>
343
- <span class="s-amt">(Save $99)</span>
344
- <span class="bil">Billed Annually</span>
345
- <span class="s">10 Site License</span>
346
- <span class="e">Tech Support</span>
347
- <span class="f">1 year Updates</span>
348
- <span class="etoc-sv">Save 83%</span>
349
- <span class="pri-by">Buy Now</span>
350
- </a>
351
  </div>
352
- <div class="pri-tb">
353
- <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=4" target="_blank">
354
- <h5>FREELANCER</h5>
355
- <span class="d-amt"><sup>$</sup>99</span>
356
- <span class="amt"><sup>$</sup>99</span>
357
- <span class="s-amt">(Save $119)</span>
358
- <span class="bil">Billed Annually</span>
359
- <span class="s">25 Site License</span>
360
- <span class="e">Tech Support</span>
361
- <span class="f">1 year Updates</span>
362
- <span class="etoc-sv">Save 90%</span>
363
- <span class="pri-by">Buy Now</span>
364
- </a>
 
 
 
 
 
 
 
 
 
 
 
365
  </div>
366
- <div class="pri-tb">
367
- <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=5" target="_blank">
368
- <h5>AGENCY</h5>
369
- <span class="d-amt"><sup>$</sup>199</span>
370
- <span class="amt"><sup>$</sup>199</span>
371
- <span class="s-amt">(Save $199)</span>
372
- <span class="bil">Billed Annually</span>
373
- <span class="s">Unlimited Sites</span>
374
- <span class="e">E-mail support</span>
375
- <span class="f">1 year Updates</span>
376
- <span class="etoc-sv">UNLIMITED</span>
377
- <span class="pri-by">Buy Now</span>
378
- </a>
379
  </div>
380
- <div class="pri-tb">
381
- <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=6" target="_blank">
382
- <h5>LIFETIME</h5>
383
- <span class="d-amt"><sup>$</sup>499</span>
384
- <span class="amt"><sup>$</sup>499</span>
385
- <span class="s-amt">(Save $199)</span>
386
- <span class="bil">Billed Annually</span>
387
- <span class="s">Unlimited Sites</span>
388
- <span class="e">Unlimited E-mail support</span>
389
- <span class="f">Lifetime License</span>
390
- <span class="etoc-sv">UNLIMITED</span>
391
- <span class="pri-by">Buy Now</span>
392
- </a>
393
  </div>
394
- </div><!-- /.pri-lst -->
395
- <div class="tru-us">
396
- <img src="<?php echo plugins_url( 'assets/toc-rating.png', dirname(__FILE__) ) ?>">
397
- <h2>Used by more than 300,000+ Users!</h2>
398
- <p>More than 300k Websites, Blogs &amp; E-Commerce shops are powered by our easy table of contents plugin making it the #1 Independent TOC plugin in WordPress.</p>
399
- <a href="https://wordpress.org/support/plugin/easy-table-of-contents/reviews/?filter=5" target="_blank">Read The Reviews</a>
400
- </div>
401
- </div><!--/ .amp-upg -->
402
- <div class="ampfaq">
403
- <h2>Frequently Asked Questions</h2>
404
- <div class="faq-lst">
405
- <div class="lt">
406
- <ul>
407
- <li>
408
- <span>Is there a setup fee?</span>
409
- <p>No. There are no setup fees on any of our plans</p>
410
- </li>
411
- <li>
412
- <span>What's the time span for your contracts?</span>
413
- <p>All the plans are year-to-year which are subscribed annually except for lifetime plan.</p>
414
- </li>
415
- <li>
416
- <span>What payment methods are accepted?</span>
417
- <p>We accepts PayPal and Credit Card payments.</p>
418
- </li>
419
- <li>
420
- <span>Do you offer support if I need help?</span>
421
- <p>Yes! Top-notch customer support for our paid customers is key for a quality product, so we’ll do our very best to resolve any issues you encounter via our support page.</p>
422
- </li>
423
- <li>
424
- <span>Can I use the plugins after my subscription is expired?</span>
425
- <p>Yes, you can use the plugins but you will not get future updates for those plugins.</p>
426
- </li>
427
- </ul>
428
  </div>
429
- <div class="rt">
430
- <ul>
431
- <li>
432
- <span>Can I cancel my membership at any time?</span>
433
- <p>Yes. You can cancel your membership by contacting us.</p>
434
- </li>
435
- <li>
436
- <span>Can I change my plan later on?</span>
437
- <p>Yes. You can upgrade your plan by contacting us.</p>
438
- </li>
439
- <li>
440
- <span>Do you offer refunds?</span>
441
- <p>You are fully protected by our 100% Money Back Guarantee Unconditional. If during the next 14 days you experience an issue that makes the plugin unusable and we are unable to resolve it, we’ll happily offer a full refund.</p>
442
- </li>
443
- <li>
444
- <span>Do I get updates for the premium plugin?</span>
445
- <p>Yes, you will get updates for all the premium plugins until your subscription is active.</p>
446
- </li>
447
- </ul>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
448
  </div>
449
- </div><!-- /.faq-lst -->
450
- <div class="f-cnt">
451
- <span>I have other pre-sale questions, can you help?</span>
452
- <p>All the plans are year-to-year which are subscribed annually.</p>
453
- <a href="https://tocwp.com/contact/'?utm_source=tocwp-plugin&utm_medium=addon-card'" target="_blank">Contact a Human</a>
454
- </div><!-- /.f-cnt -->
455
- </div><!-- /.faq -->
456
- </div><!-- /. pvf -->
457
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
458
  </div>
459
- </div><!-- /.freevspro div ended -->
 
460
 
461
- <div id="license" class="eztoc_support_div eztoc-tabcontent">
462
- <?php
463
  do_action("admin_upgrade_license_page");
464
- ?>
465
- </div>
466
  </div>
1
  <div id='toc' class='wrap'>
2
+ <a href="https://tocwp.com/" target="_blank">
3
+ <img src="<?php echo plugins_url('assets/eztoc-logo.png', dirname(__FILE__)) ?>" alt="tocwp"
4
+ srcset="<?php echo plugins_url('assets/eztoc-logo.png', dirname(__FILE__)) ?> 1x, <?php echo plugins_url('assets/eztoc-logo.png', dirname(__FILE__)) ?> 2x">
5
+ </a>
6
+ <h1 style="display:none;">&nbsp;</h1>
7
+ <div class="toc-tab-panel">
8
+ <a id="eztoc-welcome" class="eztoc-tablinks" data-href="no" href="#welcome"
9
+ onclick="ezTocTabToggle(event, 'welcome')"><?= esc_html_e( 'Welcome', 'easy-table-of-contents' ) ?></a>
10
+ <a id="eztoc-default" class="eztoc-tablinks" data-href="no" href="#general-settings"
11
+ onclick="ezTocTabToggle(event, 'general')"><?= esc_html_e( 'Settings', 'easy-table-of-contents' ) ?></a>
12
+ <?php
13
+ $pro = '';
14
+
15
+ if (function_exists('ez_toc_pro_activation_link')) {
16
+ $pro = '<a id="eztoc-default" class="eztoc-tablinks" data-href="no" href="#eztoc-prosettings" onclick="ezTocTabToggle(event, \'prosettings\')">' . esc_html_e( 'PRO Settings', 'easy-table-of-contents' ) . '</a>';
17
+ } ?>
18
+ <?php echo $pro; ?>
19
+
20
+ <?php
21
+ if (!function_exists('ez_toc_pro_activation_link')) { ?>
22
+ <a class="eztoc-tablinks" id="eztoc-freevspro" href="#freevspro-support"
23
+ onclick="ezTocTabToggle(event, 'freevspro')" data-href="no"><?= esc_html_e( 'Free vs PRO', 'easy-table-of-contents' ) ?></a>
24
+ <?php }
25
+ ?>
26
+ <a class="eztoc-tablinks" id="eztoc-technical" href="#technical-support"
27
+ onclick="ezTocTabToggle(event, 'technical')" data-href="no"><?= esc_html_e( 'Help & Support', 'easy-table-of-contents' ) ?></a>
28
+ <a class="eztoc-tablinks" id="eztoc-upgrade" href="https://tocwp.com/pricing/" target="_blank"><?= esc_html_e( 'UPGRADE to PRO', 'easy-table-of-contents' ) ?></a>
29
+ <?php
30
+
31
+ if (function_exists('ez_toc_pro_activation_link')) {
32
+ $license_info = get_option("easytoc_pro_upgrade_license");
33
+ $license_exp = date('Y-m-d', strtotime($license_info['pro']['license_key_expires']));
34
+ $today = date('Y-m-d');
35
+ $exp_date = $license_exp;
36
+ $date1 = date_create($today);
37
+ $date2 = date_create($exp_date);
38
+ $diff = date_diff($date1, $date2);
39
+ $days = $diff->format("%a");
40
+ $days = intval($days); ?>
41
+ <a class="eztoc-tablinks" id="eztoc-license" href="#license"
42
+ onclick="ezTocTabToggle(event, 'license')"
43
+ data-href="no"><?= esc_html_e('License', 'easy-table-of-contents') ?></a>
44
+ <?php
45
+ if ($days < 30) {
46
+ ?>
47
+ <span class="dashicons dashicons-warning" style="color: #ffb229;position: relative;top:
48
+ 15px;left: -10px;"></span>
49
+ <?php }
50
+ } ?>
51
+ </div><!-- /.Tab panel -->
52
+ <div class="eztoc_support_div eztoc-tabcontent" id="welcome" style="display: block;">
53
+ <p style="font-weight: bold;font-size: 30px;color: #000;"><?= esc_html_e( 'Thank YOU for using Easy Table of Content.', 'easy-table-of-contents' ) ?></p>
54
+ <p style="font-size: 18px;padding: 0 10%;line-height: 1.7;color: #000;"><?= esc_html_e( 'We strive to create the best TOC solution in WordPress. Our dedicated development team does continuous development and innovation to make sure we are able to meet your demand.', 'easy-table-of-contents' ) ?></p>
55
+ <p style="font-size: 16px;font-weight: 600;color: #000;"><?= esc_html_e( 'Please support us by Upgrading to Premium version.', 'easy-table-of-contents' ) ?></p>
56
+ <a target="_blank" href="https://tocwp.com/pricing/">
57
+ <button class="button-toc" style="display: inline-block;font-size: 20px;">
58
+ <span><?= esc_html_e( 'YES! I want to Support by UPGRADING.', 'easy-table-of-contents' ) ?></span></button>
59
+ </a>
60
+ <a href="<?php echo add_query_arg('page', 'table-of-contents', admin_url('options-general.php')); ?>"
61
+ style="text-decoration: none;">
62
+ <button class="button-toc1"
63
+ style="display: block;text-align: center;border: 0;margin: 0 auto;background: none;">
64
+ <span style="cursor: pointer;"><?= esc_html_e( 'No Thanks, I will stick with FREE version for now.', 'easy-table-of-contents' ) ?></span>
65
+ </button>
66
+ </a>
67
+ </div>
68
+ <div class="eztoc-tabcontent" id="general">
69
+ <div id="eztoc-tabs" style="margin-top: 10px;">
70
+ <a href="#eztoc-general"><?= esc_html_e( 'General', 'easy-table-of-contents' ) ?></a> | <a href="#eztoc-appearance"><?= esc_html_e( 'Appearance', 'easy-table-of-contents' ) ?></a> | <a
71
+ href="#eztoc-advanced"><?= esc_html_e( 'Advanced', 'easy-table-of-contents' ) ?></a> | <a href="#eztoc-shortcode"><?= esc_html_e( 'Shortcode', 'easy-table-of-contents' ) ?></a>
72
+ </div>
73
+ <form method="post" action="<?php echo esc_url(self_admin_url('options.php')); ?>">
74
+
75
+ <div class="metabox-holder">
76
+
77
+ <div class="postbox" id="eztoc-general">
78
+ <h3><span><?= esc_html_e('General', 'easy-table-of-contents'); ?></span></h3>
79
+
80
+ <div class="inside">
81
+
82
+ <table class="form-table">
83
+
84
+ <?php do_settings_fields('ez_toc_settings_general', 'ez_toc_settings_general'); ?>
85
+
86
+ </table>
87
+
88
+ </div><!-- /.inside -->
89
+ </div><!-- /.postbox -->
90
+
91
+ </div><!-- /.metabox-holder -->
92
+
93
+ <div class="metabox-holder">
94
+
95
+ <div class="postbox" id="eztoc-appearance">
96
+ <h3><span><?= esc_html_e('Appearance', 'easy-table-of-contents'); ?></span></h3>
97
+
98
+ <div class="inside">
99
+
100
+ <table class="form-table">
101
+
102
+ <?php do_settings_fields('ez_toc_settings_appearance', 'ez_toc_settings_appearance'); ?>
103
+
104
+ </table>
105
+
106
+ </div><!-- /.inside -->
107
+ </div><!-- /.postbox -->
108
+
109
+ </div><!-- /.metabox-holder -->
110
+
111
+ <div class="metabox-holder">
112
+
113
+ <div class="postbox" id="eztoc-advanced">
114
+ <h3><span><?= esc_html_e('Advanced', 'easy-table-of-contents'); ?></span></h3>
115
+
116
+ <div class="inside">
117
 
118
+ <table class="form-table">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
 
120
+ <?php do_settings_fields('ez_toc_settings_advanced', 'ez_toc_settings_advanced'); ?>
 
 
121
 
122
+ </table>
 
 
 
 
 
123
 
124
+ </div><!-- /.inside -->
125
+ </div><!-- /.postbox -->
126
 
127
+ </div><!-- /.metabox-holder -->
 
128
 
129
+ <div class="metabox-holder">
130
+
131
+ <div class="postbox" id="eztoc-shortcode">
132
+ <h3><span><?= esc_html_e('Shortcode', 'easy-table-of-contents'); ?></span></h3>
133
+ <div class="inside">
134
+
135
+ <table class="form-table">
136
+ <?php do_settings_fields('ez_toc_settings_shortcode', 'ez_toc_settings_shortcode'); ?>
137
+ </table>
138
+
139
+ </div><!-- /.inside -->
140
+ </div><!-- /.postbox -->
141
+
142
+ </div><!-- /.metabox-holder -->
143
+ <?php if (function_exists('ez_toc_pro_activation_link')) { ?>
144
+ <div class="metabox-holder">
145
+
146
+ <div class="postbox" id="eztoc-prosettings">
147
+ <h3><span><?= esc_html_e('PRO Settings', 'easy-table-of-contents'); ?></span></h3>
148
+ <div class="inside">
149
+
150
+ <table class="form-table">
151
+ <?php do_settings_fields('ez_toc_settings_prosettings', 'ez_toc_settings_prosettings'); ?>
152
+
153
+ </table>
154
+
155
+ </div><!-- /.inside -->
156
+ </div><!-- /.postbox -->
157
+
158
+ </div><!-- /.metabox-holder -->
159
+ <?php } ?>
160
+ <?php settings_fields('ez-toc-settings'); ?>
161
+ <?php submit_button(esc_html_e('Save Changes', 'easy-table-of-contents')); ?>
162
+ </form>
163
  </div><!-- /.General Settings ended -->
164
 
165
+
166
+ <div class="eztoc_support_div eztoc-tabcontent" id="technical">
167
+ <div id="eztoc-tabs-technical">
168
+ <a href="javascript:void(0)" onclick="ezTocTabToggle(event, 'eztoc-technical-support',
169
+ 'eztoc-tabcontent-technical', 'eztoc-tablinks-technical')"
170
+ class="eztoc-tablinks-technical active"><?php echo esc_html_e('Technical Support', 'easy-table-of-contents') ?></a>
171
+ |
172
+ <a href="javascript:void(0)" onclick="ezTocTabToggle(event, 'eztoc-technical-how-to-use',
173
+ 'eztoc-tabcontent-technical', 'eztoc-tablinks-technical')"
174
+ class="eztoc-tablinks-technical"><?php echo esc_html_e('How to Use', 'easy-table-of-contents') ?></a>
175
+ |
176
+ <a href="javascript:void(0)" onclick="ezTocTabToggle(event, 'eztoc-technical-shortcode',
177
+ 'eztoc-tabcontent-technical', 'eztoc-tablinks-technical')"
178
+ class="eztoc-tablinks-technical"><?php echo esc_html_e('Shortcode', 'easy-table-of-contents') ?></a>
179
+ |
180
+ <a href="https://tocwp.com/docs/" target="_blank" class="eztoc-tablinks-technical"><?php echo
181
+ esc_html_e('Documentation', 'easy-table-of-contents') ?></a>
182
+ |
183
+ <a href="javascript:void(0)" onclick="ezTocTabToggle(event, 'eztoc-technical-hooks-for-developers',
184
+ 'eztoc-tabcontent-technical', 'eztoc-tablinks-technical')"
185
+ class="eztoc-tablinks-technical"><?php echo esc_html_e('Hooks (for Developers)', 'easy-table-of-contents') ?></a>
186
+ </div>
187
+ <div class="eztoc-form-page-ui">
188
+ <div class="eztoc-left-side">
189
+ <div class="eztoc-tabcontent-technical" id="eztoc-technical-support">
190
+ <h1><?= esc_html_e('Technical Support', 'easy-table-of-contents'); ?></h1>
191
+ <p class="ez-toc-tabcontent-technical-title-content"><?php echo esc_html_e('We are dedicated to provide Technical support & Help to our users. Use the below form for sending your questions.', 'easy-table-of-contents') ?> </p>
192
+ <p><?php echo esc_html_e('You can also contact us from ', 'easy-table-of-contents') ?><a
193
+ href="https://tocwp.com/contact/">https://tocwp.com/contact/</a>.</p>
194
+
195
+ <div class="eztoc_support_div_form" id="technical-form">
196
+ <ul>
197
+ <li>
198
+ <label class="support-label"><?= esc_html_e( 'Email', 'easy-table-of-contents' ) ?><span class="star-mark">*</span></label>
199
+ <div class="support-input">
200
+
201
+ <input type="text" id="eztoc_query_email" name="eztoc_query_email"
202
+ placeholder="<?= esc_html_e( 'Enter your Email', 'easy-table-of-contents' ) ?>" required/>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
  </div>
204
+ </li>
205
+
206
+ <li>
207
+ <label class="support-label"><?= esc_html_e( 'Query', 'easy-table-of-contents' ) ?><span class="star-mark">*</span></label>
208
+
209
+ <div class="support-input">
210
+ <label for="eztoc_query_message">
211
+ <textarea rows="5" cols="50" id="eztoc_query_message"
212
+ name="eztoc_query_message"
213
+ placeholder="Write your query"></textarea></label>
214
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
 
 
 
 
 
 
 
 
216
 
217
+ </li>
218
+
219
+
220
+ <li>
221
+ <div class="eztoc-customer-type">
222
+ <label class="support-label"><?= esc_html_e( 'Type', 'easy-table-of-contents' ) ?></label>
223
+ <div class="support-input">
224
+ <select name="eztoc_customer_type" id="eztoc_customer_type">
225
+ <option value="select"><?= esc_html_e( 'Select Customer Type', 'easy-table-of-contents' ) ?></option>
226
+ <option value="paid"><?= esc_html_e( 'Paid', 'easy-table-of-contents' ) ?><span> <?= esc_html_e( '(Response within 24 hrs)', 'easy-table-of-contents' ) ?></span>
227
+ </option>
228
+ <option value="free">
229
+ <?= esc_html_e( 'Free', 'easy-table-of-contents' ) ?><span> <?= esc_html_e( '( Avg Response within 48-72 hrs)', 'easy-table-of-contents' ) ?></span>
230
+ </option>
231
+ </select>
 
 
 
 
 
 
232
  </div>
233
+ </div>
234
+ </li>
235
+ <li>
236
+ <button class="button button-primary eztoc-send-query"><?php echo esc_html_e('Send Support Request', 'easy-table-of-contents'); ?></button>
237
+ </li>
238
+ </ul>
239
+ <div class="clear"></div>
240
+ <span class="eztoc-query-success eztoc-result eztoc_hide"><?php echo esc_html_e('Message sent successfully, Please wait we will get back to you shortly', 'easy-table-of-contents'); ?></span>
241
+ <span class="eztoc-query-error eztoc-result eztoc_hide"><?php echo esc_html_e('Message not sent. please check your network connection', 'easy-table-of-contents'); ?></span>
 
 
 
242
  </div>
243
+ </div>
244
+ <div class="eztoc-tabcontent-technical" id="eztoc-technical-how-to-use" style="display:
245
+ none;">
246
+ <h1><?= esc_html_e('How to Use', 'easy-table-of-contents'); ?></h1>
247
+ <p class="ez-toc-tabcontent-technical-title-content"><?= esc_html_e('You can check how to use `Easy Table of Contents`, follow the basic details below.', 'easy-table-of-contents'); ?></p>
248
+ <h3><?= esc_html_e('1. AUTOMATICALLY', 'easy-table-of-contents'); ?></h3>
249
+ <ol>
250
+ <li><?= esc_html_e('Go to the tab Settings &gt; General section, check Auto Insert', 'easy-table-of-contents');
251
+ ?></li>
252
+ <li><?= esc_html_e('Select the post types which will have the table of contents automatically inserted.', 'easy-table-of-contents'); ?></li>
253
+ <li><?= esc_html_e('NOTE: The table of contents will only be automatically inserted on post types for which it has been enabled.', 'easy-table-of-contents'); ?></li>
254
+ <li><?= esc_html_e('After Auto Insert, the Position option for choosing where you want to display the `Easy Table of Contents`.', 'easy-table-of-contents'); ?></li>
255
+ </ol>
256
+ <h3><?= esc_html_e('2. MANUALLY', 'easy-table-of-contents'); ?></h3>
257
+ <p><?= esc_html_e('There are two ways for manual adding & display `Easy Table of Contents`:', 'easy-table-of-contents');
258
+ ?></p>
259
+ <ol>
260
+ <li><?= esc_html_e('Using shortcode, you can copy shortcode and paste the shortcode on editor of any post type.', 'easy-table-of-contents');
261
+ ?></li>
262
+ <li><?= esc_html_e('Using Insert table of contents option on editor of any post type.',
263
+ 'easy-table-of-contents');
264
+ ?></li>
265
+ <li><?= esc_html_e('You have to choose post types on tab General &gt; Enable Support section then `Easy Table of Contents` editor options would be shown to choose settings for particular post type.', 'easy-table-of-contents'); ?></li>
266
+ </ol>
267
+ <h3><?= esc_html_e('3. DESIGN CUSTOMIZATION', 'easy-table-of-contents');
268
+ ?></h3>
269
+ <ol>
270
+ <li><?= esc_html_e('Go to tab Settings &gt; Appearance for design customization.', 'easy-table-of-contents');
271
+ ?></li>
272
+ <li><?= esc_html_e('You can change width of `Easy Table of Contents` from select Fixed or Relative sizes or you select custom width then it will be showing custom width option for enter manually width.', 'easy-table-of-contents');
273
+ ?></li>
274
+ <li><?= esc_html_e('You can also choose Alignment of `Easy Table of Contents`.', 'easy-table-of-contents');
275
+ ?></li>
276
+ <li><?= esc_html_e('You can also set Font Option of `Easy Table of Contents` according to your needs.', 'easy-table-of-contents');
277
+ ?></li>
278
+ <li><?= esc_html_e('You can also choose Theme color of `Easy Table of Contents` on Theme Options section according to your choice.', 'easy-table-of-contents');
279
+ ?></li>
280
+ <li><?= esc_html_e('You can also choose Custom Theme colors of `Easy Table of Contents`. according to your requirements', 'easy-table-of-contents');
281
+ ?></li>
282
+ </ol>
283
+ <h3><?= esc_html_e('4. MORE DOCUMENTATION:', 'easy-table-of-contents'); ?></h3>
284
+ <p><?= esc_html_e('You can visit this link ', 'easy-table-of-contents') . '<a href="https://tocwp.com/docs/" target="_blank">' . esc_html_e('More Documentation', 'easy-table-of-contents') . '</a>' . esc_html_e(' for more documentation of `Easy Table of Contents`', 'easy-table-of-contents'); ?></p>
285
+ </div>
286
+ <div class="eztoc-tabcontent-technical" id="eztoc-technical-shortcode" style="display: none;">
287
+ <h1><?= esc_html_e('Shortcode', 'easy-table-of-contents'); ?></h1>
288
+ <p class="ez-toc-tabcontent-technical-title-content"><?= esc_html_e('Use the following shortcode within your content to have the table of contents display where you wish to:', 'easy-table-of-contents'); ?></p>
289
+ <table class="form-table">
290
+ <?php do_settings_fields('ez_toc_settings_shortcode', 'ez_toc_settings_shortcode'); ?>
291
+ </table>
292
+ </div>
293
+ <div class="eztoc-tabcontent-technical" id="eztoc-technical-hooks-for-developers" style="display:
294
+ none;">
295
+ <h1><?= esc_html_e('Hooks (for Developers)', 'easy-table-of-contents'); ?></h1>
296
+ <p class="ez-toc-tabcontent-technical-title-content"><?php echo esc_html_e('This plugin has been designed for easiest way & best features for the users & also as well as for the developers, any developer follow the below advanced instructions:', 'easy-table-of-contents') ?> </p>
297
+
298
+ <h2><?php echo esc_html_e('Hooks', 'easy-table-of-contents') ?></h2>
299
+ <p><?php echo esc_html_e('Developer can use these below hooks for customization of this plugin:', 'easy-table-of-contents')
300
+ ?></p>
301
+ <h4><?php echo esc_html_e('Actions:', 'easy-table-of-contents') ?></h4>
302
+ <ul>
303
+ <li><code><?php echo esc_html_e('ez_toc_before', 'easy-table-of-contents') ?></code>
304
+ </li>
305
+ <li><code><?php echo esc_html_e('ez_toc_after', 'easy-table-of-contents')
306
+ ?></code></li>
307
+ <li>
308
+ <code><?php echo esc_html_e('ez_toc_sticky_toggle_before', 'easy-table-of-contents') ?></code>
309
+ </li>
310
+ <li>
311
+ <code><?php echo esc_html_e('ez_toc_sticky_toggle_after', 'easy-table-of-contents')
312
+ ?></code></li>
313
+ <li>
314
+ <code><?php echo esc_html_e('ez_toc_before_widget_container', 'easy-table-of-contents')
315
+ ?></code></li>
316
+ <li><code><?php echo esc_html_e('ez_toc_before_widget', 'easy-table-of-contents')
317
+ ?></code></li>
318
+ <li>
319
+ <code><?php echo esc_html_e('ez_toc_after_widget_container', 'easy-table-of-contents') ?></code>
320
+ </li>
321
+ <li><code><?php echo esc_html_e('ez_toc_after_widget', 'easy-table-of-contents')
322
+ ?></code></li>
323
+ </ul>
324
+
325
+
326
+ <h4><?php echo esc_html_e('Example: adding a span tag before the `Easy Table of Contents`',
327
+ 'easy-table-of-contents') ?></h4>
328
+ <p><?php echo esc_html_e("Get this following code and paste into your theme\'s function.php file:", 'easy-table-of-contents') ?></p>
329
+ <pre>
330
+ <?php
331
+ $addCustomSpanText = esc_html_e("Some Text or Element here ", 'easy-table-of-contents');
332
+ echo "
333
+ add_action( 'ez_toc_before', 'addCustomSpan' );
334
+ function addCustomSpan()
335
+ {
336
+ echo '&lt;span&gt;$addCustomSpanText&lt;/span&gt;';
337
+ }
338
+ "; ?>
339
+ </pre>
340
+
341
+ </div>
342
+ </div>
343
+ <div class="eztoc-right-side">
344
+ <div class="eztoc-bio-box" id="ez_Bio">
345
+ <h1><?php echo esc_html_e("Vision & Mission", 'easy-table-of-contents') ?></h1>
346
+ <p class="eztoc-p"><?php echo esc_html_e("We strive to provide the best TOC in the world.", 'easy-table-of-contents') ?></p>
347
+ <section class="eztoc_dev-bio">
348
+ <div class="ezoc-bio-wrap">
349
+ <img width="50px" height="50px"
350
+ src="<?php echo plugins_url('assets/ahmed-kaludi.jpg', dirname(__FILE__))
351
+ ?>" alt="ahmed-kaludi"/>
352
+ <p><?= esc_html_e('Lead Dev', 'easy-table-of-contents'); ?></p>
353
  </div>
354
+ <div class="ezoc-bio-wrap">
355
+ <img width="50px" height="50px"
356
+ src="<?php echo plugins_url('assets/Mohammed-kaludi.jpeg', dirname
357
+ (__FILE__)) ?>" alt="Mohammed-kaludi"/>
358
+ <p><?= esc_html_e('Developer', 'easy-table-of-contents'); ?></p>
 
 
 
 
 
 
 
 
 
359
  </div>
360
+ <div class="ezoc-bio-wrap">
361
+ <img width="50px" height="50px"
362
+ src="<?php echo plugins_url('assets/zabi.jpg', dirname(__FILE__)) ?>"
363
+ alt="zabi.jpg"/>
364
+ <p><?= esc_html_e('Developer', 'easy-table-of-contents'); ?></p>
 
 
 
 
 
 
 
 
365
  </div>
366
+ </section>
367
+ <p class="eztoc_boxdesk"><?= esc_html_e('Delivering a good user experience means a lot to us, so we try our best to reply each and every question.', 'easy-table-of-contents'); ?></p>
368
+ <p class="company-link"><?= esc_html_e('Support the innovation & development by upgrading to PRO ', 'easy-table-of-contents'); ?> <a href="https://tocwp.com/pricing/">I Want To Upgrade!</a></p>
369
+ </div>
370
+ </div>
371
+ </div>
372
+ </div> <!-- /.Technical support div ended -->
373
+
374
+ <div class="eztoc_support_div eztoc-tabcontent" id="freevspro">
375
+ <div class="eztoc-wrapper">
376
+ <div class="eztoc-wr">
377
+ <div class="etoc-eztoc-img">
378
+ <span class="sp_ov"></span>
379
+ </div>
380
+ <div class="etoc-eztoc-cnt">
381
+ <h1><?= esc_html_e('UPGRADE to PRO Version'); ?></h1>
382
+ <p><?= esc_html_e('Take your Table of Contents to the NEXT Level!', 'easy-table-of-contents'); ?></p>
383
+ <a class="buy" href="#upgrade"><?= esc_html_e('Purchase Now', 'easy-table-of-contents'); ?></a>
384
+ </div>
385
+ <div class="pvf">
386
+ <div class="ext">
387
+ <div class="ex-1 e-1">
388
+ <h4><?= esc_html_e('Premium Features', 'easy-table-of-contents'); ?></h4>
389
+ <p><?= esc_html_e('Easy TOC Pro will enhances your website table of contents and takes it to a next level to help you reach more engagement and personalization with your users.', 'easy-table-of-contents'); ?></p>
390
  </div>
391
+ <div class="ex-1 e-2">
392
+ <h4><?= esc_html_e('Continuous Innovation', 'easy-table-of-contents'); ?></h4>
393
+ <p><?= esc_html_e('We are planning to continiously build premium features and release them. We have a roadmap and we listen to our customers to turn their feedback into reality.', 'easy-table-of-contents'); ?></p>
 
 
 
 
 
 
 
 
 
 
394
  </div>
395
+ <div class="ex-1 e-3">
396
+ <h4><?= esc_html_e('Tech Support', 'easy-table-of-contents'); ?></h4>
397
+ <p><?= esc_html_e('Get private ticketing help from our full-time technical staff & developers who helps you with the technical issues.', 'easy-table-of-contents'); ?></p>
 
 
 
 
 
 
 
 
 
 
398
  </div>
399
+ </div><!-- /. ext -->
400
+ <div class="pvf-cnt">
401
+ <div class="pvf-tlt">
402
+ <h2><?= esc_html_e('Compare Pro vs. Free Version', 'easy-table-of-contents'); ?></h2>
403
+ <span><?= esc_html_e('See what you\'ll get with the professional version', 'easy-table-of-contents'); ?></span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
404
  </div>
405
+ <div class="pvf-cmp">
406
+ <div class="fr">
407
+ <h1><?= esc_html_e('FREE', 'easy-table-of-contents'); ?></h1>
408
+ <div class="fr-fe">
409
+ <div class="fe-1">
410
+ <h4><?= esc_html_e('Continious Development', 'easy-table-of-contents'); ?></h4>
411
+ <p><?= esc_html_e('We take bug reports and feature requests seriously. We’re continiously developing &amp; improve this product for last 2 years with passion and love.', 'easy-table-of-contents'); ?></p>
412
+ </div>
413
+ <div class="fe-1">
414
+ <h4><?= esc_html_e('50+ Features', 'easy-table-of-contents'); ?></h4>
415
+ <p><?= esc_html_e('We\'re constantly expanding the plugin and make it more useful. We have wide variety of features which will fit any use-case.', 'easy-table-of-contents'); ?></p>
416
+ </div>
417
+ </div><!-- /. fr-fe -->
418
+ </div><!-- /. fr -->
419
+ <div class="pr">
420
+ <h1><?= esc_html_e('PRO', 'easy-table-of-contents'); ?></h1>
421
+ <div class="pr-fe">
422
+ <span><?= esc_html_e('Everything in Free, and:', 'easy-table-of-contents'); ?></span>
423
+ <div class="fet">
424
+ <div class="fe-2">
425
+ <div class="fe-t">
426
+ <img src="<?php echo plugins_url('assets/right-tick.png',
427
+ dirname(__FILE__)) ?>" alt="right-tick"/>
428
+ <h4><?= esc_html_e('Gutenberg Block', 'easy-table-of-contents'); ?></h4>
429
+ </div>
430
+ <p><?= esc_html_e('Easily create TOC in Gutenberg block without the need any coding or shortcode.', 'easy-table-of-contents'); ?></p>
431
+ </div>
432
+ <div class="fe-2">
433
+ <div class="fe-t">
434
+ <img src="<?php echo plugins_url('assets/right-tick.png',
435
+ dirname(__FILE__)) ?>" alt="right-tick"/>
436
+ <h4><?= esc_html_e('Elementor Widget', 'easy-table-of-contents'); ?></h4>
437
+ </div>
438
+ <p><?= esc_html_e('Easily create TOC in Elementor with the widget without the need any coding or shortcode.', 'easy-table-of-contents'); ?></p>
439
+ </div>
440
+
441
+ <div class="fe-2">
442
+ <div class="fe-t">
443
+ <img src="<?php echo plugins_url('assets/right-tick.png',
444
+ dirname(__FILE__)) ?>" alt="right-tick"/>
445
+ <h4><?= esc_html_e('Fixed/Sticky TOC', 'easy-table-of-contents'); ?></h4>
446
+ </div>
447
+ <p><?= esc_html_e('Users can faster find the content they want with sticky', 'easy-table-of-contents'); ?></p>
448
+ </div>
449
+
450
+
451
+ <div class="fe-2">
452
+ <div class="fe-t">
453
+ <img src="<?php echo plugins_url('assets/right-tick.png',
454
+ dirname(__FILE__)) ?>" alt="right-tick"/>
455
+ <h4><?= esc_html_e('Full AMP Support', 'easy-table-of-contents'); ?></h4>
456
+ </div>
457
+ <p><?= esc_html_e('Generates a table of contents with your existing setup and makes them AMP automatically.', 'easy-table-of-contents'); ?></p>
458
+ </div>
459
+ <div class="fe-2">
460
+ <div class="fe-t">
461
+ <img src="<?php echo plugins_url('assets/right-tick.png',
462
+ dirname(__FILE__)) ?>" alt="right-tick"/>
463
+ <h4><?= esc_html_e('Continuous Updates', 'easy-table-of-contents'); ?></h4>
464
+ </div>
465
+ <p><?= esc_html_e("We're continuously updating our premium features and releasing them.", 'easy-table-of-contents'); ?></p>
466
+ </div>
467
+ <div class="fe-2">
468
+ <div class="fe-t">
469
+ <img src="<?php echo plugins_url('assets/right-tick.png',
470
+ dirname(__FILE__)) ?>" alt="right-tick"/>
471
+ <h4><?= esc_html_e("Documentation", 'easy-table-of-contents'); ?></h4>
472
+ </div>
473
+ <p><?= esc_html_e("We create tutorials for every possible feature and keep it updated for you.", 'easy-table-of-contents'); ?></p>
474
+ </div>
475
+ </div><!-- /. fet -->
476
+ <div class="pr-btn">
477
+ <a href="#upgrade"><?= esc_html_e("Upgrade to Pro", 'easy-table-of-contents'); ?></a>
478
+ </div><!-- /. pr-btn -->
479
+ </div><!-- /. pr-fe -->
480
+ </div><!-- /.pr -->
481
+ </div><!-- /. pvf-cmp -->
482
+ </div><!-- /. pvf-cnt -->
483
+ <div id="upgrade" class="amp-upg">
484
+ <div class="upg-t">
485
+ <h2><?= esc_html_e("Let's Upgrade Your Easy Table of Contents", 'easy-table-of-contents'); ?></h2>
486
+ <span><?= esc_html_e("Choose your plan and upgrade in minutes!", 'easy-table-of-contents'); ?></span>
487
  </div>
488
+ <div class="etoc-pri-lst">
489
+ <div class="pri-tb">
490
+ <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=1"
491
+ target="_blank">
492
+ <h5><?= esc_html_e("PERSONAL", 'easy-table-of-contents'); ?></h5>
493
+ <span class="d-amt"><sup>$</sup>49</span>
494
+ <span class="amt"><sup>$</sup>49</span>
495
+ <span class="s-amt"><?= esc_html_e("(Save $59)", 'easy-table-of-contents'); ?></span>
496
+ <span class="bil"><?= esc_html_e("Billed Annually", 'easy-table-of-contents'); ?></span>
497
+ <span class="s"><?= esc_html_e("1 Site License", 'easy-table-of-contents'); ?></span>
498
+ <span class="e"><?= esc_html_e("Tech Support", 'easy-table-of-contents'); ?></span>
499
+ <span class="f"><?= esc_html_e("1 year Updates", 'easy-table-of-contents'); ?> </span>
500
+ <span class="etoc-sv"><?= esc_html_e("Pro Features", 'easy-table-of-contents'); ?> </span>
501
+ <span class="pri-by"><?= esc_html_e("Buy Now", 'easy-table-of-contents'); ?></span>
502
+ </a>
503
+ </div>
504
+ <div class="pri-tb rec">
505
+ <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=2"
506
+ target="_blank">
507
+ <h5><?= esc_html_e("MULTIPLE", 'easy-table-of-contents'); ?></h5>
508
+ <span class="d-amt"><sup>$</sup>69</span>
509
+ <span class="amt"><sup>$</sup>69</span>
510
+ <span class="s-amt"><?= esc_html_e("(Save $79)", 'easy-table-of-contents'); ?></span>
511
+ <span class="bil"><?= esc_html_e("Billed Annually", 'easy-table-of-contents'); ?></span>
512
+ <span class="s"><?= esc_html_e("3 Site License", 'easy-table-of-contents'); ?></span>
513
+ <span class="e"><?= esc_html_e("Tech Support", 'easy-table-of-contents'); ?></span>
514
+ <span class="f"><?= esc_html_e("1 year Updates", 'easy-table-of-contents'); ?></span>
515
+ <span class="etoc-sv"><?= esc_html_e("Save 78%", 'easy-table-of-contents'); ?></span>
516
+ <span class="pri-by"><?= esc_html_e("Buy Now", 'easy-table-of-contents'); ?></span>
517
+ <span class="etoc-rcm"><?= esc_html_e("RECOMMENDED", 'easy-table-of-contents'); ?></span>
518
+ </a>
519
+ </div>
520
+ <div class="pri-tb">
521
+ <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=3"
522
+ target="_blank">
523
+ <h5><?= esc_html_e("WEBMASTER", 'easy-table-of-contents'); ?></h5>
524
+ <span class="d-amt"><sup>$</sup>79</span>
525
+ <span class="amt"><sup>$</sup>79</span>
526
+ <span class="s-amt"><?= esc_html_e("(Save $99)", 'easy-table-of-contents'); ?></span>
527
+ <span class="bil"><?= esc_html_e("Billed Annually", 'easy-table-of-contents'); ?></span>
528
+ <span class="s"><?= esc_html_e("10 Site License", 'easy-table-of-contents'); ?></span>
529
+ <span class="e"><?= esc_html_e("Tech Support", 'easy-table-of-contents'); ?></span>
530
+ <span class="f"><?= esc_html_e("1 year Updates", 'easy-table-of-contents'); ?></span>
531
+ <span class="etoc-sv"><?= esc_html_e("Save 83%", 'easy-table-of-contents'); ?></span>
532
+ <span class="pri-by"><?= esc_html_e("Buy Now", 'easy-table-of-contents'); ?></span>
533
+ </a>
534
+ </div>
535
+ <div class="pri-tb">
536
+ <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=4"
537
+ target="_blank">
538
+ <h5><?= esc_html_e("FREELANCER", 'easy-table-of-contents'); ?></h5>
539
+ <span class="d-amt"><sup>$</sup>99</span>
540
+ <span class="amt"><sup>$</sup>99</span>
541
+ <span class="s-amt"><?= esc_html_e("(Save $119)", 'easy-table-of-contents'); ?></span>
542
+ <span class="bil"><?= esc_html_e("Billed Annually", 'easy-table-of-contents'); ?></span>
543
+ <span class="s"><?= esc_html_e("25 Site License", 'easy-table-of-contents'); ?></span>
544
+ <span class="e"><?= esc_html_e("Tech Support", 'easy-table-of-contents'); ?></span>
545
+ <span class="f"><?= esc_html_e("1 year Updates", 'easy-table-of-contents'); ?></span>
546
+ <span class="etoc-sv"><?= esc_html_e("Save 90%", 'easy-table-of-contents'); ?></span>
547
+ <span class="pri-by"><?= esc_html_e("Buy Now", 'easy-table-of-contents'); ?></span>
548
+ </a>
549
+ </div>
550
+ <div class="pri-tb">
551
+ <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=5"
552
+ target="_blank">
553
+ <h5><?= esc_html_e("AGENCY", 'easy-table-of-contents'); ?></h5>
554
+ <span class="d-amt"><sup>$</sup>199</span>
555
+ <span class="amt"><sup>$</sup>199</span>
556
+ <span class="s-amt"><?= esc_html_e("(Save $199)", 'easy-table-of-contents'); ?></span>
557
+ <span class="bil"><?= esc_html_e("Billed Annually", 'easy-table-of-contents'); ?></span>
558
+ <span class="s"><?= esc_html_e("Unlimited Sites", 'easy-table-of-contents'); ?></span>
559
+ <span class="e"><?= esc_html_e("E-mail support", 'easy-table-of-contents'); ?></span>
560
+ <span class="f"><?= esc_html_e("1 year Updates", 'easy-table-of-contents'); ?></span>
561
+ <span class="etoc-sv"><?= esc_html_e("UNLIMITED", 'easy-table-of-contents'); ?></span>
562
+ <span class="pri-by"><?= esc_html_e("Buy Now", 'easy-table-of-contents'); ?></span>
563
+ </a>
564
+ </div>
565
+ <div class="pri-tb">
566
+ <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=6"
567
+ target="_blank">
568
+ <h5><?= esc_html_e("LIFETIME", 'easy-table-of-contents'); ?></h5>
569
+ <span class="d-amt"><sup>$</sup>499</span>
570
+ <span class="amt"><sup>$</sup>499</span>
571
+ <span class="s-amt"><?= esc_html_e("(Save $199)", 'easy-table-of-contents'); ?></span>
572
+ <span class="bil"><?= esc_html_e("Billed Annually", 'easy-table-of-contents'); ?></span>
573
+ <span class="s"><?= esc_html_e("Unlimited Sites", 'easy-table-of-contents'); ?></span>
574
+ <span class="e"><?= esc_html_e("Unlimited E-mail support", 'easy-table-of-contents'); ?></span>
575
+ <span class="f"><?= esc_html_e("Lifetime License", 'easy-table-of-contents'); ?></span>
576
+ <span class="etoc-sv"><?= esc_html_e("UNLIMITED", 'easy-table-of-contents'); ?></span>
577
+ <span class="pri-by"><?= esc_html_e("Buy Now", 'easy-table-of-contents'); ?></span>
578
+ </a>
579
+ </div>
580
+ </div><!-- /.pri-lst -->
581
+ <div class="tru-us">
582
+ <img src="<?php echo plugins_url('assets/toc-rating.png', dirname(__FILE__))
583
+ ?>" alt="toc-rating"/>
584
+ <h2><?= esc_html_e("Used by more than 3,00,000+ Users!", 'easy-table-of-contents'); ?></h2>
585
+ <p><?= esc_html_e("More than 300k Websites, Blogs &amp; E-Commerce shops are powered by our easy table of contents plugin making it the #1 Independent TOC plugin in WordPress.", 'easy-table-of-contents'); ?></p>
586
+ <a href="https://wordpress.org/support/plugin/easy-table-of-contents/reviews/?filter=5"
587
+ target="_blank"><?= esc_html_e("Read The Reviews", 'easy-table-of-contents'); ?></a>
588
+ </div>
589
+ </div><!--/ .amp-upg -->
590
+ <div class="ampfaq">
591
+ <h2><?= esc_html_e("Frequently Asked Questions", 'easy-table-of-contents'); ?></h2>
592
+ <div class="faq-lst">
593
+ <div class="lt">
594
+ <ul>
595
+ <li>
596
+ <span><?= esc_html_e("Is there a setup fee?", 'easy-table-of-contents'); ?></span>
597
+ <p><?= esc_html_e("No. There are no setup fees on any of our plans", 'easy-table-of-contents'); ?></p>
598
+ </li>
599
+ <li>
600
+ <span><?= esc_html_e("What's the time span for your contracts?", 'easy-table-of-contents'); ?></span>
601
+ <p><?= esc_html_e("All the plans are year-to-year which are subscribed annually except for lifetime plan.", 'easy-table-of-contents'); ?></p>
602
+ </li>
603
+ <li>
604
+ <span><?php echo esc_html_e("What payment methods are accepted?", 'easy-table-of-contents') ?></span>
605
+ <p><?php echo esc_html_e("We accepts PayPal and Credit Card payments.", 'easy-table-of-contents') ?></p>
606
+ </li>
607
+ <li>
608
+ <span><?php echo esc_html_e("Do you offer support if I need help?", 'easy-table-of-contents') ?></span>
609
+ <p><?php echo esc_html_e("Yes! Top-notch customer support for our paid customers is key for a quality product, so we’ll do our very best to resolve any issues you encounter via our support page.", 'easy-table-of-contents') ?></p>
610
+ </li>
611
+ <li>
612
+ <span><?php echo esc_html_e("Can I use the plugins after my subscription is expired?", 'easy-table-of-contents') ?></span>
613
+ <p><?php echo esc_html_e("Yes, you can use the plugins, but you will not get future updates for those plugins.", 'easy-table-of-contents') ?></p>
614
+ </li>
615
+ </ul>
616
+ </div>
617
+ <div class="rt">
618
+ <ul>
619
+ <li>
620
+ <span><?php echo esc_html_e("Can I cancel my membership at any time?", 'easy-table-of-contents') ?></span>
621
+ <p><?php echo esc_html_e("Yes. You can cancel your membership by contacting us.", 'easy-table-of-contents') ?></p>
622
+ </li>
623
+ <li>
624
+ <span><?php echo esc_html_e("Can I change my plan later on?", 'easy-table-of-contents') ?></span>
625
+ <p><?php echo esc_html_e("Yes. You can upgrade your plan by contacting us.", 'easy-table-of-contents') ?></p>
626
+ </li>
627
+ <li>
628
+ <span><?php echo esc_html_e("Do you offer refunds?", 'easy-table-of-contents') ?></span>
629
+ <p><?php echo esc_html_e("You are fully protected by our 100% Money-Back Guarantee Unconditional. If during the next 14 days you experience an issue that makes the plugin unusable, and we are unable to resolve it, we’ll happily offer a full refund.", 'easy-table-of-contents') ?></p>
630
+ </li>
631
+ <li>
632
+ <span><?php echo esc_html_e("Do I get updates for the premium plugin?", 'easy-table-of-contents') ?></span>
633
+ <p><?php echo esc_html_e("Yes, you will get updates for all the premium plugins until your subscription is active.", 'easy-table-of-contents') ?></p>
634
+ </li>
635
+ </ul>
636
+ </div>
637
+ </div><!-- /.faq-lst -->
638
+ <div class="f-cnt">
639
+ <span><?php echo esc_html_e("I have other pre-sale questions, can you help?", 'easy-table-of-contents') ?></span>
640
+ <p><?php echo esc_html_e("All the plans are year-to-year which are subscribed annually.", 'easy-table-of-contents') ?></p>
641
+ <a href="https://tocwp.com/contact/'?utm_source=tocwp-plugin&utm_medium=addon-card'"
642
+ target="_blank"><?php echo esc_html_e("Contact a Human", 'easy-table-of-contents') ?></a>
643
+ </div><!-- /.f-cnt -->
644
+ </div><!-- /.faq -->
645
+ </div><!-- /. pvf -->
646
  </div>
647
+ </div>
648
+ </div><!-- /.freevspro div ended -->
649
 
650
+ <div id="license" class="eztoc_support_div eztoc-tabcontent">
651
+ <?php
652
  do_action("admin_upgrade_license_page");
653
+ ?>
654
+ </div>
655
  </div>
includes/inc.functions.php CHANGED
@@ -107,7 +107,7 @@ function ez_toc_woo_category_desc() {
107
  $desc = $term_object->description;
108
  preg_match_all( '@<h1.*?>(.*?)<\/h1>@', $desc, $matches );
109
  $array = $matches[1];
110
- $container = '<div id="ez-toc-container" class="counter-hierarchy counter-decimal ez-toc-grey"><div class="ez-toc-title-container"><p class="ez-toc-title">Table of Contents</p><span class="ez-toc-title-toggle"><a class="ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle" style="display: inline;"><i class="ez-toc-glyphicon ez-toc-icon-toggle"></i></a></span></div><nav><ul class="ez-toc-list">';
111
  foreach ( $array as $val ) {
112
  $vals .= '<li><a class="anchor" href="#'.$val.'">'.$val.'</a></li>';
113
  $desc = preg_replace('/<h1>(.*?)<\/h1>/', "<h1 id='$1'>$1</h1>", $desc);
@@ -122,4 +122,27 @@ function ez_toc_woo_cat_desc_remove(){
122
  return false;
123
  }
124
  remove_action( 'woocommerce_archive_description', 'woocommerce_taxonomy_archive_description', 10 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  }
107
  $desc = $term_object->description;
108
  preg_match_all( '@<h1.*?>(.*?)<\/h1>@', $desc, $matches );
109
  $array = $matches[1];
110
+ $container = '<div id="ez-toc-container" class="counter-hierarchy counter-decimal ez-toc-grey"><div class="ez-toc-title-container"><p class="ez-toc-title">' . esc_html_e('Table of Contents', 'easy-table-of-contents') . '</p><span class="ez-toc-title-toggle"><a class="ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle" style="display: inline;"><i class="ez-toc-glyphicon ez-toc-icon-toggle"></i></a></span></div><nav><ul class="ez-toc-list">';
111
  foreach ( $array as $val ) {
112
  $vals .= '<li><a class="anchor" href="#'.$val.'">'.$val.'</a></li>';
113
  $desc = preg_replace('/<h1>(.*?)<\/h1>/', "<h1 id='$1'>$1</h1>", $desc);
122
  return false;
123
  }
124
  remove_action( 'woocommerce_archive_description', 'woocommerce_taxonomy_archive_description', 10 );
125
+ }
126
+
127
+
128
+ if (function_exists( 'mpg_run' )) {
129
+ add_filter('the_content', 'ez_toc_mpg');
130
+ }
131
+ function ez_toc_mpg($content){
132
+ if (is_front_page() || is_single()) {
133
+ return $content;
134
+ }
135
+ preg_match_all( '/<h(.*?).*?>(.*?)<\/h(.*?)>/', $content, $matches );
136
+ $array = $matches[2];
137
+ $container = '<div id="ez-toc-container" class="container counter-hierarchy counter-decimal ez-toc-grey"><div class="ez-toc-title-container"><p class="ez-toc-title">' . esc_html_e('Table of Contents', 'easy-table-of-contents') . '</p><span class="ez-toc-title-toggle"><a class="ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle" style="display: inline;"><i class="ez-toc-glyphicon ez-toc-icon-toggle"></i></a></span></div><nav><ul class="ez-toc-list">';
138
+ foreach ( $array as $val ) {
139
+ $val = preg_replace('/\[(.*?)\](.*?)\[(.*?)\]/', '$2', $val);
140
+ $val = preg_replace('/{(.*?)\|(.*?)\|(.*?)}/', '$3', $val);
141
+ $vals .= '<li><a class="anchor" href="#'.$val.'">'.$val.'</a></li>';
142
+ $content = preg_replace('/<h(.*?).*?>(.*?)<\/h(.*?)>/', "<h$3 id='$2'>$2</h$3>", $content);
143
+ }
144
+ $last .= '</ul></nav></div>';
145
+ $content = $container . $vals . $last . $content;
146
+
147
+ return $content;
148
  }
includes/vendor/ultimate-web-scraper/tag_filter.php CHANGED
@@ -1,3260 +1,3260 @@
1
- <?php
2
- // CubicleSoft PHP Tag Filter class. Can repair broken HTML.
3
- // (C) 2020 CubicleSoft. All Rights Reserved.
4
-
5
- class TagFilterStream
6
- {
7
- protected $lastcontent, $lastresult, $final, $options, $stack;
8
-
9
- public function __construct($options = array())
10
- {
11
- $this->Init($options);
12
- }
13
-
14
- public function Init($options = array())
15
- {
16
- if (!isset($options["keep_attr_newlines"])) $options["keep_attr_newlines"] = false;
17
- if (!isset($options["keep_comments"])) $options["keep_comments"] = false;
18
- if (!isset($options["allow_namespaces"])) $options["allow_namespaces"] = true;
19
- if (!isset($options["process_attrs"])) $options["process_attrs"] = array();
20
- if (!isset($options["charset"])) $options["charset"] = "UTF-8";
21
- $options["charset"] = strtoupper($options["charset"]);
22
- if (!isset($options["charset_tags"])) $options["charset_tags"] = true;
23
- if (!isset($options["charset_attrs"])) $options["charset_attrs"] = true;
24
- if (!isset($options["tag_name_map"])) $options["tag_name_map"] = array();
25
- if (!isset($options["untouched_tag_attr_keys"])) $options["untouched_tag_attr_keys"] = array();
26
- if (!isset($options["void_tags"])) $options["void_tags"] = array();
27
- if (!isset($options["alt_tag_content_rules"])) $options["alt_tag_content_rules"] = array();
28
- if (!isset($options["pre_close_tags"])) $options["pre_close_tags"] = array();
29
- if (!isset($options["output_mode"])) $options["output_mode"] = "html";
30
- if (!isset($options["lowercase_tags"])) $options["lowercase_tags"] = true;
31
- if (!isset($options["lowercase_attrs"])) $options["lowercase_attrs"] = true;
32
- $options["tag_num"] = 0;
33
-
34
- $this->lastcontent = "";
35
- $this->lastresult = "";
36
- $this->final = false;
37
- $this->options = $options;
38
- $this->stack = array();
39
- }
40
-
41
- public function Process($content)
42
- {
43
- if ($this->lastcontent !== "") $content = $this->lastcontent . $content;
44
-
45
- $result = $this->lastresult;
46
- $this->lastresult = "";
47
- $tag = false;
48
- $a = ord("A");
49
- $a2 = ord("a");
50
- $f = ord("F");
51
- $f2 = ord("f");
52
- $z = ord("Z");
53
- $z2 = ord("z");
54
- $hyphen = ord("-");
55
- $underscore = ord("_");
56
- $period = ord(".");
57
- $colon = ord(":");
58
- $zero = ord("0");
59
- $nine = ord("9");
60
- $cx = 0;
61
- $cy = strlen($content);
62
- while ($cx < $cy)
63
- {
64
- if ($tag)
65
- {
66
- $firstcx = $cx;
67
-
68
- // First character is '<'. Extract all non-alpha chars.
69
- $prefix = "";
70
- $startpos = $cx + 1;
71
- for ($x = $startpos; $x < $cy; $x++)
72
- {
73
- $val = ord($content[$x]);
74
- if (($val >= $a && $val <= $z) || ($val >= $a2 && $val <= $z2))
75
- {
76
- if ($x > $cx + 1) $prefix = ltrim(substr($content, $cx + 1, $x - $cx - 1));
77
- $startpos = $x;
78
-
79
- break;
80
- }
81
- }
82
-
83
- if ($prefix === "") $open = true;
84
- else
85
- {
86
- if ($prefix[0] === "!")
87
- {
88
- // !DOCTYPE vs. comment.
89
- if (substr($prefix, 0, 3) !== "!--")
90
- {
91
- $prefix = "!";
92
- $open = true;
93
- }
94
- else
95
- {
96
- // Comment.
97
- $pos = strpos($content, "!--", $cx);
98
- $pos2 = strpos($content, "-->", $pos + 3);
99
- if ($pos2 === false)
100
- {
101
- if (!$this->final)
102
- {
103
- $cx = $firstcx;
104
-
105
- break;
106
- }
107
-
108
- $pos2 = $cy;
109
- }
110
-
111
- if ($this->options["keep_comments"])
112
- {
113
- $content2 = substr($content, $pos + 3, $pos2 - $pos - 3);
114
- if ($this->options["charset"] === "UTF-8" && !self::IsValidUTF8($content2)) $content2 = self::MakeValidUTF8($content2);
115
- $content2 = "<!-- " . trim(htmlspecialchars($content2, ENT_COMPAT | ENT_HTML5, $this->options["charset"])) . " -->";
116
-
117
- // Let a callback handle any necessary changes.
118
- if (isset($this->options["content_callback"]) && is_callable($this->options["content_callback"])) call_user_func_array($this->options["content_callback"], array($this->stack, $result, &$content2, $this->options));
119
-
120
- $result .= $content2;
121
- }
122
- $cx = $pos2 + 3;
123
-
124
- $tag = false;
125
-
126
- continue;
127
- }
128
- }
129
- else if ($prefix[0] === "/")
130
- {
131
- // Close tag.
132
- $prefix = "/";
133
- $open = false;
134
- }
135
- else if ($prefix[0] === "<")
136
- {
137
- // Stray less than. Encode and reset.
138
- $content2 = "&lt;";
139
-
140
- // Let a callback handle any necessary changes.
141
- if (isset($this->options["content_callback"]) && is_callable($this->options["content_callback"])) call_user_func_array($this->options["content_callback"], array($this->stack, $result, &$content2, $this->options));
142
-
143
- $result .= $content2;
144
- $cx++;
145
-
146
- continue;
147
- }
148
- else
149
- {
150
- // Unknown. Encode it.
151
- $data = substr($content, $cx, strpos($content, $prefix, $cx) + strlen($prefix) - $cx);
152
- $content2 = $data;
153
- if ($this->options["charset"] === "UTF-8" && !self::IsValidUTF8($content2)) $content2 = self::MakeValidUTF8($content2);
154
- $content2 = htmlspecialchars($content2, ENT_COMPAT | ENT_HTML5, $this->options["charset"]);
155
-
156
- // Let a callback handle any necessary changes.
157
- if (isset($this->options["content_callback"]) && is_callable($this->options["content_callback"])) call_user_func_array($this->options["content_callback"], array($this->stack, $result, &$content2, $this->options));
158
-
159
- $result .= $content2;
160
- $cx += strlen($data);
161
-
162
- $tag = false;
163
-
164
- continue;
165
- }
166
- }
167
-
168
- // Read the tag name.
169
- $tagname = "";
170
- $parse = false;
171
- $cx = $startpos;
172
- for (; $cx < $cy; $cx++)
173
- {
174
- $val = ord($content[$cx]);
175
- if ($val > 127) $parse = true;
176
- else if (!(($val >= $a && $val <= $z) || ($val >= $a2 && $val <= $z2) || ($cx > $startpos && (($val >= $zero && $val <= $nine) || $val == $hyphen || $val == $underscore || $val == $period)) || ($this->options["allow_namespaces"] && $val == $colon))) break;
177
- }
178
- $tagname = substr($content, $startpos, $cx - $startpos);
179
- if ($parse)
180
- {
181
- if ($this->options["charset_tags"] && $this->options["charset"] === "UTF-8") $tagname = (self::IsValidUTF8($tagname) ? $tagname : self::MakeValidUTF8($tagname));
182
- else $tagname = preg_replace(($this->options["allow_namespaces"] ? '/[^A-Za-z0-9:._-]/' : '/[^A-Za-z0-9._-]/'), "", $tagname);
183
- }
184
- $tagname = rtrim($tagname, "._-:");
185
- if (!$this->options["charset_tags"]) $tagname = preg_replace('/[^A-Za-z0-9:]/', "", $tagname);
186
- $outtagname = ($this->options["lowercase_tags"] ? strtolower($tagname) : $tagname);
187
- $tagname = strtolower($tagname);
188
-
189
- // Close open tags in the stack that match the set of tags to look for to close.
190
- if ($open && isset($this->options["pre_close_tags"][$tagname]))
191
- {
192
- // Find matches.
193
- $info2 = $this->options["pre_close_tags"][$tagname];
194
- $limit = (isset($info2["_limit"]) ? $info2["_limit"] : array());
195
- if (is_string($limit)) $limit = array($limit => true);
196
-
197
- // Unwind the stack.
198
- do
199
- {
200
- $found = false;
201
- foreach ($this->stack as $info)
202
- {
203
- if (isset($info2[$info["tag_name"]]))
204
- {
205
- $found = true;
206
-
207
- break;
208
- }
209
-
210
- if (isset($limit[$info["tag_name"]])) break;
211
- }
212
-
213
- if ($found)
214
- {
215
- do
216
- {
217
- // Let a callback handle any necessary changes.
218
- $attrs = array();
219
- if (isset($this->options["tag_callback"]) && is_callable($this->options["tag_callback"])) $funcresult = call_user_func_array($this->options["tag_callback"], array($this->stack, &$result, false, "/" . $this->stack[0]["tag_name"], &$attrs, $this->options));
220
- else $funcresult = array();
221
-
222
- if (!isset($funcresult["keep_tag"])) $funcresult["keep_tag"] = true;
223
-
224
- $info = array_shift($this->stack);
225
-
226
- $result = $info["result"] . ($funcresult["keep_tag"] ? $info["open_tag"] : "") . ($info["keep_interior"] ? $result : "");
227
- if ($info["close_tag"] && $funcresult["keep_tag"]) $result .= "</" . $info["out_tag_name"] . ">" . $info["post_tag"];
228
- } while (!isset($info2[$info["tag_name"]]));
229
- }
230
- } while ($found);
231
- }
232
-
233
- // Process attributes/properties until a closing condition is encountered.
234
- $state = "name";
235
- $voidtag = false;
236
- $attrs = array();
237
- do
238
- {
239
- if ($state === "name")
240
- {
241
- // Find attribute key/property.
242
- for ($x = $cx; $x < $cy; $x++)
243
- {
244
- if ($content[$x] === ">" || $content[$x] === "<")
245
- {
246
- $cx = $x;
247
-
248
- $state = "exit";
249
-
250
- break;
251
- }
252
- else if ($content[$x] === "/")
253
- {
254
- $pos = strpos($content, ">", $x + 1);
255
- if ($pos !== false && trim(substr($content, $x + 1, $pos - $x - 1)) === "")
256
- {
257
- $cx = $pos;
258
- $voidtag = true;
259
-
260
- $state = "exit";
261
-
262
- break;
263
- }
264
- }
265
- else if ($content[$x] === "\"" || $content[$x] === "'" || $content[$x] === "`")
266
- {
267
- $pos = strpos($content, $content[$x], $x + 1);
268
- if ($pos === false) $content .= $content[$x];
269
- else if (isset($this->options["untouched_tag_attr_keys"][$tagname]))
270
- {
271
- $keyname = substr($content, $x, $pos - $x + 1);
272
- $cx = $pos + 1;
273
-
274
- $state = "equals";
275
- }
276
- else
277
- {
278
- $keyname = substr($content, $x + 1, $pos - $x - 1);
279
- if ($this->options["lowercase_attrs"]) $keyname = strtolower($keyname);
280
- if (preg_match('/<\s*\/\s*' . $tagname . '(\s*|\s+.+?)>/is', strtolower($keyname)) || (count($this->stack) && preg_match('/<\s*\/\s*' . $this->stack[0]["tag_name"] . '(\s*|\s+.+?)>/is', strtolower($keyname))))
281
- {
282
- // Found a matching close tag within the key name. Bail out.
283
- $state = "exit";
284
-
285
- break;
286
- }
287
- else
288
- {
289
- $keyname = preg_replace('/[^' . ($this->options["lowercase_attrs"] ? "" : "A-Z") . 'a-z' . ($this->options["allow_namespaces"] ? ":" : "") . ']/', "", $keyname);
290
- if ($this->options["allow_namespaces"]) $keyname = rtrim($keyname, ":");
291
- $cx = $pos + 1;
292
-
293
- $state = "equals";
294
- }
295
- }
296
-
297
- break;
298
- }
299
- else
300
- {
301
- $val = ord($content[$x]);
302
- if (($val >= $a && $val <= $z) || ($val >= $a2 && $val <= $z2))
303
- {
304
- $cx = $x;
305
- $parse = false;
306
-
307
- for (; $cx < $cy; $cx++)
308
- {
309
- if ($content[$cx] === " " || $content[$cx] === "=" || $content[$cx] === "\"" || $content[$cx] === "'" || $content[$cx] === "`" || $content[$cx] === ">" || $content[$cx] === "<" || $content[$cx] === "/" || $content[$cx] === "\0" || $content[$cx] === "\r" || $content[$cx] === "\n" || $content[$cx] === "\t") break;
310
- else if (ord($content[$cx]) > 127) $parse = true;
311
- }
312
-
313
- $keyname = substr($content, $x, $cx - $x);
314
- if ($parse && $this->options["charset_attrs"] && $this->options["charset"] === "UTF-8")
315
- {
316
- $keyname = preg_replace(($this->options["allow_namespaces"] ? '/[^A-Za-z0-9:._\-\x80-\xFF]/' : '/[^A-Za-z0-9._\-\x80-\xFF]/'), "", $keyname);
317
- if (!self::IsValidUTF8($keyname)) $keyname = self::MakeValidUTF8($keyname);
318
- }
319
- else
320
- {
321
- $keyname = preg_replace(($this->options["allow_namespaces"] ? '/[^A-Za-z0-9:._-]/' : '/[^A-Za-z0-9._-]/'), "", $keyname);
322
- }
323
- $keyname = rtrim($keyname, "._-:");
324
- if (!isset($this->options["untouched_tag_attr_keys"][$tagname]) && $this->options["lowercase_attrs"]) $keyname = strtolower($keyname);
325
-
326
- $state = "equals";
327
-
328
- break;
329
- }
330
- }
331
- }
332
-
333
- if ($state === "name")
334
- {
335
- $cx = $cy;
336
-
337
- $state = "exit";
338
- }
339
- }
340
- else if ($state === "equals")
341
- {
342
- // Find the equals sign OR the start of the next attribute/property.
343
- for ($x = $cx; $x < $cy; $x++)
344
- {
345
- if ($content[$x] === ">" || $content[$x] === "<")
346
- {
347
- $cx = $x;
348
-
349
- $attrs[$keyname] = true;
350
-
351
- $state = "exit";
352
-
353
- break;
354
- }
355
- else if ($content[$x] === "=")
356
- {
357
- $cx = $x + 1;
358
-
359
- $state = "value";
360
-
361
- break;
362
- }
363
- else if ($content[$x] === "\"" || $content[$x] === "'")
364
- {
365
- $cx = $x;
366
-
367
- $attrs[$keyname] = true;
368
-
369
- $state = "name";
370
-
371
- break;
372
- }
373
- else
374
- {
375
- $val = ord($content[$x]);
376
- if (($val >= $a && $val <= $z) || ($val >= $a2 && $val <= $z2) || ($val >= $zero && $val <= $nine))
377
- {
378
- $cx = $x;
379
-
380
- $attrs[$keyname] = true;
381
-
382
- $state = "name";
383
-
384
- break;
385
- }
386
- }
387
- }
388
-
389
- if ($state === "equals")
390
- {
391
- $cx = $cy;
392
-
393
- $attrs[$keyname] = true;
394
-
395
- $state = "exit";
396
- }
397
- }
398
- else if ($state === "value")
399
- {
400
- for ($x = $cx; $x < $cy; $x++)
401
- {
402
- if ($content[$x] === ">" || $content[$x] === "<")
403
- {
404
- $cx = $x;
405
-
406
- $attrs[$keyname] = true;
407
-
408
- $state = "exit";
409
-
410
- break;
411
- }
412
- else if ($content[$x] === "\"" || $content[$x] === "'" || $content[$x] === "`")
413
- {
414
- $pos = strpos($content, $content[$x], $x + 1);
415
- if ($pos === false) $content .= $content[$x];
416
- else
417
- {
418
- $value = substr($content, $x + 1, $pos - $x - 1);
419
- $cx = $pos + 1;
420
-
421
- $state = "name";
422
- }
423
-
424
- break;
425
- }
426
- else if ($content[$x] !== "\0" && $content[$x] !== "\r" && $content[$x] !== "\n" && $content[$x] !== "\t" && $content[$x] !== " ")
427
- {
428
- $cx = $x;
429
-
430
- for (; $cx < $cy; $cx++)
431
- {
432
- if ($content[$cx] === "\0" || $content[$cx] === "\r" || $content[$cx] === "\n" || $content[$cx] === "\t" || $content[$cx] === " " || $content[$cx] === "<" || $content[$cx] === ">")
433
- {
434
- break;
435
- }
436
- }
437
-
438
- $value = substr($content, $x, $cx - $x);
439
-
440
- $state = "name";
441
-
442
- break;
443
- }
444
- }
445
-
446
- if ($state === "value")
447
- {
448
- $cx = $cy;
449
-
450
- $attrs[$keyname] = true;
451
-
452
- $state = "exit";
453
- }
454
-
455
- if ($state === "name")
456
- {
457
- if ($this->options["charset"] === "UTF-8" && !self::IsValidUTF8($value)) $value = self::MakeValidUTF8($value);
458
- $value = html_entity_decode($value, ENT_QUOTES | ENT_HTML5, $this->options["charset"]);
459
-
460
- // Decode remaining entities.
461
- $value2 = "";
462
- $vx = 0;
463
- $vy = strlen($value);
464
- while ($vx < $vy)
465
- {
466
- $pos = strpos($value, "&#", $vx);
467
- $pos2 = strpos($value, "\\", $vx);
468
- if ($pos === false) $pos = $vy;
469
- if ($pos2 === false) $pos2 = $vy;
470
- if ($pos < $pos2)
471
- {
472
- // &#32 or &#x20 (optional trailing semi-colon)
473
- $value2 .= substr($value, $vx, $pos - $vx);
474
- $vx = $pos + 2;
475
- if ($vx < $vy)
476
- {
477
- if ($value[$vx] == "x" || $value[$vx] == "X")
478
- {
479
- $vx++;
480
- if ($vx < $vy)
481
- {
482
- for ($x = $vx; $x < $vy; $x++)
483
- {
484
- $val = ord($value[$x]);
485
- if (!(($val >= $a && $val <= $f) || ($val >= $a2 && $val <= $f2) || ($val >= $zero && $val <= $nine))) break;
486
- }
487
-
488
- $num = hexdec(substr($value, $vx, $x - $vx));
489
- $vx = $x;
490
- if ($vx < $vy && $value[$vx] == ";") $vx++;
491
-
492
- $value2 .= self::UTF8Chr($num);
493
- }
494
- }
495
- else
496
- {
497
- for ($x = $vx; $x < $vy; $x++)
498
- {
499
- $val = ord($value[$x]);
500
- if (!($val >= $zero && $val <= $nine)) break;
501
- }
502
-
503
- $num = (int)substr($value, $vx, $x - $vx);
504
- $vx = $x;
505
- if ($vx < $vy && $value[$vx] == ";") $vx++;
506
-
507
- $value2 .= self::UTF8Chr($num);
508
- }
509
- }
510
- }
511
- else if ($pos2 < $pos)
512
- {
513
- // Unicode (e.g. \0020)
514
- $value2 .= substr($value, $vx, $pos2 - $vx);
515
- $vx = $pos2 + 1;
516
- if ($vx >= $vy) $value2 .= "\\";
517
- else
518
- {
519
- for ($x = $vx; $x < $vy; $x++)
520
- {
521
- $val = ord($value[$x]);
522
- if (!(($val >= $a && $val <= $f) || ($val >= $a2 && $val <= $f2) || ($val >= $zero && $val <= $nine))) break;
523
- }
524
-
525
- if ($x > $vx)
526
- {
527
- $num = hexdec(substr($value, $vx, $x - $vx));
528
- $vx = $x;
529
-
530
- $value2 .= self::UTF8Chr($num);
531
- }
532
- else
533
- {
534
- $value2 .= "\\";
535
- }
536
- }
537
- }
538
- else
539
- {
540
- $value2 .= substr($value, $vx);
541
- $vx = $vy;
542
- }
543
- }
544
- $value = $value2;
545
-
546
- if (!$this->options["keep_attr_newlines"]) $value = str_replace(array("\r\n", "\r", "\n"), " ", $value);
547
-
548
- if (isset($this->options["process_attrs"][$keyname]))
549
- {
550
- $type = $this->options["process_attrs"][$keyname];
551
- if ($type === "classes")
552
- {
553
- $classes = explode(" ", $value);
554
- $value = array();
555
- foreach ($classes as $class)
556
- {
557
- if ($class !== "") $value[$class] = $class;
558
- }
559
- }
560
- else if ($type === "uri")
561
- {
562
- $value = str_replace(array("\0", "\r", "\n", "\t", " "), "", $value);
563
- $pos = strpos($value, ":");
564
- if ($pos !== false) $value = preg_replace('/[^a-z]/', "", strtolower(substr($value, 0, $pos))) . substr($value, $pos);
565
- }
566
- }
567
-
568
- $attrs[$keyname] = $value;
569
- }
570
- }
571
- } while ($cx < $cy && $state !== "exit");
572
-
573
- // Break out of the loop if the end of the stream has been reached but not finalized and most likely in the middle of a tag.
574
- if ($cx >= $cy && !$this->final)
575
- {
576
- $cx = $firstcx;
577
-
578
- break;
579
- }
580
-
581
- unset($attrs[""]);
582
-
583
- if ($cx < $cy && $content[$cx] === ">") $cx++;
584
-
585
- if (isset($this->options["tag_name_map"][$prefix . $tagname])) $outtagname = $tagname = $this->options["tag_name_map"][$prefix . $tagname];
586
-
587
- if ($tagname != "")
588
- {
589
- if ($open)
590
- {
591
- if ($voidtag && isset($this->options["void_tags"][$tagname])) $voidtag = false;
592
- $this->options["tag_num"]++;
593
-
594
- // Let a callback handle any necessary changes.
595
- if (isset($this->options["tag_callback"]) && is_callable($this->options["tag_callback"])) $funcresult = call_user_func_array($this->options["tag_callback"], array($this->stack, &$result, $open, $prefix . $tagname, &$attrs, $this->options));
596
- else $funcresult = array();
597
-
598
- if (!isset($funcresult["keep_tag"])) $funcresult["keep_tag"] = true;
599
- if (!isset($funcresult["keep_interior"])) $funcresult["keep_interior"] = true;
600
- if (!isset($funcresult["pre_tag"])) $funcresult["pre_tag"] = "";
601
- if (!isset($funcresult["post_tag"])) $funcresult["post_tag"] = "";
602
- if (!isset($funcresult["state"])) $funcresult["state"] = false;
603
- }
604
-
605
- if ($open && $funcresult["keep_tag"])
606
- {
607
- $opentag = $funcresult["pre_tag"];
608
- $opentag .= "<" . $prefix . $outtagname;
609
- foreach ($attrs as $key => $val)
610
- {
611
- $opentag .= " " . $key;
612
-
613
- if (is_array($val)) $val = implode(" ", $val);
614
- if (is_string($val))
615
- {
616
- if ($this->options["charset"] === "UTF-8" && !self::IsValidUTF8($val)) $val = self::MakeValidUTF8($val);
617
- $opentag .= "=\"" . htmlspecialchars($val, ENT_COMPAT | ENT_HTML5, $this->options["charset"]) . "\"";
618
- }
619
- }
620
- if (($voidtag || isset($this->options["void_tags"][$tagname])) && $this->options["output_mode"] === "xml")
621
- {
622
- $opentag .= " /";
623
-
624
- $voidtag = false;
625
- }
626
- $opentag .= ">";
627
-
628
- if (!isset($this->options["void_tags"][$tagname]) && $prefix === "")
629
- {
630
- array_unshift($this->stack, array("tag_num" => $this->options["tag_num"], "tag_name" => $tagname, "out_tag_name" => $outtagname, "attrs" => $attrs, "result" => $result, "open_tag" => $opentag, "close_tag" => true, "keep_interior" => $funcresult["keep_interior"], "post_tag" => $funcresult["post_tag"], "state" => $funcresult["state"]));
631
- $result = "";
632
-
633
- if ($voidtag) $open = false;
634
- }
635
- else
636
- {
637
- $result .= $opentag;
638
- $result .= $funcresult["post_tag"];
639
- }
640
- }
641
-
642
- if ((!$open || !$funcresult["keep_tag"]) && !isset($this->options["void_tags"][$tagname]))
643
- {
644
- if ($open)
645
- {
646
- array_unshift($this->stack, array("tag_num" => $this->options["tag_num"], "tag_name" => $tagname, "out_tag_name" => $outtagname, "attrs" => $attrs, "result" => $result, "open_tag" => "", "close_tag" => false, "keep_interior" => $funcresult["keep_interior"], "post_tag" => $funcresult["post_tag"], "state" => $funcresult["state"]));
647
- $result = "";
648
- }
649
-
650
- if (!$open)
651
- {
652
- $found = false;
653
- foreach ($this->stack as $info)
654
- {
655
- if ($tagname === $info["tag_name"])
656
- {
657
- $found = true;
658
-
659
- break;
660
- }
661
- }
662
-
663
- if ($found)
664
- {
665
- do
666
- {
667
- // Let a callback handle any necessary changes.
668
- $attrs = array();
669
- if (isset($this->options["tag_callback"]) && is_callable($this->options["tag_callback"])) $funcresult = call_user_func_array($this->options["tag_callback"], array($this->stack, &$result, false, "/" . $this->stack[0]["tag_name"], &$attrs, $this->options));
670
- else $funcresult = array();
671
-
672
- // Force close tag to be kept if the stream already output the open tag.
673
- if (!isset($funcresult["keep_tag"]) || ($info["close_tag"] && $info["open_tag"] == "")) $funcresult["keep_tag"] = true;
674
-
675
- $info = array_shift($this->stack);
676
-
677
- $result = $info["result"] . ($funcresult["keep_tag"] ? $info["open_tag"] : "") . ($info["keep_interior"] ? $result : "");
678
- if ($info["close_tag"] && $funcresult["keep_tag"]) $result .= "</" . $info["out_tag_name"] . ">" . $info["post_tag"];
679
- } while ($tagname !== $info["tag_name"]);
680
- }
681
- }
682
- }
683
- }
684
-
685
- //echo "Current output:\n" . $result . "\n\n";
686
- //echo "Prefix: " . $prefix . "\n\n";
687
- //echo "Tag: " . $tagname . "\n\n";
688
- //echo "Attrs:\n";
689
- //var_dump($attrs);
690
- //
691
- //echo "Tag stack:\n";
692
- //var_dump($this->stack);
693
- //
694
- //echo "\n\n";
695
- //echo $content . "\n";
696
- //exit();
697
-
698
- $tag = false;
699
- }
700
- else
701
- {
702
- $regular = true;
703
-
704
- // Special content handler for certain tags.
705
- if (count($this->stack) && isset($this->options["alt_tag_content_rules"][$this->stack[0]["tag_name"]]) && is_callable($this->options["alt_tag_content_rules"][$this->stack[0]["tag_name"]]))
706
- {
707
- $content2 = "";
708
-
709
- // Expected to return true until the function is no longer interested in the data.
710
- if (call_user_func_array($this->options["alt_tag_content_rules"][$this->stack[0]["tag_name"]], array($this->stack, $this->final, &$tag, &$content, &$cx, $cy, &$content2, $this->options))) $regular = false;
711
- else if (!$this->final)
712
- {
713
- // Let a callback handle any necessary changes.
714
- if (isset($this->options["content_callback"]) && is_callable($this->options["content_callback"])) call_user_func_array($this->options["content_callback"], array($this->stack, $result, &$content2, $this->options));
715
-
716
- $result .= $content2;
717
-
718
- break;
719
- }
720
- }
721
-
722
- if ($regular)
723
- {
724
- // Regular content.
725
- $pos = strpos($content, "<", $cx);
726
- if ($pos === false)
727
- {
728
- $content2 = str_replace(">", "&gt;", substr($content, $cx));
729
- $cx = $cy;
730
- }
731
- else
732
- {
733
- $content2 = str_replace(">", "&gt;", substr($content, $cx, $pos - $cx));
734
- $cx = $pos;
735
-
736
- $tag = true;
737
- }
738
- }
739
-
740
- // Let a callback handle any necessary changes.
741
- if (isset($this->options["content_callback"]) && is_callable($this->options["content_callback"])) call_user_func_array($this->options["content_callback"], array($this->stack, $result, &$content2, $this->options));
742
-
743
- $result .= $content2;
744
- }
745
- }
746
-
747
- if ($this->final)
748
- {
749
- while (count($this->stack))
750
- {
751
- // Let a callback handle any necessary changes.
752
- $attrs = array();
753
- if (isset($this->options["tag_callback"]) && is_callable($this->options["tag_callback"])) $funcresult = call_user_func_array($this->options["tag_callback"], array($this->stack, &$result, false, "/" . $this->stack[0]["tag_name"], &$attrs, $this->options));
754
- else $funcresult = array();
755
-
756
- $info = array_shift($this->stack);
757
-
758
- // Force close tag to be kept if the stream already output the open tag.
759
- if (!isset($funcresult["keep_tag"]) || ($info["close_tag"] && $info["open_tag"] == "")) $funcresult["keep_tag"] = true;
760
-
761
- $result = $info["result"] . ($funcresult["keep_tag"] ? $info["open_tag"] : "") . ($info["keep_interior"] ? $result : "");
762
- if ($info["close_tag"] && $funcresult["keep_tag"]) $result .= "</" . $info["out_tag_name"] . ">" . $info["post_tag"];
763
- }
764
- }
765
- else
766
- {
767
- $this->lastcontent = ($cx < $cy ? substr($content, $cx) : "");
768
- $this->lastresult = $result;
769
- $result = "";
770
- }
771
-
772
- return $result;
773
- }
774
-
775
- public function Finalize()
776
- {
777
- $this->final = true;
778
- }
779
-
780
- // To cleanly figure out how far in to flush output, call GetStack(true), use TagFilter::GetParentPos(), and call GetResult().
781
- public function GetStack($invert = false)
782
- {
783
- return ($invert ? array_reverse($this->stack) : $this->stack);
784
- }
785
-
786
- // Returns the result so far up to the specified stack position and flushes the stored output to keep RAM usage low.
787
- // NOTE: Callback functions returning 'keep_tag' of false for the closing tag won't work for tags that were already output using this function.
788
- public function GetResult($invertedstackpos)
789
- {
790
- $y = count($this->stack);
791
- $pos = $y - $invertedstackpos - 1;
792
- if ($pos < 0) $pos = 0;
793
-
794
- $result = "";
795
- for ($x = $y - 1; $x >= $pos; $x--)
796
- {
797
- $result .= $this->stack[$x]["result"] . $this->stack[$x]["open_tag"];
798
-
799
- $this->stack[$x]["result"] = "";
800
- $this->stack[$x]["open_tag"] = "";
801
- }
802
-
803
- if (!$pos)
804
- {
805
- $result .= $this->lastresult;
806
- $this->lastresult = "";
807
- }
808
-
809
- return $result;
810
- }
811
-
812
- public static function MakeValidUTF8($data)
813
- {
814
- $result = "";
815
- $x = 0;
816
- $y = strlen($data);
817
- while ($x < $y)
818
- {
819
- $tempchr = ord($data[$x]);
820
- if ($y - $x > 1) $tempchr2 = ord($data[$x + 1]);
821
- else $tempchr2 = 0x00;
822
- if ($y - $x > 2) $tempchr3 = ord($data[$x + 2]);
823
- else $tempchr3 = 0x00;
824
- if ($y - $x > 3) $tempchr4 = ord($data[$x + 3]);
825
- else $tempchr4 = 0x00;
826
- if (($tempchr >= 0x20 && $tempchr <= 0x7E) || $tempchr == 0x09 || $tempchr == 0x0A || $tempchr == 0x0D)
827
- {
828
- // ASCII minus control and special characters.
829
- $result .= chr($tempchr);
830
- $x++;
831
- }
832
- else if (($tempchr >= 0xC2 && $tempchr <= 0xDF) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF))
833
- {
834
- // Non-overlong (2 bytes).
835
- $result .= chr($tempchr);
836
- $result .= chr($tempchr2);
837
- $x += 2;
838
- }
839
- else if ($tempchr == 0xE0 && ($tempchr2 >= 0xA0 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF))
840
- {
841
- // Non-overlong (3 bytes).
842
- $result .= chr($tempchr);
843
- $result .= chr($tempchr2);
844
- $result .= chr($tempchr3);
845
- $x += 3;
846
- }
847
- else if ((($tempchr >= 0xE1 && $tempchr <= 0xEC) || $tempchr == 0xEE || $tempchr == 0xEF) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF))
848
- {
849
- // Normal/straight (3 bytes).
850
- $result .= chr($tempchr);
851
- $result .= chr($tempchr2);
852
- $result .= chr($tempchr3);
853
- $x += 3;
854
- }
855
- else if ($tempchr == 0xED && ($tempchr2 >= 0x80 && $tempchr2 <= 0x9F) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF))
856
- {
857
- // Non-surrogates (3 bytes).
858
- $result .= chr($tempchr);
859
- $result .= chr($tempchr2);
860
- $result .= chr($tempchr3);
861
- $x += 3;
862
- }
863
- else if ($tempchr == 0xF0 && ($tempchr2 >= 0x90 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF) && ($tempchr4 >= 0x80 && $tempchr4 <= 0xBF))
864
- {
865
- // Planes 1-3 (4 bytes).
866
- $result .= chr($tempchr);
867
- $result .= chr($tempchr2);
868
- $result .= chr($tempchr3);
869
- $result .= chr($tempchr4);
870
- $x += 4;
871
- }
872
- else if (($tempchr >= 0xF1 && $tempchr <= 0xF3) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF) && ($tempchr4 >= 0x80 && $tempchr4 <= 0xBF))
873
- {
874
- // Planes 4-15 (4 bytes).
875
- $result .= chr($tempchr);
876
- $result .= chr($tempchr2);
877
- $result .= chr($tempchr3);
878
- $result .= chr($tempchr4);
879
- $x += 4;
880
- }
881
- else if ($tempchr == 0xF4 && ($tempchr2 >= 0x80 && $tempchr2 <= 0x8F) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF) && ($tempchr4 >= 0x80 && $tempchr4 <= 0xBF))
882
- {
883
- // Plane 16 (4 bytes).
884
- $result .= chr($tempchr);
885
- $result .= chr($tempchr2);
886
- $result .= chr($tempchr3);
887
- $result .= chr($tempchr4);
888
- $x += 4;
889
- }
890
- else $x++;
891
- }
892
-
893
- return $result;
894
- }
895
-
896
- public static function IsValidUTF8($data)
897
- {
898
- $x = 0;
899
- $y = strlen($data);
900
- while ($x < $y)
901
- {
902
- $tempchr = ord($data[$x]);
903
- if (($tempchr >= 0x20 && $tempchr <= 0x7E) || $tempchr == 0x09 || $tempchr == 0x0A || $tempchr == 0x0D) $x++;
904
- else if ($tempchr < 0xC2) return false;
905
- else
906
- {
907
- $left = $y - $x;
908
- if ($left > 1) $tempchr2 = ord($data[$x + 1]);
909
- else return false;
910
-
911
- if (($tempchr >= 0xC2 && $tempchr <= 0xDF) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF)) $x += 2;
912
- else
913
- {
914
- if ($left > 2) $tempchr3 = ord($data[$x + 2]);
915
- else return false;
916
-
917
- if ($tempchr3 < 0x80 || $tempchr3 > 0xBF) return false;
918
-
919
- if ($tempchr == 0xE0 && ($tempchr2 >= 0xA0 && $tempchr2 <= 0xBF)) $x += 3;
920
- else if ((($tempchr >= 0xE1 && $tempchr <= 0xEC) || $tempchr == 0xEE || $tempchr == 0xEF) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF)) $x += 3;
921
- else if ($tempchr == 0xED && ($tempchr2 >= 0x80 && $tempchr2 <= 0x9F)) $x += 3;
922
- else
923
- {
924
- if ($left > 3) $tempchr4 = ord($data[$x + 3]);
925
- else return false;
926
-
927
- if ($tempchr4 < 0x80 || $tempchr4 > 0xBF) return false;
928
-
929
- if ($tempchr == 0xF0 && ($tempchr2 >= 0x90 && $tempchr2 <= 0xBF)) $x += 4;
930
- else if (($tempchr >= 0xF1 && $tempchr <= 0xF3) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF)) $x += 4;
931
- else if ($tempchr == 0xF4 && ($tempchr2 >= 0x80 && $tempchr2 <= 0x8F)) $x += 4;
932
- else return false;
933
- }
934
- }
935
- }
936
- }
937
-
938
- return true;
939
- }
940
-
941
- public static function UTF8Chr($num)
942
- {
943
- if ($num < 0 || ($num >= 0xD800 && $num <= 0xDFFF) || ($num >= 0xFDD0 && $num <= 0xFDEF) || ($num & 0xFFFE) == 0xFFFE) return "";
944
-
945
- if ($num <= 0x7F) $result = chr($num);
946
- else if ($num <= 0x7FF) $result = chr(0xC0 | ($num >> 6)) . chr(0x80 | ($num & 0x3F));
947
- else if ($num <= 0xFFFF) $result = chr(0xE0 | ($num >> 12)) . chr(0x80 | (($num >> 6) & 0x3F)) . chr(0x80 | ($num & 0x3F));
948
- else if ($num <= 0x10FFFF) $result = chr(0xF0 | ($num >> 18)) . chr(0x80 | (($num >> 12) & 0x3F)) . chr(0x80 | (($num >> 6) & 0x3F)) . chr(0x80 | ($num & 0x3F));
949
- else $result = "";
950
-
951
- return $result;
952
- }
953
- }
954
-
955
- // Accessing the data in TagFilterNodes (with an 's') via objects is not the most performance-friendly method of access.
956
- // The classes TagFilterNode and TagFilterNodeIterator defer method calls to the referenced TagFilterNodes instance.
957
- // Removed/replaced nodes in the original data will result in undefined behavior with object reuse.
958
- class TagFilterNode
959
- {
960
- private $tfn, $id;
961
-
962
- public function __construct($tfn, $rootid)
963
- {
964
- $this->tfn = $tfn;
965
- $this->id = $rootid;
966
- }
967
-
968
- public function __get($key)
969
- {
970
- return (isset($this->tfn->nodes[$this->id]) && isset($this->tfn->nodes[$this->id]["attrs"]) && isset($this->tfn->nodes[$this->id]["attrs"][$key]) ? $this->tfn->nodes[$this->id]["attrs"][$key] : false);
971
- }
972
-
973
- public function __set($key, $val)
974
- {
975
- if (isset($this->tfn->nodes[$this->id]) && isset($this->tfn->nodes[$this->id]["attrs"]))
976
- {
977
- if (is_array($val)) $this->tfn->nodes[$this->id]["attrs"][$key] = $val;
978
- else if (isset($this->tfn->nodes[$this->id]["attrs"][$key]) && is_array($this->tfn->nodes[$this->id]["attrs"][$key])) $this->tfn->nodes[$this->id]["attrs"][$key][(string)$val] = (string)$val;
979
- else $this->tfn->nodes[$this->id]["attrs"][$key] = (string)$val;
980
- }
981
- }
982
-
983
- public function __isset($key)
984
- {
985
- return (isset($this->tfn->nodes[$this->id]) && isset($this->tfn->nodes[$this->id]["attrs"]) && isset($this->tfn->nodes[$this->id]["attrs"][$key]));
986
- }
987
-
988
- public function __unset($key)
989
- {
990
- if (isset($this->tfn->nodes[$this->id]) && isset($this->tfn->nodes[$this->id]["attrs"])) unset($this->tfn->nodes[$this->id]["attrs"][$key]);
991
- }
992
-
993
- public function __toString()
994
- {
995
- return $this->tfn->GetOuterHTML($this->id);
996
- }
997
-
998
- public function __debugInfo()
999
- {
1000
- $result = (isset($this->tfn->nodes[$this->id]) ? $this->tfn->nodes[$this->id] : array());
1001
- $result["id"] = $this->id;
1002
-
1003
- return $result;
1004
- }
1005
-
1006
- public function ID()
1007
- {
1008
- return $this->id;
1009
- }
1010
-
1011
- public function Node()
1012
- {
1013
- return (isset($this->tfn->nodes[$this->id]) ? $this->tfn->nodes[$this->id] : false);
1014
- }
1015
-
1016
- public function Type()
1017
- {
1018
- return (isset($this->tfn->nodes[$this->id]) ? $this->tfn->nodes[$this->id]["type"] : false);
1019
- }
1020
-
1021
- public function Tag()
1022
- {
1023
- return $this->tfn->GetTag($this->id);
1024
- }
1025
-
1026
- public function Text($val = null)
1027
- {
1028
- if ($val !== null) $this->tfn->SetText($this->id, $val);
1029
- else return $this->tfn->GetText($this->id);
1030
- }
1031
-
1032
- public function AddClass($name, $attr = "class")
1033
- {
1034
- if (isset($this->tfn->nodes[$this->id]) && isset($this->tfn->nodes[$this->id]["attrs"]))
1035
- {
1036
- if (!isset($this->tfn->nodes[$this->id]["attrs"][$attr]) || !is_array($this->tfn->nodes[$this->id]["attrs"][$attr])) $this->tfn->nodes[$this->id]["attrs"][$attr] = array();
1037
-
1038
- $this->tfn->nodes[$this->id]["attrs"][$attr][$name] = $name;
1039
- }
1040
- }
1041
-
1042
- public function RemoveClass($name, $attr = "class")
1043
- {
1044
- if (isset($this->tfn->nodes[$this->id]) && isset($this->tfn->nodes[$this->id]["attrs"]))
1045
- {
1046
- if (isset($this->tfn->nodes[$this->id]["attrs"][$attr]) && is_array($this->tfn->nodes[$this->id]["attrs"][$attr])) unset($this->tfn->nodes[$this->id]["attrs"][$attr][$name]);
1047
- }
1048
- }
1049
-
1050
- public function Parent()
1051
- {
1052
- return $this->tfn->GetParent($this->id);
1053
- }
1054
-
1055
- public function ParentPos()
1056
- {
1057
- return (isset($this->tfn->nodes[$this->id]) ? $this->tfn->nodes[$this->id]["parentpos"] : false);
1058
- }
1059
-
1060
- // Passing true to this method has the potential to leak RAM. Passing false is preferred, use with caution.
1061
- public function Children($objects = false)
1062
- {
1063
- return $this->tfn->GetChildren($this->id, $objects);
1064
- }
1065
-
1066
- public function Child($pos)
1067
- {
1068
- return $this->tfn->GetChild($this->id, $pos);
1069
- }
1070
-
1071
- public function PrevSibling()
1072
- {
1073
- return $this->tfn->GetPrevSibling($this->id);
1074
- }
1075
-
1076
- public function NextSibling()
1077
- {
1078
- return $this->tfn->GetNextSibling($this->id);
1079
- }
1080
-
1081
- public function Find($query, $cachequery = true, $firstmatch = false)
1082
- {
1083
- $result = $this->tfn->Find($query, $this->id, $cachequery, $firstmatch);
1084
- if (!$result["success"]) return $result;
1085
-
1086
- return new TagFilterNodeIterator($this->tfn, $result["ids"]);
1087
- }
1088
-
1089
- public function Implode($options = array())
1090
- {
1091
- return $this->tfn->Implode($this->id, $options);
1092
- }
1093
-
1094
- public function GetOuterHTML($mode = "html")
1095
- {
1096
- return $this->tfn->GetOuterHTML($this->id, $mode);
1097
- }
1098
-
1099
- // Set functions ruin the object.
1100
- public function SetOuterHTML($src)
1101
- {
1102
- return $this->tfn->SetOuterHTML($this->id, $src);
1103
- }
1104
-
1105
- public function GetInnerHTML($mode = "html")
1106
- {
1107
- return $this->tfn->GetInnerHTML($this->id, $mode);
1108
- }
1109
-
1110
- public function SetInnerHTML($src)
1111
- {
1112
- return $this->tfn->SetInnerHTML($this->id, $src);
1113
- }
1114
-
1115
- public function GetPlainText()
1116
- {
1117
- return $this->tfn->GetPlainText($this->id);
1118
- }
1119
-
1120
- // Set functions ruin the object.
1121
- public function SetPlainText($src)
1122
- {
1123
- return $this->tfn->SetPlainText($this->id, $src);
1124
- }
1125
- }
1126
-
1127
- class TagFilterNodeIterator implements Iterator, Countable
1128
- {
1129
- private $tfn, $ids, $x, $y;
1130
-
1131
- public function __construct($tfn, $ids)
1132
- {
1133
- $this->tfn = $tfn;
1134
- $this->ids = $ids;
1135
- $this->x = 0;
1136
- $this->y = count($ids);
1137
- }
1138
-
1139
- public function rewind()
1140
- {
1141
- $this->x = 0;
1142
- }
1143
-
1144
- public function valid()
1145
- {
1146
- return ($this->x < $this->y);
1147
- }
1148
-
1149
- public function current()
1150
- {
1151
- return $this->tfn->Get($this->ids[$this->x]);
1152
- }
1153
-
1154
- public function key()
1155
- {
1156
- return $this->ids[$this->x];
1157
- }
1158
-
1159
- public function next()
1160
- {
1161
- $this->x++;
1162
- }
1163
-
1164
- public function count()
1165
- {
1166
- return $this->y;
1167
- }
1168
-
1169
- public function Filter($query, $cachequery = true)
1170
- {
1171
- $result = $this->tfn->Filter($this->ids, $query, $cachequery);
1172
- if (!$result["success"]) return $result;
1173
-
1174
- return new TagFilterNodeIterator($this->tfn, $result["ids"]);
1175
- }
1176
- }
1177
-
1178
- // Output from TagFilter::Explode().
1179
- class TagFilterNodes
1180
- {
1181
- public $nodes, $nextid;
1182
- private $queries;
1183
-
1184
- public function __construct()
1185
- {
1186
- $this->nodes = array(
1187
- array(
1188
- "type" => "root",
1189
- "parent" => false,
1190
- "parentpos" => false,
1191
- "children" => array()
1192
- )
1193
- );
1194
-
1195
- $this->nextid = 1;
1196
- $this->queries = array();
1197
- }
1198
-
1199
- // Makes a selector suitable for Find() and Filter() by altering or removing rules. Query is not cached.
1200
- public static function MakeValidSelector($query)
1201
- {
1202
- if (!is_array($query)) $result = TagFilter::ParseSelector($query, true);
1203
- else if (isset($query["success"]) && isset($query["tokens"]))
1204
- {
1205
- $result = $query;
1206
- $result["tokens"] = TagFilter::ReorderSelectorTokens(array_reverse($result["tokens"]), true);
1207
- }
1208
- else
1209
- {
1210
- $result = array("success" => true, "tokens" => TagFilter::ReorderSelectorTokens(array_reverse($query), true));
1211
- }
1212
-
1213
- // Alter certain CSS3 tokens to equivalent tokens.
1214
- foreach ($result["tokens"] as $num => $rules)
1215
- {
1216
- foreach ($rules as $num2 => $rule)
1217
- {
1218
- if ($rule["type"] === "pseudo-class")
1219
- {
1220
- if ($rule["pseudo"] === "link") $result["tokens"][$num][$num2] = array("not" => false, "type" => "element", "namespace" => false, "tag" => "a");
1221
- else if ($rule["pseudo"] === "disabled") $result["tokens"][$num][$num2] = array("not" => false, "type" => "attr", "namespace" => false, "attr" => "disabled", "cmp" => false);
1222
- else if ($rule["pseudo"] === "enabled") $result["tokens"][$num][$num2] = array("not" => false, "type" => "attr", "namespace" => false, "attr" => "enabled", "cmp" => false);
1223
- else if ($rule["pseudo"] === "checked") $result["tokens"][$num][$num2] = array("not" => false, "type" => "attr", "namespace" => false, "attr" => "checked", "cmp" => false);
1224
- }
1225
- }
1226
- }
1227
-
1228
- // Reorder the tokens so that the order is simple for output.
1229
- $tokens = TagFilter::ReorderSelectorTokens(array_reverse($result["tokens"]), true, array("element" => array(), "id" => array(), "class" => array(), "attr" => array(), "pseudo-class" => array(), "pseudo-element" => array()), false);
1230
-
1231
- // Generate a duplicate-free Find()-safe string.
1232
- $result = array();
1233
- foreach ($tokens as $rules)
1234
- {
1235
- $groups = array();
1236
- $strs = array();
1237
- $rules = array_reverse($rules);
1238
- $y = count($rules);
1239
- for ($x = 0; $x < $y; $x++)
1240
- {
1241
- $str = "";
1242
-
1243
- if (isset($rules[$x]["not"]) && $rules[$x]["not"]) $str .= ":not(";
1244
-
1245
- switch ($rules[$x]["type"])
1246
- {
1247
- case "id": $str .= "#" . $rules[$x]["id"]; $valid = true; break;
1248
- case "element": $str .= ($rules[$x]["namespace"] !== false ? $rules[$x]["namespace"] . "|" : "") . strtolower($rules[$x]["tag"]); $valid = true; break;
1249
- case "class": $str .= "." . $rules[$x]["class"]; $valid = true; break;
1250
- case "attr": $str .= "[" . ($rules[$x]["namespace"] !== false ? $rules[$x]["namespace"] . "|" : "") . strtolower($rules[$x]["attr"]) . ($rules[$x]["cmp"] !== false ? $rules[$x]["cmp"] . "\"" . str_replace("\"", "\\\"", $rules[$x]["val"]) . "\"" : "") . "]"; $valid = true; break;
1251
- case "pseudo-class":
1252
- {
1253
- $pc = $rules[$x]["pseudo"];
1254
- $valid = ($pc === "first-child" || $pc === "last-child" || $pc === "only-child" || $pc === "nth-child" || $pc === "nth-last-child" || $pc === "first-child-all" || $pc === "last-child-all" || $pc === "only-child-all" || $pc === "nth-child-all" || $pc === "nth-last-child-all" || $pc === "first-of-type" || $pc === "last-of-type" || $pc === "only-of-type" || $pc === "nth-of-type" || $pc === "nth-last-of-type" || $pc === "empty");
1255
-
1256
- if ($valid && substr($rules[$x]["pseudo"], 0, 4) === "nth-" && (!isset($rules[$x]["a"]) || !isset($rules[$x]["b"]))) $valid = false;
1257
-
1258
- break;
1259
- }
1260
- case "combine":
1261
- {
1262
- switch ($rules[$x]["combine"])
1263
- {
1264
- case "prev-parent": $groups[] = implode("", $strs); $groups[] = ">"; $strs = array(); $valid = true; break;
1265
- case "any-parent": $groups[] = implode("", $strs); $strs = array(); $valid = true; break;
1266
- case "prev-sibling": $groups[] = implode("", $strs); $groups[] = "+"; $strs = array(); $valid = true; break;
1267
- case "any-prev-sibling": $groups[] = implode("", $strs); $groups[] = "~"; $strs = array(); $valid = true; break;
1268
- default: $valid = false;
1269
- }
1270
-
1271
- break;
1272
- }
1273
- default: $valid = false; break;
1274
- }
1275
-
1276
- if (!$valid) break;
1277
-
1278
- if (isset($rules[$x]["not"]) && $rules[$x]["not"]) $str .= ")";
1279
-
1280
- $strs[$str] = $str;
1281
- }
1282
-
1283
- if ($x == $y)
1284
- {
1285
- if (count($strs)) $groups[] = implode("", $strs);
1286
- $str = implode(" ", $groups);
1287
- $result[$str] = $str;
1288
- }
1289
- }
1290
-
1291
- return implode(", ", $result);
1292
- }
1293
-
1294
- public function Find($query, $id = 0, $cachequery = true, $firstmatch = false)
1295
- {
1296
- $id = (int)$id;
1297
- if (!isset($this->nodes[$id])) return array("success" => false, "error" => "Invalid initial ID.", "errorcode" => "invalid_init_id");
1298
-
1299
- if (isset($this->queries[$query])) $result = $this->queries[$query];
1300
- else
1301
- {
1302
- if (!is_array($query)) $result = TagFilter::ParseSelector($query, true);
1303
- else if (isset($query["success"]) && isset($result["selector"]) && isset($query["tokens"]))
1304
- {
1305
- $result = $query;
1306
- $result["tokens"] = TagFilter::ReorderSelectorTokens($result["tokens"], true);
1307
-
1308
- $query = $result["selector"];
1309
- }
1310
- else
1311
- {
1312
- $result = array("success" => true, "tokens" => TagFilter::ReorderSelectorTokens($query, true));
1313
-
1314
- $cachequery = false;
1315
- }
1316
-
1317
- if ($cachequery)
1318
- {
1319
- foreach ($this->queries as $key => $val)
1320
- {
1321
- if (count($this->queries) < 25) break;
1322
-
1323
- unset($this->queries[$key]);
1324
- }
1325
-
1326
- $this->queries[$query] = $result;
1327
- }
1328
- }
1329
-
1330
- if (!$result["success"]) return $result;
1331
-
1332
- $rules = $result["tokens"];
1333
- $numrules = count($rules);
1334
-
1335
- $result = array();
1336
- $childcache = array();
1337
- $oftypecache = array();
1338
- $rootid = $id;
1339
- $pos = 0;
1340
- $maxpos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
1341
- do
1342
- {
1343
- if (!$pos && $this->nodes[$id]["type"] === "element")
1344
- {
1345
- // Attempt to match a rule.
1346
- for ($x = 0; $x < $numrules; $x++)
1347
- {
1348
- $id2 = $id;
1349
- $y = count($rules[$x]);
1350
- for ($x2 = 0; $x2 < $y; $x2++)
1351
- {
1352
- if ($this->nodes[$id2]["type"] === "content" || $this->nodes[$id2]["type"] === "comment")
1353
- {
1354
- // Always backtrack at non-element nodes since the rules are element based.
1355
- $backtrack = !(isset($rules[$x][$x2]["not"]) && $rules[$x][$x2]["not"]);
1356
- }
1357
- else if (isset($rules[$x][$x2]["namespace"]) && $rules[$x][$x2]["namespace"] !== false && $rules[$x][$x2]["namespace"] !== "*" && (($rules[$x][$x2]["namespace"] === "" && strpos($this->nodes[$id2]["tag"], ":") !== false) || ($rules[$x][$x2]["namespace"] !== "" && strcasecmp(substr($this->nodes[$id2]["tag"], 0, strlen($rules[$x][$x2]["namespace"]) + 1), $rules[$x][$x2]["namespace"] . ":") !== 0)))
1358
- {
1359
- $backtrack = true;
1360
- }
1361
- else
1362
- {
1363
- switch ($rules[$x][$x2]["type"])
1364
- {
1365
- case "id": $backtrack = (!isset($this->nodes[$id2]["attrs"]["id"]) || $this->nodes[$id2]["attrs"]["id"] !== $rules[$x][$x2]["id"]); break;
1366
- case "element": $backtrack = (strcasecmp($this->nodes[$id2]["tag"], (isset($rules[$x][$x2]["namespace"]) && $rules[$x][$x2]["namespace"] !== false ? $rules[$x][$x2]["namespace"] . ":" : "") . $rules[$x][$x2]["tag"]) !== 0); break;
1367
- case "class": $backtrack = (!isset($this->nodes[$id2]["attrs"]["class"]) || !isset($this->nodes[$id2]["attrs"]["class"][$rules[$x][$x2]["class"]])); break;
1368
- case "attr":
1369
- {
1370
- $attr = strtolower($rules[$x][$x2]["attr"]);
1371
- if (!isset($this->nodes[$id2]["attrs"][$attr])) $backtrack = true;
1372
- else
1373
- {
1374
- $val = $this->nodes[$id2]["attrs"][$attr];
1375
- if (is_array($val)) $val = implode(" ", $val);
1376
-
1377
- switch ($rules[$x][$x2]["cmp"])
1378
- {
1379
- case "=": $backtrack = ($val !== $rules[$x][$x2]["val"]); break;
1380
- case "^=": $backtrack = ($rules[$x][$x2]["val"] === "" || substr($val, 0, strlen($rules[$x][$x2]["val"])) !== $rules[$x][$x2]["val"]); break;
1381
- case "$=": $backtrack = ($rules[$x][$x2]["val"] === "" || substr($val, -strlen($rules[$x][$x2]["val"])) !== $rules[$x][$x2]["val"]); break;
1382
- case "*=": $backtrack = ($rules[$x][$x2]["val"] === "" || strpos($val, $rules[$x][$x2]["val"]) === false); break;
1383
- case "~=": $backtrack = ($rules[$x][$x2]["val"] === "" || strpos($rules[$x][$x2]["val"], " ") !== false || strpos(" " . $val . " ", " " . $rules[$x][$x2]["val"] . " ") === false); break;
1384
- case "|=": $backtrack = ($rules[$x][$x2]["val"] === "" || ($val !== $rules[$x][$x2]["val"] && substr($val, 0, strlen($rules[$x][$x2]["val"]) + 1) !== $rules[$x][$x2]["val"] . "-")); break;
1385
- default: $backtrack = false; break;
1386
- }
1387
- }
1388
-
1389
- break;
1390
- }
1391
- case "pseudo-class":
1392
- {
1393
- // Handle various bits of common code.
1394
- $pid = $this->nodes[$id2]["parent"];
1395
- $pnum = count($this->nodes[$pid]["children"]);
1396
-
1397
- $nth = (substr($rules[$x][$x2]["pseudo"], 0, 4) === "nth-");
1398
- if ($nth && (!isset($rules[$x][$x2]["a"]) || !isset($rules[$x][$x2]["b"]))) return array("success" => false, "error" => "Pseudo-class ':" . $rules[$x][$x2]["pseudo"] . "(n)' requires an expression for 'n'.", "errorcode" => "missing_pseudo_class_expression");
1399
-
1400
- if (substr($rules[$x][$x2]["pseudo"], -6) === "-child")
1401
- {
1402
- if (!isset($childcache[$id2]))
1403
- {
1404
- $children = 0;
1405
- foreach ($this->nodes[$pid]["children"] as $id3)
1406
- {
1407
- if ($this->nodes[$id3]["type"] === "element")
1408
- {
1409
- $childcache[$id3] = array("cx" => $children);
1410
-
1411
- $children++;
1412
- }
1413
- }
1414
-
1415
- foreach ($this->nodes[$pid]["children"] as $id3)
1416
- {
1417
- if ($this->nodes[$id3]["type"] === "element") $childcache[$id3]["cy"] = $children;
1418
- }
1419
- }
1420
-
1421
- $cx = $childcache[$id2]["cx"];
1422
- $cy = $childcache[$id2]["cy"];
1423
- }
1424
-
1425
- if (substr($rules[$x][$x2]["pseudo"], -8) === "-of-type")
1426
- {
1427
- if (!isset($oftypecache[$id2]))
1428
- {
1429
- $types = array();
1430
- foreach ($this->nodes[$pid]["children"] as $id3)
1431
- {
1432
- if ($this->nodes[$id3]["type"] === "element")
1433
- {
1434
- $tag = $this->nodes[$id3]["tag"];
1435
- if (!isset($types[$tag])) $types[$tag] = 0;
1436
-
1437
- $oftypecache[$id3] = array("tx" => $types[$tag]);
1438
-
1439
- $types[$tag]++;
1440
- }
1441
- }
1442
-
1443
- foreach ($this->nodes[$pid]["children"] as $id3)
1444
- {
1445
- if ($this->nodes[$id3]["type"] === "element")
1446
- {
1447
- $tag = $this->nodes[$id3]["tag"];
1448
- $oftypecache[$id3]["ty"] = $types[$tag];
1449
- }
1450
- }
1451
- }
1452
-
1453
- $tx = $oftypecache[$id2]["tx"];
1454
- $ty = $oftypecache[$id2]["ty"];
1455
- }
1456
-
1457
- switch ($rules[$x][$x2]["pseudo"])
1458
- {
1459
- case "first-child": $backtrack = ($cx !== 0); break;
1460
- case "last-child": $backtrack = ($cx !== $cy - 1); break;
1461
- case "only-child": $backtrack = ($cy !== 1); break;
1462
- case "nth-child": $px = $cx; break;
1463
- case "nth-last-child": $px = $cy - $cx - 1; break;
1464
- case "first-child-all": $backtrack = ($this->nodes[$id2]["parentpos"] !== 0); break;
1465
- case "last-child-all": $backtrack = ($this->nodes[$id2]["parentpos"] !== $pnum - 1); break;
1466
- case "only-child-all": $backtrack = ($pnum !== 1); break;
1467
- case "nth-child-all": $px = $this->nodes[$id2]["parentpos"]; break;
1468
- case "nth-last-child-all": $px = $pnum - $this->nodes[$id2]["parentpos"] - 1; break;
1469
- case "first-of-type": $backtrack = ($tx !== 0); break;
1470
- case "last-of-type": $backtrack = ($tx !== $ty - 1); break;
1471
- case "only-of-type": $backtrack = ($ty !== 1); break;
1472
- case "nth-of-type": $px = $tx; break;
1473
- case "nth-last-of-type": $px = $ty - $tx - 1; break;
1474
- case "empty":
1475
- {
1476
- $backtrack = false;
1477
- foreach ($this->nodes[$id2]["children"] as $id3)
1478
- {
1479
- if ($this->nodes[$id3]["type"] === "element" || ($this->nodes[$id3]["type"] === "content" && trim($this->nodes[$id3]["text"]) !== ""))
1480
- {
1481
- $backtrack = true;
1482
-
1483
- break;
1484
- }
1485
- }
1486
-
1487
- break;
1488
- }
1489
- default: return array("success" => false, "error" => "Unknown/Unsupported pseudo-class ':" . $rules[$x][$x2]["pseudo"] . "'.", "errorcode" => "unknown_unsupported_pseudo_class");
1490
- }
1491
-
1492
- if ($nth)
1493
- {
1494
- // Calculated expression: a * n + b - 1 = x
1495
- // Solved for n: n = (x + 1 - b) / a
1496
- // Where 'n' is a non-negative integer. When 'a' is 0, solve for 'b' instead.
1497
- $pa = $rules[$x][$x2]["a"];
1498
- $pb = $rules[$x][$x2]["b"];
1499
-
1500
- if ($pa == 0) $backtrack = ($pb != $px + 1);
1501
- else
1502
- {
1503
- $pn = (($px + 1 - $pb) / $pa);
1504
-
1505
- $backtrack = ($pn < 0 || $pn - (int)$pn > 0.000001);
1506
- }
1507
- }
1508
-
1509
- break;
1510
- }
1511
- case "pseudo-element": return array("success" => false, "error" => "Pseudo-elements are not supported. Found '::" . $rules[$x][$x2]["pseudo"] . "'.", "errorcode" => "unsupported_selector_type");
1512
- case "combine":
1513
- {
1514
- switch ($rules[$x][$x2]["combine"])
1515
- {
1516
- case "prev-parent":
1517
- case "any-parent":
1518
- {
1519
- $backtrack = ($id2 === $rootid || !$this->nodes[$id2]["parent"]);
1520
- if (!$backtrack) $id2 = $this->nodes[$id2]["parent"];
1521
-
1522
- break;
1523
- }
1524
- case "prev-sibling":
1525
- case "any-prev-sibling":
1526
- {
1527
- $backtrack = ($this->nodes[$id2]["parentpos"] == 0);
1528
- if (!$backtrack) $id2 = $this->nodes[$this->nodes[$id2]["parent"]]["children"][$this->nodes[$id2]["parentpos"] - 1];
1529
-
1530
- break;
1531
- }
1532
- default: return array("success" => false, "error" => "Unknown combiner " . $rules[$x][$x2]["pseudo"] . ".", "errorcode" => "unknown_combiner");
1533
- }
1534
-
1535
- // For unknown parent/sibling combiners such as '~', use the rule stack to allow for backtracking to try another path if a match fails (e.g. h1 p ~ p).
1536
- $rules[$x][$x2]["lastid"] = $id2;
1537
-
1538
- break;
1539
- }
1540
- default: return array("success" => false, "error" => "Unknown selector type '" . $rules[$x][$x2]["type"] . "'.", "errorcode" => "unknown_selector_type");
1541
- }
1542
- }
1543
-
1544
- if (isset($rules[$x][$x2]["not"]) && $rules[$x][$x2]["not"]) $backtrack = !$backtrack;
1545
-
1546
- // Backtrack through the rule to an unknown parent/sibling combiner.
1547
- if ($backtrack)
1548
- {
1549
- if ($x2)
1550
- {
1551
- for ($x2--; $x2; $x2--)
1552
- {
1553
- if ($rules[$x][$x2]["type"] === "combine")
1554
- {
1555
- if ($rules[$x][$x2]["combine"] === "any-parent")
1556
- {
1557
- $id2 = $rules[$x][$x2]["lastid"];
1558
- if ($id2 !== $rootid && $this->nodes[$id2]["parent"])
1559
- {
1560
- $id2 = $this->nodes[$id2]["parent"];
1561
- $rules[$x][$x2]["lastid"] = $id2;
1562
-
1563
- break;
1564
- }
1565
- }
1566
- else if ($rules[$x][$x2]["combine"] === "any-prev-sibling")
1567
- {
1568
- $id2 = $rules[$x][$x2]["lastid"];
1569
- if ($this->nodes[$id2]["parentpos"] != 0)
1570
- {
1571
- $id2 = $this->nodes[$this->nodes[$id2]["parent"]]["children"][$this->nodes[$id2]["parentpos"] - 1];
1572
- $rules[$x][$x2]["lastid"] = $id2;
1573
-
1574
- break;
1575
- }
1576
- }
1577
- }
1578
- }
1579
- }
1580
-
1581
- if (!$x2) break;
1582
- }
1583
- }
1584
-
1585
- // Match found.
1586
- if ($x2 === $y)
1587
- {
1588
- $result[] = $id;
1589
-
1590
- if ($firstmatch) return array("success" => true, "ids" => $result);
1591
-
1592
- break;
1593
- }
1594
- }
1595
- }
1596
-
1597
- if ($pos >= $maxpos)
1598
- {
1599
- if ($rootid === $id) break;
1600
-
1601
- $pos = $this->nodes[$id]["parentpos"] + 1;
1602
- $id = $this->nodes[$id]["parent"];
1603
- $maxpos = count($this->nodes[$id]["children"]);
1604
- }
1605
- else
1606
- {
1607
- $id = $this->nodes[$id]["children"][$pos];
1608
- $pos = 0;
1609
- $maxpos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
1610
- }
1611
- } while (1);
1612
-
1613
- return array("success" => true, "ids" => $result);
1614
- }
1615
-
1616
- // Filter results from Find() based on a matching query.
1617
- public function Filter($ids, $query, $cachequery = true)
1618
- {
1619
- if (!is_array($ids)) $ids = array($ids);
1620
-
1621
- // Handle lazy chaining from both Find() and Filter().
1622
- if (isset($ids["success"]))
1623
- {
1624
- if (!$ids["success"]) return $ids;
1625
- if (!isset($ids["ids"])) return array("success" => false, "error" => "Bad filter input.", "invalid_filter_ids");
1626
-
1627
- $ids = $ids["ids"];
1628
- }
1629
-
1630
- $ids2 = array();
1631
- if (is_string($query) && strtolower(substr($query, 0, 10)) === "/contains:")
1632
- {
1633
- $query = substr($query, 10);
1634
- foreach ($ids as $id)
1635
- {
1636
- if (strpos($this->GetPlainText($id), $query) !== false) $ids2[] = $id;
1637
- }
1638
- }
1639
- else if (is_string($query) && strtolower(substr($query, 0, 11)) === "/~contains:")
1640
- {
1641
- $query = substr($query, 11);
1642
- foreach ($ids as $id)
1643
- {
1644
- if (stripos($this->GetPlainText($id), $query) !== false) $ids2[] = $id;
1645
- }
1646
- }
1647
- else
1648
- {
1649
- foreach ($ids as $id)
1650
- {
1651
- $result = $this->Find($query, $id, $cachequery, true);
1652
- if ($result["success"] && count($result["ids"])) $ids2[] = $id;
1653
- }
1654
- }
1655
-
1656
- return array("success" => true, "ids" => $ids2);
1657
- }
1658
-
1659
- // Convert all or some of the nodes back into a string.
1660
- public function Implode($id, $options = array())
1661
- {
1662
- $id = (int)$id;
1663
- if (!isset($this->nodes[$id])) return "";
1664
-
1665
- if (!isset($options["include_id"])) $options["include_id"] = true;
1666
- if (!isset($options["types"])) $options["types"] = "element,content,comment";
1667
- if (!isset($options["output_mode"])) $options["output_mode"] = "html";
1668
- if (!isset($options["post_elements"])) $options["post_elements"] = array();
1669
- if (!isset($options["no_content_elements"])) $options["no_content_elements"] = array("script" => true, "style" => true);
1670
- if (!isset($options["charset"])) $options["charset"] = "UTF-8";
1671
- $options["charset"] = strtoupper($options["charset"]);
1672
-
1673
- $types2 = explode(",", $options["types"]);
1674
- $types = array();
1675
- foreach ($types2 as $type)
1676
- {
1677
- $type = trim($type);
1678
- if ($type !== "") $types[$type] = true;
1679
- }
1680
-
1681
- $result = "";
1682
- $include = (bool)$options["include_id"];
1683
- $rootid = $id;
1684
- $pos = 0;
1685
- $maxpos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
1686
- do
1687
- {
1688
- if (!$pos && isset($types[$this->nodes[$id]["type"]]))
1689
- {
1690
- switch ($this->nodes[$id]["type"])
1691
- {
1692
- case "element":
1693
- {
1694
- if ($include || $rootid != $id)
1695
- {
1696
- $result .= "<" . $this->nodes[$id]["tag"];
1697
- foreach ($this->nodes[$id]["attrs"] as $key => $val)
1698
- {
1699
- $result .= " " . $key;
1700
-
1701
- if (is_array($val)) $val = implode(" ", $val);
1702
- if (is_string($val)) $result .= "=\"" . htmlspecialchars($val, ENT_COMPAT | ENT_HTML5, $options["charset"]) . "\"";
1703
- }
1704
- $result .= (!$maxpos && $options["output_mode"] === "xml" ? " />" : ">");
1705
- }
1706
-
1707
- break;
1708
- }
1709
- case "content":
1710
- case "comment":
1711
- {
1712
- if (isset($types["element"]) || !isset($this->nodes[$this->nodes[$id]["parent"]]["tag"]) || !isset($options["no_content_elements"][$this->nodes[$this->nodes[$id]["parent"]]["tag"]])) $result .= $this->nodes[$id]["text"];
1713
-
1714
- break;
1715
- }
1716
- default: break;
1717
- }
1718
- }
1719
-
1720
- if ($pos >= $maxpos)
1721
- {
1722
- if ($this->nodes[$id]["type"] === "element" && is_array($this->nodes[$id]["children"]))
1723
- {
1724
- if (($include || $rootid != $id) && isset($types[$this->nodes[$id]["type"]])) $result .= "</" . $this->nodes[$id]["tag"] . ">";
1725
- }
1726
-
1727
- if ($this->nodes[$id]["type"] === "element" && isset($options["post_elements"][$this->nodes[$id]["tag"]])) $result .= $options["post_elements"][$this->nodes[$id]["tag"]];
1728
-
1729
- if ($rootid === $id) break;
1730
-
1731
- $pos = $this->nodes[$id]["parentpos"] + 1;
1732
- $id = $this->nodes[$id]["parent"];
1733
- $maxpos = count($this->nodes[$id]["children"]);
1734
- }
1735
- else
1736
- {
1737
- $id = $this->nodes[$id]["children"][$pos];
1738
- $pos = 0;
1739
- $maxpos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
1740
- }
1741
- } while (1);
1742
-
1743
- return $result;
1744
- }
1745
-
1746
- // Object-oriented access methods. Only Get() supports multiple IDs.
1747
- public function Get($id = 0)
1748
- {
1749
- if (is_array($id))
1750
- {
1751
- if (isset($id["success"]) && $id["ids"]) $id = $id["ids"];
1752
-
1753
- $result = array();
1754
- foreach ($id as $id2) $result[] = $this->Get($id2);
1755
-
1756
- return $result;
1757
- }
1758
-
1759
- return ($id !== false && isset($this->nodes[$id]) ? new TagFilterNode($this, $id) : false);
1760
- }
1761
-
1762
- public function GetParent($id)
1763
- {
1764
- return ($id !== false && isset($this->nodes[$id]) && isset($this->nodes[$this->nodes[$id]["parent"]]) ? new TagFilterNode($this, $this->nodes[$id]["parent"]) : false);
1765
- }
1766
-
1767
- public function GetChildren($id, $objects = false)
1768
- {
1769
- if (!isset($this->nodes[$id]) || !isset($this->nodes[$id]["children"]) || !is_array($this->nodes[$id]["children"])) return false;
1770
-
1771
- return ($objects ? $this->Get($this->nodes[$id]["children"]) : $this->nodes[$id]["children"]);
1772
- }
1773
-
1774
- public function GetChild($id, $pos)
1775
- {
1776
- if (!isset($this->nodes[$id]) || !isset($this->nodes[$id]["children"]) || !is_array($this->nodes[$id]["children"])) return false;
1777
-
1778
- $pos = (int)$pos;
1779
- $y = count($this->nodes[$id]["children"]);
1780
- if ($pos < 0) $pos = $y + $pos;
1781
- if ($pos < 0 || $pos > $y - 1) return false;
1782
-
1783
- return $this->Get($this->nodes[$id]["children"][$pos]);
1784
- }
1785
-
1786
- public function GetPrevSibling($id)
1787
- {
1788
- if (!isset($this->nodes[$id]) || $this->nodes[$id]["parentpos"] == 0) return false;
1789
-
1790
- return $this->Get($this->nodes[$this->nodes[$id]["parent"]]["children"][$this->nodes[$id]["parentpos"] - 1]);
1791
- }
1792
-
1793
- public function GetNextSibling($id)
1794
- {
1795
- if ($id === false || !isset($this->nodes[$id]) || $this->nodes[$id]["parentpos"] >= count($this->nodes[$this->nodes[$id]["parent"]]["children"]) - 1) return false;
1796
-
1797
- return $this->Get($this->nodes[$this->nodes[$id]["parent"]]["children"][$this->nodes[$id]["parentpos"] + 1]);
1798
- }
1799
-
1800
- public function GetTag($id)
1801
- {
1802
- return (isset($this->nodes[$id]) && $this->nodes[$id]["type"] === "element" ? $this->nodes[$id]["tag"] : false);
1803
- }
1804
-
1805
- public function SetText($id, $val)
1806
- {
1807
- if (isset($this->nodes[$id]) && ($this->nodes[$id]["type"] === "content" || $this->nodes[$id]["type"] === "comment")) $this->nodes[$id]["text"] = (string)$val;
1808
- }
1809
-
1810
- public function GetText($id)
1811
- {
1812
- return (isset($this->nodes[$id]) && ($this->nodes[$id]["type"] === "content" || $this->nodes[$id]["type"] === "comment") ? $this->nodes[$id]["text"] : false);
1813
- }
1814
-
1815
- public function Move($src, $newpid, $newpos)
1816
- {
1817
- $newpid = (int)$newpid;
1818
- if (!isset($this->nodes[$newpid]) || !isset($this->nodes[$newpid]["children"]) || !is_array($this->nodes[$newpid]["children"])) return false;
1819
-
1820
- $newpos = (is_bool($newpos) ? count($this->nodes[$newpid]["children"]) : (int)$newpos);
1821
- if ($newpos < 0) $newpos = count($this->nodes[$newpid]["children"]) + $newpos;
1822
- if ($newpos < 0) $newpos = 0;
1823
- if ($newpos > count($this->nodes[$newpid]["children"])) $newpos = count($this->nodes[$newpid]["children"]);
1824
-
1825
- if ($src instanceof TagFilterNodes)
1826
- {
1827
- if ($src === $this) return false;
1828
-
1829
- // Bulk node import. Doesn't remove source nodes.
1830
- foreach ($src->nodes as $id => $node)
1831
- {
1832
- if ($node["type"] === "element" || $node["type"] === "content" || $node["type"] === "comment")
1833
- {
1834
- $node["parent"] += $this->nextid - 1;
1835
-
1836
- if (isset($node["children"]) && is_array($node["children"]))
1837
- {
1838
- foreach ($node["children"] as $pos => $id2) $node["children"][$pos] += $this->nextid - 1;
1839
- }
1840
-
1841
- $this->nodes[$id + $this->nextid - 1] = $node;
1842
- }
1843
- }
1844
-
1845
- // Merge root children.
1846
- foreach ($src->nodes[0]["children"] as $pos => $id)
1847
- {
1848
- $this->nodes[$id + $this->nextid - 1]["parent"] = $newpid;
1849
- array_splice($this->nodes[$newpid]["children"], $newpos + $pos, 0, array($id + $this->nextid - 1));
1850
- }
1851
-
1852
- $this->RealignChildren($newpid, $newpos);
1853
-
1854
- $this->nextid += $src->nextid - 1;
1855
- }
1856
- else if (is_array($src))
1857
- {
1858
- // Attach the array to the position if it is valid.
1859
- if (!isset($src["type"])) return false;
1860
-
1861
- switch ($src["type"])
1862
- {
1863
- case "element":
1864
- {
1865
- if (!isset($src["tag"]) || !isset($src["attrs"]) || !is_array($src["attrs"]) || !isset($src["children"])) return false;
1866
-
1867
- $src["tag"] = (string)$src["tag"];
1868
- $src["parent"] = $newpid;
1869
-
1870
- break;
1871
- }
1872
- case "content":
1873
- case "comment":
1874
- {
1875
- if (!isset($src["text"]) || isset($src["children"])) return false;
1876
-
1877
- $src["text"] = (string)$src["text"];
1878
-
1879
- break;
1880
- }
1881
- default: return false;
1882
- }
1883
-
1884
- array_splice($this->nodes[$newpid]["children"], $newpos, 0, array($this->nextid));
1885
- $this->RealignChildren($newpid, $newpos);
1886
- $this->nextid++;
1887
- }
1888
- else if (is_string($src))
1889
- {
1890
- return $this->Move(TagFilter::Explode($src, TagFilter::GetHTMLOptions()), $newpid, $newpos);
1891
- }
1892
- else
1893
- {
1894
- // Reparents an internal id.
1895
- $id = (int)$src;
1896
-
1897
- if (!$id || !isset($this->nodes[$id])) return false;
1898
-
1899
- // Don't allow reparenting to a child node.
1900
- $id2 = $newpid;
1901
- while ($id2)
1902
- {
1903
- if ($id === $id2) return false;
1904
-
1905
- $id2 = $this->nodes[$id2]["parent"];
1906
- }
1907
-
1908
- // Detach.
1909
- array_splice($this->nodes[$this->nodes[$id]["parent"]]["children"], $this->nodes[$id]["parentpos"], 1);
1910
- $this->RealignChildren($this->nodes[$id]["parent"], $this->nodes[$id]["parentpos"]);
1911
-
1912
- // Attach.
1913
- array_splice($this->nodes[$newpid]["children"], $newpos, 0, array($id));
1914
- $this->RealignChildren($newpid, $newpos);
1915
- }
1916
-
1917
- return true;
1918
- }
1919
-
1920
- // When $keepchildren is true, the node's children are moved into the parent of the node being removed.
1921
- public function Remove($id, $keepchildren = false)
1922
- {
1923
- $id = (int)$id;
1924
- if (!isset($this->nodes[$id])) return;
1925
-
1926
- if (!$id)
1927
- {
1928
- if (!$keepchildren)
1929
- {
1930
- // Reset all nodes.
1931
- $this->nodes = array(
1932
- array(
1933
- "type" => "root",
1934
- "parent" => false,
1935
- "parentpos" => false,
1936
- "children" => array()
1937
- )
1938
- );
1939
-
1940
- $this->nextid = 1;
1941
- }
1942
- }
1943
- else
1944
- {
1945
- // Detach the node from the parent.
1946
- $pid = $this->nodes[$id]["parent"];
1947
- $pos = $this->nodes[$id]["parentpos"];
1948
-
1949
- if ($keepchildren)
1950
- {
1951
- // Reparent the children and attach them to the new parent.
1952
- if (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]))
1953
- {
1954
- foreach ($this->nodes[$id]["children"] as $cid) $this->nodes[$cid]["parent"] = $pid;
1955
- array_splice($this->nodes[$pid]["children"], $pos, 1, $this->nodes[$id]["children"]);
1956
- }
1957
- else
1958
- {
1959
- array_splice($this->nodes[$pid]["children"], $pos, 1);
1960
- }
1961
-
1962
- $this->RealignChildren($pid, $pos);
1963
-
1964
- unset($this->nodes[$id]);
1965
- }
1966
- else
1967
- {
1968
- array_splice($this->nodes[$pid]["children"], $pos, 1);
1969
-
1970
- $this->RealignChildren($pid, $pos);
1971
-
1972
- // Remove node and all children.
1973
- $rootid = $id;
1974
- $pos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
1975
- do
1976
- {
1977
- if (!$pos)
1978
- {
1979
- $pid = $this->nodes[$id]["parent"];
1980
- $pos = $this->nodes[$id]["parentpos"];
1981
-
1982
- unset($this->nodes[$id]);
1983
- if ($rootid === $id) break;
1984
-
1985
- $id = $pid;
1986
- }
1987
- else
1988
- {
1989
- $id = $this->nodes[$id]["children"][$pos - 1];
1990
- $pos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
1991
- }
1992
- } while (1);
1993
- }
1994
- }
1995
- }
1996
-
1997
- public function Replace($id, $src, $inneronly = false)
1998
- {
1999
- $id = (int)$id;
2000
- if (!isset($this->nodes[$id])) return false;
2001
-
2002
- if ($inneronly)
2003
- {
2004
- // Remove children.
2005
- if (!isset($this->nodes[$id]["children"]) || !is_array($this->nodes[$id]["children"])) return false;
2006
-
2007
- while (count($this->nodes[$id]["children"])) $this->Remove($this->nodes[$id]["children"][0]);
2008
-
2009
- $newpid = $id;
2010
- $newpos = 0;
2011
- }
2012
- else
2013
- {
2014
- $newpid = $this->nodes[$id]["parent"];
2015
- $newpos = $this->nodes[$id]["parentpos"];
2016
-
2017
- $this->Remove($id);
2018
- }
2019
-
2020
- return $this->Move($src, $newpid, $newpos);
2021
- }
2022
-
2023
- private static function SplitAt_CopyNode($nodes, &$pid, $node)
2024
- {
2025
- // Copy the node.
2026
- $node["parent"] = $pid;
2027
- $node["parentpos"] = count($nodes->nodes[$pid]["children"]);
2028
- if (isset($node["children"])) $node["children"] = (is_array($node["children"]) ? array() : false);
2029
-
2030
- // Attach the node.
2031
- $nodes->nodes[$nodes->nextid] = $node;
2032
- $nodes->nodes[$pid]["children"][] = $nodes->nextid;
2033
-
2034
- $pid = $nodes->nextid;
2035
-
2036
- $nodes->nextid++;
2037
- }
2038
-
2039
- public function SplitAt($ids, $keepidparents = false)
2040
- {
2041
- $ids2 = array();
2042
- if (!is_array($ids)) $ids = array($ids);
2043
- foreach ($ids as $id) $ids2[(int)$id] = true;
2044
- unset($ids2[0]);
2045
-
2046
- $result = array();
2047
-
2048
- // Walk the entire set of nodes, cloning until an ID match occurs (if any).
2049
- $newnodes = new TagFilterNodes();
2050
- $newpid = 0;
2051
- $id = 0;
2052
- $pos = 0;
2053
- $maxpos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
2054
- do
2055
- {
2056
- if (!$pos)
2057
- {
2058
- if (isset($ids2[$id]) && count($newnodes->nodes[0]["children"]))
2059
- {
2060
- // Found an ID match.
2061
- $result[] = $newnodes;
2062
- $newnodes = new TagFilterNodes();
2063
- $newpid = 0;
2064
-
2065
- if ($keepidparents instanceof TagFilterNodes)
2066
- {
2067
- $newnodes = clone $keepidparents;
2068
- $newpid = $newnodes->nextid - 1;
2069
- }
2070
- else if ($keepidparents)
2071
- {
2072
- $stack = array();
2073
- $id2 = $this->nodes[$id]["parent"];
2074
- while ($id2)
2075
- {
2076
- $stack[] = $id2;
2077
-
2078
- $id2 = $this->nodes[$id2]["parent"];
2079
- }
2080
- $stack = array_reverse($stack);
2081
- foreach ($stack as $id2)
2082
- {
2083
- self::SplitAt_CopyNode($newnodes, $newpid, $this->nodes[$id2]);
2084
- }
2085
- }
2086
- }
2087
-
2088
- if ($id) self::SplitAt_CopyNode($newnodes, $newpid, $this->nodes[$id]);
2089
- }
2090
-
2091
- if ($pos >= $maxpos)
2092
- {
2093
- if (!$id) break;
2094
-
2095
- if (isset($ids2[$id]))
2096
- {
2097
- // Start a new set of nodes.
2098
- $result[] = $newnodes;
2099
- $newnodes = new TagFilterNodes();
2100
- $newpid = 0;
2101
-
2102
- $stack = array();
2103
- $id2 = $this->nodes[$id]["parent"];
2104
- while ($id2)
2105
- {
2106
- $stack[] = $id2;
2107
-
2108
- $id2 = $this->nodes[$id2]["parent"];
2109
- }
2110
- $stack = array_reverse($stack);
2111
- foreach ($stack as $id2)
2112
- {
2113
- self::SplitAt_CopyNode($newnodes, $newpid, $this->nodes[$id2]);
2114
- }
2115
- }
2116
- else
2117
- {
2118
- $newpid = $newnodes->nodes[$newpid]["parent"];
2119
- }
2120
-
2121
- $pos = $this->nodes[$id]["parentpos"] + 1;
2122
- $id = $this->nodes[$id]["parent"];
2123
- $maxpos = count($this->nodes[$id]["children"]);
2124
- }
2125
- else
2126
- {
2127
- $id = $this->nodes[$id]["children"][$pos];
2128
- $pos = 0;
2129
- $maxpos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
2130
- }
2131
- } while (1);
2132
-
2133
- if (!count($result) || count($newnodes->nodes[0]["children"])) $result[] = $newnodes;
2134
-
2135
- return $result;
2136
- }
2137
-
2138
- public function GetOuterHTML($id, $mode = "html")
2139
- {
2140
- return $this->Implode($id, array("output_mode" => $mode));
2141
- }
2142
-
2143
- public function SetOuterHTML($id, $src)
2144
- {
2145
- return $this->Replace($id, $src);
2146
- }
2147
-
2148
- public function GetInnerHTML($id, $mode = "html")
2149
- {
2150
- return $this->Implode($id, array("include_id" => false, "output_mode" => $mode));
2151
- }
2152
-
2153
- public function SetInnerHTML($id, $src)
2154
- {
2155
- return $this->Replace($id, $src, true);
2156
- }
2157
-
2158
- public function GetPlainText($id)
2159
- {
2160
- return $this->Implode($id, array("types" => "content", "post_elements" => array("p" => "\n\n", "br" => "\n")));
2161
- }
2162
-
2163
- public function SetPlainText($id, $src)
2164
- {
2165
- // Convert $src to a string.
2166
- if ($src instanceof TagFilterNodes)
2167
- {
2168
- $src = $src->GetPlainText(0);
2169
- }
2170
- else if (is_array($src))
2171
- {
2172
- $temp = new TagFilterNodes();
2173
- $temp->Move($src, 0, 0);
2174
-
2175
- $src = $temp->GetPlainText(0);
2176
- }
2177
- else if (!is_string($src))
2178
- {
2179
- $src = $this->GetPlainText((int)$src);
2180
- }
2181
-
2182
- $src = array(
2183
- "type" => "content",
2184
- "text" => (string)$src,
2185
- "parent" => false,
2186
- "parentpos" => false
2187
- );
2188
-
2189
- return $this->Replace($id, $src, true);
2190
- }
2191
-
2192
- private function RealignChildren($id, $pos)
2193
- {
2194
- $y = count($this->nodes[$id]["children"]);
2195
- for ($x = $pos; $x < $y; $x++) $this->nodes[$this->nodes[$id]["children"][$x]]["parentpos"] = $x;
2196
- }
2197
- }
2198
-
2199
- class TagFilter
2200
- {
2201
- // Internal callback function for extracting interior content of HTML 'script' and 'style' tags.
2202
- public static function HTMLSpecialTagContentCallback($stack, $final, &$tag, &$content, &$cx, $cy, &$content2, $options)
2203
- {
2204
- if (preg_match('/<\s*\/\s*' . $stack[0]["tag_name"] . '(\s*|\s+.+?)>/is', $content, $matches, PREG_OFFSET_CAPTURE, $cx))
2205
- {
2206
- $pos = $matches[0][1];
2207
-
2208
- $content2 = substr($content, $cx, $pos - $cx);
2209
- $cx = $pos;
2210
- $tag = true;
2211
-
2212
- return true;
2213
- }
2214
- else
2215
- {
2216
- if ($final)
2217
- {
2218
- $content2 = substr($content, $cx);
2219
- $cx = $cy;
2220
- }
2221
-
2222
- return false;
2223
- }
2224
- }
2225
-
2226
- public static function GetHTMLOptions()
2227
- {
2228
- $result = array(
2229
- "tag_name_map" => array(
2230
- "!doctype" => "DOCTYPE"
2231
- ),
2232
- "untouched_tag_attr_keys" => array(
2233
- "doctype" => true,
2234
- ),
2235
- "void_tags" => array(
2236
- "DOCTYPE" => true,
2237
- "area" => true,
2238
- "base" => true,
2239
- "bgsound" => true,
2240
- "br" => true,
2241
- "col" => true,
2242
- "embed" => true,
2243
- "hr" => true,
2244
- "img" => true,
2245
- "input" => true,
2246
- "keygen" => true,
2247
- "link" => true,
2248
- "menuitem" => true,
2249
- "meta" => true,
2250
- "param" => true,
2251
- "source" => true,
2252
- "track" => true,
2253
- "wbr" => true
2254
- ),
2255
- // Alternate tag internal content rules for specialized tags.
2256
- "alt_tag_content_rules" => array(
2257
- "script" => __CLASS__ . "::HTMLSpecialTagContentCallback",
2258
- "style" => __CLASS__ . "::HTMLSpecialTagContentCallback"
2259
- ),
2260
- // Stored as a map for open tag elements.
2261
- // For example, '"address" => array("p" => true)' means: When an open 'address' tag is encountered,
2262
- // look for an open 'p' tag anywhere (no '_limit') in the tag stack. Apply a closing '</p>' tag for all matches.
2263
- //
2264
- // If '_limit' is defined as a string or an array, then stack walking stops as soon as one of the specified tags is encountered.
2265
- "pre_close_tags" => array(
2266
- "body" => array("body" => true, "head" => true),
2267
-
2268
- "address" => array("p" => true),
2269
- "article" => array("p" => true),
2270
- "aside" => array("p" => true),
2271
- "blockquote" => array("p" => true),
2272
- "div" => array("p" => true),
2273
- "dl" => array("p" => true),
2274
- "fieldset" => array("p" => true),
2275
- "footer" => array("p" => true),
2276
- "form" => array("p" => true),
2277
- "h1" => array("p" => true),
2278
- "h2" => array("p" => true),
2279
- "h3" => array("p" => true),
2280
- "h4" => array("p" => true),
2281
- "h5" => array("p" => true),
2282
- "h6" => array("p" => true),
2283
- "header" => array("p" => true),
2284
- "hr" => array("p" => true),
2285
- "menu" => array("p" => true),
2286
- "nav" => array("p" => true),
2287
- "ol" => array("p" => true),
2288
- "pre" => array("p" => true),
2289
- "section" => array("p" => true),
2290
- "table" => array("p" => true),
2291
- "ul" => array("p" => true),
2292
- "p" => array("p" => true),
2293
-
2294
- "tbody" => array("_limit" => "table", "thead" => true, "tr" => true, "th" => true, "td" => true),
2295
- "tr" => array("_limit" => "table", "tr" => true, "th" => true, "td" => true),
2296
- "th" => array("_limit" => "table", "th" => true, "td" => true),
2297
- "td" => array("_limit" => "table", "th" => true, "td" => true),
2298
- "tfoot" => array("_limit" => "table", "thead" => true, "tbody" => true, "tr" => true, "th" => true, "td" => true),
2299
-
2300
- "optgroup" => array("optgroup" => true, "option" => true),
2301
- "option" => array("option" => true),
2302
-
2303
- "dd" => array("_limit" => "dl", "dd" => true, "dt" => true),
2304
- "dt" => array("_limit" => "dl", "dd" => true, "dt" => true),
2305
-
2306
- "colgroup" => array("colgroup" => true),
2307
-
2308
- "li" => array("_limit" => array("ul" => true, "ol" => true, "menu" => true, "dir" => true), "li" => true),
2309
- ),
2310
- "process_attrs" => array(
2311
- "class" => "classes",
2312
- "href" => "uri",
2313
- "src" => "uri",
2314
- "dynsrc" => "uri",
2315
- "lowsrc" => "uri",
2316
- "background" => "uri",
2317
- ),
2318
- "keep_attr_newlines" => false,
2319
- "keep_comments" => false,
2320
- "allow_namespaces" => true,
2321
- "charset" => "UTF-8",
2322
- "charset_tags" => true,
2323
- "charset_attrs" => true,
2324
- "output_mode" => "html",
2325
- "lowercase_tags" => true,
2326
- "lowercase_attrs" => true,
2327
- );
2328
-
2329
- return $result;
2330
- }
2331
-
2332
- public static function Run($content, $options = array())
2333
- {
2334
- $tfs = new TagFilterStream($options);
2335
- $tfs->Finalize();
2336
- $result = $tfs->Process($content);
2337
-
2338
- // Clean up output.
2339
- $result = trim($result);
2340
- $result = self::CleanupResults($result);
2341
-
2342
- if (function_exists("gc_mem_caches")) gc_mem_caches();
2343
-
2344
- return $result;
2345
- }
2346
-
2347
- public static function CleanupResults($content)
2348
- {
2349
- $result = str_replace("\r\n", "\n", $content);
2350
- $result = str_replace("\r", "\n", $result);
2351
- while (strpos($result, "\n\n\n") !== false) $result = str_replace("\n\n\n", "\n\n", $result);
2352
-
2353
- return $result;
2354
- }
2355
-
2356
- public static function ExplodeTagCallback($stack, &$content, $open, $tagname, &$attrs, $options)
2357
- {
2358
- if ($open)
2359
- {
2360
- $pid = (count($options["data"]->stackmap) ? $options["data"]->stackmap[0] : 0);
2361
-
2362
- $tagname2 = (isset($options["tag_name_map"][strtolower($tagname)]) ? $options["tag_name_map"][strtolower($tagname)] : $tagname);
2363
-
2364
- $options["nodes"]->nodes[$options["nodes"]->nextid] = array(
2365
- "type" => "element",
2366
- "tag" => $tagname,
2367
- "attrs" => $attrs,
2368
- "parent" => $pid,
2369
- "parentpos" => count($options["nodes"]->nodes[$pid]["children"]),
2370
- "children" => (isset($options["void_tags"][$tagname2]) ? false : array())
2371
- );
2372
-
2373
- $options["nodes"]->nodes[$pid]["children"][] = $options["nodes"]->nextid;
2374
-
2375
- // Append non-void tags to the ID stack.
2376
- if (!isset($options["void_tags"][$tagname2])) array_unshift($options["data"]->stackmap, $options["nodes"]->nextid);
2377
-
2378
- $options["nodes"]->nextid++;
2379
- }
2380
- else
2381
- {
2382
- array_shift($options["data"]->stackmap);
2383
- }
2384
-
2385
- return array("keep_tag" => false, "keep_interior" => false);
2386
- }
2387
-
2388
- public static function ExplodeContentCallback($stack, $result, &$content, $options)
2389
- {
2390
- if ($content === "") return;
2391
-
2392
- $type = (substr($content, 0, 5) === "<!-- " ? "comment" : "content");
2393
- $pid = (count($options["data"]->stackmap) ? $options["data"]->stackmap[0] : 0);
2394
- $parentpos = count($options["nodes"]->nodes[$pid]["children"]);
2395
-
2396
- if ($parentpos && $options["nodes"]->nodes[$options["nodes"]->nodes[$pid]["children"][$parentpos - 1]]["type"] == $type) $options["nodes"]->nodes[$options["nodes"]->nodes[$pid]["children"][$parentpos - 1]]["text"] .= $content;
2397
- else
2398
- {
2399
- $options["nodes"]->nodes[$options["nodes"]->nextid] = array(
2400
- "type" => $type,
2401
- "text" => $content,
2402
- "parent" => $pid,
2403
- "parentpos" => $parentpos
2404
- );
2405
-
2406
- $options["nodes"]->nodes[$pid]["children"][] = $options["nodes"]->nextid;
2407
-
2408
- $options["nodes"]->nextid++;
2409
- }
2410
-
2411
- $content = "";
2412
- }
2413
-
2414
- public static function Explode($content, $options = array())
2415
- {
2416
- $options["tag_callback"] = __CLASS__ . "::ExplodeTagCallback";
2417
- $options["content_callback"] = __CLASS__ . "::ExplodeContentCallback";
2418
- $options["nodes"] = new TagFilterNodes();
2419
- $options["data"] = new stdClass();
2420
- $options["data"]->stackmap = array();
2421
-
2422
- self::Run($content, $options);
2423
-
2424
- return $options["nodes"];
2425
- }
2426
-
2427
- public static function HTMLPurifyTagCallback($stack, &$content, $open, $tagname, &$attrs, $options)
2428
- {
2429
- if ($open)
2430
- {
2431
- if ($tagname === "script") return array("keep_tag" => false, "keep_interior" => false);
2432
- if ($tagname === "style") return array("keep_tag" => false, "keep_interior" => false);
2433
-
2434
- if (isset($attrs["src"]) && substr($attrs["src"], 0, 11) === "javascript:") return array("keep_tag" => false, "keep_interior" => false);
2435
- if (isset($attrs["href"]) && substr($attrs["href"], 0, 11) === "javascript:") return array("keep_tag" => false);
2436
-
2437
- if (!isset($options["htmlpurify"]["allowed_tags"][$tagname])) return array("keep_tag" => false);
2438
-
2439
- if (!isset($options["htmlpurify"]["allowed_attrs"][$tagname])) $attrs = array();
2440
- else
2441
- {
2442
- // For classes, "class" needs to be specified as an allowed attribute.
2443
- foreach ($attrs as $attr => $val)
2444
- {
2445
- if (!isset($options["htmlpurify"]["allowed_attrs"][$tagname][$attr])) unset($attrs[$attr]);
2446
- }
2447
- }
2448
-
2449
- if (isset($options["htmlpurify"]["required_attrs"][$tagname]))
2450
- {
2451
- foreach ($options["htmlpurify"]["required_attrs"][$tagname] as $attr => $val)
2452
- {
2453
- if (!isset($attrs[$attr])) return array("keep_tag" => false);
2454
- }
2455
- }
2456
-
2457
- if (isset($attrs["class"]))
2458
- {
2459
- if (!isset($options["htmlpurify"]["allowed_classes"][$tagname])) unset($attrs["class"]);
2460
- else
2461
- {
2462
- foreach ($attrs["class"] as $class)
2463
- {
2464
- if (!isset($options["htmlpurify"]["allowed_classes"][$tagname][$class])) unset($attrs["class"][$class]);
2465
- }
2466
-
2467
- if (!count($attrs["class"])) unset($attrs["class"]);
2468
- }
2469
- }
2470
- }
2471
- else
2472
- {
2473
- if (isset($options["htmlpurify"]["remove_empty"][substr($tagname, 1)]) && trim(str_replace(array("&nbsp;", "\xC2\xA0"), " ", $content)) === "")
2474
- {
2475
- if ($content !== "") $content = " ";
2476
-
2477
- return array("keep_tag" => false);
2478
- }
2479
- }
2480
-
2481
- return array();
2482
- }
2483
-
2484
- private static function Internal_NormalizeHTMLPurifyOptions($value)
2485
- {
2486
- if (is_string($value))
2487
- {
2488
- $opts = explode(",", $value);
2489
- $value = array();
2490
- foreach ($opts as $opt)
2491
- {
2492
- $opt = (string)trim($opt);
2493
- if ($opt !== "") $value[$opt] = true;
2494
- }
2495
- }
2496
-
2497
- return $value;
2498
- }
2499
-
2500
- public static function NormalizeHTMLPurifyOptions($purifyopts)
2501
- {
2502
- if (!isset($purifyopts["allowed_tags"])) $purifyopts["allowed_tags"] = array();
2503
- if (!isset($purifyopts["allowed_attrs"])) $purifyopts["allowed_attrs"] = array();
2504
- if (!isset($purifyopts["required_attrs"])) $purifyopts["required_attrs"] = array();
2505
- if (!isset($purifyopts["allowed_classes"])) $purifyopts["allowed_classes"] = array();
2506
- if (!isset($purifyopts["remove_empty"])) $purifyopts["remove_empty"] = array();
2507
-
2508
- $purifyopts["allowed_tags"] = self::Internal_NormalizeHTMLPurifyOptions($purifyopts["allowed_tags"]);
2509
- foreach ($purifyopts["allowed_attrs"] as $key => $val) $purifyopts["allowed_attrs"][$key] = self::Internal_NormalizeHTMLPurifyOptions($val);
2510
- foreach ($purifyopts["required_attrs"] as $key => $val) $purifyopts["required_attrs"][$key] = self::Internal_NormalizeHTMLPurifyOptions($val);
2511
- foreach ($purifyopts["allowed_classes"] as $key => $val) $purifyopts["allowed_classes"][$key] = self::Internal_NormalizeHTMLPurifyOptions($val);
2512
- $purifyopts["remove_empty"] = self::Internal_NormalizeHTMLPurifyOptions($purifyopts["remove_empty"]);
2513
-
2514
- return $purifyopts;
2515
- }
2516
-
2517
- public static function HTMLPurify($content, $htmloptions, $purifyopts)
2518
- {
2519
- $htmloptions["tag_callback"] = __CLASS__ . "::HTMLPurifyTagCallback";
2520
- $htmloptions["htmlpurify"] = self::NormalizeHTMLPurifyOptions($purifyopts);
2521
-
2522
- return self::Run($content, $htmloptions);
2523
- }
2524
-
2525
- public static function ReorderSelectorTokens($tokens, $splitrules, $order = array("pseudo-element" => array(), "pseudo-class" => array(), "attr" => array(), "class" => array(), "element" => array(), "id" => array()), $endnots = true)
2526
- {
2527
- // Collapse split rules.
2528
- if (count($tokens) && !isset($tokens[0]["type"]) && isset($tokens[0][0]["type"]))
2529
- {
2530
- $tokens2 = array();
2531
- foreach ($tokens as $rules)
2532
- {
2533
- if (count($tokens2)) $tokens2[] = array("type" => "combine", "combine" => "or");
2534
- $rules = array_reverse($rules);
2535
- foreach ($rules as $rule) $tokens2[] = $rule;
2536
- }
2537
-
2538
- $tokens = $tokens2;
2539
- }
2540
-
2541
- $result = array();
2542
- $rules = array();
2543
- $selector = $order;
2544
- foreach ($tokens as $token)
2545
- {
2546
- if ($token["type"] != "combine") array_unshift($selector[$token["type"]], $token);
2547
- else
2548
- {
2549
- foreach ($selector as $vals)
2550
- {
2551
- foreach ($vals as $token2)
2552
- {
2553
- if (($endnots && $token2["not"]) || (!$endnots && !$token2["not"])) array_unshift($result, $token2);
2554
- }
2555
-
2556
- foreach ($vals as $token2)
2557
- {
2558
- if (($endnots && !$token2["not"]) || (!$endnots && $token2["not"])) array_unshift($result, $token2);
2559
- }
2560
- }
2561
-
2562
- if (!$splitrules || $token["combine"] != "or") array_unshift($result, $token);
2563
- else if ($token["combine"] == "or")
2564
- {
2565
- if (count($result)) $rules[] = $result;
2566
-
2567
- $result = array();
2568
- }
2569
-
2570
- $selector = $order;
2571
- }
2572
- }
2573
-
2574
- foreach ($selector as $vals)
2575
- {
2576
- foreach ($vals as $token2)
2577
- {
2578
- if (($endnots && $token2["not"]) || (!$endnots && !$token2["not"])) array_unshift($result, $token2);
2579
- }
2580
-
2581
- foreach ($vals as $token2)
2582
- {
2583
- if (($endnots && !$token2["not"]) || (!$endnots && $token2["not"])) array_unshift($result, $token2);
2584
- }
2585
- }
2586
-
2587
- if ($splitrules)
2588
- {
2589
- if (count($result)) $rules[] = $result;
2590
-
2591
- $result = $rules;
2592
- }
2593
- else
2594
- {
2595
- // Ignore a stray group combiner at the end.
2596
- if (count($result) && $result[0]["type"] == "combine" && $result[0]["combine"] == "or") array_shift($result);
2597
- }
2598
-
2599
- return $result;
2600
- }
2601
-
2602
- public static function ParseSelector($query, $splitrules = false)
2603
- {
2604
- // Tokenize query into individual action steps.
2605
- $query = trim($query);
2606
- $tokens = array();
2607
- $lastor = 0;
2608
- $a = ord("A");
2609
- $a2 = ord("a");
2610
- $f = ord("F");
2611
- $f2 = ord("f");
2612
- $z = ord("Z");
2613
- $z2 = ord("z");
2614
- $backslash = ord("\\");
2615
- $hyphen = ord("-");
2616
- $underscore = ord("_");
2617
- $pipe = ord("|");
2618
- $asterisk = ord("*");
2619
- $colon = ord(":");
2620
- $period = ord(".");
2621
- $zero = ord("0");
2622
- $nine = ord("9");
2623
- $cr = ord("\r");
2624
- $nl = ord("\n");
2625
- $ff = ord("\f");
2626
- $cx = 0;
2627
- $cy = strlen($query);
2628
- $state = "next_selector";
2629
- do
2630
- {
2631
- $currcx = $cx;
2632
- $currstate = $state;
2633
-
2634
- switch ($state)
2635
- {
2636
- case "next_selector":
2637
- {
2638
- // This state is necessary to handle the :not(selector) function.
2639
- $token = array("not" => false);
2640
- }
2641
- case "selector":
2642
- {
2643
- if ($cx >= $cy) break;
2644
-
2645
- switch ($query[$cx])
2646
- {
2647
- case "#":
2648
- {
2649
- $token["type"] = "id";
2650
- $state = "ident_name";
2651
- $allownamespace = false;
2652
- $identasterisk = false;
2653
- $allowperiod = false;
2654
- $namespace = false;
2655
- $range = true;
2656
- $ident = "";
2657
- $nextstate = "selector_ident_result";
2658
- $cx++;
2659
-
2660
- break;
2661
- }
2662
- case ".":
2663
- {
2664
- $token["type"] = "class";
2665
- $state = "ident";
2666
- $allownamespace = false;
2667
- $identasterisk = false;
2668
- $allowperiod = false;
2669
- $nextstate = "selector_ident_result";
2670
- $cx++;
2671
-
2672
- break;
2673
- }
2674
- case "[":
2675
- {
2676
- $token["type"] = "attr";
2677
- $state = "ident";
2678
- $state2 = "attr";
2679
- $allownamespace = true;
2680
- $identasterisk = false;
2681
- $allowperiod = false;
2682
- $nextstate = "selector_ident_result";
2683
- $cx++;
2684
-
2685
- // Find a non-whitespace character.
2686
- while ($cx < $cy && ($query[$cx] == " " || $query[$cx] == "\t" || $query[$cx] == "\r" || $query[$cx] == "\n" || $query[$cx] == "\f")) $cx++;
2687
-
2688
- break;
2689
- }
2690
- case ":":
2691
- {
2692
- $cx++;
2693
- if ($cx >= $cy || $query[$cx] != ":") $token["type"] = "pseudo-class";
2694
- else
2695
- {
2696
- $token["type"] = "pseudo-element";
2697
- $cx++;
2698
- }
2699
-
2700
- $state = "ident";
2701
- $allownamespace = true;
2702
- $identasterisk = false;
2703
- $allowperiod = false;
2704
- $nextstate = "selector_ident_result";
2705
-
2706
- break;
2707
- }
2708
- case ",":
2709
- case "+":
2710
- case ">":
2711
- case "~":
2712
- case " ":
2713
- case "\r":
2714
- case "\n":
2715
- case "\t":
2716
- case "\f":
2717
- {
2718
- $state = "combine";
2719
-
2720
- break;
2721
- }
2722
- default:
2723
- {
2724
- $token["type"] = "element";
2725
- $state = "ident";
2726
- $allownamespace = true;
2727
- $identasterisk = true;
2728
- $allowperiod = false;
2729
- $nextstate = "selector_ident_result";
2730
-
2731
- break;
2732
- }
2733
- }
2734
-
2735
- break;
2736
- }
2737
- case "selector_ident_result":
2738
- {
2739
- switch ($token["type"])
2740
- {
2741
- case "id":
2742
- {
2743
- $token["id"] = $ident;
2744
- $tokens[] = $token;
2745
- $state = ($token["not"] ? "negate_close" : "next_selector");
2746
-
2747
- break;
2748
- }
2749
- case "class":
2750
- {
2751
- $token["class"] = $ident;
2752
- $tokens[] = $token;
2753
- $state = ($token["not"] ? "negate_close" : "next_selector");
2754
-
2755
- break;
2756
- }
2757
- case "element":
2758
- {
2759
- $token["namespace"] = $namespace;
2760
- $token["tag"] = $ident;
2761
- $tokens[] = $token;
2762
- $state = ($token["not"] ? "negate_close" : "next_selector");
2763
-
2764
- break;
2765
- }
2766
- case "attr":
2767
- {
2768
- if ($state2 == "attr")
2769
- {
2770
- $token["namespace"] = $namespace;
2771
- $token[$state2] = $ident;
2772
-
2773
- // Find a non-whitespace character.
2774
- while ($cx < $cy && ($query[$cx] == " " || $query[$cx] == "\t" || $query[$cx] == "\r" || $query[$cx] == "\n" || $query[$cx] == "\f")) $cx++;
2775
-
2776
- if ($cx >= $cy || $query[$cx] == "]")
2777
- {
2778
- $token["cmp"] = false;
2779
- $tokens[] = $token;
2780
- $state = ($token["not"] ? "negate_close" : "next_selector");
2781
- $cx++;
2782
- }
2783
- else
2784
- {
2785
- if ($query[$cx] == "=")
2786
- {
2787
- $token["cmp"] = "=";
2788
- $cx++;
2789
- }
2790
- else if ($cx + 1 < $cy && ($query[$cx] == "^" || $query[$cx] == "$" || $query[$cx] == "*" || $query[$cx] == "~" || $query[$cx] == "|") && $query[$cx + 1] == "=")
2791
- {
2792
- $token["cmp"] = substr($query, $cx, 2);
2793
- $cx += 2;
2794
- }
2795
- else
2796
- {
2797
- return array("success" => false, "error" => "Unknown or invalid attribute comparison operator '" . $query[$cx] . "' detected at position " . $cx . ".", "errorcode" => "invalid_attr_compare", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
2798
- }
2799
-
2800
- // Find a non-whitespace character.
2801
- while ($cx < $cy && ($query[$cx] == " " || $query[$cx] == "\t" || $query[$cx] == "\r" || $query[$cx] == "\n" || $query[$cx] == "\f")) $cx++;
2802
-
2803
- if ($cx < $cy && ($query[$cx] == "\"" || $query[$cx] == "'"))
2804
- {
2805
- $state = "string";
2806
- $endchr = ord($query[$cx]);
2807
- $cx++;
2808
- }
2809
- else
2810
- {
2811
- $state = "ident";
2812
- $allownamespace = false;
2813
- $identasterisk = false;
2814
- $allowperiod = false;
2815
- }
2816
-
2817
- $state2 = "val";
2818
- $nextstate = "selector_ident_result";
2819
- }
2820
- }
2821
- else if ($state2 == "val")
2822
- {
2823
- $token[$state2] = $ident;
2824
-
2825
- // Find a non-whitespace character.
2826
- while ($cx < $cy && ($query[$cx] == " " || $query[$cx] == "\t" || $query[$cx] == "\r" || $query[$cx] == "\n" || $query[$cx] == "\f")) $cx++;
2827
-
2828
- $tokens[] = $token;
2829
- $state = ($token["not"] ? "negate_close" : "next_selector");
2830
-
2831
- if ($cx < $cy && $query[$cx] == "]") $cx++;
2832
- }
2833
-
2834
- break;
2835
- }
2836
- case "pseudo-class":
2837
- case "pseudo-element":
2838
- {
2839
- $ident = strtolower($ident);
2840
-
2841
- // Deal with CSS1 and CSS2 compatibility.
2842
- if ($ident === "first-line" || $ident === "first-letter" || $ident === "before" || $ident === "after") $token["type"] = "pseudo-element";
2843
-
2844
- if ($token["type"] == "pseudo-class" && $ident == "not")
2845
- {
2846
- if ($token["not"]) return array("success" => false, "error" => "Invalid :not() embedded inside another :not() detected at position " . $cx . ".", "errorcode" => "invalid_not", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
2847
- if ($cx >= $cy || $query[$cx] != "(") return array("success" => false, "error" => "Missing '(' detected at position " . $cx . ".", "errorcode" => "invalid_not", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
2848
-
2849
- unset($token["type"]);
2850
- $token["not"] = true;
2851
-
2852
- $state = "selector";
2853
- $cx++;
2854
-
2855
- // Find a non-whitespace character.
2856
- while ($cx < $cy && ($query[$cx] == " " || $query[$cx] == "\t" || $query[$cx] == "\r" || $query[$cx] == "\n" || $query[$cx] == "\f")) $cx++;
2857
- }
2858
- else
2859
- {
2860
- $token["pseudo"] = $ident;
2861
-
2862
- if ($cx < $cy && $query[$cx] == "(")
2863
- {
2864
- $token["expression"] = "";
2865
- $ident = "";
2866
- $state = "pseudo_expression";
2867
- $cx++;
2868
- }
2869
- else
2870
- {
2871
- $token["expression"] = false;
2872
- $tokens[] = $token;
2873
- $state = ($token["not"] ? "negate_close" : "next_selector");
2874
- }
2875
- }
2876
-
2877
- break;
2878
- }
2879
- }
2880
-
2881
- break;
2882
- }
2883
- case "negate_close":
2884
- {
2885
- // Find a non-whitespace character.
2886
- while ($cx < $cy && ($query[$cx] == " " || $query[$cx] == "\t" || $query[$cx] == "\r" || $query[$cx] == "\n" || $query[$cx] == "\f")) $cx++;
2887
-
2888
- if ($cx < $cy && $query[$cx] != ")") return array("success" => false, "error" => "Invalid :not() close character '" . $query[$cx] . "' detected at position " . $cx . ".", "errorcode" => "invalid_negate_close", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
2889
-
2890
- $cx++;
2891
- $state = "next_selector";
2892
-
2893
- break;
2894
- }
2895
- case "pseudo_expression":
2896
- {
2897
- $token["expression"] .= $ident;
2898
-
2899
- // Find a non-whitespace character.
2900
- while ($cx < $cy && ($query[$cx] == " " || $query[$cx] == "\t" || $query[$cx] == "\r" || $query[$cx] == "\n" || $query[$cx] == "\f")) $cx++;
2901
-
2902
- if ($cx >= $cy) break;
2903
-
2904
- if ($query[$cx] == ")")
2905
- {
2906
- if (substr($token["pseudo"], 0, 4) === "nth-")
2907
- {
2908
- // Convert the expression to an+b syntax.
2909
- $exp = strtolower($token["expression"]);
2910
-
2911
- if ($exp == "even") $exp = "2n";
2912
- else if ($exp == "odd") $exp = "2n+1";
2913
- else
2914
- {
2915
- do
2916
- {
2917
- $currexp = $exp;
2918
-
2919
- $exp = str_replace(array("++", "+-", "-+", "--"), array("+", "-", "-", "+"), $exp);
2920
-
2921
- } while ($currexp !== $exp);
2922
- }
2923
-
2924
- if (substr($exp, 0, 2) == "-n") $exp = "-1n" . substr($exp, 2);
2925
- else if (substr($exp, 0, 2) == "+n") $exp = "1n" . substr($exp, 2);
2926
- else if (substr($exp, 0, 1) == "n") $exp = "1n" . substr($exp, 1);
2927
-
2928
- $pos = strpos($exp, "n");
2929
- if ($pos === false)
2930
- {
2931
- $token["a"] = 0;
2932
- $token["b"] = (double)$exp;
2933
- }
2934
- else
2935
- {
2936
- $token["a"] = (double)$exp;
2937
- $token["b"] = (double)substr($exp, $pos + 1);
2938
- }
2939
-
2940
- $token["expression"] = $token["a"] . "n" . ($token["b"] < 0 ? $token["b"] : "+" . $token["b"]);
2941
- }
2942
-
2943
- $tokens[] = $token;
2944
- $state = ($token["not"] ? "negate_close" : "next_selector");
2945
- $cx++;
2946
- }
2947
- else if ($query[$cx] == "+" || $query[$cx] == "-")
2948
- {
2949
- $ident = $query[$cx];
2950
- $cx++;
2951
- }
2952
- else if ($query[$cx] == "\"" || $query[$cx] == "'")
2953
- {
2954
- $state = "string";
2955
- $endchr = ord($query[$cx]);
2956
- $cx++;
2957
- }
2958
- else
2959
- {
2960
- $val = ord($query[$cx]);
2961
-
2962
- $state = ($val >= $zero && $val <= $nine ? "ident_name" : "ident");
2963
- $allownamespace = false;
2964
- $identasterisk = false;
2965
- $allowperiod = ($val >= $zero && $val <= $nine);
2966
- $namespace = false;
2967
- $range = true;
2968
- $ident = "";
2969
-
2970
- $nextstate = "pseudo_expression";
2971
- }
2972
-
2973
- break;
2974
- }
2975
- case "string":
2976
- {
2977
- $startcx = $cx;
2978
- $ident = "";
2979
-
2980
- for (; $cx < $cy; $cx++)
2981
- {
2982
- $val = ord($query[$cx]);
2983
-
2984
- if ($val == $endchr)
2985
- {
2986
- $cx++;
2987
-
2988
- break;
2989
- }
2990
- else if ($val == $backslash)
2991
- {
2992
- // Escape sequence.
2993
- if ($cx + 1 >= $cy) $ident .= "\\";
2994
- else
2995
- {
2996
- $cx++;
2997
- $val = ord($query[$cx]);
2998
-
2999
- if (($val >= $a && $val <= $f) || ($val >= $a2 && $val <= $f2) || ($val >= $zero && $val <= $nine))
3000
- {
3001
- // Unicode (e.g. \0020)
3002
- for ($x = $cx + 1; $x < $cy; $x++)
3003
- {
3004
- $val = ord($query[$x]);
3005
- if (!(($val >= $a && $val <= $f) || ($val >= $a2 && $val <= $f2) || ($val >= $zero && $val <= $nine))) break;
3006
- }
3007
-
3008
- $num = hexdec(substr($query, $cx, $x - $cx));
3009
- $cx = $x - 1;
3010
-
3011
- $ident .= TagFilterStream::UTF8Chr($num);
3012
-
3013
- // Skip one optional \r\n OR a single whitespace char.
3014
- if ($cx + 2 < $cy && $query[$cx + 1] == "\r" && $query[$cx + 2] == "\n") $cx += 2;
3015
- else if ($cx + 1 < $cy && ($query[$cx + 1] == " " || $query[$cx + 1] == "\r" || $query[$cx + 1] == "\n" || $query[$cx + 1] == "\t" || $query[$cx + 1] == "\f")) $cx++;
3016
- }
3017
- else
3018
- {
3019
- $ident .= $query[$cx];
3020
- }
3021
- }
3022
- }
3023
- else
3024
- {
3025
- $ident .= $query[$cx];
3026
- }
3027
- }
3028
-
3029
- $state = $nextstate;
3030
-
3031
- break;
3032
- }
3033
- case "ident":
3034
- {
3035
- $namespace = false;
3036
- $range = false;
3037
-
3038
- if ($cx >= $cy) break;
3039
-
3040
- if ($query[$cx] != "-") $ident = "";
3041
- else
3042
- {
3043
- $ident = "-";
3044
- $cx++;
3045
- }
3046
-
3047
- $state = "ident_name";
3048
-
3049
- break;
3050
- }
3051
- case "ident_name":
3052
- {
3053
- // Find the first invalid character.
3054
- $startcx = $cx;
3055
- for (; $cx < $cy; $cx++)
3056
- {
3057
- $val = ord($query[$cx]);
3058
-
3059
- if ($val != $period && ($val < $zero || $val > $nine)) $allowperiod = false;
3060
-
3061
- if (($val >= $a && $val <= $z) || ($val >= $a2 && $val <= $z2) || $val == $underscore || $val > 127)
3062
- {
3063
- $ident .= $query[$cx];
3064
- }
3065
- else if ($allowperiod && $val == $period)
3066
- {
3067
- $allowperiod = false;
3068
-
3069
- $ident .= ".";
3070
- }
3071
- else if ($val == $hyphen || ($val >= $zero && $val <= $nine))
3072
- {
3073
- // Only allowed AFTER the first character.
3074
- if (!$range) return array("success" => false, "error" => "Invalid identifier character '" . $query[$cx] . "' detected at position " . $cx . ".", "errorcode" => "invalid_ident", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
3075
-
3076
- $allowperiod = false;
3077
-
3078
- $ident .= $query[$cx];
3079
- }
3080
- else if ($val == $backslash)
3081
- {
3082
- // Escape sequence.
3083
- if ($cx + 1 >= $cy) $ident .= "\\";
3084
- else
3085
- {
3086
- $cx++;
3087
- $val = ord($query[$cx]);
3088
-
3089
- if (($val >= $a && $val <= $f) || ($val >= $a2 && $val <= $f2) || ($val >= $zero && $val <= $nine))
3090
- {
3091
- // Unicode (e.g. \0020)
3092
- for ($x = $cx + 1; $x < $cy; $x++)
3093
- {
3094
- $val = ord($query[$x]);
3095
- if (!(($val >= $a && $val <= $f) || ($val >= $a2 && $val <= $f2) || ($val >= $zero && $val <= $nine))) break;
3096
- }
3097
-
3098
- $num = hexdec(substr($query, $cx, $x - $cx));
3099
- $cx = $x - 1;
3100
-
3101
- $ident .= TagFilterStream::UTF8Chr($num);
3102
-
3103
- // Skip one optional \r\n OR a single whitespace char.
3104
- if ($cx + 2 < $cy && $query[$cx + 1] == "\r" && $query[$cx + 2] == "\n") $cx += 2;
3105
- else if ($cx + 1 < $cy && ($query[$cx + 1] == " " || $query[$cx + 1] == "\r" || $query[$cx + 1] == "\n" || $query[$cx + 1] == "\t" || $query[$cx + 1] == "\f")) $cx++;
3106
- }
3107
- else if ($val != $cr && $val != $nl && $val != $ff)
3108
- {
3109
- $ident .= $query[$cx];
3110
- }
3111
- }
3112
- }
3113
- else if ($allownamespace && $val == $pipe && ($cx + 1 >= $cy || $query[$cx + 1] != "="))
3114
- {
3115
- // Handle namespaces (rare).
3116
- if ($ident != "")
3117
- {
3118
- $namespace = $ident;
3119
- $ident = "";
3120
- }
3121
-
3122
- $allownamespace = false;
3123
- }
3124
- else if ($val == $asterisk)
3125
- {
3126
- // Handle wildcard (*) characters.
3127
- if ($allownamespace && $cx + 1 < $cy && $query[$cx + 1] == "|")
3128
- {
3129
- // Wildcard namespace (*|).
3130
- $namespace = "*";
3131
- $allownamespace = false;
3132
- $cx++;
3133
- }
3134
- else if ($identasterisk)
3135
- {
3136
- if ($ident != "") return array("success" => false, "error" => "Invalid identifier wildcard character '*' detected at position " . $cx . ".", "errorcode" => "invalid_wildcard_ident", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
3137
-
3138
- $ident = "*";
3139
- $cx++;
3140
-
3141
- break;
3142
- }
3143
- else
3144
- {
3145
- // End of ident.
3146
- break;
3147
- }
3148
- }
3149
- else
3150
- {
3151
- // End of ident.
3152
- break;
3153
- }
3154
-
3155
- $range = true;
3156
- }
3157
-
3158
- if ($ident == "") return array("success" => false, "error" => "Missing or invalid identifier at position " . $cx . ".", "errorcode" => "missing_ident", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
3159
-
3160
- $state = $nextstate;
3161
-
3162
- break;
3163
- }
3164
- case "combine":
3165
- {
3166
- $token = array("type" => "combine");
3167
-
3168
- // Find a non-whitespace character.
3169
- while ($cx < $cy && ($query[$cx] == " " || $query[$cx] == "\t" || $query[$cx] == "\r" || $query[$cx] == "\n" || $query[$cx] == "\f")) $cx++;
3170
-
3171
- if ($cx < $cy)
3172
- {
3173
- switch ($query[$cx])
3174
- {
3175
- case ",":
3176
- {
3177
- $token["combine"] = "or";
3178
- $lastor = count($tokens);
3179
- $cx++;
3180
-
3181
- break;
3182
- }
3183
- case "+":
3184
- {
3185
- $token["combine"] = "prev-sibling";
3186
- $cx++;
3187
-
3188
- break;
3189
- }
3190
- case ">":
3191
- {
3192
- $token["combine"] = "prev-parent";
3193
- $cx++;
3194
-
3195
- break;
3196
- }
3197
- case "~":
3198
- {
3199
- $token["combine"] = "any-prev-sibling";
3200
- $cx++;
3201
-
3202
- break;
3203
- }
3204
- default:
3205
- {
3206
- $token["combine"] = "any-parent";
3207
-
3208
- break;
3209
- }
3210
- }
3211
-
3212
- if (!count($tokens) || $tokens[count($tokens) - 1]["type"] == "combine") return array("success" => false, "error" => "Invalid combiner '" . $token["type"] . "' detected at position " . $cx . ".", "errorcode" => "invalid_combiner", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
3213
-
3214
- $tokens[] = $token;
3215
-
3216
- // Find a non-whitespace character.
3217
- while ($cx < $cy && ($query[$cx] == " " || $query[$cx] == "\t" || $query[$cx] == "\r" || $query[$cx] == "\n" || $query[$cx] == "\f")) $cx++;
3218
- }
3219
-
3220
- $state = "next_selector";
3221
-
3222
- break;
3223
- }
3224
- }
3225
- } while ($currstate !== $state || $currcx !== $cx);
3226
-
3227
- return array("success" => true, "selector" => $query, "tokens" => self::ReorderSelectorTokens($tokens, $splitrules), "splitrules" => $splitrules);
3228
- }
3229
-
3230
- public static function GetParentPos($stack, $tagname, $start = 0, $attrs = array())
3231
- {
3232
- $y = count($stack);
3233
- for ($x = $start; $x < $y; $x++)
3234
- {
3235
- if ($stack[$x]["tag_name"] === $tagname)
3236
- {
3237
- $found = true;
3238
- foreach ($attrs as $key => $val)
3239
- {
3240
- if (!isset($stack[$x]["attrs"][$key])) $found = false;
3241
- else if (is_string($stack[$x]["attrs"][$key]) && is_string($val) && stripos($stack[$x]["attrs"][$key], $val) === false) $found = false;
3242
- else if (is_array($stack[$x]["attrs"][$key]))
3243
- {
3244
- if (is_string($val)) $val = explode(" ", $val);
3245
-
3246
- foreach ($val as $val2)
3247
- {
3248
- if ($val2 !== "" && !isset($stack[$x]["attrs"][$key][$val2])) $found = false;
3249
- }
3250
- }
3251
- }
3252
-
3253
- if ($found) return $x;
3254
- }
3255
- }
3256
-
3257
- return false;
3258
- }
3259
- }
3260
  ?>
1
+ <?php
2
+ // CubicleSoft PHP Tag Filter class. Can repair broken HTML.
3
+ // (C) 2020 CubicleSoft. All Rights Reserved.
4
+
5
+ class TagFilterStream
6
+ {
7
+ protected $lastcontent, $lastresult, $final, $options, $stack;
8
+
9
+ public function __construct($options = array())
10
+ {
11
+ $this->Init($options);
12
+ }
13
+
14
+ public function Init($options = array())
15
+ {
16
+ if (!isset($options["keep_attr_newlines"])) $options["keep_attr_newlines"] = false;
17
+ if (!isset($options["keep_comments"])) $options["keep_comments"] = false;
18
+ if (!isset($options["allow_namespaces"])) $options["allow_namespaces"] = true;
19
+ if (!isset($options["process_attrs"])) $options["process_attrs"] = array();
20
+ if (!isset($options["charset"])) $options["charset"] = "UTF-8";
21
+ $options["charset"] = strtoupper($options["charset"]);
22
+ if (!isset($options["charset_tags"])) $options["charset_tags"] = true;
23
+ if (!isset($options["charset_attrs"])) $options["charset_attrs"] = true;
24
+ if (!isset($options["tag_name_map"])) $options["tag_name_map"] = array();
25
+ if (!isset($options["untouched_tag_attr_keys"])) $options["untouched_tag_attr_keys"] = array();
26
+ if (!isset($options["void_tags"])) $options["void_tags"] = array();
27
+ if (!isset($options["alt_tag_content_rules"])) $options["alt_tag_content_rules"] = array();
28
+ if (!isset($options["pre_close_tags"])) $options["pre_close_tags"] = array();
29
+ if (!isset($options["output_mode"])) $options["output_mode"] = "html";
30
+ if (!isset($options["lowercase_tags"])) $options["lowercase_tags"] = true;
31
+ if (!isset($options["lowercase_attrs"])) $options["lowercase_attrs"] = true;
32
+ $options["tag_num"] = 0;
33
+
34
+ $this->lastcontent = "";
35
+ $this->lastresult = "";
36
+ $this->final = false;
37
+ $this->options = $options;
38
+ $this->stack = array();
39
+ }
40
+
41
+ public function Process($content)
42
+ {
43
+ if ($this->lastcontent !== "") $content = $this->lastcontent . $content;
44
+
45
+ $result = $this->lastresult;
46
+ $this->lastresult = "";
47
+ $tag = false;
48
+ $a = ord("A");
49
+ $a2 = ord("a");
50
+ $f = ord("F");
51
+ $f2 = ord("f");
52
+ $z = ord("Z");
53
+ $z2 = ord("z");
54
+ $hyphen = ord("-");
55
+ $underscore = ord("_");
56
+ $period = ord(".");
57
+ $colon = ord(":");
58
+ $zero = ord("0");
59
+ $nine = ord("9");
60
+ $cx = 0;
61
+ $cy = strlen($content);
62
+ while ($cx < $cy)
63
+ {
64
+ if ($tag)
65
+ {
66
+ $firstcx = $cx;
67
+
68
+ // First character is '<'. Extract all non-alpha chars.
69
+ $prefix = "";
70
+ $startpos = $cx + 1;
71
+ for ($x = $startpos; $x < $cy; $x++)
72
+ {
73
+ $val = ord($content[$x]);
74
+ if (($val >= $a && $val <= $z) || ($val >= $a2 && $val <= $z2))
75
+ {
76
+ if ($x > $cx + 1) $prefix = ltrim(substr($content, $cx + 1, $x - $cx - 1));
77
+ $startpos = $x;
78
+
79
+ break;
80
+ }
81
+ }
82
+
83
+ if ($prefix === "") $open = true;
84
+ else
85
+ {
86
+ if ($prefix[0] === "!")
87
+ {
88
+ // !DOCTYPE vs. comment.
89
+ if (substr($prefix, 0, 3) !== "!--")
90
+ {
91
+ $prefix = "!";
92
+ $open = true;
93
+ }
94
+ else
95
+ {
96
+ // Comment.
97
+ $pos = strpos($content, "!--", $cx);
98
+ $pos2 = strpos($content, "-->", $pos + 3);
99
+ if ($pos2 === false)
100
+ {
101
+ if (!$this->final)
102
+ {
103
+ $cx = $firstcx;
104
+
105
+ break;
106
+ }
107
+
108
+ $pos2 = $cy;
109
+ }
110
+
111
+ if ($this->options["keep_comments"])
112
+ {
113
+ $content2 = substr($content, $pos + 3, $pos2 - $pos - 3);
114
+ if ($this->options["charset"] === "UTF-8" && !self::IsValidUTF8($content2)) $content2 = self::MakeValidUTF8($content2);
115
+ $content2 = "<!-- " . trim(htmlspecialchars($content2, ENT_COMPAT | ENT_HTML5, $this->options["charset"])) . " -->";
116
+
117
+ // Let a callback handle any necessary changes.
118
+ if (isset($this->options["content_callback"]) && is_callable($this->options["content_callback"])) call_user_func_array($this->options["content_callback"], array($this->stack, $result, &$content2, $this->options));
119
+
120
+ $result .= $content2;
121
+ }
122
+ $cx = $pos2 + 3;
123
+
124
+ $tag = false;
125
+
126
+ continue;
127
+ }
128
+ }
129
+ else if ($prefix[0] === "/")
130
+ {
131
+ // Close tag.
132
+ $prefix = "/";
133
+ $open = false;
134
+ }
135
+ else if ($prefix[0] === "<")
136
+ {
137
+ // Stray less than. Encode and reset.
138
+ $content2 = "&lt;";
139
+
140
+ // Let a callback handle any necessary changes.
141
+ if (isset($this->options["content_callback"]) && is_callable($this->options["content_callback"])) call_user_func_array($this->options["content_callback"], array($this->stack, $result, &$content2, $this->options));
142
+
143
+ $result .= $content2;
144
+ $cx++;
145
+
146
+ continue;
147
+ }
148
+ else
149
+ {
150
+ // Unknown. Encode it.
151
+ $data = substr($content, $cx, strpos($content, $prefix, $cx) + strlen($prefix) - $cx);
152
+ $content2 = $data;
153
+ if ($this->options["charset"] === "UTF-8" && !self::IsValidUTF8($content2)) $content2 = self::MakeValidUTF8($content2);
154
+ $content2 = htmlspecialchars($content2, ENT_COMPAT | ENT_HTML5, $this->options["charset"]);
155
+
156
+ // Let a callback handle any necessary changes.
157
+ if (isset($this->options["content_callback"]) && is_callable($this->options["content_callback"])) call_user_func_array($this->options["content_callback"], array($this->stack, $result, &$content2, $this->options));
158
+
159
+ $result .= $content2;
160
+ $cx += strlen($data);
161
+
162
+ $tag = false;
163
+
164
+ continue;
165
+ }
166
+ }
167
+
168
+ // Read the tag name.
169
+ $tagname = "";
170
+ $parse = false;
171
+ $cx = $startpos;
172
+ for (; $cx < $cy; $cx++)
173
+ {
174
+ $val = ord($content[$cx]);
175
+ if ($val > 127) $parse = true;
176
+ else if (!(($val >= $a && $val <= $z) || ($val >= $a2 && $val <= $z2) || ($cx > $startpos && (($val >= $zero && $val <= $nine) || $val == $hyphen || $val == $underscore || $val == $period)) || ($this->options["allow_namespaces"] && $val == $colon))) break;
177
+ }
178
+ $tagname = substr($content, $startpos, $cx - $startpos);
179
+ if ($parse)
180
+ {
181
+ if ($this->options["charset_tags"] && $this->options["charset"] === "UTF-8") $tagname = (self::IsValidUTF8($tagname) ? $tagname : self::MakeValidUTF8($tagname));
182
+ else $tagname = preg_replace(($this->options["allow_namespaces"] ? '/[^A-Za-z0-9:._-]/' : '/[^A-Za-z0-9._-]/'), "", $tagname);
183
+ }
184
+ $tagname = rtrim($tagname, "._-:");
185
+ if (!$this->options["charset_tags"]) $tagname = preg_replace('/[^A-Za-z0-9:]/', "", $tagname);
186
+ $outtagname = ($this->options["lowercase_tags"] ? strtolower($tagname) : $tagname);
187
+ $tagname = strtolower($tagname);
188
+
189
+ // Close open tags in the stack that match the set of tags to look for to close.
190
+ if ($open && isset($this->options["pre_close_tags"][$tagname]))
191
+ {
192
+ // Find matches.
193
+ $info2 = $this->options["pre_close_tags"][$tagname];
194
+ $limit = (isset($info2["_limit"]) ? $info2["_limit"] : array());
195
+ if (is_string($limit)) $limit = array($limit => true);
196
+
197
+ // Unwind the stack.
198
+ do
199
+ {
200
+ $found = false;
201
+ foreach ($this->stack as $info)
202
+ {
203
+ if (isset($info2[$info["tag_name"]]))
204
+ {
205
+ $found = true;
206
+
207
+ break;
208
+ }
209
+
210
+ if (isset($limit[$info["tag_name"]])) break;
211
+ }
212
+
213
+ if ($found)
214
+ {
215
+ do
216
+ {
217
+ // Let a callback handle any necessary changes.
218
+ $attrs = array();
219
+ if (isset($this->options["tag_callback"]) && is_callable($this->options["tag_callback"])) $funcresult = call_user_func_array($this->options["tag_callback"], array($this->stack, &$result, false, "/" . $this->stack[0]["tag_name"], &$attrs, $this->options));
220
+ else $funcresult = array();
221
+
222
+ if (!isset($funcresult["keep_tag"])) $funcresult["keep_tag"] = true;
223
+
224
+ $info = array_shift($this->stack);
225
+
226
+ $result = $info["result"] . ($funcresult["keep_tag"] ? $info["open_tag"] : "") . ($info["keep_interior"] ? $result : "");
227
+ if ($info["close_tag"] && $funcresult["keep_tag"]) $result .= "</" . $info["out_tag_name"] . ">" . $info["post_tag"];
228
+ } while (!isset($info2[$info["tag_name"]]));
229
+ }
230
+ } while ($found);
231
+ }
232
+
233
+ // Process attributes/properties until a closing condition is encountered.
234
+ $state = "name";
235
+ $voidtag = false;
236
+ $attrs = array();
237
+ do
238
+ {
239
+ if ($state === "name")
240
+ {
241
+ // Find attribute key/property.
242
+ for ($x = $cx; $x < $cy; $x++)
243
+ {
244
+ if ($content[$x] === ">" || $content[$x] === "<")
245
+ {
246
+ $cx = $x;
247
+
248
+ $state = "exit";
249
+
250
+ break;
251
+ }
252
+ else if ($content[$x] === "/")
253
+ {
254
+ $pos = strpos($content, ">", $x + 1);
255
+ if ($pos !== false && trim(substr($content, $x + 1, $pos - $x - 1)) === "")
256
+ {
257
+ $cx = $pos;
258
+ $voidtag = true;
259
+
260
+ $state = "exit";
261
+
262
+ break;
263
+ }
264
+ }
265
+ else if ($content[$x] === "\"" || $content[$x] === "'" || $content[$x] === "`")
266
+ {
267
+ $pos = strpos($content, $content[$x], $x + 1);
268
+ if ($pos === false) $content .= $content[$x];
269
+ else if (isset($this->options["untouched_tag_attr_keys"][$tagname]))
270
+ {
271
+ $keyname = substr($content, $x, $pos - $x + 1);
272
+ $cx = $pos + 1;
273
+
274
+ $state = "equals";
275
+ }
276
+ else
277
+ {
278
+ $keyname = substr($content, $x + 1, $pos - $x - 1);
279
+ if ($this->options["lowercase_attrs"]) $keyname = strtolower($keyname);
280
+ if (preg_match('/<\s*\/\s*' . $tagname . '(\s*|\s+.+?)>/is', strtolower($keyname)) || (count($this->stack) && preg_match('/<\s*\/\s*' . $this->stack[0]["tag_name"] . '(\s*|\s+.+?)>/is', strtolower($keyname))))
281
+ {
282
+ // Found a matching close tag within the key name. Bail out.
283
+ $state = "exit";
284
+
285
+ break;
286
+ }
287
+ else
288
+ {
289
+ $keyname = preg_replace('/[^' . ($this->options["lowercase_attrs"] ? "" : "A-Z") . 'a-z' . ($this->options["allow_namespaces"] ? ":" : "") . ']/', "", $keyname);
290
+ if ($this->options["allow_namespaces"]) $keyname = rtrim($keyname, ":");
291
+ $cx = $pos + 1;
292
+
293
+ $state = "equals";
294
+ }
295
+ }
296
+
297
+ break;
298
+ }
299
+ else
300
+ {
301
+ $val = ord($content[$x]);
302
+ if (($val >= $a && $val <= $z) || ($val >= $a2 && $val <= $z2))
303
+ {
304
+ $cx = $x;
305
+ $parse = false;
306
+
307
+ for (; $cx < $cy; $cx++)
308
+ {
309
+ if ($content[$cx] === " " || $content[$cx] === "=" || $content[$cx] === "\"" || $content[$cx] === "'" || $content[$cx] === "`" || $content[$cx] === ">" || $content[$cx] === "<" || $content[$cx] === "/" || $content[$cx] === "\0" || $content[$cx] === "\r" || $content[$cx] === "\n" || $content[$cx] === "\t") break;
310
+ else if (ord($content[$cx]) > 127) $parse = true;
311
+ }
312
+
313
+ $keyname = substr($content, $x, $cx - $x);
314
+ if ($parse && $this->options["charset_attrs"] && $this->options["charset"] === "UTF-8")
315
+ {
316
+ $keyname = preg_replace(($this->options["allow_namespaces"] ? '/[^A-Za-z0-9:._\-\x80-\xFF]/' : '/[^A-Za-z0-9._\-\x80-\xFF]/'), "", $keyname);
317
+ if (!self::IsValidUTF8($keyname)) $keyname = self::MakeValidUTF8($keyname);
318
+ }
319
+ else
320
+ {
321
+ $keyname = preg_replace(($this->options["allow_namespaces"] ? '/[^A-Za-z0-9:._-]/' : '/[^A-Za-z0-9._-]/'), "", $keyname);
322
+ }
323
+ $keyname = rtrim($keyname, "._-:");
324
+ if (!isset($this->options["untouched_tag_attr_keys"][$tagname]) && $this->options["lowercase_attrs"]) $keyname = strtolower($keyname);
325
+
326
+ $state = "equals";
327
+
328
+ break;
329
+ }
330
+ }
331
+ }
332
+
333
+ if ($state === "name")
334
+ {
335
+ $cx = $cy;
336
+
337
+ $state = "exit";
338
+ }
339
+ }
340
+ else if ($state === "equals")
341
+ {
342
+ // Find the equals sign OR the start of the next attribute/property.
343
+ for ($x = $cx; $x < $cy; $x++)
344
+ {
345
+ if ($content[$x] === ">" || $content[$x] === "<")
346
+ {
347
+ $cx = $x;
348
+
349
+ $attrs[$keyname] = true;
350
+
351
+ $state = "exit";
352
+
353
+ break;
354
+ }
355
+ else if ($content[$x] === "=")
356
+ {
357
+ $cx = $x + 1;
358
+
359
+ $state = "value";
360
+
361
+ break;
362
+ }
363
+ else if ($content[$x] === "\"" || $content[$x] === "'")
364
+ {
365
+ $cx = $x;
366
+
367
+ $attrs[$keyname] = true;
368
+
369
+ $state = "name";
370
+
371
+ break;
372
+ }
373
+ else
374
+ {
375
+ $val = ord($content[$x]);
376
+ if (($val >= $a && $val <= $z) || ($val >= $a2 && $val <= $z2) || ($val >= $zero && $val <= $nine))
377
+ {
378
+ $cx = $x;
379
+
380
+ $attrs[$keyname] = true;
381
+
382
+ $state = "name";
383
+
384
+ break;
385
+ }
386
+ }
387
+ }
388
+
389
+ if ($state === "equals")
390
+ {
391
+ $cx = $cy;
392
+
393
+ $attrs[$keyname] = true;
394
+
395
+ $state = "exit";
396
+ }
397
+ }
398
+ else if ($state === "value")
399
+ {
400
+ for ($x = $cx; $x < $cy; $x++)
401
+ {
402
+ if ($content[$x] === ">" || $content[$x] === "<")
403
+ {
404
+ $cx = $x;
405
+
406
+ $attrs[$keyname] = true;
407
+
408
+ $state = "exit";
409
+
410
+ break;
411
+ }
412
+ else if ($content[$x] === "\"" || $content[$x] === "'" || $content[$x] === "`")
413
+ {
414
+ $pos = strpos($content, $content[$x], $x + 1);
415
+ if ($pos === false) $content .= $content[$x];
416
+ else
417
+ {
418
+ $value = substr($content, $x + 1, $pos - $x - 1);
419
+ $cx = $pos + 1;
420
+
421
+ $state = "name";
422
+ }
423
+
424
+ break;
425
+ }
426
+ else if ($content[$x] !== "\0" && $content[$x] !== "\r" && $content[$x] !== "\n" && $content[$x] !== "\t" && $content[$x] !== " ")
427
+ {
428
+ $cx = $x;
429
+
430
+ for (; $cx < $cy; $cx++)
431
+ {
432
+ if ($content[$cx] === "\0" || $content[$cx] === "\r" || $content[$cx] === "\n" || $content[$cx] === "\t" || $content[$cx] === " " || $content[$cx] === "<" || $content[$cx] === ">")
433
+ {
434
+ break;
435
+ }
436
+ }
437
+
438
+ $value = substr($content, $x, $cx - $x);
439
+
440
+ $state = "name";
441
+
442
+ break;
443
+ }
444
+ }
445
+
446
+ if ($state === "value")
447
+ {
448
+ $cx = $cy;
449
+
450
+ $attrs[$keyname] = true;
451
+
452
+ $state = "exit";
453
+ }
454
+
455
+ if ($state === "name")
456
+ {
457
+ if ($this->options["charset"] === "UTF-8" && !self::IsValidUTF8($value)) $value = self::MakeValidUTF8($value);
458
+ $value = html_entity_decode($value, ENT_QUOTES | ENT_HTML5, $this->options["charset"]);
459
+
460
+ // Decode remaining entities.
461
+ $value2 = "";
462
+ $vx = 0;
463
+ $vy = strlen($value);
464
+ while ($vx < $vy)
465
+ {
466
+ $pos = strpos($value, "&#", $vx);
467
+ $pos2 = strpos($value, "\\", $vx);
468
+ if ($pos === false) $pos = $vy;
469
+ if ($pos2 === false) $pos2 = $vy;
470
+ if ($pos < $pos2)
471
+ {
472
+ // &#32 or &#x20 (optional trailing semi-colon)
473
+ $value2 .= substr($value, $vx, $pos - $vx);
474
+ $vx = $pos + 2;
475
+ if ($vx < $vy)
476
+ {
477
+ if ($value[$vx] == "x" || $value[$vx] == "X")
478
+ {
479
+ $vx++;
480
+ if ($vx < $vy)
481
+ {
482
+ for ($x = $vx; $x < $vy; $x++)
483
+ {
484
+ $val = ord($value[$x]);
485
+ if (!(($val >= $a && $val <= $f) || ($val >= $a2 && $val <= $f2) || ($val >= $zero && $val <= $nine))) break;
486
+ }
487
+
488
+ $num = hexdec(substr($value, $vx, $x - $vx));
489
+ $vx = $x;
490
+ if ($vx < $vy && $value[$vx] == ";") $vx++;
491
+
492
+ $value2 .= self::UTF8Chr($num);
493
+ }
494
+ }
495
+ else
496
+ {
497
+ for ($x = $vx; $x < $vy; $x++)
498
+ {
499
+ $val = ord($value[$x]);
500
+ if (!($val >= $zero && $val <= $nine)) break;
501
+ }
502
+
503
+ $num = (int)substr($value, $vx, $x - $vx);
504
+ $vx = $x;
505
+ if ($vx < $vy && $value[$vx] == ";") $vx++;
506
+
507
+ $value2 .= self::UTF8Chr($num);
508
+ }
509
+ }
510
+ }
511
+ else if ($pos2 < $pos)
512
+ {
513
+ // Unicode (e.g. \0020)
514
+ $value2 .= substr($value, $vx, $pos2 - $vx);
515
+ $vx = $pos2 + 1;
516
+ if ($vx >= $vy) $value2 .= "\\";
517
+ else
518
+ {
519
+ for ($x = $vx; $x < $vy; $x++)
520
+ {
521
+ $val = ord($value[$x]);
522
+ if (!(($val >= $a && $val <= $f) || ($val >= $a2 && $val <= $f2) || ($val >= $zero && $val <= $nine))) break;
523
+ }
524
+
525
+ if ($x > $vx)
526
+ {
527
+ $num = hexdec(substr($value, $vx, $x - $vx));
528
+ $vx = $x;
529
+
530
+ $value2 .= self::UTF8Chr($num);
531
+ }
532
+ else
533
+ {
534
+ $value2 .= "\\";
535
+ }
536
+ }
537
+ }
538
+ else
539
+ {
540
+ $value2 .= substr($value, $vx);
541
+ $vx = $vy;
542
+ }
543
+ }
544
+ $value = $value2;
545
+
546
+ if (!$this->options["keep_attr_newlines"]) $value = str_replace(array("\r\n", "\r", "\n"), " ", $value);
547
+
548
+ if (isset($this->options["process_attrs"][$keyname]))
549
+ {
550
+ $type = $this->options["process_attrs"][$keyname];
551
+ if ($type === "classes")
552
+ {
553
+ $classes = explode(" ", $value);
554
+ $value = array();
555
+ foreach ($classes as $class)
556
+ {
557
+ if ($class !== "") $value[$class] = $class;
558
+ }
559
+ }
560
+ else if ($type === "uri")
561
+ {
562
+ $value = str_replace(array("\0", "\r", "\n", "\t", " "), "", $value);
563
+ $pos = strpos($value, ":");
564
+ if ($pos !== false) $value = preg_replace('/[^a-z]/', "", strtolower(substr($value, 0, $pos))) . substr($value, $pos);
565
+ }
566
+ }
567
+
568
+ $attrs[$keyname] = $value;
569
+ }
570
+ }
571
+ } while ($cx < $cy && $state !== "exit");
572
+
573
+ // Break out of the loop if the end of the stream has been reached but not finalized and most likely in the middle of a tag.
574
+ if ($cx >= $cy && !$this->final)
575
+ {
576
+ $cx = $firstcx;
577
+
578
+ break;
579
+ }
580
+
581
+ unset($attrs[""]);
582
+
583
+ if ($cx < $cy && $content[$cx] === ">") $cx++;
584
+
585
+ if (isset($this->options["tag_name_map"][$prefix . $tagname])) $outtagname = $tagname = $this->options["tag_name_map"][$prefix . $tagname];
586
+
587
+ if ($tagname != "")
588
+ {
589
+ if ($open)
590
+ {
591
+ if ($voidtag && isset($this->options["void_tags"][$tagname])) $voidtag = false;
592
+ $this->options["tag_num"]++;
593
+
594
+ // Let a callback handle any necessary changes.
595
+ if (isset($this->options["tag_callback"]) && is_callable($this->options["tag_callback"])) $funcresult = call_user_func_array($this->options["tag_callback"], array($this->stack, &$result, $open, $prefix . $tagname, &$attrs, $this->options));
596
+ else $funcresult = array();
597
+
598
+ if (!isset($funcresult["keep_tag"])) $funcresult["keep_tag"] = true;
599
+ if (!isset($funcresult["keep_interior"])) $funcresult["keep_interior"] = true;
600
+ if (!isset($funcresult["pre_tag"])) $funcresult["pre_tag"] = "";
601
+ if (!isset($funcresult["post_tag"])) $funcresult["post_tag"] = "";
602
+ if (!isset($funcresult["state"])) $funcresult["state"] = false;
603
+ }
604
+
605
+ if ($open && $funcresult["keep_tag"])
606
+ {
607
+ $opentag = $funcresult["pre_tag"];
608
+ $opentag .= "<" . $prefix . $outtagname;
609
+ foreach ($attrs as $key => $val)
610
+ {
611
+ $opentag .= " " . $key;
612
+
613
+ if (is_array($val)) $val = implode(" ", $val);
614
+ if (is_string($val))
615
+ {
616
+ if ($this->options["charset"] === "UTF-8" && !self::IsValidUTF8($val)) $val = self::MakeValidUTF8($val);
617
+ $opentag .= "=\"" . htmlspecialchars($val, ENT_COMPAT | ENT_HTML5, $this->options["charset"]) . "\"";
618
+ }
619
+ }
620
+ if (($voidtag || isset($this->options["void_tags"][$tagname])) && $this->options["output_mode"] === "xml")
621
+ {
622
+ $opentag .= " /";
623
+
624
+ $voidtag = false;
625
+ }
626
+ $opentag .= ">";
627
+
628
+ if (!isset($this->options["void_tags"][$tagname]) && $prefix === "")
629
+ {
630
+ array_unshift($this->stack, array("tag_num" => $this->options["tag_num"], "tag_name" => $tagname, "out_tag_name" => $outtagname, "attrs" => $attrs, "result" => $result, "open_tag" => $opentag, "close_tag" => true, "keep_interior" => $funcresult["keep_interior"], "post_tag" => $funcresult["post_tag"], "state" => $funcresult["state"]));
631
+ $result = "";
632
+
633
+ if ($voidtag) $open = false;
634
+ }
635
+ else
636
+ {
637
+ $result .= $opentag;
638
+ $result .= $funcresult["post_tag"];
639
+ }
640
+ }
641
+
642
+ if ((!$open || !$funcresult["keep_tag"]) && !isset($this->options["void_tags"][$tagname]))
643
+ {
644
+ if ($open)
645
+ {
646
+ array_unshift($this->stack, array("tag_num" => $this->options["tag_num"], "tag_name" => $tagname, "out_tag_name" => $outtagname, "attrs" => $attrs, "result" => $result, "open_tag" => "", "close_tag" => false, "keep_interior" => $funcresult["keep_interior"], "post_tag" => $funcresult["post_tag"], "state" => $funcresult["state"]));
647
+ $result = "";
648
+ }
649
+
650
+ if (!$open)
651
+ {
652
+ $found = false;
653
+ foreach ($this->stack as $info)
654
+ {
655
+ if ($tagname === $info["tag_name"])
656
+ {
657
+ $found = true;
658
+
659
+ break;
660
+ }
661
+ }
662
+
663
+ if ($found)
664
+ {
665
+ do
666
+ {
667
+ // Let a callback handle any necessary changes.
668
+ $attrs = array();
669
+ if (isset($this->options["tag_callback"]) && is_callable($this->options["tag_callback"])) $funcresult = call_user_func_array($this->options["tag_callback"], array($this->stack, &$result, false, "/" . $this->stack[0]["tag_name"], &$attrs, $this->options));
670
+ else $funcresult = array();
671
+
672
+ // Force close tag to be kept if the stream already output the open tag.
673
+ if (!isset($funcresult["keep_tag"]) || ($info["close_tag"] && $info["open_tag"] == "")) $funcresult["keep_tag"] = true;
674
+
675
+ $info = array_shift($this->stack);
676
+
677
+ $result = $info["result"] . ($funcresult["keep_tag"] ? $info["open_tag"] : "") . ($info["keep_interior"] ? $result : "");
678
+ if ($info["close_tag"] && $funcresult["keep_tag"]) $result .= "</" . $info["out_tag_name"] . ">" . $info["post_tag"];
679
+ } while ($tagname !== $info["tag_name"]);
680
+ }
681
+ }
682
+ }
683
+ }
684
+
685
+ //echo "Current output:\n" . $result . "\n\n";
686
+ //echo "Prefix: " . $prefix . "\n\n";
687
+ //echo "Tag: " . $tagname . "\n\n";
688
+ //echo "Attrs:\n";
689
+ //var_dump($attrs);
690
+ //
691
+ //echo "Tag stack:\n";
692
+ //var_dump($this->stack);
693
+ //
694
+ //echo "\n\n";
695
+ //echo $content . "\n";
696
+ //exit();
697
+
698
+ $tag = false;
699
+ }
700
+ else
701
+ {
702
+ $regular = true;
703
+
704
+ // Special content handler for certain tags.
705
+ if (count($this->stack) && isset($this->options["alt_tag_content_rules"][$this->stack[0]["tag_name"]]) && is_callable($this->options["alt_tag_content_rules"][$this->stack[0]["tag_name"]]))
706
+ {
707
+ $content2 = "";
708
+
709
+ // Expected to return true until the function is no longer interested in the data.
710
+ if (call_user_func_array($this->options["alt_tag_content_rules"][$this->stack[0]["tag_name"]], array($this->stack, $this->final, &$tag, &$content, &$cx, $cy, &$content2, $this->options))) $regular = false;
711
+ else if (!$this->final)
712
+ {
713
+ // Let a callback handle any necessary changes.
714
+ if (isset($this->options["content_callback"]) && is_callable($this->options["content_callback"])) call_user_func_array($this->options["content_callback"], array($this->stack, $result, &$content2, $this->options));
715
+
716
+ $result .= $content2;
717
+
718
+ break;
719
+ }
720
+ }
721
+
722
+ if ($regular)
723
+ {
724
+ // Regular content.
725
+ $pos = strpos($content, "<", $cx);
726
+ if ($pos === false)
727
+ {
728
+ $content2 = str_replace(">", "&gt;", substr($content, $cx));
729
+ $cx = $cy;
730
+ }
731
+ else
732
+ {
733
+ $content2 = str_replace(">", "&gt;", substr($content, $cx, $pos - $cx));
734
+ $cx = $pos;
735
+
736
+ $tag = true;
737
+ }
738
+ }
739
+
740
+ // Let a callback handle any necessary changes.
741
+ if (isset($this->options["content_callback"]) && is_callable($this->options["content_callback"])) call_user_func_array($this->options["content_callback"], array($this->stack, $result, &$content2, $this->options));
742
+
743
+ $result .= $content2;
744
+ }
745
+ }
746
+
747
+ if ($this->final)
748
+ {
749
+ while (count($this->stack))
750
+ {
751
+ // Let a callback handle any necessary changes.
752
+ $attrs = array();
753
+ if (isset($this->options["tag_callback"]) && is_callable($this->options["tag_callback"])) $funcresult = call_user_func_array($this->options["tag_callback"], array($this->stack, &$result, false, "/" . $this->stack[0]["tag_name"], &$attrs, $this->options));
754
+ else $funcresult = array();
755
+
756
+ $info = array_shift($this->stack);
757
+
758
+ // Force close tag to be kept if the stream already output the open tag.
759
+ if (!isset($funcresult["keep_tag"]) || ($info["close_tag"] && $info["open_tag"] == "")) $funcresult["keep_tag"] = true;
760
+
761
+ $result = $info["result"] . ($funcresult["keep_tag"] ? $info["open_tag"] : "") . ($info["keep_interior"] ? $result : "");
762
+ if ($info["close_tag"] && $funcresult["keep_tag"]) $result .= "</" . $info["out_tag_name"] . ">" . $info["post_tag"];
763
+ }
764
+ }
765
+ else
766
+ {
767
+ $this->lastcontent = ($cx < $cy ? substr($content, $cx) : "");
768
+ $this->lastresult = $result;
769
+ $result = "";
770
+ }
771
+
772
+ return $result;
773
+ }
774
+
775
+ public function Finalize()
776
+ {
777
+ $this->final = true;
778
+ }
779
+
780
+ // To cleanly figure out how far in to flush output, call GetStack(true), use TagFilter::GetParentPos(), and call GetResult().
781
+ public function GetStack($invert = false)
782
+ {
783
+ return ($invert ? array_reverse($this->stack) : $this->stack);
784
+ }
785
+
786
+ // Returns the result so far up to the specified stack position and flushes the stored output to keep RAM usage low.
787
+ // NOTE: Callback functions returning 'keep_tag' of false for the closing tag won't work for tags that were already output using this function.
788
+ public function GetResult($invertedstackpos)
789
+ {
790
+ $y = count($this->stack);
791
+ $pos = $y - $invertedstackpos - 1;
792
+ if ($pos < 0) $pos = 0;
793
+
794
+ $result = "";
795
+ for ($x = $y - 1; $x >= $pos; $x--)
796
+ {
797
+ $result .= $this->stack[$x]["result"] . $this->stack[$x]["open_tag"];
798
+
799
+ $this->stack[$x]["result"] = "";
800
+ $this->stack[$x]["open_tag"] = "";
801
+ }
802
+
803
+ if (!$pos)
804
+ {
805
+ $result .= $this->lastresult;
806
+ $this->lastresult = "";
807
+ }
808
+
809
+ return $result;
810
+ }
811
+
812
+ public static function MakeValidUTF8($data)
813
+ {
814
+ $result = "";
815
+ $x = 0;
816
+ $y = strlen($data);
817
+ while ($x < $y)
818
+ {
819
+ $tempchr = ord($data[$x]);
820
+ if ($y - $x > 1) $tempchr2 = ord($data[$x + 1]);
821
+ else $tempchr2 = 0x00;
822
+ if ($y - $x > 2) $tempchr3 = ord($data[$x + 2]);
823
+ else $tempchr3 = 0x00;
824
+ if ($y - $x > 3) $tempchr4 = ord($data[$x + 3]);
825
+ else $tempchr4 = 0x00;
826
+ if (($tempchr >= 0x20 && $tempchr <= 0x7E) || $tempchr == 0x09 || $tempchr == 0x0A || $tempchr == 0x0D)
827
+ {
828
+ // ASCII minus control and special characters.
829
+ $result .= chr($tempchr);
830
+ $x++;
831
+ }
832
+ else if (($tempchr >= 0xC2 && $tempchr <= 0xDF) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF))
833
+ {
834
+ // Non-overlong (2 bytes).
835
+ $result .= chr($tempchr);
836
+ $result .= chr($tempchr2);
837
+ $x += 2;
838
+ }
839
+ else if ($tempchr == 0xE0 && ($tempchr2 >= 0xA0 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF))
840
+ {
841
+ // Non-overlong (3 bytes).
842
+ $result .= chr($tempchr);
843
+ $result .= chr($tempchr2);
844
+ $result .= chr($tempchr3);
845
+ $x += 3;
846
+ }
847
+ else if ((($tempchr >= 0xE1 && $tempchr <= 0xEC) || $tempchr == 0xEE || $tempchr == 0xEF) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF))
848
+ {
849
+ // Normal/straight (3 bytes).
850
+ $result .= chr($tempchr);
851
+ $result .= chr($tempchr2);
852
+ $result .= chr($tempchr3);
853
+ $x += 3;
854
+ }
855
+ else if ($tempchr == 0xED && ($tempchr2 >= 0x80 && $tempchr2 <= 0x9F) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF))
856
+ {
857
+ // Non-surrogates (3 bytes).
858
+ $result .= chr($tempchr);
859
+ $result .= chr($tempchr2);
860
+ $result .= chr($tempchr3);
861
+ $x += 3;
862
+ }
863
+ else if ($tempchr == 0xF0 && ($tempchr2 >= 0x90 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF) && ($tempchr4 >= 0x80 && $tempchr4 <= 0xBF))
864
+ {
865
+ // Planes 1-3 (4 bytes).
866
+ $result .= chr($tempchr);
867
+ $result .= chr($tempchr2);
868
+ $result .= chr($tempchr3);
869
+ $result .= chr($tempchr4);
870
+ $x += 4;
871
+ }
872
+ else if (($tempchr >= 0xF1 && $tempchr <= 0xF3) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF) && ($tempchr4 >= 0x80 && $tempchr4 <= 0xBF))
873
+ {
874
+ // Planes 4-15 (4 bytes).
875
+ $result .= chr($tempchr);
876
+ $result .= chr($tempchr2);
877
+ $result .= chr($tempchr3);
878
+ $result .= chr($tempchr4);
879
+ $x += 4;
880
+ }
881
+ else if ($tempchr == 0xF4 && ($tempchr2 >= 0x80 && $tempchr2 <= 0x8F) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF) && ($tempchr4 >= 0x80 && $tempchr4 <= 0xBF))
882
+ {
883
+ // Plane 16 (4 bytes).
884
+ $result .= chr($tempchr);
885
+ $result .= chr($tempchr2);
886
+ $result .= chr($tempchr3);
887
+ $result .= chr($tempchr4);
888
+ $x += 4;
889
+ }
890
+ else $x++;
891
+ }
892
+
893
+ return $result;
894
+ }
895
+
896
+ public static function IsValidUTF8($data)
897
+ {
898
+ $x = 0;
899
+ $y = strlen($data);
900
+ while ($x < $y)
901
+ {
902
+ $tempchr = ord($data[$x]);
903
+ if (($tempchr >= 0x20 && $tempchr <= 0x7E) || $tempchr == 0x09 || $tempchr == 0x0A || $tempchr == 0x0D) $x++;
904
+ else if ($tempchr < 0xC2) return false;
905
+ else
906
+ {
907
+ $left = $y - $x;
908
+ if ($left > 1) $tempchr2 = ord($data[$x + 1]);
909
+ else return false;
910
+
911
+ if (($tempchr >= 0xC2 && $tempchr <= 0xDF) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF)) $x += 2;
912
+ else
913
+ {
914
+ if ($left > 2) $tempchr3 = ord($data[$x + 2]);
915
+ else return false;
916
+
917
+ if ($tempchr3 < 0x80 || $tempchr3 > 0xBF) return false;
918
+
919
+ if ($tempchr == 0xE0 && ($tempchr2 >= 0xA0 && $tempchr2 <= 0xBF)) $x += 3;
920
+ else if ((($tempchr >= 0xE1 && $tempchr <= 0xEC) || $tempchr == 0xEE || $tempchr == 0xEF) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF)) $x += 3;
921
+ else if ($tempchr == 0xED && ($tempchr2 >= 0x80 && $tempchr2 <= 0x9F)) $x += 3;
922
+ else
923
+ {
924
+ if ($left > 3) $tempchr4 = ord($data[$x + 3]);
925
+ else return false;
926
+
927
+ if ($tempchr4 < 0x80 || $tempchr4 > 0xBF) return false;
928
+
929
+ if ($tempchr == 0xF0 && ($tempchr2 >= 0x90 && $tempchr2 <= 0xBF)) $x += 4;
930
+ else if (($tempchr >= 0xF1 && $tempchr <= 0xF3) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF)) $x += 4;
931
+ else if ($tempchr == 0xF4 && ($tempchr2 >= 0x80 && $tempchr2 <= 0x8F)) $x += 4;
932
+ else return false;
933
+ }
934
+ }
935
+ }
936
+ }
937
+
938
+ return true;
939
+ }
940
+
941
+ public static function UTF8Chr($num)
942
+ {
943
+ if ($num < 0 || ($num >= 0xD800 && $num <= 0xDFFF) || ($num >= 0xFDD0 && $num <= 0xFDEF) || ($num & 0xFFFE) == 0xFFFE) return "";
944
+
945
+ if ($num <= 0x7F) $result = chr($num);
946
+ else if ($num <= 0x7FF) $result = chr(0xC0 | ($num >> 6)) . chr(0x80 | ($num & 0x3F));
947
+ else if ($num <= 0xFFFF) $result = chr(0xE0 | ($num >> 12)) . chr(0x80 | (($num >> 6) & 0x3F)) . chr(0x80 | ($num & 0x3F));
948
+ else if ($num <= 0x10FFFF) $result = chr(0xF0 | ($num >> 18)) . chr(0x80 | (($num >> 12) & 0x3F)) . chr(0x80 | (($num >> 6) & 0x3F)) . chr(0x80 | ($num & 0x3F));
949
+ else $result = "";
950
+
951
+ return $result;
952
+ }
953
+ }
954
+
955
+ // Accessing the data in TagFilterNodes (with an 's') via objects is not the most performance-friendly method of access.
956
+ // The classes TagFilterNode and TagFilterNodeIterator defer method calls to the referenced TagFilterNodes instance.
957
+ // Removed/replaced nodes in the original data will result in undefined behavior with object reuse.
958
+ class TagFilterNode
959
+ {
960
+ private $tfn, $id;
961
+
962
+ public function __construct($tfn, $rootid)
963
+ {
964
+ $this->tfn = $tfn;
965
+ $this->id = $rootid;
966
+ }
967
+
968
+ public function __get($key)
969
+ {
970
+ return (isset($this->tfn->nodes[$this->id]) && isset($this->tfn->nodes[$this->id]["attrs"]) && isset($this->tfn->nodes[$this->id]["attrs"][$key]) ? $this->tfn->nodes[$this->id]["attrs"][$key] : false);
971
+ }
972
+
973
+ public function __set($key, $val)
974
+ {
975
+ if (isset($this->tfn->nodes[$this->id]) && isset($this->tfn->nodes[$this->id]["attrs"]))
976
+ {
977
+ if (is_array($val)) $this->tfn->nodes[$this->id]["attrs"][$key] = $val;
978
+ else if (isset($this->tfn->nodes[$this->id]["attrs"][$key]) && is_array($this->tfn->nodes[$this->id]["attrs"][$key])) $this->tfn->nodes[$this->id]["attrs"][$key][(string)$val] = (string)$val;
979
+ else $this->tfn->nodes[$this->id]["attrs"][$key] = (string)$val;
980
+ }
981
+ }
982
+
983
+ public function __isset($key)
984
+ {
985
+ return (isset($this->tfn->nodes[$this->id]) && isset($this->tfn->nodes[$this->id]["attrs"]) && isset($this->tfn->nodes[$this->id]["attrs"][$key]));
986
+ }
987
+
988
+ public function __unset($key)
989
+ {
990
+ if (isset($this->tfn->nodes[$this->id]) && isset($this->tfn->nodes[$this->id]["attrs"])) unset($this->tfn->nodes[$this->id]["attrs"][$key]);
991
+ }
992
+
993
+ public function __toString()
994
+ {
995
+ return $this->tfn->GetOuterHTML($this->id);
996
+ }
997
+
998
+ public function __debugInfo()
999
+ {
1000
+ $result = (isset($this->tfn->nodes[$this->id]) ? $this->tfn->nodes[$this->id] : array());
1001
+ $result["id"] = $this->id;
1002
+
1003
+ return $result;
1004
+ }
1005
+
1006
+ public function ID()
1007
+ {
1008
+ return $this->id;
1009
+ }
1010
+
1011
+ public function Node()
1012
+ {
1013
+ return (isset($this->tfn->nodes[$this->id]) ? $this->tfn->nodes[$this->id] : false);
1014
+ }
1015
+
1016
+ public function Type()
1017
+ {
1018
+ return (isset($this->tfn->nodes[$this->id]) ? $this->tfn->nodes[$this->id]["type"] : false);
1019
+ }
1020
+
1021
+ public function Tag()
1022
+ {
1023
+ return $this->tfn->GetTag($this->id);
1024
+ }
1025
+
1026
+ public function Text($val = null)
1027
+ {
1028
+ if ($val !== null) $this->tfn->SetText($this->id, $val);
1029
+ else return $this->tfn->GetText($this->id);
1030
+ }
1031
+
1032
+ public function AddClass($name, $attr = "class")
1033
+ {
1034
+ if (isset($this->tfn->nodes[$this->id]) && isset($this->tfn->nodes[$this->id]["attrs"]))
1035
+ {
1036
+ if (!isset($this->tfn->nodes[$this->id]["attrs"][$attr]) || !is_array($this->tfn->nodes[$this->id]["attrs"][$attr])) $this->tfn->nodes[$this->id]["attrs"][$attr] = array();
1037
+
1038
+ $this->tfn->nodes[$this->id]["attrs"][$attr][$name] = $name;
1039
+ }
1040
+ }
1041
+
1042
+ public function RemoveClass($name, $attr = "class")
1043
+ {
1044
+ if (isset($this->tfn->nodes[$this->id]) && isset($this->tfn->nodes[$this->id]["attrs"]))
1045
+ {
1046
+ if (isset($this->tfn->nodes[$this->id]["attrs"][$attr]) && is_array($this->tfn->nodes[$this->id]["attrs"][$attr])) unset($this->tfn->nodes[$this->id]["attrs"][$attr][$name]);
1047
+ }
1048
+ }
1049
+
1050
+ public function Parent()
1051
+ {
1052
+ return $this->tfn->GetParent($this->id);
1053
+ }
1054
+
1055
+ public function ParentPos()
1056
+ {
1057
+ return (isset($this->tfn->nodes[$this->id]) ? $this->tfn->nodes[$this->id]["parentpos"] : false);
1058
+ }
1059
+
1060
+ // Passing true to this method has the potential to leak RAM. Passing false is preferred, use with caution.
1061
+ public function Children($objects = false)
1062
+ {
1063
+ return $this->tfn->GetChildren($this->id, $objects);
1064
+ }
1065
+
1066
+ public function Child($pos)
1067
+ {
1068
+ return $this->tfn->GetChild($this->id, $pos);
1069
+ }
1070
+
1071
+ public function PrevSibling()
1072
+ {
1073
+ return $this->tfn->GetPrevSibling($this->id);
1074
+ }
1075
+
1076
+ public function NextSibling()
1077
+ {
1078
+ return $this->tfn->GetNextSibling($this->id);
1079
+ }
1080
+
1081
+ public function Find($query, $cachequery = true, $firstmatch = false)
1082
+ {
1083
+ $result = $this->tfn->Find($query, $this->id, $cachequery, $firstmatch);
1084
+ if (!$result["success"]) return $result;
1085
+
1086
+ return new TagFilterNodeIterator($this->tfn, $result["ids"]);
1087
+ }
1088
+
1089
+ public function Implode($options = array())
1090
+ {
1091
+ return $this->tfn->Implode($this->id, $options);
1092
+ }
1093
+
1094
+ public function GetOuterHTML($mode = "html")
1095
+ {
1096
+ return $this->tfn->GetOuterHTML($this->id, $mode);
1097
+ }
1098
+
1099
+ // Set functions ruin the object.
1100
+ public function SetOuterHTML($src)
1101
+ {
1102
+ return $this->tfn->SetOuterHTML($this->id, $src);
1103
+ }
1104
+
1105
+ public function GetInnerHTML($mode = "html")
1106
+ {
1107
+ return $this->tfn->GetInnerHTML($this->id, $mode);
1108
+ }
1109
+
1110
+ public function SetInnerHTML($src)
1111
+ {
1112
+ return $this->tfn->SetInnerHTML($this->id, $src);
1113
+ }
1114
+
1115
+ public function GetPlainText()
1116
+ {
1117
+ return $this->tfn->GetPlainText($this->id);
1118
+ }
1119
+
1120
+ // Set functions ruin the object.
1121
+ public function SetPlainText($src)
1122
+ {
1123
+ return $this->tfn->SetPlainText($this->id, $src);
1124
+ }
1125
+ }
1126
+
1127
+ class TagFilterNodeIterator implements Iterator, Countable
1128
+ {
1129
+ private $tfn, $ids, $x, $y;
1130
+
1131
+ public function __construct($tfn, $ids)
1132
+ {
1133
+ $this->tfn = $tfn;
1134
+ $this->ids = $ids;
1135
+ $this->x = 0;
1136
+ $this->y = count($ids);
1137
+ }
1138
+
1139
+ public function rewind()
1140
+ {
1141
+ $this->x = 0;
1142
+ }
1143
+
1144
+ public function valid()
1145
+ {
1146
+ return ($this->x < $this->y);
1147
+ }
1148
+
1149
+ public function current()
1150
+ {
1151
+ return $this->tfn->Get($this->ids[$this->x]);
1152
+ }
1153
+
1154
+ public function key()
1155
+ {
1156
+ return $this->ids[$this->x];
1157
+ }
1158
+
1159
+ public function next()
1160
+ {
1161
+ $this->x++;
1162
+ }
1163
+
1164
+ public function count()
1165
+ {
1166
+ return $this->y;
1167
+ }
1168
+
1169
+ public function Filter($query, $cachequery = true)
1170
+ {
1171
+ $result = $this->tfn->Filter($this->ids, $query, $cachequery);
1172
+ if (!$result["success"]) return $result;
1173
+
1174
+ return new TagFilterNodeIterator($this->tfn, $result["ids"]);
1175
+ }
1176
+ }
1177
+
1178
+ // Output from TagFilter::Explode().
1179
+ class TagFilterNodes
1180
+ {
1181
+ public $nodes, $nextid;
1182
+ private $queries;
1183
+
1184
+ public function __construct()
1185
+ {
1186
+ $this->nodes = array(
1187
+ array(
1188
+ "type" => "root",
1189
+ "parent" => false,
1190
+ "parentpos" => false,
1191
+ "children" => array()
1192
+ )
1193
+ );
1194
+
1195
+ $this->nextid = 1;
1196
+ $this->queries = array();
1197
+ }
1198
+
1199
+ // Makes a selector suitable for Find() and Filter() by altering or removing rules. Query is not cached.
1200
+ public static function MakeValidSelector($query)
1201
+ {
1202
+ if (!is_array($query)) $result = TagFilter::ParseSelector($query, true);
1203
+ else if (isset($query["success"]) && isset($query["tokens"]))
1204
+ {
1205
+ $result = $query;
1206
+ $result["tokens"] = TagFilter::ReorderSelectorTokens(array_reverse($result["tokens"]), true);
1207
+ }
1208
+ else
1209
+ {
1210
+ $result = array("success" => true, "tokens" => TagFilter::ReorderSelectorTokens(array_reverse($query), true));
1211
+ }
1212
+
1213
+ // Alter certain CSS3 tokens to equivalent tokens.
1214
+ foreach ($result["tokens"] as $num => $rules)
1215
+ {
1216
+ foreach ($rules as $num2 => $rule)
1217
+ {
1218
+ if ($rule["type"] === "pseudo-class")
1219
+ {
1220
+ if ($rule["pseudo"] === "link") $result["tokens"][$num][$num2] = array("not" => false, "type" => "element", "namespace" => false, "tag" => "a");
1221
+ else if ($rule["pseudo"] === "disabled") $result["tokens"][$num][$num2] = array("not" => false, "type" => "attr", "namespace" => false, "attr" => "disabled", "cmp" => false);
1222
+ else if ($rule["pseudo"] === "enabled") $result["tokens"][$num][$num2] = array("not" => false, "type" => "attr", "namespace" => false, "attr" => "enabled", "cmp" => false);
1223
+ else if ($rule["pseudo"] === "checked") $result["tokens"][$num][$num2] = array("not" => false, "type" => "attr", "namespace" => false, "attr" => "checked", "cmp" => false);
1224
+ }
1225
+ }
1226
+ }
1227
+
1228
+ // Reorder the tokens so that the order is simple for output.
1229
+ $tokens = TagFilter::ReorderSelectorTokens(array_reverse($result["tokens"]), true, array("element" => array(), "id" => array(), "class" => array(), "attr" => array(), "pseudo-class" => array(), "pseudo-element" => array()), false);
1230
+
1231
+ // Generate a duplicate-free Find()-safe string.
1232
+ $result = array();
1233
+ foreach ($tokens as $rules)
1234
+ {
1235
+ $groups = array();
1236
+ $strs = array();
1237
+ $rules = array_reverse($rules);
1238
+ $y = count($rules);
1239
+ for ($x = 0; $x < $y; $x++)
1240
+ {
1241
+ $str = "";
1242
+
1243
+ if (isset($rules[$x]["not"]) && $rules[$x]["not"]) $str .= ":not(";
1244
+
1245
+ switch ($rules[$x]["type"])
1246
+ {
1247
+ case "id": $str .= "#" . $rules[$x]["id"]; $valid = true; break;
1248
+ case "element": $str .= ($rules[$x]["namespace"] !== false ? $rules[$x]["namespace"] . "|" : "") . strtolower($rules[$x]["tag"]); $valid = true; break;
1249
+ case "class": $str .= "." . $rules[$x]["class"]; $valid = true; break;
1250
+ case "attr": $str .= "[" . ($rules[$x]["namespace"] !== false ? $rules[$x]["namespace"] . "|" : "") . strtolower($rules[$x]["attr"]) . ($rules[$x]["cmp"] !== false ? $rules[$x]["cmp"] . "\"" . str_replace("\"", "\\\"", $rules[$x]["val"]) . "\"" : "") . "]"; $valid = true; break;
1251
+ case "pseudo-class":
1252
+ {
1253
+ $pc = $rules[$x]["pseudo"];
1254
+ $valid = ($pc === "first-child" || $pc === "last-child" || $pc === "only-child" || $pc === "nth-child" || $pc === "nth-last-child" || $pc === "first-child-all" || $pc === "last-child-all" || $pc === "only-child-all" || $pc === "nth-child-all" || $pc === "nth-last-child-all" || $pc === "first-of-type" || $pc === "last-of-type" || $pc === "only-of-type" || $pc === "nth-of-type" || $pc === "nth-last-of-type" || $pc === "empty");
1255
+
1256
+ if ($valid && substr($rules[$x]["pseudo"], 0, 4) === "nth-" && (!isset($rules[$x]["a"]) || !isset($rules[$x]["b"]))) $valid = false;
1257
+
1258
+ break;
1259
+ }
1260
+ case "combine":
1261
+ {
1262
+ switch ($rules[$x]["combine"])
1263
+ {
1264
+ case "prev-parent": $groups[] = implode("", $strs); $groups[] = ">"; $strs = array(); $valid = true; break;
1265
+ case "any-parent": $groups[] = implode("", $strs); $strs = array(); $valid = true; break;
1266
+ case "prev-sibling": $groups[] = implode("", $strs); $groups[] = "+"; $strs = array(); $valid = true; break;
1267
+ case "any-prev-sibling": $groups[] = implode("", $strs); $groups[] = "~"; $strs = array(); $valid = true; break;
1268
+ default: $valid = false;
1269
+ }
1270
+
1271
+ break;
1272
+ }
1273
+ default: $valid = false; break;
1274
+ }
1275
+
1276
+ if (!$valid) break;
1277
+
1278
+ if (isset($rules[$x]["not"]) && $rules[$x]["not"]) $str .= ")";
1279
+
1280
+ $strs[$str] = $str;
1281
+ }
1282
+
1283
+ if ($x == $y)
1284
+ {
1285
+ if (count($strs)) $groups[] = implode("", $strs);
1286
+ $str = implode(" ", $groups);
1287
+ $result[$str] = $str;
1288
+ }
1289
+ }
1290
+
1291
+ return implode(", ", $result);
1292
+ }
1293
+
1294
+ public function Find($query, $id = 0, $cachequery = true, $firstmatch = false)
1295
+ {
1296
+ $id = (int)$id;
1297
+ if (!isset($this->nodes[$id])) return array("success" => false, "error" => "Invalid initial ID.", "errorcode" => "invalid_init_id");
1298
+
1299
+ if (isset($this->queries[$query])) $result = $this->queries[$query];
1300
+ else
1301
+ {
1302
+ if (!is_array($query)) $result = TagFilter::ParseSelector($query, true);
1303
+ else if (isset($query["success"]) && isset($result["selector"]) && isset($query["tokens"]))
1304
+ {
1305
+ $result = $query;
1306
+ $result["tokens"] = TagFilter::ReorderSelectorTokens($result["tokens"], true);
1307
+
1308
+ $query = $result["selector"];
1309
+ }
1310
+ else
1311
+ {
1312
+ $result = array("success" => true, "tokens" => TagFilter::ReorderSelectorTokens($query, true));
1313
+
1314
+ $cachequery = false;
1315
+ }
1316
+
1317
+ if ($cachequery)
1318
+ {
1319
+ foreach ($this->queries as $key => $val)
1320
+ {
1321
+ if (count($this->queries) < 25) break;
1322
+
1323
+ unset($this->queries[$key]);
1324
+ }
1325
+
1326
+ $this->queries[$query] = $result;
1327
+ }
1328
+ }
1329
+
1330
+ if (!$result["success"]) return $result;
1331
+
1332
+ $rules = $result["tokens"];
1333
+ $numrules = count($rules);
1334
+
1335
+ $result = array();
1336
+ $childcache = array();
1337
+ $oftypecache = array();
1338
+ $rootid = $id;
1339
+ $pos = 0;
1340
+ $maxpos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
1341
+ do
1342
+ {
1343
+ if (!$pos && $this->nodes[$id]["type"] === "element")
1344
+ {
1345
+ // Attempt to match a rule.
1346
+ for ($x = 0; $x < $numrules; $x++)
1347
+ {
1348
+ $id2 = $id;
1349
+ $y = count($rules[$x]);
1350
+ for ($x2 = 0; $x2 < $y; $x2++)
1351
+ {
1352
+ if ($this->nodes[$id2]["type"] === "content" || $this->nodes[$id2]["type"] === "comment")
1353
+ {
1354
+ // Always backtrack at non-element nodes since the rules are element based.
1355
+ $backtrack = !(isset($rules[$x][$x2]["not"]) && $rules[$x][$x2]["not"]);
1356
+ }
1357
+ else if (isset($rules[$x][$x2]["namespace"]) && $rules[$x][$x2]["namespace"] !== false && $rules[$x][$x2]["namespace"] !== "*" && (($rules[$x][$x2]["namespace"] === "" && strpos($this->nodes[$id2]["tag"], ":") !== false) || ($rules[$x][$x2]["namespace"] !== "" && strcasecmp(substr($this->nodes[$id2]["tag"], 0, strlen($rules[$x][$x2]["namespace"]) + 1), $rules[$x][$x2]["namespace"] . ":") !== 0)))
1358
+ {
1359
+ $backtrack = true;
1360
+ }
1361
+ else
1362
+ {
1363
+ switch ($rules[$x][$x2]["type"])
1364
+ {
1365
+ case "id": $backtrack = (!isset($this->nodes[$id2]["attrs"]["id"]) || $this->nodes[$id2]["attrs"]["id"] !== $rules[$x][$x2]["id"]); break;
1366
+ case "element": $backtrack = (strcasecmp($this->nodes[$id2]["tag"], (isset($rules[$x][$x2]["namespace"]) && $rules[$x][$x2]["namespace"] !== false ? $rules[$x][$x2]["namespace"] . ":" : "") . $rules[$x][$x2]["tag"]) !== 0); break;
1367
+ case "class": $backtrack = (!isset($this->nodes[$id2]["attrs"]["class"]) || !isset($this->nodes[$id2]["attrs"]["class"][$rules[$x][$x2]["class"]])); break;
1368
+ case "attr":
1369
+ {
1370
+ $attr = strtolower($rules[$x][$x2]["attr"]);
1371
+ if (!isset($this->nodes[$id2]["attrs"][$attr])) $backtrack = true;
1372
+ else
1373
+ {
1374
+ $val = $this->nodes[$id2]["attrs"][$attr];
1375
+ if (is_array($val)) $val = implode(" ", $val);
1376
+
1377
+ switch ($rules[$x][$x2]["cmp"])
1378
+ {
1379
+ case "=": $backtrack = ($val !== $rules[$x][$x2]["val"]); break;
1380
+ case "^=": $backtrack = ($rules[$x][$x2]["val"] === "" || substr($val, 0, strlen($rules[$x][$x2]["val"])) !== $rules[$x][$x2]["val"]); break;
1381
+ case "$=": $backtrack = ($rules[$x][$x2]["val"] === "" || substr($val, -strlen($rules[$x][$x2]["val"])) !== $rules[$x][$x2]["val"]); break;
1382
+ case "*=": $backtrack = ($rules[$x][$x2]["val"] === "" || strpos($val, $rules[$x][$x2]["val"]) === false); break;
1383
+ case "~=": $backtrack = ($rules[$x][$x2]["val"] === "" || strpos($rules[$x][$x2]["val"], " ") !== false || strpos(" " . $val . " ", " " . $rules[$x][$x2]["val"] . " ") === false); break;
1384
+ case "|=": $backtrack = ($rules[$x][$x2]["val"] === "" || ($val !== $rules[$x][$x2]["val"] && substr($val, 0, strlen($rules[$x][$x2]["val"]) + 1) !== $rules[$x][$x2]["val"] . "-")); break;
1385
+ default: $backtrack = false; break;
1386
+ }
1387
+ }
1388
+
1389
+ break;
1390
+ }
1391
+ case "pseudo-class":
1392
+ {
1393
+ // Handle various bits of common code.
1394
+ $pid = $this->nodes[$id2]["parent"];
1395
+ $pnum = count($this->nodes[$pid]["children"]);
1396
+
1397
+ $nth = (substr($rules[$x][$x2]["pseudo"], 0, 4) === "nth-");
1398
+ if ($nth && (!isset($rules[$x][$x2]["a"]) || !isset($rules[$x][$x2]["b"]))) return array("success" => false, "error" => "Pseudo-class ':" . $rules[$x][$x2]["pseudo"] . "(n)' requires an expression for 'n'.", "errorcode" => "missing_pseudo_class_expression");
1399
+
1400
+ if (substr($rules[$x][$x2]["pseudo"], -6) === "-child")
1401
+ {
1402
+ if (!isset($childcache[$id2]))
1403
+ {
1404
+ $children = 0;
1405
+ foreach ($this->nodes[$pid]["children"] as $id3)
1406
+ {
1407
+ if ($this->nodes[$id3]["type"] === "element")
1408
+ {
1409
+ $childcache[$id3] = array("cx" => $children);
1410
+
1411
+ $children++;
1412
+ }
1413
+ }
1414
+
1415
+ foreach ($this->nodes[$pid]["children"] as $id3)
1416
+ {
1417
+ if ($this->nodes[$id3]["type"] === "element") $childcache[$id3]["cy"] = $children;
1418
+ }
1419
+ }
1420
+
1421
+ $cx = $childcache[$id2]["cx"];
1422
+ $cy = $childcache[$id2]["cy"];
1423
+ }
1424
+
1425
+ if (substr($rules[$x][$x2]["pseudo"], -8) === "-of-type")
1426
+ {
1427
+ if (!isset($oftypecache[$id2]))
1428
+ {
1429
+ $types = array();
1430
+ foreach ($this->nodes[$pid]["children"] as $id3)
1431
+ {
1432
+ if ($this->nodes[$id3]["type"] === "element")
1433
+ {
1434
+ $tag = $this->nodes[$id3]["tag"];
1435
+ if (!isset($types[$tag])) $types[$tag] = 0;
1436
+
1437
+ $oftypecache[$id3] = array("tx" => $types[$tag]);
1438
+
1439
+ $types[$tag]++;
1440
+ }
1441
+ }
1442
+
1443
+ foreach ($this->nodes[$pid]["children"] as $id3)
1444
+ {
1445
+ if ($this->nodes[$id3]["type"] === "element")
1446
+ {
1447
+ $tag = $this->nodes[$id3]["tag"];
1448
+ $oftypecache[$id3]["ty"] = $types[$tag];
1449
+ }
1450
+ }
1451
+ }
1452
+
1453
+ $tx = $oftypecache[$id2]["tx"];
1454
+ $ty = $oftypecache[$id2]["ty"];
1455
+ }
1456
+
1457
+ switch ($rules[$x][$x2]["pseudo"])
1458
+ {
1459
+ case "first-child": $backtrack = ($cx !== 0); break;
1460
+ case "last-child": $backtrack = ($cx !== $cy - 1); break;
1461
+ case "only-child": $backtrack = ($cy !== 1); break;
1462
+ case "nth-child": $px = $cx; break;
1463
+ case "nth-last-child": $px = $cy - $cx - 1; break;
1464
+ case "first-child-all": $backtrack = ($this->nodes[$id2]["parentpos"] !== 0); break;
1465
+ case "last-child-all": $backtrack = ($this->nodes[$id2]["parentpos"] !== $pnum - 1); break;
1466
+ case "only-child-all": $backtrack = ($pnum !== 1); break;
1467
+ case "nth-child-all": $px = $this->nodes[$id2]["parentpos"]; break;
1468
+ case "nth-last-child-all": $px = $pnum - $this->nodes[$id2]["parentpos"] - 1; break;
1469
+ case "first-of-type": $backtrack = ($tx !== 0); break;
1470
+ case "last-of-type": $backtrack = ($tx !== $ty - 1); break;
1471
+ case "only-of-type": $backtrack = ($ty !== 1); break;
1472
+ case "nth-of-type": $px = $tx; break;
1473
+ case "nth-last-of-type": $px = $ty - $tx - 1; break;
1474
+ case "empty":
1475
+ {
1476
+ $backtrack = false;
1477
+ foreach ($this->nodes[$id2]["children"] as $id3)
1478
+ {
1479
+ if ($this->nodes[$id3]["type"] === "element" || ($this->nodes[$id3]["type"] === "content" && trim($this->nodes[$id3]["text"]) !== ""))
1480
+ {
1481
+ $backtrack = true;
1482
+
1483
+ break;
1484
+ }
1485
+ }
1486
+
1487
+ break;
1488
+ }
1489
+ default: return array("success" => false, "error" => "Unknown/Unsupported pseudo-class ':" . $rules[$x][$x2]["pseudo"] . "'.", "errorcode" => "unknown_unsupported_pseudo_class");
1490
+ }
1491
+
1492
+ if ($nth)
1493
+ {
1494
+ // Calculated expression: a * n + b - 1 = x
1495
+ // Solved for n: n = (x + 1 - b) / a
1496
+ // Where 'n' is a non-negative integer. When 'a' is 0, solve for 'b' instead.
1497
+ $pa = $rules[$x][$x2]["a"];
1498
+ $pb = $rules[$x][$x2]["b"];
1499
+
1500
+ if ($pa == 0) $backtrack = ($pb != $px + 1);
1501
+ else
1502
+ {
1503
+ $pn = (($px + 1 - $pb) / $pa);
1504
+
1505
+ $backtrack = ($pn < 0 || $pn - (int)$pn > 0.000001);
1506
+ }
1507
+ }
1508
+
1509
+ break;
1510
+ }
1511
+ case "pseudo-element": return array("success" => false, "error" => "Pseudo-elements are not supported. Found '::" . $rules[$x][$x2]["pseudo"] . "'.", "errorcode" => "unsupported_selector_type");
1512
+ case "combine":
1513
+ {
1514
+ switch ($rules[$x][$x2]["combine"])
1515
+ {
1516
+ case "prev-parent":
1517
+ case "any-parent":
1518
+ {
1519
+ $backtrack = ($id2 === $rootid || !$this->nodes[$id2]["parent"]);
1520
+ if (!$backtrack) $id2 = $this->nodes[$id2]["parent"];
1521
+
1522
+ break;
1523
+ }
1524
+ case "prev-sibling":
1525
+ case "any-prev-sibling":
1526
+ {
1527
+ $backtrack = ($this->nodes[$id2]["parentpos"] == 0);
1528
+ if (!$backtrack) $id2 = $this->nodes[$this->nodes[$id2]["parent"]]["children"][$this->nodes[$id2]["parentpos"] - 1];
1529
+
1530
+ break;
1531
+ }
1532
+ default: return array("success" => false, "error" => "Unknown combiner " . $rules[$x][$x2]["pseudo"] . ".", "errorcode" => "unknown_combiner");
1533
+ }
1534
+
1535
+ // For unknown parent/sibling combiners such as '~', use the rule stack to allow for backtracking to try another path if a match fails (e.g. h1 p ~ p).
1536
+ $rules[$x][$x2]["lastid"] = $id2;
1537
+
1538
+ break;
1539
+ }
1540
+ default: return array("success" => false, "error" => "Unknown selector type '" . $rules[$x][$x2]["type"] . "'.", "errorcode" => "unknown_selector_type");
1541
+ }
1542
+ }
1543
+
1544
+ if (isset($rules[$x][$x2]["not"]) && $rules[$x][$x2]["not"]) $backtrack = !$backtrack;
1545
+
1546
+ // Backtrack through the rule to an unknown parent/sibling combiner.
1547
+ if ($backtrack)
1548
+ {
1549
+ if ($x2)
1550
+ {
1551
+ for ($x2--; $x2; $x2--)
1552
+ {
1553
+ if ($rules[$x][$x2]["type"] === "combine")
1554
+ {
1555
+ if ($rules[$x][$x2]["combine"] === "any-parent")
1556
+ {
1557
+ $id2 = $rules[$x][$x2]["lastid"];
1558
+ if ($id2 !== $rootid && $this->nodes[$id2]["parent"])
1559
+ {
1560
+ $id2 = $this->nodes[$id2]["parent"];
1561
+ $rules[$x][$x2]["lastid"] = $id2;
1562
+
1563
+ break;
1564
+ }
1565
+ }
1566
+ else if ($rules[$x][$x2]["combine"] === "any-prev-sibling")
1567
+ {
1568
+ $id2 = $rules[$x][$x2]["lastid"];
1569
+ if ($this->nodes[$id2]["parentpos"] != 0)
1570
+ {
1571
+ $id2 = $this->nodes[$this->nodes[$id2]["parent"]]["children"][$this->nodes[$id2]["parentpos"] - 1];
1572
+ $rules[$x][$x2]["lastid"] = $id2;
1573
+
1574
+ break;
1575
+ }
1576
+ }
1577
+ }
1578
+ }
1579
+ }
1580
+
1581
+ if (!$x2) break;
1582
+ }
1583
+ }
1584
+
1585
+ // Match found.
1586
+ if ($x2 === $y)
1587
+ {
1588
+ $result[] = $id;
1589
+
1590
+ if ($firstmatch) return array("success" => true, "ids" => $result);
1591
+
1592
+ break;
1593
+ }
1594
+ }
1595
+ }
1596
+
1597
+ if ($pos >= $maxpos)
1598
+ {
1599
+ if ($rootid === $id) break;
1600
+
1601
+ $pos = $this->nodes[$id]["parentpos"] + 1;
1602
+ $id = $this->nodes[$id]["parent"];
1603
+ $maxpos = count($this->nodes[$id]["children"]);
1604
+ }
1605
+ else
1606
+ {
1607
+ $id = $this->nodes[$id]["children"][$pos];
1608
+ $pos = 0;
1609
+ $maxpos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
1610
+ }
1611
+ } while (1);
1612
+
1613
+ return array("success" => true, "ids" => $result);
1614
+ }
1615
+
1616
+ // Filter results from Find() based on a matching query.
1617
+ public function Filter($ids, $query, $cachequery = true)
1618
+ {
1619
+ if (!is_array($ids)) $ids = array($ids);
1620
+
1621
+ // Handle lazy chaining from both Find() and Filter().
1622
+ if (isset($ids["success"]))
1623
+ {
1624
+ if (!$ids["success"]) return $ids;
1625
+ if (!isset($ids["ids"])) return array("success" => false, "error" => "Bad filter input.", "invalid_filter_ids");
1626
+
1627
+ $ids = $ids["ids"];
1628
+ }
1629
+
1630
+ $ids2 = array();
1631
+ if (is_string($query) && strtolower(substr($query, 0, 10)) === "/contains:")
1632
+ {
1633
+ $query = substr($query, 10);
1634
+ foreach ($ids as $id)
1635
+ {
1636
+ if (strpos($this->GetPlainText($id), $query) !== false) $ids2[] = $id;
1637
+ }
1638
+ }
1639
+ else if (is_string($query) && strtolower(substr($query, 0, 11)) === "/~contains:")
1640
+ {
1641
+ $query = substr($query, 11);
1642
+ foreach ($ids as $id)
1643
+ {
1644
+ if (stripos($this->GetPlainText($id), $query) !== false) $ids2[] = $id;
1645
+ }
1646
+ }
1647
+ else
1648
+ {
1649
+ foreach ($ids as $id)
1650
+ {
1651
+ $result = $this->Find($query, $id, $cachequery, true);
1652
+ if ($result["success"] && count($result["ids"])) $ids2[] = $id;
1653
+ }
1654
+ }
1655
+
1656
+ return array("success" => true, "ids" => $ids2);
1657
+ }
1658
+
1659
+ // Convert all or some of the nodes back into a string.
1660
+ public function Implode($id, $options = array())
1661
+ {
1662
+ $id = (int)$id;
1663
+ if (!isset($this->nodes[$id])) return "";
1664
+
1665
+ if (!isset($options["include_id"])) $options["include_id"] = true;
1666
+ if (!isset($options["types"])) $options["types"] = "element,content,comment";
1667
+ if (!isset($options["output_mode"])) $options["output_mode"] = "html";
1668
+ if (!isset($options["post_elements"])) $options["post_elements"] = array();
1669
+ if (!isset($options["no_content_elements"])) $options["no_content_elements"] = array("script" => true, "style" => true);
1670
+ if (!isset($options["charset"])) $options["charset"] = "UTF-8";
1671
+ $options["charset"] = strtoupper($options["charset"]);
1672
+
1673
+ $types2 = explode(",", $options["types"]);
1674
+ $types = array();
1675
+ foreach ($types2 as $type)
1676
+ {
1677
+ $type = trim($type);
1678
+ if ($type !== "") $types[$type] = true;
1679
+ }
1680
+
1681
+ $result = "";
1682
+ $include = (bool)$options["include_id"];
1683
+ $rootid = $id;
1684
+ $pos = 0;
1685
+ $maxpos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
1686
+ do
1687
+ {
1688
+ if (!$pos && isset($types[$this->nodes[$id]["type"]]))
1689
+ {
1690
+ switch ($this->nodes[$id]["type"])
1691
+ {
1692
+ case "element":
1693
+ {
1694
+ if ($include || $rootid != $id)
1695
+ {
1696
+ $result .= "<" . $this->nodes[$id]["tag"];
1697
+ foreach ($this->nodes[$id]["attrs"] as $key => $val)
1698
+ {
1699
+ $result .= " " . $key;
1700
+
1701
+ if (is_array($val)) $val = implode(" ", $val);
1702
+ if (is_string($val)) $result .= "=\"" . htmlspecialchars($val, ENT_COMPAT | ENT_HTML5, $options["charset"]) . "\"";
1703
+ }
1704
+ $result .= (!$maxpos && $options["output_mode"] === "xml" ? " />" : ">");
1705
+ }
1706
+
1707
+ break;
1708
+ }
1709
+ case "content":
1710
+ case "comment":
1711
+ {
1712
+ if (isset($types["element"]) || !isset($this->nodes[$this->nodes[$id]["parent"]]["tag"]) || !isset($options["no_content_elements"][$this->nodes[$this->nodes[$id]["parent"]]["tag"]])) $result .= $this->nodes[$id]["text"];
1713
+
1714
+ break;
1715
+ }
1716
+ default: break;
1717
+ }
1718
+ }
1719
+
1720
+ if ($pos >= $maxpos)
1721
+ {
1722
+ if ($this->nodes[$id]["type"] === "element" && is_array($this->nodes[$id]["children"]))
1723
+ {
1724
+ if (($include || $rootid != $id) && isset($types[$this->nodes[$id]["type"]])) $result .= "</" . $this->nodes[$id]["tag"] . ">";
1725
+ }
1726
+
1727
+ if ($this->nodes[$id]["type"] === "element" && isset($options["post_elements"][$this->nodes[$id]["tag"]])) $result .= $options["post_elements"][$this->nodes[$id]["tag"]];
1728
+
1729
+ if ($rootid === $id) break;
1730
+
1731
+ $pos = $this->nodes[$id]["parentpos"] + 1;
1732
+ $id = $this->nodes[$id]["parent"];
1733
+ $maxpos = count($this->nodes[$id]["children"]);
1734
+ }
1735
+ else
1736
+ {
1737
+ $id = $this->nodes[$id]["children"][$pos];
1738
+ $pos = 0;
1739
+ $maxpos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
1740
+ }
1741
+ } while (1);
1742
+
1743
+ return $result;
1744
+ }
1745
+
1746
+ // Object-oriented access methods. Only Get() supports multiple IDs.
1747
+ public function Get($id = 0)
1748
+ {
1749
+ if (is_array($id))
1750
+ {
1751
+ if (isset($id["success"]) && $id["ids"]) $id = $id["ids"];
1752
+
1753
+ $result = array();
1754
+ foreach ($id as $id2) $result[] = $this->Get($id2);
1755
+
1756
+ return $result;
1757
+ }
1758
+
1759
+ return ($id !== false && isset($this->nodes[$id]) ? new TagFilterNode($this, $id) : false);
1760
+ }
1761
+
1762
+ public function GetParent($id)
1763
+ {
1764
+ return ($id !== false && isset($this->nodes[$id]) && isset($this->nodes[$this->nodes[$id]["parent"]]) ? new TagFilterNode($this, $this->nodes[$id]["parent"]) : false);
1765
+ }
1766
+
1767
+ public function GetChildren($id, $objects = false)
1768
+ {
1769
+ if (!isset($this->nodes[$id]) || !isset($this->nodes[$id]["children"]) || !is_array($this->nodes[$id]["children"])) return false;
1770
+
1771
+ return ($objects ? $this->Get($this->nodes[$id]["children"]) : $this->nodes[$id]["children"]);
1772
+ }
1773
+
1774
+ public function GetChild($id, $pos)
1775
+ {
1776
+ if (!isset($this->nodes[$id]) || !isset($this->nodes[$id]["children"]) || !is_array($this->nodes[$id]["children"])) return false;
1777
+
1778
+ $pos = (int)$pos;
1779
+ $y = count($this->nodes[$id]["children"]);
1780
+ if ($pos < 0) $pos = $y + $pos;
1781
+ if ($pos < 0 || $pos > $y - 1) return false;
1782
+
1783
+ return $this->Get($this->nodes[$id]["children"][$pos]);
1784
+ }
1785
+
1786
+ public function GetPrevSibling($id)
1787
+ {
1788
+ if (!isset($this->nodes[$id]) || $this->nodes[$id]["parentpos"] == 0) return false;
1789
+
1790
+ return $this->Get($this->nodes[$this->nodes[$id]["parent"]]["children"][$this->nodes[$id]["parentpos"] - 1]);
1791
+ }
1792
+
1793
+ public function GetNextSibling($id)
1794
+ {
1795
+ if ($id === false || !isset($this->nodes[$id]) || $this->nodes[$id]["parentpos"] >= count($this->nodes[$this->nodes[$id]["parent"]]["children"]) - 1) return false;
1796
+
1797
+ return $this->Get($this->nodes[$this->nodes[$id]["parent"]]["children"][$this->nodes[$id]["parentpos"] + 1]);
1798
+ }
1799
+
1800
+ public function GetTag($id)
1801
+ {
1802
+ return (isset($this->nodes[$id]) && $this->nodes[$id]["type"] === "element" ? $this->nodes[$id]["tag"] : false);
1803
+ }
1804
+
1805
+ public function SetText($id, $val)
1806
+ {
1807
+ if (isset($this->nodes[$id]) && ($this->nodes[$id]["type"] === "content" || $this->nodes[$id]["type"] === "comment")) $this->nodes[$id]["text"] = (string)$val;
1808
+ }
1809
+
1810
+ public function GetText($id)
1811
+ {
1812
+ return (isset($this->nodes[$id]) && ($this->nodes[$id]["type"] === "content" || $this->nodes[$id]["type"] === "comment") ? $this->nodes[$id]["text"] : false);
1813
+ }
1814
+
1815
+ public function Move($src, $newpid, $newpos)
1816
+ {
1817
+ $newpid = (int)$newpid;
1818
+ if (!isset($this->nodes[$newpid]) || !isset($this->nodes[$newpid]["children"]) || !is_array($this->nodes[$newpid]["children"])) return false;
1819
+
1820
+ $newpos = (is_bool($newpos) ? count($this->nodes[$newpid]["children"]) : (int)$newpos);
1821
+ if ($newpos < 0) $newpos = count($this->nodes[$newpid]["children"]) + $newpos;
1822
+ if ($newpos < 0) $newpos = 0;
1823
+ if ($newpos > count($this->nodes[$newpid]["children"])) $newpos = count($this->nodes[$newpid]["children"]);
1824
+
1825
+ if ($src instanceof TagFilterNodes)
1826
+ {
1827
+ if ($src === $this) return false;
1828
+
1829
+ // Bulk node import. Doesn't remove source nodes.
1830
+ foreach ($src->nodes as $id => $node)
1831
+ {
1832
+ if ($node["type"] === "element" || $node["type"] === "content" || $node["type"] === "comment")
1833
+ {
1834
+ $node["parent"] += $this->nextid - 1;
1835
+
1836
+ if (isset($node["children"]) && is_array($node["children"]))
1837
+ {
1838
+ foreach ($node["children"] as $pos => $id2) $node["children"][$pos] += $this->nextid - 1;
1839
+ }
1840
+
1841
+ $this->nodes[$id + $this->nextid - 1] = $node;
1842
+ }
1843
+ }
1844
+
1845
+ // Merge root children.
1846
+ foreach ($src->nodes[0]["children"] as $pos => $id)
1847
+ {
1848
+ $this->nodes[$id + $this->nextid - 1]["parent"] = $newpid;
1849
+ array_splice($this->nodes[$newpid]["children"], $newpos + $pos, 0, array($id + $this->nextid - 1));
1850
+ }
1851
+
1852
+ $this->RealignChildren($newpid, $newpos);
1853
+
1854
+ $this->nextid += $src->nextid - 1;
1855
+ }
1856
+ else if (is_array($src))
1857
+ {
1858
+ // Attach the array to the position if it is valid.
1859
+ if (!isset($src["type"])) return false;
1860
+
1861
+ switch ($src["type"])
1862
+ {
1863
+ case "element":
1864
+ {
1865
+ if (!isset($src["tag"]) || !isset($src["attrs"]) || !is_array($src["attrs"]) || !isset($src["children"])) return false;
1866
+
1867
+ $src["tag"] = (string)$src["tag"];
1868
+ $src["parent"] = $newpid;
1869
+
1870
+ break;
1871
+ }
1872
+ case "content":
1873
+ case "comment":
1874
+ {
1875
+ if (!isset($src["text"]) || isset($src["children"])) return false;
1876
+
1877
+ $src["text"] = (string)$src["text"];
1878
+
1879
+ break;
1880
+ }
1881
+ default: return false;
1882
+ }
1883
+
1884
+ array_splice($this->nodes[$newpid]["children"], $newpos, 0, array($this->nextid));
1885
+ $this->RealignChildren($newpid, $newpos);
1886
+ $this->nextid++;
1887
+ }
1888
+ else if (is_string($src))
1889
+ {
1890
+ return $this->Move(TagFilter::Explode($src, TagFilter::GetHTMLOptions()), $newpid, $newpos);
1891
+ }
1892
+ else
1893
+ {
1894
+ // Reparents an internal id.
1895
+ $id = (int)$src;
1896
+
1897
+ if (!$id || !isset($this->nodes[$id])) return false;
1898
+
1899
+ // Don't allow reparenting to a child node.
1900
+ $id2 = $newpid;
1901
+ while ($id2)
1902
+ {
1903
+ if ($id === $id2) return false;
1904
+
1905
+ $id2 = $this->nodes[$id2]["parent"];
1906
+ }
1907
+
1908
+ // Detach.
1909
+ array_splice($this->nodes[$this->nodes[$id]["parent"]]["children"], $this->nodes[$id]["parentpos"], 1);
1910
+ $this->RealignChildren($this->nodes[$id]["parent"], $this->nodes[$id]["parentpos"]);
1911
+
1912
+ // Attach.
1913
+ array_splice($this->nodes[$newpid]["children"], $newpos, 0, array($id));
1914
+ $this->RealignChildren($newpid, $newpos);
1915
+ }
1916
+
1917
+ return true;
1918
+ }
1919
+
1920
+ // When $keepchildren is true, the node's children are moved into the parent of the node being removed.
1921
+ public function Remove($id, $keepchildren = false)
1922
+ {
1923
+ $id = (int)$id;
1924
+ if (!isset($this->nodes[$id])) return;
1925
+
1926
+ if (!$id)
1927
+ {
1928
+ if (!$keepchildren)
1929
+ {
1930
+ // Reset all nodes.
1931
+ $this->nodes = array(
1932
+ array(
1933
+ "type" => "root",
1934
+ "parent" => false,
1935
+ "parentpos" => false,
1936
+ "children" => array()
1937
+ )
1938
+ );
1939
+
1940
+ $this->nextid = 1;
1941
+ }
1942
+ }
1943
+ else
1944
+ {
1945
+ // Detach the node from the parent.
1946
+ $pid = $this->nodes[$id]["parent"];
1947
+ $pos = $this->nodes[$id]["parentpos"];
1948
+
1949
+ if ($keepchildren)
1950
+ {
1951
+ // Reparent the children and attach them to the new parent.
1952
+ if (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]))
1953
+ {
1954
+ foreach ($this->nodes[$id]["children"] as $cid) $this->nodes[$cid]["parent"] = $pid;
1955
+ array_splice($this->nodes[$pid]["children"], $pos, 1, $this->nodes[$id]["children"]);
1956
+ }
1957
+ else
1958
+ {
1959
+ array_splice($this->nodes[$pid]["children"], $pos, 1);
1960
+ }
1961
+
1962
+ $this->RealignChildren($pid, $pos);
1963
+
1964
+ unset($this->nodes[$id]);
1965
+ }
1966
+ else
1967
+ {
1968
+ array_splice($this->nodes[$pid]["children"], $pos, 1);
1969
+
1970
+ $this->RealignChildren($pid, $pos);
1971
+
1972
+ // Remove node and all children.
1973
+ $rootid = $id;
1974
+ $pos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
1975
+ do
1976
+ {
1977
+ if (!$pos)
1978
+ {
1979
+ $pid = $this->nodes[$id]["parent"];
1980
+ $pos = $this->nodes[$id]["parentpos"];
1981
+
1982
+ unset($this->nodes[$id]);
1983
+ if ($rootid === $id) break;
1984
+
1985
+ $id = $pid;
1986
+ }
1987
+ else
1988
+ {
1989
+ $id = $this->nodes[$id]["children"][$pos - 1];
1990
+ $pos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
1991
+ }
1992
+ } while (1);
1993
+ }
1994
+ }
1995
+ }
1996
+
1997
+ public function Replace($id, $src, $inneronly = false)
1998
+ {
1999
+ $id = (int)$id;
2000
+ if (!isset($this->nodes[$id])) return false;
2001
+
2002
+ if ($inneronly)
2003
+ {
2004
+ // Remove children.
2005
+ if (!isset($this->nodes[$id]["children"]) || !is_array($this->nodes[$id]["children"])) return false;
2006
+
2007
+ while (count($this->nodes[$id]["children"])) $this->Remove($this->nodes[$id]["children"][0]);
2008
+
2009
+ $newpid = $id;
2010
+ $newpos = 0;
2011
+ }
2012
+ else
2013
+ {
2014
+ $newpid = $this->nodes[$id]["parent"];
2015
+ $newpos = $this->nodes[$id]["parentpos"];
2016
+
2017
+ $this->Remove($id);
2018
+ }
2019
+
2020
+ return $this->Move($src, $newpid, $newpos);
2021
+ }
2022
+
2023
+ private static function SplitAt_CopyNode($nodes, &$pid, $node)
2024
+ {
2025
+ // Copy the node.
2026
+ $node["parent"] = $pid;
2027
+ $node["parentpos"] = count($nodes->nodes[$pid]["children"]);
2028
+ if (isset($node["children"])) $node["children"] = (is_array($node["children"]) ? array() : false);
2029
+
2030
+ // Attach the node.
2031
+ $nodes->nodes[$nodes->nextid] = $node;
2032
+ $nodes->nodes[$pid]["children"][] = $nodes->nextid;
2033
+
2034
+ $pid = $nodes->nextid;
2035
+
2036
+ $nodes->nextid++;
2037
+ }
2038
+
2039
+ public function SplitAt($ids, $keepidparents = false)
2040
+ {
2041
+ $ids2 = array();
2042
+ if (!is_array($ids)) $ids = array($ids);
2043
+ foreach ($ids as $id) $ids2[(int)$id] = true;
2044
+ unset($ids2[0]);
2045
+
2046
+ $result = array();
2047
+
2048
+ // Walk the entire set of nodes, cloning until an ID match occurs (if any).
2049
+ $newnodes = new TagFilterNodes();
2050
+ $newpid = 0;
2051
+ $id = 0;
2052
+ $pos = 0;
2053
+ $maxpos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
2054
+ do
2055
+ {
2056
+ if (!$pos)
2057
+ {
2058
+ if (isset($ids2[$id]) && count($newnodes->nodes[0]["children"]))
2059
+ {
2060
+ // Found an ID match.
2061
+ $result[] = $newnodes;
2062
+ $newnodes = new TagFilterNodes();
2063
+ $newpid = 0;
2064
+
2065
+ if ($keepidparents instanceof TagFilterNodes)
2066
+ {
2067
+ $newnodes = clone $keepidparents;
2068
+ $newpid = $newnodes->nextid - 1;
2069
+ }
2070
+ else if ($keepidparents)
2071
+ {
2072
+ $stack = array();
2073
+ $id2 = $this->nodes[$id]["parent"];
2074
+ while ($id2)
2075
+ {
2076
+ $stack[] = $id2;
2077
+
2078
+ $id2 = $this->nodes[$id2]["parent"];
2079
+ }
2080
+ $stack = array_reverse($stack);
2081
+ foreach ($stack as $id2)
2082
+ {
2083
+ self::SplitAt_CopyNode($newnodes, $newpid, $this->nodes[$id2]);
2084
+ }
2085
+ }
2086
+ }
2087
+
2088
+ if ($id) self::SplitAt_CopyNode($newnodes, $newpid, $this->nodes[$id]);
2089
+ }
2090
+
2091
+ if ($pos >= $maxpos)
2092
+ {
2093
+ if (!$id) break;
2094
+
2095
+ if (isset($ids2[$id]))
2096
+ {
2097
+ // Start a new set of nodes.
2098
+ $result[] = $newnodes;
2099
+ $newnodes = new TagFilterNodes();
2100
+ $newpid = 0;
2101
+
2102
+ $stack = array();
2103
+ $id2 = $this->nodes[$id]["parent"];
2104
+ while ($id2)
2105
+ {
2106
+ $stack[] = $id2;
2107
+
2108
+ $id2 = $this->nodes[$id2]["parent"];
2109
+ }
2110
+ $stack = array_reverse($stack);
2111
+ foreach ($stack as $id2)
2112
+ {
2113
+ self::SplitAt_CopyNode($newnodes, $newpid, $this->nodes[$id2]);
2114
+ }
2115
+ }
2116
+ else
2117
+ {
2118
+ $newpid = $newnodes->nodes[$newpid]["parent"];
2119
+ }
2120
+
2121
+ $pos = $this->nodes[$id]["parentpos"] + 1;
2122
+ $id = $this->nodes[$id]["parent"];
2123
+ $maxpos = count($this->nodes[$id]["children"]);
2124
+ }
2125
+ else
2126
+ {
2127
+ $id = $this->nodes[$id]["children"][$pos];
2128
+ $pos = 0;
2129
+ $maxpos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
2130
+ }
2131
+ } while (1);
2132
+
2133
+ if (!count($result) || count($newnodes->nodes[0]["children"])) $result[] = $newnodes;
2134
+
2135
+ return $result;
2136
+ }
2137
+
2138
+ public function GetOuterHTML($id, $mode = "html")
2139
+ {
2140
+ return $this->Implode($id, array("output_mode" => $mode));
2141
+ }
2142
+
2143
+ public function SetOuterHTML($id, $src)
2144
+ {
2145
+ return $this->Replace($id, $src);
2146
+ }
2147
+
2148
+ public function GetInnerHTML($id, $mode = "html")
2149
+ {
2150
+ return $this->Implode($id, array("include_id" => false, "output_mode" => $mode));
2151
+ }
2152
+
2153
+ public function SetInnerHTML($id, $src)
2154
+ {
2155
+ return $this->Replace($id, $src, true);
2156
+ }
2157
+
2158
+ public function GetPlainText($id)
2159
+ {
2160
+ return $this->Implode($id, array("types" => "content", "post_elements" => array("p" => "\n\n", "br" => "\n")));
2161
+ }
2162
+
2163
+ public function SetPlainText($id, $src)
2164
+ {
2165
+ // Convert $src to a string.
2166
+ if ($src instanceof TagFilterNodes)
2167
+ {
2168
+ $src = $src->GetPlainText(0);
2169
+ }
2170
+ else if (is_array($src))
2171
+ {
2172
+ $temp = new TagFilterNodes();
2173
+ $temp->Move($src, 0, 0);
2174
+
2175
+ $src = $temp->GetPlainText(0);
2176
+ }
2177
+ else if (!is_string($src))
2178
+ {
2179
+ $src = $this->GetPlainText((int)$src);
2180
+ }
2181
+
2182
+ $src = array(
2183
+ "type" => "content",
2184
+ "text" => (string)$src,
2185
+ "parent" => false,
2186
+ "parentpos" => false
2187
+ );
2188
+
2189
+ return $this->Replace($id, $src, true);
2190
+ }
2191
+
2192
+ private function RealignChildren($id, $pos)
2193
+ {
2194
+ $y = count($this->nodes[$id]["children"]);
2195
+ for ($x = $pos; $x < $y; $x++) $this->nodes[$this->nodes[$id]["children"][$x]]["parentpos"] = $x;
2196
+ }
2197
+ }
2198
+
2199
+ class TagFilter
2200
+ {
2201
+ // Internal callback function for extracting interior content of HTML 'script' and 'style' tags.
2202
+ public static function HTMLSpecialTagContentCallback($stack, $final, &$tag, &$content, &$cx, $cy, &$content2, $options)
2203
+ {
2204
+ if (preg_match('/<\s*\/\s*' . $stack[0]["tag_name"] . '(\s*|\s+.+?)>/is', $content, $matches, PREG_OFFSET_CAPTURE, $cx))
2205
+ {
2206
+ $pos = $matches[0][1];
2207
+
2208
+ $content2 = substr($content, $cx, $pos - $cx);
2209
+ $cx = $pos;
2210
+ $tag = true;
2211
+
2212
+ return true;
2213
+ }
2214
+ else
2215
+ {
2216
+ if ($final)
2217
+ {
2218
+ $content2 = substr($content, $cx);
2219
+ $cx = $cy;
2220
+ }
2221
+
2222
+ return false;
2223
+ }
2224
+ }
2225
+
2226
+ public static function GetHTMLOptions()
2227
+ {
2228
+ $result = array(
2229
+ "tag_name_map" => array(
2230
+ "!doctype" => "DOCTYPE"
2231
+ ),
2232
+ "untouched_tag_attr_keys" => array(
2233
+ "doctype" => true,
2234
+ ),
2235
+ "void_tags" => array(
2236
+ "DOCTYPE" => true,
2237
+ "area" => true,
2238
+ "base" => true,
2239
+ "bgsound" => true,
2240
+ "br" => true,
2241
+ "col" => true,
2242
+ "embed" => true,
2243
+ "hr" => true,
2244
+ "img" => true,
2245
+ "input" => true,
2246
+ "keygen" => true,
2247
+ "link" => true,
2248
+ "menuitem" => true,
2249
+ "meta" => true,
2250
+ "param" => true,
2251
+ "source" => true,
2252
+ "track" => true,
2253
+ "wbr" => true
2254
+ ),
2255
+ // Alternate tag internal content rules for specialized tags.
2256
+ "alt_tag_content_rules" => array(
2257
+ "script" => __CLASS__ . "::HTMLSpecialTagContentCallback",
2258
+ "style" => __CLASS__ . "::HTMLSpecialTagContentCallback"
2259
+ ),
2260
+ // Stored as a map for open tag elements.
2261
+ // For example, '"address" => array("p" => true)' means: When an open 'address' tag is encountered,
2262
+ // look for an open 'p' tag anywhere (no '_limit') in the tag stack. Apply a closing '</p>' tag for all matches.
2263
+ //
2264
+ // If '_limit' is defined as a string or an array, then stack walking stops as soon as one of the specified tags is encountered.
2265
+ "pre_close_tags" => array(
2266
+ "body" => array("body" => true, "head" => true),
2267
+
2268
+ "address" => array("p" => true),
2269
+ "article" => array("p" => true),
2270
+ "aside" => array("p" => true),
2271
+ "blockquote" => array("p" => true),
2272
+ "div" => array("p" => true),
2273
+ "dl" => array("p" => true),
2274
+ "fieldset" => array("p" => true),
2275
+ "footer" => array("p" => true),
2276
+ "form" => array("p" => true),
2277
+ "h1" => array("p" => true),
2278
+ "h2" => array("p" => true),
2279
+ "h3" => array("p" => true),
2280
+ "h4" => array("p" => true),
2281
+ "h5" => array("p" => true),
2282
+ "h6" => array("p" => true),
2283
+ "header" => array("p" => true),
2284
+ "hr" => array("p" => true),
2285
+ "menu" => array("p" => true),
2286
+ "nav" => array("p" => true),
2287
+ "ol" => array("p" => true),
2288
+ "pre" => array("p" => true),
2289
+ "section" => array("p" => true),
2290
+ "table" => array("p" => true),
2291
+ "ul" => array("p" => true),
2292
+ "p" => array("p" => true),
2293
+
2294
+ "tbody" => array("_limit" => "table", "thead" => true, "tr" => true, "th" => true, "td" => true),
2295
+ "tr" => array("_limit" => "table", "tr" => true, "th" => true, "td" => true),
2296
+ "th" => array("_limit" => "table", "th" => true, "td" => true),
2297
+ "td" => array("_limit" => "table", "th" => true, "td" => true),
2298
+ "tfoot" => array("_limit" => "table", "thead" => true, "tbody" => true, "tr" => true, "th" => true, "td" => true),
2299
+
2300
+ "optgroup" => array("optgroup" => true, "option" => true),
2301
+ "option" => array("option" => true),
2302
+
2303
+ "dd" => array("_limit" => "dl", "dd" => true, "dt" => true),
2304
+ "dt" => array("_limit" => "dl", "dd" => true, "dt" => true),
2305
+
2306
+ "colgroup" => array("colgroup" => true),
2307
+
2308
+ "li" => array("_limit" => array("ul" => true, "ol" => true, "menu" => true, "dir" => true), "li" => true),
2309
+ ),
2310
+ "process_attrs" => array(
2311
+ "class" => "classes",
2312
+ "href" => "uri",
2313
+ "src" => "uri",
2314
+ "dynsrc" => "uri",
2315
+ "lowsrc" => "uri",
2316
+ "background" => "uri",
2317
+ ),
2318
+ "keep_attr_newlines" => false,
2319
+ "keep_comments" => false,
2320
+ "allow_namespaces" => true,
2321
+ "charset" => "UTF-8",
2322
+ "charset_tags" => true,
2323
+ "charset_attrs" => true,
2324
+ "output_mode" => "html",
2325
+ "lowercase_tags" => true,
2326
+ "lowercase_attrs" => true,
2327
+ );
2328
+
2329
+ return $result;
2330
+ }
2331
+
2332
+ public static function Run($content, $options = array())
2333
+ {
2334
+ $tfs = new TagFilterStream($options);
2335
+ $tfs->Finalize();
2336
+ $result = $tfs->Process($content);
2337
+
2338
+ // Clean up output.
2339
+ $result = trim($result);
2340
+ $result = self::CleanupResults($result);
2341
+
2342
+ if (function_exists("gc_mem_caches")) gc_mem_caches();
2343
+
2344
+ return $result;
2345
+ }
2346
+
2347
+ public static function CleanupResults($content)
2348
+ {
2349
+ $result = str_replace("\r\n", "\n", $content);
2350
+ $result = str_replace("\r", "\n", $result);
2351
+ while (strpos($result, "\n\n\n") !== false) $result = str_replace("\n\n\n", "\n\n", $result);
2352
+
2353
+ return $result;
2354
+ }
2355
+
2356
+ public static function ExplodeTagCallback($stack, &$content, $open, $tagname, &$attrs, $options)
2357
+ {
2358
+ if ($open)
2359
+ {
2360
+ $pid = (count($options["data"]->stackmap) ? $options["data"]->stackmap[0] : 0);
2361
+
2362
+ $tagname2 = (isset($options["tag_name_map"][strtolower($tagname)]) ? $options["tag_name_map"][strtolower($tagname)] : $tagname);
2363
+
2364
+ $options["nodes"]->nodes[$options["nodes"]->nextid] = array(
2365
+ "type" => "element",
2366
+ "tag" => $tagname,
2367
+ "attrs" => $attrs,
2368
+ "parent" => $pid,
2369
+ "parentpos" => count($options["nodes"]->nodes[$pid]["children"]),
2370
+ "children" => (isset($options["void_tags"][$tagname2]) ? false : array())
2371
+ );
2372
+
2373
+ $options["nodes"]->nodes[$pid]["children"][] = $options["nodes"]->nextid;
2374
+
2375
+ // Append non-void tags to the ID stack.
2376
+ if (!isset($options["void_tags"][$tagname2])) array_unshift($options["data"]->stackmap, $options["nodes"]->nextid);
2377
+
2378
+ $options["nodes"]->nextid++;
2379
+ }
2380
+ else
2381
+ {
2382
+ array_shift($options["data"]->stackmap);
2383
+ }
2384
+
2385
+ return array("keep_tag" => false, "keep_interior" => false);
2386
+ }
2387
+
2388
+ public static function ExplodeContentCallback($stack, $result, &$content, $options)
2389
+ {
2390
+ if ($content === "") return;
2391
+
2392
+ $type = (substr($content, 0, 5) === "<!-- " ? "comment" : "content");
2393
+ $pid = (count($options["data"]->stackmap) ? $options["data"]->stackmap[0] : 0);
2394
+ $parentpos = count($options["nodes"]->nodes[$pid]["children"]);
2395
+
2396
+ if ($parentpos && $options["nodes"]->nodes[$options["nodes"]->nodes[$pid]["children"][$parentpos - 1]]["type"] == $type) $options["nodes"]->nodes[$options["nodes"]->nodes[$pid]["children"][$parentpos - 1]]["text"] .= $content;
2397
+ else
2398
+ {
2399
+ $options["nodes"]->nodes[$options["nodes"]->nextid] = array(
2400
+ "type" => $type,
2401
+ "text" => $content,
2402
+ "parent" => $pid,
2403
+ "parentpos" => $parentpos
2404
+ );
2405
+
2406
+ $options["nodes"]->nodes[$pid]["children"][] = $options["nodes"]->nextid;
2407
+
2408
+ $options["nodes"]->nextid++;
2409
+ }
2410
+
2411
+ $content = "";
2412
+ }
2413
+
2414
+ public static function Explode($content, $options = array())
2415
+ {
2416
+ $options["tag_callback"] = __CLASS__ . "::ExplodeTagCallback";
2417
+ $options["content_callback"] = __CLASS__ . "::ExplodeContentCallback";
2418
+ $options["nodes"] = new TagFilterNodes();
2419
+ $options["data"] = new stdClass();
2420
+ $options["data"]->stackmap = array();
2421
+
2422
+ self::Run($content, $options);
2423
+
2424
+ return $options["nodes"];
2425
+ }
2426
+
2427
+ public static function HTMLPurifyTagCallback($stack, &$content, $open, $tagname, &$attrs, $options)
2428
+ {
2429
+ if ($open)
2430
+ {
2431
+ if ($tagname === "script") return array("keep_tag" => false, "keep_interior" => false);
2432
+ if ($tagname === "style") return array("keep_tag" => false, "keep_interior" => false);
2433
+
2434
+ if (isset($attrs["src"]) && substr($attrs["src"], 0, 11) === "javascript:") return array("keep_tag" => false, "keep_interior" => false);
2435
+ if (isset($attrs["href"]) && substr($attrs["href"], 0, 11) === "javascript:") return array("keep_tag" => false);
2436
+
2437
+ if (!isset($options["htmlpurify"]["allowed_tags"][$tagname])) return array("keep_tag" => false);
2438
+
2439
+ if (!isset($options["htmlpurify"]["allowed_attrs"][$tagname])) $attrs = array();
2440
+ else
2441
+ {
2442
+ // For classes, "class" needs to be specified as an allowed attribute.
2443
+ foreach ($attrs as $attr => $val)
2444
+ {
2445
+ if (!isset($options["htmlpurify"]["allowed_attrs"][$tagname][$attr])) unset($attrs[$attr]);
2446
+ }
2447
+ }
2448
+
2449
+ if (isset($options["htmlpurify"]["required_attrs"][$tagname]))
2450
+ {
2451
+ foreach ($options["htmlpurify"]["required_attrs"][$tagname] as $attr => $val)
2452
+ {
2453
+ if (!isset($attrs[$attr])) return array("keep_tag" => false);
2454
+ }
2455
+ }
2456
+
2457
+ if (isset($attrs["class"]))
2458
+ {
2459
+ if (!isset($options["htmlpurify"]["allowed_classes"][$tagname])) unset($attrs["class"]);
2460
+ else
2461
+ {
2462
+ foreach ($attrs["class"] as $class)
2463
+ {
2464
+ if (!isset($options["htmlpurify"]["allowed_classes"][$tagname][$class])) unset($attrs["class"][$class]);
2465
+ }
2466
+
2467
+ if (!count($attrs["class"])) unset($attrs["class"]);
2468
+ }
2469
+ }
2470
+ }
2471
+ else
2472
+ {
2473
+ if (isset($options["htmlpurify"]["remove_empty"][substr($tagname, 1)]) && trim(str_replace(array("&nbsp;", "\xC2\xA0"), " ", $content)) === "")
2474
+ {
2475
+ if ($content !== "") $content = " ";
2476
+
2477
+ return array("keep_tag" => false);
2478
+ }
2479
+ }
2480
+
2481
+ return array();
2482
+ }
2483
+
2484
+ private static function Internal_NormalizeHTMLPurifyOptions($value)
2485
+ {
2486
+ if (is_string($value))
2487
+ {
2488
+ $opts = explode(",", $value);
2489
+ $value = array();
2490
+ foreach ($opts as $opt)
2491
+ {
2492
+ $opt = (string)trim($opt);
2493
+ if ($opt !== "") $value[$opt] = true;
2494
+ }
2495
+ }
2496
+
2497
+ return $value;
2498
+ }
2499
+
2500
+ public static function NormalizeHTMLPurifyOptions($purifyopts)
2501
+ {
2502
+ if (!isset($purifyopts["allowed_tags"])) $purifyopts["allowed_tags"] = array();
2503
+ if (!isset($purifyopts["allowed_attrs"])) $purifyopts["allowed_attrs"] = array();
2504
+ if (!isset($purifyopts["required_attrs"])) $purifyopts["required_attrs"] = array();
2505
+ if (!isset($purifyopts["allowed_classes"])) $purifyopts["allowed_classes"] = array();
2506
+ if (!isset($purifyopts["remove_empty"])) $purifyopts["remove_empty"] = array();
2507
+
2508
+ $purifyopts["allowed_tags"] = self::Internal_NormalizeHTMLPurifyOptions($purifyopts["allowed_tags"]);
2509
+ foreach ($purifyopts["allowed_attrs"] as $key => $val) $purifyopts["allowed_attrs"][$key] = self::Internal_NormalizeHTMLPurifyOptions($val);
2510
+ foreach ($purifyopts["required_attrs"] as $key => $val) $purifyopts["required_attrs"][$key] = self::Internal_NormalizeHTMLPurifyOptions($val);
2511
+ foreach ($purifyopts["allowed_classes"] as $key => $val) $purifyopts["allowed_classes"][$key] = self::Internal_NormalizeHTMLPurifyOptions($val);
2512
+ $purifyopts["remove_empty"] = self::Internal_NormalizeHTMLPurifyOptions($purifyopts["remove_empty"]);
2513
+
2514
+ return $purifyopts;
2515
+ }
2516
+
2517
+ public static function HTMLPurify($content, $htmloptions, $purifyopts)
2518
+ {
2519
+ $htmloptions["tag_callback"] = __CLASS__ . "::HTMLPurifyTagCallback";
2520
+ $htmloptions["htmlpurify"] = self::NormalizeHTMLPurifyOptions($purifyopts);
2521
+
2522
+ return self::Run($content, $htmloptions);
2523
+ }
2524
+
2525
+ public static function ReorderSelectorTokens($tokens, $splitrules, $order = array("pseudo-element" => array(), "pseudo-class" => array(), "attr" => array(), "class" => array(), "element" => array(), "id" => array()), $endnots = true)
2526
+ {
2527
+ // Collapse split rules.
2528
+ if (count($tokens) && !isset($tokens[0]["type"]) && isset($tokens[0][0]["type"]))
2529
+ {
2530
+ $tokens2 = array();
2531
+ foreach ($tokens as $rules)
2532
+ {
2533
+ if (count($tokens2)) $tokens2[] = array("type" => "combine", "combine" => "or");
2534
+ $rules = array_reverse($rules);
2535
+ foreach ($rules as $rule) $tokens2[] = $rule;
2536
+ }
2537
+
2538
+ $tokens = $tokens2;
2539
+ }
2540
+
2541
+ $result = array();
2542
+ $rules = array();
2543
+ $selector = $order;
2544
+ foreach ($tokens as $token)
2545
+ {
2546
+ if ($token["type"] != "combine") array_unshift($selector[$token["type"]], $token);
2547
+ else
2548
+ {
2549
+ foreach ($selector as $vals)
2550
+ {
2551
+ foreach ($vals as $token2)
2552
+ {
2553
+ if (($endnots && $token2["not"]) || (!$endnots && !$token2["not"])) array_unshift($result, $token2);
2554
+ }
2555
+
2556
+ foreach ($vals as $token2)
2557
+ {
2558
+ if (($endnots && !$token2["not"]) || (!$endnots && $token2["not"])) array_unshift($result, $token2);
2559
+ }
2560
+ }
2561
+
2562
+ if (!$splitrules || $token["combine"] != "or") array_unshift($result, $token);
2563
+ else if ($token["combine"] == "or")
2564
+ {
2565
+ if (count($result)) $rules[] = $result;
2566
+
2567
+ $result = array();
2568
+ }
2569
+
2570
+ $selector = $order;
2571
+ }
2572
+ }
2573
+
2574
+ foreach ($selector as $vals)
2575
+ {
2576
+ foreach ($vals as $token2)
2577
+ {
2578
+ if (($endnots && $token2["not"]) || (!$endnots && !$token2["not"])) array_unshift($result, $token2);
2579
+ }
2580
+
2581
+ foreach ($vals as $token2)
2582
+ {
2583
+ if (($endnots && !$token2["not"]) || (!$endnots && $token2["not"])) array_unshift($result, $token2);
2584
+ }
2585
+ }
2586
+
2587
+ if ($splitrules)
2588
+ {
2589
+ if (count($result)) $rules[] = $result;
2590
+
2591
+ $result = $rules;
2592
+ }
2593
+ else
2594
+ {
2595
+ // Ignore a stray group combiner at the end.
2596
+ if (count($result) && $result[0]["type"] == "combine" && $result[0]["combine"] == "or") array_shift($result);
2597
+ }
2598
+
2599
+ return $result;
2600
+ }
2601
+
2602
+ public static function ParseSelector($query, $splitrules = false)
2603
+ {
2604
+ // Tokenize query into individual action steps.
2605
+ $query = trim($query);
2606
+ $tokens = array();
2607
+ $lastor = 0;
2608
+ $a = ord("A");
2609
+ $a2 = ord("a");
2610
+ $f = ord("F");
2611
+ $f2 = ord("f");
2612
+ $z = ord("Z");
2613
+ $z2 = ord("z");
2614
+ $backslash = ord("\\");
2615
+ $hyphen = ord("-");
2616
+ $underscore = ord("_");
2617
+ $pipe = ord("|");
2618
+ $asterisk = ord("*");
2619
+ $colon = ord(":");
2620
+ $period = ord(".");
2621
+ $zero = ord("0");
2622
+ $nine = ord("9");
2623
+ $cr = ord("\r");
2624
+ $nl = ord("\n");
2625
+ $ff = ord("\f");
2626
+ $cx = 0;
2627
+ $cy = strlen($query);
2628
+ $state = "next_selector";
2629
+ do
2630
+ {
2631
+ $currcx = $cx;
2632
+ $currstate = $state;
2633
+
2634
+ switch ($state)
2635
+ {
2636
+ case "next_selector":
2637
+ {
2638
+ // This state is necessary to handle the :not(selector) function.
2639
+ $token = array("not" => false);
2640
+ }
2641
+ case "selector":
2642
+ {
2643
+ if ($cx >= $cy) break;
2644
+
2645
+ switch ($query[$cx])
2646
+ {
2647
+ case "#":
2648
+ {
2649
+ $token["type"] = "id";
2650
+ $state = "ident_name";
2651
+ $allownamespace = false;
2652
+ $identasterisk = false;
2653
+ $allowperiod = false;
2654
+ $namespace = false;
2655
+ $range = true;
2656
+ $ident = "";
2657
+ $nextstate = "selector_ident_result";
2658
+ $cx++;
2659
+
2660
+ break;
2661
+ }
2662
+ case ".":
2663
+ {
2664
+ $token["type"] = "class";
2665
+ $state = "ident";
2666
+ $allownamespace = false;
2667
+ $identasterisk = false;
2668
+ $allowperiod = false;
2669
+ $nextstate = "selector_ident_result";
2670
+ $cx++;
2671
+
2672
+ break;
2673
+ }
2674
+ case "[":
2675
+ {
2676
+ $token["type"] = "attr";
2677
+ $state = "ident";
2678
+ $state2 = "attr";
2679
+ $allownamespace = true;
2680
+ $identasterisk = false;
2681
+ $allowperiod = false;
2682
+ $nextstate = "selector_ident_result";
2683
+ $cx++;
2684
+
2685
+ // Find a non-whitespace character.
2686
+ while ($cx < $cy && ($query[$cx] == " " || $query[$cx] == "\t" || $query[$cx] == "\r" || $query[$cx] == "\n" || $query[$cx] == "\f")) $cx++;
2687
+
2688
+ break;
2689
+ }
2690
+ case ":":
2691
+ {
2692
+ $cx++;
2693
+ if ($cx >= $cy || $query[$cx] != ":") $token["type"] = "pseudo-class";
2694
+ else
2695
+ {
2696
+ $token["type"] = "pseudo-element";
2697
+ $cx++;
2698
+ }
2699
+
2700
+ $state = "ident";
2701
+ $allownamespace = true;
2702
+ $identasterisk = false;
2703
+ $allowperiod = false;
2704
+ $nextstate = "selector_ident_result";
2705
+
2706
+ break;
2707
+ }
2708
+ case ",":
2709
+ case "+":
2710
+ case ">":
2711
+ case "~":
2712
+ case " ":
2713
+ case "\r":
2714
+ case "\n":
2715
+ case "\t":
2716
+ case "\f":
2717
+ {
2718
+ $state = "combine";
2719
+
2720
+ break;
2721
+ }
2722
+ default:
2723
+ {
2724
+ $token["type"] = "element";
2725
+ $state = "ident";
2726
+ $allownamespace = true;
2727
+ $identasterisk = true;
2728
+ $allowperiod = false;
2729
+ $nextstate = "selector_ident_result";
2730
+
2731
+ break;
2732
+ }
2733
+ }
2734
+
2735
+ break;
2736
+ }
2737
+ case "selector_ident_result":
2738
+ {
2739
+ switch ($token["type"])
2740
+ {
2741
+ case "id":
2742
+ {
2743
+ $token["id"] = $ident;
2744
+ $tokens[] = $token;
2745
+ $state = ($token["not"] ? "negate_close" : "next_selector");
2746
+
2747
+ break;
2748
+ }
2749
+ case "class":
2750
+ {
2751
+ $token["class"] = $ident;
2752
+ $tokens[] = $token;
2753
+ $state = ($token["not"] ? "negate_close" : "next_selector");
2754
+
2755
+ break;
2756
+ }
2757
+ case "element":
2758
+ {
2759
+ $token["namespace"] = $namespace;
2760
+ $token["tag"] = $ident;
2761
+ $tokens[] = $token;
2762
+ $state = ($token["not"] ? "negate_close" : "next_selector");
2763
+
2764
+ break;
2765
+ }
2766
+ case "attr":
2767
+ {
2768
+ if ($state2 == "attr")
2769
+ {
2770
+ $token["namespace"] = $namespace;
2771
+ $token[$state2] = $ident;
2772
+
2773
+ // Find a non-whitespace character.
2774
+ while ($cx < $cy && ($query[$cx] == " " || $query[$cx] == "\t" || $query[$cx] == "\r" || $query[$cx] == "\n" || $query[$cx] == "\f")) $cx++;
2775
+
2776
+ if ($cx >= $cy || $query[$cx] == "]")
2777
+ {
2778
+ $token["cmp"] = false;
2779
+ $tokens[] = $token;
2780
+ $state = ($token["not"] ? "negate_close" : "next_selector");
2781
+ $cx++;
2782
+ }
2783
+ else
2784
+ {
2785
+ if ($query[$cx] == "=")
2786
+ {
2787
+ $token["cmp"] = "=";
2788
+ $cx++;
2789
+ }
2790
+ else if ($cx + 1 < $cy && ($query[$cx] == "^" || $query[$cx] == "$" || $query[$cx] == "*" || $query[$cx] == "~" || $query[$cx] == "|") && $query[$cx + 1] == "=")
2791
+ {
2792
+ $token["cmp"] = substr($query, $cx, 2);
2793
+ $cx += 2;
2794
+ }
2795
+ else
2796
+ {
2797
+ return array("success" => false, "error" => "Unknown or invalid attribute comparison operator '" . $query[$cx] . "' detected at position " . $cx . ".", "errorcode" => "invalid_attr_compare", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
2798
+ }
2799
+
2800
+ // Find a non-whitespace character.
2801
+ while ($cx < $cy && ($query[$cx] == " " || $query[$cx] == "\t" || $query[$cx] == "\r" || $query[$cx] == "\n" || $query[$cx] == "\f")) $cx++;
2802
+
2803
+ if ($cx < $cy && ($query[$cx] == "\"" || $query[$cx] == "'"))
2804
+ {
2805
+ $state = "string";
2806
+ $endchr = ord($query[$cx]);
2807
+ $cx++;
2808
+ }
2809
+ else
2810
+ {
2811
+ $state = "ident";
2812
+ $allownamespace = false;
2813
+ $identasterisk = false;
2814
+ $allowperiod = false;
2815
+ }
2816
+
2817
+ $state2 = "val";
2818
+ $nextstate = "selector_ident_result";
2819
+ }
2820
+ }
2821
+ else if ($state2 == "val")
2822
+ {
2823
+ $token[$state2] = $ident;
2824
+
2825
+ // Find a non-whitespace character.
2826
+ while ($cx < $cy && ($query[$cx] == " " || $query[$cx] == "\t" || $query[$cx] == "\r" || $query[$cx] == "\n" || $query[$cx] == "\f")) $cx++;
2827
+
2828
+ $tokens[] = $token;
2829
+ $state = ($token["not"] ? "negate_close" : "next_selector");
2830
+
2831
+ if ($cx < $cy && $query[$cx] == "]") $cx++;
2832
+ }
2833
+
2834
+ break;
2835
+ }
2836
+ case "pseudo-class":
2837
+ case "pseudo-element":
2838
+ {
2839
+ $ident = strtolower($ident);
2840
+
2841
+ // Deal with CSS1 and CSS2 compatibility.
2842
+ if ($ident === "first-line" || $ident === "first-letter" || $ident === "before" || $ident === "after") $token["type"] = "pseudo-element";
2843
+
2844
+ if ($token["type"] == "pseudo-class" && $ident == "not")
2845
+ {
2846
+ if ($token["not"]) return array("success" => false, "error" => "Invalid :not() embedded inside another :not() detected at position " . $cx . ".", "errorcode" => "invalid_not", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
2847
+ if ($cx >= $cy || $query[$cx] != "(") return array("success" => false, "error" => "Missing '(' detected at position " . $cx . ".", "errorcode" => "invalid_not", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
2848
+
2849
+ unset($token["type"]);
2850
+ $token["not"] = true;
2851
+
2852
+ $state = "selector";
2853
+ $cx++;
2854
+
2855
+ // Find a non-whitespace character.
2856
+ while ($cx < $cy && ($query[$cx] == " " || $query[$cx] == "\t" || $query[$cx] == "\r" || $query[$cx] == "\n" || $query[$cx] == "\f")) $cx++;
2857
+ }
2858
+ else
2859
+ {
2860
+ $token["pseudo"] = $ident;
2861
+
2862
+ if ($cx < $cy && $query[$cx] == "(")
2863
+ {
2864
+ $token["expression"] = "";
2865
+ $ident = "";
2866
+ $state = "pseudo_expression";
2867
+ $cx++;
2868
+ }
2869
+ else
2870
+ {
2871
+ $token["expression"] = false;
2872
+ $tokens[] = $token;
2873
+ $state = ($token["not"] ? "negate_close" : "next_selector");
2874
+ }
2875
+ }
2876
+
2877
+ break;
2878
+ }
2879
+ }
2880
+
2881
+ break;
2882
+ }
2883
+ case "negate_close":
2884
+ {
2885
+ // Find a non-whitespace character.
2886
+ while ($cx < $cy && ($query[$cx] == " " || $query[$cx] == "\t" || $query[$cx] == "\r" || $query[$cx] == "\n" || $query[$cx] == "\f")) $cx++;
2887
+
2888
+ if ($cx < $cy && $query[$cx] != ")") return array("success" => false, "error" => "Invalid :not() close character '" . $query[$cx] . "' detected at position " . $cx . ".", "errorcode" => "invalid_negate_close", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
2889
+
2890
+ $cx++;
2891
+ $state = "next_selector";
2892
+
2893
+ break;
2894
+ }
2895
+ case "pseudo_expression":
2896
+ {
2897
+ $token["expression"] .= $ident;
2898
+
2899
+ // Find a non-whitespace character.
2900
+ while ($cx < $cy && ($query[$cx] == " " || $query[$cx] == "\t" || $query[$cx] == "\r" || $query[$cx] == "\n" || $query[$cx] == "\f")) $cx++;
2901
+
2902
+ if ($cx >= $cy) break;
2903
+
2904
+ if ($query[$cx] == ")")
2905
+ {
2906
+ if (substr($token["pseudo"], 0, 4) === "nth-")
2907
+ {
2908
+ // Convert the expression to an+b syntax.
2909
+ $exp = strtolower($token["expression"]);
2910
+
2911
+ if ($exp == "even") $exp = "2n";
2912
+ else if ($exp == "odd") $exp = "2n+1";
2913
+ else
2914
+ {
2915
+ do
2916
+ {
2917
+ $currexp = $exp;
2918
+
2919
+ $exp = str_replace(array("++", "+-", "-+", "--"), array("+", "-", "-", "+"), $exp);
2920
+
2921
+ } while ($currexp !== $exp);
2922
+ }
2923
+
2924
+ if (substr($exp, 0, 2) == "-n") $exp = "-1n" . substr($exp, 2);
2925
+ else if (substr($exp, 0, 2) == "+n") $exp = "1n" . substr($exp, 2);
2926
+ else if (substr($exp, 0, 1) == "n") $exp = "1n" . substr($exp, 1);
2927
+
2928
+ $pos = strpos($exp, "n");
2929
+ if ($pos === false)
2930
+ {
2931
+ $token["a"] = 0;
2932
+ $token["b"] = (double)$exp;
2933
+ }
2934
+ else
2935
+ {
2936
+ $token["a"] = (double)$exp;
2937
+ $token["b"] = (double)substr($exp, $pos + 1);
2938
+ }
2939
+
2940
+ $token["expression"] = $token["a"] . "n" . ($token["b"] < 0 ? $token["b"] : "+" . $token["b"]);
2941
+ }
2942
+
2943
+ $tokens[] = $token;
2944
+ $state = ($token["not"] ? "negate_close" : "next_selector");
2945
+ $cx++;
2946
+ }
2947
+ else if ($query[$cx] == "+" || $query[$cx] == "-")
2948
+ {
2949
+ $ident = $query[$cx];
2950
+ $cx++;
2951
+ }
2952
+ else if ($query[$cx] == "\"" || $query[$cx] == "'")
2953
+ {
2954
+ $state = "string";
2955
+ $endchr = ord($query[$cx]);
2956
+ $cx++;
2957
+ }
2958
+ else
2959
+ {
2960
+ $val = ord($query[$cx]);
2961
+
2962
+ $state = ($val >= $zero && $val <= $nine ? "ident_name" : "ident");
2963
+ $allownamespace = false;
2964
+ $identasterisk = false;
2965
+ $allowperiod = ($val >= $zero && $val <= $nine);
2966
+ $namespace = false;
2967
+ $range = true;
2968
+ $ident = "";
2969
+
2970
+ $nextstate = "pseudo_expression";
2971
+ }
2972
+
2973
+ break;
2974
+ }
2975
+ case "string":
2976
+ {
2977
+ $startcx = $cx;
2978
+ $ident = "";
2979
+
2980
+ for (; $cx < $cy; $cx++)
2981
+ {
2982
+ $val = ord($query[$cx]);
2983
+
2984
+ if ($val == $endchr)
2985
+ {
2986
+ $cx++;
2987
+
2988
+ break;
2989
+ }
2990
+ else if ($val == $backslash)
2991
+ {
2992
+ // Escape sequence.
2993
+ if ($cx + 1 >= $cy) $ident .= "\\";
2994
+ else
2995
+ {
2996
+ $cx++;
2997
+ $val = ord($query[$cx]);
2998
+
2999
+ if (($val >= $a && $val <= $f) || ($val >= $a2 && $val <= $f2) || ($val >= $zero && $val <= $nine))
3000
+ {
3001
+ // Unicode (e.g. \0020)
3002
+ for ($x = $cx + 1; $x < $cy; $x++)
3003
+ {
3004
+ $val = ord($query[$x]);
3005
+ if (!(($val >= $a && $val <= $f) || ($val >= $a2 && $val <= $f2) || ($val >= $zero && $val <= $nine))) break;
3006
+ }
3007
+
3008
+ $num = hexdec(substr($query, $cx, $x - $cx));
3009
+ $cx = $x - 1;
3010
+
3011
+ $ident .= TagFilterStream::UTF8Chr($num);
3012
+
3013
+ // Skip one optional \r\n OR a single whitespace char.
3014
+ if ($cx + 2 < $cy && $query[$cx + 1] == "\r" && $query[$cx + 2] == "\n") $cx += 2;
3015
+ else if ($cx + 1 < $cy && ($query[$cx + 1] == " " || $query[$cx + 1] == "\r" || $query[$cx + 1] == "\n" || $query[$cx + 1] == "\t" || $query[$cx + 1] == "\f")) $cx++;
3016
+ }
3017
+ else
3018
+ {
3019
+ $ident .= $query[$cx];
3020
+ }
3021
+ }
3022
+ }
3023
+ else
3024
+ {
3025
+ $ident .= $query[$cx];
3026
+ }
3027
+ }
3028
+
3029
+ $state = $nextstate;
3030
+
3031
+ break;
3032
+ }
3033
+ case "ident":
3034
+ {
3035
+ $namespace = false;
3036
+ $range = false;
3037
+
3038
+ if ($cx >= $cy) break;
3039
+
3040
+ if ($query[$cx] != "-") $ident = "";
3041
+ else
3042
+ {
3043
+ $ident = "-";
3044
+ $cx++;
3045
+ }
3046
+
3047
+ $state = "ident_name";
3048
+
3049
+ break;
3050
+ }
3051
+ case "ident_name":
3052
+ {
3053
+ // Find the first invalid character.
3054
+ $startcx = $cx;
3055
+ for (; $cx < $cy; $cx++)
3056
+ {
3057
+ $val = ord($query[$cx]);
3058
+
3059
+ if ($val != $period && ($val < $zero || $val > $nine)) $allowperiod = false;
3060
+
3061
+ if (($val >= $a && $val <= $z) || ($val >= $a2 && $val <= $z2) || $val == $underscore || $val > 127)
3062
+ {
3063
+ $ident .= $query[$cx];
3064
+ }
3065
+ else if ($allowperiod && $val == $period)
3066
+ {
3067
+ $allowperiod = false;
3068
+
3069
+ $ident .= ".";
3070
+ }
3071
+ else if ($val == $hyphen || ($val >= $zero && $val <= $nine))
3072
+ {
3073
+ // Only allowed AFTER the first character.
3074
+ if (!$range) return array("success" => false, "error" => "Invalid identifier character '" . $query[$cx] . "' detected at position " . $cx . ".", "errorcode" => "invalid_ident", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
3075
+
3076
+ $allowperiod = false;
3077
+
3078
+ $ident .= $query[$cx];
3079
+ }
3080
+ else if ($val == $backslash)
3081
+ {
3082
+ // Escape sequence.
3083
+ if ($cx + 1 >= $cy) $ident .= "\\";
3084
+ else
3085
+ {
3086
+ $cx++;
3087
+ $val = ord($query[$cx]);
3088
+
3089
+ if (($val >= $a && $val <= $f) || ($val >= $a2 && $val <= $f2) || ($val >= $zero && $val <= $nine))
3090
+ {
3091
+ // Unicode (e.g. \0020)
3092
+ for ($x = $cx + 1; $x < $cy; $x++)
3093
+ {
3094
+ $val = ord($query[$x]);
3095
+ if (!(($val >= $a && $val <= $f) || ($val >= $a2 && $val <= $f2) || ($val >= $zero && $val <= $nine))) break;
3096
+ }
3097
+
3098
+ $num = hexdec(substr($query, $cx, $x - $cx));
3099
+ $cx = $x - 1;
3100
+
3101
+ $ident .= TagFilterStream::UTF8Chr($num);
3102
+
3103
+ // Skip one optional \r\n OR a single whitespace char.
3104
+ if ($cx + 2 < $cy && $query[$cx + 1] == "\r" && $query[$cx + 2] == "\n") $cx += 2;
3105
+ else if ($cx + 1 < $cy && ($query[$cx + 1] == " " || $query[$cx + 1] == "\r" || $query[$cx + 1] == "\n" || $query[$cx + 1] == "\t" || $query[$cx + 1] == "\f")) $cx++;
3106
+ }
3107
+ else if ($val != $cr && $val != $nl && $val != $ff)
3108
+ {
3109
+ $ident .= $query[$cx];
3110
+ }
3111
+ }
3112
+ }
3113
+ else if ($allownamespace && $val == $pipe && ($cx + 1 >= $cy || $query[$cx + 1] != "="))
3114
+ {
3115
+ // Handle namespaces (rare).
3116
+ if ($ident != "")
3117
+ {
3118
+ $namespace = $ident;
3119
+ $ident = "";
3120
+ }
3121
+
3122
+ $allownamespace = false;
3123
+ }
3124
+ else if ($val == $asterisk)
3125
+ {
3126
+ // Handle wildcard (*) characters.
3127
+ if ($allownamespace && $cx + 1 < $cy && $query[$cx + 1] == "|")
3128
+ {
3129
+ // Wildcard namespace (*|).
3130
+ $namespace = "*";
3131
+ $allownamespace = false;
3132
+ $cx++;
3133
+ }
3134
+ else if ($identasterisk)
3135
+ {
3136
+ if ($ident != "") return array("success" => false, "error" => "Invalid identifier wildcard character '*' detected at position " . $cx . ".", "errorcode" => "invalid_wildcard_ident", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
3137
+
3138
+ $ident = "*";
3139
+ $cx++;
3140
+
3141
+ break;
3142
+ }
3143
+ else
3144
+ {
3145
+ // End of ident.
3146
+ break;
3147
+ }
3148
+ }
3149
+ else
3150
+ {
3151
+ // End of ident.
3152
+ break;
3153
+ }
3154
+
3155
+ $range = true;
3156
+ }
3157
+
3158
+ if ($ident == "") return array("success" => false, "error" => "Missing or invalid identifier at position " . $cx . ".", "errorcode" => "missing_ident", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
3159
+
3160
+ $state = $nextstate;
3161
+
3162
+ break;
3163
+ }
3164
+ case "combine":
3165
+ {
3166
+ $token = array("type" => "combine");
3167
+
3168
+ // Find a non-whitespace character.
3169
+ while ($cx < $cy && ($query[$cx] == " " || $query[$cx] == "\t" || $query[$cx] == "\r" || $query[$cx] == "\n" || $query[$cx] == "\f")) $cx++;
3170
+
3171
+ if ($cx < $cy)
3172
+ {
3173
+ switch ($query[$cx])
3174
+ {
3175
+ case ",":
3176
+ {
3177
+ $token["combine"] = "or";
3178
+ $lastor = count($tokens);
3179
+ $cx++;
3180
+
3181
+ break;
3182
+ }
3183
+ case "+":
3184
+ {
3185
+ $token["combine"] = "prev-sibling";
3186
+ $cx++;
3187
+
3188
+ break;
3189
+ }
3190
+ case ">":
3191
+ {
3192
+ $token["combine"] = "prev-parent";
3193
+ $cx++;
3194
+
3195
+ break;
3196
+ }
3197
+ case "~":
3198
+ {
3199
+ $token["combine"] = "any-prev-sibling";
3200
+ $cx++;
3201
+
3202
+ break;
3203
+ }
3204
+ default:
3205
+ {
3206
+ $token["combine"] = "any-parent";
3207
+
3208
+ break;
3209
+ }
3210
+ }
3211
+
3212
+ if (!count($tokens) || $tokens[count($tokens) - 1]["type"] == "combine") return array("success" => false, "error" => "Invalid combiner '" . $token["type"] . "' detected at position " . $cx . ".", "errorcode" => "invalid_combiner", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
3213
+
3214
+ $tokens[] = $token;
3215
+
3216
+ // Find a non-whitespace character.
3217
+ while ($cx < $cy && ($query[$cx] == " " || $query[$cx] == "\t" || $query[$cx] == "\r" || $query[$cx] == "\n" || $query[$cx] == "\f")) $cx++;
3218
+ }
3219
+
3220
+ $state = "next_selector";
3221
+
3222
+ break;
3223
+ }
3224
+ }
3225
+ } while ($currstate !== $state || $currcx !== $cx);
3226
+
3227
+ return array("success" => true, "selector" => $query, "tokens" => self::ReorderSelectorTokens($tokens, $splitrules), "splitrules" => $splitrules);
3228
+ }
3229
+
3230
+ public static function GetParentPos($stack, $tagname, $start = 0, $attrs = array())
3231
+ {
3232
+ $y = count($stack);
3233
+ for ($x = $start; $x < $y; $x++)
3234
+ {
3235
+ if ($stack[$x]["tag_name"] === $tagname)
3236
+ {
3237
+ $found = true;
3238
+ foreach ($attrs as $key => $val)
3239
+ {
3240
+ if (!isset($stack[$x]["attrs"][$key])) $found = false;
3241
+ else if (is_string($stack[$x]["attrs"][$key]) && is_string($val) && stripos($stack[$x]["attrs"][$key], $val) === false) $found = false;
3242
+ else if (is_array($stack[$x]["attrs"][$key]))
3243
+ {
3244
+ if (is_string($val)) $val = explode(" ", $val);
3245
+
3246
+ foreach ($val as $val2)
3247
+ {
3248
+ if ($val2 !== "" && !isset($stack[$x]["attrs"][$key][$val2])) $found = false;
3249
+ }
3250
+ }
3251
+ }
3252
+
3253
+ if ($found) return $x;
3254
+ }
3255
+ }
3256
+
3257
+ return false;
3258
+ }
3259
+ }
3260
  ?>
vendor/icomoon/fonts/ez-toc-icomoon.svg CHANGED
@@ -1,11 +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>
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/selection.json CHANGED
@@ -1,75 +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
  }
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 CHANGED
@@ -1,33 +1,33 @@
1
- @font-face {
2
- font-display: swap;
3
- font-family: 'ez-toc-icomoon';
4
- src:url('fonts/ez-toc-icomoon.eot');
5
- src:url('fonts/ez-toc-icomoon.eot?#iefix') format('embedded-opentype'),
6
- url('fonts/ez-toc-icomoon.woff2') format('woff2'),
7
- url('fonts/ez-toc-icomoon.woff') format('woff'),
8
- url('fonts/ez-toc-icomoon.ttf') format('truetype'),
9
- url('fonts/ez-toc-icomoon.svg#ez-toc-icomoon') format('svg');
10
- font-weight: normal;
11
- font-style: normal;
12
- }
13
- /*
14
- * Do not load these styles!!!
15
- * @link https://wordpress.org/support/topic/specify-css-rule-for-tag/
16
- */
17
- /*i {*/
18
- /*font-family: 'ez-toc-icomoon';*/
19
- /*speak: none;*/
20
- /*font-style: normal;*/
21
- /*font-weight: normal;*/
22
- /*font-variant: normal;*/
23
- /*text-transform: none;*/
24
- /*line-height: 1;*/
25
-
26
- /*!* Better Font Rendering =========== *!*/
27
- /*-webkit-font-smoothing: antialiased;*/
28
- /*-moz-osx-font-smoothing: grayscale;*/
29
- /*}*/
30
-
31
- /*.icon-menu:before {*/
32
- /*content: "\e87a";*/
33
- /*}*/
1
+ @font-face {
2
+ font-display: swap;
3
+ font-family: 'ez-toc-icomoon';
4
+ src:url('fonts/ez-toc-icomoon.eot');
5
+ src:url('fonts/ez-toc-icomoon.eot?#iefix') format('embedded-opentype'),
6
+ url('fonts/ez-toc-icomoon.woff2') format('woff2'),
7
+ url('fonts/ez-toc-icomoon.woff') format('woff'),
8
+ url('fonts/ez-toc-icomoon.ttf') format('truetype'),
9
+ url('fonts/ez-toc-icomoon.svg#ez-toc-icomoon') format('svg');
10
+ font-weight: normal;
11
+ font-style: normal;
12
+ }
13
+ /*
14
+ * Do not load these styles!!!
15
+ * @link https://wordpress.org/support/topic/specify-css-rule-for-tag/
16
+ */
17
+ /*i {*/
18
+ /*font-family: 'ez-toc-icomoon';*/
19
+ /*speak: none;*/
20
+ /*font-style: normal;*/
21
+ /*font-weight: normal;*/
22
+ /*font-variant: normal;*/
23
+ /*text-transform: none;*/
24
+ /*line-height: 1;*/
25
+
26
+ /*!* Better Font Rendering =========== *!*/
27
+ /*-webkit-font-smoothing: antialiased;*/
28
+ /*-moz-osx-font-smoothing: grayscale;*/
29
+ /*}*/
30
+
31
+ /*.icon-menu:before {*/
32
+ /*content: "\e87a";*/
33
+ /*}*/
vendor/js-cookie/js.cookie.js CHANGED
@@ -1,163 +1,163 @@
1
- /*!
2
- * JavaScript Cookie v2.2.1
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
- var registeredInModuleLoader;
10
- if (typeof define === 'function' && define.amd) {
11
- define(factory);
12
- registeredInModuleLoader = true;
13
- }
14
- if (typeof exports === 'object') {
15
- module.exports = factory();
16
- registeredInModuleLoader = true;
17
- }
18
- if (!registeredInModuleLoader) {
19
- var OldCookies = window.Cookies;
20
- var api = window.Cookies = factory();
21
- api.noConflict = function () {
22
- window.Cookies = OldCookies;
23
- return api;
24
- };
25
- }
26
- }(function () {
27
- function extend () {
28
- var i = 0;
29
- var result = {};
30
- for (; i < arguments.length; i++) {
31
- var attributes = arguments[ i ];
32
- for (var key in attributes) {
33
- result[key] = attributes[key];
34
- }
35
- }
36
- return result;
37
- }
38
-
39
- function decode (s) {
40
- return s.replace(/(%[0-9A-Z]{2})+/g, decodeURIComponent);
41
- }
42
-
43
- function init (converter) {
44
- function api() {}
45
-
46
- function set (key, value, attributes) {
47
- if (typeof document === 'undefined') {
48
- return;
49
- }
50
-
51
- attributes = extend({
52
- path: '/'
53
- }, api.defaults, attributes);
54
-
55
- if (typeof attributes.expires === 'number') {
56
- attributes.expires = new Date(new Date() * 1 + attributes.expires * 864e+5);
57
- }
58
-
59
- // We're using "expires" because "max-age" is not supported by IE
60
- attributes.expires = attributes.expires ? attributes.expires.toUTCString() : '';
61
-
62
- try {
63
- var result = JSON.stringify(value);
64
- if (/^[\{\[]/.test(result)) {
65
- value = result;
66
- }
67
- } catch (e) {}
68
-
69
- value = converter.write ?
70
- converter.write(value, key) :
71
- encodeURIComponent(String(value))
72
- .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
73
-
74
- key = encodeURIComponent(String(key))
75
- .replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent)
76
- .replace(/[\(\)]/g, escape);
77
-
78
- var stringifiedAttributes = '';
79
- for (var attributeName in attributes) {
80
- if (!attributes[attributeName]) {
81
- continue;
82
- }
83
- stringifiedAttributes += '; ' + attributeName;
84
- if (attributes[attributeName] === true) {
85
- continue;
86
- }
87
-
88
- // Considers RFC 6265 section 5.2:
89
- // ...
90
- // 3. If the remaining unparsed-attributes contains a %x3B (";")
91
- // character:
92
- // Consume the characters of the unparsed-attributes up to,
93
- // not including, the first %x3B (";") character.
94
- // ...
95
- stringifiedAttributes += '=' + attributes[attributeName].split(';')[0];
96
- }
97
-
98
- return (document.cookie = key + '=' + value + stringifiedAttributes);
99
- }
100
-
101
- function get (key, json) {
102
- if (typeof document === 'undefined') {
103
- return;
104
- }
105
-
106
- var jar = {};
107
- // To prevent the for loop in the first place assign an empty array
108
- // in case there are no cookies at all.
109
- var cookies = document.cookie ? document.cookie.split('; ') : [];
110
- var i = 0;
111
-
112
- for (; i < cookies.length; i++) {
113
- var parts = cookies[i].split('=');
114
- var cookie = parts.slice(1).join('=');
115
-
116
- if (!json && cookie.charAt(0) === '"') {
117
- cookie = cookie.slice(1, -1);
118
- }
119
-
120
- try {
121
- var name = decode(parts[0]);
122
- cookie = (converter.read || converter)(cookie, name) ||
123
- decode(cookie);
124
-
125
- if (json) {
126
- try {
127
- cookie = JSON.parse(cookie);
128
- } catch (e) {}
129
- }
130
-
131
- jar[name] = cookie;
132
-
133
- if (key === name) {
134
- break;
135
- }
136
- } catch (e) {}
137
- }
138
-
139
- return key ? jar[key] : jar;
140
- }
141
-
142
- api.set = set;
143
- api.get = function (key) {
144
- return get(key, false /* read as raw */);
145
- };
146
- api.getJSON = function (key) {
147
- return get(key, true /* read as json */);
148
- };
149
- api.remove = function (key, attributes) {
150
- set(key, '', extend(attributes, {
151
- expires: -1
152
- }));
153
- };
154
-
155
- api.defaults = {};
156
-
157
- api.withConverter = init;
158
-
159
- return api;
160
- }
161
-
162
- return init(function () {});
163
- }));
1
+ /*!
2
+ * JavaScript Cookie v2.2.1
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
+ var registeredInModuleLoader;
10
+ if (typeof define === 'function' && define.amd) {
11
+ define(factory);
12
+ registeredInModuleLoader = true;
13
+ }
14
+ if (typeof exports === 'object') {
15
+ module.exports = factory();
16
+ registeredInModuleLoader = true;
17
+ }
18
+ if (!registeredInModuleLoader) {
19
+ var OldCookies = window.Cookies;
20
+ var api = window.Cookies = factory();
21
+ api.noConflict = function () {
22
+ window.Cookies = OldCookies;
23
+ return api;
24
+ };
25
+ }
26
+ }(function () {
27
+ function extend () {
28
+ var i = 0;
29
+ var result = {};
30
+ for (; i < arguments.length; i++) {
31
+ var attributes = arguments[ i ];
32
+ for (var key in attributes) {
33
+ result[key] = attributes[key];
34
+ }
35
+ }
36
+ return result;
37
+ }
38
+
39
+ function decode (s) {
40
+ return s.replace(/(%[0-9A-Z]{2})+/g, decodeURIComponent);
41
+ }
42
+
43
+ function init (converter) {
44
+ function api() {}
45
+
46
+ function set (key, value, attributes) {
47
+ if (typeof document === 'undefined') {
48
+ return;
49
+ }
50
+
51
+ attributes = extend({
52
+ path: '/'
53
+ }, api.defaults, attributes);
54
+
55
+ if (typeof attributes.expires === 'number') {
56
+ attributes.expires = new Date(new Date() * 1 + attributes.expires * 864e+5);
57
+ }
58
+
59
+ // We're using "expires" because "max-age" is not supported by IE
60
+ attributes.expires = attributes.expires ? attributes.expires.toUTCString() : '';
61
+
62
+ try {
63
+ var result = JSON.stringify(value);
64
+ if (/^[\{\[]/.test(result)) {
65
+ value = result;
66
+ }
67
+ } catch (e) {}
68
+
69
+ value = converter.write ?
70
+ converter.write(value, key) :
71
+ encodeURIComponent(String(value))
72
+ .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
73
+
74
+ key = encodeURIComponent(String(key))
75
+ .replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent)
76
+ .replace(/[\(\)]/g, escape);
77
+
78
+ var stringifiedAttributes = '';
79
+ for (var attributeName in attributes) {
80
+ if (!attributes[attributeName]) {
81
+ continue;
82
+ }
83
+ stringifiedAttributes += '; ' + attributeName;
84
+ if (attributes[attributeName] === true) {
85
+ continue;
86
+ }
87
+
88
+ // Considers RFC 6265 section 5.2:
89
+ // ...
90
+ // 3. If the remaining unparsed-attributes contains a %x3B (";")
91
+ // character:
92
+ // Consume the characters of the unparsed-attributes up to,
93
+ // not including, the first %x3B (";") character.
94
+ // ...
95
+ stringifiedAttributes += '=' + attributes[attributeName].split(';')[0];
96
+ }
97
+
98
+ return (document.cookie = key + '=' + value + stringifiedAttributes);
99
+ }
100
+
101
+ function get (key, json) {
102
+ if (typeof document === 'undefined') {
103
+ return;
104
+ }
105
+
106
+ var jar = {};
107
+ // To prevent the for loop in the first place assign an empty array
108
+ // in case there are no cookies at all.
109
+ var cookies = document.cookie ? document.cookie.split('; ') : [];
110
+ var i = 0;
111
+
112
+ for (; i < cookies.length; i++) {
113
+ var parts = cookies[i].split('=');
114
+ var cookie = parts.slice(1).join('=');
115
+
116
+ if (!json && cookie.charAt(0) === '"') {
117
+ cookie = cookie.slice(1, -1);
118
+ }
119
+
120
+ try {
121
+ var name = decode(parts[0]);
122
+ cookie = (converter.read || converter)(cookie, name) ||
123
+ decode(cookie);
124
+
125
+ if (json) {
126
+ try {
127
+ cookie = JSON.parse(cookie);
128
+ } catch (e) {}
129
+ }
130
+
131
+ jar[name] = cookie;
132
+
133
+ if (key === name) {
134
+ break;
135
+ }
136
+ } catch (e) {}
137
+ }
138
+
139
+ return key ? jar[key] : jar;
140
+ }
141
+
142
+ api.set = set;
143
+ api.get = function (key) {
144
+ return get(key, false /* read as raw */);
145
+ };
146
+ api.getJSON = function (key) {
147
+ return get(key, true /* read as json */);
148
+ };
149
+ api.remove = function (key, attributes) {
150
+ set(key, '', extend(attributes, {
151
+ expires: -1
152
+ }));
153
+ };
154
+
155
+ api.defaults = {};
156
+
157
+ api.withConverter = init;
158
+
159
+ return api;
160
+ }
161
+
162
+ return init(function () {});
163
+ }));
vendor/smooth-scroll/jquery.smooth-scroll.js CHANGED
@@ -1,338 +1,338 @@
1
- (function($) {
2
- var version = '2.2.0';
3
- var optionOverrides = {};
4
- var defaults = {
5
- exclude: [],
6
- excludeWithin: [],
7
- offset: 0,
8
-
9
- // one of 'top' or 'left'
10
- direction: 'top',
11
-
12
- // if set, bind click events through delegation
13
- // supported since jQuery 1.4.2
14
- delegateSelector: null,
15
-
16
- // jQuery set of elements you wish to scroll (for $.smoothScroll).
17
- // if null (default), $('html, body').firstScrollable() is used.
18
- scrollElement: null,
19
-
20
- // only use if you want to override default behavior
21
- scrollTarget: null,
22
-
23
- // automatically focus the target element after scrolling to it
24
- autoFocus: false,
25
-
26
- // fn(opts) function to be called before scrolling occurs.
27
- // `this` is the element(s) being scrolled
28
- beforeScroll: function() {},
29
-
30
- // fn(opts) function to be called after scrolling occurs.
31
- // `this` is the triggering element
32
- afterScroll: function() {},
33
-
34
- // easing name. jQuery comes with "swing" and "linear." For others, you'll need an easing plugin
35
- // from jQuery UI or elsewhere
36
- easing: 'swing',
37
-
38
- // speed can be a number or 'auto'
39
- // if 'auto', the speed will be calculated based on the formula:
40
- // (current scroll position - target scroll position) / autoCoeffic
41
- speed: 400,
42
-
43
- // coefficient for "auto" speed
44
- autoCoefficient: 2,
45
-
46
- // $.fn.smoothScroll only: whether to prevent the default click action
47
- preventDefault: true
48
- };
49
-
50
- var getScrollable = function(opts) {
51
- var scrollable = [];
52
- var scrolled = false;
53
- var dir = opts.dir && opts.dir === 'left' ? 'scrollLeft' : 'scrollTop';
54
-
55
- this.each(function() {
56
- var el = $(this);
57
-
58
- if (this === document || this === window) {
59
- return;
60
- }
61
-
62
- if (document.scrollingElement && (this === document.documentElement || this === document.body)) {
63
- scrollable.push(document.scrollingElement);
64
-
65
- return false;
66
- }
67
-
68
- if (el[dir]() > 0) {
69
- scrollable.push(this);
70
- } else {
71
- // if scroll(Top|Left) === 0, nudge the element 1px and see if it moves
72
- el[dir](1);
73
- scrolled = el[dir]() > 0;
74
-
75
- if (scrolled) {
76
- scrollable.push(this);
77
- }
78
- // then put it back, of course
79
- el[dir](0);
80
- }
81
- });
82
-
83
- if (!scrollable.length) {
84
- this.each(function() {
85
- // If no scrollable elements and <html> has scroll-behavior:smooth because
86
- // "When this property is specified on the root element, it applies to the viewport instead."
87
- // and "The scroll-behavior property of the … body element is *not* propagated to the viewport."
88
- // → https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior
89
- if (this === document.documentElement && $(this).css('scrollBehavior') === 'smooth') {
90
- scrollable = [this];
91
- }
92
-
93
- // If still no scrollable elements, fall back to <body>,
94
- // if it's in the jQuery collection
95
- // (doing this because Safari sets scrollTop async,
96
- // so can't set it to 1 and immediately get the value.)
97
- if (!scrollable.length && this.nodeName === 'BODY') {
98
- scrollable = [this];
99
- }
100
- });
101
- }
102
-
103
- // Use the first scrollable element if we're calling firstScrollable()
104
- if (opts.el === 'first' && scrollable.length > 1) {
105
- scrollable = [scrollable[0]];
106
- }
107
-
108
- return scrollable;
109
- };
110
-
111
- var rRelative = /^([\-\+]=)(\d+)/;
112
-
113
- $.fn.extend({
114
- scrollable: function(dir) {
115
- var scrl = getScrollable.call(this, {dir: dir});
116
-
117
- return this.pushStack(scrl);
118
- },
119
- firstScrollable: function(dir) {
120
- var scrl = getScrollable.call(this, {el: 'first', dir: dir});
121
-
122
- return this.pushStack(scrl);
123
- },
124
-
125
- smoothScroll: function(options, extra) {
126
- options = options || {};
127
-
128
- if (options === 'options') {
129
- if (!extra) {
130
- return this.first().data('ssOpts');
131
- }
132
-
133
- return this.each(function() {
134
- var $this = $(this);
135
- var opts = $.extend($this.data('ssOpts') || {}, extra);
136
-
137
- $(this).data('ssOpts', opts);
138
- });
139
- }
140
-
141
- var opts = $.extend({}, $.fn.smoothScroll.defaults, options);
142
-
143
- var clickHandler = function(event) {
144
- var escapeSelector = function(str) {
145
- return str.replace(/(:|\.|\/)/g, '\\$1');
146
- };
147
-
148
- var link = this;
149
- var $link = $(this);
150
- var thisOpts = $.extend({}, opts, $link.data('ssOpts') || {});
151
- var exclude = opts.exclude;
152
- var excludeWithin = thisOpts.excludeWithin;
153
- var elCounter = 0;
154
- var ewlCounter = 0;
155
- var include = true;
156
- var clickOpts = {};
157
- var locationPath = $.smoothScroll.filterPath(location.pathname);
158
- var linkPath = $.smoothScroll.filterPath(link.pathname);
159
- var hostMatch = location.hostname === link.hostname || !link.hostname;
160
- var pathMatch = thisOpts.scrollTarget || (linkPath === locationPath);
161
- var thisHash = escapeSelector(link.hash);
162
-
163
- if (thisHash && !$(thisHash).length) {
164
- include = false;
165
- }
166
-
167
- if (!thisOpts.scrollTarget && (!hostMatch || !pathMatch || !thisHash)) {
168
- include = false;
169
- } else {
170
- while (include && elCounter < exclude.length) {
171
- if ($link.is(escapeSelector(exclude[elCounter++]))) {
172
- include = false;
173
- }
174
- }
175
-
176
- while (include && ewlCounter < excludeWithin.length) {
177
- if ($link.closest(excludeWithin[ewlCounter++]).length) {
178
- include = false;
179
- }
180
- }
181
- }
182
-
183
- if (include) {
184
- if (thisOpts.preventDefault) {
185
- event.preventDefault();
186
- }
187
-
188
- $.extend(clickOpts, thisOpts, {
189
- scrollTarget: thisOpts.scrollTarget || thisHash,
190
- link: link
191
- });
192
-
193
- $.smoothScroll(clickOpts);
194
- }
195
- };
196
-
197
- if (options.delegateSelector !== null) {
198
- this
199
- .off('click.smoothscroll', options.delegateSelector)
200
- .on('click.smoothscroll', options.delegateSelector, clickHandler);
201
- } else {
202
- this
203
- .off('click.smoothscroll')
204
- .on('click.smoothscroll', clickHandler);
205
- }
206
-
207
- return this;
208
- }
209
- });
210
-
211
- var getExplicitOffset = function(val) {
212
- var explicit = {relative: ''};
213
- var parts = typeof val === 'string' && rRelative.exec(val);
214
-
215
- if (typeof val === 'number') {
216
- explicit.px = val;
217
- } else if (parts) {
218
- explicit.relative = parts[1];
219
- explicit.px = parseFloat(parts[2]) || 0;
220
- }
221
-
222
- return explicit;
223
- };
224
-
225
- var onAfterScroll = function(opts) {
226
- var $tgt = $(opts.scrollTarget);
227
-
228
- if (opts.autoFocus && $tgt.length) {
229
- $tgt[0].focus();
230
-
231
- if (!$tgt.is(document.activeElement)) {
232
- $tgt.prop({tabIndex: -1});
233
- $tgt[0].focus();
234
- }
235
- }
236
-
237
- opts.afterScroll.call(opts.link, opts);
238
- };
239
-
240
- $.smoothScroll = function(options, px) {
241
- if (options === 'options' && typeof px === 'object') {
242
- return $.extend(optionOverrides, px);
243
- }
244
- var opts, $scroller, speed, delta;
245
- var explicitOffset = getExplicitOffset(options);
246
- var scrollTargetOffset = {};
247
- var scrollerOffset = 0;
248
- var offPos = 'offset';
249
- var scrollDir = 'scrollTop';
250
- var aniProps = {};
251
- var aniOpts = {};
252
-
253
- if (explicitOffset.px) {
254
- opts = $.extend({link: null}, $.fn.smoothScroll.defaults, optionOverrides);
255
- } else {
256
- opts = $.extend({link: null}, $.fn.smoothScroll.defaults, options || {}, optionOverrides);
257
-
258
- if (opts.scrollElement) {
259
- offPos = 'position';
260
-
261
- if (opts.scrollElement.css('position') === 'static') {
262
- opts.scrollElement.css('position', 'relative');
263
- }
264
- }
265
-
266
- if (px) {
267
- explicitOffset = getExplicitOffset(px);
268
- }
269
- }
270
-
271
- scrollDir = opts.direction === 'left' ? 'scrollLeft' : scrollDir;
272
-
273
- if (opts.scrollElement) {
274
- $scroller = opts.scrollElement;
275
-
276
- if (!explicitOffset.px && !(/^(?:HTML|BODY)$/).test($scroller[0].nodeName)) {
277
- scrollerOffset = $scroller[scrollDir]();
278
- }
279
- } else {
280
- $scroller = $('html, body').firstScrollable(opts.direction);
281
- }
282
-
283
- // beforeScroll callback function must fire before calculating offset
284
- opts.beforeScroll.call($scroller, opts);
285
-
286
- scrollTargetOffset = explicitOffset.px ? explicitOffset : {
287
- relative: '',
288
- px: ($(opts.scrollTarget)[offPos]() && $(opts.scrollTarget)[offPos]()[opts.direction]) || 0
289
- };
290
-
291
- aniProps[scrollDir] = scrollTargetOffset.relative + (scrollTargetOffset.px + scrollerOffset + opts.offset);
292
-
293
- speed = opts.speed;
294
-
295
- // automatically calculate the speed of the scroll based on distance / coefficient
296
- if (speed === 'auto') {
297
-
298
- // $scroller[scrollDir]() is position before scroll, aniProps[scrollDir] is position after
299
- // When delta is greater, speed will be greater.
300
- delta = Math.abs(aniProps[scrollDir] - $scroller[scrollDir]());
301
-
302
- // Divide the delta by the coefficient
303
- speed = delta / opts.autoCoefficient;
304
- }
305
-
306
- aniOpts = {
307
- duration: speed,
308
- easing: opts.easing,
309
- complete: function() {
310
- onAfterScroll(opts);
311
- }
312
- };
313
-
314
- if (opts.step) {
315
- aniOpts.step = opts.step;
316
- }
317
-
318
- if ($scroller.length) {
319
- $scroller.stop().animate(aniProps, aniOpts);
320
- } else {
321
- onAfterScroll(opts);
322
- }
323
- };
324
-
325
- $.smoothScroll.version = version;
326
- $.smoothScroll.filterPath = function(string) {
327
- string = string || '';
328
-
329
- return string
330
- .replace(/^\//, '')
331
- .replace(/(?:index|default).[a-zA-Z]{3,4}$/, '')
332
- .replace(/\/$/, '');
333
- };
334
-
335
- // default options
336
- $.fn.smoothScroll.defaults = defaults;
337
-
338
- })(jQuery);
1
+ (function($) {
2
+ var version = '2.2.0';
3
+ var optionOverrides = {};
4
+ var defaults = {
5
+ exclude: [],
6
+ excludeWithin: [],
7
+ offset: 0,
8
+
9
+ // one of 'top' or 'left'
10
+ direction: 'top',
11
+
12
+ // if set, bind click events through delegation
13
+ // supported since jQuery 1.4.2
14
+ delegateSelector: null,
15
+
16
+ // jQuery set of elements you wish to scroll (for $.smoothScroll).
17
+ // if null (default), $('html, body').firstScrollable() is used.
18
+ scrollElement: null,
19
+
20
+ // only use if you want to override default behavior
21
+ scrollTarget: null,
22
+
23
+ // automatically focus the target element after scrolling to it
24
+ autoFocus: false,
25
+
26
+ // fn(opts) function to be called before scrolling occurs.
27
+ // `this` is the element(s) being scrolled
28
+ beforeScroll: function() {},
29
+
30
+ // fn(opts) function to be called after scrolling occurs.
31
+ // `this` is the triggering element
32
+ afterScroll: function() {},
33
+
34
+ // easing name. jQuery comes with "swing" and "linear." For others, you'll need an easing plugin
35
+ // from jQuery UI or elsewhere
36
+ easing: 'swing',
37
+
38
+ // speed can be a number or 'auto'
39
+ // if 'auto', the speed will be calculated based on the formula:
40
+ // (current scroll position - target scroll position) / autoCoeffic
41
+ speed: 400,
42
+
43
+ // coefficient for "auto" speed
44
+ autoCoefficient: 2,
45
+
46
+ // $.fn.smoothScroll only: whether to prevent the default click action
47
+ preventDefault: true
48
+ };
49
+
50
+ var getScrollable = function(opts) {
51
+ var scrollable = [];
52
+ var scrolled = false;
53
+ var dir = opts.dir && opts.dir === 'left' ? 'scrollLeft' : 'scrollTop';
54
+
55
+ this.each(function() {
56
+ var el = $(this);
57
+
58
+ if (this === document || this === window) {
59
+ return;
60
+ }
61
+
62
+ if (document.scrollingElement && (this === document.documentElement || this === document.body)) {
63
+ scrollable.push(document.scrollingElement);
64
+
65
+ return false;
66
+ }
67
+
68
+ if (el[dir]() > 0) {
69
+ scrollable.push(this);
70
+ } else {
71
+ // if scroll(Top|Left) === 0, nudge the element 1px and see if it moves
72
+ el[dir](1);
73
+ scrolled = el[dir]() > 0;
74
+
75
+ if (scrolled) {
76
+ scrollable.push(this);
77
+ }
78
+ // then put it back, of course
79
+ el[dir](0);
80
+ }
81
+ });
82
+
83
+ if (!scrollable.length) {
84
+ this.each(function() {
85
+ // If no scrollable elements and <html> has scroll-behavior:smooth because
86
+ // "When this property is specified on the root element, it applies to the viewport instead."
87
+ // and "The scroll-behavior property of the … body element is *not* propagated to the viewport."
88
+ // → https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior
89
+ if (this === document.documentElement && $(this).css('scrollBehavior') === 'smooth') {
90
+ scrollable = [this];
91
+ }
92
+
93
+ // If still no scrollable elements, fall back to <body>,
94
+ // if it's in the jQuery collection
95
+ // (doing this because Safari sets scrollTop async,
96
+ // so can't set it to 1 and immediately get the value.)
97
+ if (!scrollable.length && this.nodeName === 'BODY') {
98
+ scrollable = [this];
99
+ }
100
+ });
101
+ }
102
+
103
+ // Use the first scrollable element if we're calling firstScrollable()
104
+ if (opts.el === 'first' && scrollable.length > 1) {
105
+ scrollable = [scrollable[0]];
106
+ }
107
+
108
+ return scrollable;
109
+ };
110
+
111
+ var rRelative = /^([\-\+]=)(\d+)/;
112
+
113
+ $.fn.extend({
114
+ scrollable: function(dir) {
115
+ var scrl = getScrollable.call(this, {dir: dir});
116
+
117
+ return this.pushStack(scrl);
118
+ },
119
+ firstScrollable: function(dir) {
120
+ var scrl = getScrollable.call(this, {el: 'first', dir: dir});
121
+
122
+ return this.pushStack(scrl);
123
+ },
124
+
125
+ smoothScroll: function(options, extra) {
126
+ options = options || {};
127
+
128
+ if (options === 'options') {
129
+ if (!extra) {
130
+ return this.first().data('ssOpts');
131
+ }
132
+
133
+ return this.each(function() {
134
+ var $this = $(this);
135
+ var opts = $.extend($this.data('ssOpts') || {}, extra);
136
+
137
+ $(this).data('ssOpts', opts);
138
+ });
139
+ }
140
+
141
+ var opts = $.extend({}, $.fn.smoothScroll.defaults, options);
142
+
143
+ var clickHandler = function(event) {
144
+ var escapeSelector = function(str) {
145
+ return str.replace(/(:|\.|\/)/g, '\\$1');
146
+ };
147
+
148
+ var link = this;
149
+ var $link = $(this);
150
+ var thisOpts = $.extend({}, opts, $link.data('ssOpts') || {});
151
+ var exclude = opts.exclude;
152
+ var excludeWithin = thisOpts.excludeWithin;
153
+ var elCounter = 0;
154
+ var ewlCounter = 0;
155
+ var include = true;
156
+ var clickOpts = {};
157
+ var locationPath = $.smoothScroll.filterPath(location.pathname);
158
+ var linkPath = $.smoothScroll.filterPath(link.pathname);
159
+ var hostMatch = location.hostname === link.hostname || !link.hostname;
160
+ var pathMatch = thisOpts.scrollTarget || (linkPath === locationPath);
161
+ var thisHash = escapeSelector(link.hash);
162
+
163
+ if (thisHash && !$(thisHash).length) {
164
+ include = false;
165
+ }
166
+
167
+ if (!thisOpts.scrollTarget && (!hostMatch || !pathMatch || !thisHash)) {
168
+ include = false;
169
+ } else {
170
+ while (include && elCounter < exclude.length) {
171
+ if ($link.is(escapeSelector(exclude[elCounter++]))) {
172
+ include = false;
173
+ }
174
+ }
175
+
176
+ while (include && ewlCounter < excludeWithin.length) {
177
+ if ($link.closest(excludeWithin[ewlCounter++]).length) {
178
+ include = false;
179
+ }
180
+ }
181
+ }
182
+
183
+ if (include) {
184
+ if (thisOpts.preventDefault) {
185
+ event.preventDefault();
186
+ }
187
+
188
+ $.extend(clickOpts, thisOpts, {
189
+ scrollTarget: thisOpts.scrollTarget || thisHash,
190
+ link: link
191
+ });
192
+
193
+ $.smoothScroll(clickOpts);
194
+ }
195
+ };
196
+
197
+ if (options.delegateSelector !== null) {
198
+ this
199
+ .off('click.smoothscroll', options.delegateSelector)
200
+ .on('click.smoothscroll', options.delegateSelector, clickHandler);
201
+ } else {
202
+ this
203
+ .off('click.smoothscroll')
204
+ .on('click.smoothscroll', clickHandler);
205
+ }
206
+
207
+ return this;
208
+ }
209
+ });
210
+
211
+ var getExplicitOffset = function(val) {
212
+ var explicit = {relative: ''};
213
+ var parts = typeof val === 'string' && rRelative.exec(val);
214
+
215
+ if (typeof val === 'number') {
216
+ explicit.px = val;
217
+ } else if (parts) {
218
+ explicit.relative = parts[1];
219
+ explicit.px = parseFloat(parts[2]) || 0;
220
+ }
221
+
222
+ return explicit;
223
+ };
224
+
225
+ var onAfterScroll = function(opts) {
226
+ var $tgt = $(opts.scrollTarget);
227
+
228
+ if (opts.autoFocus && $tgt.length) {
229
+ $tgt[0].focus();
230
+
231
+ if (!$tgt.is(document.activeElement)) {
232
+ $tgt.prop({tabIndex: -1});
233
+ $tgt[0].focus();
234
+ }
235
+ }
236
+
237
+ opts.afterScroll.call(opts.link, opts);
238
+ };
239
+
240
+ $.smoothScroll = function(options, px) {
241
+ if (options === 'options' && typeof px === 'object') {
242
+ return $.extend(optionOverrides, px);
243
+ }
244
+ var opts, $scroller, speed, delta;
245
+ var explicitOffset = getExplicitOffset(options);
246
+ var scrollTargetOffset = {};
247
+ var scrollerOffset = 0;
248
+ var offPos = 'offset';
249
+ var scrollDir = 'scrollTop';
250
+ var aniProps = {};
251
+ var aniOpts = {};
252
+
253
+ if (explicitOffset.px) {
254
+ opts = $.extend({link: null}, $.fn.smoothScroll.defaults, optionOverrides);
255
+ } else {
256
+ opts = $.extend({link: null}, $.fn.smoothScroll.defaults, options || {}, optionOverrides);
257
+
258
+ if (opts.scrollElement) {
259
+ offPos = 'position';
260
+
261
+ if (opts.scrollElement.css('position') === 'static') {
262
+ opts.scrollElement.css('position', 'relative');
263
+ }
264
+ }
265
+
266
+ if (px) {
267
+ explicitOffset = getExplicitOffset(px);
268
+ }
269
+ }
270
+
271
+ scrollDir = opts.direction === 'left' ? 'scrollLeft' : scrollDir;
272
+
273
+ if (opts.scrollElement) {
274
+ $scroller = opts.scrollElement;
275
+
276
+ if (!explicitOffset.px && !(/^(?:HTML|BODY)$/).test($scroller[0].nodeName)) {
277
+ scrollerOffset = $scroller[scrollDir]();
278
+ }
279
+ } else {
280
+ $scroller = $('html, body').firstScrollable(opts.direction);
281
+ }
282
+
283
+ // beforeScroll callback function must fire before calculating offset
284
+ opts.beforeScroll.call($scroller, opts);
285
+
286
+ scrollTargetOffset = explicitOffset.px ? explicitOffset : {
287
+ relative: '',
288
+ px: ($(opts.scrollTarget)[offPos]() && $(opts.scrollTarget)[offPos]()[opts.direction]) || 0
289
+ };
290
+
291
+ aniProps[scrollDir] = scrollTargetOffset.relative + (scrollTargetOffset.px + scrollerOffset + opts.offset);
292
+
293
+ speed = opts.speed;
294
+
295
+ // automatically calculate the speed of the scroll based on distance / coefficient
296
+ if (speed === 'auto') {
297
+
298
+ // $scroller[scrollDir]() is position before scroll, aniProps[scrollDir] is position after
299
+ // When delta is greater, speed will be greater.
300
+ delta = Math.abs(aniProps[scrollDir] - $scroller[scrollDir]());
301
+
302
+ // Divide the delta by the coefficient
303
+ speed = delta / opts.autoCoefficient;
304
+ }
305
+
306
+ aniOpts = {
307
+ duration: speed,
308
+ easing: opts.easing,
309
+ complete: function() {
310
+ onAfterScroll(opts);
311
+ }
312
+ };
313
+
314
+ if (opts.step) {
315
+ aniOpts.step = opts.step;
316
+ }
317
+
318
+ if ($scroller.length) {
319
+ $scroller.stop().animate(aniProps, aniOpts);
320
+ } else {
321
+ onAfterScroll(opts);
322
+ }
323
+ };
324
+
325
+ $.smoothScroll.version = version;
326
+ $.smoothScroll.filterPath = function(string) {
327
+ string = string || '';
328
+
329
+ return string
330
+ .replace(/^\//, '')
331
+ .replace(/(?:index|default).[a-zA-Z]{3,4}$/, '')
332
+ .replace(/\/$/, '');
333
+ };
334
+
335
+ // default options
336
+ $.fn.smoothScroll.defaults = defaults;
337
+
338
+ })(jQuery);
vendor/sticky-kit/jquery.sticky-kit.js CHANGED
@@ -1,251 +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);
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 CHANGED
@@ -1,16 +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);
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);
wpml-config.xml CHANGED
@@ -1,7 +1,7 @@
1
- <wpml-config>
2
- <admin-texts>
3
- <key name="ez-toc-settings">
4
- <key name="heading_text"/>
5
- </key>
6
- </admin-texts>
7
  </wpml-config>
1
+ <wpml-config>
2
+ <admin-texts>
3
+ <key name="ez-toc-settings">
4
+ <key name="heading_text"/>
5
+ </key>
6
+ </admin-texts>
7
  </wpml-config>