jquery.filechooser.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. // Licensed to Cloudera, Inc. under one
  2. // or more contributor license agreements. See the NOTICE file
  3. // distributed with this work for additional information
  4. // regarding copyright ownership. Cloudera, Inc. licenses this file
  5. // to you under the Apache License, Version 2.0 (the
  6. // "License"); you may not use this file except in compliance
  7. // with the License. You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. /*
  17. * jHue fileChooser plugin
  18. */
  19. ;
  20. (function ($, window, document, undefined) {
  21. var pluginName = "jHueFileChooser",
  22. // global variables (jHueFileChooserGlobals, useful for i18n) can be set on
  23. // desktop/templates/common_header.mako
  24. defaults = {
  25. initialPath:"",
  26. forceRefresh:false,
  27. errorRedirectPath:"",
  28. createFolder:true,
  29. uploadFile:true,
  30. selectFolder:false,
  31. suppressErrors:false,
  32. showExtraHome:false,
  33. extraHomeProperties:{},
  34. labels: {
  35. BACK: "Back",
  36. SELECT_FOLDER: "Select this folder",
  37. CREATE_FOLDER: "Create folder",
  38. FOLDER_NAME: "Folder name",
  39. CANCEL: "Cancel",
  40. FILE_NOT_FOUND: "The file has not been found",
  41. UPLOAD_FILE: "Upload a file",
  42. FAILED: "Failed",
  43. HOME: "Home"
  44. },
  45. user: "",
  46. onFileChoose:function () {
  47. },
  48. onFolderChoose:function () {
  49. },
  50. onFolderChange:function () {
  51. },
  52. onError:function () {
  53. }
  54. },
  55. STORAGE_PREFIX = "hueFileBrowserLastPathForUser_";
  56. function Plugin(element, options) {
  57. this.element = element;
  58. if (typeof jHueFileChooserGlobals != 'undefined') {
  59. var extendedDefaults = $.extend({}, defaults, jHueFileChooserGlobals);
  60. extendedDefaults.labels = $.extend({}, defaults.labels, jHueFileChooserGlobals.labels);
  61. this.options = $.extend({}, extendedDefaults, options);
  62. if (options != null){
  63. this.options.labels = $.extend({}, extendedDefaults.labels, options.labels);
  64. }
  65. }
  66. else {
  67. this.options = $.extend({}, defaults, options);
  68. if (options != null){
  69. this.options.labels = $.extend({}, defaults.labels, options.labels);
  70. }
  71. }
  72. this._defaults = defaults;
  73. this._name = pluginName;
  74. this.previousPath = "";
  75. this.init();
  76. }
  77. Plugin.prototype.setOptions = function (options) {
  78. this.options = $.extend({}, defaults, options);
  79. if (this.options.forceRefresh){
  80. if ($.trim(this.options.initialPath) != "") {
  81. this.navigateTo(this.options.initialPath);
  82. }
  83. else if ($.totalStorage(STORAGE_PREFIX + this.options.user) != null) {
  84. this.navigateTo($.totalStorage(STORAGE_PREFIX + this.options.user));
  85. }
  86. else {
  87. this.navigateTo("/?default_to_home");
  88. }
  89. }
  90. else {
  91. if ($.trim(this.options.initialPath) != "") {
  92. this.navigateTo(this.options.initialPath);
  93. }
  94. }
  95. };
  96. Plugin.prototype.navigateTo = function (path) {
  97. var _parent = this;
  98. if (navigator.userAgent.match(/msie/i)) {
  99. $(_parent.element).html("<img src='/static/art/spinner.gif' />");
  100. }
  101. else {
  102. $(_parent.element).html("<i style=\"font-size: 24px; color: #DDD\" class=\"fa fa-spinner fa-spin\"></i>");
  103. }
  104. $.getJSON("/filebrowser/chooser" + path, function (data) {
  105. $(_parent.element).empty();
  106. path = data.current_dir_path; // use real path.
  107. var _flist = $("<ul>").addClass("unstyled").css("margin-left", "2px");
  108. if (data.title != null && data.title == "Error") {
  109. var _errorMsg = $("<div>").addClass("alert").addClass("alert-error").text(data.message);
  110. _errorMsg.appendTo($(_parent.element));
  111. var _previousLink = $("<a>").addClass("btn").addClass("bnt-small").text(_parent.options.labels.BACK).click(function () {
  112. _parent.options.onFolderChange(_parent.previousPath);
  113. _parent.navigateTo(_parent.previousPath);
  114. });
  115. _previousLink.appendTo($(_parent.element));
  116. }
  117. else {
  118. if (data.type == "file") {
  119. _parent.navigateTo(data.view.dirname);
  120. return;
  121. }
  122. $.totalStorage(STORAGE_PREFIX + _parent.options.user, path);
  123. _parent.previousPath = path;
  124. var _breadcrumbs = $("<ul>").addClass("hueBreadcrumb").css("padding", "0").css("marginLeft", "0");
  125. var _home = $("<li>");
  126. var _homelink = $("<a>").addClass("nounderline").html('<i class="fa fa-home"></i> ' + _parent.options.labels.HOME).css("cursor", "pointer").click(function () {
  127. _parent.navigateTo("/?default_to_home");
  128. });
  129. _homelink.appendTo(_home);
  130. $("<span>").addClass("divider").css("margin-right", "20px").appendTo(_home);
  131. _home.appendTo(_breadcrumbs);
  132. if (_parent.options.showExtraHome) {
  133. var _extraHome = $("<li>");
  134. var _extraHomelink = $("<a>").addClass("nounderline").html('<i class="fa ' + _parent.options.extraHomeProperties.icon + '"></i> ' + _parent.options.extraHomeProperties.label).css("cursor", "pointer").click(function () {
  135. _parent.navigateTo(_parent.options.extraHomeProperties.path);
  136. });
  137. _extraHomelink.appendTo(_extraHome);
  138. $("<span>").addClass("divider").css("margin-right", "20px").appendTo(_extraHome);
  139. _extraHome.appendTo(_breadcrumbs);
  140. }
  141. if (typeof data.breadcrumbs != "undefined" && data.breadcrumbs != null){
  142. var _bLength = data.breadcrumbs.length;
  143. $(data.breadcrumbs).each(function (cnt, crumb) {
  144. var _crumb = $("<li>");
  145. var _crumbLink = $("<a>");
  146. var _crumbLabel = (crumb.label != null && crumb.label != "") ? crumb.label : "/";
  147. _crumbLink.attr("href", "javascript:void(0)").text(_crumbLabel).appendTo(_crumb);
  148. if (cnt < _bLength - 1) {
  149. if (cnt > 0) {
  150. $("<span>").addClass("divider").text("/").appendTo(_crumb);
  151. }
  152. else {
  153. $("<span>").html("&nbsp;").appendTo(_crumb);
  154. }
  155. }
  156. _crumb.click(function () {
  157. var _url = (crumb.url != null && crumb.url != "") ? crumb.url : "/";
  158. _parent.options.onFolderChange(_url);
  159. _parent.navigateTo(_url);
  160. });
  161. _crumb.appendTo(_breadcrumbs);
  162. });
  163. }
  164. _breadcrumbs.appendTo($(_parent.element));
  165. $(data.files).each(function (cnt, file) {
  166. var _f = $("<li>");
  167. var _flink = $("<a>");
  168. _flink.attr("href", "javascript:void(0)").text(" " + (file.name != "" ? file.name : "..")).appendTo(_f);
  169. if (file.type == "dir") {
  170. $("<i class='fa fa-folder'></i>").prependTo(_flink);
  171. _f.click(function () {
  172. _parent.options.onFolderChange(file.path);
  173. _parent.navigateTo(file.path);
  174. });
  175. }
  176. if (file.type == "file") {
  177. $("<i class='fa fa-file-o'></i>").prependTo(_flink);
  178. _f.click(function () {
  179. _parent.options.onFileChoose(file.path);
  180. });
  181. }
  182. _f.appendTo(_flist);
  183. });
  184. _flist.appendTo($(_parent.element));
  185. var _actions = $("<div>").addClass("jHueFilechooserActions");
  186. var _showActions = false;
  187. var _uploadFileBtn;
  188. var _createFolderBtn;
  189. var _selectFolderBtn;
  190. if (_parent.options.uploadFile) {
  191. _uploadFileBtn = $("<div>").attr("id", "file-uploader");
  192. _uploadFileBtn.appendTo(_actions);
  193. _showActions = true;
  194. initUploader(path, _parent, _uploadFileBtn, _parent.options.labels);
  195. }
  196. if (_parent.options.selectFolder) {
  197. _selectFolderBtn = $("<a>").addClass("btn").addClass("small").text(_parent.options.labels.SELECT_FOLDER);
  198. if (_parent.options.uploadFile){
  199. _selectFolderBtn.css("margin-top", "10px");
  200. }
  201. _selectFolderBtn.appendTo(_actions);
  202. _showActions = true;
  203. _selectFolderBtn.click(function () {
  204. _parent.options.onFolderChoose(path);
  205. });
  206. }
  207. $("<span> </span>").appendTo(_actions);
  208. if (_parent.options.createFolder) {
  209. _createFolderBtn = $("<a>").addClass("btn").addClass("small").text(_parent.options.labels.CREATE_FOLDER);
  210. if (_parent.options.uploadFile){
  211. _createFolderBtn.css("margin-top", "10px");
  212. }
  213. _createFolderBtn.appendTo(_actions);
  214. _showActions = true;
  215. var _createFolderDetails = $("<form>").css("margin-top", "10px").addClass("well form-inline");
  216. _createFolderDetails.hide();
  217. var _folderName = $("<input>").attr("type", "text").attr("placeholder", _parent.options.labels.FOLDER_NAME).appendTo(_createFolderDetails);
  218. $("<span> </span>").appendTo(_createFolderDetails);
  219. var _folderBtn = $("<input>").attr("type", "button").attr("value", _parent.options.labels.CREATE_FOLDER).addClass("btn primary").appendTo(_createFolderDetails);
  220. $("<span> </span>").appendTo(_createFolderDetails);
  221. var _folderCancel = $("<input>").attr("type", "button").attr("value", _parent.options.labels.CANCEL).addClass("btn").appendTo(_createFolderDetails);
  222. _folderCancel.click(function () {
  223. if (_uploadFileBtn) {
  224. _uploadFileBtn.removeClass("disabled");
  225. }
  226. _createFolderBtn.removeClass("disabled");
  227. _createFolderDetails.slideUp();
  228. });
  229. _folderBtn.click(function () {
  230. $.ajax({
  231. type:"POST",
  232. url:"/filebrowser/mkdir",
  233. data:{
  234. name:_folderName.val(),
  235. path:path
  236. },
  237. beforeSend:function (xhr) {
  238. xhr.setRequestHeader("X-Requested-With", "Hue"); // need to override the default one because otherwise Django returns HTTP 500
  239. },
  240. success:function (xhr, status) {
  241. if (status == "success") {
  242. _parent.navigateTo(path);
  243. if (_uploadFileBtn) {
  244. _uploadFileBtn.removeClass("disabled");
  245. }
  246. _createFolderBtn.removeClass("disabled");
  247. _createFolderDetails.slideUp();
  248. }
  249. }
  250. });
  251. });
  252. _createFolderDetails.appendTo(_actions);
  253. _createFolderBtn.click(function () {
  254. if (_uploadFileBtn) {
  255. _uploadFileBtn.addClass("disabled");
  256. }
  257. _createFolderBtn.addClass("disabled");
  258. _createFolderDetails.slideDown();
  259. });
  260. }
  261. if (_showActions){
  262. _actions.appendTo($(_parent.element));
  263. }
  264. window.setTimeout(function () {
  265. $(_parent.element).parent().scrollTop(0)
  266. }, 100);
  267. }
  268. }).error(function(){
  269. if (! _parent.options.suppressErrors) {
  270. $(document).trigger("info", _parent.options.labels.FILE_NOT_FOUND);
  271. _parent.options.onError();
  272. }
  273. _parent.navigateTo(_parent.options.errorRedirectPath != "" ? _parent.options.errorRedirectPath : "/?default_to_home");
  274. });
  275. };
  276. var num_of_pending_uploads = 0;
  277. function initUploader(path, _parent, el, labels) {
  278. var uploader = new qq.FileUploader({
  279. element:el[0],
  280. action:'/filebrowser/upload/file',
  281. params:{
  282. dest:path,
  283. fileFieldLabel:'hdfs_file'
  284. },
  285. onComplete:function (id, fileName, responseJSON) {
  286. num_of_pending_uploads--;
  287. if(num_of_pending_uploads == 0){
  288. _parent.navigateTo(path);
  289. }
  290. },
  291. onSubmit: function(id, fileName){
  292. num_of_pending_uploads++;
  293. },
  294. template: '<div class="qq-uploader">' +
  295. '<div class="qq-upload-drop-area"><span></span></div>' +
  296. '<div class="qq-upload-button">' + labels.UPLOAD_FILE + '</div>' +
  297. '<ul class="qq-upload-list"></ul>' +
  298. '</div>',
  299. fileTemplate: '<li>' +
  300. '<span class="qq-upload-file"></span>' +
  301. '<span class="qq-upload-spinner"></span>' +
  302. '<span class="qq-upload-size"></span>' +
  303. '<a class="qq-upload-cancel" href="#">' + labels.CANCEL + '</a>' +
  304. '<span class="qq-upload-failed-text">' + labels.FAILED + '</span>' +
  305. '</li>',
  306. debug:false
  307. });
  308. }
  309. Plugin.prototype.init = function () {
  310. if ($.trim(this.options.initialPath) != "") {
  311. this.navigateTo(this.options.initialPath);
  312. }
  313. else if ($.totalStorage(STORAGE_PREFIX + this.options.user) != null) {
  314. this.navigateTo($.totalStorage(STORAGE_PREFIX + this.options.user));
  315. }
  316. else {
  317. this.navigateTo("/?default_to_home");
  318. }
  319. };
  320. $.fn[pluginName] = function (options) {
  321. return this.each(function () {
  322. if (!$.data(this, 'plugin_' + pluginName)) {
  323. $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
  324. }
  325. else {
  326. $.data(this, 'plugin_' + pluginName).setOptions(options);
  327. }
  328. });
  329. }
  330. })(jQuery, window, document);