codiad/components/active/init.js

1011 lines
37 KiB
JavaScript
Raw Normal View History

/*
* Copyright (c) Codiad & Kent Safranski (codiad.com), distributed
* as-is and without warranty under the MIT License. See
* [root]/license.txt for more. This information must remain intact.
*/
(function(global, $) {
var EditSession = ace.require('ace/edit_session')
.EditSession;
var UndoManager = ace.require('ace/undomanager')
.UndoManager;
var codiad = global.codiad;
$(function() {
codiad.active.init();
});
//////////////////////////////////////////////////////////////////
//
// Active Files Component for Codiad
// ---------------------------------
// Track and manage EditSession instaces of files being edited.
//
//////////////////////////////////////////////////////////////////
codiad.active = {
controller: 'components/active/controller.php',
// Path to EditSession instance mapping
sessions: {},
// History of opened files
history: [],
//////////////////////////////////////////////////////////////////
//
// Check if a file is open.
//
// Parameters:
// path - {String}
//
//////////////////////////////////////////////////////////////////
isOpen: function(path) {
return !!this.sessions[path];
},
open: function(path, content, mtime, inBackground, focus) {
//if( this. ) {
//}
if (focus === undefined) {
focus = true;
}
var _this = this;
if (this.isOpen(path)) {
if(focus) this.focus(path);
return;
}
var ext = codiad.filemanager.getExtension(path);
var mode = codiad.editor.selectMode( path );
var fn = function() {
//var Mode = require('ace/mode/' + mode)
// .Mode;
// TODO: Ask for user confirmation before recovering
// And maybe show a diff
var draft = _this.checkDraft(path);
if (draft) {
content = draft;
codiad.message.success(i18n('Recovered unsaved content for: ') + path);
}
//var session = new EditSession(content, new Mode());
var session = new EditSession(content);
session.setMode(mode.mode);
session.setUndoManager(new UndoManager());
session.path = path;
session.serverMTime = mtime;
_this.sessions[path] = session;
session.untainted = content.slice(0);
if (!inBackground && focus) {
codiad.editor.setSession(session);
}
_this.add(path, session, focus);
/* Notify listeners. */
amplify.publish('active.onOpen', path);
};
// Assuming the mode file has no dependencies
$.loadScript('components/editor/ace-editor/mode-' + mode.name + '.js',
fn);
},
init: function() {
var _this = this;
_this.initTabDropdownMenu();
_this.updateTabDropdownVisibility();
// Focus from list.
$('#list-active-files a')
.live('click', function(e) {
e.stopPropagation();
_this.focus($(this).parent('li').attr('data-path'));
});
// Focus on left button click from dropdown.
$('#dropdown-list-active-files a')
.live('click', function(e) {
if(e.which == 1) {
/* Do not stop propagation of the event,
* it will be catch by the dropdown menu
* and close it. */
_this.focus($(this).parent('li').attr('data-path'));
}
});
// Focus on left button mousedown from tab.
$('#tab-list-active-files li.tab-item>a.label')
.live('mousedown', function(e) {
if(e.which == 1) {
e.stopPropagation();
_this.focus($(this).parent('li').attr('data-path'));
}
});
// Remove from list.
$('#list-active-files a>span')
.live('click', function(e) {
e.stopPropagation();
_this.remove($(this)
.parent('a')
.parent('li')
.attr('data-path'));
});
// Remove from dropdown.
$('#dropdown-list-active-files a>span')
.live('click', function(e) {
e.stopPropagation();
/* Get the active editor before removing anything. Remove the
* tab, then put back the focus on the previously active
* editor if it was not removed. */
var activePath = _this.getPath();
var pathToRemove = $(this).parents('li').attr('data-path');
_this.remove(pathToRemove);
if (activePath !== null && activePath !== pathToRemove) {
_this.focus(activePath);
}
_this.updateTabDropdownVisibility();
});
// Remove from tab.
$('#tab-list-active-files a.close')
.live('click', function(e) {
e.stopPropagation();
/* Get the active editor before removing anything. Remove the
* tab, then put back the focus on the previously active
* editor if it was not removed. */
var activePath = _this.getPath();
var pathToRemove = $(this).parent('li').attr('data-path');
_this.remove(pathToRemove);
if (activePath !== null && activePath !== pathToRemove) {
_this.focus(activePath);
}
_this.updateTabDropdownVisibility();
});
// Remove from middle button click on dropdown.
$('#dropdown-list-active-files li')
.live('mouseup', function(e) {
if (e.which == 2) {
e.stopPropagation();
/* Get the active editor before removing anything. Remove the
* tab, then put back the focus on the previously active
* editor if it was not removed. */
var activePath = _this.getPath();
var pathToRemove = $(this).attr('data-path');
_this.remove(pathToRemove);
if (activePath !== null && activePath !== pathToRemove) {
_this.focus(activePath);
}
_this.updateTabDropdownVisibility();
}
});
// Remove from middle button click on tab.
$('.tab-item')
.live('mouseup', function(e) {
if (e.which == 2) {
e.stopPropagation();
/* Get the active editor before removing anything. Remove the
* tab, then put back the focus on the previously active
* editor if it was not removed. */
var activePath = _this.getPath();
var pathToRemove = $(this).attr('data-path');
_this.remove(pathToRemove);
if (activePath !== null && activePath !== pathToRemove) {
_this.focus(activePath);
}
_this.updateTabDropdownVisibility();
}
});
// Make list sortable
$('#list-active-files')
.sortable({
placeholder: 'active-sort-placeholder',
tolerance: 'intersect',
start: function(e, ui) {
ui.placeholder.height(ui.item.height());
}
});
// Make dropdown sortable.
$('#dropdown-list-active-files')
.sortable({
axis: 'y',
tolerance: 'pointer',
start: function(e, ui) {
ui.placeholder.height(ui.item.height());
}
});
// Make tabs sortable.
$('#tab-list-active-files')
.sortable({
items: '> li',
axis: 'x',
tolerance: 'pointer',
containment: 'parent',
start: function(e, ui) {
ui.placeholder.css('background', 'transparent');
ui.helper.css('width', '200px');
},
stop: function(e, ui) {
// Reset css
ui.item.css('z-index', '')
ui.item.css('position', '')
}
});
/* Woaw, so tricky! At initialization, the tab-list is empty, so
* it is not marked as float so it is not detected as an horizontal
* list by the sortable plugin. Workaround is to mark it as
* floating at initialization time. See bug report
* http://bugs.jqueryui.com/ticket/6702. */
$('#tab-list-active-files').data('sortable').floating = true;
// Open saved-state active files on load
$.get(_this.controller + '?action=list', function(data) {
var listResponse = codiad.jsend.parse(data);
if (listResponse !== null) {
$.each(listResponse, function(index, data) {
codiad.filemanager.openFile(data.path, data.focused);
});
}
});
// Prompt if a user tries to close window without saving all filess
window.onbeforeunload = function(e) {
if ($('#list-active-files li.changed')
.length > 0) {
var e = e || window.event;
var errMsg = i18n('You have unsaved files.');
// For IE and Firefox prior to version 4
if (e) {
e.returnValue = errMsg;
}
// For rest
return errMsg;
}
};
},
//////////////////////////////////////////////////////////////////
// Drafts
//////////////////////////////////////////////////////////////////
checkDraft: function(path) {
var draft = localStorage.getItem(path);
if (draft !== null) {
return draft;
} else {
return false;
}
},
removeDraft: function(path) {
localStorage.removeItem(path);
},
//////////////////////////////////////////////////////////////////
// Get active editor path
//////////////////////////////////////////////////////////////////
getPath: function() {
try {
return codiad.editor.getActive()
.getSession()
.path;
} catch (e) {
return null;
}
},
//////////////////////////////////////////////////////////////////
// Check if opened by another user
//////////////////////////////////////////////////////////////////
check: function(path) {
$.get(this.controller + '?action=check&path=' + encodeURIComponent(path),
function(data) {
var checkResponse = codiad.jsend.parse(data);
});
},
//////////////////////////////////////////////////////////////////
// Add newly opened file to list
//////////////////////////////////////////////////////////////////
add: function(path, session, focus) {
if (focus === undefined) {
focus = true;
}
var listThumb = this.createListThumb(path);
session.listThumb = listThumb;
$('#list-active-files').append(listThumb);
/* If the tab list would overflow with the new tab. Move the
* first tab to dropdown, then add a new tab. */
if (this.isTabListOverflowed(true)) {
var tab = $('#tab-list-active-files li:first-child');
this.moveTabToDropdownMenu(tab);
}
var tabThumb = this.createTabThumb(path);
$('#tab-list-active-files').append(tabThumb);
session.tabThumb = tabThumb;
this.updateTabDropdownVisibility();
$.get(this.controller + '?action=add&path=' + encodeURIComponent(path));
if(focus) {
this.focus(path);
}
// Mark draft as changed
if (this.checkDraft(path)) {
this.markChanged(path);
}
},
//////////////////////////////////////////////////////////////////
// Focus on opened file
//////////////////////////////////////////////////////////////////
focus: function(path, moveToTabList) {
if (moveToTabList === undefined) {
moveToTabList = true;
}
this.highlightEntry(path, moveToTabList);
if(path != this.getPath()) {
codiad.editor.setSession(this.sessions[path]);
this.history.push(path);
$.get(this.controller, {'action':'focused', 'path':path});
}
/* Check for users registered on the file. */
this.check(path);
/* Notify listeners. */
amplify.publish('active.onFocus', path);
},
highlightEntry: function(path, moveToTabList) {
if (moveToTabList === undefined) {
moveToTabList = true;
}
$('#list-active-files li')
.removeClass('active');
$('#tab-list-active-files li')
.removeClass('active');
$('#dropdown-list-active-files li')
.removeClass('active');
var session = this.sessions[path];
if($('#dropdown-list-active-files').has(session.tabThumb).length > 0) {
if(moveToTabList) {
/* Get the menu item as a tab, and put the last tab in
* dropdown. */
var menuItem = session.tabThumb;
this.moveDropdownMenuItemToTab(menuItem, true);
var tab = $('#tab-list-active-files li:last-child');
this.moveTabToDropdownMenu(tab);
} else {
/* Show the dropdown menu if needed */
this.showTabDropdownMenu();
}
}
else if(this.history.length > 0) {
var prevPath = this.history[this.history.length-1];
var prevSession = this.sessions[prevPath];
if($('#dropdown-list-active-files').has(prevSession.tabThumb).length > 0) {
/* Hide the dropdown menu if needed */
this.hideTabDropdownMenu();
}
}
session.tabThumb.addClass('active');
session.listThumb.addClass('active');
},
//////////////////////////////////////////////////////////////////
// Mark changed
//////////////////////////////////////////////////////////////////
markChanged: function(path) {
this.sessions[path].listThumb.addClass('changed');
this.sessions[path].tabThumb.addClass('changed');
},
//////////////////////////////////////////////////////////////////
// Save active editor
//////////////////////////////////////////////////////////////////
save: function(path) {
/* Notify listeners. */
amplify.publish('active.onSave', path);
var _this = this;
if ((path && !this.isOpen(path)) || (!path && !codiad.editor.getActive())) {
codiad.message.error(i18n('No Open Files to save'));
return;
}
var session;
if (path) session = this.sessions[path];
else session = codiad.editor.getActive()
.getSession();
var content = session.getValue();
var path = session.path;
var handleSuccess = function(mtime){
var session = codiad.active.sessions[path];
if(typeof session != 'undefined') {
session.untainted = newContent;
session.serverMTime = mtime;
if (session.listThumb) session.listThumb.removeClass('changed');
if (session.tabThumb) session.tabThumb.removeClass('changed');
}
_this.removeDraft(path);
}
// Replicate the current content so as to avoid
// discrepancies due to content changes during
// computation of diff
var newContent = content.slice(0);
if (session.serverMTime && session.untainted){
codiad.workerManager.addTask({
taskType: 'diff',
id: path,
original: session.untainted,
changed: newContent
}, function(success, patch){
if (success) {
codiad.filemanager.savePatch(path, patch, session.serverMTime, {
success: handleSuccess
});
} else {
codiad.filemanager.saveFile(path, newContent, {
success: handleSuccess
});
}
}, this);
} else {
codiad.filemanager.saveFile(path, newContent, {
success: handleSuccess
});
}
},
//////////////////////////////////////////////////////////////////
// Save all files
//////////////////////////////////////////////////////////////////
saveAll: function() {
var _this = this;
for(var session in _this.sessions) {
if (_this.sessions[session].listThumb.hasClass('changed')) {
codiad.active.save(session);
}
}
},
//////////////////////////////////////////////////////////////////
// Remove file
//////////////////////////////////////////////////////////////////
remove: function(path) {
if (!this.isOpen(path)) return;
var session = this.sessions[path];
var closeFile = true;
if (session.listThumb.hasClass('changed')) {
codiad.modal.load(450, 'components/active/dialog.php?action=confirm&path=' + encodeURIComponent(path));
closeFile = false;
}
if (closeFile) {
this.close(path);
}
},
removeAll: function(discard) {
discard = discard || false;
/* Notify listeners. */
amplify.publish('active.onRemoveAll');
var _this = this;
var changed = false;
var opentabs = new Array();
for(var session in _this.sessions) {
opentabs[session] = session;
if (_this.sessions[session].listThumb.hasClass('changed')) {
changed = true;
}
}
if(changed && !discard) {
codiad.modal.load(450, 'components/active/dialog.php?action=confirmAll');
return;
}
for(var tab in opentabs) {
var session = this.sessions[tab];
session.tabThumb.remove();
_this.updateTabDropdownVisibility();
session.listThumb.remove();
/* Remove closed path from history */
var history = [];
$.each(this.history, function(index) {
if(this != tab) history.push(this);
})
this.history = history
delete this.sessions[tab];
this.removeDraft(tab);
}
codiad.editor.exterminate();
$('#list-active-files').html('');
$.get(this.controller + '?action=removeall');
},
close: function(path) {
/* Notify listeners. */
amplify.publish('active.onClose', path);
var _this = this;
var session = this.sessions[path];
/* Animate only if the tabThumb if a tab, not a dropdown item. */
if(session.tabThumb.hasClass('tab-item')) {
session.tabThumb.css({'z-index': 1});
session.tabThumb.animate({
top: $('#editor-top-bar').height() + 'px'
}, 300, function() {
session.tabThumb.remove();
_this.updateTabDropdownVisibility();
});
} else {
session.tabThumb.remove();
_this.updateTabDropdownVisibility();
}
session.listThumb.remove();
/* Remove closed path from history */
var history = [];
$.each(this.history, function(index) {
if(this != path) history.push(this);
})
this.history = history
/* Select all the tab tumbs except the one which is to be removed. */
var tabThumbs = $('#tab-list-active-files li[data-path!="' + path + '"]');
if (tabThumbs.length == 0) {
codiad.editor.exterminate();
} else {
var nextPath = '';
if(this.history.length > 0) {
nextPath = this.history[this.history.length - 1];
} else {
nextPath = $(tabThumbs[0]).attr('data-path');
}
var nextSession = this.sessions[nextPath];
codiad.editor.removeSession(session, nextSession);
this.focus(nextPath);
}
delete this.sessions[path];
$.get(this.controller + '?action=remove&path=' + encodeURIComponent(path));
this.removeDraft(path);
},
//////////////////////////////////////////////////////////////////
// Process rename
//////////////////////////////////////////////////////////////////
rename: function(oldPath, newPath) {
var switchSessions = function(oldPath, newPath) {
var tabThumb = this.sessions[oldPath].tabThumb;
tabThumb.attr('data-path', newPath);
var title = newPath;
if (codiad.project.isAbsPath(newPath)) {
title = newPath.substring(1);
}
tabThumb.find('.label')
.text(title);
this.sessions[newPath] = this.sessions[oldPath];
this.sessions[newPath].path = newPath;
delete this.sessions[oldPath];
//Rename history
for (var i = 0; i < this.history.length; i++) {
if (this.history[i] === oldPath) {
this.history[i] = newPath;
}
}
};
if (this.sessions[oldPath]) {
// A file was renamed
switchSessions.apply(this, [oldPath, newPath]);
// pass new sessions instance to setactive
for (var k = 0; k < codiad.editor.instances.length; k++) {
if (codiad.editor.instances[k].getSession().path === newPath) {
codiad.editor.setActive(codiad.editor.instances[k]);
}
}
var newSession = this.sessions[newPath];
// Change Editor Mode
var ext = codiad.filemanager.getExtension(newPath);
var mode = codiad.editor.selectMode(ext);
// handle async mode change
var fn = function() {
codiad.editor.setModeDisplay(newSession);
newSession.removeListener('changeMode', fn);
}
newSession.on("changeMode", fn);
newSession.setMode( mode.mode );
} else {
// A folder was renamed
var newKey;
for (var key in this.sessions) {
newKey = key.replace(oldPath, newPath);
if (newKey !== key) {
switchSessions.apply(this, [key, newKey]);
}
}
}
$.get(this.controller + '?action=rename&old_path=' + encodeURIComponent(oldPath) + '&new_path=' + encodeURIComponent(newPath), function() {
/* Notify listeners. */
amplify.publish('active.onRename', {"oldPath": oldPath, "newPath": newPath});
});
},
//////////////////////////////////////////////////////////////////
// Open in Browser
//////////////////////////////////////////////////////////////////
openInBrowser: function() {
var path = this.getPath();
if (path) {
codiad.filemanager.openInBrowser(path);
} else {
codiad.message.error('No Open Files');
}
},
//////////////////////////////////////////////////////////////////
// Get Selected Text
//////////////////////////////////////////////////////////////////
getSelectedText: function() {
var path = this.getPath();
var session = this.sessions[path];
if (path && this.isOpen(path)) {
return session.getTextRange(
codiad.editor.getActive()
.getSelectionRange());
} else {
codiad.message.error(i18n('No Open Files or Selected Text'));
}
},
//////////////////////////////////////////////////////////////////
// Insert Text
//////////////////////////////////////////////////////////////////
insertText: function(val) {
codiad.editor.getActive()
.insert(val);
},
//////////////////////////////////////////////////////////////////
// Goto Line
//////////////////////////////////////////////////////////////////
gotoLine: function(line) {
codiad.editor.getActive()
.gotoLine(line, 0, true);
},
//////////////////////////////////////////////////////////////////
// Move Up (Key Combo)
//////////////////////////////////////////////////////////////////
move: function(dir) {
var num = $('#tab-list-active-files li').length;
if (num === 0) return;
var newActive = null;
var active = null;
if (dir == 'up') {
// If active is in the tab list
active = $('#tab-list-active-files li.active');
if(active.length > 0) {
// Previous or rotate to the end
newActive = active.prev('li');
if (newActive.length === 0) {
newActive = $('#dropdown-list-active-files li:last-child')
if (newActive.length === 0) {
newActive = $('#tab-list-active-files li:last-child')
}
}
}
// If active is in the dropdown list
active = $('#dropdown-list-active-files li.active');
if(active.length > 0) {
// Previous
newActive = active.prev('li');
if (newActive.length === 0) {
newActive = $('#tab-list-active-files li:last-child')
}
}
} else {
// If active is in the tab list
active = $('#tab-list-active-files li.active');
if(active.length > 0) {
// Next or rotate to the beginning
newActive = active.next('li');
if (newActive.length === 0) {
newActive = $('#dropdown-list-active-files li:first-child');
if (newActive.length === 0) {
newActive = $('#tab-list-active-files li:first-child')
}
}
}
// If active is in the dropdown list
active = $('#dropdown-list-active-files li.active');
if(active.length > 0) {
// Next or rotate to the beginning
newActive = active.next('li');
if (newActive.length === 0) {
newActive = $('#tab-list-active-files li:first-child')
}
}
}
if(newActive) this.focus(newActive.attr('data-path'), false);
},
//////////////////////////////////////////////////////////////////
// Dropdown Menu
//////////////////////////////////////////////////////////////////
initTabDropdownMenu: function() {
var _this = this;
var menu = $('#dropdown-list-active-files');
var button = $('#tab-dropdown-button');
var closebutton = $('#tab-close-button');
menu.appendTo($('body'));
button.click(function(e) {
e.stopPropagation();
_this.toggleTabDropdownMenu();
});
closebutton.click(function(e) {
e.stopPropagation();
_this.removeAll();
});
},
showTabDropdownMenu: function() {
var menu = $('#dropdown-list-active-files');
if(!menu.is(':visible')) this.toggleTabDropdownMenu();
},
hideTabDropdownMenu: function() {
var menu = $('#dropdown-list-active-files');
if(menu.is(':visible')) this.toggleTabDropdownMenu();
},
toggleTabDropdownMenu: function() {
var _this = this;
var menu = $('#dropdown-list-active-files');
menu.css({
top: $("#editor-top-bar").height() + 'px',
right: '20px',
width: '200px'
});
menu.slideToggle('fast');
if(menu.is(':visible')) {
// handle click-out autoclosing
var fn = function() {
menu.hide();
$(window).off('click', fn)
}
$(window).on('click', fn);
}
},
moveTabToDropdownMenu: function(tab, prepend) {
if (prepend === undefined) {
prepend = false;
}
tab.remove();
path = tab.attr('data-path');
var tabThumb = this.createMenuItemThumb(path);
if(prepend) $('#dropdown-list-active-files').prepend(tabThumb);
else $('#dropdown-list-active-files').append(tabThumb);
if(tab.hasClass("changed")) {
tabThumb.addClass("changed");
}
if(tab.hasClass("active")) {
tabThumb.addClass("active");
}
this.sessions[path].tabThumb = tabThumb;
},
moveDropdownMenuItemToTab: function(menuItem, prepend) {
if (prepend === undefined) {
prepend = false;
}
menuItem.remove();
path = menuItem.attr('data-path');
var tabThumb = this.createTabThumb(path);
if(prepend) $('#tab-list-active-files').prepend(tabThumb);
else $('#tab-list-active-files').append(tabThumb);
if(menuItem.hasClass("changed")) {
tabThumb.addClass("changed");
}
if(menuItem.hasClass("active")) {
tabThumb.addClass("active");
}
this.sessions[path].tabThumb = tabThumb;
},
isTabListOverflowed: function(includeFictiveTab) {
if (includeFictiveTab === undefined) {
includeFictiveTab = false;
}
var tabs = $('#tab-list-active-files li');
var count = tabs.length
if (includeFictiveTab) count += 1;
if (count <= 1) return false;
var width = 0;
tabs.each(function(index) {
width += $(this).outerWidth(true);
})
if (includeFictiveTab) {
width += $(tabs[tabs.length-1]).outerWidth(true);
}
/* If we subtract the width of the left side bar, of the right side
* bar handle and of the tab dropdown handle to the window width,
* do we have enough room for the tab list? Its kind of complicated
* to handle all the offsets, so afterwards we add a fixed offset
* just t be sure. */
var lsbarWidth = $(".sidebar-handle").width();
if (codiad.sidebars.isLeftSidebarOpen) {
lsbarWidth = $("#sb-left").width();
}
var rsbarWidth = $(".sidebar-handle").width();
if (codiad.sidebars.isRightSidebarOpen) {
rsbarWidth = $("#sb-right").width();
}
var tabListWidth = $("#tab-list-active-files").width();
var dropdownWidth = $('#tab-dropdown').width();
var closeWidth = $('#tab-close').width();
var room = window.innerWidth - lsbarWidth - rsbarWidth - dropdownWidth - closeWidth - width - 30;
return (room < 0);
},
updateTabDropdownVisibility: function() {
while(this.isTabListOverflowed()) {
var tab = $('#tab-list-active-files li:last-child');
if (tab.length == 1) this.moveTabToDropdownMenu(tab, true);
else break;
}
while(!this.isTabListOverflowed(true)) {
var menuItem = $('#dropdown-list-active-files li:first-child');
if (menuItem.length == 1) this.moveDropdownMenuItemToTab(menuItem);
else break;
}
if ($('#dropdown-list-active-files li').length > 0) {
$('#tab-dropdown').show();
} else {
$('#tab-dropdown').hide();
// Be sure to hide the menu if it is opened.
$('#dropdown-list-active-files').hide();
}
if ($('#tab-list-active-files li').length > 1) {
$('#tab-close').show();
} else {
$('#tab-close').hide();
}
},
//////////////////////////////////////////////////////////////////
// Factory
//////////////////////////////////////////////////////////////////
splitDirectoryAndFileName: function(path) {
var index = path.lastIndexOf('/');
return {
fileName: path.substring(index + 1),
directory: (path.indexOf('/') == 0)? path.substring(1, index + 1):path.substring(0, index + 1)
}
},
createListThumb: function(path) {
return $('<li data-path="' + path + '"><a title="'+path+'"><span></span><div>' + path + '</div></a></li>');
},
createTabThumb: function(path) {
split = this.splitDirectoryAndFileName(path);
return $('<li class="tab-item" data-path="' + path + '"><a class="label" title="' + path + '">'
+ split.directory + '<span class="file-name">' + split.fileName + '</span>'
+ '</a><a class="close">x</a></li>');
},
createMenuItemThumb: function(path) {
split = this.splitDirectoryAndFileName(path);
return $('<li data-path="' + path + '"><a title="' + path + '"><span class="label"></span><div class="label">'
+ split.directory + '<span class="file-name">' + split.fileName + '</span>'
+ '</div></a></li>');
},
};
})(this, jQuery);