newfilemenu.js 6.8 KB

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