WebP Express - Version 0.23.0

Version Description

(pre-released: 15 Nov 2021) * Changed names for preventing replacing image with webp. Use "?dontreplace" / ".dontreplace" instead of "?original" and ".do-not-convert". The old ones are deprecated, but will still work (for a while) * You can now convert images in the file manager and view conversion log * The new file manager UI is now available in multisite too * Changed names for the escape hatches that was introduced in 0.22. Use "?dontreplace" and ".dontreplace" rather than "?original" and ".do-not-convert". The old names still works * Added message to users that have the Elementor plugin installed on how to configure Elementor to inline CSS in order for Alter HTML to be able to replace image URLs (only displayed when relevant) * Added UI for "skip-these-precompiled-binaries" cwebp option. Thanks to @madmax4ever for posting code for this. * Bumped dom-util-for-webp library to 0.5 * Bugfix: In multisite, Alter HTML produced wrong webp urls when destination structure was set to "image roots". Thanks to John A. Huebner II (@hube2) who lives on a big hill in central NY, USA for reporting the issue. * Bugfix: One of the newly introduced escape hatches didn't work in Alter HTML.

For more info, see the closed issues on the webp-express 0.23 milestone

Download this release

Release Info

Developer rosell.dk
Plugin Icon 128x128 WebP Express
Version 0.23.0
Comparing to
See all releases

Code changes from version 0.22.1 to 0.23.0

Files changed (62) hide show
  1. README.md +2 -0
  2. README.txt +26 -4
  3. changelog.txt +14 -0
  4. composer.json +1 -1
  5. docs/development.md +70 -0
  6. docs/publishing.md +3 -3
  7. lib/classes/AdminInit.php +8 -3
  8. lib/classes/AdminUi.php +29 -0
  9. lib/classes/AlterHtmlHelper.php +34 -9
  10. lib/classes/Config.php +4 -0
  11. lib/classes/Convert.php +3 -1
  12. lib/classes/ConvertHelperIndependent.php +1 -1
  13. lib/classes/DestinationUrl.php +1 -1
  14. lib/classes/HTAccess.php +10 -2
  15. lib/classes/HTAccessRules.php +12 -2
  16. lib/classes/Paths.php +8 -36
  17. lib/classes/PluginActivate.php +0 -9
  18. lib/classes/TestRun.php +44 -1
  19. lib/classes/WCFMApi.php +79 -22
  20. lib/classes/WCFMPage.php +3 -8
  21. lib/dismissable-messages/0.23.0/elementor.php +34 -0
  22. lib/options/css/webp-express-options-page.css +8 -1
  23. lib/options/enqueue_scripts.php +6 -2
  24. lib/options/js/{0.19.0/authorized_sites_bak.js → authorized_sites_bak.js} +0 -0
  25. lib/options/js/{0.19.0/bulk-convert.js → bulk-convert.js} +0 -0
  26. lib/options/js/{0.19.0/converters.js → converters.js} +44 -14
  27. lib/options/js/{0.19.0/das-popup.js → das-popup.js} +0 -0
  28. lib/options/js/{0.19.0/escapeHTML.js → escapeHTML.js} +0 -0
  29. lib/options/js/{0.19.0/image-comparison-slider.js → image-comparison-slider.js} +0 -0
  30. lib/options/js/{0.19.0/page.js → page.js} +0 -0
  31. lib/options/js/{0.19.0/purge-cache.js → purge-cache.js} +0 -0
  32. lib/options/js/{0.19.0/purge-log.js → purge-log.js} +0 -0
  33. lib/options/js/{0.19.0/self-test.js → self-test.js} +0 -0
  34. lib/options/js/{0.19.0/sortable.min.js → sortable.min.js} +0 -0
  35. lib/options/js/{0.19.0/test-convert.js → test-convert.js} +0 -0
  36. lib/options/js/{0.19.0/whitelist.js → whitelist.js} +0 -0
  37. lib/options/options/conversion-options/converter-options/cwebp.php +7 -1
  38. lib/options/options/redirection-rules/redirection-rules.inc +1 -1
  39. lib/options/page-messages.php +16 -0
  40. lib/options/submit.php +2 -1
  41. lib/wcfm/index.659b742a.css +1 -0
  42. lib/wcfm/index.ab43bb2c.css +0 -1
  43. lib/wcfm/index.ee44cdbf.js +29 -0
  44. lib/wcfm/index.f8d1bd25.js +0 -27
  45. vendor/composer/autoload_classmap.php +1 -0
  46. vendor/composer/autoload_namespaces.php +1 -0
  47. vendor/composer/autoload_static.php +12 -0
  48. vendor/composer/installed.json +63 -7
  49. vendor/composer/installed.php +14 -5
  50. vendor/kub-at/php-simple-html-dom-parser/CONTRIBUTING.md +3 -0
  51. vendor/kub-at/php-simple-html-dom-parser/LICENSE +21 -0
  52. vendor/kub-at/php-simple-html-dom-parser/README.md +29 -0
  53. vendor/kub-at/php-simple-html-dom-parser/composer.json +24 -0
  54. vendor/kub-at/php-simple-html-dom-parser/src/KubAT/PhpSimple/HtmlDomParser.php +16 -0
  55. vendor/kub-at/php-simple-html-dom-parser/src/KubAT/PhpSimple/lib/simple_html_dom.php +2355 -0
  56. vendor/rosell-dk/dom-util-for-webp/README.md +1 -1
  57. vendor/rosell-dk/dom-util-for-webp/composer.json +3 -0
  58. vendor/rosell-dk/dom-util-for-webp/phpstan.neon +3 -0
  59. vendor/rosell-dk/dom-util-for-webp/src-vendor/simple_html_dom/simple_html_dom.inc +0 -2930
  60. vendor/rosell-dk/dom-util-for-webp/src/ImageUrlReplacer.php +6 -4
  61. vendor/rosell-dk/dom-util-for-webp/src/PictureTags.php +6 -4
  62. webp-express.php +1 -1
README.md CHANGED
@@ -709,6 +709,8 @@ The current milestones, their subtasks and their progress can be viewed here: ht
709
 
710
  If you wish to affect priorities, it is certainly possible. You can try to argue your case in the forum or you can simply let the money do the talking. By donating as little as a cup of coffee on [ko-fi.com/rosell](https://ko-fi.com/rosell), you can leave a wish. I shall take these wishes into account when prioritizing between new features.
711
 
 
 
712
 
713
  ## Changes in 0.21.1
714
  *(released: 27 Oct 2021)*
709
 
710
  If you wish to affect priorities, it is certainly possible. You can try to argue your case in the forum or you can simply let the money do the talking. By donating as little as a cup of coffee on [ko-fi.com/rosell](https://ko-fi.com/rosell), you can leave a wish. I shall take these wishes into account when prioritizing between new features.
711
 
712
+ ### Beta testing
713
+ I generally create a pre-release before publishing. If you [follow me on ko-fi](https://ko-fi.com/rosell), you will get notified when a pre-release is available. I generally create a pre-release on fridays and mark it as stable on mondays. In order to download a pre-release, go to [the advanced page](https://wordpress.org/plugins/webp-express/advanced/) and scroll down to "Please select a specific version to download". I don't name the pre-releases different. You will just see the next version here before it is available the usual way.
714
 
715
  ## Changes in 0.21.1
716
  *(released: 27 Oct 2021)*
README.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: https://ko-fi.com/rosell
4
  Tags: webp, images, performance
5
  Requires at least: 4.0
6
  Tested up to: 5.8
7
- Stable tag: 0.22.1
8
  Requires PHP: 5.6
9
  License: GPLv3
10
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
@@ -175,10 +175,10 @@ Bread on the table don't come for free, even though this plugin does, and always
175
  * Ruben Solvang
176
 
177
  **Persons who recently contributed with [ko-fi](https://ko-fi.com/rosell) - Thanks!**
 
178
  * 9 Nov: @utrenkner
179
  * 26 Oct: Anonymous
180
  * 29 Aug: Pawa Tecnologia
181
- * 29 Jul: Brian Laursen
182
 
183
  **Persons who contributed with extra generously amounts of coffee / lifetime backing (>30$) - thanks!:**
184
 
@@ -722,11 +722,13 @@ I have only tested the above in *Varied image responses* mode, but it should als
722
  There can be instances where you actually need to serve a jpeg or png. For example if you are demonstrating how a jpeg looks using some compression settings.
723
 
724
  If you want an image to be served in the original format (jpeg og png), do one of the following things:
725
- - Add "?original" to the image url.
726
- - Place an empty file in the same folder as the jpeg/png. The file name must be the same as the jpeg/png with ".do-not-convert" appended
727
 
728
  Doing this will bypass redirection to webp and also prevent Alter HTML to use the webp instead of the original.
729
 
 
 
730
  *Bypassing for an entire folder*
731
  To bypass redirection for an entire folder, you can put something like this into your root .htaccess:
732
  `
@@ -764,6 +766,9 @@ The current milestones, their subtasks and their progress can be viewed here: ht
764
 
765
  If you wish to affect priorities, it is certainly possible. You can try to argue your case in the forum or you can simply let the money do the talking. By donating as little as a cup of coffee on [ko-fi.com/rosell](https://ko-fi.com/rosell), you can leave a wish. I shall take these wishes into account when prioritizing between new features.
766
 
 
 
 
767
  = Can I buy you a cup of coffee? =
768
  You sure can! To do so, [go here!](https://ko-fi.com/rosell). If payment doesn't work for your country, [try here instead](https://buymeacoff.ee/rosell).
769
 
@@ -776,6 +781,20 @@ If you want to make sure that my coffee supplies don't run dry, you can even buy
776
 
777
  == Changelog ==
778
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
779
  = 0.22.1 =
780
  *(released: 09 Nov 2021)*
781
  * Bugfix: Old unupdated rewrite rules for redirecting to converter caused error (bug was introduced in 0.22.0). Thanks, @utrenkner for reacting quickly!
@@ -834,6 +853,9 @@ For older releases, check out changelog.txt
834
 
835
  == Upgrade Notice ==
836
 
 
 
 
837
  = 0.22.1 =
838
  * Two bug fixes related to .htaccess files and redirecting to converter
839
 
4
  Tags: webp, images, performance
5
  Requires at least: 4.0
6
  Tested up to: 5.8
7
+ Stable tag: 0.23.0
8
  Requires PHP: 5.6
9
  License: GPLv3
10
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
175
  * Ruben Solvang
176
 
177
  **Persons who recently contributed with [ko-fi](https://ko-fi.com/rosell) - Thanks!**
178
+ * 13 Nov: @sween
179
  * 9 Nov: @utrenkner
180
  * 26 Oct: Anonymous
181
  * 29 Aug: Pawa Tecnologia
 
182
 
183
  **Persons who contributed with extra generously amounts of coffee / lifetime backing (>30$) - thanks!:**
184
 
722
  There can be instances where you actually need to serve a jpeg or png. For example if you are demonstrating how a jpeg looks using some compression settings.
723
 
724
  If you want an image to be served in the original format (jpeg og png), do one of the following things:
725
+ - Add "?dontreplace" to the image url.
726
+ - Place an empty file in the same folder as the jpeg/png. The file name must be the same as the jpeg/png with ".dontreplace" appended
727
 
728
  Doing this will bypass redirection to webp and also prevent Alter HTML to use the webp instead of the original.
729
 
730
+ NOTE: You may have to regenerate .htaccess rules (by clicking the button) in order for this to work. The feature was added in 0.23.0 and if you started using WebP Express before that, the necessary rules will not be there, unless you regenerate, that is.
731
+
732
  *Bypassing for an entire folder*
733
  To bypass redirection for an entire folder, you can put something like this into your root .htaccess:
734
  `
766
 
767
  If you wish to affect priorities, it is certainly possible. You can try to argue your case in the forum or you can simply let the money do the talking. By donating as little as a cup of coffee on [ko-fi.com/rosell](https://ko-fi.com/rosell), you can leave a wish. I shall take these wishes into account when prioritizing between new features.
768
 
769
+ = Beta testing =
770
+ I generally create a pre-release before publishing. If you [follow me on ko-fi](https://ko-fi.com/rosell), you will get notified when a pre-release is available. I generally create a pre-release on fridays and mark it as stable on mondays. In order to download a pre-release, go to [the advanced page](https://wordpress.org/plugins/webp-express/advanced/) and scroll down to "Please select a specific version to download". I don't name the pre-releases different. You will just see the next version here before it is available the usual way.
771
+
772
  = Can I buy you a cup of coffee? =
773
  You sure can! To do so, [go here!](https://ko-fi.com/rosell). If payment doesn't work for your country, [try here instead](https://buymeacoff.ee/rosell).
774
 
781
 
782
  == Changelog ==
783
 
784
+ = 0.23.0 =
785
+ *(pre-released: 15 Nov 2021)*
786
+ * Changed names for preventing replacing image with webp. Use "?dontreplace" / ".dontreplace" instead of "?original" and ".do-not-convert". The old ones are deprecated, but will still work (for a while)
787
+ * You can now convert images in the file manager and view conversion log
788
+ * The new file manager UI is now available in multisite too
789
+ * Changed names for the escape hatches that was introduced in 0.22. Use "?dontreplace" and ".dontreplace" rather than "?original" and ".do-not-convert". The old names still works
790
+ * Added message to users that have the Elementor plugin installed on how to configure Elementor to inline CSS in order for Alter HTML to be able to replace image URLs (only displayed when relevant)
791
+ * Added UI for "skip-these-precompiled-binaries" cwebp option. Thanks to @madmax4ever for posting code for this.
792
+ * Bumped dom-util-for-webp library to 0.5
793
+ * Bugfix: In multisite, Alter HTML produced wrong webp urls when destination structure was set to "image roots". Thanks to John A. Huebner II (@hube2) who lives on a big hill in central NY, USA for reporting the issue.
794
+ * Bugfix: One of the newly introduced escape hatches didn't work in Alter HTML.
795
+
796
+ For more info, see the closed issues on the [webp-express 0.23 milestone](https://github.com/rosell-dk/webp-express/milestone/43?closed=1)
797
+
798
  = 0.22.1 =
799
  *(released: 09 Nov 2021)*
800
  * Bugfix: Old unupdated rewrite rules for redirecting to converter caused error (bug was introduced in 0.22.0). Thanks, @utrenkner for reacting quickly!
853
 
854
  == Upgrade Notice ==
855
 
856
+ = 0.23.0 =
857
+ * Various improvements and bug fixes
858
+
859
  = 0.22.1 =
860
  * Two bug fixes related to .htaccess files and redirecting to converter
861
 
changelog.txt CHANGED
@@ -1,3 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  = 0.22.1 =
2
  *(released: 09 Nov 2021)*
3
  * Bugfix: Old unupdated rewrite rules for redirecting to converter caused error (bug was introduced in 0.22.0). Thanks, @utrenkner for reacting quickly!
1
+ = 0.23.0 =
2
+ *(pre-released: 15 Nov 2021, scheduled for release 16 Nov 2021)*
3
+ * Changed names for preventing replacing image with webp. Use "?dontreplace" / ".dontreplace" instead of "?original" and ".do-not-convert". The old ones are deprecated, but will still work (for a while)
4
+ * You can now convert images in the file manager and view conversion log
5
+ * The new file manager UI is now available in multisite too
6
+ * Changed names for the escape hatches that was introduced in 0.22. Use "?dontreplace" and ".dontreplace" rather than "?original" and ".do-not-convert". The old names still works
7
+ * Added message to users that have the Elementor plugin installed on how to configure Elementor to inline CSS in order for Alter HTML to be able to replace image URLs (only displayed when relevant)
8
+ * Added UI for "skip-these-precompiled-binaries" cwebp option. Thanks to @madmax4ever for posting code for this.
9
+ * Bumped dom-util-for-webp library to 0.5
10
+ * Bugfix: In multisite, Alter HTML produced wrong webp urls when destination structure was set to "image roots". Thanks to John A. Huebner II (@hube2) who lives on a big hill in central NY, USA for reporting the issue.
11
+ * Bugfix: One of the newly introduced escape hatches didn't work in Alter HTML.
12
+
13
+ For more info, see the closed issues on the [webp-express 0.23 milestone](https://github.com/rosell-dk/webp-express/milestone/43?closed=1)
14
+
15
  = 0.22.1 =
16
  *(released: 09 Nov 2021)*
17
  * Bugfix: Old unupdated rewrite rules for redirecting to converter caused error (bug was introduced in 0.22.0). Thanks, @utrenkner for reacting quickly!
composer.json CHANGED
@@ -7,7 +7,7 @@
7
  "composer/installers": "^1.0.0",
8
  "rosell-dk/webp-convert": "^2.7.0",
9
  "rosell-dk/webp-convert-cloud-service": "^2.0.0",
10
- "rosell-dk/dom-util-for-webp": "^0.4.0",
11
  "rosell-dk/htaccess-capability-tester": "^0.9.0"
12
  },
13
  "require-dev": {
7
  "composer/installers": "^1.0.0",
8
  "rosell-dk/webp-convert": "^2.7.0",
9
  "rosell-dk/webp-convert-cloud-service": "^2.0.0",
10
+ "rosell-dk/dom-util-for-webp": "^0.5.0",
11
  "rosell-dk/htaccess-capability-tester": "^0.9.0"
12
  },
13
  "require-dev": {
docs/development.md CHANGED
@@ -19,3 +19,73 @@ rmdir vendor/bin
19
  ```
20
 
21
  3. Commit on git
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  ```
20
 
21
  3. Commit on git
22
+
23
+
24
+ ## Copying WCFM
25
+ I created the following script for copying WCFM build to webp-express:
26
+ ```
27
+ #!/bin/bash
28
+
29
+ WCFM_PATH=/home/rosell/github/webp-convert-filemanager
30
+ WE_PATH=/home/rosell/github/webp-express/lib/wcfm
31
+ WCFMPage_PATH=/home/rosell/github/webp-express/lib/classes/WCFMPage.php
32
+
33
+ copyassets() {
34
+ # remove assets in WebP Express
35
+ rm -f $WE_PATH/index*.css
36
+ rm -f $WE_PATH/index*.js
37
+ rm -f $WE_PATH/vendor*.js
38
+
39
+ # copy assets from WCFM
40
+ cp $WCFM_PATH/dist/assets/index*.css $WE_PATH/
41
+ cp $WCFM_PATH/dist/assets/index*.js $WE_PATH/
42
+ cp $WCFM_PATH/dist/assets/vendor*.js $WE_PATH/
43
+
44
+
45
+ #CSS_FILE = $(ls /home/rosell/github/webp-express/lib/wcfm | grep 'index.*css' | tr '\n' ' ' | sed 's/\s//')
46
+ CSS_FILE=$(ls $WE_PATH | grep 'index.*css' | tr '\n' ' ' | sed 's/\s//')
47
+ JS_FILE=$(ls $WE_PATH | grep 'index.*js' | tr '\n' ' ' | sed 's/\s//')
48
+
49
+
50
+ if [ ! $CSS_FILE ]; then
51
+ echo "No CSS file! - aborting"
52
+ exit
53
+ fi
54
+ if [ ! $JS_FILE ]; then
55
+ echo "No JS file! - aborting"
56
+ exit
57
+ fi
58
+
59
+ echo "CSS file: $CSS_FILE"
60
+ echo "JS file: $JS_FILE"
61
+
62
+ # Update WCFMPage.PHP references
63
+ sed -i "s/index\..*\.css/$CSS_FILE/g" $WCFMPage_PATH
64
+ sed -i "s/index\..*\.js/$JS_FILE/g" $WCFMPage_PATH
65
+ }
66
+
67
+ if [ ! $1 ]; then
68
+ echo "Missing argument. Must be build, copy or build-copy"
69
+ exit
70
+ fi
71
+
72
+ buildwcfm() {
73
+ npm run build --prefix $WCFM_PATH
74
+ }
75
+
76
+ if [ $1 = "copy" ]; then
77
+ echo "copy"
78
+ copyassets
79
+ fi
80
+
81
+ if [ $1 = "build" ]; then
82
+ echo "build"
83
+ buildwcfm
84
+ fi
85
+
86
+ if [ $1 = "build-copy" ]; then
87
+ echo "build-copy"
88
+ buildwcfm
89
+ copyassets
90
+ fi
91
+ ```
docs/publishing.md CHANGED
@@ -44,7 +44,7 @@ before rsync, do this:
44
  1. the *webp-express.php* file
45
  2. in `lib/options/enqueue_scripts.php`
46
  3. in `lib/classes/ConverterHelperIndependent.php`
47
- 4. in `README.txt` (Stable tag)
48
  - Perhaps make some final improvements of the readme.
49
  Inspiration: https://www.smashingmagazine.com/2011/11/improve-wordpress-plugins-readme-txt/
50
  https://pippinsplugins.com/how-to-properly-format-and-enhance-your-plugins-readme-txt-file-for-the-wordpress-org-repository/
@@ -114,12 +114,12 @@ svn status | grep '^!' | awk '{print $2}' | xargs svn delete --force (t
114
  Then add a new tag
115
  ```
116
  cd svn
117
- svn cp trunk tags/0.22.0 (this will copy trunk into a new tag)
118
  ```
119
 
120
  And commit!
121
  ```
122
- svn ci -m '0.22.0'
123
  ```
124
 
125
 
44
  1. the *webp-express.php* file
45
  2. in `lib/options/enqueue_scripts.php`
46
  3. in `lib/classes/ConverterHelperIndependent.php`
47
+ 4. in `README.txt` (Stable tag) - UNLESS IT IS A PRE-RELEASE :)
48
  - Perhaps make some final improvements of the readme.
49
  Inspiration: https://www.smashingmagazine.com/2011/11/improve-wordpress-plugins-readme-txt/
50
  https://pippinsplugins.com/how-to-properly-format-and-enhance-your-plugins-readme-txt-file-for-the-wordpress-org-repository/
114
  Then add a new tag
115
  ```
116
  cd svn
117
+ svn cp trunk tags/0.22.1 (this will copy trunk into a new tag)
118
  ```
119
 
120
  And commit!
121
  ```
122
+ svn ci -m '0.22.1'
123
  ```
124
 
125
 
lib/classes/AdminInit.php CHANGED
@@ -53,12 +53,12 @@ class AdminInit
53
  if (current_user_can('manage_options')) {
54
 
55
  // Hooks related to conversion page (in media)
56
- if (self::pageNowIs('upload.php')) {
57
  if (isset($_GET['page']) && ('webp_express_conversion_page' === $_GET['page'])) {
58
  //add_action('admin_enqueue_scripts', array('\WebPExpress\WCFMPage', 'enqueueScripts'));
59
  add_action('admin_head', array('\WebPExpress\WCFMPage', 'addToHead'));
60
  }
61
- }
62
 
63
  // Hooks related to options page
64
  if (self::pageNowIs('options-general.php') || self::pageNowIs('settings.php')) {
@@ -123,7 +123,12 @@ class AdminInit
123
  add_action("admin_notices", array('\WebPExpress\DismissableGlobalMessages', 'printMessages'));
124
 
125
  if (Multisite::isNetworkActivated()) {
126
- add_action("network_admin_menu", array('\WebPExpress\AdminUi', 'networAdminMenuHook'));
 
 
 
 
 
127
  } else {
128
  add_action("admin_menu", array('\WebPExpress\AdminUi', 'adminMenuHook'));
129
  }
53
  if (current_user_can('manage_options')) {
54
 
55
  // Hooks related to conversion page (in media)
56
+ //if (self::pageNowIs('upload.php')) {
57
  if (isset($_GET['page']) && ('webp_express_conversion_page' === $_GET['page'])) {
58
  //add_action('admin_enqueue_scripts', array('\WebPExpress\WCFMPage', 'enqueueScripts'));
59
  add_action('admin_head', array('\WebPExpress\WCFMPage', 'addToHead'));
60
  }
61
+ //}
62
 
63
  // Hooks related to options page
64
  if (self::pageNowIs('options-general.php') || self::pageNowIs('settings.php')) {
123
  add_action("admin_notices", array('\WebPExpress\DismissableGlobalMessages', 'printMessages'));
124
 
125
  if (Multisite::isNetworkActivated()) {
126
+ if (is_network_admin()) {
127
+ add_action("network_admin_menu", array('\WebPExpress\AdminUi', 'networAdminMenuHook'));
128
+ } else {
129
+ add_action("admin_menu", array('\WebPExpress\AdminUi', 'adminMenuHookMultisite'));
130
+ }
131
+
132
  } else {
133
  add_action("admin_menu", array('\WebPExpress\AdminUi', 'adminMenuHook'));
134
  }
lib/classes/AdminUi.php CHANGED
@@ -40,6 +40,7 @@ class AdminUi
40
  return array_merge($links, $mylinks);
41
  }
42
 
 
43
  // callback for 'network_admin_menu' (registred in AdminInit)
44
  public static function networAdminMenuHook()
45
  {
@@ -51,6 +52,34 @@ class AdminUi
51
  'webp_express_settings_page', // slug
52
  array('\WebPExpress\OptionsPage', 'display') // Callback function which displays the page
53
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  }
55
 
56
  public static function adminMenuHook()
40
  return array_merge($links, $mylinks);
41
  }
42
 
43
+
44
  // callback for 'network_admin_menu' (registred in AdminInit)
45
  public static function networAdminMenuHook()
46
  {
52
  'webp_express_settings_page', // slug
53
  array('\WebPExpress\OptionsPage', 'display') // Callback function which displays the page
54
  );
55
+
56
+ add_submenu_page(
57
+ 'settings.php', // Parent element
58
+ 'WebP Express File Manager', //Page Title
59
+ 'WebP Express File Manager', //Menu Title
60
+ 'manage_network_options', //capability
61
+ 'webp_express_conversion_page', // slug
62
+ array('\WebPExpress\WCFMPage', 'display') //The function to be called to output the content for this page.
63
+ );
64
+
65
+ }
66
+
67
+ public static function adminMenuHookMultisite()
68
+ {
69
+ // Add Media page
70
+ /*
71
+ not ready - it should not display images for the other blogs!
72
+
73
+ add_submenu_page(
74
+ 'upload.php', // Parent element
75
+ 'WebP Express', //Page Title
76
+ 'WebP Express', //Menu Title
77
+ 'manage_network_options', //capability
78
+ 'webp_express_conversion_page', // slug
79
+ array('\WebPExpress\WCFMPage', 'display') //The function to be called to output the content for this page.
80
+ );
81
+ */
82
+
83
  }
84
 
85
  public static function adminMenuHook()
lib/classes/AlterHtmlHelper.php CHANGED
@@ -168,7 +168,6 @@ class AlterHtmlHelper
168
  */
169
  public static function getWebPUrlInImageRoot($sourceUrl, $rootId, $baseUrl, $baseDir)
170
  {
171
- //error_log('getWebPUrlInImageRoot:' . $sourceUrl . ':' . $baseUrl . ':' . $baseDir);
172
 
173
 
174
  $srcPathRel = self::getRelUrlPath($sourceUrl, $baseUrl);
@@ -185,6 +184,13 @@ class AlterHtmlHelper
185
  return false;
186
  }
187
 
 
 
 
 
 
 
 
188
  // Calculate destination of webp (both path and url)
189
  // ----------------------------------------
190
 
@@ -192,19 +198,21 @@ class AlterHtmlHelper
192
 
193
  // Make sure the options are loaded (and fixed)
194
  self::getOptions();
 
 
 
 
 
 
195
 
196
  if (!isset(self::$options['scope']) || !in_array($rootId, self::$options['scope'])) {
197
  return false;
198
  }
199
 
200
- $destinationRoot = Paths::destinationRoot(
201
- $rootId,
202
- self::$options['destination-folder'],
203
- self::$options['destination-structure']
204
- );
205
 
206
  $relPathFromImageRootToSource = PathHelper::getRelDir(
207
- realpath(Paths::getAbsDirById($rootId)),
208
  realpath($srcPathAbs)
209
  );
210
  $relPathFromImageRootToDest = ConvertHelperIndependent::appendOrSetExtension(
@@ -239,7 +247,25 @@ class AlterHtmlHelper
239
  $sourceUrlComponents = parse_url($sourceUrl);
240
  $destUrlComponents = parse_url($destUrl);
241
  $port = isset($sourceUrlComponents['port']) ? ":" . $sourceUrlComponents['port'] : "";
242
- return $sourceUrlComponents['scheme'] . '://' . $sourceUrlComponents['host'] . $port . $destUrlComponents['path'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
243
  }
244
 
245
 
@@ -295,7 +321,6 @@ class AlterHtmlHelper
295
  $baseDir = Paths::getAbsDirById($rootId);
296
  $baseUrl = Paths::getUrlById($rootId);
297
 
298
- //error_log('baseurl: ' . $baseUrl);
299
  if (Multisite::isMultisite() && ($rootId == 'uploads')) {
300
  $baseUrl = Paths::getUploadUrl();
301
  $baseDir = Paths::getUploadDirAbs();
168
  */
169
  public static function getWebPUrlInImageRoot($sourceUrl, $rootId, $baseUrl, $baseDir)
170
  {
 
171
 
172
 
173
  $srcPathRel = self::getRelUrlPath($sourceUrl, $baseUrl);
184
  return false;
185
  }
186
 
187
+ if (file_exists($srcPathAbs . '.do-not-convert')) {
188
+ return false;
189
+ }
190
+ if (file_exists($srcPathAbs . '.dontreplace')) {
191
+ return false;
192
+ }
193
+
194
  // Calculate destination of webp (both path and url)
195
  // ----------------------------------------
196
 
198
 
199
  // Make sure the options are loaded (and fixed)
200
  self::getOptions();
201
+ $destinationOptions = new DestinationOptions(
202
+ self::$options['destination-folder'] == 'mingled',
203
+ self::$options['destination-structure'] == 'doc-root',
204
+ self::$options['destination-extension'] == 'set',
205
+ self::$options['scope']
206
+ );
207
 
208
  if (!isset(self::$options['scope']) || !in_array($rootId, self::$options['scope'])) {
209
  return false;
210
  }
211
 
212
+ $destinationRoot = Paths::destinationRoot($rootId, $destinationOptions);
 
 
 
 
213
 
214
  $relPathFromImageRootToSource = PathHelper::getRelDir(
215
+ realpath(Paths::getAbsDirById($rootId)), // note: In multisite (subfolders), it contains ie "/site/2/"
216
  realpath($srcPathAbs)
217
  );
218
  $relPathFromImageRootToDest = ConvertHelperIndependent::appendOrSetExtension(
247
  $sourceUrlComponents = parse_url($sourceUrl);
248
  $destUrlComponents = parse_url($destUrl);
249
  $port = isset($sourceUrlComponents['port']) ? ":" . $sourceUrlComponents['port'] : "";
250
+ $result = $sourceUrlComponents['scheme'] . '://' . $sourceUrlComponents['host'] . $port . $destUrlComponents['path'];
251
+
252
+ /*
253
+ error_log(
254
+ "getWebPUrlInImageRoot:\n" .
255
+ "- url: " . $sourceUrl . "\n" .
256
+ "- baseUrl: " . $baseUrl . "\n" .
257
+ "- baseDir: " . $baseDir . "\n" .
258
+ "- root id: " . $rootId . "\n" .
259
+ "- root abs: " . Paths::getAbsDirById($rootId) . "\n" .
260
+ "- destination root (abs): " . $destinationRoot['abs-path'] . "\n" .
261
+ "- destination root (url): " . $destinationRoot['url'] . "\n" .
262
+ "- rel: " . $srcPathRel . "\n" .
263
+ "- srcPathAbs: " . $srcPathAbs . "\n" .
264
+ '- relPathFromImageRootToSource: ' . $relPathFromImageRootToSource . "\n" .
265
+ '- get_blog_details()->path: ' . get_blog_details()->path . "\n" .
266
+ "- result: " . $result . "\n"
267
+ );*/
268
+ return $result;
269
  }
270
 
271
 
321
  $baseDir = Paths::getAbsDirById($rootId);
322
  $baseUrl = Paths::getUrlById($rootId);
323
 
 
324
  if (Multisite::isMultisite() && ($rootId == 'uploads')) {
325
  $baseUrl = Paths::getUploadUrl();
326
  $baseDir = Paths::getUploadDirAbs();
lib/classes/Config.php CHANGED
@@ -301,6 +301,7 @@ class Config
301
  foreach ($config['converters'] as &$converter) {
302
  $converterId = $converter['converter'];
303
  $hasError = isset($testResult['errors'][$converterId]);
 
304
  $working = !$hasError;
305
 
306
  /*
@@ -341,6 +342,9 @@ class Config
341
  } else {
342
  unset($converter['error']);
343
  }
 
 
 
344
  }
345
  }
346
  return $config;
301
  foreach ($config['converters'] as &$converter) {
302
  $converterId = $converter['converter'];
303
  $hasError = isset($testResult['errors'][$converterId]);
304
+ $hasWarning = isset($testResult['warnings'][$converterId]);
305
  $working = !$hasError;
306
 
307
  /*
342
  } else {
343
  unset($converter['error']);
344
  }
345
+ if ($hasWarning) {
346
+ $converter['warnings'] = $testResult['warnings'][$converterId];
347
+ }
348
  }
349
  }
350
  return $config;
lib/classes/Convert.php CHANGED
@@ -142,7 +142,9 @@ class Convert
142
  $result['filesize-webp'] = @filesize($destination);
143
  $result['destination-path'] = $destination;
144
 
145
- $rootOfDestination = Paths::destinationRoot($rootId, $config['destination-folder'], $config['destination-structure']);
 
 
146
 
147
  $relPathFromImageRootToSource = PathHelper::getRelDir(
148
  realpath(Paths::getAbsDirById($rootId)),
142
  $result['filesize-webp'] = @filesize($destination);
143
  $result['destination-path'] = $destination;
144
 
145
+ $destinationOptions = DestinationOptions::createFromConfig($config);
146
+
147
+ $rootOfDestination = Paths::destinationRoot($rootId, $destinationOptions);
148
 
149
  $relPathFromImageRootToSource = PathHelper::getRelDir(
150
  realpath(Paths::getAbsDirById($rootId)),
lib/classes/ConvertHelperIndependent.php CHANGED
@@ -571,7 +571,7 @@ APACHE
571
  $text = preg_replace('#' . preg_quote($_SERVER["DOCUMENT_ROOT"]) . '#', '[doc-root]', $text);
572
 
573
  // TODO: Put version number somewhere else. Ie \WebPExpress\VersionNumber::version
574
- $text = 'WebP Express 0.22.1. ' . $msgTop . ', ' . date("Y-m-d H:i:s") . "\n\r\n\r" . $text;
575
 
576
  $logFile = self::getLogFilename($source, $logDir);
577
 
571
  $text = preg_replace('#' . preg_quote($_SERVER["DOCUMENT_ROOT"]) . '#', '[doc-root]', $text);
572
 
573
  // TODO: Put version number somewhere else. Ie \WebPExpress\VersionNumber::version
574
+ $text = 'WebP Express 0.23.0. ' . $msgTop . ', ' . date("Y-m-d H:i:s") . "\n\r\n\r" . $text;
575
 
576
  $logFile = self::getLogFilename($source, $logDir);
577
 
lib/classes/DestinationUrl.php CHANGED
@@ -90,7 +90,7 @@ class DestinationUrl
90
  return false;
91
  }
92
 
93
- $destinationRoot = Paths::destinationRoot2(
94
  $rootId,
95
  $destinationOptions
96
  );
90
  return false;
91
  }
92
 
93
+ $destinationRoot = Paths::destinationRoot(
94
  $rootId,
95
  $destinationOptions
96
  );
lib/classes/HTAccess.php CHANGED
@@ -387,14 +387,22 @@ class HTAccess
387
  if (count($successfullWrites) > 0) {
388
  $msg .= '<p>Rewrite rules were saved to the following files:</p>';
389
  foreach ($successfullWrites as $rootId) {
390
- $msg .= '<i>' . Paths::getAbsDirById($rootId) . '/.htaccess</i> (' . $rootId . ')<br>';
 
 
 
 
391
  }
392
  }
393
 
394
  if (count($successfulDeactivations) > 0) {
395
  $msg .= '<p>Rewrite rules were removed from the following files:</p>';
396
  foreach ($successfulDeactivations as $rootId) {
397
- $msg .= '<i>' . Paths::getAbsDirById($rootId) . '/.htaccess</i> (' . $rootId . ')<br>';
 
 
 
 
398
  }
399
  }
400
 
387
  if (count($successfullWrites) > 0) {
388
  $msg .= '<p>Rewrite rules were saved to the following files:</p>';
389
  foreach ($successfullWrites as $rootId) {
390
+ $rootIdName = $rootId;
391
+ if ($rootIdName == 'cache') {
392
+ $rootIdName = 'webp folder';
393
+ }
394
+ $msg .= '<i>' . Paths::getAbsDirById($rootId) . '/.htaccess</i> (' . $rootIdName . ')<br>';
395
  }
396
  }
397
 
398
  if (count($successfulDeactivations) > 0) {
399
  $msg .= '<p>Rewrite rules were removed from the following files:</p>';
400
  foreach ($successfulDeactivations as $rootId) {
401
+ $rootIdName = $rootId;
402
+ if ($rootIdName == 'cache') {
403
+ $rootIdName = 'webp folder';
404
+ }
405
+ $msg .= '<i>' . Paths::getAbsDirById($rootId) . '/.htaccess</i> (' . $rootIdName . ')<br>';
406
  }
407
  }
408
 
lib/classes/HTAccessRules.php CHANGED
@@ -1055,12 +1055,22 @@ class HTAccessRules
1055
  $rules .= "<IfModule mod_rewrite.c>\n" .
1056
  " RewriteEngine On\n\n";
1057
 
1058
- $rules .= " # Escape hatch #1: Adding ?original to an url can be used to bypass redirection\n";
 
 
 
 
 
 
 
 
 
 
1059
  $rules .= " RewriteCond %{QUERY_STRING} original$\n";
1060
  $rules .= " RewriteCond %{REQUEST_FILENAME} -f\n";
1061
  $rules .= " RewriteRule . - [L]\n\n";
1062
 
1063
- $rules .= " # Escape hatch #2: Placing an empty file in the same folder as the jpeg/png which has same file name, but \".do-not-convert\" appended will bypass redirection\n";
1064
  $rules .= " RewriteCond %{REQUEST_FILENAME} (?i)(.*)(\.jpe?g|\.png)$\n";
1065
  $rules .= " RewriteCond %1%2\.do-not-convert -f\n";
1066
  $rules .= " RewriteRule . - [L]\n\n";
1055
  $rules .= "<IfModule mod_rewrite.c>\n" .
1056
  " RewriteEngine On\n\n";
1057
 
1058
+ $rules .= " # Escape hatch #1: Adding ?dontreplace to an url can be used to bypass redirection\n";
1059
+ $rules .= " RewriteCond %{QUERY_STRING} dontreplace$\n";
1060
+ $rules .= " RewriteCond %{REQUEST_FILENAME} -f\n";
1061
+ $rules .= " RewriteRule . - [L]\n\n";
1062
+
1063
+ $rules .= " # Escape hatch #2: Placing an empty file in the same folder as the jpeg/png which has same file name, but \".dontreplace\" appended will bypass redirection\n";
1064
+ $rules .= " RewriteCond %{REQUEST_FILENAME} (?i)(.*)(\.jpe?g|\.png)$\n";
1065
+ $rules .= " RewriteCond %1%2\.dontreplace -f\n";
1066
+ $rules .= " RewriteRule . - [L]\n\n";
1067
+
1068
+ $rules .= " # Deprecated escape hatch: Adding ?original to an url can be used to bypass redirection\n";
1069
  $rules .= " RewriteCond %{QUERY_STRING} original$\n";
1070
  $rules .= " RewriteCond %{REQUEST_FILENAME} -f\n";
1071
  $rules .= " RewriteRule . - [L]\n\n";
1072
 
1073
+ $rules .= " # Deprecated escape hatch: Placing an empty file in the same folder as the jpeg/png which has same file name, but \".do-not-convert\" appended will bypass redirection\n";
1074
  $rules .= " RewriteCond %{REQUEST_FILENAME} (?i)(.*)(\.jpe?g|\.png)$\n";
1075
  $rules .= " RewriteCond %1%2\.do-not-convert -f\n";
1076
  $rules .= " RewriteRule . - [L]\n\n";
lib/classes/Paths.php CHANGED
@@ -586,43 +586,11 @@ APACHE
586
  * (but not quite, as the logic is also in ConverterHelperIndependent::getDestination).
587
  *
588
  * @param string $rootId
589
- * @param string $destinationFolder ("mingled" or "separate")
590
- * @param string $destinationStructure ("doc-root" or "image-roots")
591
  *
592
  * @return array url and abs-path of destination root
593
  */
594
- public static function destinationRoot($rootId, $destinationFolder, $destinationStructure)
595
- {
596
- if (($destinationFolder == 'mingled') && ($rootId == 'uploads')) {
597
- return [
598
- 'url' => self::getUrlById('uploads'),
599
- 'abs-path' => self::getUploadDirAbs()
600
- ];
601
- } else {
602
-
603
- // Its within these bases:
604
- $destUrl = self::getUrlById('wp-content') . '/webp-express/webp-images';
605
- $destPath = self::getAbsDirById('wp-content') . '/webp-express/webp-images';
606
-
607
- if (($destinationStructure == 'doc-root') && self::canUseDocRootForStructuringCacheDir()) {
608
- $relPathFromDocRootToSourceImageRoot = PathHelper::getRelPathFromDocRootToDirNoDirectoryTraversalAllowed(
609
- self::getAbsDirById($rootId)
610
- );
611
- return [
612
- 'url' => $destUrl . '/doc-root/' . $relPathFromDocRootToSourceImageRoot,
613
- 'abs-path' => $destPath . '/doc-root/' . $relPathFromDocRootToSourceImageRoot
614
- ];
615
- } else {
616
- return [
617
- 'url' => $destUrl . '/' . $rootId,
618
- 'abs-path' => $destPath . '/' . $rootId
619
- ];
620
- }
621
- }
622
- }
623
-
624
- // this shall replace destinationRoot
625
- public static function destinationRoot2($rootId, $destinationOptions)
626
  {
627
  if (($destinationOptions->mingled) && ($rootId == 'uploads')) {
628
  return [
@@ -644,9 +612,13 @@ APACHE
644
  'abs-path' => $destPath . '/doc-root/' . $relPathFromDocRootToSourceImageRoot
645
  ];
646
  } else {
 
 
 
 
647
  return [
648
- 'url' => $destUrl . '/' . $rootId,
649
- 'abs-path' => $destPath . '/' . $rootId
650
  ];
651
  }
652
  }
586
  * (but not quite, as the logic is also in ConverterHelperIndependent::getDestination).
587
  *
588
  * @param string $rootId
589
+ * @param DestinationOptions $destinationOptions
 
590
  *
591
  * @return array url and abs-path of destination root
592
  */
593
+ public static function destinationRoot($rootId, $destinationOptions)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
594
  {
595
  if (($destinationOptions->mingled) && ($rootId == 'uploads')) {
596
  return [
612
  'abs-path' => $destPath . '/doc-root/' . $relPathFromDocRootToSourceImageRoot
613
  ];
614
  } else {
615
+ $extraPath = '';
616
+ if (is_multisite() && (get_current_blog_id() != 1)) {
617
+ $extraPath = '/sites/' . get_current_blog_id(); // #510
618
+ }
619
  return [
620
+ 'url' => $destUrl . '/' . $rootId . $extraPath,
621
+ 'abs-path' => $destPath . '/' . $rootId . $extraPath
622
  ];
623
  }
624
  }
lib/classes/PluginActivate.php CHANGED
@@ -78,15 +78,6 @@ class PluginActivate
78
  );
79
  }
80
 
81
-
82
- if ( is_multisite() ) {
83
- Messenger::addMessage(
84
- 'warning',
85
- 'Multisite functionality in still new in WebP Express (it was added in release 0.12.0). ' .
86
- 'While it has been tested on several setups, there might be a bug or two yet to be found.'
87
- );
88
- }
89
-
90
  if (!version_compare(PHP_VERSION, '5.5.0', '>=')) {
91
  Messenger::addMessage(
92
  'warning',
78
  );
79
  }
80
 
 
 
 
 
 
 
 
 
 
81
  if (!version_compare(PHP_VERSION, '5.5.0', '>=')) {
82
  Messenger::addMessage(
83
  'warning',
lib/classes/TestRun.php CHANGED
@@ -22,6 +22,30 @@ class TestRun
22
 
23
  public static $converterStatus = null; // to cache the result
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  /**
26
  * Get a test result object OR false, if tests cannot be made.
27
  *
@@ -45,6 +69,7 @@ class TestRun
45
  }
46
  $workingConverters = [];
47
  $errors = [];
 
48
 
49
  // We need wod options.
50
  // But we cannot simply use loadWodOptions - because that would leave out the deactivated
@@ -60,9 +85,16 @@ class TestRun
60
  $options = Config::generateWodOptionsFromConfigObj($config);
61
  $options['converters'] = ConvertersHelper::normalize($options['webp-convert']['convert']['converters']);
62
 
 
 
 
 
 
 
63
  //echo '<pre>' . print_r($options, true) . '</pre>';
64
  foreach ($options['converters'] as $converter) {
65
  $converterId = $converter['converter'];
 
66
  try {
67
  $converterOptions = array_merge($options, $converter['options']);
68
  unset($converterOptions['converters']);
@@ -74,19 +106,30 @@ class TestRun
74
  $destination,
75
  $converterOptions
76
  );
 
 
 
 
77
  $converterInstance->doConvert();
 
 
 
 
78
  $workingConverters[] = $converterId;
79
  } catch (\Exception $e) {
80
  //echo $e->getMessage() . '<br>';
81
  $errors[$converterId] = $e->getMessage();
82
  }
83
  }
 
 
84
  //print_r($errors);
85
 
86
  // cache the result
87
  self::$converterStatus = [
88
  'workingConverters' => $workingConverters,
89
- 'errors' => $errors
 
90
  ];
91
  return self::$converterStatus;
92
  }
22
 
23
  public static $converterStatus = null; // to cache the result
24
 
25
+ private static $warnings;
26
+
27
+ public static function warningHandler($errno, $errstr, $errfile, $errline, $errcontext = null)
28
+ {
29
+ $errorTypes = [
30
+ E_WARNING => "Warning",
31
+ E_NOTICE => "Notice",
32
+ E_STRICT => "Strict Notice",
33
+ E_DEPRECATED => "Deprecated",
34
+ E_USER_DEPRECATED => "User Deprecated",
35
+ ];
36
+
37
+ if (isset($errorTypes[$errno])) {
38
+ $errType = $errorTypes[$errno];
39
+ } else {
40
+ $errType = "Warning ($errno)";
41
+ }
42
+
43
+ $msg = $errType . ': ' . $errstr . ' in ' . $errfile . ', line ' . $errline;
44
+ self::$warnings[] = $msg;
45
+
46
+ // suppress!
47
+ return true;
48
+ }
49
  /**
50
  * Get a test result object OR false, if tests cannot be made.
51
  *
69
  }
70
  $workingConverters = [];
71
  $errors = [];
72
+ self::$warnings = [];
73
 
74
  // We need wod options.
75
  // But we cannot simply use loadWodOptions - because that would leave out the deactivated
85
  $options = Config::generateWodOptionsFromConfigObj($config);
86
  $options['converters'] = ConvertersHelper::normalize($options['webp-convert']['convert']['converters']);
87
 
88
+ $previousErrorHandler = set_error_handler(
89
+ array('\WebPExpress\TestRun', "warningHandler"),
90
+ E_WARNING | E_USER_WARNING | E_NOTICE | E_USER_NOTICE
91
+ );
92
+
93
+ $warnings = [];
94
  //echo '<pre>' . print_r($options, true) . '</pre>';
95
  foreach ($options['converters'] as $converter) {
96
  $converterId = $converter['converter'];
97
+ self::$warnings = [];
98
  try {
99
  $converterOptions = array_merge($options, $converter['options']);
100
  unset($converterOptions['converters']);
106
  $destination,
107
  $converterOptions
108
  );
109
+ // Note: We now suppress warnings.
110
+ // WebPConvert logs warnings but purposefully does not stop them - warnings should generally not be
111
+ // stopped. However, as these warnings are logged in conversion log, it is preferable not to make them
112
+ // bubble here. #
113
  $converterInstance->doConvert();
114
+
115
+ if (count(self::$warnings) > 0) {
116
+ $warnings[$converterId] = self::$warnings;
117
+ }
118
  $workingConverters[] = $converterId;
119
  } catch (\Exception $e) {
120
  //echo $e->getMessage() . '<br>';
121
  $errors[$converterId] = $e->getMessage();
122
  }
123
  }
124
+
125
+ restore_error_handler();
126
  //print_r($errors);
127
 
128
  // cache the result
129
  self::$converterStatus = [
130
  'workingConverters' => $workingConverters,
131
+ 'errors' => $errors,
132
+ 'warnings' => $warnings,
133
  ];
134
  return self::$converterStatus;
135
  }
lib/classes/WCFMApi.php CHANGED
@@ -223,7 +223,8 @@ class WCFMApi
223
  //'filename' => $absPath,
224
  //'abspath' => $absPath,
225
  'size' => filesize($absPath),
226
- 'url' => Paths::getUrlById($rootId) . '/' . $relPath . '?' . SelfTestHelper::randomDigitsAndLetters(8) . '&original',
 
227
  ]
228
  ];
229
 
@@ -246,15 +247,31 @@ class WCFMApi
246
  $destinationUrl = Paths::getUrlById($rootId) . '/' . $destRelPath;
247
 
248
  SanityCheck::absPath($absPathDest);
 
249
  if (@file_exists($absPathDest)) {
250
  $result['converted'] = [
251
- 'abspath' => $absPathDest,
252
  'size' => filesize($absPathDest),
253
  'url' => $destinationUrl . '?' . SelfTestHelper::randomDigitsAndLetters(8),
254
- 'log' => ''
255
  ];
256
  }
257
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
258
  }
259
 
260
 
@@ -289,6 +306,42 @@ class WCFMApi
289
  return $result;
290
  }
291
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
292
  public static function processGetFolder() {
293
 
294
  Validate::postHasKey('args');
@@ -328,23 +381,7 @@ class WCFMApi
328
  }
329
  return $result;
330
  }
331
- $path = SanityCheck::pathWithoutDirectoryTraversal($path);
332
- $path = ltrim($path, '/');
333
- $pathTokens = explode('/', $path);
334
-
335
- $rootId = array_shift($pathTokens);
336
- $relPath = implode('/', $pathTokens);
337
-
338
- if (!in_array($rootId, $rootIds)) {
339
- throw new \Exception('Invalid rootId');
340
- }
341
-
342
- if ($relPath == '') {
343
- $relPath = '.';
344
- }
345
-
346
- $absPath = Paths::getAbsDirById($rootId) . '/' . $relPath;
347
- SanityCheck::absPathExists($absPath);
348
 
349
  $listOptions = BulkConvert::defaultListOptions($config);
350
  $listOptions['root'] = Paths::getAbsDirById($rootId);
@@ -404,11 +441,31 @@ class WCFMApi
404
  if (!array_key_exists('path', $args)) {
405
  throw new \Exception('"path" argument missing for command');
406
  }
407
- if (!array_key_exists('convertOptions', $args)) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
408
  throw new \Exception('"convertOptions" argument missing for command');
409
  }
 
 
410
 
411
- return ['success' => true, 'optionsReceived' => $args['convertOptions']];
412
 
413
  /*
414
  $path = SanityCheck::pathWithoutDirectoryTraversal($args['path']);
223
  //'filename' => $absPath,
224
  //'abspath' => $absPath,
225
  'size' => filesize($absPath),
226
+ // PS: I keep "&original" because some might have set up Nginx rules for ?original
227
+ 'url' => Paths::getUrlById($rootId) . '/' . $relPath . '?' . SelfTestHelper::randomDigitsAndLetters(8) . '&dontreplace&original',
228
  ]
229
  ];
230
 
247
  $destinationUrl = Paths::getUrlById($rootId) . '/' . $destRelPath;
248
 
249
  SanityCheck::absPath($absPathDest);
250
+
251
  if (@file_exists($absPathDest)) {
252
  $result['converted'] = [
253
+ //'abspath' => $absPathDest,
254
  'size' => filesize($absPathDest),
255
  'url' => $destinationUrl . '?' . SelfTestHelper::randomDigitsAndLetters(8),
 
256
  ];
257
  }
258
 
259
+ // Get log, if exists. Ignore errors.
260
+ $log = '';
261
+ try {
262
+ $logFile = ConvertHelperIndependent::getLogFilename($absPath, Paths::getLogDirAbs());
263
+ if (@file_exists($logFile)) {
264
+ $logContent = file_get_contents($logFile);
265
+ if ($log !== false) {
266
+ $log = $logContent;
267
+ }
268
+ }
269
+ }
270
+ catch (\Exception $e) {
271
+ //throw $e;
272
+ }
273
+
274
+ $result['log'] = $log;
275
  }
276
 
277
 
306
  return $result;
307
  }
308
 
309
+ /**
310
+ * Translate path received (ie "/uploads/2021/...") to absolute path.
311
+ *
312
+ * @param string $path
313
+ *
314
+ * @return array [$absPath, $relPath, $rootId]
315
+ * @throws \Exception if root id is invalid or path doesn't pass sanity check
316
+ */
317
+ private static function analyzePathReceived($path) {
318
+ try {
319
+ $path = SanityCheck::pathWithoutDirectoryTraversal($path);
320
+ $path = ltrim($path, '/');
321
+ $pathTokens = explode('/', $path);
322
+
323
+ $rootId = array_shift($pathTokens);
324
+ $relPath = implode('/', $pathTokens);
325
+
326
+ $rootIds = Paths::getImageRootIds();
327
+ if (!in_array($rootId, $rootIds)) {
328
+ throw new \Exception('Invalid rootId');
329
+ }
330
+ if ($relPath == '') {
331
+ $relPath = '.';
332
+ }
333
+
334
+ $absPath = PathHelper::canonicalize(Paths::getAbsDirById($rootId) . '/' . $relPath);
335
+ SanityCheck::absPathExists($absPath);
336
+
337
+ return [$absPath, $relPath, $rootId];
338
+ }
339
+ catch (\Exception $e) {
340
+ //throw new \Exception('Invalid path received (' . $e->getMessage() . ')');
341
+ throw new \Exception('Invalid path');
342
+ }
343
+ }
344
+
345
  public static function processGetFolder() {
346
 
347
  Validate::postHasKey('args');
381
  }
382
  return $result;
383
  }
384
+ list($absPath, $relPath, $rootId) = self::analyzePathReceived($path);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
385
 
386
  $listOptions = BulkConvert::defaultListOptions($config);
387
  $listOptions['root'] = Paths::getAbsDirById($rootId);
441
  if (!array_key_exists('path', $args)) {
442
  throw new \Exception('"path" argument missing for command');
443
  }
444
+
445
+ $path = SanityCheck::noStreamWrappers($args['path']);
446
+ list($absPath, $relPath, $rootId) = self::analyzePathReceived($path);
447
+ $convertResult = Convert::convertFile($absPath);
448
+ $result = [
449
+ 'success' => $convertResult['success'],
450
+ 'data' => $convertResult['msg'],
451
+ 'log' => $convertResult['log'],
452
+ ];
453
+ $info = [];
454
+ if (isset($convertResult['filesize-webp'])) {
455
+ $info['size'] = $convertResult['filesize-webp'];
456
+ }
457
+ if (isset($convertResult['destination-url'])) {
458
+ $info['url'] = $convertResult['destination-url'] . '?' . SelfTestHelper::randomDigitsAndLetters(8);
459
+ }
460
+ $result['converted'] = $info;
461
+ return $result;
462
+
463
+ /*if (!array_key_exists('convertOptions', $args)) {
464
  throw new \Exception('"convertOptions" argument missing for command');
465
  }
466
+ //return ['success' => true, 'optionsReceived' => $args['convertOptions']];
467
+ */
468
 
 
469
 
470
  /*
471
  $path = SanityCheck::pathWithoutDirectoryTraversal($args['path']);
lib/classes/WCFMPage.php CHANGED
@@ -13,10 +13,6 @@ class WCFMPage
13
  public static function display() {
14
  echo '<div id="wcfmintro">' .
15
  '<h1>WebP Express Conversion Browser</h1>' .
16
- '<p>' .
17
- 'Note: To convert manually, you still need to use Bulk Convert on the settings page ' .
18
- '(or you can use WP CLI)' .
19
- '</p>' .
20
  '</div>';
21
 
22
  echo '<div id="webpconvert-filemanager" style="position:relative; min-height:400px">loading</div>';
@@ -43,7 +39,7 @@ class WCFMPage
43
 
44
  public static function addToHead() {
45
  $baseUrl = plugins_url('lib/wcfm', WEBPEXPRESS_PLUGIN);
46
- //$url = plugins_url('js/conversion-manager/index.9149ea80.js', WEBPEXPRESS_PLUGIN);
47
 
48
  $wcfmNonce = wp_create_nonce('webpexpress-wcfm-nonce');
49
  echo '<scr' . 'ipt>window.webpExpressWCFMNonce = "' . $wcfmNonce . '";</scr' . 'ipt>';
@@ -51,9 +47,8 @@ class WCFMPage
51
  echo '<scr' . 'ipt src="' . $baseUrl . '/wcfm-options.js?11"></scr' . 'ipt>';
52
  //echo '<scr' . 'ipt type="module" src="' . $baseUrl . '/vendor.js?1"></scr' . 'ipt>';
53
 
54
- // TODO: make a script in npm for automatically updating the filenames below when copying
55
- echo '<scr' . 'ipt type="module" src="' . $baseUrl . '/index.f8d1bd25.js"></scr' . 'ipt>';
56
- echo '<link rel="stylesheet" href="' . $baseUrl . '/index.ab43bb2c.css">';
57
  }
58
 
59
  }
13
  public static function display() {
14
  echo '<div id="wcfmintro">' .
15
  '<h1>WebP Express Conversion Browser</h1>' .
 
 
 
 
16
  '</div>';
17
 
18
  echo '<div id="webpconvert-filemanager" style="position:relative; min-height:400px">loading</div>';
39
 
40
  public static function addToHead() {
41
  $baseUrl = plugins_url('lib/wcfm', WEBPEXPRESS_PLUGIN);
42
+ //$url = plugins_url('js/conversion-manager/index.ee44cdbf.js ', WEBPEXPRESS_PLUGIN);
43
 
44
  $wcfmNonce = wp_create_nonce('webpexpress-wcfm-nonce');
45
  echo '<scr' . 'ipt>window.webpExpressWCFMNonce = "' . $wcfmNonce . '";</scr' . 'ipt>';
47
  echo '<scr' . 'ipt src="' . $baseUrl . '/wcfm-options.js?11"></scr' . 'ipt>';
48
  //echo '<scr' . 'ipt type="module" src="' . $baseUrl . '/vendor.js?1"></scr' . 'ipt>';
49
 
50
+ echo '<scr' . 'ipt type="module" src="' . $baseUrl . '/index.ee44cdbf.js"></scr' . 'ipt>';
51
+ echo '<link rel="stylesheet" href="' . $baseUrl . '/index.659b742a.css">';
 
52
  }
53
 
54
  }
lib/dismissable-messages/0.23.0/elementor.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebPExpress;
4
+
5
+ $elementorActivated = in_array('elementor/elementor.php', get_option('active_plugins', []));
6
+ $showMessage = false;
7
+ if ($elementorActivated) {
8
+ try {
9
+ // The following is wrapped in a try statement because it depends on Elementor classes which might be subject to change
10
+ if (\Elementor\Plugin::$instance->experiments->is_feature_active( 'e_optimized_css_loading' ) === false) {
11
+ $showMessage = true;
12
+ }
13
+ } catch (\Exception $e) {
14
+ // Well, just bad luck.
15
+ }
16
+ }
17
+
18
+ if ($showMessage) {
19
+ DismissableMessages::printDismissableMessage(
20
+ 'info',
21
+ '<p>' .
22
+ 'You see this message because you using Elementor, you rely solely on Alter HTML for webp, and Elementor is currently set up to use external css. ' .
23
+ 'You might want to reconfigure Elementor so it inlines the CSS. This will allow Alter HTML to replace the image urls of backgrounds. ' .
24
+ 'To reconfigure, go to <i>Elementor > Settings > Experiments</i> and activate "Improved CSS Loading". ' .
25
+ 'Note: This requires that Alter HTML is configured to "Replace image URLs". ' .
26
+ 'For more information, <a target="_blank" href="https://wordpress.org/support/topic/background-images-not-working-as-webp-elementor/#post-15060686">' .
27
+ 'head over here</a>' .
28
+ '</p>',
29
+ '0.23.0/elementor',
30
+ 'Got it!'
31
+ );
32
+ } else {
33
+ DismissableMessages::dismissMessage('0.23.0/elementor');
34
+ }
lib/options/css/webp-express-options-page.css CHANGED
@@ -166,10 +166,13 @@
166
  #converters li svg#status_not_ok {
167
  color: #b11010; /* 444444 */
168
  }
 
 
 
 
169
  #converters li.deactivated svg#status_not_ok {
170
  color: #999999;
171
  }
172
-
173
  #converters li.deactivated .status {
174
  bottom: unset;
175
  }
@@ -255,6 +258,10 @@
255
  #converters li.operational .popup {
256
  background-color: #80ff80;
257
  }
 
 
 
 
258
  /* #converters li .status:hover .popup,*/
259
  #converters li:hover .status .popup,
260
  .help:hover .popup {
166
  #converters li svg#status_not_ok {
167
  color: #b11010; /* 444444 */
168
  }
169
+ #converters li svg#status_warning {
170
+ color: #dc0;
171
+ }
172
+
173
  #converters li.deactivated svg#status_not_ok {
174
  color: #999999;
175
  }
 
176
  #converters li.deactivated .status {
177
  bottom: unset;
178
  }
258
  #converters li.operational .popup {
259
  background-color: #80ff80;
260
  }
261
+ #converters li.has-warnings .popup {
262
+ background-color: #ff5;
263
+ }
264
+
265
  /* #converters li .status:hover .popup,*/
266
  #converters li:hover .status .popup,
267
  .help:hover .popup {
lib/options/enqueue_scripts.php CHANGED
@@ -5,8 +5,12 @@ if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
5
  use \WebPExpress\Paths;
6
  use \WebPExpress\Config;
7
 
8
- $ver = '8'; // note: Minimum 1
9
- $jsDir = 'js/0.19.0'; // We change dir when it is critical that no-one gets the cached version (there is a plugin that strips version strings out there...)
 
 
 
 
10
 
11
  if (!function_exists('webp_express_add_inline_script')) {
12
  function webp_express_add_inline_script($id, $script, $position) {
5
  use \WebPExpress\Paths;
6
  use \WebPExpress\Config;
7
 
8
+ // Note: $ver is added to querystring. However, when it is is critical that no-one gets the cached version,
9
+ // a change of filename is neccessary, as there is a plugin that strips version strings out there...!
10
+ // If only one file update is critical: change the name of the file
11
+ // If several files are critical: rename the folder (ie "js2")
12
+ $ver = '3'; // note: Minimum 1.
13
+ $jsDir = 'js';
14
 
15
  if (!function_exists('webp_express_add_inline_script')) {
16
  function webp_express_add_inline_script($id, $script, $position) {
lib/options/js/{0.19.0/authorized_sites_bak.js → authorized_sites_bak.js} RENAMED
File without changes
lib/options/js/{0.19.0/bulk-convert.js → bulk-convert.js} RENAMED
File without changes
lib/options/js/{0.19.0/converters.js → converters.js} RENAMED
@@ -26,7 +26,7 @@ function getConversionMethodDescription(converterId) {
26
  }
27
 
28
  function generateConverterHTML(converter) {
29
- html = '<li data-id="' + converter['id'] + '" class="' + (converter.deactivated ? 'deactivated' : '') + ' ' + (converter.working ? 'operational' : 'not-operational') + '">';
30
  //html += '<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="17px" height="17px" viewBox="0 0 100.000000 100.000000" preserveAspectRatio="xMidYMid meet"><g transform="translate(0.000000,100.000000) scale(0.100000,-0.100000)" fill="#444444" stroke="none"><path d="M415 920 l-80 -80 165 0 165 0 -80 80 c-44 44 -82 80 -85 80 -3 0 -41 -36 -85 -80z"/><path d="M0 695 l0 -45 500 0 500 0 0 45 0 45 -500 0 -500 0 0 -45z"/><path d="M0 500 l0 -40 500 0 500 0 0 40 0 40 -500 0 -500 0 0 -40z"/><path d="M0 305 l0 -45 500 0 500 0 0 45 0 45 -500 0 -500 0 0 -45z"/><path d="M418 78 l82 -83 82 83 83 82 -165 0 -165 0 83 -82z"/></g></svg>';
31
  // html += '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20 9H4v2h16V9zM4 15h16v-2H4v2z"/></svg>';
32
  // html += '<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 100.000000 100.000000" preserveAspectRatio="xMidYMid meet"><g transform="translate(0.000000,100.000000) scale(0.100000,-0.100000)" fill="#888888" stroke="none"><path d="M415 920 l-80 -80 165 0 165 0 -80 80 c-44 44 -82 80 -85 80 -3 0 -41 -36 -85 -80z"/><path d="M0 695 l0 -45 500 0 500 0 0 45 0 45 -500 0 -500 0 0 -45z"/><path d="M0 500 l0 -40 500 0 500 0 0 40 0 40 -500 0 -500 0 0 -40z"/><path d="M0 305 l0 -45 500 0 500 0 0 45 0 45 -500 0 -500 0 0 -45z"/><path d="M418 78 l82 -83 82 83 83 82 -165 0 -165 0 83 -82z"/></g></svg>';
@@ -45,23 +45,51 @@ function generateConverterHTML(converter) {
45
  }
46
 
47
  html += '<div class="status">';
48
- if (converter.working) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  html += '<svg id="status_ok" width="19" height="19" version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256.000000 256.000000" preserveAspectRatio="xMidYMid meet">';
50
  html += '<g fill="currentcolor" stroke="none" transform="translate(0.000000,256.000000) scale(0.100000,-0.100000)"><path d="M1064 2545 c-406 -72 -744 -324 -927 -690 -96 -193 -127 -333 -127 -575 0 -243 33 -387 133 -585 177 -351 518 -606 907 -676 118 -22 393 -17 511 8 110 24 252 78 356 136 327 183 569 525 628 887 19 122 19 338 0 460 -81 498 -483 914 -990 1025 -101 22 -389 28 -491 10z m814 -745 c39 -27 73 -59 77 -70 9 -27 10 -25 -372 -590 -345 -510 -357 -524 -420 -512 -19 4 -98 74 -250 225 -123 121 -225 228 -228 238 -3 10 1 31 9 47 20 40 125 132 149 132 11 0 79 -59 162 -140 79 -77 146 -140 149 -140 3 0 38 48 78 108 95 143 465 678 496 720 35 46 64 42 150 -18z"/></g></svg>';
51
  //html += '<div class="popup">' + converter['id'] + ' is operational</div>';
52
  html += '<div class="popup">Operational</div>';
53
- } else {
54
- // + converter['id'] + ' is not operational<br>';
55
- //html += 'not operational. ';
56
- if (converter['error']) {
57
- html += '<svg id="status_not_ok" width="19" height="19" title="not operational" version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500.000000 500.000000" preserveAspectRatio="xMidYMid meet">';
58
- html += '<g fill="currentcolor" stroke="none" transform="translate(0.000000,500.000000) scale(0.100000,-0.100000)"><path d="M2315 4800 c-479 -35 -928 -217 -1303 -527 -352 -293 -615 -702 -738 -1151 -104 -380 -104 -824 0 -1204 107 -389 302 -724 591 -1013 354 -354 785 -572 1279 -646 196 -30 476 -30 672 0 494 74 925 292 1279 646 354 354 571 784 646 1279 30 197 30 475 0 672 -75 495 -292 925 -646 1279 -289 289 -624 484 -1013 591 -228 62 -528 91 -767 74z m353 -511 c458 -50 874 -272 1170 -624 417 -497 536 -1174 308 -1763 -56 -145 -176 -367 -235 -434 -4 -4 -566 552 -1250 1236 l-1243 1243 94 60 c354 229 754 327 1156 282z m864 -3200 c-67 -59 -289 -179 -434 -235 -946 -366 -2024 172 -2322 1158 -47 155 -66 276 -73 453 -13 362 84 704 290 1023 l60 94 1243 -1243 c684 -684 1240 -1246 1236 -1250z"/></g></svg>';
59
- html += '<div class="popup">';
60
-
61
- html += webpexpress_escapeHTML(converter['error']);
62
-
63
- html += '</div>';
64
- }
65
  }
66
  html += '</div>';
67
 
@@ -292,6 +320,7 @@ function configureConverter(id) {
292
  document.getElementById('cwebp_use_nice').checked = getConverterOption(converter, 'use-nice', true);
293
  document.getElementById('cwebp_method').value = getConverterOption(converter, 'method', '');
294
  document.getElementById('cwebp_try_common_system_paths').checked = getConverterOption(converter, 'try-common-system-paths', '');
 
295
  document.getElementById('cwebp_try_supplied_binary').checked = getConverterOption(converter, 'try-supplied-binary-for-os', '');
296
  document.getElementById('cwebp_set_size').checked = getConverterOption(converter, 'set-size', '');
297
  document.getElementById('cwebp_size_in_percentage').value = getConverterOption(converter, 'size-in-percentage', '');
@@ -375,6 +404,7 @@ function updateConverterOptions() {
375
  var methodString = document.getElementById('cwebp_method').value;
376
  var methodNum = (methodString == '') ? 6 : parseInt(methodString, 10);
377
  setConverterOption(converter, 'method', methodNum);
 
378
  setConverterOption(converter, 'try-common-system-paths', document.getElementById('cwebp_try_common_system_paths').checked);
379
  setConverterOption(converter, 'try-supplied-binary-for-os', document.getElementById('cwebp_try_supplied_binary').checked);
380
  setConverterOption(converter, 'set-size', document.getElementById('cwebp_set_size').checked);
26
  }
27
 
28
  function generateConverterHTML(converter) {
29
+ html = '<li data-id="' + converter['id'] + '" class="' + (converter.deactivated ? 'deactivated' : '') + ' ' + (converter.working ? 'operational' : 'not-operational') + ' ' + (converter.warnings ? 'has-warnings' : '') + '">';
30
  //html += '<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="17px" height="17px" viewBox="0 0 100.000000 100.000000" preserveAspectRatio="xMidYMid meet"><g transform="translate(0.000000,100.000000) scale(0.100000,-0.100000)" fill="#444444" stroke="none"><path d="M415 920 l-80 -80 165 0 165 0 -80 80 c-44 44 -82 80 -85 80 -3 0 -41 -36 -85 -80z"/><path d="M0 695 l0 -45 500 0 500 0 0 45 0 45 -500 0 -500 0 0 -45z"/><path d="M0 500 l0 -40 500 0 500 0 0 40 0 40 -500 0 -500 0 0 -40z"/><path d="M0 305 l0 -45 500 0 500 0 0 45 0 45 -500 0 -500 0 0 -45z"/><path d="M418 78 l82 -83 82 83 83 82 -165 0 -165 0 83 -82z"/></g></svg>';
31
  // html += '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20 9H4v2h16V9zM4 15h16v-2H4v2z"/></svg>';
32
  // html += '<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 100.000000 100.000000" preserveAspectRatio="xMidYMid meet"><g transform="translate(0.000000,100.000000) scale(0.100000,-0.100000)" fill="#888888" stroke="none"><path d="M415 920 l-80 -80 165 0 165 0 -80 80 c-44 44 -82 80 -85 80 -3 0 -41 -36 -85 -80z"/><path d="M0 695 l0 -45 500 0 500 0 0 45 0 45 -500 0 -500 0 0 -45z"/><path d="M0 500 l0 -40 500 0 500 0 0 40 0 40 -500 0 -500 0 0 -40z"/><path d="M0 305 l0 -45 500 0 500 0 0 45 0 45 -500 0 -500 0 0 -45z"/><path d="M418 78 l82 -83 82 83 83 82 -165 0 -165 0 83 -82z"/></g></svg>';
45
  }
46
 
47
  html += '<div class="status">';
48
+ if (converter['error']) {
49
+ html += '<svg id="status_not_ok" width="19" height="19" title="not operational" version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500.000000 500.000000" preserveAspectRatio="xMidYMid meet">';
50
+ html += '<g fill="currentcolor" stroke="none" transform="translate(0.000000,500.000000) scale(0.100000,-0.100000)"><path d="M2315 4800 c-479 -35 -928 -217 -1303 -527 -352 -293 -615 -702 -738 -1151 -104 -380 -104 -824 0 -1204 107 -389 302 -724 591 -1013 354 -354 785 -572 1279 -646 196 -30 476 -30 672 0 494 74 925 292 1279 646 354 354 571 784 646 1279 30 197 30 475 0 672 -75 495 -292 925 -646 1279 -289 289 -624 484 -1013 591 -228 62 -528 91 -767 74z m353 -511 c458 -50 874 -272 1170 -624 417 -497 536 -1174 308 -1763 -56 -145 -176 -367 -235 -434 -4 -4 -566 552 -1250 1236 l-1243 1243 94 60 c354 229 754 327 1156 282z m864 -3200 c-67 -59 -289 -179 -434 -235 -946 -366 -2024 172 -2322 1158 -47 155 -66 276 -73 453 -13 362 84 704 290 1023 l60 94 1243 -1243 c684 -684 1240 -1246 1236 -1250z"/></g></svg>';
51
+ html += '<div class="popup">';
52
+
53
+ html += webpexpress_escapeHTML(converter['error']);
54
+
55
+ html += '</div>';
56
+ } else if (converter['warnings']) {
57
+ /*html += '<svg id="status_warning" width="19" height="19" version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 478.125 478.125">';
58
+ html += '<g fill="currentcolor"">';
59
+ html += '<circle cx="239.904" cy="314.721" r="35.878"/>';
60
+ html += '<path d="M256.657,127.525h-31.9c-10.557,0-19.125,8.645-19.125,19.125v101.975c0,10.48,8.645,19.125,19.125,19.125h31.9c10.48,0,19.125-8.645,19.125-19.125V146.65C275.782,136.17,267.138,127.525,256.657,127.525z"/>';
61
+ html += '<path d="M239.062,0C106.947,0,0,106.947,0,239.062s106.947,239.062,239.062,239.062c132.115,0,239.062-106.947,239.062-239.062S371.178,0,239.062,0z M239.292,409.734c-94.171,0-170.595-76.348-170.595-170.596c0-94.248,76.347-170.595,170.595-170.595s170.595,76.347,170.595,170.595C409.887,333.387,333.464,409.734,239.292,409.734z"/>';
62
+ html += '</g></svg>';*/
63
+ html += '<svg id="status_warning" width="19" height="19" version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 123.996 123.996">';
64
+ html += '<circle cx="62" cy="67" r="35" color="black"/>';
65
+ html += '<g fill="currentcolor">';
66
+ html += '<path d="M9.821,118.048h104.4c7.3,0,12-7.7,8.7-14.2l-52.2-92.5c-3.601-7.199-13.9-7.199-17.5,0l-52.2,92.5C-2.179,110.348,2.521,118.048,9.821,118.048z M70.222,96.548c0,4.8-3.5,8.5-8.5,8.5s-8.5-3.7-8.5-8.5v-0.2c0-4.8,3.5-8.5,8.5-8.5s8.5,3.7,8.5,8.5V96.548z M57.121,34.048h9.801c2.699,0,4.3,2.3,4,5.2l-4.301,37.6c-0.3,2.7-2.1,4.4-4.6,4.4s-4.3-1.7-4.6-4.4l-4.301-37.6C52.821,36.348,54.422,34.048,57.121,34.048z"/>';
67
+ html += '</g></svg>';
68
+
69
+
70
+ html += '<div class="popup">';
71
+
72
+ if (converter['warnings'].join) {
73
+ if (converter['warnings'].filter) {
74
+ // remove duplicate warnings
75
+ converter['warnings'] = converter['warnings'].filter(function(item, pos, self) {
76
+ return self.indexOf(item) == pos;
77
+ })
78
+ }
79
+ html += '<p>Warnings were issued:</p>';
80
+ for (var i = 0; i<converter['warnings'].length; i++) {
81
+ html += '<p>' + webpexpress_escapeHTML(converter['warnings'][i]) + '</p>';
82
+ }
83
+ // TODO: Tell him to deactivate the converter - or perhaps do it automatically?
84
+ html += '<p>check conversion log for more insight (ie by clicking the "test" link a little left of this warning triangle)</p>';
85
+ }
86
+
87
+ html += '</div>';
88
+ } else if (converter.working) {
89
  html += '<svg id="status_ok" width="19" height="19" version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256.000000 256.000000" preserveAspectRatio="xMidYMid meet">';
90
  html += '<g fill="currentcolor" stroke="none" transform="translate(0.000000,256.000000) scale(0.100000,-0.100000)"><path d="M1064 2545 c-406 -72 -744 -324 -927 -690 -96 -193 -127 -333 -127 -575 0 -243 33 -387 133 -585 177 -351 518 -606 907 -676 118 -22 393 -17 511 8 110 24 252 78 356 136 327 183 569 525 628 887 19 122 19 338 0 460 -81 498 -483 914 -990 1025 -101 22 -389 28 -491 10z m814 -745 c39 -27 73 -59 77 -70 9 -27 10 -25 -372 -590 -345 -510 -357 -524 -420 -512 -19 4 -98 74 -250 225 -123 121 -225 228 -228 238 -3 10 1 31 9 47 20 40 125 132 149 132 11 0 79 -59 162 -140 79 -77 146 -140 149 -140 3 0 38 48 78 108 95 143 465 678 496 720 35 46 64 42 150 -18z"/></g></svg>';
91
  //html += '<div class="popup">' + converter['id'] + ' is operational</div>';
92
  html += '<div class="popup">Operational</div>';
 
 
 
 
 
 
 
 
 
 
 
 
93
  }
94
  html += '</div>';
95
 
320
  document.getElementById('cwebp_use_nice').checked = getConverterOption(converter, 'use-nice', true);
321
  document.getElementById('cwebp_method').value = getConverterOption(converter, 'method', '');
322
  document.getElementById('cwebp_try_common_system_paths').checked = getConverterOption(converter, 'try-common-system-paths', '');
323
+ document.getElementById('cwebp_skip_these_precompiled_binaries').value = getConverterOption(converter, 'skip-these-precompiled-binaries', '');
324
  document.getElementById('cwebp_try_supplied_binary').checked = getConverterOption(converter, 'try-supplied-binary-for-os', '');
325
  document.getElementById('cwebp_set_size').checked = getConverterOption(converter, 'set-size', '');
326
  document.getElementById('cwebp_size_in_percentage').value = getConverterOption(converter, 'size-in-percentage', '');
404
  var methodString = document.getElementById('cwebp_method').value;
405
  var methodNum = (methodString == '') ? 6 : parseInt(methodString, 10);
406
  setConverterOption(converter, 'method', methodNum);
407
+ setConverterOption(converter, 'skip-these-precompiled-binaries', document.getElementById('cwebp_skip_these_precompiled_binaries').value);
408
  setConverterOption(converter, 'try-common-system-paths', document.getElementById('cwebp_try_common_system_paths').checked);
409
  setConverterOption(converter, 'try-supplied-binary-for-os', document.getElementById('cwebp_try_supplied_binary').checked);
410
  setConverterOption(converter, 'set-size', document.getElementById('cwebp_set_size').checked);
lib/options/js/{0.19.0/das-popup.js → das-popup.js} RENAMED
File without changes
lib/options/js/{0.19.0/escapeHTML.js → escapeHTML.js} RENAMED
File without changes
lib/options/js/{0.19.0/image-comparison-slider.js → image-comparison-slider.js} RENAMED
File without changes
lib/options/js/{0.19.0/page.js → page.js} RENAMED
File without changes
lib/options/js/{0.19.0/purge-cache.js → purge-cache.js} RENAMED
File without changes
lib/options/js/{0.19.0/purge-log.js → purge-log.js} RENAMED
File without changes
lib/options/js/{0.19.0/self-test.js → self-test.js} RENAMED
File without changes
lib/options/js/{0.19.0/sortable.min.js → sortable.min.js} RENAMED
File without changes
lib/options/js/{0.19.0/test-convert.js → test-convert.js} RENAMED
File without changes
lib/options/js/{0.19.0/whitelist.js → whitelist.js} RENAMED
File without changes
lib/options/options/conversion-options/converter-options/cwebp.php CHANGED
@@ -12,10 +12,16 @@
12
  <br>If checked, we will look for binaries in common locations, such as <i>/usr/bin/cwebp</i>
13
  </div>
14
  <div>
15
- <label for="cwebp_try_common_system_paths">Try precompiled cwebp</label>
16
  <input type="checkbox" id="cwebp_try_supplied_binary">
17
  <br>This plugin ships with precompiled cweb binaries for different platforms. If checked, and we have a precompiled binary for your OS, we will try to exectute it
18
  </div>
 
 
 
 
 
 
19
  <div>
20
  <label for="cwebp_method">Method (0-6)</label>
21
  <input type="text" size="2" id="cwebp_method">
12
  <br>If checked, we will look for binaries in common locations, such as <i>/usr/bin/cwebp</i>
13
  </div>
14
  <div>
15
+ <label for="cwebp_try_supplied_binary">Try precompiled cwebp</label>
16
  <input type="checkbox" id="cwebp_try_supplied_binary">
17
  <br>This plugin ships with precompiled cweb binaries for different platforms. If checked, and we have a precompiled binary for your OS, we will try to exectute it
18
  </div>
19
+ <div>
20
+ <label for="cwebp_skip_these_precompiled_binaries">Skip these precompiled cwebp</label>
21
+ <input type="text" size="40" id="cwebp_skip_these_precompiled_binaries" style="width:100%">
22
+ <br>To skip precompiled binaries that are known not to work on current system (check the conversion log).
23
+ This will cut down on conversion time. Separate values with comma.
24
+ </div>
25
  <div>
26
  <label for="cwebp_method">Method (0-6)</label>
27
  <input type="text" size="2" id="cwebp_method">
lib/options/options/redirection-rules/redirection-rules.inc CHANGED
@@ -6,7 +6,7 @@
6
  enables the varied image responses (such that a request for a jpeg/png will result in a webp on browsers that supports webp).
7
  The first option makes this happen for images that are already converted. The second option makes it happen even for
8
  images that has not yet been converted, by redirecting the request to the converter, which converts, saves and delivers.</p>
9
- <p>The third option is only relevant if you are using Alter HTML as well as serving varied image responses.</p>
10
  <?php elseif ($config['operation-mode'] == 'cdn-friendly') : ?>
11
  <h2><i>.htaccess</i> rules for webp generation</h2>
12
  <?php elseif ($config['operation-mode'] == 'no-conversion') : ?>
6
  enables the varied image responses (such that a request for a jpeg/png will result in a webp on browsers that supports webp).
7
  The first option makes this happen for images that are already converted. The second option makes it happen even for
8
  images that has not yet been converted, by redirecting the request to the converter, which converts, saves and delivers.</p>
9
+ <p>The third option is only relevant if you are using Alter HTML and want to reference webps that haven't been converted yet.</p>
10
  <?php elseif ($config['operation-mode'] == 'cdn-friendly') : ?>
11
  <h2><i>.htaccess</i> rules for webp generation</h2>
12
  <?php elseif ($config['operation-mode'] == 'no-conversion') : ?>
lib/options/page-messages.php CHANGED
@@ -15,6 +15,7 @@ use \WebPExpress\PlatformInfo;
15
  use \WebPExpress\State;
16
 
17
 
 
18
  // TODO: Move most of this file into a ProblemDetector class (SystemHealth)
19
 
20
  if (!(State::getState('configured', false))) {
@@ -69,6 +70,21 @@ if ($cacheEnablerActivated && !$webpEnabled) {
69
  );
70
  }
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  if (($config['operation-mode'] == 'cdn-friendly') && !$config['alter-html']['enabled']) {
73
  //echo print_r(get_option('cache-enabler'), true);
74
 
15
  use \WebPExpress\State;
16
 
17
 
18
+
19
  // TODO: Move most of this file into a ProblemDetector class (SystemHealth)
20
 
21
  if (!(State::getState('configured', false))) {
70
  );
71
  }
72
 
73
+ $elementorActivated = in_array('elementor/elementor.php', get_option('active_plugins', []));
74
+ if ($elementorActivated) {
75
+ try {
76
+ // The following is wrapped in a try statement because it depends on Elementor classes which might be subject to change
77
+ if (\Elementor\Plugin::$instance->experiments->is_feature_active( 'e_optimized_css_loading' ) === false) {
78
+ if ($config['redirect-to-existing-in-htaccess'] === false) {
79
+ DismissableMessages::addDismissableMessage('0.23.0/elementor');
80
+ }
81
+ }
82
+ } catch (\Exception $e) {
83
+ // Well, just bad luck.
84
+ }
85
+ }
86
+
87
+
88
  if (($config['operation-mode'] == 'cdn-friendly') && !$config['alter-html']['enabled']) {
89
  //echo print_r(get_option('cache-enabler'), true);
90
 
lib/options/submit.php CHANGED
@@ -229,6 +229,7 @@ function webpexpress_getSanitizedConverters() {
229
  // cwebp
230
  "try-common-system-paths" => 'boolean',
231
  "try-supplied-binary-for-os" => 'boolean',
 
232
  "method" => 'integer', // 0-6,
233
  "size-in-percentage" => 'integer', // 0-100
234
  "low-memory" => 'boolean',
@@ -241,7 +242,7 @@ function webpexpress_getSanitizedConverters() {
241
  "crypt-api-key-in-transfer" => 'boolean',
242
  "new-api-key" => 'string',
243
 
244
- //ewww
245
  "api-key" => 'string',
246
  "api-key-2" => 'string',
247
  ];
229
  // cwebp
230
  "try-common-system-paths" => 'boolean',
231
  "try-supplied-binary-for-os" => 'boolean',
232
+ "skip-these-precompiled-binaries" => 'string',
233
  "method" => 'integer', // 0-6,
234
  "size-in-percentage" => 'integer', // 0-100
235
  "low-memory" => 'boolean',
242
  "crypt-api-key-in-transfer" => 'boolean',
243
  "new-api-key" => 'string',
244
 
245
+ //ewww
246
  "api-key" => 'string',
247
  "api-key-2" => 'string',
248
  ];
lib/wcfm/index.659b742a.css ADDED
@@ -0,0 +1 @@
 
1
+ .splitpanes{display:-webkit-box;display:-ms-flexbox;display:flex;width:100%;height:100%}.splitpanes--vertical{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.splitpanes--horizontal{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.splitpanes--dragging *{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.splitpanes__pane{width:100%;height:100%;overflow:hidden}.splitpanes--vertical .splitpanes__pane{-webkit-transition:width .2s ease-out;transition:width .2s ease-out}.splitpanes--horizontal .splitpanes__pane{-webkit-transition:height .2s ease-out;transition:height .2s ease-out}.splitpanes--dragging .splitpanes__pane{-webkit-transition:none;transition:none}.splitpanes__splitter{-ms-touch-action:none;touch-action:none}.splitpanes--vertical>.splitpanes__splitter{min-width:1px;cursor:col-resize}.splitpanes--horizontal>.splitpanes__splitter{min-height:1px;cursor:row-resize}.splitpanes.default-theme .splitpanes__pane{background-color:#f2f2f2}.splitpanes.default-theme .splitpanes__splitter{background-color:#fff;-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;-ms-flex-negative:0;flex-shrink:0}.splitpanes.default-theme .splitpanes__splitter:after,.splitpanes.default-theme .splitpanes__splitter:before{content:"";position:absolute;top:50%;left:50%;background-color:#00000026;-webkit-transition:background-color .3s;transition:background-color .3s}.splitpanes.default-theme .splitpanes__splitter:hover:after,.splitpanes.default-theme .splitpanes__splitter:hover:before{background-color:#00000040}.splitpanes.default-theme .splitpanes__splitter:first-child{cursor:auto}.default-theme.splitpanes .splitpanes .splitpanes__splitter{z-index:1}.default-theme.splitpanes--vertical>.splitpanes__splitter,.default-theme .splitpanes--vertical>.splitpanes__splitter{width:7px;border-left:1px solid #eee;margin-left:-1px}.default-theme.splitpanes--vertical>.splitpanes__splitter:after,.default-theme .splitpanes--vertical>.splitpanes__splitter:after,.default-theme.splitpanes--vertical>.splitpanes__splitter:before,.default-theme .splitpanes--vertical>.splitpanes__splitter:before{-webkit-transform:translateY(-50%);transform:translateY(-50%);width:1px;height:30px}.default-theme.splitpanes--vertical>.splitpanes__splitter:before,.default-theme .splitpanes--vertical>.splitpanes__splitter:before{margin-left:-2px}.default-theme.splitpanes--vertical>.splitpanes__splitter:after,.default-theme .splitpanes--vertical>.splitpanes__splitter:after{margin-left:1px}.default-theme.splitpanes--horizontal>.splitpanes__splitter,.default-theme .splitpanes--horizontal>.splitpanes__splitter{height:7px;border-top:1px solid #eee;margin-top:-1px}.default-theme.splitpanes--horizontal>.splitpanes__splitter:after,.default-theme .splitpanes--horizontal>.splitpanes__splitter:after,.default-theme.splitpanes--horizontal>.splitpanes__splitter:before,.default-theme .splitpanes--horizontal>.splitpanes__splitter:before{-webkit-transform:translateX(-50%);transform:translate(-50%);width:30px;height:1px}.default-theme.splitpanes--horizontal>.splitpanes__splitter:before,.default-theme .splitpanes--horizontal>.splitpanes__splitter:before{margin-top:-2px}.default-theme.splitpanes--horizontal>.splitpanes__splitter:after,.default-theme .splitpanes--horizontal>.splitpanes__splitter:after{margin-top:1px}.selectbox[data-v-3ed78ba0]{width:200px;position:relative;display:inline-block}.selectbox .box[data-v-3ed78ba0]{border:1px solid black;padding:5px 10px;width:100%;box-sizing:border-box;cursor:pointer;user-select:none}.selectbox .box[data-v-3ed78ba0]:after{position:absolute;content:"";top:14px;right:10px;width:0;height:0;border:6px solid transparent;border-color:black transparent transparent transparent}.selectbox .box.is-open[data-v-3ed78ba0]:after{border-color:transparent transparent black transparent;top:6px}.selectbox .dropdown[data-v-3ed78ba0]{position:absolute;z-index:100;background-color:#fff;border:1px solid #eee;left:0;right:0}.selectbox .dropdown .option[data-v-3ed78ba0]{padding:5px 10px;border-bottom:1px solid #eee}.selectbox .dropdown .option .icon[data-v-3ed78ba0]{width:18px;height:18px;float:right}.selectbox .dropdown .option[data-v-3ed78ba0]:hover{background-color:#eee;cursor:pointer;user-select:none}.help-icon{display:inline-block;margin-left:2px}.convert-option-menu{display:inline-block;margin-left:2px}.menu-inner{font-size:16px}.icon{width:16px;height:16px;vertical-align:top;padding:0 2px 1px}.buttons a:first-child{margin-left:0}.buttons a{margin:0 5px;background-color:#f5f5f5;border-radius:0;color:#000!important;padding:2px 10px;border-color:#fff;text-decoration:none!important;font-family:arial,sans-serif;font-size:13.33px;border-width:1px;border-style:solid;border-bottom-color:#ccc;border-right-color:#ccc}.buttons a:hover{background-color:#fff}.buttons a.mouse-down{border-bottom-color:#fff;border-right-color:#fff;border-top-color:#ccc;border-left-color:#ccc}input[data-v-641ada22]{width:100%}input.small[data-v-641ada22]{max-width:100px}.multiselect__option--selected .click-to-add{display:none}.click-to-add[data-v-6b6f53d2]{float:right;font-size:13px}.vue-toggles{cursor:pointer;display:flex;align-items:center;border-radius:9999px;overflow:hidden;transition:background-color ease .2s,width ease .2s,height ease .2s}.vue-toggles .dot{position:relative;display:flex;align-items:center;border-radius:9999px;box-shadow:0 1px 3px #0000001a,0 1px 2px #0000000f;transition:margin ease .2s}.vue-toggles .text{position:absolute;font-family:inherit;user-select:none;white-space:nowrap}@media all and (-ms-high-contrast: none){.vue-toggles .text{top:50%;transform:translateY(-50%)}}@media (prefers-reduced-motion){.vue-toggles,.vue-toggles *,.vue-toggles *:before,.vue-toggles *:after{animation:none!important;transition:none!important;transition-duration:none!important}}.slider-target,.slider-target *{-webkit-touch-callout:none;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-user-select:none;touch-action:none;-ms-user-select:none;-moz-user-select:none;user-select:none;box-sizing:border-box}.slider-target{position:relative}.slider-base,.slider-connects{width:100%;height:100%;position:relative;z-index:1}.slider-connects{overflow:hidden;z-index:0}.slider-connect,.slider-origin{will-change:transform;position:absolute;z-index:1;top:0;right:0;-ms-transform-origin:0 0;-webkit-transform-origin:0 0;-webkit-transform-style:preserve-3d;transform-origin:0 0;transform-style:flat}.slider-connect{height:100%;width:100%}.slider-origin{height:10%;width:10%}.slider-txt-dir-rtl.slider-horizontal .slider-origin{left:0;right:auto}.slider-vertical .slider-origin{width:0}.slider-horizontal .slider-origin{height:0}.slider-handle{-webkit-backface-visibility:hidden;backface-visibility:hidden;position:absolute}.slider-touch-area{height:100%;width:100%}.slider-state-tap .slider-connect,.slider-state-tap .slider-origin{transition:transform .3s}.slider-state-drag *{cursor:inherit!important}.slider-horizontal{height:6px}.slider-horizontal .slider-handle{width:16px;height:16px;top:-6px;right:-8px}.slider-vertical{width:6px;height:300px}.slider-vertical .slider-handle{width:16px;height:16px;top:-8px;right:-6px}.slider-txt-dir-rtl.slider-horizontal .slider-handle{left:-8px;right:auto}.slider-base{background-color:#d4e0e7}.slider-base,.slider-connects{border-radius:3px}.slider-connect{background:#41b883;cursor:pointer}.slider-draggable{cursor:ew-resize}.slider-vertical .slider-draggable{cursor:ns-resize}.slider-handle{width:16px;height:16px;border-radius:50%;background:#fff;border:0;right:-8px;box-shadow:.5px .5px 2px 1px #00000052;cursor:-webkit-grab;cursor:grab}.slider-handle:focus{outline:none}.slider-active{box-shadow:.5px .5px 2px 1px #0000006b;cursor:-webkit-grabbing;cursor:grabbing}[disabled] .slider-connect{background:#b8b8b8}[disabled].slider-handle,[disabled] .slider-handle,[disabled].slider-target{cursor:not-allowed}[disabled] .slider-tooltip{background:#b8b8b8;border-color:#b8b8b8}.slider-tooltip{position:absolute;display:block;font-size:14px;font-weight:500;white-space:nowrap;padding:2px 5px;min-width:20px;text-align:center;color:#fff;border-radius:5px;border:1px solid #41b883;background:#41b883}.slider-horizontal .slider-tooltip{transform:translate(-50%);left:50%;bottom:24px}.slider-horizontal .slider-tooltip:before{content:"";position:absolute;bottom:-10px;left:50%;width:0;height:0;border:5px solid transparent;border-top-color:inherit;transform:translate(-50%)}.slider-vertical .slider-tooltip{transform:translateY(-50%);top:50%;right:24px}.slider-vertical .slider-tooltip:before{content:"";position:absolute;right:-10px;top:50%;width:0;height:0;border:5px solid transparent;border-left-color:inherit;transform:translateY(-50%)}.slider-horizontal .slider-origin>.slider-tooltip{transform:translate(50%);left:auto;bottom:14px}.slider-vertical .slider-origin>.slider-tooltip{transform:translateY(-18px);top:auto;right:18px}.slider-pips,.slider-pips *{box-sizing:border-box}.slider-pips{position:absolute;color:#999}.slider-value{position:absolute;white-space:nowrap;text-align:center}.slider-value-sub{color:#ccc;font-size:10px}.slider-marker{position:absolute;background:#ccc}.slider-marker-large,.slider-marker-sub{background:#aaa}.slider-pips-horizontal{padding:10px 0;height:80px;top:100%;left:0;width:100%}.slider-value-horizontal{transform:translate(-50%,50%)}.slider-rtl .slider-value-horizontal{transform:translate(50%,50%)}.slider-marker-horizontal.slider-marker{margin-left:-1px;width:2px;height:5px}.slider-marker-horizontal.slider-marker-sub{height:10px}.slider-marker-horizontal.slider-marker-large{height:15px}.slider-pips-vertical{padding:0 10px;height:100%;top:0;left:100%}.slider-value-vertical{transform:translateY(-50%);padding-left:25px}.slider-rtl .slider-value-vertical{transform:translateY(50%)}.slider-marker-vertical.slider-marker{width:5px;height:2px;margin-top:-1px}.slider-marker-vertical.slider-marker-sub{width:10px}.slider-marker-vertical.slider-marker-large{width:15px}.slider[data-v-636c0afb]{padding:10px 0}.slider .slider-connect{background-color:#0075ff}.slider .slider-tooltip{background-color:#0075ff;border-color:#0075ff;display:none}.slider:hover .slider-tooltip{display:block}.slider .slider-active .slider-tooltip{display:block}.convert-option>div[data-v-5def6a67]:first-child{min-width:210px;vertical-align:top;padding-top:10px}.convert-option>div[data-v-5def6a67]:last-child{width:300px;box-sizing:border-box}.convert-option input.method[data-v-5def6a67]{width:40px}.fade-enter-active[data-v-5def6a67]{transition:all 1s;opacity:0;transform:scale(0);transform:translate(30px)}.fade-enter-to[data-v-5def6a67]{opacity:1;transform:translate(0);transform:scale(1)}.fade-leave-active[data-v-5def6a67]{transition:all 1s;opacity:1}.fade-leave-to[data-v-5def6a67]{opacity:0}.view-select[data-v-563ca147]{display:block;text-align:right}.view *[data-v-563ca147]:first-child{display:inline-block;margin-right:10px}.view *[data-v-563ca147]:last-child{width:200px;display:inline-block}.fileitem.selected p[data-v-4fb0cc48]{background:#ccc!important}.fileitem[data-v-4fb0cc48]{vertical-align:middle;white-space:nowrap}.fileitem p[data-v-4fb0cc48]:hover{background:#eee}.fileitem p[data-v-4fb0cc48]{user-select:none;cursor:pointer;margin:0;padding:3px;line-height:25px;border-bottom:1px solid #f2f2f2}.fileitem p .fold-unfold[data-v-4fb0cc48]{user-select:none;cursor:pointer}.fileitem p .fold-unfold.empty[data-v-4fb0cc48]{visibility:hidden}.fileitem p svg.icon-unfold[data-v-4fb0cc48],.fileitem p svg.icon-fold[data-v-4fb0cc48]{width:12px;height:12px;vertical-align:middle;padding:3px;margin-right:3px;display:inline-block;border:0px solid grey}.fileitem p svg.icon-folder[data-v-4fb0cc48],.fileitem p svg.icon-file[data-v-4fb0cc48]{width:20px;height:20px;display:inline;vertical-align:middle;padding-top:1px;padding-bottom:2px;padding-right:5px}.fileitem p svg.icon-file[data-v-4fb0cc48]{margin-left:22px}ul{list-style-type:none;padding:0;margin:0}li{margin:0 0 0 20px}.modal-mask{position:fixed;z-index:9998;top:0;left:0;width:100%;height:100%;background-color:#00000080;display:table}.modal-mask .modal-wrapper{height:100%;width:100%}.modal-mask .modal-wrapper .modal-container{padding:0;background-color:#fff;border-radius:2px;box-shadow:0 2px 8px #00000054;font-family:Helvetica,Arial,sans-serif;position:relative}.modal-mask .modal-wrapper .modal-container .title{position:absolute;left:0px;top:0;right:0;height:20px;background-color:#ccc;padding:5px 0 0 15px;font-size:14px;font-weight:bold}.modal-mask .modal-wrapper .modal-container .close-button{position:absolute;right:2px;top:2px;background-color:#fff;padding:2px 5px;font-size:12px;z-index:999;border-radius:20px;border:1px solid #ccc}.modal-mask .modal-wrapper .modal-container .close-button:hover{cursor:pointer}.modal-mask .modal-wrapper .modal-container .modal-body{position:absolute;top:25px;bottom:0px;left:0;right:0;overflow-y:auto;padding:20px}.modal-mask .modal-wrapper .modal-container .modal-body .close-button-with-text{text-align:right;margin-bottom:5px}.modal-mask .modal-wrapper .modal-container .modal-body .close-button-with-text button{padding:3px 20px}.modal-enter-active,.modal-leave-active{transition:opacity .5s ease}.modal-enter-from,.modal-leave-to{opacity:0}.image-viewport{position:relative}.image-viewport>.zoomer{width:100%;border:solid 1px silver;overflow:hidden}.image-viewport>.zoomer img{vertical-align:top;object-fit:contain;width:100%;height:100%;user-drag:none;-webkit-user-drag:none;-moz-user-drag:none}.image-viewport .zoom-info{display:none;position:absolute;bottom:0px;right:0px;padding:1px 4px;font-size:9px;background-color:#fff}.image-viewport:hover .zoom-info{display:block;cursor:pointer}.variant[data-v-0372e854]{display:inline-block;width:48%;margin-right:2%;margin-bottom:20px}.variant .header .title[data-v-0372e854]{display:inline-block}.variant .header .size[data-v-0372e854]{display:inline-block;float:right}.variant .header .zoom[data-v-0372e854]{display:inline-block;float:right;visibility:hidden}.variant .footer[data-v-0372e854]{font-style:italic;margin-top:2px}.variant .footer .select[data-v-0372e854]{float:right}.variant .footer .select button[data-v-0372e854]{padding:3px 10px}.variant:hover .header .zoom[data-v-0372e854]{visibility:visible}.variants-component .variants .variant.selected[data-v-25a3327e]{background-color:#ccc}.variants-component .variants .variant[data-v-25a3327e]{display:inline-block;width:47%;margin-right:1%;padding:1%;margin-bottom:20px}.variants-component .variants .variant .header .title[data-v-25a3327e]{display:inline-block}.variants-component .variants .variant .header .size[data-v-25a3327e]{display:inline-block;float:right}.variants-component .variants .variant .header .zoom[data-v-25a3327e]{display:inline-block;float:right;visibility:hidden}.variants-component .variants .variant .footer[data-v-25a3327e]{font-style:italic}.variants-component .variants .variant .footer .select[data-v-25a3327e]{float:right}.variants-component .variants .variant .footer .select button[data-v-25a3327e]{padding:3px 10px}.variants-component .variants .variant:hover .header .zoom[data-v-25a3327e]{visibility:visible}.file-properties .error[data-v-1f62a342]{color:red;font-weight:bold}.file-properties .path[data-v-1f62a342]{margin-bottom:20px}.file-properties .path .path[data-v-1f62a342]{color:#666;font-style:italic}.file-properties .log-button[data-v-1f62a342]{margin-left:15px}.file-properties .icon-converting[data-v-1f62a342]{padding:0 5px}.folder-properties .path{margin-bottom:20px}.folder-properties .path .path{color:#666;font-style:italic}.welcome{padding:20px 30px}.welcome h4{margin-bottom:3px}.welcome li{list-style-type:disc}.welcome ul{margin:0 0 20px}.welcome .headline h3{margin-top:0;padding-top:0;font-size:24px}.convertOptionsButton{position:absolute;right:10px;top:8px}.splitpanes__pane{background-color:#fff!important;padding:0;min-height:80px;box-shadow:inset 0 0 3px #0003}.pane-content{height:100%;overflow-y:auto}.pane-content>*{padding:10px 20px}body,html{height:100%;margin:0;padding:0}.mainpanel,#webpconvert-filemanager{height:100%;min-height:300px;position:relative}.mainpanel{min-height:400px}.wcfm,input{font-family:"Avenir",Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:#222;font-size:14px}input{padding:5px 8px;border-color:#333;border-width:1px;box-sizing:border-box}div .multiselect{min-height:30px}div .multiselect__select{height:30px;line-height:16px;width:30px}div .multiselect__select:before{border-top-color:#000;border-width:6px 6px 0 6px}div .multiselect__single{margin-bottom:3px}div .multiselect__tags{border-color:#333;border-radius:0;padding:5px 40px 0 5px;min-height:30px}li.multiselect__element{margin-left:0}div .multiselect__tag{margin-bottom:0;padding-bottom:3px;padding-top:3px}fieldset[disabled] .multiselect{pointer-events:none}.multiselect__spinner{position:absolute;right:1px;top:1px;width:48px;height:35px;background:#fff;display:block}.multiselect__spinner:after,.multiselect__spinner:before{position:absolute;content:"";top:50%;left:50%;margin:-8px 0 0 -8px;width:16px;height:16px;border-radius:100%;border-color:#41b883 transparent transparent;border-style:solid;border-width:2px;box-shadow:0 0 0 1px transparent}.multiselect__spinner:before{-webkit-animation:spinning 2.4s cubic-bezier(.41,.26,.2,.62);animation:spinning 2.4s cubic-bezier(.41,.26,.2,.62);-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.multiselect__spinner:after{-webkit-animation:spinning 2.4s cubic-bezier(.51,.09,.21,.8);animation:spinning 2.4s cubic-bezier(.51,.09,.21,.8);-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.multiselect__loading-enter-active,.multiselect__loading-leave-active{transition:opacity .4s ease-in-out;opacity:1}.multiselect__loading-enter,.multiselect__loading-leave-active{opacity:0}.multiselect,.multiselect__input,.multiselect__single{font-family:inherit;font-size:16px;touch-action:manipulation}.multiselect{box-sizing:content-box;display:block;position:relative;width:100%;min-height:40px;text-align:left;color:#35495e}.multiselect *{box-sizing:border-box}.multiselect:focus{outline:none}.multiselect--disabled{background:#ededed;pointer-events:none;opacity:.6}.multiselect--active{z-index:50}.multiselect--active:not(.multiselect--above) .multiselect__current,.multiselect--active:not(.multiselect--above) .multiselect__input,.multiselect--active:not(.multiselect--above) .multiselect__tags{border-bottom-left-radius:0;border-bottom-right-radius:0}.multiselect--active .multiselect__select{transform:rotate(180deg)}.multiselect--above.multiselect--active .multiselect__current,.multiselect--above.multiselect--active .multiselect__input,.multiselect--above.multiselect--active .multiselect__tags{border-top-left-radius:0;border-top-right-radius:0}.multiselect__input,.multiselect__single{position:relative;display:inline-block;min-height:20px;line-height:20px;border:none;border-radius:5px;background:#fff;padding:0 0 0 5px;width:100%;transition:border .1s ease;box-sizing:border-box;margin-bottom:8px;vertical-align:top}.multiselect__input::-moz-placeholder{color:#35495e}.multiselect__input:-ms-input-placeholder{color:#35495e}.multiselect__input::placeholder{color:#35495e}.multiselect__tag~.multiselect__input,.multiselect__tag~.multiselect__single{width:auto}.multiselect__input:hover,.multiselect__single:hover{border-color:#cfcfcf}.multiselect__input:focus,.multiselect__single:focus{border-color:#a8a8a8;outline:none}.multiselect__single{padding-left:5px;margin-bottom:8px}.multiselect__tags-wrap{display:inline}.multiselect__tags{min-height:40px;display:block;padding:8px 40px 0 8px;border-radius:5px;border:1px solid #e8e8e8;background:#fff;font-size:14px}.multiselect__tag{position:relative;display:inline-block;padding:4px 26px 4px 10px;border-radius:5px;margin-right:10px;color:#fff;line-height:1;background:#41b883;margin-bottom:5px;white-space:nowrap;overflow:hidden;max-width:100%;text-overflow:ellipsis}.multiselect__tag-icon{cursor:pointer;margin-left:7px;position:absolute;right:0;top:0;bottom:0;font-weight:700;font-style:normal;width:22px;text-align:center;line-height:22px;transition:all .2s ease;border-radius:5px}.multiselect__tag-icon:after{content:"\d7";color:#266d4d;font-size:14px}.multiselect__tag-icon:focus:after,.multiselect__tag-icon:hover:after{color:#fff}.multiselect__current{min-height:40px;overflow:hidden;padding:8px 30px 0 12px;white-space:nowrap;border-radius:5px;border:1px solid #e8e8e8}.multiselect__current,.multiselect__select{line-height:16px;box-sizing:border-box;display:block;margin:0;text-decoration:none;cursor:pointer}.multiselect__select{position:absolute;width:40px;height:38px;right:1px;top:1px;padding:4px 8px;text-align:center;transition:transform .2s ease}.multiselect__select:before{position:relative;right:0;top:65%;color:#999;margin-top:4px;border-style:solid;border-width:5px 5px 0 5px;border-color:#999 transparent transparent transparent;content:""}.multiselect__placeholder{color:#adadad;display:inline-block;margin-bottom:10px;padding-top:2px}.multiselect--active .multiselect__placeholder{display:none}.multiselect__content-wrapper{position:absolute;display:block;background:#fff;width:100%;max-height:240px;overflow:auto;border:1px solid #e8e8e8;border-top:none;border-bottom-left-radius:5px;border-bottom-right-radius:5px;z-index:50;-webkit-overflow-scrolling:touch}.multiselect__content{list-style:none;display:inline-block;padding:0;margin:0;min-width:100%;vertical-align:top}.multiselect--above .multiselect__content-wrapper{bottom:100%;border-radius:5px 5px 0 0;border-bottom:none;border-top:1px solid #e8e8e8}.multiselect__content::-webkit-scrollbar{display:none}.multiselect__element{display:block}.multiselect__option{display:block;padding:12px;min-height:40px;line-height:16px;text-decoration:none;text-transform:none;vertical-align:middle;position:relative;cursor:pointer;white-space:nowrap}.multiselect__option:after{top:0;right:0;position:absolute;line-height:40px;padding-right:12px;padding-left:20px;font-size:13px}.multiselect__option--highlight{background:#41b883;outline:none;color:#fff}.multiselect__option--highlight:after{content:attr(data-select);background:#41b883;color:#fff}.multiselect__option--selected{background:#f3f3f3;color:#35495e;font-weight:700}.multiselect__option--selected:after{content:attr(data-selected);color:silver}.multiselect__option--selected.multiselect__option--highlight{background:#ff6a6a;color:#fff}.multiselect__option--selected.multiselect__option--highlight:after{background:#ff6a6a;content:attr(data-deselect);color:#fff}.multiselect--disabled .multiselect__current,.multiselect--disabled .multiselect__select{background:#ededed;color:#a6a6a6}.multiselect__option--disabled{background:#ededed!important;color:#a6a6a6!important;cursor:text;pointer-events:none}.multiselect__option--group{background:#ededed;color:#35495e}.multiselect__option--group.multiselect__option--highlight{background:#35495e;color:#fff}.multiselect__option--group.multiselect__option--highlight:after{background:#35495e}.multiselect__option--disabled.multiselect__option--highlight{background:#dedede}.multiselect__option--group-selected.multiselect__option--highlight{background:#ff6a6a;color:#fff}.multiselect__option--group-selected.multiselect__option--highlight:after{background:#ff6a6a;content:attr(data-deselect);color:#fff}.multiselect-enter-active,.multiselect-leave-active{transition:all .15s ease}.multiselect-enter,.multiselect-leave-active{opacity:0}.multiselect__strong{margin-bottom:8px;line-height:20px;display:inline-block;vertical-align:top}[dir=rtl] .multiselect{text-align:right}[dir=rtl] .multiselect__select{right:auto;left:1px}[dir=rtl] .multiselect__tags{padding:8px 8px 0 40px}[dir=rtl] .multiselect__content{text-align:right}[dir=rtl] .multiselect__option:after{right:auto;left:0}[dir=rtl] .multiselect__clear{right:auto;left:12px}[dir=rtl] .multiselect__spinner{right:auto;left:1px}@-webkit-keyframes spinning{0%{transform:rotate(0)}to{transform:rotate(2turn)}}@keyframes spinning{0%{transform:rotate(0)}to{transform:rotate(2turn)}}div.v-popper--theme-menu .v-popper__inner{background-color:#66f;color:#fff;padding:10px 15px 11px;line-height:1.2;max-width:300px}.v-popper__inner a{color:#fff;text-decoration:underline}.v-popper__inner p{margin-top:0}.v-popper__inner p:last-child{margin-bottom:0}.table-table{display:table}.table-table>*{display:table-row}.table-table>*>*{display:table-cell;padding:5px 20px 5px 0}.table-inline-block>div>*{display:inline-block;margin-right:10px;padding:5px 20px 5px 0}.table-inline-block>div>*:first-child{width:120px}.resize-observer[data-v-b329ee4c]{position:absolute;top:0;left:0;z-index:-1;width:100%;height:100%;border:none;background-color:transparent;pointer-events:none;display:block;overflow:hidden;opacity:0}.resize-observer[data-v-b329ee4c] object{display:block;position:absolute;top:0;left:0;height:100%;width:100%;overflow:hidden;pointer-events:none;z-index:-1}.v-popper--theme-dropdown .v-popper__inner{background:#fff;color:#000;padding:24px;border-radius:6px;box-shadow:0 6px 30px #0000001a}.v-popper--theme-dropdown .v-popper__arrow{border-color:#fff}.v-popper{width:max-content}.v-popper--theme-tooltip .v-popper__inner{background:rgba(0,0,0,.8);color:#fff;border-radius:6px;padding:7px 12px 6px}.v-popper--theme-tooltip .v-popper__arrow{border-color:#000c}.v-popper__popper{z-index:10000}.v-popper__popper.v-popper__popper--hidden{visibility:hidden;opacity:0;transition:opacity .15s,visibility .15s}.v-popper__popper.v-popper__popper--shown{visibility:visible;opacity:1;transition:opacity .15s}.v-popper__popper.v-popper__popper--skip-transition,.v-popper__popper.v-popper__popper--skip-transition>.v-popper__wrapper{transition:none!important}.v-popper__inner{position:relative}.v-popper__arrow-container{width:10px;height:10px}.v-popper__arrow{border-style:solid;position:relative;width:0;height:0}.v-popper__popper[data-popper-placement^=top] .v-popper__arrow{border-width:5px 5px 0 5px;border-left-color:transparent!important;border-right-color:transparent!important;border-bottom-color:transparent!important}.v-popper__popper[data-popper-placement^=bottom] .v-popper__arrow-container{top:0}.v-popper__popper[data-popper-placement^=bottom] .v-popper__arrow{border-width:0 5px 5px 5px;border-left-color:transparent!important;border-right-color:transparent!important;border-top-color:transparent!important;top:-5px}.v-popper__popper[data-popper-placement^=right] .v-popper__arrow{border-width:5px 5px 5px 0;border-left-color:transparent!important;border-top-color:transparent!important;border-bottom-color:transparent!important;left:-5px}.v-popper__popper[data-popper-placement^=left] .v-popper__arrow-container{right:-5px}.v-popper__popper[data-popper-placement^=left] .v-popper__arrow{border-width:5px 0 5px 5px;border-top-color:transparent!important;border-right-color:transparent!important;border-bottom-color:transparent!important;right:-5px}
lib/wcfm/index.ab43bb2c.css DELETED
@@ -1 +0,0 @@
1
- .splitpanes{display:-webkit-box;display:-ms-flexbox;display:flex;width:100%;height:100%}.splitpanes--vertical{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.splitpanes--horizontal{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.splitpanes--dragging *{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.splitpanes__pane{width:100%;height:100%;overflow:hidden}.splitpanes--vertical .splitpanes__pane{-webkit-transition:width .2s ease-out;transition:width .2s ease-out}.splitpanes--horizontal .splitpanes__pane{-webkit-transition:height .2s ease-out;transition:height .2s ease-out}.splitpanes--dragging .splitpanes__pane{-webkit-transition:none;transition:none}.splitpanes__splitter{-ms-touch-action:none;touch-action:none}.splitpanes--vertical>.splitpanes__splitter{min-width:1px;cursor:col-resize}.splitpanes--horizontal>.splitpanes__splitter{min-height:1px;cursor:row-resize}.splitpanes.default-theme .splitpanes__pane{background-color:#f2f2f2}.splitpanes.default-theme .splitpanes__splitter{background-color:#fff;-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;-ms-flex-negative:0;flex-shrink:0}.splitpanes.default-theme .splitpanes__splitter:after,.splitpanes.default-theme .splitpanes__splitter:before{content:"";position:absolute;top:50%;left:50%;background-color:#00000026;-webkit-transition:background-color .3s;transition:background-color .3s}.splitpanes.default-theme .splitpanes__splitter:hover:after,.splitpanes.default-theme .splitpanes__splitter:hover:before{background-color:#00000040}.splitpanes.default-theme .splitpanes__splitter:first-child{cursor:auto}.default-theme.splitpanes .splitpanes .splitpanes__splitter{z-index:1}.default-theme.splitpanes--vertical>.splitpanes__splitter,.default-theme .splitpanes--vertical>.splitpanes__splitter{width:7px;border-left:1px solid #eee;margin-left:-1px}.default-theme.splitpanes--vertical>.splitpanes__splitter:after,.default-theme .splitpanes--vertical>.splitpanes__splitter:after,.default-theme.splitpanes--vertical>.splitpanes__splitter:before,.default-theme .splitpanes--vertical>.splitpanes__splitter:before{-webkit-transform:translateY(-50%);transform:translateY(-50%);width:1px;height:30px}.default-theme.splitpanes--vertical>.splitpanes__splitter:before,.default-theme .splitpanes--vertical>.splitpanes__splitter:before{margin-left:-2px}.default-theme.splitpanes--vertical>.splitpanes__splitter:after,.default-theme .splitpanes--vertical>.splitpanes__splitter:after{margin-left:1px}.default-theme.splitpanes--horizontal>.splitpanes__splitter,.default-theme .splitpanes--horizontal>.splitpanes__splitter{height:7px;border-top:1px solid #eee;margin-top:-1px}.default-theme.splitpanes--horizontal>.splitpanes__splitter:after,.default-theme .splitpanes--horizontal>.splitpanes__splitter:after,.default-theme.splitpanes--horizontal>.splitpanes__splitter:before,.default-theme .splitpanes--horizontal>.splitpanes__splitter:before{-webkit-transform:translateX(-50%);transform:translate(-50%);width:30px;height:1px}.default-theme.splitpanes--horizontal>.splitpanes__splitter:before,.default-theme .splitpanes--horizontal>.splitpanes__splitter:before{margin-top:-2px}.default-theme.splitpanes--horizontal>.splitpanes__splitter:after,.default-theme .splitpanes--horizontal>.splitpanes__splitter:after{margin-top:1px}.selectbox[data-v-3ed78ba0]{width:200px;position:relative;display:inline-block}.selectbox .box[data-v-3ed78ba0]{border:1px solid black;padding:5px 10px;width:100%;box-sizing:border-box;cursor:pointer;user-select:none}.selectbox .box[data-v-3ed78ba0]:after{position:absolute;content:"";top:14px;right:10px;width:0;height:0;border:6px solid transparent;border-color:black transparent transparent transparent}.selectbox .box.is-open[data-v-3ed78ba0]:after{border-color:transparent transparent black transparent;top:6px}.selectbox .dropdown[data-v-3ed78ba0]{position:absolute;z-index:100;background-color:#fff;border:1px solid #eee;left:0;right:0}.selectbox .dropdown .option[data-v-3ed78ba0]{padding:5px 10px;border-bottom:1px solid #eee}.selectbox .dropdown .option .icon[data-v-3ed78ba0]{width:18px;height:18px;float:right}.selectbox .dropdown .option[data-v-3ed78ba0]:hover{background-color:#eee;cursor:pointer;user-select:none}.help-icon{display:inline-block;margin-left:2px}.convert-option-menu{display:inline-block;margin-left:2px}.menu-inner{font-size:16px}.icon{width:16px;height:16px;vertical-align:top;padding:0 2px 1px}.buttons a:first-child{margin-left:0}.buttons a{margin:0 5px;background-color:#f5f5f5;border-radius:0;color:#000!important;padding:2px 10px;border-color:#fff;text-decoration:none!important;font-family:arial,sans-serif;font-size:13.33px;border-width:1px;border-style:solid;border-bottom-color:#ccc;border-right-color:#ccc}.buttons a:hover{background-color:#fff}.buttons a.mouse-down{border-bottom-color:#fff;border-right-color:#fff;border-top-color:#ccc;border-left-color:#ccc}input[data-v-641ada22]{width:100%}input.small[data-v-641ada22]{max-width:100px}.multiselect__option--selected .click-to-add{display:none}.click-to-add[data-v-6b6f53d2]{float:right;font-size:13px}.vue-toggles{cursor:pointer;display:flex;align-items:center;border-radius:9999px;overflow:hidden;transition:background-color ease .2s,width ease .2s,height ease .2s}.vue-toggles .dot{position:relative;display:flex;align-items:center;border-radius:9999px;box-shadow:0 1px 3px #0000001a,0 1px 2px #0000000f;transition:margin ease .2s}.vue-toggles .text{position:absolute;font-family:inherit;user-select:none;white-space:nowrap}@media all and (-ms-high-contrast: none){.vue-toggles .text{top:50%;transform:translateY(-50%)}}@media (prefers-reduced-motion){.vue-toggles,.vue-toggles *,.vue-toggles *:before,.vue-toggles *:after{animation:none!important;transition:none!important;transition-duration:none!important}}.slider-target,.slider-target *{-webkit-touch-callout:none;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-user-select:none;touch-action:none;-ms-user-select:none;-moz-user-select:none;user-select:none;box-sizing:border-box}.slider-target{position:relative}.slider-base,.slider-connects{width:100%;height:100%;position:relative;z-index:1}.slider-connects{overflow:hidden;z-index:0}.slider-connect,.slider-origin{will-change:transform;position:absolute;z-index:1;top:0;right:0;-ms-transform-origin:0 0;-webkit-transform-origin:0 0;-webkit-transform-style:preserve-3d;transform-origin:0 0;transform-style:flat}.slider-connect{height:100%;width:100%}.slider-origin{height:10%;width:10%}.slider-txt-dir-rtl.slider-horizontal .slider-origin{left:0;right:auto}.slider-vertical .slider-origin{width:0}.slider-horizontal .slider-origin{height:0}.slider-handle{-webkit-backface-visibility:hidden;backface-visibility:hidden;position:absolute}.slider-touch-area{height:100%;width:100%}.slider-state-tap .slider-connect,.slider-state-tap .slider-origin{transition:transform .3s}.slider-state-drag *{cursor:inherit!important}.slider-horizontal{height:6px}.slider-horizontal .slider-handle{width:16px;height:16px;top:-6px;right:-8px}.slider-vertical{width:6px;height:300px}.slider-vertical .slider-handle{width:16px;height:16px;top:-8px;right:-6px}.slider-txt-dir-rtl.slider-horizontal .slider-handle{left:-8px;right:auto}.slider-base{background-color:#d4e0e7}.slider-base,.slider-connects{border-radius:3px}.slider-connect{background:#41b883;cursor:pointer}.slider-draggable{cursor:ew-resize}.slider-vertical .slider-draggable{cursor:ns-resize}.slider-handle{width:16px;height:16px;border-radius:50%;background:#fff;border:0;right:-8px;box-shadow:.5px .5px 2px 1px #00000052;cursor:-webkit-grab;cursor:grab}.slider-handle:focus{outline:none}.slider-active{box-shadow:.5px .5px 2px 1px #0000006b;cursor:-webkit-grabbing;cursor:grabbing}[disabled] .slider-connect{background:#b8b8b8}[disabled].slider-handle,[disabled] .slider-handle,[disabled].slider-target{cursor:not-allowed}[disabled] .slider-tooltip{background:#b8b8b8;border-color:#b8b8b8}.slider-tooltip{position:absolute;display:block;font-size:14px;font-weight:500;white-space:nowrap;padding:2px 5px;min-width:20px;text-align:center;color:#fff;border-radius:5px;border:1px solid #41b883;background:#41b883}.slider-horizontal .slider-tooltip{transform:translate(-50%);left:50%;bottom:24px}.slider-horizontal .slider-tooltip:before{content:"";position:absolute;bottom:-10px;left:50%;width:0;height:0;border:5px solid transparent;border-top-color:inherit;transform:translate(-50%)}.slider-vertical .slider-tooltip{transform:translateY(-50%);top:50%;right:24px}.slider-vertical .slider-tooltip:before{content:"";position:absolute;right:-10px;top:50%;width:0;height:0;border:5px solid transparent;border-left-color:inherit;transform:translateY(-50%)}.slider-horizontal .slider-origin>.slider-tooltip{transform:translate(50%);left:auto;bottom:14px}.slider-vertical .slider-origin>.slider-tooltip{transform:translateY(-18px);top:auto;right:18px}.slider-pips,.slider-pips *{box-sizing:border-box}.slider-pips{position:absolute;color:#999}.slider-value{position:absolute;white-space:nowrap;text-align:center}.slider-value-sub{color:#ccc;font-size:10px}.slider-marker{position:absolute;background:#ccc}.slider-marker-large,.slider-marker-sub{background:#aaa}.slider-pips-horizontal{padding:10px 0;height:80px;top:100%;left:0;width:100%}.slider-value-horizontal{transform:translate(-50%,50%)}.slider-rtl .slider-value-horizontal{transform:translate(50%,50%)}.slider-marker-horizontal.slider-marker{margin-left:-1px;width:2px;height:5px}.slider-marker-horizontal.slider-marker-sub{height:10px}.slider-marker-horizontal.slider-marker-large{height:15px}.slider-pips-vertical{padding:0 10px;height:100%;top:0;left:100%}.slider-value-vertical{transform:translateY(-50%);padding-left:25px}.slider-rtl .slider-value-vertical{transform:translateY(50%)}.slider-marker-vertical.slider-marker{width:5px;height:2px;margin-top:-1px}.slider-marker-vertical.slider-marker-sub{width:10px}.slider-marker-vertical.slider-marker-large{width:15px}.slider[data-v-636c0afb]{padding:10px 0}.slider .slider-connect{background-color:#0075ff}.slider .slider-tooltip{background-color:#0075ff;border-color:#0075ff;display:none}.slider:hover .slider-tooltip{display:block}.slider .slider-active .slider-tooltip{display:block}.convert-option>div[data-v-5def6a67]:first-child{min-width:210px;vertical-align:top;padding-top:10px}.convert-option>div[data-v-5def6a67]:last-child{width:300px;box-sizing:border-box}.convert-option input.method[data-v-5def6a67]{width:40px}.fade-enter-active[data-v-5def6a67]{transition:all 1s;opacity:0;transform:scale(0);transform:translate(30px)}.fade-enter-to[data-v-5def6a67]{opacity:1;transform:translate(0);transform:scale(1)}.fade-leave-active[data-v-5def6a67]{transition:all 1s;opacity:1}.fade-leave-to[data-v-5def6a67]{opacity:0}.view-select[data-v-563ca147]{display:block;text-align:right}.view *[data-v-563ca147]:first-child{display:inline-block;margin-right:10px}.view *[data-v-563ca147]:last-child{width:200px;display:inline-block}.fileitem.selected p[data-v-4fb0cc48]{background:#ccc!important}.fileitem[data-v-4fb0cc48]{vertical-align:middle;white-space:nowrap}.fileitem p[data-v-4fb0cc48]:hover{background:#eee}.fileitem p[data-v-4fb0cc48]{user-select:none;cursor:pointer;margin:0;padding:3px;line-height:25px;border-bottom:1px solid #f2f2f2}.fileitem p .fold-unfold[data-v-4fb0cc48]{user-select:none;cursor:pointer}.fileitem p .fold-unfold.empty[data-v-4fb0cc48]{visibility:hidden}.fileitem p svg.icon-unfold[data-v-4fb0cc48],.fileitem p svg.icon-fold[data-v-4fb0cc48]{width:12px;height:12px;vertical-align:middle;padding:3px;margin-right:3px;display:inline-block;border:0px solid grey}.fileitem p svg.icon-folder[data-v-4fb0cc48],.fileitem p svg.icon-file[data-v-4fb0cc48]{width:20px;height:20px;display:inline;vertical-align:middle;padding-top:1px;padding-bottom:2px;padding-right:5px}.fileitem p svg.icon-file[data-v-4fb0cc48]{margin-left:22px}ul{list-style-type:none;padding:0;margin:0}li{margin:0 0 0 20px}.modal-mask{position:fixed;z-index:9998;top:0;left:0;width:100%;height:100%;background-color:#00000080;display:table}.modal-mask .modal-wrapper{height:100%;width:100%;padding-top:30px}.modal-mask .modal-wrapper .modal-container{padding:0;background-color:#fff;border-radius:2px;box-shadow:0 2px 8px #00000054;font-family:Helvetica,Arial,sans-serif;position:relative}.modal-mask .modal-wrapper .modal-container .title{position:absolute;left:0px;top:0;right:0;height:20px;background-color:#ccc;padding:5px 0 0 15px;font-size:14px;font-weight:bold}.modal-mask .modal-wrapper .modal-container .close-button{position:absolute;right:2px;top:2px;background-color:#fff;padding:2px 5px;font-size:12px;z-index:999;border-radius:20px;border:1px solid #ccc}.modal-mask .modal-wrapper .modal-container .close-button:hover{cursor:pointer}.modal-mask .modal-wrapper .modal-container .modal-body{position:absolute;top:25px;bottom:0px;left:0;right:0;overflow-y:auto;padding:20px}.modal-mask .modal-wrapper .modal-container .modal-body .close-button-with-text{text-align:right;margin-bottom:5px}.modal-mask .modal-wrapper .modal-container .modal-body .close-button-with-text button{padding:3px 20px}.modal-enter-active,.modal-leave-active{transition:opacity .5s ease}.modal-enter-from,.modal-leave-to{opacity:0}.image-viewport{position:relative}.image-viewport>.zoomer{width:100%;border:solid 1px silver;overflow:hidden}.image-viewport>.zoomer img{vertical-align:top;object-fit:contain;width:100%;height:100%;user-drag:none;-webkit-user-drag:none;-moz-user-drag:none}.image-viewport .zoom-info{display:none;position:absolute;bottom:0px;right:0px;padding:1px 4px;font-size:9px;background-color:#fff}.image-viewport:hover .zoom-info{display:block;cursor:pointer}.variant[data-v-0372e854]{display:inline-block;width:48%;margin-right:2%;margin-bottom:20px}.variant .header .title[data-v-0372e854]{display:inline-block}.variant .header .size[data-v-0372e854]{display:inline-block;float:right}.variant .header .zoom[data-v-0372e854]{display:inline-block;float:right;visibility:hidden}.variant .footer[data-v-0372e854]{font-style:italic;margin-top:2px}.variant .footer .select[data-v-0372e854]{float:right}.variant .footer .select button[data-v-0372e854]{padding:3px 10px}.variant:hover .header .zoom[data-v-0372e854]{visibility:visible}.variants-component .variants .variant.selected[data-v-25a3327e]{background-color:#ccc}.variants-component .variants .variant[data-v-25a3327e]{display:inline-block;width:47%;margin-right:1%;padding:1%;margin-bottom:20px}.variants-component .variants .variant .header .title[data-v-25a3327e]{display:inline-block}.variants-component .variants .variant .header .size[data-v-25a3327e]{display:inline-block;float:right}.variants-component .variants .variant .header .zoom[data-v-25a3327e]{display:inline-block;float:right;visibility:hidden}.variants-component .variants .variant .footer[data-v-25a3327e]{font-style:italic}.variants-component .variants .variant .footer .select[data-v-25a3327e]{float:right}.variants-component .variants .variant .footer .select button[data-v-25a3327e]{padding:3px 10px}.variants-component .variants .variant:hover .header .zoom[data-v-25a3327e]{visibility:visible}.file-properties .error[data-v-32d950b3]{color:red;font-weight:bold}.file-properties .path[data-v-32d950b3]{margin-bottom:20px}.file-properties .path .path[data-v-32d950b3]{color:#666;font-style:italic}.folder-properties .path{margin-bottom:20px}.folder-properties .path .path{color:#666;font-style:italic}.welcome{padding:20px 30px}.welcome h4{margin-bottom:3px}.welcome li{list-style-type:disc}.welcome ul{margin:0 0 20px}.welcome .headline h3{margin-top:0;padding-top:0;font-size:24px}.convertOptionsButton{position:absolute;right:10px;top:8px}.splitpanes__pane{background-color:#fff!important;padding:0;min-height:80px;box-shadow:inset 0 0 3px #0003}.pane-content{height:100%;overflow-y:auto}.pane-content>*{padding:10px 20px}body,html{height:100%;margin:0;padding:0}.mainpanel,#webpconvert-filemanager{height:100%;min-height:300px;position:relative}.mainpanel{min-height:400px}.wcfm,input{font-family:"Avenir",Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:#222;font-size:14px}input{padding:5px 8px;border-color:#333;border-width:1px;box-sizing:border-box}div .multiselect{min-height:30px}div .multiselect__select{height:30px;line-height:16px;width:30px}div .multiselect__select:before{border-top-color:#000;border-width:6px 6px 0 6px}div .multiselect__single{margin-bottom:3px}div .multiselect__tags{border-color:#333;border-radius:0;padding:5px 40px 0 5px;min-height:30px}li.multiselect__element{margin-left:0}div .multiselect__tag{margin-bottom:0;padding-bottom:3px;padding-top:3px}fieldset[disabled] .multiselect{pointer-events:none}.multiselect__spinner{position:absolute;right:1px;top:1px;width:48px;height:35px;background:#fff;display:block}.multiselect__spinner:after,.multiselect__spinner:before{position:absolute;content:"";top:50%;left:50%;margin:-8px 0 0 -8px;width:16px;height:16px;border-radius:100%;border-color:#41b883 transparent transparent;border-style:solid;border-width:2px;box-shadow:0 0 0 1px transparent}.multiselect__spinner:before{-webkit-animation:spinning 2.4s cubic-bezier(.41,.26,.2,.62);animation:spinning 2.4s cubic-bezier(.41,.26,.2,.62);-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.multiselect__spinner:after{-webkit-animation:spinning 2.4s cubic-bezier(.51,.09,.21,.8);animation:spinning 2.4s cubic-bezier(.51,.09,.21,.8);-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.multiselect__loading-enter-active,.multiselect__loading-leave-active{transition:opacity .4s ease-in-out;opacity:1}.multiselect__loading-enter,.multiselect__loading-leave-active{opacity:0}.multiselect,.multiselect__input,.multiselect__single{font-family:inherit;font-size:16px;touch-action:manipulation}.multiselect{box-sizing:content-box;display:block;position:relative;width:100%;min-height:40px;text-align:left;color:#35495e}.multiselect *{box-sizing:border-box}.multiselect:focus{outline:none}.multiselect--disabled{background:#ededed;pointer-events:none;opacity:.6}.multiselect--active{z-index:50}.multiselect--active:not(.multiselect--above) .multiselect__current,.multiselect--active:not(.multiselect--above) .multiselect__input,.multiselect--active:not(.multiselect--above) .multiselect__tags{border-bottom-left-radius:0;border-bottom-right-radius:0}.multiselect--active .multiselect__select{transform:rotate(180deg)}.multiselect--above.multiselect--active .multiselect__current,.multiselect--above.multiselect--active .multiselect__input,.multiselect--above.multiselect--active .multiselect__tags{border-top-left-radius:0;border-top-right-radius:0}.multiselect__input,.multiselect__single{position:relative;display:inline-block;min-height:20px;line-height:20px;border:none;border-radius:5px;background:#fff;padding:0 0 0 5px;width:100%;transition:border .1s ease;box-sizing:border-box;margin-bottom:8px;vertical-align:top}.multiselect__input::-moz-placeholder{color:#35495e}.multiselect__input:-ms-input-placeholder{color:#35495e}.multiselect__input::placeholder{color:#35495e}.multiselect__tag~.multiselect__input,.multiselect__tag~.multiselect__single{width:auto}.multiselect__input:hover,.multiselect__single:hover{border-color:#cfcfcf}.multiselect__input:focus,.multiselect__single:focus{border-color:#a8a8a8;outline:none}.multiselect__single{padding-left:5px;margin-bottom:8px}.multiselect__tags-wrap{display:inline}.multiselect__tags{min-height:40px;display:block;padding:8px 40px 0 8px;border-radius:5px;border:1px solid #e8e8e8;background:#fff;font-size:14px}.multiselect__tag{position:relative;display:inline-block;padding:4px 26px 4px 10px;border-radius:5px;margin-right:10px;color:#fff;line-height:1;background:#41b883;margin-bottom:5px;white-space:nowrap;overflow:hidden;max-width:100%;text-overflow:ellipsis}.multiselect__tag-icon{cursor:pointer;margin-left:7px;position:absolute;right:0;top:0;bottom:0;font-weight:700;font-style:normal;width:22px;text-align:center;line-height:22px;transition:all .2s ease;border-radius:5px}.multiselect__tag-icon:after{content:"\d7";color:#266d4d;font-size:14px}.multiselect__tag-icon:focus:after,.multiselect__tag-icon:hover:after{color:#fff}.multiselect__current{min-height:40px;overflow:hidden;padding:8px 30px 0 12px;white-space:nowrap;border-radius:5px;border:1px solid #e8e8e8}.multiselect__current,.multiselect__select{line-height:16px;box-sizing:border-box;display:block;margin:0;text-decoration:none;cursor:pointer}.multiselect__select{position:absolute;width:40px;height:38px;right:1px;top:1px;padding:4px 8px;text-align:center;transition:transform .2s ease}.multiselect__select:before{position:relative;right:0;top:65%;color:#999;margin-top:4px;border-style:solid;border-width:5px 5px 0 5px;border-color:#999 transparent transparent transparent;content:""}.multiselect__placeholder{color:#adadad;display:inline-block;margin-bottom:10px;padding-top:2px}.multiselect--active .multiselect__placeholder{display:none}.multiselect__content-wrapper{position:absolute;display:block;background:#fff;width:100%;max-height:240px;overflow:auto;border:1px solid #e8e8e8;border-top:none;border-bottom-left-radius:5px;border-bottom-right-radius:5px;z-index:50;-webkit-overflow-scrolling:touch}.multiselect__content{list-style:none;display:inline-block;padding:0;margin:0;min-width:100%;vertical-align:top}.multiselect--above .multiselect__content-wrapper{bottom:100%;border-radius:5px 5px 0 0;border-bottom:none;border-top:1px solid #e8e8e8}.multiselect__content::-webkit-scrollbar{display:none}.multiselect__element{display:block}.multiselect__option{display:block;padding:12px;min-height:40px;line-height:16px;text-decoration:none;text-transform:none;vertical-align:middle;position:relative;cursor:pointer;white-space:nowrap}.multiselect__option:after{top:0;right:0;position:absolute;line-height:40px;padding-right:12px;padding-left:20px;font-size:13px}.multiselect__option--highlight{background:#41b883;outline:none;color:#fff}.multiselect__option--highlight:after{content:attr(data-select);background:#41b883;color:#fff}.multiselect__option--selected{background:#f3f3f3;color:#35495e;font-weight:700}.multiselect__option--selected:after{content:attr(data-selected);color:silver}.multiselect__option--selected.multiselect__option--highlight{background:#ff6a6a;color:#fff}.multiselect__option--selected.multiselect__option--highlight:after{background:#ff6a6a;content:attr(data-deselect);color:#fff}.multiselect--disabled .multiselect__current,.multiselect--disabled .multiselect__select{background:#ededed;color:#a6a6a6}.multiselect__option--disabled{background:#ededed!important;color:#a6a6a6!important;cursor:text;pointer-events:none}.multiselect__option--group{background:#ededed;color:#35495e}.multiselect__option--group.multiselect__option--highlight{background:#35495e;color:#fff}.multiselect__option--group.multiselect__option--highlight:after{background:#35495e}.multiselect__option--disabled.multiselect__option--highlight{background:#dedede}.multiselect__option--group-selected.multiselect__option--highlight{background:#ff6a6a;color:#fff}.multiselect__option--group-selected.multiselect__option--highlight:after{background:#ff6a6a;content:attr(data-deselect);color:#fff}.multiselect-enter-active,.multiselect-leave-active{transition:all .15s ease}.multiselect-enter,.multiselect-leave-active{opacity:0}.multiselect__strong{margin-bottom:8px;line-height:20px;display:inline-block;vertical-align:top}[dir=rtl] .multiselect{text-align:right}[dir=rtl] .multiselect__select{right:auto;left:1px}[dir=rtl] .multiselect__tags{padding:8px 8px 0 40px}[dir=rtl] .multiselect__content{text-align:right}[dir=rtl] .multiselect__option:after{right:auto;left:0}[dir=rtl] .multiselect__clear{right:auto;left:12px}[dir=rtl] .multiselect__spinner{right:auto;left:1px}@-webkit-keyframes spinning{0%{transform:rotate(0)}to{transform:rotate(2turn)}}@keyframes spinning{0%{transform:rotate(0)}to{transform:rotate(2turn)}}div.v-popper--theme-menu .v-popper__inner{background-color:#66f;color:#fff;padding:10px 15px 11px;line-height:1.2;max-width:300px}.v-popper__inner a{color:#fff;text-decoration:underline}.v-popper__inner p{margin-top:0}.v-popper__inner p:last-child{margin-bottom:0}.table-table{display:table}.table-table>*{display:table-row}.table-table>*>*{display:table-cell;padding:5px 20px 5px 0}.table-inline-block>div>*{display:inline-block;margin-right:10px;padding:5px 20px 5px 0}.table-inline-block>div>*:first-child{width:120px}.resize-observer[data-v-b329ee4c]{position:absolute;top:0;left:0;z-index:-1;width:100%;height:100%;border:none;background-color:transparent;pointer-events:none;display:block;overflow:hidden;opacity:0}.resize-observer[data-v-b329ee4c] object{display:block;position:absolute;top:0;left:0;height:100%;width:100%;overflow:hidden;pointer-events:none;z-index:-1}.v-popper--theme-dropdown .v-popper__inner{background:#fff;color:#000;padding:24px;border-radius:6px;box-shadow:0 6px 30px #0000001a}.v-popper--theme-dropdown .v-popper__arrow{border-color:#fff}.v-popper{width:max-content}.v-popper--theme-tooltip .v-popper__inner{background:rgba(0,0,0,.8);color:#fff;border-radius:6px;padding:7px 12px 6px}.v-popper--theme-tooltip .v-popper__arrow{border-color:#000c}.v-popper__popper{z-index:10000}.v-popper__popper.v-popper__popper--hidden{visibility:hidden;opacity:0;transition:opacity .15s,visibility .15s}.v-popper__popper.v-popper__popper--shown{visibility:visible;opacity:1;transition:opacity .15s}.v-popper__popper.v-popper__popper--skip-transition,.v-popper__popper.v-popper__popper--skip-transition>.v-popper__wrapper{transition:none!important}.v-popper__inner{position:relative}.v-popper__arrow-container{width:10px;height:10px}.v-popper__arrow{border-style:solid;position:relative;width:0;height:0}.v-popper__popper[data-popper-placement^=top] .v-popper__arrow{border-width:5px 5px 0 5px;border-left-color:transparent!important;border-right-color:transparent!important;border-bottom-color:transparent!important}.v-popper__popper[data-popper-placement^=bottom] .v-popper__arrow-container{top:0}.v-popper__popper[data-popper-placement^=bottom] .v-popper__arrow{border-width:0 5px 5px 5px;border-left-color:transparent!important;border-right-color:transparent!important;border-top-color:transparent!important;top:-5px}.v-popper__popper[data-popper-placement^=right] .v-popper__arrow{border-width:5px 5px 5px 0;border-left-color:transparent!important;border-top-color:transparent!important;border-bottom-color:transparent!important;left:-5px}.v-popper__popper[data-popper-placement^=left] .v-popper__arrow-container{right:-5px}.v-popper__popper[data-popper-placement^=left] .v-popper__arrow{border-width:5px 0 5px 5px;border-top-color:transparent!important;border-right-color:transparent!important;border-bottom-color:transparent!important;right:-5px}
 
lib/wcfm/index.ee44cdbf.js ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import{_ as f,o as l,c,a as R,b as a,n as S,d as u,e as y,t as p,p as V,f as I,r as m,g as _,F as x,h as Y,i as z,j as D,k as H,m as j,V as O,w as b,l as $,v as k,s as X,q as B,u as U}from"./vendor.b4e4e155.js";const A=function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))n(o);new MutationObserver(o=>{for(const i of o)if(i.type==="childList")for(const r of i.addedNodes)r.tagName==="LINK"&&r.rel==="modulepreload"&&n(r)}).observe(document,{childList:!0,subtree:!0});function s(o){const i={};return o.integrity&&(i.integrity=o.integrity),o.referrerpolicy&&(i.referrerPolicy=o.referrerpolicy),o.crossorigin==="use-credentials"?i.credentials="include":o.crossorigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function n(o){if(o.ep)return;o.ep=!0;const i=s(o);fetch(o.href,i)}};A();class v{static post(e,s,n){var o=this;window.wcfmoptions.poster(e,s,function(i){n.call(o,i)},function(){console.log("failure")})}}const E={},q={style:{position:"absolute",width:"0",height:"0"},width:"0",height:"0",version:"1.1",xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink"},G=R(`<defs><symbol id="icon-folder" viewBox="0 0 309.267 309.267"><g><path style="fill:#D0994B;" d="M260.944,43.491H125.64c0,0-18.324-28.994-28.994-28.994H48.323c-10.67,0-19.329,8.65-19.329,19.329
2
+ v222.286c0,10.67,8.659,19.329,19.329,19.329h212.621c10.67,0,19.329-8.659,19.329-19.329V62.82
3
+ C280.273,52.15,271.614,43.491,260.944,43.491z"></path><path style="fill:#E4E7E7;" d="M28.994,72.484h251.279v77.317H28.994V72.484z"></path><path style="fill:#F4B459;" d="M19.329,91.814h270.609c10.67,0,19.329,8.65,19.329,19.329l-19.329,164.298
4
+ c0,10.67-8.659,19.329-19.329,19.329H38.658c-10.67,0-19.329-8.659-19.329-19.329L0,111.143C0,100.463,8.659,91.814,19.329,91.814z
5
+ "></path></g></symbol><symbol id="icon-unfold" viewBox="0 0 32 32"><path d="M28,14H18V4c0-1.104-0.896-2-2-2s-2,0.896-2,2v10H4c-1.104,0-2,0.896-2,2s0.896,2,2,2h10v10c0,1.104,0.896,2,2,2 s2-0.896,2-2V18h10c1.104,0,2-0.896,2-2S29.104,14,28,14z"></path></symbol><symbol id="icon-fold" viewBox="0 0 24 24"><g fill="none" stroke="#000" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"></line></g></symbol><symbol id="icon-file" viewBox="0 0 56 56"><g><path style="fill:#E9E9E0;" d="M36.985,0H7.963C7.155,0,6.5,0.655,6.5,1.926V55c0,0.345,0.655,1,1.463,1h40.074
6
+ c0.808,0,1.463-0.655,1.463-1V12.978c0-0.696-0.093-0.92-0.257-1.085L37.607,0.257C37.442,0.093,37.218,0,36.985,0z"></path><polygon style="fill:#D9D7CA;" points="37.5,0.151 37.5,12 49.349,12 "></polygon><circle style="fill:#F3D55B;" cx="18.931" cy="14.431" r="4.569"></circle><polygon style="fill:#c5e8e1;" points="6.5,39 17.5,39 49.5,39 49.5,28 39.5,18.5 29,30 23.517,24.517 "></polygon><path style="fill:#14A085;" d="M48.037,56H7.963C7.155,56,6.5,55.345,6.5,54.537V39h43v15.537C49.5,55.345,48.845,56,48.037,56z"></path><g></g></g></symbol><svg id="icon-ok" viewBox="0 0 256 256"><g fill="green" stroke="none" transform="translate(0.000000,256.000000) scale(0.100000,-0.100000)"><path d="M1064 2545 c-406 -72 -744 -324 -927 -690 -96 -193 -127 -333 -127 -575 0 -243 33 -387 133 -585 177 -351 518 -606 907 -676 118 -22 393 -17 511 8 110 24 252 78 356 136 327 183 569 525 628 887 19 122 19 338 0 460 -81 498 -483 914 -990 1025 -101 22 -389 28 -491 10z m814 -745 c39 -27 73 -59 77 -70 9 -27 10 -25 -372 -590 -345 -510 -357 -524 -420 -512 -19 4 -98 74 -250 225 -123 121 -225 228 -228 238 -3 10 1 31 9 47 20 40 125 132 149 132 11 0 79 -59 162 -140 79 -77 146 -140 149 -140 3 0 38 48 78 108 95 143 465 678 496 720 35 46 64 42 150 -18z"></path></g></svg><svg id="icon-not-available" viewBox="0 0 500.000000 500.000000" preserveAspectRatio="xMidYMid meet"><g fill="#b11010" stroke="none" transform="translate(0.000000,500.000000) scale(0.100000,-0.100000)"><path d="M2315 4800 c-479 -35 -928 -217 -1303 -527 -352 -293 -615 -702 -738 -1151 -104 -380 -104 -824 0 -1204 107 -389 302 -724 591 -1013 354 -354 785 -572 1279 -646 196 -30 476 -30 672 0 494 74 925 292 1279 646 354 354 571 784 646 1279 30 197 30 475 0 672 -75 495 -292 925 -646 1279 -289 289 -624 484 -1013 591 -228 62 -528 91 -767 74z m353 -511 c458 -50 874 -272 1170 -624 417 -497 536 -1174 308 -1763 -56 -145 -176 -367 -235 -434 -4 -4 -566 552 -1250 1236 l-1243 1243 94 60 c354 229 754 327 1156 282z m864 -3200 c-67 -59 -289 -179 -434 -235 -946 -366 -2024 172 -2322 1158 -47 155 -66 276 -73 453 -13 362 84 704 290 1023 l60 94 1243 -1243 c684 -684 1240 -1246 1236 -1250z"></path></g></svg><svg id="icon-help" viewBox="0 0 400 400" style="enable-background:new 0 0 400 400;" xml:space="preserve"><g><path style="fill:#cccccc;" d="M199.996,0C89.719,0,0,89.72,0,200c0,110.279,89.719,200,199.996,200C310.281,400,400,310.279,400,200
7
+ C400,89.72,310.281,0,199.996,0z M199.996,373.77C104.187,373.77,26.23,295.816,26.23,200
8
+ c0-95.817,77.957-173.769,173.766-173.769c95.816,0,173.772,77.953,173.772,173.769
9
+ C373.769,295.816,295.812,373.77,199.996,373.77z"></path><path style="fill:#000000;" d="M199.996,91.382c-35.176,0-63.789,28.616-63.789,63.793c0,7.243,5.871,13.115,13.113,13.115
10
+ c7.246,0,13.117-5.873,13.117-13.115c0-20.71,16.848-37.562,37.559-37.562c20.719,0,37.566,16.852,37.566,37.562
11
+ c0,20.714-16.849,37.566-37.566,37.566c-7.242,0-13.113,5.873-13.113,13.114v45.684c0,7.243,5.871,13.115,13.113,13.115
12
+ s13.117-5.872,13.117-13.115v-33.938c28.905-6.064,50.68-31.746,50.68-62.427C263.793,119.998,235.176,91.382,199.996,91.382z"></path><path d="M200.004,273.738c-9.086,0-16.465,7.371-16.465,16.462s7.379,16.465,16.465,16.465c9.094,0,16.457-7.374,16.457-16.465
13
+ S209.098,273.738,200.004,273.738z"></path></g></svg><svg id="icon-help2" viewBox="0 0 431.855 431.855" style="enable-background:new 0 0 431.855 431.855;" xml:space="preserve"><g><path style="fill:#aaaaaa;" d="M215.936,0C96.722,0,0.008,96.592,0.008,215.814c0,119.336,96.714,216.041,215.927,216.041
14
+ c119.279,0,215.911-96.706,215.911-216.041C431.847,96.592,335.214,0,215.936,0z M231.323,335.962
15
+ c-5.015,4.463-10.827,6.706-17.411,6.706c-6.812,0-12.754-2.203-17.826-6.617c-5.08-4.406-7.625-10.575-7.625-18.501
16
+ c0-7.031,2.463-12.949,7.373-17.745c4.91-4.796,10.933-7.194,18.078-7.194c7.031,0,12.949,2.398,17.753,7.194
17
+ c4.796,4.796,7.202,10.713,7.202,17.745C238.858,325.362,236.346,331.5,231.323,335.962z M293.856,180.934
18
+ c-3.853,7.145-8.429,13.306-13.737,18.501c-5.292,5.194-14.81,13.924-28.548,26.198c-3.788,3.463-6.836,6.503-9.12,9.12
19
+ c-2.284,2.626-3.991,5.023-5.105,7.202c-1.122,2.178-1.983,4.357-2.593,6.535c-0.61,2.17-1.528,5.999-2.772,11.469
20
+ c-2.113,11.608-8.754,17.411-19.915,17.411c-5.804,0-10.681-1.894-14.656-5.69c-3.959-3.796-5.934-9.429-5.934-16.907
21
+ c0-9.372,1.455-17.493,4.357-24.361c2.886-6.869,6.747-12.892,11.543-18.086c4.804-5.194,11.274-11.356,19.427-18.501
22
+ c7.145-6.251,12.307-10.965,15.485-14.144c3.186-3.186,5.861-6.73,8.031-10.632c2.187-3.91,3.26-8.145,3.26-12.721
23
+ c0-8.933-3.308-16.46-9.957-22.597c-6.641-6.137-15.209-9.21-25.703-9.21c-12.282,0-21.321,3.097-27.125,9.291
24
+ c-5.804,6.194-10.705,15.314-14.729,27.369c-3.804,12.616-11.006,18.923-21.598,18.923c-6.251,0-11.526-2.203-15.826-6.609
25
+ c-4.292-4.406-6.438-9.177-6.438-14.314c0-10.6,3.406-21.346,10.21-32.23c6.812-10.884,16.745-19.899,29.807-27.036
26
+ c13.054-7.145,28.296-10.722,45.699-10.722c16.184,0,30.466,2.991,42.854,8.966c12.388,5.966,21.963,14.087,28.718,24.361
27
+ c6.747,10.266,10.128,21.427,10.128,33.482C299.635,165.473,297.709,173.789,293.856,180.934z"></path></g></svg><svg id="icon-loading" viewBox="0 0 128 128" xml:space="preserve"><g><path d="M38.52 33.37L21.36 16.2A63.6 63.6 0 0 1 59.5.16v24.3a39.5 39.5 0 0 0-20.98 8.92z" fill="#049046"></path><path d="M38.52 33.37L21.36 16.2A63.6 63.6 0 0 1 59.5.16v24.3a39.5 39.5 0 0 0-20.98 8.92z" fill="#c5e8e1" transform="rotate(45 64 64)"></path><path d="M38.52 33.37L21.36 16.2A63.6 63.6 0 0 1 59.5.16v24.3a39.5 39.5 0 0 0-20.98 8.92z" fill="#c5e8e1" transform="rotate(90 64 64)"></path><path d="M38.52 33.37L21.36 16.2A63.6 63.6 0 0 1 59.5.16v24.3a39.5 39.5 0 0 0-20.98 8.92z" fill="#c5e8e1" transform="rotate(135 64 64)"></path><path d="M38.52 33.37L21.36 16.2A63.6 63.6 0 0 1 59.5.16v24.3a39.5 39.5 0 0 0-20.98 8.92z" fill="#c5e8e1" transform="rotate(180 64 64)"></path><path d="M38.52 33.37L21.36 16.2A63.6 63.6 0 0 1 59.5.16v24.3a39.5 39.5 0 0 0-20.98 8.92z" fill="#c5e8e1" transform="rotate(225 64 64)"></path><path d="M38.52 33.37L21.36 16.2A63.6 63.6 0 0 1 59.5.16v24.3a39.5 39.5 0 0 0-20.98 8.92z" fill="#c5e8e1" transform="rotate(270 64 64)"></path><path d="M38.52 33.37L21.36 16.2A63.6 63.6 0 0 1 59.5.16v24.3a39.5 39.5 0 0 0-20.98 8.92z" fill="#c5e8e1" transform="rotate(315 64 64)"></path><animateTransform attributeName="transform" type="rotate" values="0 64 64;45 64 64;90 64 64;135 64 64;180 64 64;225 64 64;270 64 64;315 64 64" calcMode="discrete" dur="720ms" repeatCount="indefinite"></animateTransform></g></svg></defs>`,1),K=[G];function J(t,e){return l(),c("svg",q,K)}var Q=f(E,[["render",J]]);class w{static escape(e){return e.replace(/./gm,function(s){var n=/[0-9a-zA-Z\!\[\]\(\)\*\#]/;return n.test(s.charAt(0))?s.charAt(0):"&#"+s.charCodeAt(0)+";"})}static md2htmlOneLine(e){return e=w.escape(e),e=e.replace(/\[([^[]+)\]\(([^)]+)\)/gm,function(s,n,o){return'<a target="blank" href="'+o+'">'+n+"</a>"}),e=e.replace(/(\*\*[^\*]+\*\*)/gm,function(s){return"<b>"+s.substr(2,s.length-4)+"</b>"}),e=e.replace(/(\*[^\*]+\*)/gm,function(s){return"<i>"+s.substr(1,s.length-2)+"</i>"}),e.substr(0,1)=="#"&&(e.substr(0,2)=="# "&&(e="<h1>"+e.substr(2)+"</h1>"),e.substr(0,3)=="## "&&(e="<h2>"+e.substr(3)+"</h2>"),e.substr(0,4)=="### "&&(e="<h3>"+e.substr(4)+"</h3>"),e.substr(0,5)=="#### "&&(e="<h4>"+e.substr(5)+"</h4>")),e==""&&(e="<br>"),e}static md2html(e){for(var s=e.match(/[^\r\n]+/g),n=[],o=0;o<s.length;o++)n.push(w.md2htmlOneLine(s[o]));return n.join("<br>")}}const ee={name:"FileItem",emits:["toggle","select"],props:{item:Object},data(){return{hover:!1,selected:!1}},inject:["wcfm"],methods:{onClick(t){this.selected=!0,this.$emit("select",this)},getWCFM(){return this.wcfm},getFullPath(){for(var t=this.$parent,e=[];t!==null&&t.$parent!==null;)t.item&&e.push(t.item.name),t=t.$parent;return e.pop(),e=e.reverse().join("/"),e=e.replace("//","/"),e},infoClick(){this.getWCFM().displayInfo(this.getFullPath())},convertClick(){this.getWCFM().onConvertClick(this.getFullPath())}}},C=t=>(V("data-v-4fb0cc48"),t=t(),I(),t),te={key:0,class:"icon-fold"},oe=C(()=>a("use",{"xlink:href":"#icon-fold"},null,-1)),se=[oe],ie={key:1,class:"icon-unfold"},ne=C(()=>a("use",{"xlink:href":"#icon-unfold"},null,-1)),ae=[ne],le=C(()=>a("use",{"xlink:href":"#icon-folder"},null,-1)),re=[le],ce={key:2,class:"icon-file"},de=C(()=>a("use",{"xlink:href":"#icon-file"},null,-1)),he=[de];function ue(t,e,s,n,o,i){return l(),c("div",{class:S({fileitem:!0,selected:o.selected}),onMouseover:e[2]||(e[2]=r=>o.hover=!0),onMouseleave:e[3]||(e[3]=r=>o.hover=!1),onClick:e[4]||(e[4]=(...r)=>i.onClick&&i.onClick(...r))},[a("p",null,[s.item.isDir?(l(),c("span",{key:0,class:S({"fold-unfold":!0,empty:s.item.isEmpty}),onClick:e[0]||(e[0]=r=>this.$emit("toggle"))},[s.item.isOpen?(l(),c("svg",te,se)):u("",!0),s.item.isOpen?u("",!0):(l(),c("svg",ie,ae))],2)):u("",!0),s.item.isDir?(l(),c("svg",{key:1,class:"icon-folder",onClick:e[1]||(e[1]=r=>this.$emit("toggle"))},re)):u("",!0),s.item.isDir?u("",!0):(l(),c("svg",ce,he)),y(" "+p(s.item.nickname||s.item.name),1)])],34)}var me=f(ee,[["render",ue],["__scopeId","data-v-4fb0cc48"]]);const fe={name:"FileTree",components:{FileItem:me},emits:["select"],props:{item:Object},data(){return{loading:!1}},methods:{load(){var t=this;v.post("get-folder",{path:this.$refs.thefileitem.getFullPath()},function(e){t.loading=!0,t.item.children=e.children.sort(function(s,n){return s.isDir&&!n.isDir?-1:!s.isDir&&n.isDir||s.name>n.name?1:s.name<n.name?-1:0}),t.item.loaded=!0,t.loading=!1})},toggle(){this.item.isOpen=!this.item.isOpen,this.item.loaded||this.load()},onSelect(t){this.$emit("select",t)}},mounted(){let t=this.$refs.thefileitem.getFullPath();(t=="/"||t.indexOf("/")==-1)&&this.toggle()}},_e={key:0},pe=a("li",null,"loading...",-1),ge=[pe],ve={key:1,class:"tree"};function ye(t,e,s,n,o,i){const r=m("FileItem"),h=m("FileTree",!0);return l(),c(x,null,[_(r,{ref:"thefileitem",item:s.item,onDblclick:i.toggle,onToggle:i.toggle,onSelect:i.onSelect},null,8,["item","onDblclick","onToggle","onSelect"]),o.loading?(l(),c("ul",_e,ge)):u("",!0),s.item.children!==void 0&&s.item.isOpen?(l(),c("ul",ve,[(l(!0),c(x,null,Y(s.item.children,d=>(l(),c("li",null,[_(h,{item:d,onSelect:i.onSelect},null,8,["item","onSelect"])]))),256))])):u("",!0)],64)}var ze=f(fe,[["render",ye]]);const be={name:"Files",components:{FileTree:ze},emits:["select"],props:{item:Object,statusText:String},methods:{onSelect(t){this.selectedItem&&(this.selectedItem.selected=!1),this.selectedItem=t,this.$emit("select",this.selectedItem.getFullPath(),this.selectedItem.item.isDir)}},data(){return{selected:null}}},we={key:1};function xe(t,e,s,n,o,i){const r=m("FileTree");return l(),c(x,null,[s.item?(l(),z(r,{key:0,item:s.item,onSelect:i.onSelect},null,8,["item","onSelect"])):u("",!0),s.item?u("",!0):(l(),c("div",we,p(s.statusText),1))],64)}var $e=f(be,[["render",xe]]);const ke={name:"Modal",emits:["close"],props:{title:{type:String},closeButtonText:{type:String},width:{type:[Number,String],default:"95%"},maxwidth:{type:[Number,String],default:"700px"},alignment:{type:String,default:"center"},height:{type:[Number,String],default:"92%"},maxheight:{type:[Number,String],default:"700px"},valignment:{type:String,default:"center"}},computed:{containerStyle(){let t={width:this.width,"max-width":this.maxwidth,height:this.height,"max-height":this.maxheight};return this.alignment=="center"&&(t.margin="0px auto"),this.alignment=="right"&&(t.position="absolute",t.right="10px"),this.valignment=="center"&&(t.top="50%",t.transform="translateY(-50%)"),this.alignment=="bottom"&&(t.position="absolute",t.bottom="10px"),t}},methods:{onCloseClick(){this.$emit("close")},registerKeyDownEvent(){let t=this;document.onkeydown=function(e){e=e||window.event;var s=!1;"key"in e?s=e.key==="Escape"||e.key==="Esc":s=e.keyCode===27,s&&t.$emit("close")}}},mounted(){this.registerKeyDownEvent()}},Ce={class:"modal-mask"},Se={class:"modal-wrapper"},Ve={class:"title"},Ie={class:"modal-body"},Me={class:"content"},Fe=y(" default body "),Re={class:"close-button-with-text"};function Ye(t,e,s,n,o,i){return l(),c("div",Ce,[a("div",Se,[a("div",{class:"modal-container",style:D(i.containerStyle)},[a("a",{class:"close-button",onClick:e[0]||(e[0]=(...r)=>i.onCloseClick&&i.onCloseClick(...r))},"X"),a("div",Ve,p(s.title),1),a("div",Ie,[a("div",Me,[H(t.$slots,"default",{},()=>[Fe]),a("div",Re,[a("button",{onClick:e[1]||(e[1]=(...r)=>i.onCloseClick&&i.onCloseClick(...r))},p(s.closeButtonText),1)])])])],4)])])}var L=f(ke,[["render",Ye]]);const De={name:"ZoomSlider",components:{Slider:j},emits:["update:zoom"],props:{zoom:{type:Number,default:1}},watch:{exp(t,e){this.$emit("update:zoom",2**t)},zoom(t,e){this.exp=Math.log2(t)}},methods:{sliderFormat(t){return Math.round(2**t*100)+"%"}},mounted(){},data(){return{exp:0}}},Oe={class:"zoom-slider"};function Xe(t,e,s,n,o,i){const r=m("Slider");return l(),c("div",Oe,[_(r,{modelValue:o.exp,"onUpdate:modelValue":e[0]||(e[0]=h=>o.exp=h),min:-4,max:4,width:100,step:-1,format:i.sliderFormat,tooltipPosition:"bottom",orientation:"horizontal"},null,8,["modelValue","format"])])}var Le=f(De,[["render",Xe]]);const Te={name:"ImageViewport",components:{VueZoomer:O,ZoomSlider:Le},emits:["update:zoom","update:translateX","update:translateY","load","resize"],props:{src:{type:String},height:{type:Number,default:500},zoom:{type:Number,default:1},scaleZoomRatio:{type:Number},translateX:{type:Number,default:1},translateY:{type:Number,default:1}},data(){return{ratio:1,ro:null}},watch:{height(t,e){var s;((s=this.$refs)==null?void 0:s.zoomer)&&(this.$refs.zoomer.onWindowResize(),this.$refs.zoomer.refreshContainerPos())},scaleZoomRatio(t){var e;((e=this.$refs)==null?void 0:e.zoomer)&&(this.$refs.zoomer.onWindowResize(),this.$refs.zoomer.refreshContainerPos()),this.$refs.zoomer.scale=this.zoom*this.scaleZoomRatio},zoom(t,e){this.isImageReady(),this.$refs.zoomer.scale=t*this.scaleZoomRatio},translateX(t,e){this.$refs.zoomer.translateX!=t&&(this.$refs.zoomer.translateX=t)},translateY(t,e){this.$refs.zoomer.translateY!=t&&(this.$refs.zoomer.translateY=t)}},methods:{getGoodContainerHeight(){var t,e,s;if((e=(t=this.$refs)==null?void 0:t.theimg)==null?void 0:e.naturalWidth){let n=this.$refs.theimg.naturalWidth/this.$refs.theimg.naturalHeight,i=((s=this.$refs.root)==null?void 0:s.offsetWidth)/n;return i>300&&(i=300),i}return 300},updateContainerHeight(){},isImageReady(){var t,e,s;return!(!((e=(t=this.$refs)==null?void 0:t.theimg)==null?void 0:e.naturalWidth)||!((s=this.$refs.root)==null?void 0:s.offsetWidth))},calcScaleZoomRatio(){var n,o;if(!this.isImageReady())return 1;let t=this.$refs.theimg.naturalWidth/((n=this.$refs.root)==null?void 0:n.offsetWidth),e=this.$refs.theimg.naturalHeight/((o=this.$refs.root)==null?void 0:o.offsetHeight),s=Math.max(t,e);return isNaN(s)?1:s},updateRatio(){},updateScale(){this.zoom&&(this.$refs.zoomer.scale=this.zoom*this.scaleZoomRatio)},zoomToFit(){},onImgLoad(){var t,e;((e=(t=this.$refs)==null?void 0:t.theimg)==null?void 0:e.naturalWidth)&&this.$emit("load")},onResize(){this.$emit("resize")},onDoubleTap(){console.log("double tab - zoom to 100%"),this.$emit("update:zoom",1),this.$emit("update:translateX",0),this.$emit("update:translateY",0)}},mounted(){window.ResizeObserver&&(this.ro=new ResizeObserver(this.onResize).observe(this.$refs.root)),this.$refs.zoomer.tapDetector.onDoubleTap(this.onDoubleTap),this.$watch("$refs.zoomer.scale",(t,e)=>{this.isImageReady(),this.$emit("update:zoom",t/this.scaleZoomRatio)}),this.$watch("$refs.zoomer.translateX",(t,e)=>{this.$emit("update:translateX",t)}),this.$watch("$refs.zoomer.translateY",(t,e)=>{this.$emit("update:translateY",t)})},beforeDestroy(){window.ResizeObserver&&this.ro.unobserve(this.$refs.zoomer)}},We={ref:"root",class:"image-viewport"},Ne=["src"],Pe={class:"zoom-info"};function Ze(t,e,s,n,o,i){const r=m("v-zoomer");return l(),c("div",We,[_(r,{ref:"zoomer",class:"zoomer",minScale:.1,maxScale:8,onResize:i.onResize,doubleClickToZoom:!1,style:D({height:s.height+"px"}),pivot:"cursor",limitTranslation:!1,lockPanOnNoScale:!1},{default:b(()=>[a("img",{ref:"theimg",src:s.src,onLoad:e[0]||(e[0]=(...h)=>i.onImgLoad&&i.onImgLoad(...h))},null,40,Ne)]),_:1},8,["minScale","onResize","style"]),a("div",Pe," zoom: "+p(Math.round(s.zoom*100))+"% ",1)],512)}var He=f(Te,[["render",Ze]]);const je={name:"Variant",components:{ImageViewport:He},emits:["select","update:zoom","update:translateX","update:translateY","load","resize"],props:{title:{type:String},info:{type:Object},url:{type:String,default:""},height:{type:Number},zoom:{type:Number},scaleZoomRatio:{type:Number},translateX:{type:Number},translateY:{type:Number},variantIndex:{type:Number}},computed:{imageUrl:function(){var t;return(t=this.info)==null?void 0:t.url},filesize:function(){var e;if(!((e=this.info)==null?void 0:e.size))return"";let t=this.info.size;return t<1024?t+" bytes":(t/=1024,t<1024?Math.round(t*10)/10+" kb":(t/=1024,Math.round(t*10)/10+" MB"))}},methods:{onVariantSelect(){this.$emit("select",this.variantIndex)},onLoad(){this.$emit("load")},zoomToFit(){this.$refs.theport.zoomToFit()}},mounted(){this.$watch("$refs.theport.zoom",(t,e)=>{this.$emit("update:zoom",t)}),this.$watch("$refs.theport.translateX",(t,e)=>{this.$emit("update:translateX",t)}),this.$watch("$refs.theport.translateY",(t,e)=>{this.$emit("update:translateY",t)})},data(){return{}}},Be={class:"variant"},Ue={class:"header"},Ae={class:"title"},Ee={class:"size"};function qe(t,e,s,n,o,i){const r=m("ImageViewport");return l(),c("div",Be,[a("div",Ue,[a("div",Ae,p(s.title),1),a("div",Ee,p(i.filesize),1)]),_(r,{ref:"theport",src:i.imageUrl,height:s.height,zoom:s.zoom,"onUpdate:zoom":e[0]||(e[0]=h=>s.zoom=h),scaleZoomRatio:s.scaleZoomRatio,translateX:s.translateX,"onUpdate:translateX":e[1]||(e[1]=h=>s.translateX=h),translateY:s.translateY,"onUpdate:translateY":e[2]||(e[2]=h=>s.translateY=h),onLoad:i.onLoad,onResize:e[3]||(e[3]=h=>this.$emit("resize"))},null,8,["src","height","zoom","scaleZoomRatio","translateX","translateY","onLoad"])])}var T=f(je,[["render",qe],["__scopeId","data-v-0372e854"]]);const Ge={name:"Variants",components:{Variant:T},emits:["update:zoom","update:translateX","update:translateY"],props:{file:{type:Object},viewport:{type:Object},height:{type:Number},zoom:{type:Number,default:1},translateX:{type:Number,default:0},translateY:{type:Number,default:0}},watch:{file(t,e){}},methods:{onZoomChange(t){this.$emit("update:zoom",t)},onTranslateXChange(t){this.$emit("update:translateX",t)},onTranslateYChange(t){this.$emit("update:translateY",t)},sliderFormat(t){return Math.round(t*100)+"%"},changeImage(){this.imageUrl=="http://localhost:3000/src/assets/dummy.jpg"?this.imageUrl="http://localhost:3000/src/assets/dummy2.jpg":this.imageUrl="http://localhost:3000/src/assets/dummy.jpg",this.selectedVariant=-1},onVariantSelect(t){this.selectedVariant=t}},mounted(){this.$watch("$refs.variants.zoom",(t,e)=>{})},data(){var t="http://localhost:3000/src/assets/200x100.jpg";return{imageUrl:"",selectedVariant:-1,variants:[{title:"Existing conversion",size:732,url:t},{title:"Lossy, q:20",size:35e5,url:t}]}}},W=t=>(V("data-v-25a3327e"),t=t(),I(),t),Ke={class:"variants-component"},Je=W(()=>a("br",null,null,-1)),Qe=W(()=>a("br",null,null,-1)),et={class:"variants"};function tt(t,e,s,n,o,i){const r=m("Variant");return l(),c("div",Ke,[y(" File: "+p(s.file)+" ",1),a("button",{onClick:e[0]||(e[0]=h=>i.changeImage())},"Change image"),Je,Qe,a("div",et,[(l(!0),c(x,null,Y(o.variants,(h,d)=>(l(),z(r,{title:h.title,info:h,variantIndex:d,class:S({selected:d==o.selectedVariant}),height:s.height,zoom:s.zoom,"onUpdate:zoom":[e[1]||(e[1]=g=>s.zoom=g),i.onZoomChange],translateX:s.translateX,"onUpdate:translateX":[e[2]||(e[2]=g=>s.translateX=g),i.onTranslateXChange],translateY:s.translateY,"onUpdate:translateY":[e[3]||(e[3]=g=>s.translateY=g),i.onTranslateYChange],onSelect:i.onVariantSelect},null,8,["title","info","variantIndex","class","height","zoom","translateX","translateY","onSelect","onUpdate:zoom","onUpdate:translateX","onUpdate:translateY"]))),256))])])}var ot=f(Ge,[["render",tt],["__scopeId","data-v-25a3327e"]]);const st={name:"FileProperties",components:{Variant:T,Variants:ot,Modal:L},props:{file:{type:Object,default:{}}},watch:{file(t,e){t.isDir||this.changePath(t.path)}},methods:{onVariantSelect(t){this.selectedVariant=t},onOriginalLoad(){if(this.updateHeight(),this.$refs.original.$refs.theport.calcScaleZoomRatio()>1){let e=this.$refs.original.$refs.theport,s=e.$refs.theimg,n=e.$refs.root,o=s.naturalWidth,i=s.naturalHeight,r=n.offsetWidth,d=this.height/i,g=r/o;this.zoom=Math.min(d,g)}else this.zoom=1;this.translateX=0,this.translateY=0},onOriginalResize(){this.updateHeight()},onConvertClick(){let t=this;this.converting=!0,v.post("convert",{path:this.path},function(e){t.converting=!1,(e==null?void 0:e.success)==!1&&(t.errorMsg=e.data),e.converted&&(t.convertedInfo=e.converted),e.log&&(t.log=w.md2html(e.log))})},updateHeight(){this.$refs.original&&(this.height=this.$refs.original.$refs.theport.getGoodContainerHeight(),this.scaleZoomRatio=this.$refs.original.$refs.theport.calcScaleZoomRatio())},reset(){this.originalInfo=null,this.convertedInfo=null},reload(){this.load()},changePath(t){this.reset(),this.path=t,this.loading=!0,this.errorMsg="",this.log="",this.load()},load(){let t=this;v.post("info",{path:this.path},function(e){(e==null?void 0:e.success)==!1&&(t.errorMsg=e.data),t.loading=!1,t.originalInfo=e.original,e.converted&&(t.convertedInfo=e.converted),e.log&&(t.log=w.md2html(e.log))})}},mounted(){this.file&&(this.path=this.file.path,this.load())},data(){return{zoom:1,scaleZoomRatio:1,translateX:0,translateY:0,height:100,loading:!1,errorMsg:"",originalInfo:null,convertedInfo:null,path:"",log:"",showingLogDialog:!1,converting:!1}}},M=t=>(V("data-v-1f62a342"),t=t(),I(),t),it={class:"file-properties"},nt={class:"path"},at=y(" Path: "),lt={class:"path"},rt={key:0,class:"error"},ct=["innerHTML"],dt={key:0},ht={key:1},ut={key:0,class:"icon-converting",width:"15",height:"15"},mt=M(()=>a("use",{"xlink:href":"#icon-loading"},null,-1)),ft=[mt],_t=["disabled"],pt=M(()=>a("p",null," Above, you see the original image. If it has been converted, you also see the converted image (provided that your browser supports webp). ",-1)),gt=M(()=>a("p",null," You can zoom in on the image, ie using scroll wheel. Both images will zoom, allowing you to compare the quality. Double-click the image to set zoom to 100%. You can also drag the image. ",-1));function vt(t,e,s,n,o,i){const r=m("Variant"),h=m("Modal");return l(),c("div",it,[a("div",nt,[at,a("span",lt,p(s.file.path),1)]),o.errorMsg!=""?(l(),c("div",rt,[a("p",null,"Error: "+p(o.errorMsg),1)])):u("",!0),$(a("div",null,"Getting info...",512),[[k,o.loading]]),$(_(r,{ref:"original",title:"Original",info:o.originalInfo,height:o.height,zoom:o.zoom,"onUpdate:zoom":e[0]||(e[0]=d=>o.zoom=d),scaleZoomRatio:o.scaleZoomRatio,translateX:o.translateX,"onUpdate:translateX":e[1]||(e[1]=d=>o.translateX=d),translateY:o.translateY,"onUpdate:translateY":e[2]||(e[2]=d=>o.translateY=d),onLoad:i.onOriginalLoad,onResize:i.onOriginalResize},null,8,["info","height","zoom","scaleZoomRatio","translateX","translateY","onLoad","onResize"]),[[k,o.originalInfo]]),$(_(r,{title:"Existing conversion",info:o.convertedInfo,height:o.height,zoom:o.zoom,"onUpdate:zoom":e[3]||(e[3]=d=>o.zoom=d),scaleZoomRatio:o.scaleZoomRatio,translateX:o.translateX,"onUpdate:translateX":e[4]||(e[4]=d=>o.translateX=d),translateY:o.translateY,"onUpdate:translateY":e[5]||(e[5]=d=>o.translateY=d)},null,8,["info","height","zoom","scaleZoomRatio","translateX","translateY"]),[[k,o.convertedInfo]]),$(_(h,{title:"Conversion log",closeButtonText:"Ok",width:"95vw",maxwidth:"1400px",height:"95vh",onClose:e[6]||(e[6]=d=>o.showingLogDialog=!1)},{default:b(()=>[a("div",{innerHTML:o.log},null,8,ct)]),_:1},512),[[k,o.showingLogDialog]]),a("div",null,[a("button",{onClick:e[7]||(e[7]=(...d)=>i.onConvertClick&&i.onConvertClick(...d))},[o.convertedInfo?(l(),c("span",dt,"Reconvert")):u("",!0),o.convertedInfo?u("",!0):(l(),c("span",ht,"Convert"))]),o.converting?(l(),c("svg",ut,ft)):u("",!0),o.log!=""?(l(),c("button",{key:1,onClick:e[8]||(e[8]=d=>o.showingLogDialog=!0),class:"log-button",disabled:o.converting},"View conversion log",8,_t)):u("",!0)]),pt,gt])}var yt=f(st,[["render",vt],["__scopeId","data-v-1f62a342"]]);const zt={name:"FolderProperties",components:{},props:{file:{type:Object,default:{}}},watch:{file(t,e){}}},bt={class:"folder-properties"},wt={class:"path"},xt=y(" Path: "),$t={class:"path"},kt=a("p",null," You cannot do anything on folders yet. Browse to an image... ",-1);function Ct(t,e,s,n,o,i){return l(),c("div",bt,[a("div",wt,[xt,a("span",$t,p(s.file.path),1)]),kt])}var St=f(zt,[["render",Ct]]);const Vt={name:"Welcome"},It={class:"welcome"},Mt=R('<div class="headline"><div>Welcome to</div><h3>WebP Convert file manager</h3></div><p> To open a folder, click the &quot;+&quot; sign next to the folder name or double click the folder name </p><p><h4>Whats new?</h4><ul><li>You can now convert files and view conversion log</li></ul></p><p><h4>Whats planned ahead?</h4> I have plenty of ideas, but no planned priority. Ideas: <ul><li>Trigger bulk conversion on folders / mark for background conversion</li><li>Stats on folders</li><li>Display more info on images (mime type, dimensions and such)</li><li>Adjust conversion settings</li><li>Interface to allow adjusting quality on a conversion quickly and compare directly</li></ul> To support development, you can <a href="https://ko-fi.com/rosell" target="_blank">buy me a cup of coffee</a></p>',4),Ft=[Mt];function Rt(t,e,s,n,o,i){return l(),c("div",It,Ft)}var Yt=f(Vt,[["render",Rt]]);const Dt={name:"WCFM",components:{SVGs:Q,FileProperties:yt,FolderProperties:St,Modal:L,Files:$e,Splitpanes:X.exports.Splitpanes,Pane:X.exports.Pane,Welcome:Yt},methods:{onConvertClick(t){var n,o;let e=(o=(n=this.$refs.convertOptions)==null?void 0:n.general)==null?void 0:o.data,s={path:t,convertOptions:e};console.log(s),v.post("convert",s,function(i){console.log("convert response:",i)})},onConvertCloseClick(){console.log("CLRCL"),this.showConvertOptions=!1},onFileSelect(t,e){this.file={path:t,isDir:e}},displayInfo(t){var e=this;v.post("info",{path:t},function(s){e.selectedInfo=s})}},mounted(){var t=this;v.post("get-folder",{path:""},function(e){t.item=e.children[0]})},data(){return{file:null,selectedItem:null,item:null,treeStatusText:"loading file tree...",selectedInfo:{},showConvertOptions:!1}},provide(){return{wcfm:this}}},Ot={class:"wcfm",style:{overflow:"hidden"}},Xt={class:"pane-content"},Lt={key:0,class:"pane-content"};function Tt(t,e,s,n,o,i){const r=m("SVGs"),h=m("Files"),d=m("pane"),g=m("FileProperties"),N=m("FolderProperties"),P=m("Welcome"),Z=m("splitpanes");return l(),c("div",Ot,[_(r),_(Z,{class:"default-theme",style:{position:"absolute",top:"0",left:"0"}},{default:b(()=>[_(d,{size:"30"},{default:b(()=>[a("div",Xt,[a("div",null,[_(h,{item:o.item,statusText:o.treeStatusText,onSelect:i.onFileSelect},null,8,["item","statusText","onSelect"])])])]),_:1}),_(d,{size:"70",style:{"overflow-y":"auto"}},{default:b(()=>[o.file?(l(),c("div",Lt,[o.file.isDir?u("",!0):(l(),z(g,{key:0,file:o.file},null,8,["file"])),o.file.isDir?(l(),z(N,{key:1,file:o.file},null,8,["file"])):u("",!0)])):u("",!0),o.file?u("",!0):(l(),z(P,{key:1}))]),_:1})]),_:1})])}var Wt=f(Dt,[["render",Tt]]);const F=B(Wt);F.use(O);F.use(U,{defaultHtml:!1});window.wcfmoptions||(window.wcfmoptions={},window.wcfmoptions.poster=function(t,e,s,n){switch(t){case"get-folder":switch(e.path){case"":var o={children:[{name:"/",isDir:!0,nickname:"root"}]};break;case"/":var o={children:[{name:"empty-folder",isDir:!0,isEmpty:!0},{name:"file",isDir:!1,isConverted:!0},{name:"aaa",isDir:!1,isConverted:!0},{name:"test-folder",isDir:!0},{name:"file2",isDir:!1,isConverted:!1}]};break;case"/empty-folder":var o={children:[]};break;case"/test-folder":var o={children:[{name:"banana",isDir:!1},{name:"subfolder",isDir:!0},{name:"apple",isDir:!1}]};break;case"/test-folder/subfolder":var o={children:[{name:"file2",isDir:!1},{name:"file1",isDir:!1}]};break;default:n();return}break;case"conversion-settings":var o={systemStatus:{converterRequirements:{gd:{extensionLoaded:!1,compiledWithWebP:!0}}}};break;case"info":if(e.path=="/file2")var o={original:{size:100,url:"http://localhost:3000/src/assets/200x100.jpg"},converted:{size:70,url:"http://localhost:3000/src/assets/200x100.jpg"},log:`blah blah blah
28
+ \rand *more* blah`};else if(e.path=="/file")var o={original:{size:100,url:"http://localhost:3000/src/assets/dummy2.jpg"},log:"blah blah *blah*"};else var o={original:{size:100,url:"http://localhost:3000/src/assets/dummy.jpg"},converted:{size:70,url:"http://localhost:3000/src/assets/dummy.jpg"},log:"blah blah *blah*"};break;case"convert":if(e.path=="/file2")var o={success:!1,data:"We pretend file2 errors converting...",log:"Oh no!"};else var o={success:!0,converted:{size:26050,url:"http://we0/wordpress/wp-content/uploads/2021/10/Screenshot_2021-10-04_13-43-11.png.webp"},log:`All is *groovy*
29
+ next line`};break;default:var o="ok";break}s(o)});F.mount("#webpconvert-filemanager");
lib/wcfm/index.f8d1bd25.js DELETED
@@ -1,27 +0,0 @@
1
- import{_ as m,o as c,c as d,a as F,b as l,n as $,d as u,e as v,t as f,p as C,f as k,r as h,g as _,F as b,h as M,i as y,j as R,k as P,m as H,V as Y,w,l as S,v as V,s as X,q as L,u as j}from"./vendor.b4e4e155.js";const B=function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))n(o);new MutationObserver(o=>{for(const i of o)if(i.type==="childList")for(const a of i.addedNodes)a.tagName==="LINK"&&a.rel==="modulepreload"&&n(a)}).observe(document,{childList:!0,subtree:!0});function s(o){const i={};return o.integrity&&(i.integrity=o.integrity),o.referrerpolicy&&(i.referrerPolicy=o.referrerpolicy),o.crossorigin==="use-credentials"?i.credentials="include":o.crossorigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function n(o){if(o.ep)return;o.ep=!0;const i=s(o);fetch(o.href,i)}};B();class z{static post(t,s,n){var o=this;window.wcfmoptions.poster(t,s,function(i){n.call(o,i)},function(){console.log("failure")})}}const U={},E={style:{position:"absolute",width:"0",height:"0"},width:"0",height:"0",version:"1.1",xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink"},q=F(`<defs><symbol id="icon-folder" viewBox="0 0 309.267 309.267"><g><path style="fill:#D0994B;" d="M260.944,43.491H125.64c0,0-18.324-28.994-28.994-28.994H48.323c-10.67,0-19.329,8.65-19.329,19.329
2
- v222.286c0,10.67,8.659,19.329,19.329,19.329h212.621c10.67,0,19.329-8.659,19.329-19.329V62.82
3
- C280.273,52.15,271.614,43.491,260.944,43.491z"></path><path style="fill:#E4E7E7;" d="M28.994,72.484h251.279v77.317H28.994V72.484z"></path><path style="fill:#F4B459;" d="M19.329,91.814h270.609c10.67,0,19.329,8.65,19.329,19.329l-19.329,164.298
4
- c0,10.67-8.659,19.329-19.329,19.329H38.658c-10.67,0-19.329-8.659-19.329-19.329L0,111.143C0,100.463,8.659,91.814,19.329,91.814z
5
- "></path></g></symbol><symbol id="icon-unfold" viewBox="0 0 32 32"><path d="M28,14H18V4c0-1.104-0.896-2-2-2s-2,0.896-2,2v10H4c-1.104,0-2,0.896-2,2s0.896,2,2,2h10v10c0,1.104,0.896,2,2,2 s2-0.896,2-2V18h10c1.104,0,2-0.896,2-2S29.104,14,28,14z"></path></symbol><symbol id="icon-fold" viewBox="0 0 24 24"><g fill="none" stroke="#000" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"></line></g></symbol><symbol id="icon-file" viewBox="0 0 56 56"><g><path style="fill:#E9E9E0;" d="M36.985,0H7.963C7.155,0,6.5,0.655,6.5,1.926V55c0,0.345,0.655,1,1.463,1h40.074
6
- c0.808,0,1.463-0.655,1.463-1V12.978c0-0.696-0.093-0.92-0.257-1.085L37.607,0.257C37.442,0.093,37.218,0,36.985,0z"></path><polygon style="fill:#D9D7CA;" points="37.5,0.151 37.5,12 49.349,12 "></polygon><circle style="fill:#F3D55B;" cx="18.931" cy="14.431" r="4.569"></circle><polygon style="fill:#26B99A;" points="6.5,39 17.5,39 49.5,39 49.5,28 39.5,18.5 29,30 23.517,24.517 "></polygon><path style="fill:#14A085;" d="M48.037,56H7.963C7.155,56,6.5,55.345,6.5,54.537V39h43v15.537C49.5,55.345,48.845,56,48.037,56z"></path><g></g></g></symbol><svg id="icon-ok" viewBox="0 0 256 256"><g fill="green" stroke="none" transform="translate(0.000000,256.000000) scale(0.100000,-0.100000)"><path d="M1064 2545 c-406 -72 -744 -324 -927 -690 -96 -193 -127 -333 -127 -575 0 -243 33 -387 133 -585 177 -351 518 -606 907 -676 118 -22 393 -17 511 8 110 24 252 78 356 136 327 183 569 525 628 887 19 122 19 338 0 460 -81 498 -483 914 -990 1025 -101 22 -389 28 -491 10z m814 -745 c39 -27 73 -59 77 -70 9 -27 10 -25 -372 -590 -345 -510 -357 -524 -420 -512 -19 4 -98 74 -250 225 -123 121 -225 228 -228 238 -3 10 1 31 9 47 20 40 125 132 149 132 11 0 79 -59 162 -140 79 -77 146 -140 149 -140 3 0 38 48 78 108 95 143 465 678 496 720 35 46 64 42 150 -18z"></path></g></svg><svg id="icon-not-available" viewBox="0 0 500.000000 500.000000" preserveAspectRatio="xMidYMid meet"><g fill="#b11010" stroke="none" transform="translate(0.000000,500.000000) scale(0.100000,-0.100000)"><path d="M2315 4800 c-479 -35 -928 -217 -1303 -527 -352 -293 -615 -702 -738 -1151 -104 -380 -104 -824 0 -1204 107 -389 302 -724 591 -1013 354 -354 785 -572 1279 -646 196 -30 476 -30 672 0 494 74 925 292 1279 646 354 354 571 784 646 1279 30 197 30 475 0 672 -75 495 -292 925 -646 1279 -289 289 -624 484 -1013 591 -228 62 -528 91 -767 74z m353 -511 c458 -50 874 -272 1170 -624 417 -497 536 -1174 308 -1763 -56 -145 -176 -367 -235 -434 -4 -4 -566 552 -1250 1236 l-1243 1243 94 60 c354 229 754 327 1156 282z m864 -3200 c-67 -59 -289 -179 -434 -235 -946 -366 -2024 172 -2322 1158 -47 155 -66 276 -73 453 -13 362 84 704 290 1023 l60 94 1243 -1243 c684 -684 1240 -1246 1236 -1250z"></path></g></svg><svg id="icon-help" viewBox="0 0 400 400" style="enable-background:new 0 0 400 400;" xml:space="preserve"><g><path style="fill:#cccccc;" d="M199.996,0C89.719,0,0,89.72,0,200c0,110.279,89.719,200,199.996,200C310.281,400,400,310.279,400,200
7
- C400,89.72,310.281,0,199.996,0z M199.996,373.77C104.187,373.77,26.23,295.816,26.23,200
8
- c0-95.817,77.957-173.769,173.766-173.769c95.816,0,173.772,77.953,173.772,173.769
9
- C373.769,295.816,295.812,373.77,199.996,373.77z"></path><path style="fill:#000000;" d="M199.996,91.382c-35.176,0-63.789,28.616-63.789,63.793c0,7.243,5.871,13.115,13.113,13.115
10
- c7.246,0,13.117-5.873,13.117-13.115c0-20.71,16.848-37.562,37.559-37.562c20.719,0,37.566,16.852,37.566,37.562
11
- c0,20.714-16.849,37.566-37.566,37.566c-7.242,0-13.113,5.873-13.113,13.114v45.684c0,7.243,5.871,13.115,13.113,13.115
12
- s13.117-5.872,13.117-13.115v-33.938c28.905-6.064,50.68-31.746,50.68-62.427C263.793,119.998,235.176,91.382,199.996,91.382z"></path><path d="M200.004,273.738c-9.086,0-16.465,7.371-16.465,16.462s7.379,16.465,16.465,16.465c9.094,0,16.457-7.374,16.457-16.465
13
- S209.098,273.738,200.004,273.738z"></path></g></svg><svg id="icon-help2" viewBox="0 0 431.855 431.855" style="enable-background:new 0 0 431.855 431.855;" xml:space="preserve"><g><path style="fill:#aaaaaa;" d="M215.936,0C96.722,0,0.008,96.592,0.008,215.814c0,119.336,96.714,216.041,215.927,216.041
14
- c119.279,0,215.911-96.706,215.911-216.041C431.847,96.592,335.214,0,215.936,0z M231.323,335.962
15
- c-5.015,4.463-10.827,6.706-17.411,6.706c-6.812,0-12.754-2.203-17.826-6.617c-5.08-4.406-7.625-10.575-7.625-18.501
16
- c0-7.031,2.463-12.949,7.373-17.745c4.91-4.796,10.933-7.194,18.078-7.194c7.031,0,12.949,2.398,17.753,7.194
17
- c4.796,4.796,7.202,10.713,7.202,17.745C238.858,325.362,236.346,331.5,231.323,335.962z M293.856,180.934
18
- c-3.853,7.145-8.429,13.306-13.737,18.501c-5.292,5.194-14.81,13.924-28.548,26.198c-3.788,3.463-6.836,6.503-9.12,9.12
19
- c-2.284,2.626-3.991,5.023-5.105,7.202c-1.122,2.178-1.983,4.357-2.593,6.535c-0.61,2.17-1.528,5.999-2.772,11.469
20
- c-2.113,11.608-8.754,17.411-19.915,17.411c-5.804,0-10.681-1.894-14.656-5.69c-3.959-3.796-5.934-9.429-5.934-16.907
21
- c0-9.372,1.455-17.493,4.357-24.361c2.886-6.869,6.747-12.892,11.543-18.086c4.804-5.194,11.274-11.356,19.427-18.501
22
- c7.145-6.251,12.307-10.965,15.485-14.144c3.186-3.186,5.861-6.73,8.031-10.632c2.187-3.91,3.26-8.145,3.26-12.721
23
- c0-8.933-3.308-16.46-9.957-22.597c-6.641-6.137-15.209-9.21-25.703-9.21c-12.282,0-21.321,3.097-27.125,9.291
24
- c-5.804,6.194-10.705,15.314-14.729,27.369c-3.804,12.616-11.006,18.923-21.598,18.923c-6.251,0-11.526-2.203-15.826-6.609
25
- c-4.292-4.406-6.438-9.177-6.438-14.314c0-10.6,3.406-21.346,10.21-32.23c6.812-10.884,16.745-19.899,29.807-27.036
26
- c13.054-7.145,28.296-10.722,45.699-10.722c16.184,0,30.466,2.991,42.854,8.966c12.388,5.966,21.963,14.087,28.718,24.361
27
- c6.747,10.266,10.128,21.427,10.128,33.482C299.635,165.473,297.709,173.789,293.856,180.934z"></path></g></svg></defs>`,1),A=[q];function G(e,t){return c(),d("svg",E,A)}var K=m(U,[["render",G]]);const J={name:"FileItem",emits:["toggle","select"],props:{item:Object},data(){return{hover:!1,selected:!1}},inject:["wcfm"],methods:{onClick(e){this.selected=!0,this.$emit("select",this)},getWCFM(){return this.wcfm},getFullPath(){for(var e=this.$parent,t=[];e!==null&&e.$parent!==null;)e.item&&t.push(e.item.name),e=e.$parent;return t.pop(),t=t.reverse().join("/"),t=t.replace("//","/"),t},infoClick(){this.getWCFM().displayInfo(this.getFullPath())},convertClick(){this.getWCFM().onConvertClick(this.getFullPath())}}},x=e=>(C("data-v-4fb0cc48"),e=e(),k(),e),Q={key:0,class:"icon-fold"},ee=x(()=>l("use",{"xlink:href":"#icon-fold"},null,-1)),te=[ee],oe={key:1,class:"icon-unfold"},se=x(()=>l("use",{"xlink:href":"#icon-unfold"},null,-1)),ie=[se],ne=x(()=>l("use",{"xlink:href":"#icon-folder"},null,-1)),le=[ne],ae={key:2,class:"icon-file"},re=x(()=>l("use",{"xlink:href":"#icon-file"},null,-1)),ce=[re];function de(e,t,s,n,o,i){return c(),d("div",{class:$({fileitem:!0,selected:o.selected}),onMouseover:t[2]||(t[2]=a=>o.hover=!0),onMouseleave:t[3]||(t[3]=a=>o.hover=!1),onClick:t[4]||(t[4]=(...a)=>i.onClick&&i.onClick(...a))},[l("p",null,[s.item.isDir?(c(),d("span",{key:0,class:$({"fold-unfold":!0,empty:s.item.isEmpty}),onClick:t[0]||(t[0]=a=>this.$emit("toggle"))},[s.item.isOpen?(c(),d("svg",Q,te)):u("",!0),s.item.isOpen?u("",!0):(c(),d("svg",oe,ie))],2)):u("",!0),s.item.isDir?(c(),d("svg",{key:1,class:"icon-folder",onClick:t[1]||(t[1]=a=>this.$emit("toggle"))},le)):u("",!0),s.item.isDir?u("",!0):(c(),d("svg",ae,ce)),v(" "+f(s.item.nickname||s.item.name),1)])],34)}var he=m(J,[["render",de],["__scopeId","data-v-4fb0cc48"]]);const ue={name:"FileTree",components:{FileItem:he},emits:["select"],props:{item:Object},data(){return{loading:!1}},methods:{load(){var e=this;z.post("get-folder",{path:this.$refs.thefileitem.getFullPath()},function(t){e.loading=!0,e.item.children=t.children.sort(function(s,n){return s.isDir&&!n.isDir?-1:!s.isDir&&n.isDir||s.name>n.name?1:s.name<n.name?-1:0}),e.item.loaded=!0,e.loading=!1})},toggle(){this.item.isOpen=!this.item.isOpen,this.item.loaded||this.load()},onSelect(e){this.$emit("select",e)}},mounted(){let e=this.$refs.thefileitem.getFullPath();(e=="/"||e.indexOf("/")==-1)&&this.toggle()}},me={key:0},_e=l("li",null,"loading...",-1),fe=[_e],pe={key:1,class:"tree"};function ge(e,t,s,n,o,i){const a=h("FileItem"),r=h("FileTree",!0);return c(),d(b,null,[_(a,{ref:"thefileitem",item:s.item,onDblclick:i.toggle,onToggle:i.toggle,onSelect:i.onSelect},null,8,["item","onDblclick","onToggle","onSelect"]),o.loading?(c(),d("ul",me,fe)):u("",!0),s.item.children!==void 0&&s.item.isOpen?(c(),d("ul",pe,[(c(!0),d(b,null,M(s.item.children,p=>(c(),d("li",null,[_(r,{item:p,onSelect:i.onSelect},null,8,["item","onSelect"])]))),256))])):u("",!0)],64)}var ve=m(ue,[["render",ge]]);const ye={name:"Files",components:{FileTree:ve},emits:["select"],props:{item:Object,statusText:String},methods:{onSelect(e){this.selectedItem&&(this.selectedItem.selected=!1),this.selectedItem=e,this.$emit("select",this.selectedItem.getFullPath(),this.selectedItem.item.isDir)}},data(){return{selected:null}}},ze={key:1};function be(e,t,s,n,o,i){const a=h("FileTree");return c(),d(b,null,[s.item?(c(),y(a,{key:0,item:s.item,onSelect:i.onSelect},null,8,["item","onSelect"])):u("",!0),s.item?u("",!0):(c(),d("div",ze,f(s.statusText),1))],64)}var we=m(ye,[["render",be]]);const xe={name:"Modal",emits:["close"],props:{title:{type:String},closeButtonText:{type:String},alignment:{type:String},width:{type:[Number,String],default:"95%"},height:{type:[Number,String],default:"95%"},maxheight:{type:[Number,String],default:"700px"}},computed:{containerStyle(){let e={width:this.width,height:this.height,"max-height":this.maxheight};return this.alignment=="center"&&(e.margin="0px auto"),this.alignment=="right"&&(e.position="absolute",e.right="10px"),e}},methods:{onCloseClick(){this.$emit("close")}}},$e={class:"modal-mask"},Ce={class:"modal-wrapper"},ke={class:"title"},Se={class:"modal-body"},Ve={class:"content"},Ie=v(" default body "),Fe={class:"close-button-with-text"};function Me(e,t,s,n,o,i){return c(),d("div",$e,[l("div",Ce,[l("div",{class:"modal-container",style:R(i.containerStyle)},[l("a",{class:"close-button",onClick:t[0]||(t[0]=(...a)=>i.onCloseClick&&i.onCloseClick(...a))},"X"),l("div",ke,f(s.title),1),l("div",Se,[l("div",Ve,[P(e.$slots,"default",{},()=>[Ie]),l("div",Fe,[l("button",{onClick:t[1]||(t[1]=(...a)=>i.onCloseClick&&i.onCloseClick(...a))},f(s.closeButtonText),1)])])])],4)])])}var Re=m(xe,[["render",Me]]);const Ye={name:"ZoomSlider",components:{Slider:H},emits:["update:zoom"],props:{zoom:{type:Number,default:1}},watch:{exp(e,t){this.$emit("update:zoom",2**e)},zoom(e,t){this.exp=Math.log2(e)}},methods:{sliderFormat(e){return Math.round(2**e*100)+"%"}},mounted(){},data(){return{exp:0}}},Xe={class:"zoom-slider"};function Oe(e,t,s,n,o,i){const a=h("Slider");return c(),d("div",Xe,[_(a,{modelValue:o.exp,"onUpdate:modelValue":t[0]||(t[0]=r=>o.exp=r),min:-4,max:4,width:100,step:-1,format:i.sliderFormat,tooltipPosition:"bottom",orientation:"horizontal"},null,8,["modelValue","format"])])}var De=m(Ye,[["render",Oe]]);const Te={name:"ImageViewport",components:{VueZoomer:Y,ZoomSlider:De},emits:["update:zoom","update:translateX","update:translateY","load","resize"],props:{src:{type:String},height:{type:Number,default:500},zoom:{type:Number,default:1},scaleZoomRatio:{type:Number},translateX:{type:Number,default:1},translateY:{type:Number,default:1}},data(){return{ratio:1,ro:null}},watch:{height(e,t){var s;((s=this.$refs)==null?void 0:s.zoomer)&&(this.$refs.zoomer.onWindowResize(),this.$refs.zoomer.refreshContainerPos())},scaleZoomRatio(e){var t;((t=this.$refs)==null?void 0:t.zoomer)&&(this.$refs.zoomer.onWindowResize(),this.$refs.zoomer.refreshContainerPos()),this.$refs.zoomer.scale=this.zoom*this.scaleZoomRatio},zoom(e,t){this.isImageReady(),this.$refs.zoomer.scale=e*this.scaleZoomRatio},translateX(e,t){this.$refs.zoomer.translateX!=e&&(this.$refs.zoomer.translateX=e)},translateY(e,t){this.$refs.zoomer.translateY!=e&&(this.$refs.zoomer.translateY=e)}},methods:{getGoodContainerHeight(){var e,t,s;if((t=(e=this.$refs)==null?void 0:e.theimg)==null?void 0:t.naturalWidth){let n=this.$refs.theimg.naturalWidth/this.$refs.theimg.naturalHeight,i=((s=this.$refs.root)==null?void 0:s.offsetWidth)/n;return i>300&&(i=300),i}return 300},updateContainerHeight(){},isImageReady(){var e,t,s;return!(!((t=(e=this.$refs)==null?void 0:e.theimg)==null?void 0:t.naturalWidth)||!((s=this.$refs.root)==null?void 0:s.offsetWidth))},calcScaleZoomRatio(){var n,o;if(!this.isImageReady())return 1;let e=this.$refs.theimg.naturalWidth/((n=this.$refs.root)==null?void 0:n.offsetWidth),t=this.$refs.theimg.naturalHeight/((o=this.$refs.root)==null?void 0:o.offsetHeight),s=Math.max(e,t);return isNaN(s)?1:s},updateRatio(){},updateScale(){this.zoom&&(this.$refs.zoomer.scale=this.zoom*this.scaleZoomRatio)},zoomToFit(){},onImgLoad(){var e,t;((t=(e=this.$refs)==null?void 0:e.theimg)==null?void 0:t.naturalWidth)&&this.$emit("load")},onResize(){this.$emit("resize")},onDoubleTap(){console.log("double tab - zoom to 100%"),this.$emit("update:zoom",1),this.$emit("update:translateX",0),this.$emit("update:translateY",0)}},mounted(){window.ResizeObserver&&(this.ro=new ResizeObserver(this.onResize).observe(this.$refs.root)),this.$refs.zoomer.tapDetector.onDoubleTap(this.onDoubleTap),this.$watch("$refs.zoomer.scale",(e,t)=>{this.isImageReady(),this.$emit("update:zoom",e/this.scaleZoomRatio)}),this.$watch("$refs.zoomer.translateX",(e,t)=>{this.$emit("update:translateX",e)}),this.$watch("$refs.zoomer.translateY",(e,t)=>{this.$emit("update:translateY",e)})},beforeDestroy(){window.ResizeObserver&&this.ro.unobserve(this.$refs.zoomer)}},We={ref:"root",class:"image-viewport"},Ne=["src"],Ze={class:"zoom-info"};function Pe(e,t,s,n,o,i){const a=h("v-zoomer");return c(),d("div",We,[_(a,{ref:"zoomer",class:"zoomer",minScale:.1,maxScale:8,onResize:i.onResize,doubleClickToZoom:!1,style:R({height:s.height+"px"}),pivot:"cursor",limitTranslation:!1,lockPanOnNoScale:!1},{default:w(()=>[l("img",{ref:"theimg",src:s.src,onLoad:t[0]||(t[0]=(...r)=>i.onImgLoad&&i.onImgLoad(...r))},null,40,Ne)]),_:1},8,["minScale","onResize","style"]),l("div",Ze," zoom: "+f(Math.round(s.zoom*100))+"% ",1)],512)}var He=m(Te,[["render",Pe]]);const Le={name:"Variant",components:{ImageViewport:He},emits:["select","update:zoom","update:translateX","update:translateY","load","resize"],props:{title:{type:String},info:{type:Object},url:{type:String,default:""},height:{type:Number},zoom:{type:Number},scaleZoomRatio:{type:Number},translateX:{type:Number},translateY:{type:Number},variantIndex:{type:Number}},computed:{imageUrl:function(){var e;return(e=this.info)==null?void 0:e.url},filesize:function(){var t;if(!((t=this.info)==null?void 0:t.size))return"";let e=this.info.size;return e<1024?e+" bytes":(e/=1024,e<1024?Math.round(e*10)/10+" kb":(e/=1024,Math.round(e*10)/10+" MB"))}},methods:{onVariantSelect(){this.$emit("select",this.variantIndex)},onLoad(){this.$emit("load")},zoomToFit(){this.$refs.theport.zoomToFit()}},mounted(){this.$watch("$refs.theport.zoom",(e,t)=>{this.$emit("update:zoom",e)}),this.$watch("$refs.theport.translateX",(e,t)=>{this.$emit("update:translateX",e)}),this.$watch("$refs.theport.translateY",(e,t)=>{this.$emit("update:translateY",e)})},data(){return{}}},je={class:"variant"},Be={class:"header"},Ue={class:"title"},Ee={class:"size"};function qe(e,t,s,n,o,i){const a=h("ImageViewport");return c(),d("div",je,[l("div",Be,[l("div",Ue,f(s.title),1),l("div",Ee,f(i.filesize),1)]),_(a,{ref:"theport",src:i.imageUrl,height:s.height,zoom:s.zoom,"onUpdate:zoom":t[0]||(t[0]=r=>s.zoom=r),scaleZoomRatio:s.scaleZoomRatio,translateX:s.translateX,"onUpdate:translateX":t[1]||(t[1]=r=>s.translateX=r),translateY:s.translateY,"onUpdate:translateY":t[2]||(t[2]=r=>s.translateY=r),onLoad:i.onLoad,onResize:t[3]||(t[3]=r=>this.$emit("resize"))},null,8,["src","height","zoom","scaleZoomRatio","translateX","translateY","onLoad"])])}var O=m(Le,[["render",qe],["__scopeId","data-v-0372e854"]]);const Ae={name:"Variants",components:{Variant:O},emits:["update:zoom","update:translateX","update:translateY"],props:{file:{type:Object},viewport:{type:Object},height:{type:Number},zoom:{type:Number,default:1},translateX:{type:Number,default:0},translateY:{type:Number,default:0}},watch:{file(e,t){}},methods:{onZoomChange(e){this.$emit("update:zoom",e)},onTranslateXChange(e){this.$emit("update:translateX",e)},onTranslateYChange(e){this.$emit("update:translateY",e)},sliderFormat(e){return Math.round(e*100)+"%"},changeImage(){this.imageUrl=="http://localhost:3000/src/assets/dummy.jpg"?this.imageUrl="http://localhost:3000/src/assets/dummy2.jpg":this.imageUrl="http://localhost:3000/src/assets/dummy.jpg",this.selectedVariant=-1},onVariantSelect(e){this.selectedVariant=e}},mounted(){this.$watch("$refs.variants.zoom",(e,t)=>{})},data(){var e="http://localhost:3000/src/assets/200x100.jpg";return{imageUrl:"",selectedVariant:-1,variants:[{title:"Existing conversion",size:732,url:e},{title:"Lossy, q:20",size:35e5,url:e}]}}},D=e=>(C("data-v-25a3327e"),e=e(),k(),e),Ge={class:"variants-component"},Ke=D(()=>l("br",null,null,-1)),Je=D(()=>l("br",null,null,-1)),Qe={class:"variants"};function et(e,t,s,n,o,i){const a=h("Variant");return c(),d("div",Ge,[v(" File: "+f(s.file)+" ",1),l("button",{onClick:t[0]||(t[0]=r=>i.changeImage())},"Change image"),Ke,Je,l("div",Qe,[(c(!0),d(b,null,M(o.variants,(r,p)=>(c(),y(a,{title:r.title,info:r,variantIndex:p,class:$({selected:p==o.selectedVariant}),height:s.height,zoom:s.zoom,"onUpdate:zoom":[t[1]||(t[1]=g=>s.zoom=g),i.onZoomChange],translateX:s.translateX,"onUpdate:translateX":[t[2]||(t[2]=g=>s.translateX=g),i.onTranslateXChange],translateY:s.translateY,"onUpdate:translateY":[t[3]||(t[3]=g=>s.translateY=g),i.onTranslateYChange],onSelect:i.onVariantSelect},null,8,["title","info","variantIndex","class","height","zoom","translateX","translateY","onSelect","onUpdate:zoom","onUpdate:translateX","onUpdate:translateY"]))),256))])])}var tt=m(Ae,[["render",et],["__scopeId","data-v-25a3327e"]]);const ot={name:"FileProperties",components:{Variant:O,Variants:tt},props:{file:{type:Object,default:{}}},watch:{file(e,t){e.isDir||this.load(e.path)}},methods:{onVariantSelect(e){this.selectedVariant=e},onOriginalLoad(){if(this.updateHeight(),this.$refs.original.$refs.theport.calcScaleZoomRatio()>1){let t=this.$refs.original.$refs.theport,s=t.$refs.theimg,n=t.$refs.root,o=s.naturalWidth,i=s.naturalHeight,a=n.offsetWidth,p=this.height/i,g=a/o;this.zoom=Math.min(p,g)}else this.zoom=1;this.translateX=0,this.translateY=0},onOriginalResize(){this.updateHeight()},updateHeight(){this.$refs.original&&(this.height=this.$refs.original.$refs.theport.getGoodContainerHeight(),this.scaleZoomRatio=this.$refs.original.$refs.theport.calcScaleZoomRatio())},reset(){this.originalInfo=null,this.convertedInfo=null,this.errorMsg=""},load(e){let t=this;t.reset(),t.loading=!0,z.post("info",{path:e},function(s){s.success||(t.errorMsg=s.data),t.loading=!1,t.originalInfo=s.original,s.converted&&(t.convertedInfo=s.converted)})}},mounted(){this.file&&this.load(this.file.path)},data(){return{zoom:1,scaleZoomRatio:1,translateX:0,translateY:0,height:100,loading:!1,errorMsg:"",originalInfo:null,convertedInfo:null}}},T=e=>(C("data-v-32d950b3"),e=e(),k(),e),st={class:"file-properties"},it={class:"path"},nt=v(" Path: "),lt={class:"path"},at={key:0,class:"error"},rt=T(()=>l("p",null," Above, you see the original image. If it has been converted, you also see the converted image (provided that your browser supports webp). ",-1)),ct=T(()=>l("p",null," You can zoom in on the image, ie using scroll wheel. Both images will zoom, allowing you to compare the quality. Double-click the image to set zoom to 100%. You can also drag the image. ",-1));function dt(e,t,s,n,o,i){const a=h("Variant");return c(),d("div",st,[l("div",it,[nt,l("span",lt,f(s.file.path),1)]),o.errorMsg?(c(),d("div",at,f(o.errorMsg),1)):u("",!0),S(l("div",null,"Getting info...",512),[[V,o.loading]]),S(_(a,{ref:"original",title:"Original",info:o.originalInfo,height:o.height,zoom:o.zoom,"onUpdate:zoom":t[0]||(t[0]=r=>o.zoom=r),scaleZoomRatio:o.scaleZoomRatio,translateX:o.translateX,"onUpdate:translateX":t[1]||(t[1]=r=>o.translateX=r),translateY:o.translateY,"onUpdate:translateY":t[2]||(t[2]=r=>o.translateY=r),onLoad:i.onOriginalLoad,onResize:i.onOriginalResize},null,8,["info","height","zoom","scaleZoomRatio","translateX","translateY","onLoad","onResize"]),[[V,o.originalInfo]]),S(_(a,{title:"Existing conversion",info:o.convertedInfo,height:o.height,zoom:o.zoom,"onUpdate:zoom":t[3]||(t[3]=r=>o.zoom=r),scaleZoomRatio:o.scaleZoomRatio,translateX:o.translateX,"onUpdate:translateX":t[4]||(t[4]=r=>o.translateX=r),translateY:o.translateY,"onUpdate:translateY":t[5]||(t[5]=r=>o.translateY=r)},null,8,["info","height","zoom","scaleZoomRatio","translateX","translateY"]),[[V,o.convertedInfo]]),rt,ct])}var ht=m(ot,[["render",dt],["__scopeId","data-v-32d950b3"]]);const ut={name:"FolderProperties",components:{},props:{file:{type:Object,default:{}}},watch:{file(e,t){}}},mt={class:"folder-properties"},_t={class:"path"},ft=v(" Path: "),pt={class:"path"},gt=l("p",null," You cannot do anything on folders yet. Browse to an image... ",-1);function vt(e,t,s,n,o,i){return c(),d("div",mt,[l("div",_t,[ft,l("span",pt,f(s.file.path),1)]),gt])}var yt=m(ut,[["render",vt]]);const zt={name:"Welcome"},bt={class:"welcome"},wt=F('<div class="headline"><div>Welcome to</div><h3>WebP Convert file manager 0.2</h3></div><p> At current stage you can browse the image files and compare the original vs the converted file.<br> To open a folder, click the &quot;+&quot; sign next to the folder name or double click the folder name </p><p><h4>Whats new?</h4><i>Changes in 0.2:</i><ul><li>Tree branches are now loaded on need basis (loaded the complete tree in one go was causing timeout on sites with huge amounts of images)</li></ul><i>Changes in 0.1:</i><ul><li>Everything is new! This is the first tentative pre-alpha work-in-progress release.</li></ul></p><p><h4>Whats planned ahead?</h4> Next thing is of course to enable you to trigger conversions. To support development, you can <a href="https://ko-fi.com/rosell" target="_blank">buy me a cup of coffee</a></p>',4),xt=[wt];function $t(e,t,s,n,o,i){return c(),d("div",bt,xt)}var Ct=m(zt,[["render",$t]]);const kt={name:"WCFM",components:{SVGs:K,FileProperties:ht,FolderProperties:yt,Modal:Re,Files:we,Splitpanes:X.exports.Splitpanes,Pane:X.exports.Pane,Welcome:Ct},methods:{onConvertClick(e){var n,o;let t=(o=(n=this.$refs.convertOptions)==null?void 0:n.general)==null?void 0:o.data,s={path:e,convertOptions:t};console.log(s),z.post("convert",s,function(i){console.log("convert response:",i)})},onConvertCloseClick(){console.log("CLRCL"),this.showConvertOptions=!1},onFileSelect(e,t){this.file={path:e,isDir:t}},displayInfo(e){var t=this;z.post("info",{path:e},function(s){t.selectedInfo=s})}},mounted(){var e=this;z.post("get-folder",{path:""},function(t){e.item=t.children[0]})},data(){return{file:null,selectedItem:null,item:null,treeStatusText:"loading file tree...",selectedInfo:{},showConvertOptions:!1}},provide(){return{wcfm:this}}},St={class:"wcfm",style:{overflow:"hidden"}},Vt={class:"pane-content"},It={key:0,class:"pane-content"};function Ft(e,t,s,n,o,i){const a=h("SVGs"),r=h("Files"),p=h("pane"),g=h("FileProperties"),W=h("FolderProperties"),N=h("Welcome"),Z=h("splitpanes");return c(),d("div",St,[_(a),_(Z,{class:"default-theme",style:{position:"absolute",top:"0",left:"0"}},{default:w(()=>[_(p,{size:"30"},{default:w(()=>[l("div",Vt,[l("div",null,[_(r,{item:o.item,statusText:o.treeStatusText,onSelect:i.onFileSelect},null,8,["item","statusText","onSelect"])])])]),_:1}),_(p,{size:"70",style:{"overflow-y":"auto"}},{default:w(()=>[o.file?(c(),d("div",It,[o.file.isDir?u("",!0):(c(),y(g,{key:0,file:o.file},null,8,["file"])),o.file.isDir?(c(),y(W,{key:1,file:o.file},null,8,["file"])):u("",!0)])):u("",!0),o.file?u("",!0):(c(),y(N,{key:1}))]),_:1})]),_:1})])}var Mt=m(kt,[["render",Ft]]);const I=L(Mt);I.use(Y);I.use(j,{defaultHtml:!1});window.wcfmoptions||(window.wcfmoptions={},window.wcfmoptions.poster=function(e,t,s,n){switch(e){case"get-folder":switch(t.path){case"":var o={children:[{name:"/",isDir:!0,nickname:"root"}]};break;case"/":var o={children:[{name:"empty-folder",isDir:!0,isEmpty:!0},{name:"file",isDir:!1,isConverted:!0},{name:"aaa",isDir:!1,isConverted:!0},{name:"test-folder",isDir:!0},{name:"file2",isDir:!1,isConverted:!1}]};break;case"/empty-folder":var o={children:[]};break;case"/test-folder":var o={children:[{name:"banana",isDir:!1},{name:"subfolder",isDir:!0},{name:"apple",isDir:!1}]};break;case"/test-folder/subfolder":var o={children:[{name:"file2",isDir:!1},{name:"file1",isDir:!1}]};break;default:n();return}break;case"conversion-settings":var o={systemStatus:{converterRequirements:{gd:{extensionLoaded:!1,compiledWithWebP:!0}}}};break;case"info":if(t.path=="root/file2")var o={original:{filename:"file.png",size:100,url:"http://localhost:3000/src/assets/200x100.jpg"},converted:{filename:"file.png.webp",size:70,url:"http://localhost:3000/src/assets/200x100.jpg"},log:"blah blah blah"};else if(t.path=="root/file")var o={original:{filename:"file.png",size:100,url:"http://localhost:3000/src/assets/dummy2.jpg"},log:"blah blah blah"};else var o={original:{filename:"file.png",size:100,url:"http://localhost:3000/src/assets/dummy.jpg"},converted:{filename:"file.png.webp",size:70,url:"http://localhost:3000/src/assets/dummy.jpg"},log:"blah blah blah"};break;case"convert":var o={success:!1,msg:"Image type could not be detected"};break;default:var o="ok";break}s(o)});I.mount("#webpconvert-filemanager");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/composer/autoload_classmap.php CHANGED
@@ -144,6 +144,7 @@ return array(
144
  'ImageMimeTypeGuesser\\Detectors\\Stack' => $vendorDir . '/rosell-dk/image-mime-type-guesser/src/Detectors/Stack.php',
145
  'ImageMimeTypeGuesser\\GuessFromExtension' => $vendorDir . '/rosell-dk/image-mime-type-guesser/src/GuessFromExtension.php',
146
  'ImageMimeTypeGuesser\\ImageMimeTypeGuesser' => $vendorDir . '/rosell-dk/image-mime-type-guesser/src/ImageMimeTypeGuesser.php',
 
147
  'WebPConvertCloudService\\AccessCheck' => $vendorDir . '/rosell-dk/webp-convert-cloud-service/src/AccessCheck.php',
148
  'WebPConvertCloudService\\Serve' => $vendorDir . '/rosell-dk/webp-convert-cloud-service/src/Serve.php',
149
  'WebPConvertCloudService\\WebPConvertCloudService' => $vendorDir . '/rosell-dk/webp-convert-cloud-service/src/WebPConvertCloudService.php',
144
  'ImageMimeTypeGuesser\\Detectors\\Stack' => $vendorDir . '/rosell-dk/image-mime-type-guesser/src/Detectors/Stack.php',
145
  'ImageMimeTypeGuesser\\GuessFromExtension' => $vendorDir . '/rosell-dk/image-mime-type-guesser/src/GuessFromExtension.php',
146
  'ImageMimeTypeGuesser\\ImageMimeTypeGuesser' => $vendorDir . '/rosell-dk/image-mime-type-guesser/src/ImageMimeTypeGuesser.php',
147
+ 'KubAT\\PhpSimple\\HtmlDomParser' => $vendorDir . '/kub-at/php-simple-html-dom-parser/src/KubAT/PhpSimple/HtmlDomParser.php',
148
  'WebPConvertCloudService\\AccessCheck' => $vendorDir . '/rosell-dk/webp-convert-cloud-service/src/AccessCheck.php',
149
  'WebPConvertCloudService\\Serve' => $vendorDir . '/rosell-dk/webp-convert-cloud-service/src/Serve.php',
150
  'WebPConvertCloudService\\WebPConvertCloudService' => $vendorDir . '/rosell-dk/webp-convert-cloud-service/src/WebPConvertCloudService.php',
vendor/composer/autoload_namespaces.php CHANGED
@@ -6,4 +6,5 @@ $vendorDir = dirname(dirname(__FILE__));
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
 
9
  );
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
9
+ 'KubAT\\PhpSimple\\HtmlDomParser' => array($vendorDir . '/kub-at/php-simple-html-dom-parser/src'),
10
  );
vendor/composer/autoload_static.php CHANGED
@@ -57,6 +57,16 @@ class ComposerStaticInit16597e36dd1bfcd787ed5a8e6d908243
57
  ),
58
  );
59
 
 
 
 
 
 
 
 
 
 
 
60
  public static $classMap = array (
61
  'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
62
  'Composer\\Installers\\AglInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/AglInstaller.php',
@@ -196,6 +206,7 @@ class ComposerStaticInit16597e36dd1bfcd787ed5a8e6d908243
196
  'ImageMimeTypeGuesser\\Detectors\\Stack' => __DIR__ . '/..' . '/rosell-dk/image-mime-type-guesser/src/Detectors/Stack.php',
197
  'ImageMimeTypeGuesser\\GuessFromExtension' => __DIR__ . '/..' . '/rosell-dk/image-mime-type-guesser/src/GuessFromExtension.php',
198
  'ImageMimeTypeGuesser\\ImageMimeTypeGuesser' => __DIR__ . '/..' . '/rosell-dk/image-mime-type-guesser/src/ImageMimeTypeGuesser.php',
 
199
  'WebPConvertCloudService\\AccessCheck' => __DIR__ . '/..' . '/rosell-dk/webp-convert-cloud-service/src/AccessCheck.php',
200
  'WebPConvertCloudService\\Serve' => __DIR__ . '/..' . '/rosell-dk/webp-convert-cloud-service/src/Serve.php',
201
  'WebPConvertCloudService\\WebPConvertCloudService' => __DIR__ . '/..' . '/rosell-dk/webp-convert-cloud-service/src/WebPConvertCloudService.php',
@@ -280,6 +291,7 @@ class ComposerStaticInit16597e36dd1bfcd787ed5a8e6d908243
280
  return \Closure::bind(function () use ($loader) {
281
  $loader->prefixLengthsPsr4 = ComposerStaticInit16597e36dd1bfcd787ed5a8e6d908243::$prefixLengthsPsr4;
282
  $loader->prefixDirsPsr4 = ComposerStaticInit16597e36dd1bfcd787ed5a8e6d908243::$prefixDirsPsr4;
 
283
  $loader->classMap = ComposerStaticInit16597e36dd1bfcd787ed5a8e6d908243::$classMap;
284
 
285
  }, null, ClassLoader::class);
57
  ),
58
  );
59
 
60
+ public static $prefixesPsr0 = array (
61
+ 'K' =>
62
+ array (
63
+ 'KubAT\\PhpSimple\\HtmlDomParser' =>
64
+ array (
65
+ 0 => __DIR__ . '/..' . '/kub-at/php-simple-html-dom-parser/src',
66
+ ),
67
+ ),
68
+ );
69
+
70
  public static $classMap = array (
71
  'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
72
  'Composer\\Installers\\AglInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/AglInstaller.php',
206
  'ImageMimeTypeGuesser\\Detectors\\Stack' => __DIR__ . '/..' . '/rosell-dk/image-mime-type-guesser/src/Detectors/Stack.php',
207
  'ImageMimeTypeGuesser\\GuessFromExtension' => __DIR__ . '/..' . '/rosell-dk/image-mime-type-guesser/src/GuessFromExtension.php',
208
  'ImageMimeTypeGuesser\\ImageMimeTypeGuesser' => __DIR__ . '/..' . '/rosell-dk/image-mime-type-guesser/src/ImageMimeTypeGuesser.php',
209
+ 'KubAT\\PhpSimple\\HtmlDomParser' => __DIR__ . '/..' . '/kub-at/php-simple-html-dom-parser/src/KubAT/PhpSimple/HtmlDomParser.php',
210
  'WebPConvertCloudService\\AccessCheck' => __DIR__ . '/..' . '/rosell-dk/webp-convert-cloud-service/src/AccessCheck.php',
211
  'WebPConvertCloudService\\Serve' => __DIR__ . '/..' . '/rosell-dk/webp-convert-cloud-service/src/Serve.php',
212
  'WebPConvertCloudService\\WebPConvertCloudService' => __DIR__ . '/..' . '/rosell-dk/webp-convert-cloud-service/src/WebPConvertCloudService.php',
291
  return \Closure::bind(function () use ($loader) {
292
  $loader->prefixLengthsPsr4 = ComposerStaticInit16597e36dd1bfcd787ed5a8e6d908243::$prefixLengthsPsr4;
293
  $loader->prefixDirsPsr4 = ComposerStaticInit16597e36dd1bfcd787ed5a8e6d908243::$prefixDirsPsr4;
294
+ $loader->prefixesPsr0 = ComposerStaticInit16597e36dd1bfcd787ed5a8e6d908243::$prefixesPsr0;
295
  $loader->classMap = ComposerStaticInit16597e36dd1bfcd787ed5a8e6d908243::$classMap;
296
 
297
  }, null, ClassLoader::class);
vendor/composer/installed.json CHANGED
@@ -154,27 +154,83 @@
154
  ],
155
  "install-path": "./installers"
156
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
  {
158
  "name": "rosell-dk/dom-util-for-webp",
159
- "version": "0.4.2",
160
- "version_normalized": "0.4.2.0",
161
  "source": {
162
  "type": "git",
163
  "url": "https://github.com/rosell-dk/dom-util-for-webp.git",
164
- "reference": "f33515fbb90067cb982dc3109d7193f27ab97619"
165
  },
166
  "dist": {
167
  "type": "zip",
168
- "url": "https://api.github.com/repos/rosell-dk/dom-util-for-webp/zipball/f33515fbb90067cb982dc3109d7193f27ab97619",
169
- "reference": "f33515fbb90067cb982dc3109d7193f27ab97619",
170
  "shasum": ""
171
  },
 
 
 
172
  "require-dev": {
173
  "friendsofphp/php-cs-fixer": "^2.11",
174
  "phpunit/phpunit": "^9.3",
175
  "squizlabs/php_codesniffer": "3.*"
176
  },
177
- "time": "2021-11-04T11:13:34+00:00",
178
  "type": "library",
179
  "extra": {
180
  "scripts-descriptions": {
@@ -212,7 +268,7 @@
212
  ],
213
  "support": {
214
  "issues": "https://github.com/rosell-dk/dom-util-for-webp/issues",
215
- "source": "https://github.com/rosell-dk/dom-util-for-webp/tree/0.4.2"
216
  },
217
  "funding": [
218
  {
154
  ],
155
  "install-path": "./installers"
156
  },
157
+ {
158
+ "name": "kub-at/php-simple-html-dom-parser",
159
+ "version": "1.9.1",
160
+ "version_normalized": "1.9.1.0",
161
+ "source": {
162
+ "type": "git",
163
+ "url": "https://github.com/Kub-AT/php-simple-html-dom-parser.git",
164
+ "reference": "ff22f98bfd9235115c128059076f3eb740d66913"
165
+ },
166
+ "dist": {
167
+ "type": "zip",
168
+ "url": "https://api.github.com/repos/Kub-AT/php-simple-html-dom-parser/zipball/ff22f98bfd9235115c128059076f3eb740d66913",
169
+ "reference": "ff22f98bfd9235115c128059076f3eb740d66913",
170
+ "shasum": ""
171
+ },
172
+ "require": {
173
+ "php": ">=5.3.2"
174
+ },
175
+ "time": "2019-10-25T12:34:43+00:00",
176
+ "type": "library",
177
+ "installation-source": "dist",
178
+ "autoload": {
179
+ "psr-0": {
180
+ "KubAT\\PhpSimple\\HtmlDomParser": "src/"
181
+ }
182
+ },
183
+ "notification-url": "https://packagist.org/downloads/",
184
+ "license": [
185
+ "MIT"
186
+ ],
187
+ "authors": [
188
+ {
189
+ "name": "S.C. Chen",
190
+ "email": "me578022@gmail.com"
191
+ },
192
+ {
193
+ "name": "Jakub Stawowy",
194
+ "email": "Kub-AT@users.noreply.github.com"
195
+ }
196
+ ],
197
+ "description": "PHP Simple HTML DOM Parser with namespace and PHP 7.3 compatible",
198
+ "homepage": "http://simplehtmldom.sourceforge.net/",
199
+ "keywords": [
200
+ "Simple",
201
+ "dom",
202
+ "html"
203
+ ],
204
+ "support": {
205
+ "issues": "https://github.com/Kub-AT/php-simple-html-dom-parser/issues",
206
+ "source": "https://github.com/Kub-AT/php-simple-html-dom-parser/tree/master"
207
+ },
208
+ "install-path": "../kub-at/php-simple-html-dom-parser"
209
+ },
210
  {
211
  "name": "rosell-dk/dom-util-for-webp",
212
+ "version": "0.5.0",
213
+ "version_normalized": "0.5.0.0",
214
  "source": {
215
  "type": "git",
216
  "url": "https://github.com/rosell-dk/dom-util-for-webp.git",
217
+ "reference": "d2554c79a0e6ffc710c2c0d646e217a9ac76dcaf"
218
  },
219
  "dist": {
220
  "type": "zip",
221
+ "url": "https://api.github.com/repos/rosell-dk/dom-util-for-webp/zipball/d2554c79a0e6ffc710c2c0d646e217a9ac76dcaf",
222
+ "reference": "d2554c79a0e6ffc710c2c0d646e217a9ac76dcaf",
223
  "shasum": ""
224
  },
225
+ "require": {
226
+ "kub-at/php-simple-html-dom-parser": "^1.9"
227
+ },
228
  "require-dev": {
229
  "friendsofphp/php-cs-fixer": "^2.11",
230
  "phpunit/phpunit": "^9.3",
231
  "squizlabs/php_codesniffer": "3.*"
232
  },
233
+ "time": "2021-11-10T08:51:27+00:00",
234
  "type": "library",
235
  "extra": {
236
  "scripts-descriptions": {
268
  ],
269
  "support": {
270
  "issues": "https://github.com/rosell-dk/dom-util-for-webp/issues",
271
+ "source": "https://github.com/rosell-dk/dom-util-for-webp/tree/0.5.0"
272
  },
273
  "funding": [
274
  {
vendor/composer/installed.php CHANGED
@@ -5,7 +5,7 @@
5
  'type' => 'wordpress-plugin',
6
  'install_path' => __DIR__ . '/../../',
7
  'aliases' => array(),
8
- 'reference' => 'f5035d6408254d4070e9edfb7b2b6348753d4e83',
9
  'name' => 'rosell-dk/webp-express',
10
  'dev' => true,
11
  ),
@@ -19,13 +19,22 @@
19
  'reference' => 'd20a64ed3c94748397ff5973488761b22f6d3f19',
20
  'dev_requirement' => false,
21
  ),
 
 
 
 
 
 
 
 
 
22
  'rosell-dk/dom-util-for-webp' => array(
23
- 'pretty_version' => '0.4.2',
24
- 'version' => '0.4.2.0',
25
  'type' => 'library',
26
  'install_path' => __DIR__ . '/../rosell-dk/dom-util-for-webp',
27
  'aliases' => array(),
28
- 'reference' => 'f33515fbb90067cb982dc3109d7193f27ab97619',
29
  'dev_requirement' => false,
30
  ),
31
  'rosell-dk/htaccess-capability-tester' => array(
@@ -70,7 +79,7 @@
70
  'type' => 'wordpress-plugin',
71
  'install_path' => __DIR__ . '/../../',
72
  'aliases' => array(),
73
- 'reference' => 'f5035d6408254d4070e9edfb7b2b6348753d4e83',
74
  'dev_requirement' => false,
75
  ),
76
  'roundcube/plugin-installer' => array(
5
  'type' => 'wordpress-plugin',
6
  'install_path' => __DIR__ . '/../../',
7
  'aliases' => array(),
8
+ 'reference' => '8164dbbb89311a20d4cf5dcdf33cfac7c788cfce',
9
  'name' => 'rosell-dk/webp-express',
10
  'dev' => true,
11
  ),
19
  'reference' => 'd20a64ed3c94748397ff5973488761b22f6d3f19',
20
  'dev_requirement' => false,
21
  ),
22
+ 'kub-at/php-simple-html-dom-parser' => array(
23
+ 'pretty_version' => '1.9.1',
24
+ 'version' => '1.9.1.0',
25
+ 'type' => 'library',
26
+ 'install_path' => __DIR__ . '/../kub-at/php-simple-html-dom-parser',
27
+ 'aliases' => array(),
28
+ 'reference' => 'ff22f98bfd9235115c128059076f3eb740d66913',
29
+ 'dev_requirement' => false,
30
+ ),
31
  'rosell-dk/dom-util-for-webp' => array(
32
+ 'pretty_version' => '0.5.0',
33
+ 'version' => '0.5.0.0',
34
  'type' => 'library',
35
  'install_path' => __DIR__ . '/../rosell-dk/dom-util-for-webp',
36
  'aliases' => array(),
37
+ 'reference' => 'd2554c79a0e6ffc710c2c0d646e217a9ac76dcaf',
38
  'dev_requirement' => false,
39
  ),
40
  'rosell-dk/htaccess-capability-tester' => array(
79
  'type' => 'wordpress-plugin',
80
  'install_path' => __DIR__ . '/../../',
81
  'aliases' => array(),
82
+ 'reference' => '8164dbbb89311a20d4cf5dcdf33cfac7c788cfce',
83
  'dev_requirement' => false,
84
  ),
85
  'roundcube/plugin-installer' => array(
vendor/kub-at/php-simple-html-dom-parser/CONTRIBUTING.md ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ # Contributing
2
+
3
+ I'm not the maintainer of the PHP Simple HTML DOM Parser project (https://sourceforge.net/projects/simplehtmldom/)
vendor/kub-at/php-simple-html-dom-parser/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2019 Jakub Stawowy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
vendor/kub-at/php-simple-html-dom-parser/README.md ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ php-simple-html-dom-parser
2
+ ==========================
3
+
4
+ Version 1.9.1 - PHP 7.3 compatible
5
+ PHP Simple HTML DOM Parser changelog: https://sourceforge.net/projects/simplehtmldom/files/simplehtmldom/1.9.1/
6
+
7
+
8
+ Install
9
+ -------
10
+
11
+ ```
12
+ composer require kub-at/php-simple-html-dom-parser
13
+ ```
14
+
15
+ Usage
16
+ -----
17
+
18
+ ```php
19
+ use KubAT\PhpSimple\HtmlDomParser;
20
+
21
+ ...
22
+ $dom = HtmlDomParser::str_get_html( $str );
23
+ or
24
+ $dom = HtmlDomParser::file_get_html( $file_name );
25
+
26
+ $elems = $dom->find($elem_name);
27
+ ...
28
+
29
+ ```
vendor/kub-at/php-simple-html-dom-parser/composer.json ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "kub-at/php-simple-html-dom-parser",
3
+ "description": "PHP Simple HTML DOM Parser with namespace and PHP 7.3 compatible",
4
+ "keywords": ["html", "dom", "simple"],
5
+ "homepage": "http://simplehtmldom.sourceforge.net/",
6
+ "type": "library",
7
+ "license": "MIT",
8
+ "authors": [
9
+ {
10
+ "name": "S.C. Chen",
11
+ "email": "me578022@gmail.com"
12
+ },
13
+ {
14
+ "name": "Jakub Stawowy",
15
+ "email": "Kub-AT@users.noreply.github.com"
16
+ }
17
+ ],
18
+ "require": {
19
+ "php": ">=5.3.2"
20
+ },
21
+ "autoload": {
22
+ "psr-0": { "KubAT\\PhpSimple\\HtmlDomParser": "src/" }
23
+ }
24
+ }
vendor/kub-at/php-simple-html-dom-parser/src/KubAT/PhpSimple/HtmlDomParser.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace KubAT\PhpSimple;
3
+
4
+ require 'lib'.DIRECTORY_SEPARATOR.'simple_html_dom.php';
5
+
6
+
7
+ class HtmlDomParser {
8
+
9
+ static public function file_get_html() {
10
+ return call_user_func_array('\simple_html_dom\file_get_html' , func_get_args());
11
+ }
12
+
13
+ static public function str_get_html() {
14
+ return call_user_func_array('\simple_html_dom\str_get_html' , func_get_args());
15
+ }
16
+ }
vendor/kub-at/php-simple-html-dom-parser/src/KubAT/PhpSimple/lib/simple_html_dom.php ADDED
@@ -0,0 +1,2355 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace simple_html_dom;
3
+
4
+ /**
5
+ * Website: http://sourceforge.net/projects/simplehtmldom/
6
+ * Additional projects: http://sourceforge.net/projects/debugobject/
7
+ * Acknowledge: Jose Solorzano (https://sourceforge.net/projects/php-html/)
8
+ *
9
+ * Licensed under The MIT License
10
+ * See the LICENSE file in the project root for more information.
11
+ *
12
+ * Authors:
13
+ * S.C. Chen
14
+ * John Schlick
15
+ * Rus Carroll
16
+ * logmanoriginal
17
+ *
18
+ * Contributors:
19
+ * Yousuke Kumakura
20
+ * Vadim Voituk
21
+ * Antcs
22
+ *
23
+ * Version Rev. 1.9.1 (291)
24
+ */
25
+
26
+ define('HDOM_TYPE_ELEMENT', 1);
27
+ define('HDOM_TYPE_COMMENT', 2);
28
+ define('HDOM_TYPE_TEXT', 3);
29
+ define('HDOM_TYPE_ENDTAG', 4);
30
+ define('HDOM_TYPE_ROOT', 5);
31
+ define('HDOM_TYPE_UNKNOWN', 6);
32
+ define('HDOM_QUOTE_DOUBLE', 0);
33
+ define('HDOM_QUOTE_SINGLE', 1);
34
+ define('HDOM_QUOTE_NO', 3);
35
+ define('HDOM_INFO_BEGIN', 0);
36
+ define('HDOM_INFO_END', 1);
37
+ define('HDOM_INFO_QUOTE', 2);
38
+ define('HDOM_INFO_SPACE', 3);
39
+ define('HDOM_INFO_TEXT', 4);
40
+ define('HDOM_INFO_INNER', 5);
41
+ define('HDOM_INFO_OUTER', 6);
42
+ define('HDOM_INFO_ENDSPACE', 7);
43
+
44
+ defined('DEFAULT_TARGET_CHARSET') || define('DEFAULT_TARGET_CHARSET', 'UTF-8');
45
+ defined('DEFAULT_BR_TEXT') || define('DEFAULT_BR_TEXT', "\r\n");
46
+ defined('DEFAULT_SPAN_TEXT') || define('DEFAULT_SPAN_TEXT', ' ');
47
+ defined('MAX_FILE_SIZE') || define('MAX_FILE_SIZE', 600000);
48
+ define('HDOM_SMARTY_AS_TEXT', 1);
49
+
50
+ function file_get_html(
51
+ $url,
52
+ $use_include_path = false,
53
+ $context = null,
54
+ $offset = 0,
55
+ $maxLen = -1,
56
+ $lowercase = true,
57
+ $forceTagsClosed = true,
58
+ $target_charset = DEFAULT_TARGET_CHARSET,
59
+ $stripRN = true,
60
+ $defaultBRText = DEFAULT_BR_TEXT,
61
+ $defaultSpanText = DEFAULT_SPAN_TEXT)
62
+ {
63
+ if($maxLen <= 0) { $maxLen = MAX_FILE_SIZE; }
64
+
65
+ $dom = new simple_html_dom(
66
+ null,
67
+ $lowercase,
68
+ $forceTagsClosed,
69
+ $target_charset,
70
+ $stripRN,
71
+ $defaultBRText,
72
+ $defaultSpanText
73
+ );
74
+
75
+ /**
76
+ * For sourceforge users: uncomment the next line and comment the
77
+ * retrieve_url_contents line 2 lines down if it is not already done.
78
+ */
79
+ $contents = file_get_contents(
80
+ $url,
81
+ $use_include_path,
82
+ $context,
83
+ $offset,
84
+ $maxLen
85
+ );
86
+ // $contents = retrieve_url_contents($url);
87
+
88
+ if (empty($contents) || strlen($contents) > $maxLen) {
89
+ $dom->clear();
90
+ return false;
91
+ }
92
+
93
+ return $dom->load($contents, $lowercase, $stripRN);
94
+ }
95
+
96
+ function str_get_html(
97
+ $str,
98
+ $lowercase = true,
99
+ $forceTagsClosed = true,
100
+ $target_charset = DEFAULT_TARGET_CHARSET,
101
+ $stripRN = true,
102
+ $defaultBRText = DEFAULT_BR_TEXT,
103
+ $defaultSpanText = DEFAULT_SPAN_TEXT)
104
+ {
105
+ $dom = new simple_html_dom(
106
+ null,
107
+ $lowercase,
108
+ $forceTagsClosed,
109
+ $target_charset,
110
+ $stripRN,
111
+ $defaultBRText,
112
+ $defaultSpanText
113
+ );
114
+
115
+ if (empty($str) || strlen($str) > MAX_FILE_SIZE) {
116
+ $dom->clear();
117
+ return false;
118
+ }
119
+
120
+ return $dom->load($str, $lowercase, $stripRN);
121
+ }
122
+
123
+ function dump_html_tree($node, $show_attr = true, $deep = 0)
124
+ {
125
+ $node->dump($node);
126
+ }
127
+
128
+ class simple_html_dom_node
129
+ {
130
+ public $nodetype = HDOM_TYPE_TEXT;
131
+ public $tag = 'text';
132
+ public $attr = array();
133
+ public $children = array();
134
+ public $nodes = array();
135
+ public $parent = null;
136
+ public $_ = array();
137
+ public $tag_start = 0;
138
+ private $dom = null;
139
+
140
+ function __construct($dom)
141
+ {
142
+ $this->dom = $dom;
143
+ $dom->nodes[] = $this;
144
+ }
145
+
146
+ function __destruct()
147
+ {
148
+ $this->clear();
149
+ }
150
+
151
+ function __toString()
152
+ {
153
+ return $this->outertext();
154
+ }
155
+
156
+ function clear()
157
+ {
158
+ $this->dom = null;
159
+ $this->nodes = null;
160
+ $this->parent = null;
161
+ $this->children = null;
162
+ }
163
+
164
+ function dump($show_attr = true, $depth = 0)
165
+ {
166
+ echo str_repeat("\t", $depth) . $this->tag;
167
+
168
+ if ($show_attr && count($this->attr) > 0) {
169
+ echo '(';
170
+ foreach ($this->attr as $k => $v) {
171
+ echo "[$k]=>\"$v\", ";
172
+ }
173
+ echo ')';
174
+ }
175
+
176
+ echo "\n";
177
+
178
+ if ($this->nodes) {
179
+ foreach ($this->nodes as $node) {
180
+ $node->dump($show_attr, $depth + 1);
181
+ }
182
+ }
183
+ }
184
+
185
+ function dump_node($echo = true)
186
+ {
187
+ $string = $this->tag;
188
+
189
+ if (count($this->attr) > 0) {
190
+ $string .= '(';
191
+ foreach ($this->attr as $k => $v) {
192
+ $string .= "[$k]=>\"$v\", ";
193
+ }
194
+ $string .= ')';
195
+ }
196
+
197
+ if (count($this->_) > 0) {
198
+ $string .= ' $_ (';
199
+ foreach ($this->_ as $k => $v) {
200
+ if (is_array($v)) {
201
+ $string .= "[$k]=>(";
202
+ foreach ($v as $k2 => $v2) {
203
+ $string .= "[$k2]=>\"$v2\", ";
204
+ }
205
+ $string .= ')';
206
+ } else {
207
+ $string .= "[$k]=>\"$v\", ";
208
+ }
209
+ }
210
+ $string .= ')';
211
+ }
212
+
213
+ if (isset($this->text)) {
214
+ $string .= " text: ({$this->text})";
215
+ }
216
+
217
+ $string .= ' HDOM_INNER_INFO: ';
218
+
219
+ if (isset($node->_[HDOM_INFO_INNER])) {
220
+ $string .= "'" . $node->_[HDOM_INFO_INNER] . "'";
221
+ } else {
222
+ $string .= ' NULL ';
223
+ }
224
+
225
+ $string .= ' children: ' . count($this->children);
226
+ $string .= ' nodes: ' . count($this->nodes);
227
+ $string .= ' tag_start: ' . $this->tag_start;
228
+ $string .= "\n";
229
+
230
+ if ($echo) {
231
+ echo $string;
232
+ return;
233
+ } else {
234
+ return $string;
235
+ }
236
+ }
237
+
238
+ function parent($parent = null)
239
+ {
240
+ // I am SURE that this doesn't work properly.
241
+ // It fails to unset the current node from it's current parents nodes or
242
+ // children list first.
243
+ if ($parent !== null) {
244
+ $this->parent = $parent;
245
+ $this->parent->nodes[] = $this;
246
+ $this->parent->children[] = $this;
247
+ }
248
+
249
+ return $this->parent;
250
+ }
251
+
252
+ function has_child()
253
+ {
254
+ return !empty($this->children);
255
+ }
256
+
257
+ function children($idx = -1)
258
+ {
259
+ if ($idx === -1) {
260
+ return $this->children;
261
+ }
262
+
263
+ if (isset($this->children[$idx])) {
264
+ return $this->children[$idx];
265
+ }
266
+
267
+ return null;
268
+ }
269
+
270
+ function first_child()
271
+ {
272
+ if (count($this->children) > 0) {
273
+ return $this->children[0];
274
+ }
275
+ return null;
276
+ }
277
+
278
+ function last_child()
279
+ {
280
+ if (count($this->children) > 0) {
281
+ return end($this->children);
282
+ }
283
+ return null;
284
+ }
285
+
286
+ function next_sibling()
287
+ {
288
+ if ($this->parent === null) {
289
+ return null;
290
+ }
291
+
292
+ $idx = array_search($this, $this->parent->children, true);
293
+
294
+ if ($idx !== false && isset($this->parent->children[$idx + 1])) {
295
+ return $this->parent->children[$idx + 1];
296
+ }
297
+
298
+ return null;
299
+ }
300
+
301
+ function prev_sibling()
302
+ {
303
+ if ($this->parent === null) {
304
+ return null;
305
+ }
306
+
307
+ $idx = array_search($this, $this->parent->children, true);
308
+
309
+ if ($idx !== false && $idx > 0) {
310
+ return $this->parent->children[$idx - 1];
311
+ }
312
+
313
+ return null;
314
+ }
315
+
316
+ function find_ancestor_tag($tag)
317
+ {
318
+ global $debug_object;
319
+ if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
320
+
321
+ if ($this->parent === null) {
322
+ return null;
323
+ }
324
+
325
+ $ancestor = $this->parent;
326
+
327
+ while (!is_null($ancestor)) {
328
+ if (is_object($debug_object)) {
329
+ $debug_object->debug_log(2, 'Current tag is: ' . $ancestor->tag);
330
+ }
331
+
332
+ if ($ancestor->tag === $tag) {
333
+ break;
334
+ }
335
+
336
+ $ancestor = $ancestor->parent;
337
+ }
338
+
339
+ return $ancestor;
340
+ }
341
+
342
+ function innertext()
343
+ {
344
+ if (isset($this->_[HDOM_INFO_INNER])) {
345
+ return $this->_[HDOM_INFO_INNER];
346
+ }
347
+
348
+ if (isset($this->_[HDOM_INFO_TEXT])) {
349
+ return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
350
+ }
351
+
352
+ $ret = '';
353
+
354
+ foreach ($this->nodes as $n) {
355
+ $ret .= $n->outertext();
356
+ }
357
+
358
+ return $ret;
359
+ }
360
+
361
+ function outertext()
362
+ {
363
+ global $debug_object;
364
+
365
+ if (is_object($debug_object)) {
366
+ $text = '';
367
+
368
+ if ($this->tag === 'text') {
369
+ if (!empty($this->text)) {
370
+ $text = ' with text: ' . $this->text;
371
+ }
372
+ }
373
+
374
+ $debug_object->debug_log(1, 'Innertext of tag: ' . $this->tag . $text);
375
+ }
376
+
377
+ if ($this->tag === 'root') {
378
+ return $this->innertext();
379
+ }
380
+
381
+ // todo: What is the use of this callback? Remove?
382
+ if ($this->dom && $this->dom->callback !== null) {
383
+ call_user_func_array($this->dom->callback, array($this));
384
+ }
385
+
386
+ if (isset($this->_[HDOM_INFO_OUTER])) {
387
+ return $this->_[HDOM_INFO_OUTER];
388
+ }
389
+
390
+ if (isset($this->_[HDOM_INFO_TEXT])) {
391
+ return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
392
+ }
393
+
394
+ $ret = '';
395
+
396
+ if ($this->dom && $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]) {
397
+ $ret = $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]->makeup();
398
+ }
399
+
400
+ if (isset($this->_[HDOM_INFO_INNER])) {
401
+ // todo: <br> should either never have HDOM_INFO_INNER or always
402
+ if ($this->tag !== 'br') {
403
+ $ret .= $this->_[HDOM_INFO_INNER];
404
+ }
405
+ } elseif ($this->nodes) {
406
+ foreach ($this->nodes as $n) {
407
+ $ret .= $this->convert_text($n->outertext());
408
+ }
409
+ }
410
+
411
+ if (isset($this->_[HDOM_INFO_END]) && $this->_[HDOM_INFO_END] != 0) {
412
+ $ret .= '</' . $this->tag . '>';
413
+ }
414
+
415
+ return $ret;
416
+ }
417
+
418
+ function text()
419
+ {
420
+ if (isset($this->_[HDOM_INFO_INNER])) {
421
+ return $this->_[HDOM_INFO_INNER];
422
+ }
423
+
424
+ switch ($this->nodetype) {
425
+ case HDOM_TYPE_TEXT: return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
426
+ case HDOM_TYPE_COMMENT: return '';
427
+ case HDOM_TYPE_UNKNOWN: return '';
428
+ }
429
+
430
+ if (strcasecmp($this->tag, 'script') === 0) { return ''; }
431
+ if (strcasecmp($this->tag, 'style') === 0) { return ''; }
432
+
433
+ $ret = '';
434
+
435
+ // In rare cases, (always node type 1 or HDOM_TYPE_ELEMENT - observed
436
+ // for some span tags, and some p tags) $this->nodes is set to NULL.
437
+ // NOTE: This indicates that there is a problem where it's set to NULL
438
+ // without a clear happening.
439
+ // WHY is this happening?
440
+ if (!is_null($this->nodes)) {
441
+ foreach ($this->nodes as $n) {
442
+ // Start paragraph after a blank line
443
+ if ($n->tag === 'p') {
444
+ $ret = trim($ret) . "\n\n";
445
+ }
446
+
447
+ $ret .= $this->convert_text($n->text());
448
+
449
+ // If this node is a span... add a space at the end of it so
450
+ // multiple spans don't run into each other. This is plaintext
451
+ // after all.
452
+ if ($n->tag === 'span') {
453
+ $ret .= $this->dom->default_span_text;
454
+ }
455
+ }
456
+ }
457
+ return $ret;
458
+ }
459
+
460
+ function xmltext()
461
+ {
462
+ $ret = $this->innertext();
463
+ $ret = str_ireplace('<![CDATA[', '', $ret);
464
+ $ret = str_replace(']]>', '', $ret);
465
+ return $ret;
466
+ }
467
+
468
+ function makeup()
469
+ {
470
+ // text, comment, unknown
471
+ if (isset($this->_[HDOM_INFO_TEXT])) {
472
+ return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
473
+ }
474
+
475
+ $ret = '<' . $this->tag;
476
+ $i = -1;
477
+
478
+ foreach ($this->attr as $key => $val) {
479
+ ++$i;
480
+
481
+ // skip removed attribute
482
+ if ($val === null || $val === false) { continue; }
483
+
484
+ $ret .= $this->_[HDOM_INFO_SPACE][$i][0];
485
+
486
+ //no value attr: nowrap, checked selected...
487
+ if ($val === true) {
488
+ $ret .= $key;
489
+ } else {
490
+ switch ($this->_[HDOM_INFO_QUOTE][$i])
491
+ {
492
+ case HDOM_QUOTE_DOUBLE: $quote = '"'; break;
493
+ case HDOM_QUOTE_SINGLE: $quote = '\''; break;
494
+ default: $quote = '';
495
+ }
496
+
497
+ $ret .= $key
498
+ . $this->_[HDOM_INFO_SPACE][$i][1]
499
+ . '='
500
+ . $this->_[HDOM_INFO_SPACE][$i][2]
501
+ . $quote
502
+ . $val
503
+ . $quote;
504
+ }
505
+ }
506
+
507
+ $ret = $this->dom->restore_noise($ret);
508
+ return $ret . $this->_[HDOM_INFO_ENDSPACE] . '>';
509
+ }
510
+
511
+ function find($selector, $idx = null, $lowercase = false)
512
+ {
513
+ $selectors = $this->parse_selector($selector);
514
+ if (($count = count($selectors)) === 0) { return array(); }
515
+ $found_keys = array();
516
+
517
+ // find each selector
518
+ for ($c = 0; $c < $count; ++$c) {
519
+ // The change on the below line was documented on the sourceforge
520
+ // code tracker id 2788009
521
+ // used to be: if (($levle=count($selectors[0]))===0) return array();
522
+ if (($levle = count($selectors[$c])) === 0) { return array(); }
523
+ if (!isset($this->_[HDOM_INFO_BEGIN])) { return array(); }
524
+
525
+ $head = array($this->_[HDOM_INFO_BEGIN] => 1);
526
+ $cmd = ' '; // Combinator
527
+
528
+ // handle descendant selectors, no recursive!
529
+ for ($l = 0; $l < $levle; ++$l) {
530
+ $ret = array();
531
+
532
+ foreach ($head as $k => $v) {
533
+ $n = ($k === -1) ? $this->dom->root : $this->dom->nodes[$k];
534
+ //PaperG - Pass this optional parameter on to the seek function.
535
+ $n->seek($selectors[$c][$l], $ret, $cmd, $lowercase);
536
+ }
537
+
538
+ $head = $ret;
539
+ $cmd = $selectors[$c][$l][4]; // Next Combinator
540
+ }
541
+
542
+ foreach ($head as $k => $v) {
543
+ if (!isset($found_keys[$k])) {
544
+ $found_keys[$k] = 1;
545
+ }
546
+ }
547
+ }
548
+
549
+ // sort keys
550
+ ksort($found_keys);
551
+
552
+ $found = array();
553
+ foreach ($found_keys as $k => $v) {
554
+ $found[] = $this->dom->nodes[$k];
555
+ }
556
+
557
+ // return nth-element or array
558
+ if (is_null($idx)) { return $found; }
559
+ elseif ($idx < 0) { $idx = count($found) + $idx; }
560
+ return (isset($found[$idx])) ? $found[$idx] : null;
561
+ }
562
+
563
+ protected function seek($selector, &$ret, $parent_cmd, $lowercase = false)
564
+ {
565
+ global $debug_object;
566
+ if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
567
+
568
+ list($tag, $id, $class, $attributes, $cmb) = $selector;
569
+ $nodes = array();
570
+
571
+ if ($parent_cmd === ' ') { // Descendant Combinator
572
+ // Find parent closing tag if the current element doesn't have a closing
573
+ // tag (i.e. void element)
574
+ $end = (!empty($this->_[HDOM_INFO_END])) ? $this->_[HDOM_INFO_END] : 0;
575
+ if ($end == 0) {
576
+ $parent = $this->parent;
577
+ while (!isset($parent->_[HDOM_INFO_END]) && $parent !== null) {
578
+ $end -= 1;
579
+ $parent = $parent->parent;
580
+ }
581
+ $end += $parent->_[HDOM_INFO_END];
582
+ }
583
+
584
+ // Get list of target nodes
585
+ $nodes_start = $this->_[HDOM_INFO_BEGIN] + 1;
586
+ $nodes_count = $end - $nodes_start;
587
+ $nodes = array_slice($this->dom->nodes, $nodes_start, $nodes_count, true);
588
+ } elseif ($parent_cmd === '>') { // Child Combinator
589
+ $nodes = $this->children;
590
+ } elseif ($parent_cmd === '+'
591
+ && $this->parent
592
+ && in_array($this, $this->parent->children)) { // Next-Sibling Combinator
593
+ $index = array_search($this, $this->parent->children, true) + 1;
594
+ if ($index < count($this->parent->children))
595
+ $nodes[] = $this->parent->children[$index];
596
+ } elseif ($parent_cmd === '~'
597
+ && $this->parent
598
+ && in_array($this, $this->parent->children)) { // Subsequent Sibling Combinator
599
+ $index = array_search($this, $this->parent->children, true);
600
+ $nodes = array_slice($this->parent->children, $index);
601
+ }
602
+
603
+ // Go throgh each element starting at this element until the end tag
604
+ // Note: If this element is a void tag, any previous void element is
605
+ // skipped.
606
+ foreach($nodes as $node) {
607
+ $pass = true;
608
+
609
+ // Skip root nodes
610
+ if(!$node->parent) {
611
+ $pass = false;
612
+ }
613
+
614
+ // Handle 'text' selector
615
+ if($pass && $tag === 'text' && $node->tag === 'text') {
616
+ $ret[array_search($node, $this->dom->nodes, true)] = 1;
617
+ unset($node);
618
+ continue;
619
+ }
620
+
621
+ // Skip if node isn't a child node (i.e. text nodes)
622
+ if($pass && !in_array($node, $node->parent->children, true)) {
623
+ $pass = false;
624
+ }
625
+
626
+ // Skip if tag doesn't match
627
+ if ($pass && $tag !== '' && $tag !== $node->tag && $tag !== '*') {
628
+ $pass = false;
629
+ }
630
+
631
+ // Skip if ID doesn't exist
632
+ if ($pass && $id !== '' && !isset($node->attr['id'])) {
633
+ $pass = false;
634
+ }
635
+
636
+ // Check if ID matches
637
+ if ($pass && $id !== '' && isset($node->attr['id'])) {
638
+ // Note: Only consider the first ID (as browsers do)
639
+ $node_id = explode(' ', trim($node->attr['id']))[0];
640
+
641
+ if($id !== $node_id) { $pass = false; }
642
+ }
643
+
644
+ // Check if all class(es) exist
645
+ if ($pass && $class !== '' && is_array($class) && !empty($class)) {
646
+ if (isset($node->attr['class'])) {
647
+ $node_classes = explode(' ', $node->attr['class']);
648
+
649
+ if ($lowercase) {
650
+ $node_classes = array_map('strtolower', $node_classes);
651
+ }
652
+
653
+ foreach($class as $c) {
654
+ if(!in_array($c, $node_classes)) {
655
+ $pass = false;
656
+ break;
657
+ }
658
+ }
659
+ } else {
660
+ $pass = false;
661
+ }
662
+ }
663
+
664
+ // Check attributes
665
+ if ($pass
666
+ && $attributes !== ''
667
+ && is_array($attributes)
668
+ && !empty($attributes)) {
669
+ foreach($attributes as $a) {
670
+ list (
671
+ $att_name,
672
+ $att_expr,
673
+ $att_val,
674
+ $att_inv,
675
+ $att_case_sensitivity
676
+ ) = $a;
677
+
678
+ // Handle indexing attributes (i.e. "[2]")
679
+ /**
680
+ * Note: This is not supported by the CSS Standard but adds
681
+ * the ability to select items compatible to XPath (i.e.
682
+ * the 3rd element within it's parent).
683
+ *
684
+ * Note: This doesn't conflict with the CSS Standard which
685
+ * doesn't work on numeric attributes anyway.
686
+ */
687
+ if (is_numeric($att_name)
688
+ && $att_expr === ''
689
+ && $att_val === '') {
690
+ $count = 0;
691
+
692
+ // Find index of current element in parent
693
+ foreach ($node->parent->children as $c) {
694
+ if ($c->tag === $node->tag) ++$count;
695
+ if ($c === $node) break;
696
+ }
697
+
698
+ // If this is the correct node, continue with next
699
+ // attribute
700
+ if ($count === (int)$att_name) continue;
701
+ }
702
+
703
+ // Check attribute availability
704
+ if ($att_inv) { // Attribute should NOT be set
705
+ if (isset($node->attr[$att_name])) {
706
+ $pass = false;
707
+ break;
708
+ }
709
+ } else { // Attribute should be set
710
+ // todo: "plaintext" is not a valid CSS selector!
711
+ if ($att_name !== 'plaintext'
712
+ && !isset($node->attr[$att_name])) {
713
+ $pass = false;
714
+ break;
715
+ }
716
+ }
717
+
718
+ // Continue with next attribute if expression isn't defined
719
+ if ($att_expr === '') continue;
720
+
721
+ // If they have told us that this is a "plaintext"
722
+ // search then we want the plaintext of the node - right?
723
+ // todo "plaintext" is not a valid CSS selector!
724
+ if ($att_name === 'plaintext') {
725
+ $nodeKeyValue = $node->text();
726
+ } else {
727
+ $nodeKeyValue = $node->attr[$att_name];
728
+ }
729
+
730
+ if (is_object($debug_object)) {
731
+ $debug_object->debug_log(2,
732
+ 'testing node: '
733
+ . $node->tag
734
+ . ' for attribute: '
735
+ . $att_name
736
+ . $att_expr
737
+ . $att_val
738
+ . ' where nodes value is: '
739
+ . $nodeKeyValue
740
+ );
741
+ }
742
+
743
+ // If lowercase is set, do a case insensitive test of
744
+ // the value of the selector.
745
+ if ($lowercase) {
746
+ $check = $this->match(
747
+ $att_expr,
748
+ strtolower($att_val),
749
+ strtolower($nodeKeyValue),
750
+ $att_case_sensitivity
751
+ );
752
+ } else {
753
+ $check = $this->match(
754
+ $att_expr,
755
+ $att_val,
756
+ $nodeKeyValue,
757
+ $att_case_sensitivity
758
+ );
759
+ }
760
+
761
+ if (is_object($debug_object)) {
762
+ $debug_object->debug_log(2,
763
+ 'after match: '
764
+ . ($check ? 'true' : 'false')
765
+ );
766
+ }
767
+
768
+ if (!$check) {
769
+ $pass = false;
770
+ break;
771
+ }
772
+ }
773
+ }
774
+
775
+ // Found a match. Add to list and clear node
776
+ if ($pass) $ret[$node->_[HDOM_INFO_BEGIN]] = 1;
777
+ unset($node);
778
+ }
779
+ // It's passed by reference so this is actually what this function returns.
780
+ if (is_object($debug_object)) {
781
+ $debug_object->debug_log(1, 'EXIT - ret: ', $ret);
782
+ }
783
+ }
784
+
785
+ protected function match($exp, $pattern, $value, $case_sensitivity)
786
+ {
787
+ global $debug_object;
788
+ if (is_object($debug_object)) {$debug_object->debug_log_entry(1);}
789
+
790
+ if ($case_sensitivity === 'i') {
791
+ $pattern = strtolower($pattern);
792
+ $value = strtolower($value);
793
+ }
794
+
795
+ switch ($exp) {
796
+ case '=':
797
+ return ($value === $pattern);
798
+ case '!=':
799
+ return ($value !== $pattern);
800
+ case '^=':
801
+ return preg_match('/^' . preg_quote($pattern, '/') . '/', $value);
802
+ case '$=':
803
+ return preg_match('/' . preg_quote($pattern, '/') . '$/', $value);
804
+ case '*=':
805
+ return preg_match('/' . preg_quote($pattern, '/') . '/', $value);
806
+ case '|=':
807
+ /**
808
+ * [att|=val]
809
+ *
810
+ * Represents an element with the att attribute, its value
811
+ * either being exactly "val" or beginning with "val"
812
+ * immediately followed by "-" (U+002D).
813
+ */
814
+ return strpos($value, $pattern) === 0;
815
+ case '~=':
816
+ /**
817
+ * [att~=val]
818
+ *
819
+ * Represents an element with the att attribute whose value is a
820
+ * whitespace-separated list of words, one of which is exactly
821
+ * "val". If "val" contains whitespace, it will never represent
822
+ * anything (since the words are separated by spaces). Also if
823
+ * "val" is the empty string, it will never represent anything.
824
+ */
825
+ return in_array($pattern, explode(' ', trim($value)), true);
826
+ }
827
+ return false;
828
+ }
829
+
830
+ protected function parse_selector($selector_string)
831
+ {
832
+ global $debug_object;
833
+ if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
834
+
835
+ /**
836
+ * Pattern of CSS selectors, modified from mootools (https://mootools.net/)
837
+ *
838
+ * Paperg: Add the colon to the attribute, so that it properly finds
839
+ * <tag attr:ibute="something" > like google does.
840
+ *
841
+ * Note: if you try to look at this attribute, you MUST use getAttribute
842
+ * since $dom->x:y will fail the php syntax check.
843
+ *
844
+ * Notice the \[ starting the attribute? and the @? following? This
845
+ * implies that an attribute can begin with an @ sign that is not
846
+ * captured. This implies that an html attribute specifier may start
847
+ * with an @ sign that is NOT captured by the expression. Farther study
848
+ * is required to determine of this should be documented or removed.
849
+ *
850
+ * Matches selectors in this order:
851
+ *
852
+ * [0] - full match
853
+ *
854
+ * [1] - tag name
855
+ * ([\w:\*-]*)
856
+ * Matches the tag name consisting of zero or more words, colons,
857
+ * asterisks and hyphens.
858
+ *
859
+ * [2] - id name
860
+ * (?:\#([\w-]+))
861
+ * Optionally matches a id name, consisting of an "#" followed by
862
+ * the id name (one or more words and hyphens).
863
+ *
864
+ * [3] - class names (including dots)
865
+ * (?:\.([\w\.-]+))?
866
+ * Optionally matches a list of classs, consisting of an "."
867
+ * followed by the class name (one or more words and hyphens)
868
+ * where multiple classes can be chained (i.e. ".foo.bar.baz")
869
+ *
870
+ * [4] - attributes
871
+ * ((?:\[@?(?:!?[\w:-]+)(?:(?:[!*^$|~]?=)[\"']?(?:.*?)[\"']?)?(?:\s*?(?:[iIsS])?)?\])+)?
872
+ * Optionally matches the attributes list
873
+ *
874
+ * [5] - separator
875
+ * ([\/, >+~]+)
876
+ * Matches the selector list separator
877
+ */
878
+ // phpcs:ignore Generic.Files.LineLength
879
+ $pattern = "/([\w:\*-]*)(?:\#([\w-]+))?(?:|\.([\w\.-]+))?((?:\[@?(?:!?[\w:-]+)(?:(?:[!*^$|~]?=)[\"']?(?:.*?)[\"']?)?(?:\s*?(?:[iIsS])?)?\])+)?([\/, >+~]+)/is";
880
+
881
+ preg_match_all(
882
+ $pattern,
883
+ trim($selector_string) . ' ', // Add final ' ' as pseudo separator
884
+ $matches,
885
+ PREG_SET_ORDER
886
+ );
887
+
888
+ if (is_object($debug_object)) {
889
+ $debug_object->debug_log(2, 'Matches Array: ', $matches);
890
+ }
891
+
892
+ $selectors = array();
893
+ $result = array();
894
+
895
+ foreach ($matches as $m) {
896
+ $m[0] = trim($m[0]);
897
+
898
+ // Skip NoOps
899
+ if ($m[0] === '' || $m[0] === '/' || $m[0] === '//') { continue; }
900
+
901
+ // Convert to lowercase
902
+ if ($this->dom->lowercase) {
903
+ $m[1] = strtolower($m[1]);
904
+ }
905
+
906
+ // Extract classes
907
+ if ($m[3] !== '') { $m[3] = explode('.', $m[3]); }
908
+
909
+ /* Extract attributes (pattern based on the pattern above!)
910
+
911
+ * [0] - full match
912
+ * [1] - attribute name
913
+ * [2] - attribute expression
914
+ * [3] - attribute value
915
+ * [4] - case sensitivity
916
+ *
917
+ * Note: Attributes can be negated with a "!" prefix to their name
918
+ */
919
+ if($m[4] !== '') {
920
+ preg_match_all(
921
+ "/\[@?(!?[\w:-]+)(?:([!*^$|~]?=)[\"']?(.*?)[\"']?)?(?:\s+?([iIsS])?)?\]/is",
922
+ trim($m[4]),
923
+ $attributes,
924
+ PREG_SET_ORDER
925
+ );
926
+
927
+ // Replace element by array
928
+ $m[4] = array();
929
+
930
+ foreach($attributes as $att) {
931
+ // Skip empty matches
932
+ if(trim($att[0]) === '') { continue; }
933
+
934
+ $inverted = (isset($att[1][0]) && $att[1][0] === '!');
935
+ $m[4][] = array(
936
+ $inverted ? substr($att[1], 1) : $att[1], // Name
937
+ (isset($att[2])) ? $att[2] : '', // Expression
938
+ (isset($att[3])) ? $att[3] : '', // Value
939
+ $inverted, // Inverted Flag
940
+ (isset($att[4])) ? strtolower($att[4]) : '', // Case-Sensitivity
941
+ );
942
+ }
943
+ }
944
+
945
+ // Sanitize Separator
946
+ if ($m[5] !== '' && trim($m[5]) === '') { // Descendant Separator
947
+ $m[5] = ' ';
948
+ } else { // Other Separator
949
+ $m[5] = trim($m[5]);
950
+ }
951
+
952
+ // Clear Separator if it's a Selector List
953
+ if ($is_list = ($m[5] === ',')) { $m[5] = ''; }
954
+
955
+ // Remove full match before adding to results
956
+ array_shift($m);
957
+ $result[] = $m;
958
+
959
+ if ($is_list) { // Selector List
960
+ $selectors[] = $result;
961
+ $result = array();
962
+ }
963
+ }
964
+
965
+ if (count($result) > 0) { $selectors[] = $result; }
966
+ return $selectors;
967
+ }
968
+
969
+ function __get($name)
970
+ {
971
+ if (isset($this->attr[$name])) {
972
+ return $this->convert_text($this->attr[$name]);
973
+ }
974
+ switch ($name) {
975
+ case 'outertext': return $this->outertext();
976
+ case 'innertext': return $this->innertext();
977
+ case 'plaintext': return $this->text();
978
+ case 'xmltext': return $this->xmltext();
979
+ default: return array_key_exists($name, $this->attr);
980
+ }
981
+ }
982
+
983
+ function __set($name, $value)
984
+ {
985
+ global $debug_object;
986
+ if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
987
+
988
+ switch ($name) {
989
+ case 'outertext': return $this->_[HDOM_INFO_OUTER] = $value;
990
+ case 'innertext':
991
+ if (isset($this->_[HDOM_INFO_TEXT])) {
992
+ return $this->_[HDOM_INFO_TEXT] = $value;
993
+ }
994
+ return $this->_[HDOM_INFO_INNER] = $value;
995
+ }
996
+
997
+ if (!isset($this->attr[$name])) {
998
+ $this->_[HDOM_INFO_SPACE][] = array(' ', '', '');
999
+ $this->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE;
1000
+ }
1001
+
1002
+ $this->attr[$name] = $value;
1003
+ }
1004
+
1005
+ function __isset($name)
1006
+ {
1007
+ switch ($name) {
1008
+ case 'outertext': return true;
1009
+ case 'innertext': return true;
1010
+ case 'plaintext': return true;
1011
+ }
1012
+ //no value attr: nowrap, checked selected...
1013
+ return (array_key_exists($name, $this->attr)) ? true : isset($this->attr[$name]);
1014
+ }
1015
+
1016
+ function __unset($name)
1017
+ {
1018
+ if (isset($this->attr[$name])) { unset($this->attr[$name]); }
1019
+ }
1020
+
1021
+ function convert_text($text)
1022
+ {
1023
+ global $debug_object;
1024
+ if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
1025
+
1026
+ $converted_text = $text;
1027
+
1028
+ $sourceCharset = '';
1029
+ $targetCharset = '';
1030
+
1031
+ if ($this->dom) {
1032
+ $sourceCharset = strtoupper($this->dom->_charset);
1033
+ $targetCharset = strtoupper($this->dom->_target_charset);
1034
+ }
1035
+
1036
+ if (is_object($debug_object)) {
1037
+ $debug_object->debug_log(3,
1038
+ 'source charset: '
1039
+ . $sourceCharset
1040
+ . ' target charaset: '
1041
+ . $targetCharset
1042
+ );
1043
+ }
1044
+
1045
+ if (!empty($sourceCharset)
1046
+ && !empty($targetCharset)
1047
+ && (strcasecmp($sourceCharset, $targetCharset) != 0)) {
1048
+ // Check if the reported encoding could have been incorrect and the text is actually already UTF-8
1049
+ if ((strcasecmp($targetCharset, 'UTF-8') == 0)
1050
+ && ($this->is_utf8($text))) {
1051
+ $converted_text = $text;
1052
+ } else {
1053
+ $converted_text = iconv($sourceCharset, $targetCharset, $text);
1054
+ }
1055
+ }
1056
+
1057
+ // Lets make sure that we don't have that silly BOM issue with any of the utf-8 text we output.
1058
+ if ($targetCharset === 'UTF-8') {
1059
+ if (substr($converted_text, 0, 3) === "\xef\xbb\xbf") {
1060
+ $converted_text = substr($converted_text, 3);
1061
+ }
1062
+
1063
+ if (substr($converted_text, -3) === "\xef\xbb\xbf") {
1064
+ $converted_text = substr($converted_text, 0, -3);
1065
+ }
1066
+ }
1067
+
1068
+ return $converted_text;
1069
+ }
1070
+
1071
+ static function is_utf8($str)
1072
+ {
1073
+ $c = 0; $b = 0;
1074
+ $bits = 0;
1075
+ $len = strlen($str);
1076
+ for($i = 0; $i < $len; $i++) {
1077
+ $c = ord($str[$i]);
1078
+ if($c > 128) {
1079
+ if(($c >= 254)) { return false; }
1080
+ elseif($c >= 252) { $bits = 6; }
1081
+ elseif($c >= 248) { $bits = 5; }
1082
+ elseif($c >= 240) { $bits = 4; }
1083
+ elseif($c >= 224) { $bits = 3; }
1084
+ elseif($c >= 192) { $bits = 2; }
1085
+ else { return false; }
1086
+ if(($i + $bits) > $len) { return false; }
1087
+ while($bits > 1) {
1088
+ $i++;
1089
+ $b = ord($str[$i]);
1090
+ if($b < 128 || $b > 191) { return false; }
1091
+ $bits--;
1092
+ }
1093
+ }
1094
+ }
1095
+ return true;
1096
+ }
1097
+
1098
+ function get_display_size()
1099
+ {
1100
+ global $debug_object;
1101
+
1102
+ $width = -1;
1103
+ $height = -1;
1104
+
1105
+ if ($this->tag !== 'img') {
1106
+ return false;
1107
+ }
1108
+
1109
+ // See if there is aheight or width attribute in the tag itself.
1110
+ if (isset($this->attr['width'])) {
1111
+ $width = $this->attr['width'];
1112
+ }
1113
+
1114
+ if (isset($this->attr['height'])) {
1115
+ $height = $this->attr['height'];
1116
+ }
1117
+
1118
+ // Now look for an inline style.
1119
+ if (isset($this->attr['style'])) {
1120
+ // Thanks to user gnarf from stackoverflow for this regular expression.
1121
+ $attributes = array();
1122
+
1123
+ preg_match_all(
1124
+ '/([\w-]+)\s*:\s*([^;]+)\s*;?/',
1125
+ $this->attr['style'],
1126
+ $matches,
1127
+ PREG_SET_ORDER
1128
+ );
1129
+
1130
+ foreach ($matches as $match) {
1131
+ $attributes[$match[1]] = $match[2];
1132
+ }
1133
+
1134
+ // If there is a width in the style attributes:
1135
+ if (isset($attributes['width']) && $width == -1) {
1136
+ // check that the last two characters are px (pixels)
1137
+ if (strtolower(substr($attributes['width'], -2)) === 'px') {
1138
+ $proposed_width = substr($attributes['width'], 0, -2);
1139
+ // Now make sure that it's an integer and not something stupid.
1140
+ if (filter_var($proposed_width, FILTER_VALIDATE_INT)) {
1141
+ $width = $proposed_width;
1142
+ }
1143
+ }
1144
+ }
1145
+
1146
+ // If there is a width in the style attributes:
1147
+ if (isset($attributes['height']) && $height == -1) {
1148
+ // check that the last two characters are px (pixels)
1149
+ if (strtolower(substr($attributes['height'], -2)) == 'px') {
1150
+ $proposed_height = substr($attributes['height'], 0, -2);
1151
+ // Now make sure that it's an integer and not something stupid.
1152
+ if (filter_var($proposed_height, FILTER_VALIDATE_INT)) {
1153
+ $height = $proposed_height;
1154
+ }
1155
+ }
1156
+ }
1157
+
1158
+ }
1159
+
1160
+ // Future enhancement:
1161
+ // Look in the tag to see if there is a class or id specified that has
1162
+ // a height or width attribute to it.
1163
+
1164
+ // Far future enhancement
1165
+ // Look at all the parent tags of this image to see if they specify a
1166
+ // class or id that has an img selector that specifies a height or width
1167
+ // Note that in this case, the class or id will have the img subselector
1168
+ // for it to apply to the image.
1169
+
1170
+ // ridiculously far future development
1171
+ // If the class or id is specified in a SEPARATE css file thats not on
1172
+ // the page, go get it and do what we were just doing for the ones on
1173
+ // the page.
1174
+
1175
+ $result = array(
1176
+ 'height' => $height,
1177
+ 'width' => $width
1178
+ );
1179
+
1180
+ return $result;
1181
+ }
1182
+
1183
+ function save($filepath = '')
1184
+ {
1185
+ $ret = $this->outertext();
1186
+
1187
+ if ($filepath !== '') {
1188
+ file_put_contents($filepath, $ret, LOCK_EX);
1189
+ }
1190
+
1191
+ return $ret;
1192
+ }
1193
+
1194
+ function addClass($class)
1195
+ {
1196
+ if (is_string($class)) {
1197
+ $class = explode(' ', $class);
1198
+ }
1199
+
1200
+ if (is_array($class)) {
1201
+ foreach($class as $c) {
1202
+ if (isset($this->class)) {
1203
+ if ($this->hasClass($c)) {
1204
+ continue;
1205
+ } else {
1206
+ $this->class .= ' ' . $c;
1207
+ }
1208
+ } else {
1209
+ $this->class = $c;
1210
+ }
1211
+ }
1212
+ } else {
1213
+ if (is_object($debug_object)) {
1214
+ $debug_object->debug_log(2, 'Invalid type: ', gettype($class));
1215
+ }
1216
+ }
1217
+ }
1218
+
1219
+ function hasClass($class)
1220
+ {
1221
+ if (is_string($class)) {
1222
+ if (isset($this->class)) {
1223
+ return in_array($class, explode(' ', $this->class), true);
1224
+ }
1225
+ } else {
1226
+ if (is_object($debug_object)) {
1227
+ $debug_object->debug_log(2, 'Invalid type: ', gettype($class));
1228
+ }
1229
+ }
1230
+
1231
+ return false;
1232
+ }
1233
+
1234
+ function removeClass($class = null)
1235
+ {
1236
+ if (!isset($this->class)) {
1237
+ return;
1238
+ }
1239
+
1240
+ if (is_null($class)) {
1241
+ $this->removeAttribute('class');
1242
+ return;
1243
+ }
1244
+
1245
+ if (is_string($class)) {
1246
+ $class = explode(' ', $class);
1247
+ }
1248
+
1249
+ if (is_array($class)) {
1250
+ $class = array_diff(explode(' ', $this->class), $class);
1251
+ if (empty($class)) {
1252
+ $this->removeAttribute('class');
1253
+ } else {
1254
+ $this->class = implode(' ', $class);
1255
+ }
1256
+ }
1257
+ }
1258
+
1259
+ function getAllAttributes()
1260
+ {
1261
+ return $this->attr;
1262
+ }
1263
+
1264
+ function getAttribute($name)
1265
+ {
1266
+ return $this->__get($name);
1267
+ }
1268
+
1269
+ function setAttribute($name, $value)
1270
+ {
1271
+ $this->__set($name, $value);
1272
+ }
1273
+
1274
+ function hasAttribute($name)
1275
+ {
1276
+ return $this->__isset($name);
1277
+ }
1278
+
1279
+ function removeAttribute($name)
1280
+ {
1281
+ $this->__set($name, null);
1282
+ }
1283
+
1284
+ function remove()
1285
+ {
1286
+ if ($this->parent) {
1287
+ $this->parent->removeChild($this);
1288
+ }
1289
+ }
1290
+
1291
+ function removeChild($node)
1292
+ {
1293
+ $nidx = array_search($node, $this->nodes, true);
1294
+ $cidx = array_search($node, $this->children, true);
1295
+ $didx = array_search($node, $this->dom->nodes, true);
1296
+
1297
+ if ($nidx !== false && $cidx !== false && $didx !== false) {
1298
+
1299
+ foreach($node->children as $child) {
1300
+ $node->removeChild($child);
1301
+ }
1302
+
1303
+ foreach($node->nodes as $entity) {
1304
+ $enidx = array_search($entity, $node->nodes, true);
1305
+ $edidx = array_search($entity, $node->dom->nodes, true);
1306
+
1307
+ if ($enidx !== false && $edidx !== false) {
1308
+ unset($node->nodes[$enidx]);
1309
+ unset($node->dom->nodes[$edidx]);
1310
+ }
1311
+ }
1312
+
1313
+ unset($this->nodes[$nidx]);
1314
+ unset($this->children[$cidx]);
1315
+ unset($this->dom->nodes[$didx]);
1316
+
1317
+ $node->clear();
1318
+
1319
+ }
1320
+ }
1321
+
1322
+ function getElementById($id)
1323
+ {
1324
+ return $this->find("#$id", 0);
1325
+ }
1326
+
1327
+ function getElementsById($id, $idx = null)
1328
+ {
1329
+ return $this->find("#$id", $idx);
1330
+ }
1331
+
1332
+ function getElementByTagName($name)
1333
+ {
1334
+ return $this->find($name, 0);
1335
+ }
1336
+
1337
+ function getElementsByTagName($name, $idx = null)
1338
+ {
1339
+ return $this->find($name, $idx);
1340
+ }
1341
+
1342
+ function parentNode()
1343
+ {
1344
+ return $this->parent();
1345
+ }
1346
+
1347
+ function childNodes($idx = -1)
1348
+ {
1349
+ return $this->children($idx);
1350
+ }
1351
+
1352
+ function firstChild()
1353
+ {
1354
+ return $this->first_child();
1355
+ }
1356
+
1357
+ function lastChild()
1358
+ {
1359
+ return $this->last_child();
1360
+ }
1361
+
1362
+ function nextSibling()
1363
+ {
1364
+ return $this->next_sibling();
1365
+ }
1366
+
1367
+ function previousSibling()
1368
+ {
1369
+ return $this->prev_sibling();
1370
+ }
1371
+
1372
+ function hasChildNodes()
1373
+ {
1374
+ return $this->has_child();
1375
+ }
1376
+
1377
+ function nodeName()
1378
+ {
1379
+ return $this->tag;
1380
+ }
1381
+
1382
+ function appendChild($node)
1383
+ {
1384
+ $node->parent($this);
1385
+ return $node;
1386
+ }
1387
+
1388
+ }
1389
+
1390
+ class simple_html_dom
1391
+ {
1392
+ public $root = null;
1393
+ public $nodes = array();
1394
+ public $callback = null;
1395
+ public $lowercase = false;
1396
+ public $original_size;
1397
+ public $size;
1398
+
1399
+ protected $pos;
1400
+ protected $doc;
1401
+ protected $char;
1402
+
1403
+ protected $cursor;
1404
+ protected $parent;
1405
+ protected $noise = array();
1406
+ protected $token_blank = " \t\r\n";
1407
+ protected $token_equal = ' =/>';
1408
+ protected $token_slash = " />\r\n\t";
1409
+ protected $token_attr = ' >';
1410
+
1411
+ public $_charset = '';
1412
+ public $_target_charset = '';
1413
+
1414
+ protected $default_br_text = '';
1415
+
1416
+ public $default_span_text = '';
1417
+
1418
+ protected $self_closing_tags = array(
1419
+ 'area' => 1,
1420
+ 'base' => 1,
1421
+ 'br' => 1,
1422
+ 'col' => 1,
1423
+ 'embed' => 1,
1424
+ 'hr' => 1,
1425
+ 'img' => 1,
1426
+ 'input' => 1,
1427
+ 'link' => 1,
1428
+ 'meta' => 1,
1429
+ 'param' => 1,
1430
+ 'source' => 1,
1431
+ 'track' => 1,
1432
+ 'wbr' => 1
1433
+ );
1434
+ protected $block_tags = array(
1435
+ 'body' => 1,
1436
+ 'div' => 1,
1437
+ 'form' => 1,
1438
+ 'root' => 1,
1439
+ 'span' => 1,
1440
+ 'table' => 1
1441
+ );
1442
+ protected $optional_closing_tags = array(
1443
+ // Not optional, see
1444
+ // https://www.w3.org/TR/html/textlevel-semantics.html#the-b-element
1445
+ 'b' => array('b' => 1),
1446
+ 'dd' => array('dd' => 1, 'dt' => 1),
1447
+ // Not optional, see
1448
+ // https://www.w3.org/TR/html/grouping-content.html#the-dl-element
1449
+ 'dl' => array('dd' => 1, 'dt' => 1),
1450
+ 'dt' => array('dd' => 1, 'dt' => 1),
1451
+ 'li' => array('li' => 1),
1452
+ 'optgroup' => array('optgroup' => 1, 'option' => 1),
1453
+ 'option' => array('optgroup' => 1, 'option' => 1),
1454
+ 'p' => array('p' => 1),
1455
+ 'rp' => array('rp' => 1, 'rt' => 1),
1456
+ 'rt' => array('rp' => 1, 'rt' => 1),
1457
+ 'td' => array('td' => 1, 'th' => 1),
1458
+ 'th' => array('td' => 1, 'th' => 1),
1459
+ 'tr' => array('td' => 1, 'th' => 1, 'tr' => 1),
1460
+ );
1461
+
1462
+ function __construct(
1463
+ $str = null,
1464
+ $lowercase = true,
1465
+ $forceTagsClosed = true,
1466
+ $target_charset = DEFAULT_TARGET_CHARSET,
1467
+ $stripRN = true,
1468
+ $defaultBRText = DEFAULT_BR_TEXT,
1469
+ $defaultSpanText = DEFAULT_SPAN_TEXT,
1470
+ $options = 0)
1471
+ {
1472
+ if ($str) {
1473
+ if (preg_match('/^http:\/\//i', $str) || is_file($str)) {
1474
+ $this->load_file($str);
1475
+ } else {
1476
+ $this->load(
1477
+ $str,
1478
+ $lowercase,
1479
+ $stripRN,
1480
+ $defaultBRText,
1481
+ $defaultSpanText,
1482
+ $options
1483
+ );
1484
+ }
1485
+ }
1486
+ // Forcing tags to be closed implies that we don't trust the html, but
1487
+ // it can lead to parsing errors if we SHOULD trust the html.
1488
+ if (!$forceTagsClosed) {
1489
+ $this->optional_closing_array = array();
1490
+ }
1491
+
1492
+ $this->_target_charset = $target_charset;
1493
+ }
1494
+
1495
+ function __destruct()
1496
+ {
1497
+ $this->clear();
1498
+ }
1499
+
1500
+ function load(
1501
+ $str,
1502
+ $lowercase = true,
1503
+ $stripRN = true,
1504
+ $defaultBRText = DEFAULT_BR_TEXT,
1505
+ $defaultSpanText = DEFAULT_SPAN_TEXT,
1506
+ $options = 0)
1507
+ {
1508
+ global $debug_object;
1509
+
1510
+ // prepare
1511
+ $this->prepare($str, $lowercase, $defaultBRText, $defaultSpanText);
1512
+
1513
+ // Per sourceforge http://sourceforge.net/tracker/?func=detail&aid=2949097&group_id=218559&atid=1044037
1514
+ // Script tags removal now preceeds style tag removal.
1515
+ // strip out <script> tags
1516
+ $this->remove_noise("'<\s*script[^>]*[^/]>(.*?)<\s*/\s*script\s*>'is");
1517
+ $this->remove_noise("'<\s*script\s*>(.*?)<\s*/\s*script\s*>'is");
1518
+
1519
+ // strip out the \r \n's if we are told to.
1520
+ if ($stripRN) {
1521
+ $this->doc = str_replace("\r", ' ', $this->doc);
1522
+ $this->doc = str_replace("\n", ' ', $this->doc);
1523
+
1524
+ // set the length of content since we have changed it.
1525
+ $this->size = strlen($this->doc);
1526
+ }
1527
+
1528
+ // strip out cdata
1529
+ $this->remove_noise("'<!\[CDATA\[(.*?)\]\]>'is", true);
1530
+ // strip out comments
1531
+ $this->remove_noise("'<!--(.*?)-->'is");
1532
+ // strip out <style> tags
1533
+ $this->remove_noise("'<\s*style[^>]*[^/]>(.*?)<\s*/\s*style\s*>'is");
1534
+ $this->remove_noise("'<\s*style\s*>(.*?)<\s*/\s*style\s*>'is");
1535
+ // strip out preformatted tags
1536
+ $this->remove_noise("'<\s*(?:code)[^>]*>(.*?)<\s*/\s*(?:code)\s*>'is");
1537
+ // strip out server side scripts
1538
+ $this->remove_noise("'(<\?)(.*?)(\?>)'s", true);
1539
+
1540
+ if($options & HDOM_SMARTY_AS_TEXT) { // Strip Smarty scripts
1541
+ $this->remove_noise("'(\{\w)(.*?)(\})'s", true);
1542
+ }
1543
+
1544
+ // parsing
1545
+ $this->parse();
1546
+ // end
1547
+ $this->root->_[HDOM_INFO_END] = $this->cursor;
1548
+ $this->parse_charset();
1549
+
1550
+ // make load function chainable
1551
+ return $this;
1552
+ }
1553
+
1554
+ function load_file()
1555
+ {
1556
+ $args = func_get_args();
1557
+
1558
+ if(($doc = call_user_func_array('file_get_contents', $args)) !== false) {
1559
+ $this->load($doc, true);
1560
+ } else {
1561
+ return false;
1562
+ }
1563
+ }
1564
+
1565
+ function set_callback($function_name)
1566
+ {
1567
+ $this->callback = $function_name;
1568
+ }
1569
+
1570
+ function remove_callback()
1571
+ {
1572
+ $this->callback = null;
1573
+ }
1574
+
1575
+ function save($filepath = '')
1576
+ {
1577
+ $ret = $this->root->innertext();
1578
+ if ($filepath !== '') { file_put_contents($filepath, $ret, LOCK_EX); }
1579
+ return $ret;
1580
+ }
1581
+
1582
+ function find($selector, $idx = null, $lowercase = false)
1583
+ {
1584
+ return $this->root->find($selector, $idx, $lowercase);
1585
+ }
1586
+
1587
+ function clear()
1588
+ {
1589
+ if (isset($this->nodes)) {
1590
+ foreach ($this->nodes as $n) {
1591
+ $n->clear();
1592
+ $n = null;
1593
+ }
1594
+ }
1595
+
1596
+ // This add next line is documented in the sourceforge repository.
1597
+ // 2977248 as a fix for ongoing memory leaks that occur even with the
1598
+ // use of clear.
1599
+ if (isset($this->children)) {
1600
+ foreach ($this->children as $n) {
1601
+ $n->clear();
1602
+ $n = null;
1603
+ }
1604
+ }
1605
+
1606
+ if (isset($this->parent)) {
1607
+ $this->parent->clear();
1608
+ unset($this->parent);
1609
+ }
1610
+
1611
+ if (isset($this->root)) {
1612
+ $this->root->clear();
1613
+ unset($this->root);
1614
+ }
1615
+
1616
+ unset($this->doc);
1617
+ unset($this->noise);
1618
+ }
1619
+
1620
+ function dump($show_attr = true)
1621
+ {
1622
+ $this->root->dump($show_attr);
1623
+ }
1624
+
1625
+ protected function prepare(
1626
+ $str, $lowercase = true,
1627
+ $defaultBRText = DEFAULT_BR_TEXT,
1628
+ $defaultSpanText = DEFAULT_SPAN_TEXT)
1629
+ {
1630
+ $this->clear();
1631
+
1632
+ $this->doc = trim($str);
1633
+ $this->size = strlen($this->doc);
1634
+ $this->original_size = $this->size; // original size of the html
1635
+ $this->pos = 0;
1636
+ $this->cursor = 1;
1637
+ $this->noise = array();
1638
+ $this->nodes = array();
1639
+ $this->lowercase = $lowercase;
1640
+ $this->default_br_text = $defaultBRText;
1641
+ $this->default_span_text = $defaultSpanText;
1642
+ $this->root = new simple_html_dom_node($this);
1643
+ $this->root->tag = 'root';
1644
+ $this->root->_[HDOM_INFO_BEGIN] = -1;
1645
+ $this->root->nodetype = HDOM_TYPE_ROOT;
1646
+ $this->parent = $this->root;
1647
+ if ($this->size > 0) { $this->char = $this->doc[0]; }
1648
+ }
1649
+
1650
+ protected function parse()
1651
+ {
1652
+ while (true) {
1653
+ // Read next tag if there is no text between current position and the
1654
+ // next opening tag.
1655
+ if (($s = $this->copy_until_char('<')) === '') {
1656
+ if($this->read_tag()) {
1657
+ continue;
1658
+ } else {
1659
+ return true;
1660
+ }
1661
+ }
1662
+
1663
+ // Add a text node for text between tags
1664
+ $node = new simple_html_dom_node($this);
1665
+ ++$this->cursor;
1666
+ $node->_[HDOM_INFO_TEXT] = $s;
1667
+ $this->link_nodes($node, false);
1668
+ }
1669
+ }
1670
+
1671
+ protected function parse_charset()
1672
+ {
1673
+ global $debug_object;
1674
+
1675
+ $charset = null;
1676
+
1677
+ if (function_exists('get_last_retrieve_url_contents_content_type')) {
1678
+ $contentTypeHeader = get_last_retrieve_url_contents_content_type();
1679
+ $success = preg_match('/charset=(.+)/', $contentTypeHeader, $matches);
1680
+ if ($success) {
1681
+ $charset = $matches[1];
1682
+ if (is_object($debug_object)) {
1683
+ $debug_object->debug_log(2,
1684
+ 'header content-type found charset of: '
1685
+ . $charset
1686
+ );
1687
+ }
1688
+ }
1689
+ }
1690
+
1691
+ if (empty($charset)) {
1692
+ // https://www.w3.org/TR/html/document-metadata.html#statedef-http-equiv-content-type
1693
+ $el = $this->root->find('meta[http-equiv=Content-Type]', 0, true);
1694
+
1695
+ if (!empty($el)) {
1696
+ $fullvalue = $el->content;
1697
+ if (is_object($debug_object)) {
1698
+ $debug_object->debug_log(2,
1699
+ 'meta content-type tag found'
1700
+ . $fullvalue
1701
+ );
1702
+ }
1703
+
1704
+ if (!empty($fullvalue)) {
1705
+ $success = preg_match(
1706
+ '/charset=(.+)/i',
1707
+ $fullvalue,
1708
+ $matches
1709
+ );
1710
+
1711
+ if ($success) {
1712
+ $charset = $matches[1];
1713
+ } else {
1714
+ // If there is a meta tag, and they don't specify the
1715
+ // character set, research says that it's typically
1716
+ // ISO-8859-1
1717
+ if (is_object($debug_object)) {
1718
+ $debug_object->debug_log(2,
1719
+ 'meta content-type tag couldn\'t be parsed. using iso-8859 default.'
1720
+ );
1721
+ }
1722
+
1723
+ $charset = 'ISO-8859-1';
1724
+ }
1725
+ }
1726
+ }
1727
+ }
1728
+
1729
+ if (empty($charset)) {
1730
+ // https://www.w3.org/TR/html/document-metadata.html#character-encoding-declaration
1731
+ if ($meta = $this->root->find('meta[charset]', 0)) {
1732
+ $charset = $meta->charset;
1733
+ if (is_object($debug_object)) {
1734
+ $debug_object->debug_log(2, 'meta charset: ' . $charset);
1735
+ }
1736
+ }
1737
+ }
1738
+
1739
+ if (empty($charset)) {
1740
+ // Try to guess the charset based on the content
1741
+ // Requires Multibyte String (mbstring) support (optional)
1742
+ if (function_exists('mb_detect_encoding')) {
1743
+ /**
1744
+ * mb_detect_encoding() is not intended to distinguish between
1745
+ * charsets, especially single-byte charsets. Its primary
1746
+ * purpose is to detect which multibyte encoding is in use,
1747
+ * i.e. UTF-8, UTF-16, shift-JIS, etc.
1748
+ *
1749
+ * -- https://bugs.php.net/bug.php?id=38138
1750
+ *
1751
+ * Adding both CP1251/ISO-8859-5 and CP1252/ISO-8859-1 will
1752
+ * always result in CP1251/ISO-8859-5 and vice versa.
1753
+ *
1754
+ * Thus, only detect if it's either UTF-8 or CP1252/ISO-8859-1
1755
+ * to stay compatible.
1756
+ */
1757
+ $encoding = mb_detect_encoding(
1758
+ $this->doc,
1759
+ array( 'UTF-8', 'CP1252', 'ISO-8859-1' )
1760
+ );
1761
+
1762
+ if ($encoding === 'CP1252' || $encoding === 'ISO-8859-1') {
1763
+ // Due to a limitation of mb_detect_encoding
1764
+ // 'CP1251'/'ISO-8859-5' will be detected as
1765
+ // 'CP1252'/'ISO-8859-1'. This will cause iconv to fail, in
1766
+ // which case we can simply assume it is the other charset.
1767
+ if (!@iconv('CP1252', 'UTF-8', $this->doc)) {
1768
+ $encoding = 'CP1251';
1769
+ }
1770
+ }
1771
+
1772
+ if ($encoding !== false) {
1773
+ $charset = $encoding;
1774
+ if (is_object($debug_object)) {
1775
+ $debug_object->debug_log(2, 'mb_detect: ' . $charset);
1776
+ }
1777
+ }
1778
+ }
1779
+ }
1780
+
1781
+ if (empty($charset)) {
1782
+ // Assume it's UTF-8 as it is the most likely charset to be used
1783
+ $charset = 'UTF-8';
1784
+ if (is_object($debug_object)) {
1785
+ $debug_object->debug_log(2, 'No match found, assume ' . $charset);
1786
+ }
1787
+ }
1788
+
1789
+ // Since CP1252 is a superset, if we get one of it's subsets, we want
1790
+ // it instead.
1791
+ if ((strtolower($charset) == 'iso-8859-1')
1792
+ || (strtolower($charset) == 'latin1')
1793
+ || (strtolower($charset) == 'latin-1')) {
1794
+ $charset = 'CP1252';
1795
+ if (is_object($debug_object)) {
1796
+ $debug_object->debug_log(2,
1797
+ 'replacing ' . $charset . ' with CP1252 as its a superset'
1798
+ );
1799
+ }
1800
+ }
1801
+
1802
+ if (is_object($debug_object)) {
1803
+ $debug_object->debug_log(1, 'EXIT - ' . $charset);
1804
+ }
1805
+
1806
+ return $this->_charset = $charset;
1807
+ }
1808
+
1809
+ protected function read_tag()
1810
+ {
1811
+ // Set end position if no further tags found
1812
+ if ($this->char !== '<') {
1813
+ $this->root->_[HDOM_INFO_END] = $this->cursor;
1814
+ return false;
1815
+ }
1816
+
1817
+ $begin_tag_pos = $this->pos;
1818
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
1819
+
1820
+ // end tag
1821
+ if ($this->char === '/') {
1822
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
1823
+
1824
+ // Skip whitespace in end tags (i.e. in "</ html>")
1825
+ $this->skip($this->token_blank);
1826
+ $tag = $this->copy_until_char('>');
1827
+
1828
+ // Skip attributes in end tags
1829
+ if (($pos = strpos($tag, ' ')) !== false) {
1830
+ $tag = substr($tag, 0, $pos);
1831
+ }
1832
+
1833
+ $parent_lower = strtolower($this->parent->tag);
1834
+ $tag_lower = strtolower($tag);
1835
+
1836
+ // The end tag is supposed to close the parent tag. Handle situations
1837
+ // when it doesn't
1838
+ if ($parent_lower !== $tag_lower) {
1839
+ // Parent tag does not have to be closed necessarily (optional closing tag)
1840
+ // Current tag is a block tag, so it may close an ancestor
1841
+ if (isset($this->optional_closing_tags[$parent_lower])
1842
+ && isset($this->block_tags[$tag_lower])) {
1843
+
1844
+ $this->parent->_[HDOM_INFO_END] = 0;
1845
+ $org_parent = $this->parent;
1846
+
1847
+ // Traverse ancestors to find a matching opening tag
1848
+ // Stop at root node
1849
+ while (($this->parent->parent)
1850
+ && strtolower($this->parent->tag) !== $tag_lower
1851
+ ){
1852
+ $this->parent = $this->parent->parent;
1853
+ }
1854
+
1855
+ // If we don't have a match add current tag as text node
1856
+ if (strtolower($this->parent->tag) !== $tag_lower) {
1857
+ $this->parent = $org_parent; // restore origonal parent
1858
+
1859
+ if ($this->parent->parent) {
1860
+ $this->parent = $this->parent->parent;
1861
+ }
1862
+
1863
+ $this->parent->_[HDOM_INFO_END] = $this->cursor;
1864
+ return $this->as_text_node($tag);
1865
+ }
1866
+ } elseif (($this->parent->parent)
1867
+ && isset($this->block_tags[$tag_lower])
1868
+ ) {
1869
+ // Grandparent exists and current tag is a block tag, so our
1870
+ // parent doesn't have an end tag
1871
+ $this->parent->_[HDOM_INFO_END] = 0; // No end tag
1872
+ $org_parent = $this->parent;
1873
+
1874
+ // Traverse ancestors to find a matching opening tag
1875
+ // Stop at root node
1876
+ while (($this->parent->parent)
1877
+ && strtolower($this->parent->tag) !== $tag_lower
1878
+ ) {
1879
+ $this->parent = $this->parent->parent;
1880
+ }
1881
+
1882
+ // If we don't have a match add current tag as text node
1883
+ if (strtolower($this->parent->tag) !== $tag_lower) {
1884
+ $this->parent = $org_parent; // restore origonal parent
1885
+ $this->parent->_[HDOM_INFO_END] = $this->cursor;
1886
+ return $this->as_text_node($tag);
1887
+ }
1888
+ } elseif (($this->parent->parent)
1889
+ && strtolower($this->parent->parent->tag) === $tag_lower
1890
+ ) { // Grandparent exists and current tag closes it
1891
+ $this->parent->_[HDOM_INFO_END] = 0;
1892
+ $this->parent = $this->parent->parent;
1893
+ } else { // Random tag, add as text node
1894
+ return $this->as_text_node($tag);
1895
+ }
1896
+ }
1897
+
1898
+ // Set end position of parent tag to current cursor position
1899
+ $this->parent->_[HDOM_INFO_END] = $this->cursor;
1900
+
1901
+ if ($this->parent->parent) {
1902
+ $this->parent = $this->parent->parent;
1903
+ }
1904
+
1905
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
1906
+ return true;
1907
+ }
1908
+
1909
+ // start tag
1910
+ $node = new simple_html_dom_node($this);
1911
+ $node->_[HDOM_INFO_BEGIN] = $this->cursor;
1912
+ ++$this->cursor;
1913
+ $tag = $this->copy_until($this->token_slash); // Get tag name
1914
+ $node->tag_start = $begin_tag_pos;
1915
+
1916
+ // doctype, cdata & comments...
1917
+ // <!DOCTYPE html>
1918
+ // <![CDATA[ ... ]]>
1919
+ // <!-- Comment -->
1920
+ if (isset($tag[0]) && $tag[0] === '!') {
1921
+ $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until_char('>');
1922
+
1923
+ if (isset($tag[2]) && $tag[1] === '-' && $tag[2] === '-') { // Comment ("<!--")
1924
+ $node->nodetype = HDOM_TYPE_COMMENT;
1925
+ $node->tag = 'comment';
1926
+ } else { // Could be doctype or CDATA but we don't care
1927
+ $node->nodetype = HDOM_TYPE_UNKNOWN;
1928
+ $node->tag = 'unknown';
1929
+ }
1930
+
1931
+ if ($this->char === '>') { $node->_[HDOM_INFO_TEXT] .= '>'; }
1932
+
1933
+ $this->link_nodes($node, true);
1934
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
1935
+ return true;
1936
+ }
1937
+
1938
+ // The start tag cannot contain another start tag, if so add as text
1939
+ // i.e. "<<html>"
1940
+ if ($pos = strpos($tag, '<') !== false) {
1941
+ $tag = '<' . substr($tag, 0, -1);
1942
+ $node->_[HDOM_INFO_TEXT] = $tag;
1943
+ $this->link_nodes($node, false);
1944
+ $this->char = $this->doc[--$this->pos]; // prev
1945
+ return true;
1946
+ }
1947
+
1948
+ // Handle invalid tag names (i.e. "<html#doc>")
1949
+ if (!preg_match('/^\w[\w:-]*$/', $tag)) {
1950
+ $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until('<>');
1951
+
1952
+ // Next char is the beginning of a new tag, don't touch it.
1953
+ if ($this->char === '<') {
1954
+ $this->link_nodes($node, false);
1955
+ return true;
1956
+ }
1957
+
1958
+ // Next char closes current tag, add and be done with it.
1959
+ if ($this->char === '>') { $node->_[HDOM_INFO_TEXT] .= '>'; }
1960
+ $this->link_nodes($node, false);
1961
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
1962
+ return true;
1963
+ }
1964
+
1965
+ // begin tag, add new node
1966
+ $node->nodetype = HDOM_TYPE_ELEMENT;
1967
+ $tag_lower = strtolower($tag);
1968
+ $node->tag = ($this->lowercase) ? $tag_lower : $tag;
1969
+
1970
+ // handle optional closing tags
1971
+ if (isset($this->optional_closing_tags[$tag_lower])) {
1972
+ // Traverse ancestors to close all optional closing tags
1973
+ while (isset($this->optional_closing_tags[$tag_lower][strtolower($this->parent->tag)])) {
1974
+ $this->parent->_[HDOM_INFO_END] = 0;
1975
+ $this->parent = $this->parent->parent;
1976
+ }
1977
+ $node->parent = $this->parent;
1978
+ }
1979
+
1980
+ $guard = 0; // prevent infinity loop
1981
+
1982
+ // [0] Space between tag and first attribute
1983
+ $space = array($this->copy_skip($this->token_blank), '', '');
1984
+
1985
+ // attributes
1986
+ do {
1987
+ // Everything until the first equal sign should be the attribute name
1988
+ $name = $this->copy_until($this->token_equal);
1989
+
1990
+ if ($name === '' && $this->char !== null && $space[0] === '') {
1991
+ break;
1992
+ }
1993
+
1994
+ if ($guard === $this->pos) { // Escape infinite loop
1995
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
1996
+ continue;
1997
+ }
1998
+
1999
+ $guard = $this->pos;
2000
+
2001
+ // handle endless '<'
2002
+ // Out of bounds before the tag ended
2003
+ if ($this->pos >= $this->size - 1 && $this->char !== '>') {
2004
+ $node->nodetype = HDOM_TYPE_TEXT;
2005
+ $node->_[HDOM_INFO_END] = 0;
2006
+ $node->_[HDOM_INFO_TEXT] = '<' . $tag . $space[0] . $name;
2007
+ $node->tag = 'text';
2008
+ $this->link_nodes($node, false);
2009
+ return true;
2010
+ }
2011
+
2012
+ // handle mismatch '<'
2013
+ // Attributes cannot start after opening tag
2014
+ if ($this->doc[$this->pos - 1] == '<') {
2015
+ $node->nodetype = HDOM_TYPE_TEXT;
2016
+ $node->tag = 'text';
2017
+ $node->attr = array();
2018
+ $node->_[HDOM_INFO_END] = 0;
2019
+ $node->_[HDOM_INFO_TEXT] = substr(
2020
+ $this->doc,
2021
+ $begin_tag_pos,
2022
+ $this->pos - $begin_tag_pos - 1
2023
+ );
2024
+ $this->pos -= 2;
2025
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2026
+ $this->link_nodes($node, false);
2027
+ return true;
2028
+ }
2029
+
2030
+ if ($name !== '/' && $name !== '') { // this is a attribute name
2031
+ // [1] Whitespace after attribute name
2032
+ $space[1] = $this->copy_skip($this->token_blank);
2033
+
2034
+ $name = $this->restore_noise($name); // might be a noisy name
2035
+
2036
+ if ($this->lowercase) { $name = strtolower($name); }
2037
+
2038
+ if ($this->char === '=') { // attribute with value
2039
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2040
+ $this->parse_attr($node, $name, $space); // get attribute value
2041
+ } else {
2042
+ //no value attr: nowrap, checked selected...
2043
+ $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_NO;
2044
+ $node->attr[$name] = true;
2045
+ if ($this->char != '>') { $this->char = $this->doc[--$this->pos]; } // prev
2046
+ }
2047
+
2048
+ $node->_[HDOM_INFO_SPACE][] = $space;
2049
+
2050
+ // prepare for next attribute
2051
+ $space = array(
2052
+ $this->copy_skip($this->token_blank),
2053
+ '',
2054
+ ''
2055
+ );
2056
+ } else { // no more attributes
2057
+ break;
2058
+ }
2059
+ } while ($this->char !== '>' && $this->char !== '/'); // go until the tag ended
2060
+
2061
+ $this->link_nodes($node, true);
2062
+ $node->_[HDOM_INFO_ENDSPACE] = $space[0];
2063
+
2064
+ // handle empty tags (i.e. "<div/>")
2065
+ if ($this->copy_until_char('>') === '/') {
2066
+ $node->_[HDOM_INFO_ENDSPACE] .= '/';
2067
+ $node->_[HDOM_INFO_END] = 0;
2068
+ } else {
2069
+ // reset parent
2070
+ if (!isset($this->self_closing_tags[strtolower($node->tag)])) {
2071
+ $this->parent = $node;
2072
+ }
2073
+ }
2074
+
2075
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2076
+
2077
+ // If it's a BR tag, we need to set it's text to the default text.
2078
+ // This way when we see it in plaintext, we can generate formatting that the user wants.
2079
+ // since a br tag never has sub nodes, this works well.
2080
+ if ($node->tag === 'br') {
2081
+ $node->_[HDOM_INFO_INNER] = $this->default_br_text;
2082
+ }
2083
+
2084
+ return true;
2085
+ }
2086
+
2087
+ protected function parse_attr($node, $name, &$space)
2088
+ {
2089
+ $is_duplicate = isset($node->attr[$name]);
2090
+
2091
+ if (!$is_duplicate) // Copy whitespace between "=" and value
2092
+ $space[2] = $this->copy_skip($this->token_blank);
2093
+
2094
+ switch ($this->char) {
2095
+ case '"':
2096
+ $quote_type = HDOM_QUOTE_DOUBLE;
2097
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2098
+ $value = $this->copy_until_char('"');
2099
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2100
+ break;
2101
+ case '\'':
2102
+ $quote_type = HDOM_QUOTE_SINGLE;
2103
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2104
+ $value = $this->copy_until_char('\'');
2105
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2106
+ break;
2107
+ default:
2108
+ $quote_type = HDOM_QUOTE_NO;
2109
+ $value = $this->copy_until($this->token_attr);
2110
+ }
2111
+
2112
+ $value = $this->restore_noise($value);
2113
+
2114
+ // PaperG: Attributes should not have \r or \n in them, that counts as
2115
+ // html whitespace.
2116
+ $value = str_replace("\r", '', $value);
2117
+ $value = str_replace("\n", '', $value);
2118
+
2119
+ // PaperG: If this is a "class" selector, lets get rid of the preceeding
2120
+ // and trailing space since some people leave it in the multi class case.
2121
+ if ($name === 'class') {
2122
+ $value = trim($value);
2123
+ }
2124
+
2125
+ if (!$is_duplicate) {
2126
+ $node->_[HDOM_INFO_QUOTE][] = $quote_type;
2127
+ $node->attr[$name] = $value;
2128
+ }
2129
+ }
2130
+
2131
+ protected function link_nodes(&$node, $is_child)
2132
+ {
2133
+ $node->parent = $this->parent;
2134
+ $this->parent->nodes[] = $node;
2135
+ if ($is_child) {
2136
+ $this->parent->children[] = $node;
2137
+ }
2138
+ }
2139
+
2140
+ protected function as_text_node($tag)
2141
+ {
2142
+ $node = new simple_html_dom_node($this);
2143
+ ++$this->cursor;
2144
+ $node->_[HDOM_INFO_TEXT] = '</' . $tag . '>';
2145
+ $this->link_nodes($node, false);
2146
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2147
+ return true;
2148
+ }
2149
+
2150
+ protected function skip($chars)
2151
+ {
2152
+ $this->pos += strspn($this->doc, $chars, $this->pos);
2153
+ $this->char = ($this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2154
+ }
2155
+
2156
+ protected function copy_skip($chars)
2157
+ {
2158
+ $pos = $this->pos;
2159
+ $len = strspn($this->doc, $chars, $pos);
2160
+ $this->pos += $len;
2161
+ $this->char = ($this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2162
+ if ($len === 0) { return ''; }
2163
+ return substr($this->doc, $pos, $len);
2164
+ }
2165
+
2166
+ protected function copy_until($chars)
2167
+ {
2168
+ $pos = $this->pos;
2169
+ $len = strcspn($this->doc, $chars, $pos);
2170
+ $this->pos += $len;
2171
+ $this->char = ($this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2172
+ return substr($this->doc, $pos, $len);
2173
+ }
2174
+
2175
+ protected function copy_until_char($char)
2176
+ {
2177
+ if ($this->char === null) { return ''; }
2178
+
2179
+ if (($pos = strpos($this->doc, $char, $this->pos)) === false) {
2180
+ $ret = substr($this->doc, $this->pos, $this->size - $this->pos);
2181
+ $this->char = null;
2182
+ $this->pos = $this->size;
2183
+ return $ret;
2184
+ }
2185
+
2186
+ if ($pos === $this->pos) { return ''; }
2187
+
2188
+ $pos_old = $this->pos;
2189
+ $this->char = $this->doc[$pos];
2190
+ $this->pos = $pos;
2191
+ return substr($this->doc, $pos_old, $pos - $pos_old);
2192
+ }
2193
+
2194
+ protected function remove_noise($pattern, $remove_tag = false)
2195
+ {
2196
+ global $debug_object;
2197
+ if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
2198
+
2199
+ $count = preg_match_all(
2200
+ $pattern,
2201
+ $this->doc,
2202
+ $matches,
2203
+ PREG_SET_ORDER | PREG_OFFSET_CAPTURE
2204
+ );
2205
+
2206
+ for ($i = $count - 1; $i > -1; --$i) {
2207
+ $key = '___noise___' . sprintf('% 5d', count($this->noise) + 1000);
2208
+
2209
+ if (is_object($debug_object)) {
2210
+ $debug_object->debug_log(2, 'key is: ' . $key);
2211
+ }
2212
+
2213
+ $idx = ($remove_tag) ? 0 : 1; // 0 = entire match, 1 = submatch
2214
+ $this->noise[$key] = $matches[$i][$idx][0];
2215
+ $this->doc = substr_replace($this->doc, $key, $matches[$i][$idx][1], strlen($matches[$i][$idx][0]));
2216
+ }
2217
+
2218
+ // reset the length of content
2219
+ $this->size = strlen($this->doc);
2220
+
2221
+ if ($this->size > 0) {
2222
+ $this->char = $this->doc[0];
2223
+ }
2224
+ }
2225
+
2226
+ function restore_noise($text)
2227
+ {
2228
+ global $debug_object;
2229
+ if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
2230
+
2231
+ while (($pos = strpos($text, '___noise___')) !== false) {
2232
+ // Sometimes there is a broken piece of markup, and we don't GET the
2233
+ // pos+11 etc... token which indicates a problem outside of us...
2234
+
2235
+ // todo: "___noise___1000" (or any number with four or more digits)
2236
+ // in the DOM causes an infinite loop which could be utilized by
2237
+ // malicious software
2238
+ if (strlen($text) > $pos + 15) {
2239
+ $key = '___noise___'
2240
+ . $text[$pos + 11]
2241
+ . $text[$pos + 12]
2242
+ . $text[$pos + 13]
2243
+ . $text[$pos + 14]
2244
+ . $text[$pos + 15];
2245
+
2246
+ if (is_object($debug_object)) {
2247
+ $debug_object->debug_log(2, 'located key of: ' . $key);
2248
+ }
2249
+
2250
+ if (isset($this->noise[$key])) {
2251
+ $text = substr($text, 0, $pos)
2252
+ . $this->noise[$key]
2253
+ . substr($text, $pos + 16);
2254
+ } else {
2255
+ // do this to prevent an infinite loop.
2256
+ $text = substr($text, 0, $pos)
2257
+ . 'UNDEFINED NOISE FOR KEY: '
2258
+ . $key
2259
+ . substr($text, $pos + 16);
2260
+ }
2261
+ } else {
2262
+ // There is no valid key being given back to us... We must get
2263
+ // rid of the ___noise___ or we will have a problem.
2264
+ $text = substr($text, 0, $pos)
2265
+ . 'NO NUMERIC NOISE KEY'
2266
+ . substr($text, $pos + 11);
2267
+ }
2268
+ }
2269
+ return $text;
2270
+ }
2271
+
2272
+ function search_noise($text)
2273
+ {
2274
+ global $debug_object;
2275
+ if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
2276
+
2277
+ foreach($this->noise as $noiseElement) {
2278
+ if (strpos($noiseElement, $text) !== false) {
2279
+ return $noiseElement;
2280
+ }
2281
+ }
2282
+ }
2283
+
2284
+ function __toString()
2285
+ {
2286
+ return $this->root->innertext();
2287
+ }
2288
+
2289
+ function __get($name)
2290
+ {
2291
+ switch ($name) {
2292
+ case 'outertext':
2293
+ return $this->root->innertext();
2294
+ case 'innertext':
2295
+ return $this->root->innertext();
2296
+ case 'plaintext':
2297
+ return $this->root->text();
2298
+ case 'charset':
2299
+ return $this->_charset;
2300
+ case 'target_charset':
2301
+ return $this->_target_charset;
2302
+ }
2303
+ }
2304
+
2305
+ function childNodes($idx = -1)
2306
+ {
2307
+ return $this->root->childNodes($idx);
2308
+ }
2309
+
2310
+ function firstChild()
2311
+ {
2312
+ return $this->root->first_child();
2313
+ }
2314
+
2315
+ function lastChild()
2316
+ {
2317
+ return $this->root->last_child();
2318
+ }
2319
+
2320
+ function createElement($name, $value = null)
2321
+ {
2322
+ return @str_get_html("<$name>$value</$name>")->firstChild();
2323
+ }
2324
+
2325
+ function createTextNode($value)
2326
+ {
2327
+ return @end(str_get_html($value)->nodes);
2328
+ }
2329
+
2330
+ function getElementById($id)
2331
+ {
2332
+ return $this->find("#$id", 0);
2333
+ }
2334
+
2335
+ function getElementsById($id, $idx = null)
2336
+ {
2337
+ return $this->find("#$id", $idx);
2338
+ }
2339
+
2340
+ function getElementByTagName($name)
2341
+ {
2342
+ return $this->find($name, 0);
2343
+ }
2344
+
2345
+ function getElementsByTagName($name, $idx = -1)
2346
+ {
2347
+ return $this->find($name, $idx);
2348
+ }
2349
+
2350
+ function loadFile()
2351
+ {
2352
+ $args = func_get_args();
2353
+ $this->load_file($args);
2354
+ }
2355
+ }
vendor/rosell-dk/dom-util-for-webp/README.md CHANGED
@@ -2,7 +2,7 @@
2
 
3
  [![Latest Stable Version](https://img.shields.io/packagist/v/rosell-dk/dom-util-for-webp.svg?style=flat-square)](https://packagist.org/packages/rosell-dk/dom-util-for-webp)
4
  [![Minimum PHP Version](https://img.shields.io/badge/php-%3E%3D%205.6-8892BF.svg?style=flat-square)](https://php.net)
5
- [![Build Status](https://img.shields.io/github/workflow/status/rosell-dk/dom-util-for-webp/PHP?style=flat-square)](https://github.com/rosell-dk/dom-util-for-webp/actions/workflows/php.yml)
6
  [![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/rosell-dk/dom-util-for-webp.svg?style=flat-square)](https://scrutinizer-ci.com/g/rosell-dk/dom-util-for-webp/code-structure/master)
7
  [![Quality Score](https://img.shields.io/scrutinizer/g/rosell-dk/dom-util-for-webp.svg?style=flat-square)](https://scrutinizer-ci.com/g/rosell-dk/dom-util-for-webp/)
8
  [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](https://github.com/rosell-dk/dom-util-for-webp/blob/master/LICENSE)
2
 
3
  [![Latest Stable Version](https://img.shields.io/packagist/v/rosell-dk/dom-util-for-webp.svg?style=flat-square)](https://packagist.org/packages/rosell-dk/dom-util-for-webp)
4
  [![Minimum PHP Version](https://img.shields.io/badge/php-%3E%3D%205.6-8892BF.svg?style=flat-square)](https://php.net)
5
+ [![Build Status](https://img.shields.io/github/workflow/status/rosell-dk/dom-util-for-webp/PHP?logo=GitHub&style=flat-square)](https://github.com/rosell-dk/dom-util-for-webp/actions/workflows/php.yml)
6
  [![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/rosell-dk/dom-util-for-webp.svg?style=flat-square)](https://scrutinizer-ci.com/g/rosell-dk/dom-util-for-webp/code-structure/master)
7
  [![Quality Score](https://img.shields.io/scrutinizer/g/rosell-dk/dom-util-for-webp.svg?style=flat-square)](https://scrutinizer-ci.com/g/rosell-dk/dom-util-for-webp/)
8
  [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](https://github.com/rosell-dk/dom-util-for-webp/blob/master/LICENSE)
vendor/rosell-dk/dom-util-for-webp/composer.json CHANGED
@@ -55,5 +55,8 @@
55
  },
56
  "config": {
57
  "sort-packages": true
 
 
 
58
  }
59
  }
55
  },
56
  "config": {
57
  "sort-packages": true
58
+ },
59
+ "require": {
60
+ "kub-at/php-simple-html-dom-parser": "^1.9"
61
  }
62
  }
vendor/rosell-dk/dom-util-for-webp/phpstan.neon ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ parameters:
2
+ ignoreErrors:
3
+ - '#Function str_get_html not found.#'
vendor/rosell-dk/dom-util-for-webp/src-vendor/simple_html_dom/simple_html_dom.inc DELETED
@@ -1,2930 +0,0 @@
1
- <?php
2
- /**
3
- * Website: http://sourceforge.net/projects/simplehtmldom/
4
- * Additional projects: http://sourceforge.net/projects/debugobject/
5
- * Acknowledge: Jose Solorzano (https://sourceforge.net/projects/php-html/)
6
- * Contributions by:
7
- * Yousuke Kumakura (Attribute filters)
8
- * Vadim Voituk (Negative indexes supports of "find" method)
9
- * Antcs (Constructor with automatically load contents either text or file/url)
10
- *
11
- * all affected sections have comments starting with "PaperG"
12
- *
13
- * Paperg - Added case insensitive testing of the value of the selector.
14
- *
15
- * Paperg - Added tag_start for the starting index of tags - NOTE: This works
16
- * but not accurately. This tag_start gets counted AFTER \r\n have been crushed
17
- * out, and after the remove_noice calls so it will not reflect the REAL
18
- * position of the tag in the source, it will almost always be smaller by some
19
- * amount. We use this to determine how far into the file the tag in question
20
- * is. This "percentage" will never be accurate as the $dom->size is the "real"
21
- * number of bytes the dom was created from. But for most purposes, it's a
22
- * really good estimation.
23
- *
24
- * Paperg - Added the forceTagsClosed to the dom constructor. Forcing tags
25
- * closed is great for malformed html, but it CAN lead to parsing errors.
26
- *
27
- * Allow the user to tell us how much they trust the html.
28
- *
29
- * Paperg add the text and plaintext to the selectors for the find syntax.
30
- * plaintext implies text in the innertext of a node. text implies that the
31
- * tag is a text node. This allows for us to find tags based on the text they
32
- * contain.
33
- *
34
- * Create find_ancestor_tag to see if a tag is - at any level - inside of
35
- * another specific tag.
36
- *
37
- * Paperg: added parse_charset so that we know about the character set of
38
- * the source document. NOTE: If the user's system has a routine called
39
- * get_last_retrieve_url_contents_content_type availalbe, we will assume it's
40
- * returning the content-type header from the last transfer or curl_exec, and
41
- * we will parse that and use it in preference to any other method of charset
42
- * detection.
43
- *
44
- * Found infinite loop in the case of broken html in restore_noise. Rewrote to
45
- * protect from that.
46
- *
47
- * PaperG (John Schlick) Added get_display_size for "IMG" tags.
48
- *
49
- * Licensed under The MIT License
50
- * Redistributions of files must retain the above copyright notice.
51
- *
52
- * @author S.C. Chen <me578022@gmail.com>
53
- * @author John Schlick
54
- * @author Rus Carroll
55
- * @version Rev. 1.8.1 (247)
56
- * @package PlaceLocalInclude
57
- * @subpackage simple_html_dom
58
- */
59
-
60
- /**
61
- * All of the Defines for the classes below.
62
- * @author S.C. Chen <me578022@gmail.com>
63
- */
64
- define('HDOM_TYPE_ELEMENT', 1);
65
- define('HDOM_TYPE_COMMENT', 2);
66
- define('HDOM_TYPE_TEXT', 3);
67
- define('HDOM_TYPE_ENDTAG', 4);
68
- define('HDOM_TYPE_ROOT', 5);
69
- define('HDOM_TYPE_UNKNOWN', 6);
70
- define('HDOM_QUOTE_DOUBLE', 0);
71
- define('HDOM_QUOTE_SINGLE', 1);
72
- define('HDOM_QUOTE_NO', 3);
73
- define('HDOM_INFO_BEGIN', 0);
74
- define('HDOM_INFO_END', 1);
75
- define('HDOM_INFO_QUOTE', 2);
76
- define('HDOM_INFO_SPACE', 3);
77
- define('HDOM_INFO_TEXT', 4);
78
- define('HDOM_INFO_INNER', 5);
79
- define('HDOM_INFO_OUTER', 6);
80
- define('HDOM_INFO_ENDSPACE', 7);
81
-
82
- /** The default target charset */
83
- defined('DEFAULT_TARGET_CHARSET') || define('DEFAULT_TARGET_CHARSET', 'UTF-8');
84
-
85
- /** The default <br> text used instead of <br> tags when returning text */
86
- defined('DEFAULT_BR_TEXT') || define('DEFAULT_BR_TEXT', "\r\n");
87
-
88
- /** The default <span> text used instead of <span> tags when returning text */
89
- defined('DEFAULT_SPAN_TEXT') || define('DEFAULT_SPAN_TEXT', ' ');
90
-
91
- /** The maximum file size the parser should load */
92
- defined('MAX_FILE_SIZE') || define('MAX_FILE_SIZE', 600000);
93
-
94
- /** Contents between curly braces "{" and "}" are interpreted as text */
95
- define('HDOM_SMARTY_AS_TEXT', 1);
96
-
97
- // helper functions
98
- // -----------------------------------------------------------------------------
99
- // get html dom from file
100
- // $maxlen is defined in the code as PHP_STREAM_COPY_ALL which is defined as -1.
101
- function file_get_html(
102
- $url,
103
- $use_include_path = false,
104
- $context = null,
105
- $offset = 0,
106
- $maxLen = -1,
107
- $lowercase = true,
108
- $forceTagsClosed = true,
109
- $target_charset = DEFAULT_TARGET_CHARSET,
110
- $stripRN = true,
111
- $defaultBRText = DEFAULT_BR_TEXT,
112
- $defaultSpanText = DEFAULT_SPAN_TEXT
113
- ) {
114
- // Ensure maximum length is greater than zero
115
- if ($maxLen <= 0) {
116
- $maxLen = MAX_FILE_SIZE;
117
- }
118
-
119
- // We DO force the tags to be terminated.
120
- $dom = new simple_html_dom(
121
- null,
122
- $lowercase,
123
- $forceTagsClosed,
124
- $target_charset,
125
- $stripRN,
126
- $defaultBRText,
127
- $defaultSpanText
128
- );
129
-
130
- /**
131
- * For sourceforge users: uncomment the next line and comment the
132
- * retrieve_url_contents line 2 lines down if it is not already done.
133
- */
134
- $contents = file_get_contents(
135
- $url,
136
- $use_include_path,
137
- $context,
138
- $offset,
139
- $maxLen
140
- );
141
-
142
- // Paperg - use our own mechanism for getting the contents as we want to
143
- // control the timeout.
144
- // $contents = retrieve_url_contents($url);
145
- if (empty($contents) || strlen($contents) > $maxLen) {
146
- return false;
147
- }
148
-
149
- // The second parameter can force the selectors to all be lowercase.
150
- $dom->load($contents, $lowercase, $stripRN);
151
- return $dom;
152
- }
153
-
154
- // get html dom from string
155
- function str_get_html(
156
- $str,
157
- $lowercase = true,
158
- $forceTagsClosed = true,
159
- $target_charset = DEFAULT_TARGET_CHARSET,
160
- $stripRN = true,
161
- $defaultBRText = DEFAULT_BR_TEXT,
162
- $defaultSpanText = DEFAULT_SPAN_TEXT
163
- ) {
164
- $dom = new simple_html_dom(
165
- null,
166
- $lowercase,
167
- $forceTagsClosed,
168
- $target_charset,
169
- $stripRN,
170
- $defaultBRText,
171
- $defaultSpanText
172
- );
173
-
174
- if (empty($str) || strlen($str) > MAX_FILE_SIZE) {
175
- $dom->clear();
176
- return false;
177
- }
178
-
179
- $dom->load($str, $lowercase, $stripRN);
180
- return $dom;
181
- }
182
-
183
- // dump html dom tree
184
- function dump_html_tree($node, $show_attr = true, $deep = 0)
185
- {
186
- $node->dump($node);
187
- }
188
-
189
- /**
190
- * simple html dom node
191
- * PaperG - added ability for "find" routine to lowercase the value of the
192
- * selector.
193
- *
194
- * PaperG - added $tag_start to track the start position of the tag in the total
195
- * byte index
196
- *
197
- * @package PlaceLocalInclude
198
- */
199
- class simple_html_dom_node
200
- {
201
- /**
202
- * Node type
203
- *
204
- * Default is {@see HDOM_TYPE_TEXT}
205
- *
206
- * @var int
207
- */
208
- public $nodetype = HDOM_TYPE_TEXT;
209
-
210
- /**
211
- * Tag name
212
- *
213
- * Default is 'text'
214
- *
215
- * @var string
216
- */
217
- public $tag = 'text';
218
-
219
- /**
220
- * List of attributes
221
- *
222
- * @var array
223
- */
224
- public $attr = array();
225
-
226
- /**
227
- * List of child node objects
228
- *
229
- * @var array
230
- */
231
- public $children = array();
232
- public $nodes = array();
233
-
234
- /**
235
- * The parent node object
236
- *
237
- * @var object|null
238
- */
239
- public $parent = null;
240
-
241
- // The "info" array - see HDOM_INFO_... for what each element contains.
242
- public $_ = array();
243
-
244
- /**
245
- * Start position of the tag in the document
246
- *
247
- * @var int
248
- */
249
- public $tag_start = 0;
250
-
251
- /**
252
- * The DOM object
253
- *
254
- * @var object|null
255
- */
256
- private $dom = null;
257
-
258
- /**
259
- * Construct new node object
260
- *
261
- * Adds itself to the list of DOM Nodes {@see simple_html_dom::$nodes}
262
- */
263
- function __construct($dom)
264
- {
265
- $this->dom = $dom;
266
- $dom->nodes[] = $this;
267
- }
268
-
269
- function __destruct()
270
- {
271
- $this->clear();
272
- }
273
-
274
- function __toString()
275
- {
276
- return $this->outertext();
277
- }
278
-
279
- // clean up memory due to php5 circular references memory leak...
280
- function clear()
281
- {
282
- $this->dom = null;
283
- $this->nodes = null;
284
- $this->parent = null;
285
- $this->children = null;
286
- }
287
-
288
- // dump node's tree
289
- function dump($show_attr = true, $deep = 0)
290
- {
291
- $lead = str_repeat(' ', $deep);
292
-
293
- echo $lead . $this->tag;
294
-
295
- if ($show_attr && count($this->attr) > 0) {
296
- echo '(';
297
- foreach ($this->attr as $k => $v) {
298
- echo "[$k]=>\"" . $this->$k . '", ';
299
- }
300
- echo ')';
301
- }
302
-
303
- echo "\n";
304
-
305
- if ($this->nodes) {
306
- foreach ($this->nodes as $c) {
307
- $c->dump($show_attr, $deep + 1);
308
- }
309
- }
310
- }
311
-
312
-
313
- // Debugging function to dump a single dom node with a bunch of information about it.
314
- function dump_node($echo = true)
315
- {
316
- $string = $this->tag;
317
-
318
- if (count($this->attr) > 0) {
319
- $string .= '(';
320
- foreach ($this->attr as $k => $v) {
321
- $string .= "[$k]=>\"" . $this->$k . '", ';
322
- }
323
- $string .= ')';
324
- }
325
-
326
- if (count($this->_) > 0) {
327
- $string .= ' $_ (';
328
- foreach ($this->_ as $k => $v) {
329
- if (is_array($v)) {
330
- $string .= "[$k]=>(";
331
- foreach ($v as $k2 => $v2) {
332
- $string .= "[$k2]=>\"" . $v2 . '", ';
333
- }
334
- $string .= ')';
335
- } else {
336
- $string .= "[$k]=>\"" . $v . '", ';
337
- }
338
- }
339
- $string .= ')';
340
- }
341
-
342
- if (isset($this->text)) {
343
- $string .= ' text: (' . $this->text . ')';
344
- }
345
-
346
- $string .= " HDOM_INNER_INFO: '";
347
-
348
- if (isset($node->_[HDOM_INFO_INNER])) {
349
- $string .= $node->_[HDOM_INFO_INNER] . "'";
350
- } else {
351
- $string .= ' NULL ';
352
- }
353
-
354
- $string .= ' children: ' . count($this->children);
355
- $string .= ' nodes: ' . count($this->nodes);
356
- $string .= ' tag_start: ' . $this->tag_start;
357
- $string .= "\n";
358
-
359
- if ($echo) {
360
- echo $string;
361
- return;
362
- } else {
363
- return $string;
364
- }
365
- }
366
-
367
- /**
368
- * Return or set parent node
369
- *
370
- * @param object|null $parent (optional) The parent node, `null` to return
371
- * the current parent node.
372
- * @return object|null The parent node
373
- */
374
- function parent($parent = null)
375
- {
376
- // I am SURE that this doesn't work properly.
377
- // It fails to unset the current node from it's current parents nodes or
378
- // children list first.
379
- if ($parent !== null) {
380
- $this->parent = $parent;
381
- $this->parent->nodes[] = $this;
382
- $this->parent->children[] = $this;
383
- }
384
-
385
- return $this->parent;
386
- }
387
-
388
- /**
389
- * @return bool True if the node has at least one child node
390
- */
391
- function has_child()
392
- {
393
- return !empty($this->children);
394
- }
395
-
396
- /**
397
- * Get child node at specified index
398
- *
399
- * @param int $idx The index of the child node to return, `-1` to return all
400
- * child nodes.
401
- * @return object|array|null The child node at the specified index, all child
402
- * nodes or null if the index is invalid.
403
- */
404
- function children($idx = -1)
405
- {
406
- if ($idx === -1) {
407
- return $this->children;
408
- }
409
-
410
- if (isset($this->children[$idx])) {
411
- return $this->children[$idx];
412
- }
413
-
414
- return null;
415
- }
416
-
417
- /**
418
- * Get first child node
419
- *
420
- * @return object|null The first child node or null if the current node has
421
- * no child nodes.
422
- *
423
- * @todo Use `empty()` instead of `count()` to improve performance on large
424
- * arrays.
425
- */
426
- function first_child()
427
- {
428
- if (count($this->children) > 0) {
429
- return $this->children[0];
430
- }
431
- return null;
432
- }
433
-
434
- /**
435
- * Get last child node
436
- *
437
- * @return object|null The last child node or null if the current node has
438
- * no child nodes.
439
- *
440
- * @todo Use `end()` to slightly improve performance on large arrays.
441
- */
442
- function last_child()
443
- {
444
- if (($count = count($this->children)) > 0) {
445
- return $this->children[$count - 1];
446
- }
447
- return null;
448
- }
449
-
450
- /**
451
- * Get next sibling node
452
- *
453
- * @return object|null The sibling node or null if the current node has no
454
- * sibling nodes.
455
- */
456
- function next_sibling()
457
- {
458
- if ($this->parent === null) {
459
- return null;
460
- }
461
-
462
- $idx = 0;
463
- $count = count($this->parent->children);
464
-
465
- while ($idx < $count && $this !== $this->parent->children[$idx]) {
466
- ++$idx;
467
- }
468
-
469
- if (++$idx >= $count) {
470
- return null;
471
- }
472
-
473
- return $this->parent->children[$idx];
474
- }
475
-
476
- /**
477
- * Get previous sibling node
478
- *
479
- * @return object|null The sibling node or null if the current node has no
480
- * sibling nodes.
481
- */
482
- function prev_sibling()
483
- {
484
- if ($this->parent === null) {
485
- return null;
486
- }
487
-
488
- $idx = 0;
489
- $count = count($this->parent->children);
490
-
491
- while ($idx < $count && $this !== $this->parent->children[$idx]) {
492
- ++$idx;
493
- }
494
-
495
- if (--$idx < 0) {
496
- return null;
497
- }
498
-
499
- return $this->parent->children[$idx];
500
- }
501
-
502
- /**
503
- * Traverse ancestors to the first matching tag.
504
- *
505
- * @param string $tag Tag to find
506
- * @return object|null First matching node in the DOM tree or null if no
507
- * match was found.
508
- *
509
- * @todo Null is returned implicitly by calling ->parent on the root node.
510
- * This behaviour could change at any time, rendering this function invalid.
511
- */
512
- function find_ancestor_tag($tag)
513
- {
514
- global $debug_object;
515
- if (is_object($debug_object)) {
516
- $debug_object->debug_log_entry(1);
517
- }
518
-
519
- // Start by including ourselves in the comparison.
520
- $returnDom = $this;
521
-
522
- while (!is_null($returnDom)) {
523
- if (is_object($debug_object)) {
524
- $debug_object->debug_log(2, 'Current tag is: ' . $returnDom->tag);
525
- }
526
-
527
- if ($returnDom->tag == $tag) {
528
- break;
529
- }
530
-
531
- $returnDom = $returnDom->parent;
532
- }
533
-
534
- return $returnDom;
535
- }
536
-
537
- /**
538
- * Get node's inner text (everything inside the opening and closing tags)
539
- *
540
- * @return string
541
- */
542
- function innertext()
543
- {
544
- if (isset($this->_[HDOM_INFO_INNER])) {
545
- return $this->_[HDOM_INFO_INNER];
546
- }
547
-
548
- if (isset($this->_[HDOM_INFO_TEXT])) {
549
- return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
550
- }
551
-
552
- $ret = '';
553
-
554
- foreach ($this->nodes as $n) {
555
- $ret .= $n->outertext();
556
- }
557
-
558
- return $ret;
559
- }
560
-
561
- /**
562
- * Get node's outer text (everything including the opening and closing tags)
563
- *
564
- * @return string
565
- */
566
- function outertext()
567
- {
568
- global $debug_object;
569
-
570
- if (is_object($debug_object)) {
571
- $text = '';
572
-
573
- if ($this->tag === 'text') {
574
- if (!empty($this->text)) {
575
- $text = ' with text: ' . $this->text;
576
- }
577
- }
578
-
579
- $debug_object->debug_log(1, 'Innertext of tag: ' . $this->tag . $text);
580
- }
581
-
582
- if ($this->tag === 'root') {
583
- return $this->innertext();
584
- }
585
-
586
- // trigger callback
587
- if ($this->dom && $this->dom->callback !== null) {
588
- call_user_func_array($this->dom->callback, array($this));
589
- }
590
-
591
- if (isset($this->_[HDOM_INFO_OUTER])) {
592
- return $this->_[HDOM_INFO_OUTER];
593
- }
594
-
595
- if (isset($this->_[HDOM_INFO_TEXT])) {
596
- return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
597
- }
598
-
599
- // render begin tag
600
- if ($this->dom && $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]) {
601
- $ret = $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]->makeup();
602
- } else {
603
- $ret = '';
604
- }
605
-
606
- // render inner text
607
- if (isset($this->_[HDOM_INFO_INNER])) {
608
- // If it's a br tag... don't return the HDOM_INNER_INFO that we
609
- // may or may not have added.
610
- if ($this->tag !== 'br') {
611
- $ret .= $this->_[HDOM_INFO_INNER];
612
- }
613
- } else {
614
- if ($this->nodes) {
615
- foreach ($this->nodes as $n) {
616
- $ret .= $this->convert_text($n->outertext());
617
- }
618
- }
619
- }
620
-
621
- // render end tag
622
- if (isset($this->_[HDOM_INFO_END]) && $this->_[HDOM_INFO_END] != 0) {
623
- $ret .= '</' . $this->tag . '>';
624
- }
625
-
626
- return $ret;
627
- }
628
-
629
- /**
630
- * Get node's plain text (everything excluding all tags)
631
- *
632
- * @return string
633
- */
634
- function text()
635
- {
636
- if (isset($this->_[HDOM_INFO_INNER])) {
637
- return $this->_[HDOM_INFO_INNER];
638
- }
639
-
640
- switch ($this->nodetype) {
641
- case HDOM_TYPE_TEXT:
642
- return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
643
- case HDOM_TYPE_COMMENT:
644
- return '';
645
- case HDOM_TYPE_UNKNOWN:
646
- return '';
647
- }
648
-
649
- if (strcasecmp($this->tag, 'script') === 0) {
650
- return '';
651
- }
652
- if (strcasecmp($this->tag, 'style') === 0) {
653
- return '';
654
- }
655
-
656
- $ret = '';
657
-
658
- // In rare cases, (always node type 1 or HDOM_TYPE_ELEMENT - observed
659
- // for some span tags, and some p tags) $this->nodes is set to NULL.
660
- // NOTE: This indicates that there is a problem where it's set to NULL
661
- // without a clear happening.
662
- // WHY is this happening?
663
- if (!is_null($this->nodes)) {
664
- foreach ($this->nodes as $n) {
665
- // Start paragraph after a blank line
666
- if ($n->tag === 'p') {
667
- $ret .= "\n\n";
668
- }
669
-
670
- $ret .= $this->convert_text($n->text());
671
-
672
- // If this node is a span... add a space at the end of it so
673
- // multiple spans don't run into each other. This is plaintext
674
- // after all.
675
- if ($n->tag === 'span') {
676
- $ret .= $this->dom->default_span_text;
677
- }
678
- }
679
- }
680
- return trim($ret);
681
- }
682
-
683
- /**
684
- * Get node's xml text (inner text as a CDATA section)
685
- *
686
- * @return string
687
- */
688
- function xmltext()
689
- {
690
- $ret = $this->innertext();
691
- $ret = str_ireplace('<![CDATA[', '', $ret);
692
- $ret = str_replace(']]>', '', $ret);
693
- return $ret;
694
- }
695
-
696
- // build node's text with tag
697
- function makeup()
698
- {
699
- // text, comment, unknown
700
- if (isset($this->_[HDOM_INFO_TEXT])) {
701
- return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
702
- }
703
-
704
- $ret = '<' . $this->tag;
705
- $i = -1;
706
-
707
- foreach ($this->attr as $key => $val) {
708
- ++$i;
709
-
710
- // skip removed attribute
711
- if ($val === null || $val === false) {
712
- continue;
713
- }
714
-
715
- $ret .= $this->_[HDOM_INFO_SPACE][$i][0];
716
-
717
- //no value attr: nowrap, checked selected...
718
- if ($val === true) {
719
- $ret .= $key;
720
- } else {
721
- switch ($this->_[HDOM_INFO_QUOTE][$i]) {
722
- case HDOM_QUOTE_DOUBLE:
723
- $quote = '"';
724
- break;
725
- case HDOM_QUOTE_SINGLE:
726
- $quote = '\'';
727
- break;
728
- default:
729
- $quote = '';
730
- }
731
-
732
- $ret .= $key
733
- . $this->_[HDOM_INFO_SPACE][$i][1]
734
- . '='
735
- . $this->_[HDOM_INFO_SPACE][$i][2]
736
- . $quote
737
- . $val
738
- . $quote;
739
- }
740
- }
741
-
742
- $ret = $this->dom->restore_noise($ret);
743
- return $ret . $this->_[HDOM_INFO_ENDSPACE] . '>';
744
- }
745
-
746
- /**
747
- * Find elements by CSS selector
748
- *
749
- * @param string $selector The CSS selector
750
- * @param int|null $idx Index of element to return form the list of matching
751
- * elements (default: `null` = disabled).
752
- * @param bool $lowercase Matches tag names case insensitive (lowercase) if
753
- * enabled (default: `false`)
754
- * @return array|object|null A list of elements matching the specified CSS
755
- * selector or a single element if $idx is specified or null if no element
756
- * was found.
757
- */
758
- function find($selector, $idx = null, $lowercase = false)
759
- {
760
- $selectors = $this->parse_selector($selector);
761
- if (($count = count($selectors)) === 0) {
762
- return array();
763
- }
764
- $found_keys = array();
765
-
766
- // find each selector
767
- for ($c = 0; $c < $count; ++$c) {
768
- // The change on the below line was documented on the sourceforge
769
- // code tracker id 2788009
770
- // used to be: if (($levle=count($selectors[0]))===0) return array();
771
- if (($levle = count($selectors[$c])) === 0) {
772
- return array();
773
- }
774
- if (!isset($this->_[HDOM_INFO_BEGIN])) {
775
- return array();
776
- }
777
-
778
- $head = array($this->_[HDOM_INFO_BEGIN] => 1);
779
- $cmd = ' '; // Combinator
780
-
781
- // handle descendant selectors, no recursive!
782
- for ($l = 0; $l < $levle; ++$l) {
783
- $ret = array();
784
-
785
- foreach ($head as $k => $v) {
786
- $n = ($k === -1) ? $this->dom->root : $this->dom->nodes[$k];
787
- //PaperG - Pass this optional parameter on to the seek function.
788
- $n->seek($selectors[$c][$l], $ret, $cmd, $lowercase);
789
- }
790
-
791
- $head = $ret;
792
- $cmd = $selectors[$c][$l][4]; // Next Combinator
793
- }
794
-
795
- foreach ($head as $k => $v) {
796
- if (!isset($found_keys[$k])) {
797
- $found_keys[$k] = 1;
798
- }
799
- }
800
- }
801
-
802
- // sort keys
803
- ksort($found_keys);
804
-
805
- $found = array();
806
- foreach ($found_keys as $k => $v) {
807
- $found[] = $this->dom->nodes[$k];
808
- }
809
-
810
- // return nth-element or array
811
- if (is_null($idx)) {
812
- return $found;
813
- } elseif ($idx < 0) {
814
- $idx = count($found) + $idx;
815
- }
816
- return (isset($found[$idx])) ? $found[$idx] : null;
817
- }
818
-
819
- /**
820
- * Seek DOM elements by selector
821
- *
822
- * **Note**
823
- * The selector element must be compatible to a selector from
824
- * {@see simple_html_dom_node::parse_selector()}
825
- *
826
- * @param array $selector A selector element
827
- * @param array $ret An array of matches
828
- * @param bool $lowercase Matches tag names case insensitive (lowercase) if
829
- * enabled (default: `false`)
830
- * @return void
831
- */
832
- protected function seek($selector, &$ret, $parent_cmd, $lowercase = false)
833
- {
834
- global $debug_object;
835
- if (is_object($debug_object)) {
836
- $debug_object->debug_log_entry(1);
837
- }
838
-
839
- list($tag, $id, $class, $attributes, $cmb) = $selector;
840
- $nodes = array();
841
-
842
- if ($parent_cmd === ' ') { // Descendant Combinator
843
- // Find parent closing tag if the current element doesn't have a closing
844
- // tag (i.e. void element)
845
- $end = (!empty($this->_[HDOM_INFO_END])) ? $this->_[HDOM_INFO_END] : 0;
846
- if ($end == 0) {
847
- $parent = $this->parent;
848
- while (!isset($parent->_[HDOM_INFO_END]) && $parent !== null) {
849
- $end -= 1;
850
- $parent = $parent->parent;
851
- }
852
- $end += $parent->_[HDOM_INFO_END];
853
- }
854
-
855
- // Get list of target nodes
856
- $nodes_start = $this->_[HDOM_INFO_BEGIN] + 1;
857
- $nodes_count = $end - $nodes_start;
858
- $nodes = array_slice($this->dom->nodes, $nodes_start, $nodes_count, true);
859
- } elseif ($parent_cmd === '>') { // Child Combinator
860
- $nodes = $this->children;
861
- } elseif ($parent_cmd === '+'
862
- && $this->parent
863
- && in_array($this, $this->parent->children)) { // Next-Sibling Combinator
864
- $index = array_search($this, $this->parent->children, true) + 1;
865
- $nodes[] = $this->parent->children[$index];
866
- } elseif ($parent_cmd === '~'
867
- && $this->parent
868
- && in_array($this, $this->parent->children)) { // Subsequent Sibling Combinator
869
- $index = array_search($this, $this->parent->children, true);
870
- $nodes = array_slice($this->parent->children, $index);
871
- }
872
-
873
- // Go throgh each element starting at this element until the end tag
874
- // Note: If this element is a void tag, any previous void element is
875
- // skipped.
876
- foreach ($nodes as $node) {
877
- $pass = true;
878
-
879
- // Skip root nodes
880
- if (!$node->parent) {
881
- $pass = false;
882
- }
883
-
884
- // Skip if node isn't a child node (i.e. text nodes)
885
- if ($pass && !in_array($node, $node->parent->children, true)) {
886
- $pass = false;
887
- }
888
-
889
- // Skip if tag doesn't match
890
- if ($pass && $tag !== '' && $tag !== $node->tag && $tag !== '*') {
891
- $pass = false;
892
- }
893
-
894
- // Skip if ID doesn't exist
895
- if ($pass && $id !== '' && !isset($node->attr['id'])) {
896
- $pass = false;
897
- }
898
-
899
- // Check if ID matches
900
- if ($pass && $id !== '' && isset($node->attr['id'])) {
901
- // Note: Only consider the first ID (as browsers do)
902
- $node_id = explode(' ', trim($node->attr['id']))[0];
903
-
904
- if ($id !== $node_id) {
905
- $pass = false;
906
- }
907
- }
908
-
909
- // Check if all class(es) exist
910
- if ($pass && $class !== '' && is_array($class) && !empty($class)) {
911
- if (isset($node->attr['class'])) {
912
- $node_classes = explode(' ', $node->attr['class']);
913
-
914
- if ($lowercase) {
915
- $node_classes = array_map('strtolower', $node_classes);
916
- }
917
-
918
- foreach ($class as $c) {
919
- if (!in_array($c, $node_classes)) {
920
- $pass = false;
921
- break;
922
- }
923
- }
924
- } else {
925
- $pass = false;
926
- }
927
- }
928
-
929
- // Check attributes
930
- if ($pass
931
- && $attributes !== ''
932
- && is_array($attributes)
933
- && !empty($attributes)) {
934
- foreach ($attributes as $a) {
935
- list (
936
- $att_name,
937
- $att_expr,
938
- $att_val,
939
- $att_inv,
940
- $att_case_sensitivity
941
- ) = $a;
942
-
943
- // Handle indexing attributes (i.e. "[2]")
944
- /**
945
- * Note: This is not supported by the CSS Standard but adds
946
- * the ability to select items compatible to XPath (i.e.
947
- * the 3rd element within it's parent).
948
- *
949
- * Note: This doesn't conflict with the CSS Standard which
950
- * doesn't work on numeric attributes anyway.
951
- */
952
- if (is_numeric($att_name)
953
- && $att_expr === ''
954
- && $att_val === '') {
955
- $count = 0;
956
-
957
- // Find index of current element in parent
958
- foreach ($node->parent->children as $c) {
959
- if ($c->tag === $node->tag) {
960
- ++$count;
961
- }
962
- if ($c === $node) {
963
- break;
964
- }
965
- }
966
-
967
- // If this is the correct node, continue with next
968
- // attribute
969
- if ($count === (int)$att_name) {
970
- continue;
971
- }
972
- }
973
-
974
- // Check attribute availability
975
- if ($att_inv) { // Attribute should NOT be set
976
- if (isset($node->attr[$att_name])) {
977
- $pass = false;
978
- break;
979
- }
980
- } else { // Attribute should be set
981
- // todo: "plaintext" is not a valid CSS selector!
982
- if ($att_name !== 'plaintext'
983
- && !isset($node->attr[$att_name])) {
984
- $pass = false;
985
- break;
986
- }
987
- }
988
-
989
- // Continue with next attribute if expression isn't defined
990
- if ($att_expr === '') {
991
- continue;
992
- }
993
-
994
- // If they have told us that this is a "plaintext"
995
- // search then we want the plaintext of the node - right?
996
- // todo "plaintext" is not a valid CSS selector!
997
- if ($att_name === 'plaintext') {
998
- $nodeKeyValue = $node->text();
999
- } else {
1000
- $nodeKeyValue = $node->attr[$att_name];
1001
- }
1002
-
1003
- if (is_object($debug_object)) {
1004
- $debug_object->debug_log(
1005
- 2,
1006
- 'testing node: '
1007
- . $node->tag
1008
- . ' for attribute: '
1009
- . $att_name
1010
- . $att_expr
1011
- . $att_val
1012
- . ' where nodes value is: '
1013
- . $nodeKeyValue
1014
- );
1015
- }
1016
-
1017
- // If lowercase is set, do a case insensitive test of
1018
- // the value of the selector.
1019
- if ($lowercase) {
1020
- $check = $this->match(
1021
- $att_expr,
1022
- strtolower($att_val),
1023
- strtolower($nodeKeyValue),
1024
- $att_case_sensitivity
1025
- );
1026
- } else {
1027
- $check = $this->match(
1028
- $att_expr,
1029
- $att_val,
1030
- $nodeKeyValue,
1031
- $att_case_sensitivity
1032
- );
1033
- }
1034
-
1035
- if (is_object($debug_object)) {
1036
- $debug_object->debug_log(
1037
- 2,
1038
- 'after match: '
1039
- . ($check ? 'true' : 'false')
1040
- );
1041
- }
1042
-
1043
- if (!$check) {
1044
- $pass = false;
1045
- break;
1046
- }
1047
- }
1048
- }
1049
-
1050
- // Found a match. Add to list and clear node
1051
- if ($pass) {
1052
- $ret[$node->_[HDOM_INFO_BEGIN]] = 1;
1053
- }
1054
- unset($node);
1055
- }
1056
- // It's passed by reference so this is actually what this function returns.
1057
- if (is_object($debug_object)) {
1058
- $debug_object->debug_log(1, 'EXIT - ret: ', $ret);
1059
- }
1060
- }
1061
-
1062
- /**
1063
- * Match value and pattern for a given CSS expression
1064
- *
1065
- * **Supported Expressions**
1066
- *
1067
- * | Expression | Description
1068
- * | ---------- | -----------
1069
- * | `=` | $value and $pattern must be equal
1070
- * | `!=` | $value and $pattern must not be equal
1071
- * | `^=` | $value must start with $pattern
1072
- * | `$=` | $value must end with $pattern
1073
- * | `*=` | $value must contain $pattern
1074
- *
1075
- * @param string $exp The expression.
1076
- * @param string $pattern The pattern
1077
- * @param string $value The value
1078
- * @value bool True if $value matches $pattern
1079
- */
1080
- protected function match($exp, $pattern, $value, $case_sensitivity)
1081
- {
1082
- global $debug_object;
1083
- if (is_object($debug_object)) {
1084
- $debug_object->debug_log_entry(1);
1085
- }
1086
-
1087
- if ($case_sensitivity === 'i') {
1088
- $pattern = strtolower($pattern);
1089
- $value = strtolower($value);
1090
- }
1091
-
1092
- switch ($exp) {
1093
- case '=':
1094
- return ($value === $pattern);
1095
- case '!=':
1096
- return ($value !== $pattern);
1097
- case '^=':
1098
- return preg_match('/^' . preg_quote($pattern, '/') . '/', $value);
1099
- case '$=':
1100
- return preg_match('/' . preg_quote($pattern, '/') . '$/', $value);
1101
- case '*=':
1102
- return preg_match('/' . preg_quote($pattern, '/') . '/', $value);
1103
- case '|=':
1104
- /**
1105
- * [att|=val]
1106
- *
1107
- * Represents an element with the att attribute, its value
1108
- * either being exactly "val" or beginning with "val"
1109
- * immediately followed by "-" (U+002D).
1110
- */
1111
- return strpos($value, $pattern) === 0;
1112
- case '~=':
1113
- /**
1114
- * [att~=val]
1115
- *
1116
- * Represents an element with the att attribute whose value is a
1117
- * whitespace-separated list of words, one of which is exactly
1118
- * "val". If "val" contains whitespace, it will never represent
1119
- * anything (since the words are separated by spaces). Also if
1120
- * "val" is the empty string, it will never represent anything.
1121
- */
1122
- return in_array($pattern, explode(' ', trim($value)), true);
1123
- }
1124
- return false;
1125
- }
1126
-
1127
- /**
1128
- * Parse CSS selector
1129
- *
1130
- * @param string $selector_string CSS selector string
1131
- * @return array List of CSS selectors. The format depends on the type of
1132
- * selector:
1133
- *
1134
- * ```php
1135
- *
1136
- * array( // list of selectors (each separated by a comma), i.e. 'img, p, div'
1137
- * array( // list of combinator selectors, i.e. 'img > p > div'
1138
- * array( // selector element
1139
- * [0], // (string) The element tag
1140
- * [1], // (string) The element id
1141
- * [2], // (array<string>) The element classes
1142
- * [3], // (array<array<string>>) The list of attributes, each
1143
- * // with four elements: name, expression, value, inverted
1144
- * [4] // (string) The selector combinator (' ' | '>' | '+' | '~')
1145
- * )
1146
- * )
1147
- * )
1148
- * ```
1149
- *
1150
- * @link https://www.w3.org/TR/selectors/#compound Compound selector
1151
- */
1152
- protected function parse_selector($selector_string)
1153
- {
1154
- global $debug_object;
1155
- if (is_object($debug_object)) {
1156
- $debug_object->debug_log_entry(1);
1157
- }
1158
-
1159
- /**
1160
- * Pattern of CSS selectors, modified from mootools (https://mootools.net/)
1161
- *
1162
- * Paperg: Add the colon to the attribute, so that it properly finds
1163
- * <tag attr:ibute="something" > like google does.
1164
- *
1165
- * Note: if you try to look at this attribute, you MUST use getAttribute
1166
- * since $dom->x:y will fail the php syntax check.
1167
- *
1168
- * Notice the \[ starting the attribute? and the @? following? This
1169
- * implies that an attribute can begin with an @ sign that is not
1170
- * captured. This implies that an html attribute specifier may start
1171
- * with an @ sign that is NOT captured by the expression. Farther study
1172
- * is required to determine of this should be documented or removed.
1173
- *
1174
- * Matches selectors in this order:
1175
- *
1176
- * [0] - full match
1177
- *
1178
- * [1] - tag name
1179
- * ([\w:\*-]*)
1180
- * Matches the tag name consisting of zero or more words, colons,
1181
- * asterisks and hyphens.
1182
- *
1183
- * [2] - id name
1184
- * (?:\#([\w-]+))
1185
- * Optionally matches a id name, consisting of an "#" followed by
1186
- * the id name (one or more words and hyphens).
1187
- *
1188
- * [3] - class names (including dots)
1189
- * (?:\.([\w\.-]+))?
1190
- * Optionally matches a list of classs, consisting of an "."
1191
- * followed by the class name (one or more words and hyphens)
1192
- * where multiple classes can be chained (i.e. ".foo.bar.baz")
1193
- *
1194
- * [4] - attributes
1195
- * ((?:\[@?(?:!?[\w:-]+)(?:(?:[!*^$|~]?=)[\"']?(?:.*?)[\"']?)?(?:\s*?(?:[iIsS])?)?\])+)?
1196
- * Optionally matches the attributes list
1197
- *
1198
- * [5] - separator
1199
- * ([\/, >+~]+)
1200
- * Matches the selector list separator
1201
- */
1202
- // phpcs:ignore Generic.Files.LineLength
1203
- $pattern = "/([\w:\*-]*)(?:\#([\w-]+))?(?:|\.([\w\.-]+))?((?:\[@?(?:!?[\w:-]+)(?:(?:[!*^$|~]?=)[\"']?(?:.*?)[\"']?)?(?:\s*?(?:[iIsS])?)?\])+)?([\/, >+~]+)/is";
1204
-
1205
- preg_match_all(
1206
- $pattern,
1207
- trim($selector_string) . ' ', // Add final ' ' as pseudo separator
1208
- $matches,
1209
- PREG_SET_ORDER
1210
- );
1211
-
1212
- if (is_object($debug_object)) {
1213
- $debug_object->debug_log(2, 'Matches Array: ', $matches);
1214
- }
1215
-
1216
- $selectors = array();
1217
- $result = array();
1218
-
1219
- foreach ($matches as $m) {
1220
- $m[0] = trim($m[0]);
1221
-
1222
- // Skip NoOps
1223
- if ($m[0] === '' || $m[0] === '/' || $m[0] === '//') {
1224
- continue;
1225
- }
1226
-
1227
- // Convert to lowercase
1228
- if ($this->dom->lowercase) {
1229
- $m[1] = strtolower($m[1]);
1230
- }
1231
-
1232
- // Extract classes
1233
- if ($m[3] !== '') {
1234
- $m[3] = explode('.', $m[3]);
1235
- }
1236
-
1237
- /* Extract attributes (pattern based on the pattern above!)
1238
-
1239
- * [0] - full match
1240
- * [1] - attribute name
1241
- * [2] - attribute expression
1242
- * [3] - attribute value
1243
- * [4] - case sensitivity
1244
- *
1245
- * Note: Attributes can be negated with a "!" prefix to their name
1246
- */
1247
- if ($m[4] !== '') {
1248
- preg_match_all(
1249
- "/\[@?(!?[\w:-]+)(?:([!*^$|~]?=)[\"']?(.*?)[\"']?)?(?:\s*?([iIsS])?)?\]/is",
1250
- trim($m[4]),
1251
- $attributes,
1252
- PREG_SET_ORDER
1253
- );
1254
-
1255
- // Replace element by array
1256
- $m[4] = array();
1257
-
1258
- foreach ($attributes as $att) {
1259
- // Skip empty matches
1260
- if (trim($att[0]) === '') {
1261
- continue;
1262
- }
1263
-
1264
- $inverted = (isset($att[1][0]) && $att[1][0] === '!');
1265
- $m[4][] = array(
1266
- $inverted ? substr($att[1], 1) : $att[1], // Name
1267
- (isset($att[2])) ? $att[2] : '', // Expression
1268
- (isset($att[3])) ? $att[3] : '', // Value
1269
- $inverted, // Inverted Flag
1270
- (isset($att[4])) ? strtolower($att[4]) : '', // Case-Sensitivity
1271
- );
1272
- }
1273
- }
1274
-
1275
- // Sanitize Separator
1276
- if ($m[5] !== '' && trim($m[5]) === '') { // Descendant Separator
1277
- $m[5] = ' ';
1278
- } else { // Other Separator
1279
- $m[5] = trim($m[5]);
1280
- }
1281
-
1282
- // Clear Separator if it's a Selector List
1283
- if ($is_list = ($m[5] === ',')) {
1284
- $m[5] = '';
1285
- }
1286
-
1287
- // Remove full match before adding to results
1288
- array_shift($m);
1289
- $result[] = $m;
1290
-
1291
- if ($is_list) { // Selector List
1292
- $selectors[] = $result;
1293
- $result = array();
1294
- }
1295
- }
1296
-
1297
- if (count($result) > 0) {
1298
- $selectors[] = $result;
1299
- }
1300
- return $selectors;
1301
- }
1302
-
1303
- function __get($name)
1304
- {
1305
- if (isset($this->attr[$name])) {
1306
- return $this->convert_text($this->attr[$name]);
1307
- }
1308
- switch ($name) {
1309
- case 'outertext':
1310
- return $this->outertext();
1311
- case 'innertext':
1312
- return $this->innertext();
1313
- case 'plaintext':
1314
- return $this->text();
1315
- case 'xmltext':
1316
- return $this->xmltext();
1317
- default:
1318
- return array_key_exists($name, $this->attr);
1319
- }
1320
- }
1321
-
1322
- function __set($name, $value)
1323
- {
1324
- global $debug_object;
1325
- if (is_object($debug_object)) {
1326
- $debug_object->debug_log_entry(1);
1327
- }
1328
-
1329
- switch ($name) {
1330
- case 'outertext':
1331
- return $this->_[HDOM_INFO_OUTER] = $value;
1332
- case 'innertext':
1333
- if (isset($this->_[HDOM_INFO_TEXT])) {
1334
- return $this->_[HDOM_INFO_TEXT] = $value;
1335
- }
1336
- return $this->_[HDOM_INFO_INNER] = $value;
1337
- }
1338
-
1339
- if (!isset($this->attr[$name])) {
1340
- $this->_[HDOM_INFO_SPACE][] = array(' ', '', '');
1341
- $this->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE;
1342
- }
1343
-
1344
- $this->attr[$name] = $value;
1345
- }
1346
-
1347
- function __isset($name)
1348
- {
1349
- switch ($name) {
1350
- case 'outertext':
1351
- return true;
1352
- case 'innertext':
1353
- return true;
1354
- case 'plaintext':
1355
- return true;
1356
- }
1357
- //no value attr: nowrap, checked selected...
1358
- return (array_key_exists($name, $this->attr)) ? true : isset($this->attr[$name]);
1359
- }
1360
-
1361
- function __unset($name)
1362
- {
1363
- if (isset($this->attr[$name])) {
1364
- unset($this->attr[$name]);
1365
- }
1366
- }
1367
-
1368
- // PaperG - Function to convert the text from one character set to another
1369
- // if the two sets are not the same.
1370
- function convert_text($text)
1371
- {
1372
- global $debug_object;
1373
- if (is_object($debug_object)) {
1374
- $debug_object->debug_log_entry(1);
1375
- }
1376
-
1377
- $converted_text = $text;
1378
-
1379
- $sourceCharset = '';
1380
- $targetCharset = '';
1381
-
1382
- if ($this->dom) {
1383
- $sourceCharset = strtoupper($this->dom->_charset);
1384
- $targetCharset = strtoupper($this->dom->_target_charset);
1385
- }
1386
-
1387
- if (is_object($debug_object)) {
1388
- $debug_object->debug_log(
1389
- 3,
1390
- 'source charset: '
1391
- . $sourceCharset
1392
- . ' target charaset: '
1393
- . $targetCharset
1394
- );
1395
- }
1396
-
1397
- if (!empty($sourceCharset)
1398
- && !empty($targetCharset)
1399
- && (strcasecmp($sourceCharset, $targetCharset) != 0)) {
1400
- // Check if the reported encoding could have been incorrect and the text is actually already UTF-8
1401
- if ((strcasecmp($targetCharset, 'UTF-8') == 0)
1402
- && ($this->is_utf8($text))) {
1403
- $converted_text = $text;
1404
- } else {
1405
- $converted_text = iconv($sourceCharset, $targetCharset, $text);
1406
- }
1407
- }
1408
-
1409
- // Lets make sure that we don't have that silly BOM issue with any of the utf-8 text we output.
1410
- if ($targetCharset === 'UTF-8') {
1411
- if (substr($converted_text, 0, 3) === "\xef\xbb\xbf") {
1412
- $converted_text = substr($converted_text, 3);
1413
- }
1414
-
1415
- if (substr($converted_text, -3) === "\xef\xbb\xbf") {
1416
- $converted_text = substr($converted_text, 0, -3);
1417
- }
1418
- }
1419
-
1420
- return $converted_text;
1421
- }
1422
-
1423
- /**
1424
- * Returns true if $string is valid UTF-8 and false otherwise.
1425
- *
1426
- * @param mixed $str String to be tested
1427
- * @return boolean
1428
- */
1429
- static function is_utf8($str)
1430
- {
1431
- $c = 0;
1432
- $b = 0;
1433
- $bits = 0;
1434
- $len = strlen($str);
1435
- for ($i = 0; $i < $len; $i++) {
1436
- $c = ord($str[$i]);
1437
- if ($c > 128) {
1438
- if (($c >= 254)) {
1439
- return false;
1440
- } elseif ($c >= 252) {
1441
- $bits = 6;
1442
- } elseif ($c >= 248) {
1443
- $bits = 5;
1444
- } elseif ($c >= 240) {
1445
- $bits = 4;
1446
- } elseif ($c >= 224) {
1447
- $bits = 3;
1448
- } elseif ($c >= 192) {
1449
- $bits = 2;
1450
- } else {
1451
- return false;
1452
- }
1453
- if (($i + $bits) > $len) {
1454
- return false;
1455
- }
1456
- while ($bits > 1) {
1457
- $i++;
1458
- $b = ord($str[$i]);
1459
- if ($b < 128 || $b > 191) {
1460
- return false;
1461
- }
1462
- $bits--;
1463
- }
1464
- }
1465
- }
1466
- return true;
1467
- }
1468
-
1469
- /**
1470
- * Function to try a few tricks to determine the displayed size of an img on
1471
- * the page. NOTE: This will ONLY work on an IMG tag. Returns FALSE on all
1472
- * other tag types.
1473
- *
1474
- * @author John Schlick
1475
- * @version April 19 2012
1476
- * @return array an array containing the 'height' and 'width' of the image
1477
- * on the page or -1 if we can't figure it out.
1478
- */
1479
- function get_display_size()
1480
- {
1481
- global $debug_object;
1482
-
1483
- $width = -1;
1484
- $height = -1;
1485
-
1486
- if ($this->tag !== 'img') {
1487
- return false;
1488
- }
1489
-
1490
- // See if there is aheight or width attribute in the tag itself.
1491
- if (isset($this->attr['width'])) {
1492
- $width = $this->attr['width'];
1493
- }
1494
-
1495
- if (isset($this->attr['height'])) {
1496
- $height = $this->attr['height'];
1497
- }
1498
-
1499
- // Now look for an inline style.
1500
- if (isset($this->attr['style'])) {
1501
- // Thanks to user gnarf from stackoverflow for this regular expression.
1502
- $attributes = array();
1503
-
1504
- preg_match_all(
1505
- '/([\w-]+)\s*:\s*([^;]+)\s*;?/',
1506
- $this->attr['style'],
1507
- $matches,
1508
- PREG_SET_ORDER
1509
- );
1510
-
1511
- foreach ($matches as $match) {
1512
- $attributes[$match[1]] = $match[2];
1513
- }
1514
-
1515
- // If there is a width in the style attributes:
1516
- if (isset($attributes['width']) && $width == -1) {
1517
- // check that the last two characters are px (pixels)
1518
- if (strtolower(substr($attributes['width'], -2)) === 'px') {
1519
- $proposed_width = substr($attributes['width'], 0, -2);
1520
- // Now make sure that it's an integer and not something stupid.
1521
- if (filter_var($proposed_width, FILTER_VALIDATE_INT)) {
1522
- $width = $proposed_width;
1523
- }
1524
- }
1525
- }
1526
-
1527
- // If there is a width in the style attributes:
1528
- if (isset($attributes['height']) && $height == -1) {
1529
- // check that the last two characters are px (pixels)
1530
- if (strtolower(substr($attributes['height'], -2)) == 'px') {
1531
- $proposed_height = substr($attributes['height'], 0, -2);
1532
- // Now make sure that it's an integer and not something stupid.
1533
- if (filter_var($proposed_height, FILTER_VALIDATE_INT)) {
1534
- $height = $proposed_height;
1535
- }
1536
- }
1537
- }
1538
- }
1539
-
1540
- // Future enhancement:
1541
- // Look in the tag to see if there is a class or id specified that has
1542
- // a height or width attribute to it.
1543
-
1544
- // Far future enhancement
1545
- // Look at all the parent tags of this image to see if they specify a
1546
- // class or id that has an img selector that specifies a height or width
1547
- // Note that in this case, the class or id will have the img subselector
1548
- // for it to apply to the image.
1549
-
1550
- // ridiculously far future development
1551
- // If the class or id is specified in a SEPARATE css file thats not on
1552
- // the page, go get it and do what we were just doing for the ones on
1553
- // the page.
1554
-
1555
- $result = array(
1556
- 'height' => $height,
1557
- 'width' => $width
1558
- );
1559
-
1560
- return $result;
1561
- }
1562
-
1563
- // camel naming conventions
1564
- function getAllAttributes()
1565
- {
1566
- return $this->attr;
1567
- }
1568
-
1569
- function getAttribute($name)
1570
- {
1571
- return $this->__get($name);
1572
- }
1573
-
1574
- function setAttribute($name, $value)
1575
- {
1576
- $this->__set($name, $value);
1577
- }
1578
-
1579
- function hasAttribute($name)
1580
- {
1581
- return $this->__isset($name);
1582
- }
1583
-
1584
- function removeAttribute($name)
1585
- {
1586
- $this->__set($name, null);
1587
- }
1588
-
1589
- function getElementById($id)
1590
- {
1591
- return $this->find("#$id", 0);
1592
- }
1593
-
1594
- function getElementsById($id, $idx = null)
1595
- {
1596
- return $this->find("#$id", $idx);
1597
- }
1598
-
1599
- function getElementByTagName($name)
1600
- {
1601
- return $this->find($name, 0);
1602
- }
1603
-
1604
- function getElementsByTagName($name, $idx = null)
1605
- {
1606
- return $this->find($name, $idx);
1607
- }
1608
-
1609
- function parentNode()
1610
- {
1611
- return $this->parent();
1612
- }
1613
-
1614
- function childNodes($idx = -1)
1615
- {
1616
- return $this->children($idx);
1617
- }
1618
-
1619
- function firstChild()
1620
- {
1621
- return $this->first_child();
1622
- }
1623
-
1624
- function lastChild()
1625
- {
1626
- return $this->last_child();
1627
- }
1628
-
1629
- function nextSibling()
1630
- {
1631
- return $this->next_sibling();
1632
- }
1633
-
1634
- function previousSibling()
1635
- {
1636
- return $this->prev_sibling();
1637
- }
1638
-
1639
- function hasChildNodes()
1640
- {
1641
- return $this->has_child();
1642
- }
1643
-
1644
- function nodeName()
1645
- {
1646
- return $this->tag;
1647
- }
1648
-
1649
- function appendChild($node)
1650
- {
1651
- $node->parent($this);
1652
- return $node;
1653
- }
1654
- }
1655
-
1656
- /**
1657
- * simple html dom parser
1658
- *
1659
- * Paperg - in the find routine: allow us to specify that we want case
1660
- * insensitive testing of the value of the selector.
1661
- *
1662
- * Paperg - change $size from protected to public so we can easily access it
1663
- *
1664
- * Paperg - added ForceTagsClosed in the constructor which tells us whether we
1665
- * trust the html or not. Default is to NOT trust it.
1666
- *
1667
- * @package PlaceLocalInclude
1668
- */
1669
- class simple_html_dom
1670
- {
1671
- /**
1672
- * The root node of the document
1673
- *
1674
- * @var object
1675
- */
1676
- public $root = null;
1677
-
1678
- /**
1679
- * List of nodes in the current DOM
1680
- *
1681
- * @var array
1682
- */
1683
- public $nodes = array();
1684
-
1685
- /**
1686
- * Callback function to run for each element in the DOM.
1687
- *
1688
- * @var callable|null
1689
- */
1690
- public $callback = null;
1691
-
1692
- /**
1693
- * Indicates how tags and attributes are matched
1694
- *
1695
- * @var bool When set to **true** tags and attributes will be converted to
1696
- * lowercase before matching.
1697
- */
1698
- public $lowercase = false;
1699
-
1700
- /**
1701
- * Original document size
1702
- *
1703
- * Holds the original document size.
1704
- *
1705
- * @var int
1706
- */
1707
- public $original_size;
1708
-
1709
- /**
1710
- * Current document size
1711
- *
1712
- * Holds the current document size. The document size is determined by the
1713
- * string length of ({@see simple_html_dom::$doc}).
1714
- *
1715
- * _Note_: Using this variable is more efficient than calling `strlen($doc)`
1716
- *
1717
- * @var int
1718
- * */
1719
- public $size;
1720
-
1721
- /**
1722
- * Current position in the document
1723
- *
1724
- * @var int
1725
- */
1726
- protected $pos;
1727
-
1728
- /**
1729
- * The document
1730
- *
1731
- * @var string
1732
- */
1733
- protected $doc;
1734
-
1735
- /**
1736
- * Current character
1737
- *
1738
- * Holds the current character at position {@see simple_html_dom::$pos} in
1739
- * the document {@see simple_html_dom::$doc}
1740
- *
1741
- * _Note_: Using this variable is more efficient than calling
1742
- * `substr($doc, $pos, 1)`
1743
- *
1744
- * @var string
1745
- */
1746
- protected $char;
1747
-
1748
- protected $cursor;
1749
-
1750
- /**
1751
- * Parent node of the next node detected by the parser
1752
- *
1753
- * @var object
1754
- */
1755
- protected $parent;
1756
- protected $noise = array();
1757
-
1758
- /**
1759
- * Tokens considered blank in HTML
1760
- *
1761
- * @var string
1762
- */
1763
- protected $token_blank = " \t\r\n";
1764
-
1765
- /**
1766
- * Tokens to identify the equal sign for attributes, stopping either at the
1767
- * closing tag ("/" i.e. "<html />") or the end of an opening tag (">" i.e.
1768
- * "<html>")
1769
- *
1770
- * @var string
1771
- */
1772
- protected $token_equal = ' =/>';
1773
-
1774
- /**
1775
- * Tokens to identify the end of a tag name. A tag name either ends on the
1776
- * ending slash ("/" i.e. "<html/>") or whitespace ("\s\r\n\t")
1777
- *
1778
- * @var string
1779
- */
1780
- protected $token_slash = " />\r\n\t";
1781
-
1782
- /**
1783
- * Tokens to identify the end of an attribute
1784
- *
1785
- * @var string
1786
- */
1787
- protected $token_attr = ' >';
1788
-
1789
- // Note that this is referenced by a child node, and so it needs to be
1790
- // public for that node to see this information.
1791
- public $_charset = '';
1792
- public $_target_charset = '';
1793
-
1794
- /**
1795
- * Innertext for <br> elements
1796
- *
1797
- * @var string
1798
- */
1799
- protected $default_br_text = '';
1800
-
1801
- /**
1802
- * Suffix for <span> elements
1803
- *
1804
- * @var string
1805
- */
1806
- public $default_span_text = '';
1807
-
1808
- /**
1809
- * Defines a list of self-closing tags (Void elements) according to the HTML
1810
- * Specification
1811
- *
1812
- * _Remarks_:
1813
- * - Use `isset()` instead of `in_array()` on array elements to boost
1814
- * performance about 30%
1815
- * - Sort elements by name for better readability!
1816
- *
1817
- * @link https://www.w3.org/TR/html HTML Specification
1818
- * @link https://www.w3.org/TR/html/syntax.html#void-elements Void elements
1819
- */
1820
- protected $self_closing_tags = array(
1821
- 'area' => 1,
1822
- 'base' => 1,
1823
- 'br' => 1,
1824
- 'col' => 1,
1825
- 'embed' => 1,
1826
- 'hr' => 1,
1827
- 'img' => 1,
1828
- 'input' => 1,
1829
- 'link' => 1,
1830
- 'meta' => 1,
1831
- 'param' => 1,
1832
- 'source' => 1,
1833
- 'track' => 1,
1834
- 'wbr' => 1
1835
- );
1836
-
1837
- /**
1838
- * Defines a list of tags which - if closed - close all optional closing
1839
- * elements within if they haven't been closed yet. (So, an element where
1840
- * neither opening nor closing tag is omissible consistently closes every
1841
- * optional closing element within)
1842
- *
1843
- * _Remarks_:
1844
- * - Use `isset()` instead of `in_array()` on array elements to boost
1845
- * performance about 30%
1846
- * - Sort elements by name for better readability!
1847
- */
1848
- protected $block_tags = array(
1849
- 'body' => 1,
1850
- 'div' => 1,
1851
- 'form' => 1,
1852
- 'root' => 1,
1853
- 'span' => 1,
1854
- 'table' => 1
1855
- );
1856
-
1857
- /**
1858
- * Defines elements whose end tag is omissible.
1859
- *
1860
- * * key = Name of an element whose end tag is omissible.
1861
- * * value = Names of elements whose end tag is omissible, that are closed
1862
- * by the current element.
1863
- *
1864
- * _Remarks_:
1865
- * - Use `isset()` instead of `in_array()` on array elements to boost
1866
- * performance about 30%
1867
- * - Sort elements by name for better readability!
1868
- *
1869
- * **Example**
1870
- *
1871
- * An `li` element’s end tag may be omitted if the `li` element is immediately
1872
- * followed by another `li` element. To do that, add following element to the
1873
- * array:
1874
- *
1875
- * ```php
1876
- * 'li' => array('li'),
1877
- * ```
1878
- *
1879
- * With this, the following two examples are considered equal. Note that the
1880
- * second example is missing the closing tags on `li` elements.
1881
- *
1882
- * ```html
1883
- * <ul><li>First Item</li><li>Second Item</li></ul>
1884
- * ```
1885
- *
1886
- * <ul><li>First Item</li><li>Second Item</li></ul>
1887
- *
1888
- * ```html
1889
- * <ul><li>First Item<li>Second Item</ul>
1890
- * ```
1891
- *
1892
- * <ul><li>First Item<li>Second Item</ul>
1893
- *
1894
- * @var array A two-dimensional array where the key is the name of an
1895
- * element whose end tag is omissible and the value is an array of elements
1896
- * whose end tag is omissible, that are closed by the current element.
1897
- *
1898
- * @link https://www.w3.org/TR/html/syntax.html#optional-tags Optional tags
1899
- *
1900
- * @todo The implementation of optional closing tags doesn't work in all cases
1901
- * because it only consideres elements who close other optional closing
1902
- * tags, not taking into account that some (non-blocking) tags should close
1903
- * these optional closing tags. For example, the end tag for "p" is omissible
1904
- * and can be closed by an "address" element, whose end tag is NOT omissible.
1905
- * Currently a "p" element without closing tag stops at the next "p" element
1906
- * or blocking tag, even if it contains other elements.
1907
- *
1908
- * @todo Known sourceforge issue #2977341
1909
- * B tags that are not closed cause us to return everything to the end of
1910
- * the document.
1911
- */
1912
- protected $optional_closing_tags = array(
1913
- // Not optional, see
1914
- // https://www.w3.org/TR/html/textlevel-semantics.html#the-b-element
1915
- 'b' => array('b' => 1),
1916
- 'dd' => array('dd' => 1, 'dt' => 1),
1917
- // Not optional, see
1918
- // https://www.w3.org/TR/html/grouping-content.html#the-dl-element
1919
- 'dl' => array('dd' => 1, 'dt' => 1),
1920
- 'dt' => array('dd' => 1, 'dt' => 1),
1921
- 'li' => array('li' => 1),
1922
- 'optgroup' => array('optgroup' => 1, 'option' => 1),
1923
- 'option' => array('optgroup' => 1, 'option' => 1),
1924
- 'p' => array('p' => 1),
1925
- 'rp' => array('rp' => 1, 'rt' => 1),
1926
- 'rt' => array('rp' => 1, 'rt' => 1),
1927
- 'td' => array('td' => 1, 'th' => 1),
1928
- 'th' => array('td' => 1, 'th' => 1),
1929
- 'tr' => array('td' => 1, 'th' => 1, 'tr' => 1),
1930
- );
1931
-
1932
- function __construct(
1933
- $str = null,
1934
- $lowercase = true,
1935
- $forceTagsClosed = true,
1936
- $target_charset = DEFAULT_TARGET_CHARSET,
1937
- $stripRN = true,
1938
- $defaultBRText = DEFAULT_BR_TEXT,
1939
- $defaultSpanText = DEFAULT_SPAN_TEXT,
1940
- $options = 0
1941
- ) {
1942
- if ($str) {
1943
- if (preg_match('/^http:\/\//i', $str) || is_file($str)) {
1944
- $this->load_file($str);
1945
- } else {
1946
- $this->load(
1947
- $str,
1948
- $lowercase,
1949
- $stripRN,
1950
- $defaultBRText,
1951
- $defaultSpanText,
1952
- $options
1953
- );
1954
- }
1955
- }
1956
- // Forcing tags to be closed implies that we don't trust the html, but
1957
- // it can lead to parsing errors if we SHOULD trust the html.
1958
- if (!$forceTagsClosed) {
1959
- $this->optional_closing_array = array();
1960
- }
1961
-
1962
- $this->_target_charset = $target_charset;
1963
- }
1964
-
1965
- function __destruct()
1966
- {
1967
- $this->clear();
1968
- }
1969
-
1970
- // load html from string
1971
- function load(
1972
- $str,
1973
- $lowercase = true,
1974
- $stripRN = true,
1975
- $defaultBRText = DEFAULT_BR_TEXT,
1976
- $defaultSpanText = DEFAULT_SPAN_TEXT,
1977
- $options = 0
1978
- ) {
1979
- global $debug_object;
1980
-
1981
- // prepare
1982
- $this->prepare($str, $lowercase, $defaultBRText, $defaultSpanText);
1983
-
1984
- // Per sourceforge http://sourceforge.net/tracker/?func=detail&aid=2949097&group_id=218559&atid=1044037
1985
- // Script tags removal now preceeds style tag removal.
1986
- // strip out <script> tags
1987
- $this->remove_noise("'<\s*script[^>]*[^/]>(.*?)<\s*/\s*script\s*>'is");
1988
- $this->remove_noise("'<\s*script\s*>(.*?)<\s*/\s*script\s*>'is");
1989
-
1990
- // strip out the \r \n's if we are told to.
1991
- if ($stripRN) {
1992
- $this->doc = str_replace("\r", ' ', $this->doc);
1993
- $this->doc = str_replace("\n", ' ', $this->doc);
1994
-
1995
- // set the length of content since we have changed it.
1996
- $this->size = strlen($this->doc);
1997
- }
1998
-
1999
- // strip out cdata
2000
- $this->remove_noise("'<!\[CDATA\[(.*?)\]\]>'is", true);
2001
- // strip out comments
2002
- $this->remove_noise("'<!--(.*?)-->'is");
2003
- // strip out <style> tags
2004
- $this->remove_noise("'<\s*style[^>]*[^/]>(.*?)<\s*/\s*style\s*>'is");
2005
- $this->remove_noise("'<\s*style\s*>(.*?)<\s*/\s*style\s*>'is");
2006
- // strip out preformatted tags
2007
- $this->remove_noise("'<\s*(?:code)[^>]*>(.*?)<\s*/\s*(?:code)\s*>'is");
2008
- // strip out server side scripts
2009
- $this->remove_noise("'(<\?)(.*?)(\?>)'s", true);
2010
-
2011
- if ($options & HDOM_SMARTY_AS_TEXT) { // Strip Smarty scripts
2012
- $this->remove_noise("'(\{\w)(.*?)(\})'s", true);
2013
- }
2014
-
2015
- // parsing
2016
- $this->parse();
2017
- // end
2018
- $this->root->_[HDOM_INFO_END] = $this->cursor;
2019
- $this->parse_charset();
2020
-
2021
- // make load function chainable
2022
- return $this;
2023
- }
2024
-
2025
- // load html from file
2026
- function load_file()
2027
- {
2028
- $args = func_get_args();
2029
-
2030
- if (($doc = call_user_func_array('file_get_contents', $args)) !== false) {
2031
- $this->load($doc, true);
2032
- } else {
2033
- return false;
2034
- }
2035
- }
2036
-
2037
- /**
2038
- * Set the callback function
2039
- *
2040
- * @param callable $function_name Callback function to run for each element
2041
- * in the DOM.
2042
- * @return void
2043
- */
2044
- function set_callback($function_name)
2045
- {
2046
- $this->callback = $function_name;
2047
- }
2048
-
2049
- /**
2050
- * Remove callback function
2051
- *
2052
- * @return void
2053
- */
2054
- function remove_callback()
2055
- {
2056
- $this->callback = null;
2057
- }
2058
-
2059
- // save dom as string
2060
- function save($filepath = '')
2061
- {
2062
- $ret = $this->root->innertext();
2063
- if ($filepath !== '') {
2064
- file_put_contents($filepath, $ret, LOCK_EX);
2065
- }
2066
- return $ret;
2067
- }
2068
-
2069
- // find dom node by css selector
2070
- // Paperg - allow us to specify that we want case insensitive testing of the value of the selector.
2071
- function find($selector, $idx = null, $lowercase = false)
2072
- {
2073
- return $this->root->find($selector, $idx, $lowercase);
2074
- }
2075
-
2076
- // clean up memory due to php5 circular references memory leak...
2077
- function clear()
2078
- {
2079
- foreach ($this->nodes as $n) {
2080
- $n->clear();
2081
- $n = null;
2082
- }
2083
-
2084
- // This add next line is documented in the sourceforge repository.
2085
- // 2977248 as a fix for ongoing memory leaks that occur even with the
2086
- // use of clear.
2087
- if (isset($this->children)) {
2088
- foreach ($this->children as $n) {
2089
- $n->clear();
2090
- $n = null;
2091
- }
2092
- }
2093
-
2094
- if (isset($this->parent)) {
2095
- $this->parent->clear();
2096
- unset($this->parent);
2097
- }
2098
-
2099
- if (isset($this->root)) {
2100
- $this->root->clear();
2101
- unset($this->root);
2102
- }
2103
-
2104
- unset($this->doc);
2105
- unset($this->noise);
2106
- }
2107
-
2108
- function dump($show_attr = true)
2109
- {
2110
- $this->root->dump($show_attr);
2111
- }
2112
-
2113
- // prepare HTML data and init everything
2114
- protected function prepare(
2115
- $str,
2116
- $lowercase = true,
2117
- $defaultBRText = DEFAULT_BR_TEXT,
2118
- $defaultSpanText = DEFAULT_SPAN_TEXT
2119
- ) {
2120
- $this->clear();
2121
-
2122
- $this->doc = trim($str);
2123
- $this->size = strlen($this->doc);
2124
- $this->original_size = $this->size; // original size of the html
2125
- $this->pos = 0;
2126
- $this->cursor = 1;
2127
- $this->noise = array();
2128
- $this->nodes = array();
2129
- $this->lowercase = $lowercase;
2130
- $this->default_br_text = $defaultBRText;
2131
- $this->default_span_text = $defaultSpanText;
2132
- $this->root = new simple_html_dom_node($this);
2133
- $this->root->tag = 'root';
2134
- $this->root->_[HDOM_INFO_BEGIN] = -1;
2135
- $this->root->nodetype = HDOM_TYPE_ROOT;
2136
- $this->parent = $this->root;
2137
- if ($this->size > 0) {
2138
- $this->char = $this->doc[0];
2139
- }
2140
- }
2141
-
2142
- /**
2143
- * Parse HTML content
2144
- *
2145
- * @return bool True on success
2146
- */
2147
- protected function parse()
2148
- {
2149
- while (true) {
2150
- // Read next tag if there is no text between current position and the
2151
- // next opening tag.
2152
- if (($s = $this->copy_until_char('<')) === '') {
2153
- if ($this->read_tag()) {
2154
- continue;
2155
- } else {
2156
- return true;
2157
- }
2158
- }
2159
-
2160
- // Add a text node for text between tags
2161
- $node = new simple_html_dom_node($this);
2162
- ++$this->cursor;
2163
- $node->_[HDOM_INFO_TEXT] = $s;
2164
- $this->link_nodes($node, false);
2165
- }
2166
- }
2167
-
2168
- // PAPERG - dkchou - added this to try to identify the character set of the
2169
- // page we have just parsed so we know better how to spit it out later.
2170
- // NOTE: IF you provide a routine called
2171
- // get_last_retrieve_url_contents_content_type which returns the
2172
- // CURLINFO_CONTENT_TYPE from the last curl_exec
2173
- // (or the content_type header from the last transfer), we will parse THAT,
2174
- // and if a charset is specified, we will use it over any other mechanism.
2175
- protected function parse_charset()
2176
- {
2177
- global $debug_object;
2178
-
2179
- $charset = null;
2180
-
2181
- if (function_exists('get_last_retrieve_url_contents_content_type')) {
2182
- $contentTypeHeader = get_last_retrieve_url_contents_content_type();
2183
- $success = preg_match('/charset=(.+)/', $contentTypeHeader, $matches);
2184
- if ($success) {
2185
- $charset = $matches[1];
2186
- if (is_object($debug_object)) {
2187
- $debug_object->debug_log(
2188
- 2,
2189
- 'header content-type found charset of: '
2190
- . $charset
2191
- );
2192
- }
2193
- }
2194
- }
2195
-
2196
- if (empty($charset)) {
2197
- $el = $this->root->find('meta[http-equiv=Content-Type]', 0, true);
2198
-
2199
- if (!empty($el)) {
2200
- $fullvalue = $el->content;
2201
- if (is_object($debug_object)) {
2202
- $debug_object->debug_log(
2203
- 2,
2204
- 'meta content-type tag found'
2205
- . $fullvalue
2206
- );
2207
- }
2208
-
2209
- if (!empty($fullvalue)) {
2210
- $success = preg_match(
2211
- '/charset=(.+)/i',
2212
- $fullvalue,
2213
- $matches
2214
- );
2215
-
2216
- if ($success) {
2217
- $charset = $matches[1];
2218
- } else {
2219
- // If there is a meta tag, and they don't specify the
2220
- // character set, research says that it's typically
2221
- // ISO-8859-1
2222
- if (is_object($debug_object)) {
2223
- $debug_object->debug_log(
2224
- 2,
2225
- 'meta content-type tag couldn\'t be parsed. using iso-8859 default.'
2226
- );
2227
- }
2228
-
2229
- $charset = 'ISO-8859-1';
2230
- }
2231
- }
2232
- }
2233
- }
2234
-
2235
- // If we couldn't find a charset above, then lets try to detect one
2236
- // based on the text we got...
2237
- if (empty($charset)) {
2238
- // Use this in case mb_detect_charset isn't installed/loaded on
2239
- // this machine.
2240
- $charset = false;
2241
- if (function_exists('mb_detect_encoding')) {
2242
- // Have php try to detect the encoding from the text given to us.
2243
- $charset = mb_detect_encoding(
2244
- $this->doc . 'ascii',
2245
- $encoding_list = array( 'UTF-8', 'CP1252' )
2246
- );
2247
-
2248
- if (is_object($debug_object)) {
2249
- $debug_object->debug_log(2, 'mb_detect found: ' . $charset);
2250
- }
2251
- }
2252
-
2253
- // and if this doesn't work... then we need to just wrongheadedly
2254
- // assume it's UTF-8 so that we can move on - cause this will
2255
- // usually give us most of what we need...
2256
- if ($charset === false) {
2257
- if (is_object($debug_object)) {
2258
- $debug_object->debug_log(
2259
- 2,
2260
- 'since mb_detect failed - using default of utf-8'
2261
- );
2262
- }
2263
-
2264
- $charset = 'UTF-8';
2265
- }
2266
- }
2267
-
2268
- // Since CP1252 is a superset, if we get one of it's subsets, we want
2269
- // it instead.
2270
- if ((strtolower($charset) == strtolower('ISO-8859-1'))
2271
- || (strtolower($charset) == strtolower('Latin1'))
2272
- || (strtolower($charset) == strtolower('Latin-1'))) {
2273
- if (is_object($debug_object)) {
2274
- $debug_object->debug_log(
2275
- 2,
2276
- 'replacing ' . $charset . ' with CP1252 as its a superset'
2277
- );
2278
- }
2279
-
2280
- $charset = 'CP1252';
2281
- }
2282
-
2283
- if (is_object($debug_object)) {
2284
- $debug_object->debug_log(1, 'EXIT - ' . $charset);
2285
- }
2286
-
2287
- return $this->_charset = $charset;
2288
- }
2289
-
2290
- /**
2291
- * Parse tag from current document position.
2292
- *
2293
- * @return bool True if a tag was found, false otherwise
2294
- */
2295
- protected function read_tag()
2296
- {
2297
- // Set end position if no further tags found
2298
- if ($this->char !== '<') {
2299
- $this->root->_[HDOM_INFO_END] = $this->cursor;
2300
- return false;
2301
- }
2302
-
2303
- $begin_tag_pos = $this->pos;
2304
- $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2305
-
2306
- // end tag
2307
- if ($this->char === '/') {
2308
- $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2309
-
2310
- // Skip whitespace in end tags (i.e. in "</ html>")
2311
- $this->skip($this->token_blank);
2312
- $tag = $this->copy_until_char('>');
2313
-
2314
- // Skip attributes in end tags
2315
- if (($pos = strpos($tag, ' ')) !== false) {
2316
- $tag = substr($tag, 0, $pos);
2317
- }
2318
-
2319
- $parent_lower = strtolower($this->parent->tag);
2320
- $tag_lower = strtolower($tag);
2321
-
2322
- // The end tag is supposed to close the parent tag. Handle situations
2323
- // when it doesn't
2324
- if ($parent_lower !== $tag_lower) {
2325
- // Parent tag does not have to be closed necessarily (optional closing tag)
2326
- // Current tag is a block tag, so it may close an ancestor
2327
- if (isset($this->optional_closing_tags[$parent_lower])
2328
- && isset($this->block_tags[$tag_lower])) {
2329
- $this->parent->_[HDOM_INFO_END] = 0;
2330
- $org_parent = $this->parent;
2331
-
2332
- // Traverse ancestors to find a matching opening tag
2333
- // Stop at root node
2334
- while (($this->parent->parent)
2335
- && strtolower($this->parent->tag) !== $tag_lower
2336
- ) {
2337
- $this->parent = $this->parent->parent;
2338
- }
2339
-
2340
- // If we don't have a match add current tag as text node
2341
- if (strtolower($this->parent->tag) !== $tag_lower) {
2342
- $this->parent = $org_parent; // restore origonal parent
2343
-
2344
- if ($this->parent->parent) {
2345
- $this->parent = $this->parent->parent;
2346
- }
2347
-
2348
- $this->parent->_[HDOM_INFO_END] = $this->cursor;
2349
- return $this->as_text_node($tag);
2350
- }
2351
- } elseif (($this->parent->parent)
2352
- && isset($this->block_tags[$tag_lower])
2353
- ) {
2354
- // Grandparent exists and current tag is a block tag, so our
2355
- // parent doesn't have an end tag
2356
- $this->parent->_[HDOM_INFO_END] = 0; // No end tag
2357
- $org_parent = $this->parent;
2358
-
2359
- // Traverse ancestors to find a matching opening tag
2360
- // Stop at root node
2361
- while (($this->parent->parent)
2362
- && strtolower($this->parent->tag) !== $tag_lower
2363
- ) {
2364
- $this->parent = $this->parent->parent;
2365
- }
2366
-
2367
- // If we don't have a match add current tag as text node
2368
- if (strtolower($this->parent->tag) !== $tag_lower) {
2369
- $this->parent = $org_parent; // restore origonal parent
2370
- $this->parent->_[HDOM_INFO_END] = $this->cursor;
2371
- return $this->as_text_node($tag);
2372
- }
2373
- } elseif (($this->parent->parent)
2374
- && strtolower($this->parent->parent->tag) === $tag_lower
2375
- ) { // Grandparent exists and current tag closes it
2376
- $this->parent->_[HDOM_INFO_END] = 0;
2377
- $this->parent = $this->parent->parent;
2378
- } else { // Random tag, add as text node
2379
- return $this->as_text_node($tag);
2380
- }
2381
- }
2382
-
2383
- // Set end position of parent tag to current cursor position
2384
- $this->parent->_[HDOM_INFO_END] = $this->cursor;
2385
-
2386
- if ($this->parent->parent) {
2387
- $this->parent = $this->parent->parent;
2388
- }
2389
-
2390
- $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2391
- return true;
2392
- }
2393
-
2394
- // start tag
2395
- $node = new simple_html_dom_node($this);
2396
- $node->_[HDOM_INFO_BEGIN] = $this->cursor;
2397
- ++$this->cursor;
2398
- $tag = $this->copy_until($this->token_slash); // Get tag name
2399
- $node->tag_start = $begin_tag_pos;
2400
-
2401
- // doctype, cdata & comments...
2402
- // <!DOCTYPE html>
2403
- // <![CDATA[ ... ]]>
2404
- // <!-- Comment -->
2405
- if (isset($tag[0]) && $tag[0] === '!') {
2406
- $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until_char('>');
2407
-
2408
- if (isset($tag[2]) && $tag[1] === '-' && $tag[2] === '-') { // Comment ("<!--")
2409
- $node->nodetype = HDOM_TYPE_COMMENT;
2410
- $node->tag = 'comment';
2411
- } else { // Could be doctype or CDATA but we don't care
2412
- $node->nodetype = HDOM_TYPE_UNKNOWN;
2413
- $node->tag = 'unknown';
2414
- }
2415
-
2416
- if ($this->char === '>') {
2417
- $node->_[HDOM_INFO_TEXT] .= '>';
2418
- }
2419
-
2420
- $this->link_nodes($node, true);
2421
- $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2422
- return true;
2423
- }
2424
-
2425
- // The start tag cannot contain another start tag, if so add as text
2426
- // i.e. "<<html>"
2427
- if ($pos = strpos($tag, '<') !== false) {
2428
- $tag = '<' . substr($tag, 0, -1);
2429
- $node->_[HDOM_INFO_TEXT] = $tag;
2430
- $this->link_nodes($node, false);
2431
- $this->char = $this->doc[--$this->pos]; // prev
2432
- return true;
2433
- }
2434
-
2435
- // Handle invalid tag names (i.e. "<html#doc>")
2436
- if (!preg_match('/^\w[\w:-]*$/', $tag)) {
2437
- $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until('<>');
2438
-
2439
- // Next char is the beginning of a new tag, don't touch it.
2440
- if ($this->char === '<') {
2441
- $this->link_nodes($node, false);
2442
- return true;
2443
- }
2444
-
2445
- // Next char closes current tag, add and be done with it.
2446
- if ($this->char === '>') {
2447
- $node->_[HDOM_INFO_TEXT] .= '>';
2448
- }
2449
- $this->link_nodes($node, false);
2450
- $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2451
- return true;
2452
- }
2453
-
2454
- // begin tag, add new node
2455
- $node->nodetype = HDOM_TYPE_ELEMENT;
2456
- $tag_lower = strtolower($tag);
2457
- $node->tag = ($this->lowercase) ? $tag_lower : $tag;
2458
-
2459
- // handle optional closing tags
2460
- if (isset($this->optional_closing_tags[$tag_lower])) {
2461
- // Traverse ancestors to close all optional closing tags
2462
- while (isset($this->optional_closing_tags[$tag_lower][strtolower($this->parent->tag)])) {
2463
- $this->parent->_[HDOM_INFO_END] = 0;
2464
- $this->parent = $this->parent->parent;
2465
- }
2466
- $node->parent = $this->parent;
2467
- }
2468
-
2469
- $guard = 0; // prevent infinity loop
2470
-
2471
- // [0] Space between tag and first attribute
2472
- $space = array($this->copy_skip($this->token_blank), '', '');
2473
-
2474
- // attributes
2475
- do {
2476
- // Everything until the first equal sign should be the attribute name
2477
- $name = $this->copy_until($this->token_equal);
2478
-
2479
- if ($name === '' && $this->char !== null && $space[0] === '') {
2480
- break;
2481
- }
2482
-
2483
- if ($guard === $this->pos) { // Escape infinite loop
2484
- $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2485
- continue;
2486
- }
2487
-
2488
- $guard = $this->pos;
2489
-
2490
- // handle endless '<'
2491
- // Out of bounds before the tag ended
2492
- if ($this->pos >= $this->size - 1 && $this->char !== '>') {
2493
- $node->nodetype = HDOM_TYPE_TEXT;
2494
- $node->_[HDOM_INFO_END] = 0;
2495
- $node->_[HDOM_INFO_TEXT] = '<' . $tag . $space[0] . $name;
2496
- $node->tag = 'text';
2497
- $this->link_nodes($node, false);
2498
- return true;
2499
- }
2500
-
2501
- // handle mismatch '<'
2502
- // Attributes cannot start after opening tag
2503
- if ($this->doc[$this->pos - 1] == '<') {
2504
- $node->nodetype = HDOM_TYPE_TEXT;
2505
- $node->tag = 'text';
2506
- $node->attr = array();
2507
- $node->_[HDOM_INFO_END] = 0;
2508
- $node->_[HDOM_INFO_TEXT] = substr(
2509
- $this->doc,
2510
- $begin_tag_pos,
2511
- $this->pos - $begin_tag_pos - 1
2512
- );
2513
- $this->pos -= 2;
2514
- $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2515
- $this->link_nodes($node, false);
2516
- return true;
2517
- }
2518
-
2519
- if ($name !== '/' && $name !== '') { // this is a attribute name
2520
- // [1] Whitespace after attribute name
2521
- $space[1] = $this->copy_skip($this->token_blank);
2522
-
2523
- $name = $this->restore_noise($name); // might be a noisy name
2524
-
2525
- if ($this->lowercase) {
2526
- $name = strtolower($name);
2527
- }
2528
-
2529
- if ($this->char === '=') { // attribute with value
2530
- $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2531
- $this->parse_attr($node, $name, $space); // get attribute value
2532
- } else {
2533
- //no value attr: nowrap, checked selected...
2534
- $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_NO;
2535
- $node->attr[$name] = true;
2536
- if ($this->char != '>') {
2537
- $this->char = $this->doc[--$this->pos];
2538
- } // prev
2539
- }
2540
-
2541
- $node->_[HDOM_INFO_SPACE][] = $space;
2542
-
2543
- // prepare for next attribute
2544
- $space = array(
2545
- $this->copy_skip($this->token_blank),
2546
- '',
2547
- ''
2548
- );
2549
- } else { // no more attributes
2550
- break;
2551
- }
2552
- } while ($this->char !== '>' && $this->char !== '/'); // go until the tag ended
2553
-
2554
- $this->link_nodes($node, true);
2555
- $node->_[HDOM_INFO_ENDSPACE] = $space[0];
2556
-
2557
- // handle empty tags (i.e. "<div/>")
2558
- if ($this->copy_until_char('>') === '/') {
2559
- $node->_[HDOM_INFO_ENDSPACE] .= '/';
2560
- $node->_[HDOM_INFO_END] = 0;
2561
- } else {
2562
- // reset parent
2563
- if (!isset($this->self_closing_tags[strtolower($node->tag)])) {
2564
- $this->parent = $node;
2565
- }
2566
- }
2567
-
2568
- $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2569
-
2570
- // If it's a BR tag, we need to set it's text to the default text.
2571
- // This way when we see it in plaintext, we can generate formatting that the user wants.
2572
- // since a br tag never has sub nodes, this works well.
2573
- if ($node->tag === 'br') {
2574
- $node->_[HDOM_INFO_INNER] = $this->default_br_text;
2575
- }
2576
-
2577
- return true;
2578
- }
2579
-
2580
- /**
2581
- * Parse attribute from current document position
2582
- *
2583
- * @param object $node Node for the attributes
2584
- * @param string $name Name of the current attribute
2585
- * @param array $space Array for spacing information
2586
- * @return void
2587
- */
2588
- protected function parse_attr($node, $name, &$space)
2589
- {
2590
- // Per sourceforge: http://sourceforge.net/tracker/?func=detail&aid=3061408&group_id=218559&atid=1044037
2591
- // If the attribute is already defined inside a tag, only pay attention
2592
- // to the first one as opposed to the last one.
2593
- // https://stackoverflow.com/a/26341866
2594
- if (isset($node->attr[$name])) {
2595
- return;
2596
- }
2597
-
2598
- // [2] Whitespace between "=" and the value
2599
- $space[2] = $this->copy_skip($this->token_blank);
2600
-
2601
- switch ($this->char) {
2602
- case '"': // value is anything between double quotes
2603
- $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE;
2604
- $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2605
- $node->attr[$name] = $this->restore_noise($this->copy_until_char('"'));
2606
- $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2607
- break;
2608
- case '\'': // value is anything between single quotes
2609
- $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_SINGLE;
2610
- $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2611
- $node->attr[$name] = $this->restore_noise($this->copy_until_char('\''));
2612
- $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2613
- break;
2614
- default: // value is anything until the first space or end tag
2615
- $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_NO;
2616
- $node->attr[$name] = $this->restore_noise($this->copy_until($this->token_attr));
2617
- }
2618
- // PaperG: Attributes should not have \r or \n in them, that counts as
2619
- // html whitespace.
2620
- $node->attr[$name] = str_replace("\r", '', $node->attr[$name]);
2621
- $node->attr[$name] = str_replace("\n", '', $node->attr[$name]);
2622
- // PaperG: If this is a "class" selector, lets get rid of the preceeding
2623
- // and trailing space since some people leave it in the multi class case.
2624
- if ($name === 'class') {
2625
- $node->attr[$name] = trim($node->attr[$name]);
2626
- }
2627
- }
2628
-
2629
- /**
2630
- * Link node to parent node
2631
- *
2632
- * @param object $node Node to link to parent
2633
- * @param bool $is_child True if the node is a child of parent
2634
- * @return void
2635
- */
2636
- // link node's parent
2637
- protected function link_nodes(&$node, $is_child)
2638
- {
2639
- $node->parent = $this->parent;
2640
- $this->parent->nodes[] = $node;
2641
- if ($is_child) {
2642
- $this->parent->children[] = $node;
2643
- }
2644
- }
2645
-
2646
- /**
2647
- * Add tag as text node to current node
2648
- *
2649
- * @param string $tag Tag name
2650
- * @return bool True on success
2651
- */
2652
- protected function as_text_node($tag)
2653
- {
2654
- $node = new simple_html_dom_node($this);
2655
- ++$this->cursor;
2656
- $node->_[HDOM_INFO_TEXT] = '</' . $tag . '>';
2657
- $this->link_nodes($node, false);
2658
- $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2659
- return true;
2660
- }
2661
-
2662
- /**
2663
- * Seek from the current document position to the first occurrence of a
2664
- * character not defined by the provided string. Update the current document
2665
- * position to the new position.
2666
- *
2667
- * @param string $chars A string containing every allowed character.
2668
- * @return void
2669
- */
2670
- protected function skip($chars)
2671
- {
2672
- $this->pos += strspn($this->doc, $chars, $this->pos);
2673
- $this->char = ($this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2674
- }
2675
-
2676
- /**
2677
- * Copy substring from the current document position to the first occurrence
2678
- * of a character not defined by the provided string.
2679
- *
2680
- * @param string $chars A string containing every allowed character.
2681
- * @return string Substring from the current document position to the first
2682
- * occurrence of a character not defined by the provided string.
2683
- */
2684
- protected function copy_skip($chars)
2685
- {
2686
- $pos = $this->pos;
2687
- $len = strspn($this->doc, $chars, $pos);
2688
- $this->pos += $len;
2689
- $this->char = ($this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2690
- if ($len === 0) {
2691
- return '';
2692
- }
2693
- return substr($this->doc, $pos, $len);
2694
- }
2695
-
2696
- /**
2697
- * Copy substring from the current document position to the first occurrence
2698
- * of any of the provided characters.
2699
- *
2700
- * @param string $chars A string containing every character to stop at.
2701
- * @return string Substring from the current document position to the first
2702
- * occurrence of any of the provided characters.
2703
- */
2704
- protected function copy_until($chars)
2705
- {
2706
- $pos = $this->pos;
2707
- $len = strcspn($this->doc, $chars, $pos);
2708
- $this->pos += $len;
2709
- $this->char = ($this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2710
- return substr($this->doc, $pos, $len);
2711
- }
2712
-
2713
- /**
2714
- * Copy substring from the current document position to the first occurrence
2715
- * of the provided string.
2716
- *
2717
- * @param string $char The string to stop at.
2718
- * @return string Substring from the current document position to the first
2719
- * occurrence of the provided string.
2720
- */
2721
- protected function copy_until_char($char)
2722
- {
2723
- if ($this->char === null) {
2724
- return '';
2725
- }
2726
-
2727
- if (($pos = strpos($this->doc, $char, $this->pos)) === false) {
2728
- $ret = substr($this->doc, $this->pos, $this->size - $this->pos);
2729
- $this->char = null;
2730
- $this->pos = $this->size;
2731
- return $ret;
2732
- }
2733
-
2734
- if ($pos === $this->pos) {
2735
- return '';
2736
- }
2737
-
2738
- $pos_old = $this->pos;
2739
- $this->char = $this->doc[$pos];
2740
- $this->pos = $pos;
2741
- return substr($this->doc, $pos_old, $pos - $pos_old);
2742
- }
2743
-
2744
- /**
2745
- * Remove noise from HTML content
2746
- *
2747
- * Noise is stored to {@see simple_html_dom::$noise}
2748
- *
2749
- * @param string $pattern The regex pattern used for finding noise
2750
- * @param bool $remove_tag True to remove the entire match. Default is false
2751
- * to only remove the captured data.
2752
- */
2753
- protected function remove_noise($pattern, $remove_tag = false)
2754
- {
2755
- global $debug_object;
2756
- if (is_object($debug_object)) {
2757
- $debug_object->debug_log_entry(1);
2758
- }
2759
-
2760
- $count = preg_match_all(
2761
- $pattern,
2762
- $this->doc,
2763
- $matches,
2764
- PREG_SET_ORDER | PREG_OFFSET_CAPTURE
2765
- );
2766
-
2767
- for ($i = $count - 1; $i > -1; --$i) {
2768
- $key = '___noise___' . sprintf('% 5d', count($this->noise) + 1000);
2769
-
2770
- if (is_object($debug_object)) {
2771
- $debug_object->debug_log(2, 'key is: ' . $key);
2772
- }
2773
-
2774
- $idx = ($remove_tag) ? 0 : 1; // 0 = entire match, 1 = submatch
2775
- $this->noise[$key] = $matches[$i][$idx][0];
2776
- $this->doc = substr_replace($this->doc, $key, $matches[$i][$idx][1], strlen($matches[$i][$idx][0]));
2777
- }
2778
-
2779
- // reset the length of content
2780
- $this->size = strlen($this->doc);
2781
-
2782
- if ($this->size > 0) {
2783
- $this->char = $this->doc[0];
2784
- }
2785
- }
2786
-
2787
- /**
2788
- * Restore noise to HTML content
2789
- *
2790
- * Noise is restored from {@see simple_html_dom::$noise}
2791
- *
2792
- * @param string $text A subset of HTML containing noise
2793
- * @return string The same content with noise restored
2794
- */
2795
- function restore_noise($text)
2796
- {
2797
- global $debug_object;
2798
- if (is_object($debug_object)) {
2799
- $debug_object->debug_log_entry(1);
2800
- }
2801
-
2802
- while (($pos = strpos($text, '___noise___')) !== false) {
2803
- // Sometimes there is a broken piece of markup, and we don't GET the
2804
- // pos+11 etc... token which indicates a problem outside of us...
2805
-
2806
- // todo: "___noise___1000" (or any number with four or more digits)
2807
- // in the DOM causes an infinite loop which could be utilized by
2808
- // malicious software
2809
- if (strlen($text) > $pos + 15) {
2810
- $key = '___noise___'
2811
- . $text[$pos + 11]
2812
- . $text[$pos + 12]
2813
- . $text[$pos + 13]
2814
- . $text[$pos + 14]
2815
- . $text[$pos + 15];
2816
-
2817
- if (is_object($debug_object)) {
2818
- $debug_object->debug_log(2, 'located key of: ' . $key);
2819
- }
2820
-
2821
- if (isset($this->noise[$key])) {
2822
- $text = substr($text, 0, $pos)
2823
- . $this->noise[$key]
2824
- . substr($text, $pos + 16);
2825
- } else {
2826
- // do this to prevent an infinite loop.
2827
- $text = substr($text, 0, $pos)
2828
- . 'UNDEFINED NOISE FOR KEY: '
2829
- . $key
2830
- . substr($text, $pos + 16);
2831
- }
2832
- } else {
2833
- // There is no valid key being given back to us... We must get
2834
- // rid of the ___noise___ or we will have a problem.
2835
- $text = substr($text, 0, $pos)
2836
- . 'NO NUMERIC NOISE KEY'
2837
- . substr($text, $pos + 11);
2838
- }
2839
- }
2840
- return $text;
2841
- }
2842
-
2843
- // Sometimes we NEED one of the noise elements.
2844
- function search_noise($text)
2845
- {
2846
- global $debug_object;
2847
- if (is_object($debug_object)) {
2848
- $debug_object->debug_log_entry(1);
2849
- }
2850
-
2851
- foreach ($this->noise as $noiseElement) {
2852
- if (strpos($noiseElement, $text) !== false) {
2853
- return $noiseElement;
2854
- }
2855
- }
2856
- }
2857
-
2858
- function __toString()
2859
- {
2860
- return $this->root->innertext();
2861
- }
2862
-
2863
- function __get($name)
2864
- {
2865
- switch ($name) {
2866
- case 'outertext':
2867
- return $this->root->innertext();
2868
- case 'innertext':
2869
- return $this->root->innertext();
2870
- case 'plaintext':
2871
- return $this->root->text();
2872
- case 'charset':
2873
- return $this->_charset;
2874
- case 'target_charset':
2875
- return $this->_target_charset;
2876
- }
2877
- }
2878
-
2879
- // camel naming conventions
2880
- function childNodes($idx = -1)
2881
- {
2882
- return $this->root->childNodes($idx);
2883
- }
2884
-
2885
- function firstChild()
2886
- {
2887
- return $this->root->first_child();
2888
- }
2889
-
2890
- function lastChild()
2891
- {
2892
- return $this->root->last_child();
2893
- }
2894
-
2895
- function createElement($name, $value = null)
2896
- {
2897
- return @str_get_html("<$name>$value</$name>")->first_child();
2898
- }
2899
-
2900
- function createTextNode($value)
2901
- {
2902
- return @end(str_get_html($value)->nodes);
2903
- }
2904
-
2905
- function getElementById($id)
2906
- {
2907
- return $this->find("#$id", 0);
2908
- }
2909
-
2910
- function getElementsById($id, $idx = null)
2911
- {
2912
- return $this->find("#$id", $idx);
2913
- }
2914
-
2915
- function getElementByTagName($name)
2916
- {
2917
- return $this->find($name, 0);
2918
- }
2919
-
2920
- function getElementsByTagName($name, $idx = -1)
2921
- {
2922
- return $this->find($name, $idx);
2923
- }
2924
-
2925
- function loadFile()
2926
- {
2927
- $args = func_get_args();
2928
- $this->load_file($args);
2929
- }
2930
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/rosell-dk/dom-util-for-webp/src/ImageUrlReplacer.php CHANGED
@@ -3,6 +3,7 @@
3
  namespace DOMUtilForWebP;
4
 
5
  //use Sunra\PhpSimple\HtmlDomParser;
 
6
 
7
  /**
8
  * Highly configurable class for replacing image URLs in HTML (both src and srcset syntax)
@@ -179,8 +180,9 @@ class ImageUrlReplacer
179
  // function str_get_html($str, $lowercase=true, $forceTagsClosed=true, $target_charset = DEFAULT_TARGET_CHARSET,
180
  // $stripRN=true, $defaultBRText=DEFAULT_BR_TEXT, $defaultSpanText=DEFAULT_SPAN_TEXT)
181
 
182
- //$dom = HtmlDomParser::str_get_html($html, false, false, 'UTF-8', false);
183
- $dom = str_get_html($html, false, false, 'UTF-8', false);
 
184
 
185
  // MAX_FILE_SIZE is defined in simple_html_dom.
186
  // For safety sake, we make sure it is defined before using
@@ -232,9 +234,9 @@ class ImageUrlReplacer
232
  /* Main replacer function */
233
  public static function replace($html)
234
  {
235
- if (!function_exists('str_get_html')) {
236
  require_once __DIR__ . '/../src-vendor/simple_html_dom/simple_html_dom.inc';
237
- }
238
  $iur = new static();
239
  return $iur->replaceHtml($html);
240
  }
3
  namespace DOMUtilForWebP;
4
 
5
  //use Sunra\PhpSimple\HtmlDomParser;
6
+ use KubAT\PhpSimple\HtmlDomParser;
7
 
8
  /**
9
  * Highly configurable class for replacing image URLs in HTML (both src and srcset syntax)
180
  // function str_get_html($str, $lowercase=true, $forceTagsClosed=true, $target_charset = DEFAULT_TARGET_CHARSET,
181
  // $stripRN=true, $defaultBRText=DEFAULT_BR_TEXT, $defaultSpanText=DEFAULT_SPAN_TEXT)
182
 
183
+ $dom = HtmlDomParser::str_get_html($html, false, false, 'UTF-8', false);
184
+ //$dom = str_get_html($html, false, false, 'UTF-8', false);
185
+
186
 
187
  // MAX_FILE_SIZE is defined in simple_html_dom.
188
  // For safety sake, we make sure it is defined before using
234
  /* Main replacer function */
235
  public static function replace($html)
236
  {
237
+ /*if (!function_exists('str_get_html')) {
238
  require_once __DIR__ . '/../src-vendor/simple_html_dom/simple_html_dom.inc';
239
+ }*/
240
  $iur = new static();
241
  return $iur->replaceHtml($html);
242
  }
vendor/rosell-dk/dom-util-for-webp/src/PictureTags.php CHANGED
@@ -3,6 +3,8 @@
3
  namespace DOMUtilForWebP;
4
 
5
  //use Sunra\PhpSimple\HtmlDomParser;
 
 
6
  /**
7
  * Class PictureTags - convert an <img> tag to a <picture> tag and add the webp versions of the images
8
  * Code is based on code from the ShortPixel plugin, which in turn used code from Responsify WP plugin
@@ -22,7 +24,6 @@ namespace DOMUtilForWebP;
22
  * https://packagist.org/packages/masterminds/html5
23
  */
24
 
25
- use \WebPExpress\AlterHtmlHelper;
26
 
27
  class PictureTags
28
  {
@@ -127,11 +128,12 @@ class PictureTags
127
  return $attributes;
128
  } else {
129
  //$dom = HtmlDomParser::str_get_html($html, false, false, 'UTF-8', false);
130
- if (!function_exists('str_get_html')) {
131
  require_once __DIR__ . '/../src-vendor/simple_html_dom/simple_html_dom.inc';
132
- }
 
133
 
134
- $dom = str_get_html($html, false, false, 'UTF-8', false);
135
  if ($dom !== false) {
136
  $elems = $dom->find('img,IMG');
137
  foreach ($elems as $index => $elem) {
3
  namespace DOMUtilForWebP;
4
 
5
  //use Sunra\PhpSimple\HtmlDomParser;
6
+ use KubAT\PhpSimple\HtmlDomParser;
7
+
8
  /**
9
  * Class PictureTags - convert an <img> tag to a <picture> tag and add the webp versions of the images
10
  * Code is based on code from the ShortPixel plugin, which in turn used code from Responsify WP plugin
24
  * https://packagist.org/packages/masterminds/html5
25
  */
26
 
 
27
 
28
  class PictureTags
29
  {
128
  return $attributes;
129
  } else {
130
  //$dom = HtmlDomParser::str_get_html($html, false, false, 'UTF-8', false);
131
+ /*if (!function_exists('str_get_html')) {
132
  require_once __DIR__ . '/../src-vendor/simple_html_dom/simple_html_dom.inc';
133
+ }*/
134
+
135
 
136
+ $dom = HtmlDomParser::str_get_html($html, false, false, 'UTF-8', false);
137
  if ($dom !== false) {
138
  $elems = $dom->find('img,IMG');
139
  foreach ($elems as $index => $elem) {
webp-express.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: WebP Express
4
  * Plugin URI: https://github.com/rosell-dk/webp-express
5
  * Description: Serve autogenerated WebP images instead of jpeg/png to browsers that supports WebP. Works on anything (media library images, galleries, theme images etc).
6
- * Version: 0.22.1
7
  * Author: Bjørn Rosell
8
  * Author URI: https://www.bitwise-it.dk
9
  * License: GPL2
3
  * Plugin Name: WebP Express
4
  * Plugin URI: https://github.com/rosell-dk/webp-express
5
  * Description: Serve autogenerated WebP images instead of jpeg/png to browsers that supports WebP. Works on anything (media library images, galleries, theme images etc).
6
+ * Version: 0.23.0
7
  * Author: Bjørn Rosell
8
  * Author URI: https://www.bitwise-it.dk
9
  * License: GPL2