angular.module('errors', ['ngSanitize']) .filter('errorLink', ['$sanitize', function ($sanitize) { var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s\.\;\,\(\)\{\}<>]/g, MAILTO_REGEXP = /^mailto:/, STACK_TRACE_REGEXP = /:\d+:\d+$/; var truncate = function (text, nchars) { if (text.length > nchars) { return text.substr(0, nchars - 3) + '...'; } return text; }; return function (text, target) { var targetHtml = target ? ' target="' + target + '"' : ''; if (!text) return text; return $sanitize(text.replace(LINKY_URL_REGEXP, function (url) { if (STACK_TRACE_REGEXP.test(url)) { return url; } // if we did not match ftp/http/mailto then assume mailto if (!/^((ftp|https?):\/\/|mailto:)/.test(url)) url = 'mailto:' + url; return '' + truncate(url.replace(MAILTO_REGEXP, ''), 60) + ''; })); }; }]) .directive('errorDisplay', ['$location', 'errorLinkFilter', function ($location, errorLinkFilter) { var interpolate = function (formatString) { var formatArgs = arguments; return formatString.replace(/\{\d+\}/g, function (match) { // Drop the braces and use the unary plus to convert to an integer. // The index will be off by one because of the formatString. var index = +match.slice(1, -1); if (index + 1 >= formatArgs.length) { return match; } return formatArgs[index+1]; }); }; return { link: function (scope, element, attrs) { var search = $location.search(), formatArgs = [attrs.errorDisplay], i; for (i = 0; angular.isDefined(search['p'+i]); i++) { formatArgs.push(search['p'+i]); } element.html(errorLinkFilter(interpolate.apply(null, formatArgs), '_blank')); } }; }]);