angular-bootstrap.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. 'use strict';
  2. var directive = {};
  3. directive.dropdownToggle =
  4. ['$document', '$location', '$window',
  5. function ($document, $location, $window) {
  6. var openElement = null, close;
  7. return {
  8. restrict: 'C',
  9. link: function(scope, element, attrs) {
  10. scope.$watch(function dropdownTogglePathWatch(){return $location.path();}, function dropdownTogglePathWatchAction() {
  11. close && close();
  12. });
  13. element.parent().on('click', function(event) {
  14. close && close();
  15. });
  16. element.on('click', function(event) {
  17. event.preventDefault();
  18. event.stopPropagation();
  19. var iWasOpen = false;
  20. if (openElement) {
  21. iWasOpen = openElement === element;
  22. close();
  23. }
  24. if (!iWasOpen){
  25. element.parent().addClass('open');
  26. openElement = element;
  27. close = function (event) {
  28. event && event.preventDefault();
  29. event && event.stopPropagation();
  30. $document.off('click', close);
  31. element.parent().removeClass('open');
  32. close = null;
  33. openElement = null;
  34. }
  35. $document.on('click', close);
  36. }
  37. });
  38. }
  39. };
  40. }];
  41. directive.syntax = function() {
  42. return {
  43. restrict: 'A',
  44. link: function(scope, element, attrs) {
  45. function makeLink(type, text, link, icon) {
  46. return '<a href="' + link + '" class="btn syntax-' + type + '" target="_blank" rel="nofollow">' +
  47. '<span class="' + icon + '"></span> ' + text +
  48. '</a>';
  49. };
  50. var html = '';
  51. var types = {
  52. 'github' : {
  53. text : 'View on Github',
  54. key : 'syntaxGithub',
  55. icon : 'icon-github'
  56. },
  57. 'plunkr' : {
  58. text : 'View on Plunkr',
  59. key : 'syntaxPlunkr',
  60. icon : 'icon-arrow-down'
  61. },
  62. 'jsfiddle' : {
  63. text : 'View on JSFiddle',
  64. key : 'syntaxFiddle',
  65. icon : 'icon-cloud'
  66. }
  67. };
  68. for(var type in types) {
  69. var data = types[type];
  70. var link = attrs[data.key];
  71. if(link) {
  72. html += makeLink(type, data.text, link, data.icon);
  73. }
  74. };
  75. var nav = document.createElement('nav');
  76. nav.className = 'syntax-links';
  77. nav.innerHTML = html;
  78. var node = element[0];
  79. var par = node.parentNode;
  80. par.insertBefore(nav, node);
  81. }
  82. }
  83. }
  84. directive.tabbable = function() {
  85. return {
  86. restrict: 'C',
  87. compile: function(element) {
  88. var navTabs = angular.element('<ul class="nav nav-tabs"></ul>'),
  89. tabContent = angular.element('<div class="tab-content"></div>');
  90. tabContent.append(element.contents());
  91. element.append(navTabs).append(tabContent);
  92. },
  93. controller: ['$scope', '$element', function($scope, $element) {
  94. var navTabs = $element.contents().eq(0),
  95. ngModel = $element.controller('ngModel') || {},
  96. tabs = [],
  97. selectedTab;
  98. ngModel.$render = function() {
  99. var $viewValue = this.$viewValue;
  100. if (selectedTab ? (selectedTab.value != $viewValue) : $viewValue) {
  101. if(selectedTab) {
  102. selectedTab.paneElement.removeClass('active');
  103. selectedTab.tabElement.removeClass('active');
  104. selectedTab = null;
  105. }
  106. if($viewValue) {
  107. for(var i = 0, ii = tabs.length; i < ii; i++) {
  108. if ($viewValue == tabs[i].value) {
  109. selectedTab = tabs[i];
  110. break;
  111. }
  112. }
  113. if (selectedTab) {
  114. selectedTab.paneElement.addClass('active');
  115. selectedTab.tabElement.addClass('active');
  116. }
  117. }
  118. }
  119. };
  120. this.addPane = function(element, attr) {
  121. var li = angular.element('<li><a href></a></li>'),
  122. a = li.find('a'),
  123. tab = {
  124. paneElement: element,
  125. paneAttrs: attr,
  126. tabElement: li
  127. };
  128. tabs.push(tab);
  129. attr.$observe('value', update)();
  130. attr.$observe('title', function(){ update(); a.text(tab.title); })();
  131. function update() {
  132. tab.title = attr.title;
  133. tab.value = attr.value || attr.title;
  134. if (!ngModel.$setViewValue && (!ngModel.$viewValue || tab == selectedTab)) {
  135. // we are not part of angular
  136. ngModel.$viewValue = tab.value;
  137. }
  138. ngModel.$render();
  139. }
  140. navTabs.append(li);
  141. li.on('click', function(event) {
  142. event.preventDefault();
  143. event.stopPropagation();
  144. if (ngModel.$setViewValue) {
  145. $scope.$apply(function() {
  146. ngModel.$setViewValue(tab.value);
  147. ngModel.$render();
  148. });
  149. } else {
  150. // we are not part of angular
  151. ngModel.$viewValue = tab.value;
  152. ngModel.$render();
  153. }
  154. });
  155. return function() {
  156. tab.tabElement.remove();
  157. for(var i = 0, ii = tabs.length; i < ii; i++ ) {
  158. if (tab == tabs[i]) {
  159. tabs.splice(i, 1);
  160. }
  161. }
  162. };
  163. }
  164. }]
  165. };
  166. };
  167. directive.table = function() {
  168. return {
  169. restrict: 'E',
  170. link: function(scope, element, attrs) {
  171. if (!attrs['class']) {
  172. element.addClass('table table-bordered table-striped code-table');
  173. }
  174. }
  175. };
  176. };
  177. var popoverElement = function() {
  178. var object = {
  179. init : function() {
  180. this.element = angular.element(
  181. '<div class="popover popover-incode top">' +
  182. '<div class="arrow"></div>' +
  183. '<div class="popover-inner">' +
  184. '<div class="popover-title"><code></code></div>' +
  185. '<div class="popover-content"></div>' +
  186. '</div>' +
  187. '</div>'
  188. );
  189. this.node = this.element[0];
  190. this.element.css({
  191. 'display':'block',
  192. 'position':'absolute'
  193. });
  194. angular.element(document.body).append(this.element);
  195. var inner = this.element.children()[1];
  196. this.titleElement = angular.element(inner.childNodes[0].firstChild);
  197. this.contentElement = angular.element(inner.childNodes[1]);
  198. //stop the click on the tooltip
  199. this.element.bind('click', function(event) {
  200. event.preventDefault();
  201. event.stopPropagation();
  202. });
  203. var self = this;
  204. angular.element(document.body).bind('click',function(event) {
  205. if(self.visible()) self.hide();
  206. });
  207. },
  208. show : function(x,y) {
  209. this.element.addClass('visible');
  210. this.position(x || 0, y || 0);
  211. },
  212. hide : function() {
  213. this.element.removeClass('visible');
  214. this.position(-9999,-9999);
  215. },
  216. visible : function() {
  217. return this.position().y >= 0;
  218. },
  219. isSituatedAt : function(element) {
  220. return this.besideElement ? element[0] == this.besideElement[0] : false;
  221. },
  222. title : function(value) {
  223. return this.titleElement.html(value);
  224. },
  225. content : function(value) {
  226. if(value && value.length > 0) {
  227. value = marked(value);
  228. }
  229. return this.contentElement.html(value);
  230. },
  231. positionArrow : function(position) {
  232. this.node.className = 'popover ' + position;
  233. },
  234. positionAway : function() {
  235. this.besideElement = null;
  236. this.hide();
  237. },
  238. positionBeside : function(element) {
  239. this.besideElement = element;
  240. var elm = element[0];
  241. var x = elm.offsetLeft;
  242. var y = elm.offsetTop;
  243. x -= 30;
  244. y -= this.node.offsetHeight + 10;
  245. this.show(x,y);
  246. },
  247. position : function(x,y) {
  248. if(x != null && y != null) {
  249. this.element.css('left',x + 'px');
  250. this.element.css('top', y + 'px');
  251. }
  252. else {
  253. return {
  254. x : this.node.offsetLeft,
  255. y : this.node.offsetTop
  256. };
  257. }
  258. }
  259. };
  260. object.init();
  261. object.hide();
  262. return object;
  263. };
  264. directive.popover = ['popoverElement', function(popover) {
  265. return {
  266. restrict: 'A',
  267. priority : 500,
  268. link: function(scope, element, attrs) {
  269. element.bind('click',function(event) {
  270. event.preventDefault();
  271. event.stopPropagation();
  272. if(popover.isSituatedAt(element) && popover.visible()) {
  273. popover.title('');
  274. popover.content('');
  275. popover.positionAway();
  276. }
  277. else {
  278. popover.title(attrs.title);
  279. popover.content(attrs.content);
  280. popover.positionBeside(element);
  281. }
  282. });
  283. }
  284. }
  285. }];
  286. directive.tabPane = function() {
  287. return {
  288. require: '^tabbable',
  289. restrict: 'C',
  290. link: function(scope, element, attrs, tabsCtrl) {
  291. element.on('$remove', tabsCtrl.addPane(element, attrs));
  292. }
  293. };
  294. };
  295. directive.foldout = ['$http', '$animate','$window', function($http, $animate, $window) {
  296. return {
  297. restrict: 'A',
  298. priority : 500,
  299. link: function(scope, element, attrs) {
  300. var container, loading, url = attrs.url;
  301. if(/\/build\//.test($window.location.href)) {
  302. url = '/build/docs' + url;
  303. }
  304. element.bind('click',function() {
  305. scope.$apply(function() {
  306. if(!container) {
  307. if(loading) return;
  308. loading = true;
  309. var par = element.parent();
  310. container = angular.element('<div class="foldout">loading...</div>');
  311. $animate.enter(container, null, par);
  312. $http.get(url, { cache : true }).success(function(html) {
  313. loading = false;
  314. html = '<div class="foldout-inner">' +
  315. '<div calss="foldout-arrow"></div>' +
  316. html +
  317. '</div>';
  318. container.html(html);
  319. //avoid showing the element if the user has already closed it
  320. if(container.css('display') == 'block') {
  321. container.css('display','none');
  322. $animate.addClass(container, 'ng-hide');
  323. }
  324. });
  325. }
  326. else {
  327. container.hasClass('ng-hide') ? $animate.removeClass(container, 'ng-hide') : $animate.addClass(container, 'ng-hide');
  328. }
  329. });
  330. });
  331. }
  332. }
  333. }];
  334. angular.module('bootstrap', [])
  335. .directive(directive)
  336. .factory('popoverElement', popoverElement)
  337. .run(function() {
  338. marked.setOptions({
  339. gfm: true,
  340. tables: true
  341. });
  342. });