<commit_before>Webos.require([
	'/usr/lib/jquery.filedrop.js',
	'/usr/lib/fileuploader.js',
	'/usr/lib/webos/applications.js',
	'/usr/lib/webos/data.js'
], function() {
	(function($) {
		$.fn.setCursorPosition = function(pos1, pos2) {
			this.each(function(index, elem) {
				if (elem.setSelectionRange) {
					elem.setSelectionRange(pos1, pos2);
				} else if (elem.createTextRange) {
					var range = elem.createTextRange();
					range.collapse(true);
					range.moveEnd('character', pos1);
					range.moveStart('character', pos2);
					range.select();
				}
			});
			return this;
		};
	})(jQuery);

	$.webos.widget('nautilus', 'container', {
		_name: 'nautilus',
		_translationsName: 'nautilus',
		_organizedIconsConfig: 'nautilus-icons',
		options: {
			directory: '~',
			multipleWindows: false,
			uploads: [],
			display: 'icons',
			showHiddenFiles: false,
			organizeIcons: false,
			_items: {}
		},
		_create: function() {
			this._super('_create');

			var that = this;
			var t = this.translations();
			
			this.element.scrollPane({
				autoReload: true
			});
			this.options._components.container = this.element.scrollPane('content');
			
			this._insertContent();

			this.content().click(function(event) {
				var item;
				if ($(event.target).is('li, tr')) {
					item = $(event.target);
				} else if ($(event.target).parents('li, tr').length > 0) {
					item = $(event.target).parents('li, tr').first();
				} else {
					that.getSelection().removeClass('active').trigger('unselect');
					return;
				}
				
				if ($.webos.keyboard.pressed('ctrl')) {
					item.addClass('active').trigger('select');
				} else {
					that.getSelection().trigger('unselect').removeClass('active');
					item.addClass('active').trigger('select');
				}
			});
			
			$.webos.keyboard.bind(this.element, 'enter', function(e) {
				if (e.isFocused) {
					return;
				}
				
				that.getSelection().each(function() {
					$(this).data('nautilus').open();
				});
			});
			$.webos.keyboard.bind(this.element, 'del', function(e) {
				if (e.isFocused) {
					return;
				}
				
				that.getSelection().each(function() {
					$(this).data('nautilus').remove();
				});
			});
			
			$.webos.keyboard.bind(this.element, 'right', function(e) {
				if (e.isFocused) {
					return;
				}
				
				var selectedElements = that.getSelection().trigger('unselect').removeClass('active');
				var elementToSelect = selectedElements.last().next(':visible');
				if (elementToSelect.length > 0) {
					elementToSelect.addClass('active').trigger('select');
				}
			});
			$.webos.keyboard.bind(this.element, 'left', function(e) {
				if (e.isFocused) {
					return;
				}
				
				var selectedElements = that.getSelection().trigger('unselect').removeClass('active');
				var elementToSelect = selectedElements.last().prev(':visible');
				if (elementToSelect.length > 0) {
					elementToSelect.addClass('active').trigger('select');
				}
			});

			//Webos.User.bind('login logout', function() {
			//	that.refresh();
			//});

			this.readDir(this.options.directory);
		},
		_insertContent: function() {
			var that = this, t = this.translations();

			if (this.options._content) {
				$(this.options._components.filesList).remove();
			}

			if (this.options.display == 'icons') {
				this.options._content = $('<ul></ul>').addClass('icons').appendTo(this.options._components.container);

				this.content().mousedown(function(e) {
					if(e.button !== 0) {
						return;
					}
					
					if (that.content().is(e.target)) {
						var offset = $(this).offset();
						var dimentions = {
							width: $(this).width(),
							height: $(this).height()
						};
						var diff = [offset.left, offset.top];
						var pos = [e.pageX - diff[0], e.pageY - diff[1]];
						
						var helper = $('<div></div>')
							.addClass('ui-selectable-helper')
							.css('top', pos[1])
							.css('left', pos[0])
							.css('width', 0)
							.css('height', 0)
							.css('position','absolute')
							.appendTo(that.content());
						
						$(document).bind('mousemove.'+that.id()+'.nautilus.widget.webos', function(e) {
							var x1 = pos[0], y1 = pos[1], x2 = e.pageX - diff[0], y2 = e.pageY - diff[1], tmp;
							if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
							if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
							if (x1 < 0) { x1 = 0; }
							if (y1 < 0) { y1 = 0; }
							if (x2 > dimentions.width) { x2 = dimentions.width; }
							if (y2 > dimentions.height) { y2 = dimentions.height; }
							helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});
							
							that.items().each(function() {
								var elPos = $(this).position();
								var elPos1 = { left: elPos.left, top: elPos.top };
								var elPos2 = { left: elPos1.left + $(this).outerWidth(), top: elPos1.top + $(this).outerHeight() };
								var hit = ( !(elPos1.left > x2 || elPos2.left < x1 || elPos1.top > y2 || elPos2.top < y1) );
								if (hit) {
									$(this).addClass('active');
								} else if($(this).is('.active')) {
									$(this).removeClass('active');
								}
							});
							
							e.preventDefault();
						});
						
						$(document).one('mouseup', function(e) {
							$(document).unbind('mousemove.'+that.id()+'.nautilus.widget.webos');
							helper.fadeOut('fast', function() {
								$(this).remove();
							});
							e.preventDefault();
						});
					}
					
					e.preventDefault();
					
					if ($(this).is(e.target)) {
						that.getSelection().removeClass('active');
						$(this).trigger('click');
					}
				});
			}

			if (this.options.display == 'list') {
				this.options._content = $.w.list([t.get('Name'), t.get('Size'), t.get('Type')]).appendTo(this.options._components.container);
			}

			this.options._components.filesList = this.content();
		},
		items: function() {
			if (this.options.display == 'icons') {
				return this.content().children('li').filter(':visible');
			}
			if (this.options.display == 'list') {
				return this.content().list('content').children('tr').filter(':visible');
			}
		},
		readDir: function(dir, userCallback) {
			var that = this, t = this.translations();
			var op = Webos.Operation.create();

			if (typeof this.options._components.contextmenu != 'undefined') {
				this.options._components.contextmenu.contextMenu('destroy');
				delete this.options._components.contextmenu;
			}

			dir = W.File.cleanPath(dir);

			userCallback = W.Callback.toCallback(userCallback, [function() {}, function(res) {
				that._handleResponseError(res, t.get('Can\'t find « ${dir} ».', { dir: dir }));
			}]);
			op.addCallbacks(userCallback);

			this._trigger('readstart', { type: 'readstart' }, { location: dir });

			W.File.listDir(dir, [function(files) {
				that.options.directory = dir;
				
				var contextmenu;
				that.options._components.contextmenu = contextmenu = $.w.contextMenu(that.element);
				
				$.webos.menuItem(t.get('Create a new folder')).click(function() {
					that.createFile(t.get('New folder'), true);
				}).appendTo(contextmenu);
				$.webos.menuItem(t.get('Create a new file')).click(function() {
					that.createFile(t.get('New file'));
				}).appendTo(contextmenu);
				$.webos.menuItem(t.get('Download'), true).click(function() {
					that._download(W.File.get(dir));
				}).appendTo(contextmenu);
				$.webos.menuItem(t.get('Upload a file')).click(function() {
					that.openUploadWindow();
				}).appendTo(contextmenu);
				if (Webos.Clipboard) {
					var pasteItem = $.webos.menuItem(t.get('Paste'), true).click(function() {
						var item = Webos.Clipboard.get();
						if (item && item.is(Webos.File)) {
							item.paste(function(file) {
								if (item.operation() == 'cut') {
									that._move(file, dir, function(dest) {
										item.setData(dest);
										item.pasted();
									});
								} else {
									that._copy(file, dir, function(dest) {
										item.pasted();
									});
								}
							}, true);
						}
					}).appendTo(contextmenu);

					var clipboardItem = Webos.Clipboard.get();
					pasteItem.menuItem('option', 'disabled', !(clipboardItem && clipboardItem.is(Webos.File)));

					var copyCallbackId = Webos.Clipboard.bind('copy cut', function(data) {
						var item = Webos.Clipboard.get();
						pasteItem.menuItem('option', 'disabled', !(item && item.is(Webos.File)));
					});
					var clearCallbackId = Webos.Clipboard.bind('clear', function() {
						pasteItem.menuItem('option', 'disabled', true);
					});
					that.element.one('nautilusreadstart', function() {
						Webos.Clipboard.unbind(copyCallbackId);
						Webos.Clipboard.unbind(clearCallbackId);
					});
				}
				$.webos.menuItem(t.get('Refresh'), true).click(function() {
					that.refresh();
				}).appendTo(contextmenu);

				if (that.options.organizeIcons) {
					$.webos.menuItem(t.get('Reset icons position')).click(function() {
						that._resetIconsPosition();
					}).appendTo(contextmenu);
				}

				$.webos.menuItem(t.get('Properties'), true).click(function() {
					that._openProperties(W.File.get(dir));
				}).appendTo(contextmenu);
				
				var serverCall = new W.ServerCall({
					'class': 'FileController',
					'method': 'upload',
					'arguments': {
						dest: dir
					}
				});
				
				var uploadsIds = {};
				that.element.filedrop({
					url: serverCall._url,
					paramname: 'file',
					data: serverCall._data,
					error: function(event, data) {
						switch(data.error) {
							case 'BrowserNotSupported':
								W.Error.trigger(t.get('Your browser does not allow drag and drop. Please upload your files by using classical form.'));
								break;
							case 'TooManyFiles':
								W.Error.trigger(t.get('Too many files sent'));
								break;
							case 'FileTooLarge':
								W.Error.trigger(t.get('The size of the file "${name}" is too large (file size : ${fileSize}, maximum size : ${maxSize})', { name: data.file.name, fileSize: W.File.bytesToSize(data.file.size), maxSize: W.File.bytesToSize(that.element.filedrop('option', 'maxfilesize') * 1024 * 1024) }));
								break;
							default:
								W.Error.trigger(t.get('An error occurred while uploading the file : ${error}', { error: data.error }));
								break;
						}
					},
					maxfiles: 25,
					maxfilesize: 20,
					uploadstarted: function(event, data) {
						uploadsIds[data.index] = $.w.nautilus.progresses.add(0, t.get('Uploading ${name}', { name: data.file.name }));
					},
					uploadfinished: function(event, data) {
						var success = true;
						if (!data.response.isSuccess()) {
							W.Error.trigger(t.get('Can\'t upload the file "${name}"', { name: data.file.name }), data.response.getAllChannels());
							success = false;
						} else if (!data.response.getData().success) {
							W.Error.trigger(t.get('Can\'t upload the file "${name}"', { name: data.file.name }), data.response.getData().msg);
							success = false;
						}
						
						var msg;
						if (success) {
							msg = t.get('Upload completed.');
						} else {
							msg = t.get('Error while uploading.');
						}
						$.w.nautilus.progresses.update(uploadsIds[data.index], 100, msg);
						
						if (success) {
							var newFile = new W.File(data.response.getData().file);
							var newItem = that._renderItem(newFile);
							if (that.location() == newFile.get('dirname')) {
								that._insertItem(newItem);
							}
							
							$.w.notification({
								title: t.get('File uploaded'),
								message: t.get('The file ${name} has been sent', { name: newFile.get('basename') }),
								icon: that._getFileIcon(newFile),
								widgets: [
									$.w.button(t.get('Open the parent folder')).click(function() { W.Cmd.execute('nautilus "'+newFile.get('dirname')+'"'); }),
									$.w.button(t.get('Open')).click(function() { newItem.data('nautilus').open(); })
								]
							});
						}
					},
					progressupdated: function(event, data) {
						$.w.nautilus.progresses.update(uploadsIds[data.index], data.progress);
					},
					speedupdated: function(event, data) {
						$.w.nautilus.progresses.update(uploadsIds[data.index], undefined, t.get('Uploading at ${speed} Kio/s...', { speed: data.speed }));
					}
				});
				
				that.element.droppable({
					drop: function(event, ui) {
						if (!$.w.widget.is(ui.draggable, 'draggable')) { //Required. Bug because it contains draggable elements.
							return;
						}

						if (!ui.draggable.draggable('option', 'sourceFile')) {
							return;
						}

						var sourceFile = ui.draggable.draggable('option', 'sourceFile'),
							destFile = Webos.File.get(dir);

						ui.draggable.trigger('nautilusdrop', [{
							source: sourceFile,
							dest: destFile,
							droppable: that.element,
							draggable: ui.draggable,
							pageX: event.pageX,
							pageY: event.pageY
						}]);
					}
				});
				
				that._render(files);
				
				that._trigger('readcomplete', { type: 'readcomplete' }, { location: that.location() });
				that._trigger('readsuccess', { type: 'readsuccess' }, { location: that.location() });

				op.setCompleted(that);
			}, function(response) {
				that._render([]);
				
				that._trigger('readcomplete', { type: 'readcomplete' }, {
					location: that.location()
				});

				if (!that._trigger('readerror', { type: 'readerror' }, { location: that.location(), response: response })) {
					return;
				}

				op.setCompleted(response);
			}]);

			return op;
		},
		search: function(query, userCallback) {
			var that = this, t = this.translations();

			userCallback = W.Callback.toCallback(userCallback, new W.Callback(function() {}, function(res) {
				that._handleResponseError(res, t.get('Can\'t search for « ${query} ».', { query: query }));
			}));

			if (!query) {
				userCallback.error(Webos.Callback.Result.error('Empty search query'));
				return;
			}

			if (typeof this.options._components.contextmenu != 'undefined') {
				this.options._components.contextmenu.contextMenu('destroy');
				delete this.options._components.contextmenu;
			}

			this._trigger('searchstart', { type: 'searchstart' }, { location: that.location(), query: query });

			W.File.search({
				q: query,
				inDir: this.location()
			}, [function(results) {
				var files = [];
				for (var i = 0; i < results.length; i++) {
					files.push(results[i].get('file'));
				}

				that._render(files);

				that._trigger('searchcomplete', { type: 'searchcomplete' }, { location: that.location(), query: query });
				that._trigger('searchsuccess', { type: 'searchsuccess' }, { location: that.location(), query: query });

				userCallback.success();
			}, function(response) {
				that._render([]);
				
				that._trigger('searchcomplete', { type: 'searchcomplete' }, { location: that.location(), query: query });

				if (!that._trigger('searcherror', { type: 'searcherror' }, { location: that.location(), query: query, response: response })) {
					return;
				}
				
				userCallback.error(response);
			}]);
		},
		sort: function () {
			var sortAttr = this.options.sort;

			var sortedItems = this.items().detach().sort(function (a, b) {
				return ($(a).data('file')().get(sortAttr) > $(b).data('file')().get(sortAttr));
			});

			this._insertItem(sortedItems);
		},
		_update: function(name, value) {
			switch(name) {
				case 'display':
					this.options.display = String(value);
					this._insertContent();
					this.readDir(this.options.directory);
					break;
				case 'sort':
					this.options.sort = String(value || 'basename');
					this.sort();
					break;
			}
		},
		_render: function(files) {
			var that = this;
			
			if (this.options.display == 'icons') {
				this.content().empty();
			}
			if (this.options.display == 'list') {
				this.content().list('content').empty();
			}

			this.options._items = {};
			
			for (var i = 0; i < files.length; i++) {
				(function(file) {
					var item = that._renderItem(file);
					that._insertItem(item);
				})(files[i]);
			}
			
			this.element.scrollPane('reload');
			this._loadIconsPosition();
			
			Webos.File.bind('load._render.nautilus-'+this.id(), function(data) {
				var newFile = data.file;
				
				if (newFile.get('dirname') != that.location()) {
					return;
				}
				
				if (!that.options._items[newFile.get('path')]) {
					var newItem = that._renderItem(newFile);
					that._insertItem(newItem);
					if ($.webos.widget.is(that.element, 'scrollPane')) {
						that.element.scrollPane('reload');
					}
				}
			});
			Webos.File.bind('remove._render.nautilus-'+this.id(), function(data) {
				var oldFile = data.file;
				
				if (oldFile.get('dirname') != that.location()) {
					return;
				}
				
				if (that.options._items[oldFile.get('path')]) {
					that.options._items[oldFile.get('path')].remove();
					delete that.options._items[oldFile.get('path')];
				}
			});
			Webos.File.bind('umount._render.nautilus-'+this.id(), function(data) {
				if (that.location().indexOf(data.local) !== 0) {
					return;
				}
				
				that.readDir('~');
			});
			this.element.one('nautilusreadstart nautilusdestroy', function(e) {
				Webos.File.unbind('load._render.nautilus-'+that.id());
				Webos.File.unbind('remove._render.nautilus-'+that.id());
				Webos.File.unbind('umount._render.nautilus-'+that.id());
			});
		},
		_renderItem: function(file) {
			var that = this,
				t = this.translations(),
				filepath = file.get('path'),
				item = $(),
				icon = $(),
				iconPath = this._getFileIcon(file);

			if (that.options.display == 'icons') {
				item = $('<li></li>').attr('title', file.get('basename'));
				
				icon = $('<img />', { src: iconPath, alt: '' }).addClass('icon');
				icon.appendTo(item);
				
				item.append('<br />');
				
				$('<span></span>')
					.addClass('filename')
					.text(file.get('basename'))
					.appendTo(item);
			} else if (that.options.display == 'list') {
				item = $.w.listItem();
				
				var content = $('<span></span>').attr('title', file.get('basename'));
				item.listItem('addColumn', content);
				
				icon = $('<img />', { src: iconPath, alt: '' }).addClass('icon').appendTo(content);
				
				$('<span></span>').addClass('filename').text(file.get('basename')).appendTo(content);
				
				var size;
				if (file.get('is_dir')) {
					size = t.get('${nbr} element${nbr|s}', { nbr: file.get('size') });
				} else {
					size = W.File.bytesToSize(file.get('size'));
				}
				item.listItem('addColumn', size);
				
				var type;
				if (file.get('is_dir')) {
					type = t.get('Folder');
				} else {
					type = t.get('${extension} file', { extension: file.get('extension') });
				}
				item.listItem('addColumn', type);
			} else {
				return;
			}
			
			item.data('file', function() {
				return Webos.File.get(filepath);
			});
			item.data('nautilus', {
				open: function() {
					var event = jQuery.Event('open');
					item.trigger(event);
					if (!event.isDefaultPrevented()) {
						var file = item.data('file')();
						that._openFile(file);
					}
				},
				openWith: function() {
					var event = jQuery.Event('open');
					item.trigger(event);
					if (!event.isDefaultPrevented()) {
						var file = item.data('file')();
						that.openFileWindow(file);
					}
				},
				download: function() {
					that._download(item.data('file')());
					item.trigger('download');
				},
				rename: function() {
					var file = item.data('file')();

					if (item.find('input[type=text]').length) { //Already renaming this file
						return;
					}

					var renameFn = function() {
						var name = input.val();
						input.remove();
						item.find('.filename').show();
						
						if (name == file.get('basename')) { return; }
						
						file.rename(name);

						$(document).off('click.rename.nautilus');
					};

					var input = $('<input />', { type: 'text' }).keydown(function(e) {
						if (e.keyCode == 13) {
							renameFn();
							e.preventDefault();
						}
					});
					item.find('.filename').hide().after(input);

					//Let the user click in the text input
					input.on('mousedown mouseup click', function (e) {
						e.stopPropagation();
					});

					var pos = file.get('basename').length - ((file.get('extension')) ? (file.get('extension').length + 1) : 0);
					input.val(file.get('basename')).focus().setCursorPosition(0, pos);

					setTimeout(function () { //Delay otherwise the current click event is triggered
						$(document).one('click.rename.nautilus', function () {
							renameFn();
						});
					}, 0);
				},
				remove: function() {
					that._remove(item.data('file')());
				},
				openProperties: function() {
					that._openProperties(item.data('file')());
				},
				share: function () {
					that._openProperties(item.data('file')(), 'share');
				}
			});
			
			item.dblclick(function() {
				$(this).data('nautilus').open();
			});
			
			var contextmenu = $.w.contextMenu(item);
			
			$.webos.menuItem(t.get('Open')).click(function() {
				var files = (that.getSelection().length === 0) ? item : that.getSelection();
				files.each(function() {
					$(this).data('nautilus').open();
				});
			}).appendTo(contextmenu);
			$.webos.menuItem(t.get('Open with...')).click(function() {
				var files = (that.getSelection().length === 0) ? item : that.getSelection();
				files.each(function() {
					$(this).data('nautilus').openWith();
				});
			}).appendTo(contextmenu);
			$.webos.menuItem(t.get('Download')).click(function() {
				var files = (that.getSelection().length === 0) ? item : that.getSelection();
				files.each(function() {
					$(this).data('nautilus').download();
				});
			}).appendTo(contextmenu);
			$.webos.menuItem(t.get('Rename...'), true).click(function() {
				item.data('nautilus').rename();
			}).appendTo(contextmenu);
			$.webos.menuItem(t.get('Delete')).click(function() {
				var files = (that.getSelection().length === 0) ? item : that.getSelection();
				files.each(function() {
					$(this).data('nautilus').remove();
				});
			}).appendTo(contextmenu);
			if (Webos.Clipboard) {
				$.webos.menuItem(t.get('Copy'), true).click(function() {
					Webos.Clipboard.copy(file);
				}).appendTo(contextmenu);
				$.webos.menuItem(t.get('Cut')).click(function() {
					Webos.Clipboard.cut(file);
				}).appendTo(contextmenu);

				if (file.get('is_dir')) {
					var pasteItem = $.webos.menuItem(t.get('Paste')).click(function() {
						var itemToPaste = Webos.Clipboard.get();
						if (itemToPaste && itemToPaste.is(Webos.File)) {
							itemToPaste.paste(function(fileToPaste) {
								if (itemToPaste.operation() == 'cut') {
									that._move(fileToPaste, file, function(dest) {
										itemToPaste.setData(dest);
										itemToPaste.pasted();
									});
								} else {
									that._copy(fileToPaste, file, function(dest) {
										itemToPaste.pasted();
									});
								}
							}, true);
						}
					}).appendTo(contextmenu);

					var clipboardItem = Webos.Clipboard.get();
					pasteItem.menuItem('option', 'disabled', !(clipboardItem && clipboardItem.is(Webos.File)));

					var copyCallbackId = Webos.Clipboard.bind('copy cut', function(data) {
						var item = Webos.Clipboard.get();
						pasteItem.menuItem('option', 'disabled', !(item && item.is(Webos.File)));
					});
					var clearCallbackId = Webos.Clipboard.bind('clear', function() {
						pasteItem.menuItem('option', 'disabled', true);
					});
					that.element.one('nautilusreadstart', function() {
						Webos.Clipboard.unbind(copyCallbackId);
						Webos.Clipboard.unbind(clearCallbackId);
					});
				}
			}
			$.webos.menuItem(t.get('Share'), true).click(function() {
				var files = (that.getSelection().length == 0) ? item : that.getSelection();
				files.each(function() {
					$(this).data('nautilus').share();
				});
			}).appendTo(contextmenu);
			$.webos.menuItem(t.get('Properties')).click(function() {
				var files = (that.getSelection().length == 0) ? item : that.getSelection();
				files.each(function() {
					$(this).data('nautilus').openProperties();
				});
			}).appendTo(contextmenu);
			
			contextmenu.bind('contextmenuopen', function() {
				if (!item.is('.active')) {
					that.getSelection().removeClass('active').trigger('unselect');
					item.addClass('active');
				}
			});
			
			if (file.get('is_dir')) {
				var overIcon = that._getFileIcon(file, 'dropover');
				item.droppable({
					drop: function(event, ui) {
						if (overIcon != iconPath) {
							icon.attr('src', iconPath);
						}

						if (!ui.draggable.draggable('option', 'sourceFile')) {
							return;
						}

						var sourceFile = ui.draggable.draggable('option', 'sourceFile'),
							destFile = item.data('file')();

						ui.draggable.trigger('nautilusdrop', [{ source: sourceFile, dest: destFile, droppable: item }]);
					},
					over: function() {
						if (overIcon != iconPath) {
							icon.attr('src', overIcon);
						}
					},
					out: function() {
						if (overIcon != iconPath) {
							icon.attr('src', iconPath);
						}
					}
				});
			}
			
			var droppableAreas = [];
			item.draggable({
				sourceFile: file,
				dragImage: icon.clone().css({ 'max-width': '48px', 'max-height': '48px' }),
				stop: function(event) {
					setTimeout(function() {
						if (droppableAreas.length == 0) {
							return;
						}

						var doDrop = function(data) {
							var sourceFile = data.source, destFile = data.dest;

							if (data.droppable.is(that.element)) {
								var offset = that.element.offset(),
									dropPos = {
										x: data.pageX - offset.left,
										y: data.pageY - offset.top
									};

								that._setIconPos(sourceFile, dropPos);
								return;
							}

							if (destFile.get('path') == sourceFile.get('dirname')) {
								return;
							}
							if (destFile.get('path') == sourceFile.get('path')) {
								return;
							}

							destFile.load([function() {
								if (destFile.get('path') == sourceFile.get('dirname')) {
									return;
								}
								if (destFile.get('path') == sourceFile.get('path')) {
									return;
								}

								var operation = 'move';
								if (sourceFile.get('mountPoint') || destFile.get('mountPoint')) {
									if (sourceFile.get('mountPoint') != destFile.get('mountPoint')) {
										operation = 'copy';
									}
								}

								that['_'+operation](sourceFile, destFile, [function() {}, function(resp) {
									that._handleResponseError(resp);
								}]);
							}, function(resp) {
								that._handleResponseError(resp);
							}]);
						};

						if (droppableAreas.length == 1) {
							doDrop(droppableAreas[0]);
						} else {
							//TODO: integrate z-index support in draggable widget
							var maxZIndex = -1, maxZIndexArea = null;
							for (var i = 0; i < droppableAreas.length; i++) {
								var dropArea = droppableAreas[i],
									$droppable = dropArea.droppable;

								var handleZIndex = function(zIndex) {
									if (/[0-9]/.test(zIndex)) {
										zIndex = parseInt(zIndex);
										if (maxZIndex <= zIndex) {
											maxZIndex = zIndex;
											maxZIndexArea = dropArea;
										}
									}
								};

								handleZIndex($droppable.css('z-index'));

								$droppable.parents().each(function() {
									handleZIndex($(this).css('z-index'));
								});
							}

							if (!maxZIndexArea) {
								maxZIndexArea = droppableAreas.pop(); //No z-index, the one which is over others is the last one
							}

							doDrop(maxZIndexArea);
						}

						droppableAreas = [];
					}, 0);
				}
			});
			item.on('nautilusdrop', function(event, data) { //Triggered when a file is drop on a nautilus AREA only (not on a folder icon)
				droppableAreas.push(data);
			});
			
			if (/^\./.test(file.get('basename'))) { //C'est un fichier cache, on ne l'affiche pas
				item.addClass('hidden');
				if (!this.options.showHiddenFiles) {
					item.hide();
				}
			}

			if (file.is('hidden')) {
				item.addClass('hidden');
				if (!this.options.showHiddenFiles) {
					item.hide();
				}
			}
			if (file.is('trashed')) {
				item.hide();
			}
			
			var updateCallbackId = file.bind('update', function(data) {
				file.unbind('update', updateCallbackId);

				var newItem = that._renderItem(file);
				item.replaceWith(newItem);
				item = newItem;
				that.options._items[filepath] = newItem;
			});
			
			this.element.one('nautilusreadcomplete', function() {
				file.unbind('update', updateCallbackId);
			});

			this.options._items[filepath] = item;
			
			return item;
		},
		_insertItem: function(item) {
			if (this.options.display == 'icons') {
				this.content().append(item);
			}
			if (this.options.display == 'list') {
				this.content().list('content').append(item);
			}
		},
		_setIconPos: function (file, pos) {
			if (!this.options.organizeIcons) {
				return false;
			}

			file = W.File.get(file);

			var $item = this.options._items[file.get('path')];
			if (!$item) {
				return;
			}

			$item.css({
				position: 'absolute',
				left: pos.x - $item.outerWidth(true) / 2,
				top: pos.y - $item.outerHeight(true) / 2
			});

			this._saveIconsPosition();
		},
		_resetIconPos: function (file) {
			if (!this.options.organizeIcons) {
				return false;
			}
<commit_msg>Icons now stick to grid in nautilus. See #354.<commit_after>Webos.require([
	'/usr/lib/jquery.filedrop.js',
	'/usr/lib/fileuploader.js',
	'/usr/lib/webos/applications.js',
	'/usr/lib/webos/data.js'
], function() {
	(function($) {
		$.fn.setCursorPosition = function(pos1, pos2) {
			this.each(function(index, elem) {
				if (elem.setSelectionRange) {
					elem.setSelectionRange(pos1, pos2);
				} else if (elem.createTextRange) {
					var range = elem.createTextRange();
					range.collapse(true);
					range.moveEnd('character', pos1);
					range.moveStart('character', pos2);
					range.select();
				}
			});
			return this;
		};
	})(jQuery);

	$.webos.widget('nautilus', 'container', {
		_name: 'nautilus',
		_translationsName: 'nautilus',
		_organizedIconsConfig: 'nautilus-icons',
		options: {
			directory: '~',
			multipleWindows: false,
			uploads: [],
			display: 'icons',
			showHiddenFiles: false,
			organizeIcons: false,
			organizeIconsInGrid: true,
			_items: {}
		},
		_create: function() {
			this._super('_create');

			var that = this;
			var t = this.translations();
			
			this.element.scrollPane({
				autoReload: true
			});
			this.options._components.container = this.element.scrollPane('content');
			
			this._insertContent();

			this.content().click(function(event) {
				var item;
				if ($(event.target).is('li, tr')) {
					item = $(event.target);
				} else if ($(event.target).parents('li, tr').length > 0) {
					item = $(event.target).parents('li, tr').first();
				} else {
					that.getSelection().removeClass('active').trigger('unselect');
					return;
				}
				
				if ($.webos.keyboard.pressed('ctrl')) {
					item.addClass('active').trigger('select');
				} else {
					that.getSelection().trigger('unselect').removeClass('active');
					item.addClass('active').trigger('select');
				}
			});
			
			$.webos.keyboard.bind(this.element, 'enter', function(e) {
				if (e.isFocused) {
					return;
				}
				
				that.getSelection().each(function() {
					$(this).data('nautilus').open();
				});
			});
			$.webos.keyboard.bind(this.element, 'del', function(e) {
				if (e.isFocused) {
					return;
				}
				
				that.getSelection().each(function() {
					$(this).data('nautilus').remove();
				});
			});
			
			$.webos.keyboard.bind(this.element, 'right', function(e) {
				if (e.isFocused) {
					return;
				}
				
				var selectedElements = that.getSelection().trigger('unselect').removeClass('active');
				var elementToSelect = selectedElements.last().next(':visible');
				if (elementToSelect.length > 0) {
					elementToSelect.addClass('active').trigger('select');
				}
			});
			$.webos.keyboard.bind(this.element, 'left', function(e) {
				if (e.isFocused) {
					return;
				}
				
				var selectedElements = that.getSelection().trigger('unselect').removeClass('active');
				var elementToSelect = selectedElements.last().prev(':visible');
				if (elementToSelect.length > 0) {
					elementToSelect.addClass('active').trigger('select');
				}
			});

			//Webos.User.bind('login logout', function() {
			//	that.refresh();
			//});

			this.readDir(this.options.directory);
		},
		_insertContent: function() {
			var that = this, t = this.translations();

			if (this.options._content) {
				$(this.options._components.filesList).remove();
			}

			if (this.options.display == 'icons') {
				this.options._content = $('<ul></ul>').addClass('icons').appendTo(this.options._components.container);

				this.content().mousedown(function(e) {
					if(e.button !== 0) {
						return;
					}
					
					if (that.content().is(e.target)) {
						var offset = $(this).offset();
						var dimentions = {
							width: $(this).width(),
							height: $(this).height()
						};
						var diff = [offset.left, offset.top];
						var pos = [e.pageX - diff[0], e.pageY - diff[1]];
						
						var helper = $('<div></div>')
							.addClass('ui-selectable-helper')
							.css('top', pos[1])
							.css('left', pos[0])
							.css('width', 0)
							.css('height', 0)
							.css('position','absolute')
							.appendTo(that.content());
						
						$(document).bind('mousemove.'+that.id()+'.nautilus.widget.webos', function(e) {
							var x1 = pos[0], y1 = pos[1], x2 = e.pageX - diff[0], y2 = e.pageY - diff[1], tmp;
							if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
							if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
							if (x1 < 0) { x1 = 0; }
							if (y1 < 0) { y1 = 0; }
							if (x2 > dimentions.width) { x2 = dimentions.width; }
							if (y2 > dimentions.height) { y2 = dimentions.height; }
							helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});
							
							that.items().each(function() {
								var elPos = $(this).position();
								var elPos1 = { left: elPos.left, top: elPos.top };
								var elPos2 = { left: elPos1.left + $(this).outerWidth(), top: elPos1.top + $(this).outerHeight() };
								var hit = ( !(elPos1.left > x2 || elPos2.left < x1 || elPos1.top > y2 || elPos2.top < y1) );
								if (hit) {
									$(this).addClass('active');
								} else if($(this).is('.active')) {
									$(this).removeClass('active');
								}
							});
							
							e.preventDefault();
						});
						
						$(document).one('mouseup', function(e) {
							$(document).unbind('mousemove.'+that.id()+'.nautilus.widget.webos');
							helper.fadeOut('fast', function() {
								$(this).remove();
							});
							e.preventDefault();
						});
					}
					
					e.preventDefault();
					
					if ($(this).is(e.target)) {
						that.getSelection().removeClass('active');
						$(this).trigger('click');
					}
				});
			}

			if (this.options.display == 'list') {
				this.options._content = $.w.list([t.get('Name'), t.get('Size'), t.get('Type')]).appendTo(this.options._components.container);
			}

			this.options._components.filesList = this.content();
		},
		items: function() {
			if (this.options.display == 'icons') {
				return this.content().children('li').filter(':visible');
			}
			if (this.options.display == 'list') {
				return this.content().list('content').children('tr').filter(':visible');
			}
		},
		readDir: function(dir, userCallback) {
			var that = this, t = this.translations();
			var op = Webos.Operation.create();

			if (typeof this.options._components.contextmenu != 'undefined') {
				this.options._components.contextmenu.contextMenu('destroy');
				delete this.options._components.contextmenu;
			}

			dir = W.File.cleanPath(dir);

			userCallback = W.Callback.toCallback(userCallback, [function() {}, function(res) {
				that._handleResponseError(res, t.get('Can\'t find « ${dir} ».', { dir: dir }));
			}]);
			op.addCallbacks(userCallback);

			this._trigger('readstart', { type: 'readstart' }, { location: dir });

			W.File.listDir(dir, [function(files) {
				that.options.directory = dir;
				
				var contextmenu;
				that.options._components.contextmenu = contextmenu = $.w.contextMenu(that.element);
				
				$.webos.menuItem(t.get('Create a new folder')).click(function() {
					that.createFile(t.get('New folder'), true);
				}).appendTo(contextmenu);
				$.webos.menuItem(t.get('Create a new file')).click(function() {
					that.createFile(t.get('New file'));
				}).appendTo(contextmenu);
				$.webos.menuItem(t.get('Download'), true).click(function() {
					that._download(W.File.get(dir));
				}).appendTo(contextmenu);
				$.webos.menuItem(t.get('Upload a file')).click(function() {
					that.openUploadWindow();
				}).appendTo(contextmenu);
				if (Webos.Clipboard) {
					var pasteItem = $.webos.menuItem(t.get('Paste'), true).click(function() {
						var item = Webos.Clipboard.get();
						if (item && item.is(Webos.File)) {
							item.paste(function(file) {
								if (item.operation() == 'cut') {
									that._move(file, dir, function(dest) {
										item.setData(dest);
										item.pasted();
									});
								} else {
									that._copy(file, dir, function(dest) {
										item.pasted();
									});
								}
							}, true);
						}
					}).appendTo(contextmenu);

					var clipboardItem = Webos.Clipboard.get();
					pasteItem.menuItem('option', 'disabled', !(clipboardItem && clipboardItem.is(Webos.File)));

					var copyCallbackId = Webos.Clipboard.bind('copy cut', function(data) {
						var item = Webos.Clipboard.get();
						pasteItem.menuItem('option', 'disabled', !(item && item.is(Webos.File)));
					});
					var clearCallbackId = Webos.Clipboard.bind('clear', function() {
						pasteItem.menuItem('option', 'disabled', true);
					});
					that.element.one('nautilusreadstart', function() {
						Webos.Clipboard.unbind(copyCallbackId);
						Webos.Clipboard.unbind(clearCallbackId);
					});
				}
				$.webos.menuItem(t.get('Refresh'), true).click(function() {
					that.refresh();
				}).appendTo(contextmenu);

				if (that.options.organizeIcons) {
					$.webos.menuItem(t.get('Reset icons position')).click(function() {
						that._resetIconsPosition();
					}).appendTo(contextmenu);
				}

				$.webos.menuItem(t.get('Properties'), true).click(function() {
					that._openProperties(W.File.get(dir));
				}).appendTo(contextmenu);
				
				var serverCall = new W.ServerCall({
					'class': 'FileController',
					'method': 'upload',
					'arguments': {
						dest: dir
					}
				});
				
				var uploadsIds = {};
				that.element.filedrop({
					url: serverCall._url,
					paramname: 'file',
					data: serverCall._data,
					error: function(event, data) {
						switch(data.error) {
							case 'BrowserNotSupported':
								W.Error.trigger(t.get('Your browser does not allow drag and drop. Please upload your files by using classical form.'));
								break;
							case 'TooManyFiles':
								W.Error.trigger(t.get('Too many files sent'));
								break;
							case 'FileTooLarge':
								W.Error.trigger(t.get('The size of the file "${name}" is too large (file size : ${fileSize}, maximum size : ${maxSize})', { name: data.file.name, fileSize: W.File.bytesToSize(data.file.size), maxSize: W.File.bytesToSize(that.element.filedrop('option', 'maxfilesize') * 1024 * 1024) }));
								break;
							default:
								W.Error.trigger(t.get('An error occurred while uploading the file : ${error}', { error: data.error }));
								break;
						}
					},
					maxfiles: 25,
					maxfilesize: 20,
					uploadstarted: function(event, data) {
						uploadsIds[data.index] = $.w.nautilus.progresses.add(0, t.get('Uploading ${name}', { name: data.file.name }));
					},
					uploadfinished: function(event, data) {
						var success = true;
						if (!data.response.isSuccess()) {
							W.Error.trigger(t.get('Can\'t upload the file "${name}"', { name: data.file.name }), data.response.getAllChannels());
							success = false;
						} else if (!data.response.getData().success) {
							W.Error.trigger(t.get('Can\'t upload the file "${name}"', { name: data.file.name }), data.response.getData().msg);
							success = false;
						}
						
						var msg;
						if (success) {
							msg = t.get('Upload completed.');
						} else {
							msg = t.get('Error while uploading.');
						}
						$.w.nautilus.progresses.update(uploadsIds[data.index], 100, msg);
						
						if (success) {
							var newFile = new W.File(data.response.getData().file);
							var newItem = that._renderItem(newFile);
							if (that.location() == newFile.get('dirname')) {
								that._insertItem(newItem);
							}
							
							$.w.notification({
								title: t.get('File uploaded'),
								message: t.get('The file ${name} has been sent', { name: newFile.get('basename') }),
								icon: that._getFileIcon(newFile),
								widgets: [
									$.w.button(t.get('Open the parent folder')).click(function() { W.Cmd.execute('nautilus "'+newFile.get('dirname')+'"'); }),
									$.w.button(t.get('Open')).click(function() { newItem.data('nautilus').open(); })
								]
							});
						}
					},
					progressupdated: function(event, data) {
						$.w.nautilus.progresses.update(uploadsIds[data.index], data.progress);
					},
					speedupdated: function(event, data) {
						$.w.nautilus.progresses.update(uploadsIds[data.index], undefined, t.get('Uploading at ${speed} Kio/s...', { speed: data.speed }));
					}
				});
				
				that.element.droppable({
					drop: function(event, ui) {
						if (!$.w.widget.is(ui.draggable, 'draggable')) { //Required. Bug because it contains draggable elements.
							return;
						}

						if (!ui.draggable.draggable('option', 'sourceFile')) {
							return;
						}

						var sourceFile = ui.draggable.draggable('option', 'sourceFile'),
							destFile = Webos.File.get(dir);

						ui.draggable.trigger('nautilusdrop', [{
							source: sourceFile,
							dest: destFile,
							droppable: that.element,
							draggable: ui.draggable,
							pageX: event.pageX,
							pageY: event.pageY
						}]);
					}
				});
				
				that._render(files);
				
				that._trigger('readcomplete', { type: 'readcomplete' }, { location: that.location() });
				that._trigger('readsuccess', { type: 'readsuccess' }, { location: that.location() });

				op.setCompleted(that);
			}, function(response) {
				that._render([]);
				
				that._trigger('readcomplete', { type: 'readcomplete' }, {
					location: that.location()
				});

				if (!that._trigger('readerror', { type: 'readerror' }, { location: that.location(), response: response })) {
					return;
				}

				op.setCompleted(response);
			}]);

			return op;
		},
		search: function(query, userCallback) {
			var that = this, t = this.translations();

			userCallback = W.Callback.toCallback(userCallback, new W.Callback(function() {}, function(res) {
				that._handleResponseError(res, t.get('Can\'t search for « ${query} ».', { query: query }));
			}));

			if (!query) {
				userCallback.error(Webos.Callback.Result.error('Empty search query'));
				return;
			}

			if (typeof this.options._components.contextmenu != 'undefined') {
				this.options._components.contextmenu.contextMenu('destroy');
				delete this.options._components.contextmenu;
			}

			this._trigger('searchstart', { type: 'searchstart' }, { location: that.location(), query: query });

			W.File.search({
				q: query,
				inDir: this.location()
			}, [function(results) {
				var files = [];
				for (var i = 0; i < results.length; i++) {
					files.push(results[i].get('file'));
				}

				that._render(files);

				that._trigger('searchcomplete', { type: 'searchcomplete' }, { location: that.location(), query: query });
				that._trigger('searchsuccess', { type: 'searchsuccess' }, { location: that.location(), query: query });

				userCallback.success();
			}, function(response) {
				that._render([]);
				
				that._trigger('searchcomplete', { type: 'searchcomplete' }, { location: that.location(), query: query });

				if (!that._trigger('searcherror', { type: 'searcherror' }, { location: that.location(), query: query, response: response })) {
					return;
				}
				
				userCallback.error(response);
			}]);
		},
		sort: function () {
			var sortAttr = this.options.sort;

			var sortedItems = this.items().detach().sort(function (a, b) {
				return ($(a).data('file')().get(sortAttr) > $(b).data('file')().get(sortAttr));
			});

			this._insertItem(sortedItems);
		},
		_update: function(name, value) {
			switch(name) {
				case 'display':
					this.options.display = String(value);
					this._insertContent();
					this.readDir(this.options.directory);
					break;
				case 'sort':
					this.options.sort = String(value || 'basename');
					this.sort();
					break;
			}
		},
		_render: function(files) {
			var that = this;
			
			if (this.options.display == 'icons') {
				this.content().empty();
			}
			if (this.options.display == 'list') {
				this.content().list('content').empty();
			}

			this.options._items = {};
			
			for (var i = 0; i < files.length; i++) {
				(function(file) {
					var item = that._renderItem(file);
					that._insertItem(item);
				})(files[i]);
			}
			
			this.element.scrollPane('reload');
			this._loadIconsPosition();
			
			Webos.File.bind('load._render.nautilus-'+this.id(), function(data) {
				var newFile = data.file;
				
				if (newFile.get('dirname') != that.location()) {
					return;
				}
				
				if (!that.options._items[newFile.get('path')]) {
					var newItem = that._renderItem(newFile);
					that._insertItem(newItem);
					if ($.webos.widget.is(that.element, 'scrollPane')) {
						that.element.scrollPane('reload');
					}
				}
			});
			Webos.File.bind('remove._render.nautilus-'+this.id(), function(data) {
				var oldFile = data.file;
				
				if (oldFile.get('dirname') != that.location()) {
					return;
				}
				
				if (that.options._items[oldFile.get('path')]) {
					that.options._items[oldFile.get('path')].remove();
					delete that.options._items[oldFile.get('path')];
				}
			});
			Webos.File.bind('umount._render.nautilus-'+this.id(), function(data) {
				if (that.location().indexOf(data.local) !== 0) {
					return;
				}
				
				that.readDir('~');
			});
			this.element.one('nautilusreadstart nautilusdestroy', function(e) {
				Webos.File.unbind('load._render.nautilus-'+that.id());
				Webos.File.unbind('remove._render.nautilus-'+that.id());
				Webos.File.unbind('umount._render.nautilus-'+that.id());
			});
		},
		_renderItem: function(file) {
			var that = this,
				t = this.translations(),
				filepath = file.get('path'),
				item = $(),
				icon = $(),
				iconPath = this._getFileIcon(file);

			if (that.options.display == 'icons') {
				item = $('<li></li>').attr('title', file.get('basename'));
				
				icon = $('<img />', { src: iconPath, alt: '' }).addClass('icon');
				icon.appendTo(item);
				
				item.append('<br />');
				
				$('<span></span>')
					.addClass('filename')
					.text(file.get('basename'))
					.appendTo(item);
			} else if (that.options.display == 'list') {
				item = $.w.listItem();
				
				var content = $('<span></span>').attr('title', file.get('basename'));
				item.listItem('addColumn', content);
				
				icon = $('<img />', { src: iconPath, alt: '' }).addClass('icon').appendTo(content);
				
				$('<span></span>').addClass('filename').text(file.get('basename')).appendTo(content);
				
				var size;
				if (file.get('is_dir')) {
					size = t.get('${nbr} element${nbr|s}', { nbr: file.get('size') });
				} else {
					size = W.File.bytesToSize(file.get('size'));
				}
				item.listItem('addColumn', size);
				
				var type;
				if (file.get('is_dir')) {
					type = t.get('Folder');
				} else {
					type = t.get('${extension} file', { extension: file.get('extension') });
				}
				item.listItem('addColumn', type);
			} else {
				return;
			}
			
			item.data('file', function() {
				return Webos.File.get(filepath);
			});
			item.data('nautilus', {
				open: function() {
					var event = jQuery.Event('open');
					item.trigger(event);
					if (!event.isDefaultPrevented()) {
						var file = item.data('file')();
						that._openFile(file);
					}
				},
				openWith: function() {
					var event = jQuery.Event('open');
					item.trigger(event);
					if (!event.isDefaultPrevented()) {
						var file = item.data('file')();
						that.openFileWindow(file);
					}
				},
				download: function() {
					that._download(item.data('file')());
					item.trigger('download');
				},
				rename: function() {
					var file = item.data('file')();

					if (item.find('input[type=text]').length) { //Already renaming this file
						return;
					}

					var renameFn = function() {
						var name = input.val();
						input.remove();
						item.find('.filename').show();
						
						if (name == file.get('basename')) { return; }
						
						file.rename(name);

						$(document).off('click.rename.nautilus');
					};

					var input = $('<input />', { type: 'text' }).keydown(function(e) {
						if (e.keyCode == 13) {
							renameFn();
							e.preventDefault();
						}
					});
					item.find('.filename').hide().after(input);

					//Let the user click in the text input
					input.on('mousedown mouseup click', function (e) {
						e.stopPropagation();
					});

					var pos = file.get('basename').length - ((file.get('extension')) ? (file.get('extension').length + 1) : 0);
					input.val(file.get('basename')).focus().setCursorPosition(0, pos);

					setTimeout(function () { //Delay otherwise the current click event is triggered
						$(document).one('click.rename.nautilus', function () {
							renameFn();
						});
					}, 0);
				},
				remove: function() {
					that._remove(item.data('file')());
				},
				openProperties: function() {
					that._openProperties(item.data('file')());
				},
				share: function () {
					that._openProperties(item.data('file')(), 'share');
				}
			});
			
			item.dblclick(function() {
				$(this).data('nautilus').open();
			});
			
			var contextmenu = $.w.contextMenu(item);
			
			$.webos.menuItem(t.get('Open')).click(function() {
				var files = (that.getSelection().length === 0) ? item : that.getSelection();
				files.each(function() {
					$(this).data('nautilus').open();
				});
			}).appendTo(contextmenu);
			$.webos.menuItem(t.get('Open with...')).click(function() {
				var files = (that.getSelection().length === 0) ? item : that.getSelection();
				files.each(function() {
					$(this).data('nautilus').openWith();
				});
			}).appendTo(contextmenu);
			$.webos.menuItem(t.get('Download')).click(function() {
				var files = (that.getSelection().length === 0) ? item : that.getSelection();
				files.each(function() {
					$(this).data('nautilus').download();
				});
			}).appendTo(contextmenu);
			$.webos.menuItem(t.get('Rename...'), true).click(function() {
				item.data('nautilus').rename();
			}).appendTo(contextmenu);
			$.webos.menuItem(t.get('Delete')).click(function() {
				var files = (that.getSelection().length === 0) ? item : that.getSelection();
				files.each(function() {
					$(this).data('nautilus').remove();
				});
			}).appendTo(contextmenu);
			if (Webos.Clipboard) {
				$.webos.menuItem(t.get('Copy'), true).click(function() {
					Webos.Clipboard.copy(file);
				}).appendTo(contextmenu);
				$.webos.menuItem(t.get('Cut')).click(function() {
					Webos.Clipboard.cut(file);
				}).appendTo(contextmenu);

				if (file.get('is_dir')) {
					var pasteItem = $.webos.menuItem(t.get('Paste')).click(function() {
						var itemToPaste = Webos.Clipboard.get();
						if (itemToPaste && itemToPaste.is(Webos.File)) {
							itemToPaste.paste(function(fileToPaste) {
								if (itemToPaste.operation() == 'cut') {
									that._move(fileToPaste, file, function(dest) {
										itemToPaste.setData(dest);
										itemToPaste.pasted();
									});
								} else {
									that._copy(fileToPaste, file, function(dest) {
										itemToPaste.pasted();
									});
								}
							}, true);
						}
					}).appendTo(contextmenu);

					var clipboardItem = Webos.Clipboard.get();
					pasteItem.menuItem('option', 'disabled', !(clipboardItem && clipboardItem.is(Webos.File)));

					var copyCallbackId = Webos.Clipboard.bind('copy cut', function(data) {
						var item = Webos.Clipboard.get();
						pasteItem.menuItem('option', 'disabled', !(item && item.is(Webos.File)));
					});
					var clearCallbackId = Webos.Clipboard.bind('clear', function() {
						pasteItem.menuItem('option', 'disabled', true);
					});
					that.element.one('nautilusreadstart', function() {
						Webos.Clipboard.unbind(copyCallbackId);
						Webos.Clipboard.unbind(clearCallbackId);
					});
				}
			}
			$.webos.menuItem(t.get('Share'), true).click(function() {
				var files = (that.getSelection().length == 0) ? item : that.getSelection();
				files.each(function() {
					$(this).data('nautilus').share();
				});
			}).appendTo(contextmenu);
			$.webos.menuItem(t.get('Properties')).click(function() {
				var files = (that.getSelection().length == 0) ? item : that.getSelection();
				files.each(function() {
					$(this).data('nautilus').openProperties();
				});
			}).appendTo(contextmenu);
			
			contextmenu.bind('contextmenuopen', function() {
				if (!item.is('.active')) {
					that.getSelection().removeClass('active').trigger('unselect');
					item.addClass('active');
				}
			});
			
			if (file.get('is_dir')) {
				var overIcon = that._getFileIcon(file, 'dropover');
				item.droppable({
					drop: function(event, ui) {
						if (overIcon != iconPath) {
							icon.attr('src', iconPath);
						}

						if (!ui.draggable.draggable('option', 'sourceFile')) {
							return;
						}

						var sourceFile = ui.draggable.draggable('option', 'sourceFile'),
							destFile = item.data('file')();

						ui.draggable.trigger('nautilusdrop', [{ source: sourceFile, dest: destFile, droppable: item }]);
					},
					over: function() {
						if (overIcon != iconPath) {
							icon.attr('src', overIcon);
						}
					},
					out: function() {
						if (overIcon != iconPath) {
							icon.attr('src', iconPath);
						}
					}
				});
			}
			
			var droppableAreas = [];
			item.draggable({
				sourceFile: file,
				dragImage: icon.clone().css({ 'max-width': '48px', 'max-height': '48px' }),
				stop: function(event) {
					setTimeout(function() {
						if (droppableAreas.length == 0) {
							return;
						}

						var doDrop = function(data) {
							var sourceFile = data.source, destFile = data.dest;

							if (data.droppable.is(that.element)) {
								var offset = that.element.offset(),
									dropPos = {
										x: data.pageX - offset.left,
										y: data.pageY - offset.top
									};

								that._setIconPos(sourceFile, dropPos);
								return;
							}

							if (destFile.get('path') == sourceFile.get('dirname')) {
								return;
							}
							if (destFile.get('path') == sourceFile.get('path')) {
								return;
							}

							destFile.load([function() {
								if (destFile.get('path') == sourceFile.get('dirname')) {
									return;
								}
								if (destFile.get('path') == sourceFile.get('path')) {
									return;
								}

								var operation = 'move';
								if (sourceFile.get('mountPoint') || destFile.get('mountPoint')) {
									if (sourceFile.get('mountPoint') != destFile.get('mountPoint')) {
										operation = 'copy';
									}
								}

								that['_'+operation](sourceFile, destFile, [function() {}, function(resp) {
									that._handleResponseError(resp);
								}]);
							}, function(resp) {
								that._handleResponseError(resp);
							}]);
						};

						if (droppableAreas.length == 1) {
							doDrop(droppableAreas[0]);
						} else {
							//TODO: integrate z-index support in draggable widget
							var maxZIndex = -1, maxZIndexArea = null;
							for (var i = 0; i < droppableAreas.length; i++) {
								var dropArea = droppableAreas[i],
									$droppable = dropArea.droppable;

								var handleZIndex = function(zIndex) {
									if (/[0-9]/.test(zIndex)) {
										zIndex = parseInt(zIndex);
										if (maxZIndex <= zIndex) {
											maxZIndex = zIndex;
											maxZIndexArea = dropArea;
										}
									}
								};

								handleZIndex($droppable.css('z-index'));

								$droppable.parents().each(function() {
									handleZIndex($(this).css('z-index'));
								});
							}

							if (!maxZIndexArea) {
								maxZIndexArea = droppableAreas.pop(); //No z-index, the one which is over others is the last one
							}

							doDrop(maxZIndexArea);
						}

						droppableAreas = [];
					}, 0);
				}
			});
			item.on('nautilusdrop', function(event, data) { //Triggered when a file is drop on a nautilus AREA only (not on a folder icon)
				droppableAreas.push(data);
			});
			
			if (/^\./.test(file.get('basename'))) { //C'est un fichier cache, on ne l'affiche pas
				item.addClass('hidden');
				if (!this.options.showHiddenFiles) {
					item.hide();
				}
			}

			if (file.is('hidden')) {
				item.addClass('hidden');
				if (!this.options.showHiddenFiles) {
					item.hide();
				}
			}
			if (file.is('trashed')) {
				item.hide();
			}
			
			var updateCallbackId = file.bind('update', function(data) {
				file.unbind('update', updateCallbackId);

				var newItem = that._renderItem(file);
				item.replaceWith(newItem);
				item = newItem;
				that.options._items[filepath] = newItem;
			});
			
			this.element.one('nautilusreadcomplete', function() {
				file.unbind('update', updateCallbackId);
			});

			this.options._items[filepath] = item;
			
			return item;
		},
		_insertItem: function(item) {
			if (this.options.display == 'icons') {
				this.content().append(item);
			}
			if (this.options.display == 'list') {
				this.content().list('content').append(item);
			}
		},
		_setIconPos: function (file, pos) {
			if (!this.options.organizeIcons) {
				return false;
			}

			file = W.File.get(file);

			var $item = this.options._items[file.get('path')];
			if (!$item) {
				return;
			}

			var itemDim = {
				width: $item.outerWidth(true),
				height: $item.outerHeight(true)
			};

			var css = {
				position: 'absolute',
				left: pos.x - itemDim.width / 2,
				top: pos.y - itemDim.height / 2
			};

			if (this.options.organizeIconsInGrid) { //Stick icons to grid
				var diff = {
					left: css.left % itemDim.width,
					top: css.top % itemDim.height
				};

				if (diff.left > itemDim.width / 2) {
					css.left += itemDim.width - diff.left;
				} else {
					css.left -= diff.left;
				}
				if (diff.top > itemDim.height / 2) {
					css.top += itemDim.height - diff.top;
				} else {
					css.top -= diff.top;
				}
			}

			$item.css(css);

			this._saveIconsPosition();
		},
		_resetIconPos: function (file) {
			if (!this.options.organizeIcons) {
				return false;
			}

{'fraction_non_alphanumeric': 0.18783862064265514, 'fraction_numerical': 0.003867516270828364, 'mean_word_length': 2.7066624565835173, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3073733', 'n_tokens_mistral': 26254, 'n_tokens_neox': 19067, 'n_words': 3210}