angular-bootstrap-prettify.js 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. 'use strict';
  2. var directive = {};
  3. var service = { value: {} };
  4. var DEPENDENCIES = {
  5. 'angular.js': 'http://code.angularjs.org/' + angular.version.full + '/angular.min.js',
  6. 'angular-resource.js': 'http://code.angularjs.org/' + angular.version.full + '/angular-resource.min.js',
  7. 'angular-route.js': 'http://code.angularjs.org/' + angular.version.full + '/angular-route.min.js',
  8. 'angular-animate.js': 'http://code.angularjs.org/' + angular.version.full + '/angular-animate.min.js',
  9. 'angular-sanitize.js': 'http://code.angularjs.org/' + angular.version.full + '/angular-sanitize.min.js',
  10. 'angular-cookies.js': 'http://code.angularjs.org/' + angular.version.full + '/angular-cookies.min.js'
  11. };
  12. function escape(text) {
  13. return text.
  14. replace(/\&/g, '&').
  15. replace(/\</g, '&lt;').
  16. replace(/\>/g, '&gt;').
  17. replace(/"/g, '&quot;');
  18. }
  19. /**
  20. * http://stackoverflow.com/questions/451486/pre-tag-loses-line-breaks-when-setting-innerhtml-in-ie
  21. * http://stackoverflow.com/questions/195363/inserting-a-newline-into-a-pre-tag-ie-javascript
  22. */
  23. function setHtmlIe8SafeWay(element, html) {
  24. var newElement = angular.element('<pre>' + html + '</pre>');
  25. element.empty();
  26. element.append(newElement.contents());
  27. return element;
  28. }
  29. directive.jsFiddle = function(getEmbeddedTemplate, escape, script) {
  30. return {
  31. terminal: true,
  32. link: function(scope, element, attr) {
  33. var name = '',
  34. stylesheet = '<link rel="stylesheet" href="http://twitter.github.com/bootstrap/assets/css/bootstrap.css">\n',
  35. fields = {
  36. html: '',
  37. css: '',
  38. js: ''
  39. };
  40. angular.forEach(attr.jsFiddle.split(' '), function(file, index) {
  41. var fileType = file.split('.')[1];
  42. if (fileType == 'html') {
  43. if (index == 0) {
  44. fields[fileType] +=
  45. '<div ng-app' + (attr.module ? '="' + attr.module + '"' : '') + '>\n' +
  46. getEmbeddedTemplate(file, 2);
  47. } else {
  48. fields[fileType] += '\n\n\n <!-- CACHE FILE: ' + file + ' -->\n' +
  49. ' <script type="text/ng-template" id="' + file + '">\n' +
  50. getEmbeddedTemplate(file, 4) +
  51. ' </script>\n';
  52. }
  53. } else {
  54. fields[fileType] += getEmbeddedTemplate(file) + '\n';
  55. }
  56. });
  57. fields.html += '</div>\n';
  58. setHtmlIe8SafeWay(element,
  59. '<form class="jsfiddle" method="post" action="http://jsfiddle.net/api/post/library/pure/" target="_blank">' +
  60. hiddenField('title', 'AngularJS Example: ' + name) +
  61. hiddenField('css', '</style> <!-- Ugly Hack due to jsFiddle issue: http://goo.gl/BUfGZ --> \n' +
  62. stylesheet +
  63. script.angular +
  64. (attr.resource ? script.resource : '') +
  65. '<style>\n' +
  66. fields.css) +
  67. hiddenField('html', fields.html) +
  68. hiddenField('js', fields.js) +
  69. '<button class="btn btn-primary"><i class="icon-white icon-pencil"></i> Edit Me</button>' +
  70. '</form>');
  71. function hiddenField(name, value) {
  72. return '<input type="hidden" name="' + name + '" value="' + escape(value) + '">';
  73. }
  74. }
  75. }
  76. };
  77. directive.code = function() {
  78. return {restrict: 'E', terminal: true};
  79. };
  80. directive.prettyprint = ['reindentCode', function(reindentCode) {
  81. return {
  82. restrict: 'C',
  83. compile: function(element) {
  84. var html = element.html();
  85. //ensure that angular won't compile {{ curly }} values
  86. html = html.replace(/\{\{/g, '<span>{{</span>')
  87. .replace(/\}\}/g, '<span>}}</span>');
  88. if (window.RUNNING_IN_NG_TEST_RUNNER) {
  89. element.html(html);
  90. }
  91. else {
  92. element.html(window.prettyPrintOne(reindentCode(html), undefined, true));
  93. }
  94. }
  95. };
  96. }];
  97. directive.ngSetText = ['getEmbeddedTemplate', function(getEmbeddedTemplate) {
  98. return {
  99. restrict: 'CA',
  100. priority: 10,
  101. compile: function(element, attr) {
  102. setHtmlIe8SafeWay(element, escape(getEmbeddedTemplate(attr.ngSetText)));
  103. }
  104. }
  105. }]
  106. directive.ngHtmlWrap = ['reindentCode', 'templateMerge', function(reindentCode, templateMerge) {
  107. return {
  108. compile: function(element, attr) {
  109. var properties = {
  110. head: '',
  111. module: '',
  112. body: element.text()
  113. },
  114. html = "<!doctype html>\n<html ng-app{{module}}>\n <head>\n{{head:4}} </head>\n <body>\n{{body:4}} </body>\n</html>";
  115. angular.forEach((attr.ngHtmlWrap || '').split(' '), function(dep) {
  116. if (!dep) return;
  117. dep = DEPENDENCIES[dep] || dep;
  118. var ext = dep.split(/\./).pop();
  119. if (ext == 'css') {
  120. properties.head += '<link rel="stylesheet" href="' + dep + '" type="text/css">\n';
  121. } else if(ext == 'js') {
  122. properties.head += '<script src="' + dep + '"></script>\n';
  123. } else {
  124. properties.module = '="' + dep + '"';
  125. }
  126. });
  127. setHtmlIe8SafeWay(element, escape(templateMerge(html, properties)));
  128. }
  129. }
  130. }];
  131. directive.ngSetHtml = ['getEmbeddedTemplate', function(getEmbeddedTemplate) {
  132. return {
  133. restrict: 'CA',
  134. priority: 10,
  135. compile: function(element, attr) {
  136. setHtmlIe8SafeWay(element, getEmbeddedTemplate(attr.ngSetHtml));
  137. }
  138. }
  139. }];
  140. directive.ngEvalJavascript = ['getEmbeddedTemplate', function(getEmbeddedTemplate) {
  141. return {
  142. compile: function (element, attr) {
  143. var fileNames = attr.ngEvalJavascript.split(' ');
  144. angular.forEach(fileNames, function(fileName) {
  145. var script = getEmbeddedTemplate(fileName);
  146. try {
  147. if (window.execScript) { // IE
  148. window.execScript(script || '""'); // IE complains when evaling empty string
  149. } else {
  150. window.eval(script + '//@ sourceURL=' + fileName);
  151. }
  152. } catch (e) {
  153. if (window.console) {
  154. window.console.log(script, '\n', e);
  155. } else {
  156. window.alert(e);
  157. }
  158. }
  159. });
  160. }
  161. };
  162. }];
  163. directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location', '$sniffer', '$exceptionHandler',
  164. function($templateCache, $browser, docsRootScope, $location, $sniffer, $exceptionHandler) {
  165. return {
  166. terminal: true,
  167. link: function(scope, element, attrs) {
  168. var modules = ['ngAnimate'],
  169. embedRootScope,
  170. deregisterEmbedRootScope;
  171. modules.push(['$provide', function($provide) {
  172. $provide.value('$templateCache', $templateCache);
  173. $provide.value('$anchorScroll', angular.noop);
  174. $provide.value('$browser', $browser);
  175. $provide.value('$sniffer', $sniffer);
  176. $provide.provider('$location', function() {
  177. this.$get = ['$rootScope', function($rootScope) {
  178. docsRootScope.$on('$locationChangeSuccess', function(event, oldUrl, newUrl) {
  179. $rootScope.$broadcast('$locationChangeSuccess', oldUrl, newUrl);
  180. });
  181. return $location;
  182. }];
  183. this.html5Mode = angular.noop;
  184. this.hashPrefix = function () {
  185. return '';
  186. };
  187. });
  188. $provide.decorator('$rootScope', ['$delegate', function($delegate) {
  189. embedRootScope = $delegate;
  190. // Since we are teleporting the $animate service, which relies on the $$postDigestQueue
  191. // we need the embedded scope to use the same $$postDigestQueue as the outer scope
  192. function docsRootDigest() {
  193. var postDigestQueue = docsRootScope.$$postDigestQueue;
  194. while (postDigestQueue.length) {
  195. try {
  196. postDigestQueue.shift()();
  197. } catch (e) {
  198. $exceptionHandler(e);
  199. }
  200. }
  201. }
  202. embedRootScope.$watch(function () {
  203. embedRootScope.$$postDigest(docsRootDigest);
  204. })
  205. deregisterEmbedRootScope = docsRootScope.$watch(function embedRootScopeDigestWatch() {
  206. embedRootScope.$digest();
  207. });
  208. return embedRootScope;
  209. }]);
  210. }]);
  211. if (attrs.ngEmbedApp) modules.push(attrs.ngEmbedApp);
  212. element.on('click', function(event) {
  213. if (event.target.attributes.getNamedItem('ng-click')) {
  214. event.preventDefault();
  215. }
  216. });
  217. element.bind('$destroy', function() {
  218. if (deregisterEmbedRootScope) {
  219. deregisterEmbedRootScope();
  220. }
  221. if (embedRootScope) {
  222. embedRootScope.$destroy();
  223. }
  224. });
  225. element.data('$injector', null);
  226. angular.bootstrap(element, modules);
  227. }
  228. };
  229. }];
  230. service.reindentCode = function() {
  231. return function (text, spaces) {
  232. if (!text) return text;
  233. var lines = text.split(/\r?\n/);
  234. var prefix = ' '.substr(0, spaces || 0);
  235. var i;
  236. // remove any leading blank lines
  237. while (lines.length && lines[0].match(/^\s*$/)) lines.shift();
  238. // remove any trailing blank lines
  239. while (lines.length && lines[lines.length - 1].match(/^\s*$/)) lines.pop();
  240. var minIndent = 999;
  241. for (i = 0; i < lines.length; i++) {
  242. var line = lines[0];
  243. var reindentCode = line.match(/^\s*/)[0];
  244. if (reindentCode !== line && reindentCode.length < minIndent) {
  245. minIndent = reindentCode.length;
  246. }
  247. }
  248. for (i = 0; i < lines.length; i++) {
  249. lines[i] = prefix + lines[i].substring(minIndent);
  250. }
  251. lines.push('');
  252. return lines.join('\n');
  253. }
  254. };
  255. service.templateMerge = ['reindentCode', function(indentCode) {
  256. return function(template, properties) {
  257. return template.replace(/\{\{(\w+)(?:\:(\d+))?\}\}/g, function(_, key, indent) {
  258. var value = properties[key];
  259. if (indent) {
  260. value = indentCode(value, indent);
  261. }
  262. return value == undefined ? '' : value;
  263. });
  264. };
  265. }];
  266. service.getEmbeddedTemplate = ['reindentCode', function(reindentCode) {
  267. return function (id) {
  268. var element = document.getElementById(id);
  269. if (!element) {
  270. return null;
  271. }
  272. return reindentCode(angular.element(element).html(), 0);
  273. }
  274. }];
  275. angular.module('bootstrapPrettify', []).directive(directive).factory(service);