MailChimp for WordPress - Version 1.5.4

Version Description

Fixed admin notice and "add to form" button, improved Contact Form 7 integration.

Download this release

Release Info

Developer DvanKooten
Plugin Icon 128x128 MailChimp for WordPress
Version 1.5.4
Comparing to
See all releases

Code changes from version 1.5.2 to 1.5.4

assets/js/admin.js CHANGED
@@ -40,97 +40,120 @@
40
  var $placeholder = $("#mc4wp-fw-placeholder");
41
  var $required = $("#mc4wp-fw-required");
42
  var $wrapp = $("#mc4wp-fw-wrap-p");
43
- var field = {
44
- 'type': 'text',
45
- 'name': ''
46
- };
47
  var $codePreview = $("#mc4wp-fw-preview");
48
  // functions
49
 
50
  // set the fields the user can choose from
51
- function setFields()
52
  {
53
- // show notice if no lists selecteed
54
- var $selectedLists = $lists.filter(':checked');
55
- $(".no-lists-selected").toggle(($selectedLists.length == 0));
56
-
57
-
58
  // empty field select
59
  $mailchimpFields.find('option').not('.default').remove();
60
 
61
  // loop through checked lists
62
- $selectedLists.each(function() {
63
- var fields = $(this).data('fields');
64
- var groupings = $(this).data('groupings');
65
 
66
  // loop through merge fields from this list
67
- for(var i = 0; i < fields.length; i++) {
68
- var f = fields[i];
69
 
70
  // add field to select if no similar option exists yet
71
- if($mailchimpMergeFields.find("option[value='"+ f.tag +"']").length == 0) {
72
 
73
- var text = (f.name.length > 40) ? f.name.substring(0, 40) + '..' : f.name;
74
- if(f.req) { text += '*'; }
75
 
76
- // only show first 4 fields
77
- if((i <= 3)) {
78
- var $option = $("<option />").text(text).val(f.tag).data('field', f);
79
- } else {
80
- var $option = $("<option />").text("(PRO ONLY) " + text).val(f.tag).attr('disabled', 'disabled');
 
 
 
 
 
81
  }
82
-
83
  $mailchimpMergeFields.append($option);
84
  }
85
  }
86
 
87
  // loop through interest groupings
88
- for(var i = 0, groupingsCount = groupings.length; i < groupingsCount; i++) {
89
- var grouping = groupings[i];
90
-
91
  // add field to select if no similar option exists yet
92
- if($mailchimpGroupings.find("option[value='"+ grouping.id +"']").length == 0) {
93
- var text = (grouping.name.length > 40) ? grouping.name.substring(0, 40) + '..' : grouping.name;
 
 
 
 
 
 
94
 
95
  // only show 1 grouping
96
- if(i < 1) {
97
- var $option = $("<option />").text(text).val(grouping.id).data('grouping', grouping);
98
- } else {
99
- var $option = $("<option />").text("(PRO ONLY) " + text).val(grouping.id).attr('disabled', 'disabled');
100
  }
101
 
102
  $mailchimpGroupings.append($option);
103
  }
104
-
105
-
106
-
107
  }
108
 
109
 
110
  });
111
  }
112
 
 
 
 
113
  function setPresets()
114
  {
115
  resetFields();
116
 
117
  var selected = $(this).find(':selected');
118
- if(selected.val() == 'submit') {
119
- // setup values for submit field
120
- field['type'] = 'submit';
121
- $valueLabel.text("Button text");
122
- $wizardFields.find('p.row').filter('.value, .wrap-p').show();
123
- updateCodePreview();
124
- } else {
125
- var data = selected.data('field');
126
- if(data) { return setPresetsForField(data); }
 
 
 
 
 
 
 
 
 
 
 
127
 
128
- var data = selected.data('grouping');
129
- if(data) { return setPresetsForGrouping(data); }
 
 
 
 
 
130
  }
131
- return;
 
132
  }
