jquery.filechooser.js 15 KB

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