newfilemenu.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /*
  2. * Copyright (c) 2014
  3. *
  4. * This file is licensed under the Affero General Public License version 3
  5. * or later.
  6. *
  7. * See the COPYING-README file.
  8. *
  9. */
  10. /* global Files */
  11. (function() {
  12. /**
  13. * Construct a new NewFileMenu instance
  14. * @constructs NewFileMenu
  15. *
  16. * @memberof OCA.Files
  17. */
  18. var NewFileMenu = OC.Backbone.View.extend({
  19. tagName: 'div',
  20. // Menu is opened by default because it's rendered on "add-button" click
  21. className: 'newFileMenu popovermenu bubble menu open menu-left',
  22. events: {
  23. 'click .menuitem': '_onClickAction'
  24. },
  25. /**
  26. * @type OCA.Files.FileList
  27. */
  28. fileList: null,
  29. initialize: function(options) {
  30. var self = this;
  31. var $uploadEl = $('#file_upload_start');
  32. if ($uploadEl.length) {
  33. $uploadEl.on('fileuploadstart', function() {
  34. self.trigger('actionPerformed', 'upload');
  35. });
  36. } else {
  37. console.warn('Missing upload element "file_upload_start"');
  38. }
  39. this.fileList = options && options.fileList;
  40. this._menuItems = [{
  41. id: 'folder',
  42. displayName: t('files', 'New folder'),
  43. templateName: t('files', 'New folder'),
  44. iconClass: 'icon-folder',
  45. fileType: 'folder',
  46. actionHandler: function(name) {
  47. self.fileList.createDirectory(name);
  48. }
  49. }];
  50. OC.Plugins.attach('OCA.Files.NewFileMenu', this);
  51. },
  52. template: function(data) {
  53. return OCA.Files.Templates['newfilemenu'](data);
  54. },
  55. /**
  56. * Event handler whenever an action has been clicked within the menu
  57. *
  58. * @param {Object} event event object
  59. */
  60. _onClickAction: function(event) {
  61. var $target = $(event.target);
  62. if (!$target.hasClass('menuitem')) {
  63. $target = $target.closest('.menuitem');
  64. }
  65. var action = $target.attr('data-action');
  66. // note: clicking the upload label will automatically
  67. // set the focus on the "file_upload_start" hidden field
  68. // which itself triggers the upload dialog.
  69. // Currently the upload logic is still in file-upload.js and filelist.js
  70. if (action === 'upload') {
  71. OC.hideMenus();
  72. } else {
  73. event.preventDefault();
  74. this.$el.find('.menuitem.active').removeClass('active');
  75. $target.addClass('active');
  76. this._promptFileName($target);
  77. }
  78. },
  79. _promptFileName: function($target) {
  80. var self = this;
  81. if ($target.find('form').length) {
  82. $target.find('input[type=\'text\']').focus();
  83. return;
  84. }
  85. // discard other forms
  86. this.$el.find('form').remove();
  87. this.$el.find('.displayname').removeClass('hidden');
  88. $target.find('.displayname').addClass('hidden');
  89. var newName = $target.attr('data-templatename');
  90. var fileType = $target.attr('data-filetype');
  91. var $form = $(OCA.Files.Templates['newfilemenu_filename_form']({
  92. fileName: newName,
  93. cid: this.cid,
  94. fileType: fileType
  95. }));
  96. //this.trigger('actionPerformed', action);
  97. $target.append($form);
  98. // here comes the OLD code
  99. var $input = $form.find('input[type=\'text\']');
  100. var $submit = $form.find('input[type=\'submit\']');
  101. var lastPos;
  102. var checkInput = function () {
  103. var filename = $input.val();
  104. try {
  105. if (!Files.isFileNameValid(filename)) {
  106. // Files.isFileNameValid(filename) throws an exception itself
  107. } else if (self.fileList.inList(filename)) {
  108. throw t('files', '{newName} already exists', {newName: filename}, undefined, {
  109. escape: false
  110. });
  111. } else {
  112. return true;
  113. }
  114. } catch (error) {
  115. $input.attr('title', error);
  116. $input.tooltip({placement: 'right', trigger: 'manual', 'container': '.newFileMenu'});
  117. $input.tooltip('fixTitle');
  118. $input.tooltip('show');
  119. $input.addClass('error');
  120. }
  121. return false;
  122. };
  123. // verify filename on typing
  124. $input.keyup(function() {
  125. if (checkInput()) {
  126. $input.tooltip('hide');
  127. $input.removeClass('error');
  128. }
  129. });
  130. $submit.click(function(event) {
  131. event.stopPropagation();
  132. event.preventDefault();
  133. $form.submit();
  134. });
  135. $input.focus();
  136. // pre select name up to the extension
  137. lastPos = newName.lastIndexOf('.');
  138. if (lastPos === -1) {
  139. lastPos = newName.length;
  140. }
  141. $input.selectRange(0, lastPos);
  142. $form.submit(function(event) {
  143. event.stopPropagation();
  144. event.preventDefault();
  145. if (checkInput()) {
  146. var newname = $input.val().trim();
  147. /* Find the right actionHandler that should be called.
  148. * Actions is retrieved by using `actionSpec.id` */
  149. var action = _.filter(self._menuItems, function(item) {
  150. return item.id == $target.attr('data-action');
  151. }).pop();
  152. action.actionHandler(newname);
  153. $form.remove();
  154. $target.find('.displayname').removeClass('hidden');
  155. OC.hideMenus();
  156. }
  157. });
  158. },
  159. /**
  160. * Add a new item menu entry in the “New” file menu (in
  161. * last position). By clicking on the item, the
  162. * `actionHandler` function is called.
  163. *
  164. * @param {Object} actionSpec item’s properties
  165. */
  166. addMenuEntry: function(actionSpec) {
  167. this._menuItems.push({
  168. id: actionSpec.id,
  169. displayName: actionSpec.displayName,
  170. templateName: actionSpec.templateName,
  171. iconClass: actionSpec.iconClass,
  172. fileType: actionSpec.fileType,
  173. actionHandler: actionSpec.actionHandler,
  174. });
  175. },
  176. /**
  177. * Renders the menu with the currently set items
  178. */
  179. render: function() {
  180. this.$el.html(this.template({
  181. uploadMaxHumanFileSize: 'TODO',
  182. uploadLabel: t('files', 'Upload file'),
  183. items: this._menuItems
  184. }));
  185. // Trigger upload action also with keyboard navigation on enter
  186. this.$el.find('[for="file_upload_start"]').on('keyup', function(event) {
  187. if (event.key === " " || event.key === "Enter") {
  188. $('#file_upload_start').trigger('click');
  189. }
  190. });
  191. },
  192. /**
  193. * Displays the menu under the given element
  194. *
  195. * @param {Object} $target target element
  196. */
  197. showAt: function($target) {
  198. this.render();
  199. OC.showMenu(null, this.$el);
  200. }
  201. });
  202. OCA.Files.NewFileMenu = NewFileMenu;
  203. })();