jquery.filechooser.js 16 KB

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