Skip to content

Commit

Permalink
Filebrowser paging experiment
Browse files Browse the repository at this point in the history
  • Loading branch information
cnydw committed Jun 7, 2021
1 parent 12a548a commit 6e615c0
Show file tree
Hide file tree
Showing 5 changed files with 220 additions and 9 deletions.
16 changes: 11 additions & 5 deletions packages/filebrowser/src/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
TranslationBundle,
ITranslator
} from '@jupyterlab/translation';
import { Paging } from './paging';

/**
* The class name added to file browsers.
Expand Down Expand Up @@ -121,6 +122,8 @@ export class FileBrowser extends Widget {
translator: this.translator
});

this._paging = new Paging({model});

this._filenameSearcher = FilenameSearcher({
listing: this._listing,
useFuzzyFilter: this._useFuzzyFilter,
Expand All @@ -137,6 +140,7 @@ export class FileBrowser extends Widget {
this.layout.addWidget(this._filenameSearcher);
this.layout.addWidget(this._crumbs);
this.layout.addWidget(this._listing);
this.layout.addWidget(this._paging);

if (options.restore !== false) {
void model.restore(this.id);
Expand Down Expand Up @@ -174,6 +178,11 @@ export class FileBrowser extends Widget {
*/
set useFuzzyFilter(value: boolean) {
this._useFuzzyFilter = value;
// remove this._filenameSearcher before redefining it to avoid removing a non existent widget
this.layout.removeWidget(this._filenameSearcher);
this.layout.removeWidget(this._crumbs);
this.layout.removeWidget(this._listing);
this.layout.removeWidget(this._paging);

this._filenameSearcher = FilenameSearcher({
listing: this._listing,
Expand All @@ -182,14 +191,10 @@ export class FileBrowser extends Widget {
forceRefresh: true
});
this._filenameSearcher.addClass(FILTERBOX_CLASS);

this.layout.removeWidget(this._filenameSearcher);
this.layout.removeWidget(this._crumbs);
this.layout.removeWidget(this._listing);

this.layout.addWidget(this._filenameSearcher);
this.layout.addWidget(this._crumbs);
this.layout.addWidget(this._listing);
this.layout.addWidget(this._paging);
}

/**
Expand Down Expand Up @@ -357,6 +362,7 @@ export class FileBrowser extends Widget {
private _trans: TranslationBundle;
private _crumbs: BreadCrumbs;
private _listing: DirListing;
private _paging: Paging;
private _filenameSearcher: ReactWidget;
private _manager: IDocumentManager;
private _directoryPending: boolean;
Expand Down
64 changes: 60 additions & 4 deletions packages/filebrowser/src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ export class FileBrowserModel implements IDisposable {
created: 'unknown',
last_modified: 'unknown',
mimetype: 'text/plain',
format: 'text'
format: 'text',
max_page: 1,
page: 1
};
this._state = options.state || null;
const refreshInterval = options.refreshInterval || DEFAULT_REFRESH_INTERVAL;
Expand All @@ -107,7 +109,7 @@ export class FileBrowserModel implements IDisposable {
this._poll = new Poll({
auto: options.auto ?? true,
name: '@jupyterlab/filebrowser:Model',
factory: () => this.cd('.'),
factory: () => this.cd('.'), // just interesting to look at later.
frequency: {
interval: refreshInterval,
backoff: true,
Expand Down Expand Up @@ -164,6 +166,22 @@ export class FileBrowserModel implements IDisposable {
return this._pathChanged;
}

get page(): number {
if (this._model) {
return this._model.page ? this._model.page : 1;
} else {
return 1;
}
}

get max_page(): number {
if (this._model) {
return this._model.max_page ? this._model.max_page : 1;
} else {
return 1;
}
}

/**
* A signal emitted when the directory listing is refreshed.
*/
Expand Down Expand Up @@ -266,7 +284,7 @@ export class FileBrowserModel implements IDisposable {
await this._pending;
}
const oldValue = this.path;
const options: Contents.IFetchOptions = { content: true };
const options: Contents.IFetchOptions = { content: true, page: this._model.page };
this._pendingPath = newValue;
if (oldValue !== newValue) {
this._sessions.length = 0;
Expand Down Expand Up @@ -315,6 +333,42 @@ export class FileBrowserModel implements IDisposable {
return this._pending;
}

// basically cd to the same folder
// but with the page parameter being newPage instead of model.page
async cd_page(newPage: number): Promise<void> {
const options: Contents.IFetchOptions = { content: true, page: newPage };
const services = this.manager.services;
this._pending = services.contents
.get(this._model.path, options)
.then(contents => {
if (this.isDisposed) {
return;
}
this._handleContents(contents);
this._pendingPath = null;
this._pending = null;

this._onRunningChanged(services.sessions, services.sessions.running());
this._refreshed.emit(void 0);
})
.catch(error => {
this._pendingPath = null;
this._pending = null;
if (error.response && error.response.status === 404) {
error.message = this._trans.__(
'Directory not found: "%1"',
this._model.path
);
console.error(error);
this._connectionFailure.emit(error);
return this.cd('/');
} else {
this._connectionFailure.emit(error);
}
});
return this._pending;
}

/**
* Download a file.
*
Expand Down Expand Up @@ -584,7 +638,9 @@ export class FileBrowserModel implements IDisposable {
created: contents.created,
last_modified: contents.last_modified,
mimetype: contents.mimetype,
format: contents.format
format: contents.format,
page: contents.page,
max_page: contents.max_page
};
this._items = contents.content;
this._paths.clear();
Expand Down
119 changes: 119 additions & 0 deletions packages/filebrowser/src/paging.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { Widget } from '@lumino/widgets';

import { FilterFileBrowserModel } from './model';


export class Paging extends Widget {
/**
* Construct a new file browser directory listing widget.
*
* @param model - The file browser view model.
*/
constructor(options: Paging.IOptions) {
super();
this._model = options.model;
this._model.fileChanged.connect(this._onchange, this);
this._model.refreshed.connect(this._onchange, this);
this._model.pathChanged.connect(this._onchange, this);
this.addClass("jp-DirPagination");
this._onchange();
}


/**
* Get the model used by the listing.
*/
get model(): FilterFileBrowserModel {
return this._model;
}


/**
* Update the node
*/
private _onchange(): void {
const max_page = this._model.max_page;
const page = this._model.page;

while (this.node.firstChild) {
this.node.removeChild(this.node.firstChild);
}

// Don't show the paging widget if paging is not needed
if (this._model.max_page === 1) {
return;
}

/*
if max_page <= 7
show all items
otherwise
if page <= 4
show 1-5 and the right ellipse
if max_page-3 <= page
show the left ellipse and max_page-4 to max_page
if 4 < page < max_page-3
show left ellipse, page-1, page, page+1, right ellipse
*/
if ( max_page <= 7 ) {
for (let i = 1; i <= max_page; i++) {
this._createButton(i, page);
}
} else if (page <= 4) {
for (let i = 1; i <= 5; i++) {
this._createButton(i, page);
}
this._createEllipse();
this._createButton(max_page, page);
} else if (page >= max_page - 3) {
this._createButton(1, page);
this._createEllipse();
for (let i = max_page-4; i <= max_page; i++) {
this._createButton(i, page);
}
} else {
this._createButton(1, page);
this._createEllipse();
this._createButton(page - 1, page);
this._createButton(page, page);
this._createButton(page + 1, page);
this._createEllipse();
this._createButton(max_page, page);
}
}

private _createButton(i:number, activePage:number) {
let button = document.createElement("a");
button.textContent = i.toString();
button.onclick = () => {
this._model.cd_page(i);
}
if (i === activePage) {
button.className = 'active';
}
this.node.appendChild(button);

}

// TODO: remove the hover effect
private _createEllipse() {
let button = document.createElement("span");
button.textContent = "..."
this.node.appendChild(button);
}

private _model: FilterFileBrowserModel;
}

export namespace Paging {
/**
* An options object for initializing a file browser directory listing.
*/
export interface IOptions {
/**
* A file browser model instance.
*/
model: FilterFileBrowserModel;

}
}
22 changes: 22 additions & 0 deletions packages/filebrowser/style/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -300,3 +300,25 @@
min-height: 120px;
outline: none;
}


.jp-DirPagination {
flex: 0 0 auto;
display: flex;
}

.jp-DirPagination * {
color: black;
flex: 1;
text-align: center;
padding: 8px 0px;
}

.jp-DirPagination a.active {
background-color: #4CAF50;
color: white;
}

.jp-DirPagination a:hover:not(.active) {
background-color: #ddd;
}
8 changes: 8 additions & 0 deletions packages/services/src/contents/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ export namespace Contents {
*/
readonly size?: number;

readonly page?: number;

readonly max_page?: number;
/**
* The indices of the matched characters in the name.
*/
Expand Down Expand Up @@ -145,6 +148,11 @@ export namespace Contents {
* The default is `true`.
*/
content?: boolean;

/**
* The page number used for directory contents paging.
*/
page?: number;
}

/**
Expand Down

0 comments on commit 6e615c0

Please sign in to comment.