From 202d295fc043051f3752656a9ff1bb4f272ec527 Mon Sep 17 00:00:00 2001 From: chouseknecht Date: Fri, 28 Jun 2013 07:40:24 -0400 Subject: [PATCH] Variable data for hosts/groups/inventory now defaults to YAML. Data received from the API is converted to YAML. Changed job_template extra_vars to use the variable editor approach -user will now enter extra vars as either YAML or JSON with the default being YAML. --- .DS_Store | Bin 0 -> 6148 bytes awx/.DS_Store | Bin 0 -> 6148 bytes awx/ui/.DS_Store | Bin 0 -> 6148 bytes awx/ui/static/.DS_Store | Bin 0 -> 6148 bytes awx/ui/static/css/ansible-ui.css | 2 +- awx/ui/static/js/controllers/Inventories.js | 14 +-- awx/ui/static/js/controllers/JobTemplates.js | 125 +++++++++++++------ awx/ui/static/js/forms/Groups.js | 2 +- awx/ui/static/js/forms/Hosts.js | 2 +- awx/ui/static/js/forms/Inventories.js | 2 +- awx/ui/static/js/forms/JobTemplates.js | 6 +- awx/ui/static/js/helpers/Groups.js | 16 +-- awx/ui/static/js/helpers/Hosts.js | 16 +-- awx/ui/static/lib/ansible/form-generator.js | 10 +- 14 files changed, 128 insertions(+), 67 deletions(-) create mode 100644 .DS_Store create mode 100644 awx/.DS_Store create mode 100644 awx/ui/.DS_Store create mode 100644 awx/ui/static/.DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..2460542355b545c5ff8120ebe792cb248e4c617e GIT binary patch literal 6148 zcmeH~I}XA?3`A{0fkcy%avKi74OR$FzyvIYIqf#4$mI7QhFYo8^+Vg;}!TM!kPMk^St>SKu2 zy&WuhT}`%Nw2S8Op?PPuDF&v|E?SVlv^p5502LT0&_&+c`M-sKoBszbOsN1B_%j7` zy4h{kc&R*FKVHx3`>fi!!9l+q;q4~?i5e8U;9WZKn17(6`%rCU^)uq zQNCPF=aKj%RDcRhL;?Fg6u7Y_ThKop2tERU3zXfk_E`cfRsd_V1yO-%w1Uy9K89G` z+rg6iYO)2RT{MRe%{!}2F))pG(Sih~)xkgosK7{pdE}j){|ETD`G3^HlnPLRKT|*# z`{RCxm&&vC?mHt-Eh6w0<6gvL`oJkx{qD-+~ zi-^uHyQxScA|tq=Ty5x@?VES3mk|ZRamHS@yVLftIUWz4?AHO~4&@|gS;HUrwn3u; zRDcRl0V+TRKCVEP*wOgoC-XomKm~qX0sB4_xM59f1O3y1!CL^}0AV-Gy_WzM3jk|k z8;A%@g9;3)W{aUgN4#WSO>6^$E}G4U=FOTNiu&z1zj(T64dh4#sKB!V{a7|u{}=E# z{r@wGD=I(*{z?HI%$M^So|Lt<^Ej)u1-^n?&JAvcxl=HBIR<(;#=^?+#FHYg*c|&c Vu?=)O;!X$hXTWr!QGstOa0m456^#G@ literal 0 HcmV?d00001 diff --git a/awx/ui/static/.DS_Store b/awx/ui/static/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..f10092a748eb11a1cd69ed548d0241d9576a5818 GIT binary patch literal 6148 zcmeH~JqiLr422WdLa^D=avBfd4F=H@cmYvC1jRz^=jgutG_KaN$O|OjB(q_6U$L_h z5nVq|E0JDAW^kh{EeuSNcXE-NoKKJA^>Dvmt>iXIS^?h6U_ZABDnJFO02QDDRA593 zET z-P^&E*VSYTM!RSZADVYon_^%Z?V<$hojhD)^_2c!dzR#+y8yxh@5#D|Rkl0bYfV*M8*aED{7DNTc9|4zvfeQRoffuO! B5o!Pc literal 0 HcmV?d00001 diff --git a/awx/ui/static/css/ansible-ui.css b/awx/ui/static/css/ansible-ui.css index 9e1b58fcc5..48cde87441 100644 --- a/awx/ui/static/css/ansible-ui.css +++ b/awx/ui/static/css/ansible-ui.css @@ -60,7 +60,7 @@ } .navbar .brand img { - width: 243px; + width: 292px; } .navbar .nav { diff --git a/awx/ui/static/js/controllers/Inventories.js b/awx/ui/static/js/controllers/Inventories.js index 76a3545305..7e28960b19 100644 --- a/awx/ui/static/js/controllers/Inventories.js +++ b/awx/ui/static/js/controllers/Inventories.js @@ -175,7 +175,7 @@ function InventoriesAdd ($scope, $rootScope, $compile, $location, $log, $routePa var form = InventoryForm; var generator = GenerateForm; var scope = generator.inject(form, {mode: 'add', related: false}); - scope.parseType = 'json'; + scope.parseType = 'yaml'; generator.reset(); LoadBreadCrumbs(); @@ -239,7 +239,7 @@ function InventoriesAdd ($scope, $rootScope, $compile, $location, $log, $routePa }); } catch(err) { - Alert("Error", "Error parsing inventory variables. Parser returned " + err); + Alert("Error", "Error parsing inventory variables. Parser returned: " + err); } }; @@ -275,7 +275,7 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP ParseTypeChange(scope); - scope.parseType = 'json'; + scope.parseType = 'yaml'; scope['inventory_id'] = id; // Retrieve each related set and any lookups @@ -300,10 +300,10 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP Rest.get() .success( function(data, status, headers, config) { if ($.isEmptyObject(data)) { - scope.variables = "\{\}"; + scope.variables = "---"; } else { - scope.variables = JSON.stringify(data, null, " "); + scope.variables = jsyaml.safeDump(data); } }) .error( function(data, status, headers, config) { @@ -313,7 +313,7 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP }); } else { - scope.variables = "\{\}"; + scope.variables = "---"; } }); @@ -371,7 +371,7 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP }); } catch(err) { - Alert("Error", "Error parsing inventory variables. Parser returned " + err); + Alert("Error", "Error parsing inventory variables. Parser returned: " + err); } }; diff --git a/awx/ui/static/js/controllers/JobTemplates.js b/awx/ui/static/js/controllers/JobTemplates.js index 9b2e56e9d3..46aafcc894 100644 --- a/awx/ui/static/js/controllers/JobTemplates.js +++ b/awx/ui/static/js/controllers/JobTemplates.js @@ -159,7 +159,7 @@ JobTemplatesList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$rout function JobTemplatesAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, JobTemplateForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, - GetBasePath, InventoryList, CredentialList, ProjectList, LookUpInit, md5Setup) + GetBasePath, InventoryList, CredentialList, ProjectList, LookUpInit, md5Setup, ParseTypeChange) { ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior //scope. @@ -170,6 +170,9 @@ function JobTemplatesAdd ($scope, $rootScope, $compile, $location, $log, $routeP var generator = GenerateForm; var scope = generator.inject(form, {mode: 'add', related: false}); var master = {}; + + scope.parseType = 'yaml'; + ParseTypeChange(scope); scope.job_type_options = [{ value: 'run', label: 'Run' }, { value: 'check', label: 'Check' }]; scope.verbosity_options = [ @@ -243,25 +246,43 @@ function JobTemplatesAdd ($scope, $rootScope, $compile, $location, $log, $routeP // Save scope.formSave = function() { - Rest.setUrl(defaultUrl); var data = {} - for (var fld in form.fields) { - if (form.fields[fld].type == 'select' && fld != 'playbook') { - data[fld] = scope[fld].value; + try { + // Make sure we have valid variable data + if (scope.parseType == 'json') { + var myjson = JSON.parse(scope.variables); //make sure JSON parses + var json_data = scope.variables; } else { - data[fld] = scope[fld]; - } + var json_data = jsyaml.load(scope.variables); //parse yaml + } + + for (var fld in form.fields) { + if (form.fields[fld].type == 'select' && fld != 'playbook') { + data[fld] = scope[fld].value; + } + else { + if (fld != 'variables') { + data[fld] = scope[fld]; + } + } + } + data.extra_vars = json_data; + Rest.setUrl(defaultUrl); + Rest.post(data) + .success( function(data, status, headers, config) { + var base = $location.path().replace(/^\//,'').split('/')[0]; + (base == 'job_templates') ? ReturnToCaller() : ReturnToCaller(1); + }) + .error( function(data, status, headers, config) { + ProcessErrors(scope, data, status, form, + { hdr: 'Error!', msg: 'Failed to add new job template. POST returned status: ' + status }); + }); + + } + catch(err) { + Alert("Error", "Error parsing extra variables. Parser returned: " + err); } - Rest.post(data) - .success( function(data, status, headers, config) { - var base = $location.path().replace(/^\//,'').split('/')[0]; - (base == 'job_templates') ? ReturnToCaller() : ReturnToCaller(1); - }) - .error( function(data, status, headers, config) { - ProcessErrors(scope, data, status, form, - { hdr: 'Error!', msg: 'Failed to add new project. POST returned status: ' + status }); - }); }; // Reset @@ -277,13 +298,13 @@ function JobTemplatesAdd ($scope, $rootScope, $compile, $location, $log, $routeP JobTemplatesAdd.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobTemplateForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', - 'GetBasePath', 'InventoryList', 'CredentialList', 'ProjectList', 'LookUpInit', 'md5Setup' ]; + 'GetBasePath', 'InventoryList', 'CredentialList', 'ProjectList', 'LookUpInit', 'md5Setup', 'ParseTypeChange' ]; function JobTemplatesEdit ($scope, $rootScope, $compile, $location, $log, $routeParams, JobTemplateForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit, RelatedPaginateInit, ReturnToCaller, ClearScope, InventoryList, CredentialList, - ProjectList, LookUpInit, PromptPasswords, GetBasePath, md5Setup) + ProjectList, LookUpInit, PromptPasswords, GetBasePath, md5Setup, ParseTypeChange) { ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior //scope. @@ -293,6 +314,9 @@ function JobTemplatesEdit ($scope, $rootScope, $compile, $location, $log, $route var form = JobTemplateForm; var scope = generator.inject(form, {mode: 'edit', related: true}); + scope.parseType = 'yaml'; + ParseTypeChange(scope); + // Our job type options scope.job_type_options = [{ value: 'run', label: 'Run' }, { value: 'check', label: 'Check' }]; scope.verbosity_options = [ @@ -365,7 +389,7 @@ function JobTemplatesEdit ($scope, $rootScope, $compile, $location, $log, $route .success( function(data, status, headers, config) { LoadBreadCrumbs({ path: '/job_templates/' + id, title: data.name }); for (var fld in form.fields) { - if (data[fld] !== null && data[fld] !== undefined) { + if (fld != 'variables' && data[fld] !== null && data[fld] !== undefined) { if (form.fields[fld].type == 'select') { if (scope[fld + '_options'] && scope[fld + '_options'].length > 0) { for (var i=0; i < scope[fld + '_options'].length; i++) { @@ -383,6 +407,16 @@ function JobTemplatesEdit ($scope, $rootScope, $compile, $location, $log, $route } master[fld] = scope[fld]; } + if (fld == 'variables') { + // Parse extra_vars, converting to YAML. + if ($.isEmptyObject(data.extra_vars) || data.extra_vars == "\{\}") { + scope.variables = "---"; + } + else { + scope.variables = jsyaml.safeDump(JSON.parse(data.extra_vars)); + } + master.variables = scope.variables; + } if (form.fields[fld].type == 'lookup' && data.summary_fields[form.fields[fld].sourceModel]) { scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] = data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField]; @@ -435,24 +469,42 @@ function JobTemplatesEdit ($scope, $rootScope, $compile, $location, $log, $route // Save changes to the parent scope.formSave = function() { var data = {} - for (var fld in form.fields) { - if (form.fields[fld].type == 'select' && fld != 'playbook') { - data[fld] = scope[fld].value; + try { + // Make sure we have valid variable data + if (scope.parseType == 'json') { + var myjson = JSON.parse(scope.variables); //make sure JSON parses + var json_data = scope.variables; } else { - data[fld] = scope[fld]; - } - } - Rest.setUrl(defaultUrl + $routeParams.id + '/'); - Rest.put(data) - .success( function(data, status, headers, config) { - var base = $location.path().replace(/^\//,'').split('/')[0]; - (base == 'job_templates') ? ReturnToCaller() : ReturnToCaller(1); - }) - .error( function(data, status, headers, config) { - ProcessErrors(scope, data, status, form, - { hdr: 'Error!', msg: 'Failed to update team: ' + $routeParams.id + '. PUT status: ' + status }); - }); + var json_data = jsyaml.load(scope.variables); //parse yaml + } + + for (var fld in form.fields) { + if (form.fields[fld].type == 'select' && fld != 'playbook') { + data[fld] = scope[fld].value; + } + else { + if (fld != 'variables') { + data[fld] = scope[fld]; + } + } + } + data.extra_vars = json_data; + Rest.setUrl(defaultUrl + id + '/'); + Rest.put(data) + .success( function(data, status, headers, config) { + var base = $location.path().replace(/^\//,'').split('/')[0]; + (base == 'job_templates') ? ReturnToCaller() : ReturnToCaller(1); + }) + .error( function(data, status, headers, config) { + ProcessErrors(scope, data, status, form, + { hdr: 'Error!', msg: 'Failed to update job template. PUT returned status: ' + status }); + }); + + } + catch(err) { + Alert("Error", "Error parsing extra variables. Parser returned: " + err); + } }; // Cancel @@ -461,6 +513,7 @@ function JobTemplatesEdit ($scope, $rootScope, $compile, $location, $log, $route for (var fld in master) { scope[fld] = master[fld]; } + scope.parseType = 'yaml'; $('#forks-slider').slider("option", "value", scope.forks); }; @@ -506,5 +559,5 @@ function JobTemplatesEdit ($scope, $rootScope, $compile, $location, $log, $route JobTemplatesEdit.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobTemplateForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit', 'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope', 'InventoryList', 'CredentialList', - 'ProjectList', 'LookUpInit', 'PromptPasswords', 'GetBasePath', 'md5Setup' + 'ProjectList', 'LookUpInit', 'PromptPasswords', 'GetBasePath', 'md5Setup', 'ParseTypeChange' ]; diff --git a/awx/ui/static/js/forms/Groups.js b/awx/ui/static/js/forms/Groups.js index 92a01195c5..5b260623fb 100644 --- a/awx/ui/static/js/forms/Groups.js +++ b/awx/ui/static/js/forms/Groups.js @@ -36,7 +36,7 @@ angular.module('GroupFormDefinition', []) editRequird: false, rows: 10, "class": 'modal-input-xlarge', - "default": "\{\}", + "default": "---", dataTitle: 'Group Variables', dataPlacement: 'right', awPopOver: "

Enter variables using either JSON or YAML syntax. Use the radio button to toggle between the two.

" + diff --git a/awx/ui/static/js/forms/Hosts.js b/awx/ui/static/js/forms/Hosts.js index 4b35f18de7..15edca75d7 100644 --- a/awx/ui/static/js/forms/Hosts.js +++ b/awx/ui/static/js/forms/Hosts.js @@ -41,7 +41,7 @@ angular.module('HostFormDefinition', []) editRequird: false, rows: 10, "class": "modal-input-xlarge", - "default": "\{\}", + "default": "---", awPopOver: "

Enter variables using either JSON or YAML syntax. Use the radio button to toggle between the two.

" + '

View JSON examples at www.json.org

' + '

View YAML examples at ansibleworks.com

', diff --git a/awx/ui/static/js/forms/Inventories.js b/awx/ui/static/js/forms/Inventories.js index d2716b2475..e928630e59 100644 --- a/awx/ui/static/js/forms/Inventories.js +++ b/awx/ui/static/js/forms/Inventories.js @@ -63,7 +63,7 @@ angular.module('InventoryFormDefinition', []) editRequird: false, rows: 10, "class": "modal-input-xlarge", - "default": "\{\}", + "default": "---", awPopOver: "

Enter variables using either JSON or YAML syntax. Use the radio button to toggle between the two.

" + '

View JSON examples at www.json.org

' + '

View YAML examples at ansibleworks.com

', diff --git a/awx/ui/static/js/forms/JobTemplates.js b/awx/ui/static/js/forms/JobTemplates.js index f51fe001f0..98f09a21bc 100644 --- a/awx/ui/static/js/forms/JobTemplates.js +++ b/awx/ui/static/js/forms/JobTemplates.js @@ -127,17 +127,17 @@ angular.module('JobTemplateFormDefinition', []) dataTitle: 'Verbosity', dataPlacement: 'left' }, - extra_vars: { + variables: { label: 'Extra Variables', type: 'textarea', rows: 6, "class": 'span12', addRequired: false, editRequired: false, - "default": "\{\}", + "default": "---", column: 2, awPopOver: "

Pass extra command line variables to the playbook. This is the -e or --extra-vars command line parameter " + - "for ansible-playbook. Provide key=value pairs or JSON.

Click here to view documentation and examples.

", dataTitle: 'Extra Variables', dataPlacement: 'left' diff --git a/awx/ui/static/js/helpers/Groups.js b/awx/ui/static/js/helpers/Groups.js index 21c393fc4e..9aa26dcf1a 100644 --- a/awx/ui/static/js/helpers/Groups.js +++ b/awx/ui/static/js/helpers/Groups.js @@ -175,7 +175,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' scope.formModalActionLabel = 'Save'; scope.formModalHeader = 'Create Group'; scope.formModalCancelShow = true; - scope.parseType = 'json'; + scope.parseType = 'yaml'; ParseTypeChange(scope); $('#form-modal .btn-none').removeClass('btn-none').addClass('btn-success'); @@ -237,7 +237,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' }); } catch(err) { - Alert("Error", "Error parsing group variables. Expecting valid JSON. Parser returned " + err); + Alert("Error", "Error parsing group variables. Parser returned: " + err); } } @@ -270,7 +270,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' scope.formModalActionLabel = 'Save'; scope.formModalHeader = 'Edit Group'; scope.formModalCancelShow = true; - scope.parseType = 'json'; + scope.parseType = 'yaml'; ParseTypeChange(scope); $('#form-modal .btn-none').removeClass('btn-none').addClass('btn-success'); @@ -288,10 +288,10 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' Rest.get() .success( function(data, status, headers, config) { if ($.isEmptyObject(data)) { - scope.variables = "\{\}"; + scope.variables = "---"; } else { - scope.variables = JSON.stringify(data, null, " "); + scope.variables = jsyaml.safeDump(data); } }) .error( function(data, status, headers, config) { @@ -301,8 +301,9 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' }); } else { - scope.variables = "\{\}"; + scope.variables = "---"; } + master.variables = scope.variables; }); // Retrieve detail record and prepopulate the form @@ -378,7 +379,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' }); } catch(err) { - Alert("Error", "Error parsing group variables. Expecting valid JSON. Parser returned " + err); + Alert("Error", "Error parsing group variables. Parser returned: " + err); } }; @@ -388,6 +389,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' for (var fld in master) { scope[fld] = master[fld]; } + scope.parseType = 'yaml'; } } }]) diff --git a/awx/ui/static/js/helpers/Hosts.js b/awx/ui/static/js/helpers/Hosts.js index 251bd8f98f..642868c450 100644 --- a/awx/ui/static/js/helpers/Hosts.js +++ b/awx/ui/static/js/helpers/Hosts.js @@ -165,7 +165,7 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H scope.formModalActionLabel = 'Save'; scope.formModalHeader = 'Create Host'; scope.formModalCancelShow = true; - scope.parseType = 'json'; + scope.parseType = 'yaml'; ParseTypeChange(scope); $('#form-modal .btn-none').removeClass('btn-none').addClass('btn-success'); @@ -223,7 +223,7 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H }); } catch(err) { - Alert("Error", "Error parsing host variables. Parser returned " + err); + Alert("Error", "Error parsing host variables. Parser returned: " + err); } } @@ -258,7 +258,7 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H scope.formModalActionLabel = 'Save'; scope.formModalHeader = 'Edit Host'; scope.formModalCancelShow = true; - scope.parseType = 'json'; + scope.parseType = 'yaml'; ParseTypeChange(scope); $('#form-modal .btn-none').removeClass('btn-none').addClass('btn-success'); @@ -275,10 +275,10 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H Rest.get() .success( function(data, status, headers, config) { if ($.isEmptyObject(data)) { - scope.variables = "\{\}"; + scope.variables = "---"; } else { - scope.variables = JSON.stringify(data, null, " "); + scope.variables = jsyaml.safeDump(data); } }) .error( function(data, status, headers, config) { @@ -288,8 +288,9 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H }); } else { - scope.variables = "\{\}"; + scope.variables = "---"; } + master.variables = scope.variables; }); // Retrieve detail record and prepopulate the form @@ -363,7 +364,7 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H }); } catch(err) { - Alert("Error", "Error parsing group variables. Expecting valid JSON. Parser returned " + err); + Alert("Error", "Error parsing group variables. Parser returned: " + err); } }; @@ -373,6 +374,7 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H for (var fld in master) { scope[fld] = master[fld]; } + scope.parseType = 'yaml'; } } }]) diff --git a/awx/ui/static/lib/ansible/form-generator.js b/awx/ui/static/lib/ansible/form-generator.js index ebce23e3a9..b588e752b9 100644 --- a/awx/ui/static/lib/ansible/form-generator.js +++ b/awx/ui/static/lib/ansible/form-generator.js @@ -278,10 +278,14 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies']) } html += field.label + '' + "\n"; html += "
\n"; - if (fld == "variables") { - html += "
Parse as: \n"; - html += "
\n"; + + // Variable editing + if (fld == "variables" || fld == "extra_vars") { + html += "
Parse as: " + + "\n" + + "
\n"; } + html += "