You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

breadcrumb.js 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /**
  2. * ownCloud
  3. *
  4. * @author Vincent Petry
  5. * @copyright 2014 Vincent Petry <pvince81@owncloud.com>
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  9. * License as published by the Free Software Foundation; either
  10. * version 3 of the License, or any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public
  18. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  19. *
  20. */
  21. /* global OC */
  22. (function() {
  23. /**
  24. * Creates an breadcrumb element in the given container
  25. */
  26. var BreadCrumb = function(options){
  27. this.$el = $('<div class="breadcrumb"></div>');
  28. options = options || {};
  29. if (options.onClick) {
  30. this.onClick = options.onClick;
  31. }
  32. if (options.onDrop) {
  33. this.onDrop = options.onDrop;
  34. }
  35. if (options.getCrumbUrl) {
  36. this.getCrumbUrl = options.getCrumbUrl;
  37. }
  38. };
  39. BreadCrumb.prototype = {
  40. $el: null,
  41. dir: null,
  42. lastWidth: 0,
  43. hiddenBreadcrumbs: 0,
  44. totalWidth: 0,
  45. breadcrumbs: [],
  46. onClick: null,
  47. onDrop: null,
  48. /**
  49. * Sets the directory to be displayed as breadcrumb.
  50. * This will re-render the breadcrumb.
  51. * @param dir path to be displayed as breadcrumb
  52. */
  53. setDirectory: function(dir) {
  54. dir = dir || '/';
  55. if (dir !== this.dir) {
  56. this.dir = dir;
  57. this.render();
  58. }
  59. },
  60. /**
  61. * Returns the full URL to the given directory
  62. * @param part crumb data as map
  63. * @param index crumb index
  64. * @return full URL
  65. */
  66. getCrumbUrl: function(part, index) {
  67. return '#';
  68. },
  69. /**
  70. * Renders the breadcrumb elements
  71. */
  72. render: function() {
  73. var parts = this._makeCrumbs(this.dir || '/');
  74. var $crumb;
  75. this.$el.empty();
  76. this.breadcrumbs = [];
  77. for (var i = 0; i < parts.length; i++) {
  78. var part = parts[i];
  79. var $image;
  80. var $link = $('<a></a>').attr('href', this.getCrumbUrl(part, i));
  81. $link.text(part.name);
  82. $crumb = $('<div class="crumb svg"></div>');
  83. $crumb.append($link);
  84. $crumb.attr('data-dir', part.dir);
  85. if (part.img) {
  86. $image = $('<img class="svg"></img>');
  87. $image.attr('src', part.img);
  88. $link.append($image);
  89. }
  90. this.breadcrumbs.push($crumb);
  91. this.$el.append($crumb);
  92. if (this.onClick) {
  93. $crumb.on('click', this.onClick);
  94. }
  95. }
  96. $crumb.addClass('last');
  97. // in case svg is not supported by the browser we need to execute the fallback mechanism
  98. if (!OC.Util.hasSVGSupport()) {
  99. OC.Util.replaceSVG(this.$el);
  100. }
  101. // setup drag and drop
  102. if (this.onDrop) {
  103. this.$el.find('.crumb:not(.last)').droppable({
  104. drop: this.onDrop,
  105. tolerance: 'pointer'
  106. });
  107. }
  108. this._updateTotalWidth();
  109. this.resize($(window).width(), true);
  110. },
  111. /**
  112. * Makes a breadcrumb structure based on the given path
  113. * @param dir path to split into a breadcrumb structure
  114. * @return array of map {dir: path, name: displayName}
  115. */
  116. _makeCrumbs: function(dir) {
  117. var crumbs = [];
  118. var pathToHere = '';
  119. // trim leading and trailing slashes
  120. dir = dir.replace(/^\/+|\/+$/g, '');
  121. var parts = dir.split('/');
  122. if (dir === '') {
  123. parts = [];
  124. }
  125. // root part
  126. crumbs.push({
  127. dir: '/',
  128. name: '',
  129. img: OC.imagePath('core', 'places/home.svg')
  130. });
  131. for (var i = 0; i < parts.length; i++) {
  132. var part = parts[i];
  133. pathToHere = pathToHere + '/' + part;
  134. crumbs.push({
  135. dir: pathToHere,
  136. name: part
  137. });
  138. }
  139. return crumbs;
  140. },
  141. _updateTotalWidth: function () {
  142. var self = this;
  143. this.lastWidth = 0;
  144. // initialize with some extra space
  145. this.totalWidth = 64;
  146. // FIXME: this class should not know about global elements
  147. if ( $('#navigation').length ) {
  148. this.totalWidth += $('#navigation').get(0).offsetWidth;
  149. }
  150. this.hiddenBreadcrumbs = 0;
  151. for (var i = 0; i < this.breadcrumbs.length; i++ ) {
  152. this.totalWidth += $(this.breadcrumbs[i]).get(0).offsetWidth;
  153. }
  154. $.each($('#controls .actions>div'), function(index, action) {
  155. self.totalWidth += $(action).get(0).offsetWidth;
  156. });
  157. },
  158. /**
  159. * Show/hide breadcrumbs to fit the given width
  160. */
  161. resize: function (width, firstRun) {
  162. var i, $crumb;
  163. if (width === this.lastWidth) {
  164. return;
  165. }
  166. // window was shrinked since last time or first run ?
  167. if ((width < this.lastWidth || firstRun) && width < this.totalWidth) {
  168. if (this.hiddenBreadcrumbs === 0 && this.breadcrumbs.length > 1) {
  169. // start by hiding the first breadcrumb after home,
  170. // that one will have extra three dots displayed
  171. $crumb = this.breadcrumbs[1];
  172. this.totalWidth -= $crumb.get(0).offsetWidth;
  173. $crumb.find('a').addClass('hidden');
  174. $crumb.append('<span class="ellipsis">...</span>');
  175. this.totalWidth += $crumb.get(0).offsetWidth;
  176. this.hiddenBreadcrumbs = 2;
  177. }
  178. i = this.hiddenBreadcrumbs;
  179. // hide subsequent breadcrumbs if the space is still not enough
  180. while (width < this.totalWidth && i > 1 && i < this.breadcrumbs.length - 1) {
  181. $crumb = this.breadcrumbs[i];
  182. this.totalWidth -= $crumb.get(0).offsetWidth;
  183. $crumb.addClass('hidden');
  184. this.hiddenBreadcrumbs = i;
  185. i++;
  186. }
  187. // window is bigger than last time
  188. } else if (width > this.lastWidth && this.hiddenBreadcrumbs > 0) {
  189. i = this.hiddenBreadcrumbs;
  190. while (width > this.totalWidth && i > 0) {
  191. if (this.hiddenBreadcrumbs === 1) {
  192. // special handling for last one as it has the three dots
  193. $crumb = this.breadcrumbs[1];
  194. if ($crumb) {
  195. this.totalWidth -= $crumb.get(0).offsetWidth;
  196. $crumb.find('.ellipsis').remove();
  197. $crumb.find('a').removeClass('hidden');
  198. this.totalWidth += $crumb.get(0).offsetWidth;
  199. }
  200. } else {
  201. $crumb = this.breadcrumbs[i];
  202. $crumb.removeClass('hidden');
  203. this.totalWidth += $crumb.get(0).offsetWidth;
  204. if (this.totalWidth > width) {
  205. this.totalWidth -= $crumb.get(0).offsetWidth;
  206. $crumb.addClass('hidden');
  207. break;
  208. }
  209. }
  210. i--;
  211. this.hiddenBreadcrumbs = i;
  212. }
  213. }
  214. this.lastWidth = width;
  215. }
  216. };
  217. window.BreadCrumb = BreadCrumb;
  218. })();