Version Description
- Added revisions
- Added drafts/previewing
- Added minification
Download this release
Release Info
Developer | hearken |
Plugin | Custom CSS and Javascript |
Version | 2.0 |
Comparing to | |
See all releases |
Code changes from version 1.0.6 to 2.0
- css/custom-css-and-javascript.css +14 -0
- custom-css-and-javascript.php +235 -65
- images/potent-logo.png +0 -0
- js/custom-css-and-javascript.js +175 -0
- minify/LICENSE +18 -0
- minify/data/js/keywords_after.txt +7 -0
- minify/data/js/keywords_before.txt +27 -0
- minify/data/js/keywords_reserved.txt +47 -0
- minify/data/js/operators_after.txt +45 -0
- minify/data/js/operators_before.txt +43 -0
- minify/src/CSS.php +573 -0
- minify/src/Converter.php +195 -0
- minify/src/Exception.php +10 -0
- minify/src/JS.php +480 -0
- minify/src/Minify.php +382 -0
- plugin-credit.php +30 -0
- readme.txt +16 -4
css/custom-css-and-javascript.css
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Author: Hearken Media
|
3 |
+
* License: GNU General Public License version 2 or later
|
4 |
+
* License URI: http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html
|
5 |
+
*/
|
6 |
+
#hm_custom_css_js_revisions {
|
7 |
+
margin-top: 5px;
|
8 |
+
}
|
9 |
+
#hm_custom_css_js_revisions li {
|
10 |
+
white-space: nowrap;
|
11 |
+
}
|
12 |
+
#hm_custom_css_js_revisions .active a.view-rev {
|
13 |
+
font-weight: bold;
|
14 |
+
}
|
custom-css-and-javascript.php
CHANGED
@@ -2,9 +2,9 @@
|
|
2 |
/**
|
3 |
* Plugin Name: Custom CSS and Javascript
|
4 |
* Description: Easily add custom CSS and Javascript code to your WordPress site.
|
5 |
-
* Version:
|
6 |
-
* Author:
|
7 |
-
* Author URI: http://
|
8 |
* License: GNU General Public License version 2 or later
|
9 |
* License URI: http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html
|
10 |
*/
|
@@ -12,10 +12,15 @@
|
|
12 |
add_action('wp_enqueue_scripts', 'hm_custom_css_js_scripts', 999999);
|
13 |
function hm_custom_css_js_scripts() {
|
14 |
$uploadDir = wp_upload_dir();
|
15 |
-
if (
|
16 |
-
wp_enqueue_script('hm_custom_js',
|
17 |
-
|
18 |
-
|
|
|
|
|
|
|
|
|
|
|
19 |
}
|
20 |
add_action('admin_menu', 'hm_custom_css_admin_menu');
|
21 |
function hm_custom_css_admin_menu() {
|
@@ -35,7 +40,10 @@ function hm_custom_css_js_admin_scripts($hook) {
|
|
35 |
else
|
36 |
wp_enqueue_script('hm_custom_css_js_codemirror_mode_js', plugins_url('codemirror/mode/javascript.js', __FILE__));
|
37 |
wp_enqueue_style('hm_custom_css_js_codemirror', plugins_url('codemirror/codemirror.css', __FILE__));
|
|
|
|
|
38 |
}
|
|
|
39 |
add_action('wp_ajax_hm_custom_css_js_save', 'hm_custom_css_js_save');
|
40 |
function hm_custom_css_js_save() {
|
41 |
if (!current_user_can('edit_theme_options') || empty($_POST['mode']) || !isset($_POST['code']))
|
@@ -43,15 +51,216 @@ function hm_custom_css_js_save() {
|
|
43 |
$_POST['mode'] = strtolower($_POST['mode']);
|
44 |
if ($_POST['mode'] != 'css' && $_POST['mode'] != 'javascript')
|
45 |
wp_send_json_error();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
$uploadDir = wp_upload_dir();
|
47 |
if (!is_dir($uploadDir['basedir'].'/hm_custom_css_js'))
|
48 |
mkdir($uploadDir['basedir'].'/hm_custom_css_js') or wp_send_json_error();
|
49 |
-
|
|
|
50 |
wp_send_json_error();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
update_option('hm_custom_'.$_POST['mode'].'_ver', time());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
wp_send_json_success();
|
53 |
}
|
54 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
function hm_custom_css_page() {
|
56 |
hm_custom_css_js_page('CSS');
|
57 |
}
|
@@ -68,69 +277,30 @@ function hm_custom_css_js_page($mode) {
|
|
68 |
echo('
|
69 |
<div class="wrap">
|
70 |
<h2>Custom '.$mode.'</h2>
|
|
|
71 |
<div>
|
72 |
-
<div id="hm_custom_code_editor" style="margin-top: 15px;"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
<div style="float: right; padding-left: 10px; margin-top: 3px; white-space: nowrap; font-style: italic;">
|
74 |
<a href="https://codemirror.net/" target="_blank">CodeMirror</a> code editor
|
75 |
</div>
|
76 |
<button type="button" class="button-primary hm-custom-css-js-save-btn" style="margin-top: 15px;" disabled="disabled">Saved</button>
|
|
|
|
|
|
|
|
|
77 |
</div>
|
78 |
-
<
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
mode: "'.strtolower($mode).'",
|
84 |
-
value: '.$code.'
|
85 |
-
});
|
86 |
-
hm_custom_code_editor.on("change", function() {
|
87 |
-
if (hm_custom_code_editor_has_changes)
|
88 |
-
return;
|
89 |
-
hm_custom_code_editor_has_changes = true;
|
90 |
-
$(".hm-custom-css-js-save-btn").html("Save").prop("disabled", false);
|
91 |
-
});
|
92 |
-
$(".hm-custom-css-js-save-btn").click(function() {
|
93 |
-
$(".hm-custom-css-js-save-btn").prop("disabled", true).html("Saving...");
|
94 |
-
$.post(ajaxurl, {action: "hm_custom_css_js_save", mode: "'.$mode.'", code: hm_custom_code_editor.getValue()})
|
95 |
-
.done(function(data) {
|
96 |
-
if (data.success) {
|
97 |
-
$(".hm-custom-css-js-save-btn").html("Saved");
|
98 |
-
hm_custom_code_editor_has_changes = false;
|
99 |
-
} else {
|
100 |
-
alert("Error while saving. Please try again.");
|
101 |
-
$(".hm-custom-css-js-save-btn").html("Save").prop("disabled", false);
|
102 |
-
}
|
103 |
-
})
|
104 |
-
.fail(function() {
|
105 |
-
alert("Error while saving. Please try again.");
|
106 |
-
$(".hm-custom-css-js-save-btn").html("Save").prop("disabled", false);
|
107 |
-
});
|
108 |
-
});
|
109 |
-
$(window).resize(function() {
|
110 |
-
$("#hm_custom_code_editor .CodeMirror").height(Math.max(150,
|
111 |
-
$(window).height()
|
112 |
-
- $("#hm_custom_code_editor").offset().top
|
113 |
-
- $(".hm-custom-css-js-save-btn").height()
|
114 |
-
- 30));
|
115 |
-
hm_custom_code_editor.refresh();
|
116 |
-
});
|
117 |
-
$(window).resize();
|
118 |
-
$(window).on("beforeunload", function(ev) {
|
119 |
-
if (hm_custom_code_editor_has_changes) {
|
120 |
-
ev.returnValue = "You have unsaved changes that will be lost if you leave this page!";
|
121 |
-
return ev.returnValue;
|
122 |
-
}
|
123 |
-
});
|
124 |
-
});
|
125 |
-
</script>
|
126 |
-
|
127 |
-
<div style="background-color: #fff; border: 1px solid #ccc; padding: 20px; display: inline-block; margin-top: 30px;">
|
128 |
-
<h3 style="margin: 0;">Plugin by:</h3>
|
129 |
-
<a href="http://hearkenmedia.com/landing-wp-plugin.php?utm_source=custom-css-and-javascript&utm_medium=link&utm_campaign=wp-widget-link" target="_blank"><img src="'.plugins_url('images/hm-logo.png', __FILE__).'" alt="Hearken Media" style="width: 250px;" /></a><br />
|
130 |
-
<a href="https://wordpress.org/support/view/plugin-reviews/custom-css-and-javascript" target="_blank"><strong>
|
131 |
-
If you find this plugin useful, please write a brief review!
|
132 |
-
</strong></a>
|
133 |
-
</div>
|
134 |
</div>
|
135 |
');
|
136 |
}
|
2 |
/**
|
3 |
* Plugin Name: Custom CSS and Javascript
|
4 |
* Description: Easily add custom CSS and Javascript code to your WordPress site.
|
5 |
+
* Version: 2.0
|
6 |
+
* Author: Potent Plugins
|
7 |
+
* Author URI: http://potentplugins.com/?utm_source=custom-css-and-javascript&utm_medium=link&utm_campaign=wp-plugin-credit-link
|
8 |
* License: GNU General Public License version 2 or later
|
9 |
* License URI: http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html
|
10 |
*/
|
12 |
add_action('wp_enqueue_scripts', 'hm_custom_css_js_scripts', 999999);
|
13 |
function hm_custom_css_js_scripts() {
|
14 |
$uploadDir = wp_upload_dir();
|
15 |
+
if (current_user_can('edit_theme_options')) {
|
16 |
+
wp_enqueue_script('hm_custom_js', get_site_url(null, '/index.php').'?hm_custom_js_draft=1', array(), time());
|
17 |
+
wp_enqueue_style('hm_custom_css', get_site_url(null, '/index.php').'?hm_custom_css_draft=1', array(), time());
|
18 |
+
} else {
|
19 |
+
if (file_exists($uploadDir['basedir'].'/hm_custom_css_js/custom.js'))
|
20 |
+
wp_enqueue_script('hm_custom_js', $uploadDir['baseurl'].'/hm_custom_css_js/custom.js', array(), get_option('hm_custom_javascript_ver', 1));
|
21 |
+
if (file_exists($uploadDir['basedir'].'/hm_custom_css_js/custom.css'))
|
22 |
+
wp_enqueue_style('hm_custom_css', $uploadDir['baseurl'].'/hm_custom_css_js/custom.css', array(), get_option('hm_custom_css_ver', 1));
|
23 |
+
}
|
24 |
}
|
25 |
add_action('admin_menu', 'hm_custom_css_admin_menu');
|
26 |
function hm_custom_css_admin_menu() {
|
40 |
else
|
41 |
wp_enqueue_script('hm_custom_css_js_codemirror_mode_js', plugins_url('codemirror/mode/javascript.js', __FILE__));
|
42 |
wp_enqueue_style('hm_custom_css_js_codemirror', plugins_url('codemirror/codemirror.css', __FILE__));
|
43 |
+
wp_enqueue_script('hm_custom_css_js', plugins_url('js/custom-css-and-javascript.js', __FILE__));
|
44 |
+
wp_enqueue_style('hm_custom_css_js', plugins_url('css/custom-css-and-javascript.css', __FILE__));
|
45 |
}
|
46 |
+
|
47 |
add_action('wp_ajax_hm_custom_css_js_save', 'hm_custom_css_js_save');
|
48 |
function hm_custom_css_js_save() {
|
49 |
if (!current_user_can('edit_theme_options') || empty($_POST['mode']) || !isset($_POST['code']))
|
51 |
$_POST['mode'] = strtolower($_POST['mode']);
|
52 |
if ($_POST['mode'] != 'css' && $_POST['mode'] != 'javascript')
|
53 |
wp_send_json_error();
|
54 |
+
|
55 |
+
$_POST['code'] = wp_unslash($_POST['code']);
|
56 |
+
|
57 |
+
$rev_id = wp_insert_post(array(
|
58 |
+
'post_content' => $_POST['code'],
|
59 |
+
'post_status' => 'draft',
|
60 |
+
'post_type' => 'hm_custom_'.$_POST['mode'],
|
61 |
+
));
|
62 |
+
if ($rev_id === false)
|
63 |
+
wp_send_json_error();
|
64 |
+
|
65 |
+
wp_send_json_success($rev_id);
|
66 |
+
}
|
67 |
+
|
68 |
+
add_action('wp_ajax_hm_custom_css_js_publish', 'hm_custom_css_js_publish');
|
69 |
+
function hm_custom_css_js_publish() {
|
70 |
+
if (!current_user_can('edit_theme_options') || empty($_POST['mode']) || !isset($_POST['rev']) || !is_numeric($_POST['rev']))
|
71 |
+
wp_send_json_error();
|
72 |
+
$_POST['mode'] = strtolower($_POST['mode']);
|
73 |
+
if ($_POST['mode'] != 'css' && $_POST['mode'] != 'javascript')
|
74 |
+
wp_send_json_error();
|
75 |
+
|
76 |
+
$post = get_post($_POST['rev']);
|
77 |
+
if ($post->post_type != 'hm_custom_'.$_POST['mode'])
|
78 |
+
wp_send_json_error();
|
79 |
+
|
80 |
$uploadDir = wp_upload_dir();
|
81 |
if (!is_dir($uploadDir['basedir'].'/hm_custom_css_js'))
|
82 |
mkdir($uploadDir['basedir'].'/hm_custom_css_js') or wp_send_json_error();
|
83 |
+
$outputFile = $uploadDir['basedir'].'/hm_custom_css_js/custom.'.($_POST['mode'] == 'css' ? 'css' : 'js');
|
84 |
+
if (file_put_contents($outputFile, $post->post_content) === false)
|
85 |
wp_send_json_error();
|
86 |
+
if (empty($_POST['minify'])) {
|
87 |
+
update_option('hm_custom_'.$_POST['mode'].'_minify', false);
|
88 |
+
} else {
|
89 |
+
update_option('hm_custom_'.$_POST['mode'].'_minify', true);
|
90 |
+
require_once(__DIR__.'/minify/src/Minify.php');
|
91 |
+
require_once(__DIR__.'/minify/src/Exception.php');
|
92 |
+
if ($_POST['mode'] == 'css') {
|
93 |
+
require_once(__DIR__.'/minify/src/CSS.php');
|
94 |
+
require_once(__DIR__.'/minify/src/Converter.php');
|
95 |
+
$minifier = new MatthiasMullie\Minify\CSS;
|
96 |
+
} else {
|
97 |
+
require_once(__DIR__.'/minify/src/JS.php');
|
98 |
+
$minifier = new MatthiasMullie\Minify\JS;
|
99 |
+
}
|
100 |
+
$minifier->add($outputFile);
|
101 |
+
$minifier->minify($outputFile);
|
102 |
+
}
|
103 |
+
|
104 |
update_option('hm_custom_'.$_POST['mode'].'_ver', time());
|
105 |
+
|
106 |
+
// Unpublish previous revisions
|
107 |
+
$wp_query = new WP_Query(array(
|
108 |
+
'post_type' => 'hm_custom_'.$_POST['mode'],
|
109 |
+
'post_status' => 'publish',
|
110 |
+
'fields' => 'ids',
|
111 |
+
'nopaging' => true
|
112 |
+
));
|
113 |
+
$posts = $wp_query->get_posts();
|
114 |
+
foreach ($posts as $postId) {
|
115 |
+
if (!wp_update_post(array(
|
116 |
+
'ID' => $postId,
|
117 |
+
'post_status' => 'draft',
|
118 |
+
)))
|
119 |
+
wp_send_json_error();
|
120 |
+
}
|
121 |
+
|
122 |
+
if (!wp_update_post(array(
|
123 |
+
'ID' => $_POST['rev'],
|
124 |
+
'post_status' => 'publish',
|
125 |
+
'post_date' => current_time('Y-m-d H:i:s'),
|
126 |
+
)))
|
127 |
+
wp_send_json_error();
|
128 |
+
|
129 |
wp_send_json_success();
|
130 |
}
|
131 |
|
132 |
+
add_action('wp_ajax_hm_custom_css_js_delete_revision', 'hm_custom_css_js_delete_revision');
|
133 |
+
function hm_custom_css_js_delete_revision() {
|
134 |
+
if (!current_user_can('edit_theme_options') || empty($_POST['mode']) || !isset($_POST['rev']) || !is_numeric($_POST['rev']))
|
135 |
+
wp_send_json_error();
|
136 |
+
$_POST['mode'] = strtolower($_POST['mode']);
|
137 |
+
if ($_POST['mode'] != 'css' && $_POST['mode'] != 'javascript')
|
138 |
+
wp_send_json_error();
|
139 |
+
|
140 |
+
$post = get_post($_POST['rev']);
|
141 |
+
if ($post->post_type != 'hm_custom_'.$_POST['mode'] || $post->post_status == 'publish')
|
142 |
+
wp_send_json_error();
|
143 |
+
|
144 |
+
|
145 |
+
if (!wp_delete_post($post->ID, true))
|
146 |
+
wp_send_json_error();
|
147 |
+
|
148 |
+
wp_send_json_success();
|
149 |
+
}
|
150 |
+
|
151 |
+
add_action('wp_ajax_hm_custom_css_js_delete_revisions', 'hm_custom_css_js_delete_revisions');
|
152 |
+
function hm_custom_css_js_delete_revisions() {
|
153 |
+
if (!current_user_can('edit_theme_options') || empty($_POST['mode']))
|
154 |
+
wp_send_json_error();
|
155 |
+
$_POST['mode'] = strtolower($_POST['mode']);
|
156 |
+
if ($_POST['mode'] != 'css' && $_POST['mode'] != 'javascript')
|
157 |
+
wp_send_json_error();
|
158 |
+
|
159 |
+
$wp_query = new WP_Query(array(
|
160 |
+
'post_type' => 'hm_custom_'.$_POST['mode'],
|
161 |
+
'post_status' => 'draft',
|
162 |
+
'fields' => 'ids',
|
163 |
+
'nopaging' => true
|
164 |
+
));
|
165 |
+
$posts = $wp_query->get_posts();
|
166 |
+
foreach ($posts as $postId) {
|
167 |
+
if (!wp_delete_post($postId, true))
|
168 |
+
wp_send_json_error();
|
169 |
+
}
|
170 |
+
|
171 |
+
wp_send_json_success();
|
172 |
+
}
|
173 |
+
|
174 |
+
|
175 |
+
add_action('wp_ajax_hm_custom_css_js_get_revisions', 'hm_custom_css_js_get_revisions');
|
176 |
+
function hm_custom_css_js_get_revisions() {
|
177 |
+
if (!current_user_can('edit_theme_options') || empty($_POST['mode']))
|
178 |
+
wp_send_json_error();
|
179 |
+
$_POST['mode'] = strtolower($_POST['mode']);
|
180 |
+
if ($_POST['mode'] != 'css' && $_POST['mode'] != 'javascript')
|
181 |
+
wp_send_json_error();
|
182 |
+
|
183 |
+
$wp_query = new WP_Query();
|
184 |
+
$posts = $wp_query->query(array(
|
185 |
+
'post_type' => 'hm_custom_'.$_POST['mode'],
|
186 |
+
'post_status' => 'any',
|
187 |
+
'nopaging' => true
|
188 |
+
));
|
189 |
+
|
190 |
+
|
191 |
+
$revisions = array();
|
192 |
+
if (empty($posts)) {
|
193 |
+
$uploadDir = wp_upload_dir();
|
194 |
+
$customFile = $uploadDir['basedir'].'/hm_custom_css_js/custom.'.($_POST['mode'] == 'css' ? 'css' : 'js');
|
195 |
+
if (file_exists($customFile)) {
|
196 |
+
$contents = file_get_contents($customFile);
|
197 |
+
if ($contents === false)
|
198 |
+
wp_send_json_error();
|
199 |
+
$rev_id = wp_insert_post(array(
|
200 |
+
'post_content' => $contents,
|
201 |
+
'post_status' => 'publish',
|
202 |
+
'post_type' => 'hm_custom_'.$_POST['mode'],
|
203 |
+
));
|
204 |
+
$revisions[] = array('id' => $rev_id, 'rev_date' => current_time('Y-m-d H:i:s'), 'published' => true);
|
205 |
+
}
|
206 |
+
} else {
|
207 |
+
foreach ($posts as $post) {
|
208 |
+
$revisions[] = array('id' => $post->ID, 'rev_date' => $post->post_date, 'published' => ($post->post_status == 'publish'));
|
209 |
+
}
|
210 |
+
}
|
211 |
+
|
212 |
+
wp_send_json_success($revisions);
|
213 |
+
}
|
214 |
+
|
215 |
+
add_action('wp_ajax_hm_custom_css_js_get_revision', 'hm_custom_css_js_get_revision');
|
216 |
+
function hm_custom_css_js_get_revision() {
|
217 |
+
if (!current_user_can('edit_theme_options') || empty($_POST['mode']) || !isset($_POST['rev']) || !is_numeric($_POST['rev']))
|
218 |
+
wp_send_json_error();
|
219 |
+
$_POST['mode'] = strtolower($_POST['mode']);
|
220 |
+
if ($_POST['mode'] != 'css' && $_POST['mode'] != 'javascript')
|
221 |
+
wp_send_json_error();
|
222 |
+
|
223 |
+
$post = get_post($_POST['rev']);
|
224 |
+
if ($post->post_type != 'hm_custom_'.$_POST['mode'])
|
225 |
+
wp_send_json_error();
|
226 |
+
|
227 |
+
wp_send_json_success(array(
|
228 |
+
'id' => $post->ID,
|
229 |
+
'content' => $post->post_content
|
230 |
+
));
|
231 |
+
}
|
232 |
+
|
233 |
+
add_action('init', 'hm_custom_css_js_init');
|
234 |
+
function hm_custom_css_js_init() {
|
235 |
+
register_post_type('hm_custom_css');
|
236 |
+
register_post_type('hm_custom_javascript');
|
237 |
+
|
238 |
+
if (!empty($_GET['hm_custom_css_draft'])) {
|
239 |
+
$wp_query = new WP_Query(array(
|
240 |
+
'post_type' => 'hm_custom_css',
|
241 |
+
'post_status' => 'any',
|
242 |
+
'posts_per_page' => 1
|
243 |
+
));
|
244 |
+
$posts = $wp_query->get_posts();
|
245 |
+
header('Content-Type: text/css');
|
246 |
+
if (isset($posts[0]))
|
247 |
+
echo($posts[0]->post_content);
|
248 |
+
exit;
|
249 |
+
}
|
250 |
+
if (!empty($_GET['hm_custom_js_draft'])) {
|
251 |
+
$wp_query = new WP_Query(array(
|
252 |
+
'post_type' => 'hm_custom_javascript',
|
253 |
+
'post_status' => 'any',
|
254 |
+
'posts_per_page' => 1
|
255 |
+
));
|
256 |
+
$posts = $wp_query->get_posts();
|
257 |
+
header('Content-Type: text/javascript');
|
258 |
+
if (isset($posts[0]))
|
259 |
+
echo($posts[0]->post_content);
|
260 |
+
exit;
|
261 |
+
}
|
262 |
+
}
|
263 |
+
|
264 |
function hm_custom_css_page() {
|
265 |
hm_custom_css_js_page('CSS');
|
266 |
}
|
277 |
echo('
|
278 |
<div class="wrap">
|
279 |
<h2>Custom '.$mode.'</h2>
|
280 |
+
<script>var hm_custom_css_js_mode = "'.$mode.'";</script>
|
281 |
<div>
|
282 |
+
<div id="hm_custom_code_editor" style="margin-top: 15px;">
|
283 |
+
<div style="width: 200px; height: 100%; overflow: auto; float: right; padding: 0 20px;">
|
284 |
+
<h4 style="margin: 0; margin-bottom: 5px;">Revisions:</h4>
|
285 |
+
<button class="button-secondary hm-custom-css-js-delete-revisions-btn">Delete All</button>
|
286 |
+
<ul id="hm_custom_css_js_revisions">
|
287 |
+
</ul>
|
288 |
+
</div>
|
289 |
+
</div>
|
290 |
<div style="float: right; padding-left: 10px; margin-top: 3px; white-space: nowrap; font-style: italic;">
|
291 |
<a href="https://codemirror.net/" target="_blank">CodeMirror</a> code editor
|
292 |
</div>
|
293 |
<button type="button" class="button-primary hm-custom-css-js-save-btn" style="margin-top: 15px;" disabled="disabled">Saved</button>
|
294 |
+
<button type="button" class="button-primary hm-custom-css-js-publish-btn" style="margin-top: 15px; margin-right: 10px;" disabled="disabled">Save & Publish</button>
|
295 |
+
<label style="margin-top: 15px; white-space: nowrap;">
|
296 |
+
<input type="checkbox" class="hm-custom-css-js-minify-cb"'.(get_option('hm_custom_'.strtolower($mode).'_minify', true) ? ' checked="checked"' : '').' /> Minify output
|
297 |
+
</label>
|
298 |
</div>
|
299 |
+
<div style="clear: both; margin-bottom: 20px;"></div>
|
300 |
+
');
|
301 |
+
$potent_slug = 'custom-css-and-javascript';
|
302 |
+
include(__DIR__.'/plugin-credit.php');
|
303 |
+
echo('
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
304 |
</div>
|
305 |
');
|
306 |
}
|
images/potent-logo.png
ADDED
Binary file
|
js/custom-css-and-javascript.js
ADDED
@@ -0,0 +1,175 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Author: Hearken Media
|
3 |
+
* License: GNU General Public License version 2 or later
|
4 |
+
* License URI: http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html
|
5 |
+
*/
|
6 |
+
var hm_custom_code_editor, hm_custom_code_editor_has_changes = false, hm_custom_css_js_save_publish = false, hm_custom_css_js_rev = 0, hm_custom_css_js_published_rev = 0;
|
7 |
+
jQuery(document).ready(function($) {
|
8 |
+
hm_custom_code_editor = CodeMirror(document.getElementById("hm_custom_code_editor"), {
|
9 |
+
lineNumbers: true,
|
10 |
+
mode: hm_custom_css_js_mode.toLowerCase()
|
11 |
+
});
|
12 |
+
hm_custom_code_editor.on("change", function() {
|
13 |
+
if (hm_custom_code_editor_has_changes)
|
14 |
+
return;
|
15 |
+
hm_custom_code_editor_has_changes = true;
|
16 |
+
$(".hm-custom-css-js-save-btn").html("Save").prop("disabled", false);
|
17 |
+
$(".hm-custom-css-js-publish-btn").html("Save & Publish").prop("disabled", false);
|
18 |
+
});
|
19 |
+
$(".hm-custom-css-js-save-btn").click(function() {
|
20 |
+
$(".hm-custom-css-js-save-btn").prop("disabled", true).html("Saving...");
|
21 |
+
$.post(ajaxurl, {action: "hm_custom_css_js_save", mode: hm_custom_css_js_mode, code: hm_custom_code_editor.getValue()})
|
22 |
+
.done(function(data) {
|
23 |
+
if (data.success) {
|
24 |
+
$(".hm-custom-css-js-save-btn").html("Saved");
|
25 |
+
hm_custom_css_js_rev = data.data;
|
26 |
+
hm_custom_code_editor_has_changes = false;
|
27 |
+
if (hm_custom_css_js_save_publish)
|
28 |
+
$(".hm-custom-css-js-publish-btn").click()
|
29 |
+
else
|
30 |
+
hm_custom_css_js_get_revisions();
|
31 |
+
} else {
|
32 |
+
alert("Error while saving. Please try again.");
|
33 |
+
$(".hm-custom-css-js-save-btn").html("Save").prop("disabled", false);
|
34 |
+
if (hm_custom_css_js_save_publish)
|
35 |
+
$(".hm-custom-css-js-publish-btn").html("Save & Publish").prop("disabled", true);
|
36 |
+
}
|
37 |
+
})
|
38 |
+
.fail(function() {
|
39 |
+
alert("Error while saving. Please try again.");
|
40 |
+
$(".hm-custom-css-js-save-btn").html("Save").prop("disabled", false);
|
41 |
+
if (hm_custom_css_js_save_publish)
|
42 |
+
$(".hm-custom-css-js-publish-btn").html("Save & Publish").prop("disabled", true);
|
43 |
+
});
|
44 |
+
});
|
45 |
+
$(".hm-custom-css-js-publish-btn").click(function() {
|
46 |
+
$(".hm-custom-css-js-publish-btn").prop("disabled", true).html("Publishing...");
|
47 |
+
if (!$(".hm-custom-css-js-save-btn").prop("disabled")) {
|
48 |
+
hm_custom_css_js_save_publish = true;
|
49 |
+
$(".hm-custom-css-js-save-btn").click();
|
50 |
+
return;
|
51 |
+
}
|
52 |
+
hm_custom_css_js_save_publish = false;
|
53 |
+
|
54 |
+
$.post(ajaxurl, {action: "hm_custom_css_js_publish", mode: hm_custom_css_js_mode, minify: ($('.hm-custom-css-js-minify-cb').prop('checked') ? 1 : 0), rev: hm_custom_css_js_rev})
|
55 |
+
.done(function(data) {
|
56 |
+
if (data.success) {
|
57 |
+
$(".hm-custom-css-js-publish-btn").html("Published");
|
58 |
+
hm_custom_css_js_get_revisions();
|
59 |
+
} else {
|
60 |
+
alert("Error while publishing. Please try again.");
|
61 |
+
$(".hm-custom-css-js-publish-btn").html("Save & Publish").prop("disabled", false);
|
62 |
+
}
|
63 |
+
})
|
64 |
+
.fail(function() {
|
65 |
+
alert("Error while publishing. Please try again.");
|
66 |
+
$(".hm-custom-css-js-publish-btn").html("Save & Publish").prop("disabled", false);
|
67 |
+
});
|
68 |
+
});
|
69 |
+
|
70 |
+
$(".hm-custom-css-js-delete-revisions-btn").click(function() {
|
71 |
+
$(this).prop('disabled', true).html('Deleting...');
|
72 |
+
|
73 |
+
$.post(ajaxurl, {action: "hm_custom_css_js_delete_revisions", mode: hm_custom_css_js_mode})
|
74 |
+
.done(function(data) {
|
75 |
+
if (data.success) {
|
76 |
+
hm_custom_css_js_get_revisions();
|
77 |
+
$(".hm-custom-css-js-delete-revisions-btn").html('Delete All').prop('disabled', false);
|
78 |
+
} else {
|
79 |
+
alert("Error while deleting. Please try again.");
|
80 |
+
$(".hm-custom-css-js-delete-revisions-btn").html('Delete All').prop('disabled', false);
|
81 |
+
}
|
82 |
+
})
|
83 |
+
.fail(function() {
|
84 |
+
alert("Error while deleting. Please try again.");
|
85 |
+
$(".hm-custom-css-js-delete-revisions-btn").html('Delete All').prop('disabled', false);
|
86 |
+
});
|
87 |
+
});
|
88 |
+
|
89 |
+
|
90 |
+
$(window).resize(function() {
|
91 |
+
$("#hm_custom_code_editor, #hm_custom_code_editor .CodeMirror").height(Math.max(150,
|
92 |
+
$(window).height()
|
93 |
+
- $("#hm_custom_code_editor").offset().top
|
94 |
+
- $(".hm-custom-css-js-save-btn").height()
|
95 |
+
- 30));
|
96 |
+
hm_custom_code_editor.refresh();
|
97 |
+
});
|
98 |
+
$(window).resize();
|
99 |
+
$(window).on("beforeunload", function(ev) {
|
100 |
+
if (hm_custom_code_editor_has_changes) {
|
101 |
+
ev.returnValue = "You have unsaved changes that will be lost if you leave this page!";
|
102 |
+
return ev.returnValue;
|
103 |
+
}
|
104 |
+
});
|
105 |
+
|
106 |
+
$("#hm_custom_css_js_revisions").on("click", "li > a.view-rev", function(ev) {
|
107 |
+
|
108 |
+
if (hm_custom_code_editor_has_changes &&
|
109 |
+
!confirm("You have unsaved changes that will be lost if you view this revision!"))
|
110 |
+
return;
|
111 |
+
|
112 |
+
var revId = $(this).parent().attr("id").substring(20);
|
113 |
+
|
114 |
+
$.post(ajaxurl, {action: "hm_custom_css_js_get_revision", mode: hm_custom_css_js_mode, rev: revId})
|
115 |
+
.done(function(data) {
|
116 |
+
if (data.success) {
|
117 |
+
hm_custom_code_editor.doc.setValue(data.data.content);
|
118 |
+
hm_custom_css_js_rev = data.data.id;
|
119 |
+
$('#hm_custom_css_js_revisions .active').removeClass('active');
|
120 |
+
$('#hm_custom_css_js_rev' + hm_custom_css_js_rev).addClass('active');
|
121 |
+
$(".hm-custom-css-js-save-btn").html("Saved").prop("disabled", true);
|
122 |
+
if (hm_custom_css_js_rev == hm_custom_css_js_published_rev)
|
123 |
+
$(".hm-custom-css-js-publish-btn").html("Published").prop("disabled", true);
|
124 |
+
hm_custom_code_editor_has_changes = false;
|
125 |
+
} else {
|
126 |
+
alert("Error while loading. Please try again.");
|
127 |
+
}
|
128 |
+
})
|
129 |
+
.fail(function() {
|
130 |
+
alert("Error while loading. Please try again.");
|
131 |
+
});
|
132 |
+
});
|
133 |
+
|
134 |
+
$("#hm_custom_css_js_revisions").on("click", "li > a.del-rev", function(ev) {
|
135 |
+
|
136 |
+
var revId = $(this).parent().attr("id").substring(20);
|
137 |
+
|
138 |
+
$.post(ajaxurl, {action: "hm_custom_css_js_delete_revision", mode: hm_custom_css_js_mode, rev: revId})
|
139 |
+
.done(function(data) {
|
140 |
+
if (data.success) {
|
141 |
+
hm_custom_css_js_get_revisions();
|
142 |
+
} else {
|
143 |
+
alert("Error while deleting. Please try again.");
|
144 |
+
}
|
145 |
+
})
|
146 |
+
.fail(function() {
|
147 |
+
alert("Error while deleting. Please try again.");
|
148 |
+
});
|
149 |
+
});
|
150 |
+
|
151 |
+
function hm_custom_css_js_get_revisions() {
|
152 |
+
$.post(ajaxurl, {action: "hm_custom_css_js_get_revisions", mode: hm_custom_css_js_mode, })
|
153 |
+
.done(function(data) {
|
154 |
+
if (data.success) {
|
155 |
+
$("#hm_custom_css_js_revisions").empty();
|
156 |
+
if (data.data.length == 0) {
|
157 |
+
$("#hm_custom_css_js_revisions").append("<li>None</li>");
|
158 |
+
} else {
|
159 |
+
for (var i = 0; i < data.data.length; ++i) {
|
160 |
+
$("#hm_custom_css_js_revisions").append("<li id=\"hm_custom_css_js_rev" + data.data[i].id + "\"><a class=\"view-rev\" href=\"javascript:void(0);\">" + data.data[i].rev_date + "</a>" + (data.data[i].published ? " [published]" : " <a class=\"del-rev\" href=\"javascript:void(0);\">[delete]</a>") + "</li>");
|
161 |
+
if (data.data[i].published)
|
162 |
+
hm_custom_css_js_published_rev = data.data[i].id;
|
163 |
+
}
|
164 |
+
if (hm_custom_css_js_rev == 0) {
|
165 |
+
$("#hm_custom_css_js_revisions > li:first-child > a.view-rev").click();
|
166 |
+
} else {
|
167 |
+
$('#hm_custom_css_js_rev' + hm_custom_css_js_rev).addClass('active');
|
168 |
+
}
|
169 |
+
}
|
170 |
+
}
|
171 |
+
});
|
172 |
+
}
|
173 |
+
hm_custom_css_js_get_revisions();
|
174 |
+
|
175 |
+
});
|
minify/LICENSE
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Copyright (c) 2012 Matthias Mullie
|
2 |
+
|
3 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4 |
+
this software and associated documentation files (the "Software"), to deal in
|
5 |
+
the Software without restriction, including without limitation the rights to
|
6 |
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
7 |
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
8 |
+
subject to the following conditions:
|
9 |
+
|
10 |
+
The above copyright notice and this permission notice shall be included in all
|
11 |
+
copies or substantial portions of the Software.
|
12 |
+
|
13 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
15 |
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
16 |
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17 |
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18 |
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
minify/data/js/keywords_after.txt
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
in
|
2 |
+
public
|
3 |
+
extends
|
4 |
+
private
|
5 |
+
protected
|
6 |
+
implements
|
7 |
+
instanceof
|
minify/data/js/keywords_before.txt
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
do
|
2 |
+
in
|
3 |
+
let
|
4 |
+
new
|
5 |
+
var
|
6 |
+
case
|
7 |
+
else
|
8 |
+
enum
|
9 |
+
void
|
10 |
+
with
|
11 |
+
class
|
12 |
+
const
|
13 |
+
yield
|
14 |
+
delete
|
15 |
+
export
|
16 |
+
import
|
17 |
+
public
|
18 |
+
static
|
19 |
+
typeof
|
20 |
+
extends
|
21 |
+
package
|
22 |
+
private
|
23 |
+
continue
|
24 |
+
function
|
25 |
+
protected
|
26 |
+
implements
|
27 |
+
instanceof
|
minify/data/js/keywords_reserved.txt
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
do
|
2 |
+
if
|
3 |
+
in
|
4 |
+
for
|
5 |
+
let
|
6 |
+
new
|
7 |
+
try
|
8 |
+
var
|
9 |
+
case
|
10 |
+
else
|
11 |
+
enum
|
12 |
+
eval
|
13 |
+
null
|
14 |
+
this
|
15 |
+
true
|
16 |
+
void
|
17 |
+
with
|
18 |
+
break
|
19 |
+
catch
|
20 |
+
class
|
21 |
+
const
|
22 |
+
false
|
23 |
+
super
|
24 |
+
throw
|
25 |
+
while
|
26 |
+
yield
|
27 |
+
delete
|
28 |
+
export
|
29 |
+
import
|
30 |
+
public
|
31 |
+
return
|
32 |
+
static
|
33 |
+
switch
|
34 |
+
typeof
|
35 |
+
default
|
36 |
+
extends
|
37 |
+
finally
|
38 |
+
package
|
39 |
+
private
|
40 |
+
continue
|
41 |
+
debugger
|
42 |
+
function
|
43 |
+
arguments
|
44 |
+
interface
|
45 |
+
protected
|
46 |
+
implements
|
47 |
+
instanceof
|
minify/data/js/operators_after.txt
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
+
|
2 |
+
-
|
3 |
+
*
|
4 |
+
/
|
5 |
+
%
|
6 |
+
=
|
7 |
+
+=
|
8 |
+
-=
|
9 |
+
*=
|
10 |
+
/=
|
11 |
+
%=
|
12 |
+
<<=
|
13 |
+
>>=
|
14 |
+
>>>=
|
15 |
+
&=
|
16 |
+
^=
|
17 |
+
|=
|
18 |
+
&
|
19 |
+
|
|
20 |
+
^
|
21 |
+
~
|
22 |
+
<<
|
23 |
+
>>
|
24 |
+
>>>
|
25 |
+
==
|
26 |
+
===
|
27 |
+
!=
|
28 |
+
!==
|
29 |
+
>
|
30 |
+
<
|
31 |
+
>=
|
32 |
+
<=
|
33 |
+
&&
|
34 |
+
||
|
35 |
+
.
|
36 |
+
[
|
37 |
+
]
|
38 |
+
?
|
39 |
+
:
|
40 |
+
,
|
41 |
+
;
|
42 |
+
(
|
43 |
+
)
|
44 |
+
{
|
45 |
+
}
|
minify/data/js/operators_before.txt
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
+
|
2 |
+
-
|
3 |
+
*
|
4 |
+
/
|
5 |
+
%
|
6 |
+
=
|
7 |
+
+=
|
8 |
+
-=
|
9 |
+
*=
|
10 |
+
/=
|
11 |
+
%=
|
12 |
+
<<=
|
13 |
+
>>=
|
14 |
+
>>>=
|
15 |
+
&=
|
16 |
+
^=
|
17 |
+
|=
|
18 |
+
&
|
19 |
+
|
|
20 |
+
^
|
21 |
+
~
|
22 |
+
<<
|
23 |
+
>>
|
24 |
+
>>>
|
25 |
+
==
|
26 |
+
===
|
27 |
+
!=
|
28 |
+
!==
|
29 |
+
>
|
30 |
+
<
|
31 |
+
>=
|
32 |
+
<=
|
33 |
+
&&
|
34 |
+
||
|
35 |
+
!
|
36 |
+
.
|
37 |
+
[
|
38 |
+
?
|
39 |
+
:
|
40 |
+
,
|
41 |
+
;
|
42 |
+
(
|
43 |
+
{
|
minify/src/CSS.php
ADDED
@@ -0,0 +1,573 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace MatthiasMullie\Minify;
|
4 |
+
|
5 |
+
use MatthiasMullie\PathConverter\Converter;
|
6 |
+
|
7 |
+
/**
|
8 |
+
* CSS minifier.
|
9 |
+
*
|
10 |
+
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
11 |
+
*
|
12 |
+
* @author Matthias Mullie <minify@mullie.eu>
|
13 |
+
* @author Tijs Verkoyen <minify@verkoyen.eu>
|
14 |
+
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved.
|
15 |
+
* @license MIT License
|
16 |
+
*/
|
17 |
+
class CSS extends Minify
|
18 |
+
{
|
19 |
+
/**
|
20 |
+
* @var int
|
21 |
+
*/
|
22 |
+
protected $maxImportSize = 5;
|
23 |
+
|
24 |
+
/**
|
25 |
+
* @var string[]
|
26 |
+
*/
|
27 |
+
protected $importExtensions = array(
|
28 |
+
'gif' => 'data:image/gif',
|
29 |
+
'png' => 'data:image/png',
|
30 |
+
'jpe' => 'data:image/jpeg',
|
31 |
+
'jpg' => 'data:image/jpeg',
|
32 |
+
'jpeg' => 'data:image/jpeg',
|
33 |
+
'svg' => 'data:image/svg+xml',
|
34 |
+
'woff' => 'data:application/x-font-woff',
|
35 |
+
'tif' => 'image/tiff',
|
36 |
+
'tiff' => 'image/tiff',
|
37 |
+
'xbm' => 'image/x-xbitmap',
|
38 |
+
);
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Set the maximum size if files to be imported.
|
42 |
+
*
|
43 |
+
* Files larger than this size (in kB) will not be imported into the CSS.
|
44 |
+
* Importing files into the CSS as data-uri will save you some connections,
|
45 |
+
* but we should only import relatively small decorative images so that our
|
46 |
+
* CSS file doesn't get too bulky.
|
47 |
+
*
|
48 |
+
* @param int $size Size in kB
|
49 |
+
*/
|
50 |
+
public function setMaxImportSize($size)
|
51 |
+
{
|
52 |
+
$this->maxImportSize = $size;
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Set the type of extensions to be imported into the CSS (to save network
|
57 |
+
* connections).
|
58 |
+
* Keys of the array should be the file extensions & respective values
|
59 |
+
* should be the data type.
|
60 |
+
*
|
61 |
+
* @param string[] $extensions Array of file extensions
|
62 |
+
*/
|
63 |
+
public function setImportExtensions(array $extensions)
|
64 |
+
{
|
65 |
+
$this->importExtensions = $extensions;
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Move any import statements to the top.
|
70 |
+
*
|
71 |
+
* @param $content string Nearly finished CSS content
|
72 |
+
*
|
73 |
+
* @return string
|
74 |
+
*/
|
75 |
+
protected function moveImportsToTop($content)
|
76 |
+
{
|
77 |
+
if (preg_match_all('/@import[^;]+;/', $content, $matches)) {
|
78 |
+
|
79 |
+
// remove from content
|
80 |
+
foreach ($matches[0] as $import) {
|
81 |
+
$content = str_replace($import, '', $content);
|
82 |
+
}
|
83 |
+
|
84 |
+
// add to top
|
85 |
+
$content = implode('', $matches[0]).$content;
|
86 |
+
};
|
87 |
+
|
88 |
+
return $content;
|
89 |
+
}
|
90 |
+
|
91 |
+
/**
|
92 |
+
* Combine CSS from import statements.
|
93 |
+
*
|
94 |
+
* @import's will be loaded and their content merged into the original file,
|
95 |
+
* to save HTTP requests.
|
96 |
+
*
|
97 |
+
* @param string $source The file to combine imports for.
|
98 |
+
* @param string $content The CSS content to combine imports for.
|
99 |
+
*
|
100 |
+
* @return string
|
101 |
+
*/
|
102 |
+
protected function combineImports($source, $content)
|
103 |
+
{
|
104 |
+
$importRegexes = array(
|
105 |
+
// @import url(xxx)
|
106 |
+
'/
|
107 |
+
# import statement
|
108 |
+
@import
|
109 |
+
|
110 |
+
# whitespace
|
111 |
+
\s+
|
112 |
+
|
113 |
+
# open url()
|
114 |
+
url\(
|
115 |
+
|
116 |
+
# (optional) open path enclosure
|
117 |
+
(?P<quotes>["\']?)
|
118 |
+
|
119 |
+
# fetch path
|
120 |
+
(?P<path>
|
121 |
+
|
122 |
+
# do not fetch data uris or external sources
|
123 |
+
(?!(
|
124 |
+
["\']?
|
125 |
+
(data|https?):
|
126 |
+
))
|
127 |
+
|
128 |
+
.+?
|
129 |
+
)
|
130 |
+
|
131 |
+
# (optional) close path enclosure
|
132 |
+
(?P=quotes)
|
133 |
+
|
134 |
+
# close url()
|
135 |
+
\)
|
136 |
+
|
137 |
+
# (optional) trailing whitespace
|
138 |
+
\s*
|
139 |
+
|
140 |
+
# (optional) media statement(s)
|
141 |
+
(?P<media>[^;]*)
|
142 |
+
|
143 |
+
# (optional) trailing whitespace
|
144 |
+
\s*
|
145 |
+
|
146 |
+
# (optional) closing semi-colon
|
147 |
+
;?
|
148 |
+
|
149 |
+
/ix',
|
150 |
+
|
151 |
+
// @import 'xxx'
|
152 |
+
'/
|
153 |
+
|
154 |
+
# import statement
|
155 |
+
@import
|
156 |
+
|
157 |
+
# whitespace
|
158 |
+
\s+
|
159 |
+
|
160 |
+
# open path enclosure
|
161 |
+
(?P<quotes>["\'])
|
162 |
+
|
163 |
+
# fetch path
|
164 |
+
(?P<path>
|
165 |
+
|
166 |
+
# do not fetch data uris or external sources
|
167 |
+
(?!(
|
168 |
+
["\']?
|
169 |
+
(data|https?):
|
170 |
+
))
|
171 |
+
|
172 |
+
.+?
|
173 |
+
)
|
174 |
+
|
175 |
+
# close path enclosure
|
176 |
+
(?P=quotes)
|
177 |
+
|
178 |
+
# (optional) trailing whitespace
|
179 |
+
\s*
|
180 |
+
|
181 |
+
# (optional) media statement(s)
|
182 |
+
(?P<media>[^;]*)
|
183 |
+
|
184 |
+
# (optional) trailing whitespace
|
185 |
+
\s*
|
186 |
+
|
187 |
+
# (optional) closing semi-colon
|
188 |
+
;?
|
189 |
+
|
190 |
+
/ix',
|
191 |
+
);
|
192 |
+
|
193 |
+
// find all relative imports in css
|
194 |
+
$matches = array();
|
195 |
+
foreach ($importRegexes as $importRegex) {
|
196 |
+
if (preg_match_all($importRegex, $content, $regexMatches, PREG_SET_ORDER)) {
|
197 |
+
$matches = array_merge($matches, $regexMatches);
|
198 |
+
}
|
199 |
+
}
|
200 |
+
|
201 |
+
$search = array();
|
202 |
+
$replace = array();
|
203 |
+
|
204 |
+
// loop the matches
|
205 |
+
foreach ($matches as $match) {
|
206 |
+
// get the path for the file that will be imported
|
207 |
+
$importPath = dirname($source).'/'.$match['path'];
|
208 |
+
|
209 |
+
// only replace the import with the content if we can grab the
|
210 |
+
// content of the file
|
211 |
+
if (file_exists($importPath) && is_file($importPath)) {
|
212 |
+
// grab referenced file & minify it (which may include importing
|
213 |
+
// yet other @import statements recursively)
|
214 |
+
$minifier = new static($importPath);
|
215 |
+
$importContent = $minifier->execute($source);
|
216 |
+
|
217 |
+
// check if this is only valid for certain media
|
218 |
+
if ($match['media']) {
|
219 |
+
$importContent = '@media '.$match['media'].'{'.$importContent.'}';
|
220 |
+
}
|
221 |
+
|
222 |
+
// add to replacement array
|
223 |
+
$search[] = $match[0];
|
224 |
+
$replace[] = $importContent;
|
225 |
+
}
|
226 |
+
}
|
227 |
+
|
228 |
+
// replace the import statements
|
229 |
+
$content = str_replace($search, $replace, $content);
|
230 |
+
|
231 |
+
return $content;
|
232 |
+
}
|
233 |
+
|
234 |
+
/**
|
235 |
+
* Import files into the CSS, base64-ized.
|
236 |
+
*
|
237 |
+
* @url(image.jpg) images will be loaded and their content merged into the
|
238 |
+
* original file, to save HTTP requests.
|
239 |
+
*
|
240 |
+
* @param string $source The file to import files for.
|
241 |
+
* @param string $content The CSS content to import files for.
|
242 |
+
*
|
243 |
+
* @return string
|
244 |
+
*/
|
245 |
+
protected function importFiles($source, $content)
|
246 |
+
{
|
247 |
+
$extensions = array_keys($this->importExtensions);
|
248 |
+
$regex = '/url\((["\']?)((?!["\']?data:).*?\.('.implode('|', $extensions).'))\\1\)/i';
|
249 |
+
if ($extensions && preg_match_all($regex, $content, $matches, PREG_SET_ORDER)) {
|
250 |
+
$search = array();
|
251 |
+
$replace = array();
|
252 |
+
|
253 |
+
// loop the matches
|
254 |
+
foreach ($matches as $match) {
|
255 |
+
// get the path for the file that will be imported
|
256 |
+
$path = $match[2];
|
257 |
+
$path = dirname($source).'/'.$path;
|
258 |
+
$extension = $match[3];
|
259 |
+
|
260 |
+
// only replace the import with the content if we're able to get
|
261 |
+
// the content of the file, and it's relatively small
|
262 |
+
$import = file_exists($path);
|
263 |
+
$import = $import && is_file($path);
|
264 |
+
$import = $import && filesize($path) <= $this->maxImportSize * 1024;
|
265 |
+
if (!$import) {
|
266 |
+
continue;
|
267 |
+
}
|
268 |
+
|
269 |
+
// grab content && base64-ize
|
270 |
+
$importContent = $this->load($path);
|
271 |
+
$importContent = base64_encode($importContent);
|
272 |
+
|
273 |
+
// build replacement
|
274 |
+
$search[] = $match[0];
|
275 |
+
$replace[] = 'url('.$this->importExtensions[$extension].';base64,'.$importContent.')';
|
276 |
+
}
|
277 |
+
|
278 |
+
// replace the import statements
|
279 |
+
$content = str_replace($search, $replace, $content);
|
280 |
+
}
|
281 |
+
|
282 |
+
return $content;
|
283 |
+
}
|
284 |
+
|
285 |
+
/**
|
286 |
+
* Minify the data.
|
287 |
+
* Perform CSS optimizations.
|
288 |
+
*
|
289 |
+
* @param string[optional] $path Path to write the data to.
|
290 |
+
*
|
291 |
+
* @return string The minified data.
|
292 |
+
*/
|
293 |
+
public function execute($path = null)
|
294 |
+
{
|
295 |
+
$content = '';
|
296 |
+
|
297 |
+
// loop files
|
298 |
+
foreach ($this->data as $source => $css) {
|
299 |
+
/*
|
300 |
+
* Let's first take out strings & comments, since we can't just remove
|
301 |
+
* whitespace anywhere. If whitespace occurs inside a string, we should
|
302 |
+
* leave it alone. E.g.:
|
303 |
+
* p { content: "a test" }
|
304 |
+
*/
|
305 |
+
$this->extractStrings();
|
306 |
+
$this->stripComments();
|
307 |
+
$css = $this->replace($css);
|
308 |
+
|
309 |
+
$css = $this->stripWhitespace($css);
|
310 |
+
$css = $this->shortenHex($css);
|
311 |
+
$css = $this->shortenZeroes($css);
|
312 |
+
$css = $this->stripEmptyTags($css);
|
313 |
+
|
314 |
+
// restore the string we've extracted earlier
|
315 |
+
$css = $this->restoreExtractedData($css);
|
316 |
+
|
317 |
+
/*
|
318 |
+
* If we'll save to a new path, we'll have to fix the relative paths
|
319 |
+
* to be relative no longer to the source file, but to the new path.
|
320 |
+
* If we don't write to a file, fall back to same path so no
|
321 |
+
* conversion happens (because we still want it to go through most
|
322 |
+
* of the move code...)
|
323 |
+
*/
|
324 |
+
$source = $source ?: '';
|
325 |
+
$converter = new Converter($source, $path ?: $source);
|
326 |
+
$css = $this->move($converter, $css);
|
327 |
+
|
328 |
+
// if no target path is given, relative paths were not converted, so
|
329 |
+
// they'll still be relative to the source file then
|
330 |
+
$css = $this->importFiles($path ?: $source, $css);
|
331 |
+
$css = $this->combineImports($path ?: $source, $css);
|
332 |
+
|
333 |
+
// combine css
|
334 |
+
$content .= $css;
|
335 |
+
}
|
336 |
+
|
337 |
+
$content = $this->moveImportsToTop($content);
|
338 |
+
|
339 |
+
return $content;
|
340 |
+
}
|
341 |
+
|
342 |
+
/**
|
343 |
+
* Moving a css file should update all relative urls.
|
344 |
+
* Relative references (e.g. ../images/image.gif) in a certain css file,
|
345 |
+
* will have to be updated when a file is being saved at another location
|
346 |
+
* (e.g. ../../images/image.gif, if the new CSS file is 1 folder deeper).
|
347 |
+
*
|
348 |
+
* @param Converter $converter Relative path converter
|
349 |
+
* @param string $content The CSS content to update relative urls for.
|
350 |
+
*
|
351 |
+
* @return string
|
352 |
+
*/
|
353 |
+
protected function move(Converter $converter, $content)
|
354 |
+
{
|
355 |
+
/*
|
356 |
+
* Relative path references will usually be enclosed by url(). @import
|
357 |
+
* is an exception, where url() is not necessary around the path (but is
|
358 |
+
* allowed).
|
359 |
+
* This *could* be 1 regular expression, where both regular expressions
|
360 |
+
* in this array are on different sides of a |. But we're using named
|
361 |
+
* patterns in both regexes, the same name on both regexes. This is only
|
362 |
+
* possible with a (?J) modifier, but that only works after a fairly
|
363 |
+
* recent PCRE version. That's why I'm doing 2 separate regular
|
364 |
+
* expressions & combining the matches after executing of both.
|
365 |
+
*/
|
366 |
+
$relativeRegexes = array(
|
367 |
+
// url(xxx)
|
368 |
+
'/
|
369 |
+
# open url()
|
370 |
+
url\(
|
371 |
+
|
372 |
+
\s*
|
373 |
+
|
374 |
+
# open path enclosure
|
375 |
+
(?P<quotes>["\'])?
|
376 |
+
|
377 |
+
# fetch path
|
378 |
+
(?P<path>
|
379 |
+
|
380 |
+
# do not fetch data uris or external sources
|
381 |
+
(?!(
|
382 |
+
\s?
|
383 |
+
["\']?
|
384 |
+
(data|https?):
|
385 |
+
))
|
386 |
+
|
387 |
+
.+?
|
388 |
+
)
|
389 |
+
|
390 |
+
# close path enclosure
|
391 |
+
(?(quotes)(?P=quotes))
|
392 |
+
|
393 |
+
\s*
|
394 |
+
|
395 |
+
# close url()
|
396 |
+
\)
|
397 |
+
|
398 |
+
/ix',
|
399 |
+
|
400 |
+
// @import "xxx"
|
401 |
+
'/
|
402 |
+
# import statement
|
403 |
+
@import
|
404 |
+
|
405 |
+
# whitespace
|
406 |
+
\s+
|
407 |
+
|
408 |
+
# we don\'t have to check for @import url(), because the
|
409 |
+
# condition above will already catch these
|
410 |
+
|
411 |
+
# open path enclosure
|
412 |
+
(?P<quotes>["\'])
|
413 |
+
|
414 |
+
# fetch path
|
415 |
+
(?P<path>
|
416 |
+
|
417 |
+
# do not fetch data uris or external sources
|
418 |
+
(?!(
|
419 |
+
["\']?
|
420 |
+
(data|https?):
|
421 |
+
))
|
422 |
+
|
423 |
+
.+?
|
424 |
+
)
|
425 |
+
|
426 |
+
# close path enclosure
|
427 |
+
(?P=quotes)
|
428 |
+
|
429 |
+
/ix',
|
430 |
+
);
|
431 |
+
|
432 |
+
// find all relative urls in css
|
433 |
+
$matches = array();
|
434 |
+
foreach ($relativeRegexes as $relativeRegex) {
|
435 |
+
if (preg_match_all($relativeRegex, $content, $regexMatches, PREG_SET_ORDER)) {
|
436 |
+
$matches = array_merge($matches, $regexMatches);
|
437 |
+
}
|
438 |
+
}
|
439 |
+
|
440 |
+
$search = array();
|
441 |
+
$replace = array();
|
442 |
+
|
443 |
+
// loop all urls
|
444 |
+
foreach ($matches as $match) {
|
445 |
+
// determine if it's a url() or an @import match
|
446 |
+
$type = (strpos($match[0], '@import') === 0 ? 'import' : 'url');
|
447 |
+
|
448 |
+
// fix relative url
|
449 |
+
$url = $converter->convert($match['path']);
|
450 |
+
|
451 |
+
// build replacement
|
452 |
+
$search[] = $match[0];
|
453 |
+
if ($type == 'url') {
|
454 |
+
$replace[] = 'url('.$url.')';
|
455 |
+
} elseif ($type == 'import') {
|
456 |
+
$replace[] = '@import "'.$url.'"';
|
457 |
+
}
|
458 |
+
}
|
459 |
+
|
460 |
+
// replace urls
|
461 |
+
$content = str_replace($search, $replace, $content);
|
462 |
+
|
463 |
+
return $content;
|
464 |
+
}
|
465 |
+
|
466 |
+
/**
|
467 |
+
* Shorthand hex color codes.
|
468 |
+
* #FF0000 -> #F00.
|
469 |
+
*
|
470 |
+
* @param string $content The CSS content to shorten the hex color codes for.
|
471 |
+
*
|
472 |
+
* @return string
|
473 |
+
*/
|
474 |
+
protected function shortenHex($content)
|
475 |
+
{
|
476 |
+
$content = preg_replace('/(?<![\'"])#([0-9a-z])\\1([0-9a-z])\\2([0-9a-z])\\3(?![\'"])/i', '#$1$2$3', $content);
|
477 |
+
|
478 |
+
return $content;
|
479 |
+
}
|
480 |
+
|
481 |
+
/**
|
482 |
+
* Shorthand 0 values to plain 0, instead of e.g. -0em.
|
483 |
+
*
|
484 |
+
* @param string $content The CSS content to shorten the zero values for.
|
485 |
+
*
|
486 |
+
* @return string
|
487 |
+
*/
|
488 |
+
protected function shortenZeroes($content)
|
489 |
+
{
|
490 |
+
// reusable bits of code throughout these regexes:
|
491 |
+
// before & after are used to make sure we don't match lose unintended
|
492 |
+
// 0-like values (e.g. in #000, or in http://url/1.0)
|
493 |
+
// units can be stripped from 0 values, or used to recognize non 0
|
494 |
+
// values (where wa may be able to strip a .0 suffix)
|
495 |
+
$before = '(?<=[:(, ])';
|
496 |
+
$after = '(?=[ ,);}])';
|
497 |
+
$units = '(em|ex|%|px|cm|mm|in|pt|pc|ch|rem|vh|vw|vmin|vmax|vm)';
|
498 |
+
|
499 |
+
// strip units after zeroes (0px -> 0)
|
500 |
+
// NOTE: it should be safe to remove all units for a 0 value, but in
|
501 |
+
// practice, Webkit (especially Safari) seems to stumble over at least
|
502 |
+
// 0%, potentially other units as well. Only stripping 'px' for now.
|
503 |
+
// @see https://github.com/matthiasmullie/minify/issues/60
|
504 |
+
$content = preg_replace('/'.$before.'(-?0*(\.0+)?)(?<=0)px'.$after.'/', '\\1', $content);
|
505 |
+
|
506 |
+
// strip 0-digits (.0 -> 0)
|
507 |
+
$content = preg_replace('/'.$before.'\.0+'.$units.'?'.$after.'/', '0\\1', $content);
|
508 |
+
// strip trailing 0: 50.10 -> 50.1, 50.10px -> 50.1px
|
509 |
+
$content = preg_replace('/'.$before.'(-?[0-9]+\.[0-9]+)0+'.$units.'?'.$after.'/', '\\1\\2', $content);
|
510 |
+
// strip trailing 0: 50.00 -> 50, 50.00px -> 50px
|
511 |
+
$content = preg_replace('/'.$before.'(-?[0-9]+)\.0+'.$units.'?'.$after.'/', '\\1\\2', $content);
|
512 |
+
// strip leading 0: 0.1 -> .1, 01.1 -> 1.1
|
513 |
+
$content = preg_replace('/'.$before.'(-?)0+([0-9]*\.[0-9]+)'.$units.'?'.$after.'/', '\\1\\2\\3', $content);
|
514 |
+
|
515 |
+
// strip negative zeroes (-0 -> 0) & truncate zeroes (00 -> 0)
|
516 |
+
$content = preg_replace('/'.$before.'-?0+'.$units.'?'.$after.'/', '0\\1', $content);
|
517 |
+
|
518 |
+
return $content;
|
519 |
+
}
|
520 |
+
|
521 |
+
/**
|
522 |
+
* Strip comments from source code.
|
523 |
+
*
|
524 |
+
* @param string $content
|
525 |
+
* @return string
|
526 |
+
*/
|
527 |
+
protected function stripEmptyTags($content)
|
528 |
+
{
|
529 |
+
return preg_replace('/(^|\})[^\{]+\{\s*\}/', '\\1', $content);
|
530 |
+
}
|
531 |
+
|
532 |
+
/**
|
533 |
+
* Strip comments from source code.
|
534 |
+
*/
|
535 |
+
protected function stripComments()
|
536 |
+
{
|
537 |
+
$this->registerPattern('/\/\*.*?\*\//s', '');
|
538 |
+
}
|
539 |
+
|
540 |
+
/**
|
541 |
+
* Strip whitespace.
|
542 |
+
*
|
543 |
+
* @param string $content The CSS content to strip the whitespace for.
|
544 |
+
*
|
545 |
+
* @return string
|
546 |
+
*/
|
547 |
+
protected function stripWhitespace($content)
|
548 |
+
{
|
549 |
+
// remove leading & trailing whitespace
|
550 |
+
$content = preg_replace('/^\s*/m', '', $content);
|
551 |
+
$content = preg_replace('/\s*$/m', '', $content);
|
552 |
+
|
553 |
+
// replace newlines with a single space
|
554 |
+
$content = preg_replace('/\s+/', ' ', $content);
|
555 |
+
|
556 |
+
// remove whitespace around meta characters
|
557 |
+
// inspired by stackoverflow.com/questions/15195750/minify-compress-css-with-regex
|
558 |
+
$content = preg_replace('/\s*([\*$~^|]?+=|[{};,>~]|!important\b)\s*/', '$1', $content);
|
559 |
+
$content = preg_replace('/([\[(:])\s+/', '$1', $content);
|
560 |
+
$content = preg_replace('/\s+([\]\)])/', '$1', $content);
|
561 |
+
$content = preg_replace('/\s+(:)(?![^\}]*\{)/', '$1', $content);
|
562 |
+
|
563 |
+
// whitespace around + and - can only be stripped in selectors, like
|
564 |
+
// :nth-child(3+2n), not in things like calc(3px + 2px) or shorthands
|
565 |
+
// like 3px -2px
|
566 |
+
$content = preg_replace('/\s*([+-])\s*(?=[^}]*{)/', '$1', $content);
|
567 |
+
|
568 |
+
// remove semicolon/whitespace followed by closing bracket
|
569 |
+
$content = str_replace(';}', '}', $content);
|
570 |
+
|
571 |
+
return trim($content);
|
572 |
+
}
|
573 |
+
}
|
minify/src/Converter.php
ADDED
@@ -0,0 +1,195 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|