123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379 |
- /*
- author: ApmeM (artem.votincev@gmail.com)
- date: 9-June-2010
- version: 1.4
- download: http://code.google.com/p/jq-serverbrowse/
- */
- (function($) {
- $.fn.serverBrowser = function(settings) {
- this.each(function() {
- var config = {
- // Event function
- // Appear when user click 'Ok' button, or doubleclick on file
- onSelect: function(file) {
- alert('You select: ' + file);
- },
- onLoad: function() {
- return config.basePath;
- },
- multiselect: false,
- // Image parameters
- // System images (loading.gif, unknown.png, folder.png and images from knownPaths) will be referenced to systemImageUrl
- // if systemImageUrl is empty or not specified - imageUrl will be taken
- // All other images (like images for extension) will be taken from imageUrl
- imageUrl: 'img/',
- systemImageUrl: '',
- showUpInList: false,
- // Path properties
- // Base path, that links should start from.
- // If opened path is not under this path, alert will be shown and nothing will be opened
- // Path separator, that will be used to split specified paths and join paths to a string
- basePath: 'C:',
- separatorPath: '/',
- // Paths, that will be displayed on the left side of the dialog
- // This is a link to specified paths on the server
- useKnownPaths: true,
- knownPaths: [{text:'Desktop', image:'desktop.png', path:'C:/Users/All Users/Desktop'},
- {text:'Documents', image:'documents.png', path:'C:/Users/All Users/Documents'}],
- // Images for known extension (like 'png', 'exe', 'zip'), that will be displayed with its real names
- // Images, that is not in this list will be referenced to 'unknown.png' image
- // If list is empty - all images is known.
- knownExt: [],
- // Server path to this plugin handler
- handlerUrl: 'browserDlg.txt',
- // JQuery-ui dialog settings
- title: 'Browse',
- width: 300,
- height: 300,
- position: ['center', 'top'],
- // Administrative parameters used to
- // help programmer or system administrator
- requestMethod: 'POST',
- };
- if (settings) $.extend(config, settings);
- // Required configuration elements
- // We need to set some configuration elements without user
- // For example there should be 2 buttons on the bottom,
- // And dialog should be opened after button is pressed, not when it created
- // Also we need to know about dialog resizing
- $.extend(config, {
- autoOpen: false,
- modal: true,
- buttons: [
- {
- text: "Cancel",
- "class": "btn",
- click: function() {
- browserDlg.dialog("close");
- }
- },
- {
- text: "Open",
- "class": "btn",
- click: function() {
- doneOk();
- }
- }
- ],
- resize: function(event, ui) {
- recalculateSize(event, ui);
- },
- });
-
- function systemImageUrl()
- {
- if (config.systemImageUrl.length == 0) {
- return config.imageUrl;
- } else{
- return config.systemImageUrl;
- }
- }
-
- var privateConfig = {
- // This stack array will store history navigation data
- // When user open new directory, old directory will be added to this list
- // If user want, he will be able to move back by this history
- browserHistory: [],
- // This array contains all currently selected items
- // When user select element, it will add associated path into this array
- // When user deselect element - associated path will be removed
- // Exception: if 'config.multiselect' is false, only one element will be stored in this array.
- selectedItems: [],
- }
-
- // Main dialog div
- // It will be converted into jQuery-ui dialog box using my configuration parameters
- // It contains 3 divs
- var browserDlg = $('<div title="' + config.title + '"></div>').css({'overflow': 'hidden'}).appendTo(document.body);
- browserDlg.dialog(config);
-
- // First div on the top
- // It contains textbox field and buttons
- // User can enter any paths he want to open in this textbox and press enter
- // There is 3 buttons on the panel:
- var enterPathDiv = $('<div></div>').addClass('ui-widget-content').appendTo(browserDlg).css({'height': '30px', 'width': '100%', 'padding-top': '7px'});
-
- var enterButton = $('<div></div>').css({'float': 'left', 'vertical-align': 'middle', 'margin-left': '6px'}).addClass('ui-corner-all').hover(
- function() { $(this).addClass('ui-state-hover'); },
- function() { $(this).removeClass('ui-state-hover'); }
- );
- var enterLabel = $('<span></span>').text('Look in: ').appendTo(enterButton.clone(false).appendTo(enterPathDiv));
- var enterText = $('<input type="text">').keypress(function(e) {
- if (e.keyCode == '13') {
- e.preventDefault();
- loadPath(enterText.val());
- }
- }).appendTo(enterButton.clone(false).appendTo(enterPathDiv));
-
- // Back button.
- // When user click on it, 2 last elements of the history pop from the list, and reload second of them.
- var enterBack = $('<div></div>').addClass('ui-corner-all ui-icon ui-icon-circle-arrow-w').click(function(){
- privateConfig.browserHistory.pop(); // Remove current element. It is not required now.
- var backPath = config.basePath;
- if(privateConfig.browserHistory.length > 0){
- backPath = privateConfig.browserHistory.pop();
- }
- loadPath(backPath);
- }).appendTo(enterButton.clone(true).appendTo(enterPathDiv));
- // Level Up Button
- // When user click on it, last element of the history will be taken, and '..' will be applied to the end of the array.
- var enterUp = $('<div></div>').addClass('ui-corner-all ui-icon ui-icon-arrowreturnthick-1-n').click(function(){
- backPath = privateConfig.browserHistory[privateConfig.browserHistory.length - 1];
- if(backPath != config.basePath){
- loadPath(backPath + config.separatorPath + '..');
- }
- }).appendTo(enterButton.clone(true).appendTo(enterPathDiv));
-
- // Second div is on the left
- // It contains images and texts for pre-defined paths
- // User just click on them and it will open pre-defined path
- var knownPathDiv = $('<div></div>').addClass('ui-widget-content').css({'text-align':'center', 'overflow': 'auto', 'float': 'left', 'width': '100px'});
- if(config.useKnownPaths){
- knownPathDiv.appendTo(browserDlg);
- $.each(config.knownPaths, function(index, path) {
- var knownDiv = $('<div></div>').css({'margin':'10px'}).hover(
- function() { $(this).addClass('ui-state-hover'); },
- function() { $(this).removeClass('ui-state-hover'); }
- ).click(function() {
- loadPath(path.path);
- }).appendTo(knownPathDiv);
- $('<img />').attr({ src: systemImageUrl() + config.separatorPath + path.image }).css({ width: '32px', margin: '5px 10px 5px 5px' }).appendTo(knownDiv);
- $('<br/>').appendTo(knownDiv);
- $('<span></span>').text(path.text).appendTo(knownDiv);
- });
- }
-
- // Third div is everywhere :)
- // It show files and folders in the current path
- // User can click on path to select or deselect it
- // Doubleclick on path will open it
- // Also doubleclick on file will select this file and close dialog
- var browserPathDiv = $('<div></div>').addClass('ui-widget-content').css({'float': 'right', 'overflow': 'auto'}).appendTo(browserDlg);
-
- // Now everything is done
- // When user will be ready - he just click on the area you select for this plugin and dialog will appear
- $(this).click(function() {
- privateConfig.browserHistory = [];
- var startpath = removeBackPath(config.onLoad());
-
- startpath = startpath.split(config.separatorPath);
- startpath.pop();
- startpath = startpath.join(config.separatorPath);
-
- if(!checkBasePath(startpath)){
- startpath = config.basePath;
- }
- loadPath(startpath);
- browserDlg.dialog('open');
- recalculateSize();
- });
- // Function check if specified path is a child path of a 'config.basePath'
- // If it is not - user should see message, that path invalid, or path should be changed to valid.
- function checkBasePath(path){
- if(config.basePath == '')
- return true;
- var confPath = config.basePath.split(config.separatorPath);
- var curPath = path.split(config.separatorPath);
- if(confPath.length > curPath.length)
- return false;
- var result = true;
- $.each(confPath, function(index, partConfPath) {
- if(partConfPath != curPath[index]){
- result = false;
- }
- });
- return result;
- }
- // Function remove '..' parts of the path
- // Process depend on config.separatorPath option
- // On the server side you need to check / or \ separators
- function removeBackPath(path){
- var confPath = config.basePath.split(config.separatorPath);
- var curPath = path.split(config.separatorPath);
- var newcurPath = [];
- $.each(curPath, function(index, partCurPath) {
- if(partCurPath == ".."){
- newcurPath.pop();
- }else{
- newcurPath.push(partCurPath);
- }
- });
- return newcurPath.join(config.separatorPath);
- }
- // This function will be called when user click 'Open'
- // It check if any path is selected, and call config.onSelect function with path list
- function doneOk(){
- var newCurPath = [];
- $.each(privateConfig.selectedItems, function(index, item) {
- newCurPath.push($.data(item, 'path'));
- });
- if(newCurPath.length == 0) {
- newCurPath.push(privateConfig.browserHistory.pop());
- }
-
- if(config.multiselect)
- config.onSelect(newCurPath);
- else {
- if(newCurPath.length == 1) {
- config.onSelect(newCurPath[0]);
- } else if(newCurPath.length > 1){
- alert('Plugin work incorrectly. If error repeat, please add issue into http://code.google.com/p/jq-serverbrowse/issues/list with steps to reproduce.');
- return;
- }
- }
- browserDlg.dialog("close");
- }
-
- // Function recalculate and set new width and height for left and right div elements
- // height have '-2' because of the borders
- // width have '-4' because of a border an 2 pixels space between divs
- function recalculateSize(event, ui){
- knownPathDiv.css({'height' : browserDlg.height() - enterPathDiv.outerHeight(true) - 2});
- browserPathDiv.css({'height' : browserDlg.height() - enterPathDiv.outerHeight(true) - 2,
- 'width' : browserDlg.width() - knownPathDiv.outerWidth(true) - 4});
- }
- // Function adds new element into browserPathDiv element depends on file parameters
- // If file.isError is set, error message will be displayed instead of clickable area
- // Clickable div contain image from extension and text from file parameter
- function addElement(file){
- var itemDiv = $('<div></div>').css({ margin: '2px' }).appendTo(browserPathDiv);
- if(file.isError)
- {
- itemDiv.addClass('ui-state-error ui-corner-all').css({padding: '0pt 0.7em'});
- var p = $('<p></p>').appendTo(itemDiv);
- $('<span></span>').addClass('ui-icon ui-icon-alert').css({'float': 'left', 'margin-right': '0.3em'}).appendTo(p);
- $('<span></span>').text(file.name).appendTo(p);
- }else
- {
- var fullPath = file.path + config.separatorPath + file.name;
- itemDiv.hover(
- function() { $(this).addClass('ui-state-hover'); },
- function() { $(this).removeClass('ui-state-hover'); }
- );
- var itemImage = $('<img />').css({ width: '16px', margin: '0 5px 0 0' }).appendTo(itemDiv);
- var itemText = $('<span></span>').text(file.name).appendTo(itemDiv);
- if (file.isFolder)
- itemImage.attr({ src: systemImageUrl() + 'folder.png' });
- else {
- ext = file.name.split('.').pop();
- var res = '';
- if (ext == '' || ext == file.name || (config.knownExt.length > 0 && $.inArray(ext, config.knownExt) < 0))
- itemImage.attr({ src: systemImageUrl() + 'unknown.png' });
- else
- itemImage.attr({ src: config.imageUrl + ext + '.png' });
- }
- $.data(itemDiv, 'path', fullPath);
- itemDiv.unbind('click').bind('click', function(e) {
- if(!$(this).hasClass('ui-state-active')) {
- if(!config.multiselect && privateConfig.selectedItems.length > 0) {
- $(privateConfig.selectedItems[0]).click();
- }
- privateConfig.selectedItems.push(itemDiv);
- }else{
- var newCurPath = [];
- $.each(privateConfig.selectedItems, function(index, item) {
- if($.data(item, 'path') != fullPath)
- newCurPath.push(item);
- });
- privateConfig.selectedItems = newCurPath;
- }
- $(this).toggleClass('ui-state-active');
- });
- itemDiv.unbind('dblclick').bind('dblclick', function(e) {
- if (file.isFolder){
- loadPath(fullPath);
- } else {
- privateConfig.selectedItems = [itemDiv];
- doneOk();
- }
- });
- }
- }
- // Main plugin function
- // When user enter path manually, select it from pre-defined path, or doubleclick in browser this function will call
- // It send a request on the server to retrieve child directories and files of the specified path
- // If path is not under 'config.basePath', alert will be shown and nothing will be opened
- function loadPath(path) {
- privateConfig.selectedItems = [];
-
- // First we need to remove all '..' parts of the path
- path = removeBackPath(path);
-
- // Then we need to check, if path based on 'config.basePath'
- if(!checkBasePath(path)) {
- alert('Path should be based from ' + config.basePath);
- return;
- }
-
- // Then we can put this path into history
- privateConfig.browserHistory.push(path);
-
- // Show it to user
- enterText.val(path);
-
- // And load
- $.ajax({
- url: config.handlerUrl,
- type: config.requestMethod,
- data: {
- action: 'browse',
- path: path,
- time: new Date().getTime()
- },
- beforeSend: function() {
- browserPathDiv.empty().css({ 'text-align': 'center' });
- $('<img />').attr({ src: systemImageUrl() + 'loading.gif' }).css({ width: '32px' }).appendTo(browserPathDiv);
- },
- success: function(files) {
- browserPathDiv.empty().css({ 'text-align': 'left' });
- if(path != config.basePath && config.showUpInList){
- addElement({name: '..', isFolder: true, isError: false, path: path});
- }
- $.each(files, function(index, file) {
- addElement($.extend(file, {path: path}));
- });
- },
- dataType: 'json'
- });
- }
- });
- return this;
- };
- })(jQuery);
|