diff --git a/awx/ui/static/js/app.js b/awx/ui/static/js/app.js index 4efe1b6f3c..10e184080c 100644 --- a/awx/ui/static/js/app.js +++ b/awx/ui/static/js/app.js @@ -22,6 +22,7 @@ import 'tower/forms'; import 'tower/lists'; import 'tower/widgets'; import 'tower/help'; +import 'tower/filters'; import {Home, HomeGroups, HomeHosts} from 'tower/controllers/Home'; import {SocketsController} from 'tower/controllers/Sockets'; import {Authenticate} from 'tower/controllers/Authentication'; diff --git a/awx/ui/static/js/filters.js b/awx/ui/static/js/filters.js new file mode 100644 index 0000000000..ecf681eeee --- /dev/null +++ b/awx/ui/static/js/filters.js @@ -0,0 +1,5 @@ +import sanitizeFilters from 'tower/filters/sanitize/xss-sanitizer.filter'; + +export { + sanitizeFilters +}; diff --git a/awx/ui/static/js/filters/sanitize/xss-sanitizer.filter.js b/awx/ui/static/js/filters/sanitize/xss-sanitizer.filter.js new file mode 100644 index 0000000000..40689805d1 --- /dev/null +++ b/awx/ui/static/js/filters/sanitize/xss-sanitizer.filter.js @@ -0,0 +1,6 @@ +angular.module('sanitizeFilter', []).filter('sanitize', function() { + return function(input) { + input = input.replace(//g, ">"); + return input; + }; +}); diff --git a/awx/ui/static/js/lists/CompletedJobs.js b/awx/ui/static/js/lists/CompletedJobs.js index 266656dc0d..c3f8d2447d 100644 --- a/awx/ui/static/js/lists/CompletedJobs.js +++ b/awx/ui/static/js/lists/CompletedJobs.js @@ -9,7 +9,7 @@ export default - angular.module('CompletedJobsDefinition', []) + angular.module('CompletedJobsDefinition', ['sanitizeFilter']) .value( 'CompletedJobsList', { name: 'completed_jobs', @@ -71,7 +71,8 @@ export default columnClass: 'col-md-3 col-sm-4 col-xs-4', ngClick: "viewJobLog(completed_job.id, completed_job.nameHref)", defaultSearchField: true, - awToolTipEllipses: "{{ completed_job.name }}" + awToolTip: "{{ completed_job.name | sanitize }}", + dataPlacement: 'top' }, failed: { label: 'Job failed?', diff --git a/awx/ui/static/js/lists/QueuedJobs.js b/awx/ui/static/js/lists/QueuedJobs.js index 91e0cf99e5..00884cddf1 100644 --- a/awx/ui/static/js/lists/QueuedJobs.js +++ b/awx/ui/static/js/lists/QueuedJobs.js @@ -9,7 +9,7 @@ export default - angular.module('QueuedJobsDefinition', []) + angular.module('QueuedJobsDefinition', ['sanitizeFilter']) .value( 'QueuedJobsList', { name: 'queued_jobs', @@ -63,7 +63,8 @@ export default columnClass: 'col-md-3 col-sm-4 col-xs-4', ngClick: "viewJobLog(queued_job.id, queued_job.nameHref)", defaultSearchField: true, - awToolTipEllipses: "{{ queued_job.name }}" + awToolTip: "{{ queued_job.name | sanitize }}", + awTipPlacement: "top" } }, diff --git a/awx/ui/static/js/lists/RunningJobs.js b/awx/ui/static/js/lists/RunningJobs.js index d5dd3c4c73..31bb2f1e3d 100644 --- a/awx/ui/static/js/lists/RunningJobs.js +++ b/awx/ui/static/js/lists/RunningJobs.js @@ -9,7 +9,7 @@ export default - angular.module('RunningJobsDefinition', []) + angular.module('RunningJobsDefinition', ['sanitizeFilter']) .value( 'RunningJobsList', { name: 'running_jobs', @@ -64,7 +64,8 @@ export default columnClass: 'col-md-3 col-sm-4 col-xs-4', ngClick: "viewJobLog(running_job.id, running_job.nameHref)", defaultSearchField: true, - awToolTipEllipses: "{{ running_job.name }}" + awToolTip: "{{ running_job.name | sanitize }}", + awTipPlacement: "top" } }, diff --git a/awx/ui/static/js/lists/ScheduledJobs.js b/awx/ui/static/js/lists/ScheduledJobs.js index e8c8628342..08d470af43 100644 --- a/awx/ui/static/js/lists/ScheduledJobs.js +++ b/awx/ui/static/js/lists/ScheduledJobs.js @@ -9,7 +9,7 @@ export default - angular.module('ScheduledJobsDefinition', []) + angular.module('ScheduledJobsDefinition', ['sanitizeFilter']) .value( 'ScheduledJobsList', { name: 'schedules', @@ -62,7 +62,7 @@ export default sourceModel: 'unified_job_template', sourceField: 'name', ngClick: "editSchedule(schedule.id)", - awToolTip: "{{ schedule.nameTip }}", + awToolTip: "{{ schedule.nameTip | sanitize}}", dataPlacement: "top", defaultSearchField: true } diff --git a/awx/ui/static/js/shared/directives.js b/awx/ui/static/js/shared/directives.js index c131dc1a1f..93b27bdd51 100644 --- a/awx/ui/static/js/shared/directives.js +++ b/awx/ui/static/js/shared/directives.js @@ -402,7 +402,7 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job * Include the standard TB data-XXX attributes to controll a tooltip's appearance. We will * default placement to the left and delay to the config setting. */ - .directive('awToolTip', ['$sce', function($sce) { + .directive('awToolTip', [ function() { return { link: function(scope, element, attrs) { var delay = (attrs.delay !== undefined && attrs.delay !== null) ? attrs.delay : ($AnsibleConfig) ? $AnsibleConfig.tooltip_delay : {show: 500, hide: 100}, @@ -423,67 +423,25 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job }); }); - attrs.awToolTip = attrs.awToolTip.replace(//g, ">"); - attrs.awToolTip = $sce.getTrustedHtml(attrs.awToolTip); - $(element).tooltip({ - placement: placement, - delay: delay, - html: true, - title: attrs.awToolTip, - container: 'body', - trigger: 'hover focus' - }); - - if (attrs.tipWatch) { - // Add dataTipWatch: 'variable_name' - scope.$watch(attrs.tipWatch, function(newVal, oldVal) { - if (newVal !== oldVal) { - // Where did fixTitle come from?: - // http://stackoverflow.com/questions/9501921/change-twitter-bootstrap-tooltip-content-on-click - $(element).tooltip('hide').attr('data-original-title', newVal).tooltip('fixTitle'); - } - }); - } - } - }; - }]) - - /* - * This is a copy of awToolTip currently. - * TODO: only display these tool tips if the length of the anchor *as interpolated* to be larger than the table cell - */ - .directive('awToolTipEllipses', [ function() { - return { - link: function(scope, element, attrs) { - - var delay = (attrs.delay !== undefined && attrs.delay !== null) ? attrs.delay : ($AnsibleConfig) ? $AnsibleConfig.tooltip_delay : {show: 500, hide: 100}, - placement; - - if (attrs.awTipPlacement) { - placement = attrs.awTipPlacement; - } - else { - placement = (attrs.placement !== undefined && attrs.placement !== null) ? attrs.placement : 'left'; - } - - $(element).on('hidden.bs.tooltip', function( ) { - // TB3RC1 is leaving behind tooltip
elements. This will remove them - // after a tooltip fades away. If not, they lay overtop of other elements and - // honk up the page. - $('.tooltip').each(function() { - $(this).remove(); - }); - }); - $(element).tooltip({ placement: placement, delay: delay, html: true, - title: attrs.awToolTipEllipses, + title: attrs.awToolTip, container: 'body', trigger: 'hover focus' }); + + if (attrs.tipWatch) { + // Add dataTipWatch: 'variable_name' + scope.$watch(attrs.tipWatch, function(newVal, oldVal) { + if (newVal !== oldVal) { + // Where did fixTitle come from?: + // http://stackoverflow.com/questions/9501921/change-twitter-bootstrap-tooltip-content-on-click + $(element).tooltip('hide').attr('data-original-title', newVal).tooltip('fixTitle'); + } + }); + } } }; }]) diff --git a/awx/ui/static/js/shared/generator-helpers.js b/awx/ui/static/js/shared/generator-helpers.js index 25f7324833..fdb584cd8b 100644 --- a/awx/ui/static/js/shared/generator-helpers.js +++ b/awx/ui/static/js/shared/generator-helpers.js @@ -442,12 +442,6 @@ angular.module('GeneratorHelpers', [systemStatus.name]) html += (field.dataTipWatch) ? Attr(field, 'dataTipWatch') : ""; html += (field.awTipPlacement) ? Attr(field, 'awTipPlacement') : ""; } - if (field.awToolTipEllipses) { - html += Attr(field, 'awToolTipEllipses'); - html += (field.dataPlacement && !field.awPopOver) ? Attr(field, 'dataPlacement') : ""; - html += (field.dataTipWatch) ? Attr(field, 'dataTipWatch') : ""; - html += (field.awTipPlacement) ? Attr(field, 'awTipPlacement') : ""; - } if (field.awPopOver) { html += "aw-pop-over=\"" + field.awPopOver + "\" "; html += (field.dataPlacement) ? "data-placement=\"" + field.dataPlacement + "\" " : "";