jquery.filechooser.js 15 KB

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