1
0

newfilemenu.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  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. var actionItem = _.filter(this._menuItems, function(item) {
  74. return item.id === action
  75. }).pop();
  76. if (typeof actionItem.useInput === 'undefined' || actionItem.useInput === true) {
  77. event.preventDefault();
  78. this.$el.find('.menuitem.active').removeClass('active');
  79. $target.addClass('active');
  80. this._promptFileName($target);
  81. } else {
  82. actionItem.actionHandler();
  83. OC.hideMenus();
  84. }
  85. }
  86. },
  87. _promptFileName: function($target) {
  88. var self = this;
  89. if ($target.find('form').length) {
  90. $target.find('input[type=\'text\']').focus();
  91. return;
  92. }
  93. // discard other forms
  94. this.$el.find('form').remove();
  95. this.$el.find('.displayname').removeClass('hidden');
  96. $target.find('.displayname').addClass('hidden');
  97. var newName = $target.attr('data-templatename');
  98. var fileType = $target.attr('data-filetype');
  99. var $form = $(OCA.Files.Templates['newfilemenu_filename_form']({
  100. fileName: newName,
  101. cid: this.cid,
  102. fileType: fileType
  103. }));
  104. //this.trigger('actionPerformed', action);
  105. $target.append($form);
  106. // here comes the OLD code
  107. var $input = $form.find('input[type=\'text\']');
  108. var $submit = $form.find('input[type=\'submit\']');
  109. var lastPos;
  110. var checkInput = function () {
  111. // Special handling for the setup template directory
  112. if ($target.attr('data-action') === 'template-init') {
  113. return true;
  114. }
  115. var filename = $input.val();
  116. try {
  117. if (!Files.isFileNameValid(filename)) {
  118. // Files.isFileNameValid(filename) throws an exception itself
  119. } else if (self.fileList.inList(filename)) {
  120. throw t('files', '{newName} already exists', {newName: filename}, undefined, {
  121. escape: false
  122. });
  123. } else {
  124. return true;
  125. }
  126. } catch (error) {
  127. $input.attr('title', error);
  128. $input.addClass('error');
  129. }
  130. return false;
  131. };
  132. // verify filename on typing
  133. $input.keyup(function() {
  134. if (checkInput()) {
  135. $input.removeClass('error');
  136. }
  137. });
  138. $submit.click(function(event) {
  139. event.stopPropagation();
  140. event.preventDefault();
  141. $form.submit();
  142. });
  143. $input.focus();
  144. // pre select name up to the extension
  145. lastPos = newName.lastIndexOf('.');
  146. if (lastPos === -1) {
  147. lastPos = newName.length;
  148. }
  149. $input.selectRange(0, lastPos);
  150. $form.submit(function(event) {
  151. event.stopPropagation();
  152. event.preventDefault();
  153. if (checkInput()) {
  154. var newname = $input.val().trim();
  155. /* Find the right actionHandler that should be called.
  156. * Actions is retrieved by using `actionSpec.id` */
  157. var action = _.filter(self._menuItems, function(item) {
  158. return item.id == $target.attr('data-action');
  159. }).pop();
  160. action.actionHandler(newname);
  161. $form.remove();
  162. $target.find('.displayname').removeClass('hidden');
  163. OC.hideMenus();
  164. }
  165. });
  166. },
  167. /**
  168. * Add a new item menu entry in the “New” file menu (in
  169. * last position). By clicking on the item, the
  170. * `actionHandler` function is called.
  171. *
  172. * @param {Object} actionSpec item’s properties
  173. */
  174. addMenuEntry: function(actionSpec) {
  175. this._menuItems.push({
  176. id: actionSpec.id,
  177. displayName: actionSpec.displayName,
  178. templateName: actionSpec.templateName,
  179. iconClass: actionSpec.iconClass,
  180. fileType: actionSpec.fileType,
  181. useInput: actionSpec.useInput,
  182. actionHandler: actionSpec.actionHandler,
  183. checkFilename: actionSpec.checkFilename,
  184. shouldShow: actionSpec.shouldShow,
  185. });
  186. },
  187. /**
  188. * Remove a menu item from the "New" file menu
  189. * @param {string} actionId
  190. */
  191. removeMenuEntry: function(actionId) {
  192. var index = this._menuItems.findIndex(function (actionSpec) {
  193. return actionSpec.id === actionId;
  194. });
  195. if (index > -1) {
  196. this._menuItems.splice(index, 1);
  197. }
  198. },
  199. /**
  200. * Renders the menu with the currently set items
  201. */
  202. render: function() {
  203. const menuItems = this._menuItems.filter(item => !item.shouldShow || (item.shouldShow instanceof Function && item.shouldShow() === true))
  204. this.$el.html(this.template({
  205. uploadMaxHumanFileSize: 'TODO',
  206. uploadLabel: t('files', 'Upload file'),
  207. items: menuItems
  208. }));
  209. // Trigger upload action also with keyboard navigation on enter
  210. this.$el.find('[for="file_upload_start"]').on('keyup', function(event) {
  211. if (event.key === " " || event.key === "Enter") {
  212. $('#file_upload_start').trigger('click');
  213. }
  214. });
  215. },
  216. /**
  217. * Displays the menu under the given element
  218. *
  219. * @param {Object} $target target element
  220. */
  221. showAt: function($target) {
  222. this.render();
  223. OC.showMenu($target, this.$el);
  224. }
  225. });
  226. OCA.Files.NewFileMenu = NewFileMenu;
  227. })();