AC-564 added new method to codemirror wrapper to enable replacing textarea fields with an editor. Implemented in inventory, groups, hosts, and templates. Solved issues with groups related to two potential textareas at the same time. Found and fixed an error in the way ReturnToCaller() utility was being called. Finished implementing angular-md5. Adding or saving a job template now shows a pop-up on save when a callback is enabled. The pop-up shows the callback url and host key. Before user had to save and then re-open the template to get the URL. With the pop-up we're now showing it immmediately on save.

This commit is contained in:
Chris Houseknecht 2014-02-18 03:50:36 -05:00
parent 177080e43d
commit 55b574fa26
15 changed files with 309 additions and 126 deletions

View File

@ -236,11 +236,12 @@ function InventoriesAdd($scope, $rootScope, $compile, $location, $log, $routePar
generator.inject(form, { mode: 'add', related: false, scope: $scope });
$scope.inventoryParseType = 'yaml';
generator.reset();
LoadBreadCrumbs();
ParseTypeChange( $scope, 'inventory_variables', 'inventoryParseType');
$scope.inventoryParseType = 'yaml';
ParseTypeChange({ scope: $scope, variable: 'inventory_variables', parse_variable: 'inventoryParseType',
field_id: 'inventory_inventory_variables' });
LookUpInit({
scope: $scope,

View File

@ -118,12 +118,18 @@ function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $routePa
generator = GenerateForm,
master = {},
CloudCredentialList = {},
selectPlaybook, checkSCMStatus;
selectPlaybook, checkSCMStatus,
callback;
generator.inject(form, { mode: 'add', related: false, scope: $scope });
callback = function() {
// Make sure the form controller knows there was a change
$scope[form.name + '_form'].setDirty();
};
$scope.parseType = 'yaml';
ParseTypeChange($scope);
ParseTypeChange({ scope: $scope, field_id: 'job_templates_variables', onChange: callback });
$scope.job_type_options = [
{ value: 'run', label: 'Run' },
@ -131,9 +137,9 @@ function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $routePa
];
$scope.verbosity_options = [
{ value: '0', label: 'Default' },
{ value: '1', label: 'Verbose' },
{ value: '3', label: 'Debug' }
{ value: 0, label: 'Default' },
{ value: 1, label: 'Verbose' },
{ value: 3, label: 'Debug' }
];
$scope.playbook_options = [];
@ -258,6 +264,24 @@ function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $routePa
field: 'project'
});
function saveCompleted() {
setTimeout(function() { $scope.$apply(function() { $location.path('/job_templates'); }); }, 500);
}
if ($scope.removeTemplateSaveSuccess) {
$scope.removeTemplateSaveSuccess();
}
$scope.removeTemplateSaveSuccess = $scope.$on('templateSaveSuccess', function(e, data) {
Wait('stop');
if (data.related && data.related.callback) {
Alert('Callback URL', '<p>Host callbacks are enabled for this template. The callback URL is: <strong>' + data.related.callback +
'</strong></p><p>The host configuration key is: <strong>' + data.host_config_key + '</strong></p>', 'alert-info', saveCompleted);
}
else {
saveCompleted();
}
});
// Save
$scope.formSave = function () {
generator.clearApiErrors();
@ -293,16 +317,10 @@ function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $routePa
Rest.setUrl(defaultUrl);
Rest.post(data)
.success(function () {
Wait('stop');
var base = $location.path().replace(/^\//, '').split('/')[0];
if (base === 'job_templates') {
ReturnToCaller();
}
ReturnToCaller(1);
.success(function(data) {
$scope.$emit('templateSaveSuccess', data);
})
.error(function (data, status) {
Wait('stop');
ProcessErrors($scope, data, status, form, { hdr: 'Error!',
msg: 'Failed to add new job template. POST returned status: ' + status
});
@ -347,13 +365,12 @@ function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log, $routeP
master = {},
id = $routeParams.id,
relatedSets = {},
checkSCMStatus, getPlaybooks;
checkSCMStatus, getPlaybooks, callback;
generator.inject(form, { mode: 'edit', related: true, scope: $scope });
$scope.parseType = 'yaml';
ParseTypeChange($scope);
// Our job type options
$scope.job_type_options = [
{ value: 'run', label: 'Run' },
@ -361,10 +378,15 @@ function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log, $routeP
];
$scope.verbosity_options = [
{ value: '0', label: 'Default' },
{ value: '1', label: 'Verbose' },
{ value: '3', label: 'Debug' }
{ value: 0, label: 'Default' },
{ value: 1, label: 'Verbose' },
{ value: 3, label: 'Debug' }
];
callback = function() {
// Make sure the form controller knows there was a change
$scope[form.name + '_form'].$setDirty();
};
$scope.playbook_options = null;
$scope.playbook = null;
@ -524,6 +546,8 @@ function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log, $routeP
default_val: dft
});
ParseTypeChange({ scope: $scope, field_id: 'job_templates_variables', onChange: callback });
if (related_cloud_credential) {
Rest.setUrl(related_cloud_credential);
Rest.get()
@ -642,6 +666,24 @@ function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log, $routeP
});
});
function saveCompleted() {
setTimeout(function() { $scope.$apply(function() { $location.path('/job_templates'); }); }, 500);
}
if ($scope.removeTemplateSaveSuccess) {
$scope.removeTemplateSaveSuccess();
}
$scope.removeTemplateSaveSuccess = $scope.$on('templateSaveSuccess', function(e, data) {
Wait('stop');
if (Empty(master.callback_url) && data.related && data.related.callback) {
Alert('Callback URL', '<p>Host callbacks are enabled for this template. The callback URL is: <strong>' + data.related.callback +
'</strong></p><p>The host configuration key is: <strong>' + data.host_config_key + '</strong></p>', 'alert-info', saveCompleted);
}
else {
saveCompleted();
}
});
// Save changes to the parent
$scope.formSave = function () {
generator.clearApiErrors();
@ -677,19 +719,12 @@ function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log, $routeP
Rest.setUrl(defaultUrl + id + '/');
Rest.put(data)
.success(function () {
Wait('stop');
var base = $location.path().replace(/^\//, '').split('/')[0];
if (base === 'job_templates') {
ReturnToCaller();
}
ReturnToCaller(1);
.success(function (data) {
$scope.$emit('templateSaveSuccess', data);
})
.error(function (data, status) {
ProcessErrors($scope, data, status, form, {
hdr: 'Error!',
msg: 'Failed to update job template. PUT returned status: ' + status
});
ProcessErrors($scope, data, status, form, { hdr: 'Error!',
msg: 'Failed to update job template. PUT returned status: ' + status });
});
} catch (err) {
@ -711,6 +746,7 @@ function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log, $routeP
$scope[fld] = master[fld];
}
$scope.parseType = 'yaml';
ParseTypeChange({ scope: $scope, field_id: 'job_templates_variables', onChange: callback });
$('#forks-slider').slider("option", "value", $scope.forks);
};

View File

@ -444,10 +444,11 @@ function ProjectsAdd($scope, $rootScope, $compile, $location, $log, $routeParams
if (base === 'projects') {
ReturnToCaller();
}
ReturnToCaller(1);
else {
ReturnToCaller(1);
}
})
.error(function (data, status) {
Wait('stop');
ProcessErrors($scope, data, status, ProjectsForm, { hdr: 'Error!',
msg: 'Failed to add organization to project. POST returned status: ' + status });
});

View File

@ -285,7 +285,9 @@ function TeamsEdit($scope, $rootScope, $compile, $location, $log, $routeParams,
if (base === 'teams') {
ReturnToCaller();
}
ReturnToCaller(1);
else {
ReturnToCaller(1);
}
})
.error(function (data, status) {
Wait('stop');

View File

@ -166,7 +166,9 @@ function UsersAdd($scope, $rootScope, $compile, $location, $log, $routeParams, U
$rootScope.flashMessage = 'New user successfully created!';
$location.path('/users/' + data.id);
}
ReturnToCaller(1);
else {
ReturnToCaller(1);
}
})
.error(function (data, status) {
ProcessErrors($scope, data, status, form, { hdr: 'Error!', msg: 'Failed to add new user. POST returned status: ' + status });
@ -307,7 +309,9 @@ function UsersEdit($scope, $rootScope, $compile, $location, $log, $routeParams,
if (base === 'users') {
ReturnToCaller();
}
ReturnToCaller(1);
else {
ReturnToCaller(1);
}
})
.error(function (data, status) {
ProcessErrors($scope, data, status, form, { hdr: 'Error!', msg: 'Failed to update users: ' + $routeParams.id +

View File

@ -178,13 +178,13 @@ angular.module('GroupsHelper', ['RestServices', 'Utilities', 'ListGenerator', 'G
}
])
.factory('SourceChange', ['GetBasePath', 'CredentialList', 'LookUpInit', 'Empty',
function (GetBasePath, CredentialList, LookUpInit, Empty) {
.factory('SourceChange', ['GetBasePath', 'CredentialList', 'LookUpInit', 'Empty', 'Wait', 'ParseTypeChange',
function (GetBasePath, CredentialList, LookUpInit, Empty, Wait, ParseTypeChange) {
return function (params) {
var scope = params.scope,
form = params.form,
kind, url;
kind, url, callback;
if (!Empty(scope.source)) {
if (scope.source.value === 'file') {
@ -220,6 +220,13 @@ angular.module('GroupsHelper', ['RestServices', 'Utilities', 'ListGenerator', 'G
list: CredentialList,
field: 'credential'
});
if ($('#group_tabs .active a').text() === 'Source' && scope.source.value === 'ec2') {
callback = function(){ Wait('stop'); };
Wait('start');
ParseTypeChange({ scope: scope, variable: 'source_vars', parse_variable: form.fields.source_vars.parseTypeName,
field_id: 'group_source_vars', onReady: callback });
}
}
}
};
@ -314,10 +321,10 @@ angular.module('GroupsHelper', ['RestServices', 'Utilities', 'ListGenerator', 'G
])
.factory('GroupsAdd', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'GroupForm', 'GenerateForm',
'Prompt', 'ProcessErrors', 'GetBasePath', 'ParseTypeChange', 'GroupsEdit', 'Wait', 'GetChoices',
'Prompt', 'ProcessErrors', 'GetBasePath', 'ParseTypeChange', 'Wait', 'GetChoices',
'GetSourceTypeOptions', 'LookUpInit', 'BuildTree', 'SourceChange', 'WatchInventoryWindowResize',
function ($rootScope, $location, $log, $routeParams, Rest, Alert, GroupForm, GenerateForm, Prompt, ProcessErrors,
GetBasePath, ParseTypeChange, GroupsEdit, Wait, GetChoices, GetSourceTypeOptions, LookUpInit, BuildTree,
GetBasePath, ParseTypeChange, Wait, GetChoices, GetSourceTypeOptions, LookUpInit, BuildTree,
SourceChange, WatchInventoryWindowResize) {
return function (params) {
@ -333,12 +340,28 @@ angular.module('GroupsHelper', ['RestServices', 'Utilities', 'ListGenerator', 'G
scope.formModalActionLabel = 'Save';
scope.formModalCancelShow = true;
scope.parseType = 'yaml';
scope.source = null;
ParseTypeChange(scope);
generator.reset();
scope[form.fields.source_vars.parseTypeName] = 'yaml';
scope.parseType = 'yaml';
ParseTypeChange({ scope: scope, field_id: 'group_variables' });
$('#group_tabs a[data-toggle="tab"]').on('show.bs.tab', function (e) {
var callback = function(){ Wait('stop'); };
if ($(e.target).text() === 'Properties') {
Wait('start');
ParseTypeChange({ scope: scope, field_id: 'group_variables', onReady: callback });
}
else {
if (scope.source && scope.source.value === 'ec2') {
Wait('start');
ParseTypeChange({ scope: scope, variable: 'source_vars', parse_variable: form.fields.source_vars.parseTypeName,
field_id: 'group_source_vars', onReady: callback });
}
}
});
if (scope.removeAddTreeRefreshed) {
scope.removeAddTreeRefreshed();
}
@ -586,12 +609,33 @@ angular.module('GroupsHelper', ['RestServices', 'Utilities', 'ListGenerator', 'G
scope.formModalHeader = 'Group';
scope.formModalCancelShow = true;
scope.source = form.fields.source['default'];
scope.parseType = 'yaml';
scope[form.fields.source_vars.parseTypeName] = 'yaml';
scope.sourcePathRequired = false;
ParseTypeChange(scope);
ParseTypeChange(scope, 'source_vars', form.fields.source_vars.parseTypeName);
$('#group_tabs a[data-toggle="tab"]').on('show.bs.tab', function (e) {
var callback = function(){ Wait('stop'); };
if ($(e.target).text() === 'Properties') {
Wait('start');
ParseTypeChange({ scope: scope, field_id: 'group_variables', onReady: callback });
}
else {
if (scope.source && scope.source.value === 'ec2') {
Wait('start');
ParseTypeChange({ scope: scope, variable: 'source_vars', parse_variable: form.fields.source_vars.parseTypeName,
field_id: 'group_source_vars', onReady: callback });
}
}
});
scope[form.fields.source_vars.parseTypeName] = 'yaml';
scope.parseType = 'yaml';
if (scope.groupVariablesLoadedRemove) {
scope.groupVariablesLoadedRemove();
}
scope.groupVariablesLoadedRemove = scope.$on('groupVariablesLoaded', function () {
var callback = function() { Wait('stop'); };
ParseTypeChange({ scope: scope, field_id: 'group_variables', onReady: callback });
});
// After the group record is loaded, retrieve related data
if (scope.groupLoadedRemove) {
@ -608,18 +652,16 @@ angular.module('GroupsHelper', ['RestServices', 'Utilities', 'ListGenerator', 'G
} else {
scope.variables = jsyaml.safeDump(data);
}
Wait('stop');
scope.$emit('groupVariablesLoaded');
})
.error(function (data, status) {
scope.variables = null;
Wait('stop');
ProcessErrors(scope, data, status, form, {
hdr: 'Error!',
msg: 'Failed to retrieve group variables. GET returned status: ' + status
});
ProcessErrors(scope, data, status, form, { hdr: 'Error!',
msg: 'Failed to retrieve group variables. GET returned status: ' + status });
});
} else {
scope.variables = "---";
scope.$emit('groupVariablesLoaded');
}
master.variables = scope.variables;
@ -714,11 +756,10 @@ angular.module('GroupsHelper', ['RestServices', 'Utilities', 'ListGenerator', 'G
}];
}
scope.group_update_url = data.related.update;
Wait('stop');
//Wait('stop');
})
.error(function (data, status) {
scope.source = "";
Wait('stop');
ProcessErrors(scope, data, status, form, { hdr: 'Error!',
msg: 'Failed to retrieve inventory source. GET status: ' + status });
});

View File

@ -336,8 +336,9 @@ function($rootScope, $location, $log, $routeParams, Rest, Alert, HostForm, Gener
scope.formModalActionLabel = 'Save';
scope.formModalHeader = 'Create New Host';
scope.formModalCancelShow = true;
scope.parseType = 'yaml';
ParseTypeChange(scope);
ParseTypeChange({ scope: scope, field_id: 'host_variables' });
if (scope.removeHostsReload) {
scope.removeHostsReload();
@ -466,7 +467,15 @@ function($rootScope, $location, $log, $routeParams, Rest, Alert, HostForm, Gener
scope.formModalHeader = 'Host Properties';
scope.formModalCancelShow = true;
scope.parseType = 'yaml';
ParseTypeChange(scope);
if (scope.hostVariablesLoadedRemove) {
scope.hostVariablesLoadedRemove();
}
scope.hostVariablesLoadedRemove = scope.$on('hostVariablesLoaded', function() {
var callback = function() { Wait('stop'); };
$('#form-modal').modal('show');
ParseTypeChange({ scope: scope, field_id: 'host_variables', onReady: callback });
});
if (scope.hostLoadedRemove) {
scope.hostLoadedRemove();
@ -483,8 +492,7 @@ function($rootScope, $location, $log, $routeParams, Rest, Alert, HostForm, Gener
else {
scope.variables = jsyaml.safeDump(data);
}
Wait('stop');
$('#form-modal').modal('show');
scope.$emit('hostVariablesLoaded');
})
.error( function(data, status) {
scope.variables = null;
@ -494,8 +502,7 @@ function($rootScope, $location, $log, $routeParams, Rest, Alert, HostForm, Gener
}
else {
scope.variables = "---";
Wait('stop');
$('#form-modal').modal('show');
scope.$emit('hostVariablesLoaded');
}
master.variables = scope.variables;
});

View File

@ -3,8 +3,8 @@
*
* ParseHelper
*
* Routines for parsing variable data and toggling
* between JSON and YAML.
* Show the CodeMirror variable editor and allow
* toggle between JSON and YAML
*
*/
@ -12,32 +12,41 @@
angular.module('ParseHelper', ['Utilities', 'AngularCodeMirrorModule'])
.factory('ParseTypeChange', ['Alert', 'AngularCodeMirror', function (Alert, AngularCodeMirror) {
return function (scope, varName, parseTypeName) {
return function (params) {
var scope = params.scope,
field_id = params.field_id,
fld = (params.variable) ? params.variable : 'variables',
pfld = (params.parse_variable) ? params.parse_variable : 'parseType',
onReady = params.onReady,
onChange = params.onChange,
codeMirror;
function removeField() {
//set our model to the last change in CodeMirror and then destroy CodeMirror
scope[fld] = codeMirror.getValue();
codeMirror.destroy();
}
function createField(onChange, onReady) {
//hide the textarea and show a fresh CodeMirror with the current mode (json or yaml)
codeMirror = AngularCodeMirror();
codeMirror.addModes($AnsibleConfig.variable_edit_modes);
codeMirror.showTextArea({ scope: scope, model: fld, element: field_id, mode: scope[pfld], onReady: onReady, onChange: onChange });
}
// Hide the textarea and show a CodeMirror editor
createField(onChange, onReady);
// Toggle displayed variable string between JSON and YAML
var fld = (varName) ? varName : 'variables',
pfld = (parseTypeName) ? parseTypeName : 'parseType',
codeMirror = AngularCodeMirror();
codeMirror.addModes($AnsibleConfig.variable_edit_modes);
scope.showCodeEditor = function() {
var title = 'Edit ' + scope[pfld].toUpperCase(),
container = document.getElementById('main-view');
codeMirror.show({
scope: scope,
container: container,
mode: scope[pfld],
model: fld,
title: title
});
};
scope.parseTypeChange = function() {
var json_obj;
if (scope[pfld] === 'json') {
// converting yaml to json
try {
removeField();
json_obj = jsyaml.load(scope[fld]);
if ($.isEmptyObject(json_obj)) {
scope[fld] = "{}";
@ -45,15 +54,17 @@ angular.module('ParseHelper', ['Utilities', 'AngularCodeMirrorModule'])
else {
scope[fld] = JSON.stringify(json_obj, null, " ");
}
createField();
}
catch (e) {
Alert('Parse Error', 'Failed to parse valid YAML. ' + e.message);
setTimeout( function() { scope.$apply( function() { scope[pfld] = 'yaml'; }); }, 500);
setTimeout( function() { scope.$apply( function() { scope[pfld] = 'yaml'; createField(); }); }, 500);
}
}
else {
// convert json to yaml
try {
removeField();
json_obj = JSON.parse(scope[fld]);
if ($.isEmptyObject(json_obj)) {
scope[fld] = '---';
@ -61,10 +72,11 @@ angular.module('ParseHelper', ['Utilities', 'AngularCodeMirrorModule'])
else {
scope[fld] = jsyaml.safeDump(json_obj);
}
createField();
}
catch (e) {
Alert('Parse Error', 'Failed to parse valid JSON. ' + e.message);
setTimeout( function() { scope.$apply( function() { scope[pfld] = 'json'; }); }, 500 );
setTimeout( function() { scope.$apply( function() { scope[pfld] = 'json'; createField(); }); }, 500 );
}
}
};

View File

@ -8,8 +8,6 @@
*
*/
/* globals console:false */
'use strict';
angular.module('InventoryHelper', ['RestServices', 'Utilities', 'OrganizationListDefinition', 'ListGenerator', 'AuthService',
@ -131,8 +129,14 @@ angular.module('InventoryHelper', ['RestServices', 'Utilities', 'OrganizationLis
/* Reset form properties. Otherwise it screws up future requests of the Inventories detail page */
form.well = true;
ParseTypeChange(scope, 'inventory_variables', 'inventoryParseType');
scope.inventoryParseType = 'yaml';
scope.$on('inventoryPropertiesLoaded', function() {
var callback = function() { Wait('stop'); };
$('#form-modal').modal('show');
scope.inventoryParseType = 'yaml';
ParseTypeChange({ scope: scope, variable: 'inventory_variables', parse_variable: 'inventoryParseType',
field_id: 'inventory_inventory_variables', onReady: callback });
});
scope.formModalActionLabel = 'Save';
scope.formModalCancelShow = true;
scope.formModalInfo = false;
@ -156,11 +160,6 @@ angular.module('InventoryHelper', ['RestServices', 'Utilities', 'OrganizationLis
} catch (err) {
Alert('Variable Parse Error', 'Attempted to parse variables for inventory: ' + inventory_id +
'. Parse returned: ' + err);
if (console) {
console.log(err);
console.log('data:');
console.log(data.variables);
}
scope.inventory_variables = '---';
}
}
@ -193,15 +192,12 @@ angular.module('InventoryHelper', ['RestServices', 'Utilities', 'OrganizationLis
field: 'organization'
});
Wait('stop');
$('#form-modal').modal('show');
scope.$emit('inventoryPropertiesLoaded');
})
.error(function (data, status) {
ProcessErrors(scope, data, status, null, {
hdr: 'Error!',
msg: 'Failed to get inventory: ' + inventory_id + '. GET returned: ' + status
});
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
msg: 'Failed to get inventory: ' + inventory_id + '. GET returned: ' + status });
});
if (scope.removeInventorySaved) {
@ -242,11 +238,9 @@ angular.module('InventoryHelper', ['RestServices', 'Utilities', 'OrganizationLis
};
scope.formModalAction = function () {
parent_scope.inventory_id = inventory_id;
scope.inventory_id = inventory_id;
parent_scope.inventory_name = scope.inventory_name;
SaveInventory({
scope: scope
});
SaveInventory({ scope: scope });
};
};

View File

@ -10,8 +10,8 @@
'use strict';
angular.module('md5Helper', ['RestServices', 'Utilities'])
.factory('md5Setup', [ function () {
angular.module('md5Helper', ['RestServices', 'Utilities', 'angular-md5'])
.factory('md5Setup', ['md5', function (md5) {
return function (params) {
var scope = params.scope,
@ -24,7 +24,7 @@ angular.module('md5Helper', ['RestServices', 'Utilities'])
scope.genMD5 = function (fld) {
var now = new Date();
scope[fld] = $.md5('AnsibleWorks' + now.getTime());
scope[fld] = md5.createHash('AnsibleWorks' + now.getTime());
};
scope.toggleCallback = function (fld) {

View File

@ -8,6 +8,9 @@
.CodeMirror {
height: auto;
overflow-x: scroll;
overflow-y: hidden;
border: 1px solid #ccc;
}
.CodeMirror-activeline-background {

View File

@ -20,6 +20,7 @@
"commit": "94b7aac548b036f4fbd94e56129ed9574e472616"
},
"_source": "git://github.com/chouseknecht/angular-codemirror.git",
"_target": "~1.0.0",
"_originalSource": "angular-codemirror"
"_target": "~1.0.2",
"_originalSource": "angular-codemirror",
"_direct": true
}

View File

@ -32,16 +32,94 @@ angular.module('AngularCodeMirrorModule', [])
.factory('AngularCodeMirror', [ function() {
return function() {
var fn = function() {
this.show = function(params) {
this.myCodeMirror = null;
this.element = null;
this.showTextArea = function(params) {
var self = this,
element = (typeof params.element === "object") ? params.element : document.getElementById(params.element),
scope = params.scope,
model = params.model,
mode = params.mode,
onReady = params.onReady,
onChange = params.onChange,
height = 0;
self.element = $(element);
var scope = params.scope,
// We don't want to touch the original textarea. Angular likely has a model and other listeners
// attached to it. In prior iterations attaching CodeMirror to it seemed to go bad, so we'll insert a
// <div> under it, hide the textarea and let CodeMirror attach to the <div>.
if ($('#cm-' + model + '-container').length > 0) {
$('#cm-' + model + '-container').empty();
}
else {
self.element.after("<div id=\"cm-" + model + "-container\"></div>");
}
// Calc the height of the text area- our CodeMirror should match.
height += self.element.attr('rows') * parseInt($(self.element).css('line-height').replace(/px/,''),10);
height += parseInt(self.element.css('padding-top').replace(/px|%/,''),10) +
parseInt(self.element.css('padding-bottom').replace(/px|%/,''),10);
height += 2; //for the border
// hide
self.element.hide();
// Initialize CodeMirror
self.modes[mode].value = scope[model];
self.myCodeMirror = CodeMirror(document.getElementById('cm-' + model + '-container'), self.modes[mode]);
// Adjust the height
$('.CodeMirror').css({ 'min-height': height, 'max-height': height });
self.myCodeMirror.setSize(null, height);
// This doesn't work without a setTimeout
setTimeout(function() {
self.myCodeMirror.refresh();
if (onReady) {
onReady();
}
}, 500);
// Update the model on change
self.myCodeMirror.on('change', function() {
setTimeout(function() {
scope.$apply(function(){
scope[model] = self.myCodeMirror.getValue();
if (onChange) {
onChange();
}
});
}, 500);
});
};
this.getValue = function() {
var self = this;
return self.myCodeMirror.getValue();
};
this.destroy = function() {
// Intended for use with showTextArea. This will get ride of CM and put the
// textarea back to normal
var self = this;
$('.CodeMirror').empty().remove();
if (self.element) {
self.element.show();
}
};
this.showModal = function(params) {
var self = this,
scope = params.scope,
target = (typeof params.container === "string") ? document.getElementById(params.container) : params.container,
mode = params.mode,
model = params.model,
title = params.title || 'Code Editor',
modes = this.modes,
myCodeMirror;
modes = self.modes;
this.html = "<div id=\"af-code-editor-modal\"><div id=\"af-code\"></div>\n</div>\n";
if ($('#af-code-editor-modal').length === 0) {
@ -66,7 +144,7 @@ angular.module('AngularCodeMirrorModule', [])
{ text: "Cancel", id: "af-code-edit-cancel", click: function() { $(this).dialog('close'); } },
{ text: "OK", id: "af-code-edit-ok", click:
function() {
scope.$apply(function() { scope[model] = myCodeMirror.getValue(); });
scope.$apply(function() { scope[model] = self.myCodeMirror.getValue(); });
$(this).dialog('close');
}
}
@ -87,7 +165,7 @@ angular.module('AngularCodeMirrorModule', [])
// initialize CodeMirror
options = modes[mode];
options.value = scope[model];
myCodeMirror = CodeMirror(document.getElementById('af-code'), options);
self.myCodeMirror = CodeMirror(document.getElementById('af-code'), options);
}
});
};

View File

@ -85,7 +85,7 @@ angular.module('Utilities', ['RestServices', 'Utilities'])
});
$rootScope.disableButtons2 = (disableButtons) ? true : false;
if (action) {
$('#alert-modal2').on('hidden', function () {
$('#alert-modal2').on('hidden.bs.modal', function () {
action();
});
}
@ -107,6 +107,14 @@ angular.module('Utilities', ['RestServices', 'Utilities'])
backdrop: 'static'
});
$('#alert-modal').on('hidden.bs.modal', function () {
console.log('modal closed');
if (action) {
console.log('attempting callback');
action();
}
});
$(document).bind('keydown', function (e) {
if (e.keyCode === 27) {
$('#alert-modal').modal('hide');
@ -117,11 +125,7 @@ angular.module('Utilities', ['RestServices', 'Utilities'])
});
$rootScope.disableButtons = (disableButtons) ? true : false;
if (action) {
$('#alert-modal').on('hidden', function () {
action();
});
}
}
};
}
@ -630,6 +634,7 @@ angular.module('Utilities', ['RestServices', 'Utilities'])
var form = params.form,
scope = params.scope,
fld;
console.log('here');
for (fld in form.fields) {
if (scope[form.name + '_form'][fld]) {
console.log(fld + ' valid: ' + scope[form.name + '_form'][fld].$valid);

View File

@ -688,8 +688,6 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
html += "<input type=\"radio\" ng-model=\"";
html += (field.parseTypeName) ? field.parseTypeName : 'parseType';
html += "\" value=\"json\" ng-change=\"parseTypeChange()\"> <span class=\"parse-label\">JSON</span>\n";
html += "<a class=\"external-editor-link\" ng-click=\"showCodeEditor()\" data-placement=\"top\" " +
"aw-tooltip=\"View in editor\" href=\"\"><i class=\"fa fa-external-link\"></i> Editor</a>";
html += "</div>\n";
}