133
 
 
 
 
134
  function resetFields() {
135
  $wizardFields.find('.row :input').each(function() {
136
  if($(this).is(":checkbox")) { this.checked = true; } else { this.value = ''; }
@@ -140,50 +163,98 @@
140
  $multipleValues.find(':input').remove();
141
  $wizardFields.show();
142
 
143
- field['type'] = 'text';
144
- field['name'] = '';
145
  $valueLabel.html("Initial value <small>(optional)</small>");
146
  }
147
 
 
 
 
148
  function addGroupInputs(groups)
149
  {
150
  // add a text input to $multipleValues for each group
151
  for(var i = 0, groupsCount = groups.length; i < groupsCount; i++) {
152
- $("<input />").attr('type', 'text').addClass('widefat').data('value', groups[i].name).attr('placeholder', 'Label for "' + groups[i].name + '" (or leave empty)').attr('value', groups[i].name).appendTo($multipleValues);
 
 
 
 
153
  }
154
  }
155
 
 
 
 
156
  function setPresetsForGrouping(data)
157
  {
158
  $wizardFields.find('p.row').filter('.values, .label, .wrap-p').show();
159
  $label.val(data.name + ":");
160
- field['name'] = 'GROUPINGS['+ data.id + ']';
161
  addGroupInputs(data.groups);
162
 
163
- if(data.form_field == 'radio') {
164
- field['type'] = 'radio';
165
- } else if(data.form_field == 'dropdown') {
166
- field['type'] = 'select';
167
- } else if(data.form_field == 'hidden') {
168
- $wizardFields.find('p.row').filter('.values, .label, .wrap-p').hide();
169
- $wizardFields.find('p.row.value').show();
170
- field['type'] = 'hidden';
171
-
172
- for(var i = 0, groupsCount = data.groups.length; i < groupsCount; i++) {
173
- $value.val($value.val() + data.groups[i].name + ',');
174
- }
175
 
176
- } else {
177
- field['type'] = 'checkbox';
178
- field['name'] = 'GROUPINGS['+ data.id + '][]';
179
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
 
181
  // update code preview
182
  updateCodePreview();
183
  }
184
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
 
186
- // show available fields and fill it with some values
 
 
 
 
 
 
 
187
  function setPresetsForField(data)
188
  {
189
 
@@ -195,6 +266,7 @@
195
  'date': [ 'label', 'required', 'wrap-p', 'value']
196
  }
197
 
 
198
  var fieldTypesMap = {
199
  'text': 'text', 'email': 'email', 'phone': 'tel', 'address': 'text', 'number': 'number',
200
  'dropdown': 'select', 'date': 'date', 'birthday': 'date', 'radio': 'radio', 'checkbox': 'checkbox'
@@ -217,11 +289,18 @@
217
  }
218
 
219
  // populate fields with preset values
220
- field['type'] = fieldType;
221
- field['name'] = data.tag;
 
 
222
  $placeholder.val("Your " + data.name.toLowerCase());
 
 
223
  $label.val(data.name + ":");
 
 
224
  $required.attr('checked', data.req);
 
225
  if($multipleValues.is(":visible") && data.choices) {
226
  for(var i = 0, count = data.choices.length; i < count; i++) {
227
  $("<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);
@@ -232,59 +311,91 @@
232
  updateCodePreview();
233
  }
234
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
  function updateCodePreview()
236
  {
237
  var $code = $("<div></div>");
238
  var inputs = [];
239
  var $input;
240
 
241
- // build input / select / textarea element
242
- if(field['type'] == 'select') {
243
- $input = $("<select />");
244
-
245
- // add options to select
246
- $multipleValues.find(":input").each(function() {
247
- if($(this).val().length > 0) {
248
- $el = $("<option />").val($(this).data("value")).text($(this).val());
249
- $el.appendTo($input);
250
- }
251
- });
252
-
253
- } else if(field['type'] == 'radio' || field['type'] == 'checkbox') {
254
-
255
- // build multiple input values
256
- $multipleValues.find(":input").each(function() {
257
- if($(this).val().length > 0) {
258
- $input = $("<input />").attr('type', field['type']).attr('name', field.name).val($(this).data('value'));
259
 
260
- if($required.is(':visible:checked')) {
261
- $input.attr('required', 'required');
262
- }
263
-
264
- $code.append($input);
265
-
266
- $input.wrap("<label />");
267
- $("<span />").text($(this).val() + ' ').insertAfter($input);
268
- }
269
- });
270
 
271
- } else if(field['type'] == 'textarea') {
272
- $input = $("<textarea />");
273
- } else {
274
- $input = $("<input />").attr('type', field['type']);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275
  }
276
 
277
  // only do this piece when we're not adding radio inputs
278
- if(field['type'] != 'radio' && field['type'] != 'checkbox') {
279
 
280
  // set name attribute
281
- if(field.name.length > 0) {
282
- $input.attr('name', field.name);
283
  }
284
 
285
  // set value
286
  if($value.is(":visible") && $value.val().length > 0) {
287
- if(field['type'] == 'textarea') {
288
  $input.text($value.val());
289
  } else {
290
  $input.attr('value', $value.val());
@@ -298,76 +409,53 @@
298
 
299
  // add required attribute
300
  if($required.is(':visible:checked')) {
301
- $input.attr('required', 'required');
302
  }
303
 
304
- $code.append($input);
305
-
306
-
307
  }
308
 
309
  // build label
310
  if($label.is(":visible") && $label.val().length > 0) {
311
  $("<label />").text($label.val()).prependTo($code);
312
  }
313
-
314
- // start indenting and tabbing of code
315
- var codePreview = $code.html();
316
 
 
317
  if($wrapp.is(':visible:checked')) {
318
  $code.wrapInner($("<p />"));
319
-
320
- // indent code inside paragraphs (double tab)
321
- codePreview = $code.html()
322
- .replace(/<p>/gi, "<p>\n\t")
323
- .replace(/<label><input /gi, "\n\t<label><input ")
324
- .replace(/<\/label><input/gi, "</label> \n\t<input")
325
- .replace(/<select /gi, "\n\t<select ")
326
- .replace(/<\/select>/gi, "\n\t</select>")
327
- .replace(/<\/span><\/label>/gi, "</span>\n\t</label> \n")
328
- .replace(/<option /gi, "\n\t\t<option ")
329
- .replace(/<label><input type="radio"/g, "<label>\n\t\t<input type=\"radio\"")
330
- .replace(/<label><input type="checkbox"/g, "<label>\n\t\t<input type=\"checkbox\"")
331
- .replace(/<span>/gi, "\n\t\t<span>")
332
- } else {
333
- // indent code, single tab
334
- codePreview = codePreview
335
- .replace(/<option /gi, "\n\t<option ")
336
- .replace(/<label><input type="radio"/g, "<label>\n\t<input type=\"radio\"")
337
- .replace(/<label><input type="checkbox"/g, "<label>\n\t<input type=\"checkbox\"")
338
- .replace(/<span>/gi, "\n\t<span>");
339
  }
340
-
341
- // newline after every closed element
342
- codePreview = codePreview.replace(/></g, "> \n<");
343
-
344
- // add code to codePreview textarea
345
- $codePreview.val(codePreview);
346
  }
347
 
 
 
 
348
  function addCodeToFormMarkup() {
349
 
350
  var result = false;
351
 
352
  // try to insert in QuickTags editor at cursor position
353
- if(typeof QTags !='undefined' && QTags.insertContent) {
354
  result = QTags.insertContent($codePreview.val());
355
  }
356
 
357
- // fallback
358
  if(!result) {
359
- $("#mc4wpformmarkup").val($("#mc4wpformmarkup").val() + "\n" + $codePreview.val());
 
360
  }
361
  }
362
 
363
  // setup events
364
- $lists.change(setFields);
365
  $mailchimpFields.change(setPresets);
366
  $wizardFields.change(updateCodePreview);
367
  $("#mc4wp-fw-add-to-form").click(addCodeToFormMarkup);
368
 
369
  // init
370
- setFields();
371
 
372
  })();
373
 
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
+ var css_beautify = require('./beautify-css.js').css_beautify;
823
+
824
+ exports.html_beautify = function(html_source, options) {
825
+ return style_html(html_source, options, js_beautify, css_beautify);
826
+ };
827
+ } else if (typeof window !== "undefined") {
828
+ // If we're running a web page and don't have either of the above, add our one global
829
+ window.html_beautify = function(html_source, options) {
830
+ return style_html(html_source, options, window.js_beautify, window.css_beautify);
831
+ };
832
+ } else if (typeof global !== "undefined") {
833
+ // If we don't even have window, try global.
834
+ global.html_beautify = function(html_source, options) {
835
+ return style_html(html_source, options, global.js_beautify, global.css_beautify);
836
+ };
837
+ }
838
+
839
+ }());
includes/class-admin.php CHANGED
@@ -100,8 +100,9 @@ class MC4WP_Lite_Admin
100
  wp_enqueue_style( 'mc4wp-admin-css', plugins_url('mailchimp-for-wp/assets/css/admin.css') );
101
 
102
  // js
103
- wp_register_script('mc4wp-admin-js', plugins_url('mailchimp-for-wp/assets/js/admin.js'), array('jquery'), false, true);
104
- wp_enqueue_script( array('jquery', 'mc4wp-admin-js') );
 
105
  }
106
 
107
  public function get_checkbox_compatible_plugins()
100
  wp_enqueue_style( 'mc4wp-admin-css', plugins_url('mailchimp-for-wp/assets/css/admin.css') );
101
 
102
  // js
103
+ wp_register_script( 'mc4wp-beautifyhtml', MC4WP_LITE_PLUGIN_URL . 'assets/js/beautify-html.js', array('jquery'), MC4WP_LITE_VERSION, true);
104
+ wp_register_script('mc4wp-admin-js', MC4WP_LITE_PLUGIN_URL . 'assets/js/admin.js', array('jquery'), false, true);
105
+ wp_enqueue_script( array('jquery', 'mc4wp-beautifyhtml', 'mc4wp-admin-js') );
106
  }
