diff --git a/gui/slick/js/browser.js b/gui/slick/js/browser.js index f1ba76ba1477831befa869dd4673227fbff60d4d..51f6f4849dc6d84d70570af1b4c3deedb9947821 100644 --- a/gui/slick/js/browser.js +++ b/gui/slick/js/browser.js @@ -1,5 +1,5 @@ ;(function ($) { - "use strict"; + 'use strict'; $.Browser = { defaults: { @@ -36,7 +36,7 @@ }); $('<input type="text" class="form-control input-sm">') - .val(firstVal.current_path) // jshint ignore:line + .val(firstVal.currentPath) .on('keypress', function (e) { if (e.which === 13) { browse(e.target.value, endpoint, includeFiles); @@ -50,15 +50,24 @@ list = $('<ul>').appendTo(fileBrowserDialog); $.each(data, function (i, entry) { - link = $("<a href='javascript:void(0)' />").on('click', function () { browse(entry.path, endpoint, includeFiles); }).text(entry.name); - $('<span class="ui-icon ui-icon-folder-collapsed"></span>').prependTo(link); - link.hover( - function () {$("span", this).addClass("ui-icon-folder-open"); }, - function () {$("span", this).removeClass("ui-icon-folder-open"); } - ); + link = $('<a href="javascript:void(0)">').on('click', function () { + if (entry.isFile) { + currentBrowserPath = entry.path; + $('.browserDialog .ui-button:contains("Ok")').click(); + } else { + browse(entry.path, endpoint, includeFiles); + } + }).text(entry.name); + if (entry.isFile) { + link.prepend('<span class="ui-icon ui-icon-blank"></span>'); + } else { + link.prepend('<span class="ui-icon ui-icon-folder-collapsed"></span>') + .on('mouseenter', function () { $('span', this).addClass('ui-icon-folder-open'); }) + .on('mouseleave', function () { $('span', this).removeClass('ui-icon-folder-open'); }); + } link.appendTo(list); }); - $("a", list).wrap('<li class="ui-state-default ui-corner-all">'); + $('a', list).wrap('<li class="ui-state-default ui-corner-all">'); fileBrowserDialog.dialog('option', 'dialogClass', 'browserDialog'); }); } @@ -68,7 +77,6 @@ // make a fileBrowserDialog object if one doesn't exist already if (!fileBrowserDialog) { - // set up the jquery dialog fileBrowserDialog = $('<div id="fileBrowserDialog" style="display:hidden"></div>').appendTo('body').dialog({ dialogClass: 'browserDialog', @@ -85,19 +93,19 @@ fileBrowserDialog.dialog('option', 'buttons', [ { - text: "Ok", - "class": "btn", + text: 'Ok', + 'class': 'btn', click: function () { // store the browsed path to the associated text field callback(currentBrowserPath, options); - $(this).dialog("close"); + $(this).dialog('close'); } }, { - text: "Cancel", - "class": "btn", + text: 'Cancel', + 'class': 'btn', click: function () { - $(this).dialog("close"); + $(this).dialog('close'); } } ]); @@ -122,17 +130,17 @@ if (options.field.autocomplete && options.autocompleteURL) { var query = ''; options.field.autocomplete({ - position: { my : "top", at: "bottom", collision: "flipfit" }, + position: { my : 'top', at: 'bottom', collision: 'flipfit' }, source: function (request, response) { //keep track of user submitted search term query = $.ui.autocomplete.escapeRegex(request.term, options.includeFiles); $.ajax({ url: options.autocompleteURL, data: request, - dataType: "json", + dataType: 'json', success: function (data) { //implement a startsWith filter for the results - var matcher = new RegExp("^" + query, "i"); + var matcher = new RegExp('^' + query, 'i'); var a = $.grep(data, function (item) { return matcher.test(item); }); @@ -141,18 +149,18 @@ }); }, open: function () { - $(".ui-autocomplete li.ui-menu-item a").removeClass("ui-corner-all"); + $('.ui-autocomplete li.ui-menu-item a').removeClass('ui-corner-all'); } - }).data("ui-autocomplete")._renderItem = function (ul, item) { + }).data('ui-autocomplete')._renderItem = function (ul, item) { //highlight the matched search term from the item -- note that this is global and will match anywhere var resultItem = item.label; - var x = new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + query + ")(?![^<>]*>)(?![^&;]+;)", "gi"); + var x = new RegExp('(?![^&;]+;)(?!<[^<>]*)(' + query + ')(?![^<>]*>)(?![^&;]+;)', 'gi'); resultItem = resultItem.replace(x, function (fullMatch) { return '<b>' + fullMatch + '</b>'; }); - return $("<li></li>") - .data("ui-autocomplete-item", item) - .append("<a class='nowrap'>" + resultItem + "</a>") + return $('<li></li>') + .data('ui-autocomplete-item', item) + .append('<a class="nowrap">' + resultItem + '</a>') .appendTo(ul); }; } diff --git a/sickbeard/browser.py b/sickbeard/browser.py index 7f10ff350afadc1c009ae7da29b0b072dc367360..76aaee1642f9db7d5db3de878f3996c8eaab54b2 100644 --- a/sickbeard/browser.py +++ b/sickbeard/browser.py @@ -40,6 +40,34 @@ def getWinDrives(): return drives +def getFileList(path, includeFiles): + # prune out directories to protect the user from doing stupid things (already lower case the dir to reduce calls) + hideList = ["boot", "bootmgr", "cache", "config.msi", "msocache", "recovery", "$recycle.bin", + "recycler", "system volume information", "temporary internet files"] # windows specific + hideList += [".fseventd", ".spotlight", ".trashes", ".vol", "cachedmessages", "caches", "trash"] # osx specific + hideList += [".git"] + + fileList = [] + for filename in ek(os.listdir, path): + if filename.lower() in hideList: + continue + + fullFilename = ek(os.path.join, path, filename) + isDir = ek(os.path.isdir, fullFilename) + + if not includeFiles and not isDir: + continue + + entry = { + 'name': filename, + 'path': fullFilename + } + if not isDir: entry['isFile'] = True + fileList.append(entry) + + return fileList + + def foldersAtPath(path, includeParent=False, includeFiles=False): """ Returns a list of dictionaries with the folders contained at the given path Give the empty string as the path to list the contents of the root path @@ -60,7 +88,7 @@ def foldersAtPath(path, includeParent=False, includeFiles=False): if path == "": if os.name == 'nt': - entries = [{'current_path': 'Root'}] + entries = [{'currentPath': 'Root'}] for letter in getWinDrives(): letterPath = letter + ':\\' entries.append({'name': letterPath, 'path': letterPath}) @@ -77,25 +105,15 @@ def foldersAtPath(path, includeParent=False, includeFiles=False): parentPath = "" try: - fileList = [{'name': filename, 'path': ek(os.path.join, path, filename)} for filename in ek(os.listdir, path)] + fileList = getFileList(path, includeFiles) except OSError, e: logger.log(u"Unable to open " + path + ": " + repr(e) + " / " + str(e), logger.WARNING) - fileList = [{'name': filename, 'path': ek(os.path.join, parentPath, filename)} for filename in ek(os.listdir, parentPath)] - - if not includeFiles: - fileList = [x for x in fileList if ek(os.path.isdir, x['path'])] - - # prune out directories to protect the user from doing stupid things (already lower case the dir to reduce calls) - hideList = ["boot", "bootmgr", "cache", "msocache", "recovery", "$recycle.bin", "recycler", - "system volume information", "temporary internet files"] # windows specific - hideList += [".fseventd", ".spotlight", ".trashes", ".vol", "cachedmessages", "caches", "trash"] # osx specific - - fileList = [x for x in fileList if x['name'].lower() not in hideList] + fileList = getFileList(parentPath, includeFiles) fileList = sorted(fileList, lambda x, y: cmp(os.path.basename(x['name']).lower(), os.path.basename(y['path']).lower())) - entries = [{'current_path': path}] + entries = [{'currentPath': path}] if includeParent and parentPath != path: entries.append({'name': "..", 'path': parentPath}) entries.extend(fileList)