Version Description
Fixed admin notice and improved Contact Form 7 integration.
Download this release
Release Info
Developer | DvanKooten |
Plugin | MailChimp for WordPress |
Version | 1.5.3 |
Comparing to | |
See all releases |
Code changes from version 1.5.1 to 1.5.3
- assets/css/index.php +5 -5
- assets/img/index.php +5 -5
- assets/index.php +5 -5
- assets/js/admin.js +237 -147
- assets/js/beautify-html.js +839 -0
- assets/js/index.php +5 -5
- includes/class-admin.php +15 -7
- includes/class-api.php +27 -1
- includes/class-checkbox.php +40 -4
- includes/class-form.php +30 -8
- includes/class-plugin.php +6 -0
- includes/class-widget.php +6 -0
- includes/functions.php +6 -0
- includes/index.php +5 -5
- includes/template-functions.php +7 -1
- includes/views/api-settings.php +9 -1
- includes/views/checkbox-settings.php +8 -1
- includes/views/form-settings.php +11 -2
- includes/views/index.php +5 -5
- includes/views/parts/admin-field-wizard.php +9 -2
- includes/views/parts/admin-footer.php +7 -1
- includes/views/parts/admin-need-support.php +7 -1
- includes/views/parts/admin-upgrade-to-pro.php +7 -1
- includes/views/parts/index.php +5 -5
- index.php +2 -2
- mailchimp-for-wp.php +4 -4
- readme.txt +26 -5
- trunk/assets/css/admin.css +0 -82
- trunk/assets/css/checkbox.css +0 -24
- trunk/assets/css/css.php +0 -32
- trunk/assets/css/form-reset.css +0 -76
- trunk/assets/css/form-theme-base.css +0 -95
- trunk/assets/css/form-theme-blue.css +0 -23
- trunk/assets/css/form-theme-dark.css +0 -23
- trunk/assets/css/form-theme-green.css +0 -23
- trunk/assets/css/form-theme-light.css +0 -13
- trunk/assets/css/form-theme-red.css +0 -23
- trunk/assets/css/form.css +0 -23
- trunk/assets/css/index.php +0 -6
- trunk/assets/img/index.php +0 -6
- trunk/assets/img/menu-icon.png +0 -0
- trunk/assets/index.php +0 -6
- trunk/assets/js/admin.js +0 -373
- trunk/assets/js/forms.js +0 -136
- trunk/assets/js/index.php +0 -6
- trunk/assets/js/placeholders.min.js +0 -2
- trunk/includes/class-admin.php +0 -275
- trunk/includes/class-api.php +0 -133
- trunk/includes/class-checkbox.php +0 -424
- trunk/includes/class-form.php +0 -383
- trunk/includes/class-plugin.php +0 -129
- trunk/includes/class-widget.php +0 -73
- trunk/includes/functions.php +0 -71
- trunk/includes/index.php +0 -6
- trunk/includes/template-functions.php +0 -146
- trunk/includes/views/api-settings.php +0 -80
- trunk/includes/views/checkbox-settings.php +0 -98
- trunk/includes/views/form-settings.php +0 -234
- trunk/includes/views/index.php +0 -6
- trunk/includes/views/parts/admin-field-wizard.php +0 -62
- trunk/includes/views/parts/admin-footer.php +0 -5
- trunk/includes/views/parts/admin-need-support.php +0 -23
- trunk/includes/views/parts/admin-upgrade-to-pro.php +0 -10
- trunk/includes/views/parts/index.php +0 -6
- trunk/index.php +0 -6
- trunk/license.txt +0 -621
- trunk/mailchimp-for-wp.php +0 -57
- trunk/readme.txt +0 -457
- trunk/uninstall.php +0 -14
- uninstall.php +3 -2
assets/css/index.php
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
Â
<?php
|
2 |
-
|
3 |
-
|
4 |
-
header('HTTP/1.
|
5 |
-
|
6 |
-
|
1 |
Â
<?php
|
2 |
+
if( ! defined("MC4WP_LITE_VERSION") ) {
|
3 |
+
header( 'Status: 403 Forbidden' );
|
4 |
+
header( 'HTTP/1.1 403 Forbidden' );
|
5 |
+
exit;
|
6 |
+
}
|
assets/img/index.php
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
Â
<?php
|
2 |
-
|
3 |
-
|
4 |
-
header('HTTP/1.
|
5 |
-
|
6 |
-
|
1 |
Â
<?php
|
2 |
+
if( ! defined("MC4WP_LITE_VERSION") ) {
|
3 |
+
header( 'Status: 403 Forbidden' );
|
4 |
+
header( 'HTTP/1.1 403 Forbidden' );
|
5 |
+
exit;
|
6 |
+
}
|
assets/index.php
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
Â
<?php
|
2 |
-
|
3 |
-
|
4 |
-
header('HTTP/1.
|
5 |
-
|
6 |
-
|
1 |
Â
<?php
|
2 |
+
if( ! defined("MC4WP_LITE_VERSION") ) {
|
3 |
+
header( 'Status: 403 Forbidden' );
|
4 |
+
header( 'HTTP/1.1 403 Forbidden' );
|
5 |
+
exit;
|
6 |
+
}
|
assets/js/admin.js
CHANGED
@@ -1,12 +1,14 @@
|
|
1 |
Â
(function($) {
|
2 |
Â
|
3 |
-
$("tr.pro-feature td :radio").change(function() {
|
4 |
Â
this.checked = false;
|
5 |
Â
alert("This option is only available in the premium version of MailChimp for WordPress.");
|
Â
|
|
6 |
Â
});
|
7 |
Â
|
8 |
-
$("tr.pro-feature label").click(function() {
|
9 |
Â
alert("This option is only available in the premium version of MailChimp for WordPress.");
|
Â
|
|
10 |
Â
});
|
11 |
Â
|
12 |
Â
|
@@ -38,97 +40,120 @@
|
|
38 |
Â
var $placeholder = $("#mc4wp-fw-placeholder");
|
39 |
Â
var $required = $("#mc4wp-fw-required");
|
40 |
Â
var $wrapp = $("#mc4wp-fw-wrap-p");
|
41 |
-
var
|
42 |
-
'type': 'text',
|
43 |
-
'name': ''
|
44 |
-
};
|
45 |
Â
var $codePreview = $("#mc4wp-fw-preview");
|
46 |
Â
// functions
|
47 |
Â
|
48 |
Â
// set the fields the user can choose from
|
49 |
-
function
|
50 |
Â
{
|
51 |
-
// show notice if no lists selecteed
|
52 |
-
var $selectedLists = $lists.filter(':checked');
|
53 |
-
$(".no-lists-selected").toggle(($selectedLists.length == 0));
|
54 |
-
|
55 |
-
|
56 |
Â
// empty field select
|
57 |
Â
$mailchimpFields.find('option').not('.default').remove();
|
58 |
Â
|
59 |
Â
// loop through checked lists
|
60 |
-
$
|
61 |
-
var
|
62 |
-
var
|
63 |
Â
|
64 |
Â
// loop through merge fields from this list
|
65 |
-
for(var i = 0; i <
|
66 |
-
var
|
67 |
Â
|
68 |
Â
// add field to select if no similar option exists yet
|
69 |
-
if($mailchimpMergeFields.find("option[value='"+
|
70 |
Â
|
71 |
-
var text = (
|
72 |
-
if(
|
73 |
Â
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
79 |
Â
}
|
80 |
-
|
81 |
Â
$mailchimpMergeFields.append($option);
|
82 |
Â
}
|
83 |
Â
}
|
84 |
Â
|
85 |
Â
// loop through interest groupings
|
86 |
-
for(var i = 0, groupingsCount =
|
87 |
-
var
|
88 |
-
|
89 |
Â
// add field to select if no similar option exists yet
|
90 |
-
if($mailchimpGroupings.find("option[value='"+
|
91 |
-
var text = (
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
92 |
Â
|
93 |
Â
// only show 1 grouping
|
94 |
-
if(i
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
Â
}
|
99 |
Â
|
100 |
Â
$mailchimpGroupings.append($option);
|
101 |
Â
}
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
Â
}
|
106 |
Â
|
107 |
Â
|
108 |
Â
});
|
109 |
Â
}
|
110 |
Â
|
Â
|
|
Â
|
|
Â
|
|
111 |
Â
function setPresets()
|
112 |
Â
{
|
113 |
Â
resetFields();
|
114 |
Â
|
115 |
Â
var selected = $(this).find(':selected');
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
125 |
Â
|
126 |
-
|
127 |
-
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
128 |
Â
}
|
129 |
-
|
Â
|
|
130 |
Â
}
|
131 |
Â
|
Â
|
|
Â
|
|
Â
|
|
132 |
Â
function resetFields() {
|
133 |
Â
$wizardFields.find('.row :input').each(function() {
|
134 |
Â
if($(this).is(":checkbox")) { this.checked = true; } else { this.value = ''; }
|
@@ -138,50 +163,98 @@
|
|
138 |
Â
$multipleValues.find(':input').remove();
|
139 |
Â
$wizardFields.show();
|
140 |
Â
|
141 |
-
|
142 |
-
|
143 |
Â
$valueLabel.html("Initial value <small>(optional)</small>");
|
144 |
Â
}
|
145 |
Â
|
Â
|
|
Â
|
|
Â
|
|
146 |
Â
function addGroupInputs(groups)
|
147 |
Â
{
|
148 |
Â
// add a text input to $multipleValues for each group
|
149 |
Â
for(var i = 0, groupsCount = groups.length; i < groupsCount; i++) {
|
150 |
-
$("<input />").attr('type', 'text')
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
151 |
Â
}
|
152 |
Â
}
|
153 |
Â
|
Â
|
|
Â
|
|
Â
|
|
154 |
Â
function setPresetsForGrouping(data)
|
155 |
Â
{
|
156 |
Â
$wizardFields.find('p.row').filter('.values, .label, .wrap-p').show();
|
157 |
Â
$label.val(data.name + ":");
|
158 |
-
|
159 |
Â
addGroupInputs(data.groups);
|
160 |
Â
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
} else if(data.form_field == 'hidden') {
|
166 |
-
$wizardFields.find('p.row').filter('.values, .label, .wrap-p').hide();
|
167 |
-
$wizardFields.find('p.row.value').show();
|
168 |
-
field['type'] = 'hidden';
|
169 |
-
|
170 |
-
for(var i = 0, groupsCount = data.groups.length; i < groupsCount; i++) {
|
171 |
-
$value.val($value.val() + data.groups[i].name + ',');
|
172 |
-
}
|
173 |
Â
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
178 |
Â
|
179 |
Â
// update code preview
|
180 |
Â
updateCodePreview();
|
181 |
Â
}
|
182 |
Â
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
183 |
Â
|
184 |
-
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
185 |
Â
function setPresetsForField(data)
|
186 |
Â
{
|
187 |
Â
|
@@ -193,6 +266,7 @@
|
|
193 |
Â
'date': [ 'label', 'required', 'wrap-p', 'value']
|
194 |
Â
}
|
195 |
Â
|
Â
|
|
196 |
Â
var fieldTypesMap = {
|
197 |
Â
'text': 'text', 'email': 'email', 'phone': 'tel', 'address': 'text', 'number': 'number',
|
198 |
Â
'dropdown': 'select', 'date': 'date', 'birthday': 'date', 'radio': 'radio', 'checkbox': 'checkbox'
|
@@ -215,11 +289,18 @@
|
|
215 |
Â
}
|
216 |
Â
|
217 |
Â
// populate fields with preset values
|
218 |
-
|
219 |
-
|
Â
|
|
Â
|
|
220 |
Â
$placeholder.val("Your " + data.name.toLowerCase());
|
Â
|
|
Â
|
|
221 |
Â
$label.val(data.name + ":");
|
Â
|
|
Â
|
|
222 |
Â
$required.attr('checked', data.req);
|
Â
|
|
223 |
Â
if($multipleValues.is(":visible") && data.choices) {
|
224 |
Â
for(var i = 0, count = data.choices.length; i < count; i++) {
|
225 |
Â
$("<input />").attr('type', 'text').addClass('widefat').data('value', data.choices[i]).attr('placeholder', 'Label for "' + data.choices[i] + '" (or leave empty)').attr('value', data.choices[i]).appendTo($multipleValues);
|
@@ -230,59 +311,91 @@
|
|
230 |
Â
updateCodePreview();
|
231 |
Â
}
|
232 |
Â
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
233 |
Â
function updateCodePreview()
|
234 |
Â
{
|
235 |
Â
var $code = $("<div></div>");
|
236 |
Â
var inputs = [];
|
237 |
Â
var $input;
|
238 |
Â
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
// add options to select
|
244 |
-
$multipleValues.find(":input").each(function() {
|
245 |
-
if($(this).val().length > 0) {
|
246 |
-
$el = $("<option />").val($(this).data("value")).text($(this).val());
|
247 |
-
$el.appendTo($input);
|
248 |
-
}
|
249 |
-
});
|
250 |
-
|
251 |
-
} else if(field['type'] == 'radio' || field['type'] == 'checkbox') {
|
252 |
-
|
253 |
-
// build multiple input values
|
254 |
-
$multipleValues.find(":input").each(function() {
|
255 |
-
if($(this).val().length > 0) {
|
256 |
-
$input = $("<input />").attr('type', field['type']).attr('name', field.name).val($(this).data('value'));
|
257 |
Â
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
$code.append($input);
|
263 |
-
|
264 |
-
$input.wrap("<label />");
|
265 |
-
$("<span />").text($(this).val() + ' ').insertAfter($input);
|
266 |
-
}
|
267 |
-
});
|
268 |
Â
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
273 |
Â
}
|
274 |
Â
|
275 |
Â
// only do this piece when we're not adding radio inputs
|
276 |
-
if(
|
277 |
Â
|
278 |
Â
// set name attribute
|
279 |
-
if(
|
280 |
-
$input.attr('name',
|
281 |
Â
}
|
282 |
Â
|
283 |
Â
// set value
|
284 |
Â
if($value.is(":visible") && $value.val().length > 0) {
|
285 |
-
if(
|
286 |
Â
$input.text($value.val());
|
287 |
Â
} else {
|
288 |
Â
$input.attr('value', $value.val());
|
@@ -296,76 +409,53 @@
|
|
296 |
Â
|
297 |
Â
// add required attribute
|
298 |
Â
if($required.is(':visible:checked')) {
|
299 |
-
$input.attr('required',
|
300 |
Â
}
|
301 |
Â
|
302 |
-
$code.append($input);
|
303 |
-
|
304 |
-
|
305 |
Â
}
|
306 |
Â
|
307 |
Â
// build label
|
308 |
Â
if($label.is(":visible") && $label.val().length > 0) {
|
309 |
Â
$("<label />").text($label.val()).prependTo($code);
|
310 |
Â
}
|
311 |
-
|
312 |
-
// start indenting and tabbing of code
|
313 |
-
var codePreview = $code.html();
|
314 |
Â
|
Â
|
|
315 |
Â
if($wrapp.is(':visible:checked')) {
|
316 |
Â
$code.wrapInner($("<p />"));
|
317 |
-
|
318 |
-
// indent code inside paragraphs (double tab)
|
319 |
-
codePreview = $code.html()
|
320 |
-
.replace(/<p>/gi, "<p>\n\t")
|
321 |
-
.replace(/<label><input /gi, "\n\t<label><input ")
|
322 |
-
.replace(/<\/label><input/gi, "</label> \n\t<input")
|
323 |
-
.replace(/<select /gi, "\n\t<select ")
|
324 |
-
.replace(/<\/select>/gi, "\n\t</select>")
|
325 |
-
.replace(/<\/span><\/label>/gi, "</span>\n\t</label> \n")
|
326 |
-
.replace(/<option /gi, "\n\t\t<option ")
|
327 |
-
.replace(/<label><input type="radio"/g, "<label>\n\t\t<input type=\"radio\"")
|
328 |
-
.replace(/<label><input type="checkbox"/g, "<label>\n\t\t<input type=\"checkbox\"")
|
329 |
-
.replace(/<span>/gi, "\n\t\t<span>")
|
330 |
-
} else {
|
331 |
-
// indent code, single tab
|
332 |
-
codePreview = codePreview
|
333 |
-
.replace(/<option /gi, "\n\t<option ")
|
334 |
-
.replace(/<label><input type="radio"/g, "<label>\n\t<input type=\"radio\"")
|
335 |
-
.replace(/<label><input type="checkbox"/g, "<label>\n\t<input type=\"checkbox\"")
|
336 |
-
.replace(/<span>/gi, "\n\t<span>");
|
337 |
Â
}
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
// add code to codePreview textarea
|
343 |
-
$codePreview.val(codePreview);
|
344 |
Â
}
|
345 |
Â
|
Â
|
|
Â
|
|
Â
|
|
346 |
Â
function addCodeToFormMarkup() {
|
347 |
Â
|
348 |
Â
var result = false;
|
349 |
Â
|
350 |
Â
// try to insert in QuickTags editor at cursor position
|
351 |
-
if(typeof QTags !='undefined' && QTags.insertContent) {
|
352 |
Â
result = QTags.insertContent($codePreview.val());
|
353 |
Â
}
|
354 |
Â
|
355 |
-
// fallback
|
356 |
Â
if(!result) {
|
357 |
-
$
|
Â
|
|
358 |
Â
}
|
359 |
Â
}
|
360 |
Â
|
361 |
Â
// setup events
|
362 |
-
$lists.change(
|
363 |
Â
$mailchimpFields.change(setPresets);
|
364 |
Â
$wizardFields.change(updateCodePreview);
|
365 |
Â
$("#mc4wp-fw-add-to-form").click(addCodeToFormMarkup);
|
366 |
Â
|
367 |
Â
// init
|
368 |
-
|
369 |
Â
|
370 |
Â
})();
|
371 |
Â
|
1 |
Â
(function($) {
|
2 |
Â
|
3 |
+
$("tr.pro-feature, tr.pro-feature td :radio").change(function() {
|
4 |
Â
this.checked = false;
|
5 |
Â
alert("This option is only available in the premium version of MailChimp for WordPress.");
|
6 |
+
event.stopPropagation();
|
7 |
Â
});
|
8 |
Â
|
9 |
+
$("tr.pro-feature, tr.pro-feature label").click(function() {
|
10 |
Â
alert("This option is only available in the premium version of MailChimp for WordPress.");
|
11 |
+
event.stopPropagation();
|
12 |
Â
});
|
13 |
Â
|
14 |
Â
|
40 |
Â
var $placeholder = $("#mc4wp-fw-placeholder");
|
41 |
Â
var $required = $("#mc4wp-fw-required");
|
42 |
Â
var $wrapp = $("#mc4wp-fw-wrap-p");
|
43 |
+
var fieldType, fieldName;
|
Â
|
|
Â
|
|
Â
|
|
44 |
Â
var $codePreview = $("#mc4wp-fw-preview");
|
45 |
Â
// functions
|
46 |
Â
|
47 |
Â
// set the fields the user can choose from
|
48 |
+
function setMailChimpFields()
|
49 |
Â
{
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
50 |
Â
// empty field select
|
51 |
Â
$mailchimpFields.find('option').not('.default').remove();
|
52 |
Â
|
53 |
Â
// loop through checked lists
|
54 |
+
$lists.filter(':checked').each(function() {
|
55 |
+
var listFields = $(this).data('list-fields');
|
56 |
+
var listGroupings = $(this).data('list-groupings');
|
57 |
Â
|
58 |
Â
// loop through merge fields from this list
|
59 |
+
for(var i = 0, fieldCount = listFields.length; i < fieldCount; i++) {
|
60 |
+
var listField = listFields[i];
|
61 |
Â
|
62 |
Â
// add field to select if no similar option exists yet
|
63 |
+
if($mailchimpMergeFields.find("option[value='"+ listField.tag +"']").length == 0) {
|
64 |
Â
|
65 |
+
var text = (listField.name.length > 25) ? listField.name.substring(0, 25) + '..' : listField.name;
|
66 |
+
if(listField.req) { text += '*'; }
|
67 |
Â
|
68 |
+
var $option = $("<option />")
|
69 |
+
.text(text)
|
70 |
+
.val(listField.tag)
|
71 |
+
.data('list-field', listField);
|
72 |
+
|
73 |
+
// only enable 3 fields
|
74 |
+
if(i > 3) {
|
75 |
+
$option.text("(PRO ONLY) " + text)
|
76 |
+
.attr('disabled', 'disabled')
|
77 |
+
.data('field', null);
|
78 |
Â
}
|
79 |
+
|
80 |
Â
$mailchimpMergeFields.append($option);
|
81 |
Â
}
|
82 |
Â
}
|
83 |
Â
|
84 |
Â
// loop through interest groupings
|
85 |
+
for(var i = 0, groupingsCount = listGroupings.length; i < groupingsCount; i++) {
|
86 |
+
var listGrouping = listGroupings[i];
|
87 |
+
|
88 |
Â
// add field to select if no similar option exists yet
|
89 |
+
if($mailchimpGroupings.find("option[value='"+ listGrouping.id +"']").length == 0) {
|
90 |
+
var text = (listGrouping.name.length > 25) ? listGrouping.name.substring(0, 25) + '..' : listGrouping.name;
|
91 |
+
|
92 |
+
// build option HTML
|
93 |
+
var $option = $("<option />")
|
94 |
+
.text(text)
|
95 |
+
.val(listGrouping.id)
|
96 |
+
.data('list-grouping', listGrouping);
|
97 |
Â
|
98 |
Â
// only show 1 grouping
|
99 |
+
if(i >= 1) {
|
100 |
+
$option.text("(PRO ONLY) " + text)
|
101 |
+
.attr('disabled', 'disabled')
|
102 |
+
.data('list-grouping', null);
|
103 |
Â
}
|
104 |
Â
|
105 |
Â
$mailchimpGroupings.append($option);
|
106 |
Â
}
|
Â
|
|
Â
|
|
Â
|
|
107 |
Â
}
|
108 |
Â
|
109 |
Â
|
110 |
Â
});
|
111 |
Â
}
|
112 |
Â
|
113 |
+
/**
|
114 |
+
* Set Presets
|
115 |
+
*/
|
116 |
Â
function setPresets()
|
117 |
Â
{
|
118 |
Â
resetFields();
|
119 |
Â
|
120 |
Â
var selected = $(this).find(':selected');
|
121 |
+
switch( selected.val() ) {
|
122 |
+
|
123 |
+
case 'submit':
|
124 |
+
fieldType = 'submit';
|
125 |
+
$valueLabel.text("Button text");
|
126 |
+
$wizardFields.find('p.row').filter('.value, .wrap-p').show();
|
127 |
+
break;
|
128 |
+
|
129 |
+
case 'lists':
|
130 |
+
fieldType = 'lists';
|
131 |
+
$wizardFields.find('.wrap-p').show();
|
132 |
+
updateCodePreview();
|
133 |
+
break;
|
134 |
+
|
135 |
+
default:
|
136 |
+
// try data for MailChimp field
|
137 |
+
var data = selected.data('list-field');
|
138 |
+
if(data) {
|
139 |
+
return setPresetsForField(data);
|
140 |
+
}
|
141 |
Â
|
142 |
+
// try data for interest grouping
|
143 |
+
var data = selected.data('list-grouping');
|
144 |
+
if(data) {
|
145 |
+
return setPresetsForGrouping(data);
|
146 |
+
}
|
147 |
+
|
148 |
+
break;
|
149 |
Â
}
|
150 |
+
|
151 |
+
updateCodePreview();
|
152 |
Â
}
|
153 |
Â
|
154 |
+
/**
|
155 |
+
* Resets all wizard fields back to their default state
|
156 |
+
*/
|
157 |
Â
function resetFields() {
|
158 |
Â
$wizardFields.find('.row :input').each(function() {
|
159 |
Â
if($(this).is(":checkbox")) { this.checked = true; } else { this.value = ''; }
|
163 |
Â
$multipleValues.find(':input').remove();
|
164 |
Â
$wizardFields.show();
|
165 |
Â
|
166 |
+
fieldType = 'text';
|
167 |
+
fieldName = '';
|
168 |
Â
$valueLabel.html("Initial value <small>(optional)</small>");
|
169 |
Â
}
|
170 |
Â
|
171 |
+
/**
|
172 |
+
* Add inputs for each group
|
173 |
+
*/
|
174 |
Â
function addGroupInputs(groups)
|
175 |
Â
{
|
176 |
Â
// add a text input to $multipleValues for each group
|
177 |
Â
for(var i = 0, groupsCount = groups.length; i < groupsCount; i++) {
|
178 |
+
$("<input />").attr('type', 'text')
|
179 |
+
.addClass('widefat').data('value', groups[i].name)
|
180 |
+
.attr('placeholder', 'Label for "' + groups[i].name + '" (or leave empty)')
|
181 |
+
.attr('value', groups[i].name)
|
182 |
+
.appendTo($multipleValues);
|
183 |
Â
}
|
184 |
Â
}
|
185 |
Â
|
186 |
+
/**
|
187 |
+
* Set presets for interest groupings
|
188 |
+
*/
|
189 |
Â
function setPresetsForGrouping(data)
|
190 |
Â
{
|
191 |
Â
$wizardFields.find('p.row').filter('.values, .label, .wrap-p').show();
|
192 |
Â
$label.val(data.name + ":");
|
193 |
+
fieldName = 'GROUPINGS[' + data.id + ']';
|
194 |
Â
addGroupInputs(data.groups);
|
195 |
Â
|
196 |
+
switch(data.form_field) {
|
197 |
+
case 'radio':
|
198 |
+
fieldType = 'radio';
|
199 |
+
break;
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
200 |
Â
|
201 |
+
case 'hidden':
|
202 |
+
// hide all rows except value row
|
203 |
+
$wizardFields.find('p.row').filter('.values, .label, .wrap-p').hide();
|
204 |
+
$wizardFields.find('p.row.value').show();
|
205 |
+
|
206 |
+
// add group name to hidden input value
|
207 |
+
for(var i = 0, groupsCount = data.groups.length; i < groupsCount; i++) {
|
208 |
+
$value.val($value.val() + data.groups[i].name + ',');
|
209 |
+
}
|
210 |
+
|
211 |
+
fieldType = 'hidden';
|
212 |
+
break;
|
213 |
+
|
214 |
+
case 'dropdown':
|
215 |
+
fieldType = 'select';
|
216 |
+
break;
|
217 |
+
|
218 |
+
default:
|
219 |
+
fieldType = 'checkbox';
|
220 |
+
|
221 |
+
// turn field name into an array
|
222 |
+
fieldName += '[]';
|
223 |
+
break;
|
224 |
+
}
|
225 |
Â
|
226 |
Â
// update code preview
|
227 |
Â
updateCodePreview();
|
228 |
Â
}
|
229 |
Â
|
230 |
+
/**
|
231 |
+
* Build list choice HTML
|
232 |
+
*/
|
233 |
+
function getListChoiceHTML()
|
234 |
+
{
|
235 |
+
var html = '';
|
236 |
+
$lists.each(function() {
|
237 |
+
var list_id = $(this).val();
|
238 |
+
var list_name = $(this).parent('label').text();
|
239 |
+
var attrs = '';
|
240 |
+
|
241 |
+
if($(this).is(':checked')) {
|
242 |
+
attrs += 'checked ';
|
243 |
+
}
|
244 |
+
|
245 |
+
html += '<label>' + "\n"
|
246 |
+
html += "\t" + '<input type="checkbox" name="_mc4wp_lists[]" value="' + list_id +'" '+ attrs + ' /> '+ list_name + "\n";
|
247 |
+
html += '</label>' + "\n";
|
248 |
+
});
|
249 |
Â
|
250 |
+
return html;
|
251 |
+
}
|
252 |
+
|
253 |
+
|
254 |
+
|
255 |
+
/**
|
256 |
+
* Set presets for a fields
|
257 |
+
*/
|
258 |
Â
function setPresetsForField(data)
|
259 |
Â
{
|
260 |
Â
|
266 |
Â
'date': [ 'label', 'required', 'wrap-p', 'value']
|
267 |
Â
}
|
268 |
Â
|
269 |
+
// map MailChimp field types to HTML5 field type
|
270 |
Â
var fieldTypesMap = {
|
271 |
Â
'text': 'text', 'email': 'email', 'phone': 'tel', 'address': 'text', 'number': 'number',
|
272 |
Â
'dropdown': 'select', 'date': 'date', 'birthday': 'date', 'radio': 'radio', 'checkbox': 'checkbox'
|
289 |
Â
}
|
290 |
Â
|
291 |
Â
// populate fields with preset values
|
292 |
+
fieldType = fieldType;
|
293 |
+
fieldName = data.tag;
|
294 |
+
|
295 |
+
// set placeholder text
|
296 |
Â
$placeholder.val("Your " + data.name.toLowerCase());
|
297 |
+
|
298 |
+
// set label text
|
299 |
Â
$label.val(data.name + ":");
|
300 |
+
|
301 |
+
// set required attribute
|
302 |
Â
$required.attr('checked', data.req);
|
303 |
+
|
304 |
Â
if($multipleValues.is(":visible") && data.choices) {
|
305 |
Â
for(var i = 0, count = data.choices.length; i < count; i++) {
|
306 |
Â
$("<input />").attr('type', 'text').addClass('widefat').data('value', data.choices[i]).attr('placeholder', 'Label for "' + data.choices[i] + '" (or leave empty)').attr('value', data.choices[i]).appendTo($multipleValues);
|
311 |
Â
updateCodePreview();
|
312 |
Â
}
|
313 |
Â
|
314 |
+
/**
|
315 |
+
* Format and indent the generated HTML
|
316 |
+
* Then add it to the code preview textarea
|
317 |
+
*/
|
318 |
+
function setCodePreview(html) {
|
319 |
+
html = html_beautify(html);
|
320 |
+
$codePreview.val(html);
|
321 |
+
}
|
322 |
+
|
323 |
+
|
324 |
+
/**
|
325 |
+
* Generate HTML based on the various field values
|
326 |
+
*/
|
327 |
Â
function updateCodePreview()
|
328 |
Â
{
|
329 |
Â
var $code = $("<div></div>");
|
330 |
Â
var inputs = [];
|
331 |
Â
var $input;
|
332 |
Â
|
333 |
+
switch(fieldType) {
|
334 |
+
// MailChimp lists
|
335 |
+
case 'lists':
|
336 |
+
var html = getListChoiceHTML();
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
337 |
Â
|
338 |
+
if($wrapp.is(':visible:checked')) {
|
339 |
+
html = "<p>" + html + "</p>";
|
340 |
+
}
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
341 |
Â
|
342 |
+
return setCodePreview(html);
|
343 |
+
break;
|
344 |
+
|
345 |
+
// MailChimp dropdown
|
346 |
+
case 'select':
|
347 |
+
$input = $("<select />");
|
348 |
+
|
349 |
+
// add options to select
|
350 |
+
$multipleValues.find(":input").each(function() {
|
351 |
+
if($(this).val().length > 0) {
|
352 |
+
$el = $("<option />").val($(this).data("value")).text($(this).val());
|
353 |
+
$el.appendTo($input);
|
354 |
+
}
|
355 |
+
});
|
356 |
+
break;
|
357 |
+
|
358 |
+
// MailChimo choices
|
359 |
+
case 'radio':
|
360 |
+
case 'checkbox':
|
361 |
+
// build multiple input values
|
362 |
+
$multipleValues.find(":input").each(function() {
|
363 |
+
if($(this).val().length > 0) {
|
364 |
+
$input = $("<input />").attr('type', fieldType).attr('name', fieldName).val($(this).data('value'));
|
365 |
+
|
366 |
+
if($required.is(':visible:checked')) {
|
367 |
+
$input.attr('required', true);
|
368 |
+
}
|
369 |
+
|
370 |
+
$code.append($input);
|
371 |
+
|
372 |
+
$input.wrap("<label />");
|
373 |
+
$("<span />").text($(this).val() + ' ').insertAfter($input);
|
374 |
+
}
|
375 |
+
});
|
376 |
+
break;
|
377 |
+
|
378 |
+
// MailChimp long text
|
379 |
+
case 'textarea':
|
380 |
+
$input = $("<textarea />");
|
381 |
+
break;
|
382 |
+
|
383 |
+
default:
|
384 |
+
$input = $("<input />").attr('type', fieldType);
|
385 |
+
break;
|
386 |
Â
}
|
387 |
Â
|
388 |
Â
// only do this piece when we're not adding radio inputs
|
389 |
+
if(fieldType != 'radio' && fieldType != 'checkbox') {
|
390 |
Â
|
391 |
Â
// set name attribute
|
392 |
+
if(fieldName.length > 0) {
|
393 |
+
$input.attr('name', fieldName);
|
394 |
Â
}
|
395 |
Â
|
396 |
Â
// set value
|
397 |
Â
if($value.is(":visible") && $value.val().length > 0) {
|
398 |
+
if(fieldType == 'textarea') {
|
399 |
Â
$input.text($value.val());
|
400 |
Â
} else {
|
401 |
Â
$input.attr('value', $value.val());
|
409 |
Â
|
410 |
Â
// add required attribute
|
411 |
Â
if($required.is(':visible:checked')) {
|
412 |
+
$input.attr('required', true);
|
413 |
Â
}
|
414 |
Â
|
415 |
+
$code.append($input);
|
Â
|
|
Â
|
|
416 |
Â
}
|
417 |
Â
|
418 |
Â
// build label
|
419 |
Â
if($label.is(":visible") && $label.val().length > 0) {
|
420 |
Â
$("<label />").text($label.val()).prependTo($code);
|
421 |
Â
}
|
Â
|
|
Â
|
|
Â
|
|
422 |
Â
|
423 |
+
// wrap in paragraphs?
|
424 |
Â
if($wrapp.is(':visible:checked')) {
|
425 |
Â
$code.wrapInner($("<p />"));
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
426 |
Â
}
|
427 |
+
|
428 |
+
var html = $code.html();
|
429 |
+
setCodePreview(html);
|
Â
|
|
Â
|
|
Â
|
|
430 |
Â
}
|
431 |
Â
|
432 |
+
/**
|
433 |
+
* Transfer code preview field to form mark-up
|
434 |
+
*/
|
435 |
Â
function addCodeToFormMarkup() {
|
436 |
Â
|
437 |
Â
var result = false;
|
438 |
Â
|
439 |
Â
// try to insert in QuickTags editor at cursor position
|
440 |
+
if(typeof wpActiveEditor != 'undefined' && typeof QTags != 'undefined' && QTags.insertContent) {
|
441 |
Â
result = QTags.insertContent($codePreview.val());
|
442 |
Â
}
|
443 |
Â
|
444 |
+
// fallback, just append
|
445 |
Â
if(!result) {
|
446 |
+
$formContent = $("#mc4wpformmarkup");
|
447 |
+
$formContent.val($formContent.val() + "\n" + $codePreview.val());
|
448 |
Â
}
|
449 |
Â
}
|
450 |
Â
|
451 |
Â
// setup events
|
452 |
+
$lists.change(setMailChimpFields);
|
453 |
Â
$mailchimpFields.change(setPresets);
|
454 |
Â
$wizardFields.change(updateCodePreview);
|
455 |
Â
$("#mc4wp-fw-add-to-form").click(addCodeToFormMarkup);
|
456 |
Â
|
457 |
Â
// init
|
458 |
+
setMailChimpFields();
|
459 |
Â
|
460 |
Â
})();
|
461 |
Â
|
assets/js/beautify-html.js
ADDED
@@ -0,0 +1,839 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
|
2 |
+
/*
|
3 |
+
|
4 |
+
The MIT License (MIT)
|
5 |
+
|
6 |
+
Copyright (c) 2007-2013 Einar Lielmanis and contributors.
|
7 |
+
|
8 |
+
Permission is hereby granted, free of charge, to any person
|
9 |
+
obtaining a copy of this software and associated documentation files
|
10 |
+
(the "Software"), to deal in the Software without restriction,
|
11 |
+
including without limitation the rights to use, copy, modify, merge,
|
12 |
+
publish, distribute, sublicense, and/or sell copies of the Software,
|
13 |
+
and to permit persons to whom the Software is furnished to do so,
|
14 |
+
subject to the following conditions:
|
15 |
+
|
16 |
+
The above copyright notice and this permission notice shall be
|
17 |
+
included in all copies or substantial portions of the Software.
|
18 |
+
|
19 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
20 |
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
21 |
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
22 |
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
23 |
+
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
24 |
+
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
25 |
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
26 |
+
SOFTWARE.
|
27 |
+
|
28 |
+
|
29 |
+
Style HTML
|
30 |
+
---------------
|
31 |
+
|
32 |
+
Written by Nochum Sossonko, (nsossonko@hotmail.com)
|
33 |
+
|
34 |
+
Based on code initially developed by: Einar Lielmanis, <elfz@laacz.lv>
|
35 |
+
http://jsbeautifier.org/
|
36 |
+
|
37 |
+
Usage:
|
38 |
+
style_html(html_source);
|
39 |
+
|
40 |
+
style_html(html_source, options);
|
41 |
+
|
42 |
+
The options are:
|
43 |
+
indent_inner_html (default false) — indent <head> and <body> sections,
|
44 |
+
indent_size (default 4) — indentation size,
|
45 |
+
indent_char (default space) — character to indent with,
|
46 |
+
wrap_line_length (default 250) - maximum amount of characters per line (0 = disable)
|
47 |
+
brace_style (default "collapse") - "collapse" | "expand" | "end-expand"
|
48 |
+
put braces on the same line as control statements (default), or put braces on own line (Allman / ANSI style), or just put end braces on own line.
|
49 |
+
unformatted (defaults to inline tags) - list of tags, that shouldn't be reformatted
|
50 |
+
indent_scripts (default normal) - "keep"|"separate"|"normal"
|
51 |
+
preserve_newlines (default true) - whether existing line breaks before elements should be preserved
|
52 |
+
Only works before elements, not inside tags or for text.
|
53 |
+
max_preserve_newlines (default unlimited) - maximum number of line breaks to be preserved in one chunk
|
54 |
+
indent_handlebars (default false) - format and indent {{#foo}} and {{/foo}}
|
55 |
+
|
56 |
+
e.g.
|
57 |
+
|
58 |
+
style_html(html_source, {
|
59 |
+
'indent_inner_html': false,
|
60 |
+
'indent_size': 2,
|
61 |
+
'indent_char': ' ',
|
62 |
+
'wrap_line_length': 78,
|
63 |
+
'brace_style': 'expand',
|
64 |
+
'unformatted': ['a', 'sub', 'sup', 'b', 'i', 'u'],
|
65 |
+
'preserve_newlines': true,
|
66 |
+
'max_preserve_newlines': 5,
|
67 |
+
'indent_handlebars': false
|
68 |
+
});
|
69 |
+
*/
|
70 |
+
|
71 |
+
(function() {
|
72 |
+
|
73 |
+
function trim(s) {
|
74 |
+
return s.replace(/^\s+|\s+$/g, '');
|
75 |
+
}
|
76 |
+
|
77 |
+
function ltrim(s) {
|
78 |
+
return s.replace(/^\s+/g, '');
|
79 |
+
}
|
80 |
+
|
81 |
+
function style_html(html_source, options, js_beautify, css_beautify) {
|
82 |
+
//Wrapper function to invoke all the necessary constructors and deal with the output.
|
83 |
+
|
84 |
+
var multi_parser,
|
85 |
+
indent_inner_html,
|
86 |
+
indent_size,
|
87 |
+
indent_character,
|
88 |
+
wrap_line_length,
|
89 |
+
brace_style,
|
90 |
+
unformatted,
|
91 |
+
preserve_newlines,
|
92 |
+
max_preserve_newlines;
|
93 |
+
|
94 |
+
options = options || {};
|
95 |
+
|
96 |
+
// backwards compatibility to 1.3.4
|
97 |
+
if ((options.wrap_line_length === undefined || parseInt(options.wrap_line_length, 10) === 0) &&
|
98 |
+
(options.max_char === undefined || parseInt(options.max_char, 10) === 0)) {
|
99 |
+
options.wrap_line_length = options.max_char;
|
100 |
+
}
|
101 |
+
|
102 |
+
indent_inner_html = options.indent_inner_html || false;
|
103 |
+
indent_size = parseInt(options.indent_size || 4, 10);
|
104 |
+
indent_character = options.indent_char || ' ';
|
105 |
+
brace_style = options.brace_style || 'collapse';
|
106 |
+
wrap_line_length = parseInt(options.wrap_line_length, 10) === 0 ? 32786 : parseInt(options.wrap_line_length || 250, 10);
|
107 |
+
unformatted = options.unformatted || ['a', 'span', 'bdo', 'em', 'strong', 'dfn', 'code', 'samp', 'kbd', 'var', 'cite', 'abbr', 'acronym', 'q', 'sub', 'sup', 'tt', 'i', 'b', 'big', 'small', 'u', 's', 'strike', 'font', 'ins', 'del', 'pre', 'address', 'dt', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
|
108 |
+
preserve_newlines = options.preserve_newlines || true;
|
109 |
+
max_preserve_newlines = preserve_newlines ? parseInt(options.max_preserve_newlines || 32786, 10) : 0;
|
110 |
+
indent_handlebars = options.indent_handlebars || false;
|
111 |
+
|
112 |
+
function Parser() {
|
113 |
+
|
114 |
+
this.pos = 0; //Parser position
|
115 |
+
this.token = '';
|
116 |
+
this.current_mode = 'CONTENT'; //reflects the current Parser mode: TAG/CONTENT
|
117 |
+
this.tags = { //An object to hold tags, their position, and their parent-tags, initiated with default values
|
118 |
+
parent: 'parent1',
|
119 |
+
parentcount: 1,
|
120 |
+
parent1: ''
|
121 |
+
};
|
122 |
+
this.tag_type = '';
|
123 |
+
this.token_text = this.last_token = this.last_text = this.token_type = '';
|
124 |
+
this.newlines = 0;
|
125 |
+
this.indent_content = indent_inner_html;
|
126 |
+
|
127 |
+
this.Utils = { //Uilities made available to the various functions
|
128 |
+
whitespace: "\n\r\t ".split(''),
|
129 |
+
single_token: 'br,input,link,meta,!doctype,basefont,base,area,hr,wbr,param,img,isindex,?xml,embed,?php,?,?='.split(','), //all the single tags for HTML
|
130 |
+
extra_liners: 'head,body,/html'.split(','), //for tags that need a line of whitespace before them
|
131 |
+
in_array: function(what, arr) {
|
132 |
+
for (var i = 0; i < arr.length; i++) {
|
133 |
+
if (what === arr[i]) {
|
134 |
+
return true;
|
135 |
+
}
|
136 |
+
}
|
137 |
+
return false;
|
138 |
+
}
|
139 |
+
};
|
140 |
+
|
141 |
+
this.traverse_whitespace = function() {
|
142 |
+
var input_char = '';
|
143 |
+
|
144 |
+
input_char = this.input.charAt(this.pos);
|
145 |
+
if (this.Utils.in_array(input_char, this.Utils.whitespace)) {
|
146 |
+
this.newlines = 0;
|
147 |
+
while (this.Utils.in_array(input_char, this.Utils.whitespace)) {
|
148 |
+
if (preserve_newlines && input_char === '\n' && this.newlines <= max_preserve_newlines) {
|
149 |
+
this.newlines += 1;
|
150 |
+
}
|
151 |
+
|
152 |
+
this.pos++;
|
153 |
+
input_char = this.input.charAt(this.pos);
|
154 |
+
}
|
155 |
+
return true;
|
156 |
+
}
|
157 |
+
return false;
|
158 |
+
};
|
159 |
+
|
160 |
+
this.get_content = function() { //function to capture regular content between tags
|
161 |
+
|
162 |
+
var input_char = '',
|
163 |
+
content = [],
|
164 |
+
space = false; //if a space is needed
|
165 |
+
|
166 |
+
while (this.input.charAt(this.pos) !== '<') {
|
167 |
+
if (this.pos >= this.input.length) {
|
168 |
+
return content.length ? content.join('') : ['', 'TK_EOF'];
|
169 |
+
}
|
170 |
+
|
171 |
+
if (this.traverse_whitespace()) {
|
172 |
+
if (content.length) {
|
173 |
+
space = true;
|
174 |
+
}
|
175 |
+
continue; //don't want to insert unnecessary space
|
176 |
+
}
|
177 |
+
|
178 |
+
if (indent_handlebars) {
|
179 |
+
// Handlebars parsing is complicated.
|
180 |
+
// {{#foo}} and {{/foo}} are formatted tags.
|
181 |
+
// {{something}} should get treated as content, except:
|
182 |
+
// {{else}} specifically behaves like {{#if}} and {{/if}}
|
183 |
+
var peek3 = this.input.substr(this.pos, 3);
|
184 |
+
if (peek3 === '{{#' || peek3 === '{{/') {
|
185 |
+
// These are tags and not content.
|
186 |
+
break;
|
187 |
+
} else if (this.input.substr(this.pos, 2) === '{{') {
|
188 |
+
if (this.get_tag(true) === '{{else}}') {
|
189 |
+
break;
|
190 |
+
}
|
191 |
+
}
|
192 |
+
}
|
193 |
+
|
194 |
+
input_char = this.input.charAt(this.pos);
|
195 |
+
this.pos++;
|
196 |
+
|
197 |
+
if (space) {
|
198 |
+
if (this.line_char_count >= this.wrap_line_length) { //insert a line when the wrap_line_length is reached
|
199 |
+
this.print_newline(false, content);
|
200 |
+
this.print_indentation(content);
|
201 |
+
} else {
|
202 |
+
this.line_char_count++;
|
203 |
+
content.push(' ');
|
204 |
+
}
|
205 |
+
space = false;
|
206 |
+
}
|
207 |
+
this.line_char_count++;
|
208 |
+
content.push(input_char); //letter at-a-time (or string) inserted to an array
|
209 |
+
}
|
210 |
+
return content.length ? content.join('') : '';
|
211 |
+
};
|
212 |
+
|
213 |
+
this.get_contents_to = function(name) { //get the full content of a script or style to pass to js_beautify
|
214 |
+
if (this.pos === this.input.length) {
|
215 |
+
return ['', 'TK_EOF'];
|
216 |
+
}
|
217 |
+
var input_char = '';
|
218 |
+
var content = '';
|
219 |
+
var reg_match = new RegExp('</' + name + '\\s*>', 'igm');
|
220 |
+
reg_match.lastIndex = this.pos;
|
221 |
+
var reg_array = reg_match.exec(this.input);
|
222 |
+
var end_script = reg_array ? reg_array.index : this.input.length; //absolute end of script
|
223 |
+
if (this.pos < end_script) { //get everything in between the script tags
|
224 |
+
content = this.input.substring(this.pos, end_script);
|
225 |
+
this.pos = end_script;
|
226 |
+
}
|
227 |
+
return content;
|
228 |
+
};
|
229 |
+
|
230 |
+
this.record_tag = function(tag) { //function to record a tag and its parent in this.tags Object
|
231 |
+
if (this.tags[tag + 'count']) { //check for the existence of this tag type
|
232 |
+
this.tags[tag + 'count']++;
|
233 |
+
this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level
|
234 |
+
} else { //otherwise initialize this tag type
|
235 |
+
this.tags[tag + 'count'] = 1;
|
236 |
+
this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level
|
237 |
+
}
|
238 |
+
this.tags[tag + this.tags[tag + 'count'] + 'parent'] = this.tags.parent; //set the parent (i.e. in the case of a div this.tags.div1parent)
|
239 |
+
this.tags.parent = tag + this.tags[tag + 'count']; //and make this the current parent (i.e. in the case of a div 'div1')
|
240 |
+
};
|
241 |
+
|
242 |
+
this.retrieve_tag = function(tag) { //function to retrieve the opening tag to the corresponding closer
|
243 |
+
if (this.tags[tag + 'count']) { //if the openener is not in the Object we ignore it
|
244 |
+
var temp_parent = this.tags.parent; //check to see if it's a closable tag.
|
245 |
+
while (temp_parent) { //till we reach '' (the initial value);
|
246 |
+
if (tag + this.tags[tag + 'count'] === temp_parent) { //if this is it use it
|
247 |
+
break;
|
248 |
+
}
|
249 |
+
temp_parent = this.tags[temp_parent + 'parent']; //otherwise keep on climbing up the DOM Tree
|
250 |
+
}
|
251 |
+
if (temp_parent) { //if we caught something
|
252 |
+
this.indent_level = this.tags[tag + this.tags[tag + 'count']]; //set the indent_level accordingly
|
253 |
+
this.tags.parent = this.tags[temp_parent + 'parent']; //and set the current parent
|
254 |
+
}
|
255 |
+
delete this.tags[tag + this.tags[tag + 'count'] + 'parent']; //delete the closed tags parent reference...
|
256 |
+
delete this.tags[tag + this.tags[tag + 'count']]; //...and the tag itself
|
257 |
+
if (this.tags[tag + 'count'] === 1) {
|
258 |
+
delete this.tags[tag + 'count'];
|
259 |
+
} else {
|
260 |
+
this.tags[tag + 'count']--;
|
261 |
+
}
|
262 |
+
}
|
263 |
+
};
|
264 |
+
|
265 |
+
this.indent_to_tag = function(tag) {
|
266 |
+
// Match the indentation level to the last use of this tag, but don't remove it.
|
267 |
+
if (!this.tags[tag + 'count']) {
|
268 |
+
return;
|
269 |
+
}
|
270 |
+
var temp_parent = this.tags.parent;
|
271 |
+
while (temp_parent) {
|
272 |
+
if (tag + this.tags[tag + 'count'] === temp_parent) {
|
273 |
+
break;
|
274 |
+
}
|
275 |
+
temp_parent = this.tags[temp_parent + 'parent'];
|
276 |
+
}
|
277 |
+
if (temp_parent) {
|
278 |
+
this.indent_level = this.tags[tag + this.tags[tag + 'count']];
|
279 |
+
}
|
280 |
+
};
|
281 |
+
|
282 |
+
this.get_tag = function(peek) { //function to get a full tag and parse its type
|
283 |
+
var input_char = '',
|
284 |
+
content = [],
|
285 |
+
comment = '',
|
286 |
+
space = false,
|
287 |
+
tag_start, tag_end,
|
288 |
+
tag_start_char,
|
289 |
+
orig_pos = this.pos,
|
290 |
+
orig_line_char_count = this.line_char_count;
|
291 |
+
|
292 |
+
peek = peek !== undefined ? peek : false;
|
293 |
+
|
294 |
+
do {
|
295 |
+
if (this.pos >= this.input.length) {
|
296 |
+
if (peek) {
|
297 |
+
this.pos = orig_pos;
|
298 |
+
this.line_char_count = orig_line_char_count;
|
299 |
+
}
|
300 |
+
return content.length ? content.join('') : ['', 'TK_EOF'];
|
301 |
+
}
|
302 |
+
|
303 |
+
input_char = this.input.charAt(this.pos);
|
304 |
+
this.pos++;
|
305 |
+
|
306 |
+
if (this.Utils.in_array(input_char, this.Utils.whitespace)) { //don't want to insert unnecessary space
|
307 |
+
space = true;
|
308 |
+
continue;
|
309 |
+
}
|
310 |
+
|
311 |
+
if (input_char === "'" || input_char === '"') {
|
312 |
+
input_char += this.get_unformatted(input_char);
|
313 |
+
space = true;
|
314 |
+
|
315 |
+
}
|
316 |
+
|
317 |
+
if (input_char === '=') { //no space before =
|
318 |
+
space = false;
|
319 |
+
}
|
320 |
+
|
321 |
+
if (content.length && content[content.length - 1] !== '=' && input_char !== '>' && space) {
|
322 |
+
//no space after = or before >
|
323 |
+
if (this.line_char_count >= this.wrap_line_length) {
|
324 |
+
this.print_newline(false, content);
|
325 |
+
this.print_indentation(content);
|
326 |
+
} else {
|
327 |
+
content.push(' ');
|
328 |
+
this.line_char_count++;
|
329 |
+
}
|
330 |
+
space = false;
|
331 |
+
}
|
332 |
+
|
333 |
+
if (indent_handlebars && tag_start_char === '<') {
|
334 |
+
// When inside an angle-bracket tag, put spaces around
|
335 |
+
// handlebars not inside of strings.
|
336 |
+
if ((input_char + this.input.charAt(this.pos)) === '{{') {
|
337 |
+
input_char += this.get_unformatted('}}');
|
338 |
+
if (content.length && content[content.length - 1] !== ' ' && content[content.length - 1] !== '<') {
|
339 |
+
input_char = ' ' + input_char;
|
340 |
+
}
|
341 |
+
space = true;
|
342 |
+
}
|
343 |
+
}
|
344 |
+
|
345 |
+
if (input_char === '<' && !tag_start_char) {
|
346 |
+
tag_start = this.pos - 1;
|
347 |
+
tag_start_char = '<';
|
348 |
+
}
|
349 |
+
|
350 |
+
if (indent_handlebars && !tag_start_char) {
|
351 |
+
if (content.length >= 2 && content[content.length - 1] === '{' && content[content.length - 2] == '{') {
|
352 |
+
if (input_char === '#' || input_char === '/') {
|
353 |
+
tag_start = this.pos - 3;
|
354 |
+
} else {
|
355 |
+
tag_start = this.pos - 2;
|
356 |
+
}
|
357 |
+
tag_start_char = '{';
|
358 |
+
}
|
359 |
+
}
|
360 |
+
|
361 |
+
this.line_char_count++;
|
362 |
+
content.push(input_char); //inserts character at-a-time (or string)
|
363 |
+
|
364 |
+
if (content[1] && content[1] === '!') { //if we're in a comment, do something special
|
365 |
+
// We treat all comments as literals, even more than preformatted tags
|
366 |
+
// we just look for the appropriate close tag
|
367 |
+
content = [this.get_comment(tag_start)];
|
368 |
+
break;
|
369 |
+
}
|
370 |
+
|
371 |
+
if (indent_handlebars && tag_start_char === '{' && content.length > 2 && content[content.length - 2] === '}' && content[content.length - 1] === '}') {
|
372 |
+
break;
|
373 |
+
}
|
374 |
+
} while (input_char !== '>');
|
375 |
+
|
376 |
+
var tag_complete = content.join('');
|
377 |
+
var tag_index;
|
378 |
+
var tag_offset;
|
379 |
+
|
380 |
+
if (tag_complete.indexOf(' ') !== -1) { //if there's whitespace, thats where the tag name ends
|
381 |
+
tag_index = tag_complete.indexOf(' ');
|
382 |
+
} else if (tag_complete[0] === '{') {
|
383 |
+
tag_index = tag_complete.indexOf('}');
|
384 |
+
} else { //otherwise go with the tag ending
|
385 |
+
tag_index = tag_complete.indexOf('>');
|
386 |
+
}
|
387 |
+
if (tag_complete[0] === '<' || !indent_handlebars) {
|
388 |
+
tag_offset = 1;
|
389 |
+
} else {
|
390 |
+
tag_offset = tag_complete[2] === '#' ? 3 : 2;
|
391 |
+
}
|
392 |
+
var tag_check = tag_complete.substring(tag_offset, tag_index).toLowerCase();
|
393 |
+
if (tag_complete.charAt(tag_complete.length - 2) === '/' ||
|
394 |
+
this.Utils.in_array(tag_check, this.Utils.single_token)) { //if this tag name is a single tag type (either in the list or has a closing /)
|
395 |
+
if (!peek) {
|
396 |
+
this.tag_type = 'SINGLE';
|
397 |
+
}
|
398 |
+
} else if (indent_handlebars && tag_complete[0] === '{' && tag_check === 'else') {
|
399 |
+
if (!peek) {
|
400 |
+
this.indent_to_tag('if');
|
401 |
+
this.tag_type = 'HANDLEBARS_ELSE';
|
402 |
+
this.indent_content = true;
|
403 |
+
this.traverse_whitespace();
|
404 |
+
}
|
405 |
+
} else if (tag_check === 'script') { //for later script handling
|
406 |
+
if (!peek) {
|
407 |
+
this.record_tag(tag_check);
|
408 |
+
this.tag_type = 'SCRIPT';
|
409 |
+
}
|
410 |
+
} else if (tag_check === 'style') { //for future style handling (for now it justs uses get_content)
|
411 |
+
if (!peek) {
|
412 |
+
this.record_tag(tag_check);
|
413 |
+
this.tag_type = 'STYLE';
|
414 |
+
}
|
415 |
+
} else if (this.is_unformatted(tag_check, unformatted)) { // do not reformat the "unformatted" tags
|
416 |
+
comment = this.get_unformatted('</' + tag_check + '>', tag_complete); //...delegate to get_unformatted function
|
417 |
+
content.push(comment);
|
418 |
+
// Preserve collapsed whitespace either before or after this tag.
|
419 |
+
if (tag_start > 0 && this.Utils.in_array(this.input.charAt(tag_start - 1), this.Utils.whitespace)) {
|
420 |
+
content.splice(0, 0, this.input.charAt(tag_start - 1));
|
421 |
+
}
|
422 |
+
tag_end = this.pos - 1;
|
423 |
+
if (this.Utils.in_array(this.input.charAt(tag_end + 1), this.Utils.whitespace)) {
|
424 |
+
content.push(this.input.charAt(tag_end + 1));
|
425 |
+
}
|
426 |
+
this.tag_type = 'SINGLE';
|
427 |
+
} else if (tag_check.charAt(0) === '!') { //peek for <! comment
|
428 |
+
// for comments content is already correct.
|
429 |
+
if (!peek) {
|
430 |
+
this.tag_type = 'SINGLE';
|
431 |
+
this.traverse_whitespace();
|
432 |
+
}
|
433 |
+
} else if (!peek) {
|
434 |
+
if (tag_check.charAt(0) === '/') { //this tag is a double tag so check for tag-ending
|
435 |
+
this.retrieve_tag(tag_check.substring(1)); //remove it and all ancestors
|
436 |
+
this.tag_type = 'END';
|
437 |
+
this.traverse_whitespace();
|
438 |
+
} else { //otherwise it's a start-tag
|
439 |
+
this.record_tag(tag_check); //push it on the tag stack
|
440 |
+
if (tag_check.toLowerCase() !== 'html') {
|
441 |
+
this.indent_content = true;
|
442 |
+
}
|
443 |
+
this.tag_type = 'START';
|
444 |
+
|
445 |
+
// Allow preserving of newlines after a start tag
|
446 |
+
this.traverse_whitespace();
|
447 |
+
}
|
448 |
+
if (this.Utils.in_array(tag_check, this.Utils.extra_liners)) { //check if this double needs an extra line
|
449 |
+
this.print_newline(false, this.output);
|
450 |
+
if (this.output.length && this.output[this.output.length - 2] !== '\n') {
|
451 |
+
this.print_newline(true, this.output);
|
452 |
+
}
|
453 |
+
}
|
454 |
+
}
|
455 |
+
|
456 |
+
if (peek) {
|
457 |
+
this.pos = orig_pos;
|
458 |
+
this.line_char_count = orig_line_char_count;
|
459 |
+
}
|
460 |
+
|
461 |
+
return content.join(''); //returns fully formatted tag
|
462 |
+
};
|
463 |
+
|
464 |
+
this.get_comment = function(start_pos) { //function to return comment content in its entirety
|
465 |
+
// this is will have very poor perf, but will work for now.
|
466 |
+
var comment = '',
|
467 |
+
delimiter = '>',
|
468 |
+
matched = false;
|
469 |
+
|
470 |
+
this.pos = start_pos;
|
471 |
+
input_char = this.input.charAt(this.pos);
|
472 |
+
this.pos++;
|
473 |
+
|
474 |
+
while (this.pos <= this.input.length) {
|
475 |
+
comment += input_char;
|
476 |
+
|
477 |
+
// only need to check for the delimiter if the last chars match
|
478 |
+
if (comment[comment.length - 1] === delimiter[delimiter.length - 1] &&
|
479 |
+
comment.indexOf(delimiter) !== -1) {
|
480 |
+
break;
|
481 |
+
}
|
482 |
+
|
483 |
+
// only need to search for custom delimiter for the first few characters
|
484 |
+
if (!matched && comment.length < 10) {
|
485 |
+
if (comment.indexOf('<![if') === 0) { //peek for <![if conditional comment
|
486 |
+
delimiter = '<![endif]>';
|
487 |
+
matched = true;
|
488 |
+
} else if (comment.indexOf('<![cdata[') === 0) { //if it's a <[cdata[ comment...
|
489 |
+
delimiter = ']]>';
|
490 |
+
matched = true;
|
491 |
+
} else if (comment.indexOf('<![') === 0) { // some other ![ comment? ...
|
492 |
+
delimiter = ']>';
|
493 |
+
matched = true;
|
494 |
+
} else if (comment.indexOf('<!--') === 0) { // <!-- comment ...
|
495 |
+
delimiter = '-->';
|
496 |
+
matched = true;
|
497 |
+
}
|
498 |
+
}
|
499 |
+
|
500 |
+
input_char = this.input.charAt(this.pos);
|
501 |
+
this.pos++;
|
502 |
+
}
|
503 |
+
|
504 |
+
return comment;
|
505 |
+
};
|
506 |
+
|
507 |
+
this.get_unformatted = function(delimiter, orig_tag) { //function to return unformatted content in its entirety
|
508 |
+
|
509 |
+
if (orig_tag && orig_tag.toLowerCase().indexOf(delimiter) !== -1) {
|
510 |
+
return '';
|
511 |
+
}
|
512 |
+
var input_char = '';
|
513 |
+
var content = '';
|
514 |
+
var min_index = 0;
|
515 |
+
var space = true;
|
516 |
+
do {
|
517 |
+
|
518 |
+
if (this.pos >= this.input.length) {
|
519 |
+
return content;
|
520 |
+
}
|
521 |
+
|
522 |
+
input_char = this.input.charAt(this.pos);
|
523 |
+
this.pos++;
|
524 |
+
|
525 |
+
if (this.Utils.in_array(input_char, this.Utils.whitespace)) {
|
526 |
+
if (!space) {
|
527 |
+
this.line_char_count--;
|
528 |
+
continue;
|
529 |
+
}
|
530 |
+
if (input_char === '\n' || input_char === '\r') {
|
531 |
+
content += '\n';
|
532 |
+
/* Don't change tab indention for unformatted blocks. If using code for html editing, this will greatly affect <pre> tags if they are specified in the 'unformatted array'
|
533 |
+
for (var i=0; i<this.indent_level; i++) {
|
534 |
+
content += this.indent_string;
|
535 |
+
}
|
536 |
+
space = false; //...and make sure other indentation is erased
|
537 |
+
*/
|
538 |
+
this.line_char_count = 0;
|
539 |
+
continue;
|
540 |
+
}
|
541 |
+
}
|
542 |
+
content += input_char;
|
543 |
+
this.line_char_count++;
|
544 |
+
space = true;
|
545 |
+
|
546 |
+
if (indent_handlebars && input_char === '{' && content.length && content[content.length - 2] === '{') {
|
547 |
+
// Handlebars expressions in strings should also be unformatted.
|
548 |
+
content += this.get_unformatted('}}');
|
549 |
+
// These expressions are opaque. Ignore delimiters found in them.
|
550 |
+
min_index = content.length;
|
551 |
+
}
|
552 |
+
} while (content.toLowerCase().indexOf(delimiter, min_index) === -1);
|
553 |
+
return content;
|
554 |
+
};
|
555 |
+
|
556 |
+
this.get_token = function() { //initial handler for token-retrieval
|
557 |
+
var token;
|
558 |
+
|
559 |
+
if (this.last_token === 'TK_TAG_SCRIPT' || this.last_token === 'TK_TAG_STYLE') { //check if we need to format javascript
|
560 |
+
var type = this.last_token.substr(7);
|
561 |
+
token = this.get_contents_to(type);
|
562 |
+
if (typeof token !== 'string') {
|
563 |
+
return token;
|
564 |
+
}
|
565 |
+
return [token, 'TK_' + type];
|
566 |
+
}
|
567 |
+
if (this.current_mode === 'CONTENT') {
|
568 |
+
token = this.get_content();
|
569 |
+
if (typeof token !== 'string') {
|
570 |
+
return token;
|
571 |
+
} else {
|
572 |
+
return [token, 'TK_CONTENT'];
|
573 |
+
}
|
574 |
+
}
|
575 |
+
|
576 |
+
if (this.current_mode === 'TAG') {
|
577 |
+
token = this.get_tag();
|
578 |
+
if (typeof token !== 'string') {
|
579 |
+
return token;
|
580 |
+
} else {
|
581 |
+
var tag_name_type = 'TK_TAG_' + this.tag_type;
|
582 |
+
return [token, tag_name_type];
|
583 |
+
}
|
584 |
+
}
|
585 |
+
};
|
586 |
+
|
587 |
+
this.get_full_indent = function(level) {
|
588 |
+
level = this.indent_level + level || 0;
|
589 |
+
if (level < 1) {
|
590 |
+
return '';
|
591 |
+
}
|
592 |
+
|
593 |
+
return Array(level + 1).join(this.indent_string);
|
594 |
+
};
|
595 |
+
|
596 |
+
this.is_unformatted = function(tag_check, unformatted) {
|
597 |
+
//is this an HTML5 block-level link?
|
598 |
+
if (!this.Utils.in_array(tag_check, unformatted)) {
|
599 |
+
return false;
|
600 |
+
}
|
601 |
+
|
602 |
+
if (tag_check.toLowerCase() !== 'a' || !this.Utils.in_array('a', unformatted)) {
|
603 |
+
return true;
|
604 |
+
}
|
605 |
+
|
606 |
+
//at this point we have an tag; is its first child something we want to remain
|
607 |
+
//unformatted?
|
608 |
+
var next_tag = this.get_tag(true /* peek. */ );
|
609 |
+
|
610 |
+
// test next_tag to see if it is just html tag (no external content)
|
611 |
+
var tag = (next_tag || "").match(/^\s*<\s*\/?([a-z]*)\s*[^>]*>\s*$/);
|
612 |
+
|
613 |
+
// if next_tag comes back but is not an isolated tag, then
|
614 |
+
// let's treat the 'a' tag as having content
|
615 |
+
// and respect the unformatted option
|
616 |
+
if (!tag || this.Utils.in_array(tag, unformatted)) {
|
617 |
+
return true;
|
618 |
+
} else {
|
619 |
+
return false;
|
620 |
+
}
|
621 |
+
};
|
622 |
+
|
623 |
+
this.printer = function(js_source, indent_character, indent_size, wrap_line_length, brace_style) { //handles input/output and some other printing functions
|
624 |
+
|
625 |
+
this.input = js_source || ''; //gets the input for the Parser
|
626 |
+
this.output = [];
|
627 |
+
this.indent_character = indent_character;
|
628 |
+
this.indent_string = '';
|
629 |
+
this.indent_size = indent_size;
|
630 |
+
this.brace_style = brace_style;
|
631 |
+
this.indent_level = 0;
|
632 |
+
this.wrap_line_length = wrap_line_length;
|
633 |
+
this.line_char_count = 0; //count to see if wrap_line_length was exceeded
|
634 |
+
|
635 |
+
for (var i = 0; i < this.indent_size; i++) {
|
636 |
+
this.indent_string += this.indent_character;
|
637 |
+
}
|
638 |
+
|
639 |
+
this.print_newline = function(force, arr) {
|
640 |
+
this.line_char_count = 0;
|
641 |
+
if (!arr || !arr.length) {
|
642 |
+
return;
|
643 |
+
}
|
644 |
+
if (force || (arr[arr.length - 1] !== '\n')) { //we might want the extra line
|
645 |
+
arr.push('\n');
|
646 |
+
}
|
647 |
+
};
|
648 |
+
|
649 |
+
this.print_indentation = function(arr) {
|
650 |
+
for (var i = 0; i < this.indent_level; i++) {
|
651 |
+
arr.push(this.indent_string);
|
652 |
+
this.line_char_count += this.indent_string.length;
|
653 |
+
}
|
654 |
+
};
|
655 |
+
|
656 |
+
this.print_token = function(text) {
|
657 |
+
if (text || text !== '') {
|
658 |
+
if (this.output.length && this.output[this.output.length - 1] === '\n') {
|
659 |
+
this.print_indentation(this.output);
|
660 |
+
text = ltrim(text);
|
661 |
+
}
|
662 |
+
}
|
663 |
+
this.print_token_raw(text);
|
664 |
+
};
|
665 |
+
|
666 |
+
this.print_token_raw = function(text) {
|
667 |
+
if (text && text !== '') {
|
668 |
+
if (text.length > 1 && text[text.length - 1] === '\n') {
|
669 |
+
// unformatted tags can grab newlines as their last character
|
670 |
+
this.output.push(text.slice(0, -1));
|
671 |
+
this.print_newline(false, this.output);
|
672 |
+
} else {
|
673 |
+
this.output.push(text);
|
674 |
+
}
|
675 |
+
}
|
676 |
+
|
677 |
+
for (var n = 0; n < this.newlines; n++) {
|
678 |
+
this.print_newline(n > 0, this.output);
|
679 |
+
}
|
680 |
+
this.newlines = 0;
|
681 |
+
};
|
682 |
+
|
683 |
+
this.indent = function() {
|
684 |
+
this.indent_level++;
|
685 |
+
};
|
686 |
+
|
687 |
+
this.unindent = function() {
|
688 |
+
if (this.indent_level > 0) {
|
689 |
+
this.indent_level--;
|
690 |
+
}
|
691 |
+
};
|
692 |
+
};
|
693 |
+
return this;
|
694 |
+
}
|
695 |
+
|
696 |
+
/*_____________________--------------------_____________________*/
|
697 |
+
|
698 |
+
multi_parser = new Parser(); //wrapping functions Parser
|
699 |
+
multi_parser.printer(html_source, indent_character, indent_size, wrap_line_length, brace_style); //initialize starting values
|
700 |
+
|
701 |
+
while (true) {
|
702 |
+
var t = multi_parser.get_token();
|
703 |
+
multi_parser.token_text = t[0];
|
704 |
+
multi_parser.token_type = t[1];
|
705 |
+
|
706 |
+
if (multi_parser.token_type === 'TK_EOF') {
|
707 |
+
break;
|
708 |
+
}
|
709 |
+
|
710 |
+
switch (multi_parser.token_type) {
|
711 |
+
case 'TK_TAG_START':
|
712 |
+
multi_parser.print_newline(false, multi_parser.output);
|
713 |
+
multi_parser.print_token(multi_parser.token_text);
|
714 |
+
if (multi_parser.indent_content) {
|
715 |
+
multi_parser.indent();
|
716 |
+
multi_parser.indent_content = false;
|
717 |
+
}
|
718 |
+
multi_parser.current_mode = 'CONTENT';
|
719 |
+
break;
|
720 |
+
case 'TK_TAG_STYLE':
|
721 |
+
case 'TK_TAG_SCRIPT':
|
722 |
+
multi_parser.print_newline(false, multi_parser.output);
|
723 |
+
multi_parser.print_token(multi_parser.token_text);
|
724 |
+
multi_parser.current_mode = 'CONTENT';
|
725 |
+
break;
|
726 |
+
case 'TK_TAG_END':
|
727 |
+
//Print new line only if the tag has no content and has child
|
728 |
+
if (multi_parser.last_token === 'TK_CONTENT' && multi_parser.last_text === '') {
|
729 |
+
var tag_name = multi_parser.token_text.match(/\w+/)[0];
|
730 |
+
var tag_extracted_from_last_output = null;
|
731 |
+
if (multi_parser.output.length) {
|
732 |
+
tag_extracted_from_last_output = multi_parser.output[multi_parser.output.length - 1].match(/(?:<|{{#)\s*(\w+)/);
|
733 |
+
}
|
734 |
+
if (tag_extracted_from_last_output === null ||
|
735 |
+
tag_extracted_from_last_output[1] !== tag_name) {
|
736 |
+
multi_parser.print_newline(false, multi_parser.output);
|
737 |
+
}
|
738 |
+
}
|
739 |
+
multi_parser.print_token(multi_parser.token_text);
|
740 |
+
multi_parser.current_mode = 'CONTENT';
|
741 |
+
break;
|
742 |
+
case 'TK_TAG_SINGLE':
|
743 |
+
// Don't add a newline before elements that should remain unformatted.
|
744 |
+
var tag_check = multi_parser.token_text.match(/^\s*<([a-z]+)/i);
|
745 |
+
if (!tag_check || !multi_parser.Utils.in_array(tag_check[1], unformatted)) {
|
746 |
+
multi_parser.print_newline(false, multi_parser.output);
|
747 |
+
}
|
748 |
+
multi_parser.print_token(multi_parser.token_text);
|
749 |
+
multi_parser.current_mode = 'CONTENT';
|
750 |
+
break;
|
751 |
+
case 'TK_TAG_HANDLEBARS_ELSE':
|
752 |
+
multi_parser.print_token(multi_parser.token_text);
|
753 |
+
if (multi_parser.indent_content) {
|
754 |
+
multi_parser.indent();
|
755 |
+
multi_parser.indent_content = false;
|
756 |
+
}
|
757 |
+
multi_parser.current_mode = 'CONTENT';
|
758 |
+
break;
|
759 |
+
case 'TK_CONTENT':
|
760 |
+
multi_parser.print_token(multi_parser.token_text);
|
761 |
+
multi_parser.current_mode = 'TAG';
|
762 |
+
break;
|
763 |
+
case 'TK_STYLE':
|
764 |
+
case 'TK_SCRIPT':
|
765 |
+
if (multi_parser.token_text !== '') {
|
766 |
+
multi_parser.print_newline(false, multi_parser.output);
|
767 |
+
var text = multi_parser.token_text,
|
768 |
+
_beautifier,
|
769 |
+
script_indent_level = 1;
|
770 |
+
if (multi_parser.token_type === 'TK_SCRIPT') {
|
771 |
+
_beautifier = typeof js_beautify === 'function' && js_beautify;
|
772 |
+
} else if (multi_parser.token_type === 'TK_STYLE') {
|
773 |
+
_beautifier = typeof css_beautify === 'function' && css_beautify;
|
774 |
+
}
|
775 |
+
|
776 |
+
if (options.indent_scripts === "keep") {
|
777 |
+
script_indent_level = 0;
|
778 |
+
} else if (options.indent_scripts === "separate") {
|
779 |
+
script_indent_level = -multi_parser.indent_level;
|
780 |
+
}
|
781 |
+
|
782 |
+
var indentation = multi_parser.get_full_indent(script_indent_level);
|
783 |
+
if (_beautifier) {
|
784 |
+
// call the Beautifier if avaliable
|
785 |
+
text = _beautifier(text.replace(/^\s*/, indentation), options);
|
786 |
+
} else {
|
787 |
+
// simply indent the string otherwise
|
788 |
+
var white = text.match(/^\s*/)[0];
|
789 |
+
var _level = white.match(/[^\n\r]*$/)[0].split(multi_parser.indent_string).length - 1;
|
790 |
+
var reindent = multi_parser.get_full_indent(script_indent_level - _level);
|
791 |
+
text = text.replace(/^\s*/, indentation)
|
792 |
+
.replace(/\r\n|\r|\n/g, '\n' + reindent)
|
793 |
+
.replace(/\s+$/, '');
|
794 |
+
}
|
795 |
+
if (text) {
|
796 |
+
multi_parser.print_token_raw(indentation + trim(text));
|
797 |
+
multi_parser.print_newline(false, multi_parser.output);
|
798 |
+
}
|
799 |
+
}
|
800 |
+
multi_parser.current_mode = 'TAG';
|
801 |
+
break;
|
802 |
+
}
|
803 |
+
multi_parser.last_token = multi_parser.token_type;
|
804 |
+
multi_parser.last_text = multi_parser.token_text;
|
805 |
+
}
|
806 |
+
return multi_parser.output.join('');
|
807 |
+
}
|
808 |
+
|
809 |
+
if (typeof define === "function") {
|
810 |
+
// Add support for require.js
|
811 |
+
define(["./beautify.js", "./beautify-css.js"], function(js_beautify, css_beautify) {
|
812 |
+
return {
|
813 |
+
html_beautify: function(html_source, options) {
|
814 |
+
return style_html(html_source, options, js_beautify, css_beautify);
|
815 |
+
}
|
816 |
+
};
|
817 |
+
});
|
818 |
+
} else if (typeof exports !== "undefined") {
|
819 |
+
// Add support for CommonJS. Just put this file somewhere on your require.paths
|
820 |
+
// and you will be able to `var html_beautify = require("beautify").html_beautify`.
|
821 |
+
var js_beautify = require('./beautify.js').js_beautify;
|
822 |