107
 
108
  public function get_checkbox_compatible_plugins()
includes/class-checkbox.php CHANGED
@@ -80,8 +80,9 @@ class MC4WP_Lite_Checkbox
80
  public function initialize()
81
  {
82
  if(function_exists("wpcf7_add_shortcode")) {
83
- wpcf7_add_shortcode('mc4wp_checkbox', array($this, 'get_checkbox'));
84
- add_action('wpcf7_mail_sent', array($this, 'subscribe_from_cf7'));
 
85
  }
86
 
87
  // catch-all (for manual integrations with third-party forms)
@@ -93,9 +94,22 @@ class MC4WP_Lite_Checkbox
93
  public function get_checkbox($args = array())
94
  {
95
  $opts = mc4wp_get_options('checkbox');
 
96
  $label = isset($args['labels'][0]) ? $args['labels'][0] : $opts['label'];
97
  $checked = $opts['precheck'] ? "checked" : '';
98
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  $content = "\n<!-- Checkbox by MailChimp for WordPress plugin v". MC4WP_LITE_VERSION ." - http://dannyvankooten.com/mailchimp-for-wordpress/ -->\n";
100
 
101
  do_action('mc4wp_before_checkbox');
@@ -228,9 +242,18 @@ class MC4WP_Lite_Checkbox
228
  /* End Multisite functions */
229
 
230
  /* Start Contact Form 7 functions */
231
- public function subscribe_from_cf7($arg = null)
 
 
 
 
 
 
232
  {
233
- if(!isset($_POST['mc4wp-do-subscribe']) || !$_POST['mc4wp-do-subscribe']) { return false; }
 
 
 
234
 
235
  $_POST['mc4wp-try-subscribe'] = 1;
236
  unset($_POST['mc4wp-do-subscribe']);
80
  public function initialize()
81
  {
82
  if(function_exists("wpcf7_add_shortcode")) {
83
+ wpcf7_add_shortcode( 'mc4wp_checkbox', array( $this, 'get_checkbox') );
84
+ add_action( 'wpcf7_posted_data', array( $this, 'alter_cf7_data') );
85
+ add_action( 'wpcf7_mail_sent', array( $this, 'subscribe_from_cf7' ) );
86
  }
87
 
88
  // catch-all (for manual integrations with third-party forms)
94
  public function get_checkbox($args = array())
95
  {
96
  $opts = mc4wp_get_options('checkbox');
97
+
98
  $label = isset($args['labels'][0]) ? $args['labels'][0] : $opts['label'];
99
  $checked = $opts['precheck'] ? "checked" : '';
100
 
101
+ // CF7 checkbox?
102
+ if( is_array( $args ) && isset( $args['type'] ) ) {
103
+
104
+ // check for default:0 or default:1 to set the checked attribute
105
+ if( in_array( 'default:1', $args['options'] ) ) {
106
+ $checked = 'checked';
107
+ } else if( in_array( 'default:0', $args['options'] ) ) {
108
+ $checked = '';
109
+ }
110
+
111
+ }
112
+
113
  $content = "\n<!-- Checkbox by MailChimp for WordPress plugin v". MC4WP_LITE_VERSION ." - http://dannyvankooten.com/mailchimp-for-wordpress/ -->\n";
114
 
115
  do_action('mc4wp_before_checkbox');
242
  /* End Multisite functions */
243
 
244
  /* Start Contact Form 7 functions */
245
+
246
+ public function alter_cf7_data($data) {
247
+ $data['mc4wp_checkbox'] = ( isset( $_POST['mc4wp-do-subscribe'] ) && $_POST['mc4wp-do-subscribe'] == 1 ) ? __("Yes") : __("No");
248
+ return $data;
249
+ }
250
+
251
+ public function subscribe_from_cf7($args = null)
252
  {
253
+ // check if CF7 "mc4wp" checkbox was checked
254
+ if(!isset($_POST['mc4wp-do-subscribe']) || !$_POST['mc4wp-do-subscribe']) {
255
+ return false;
256
+ }
257
 
258
  $_POST['mc4wp-try-subscribe'] = 1;
259
  unset($_POST['mc4wp-do-subscribe']);
includes/class-form.php CHANGED
@@ -55,10 +55,10 @@ class MC4WP_Lite_Form {
55
  public function initialize()
56
  {
57
  // register placeholder script, which will later be enqueued for IE only
58
- wp_register_script( 'mc4wp-placeholders', plugins_url('mailchimp-for-wp/assets/js/placeholders.min.js'), array(), MC4WP_LITE_VERSION, true );
59
 
60
  // register non-AJAX script (that handles form submissions)
61
- wp_register_script( 'mc4wp-forms', plugins_url('mailchimp-for-wp/assets/js/forms.js'), array(), MC4WP_LITE_VERSION, true );
62
  }
63
 
64
  public function add_stylesheets($stylesheets) {
@@ -85,6 +85,8 @@ class MC4WP_Lite_Form {
85
  $css_classes = 'form mc4wp-form ';
86
  if ( $this->error ) $css_classes .= 'mc4wp-form-error ';
87
  if ( $this->success ) $css_classes .= 'mc4wp-form-success ';
 
 
88
  $css_classes = apply_filters( 'mc4wp_form_css_classes', $css_classes );
89
 
90
 
@@ -129,6 +131,8 @@ class MC4WP_Lite_Form {
129
 
130
  $error_type = ($e == 'already_subscribed') ? 'notice' : 'error';
131
  $error_message = isset($opts['text_' . $e]) ? $opts['text_' . $e] : $opts['text_error'];
 
 
132
  $error_message = apply_filters('mc4wp_form_error_message', $error_message);
133
 
134
  $content .= '<div class="mc4wp-alert mc4wp-'. $error_type .'">'. __($error_message, 'mailchimp-for-wp') . '</div>';
55
  public function initialize()
56
  {
57
  // register placeholder script, which will later be enqueued for IE only
58
+ wp_register_script( 'mc4wp-placeholders', MC4WP_LITE_PLUGIN_URL . 'assets/js/placeholders.min.js', array(), MC4WP_LITE_VERSION, true );
59
 
60
  // register non-AJAX script (that handles form submissions)
61
+ wp_register_script( 'mc4wp-forms', MC4WP_LITE_PLUGIN_URL . 'assets/js/forms.js', array(), MC4WP_LITE_VERSION, true );
62
  }
63
 
64
  public function add_stylesheets($stylesheets) {
85