/**
* The Documents tool shows a table of the documents in the corpus and includes functionality for modifying the corpus.
*
* @example
*
* let config = {
* "columns": null,
* "dir": null,
* "docId": null,
* "docIndex": null,
* "query": null,
* "sort": null,
* };
*
* loadCorpus("austen").tool("documents", config);
*
* @class Documents
* @tutorial documents
* @memberof Tools
*/
Ext.define('Voyant.panel.Documents', {
extend: 'Ext.grid.Panel',
mixins: ['Voyant.panel.Panel','Voyant.util.Downloadable'],
alias: 'widget.documents',
isConsumptive: true,
statics: {
i18n: {
newCorpusError: 'There was an error creating the new the corpus. You may not have permission to do this.'
},
api: {
/**
* @memberof Tools.Documents
* @instance
* @property {query}
*/
query: undefined,
/**
* @memberof Tools.Documents
* @instance
* @property {docIndex}
*/
docIndex: undefined,
/**
* @memberof Tools.Documents
* @instance
* @property {docId}
*/
docId: undefined,
/**
* @memberof Tools.Documents
* @instance
* @property {columns} columns 'title', 'author', 'pubDate', 'publisher', 'pubPlace', 'keyword', 'collection', 'tokensCount-lexical', 'typesCount-lexical', 'typeTokenRatio-lexical', 'averageWordsPerSentence', 'language'
*/
columns: undefined,
/**
* @memberof Tools.Documents
* @instance
* @property {sort}
*/
sort: undefined,
/**
* @memberof Tools.Documents
* @instance
* @property {dir}
*/
dir: undefined
},
glyph: 'xf0ce@FontAwesome'
},
MODE_EDITING: 'editing',
MODE_NORMAL: 'normal',
config: {
options: [{
xtype: 'stoplistoption'
},
{xtype: 'categoriesoption'}
],
mode: this.MODE_NORMAL
},
constructor: function(config) {
var store = Ext.create("Voyant.data.store.Documents", {
selModel: {pruneRemoved: false},
proxy: {
extraParams: {
forTool: 'documents'
}
}
});
var dockedItemsItems = [{
xtype: 'querysearchfield'
}, {
xtype: 'totalpropertystatus'
}]
var me = this;
if (!config || config.mode!=this.MODE_EDITING) {
dockedItemsItems.push({
text: this.localize("modify"),
tooltip: this.localize("modifyTip"),
glyph: 'xf044@FontAwesome',
scope: this,
itemId: 'modifyButton',
handler: function(btn) {
var win = Ext.create('Ext.window.Window', {
title: this.localize("title"),
modal: true,
width: "80%",
minWidth: 300,
minHeight: 200,
height: "80%",
layout: 'fit',
frame: true,
border: true,
items: {
xtype: 'documents',
mode: this.MODE_EDITING,
corpus: this.getStore().getCorpus(),
header: false,
viewConfig: {
plugins:{
ptype:'gridviewdragdrop'
},
listeners: {
beforedrop: function(node, data, overModel, dropPosition, dropHandlers) {
if (this.getStore().getCount()<this.getStore().getCorpus().getDocumentsCount()) {
var panel = this.up("panel");
Ext.Msg.show({
title: panel.localize('error'),
message: panel.localize('reorderFilteredError'),
buttons: Ext.Msg.OK,
icon: Ext.Msg.ERROR
});
return false;
}
return true;
}
}
}
},
buttons: [{
text: this.localize('add'),
tooltip: this.localize("addTip"),
glyph: 'xf067@FontAwesome',
handler: function(btn) {
btn.up("window").close();
Ext.create('Ext.window.Window', {
header: false,
modal: true,
layout: 'fit',
items: {
xtype: 'corpuscreator',
corpus: this.getStore().getCorpus(),
listeners: {
boxready: function(cmp) {
cmp.setStyle({borderColor: '#f5f5f5'});
}
}
}
}).show();
},
scope: this
}, {
text: this.localize('remove'),
tooltip: this.localize("removeTip"),
glyph: 'xf05e@FontAwesome',
hidden: this.getStore().getCorpus().getDocumentsCount()==1,
handler: this.keepRemoveReorderHandler,
itemId: 'remove',
scope: this
}, {
text: this.localize('keep'),
tooltip: this.localize("keepTip"),
glyph: 'xf00c@FontAwesome',
hidden: this.getStore().getCorpus().getDocumentsCount()==1,
handler: this.keepRemoveReorderHandler,
itemId: 'keep',
scope: this
}, {
text: this.localize('reorder'),
tooltip: this.localize("reorderTip"),
glyph: 'xf0dc@FontAwesome',
hidden: this.getStore().getCorpus().getDocumentsCount()==1,
handler: this.keepRemoveReorderHandler,
itemId: 'reorder',
scope: this
},{
text: 'Cancel',
glyph: 'xf00d@FontAwesome',
handler: function(btn) {
btn.up("window").close();
}
}]
}).show();
}
}, {
text: this.localize('downloadButton'),
glyph: 'xf019@FontAwesome',
itemId: 'downloadButton',
handler: function() {
me.downloadFromCorpusId(me.getStore().getCorpus().getId())
}
})
}
Ext.apply(this, {
title: this.localize('title'),
emptyText: this.localize("emptyText"),
columns:[
{
xtype: 'rownumberer',
renderer: function(value, metaData, record) {return record.getIndex()+1},
sortable: false
},{
text: this.localize('documentTitle'),
dataIndex: 'title',
sortable: true,
renderer: function(val, metadata, record) {return record.getTitle();},
flex: 3
},{
text: this.localize('documentAuthor'),
dataIndex: 'author',
sortable: true,
hidden: true,
renderer: function(val, metadata, record) {return record.getAuthor();},
flex: 2
},{
text: this.localize('documentPubDate'),
dataIndex: 'pubDate',
sortable: true,
hidden: true,
renderer: function(val, metadata, record) {return record.getPubDate();},
flex: 2
},{
text: this.localize('documentPublisher'),
dataIndex: 'publisher',
sortable: false,
hidden: true,
renderer: function(val, metadata, record) {return record.getPublisher();},
flex: 2
},{
text: this.localize('documentPubPlace'),
dataIndex: 'pubPlace',
sortable: false,
hidden: true,
renderer: function(val, metadata, record) {return record.getPubPlace();},
flex: 2
},{
text: this.localize('documentKeyword'),
dataIndex: 'keyword',
sortable: false,
hidden: true,
renderer: function(val, metadata, record) {return record.getKeyword();},
flex: 2
},{
text: this.localize('documentCollection'),
dataIndex: 'collection',
sortable: false,
hidden: true,
renderer: function(val, metadata, record) {return record.getCollection();},
flex: 2
},{
text: this.localize('tokensCountLexical'),
dataIndex: 'tokensCount-lexical',
renderer: Ext.util.Format.numberRenderer('0,000'),
sortable: true,
width: 'autoSize'
},{
text: this.localize('typesCountLexical'),
dataIndex: 'typesCount-lexical',
renderer: Ext.util.Format.numberRenderer('0,000'),
width: 'autoSize'
},{
text: this.localize('typeTokenRatioLexical'),
dataIndex: 'typeTokenRatio-lexical',
renderer: function(val) {return Ext.util.Format.percent(val)},
width: 'autoSize'
},{
text: this.localize('averageWordsPerSentence'),
dataIndex: 'averageWordsPerSentence',
renderer: Ext.util.Format.numberRenderer('0,000.0'),
tooltip: this.localize("averageWordsPerSentenceTip"),
width: 'autoSize'
},{
text: this.localize('language'),
dataIndex: 'language',
hidden: true,
renderer: function(val, metaData, record, rowIndex, colIndex, store, view) {return view.ownerCt.getLanguage(val);},
width: 'autoSize'
}
],
store: store,
selModel: {
type: 'rowmodel',
mode: 'MULTI',
listeners: {
selectionchange: {
fn: function(sm, selections) {
this.getApplication().dispatchEvent('documentsClicked', this, selections, this.getStore().getCorpus());
},
scope: this
}
}
},
dockedItems: [{
dock: 'bottom',
xtype: 'toolbar',
overflowHandler: 'scroller',
items: dockedItemsItems
}]
});
this.callParent(arguments);
this.mixins['Voyant.panel.Panel'].constructor.apply(this, arguments);
// create a listener for corpus loading (defined here, in case we need to load it next)
this.on('loadedCorpus', function(src, corpus) {
this.store.setCorpus(corpus);
if (this.isVisible()) {
this.store.load({params: this.getApiParams()});
} else {
this.on('afterrender', function() {
this.store.load({params: this.getApiParams()});
}, this);
}
if (this.hasModifyCorpusAccess(corpus) === false) {
this.queryById('modifyButton').hide();
this.queryById('downloadButton').hide();
}
});
this.on("activate", function() { // load after tab activate (if we're in a tab panel)
if (this.getStore().getCorpus()) {
this.getStore().load({params: this.getApiParams()});
}
}, this);
// create a listener for corpus loading (defined here, in case we need to load it next)
this.on('query', function(src, query) {
this.setApiParam('query', query);
this.store.load({params: this.getApiParams()});
})
if (config.embedded) {
if (Ext.getClass(config.embedded).getName() == "Voyant.data.model.Corpus") {
config.corpus = config.embedded
}
else if (Ext.getClass(config.embedded).getName() == "Voyant.data.store.Documents") {
this.store.setRecords(config.embedded.getData())
config.corpus = config.embedded.getCorpus()
}
}
// if we have a corpus, load it
if (config.corpus) {
this.fireEvent('loadedCorpus', this, config.corpus)
}
},
keepRemoveReorderHandler: function(btn) {
// we're not sure which scope we're in, so ensure we're talking about this buttons panel
var panel = btn.up("window").down("documents");
var selection = panel.getSelection();
var docs = panel.getStore().getCorpus().getDocumentsCount();
var btnMode = btn.getItemId();
// if reordering, check to make sure that we're not looking at a subset
if (btnMode=='reorder') {
if (panel.getStore().getCount()<docs) {
return Ext.Msg.show({
title: this.localize('error'),
message: this.localize('reorderFilteredError'),
buttons: Ext.Msg.OK,
icon: Ext.Msg.ERROR
});
}
else {
docIndex = [];
panel.getStore().each(function(doc) {
docIndex.push(doc.getIndex())
}, this);
for (var i=1; i<docIndex.length; i++) {
if (docIndex[i-1]>docIndex[i]) {
return Ext.Msg.confirm(panel.localize('newCorpus'), new Ext.Template(panel.localize(btnMode+'Documents')).applyTemplate([selection.length]), function(confirmBtn){
if (confirmBtn==='yes') {
docIndex = [];
this.getStore().each(function(doc) {
docIndex.push(doc.getIndex())
}, this);
var params = {docIndex: docIndex};
params[btnMode+"Documents"] = true;
this.editCorpus(params)
}
}, panel);
}
}
// if we get here it's because nothing's been reordered
return Ext.Msg.show({
title: this.localize('error'),
message: this.localize('reorderOriginalError'),
buttons: Ext.Msg.OK,
icon: Ext.Msg.ERROR
});
}
}
if (selection.length>0) {
if (selection.length==docs) {
if (docs==1) {
return Ext.Msg.show({
title: this.localize('error'),
message: this.localize('onlyOneError'),
buttons: Ext.Msg.OK,
icon: Ext.Msg.ERROR
});
}
else {
return Ext.Msg.show({
title: this.localize('error'),
message: this.localize('allSelectedError'),
buttons: Ext.Msg.OK,
icon: Ext.Msg.ERROR
});
}
}
else {
return Ext.Msg.confirm(this.localize('newCorpus'), new Ext.Template(this.localize(btnMode+'SelectedDocuments')).applyTemplate([selection.length]), function(confirmBtn){
if (confirmBtn==='yes') {
docIndex = [];
selection.forEach(function(doc){
docIndex.push(doc.getIndex())
})
var params = {docIndex: docIndex};
params[btnMode+"Documents"] = true;
this.editCorpus(params)
}
}, panel);
}
}
else if (panel.getApiParam("query") && panel.getStore().getCount()<docs) {
return Ext.Msg.confirm(this.localize('newCorpus'), new Ext.Template(this.localize(btnMode+'FilteredDocuments')).applyTemplate([selection.length]), function(confirmBtn){
if (confirmBtn==='yes') {
docIndex = [];
this.getStore().each(function(doc) {
docIndex.push(doc.getIndex())
}, this);
var params = {docIndex: docIndex};
params[btnMode+"Documents"] = true;
this.editCorpus(params)
}
}, panel);
}
else {
return Ext.Msg.show({
title: this.localize('error'),
message: this.localize('selectOrFilterError'),
buttons: Ext.Msg.OK,
icon: Ext.Msg.ERROR
});
}
},
editCorpus: function(params) {
Ext.apply(params, {
tool: 'corpus.CorpusManager',
corpus: this.getStore().getCorpus().getId()
})
// mask main viewport while we create a new corpus
var app = this.getApplication();
var view = app.getViewport();
view.mask(this.localize("Creating new corpus…"));
Ext.Ajax.request({
url: this.getApplication().getTromboneUrl(),
method: 'POST',
params: params,
success: function(response) {
view.unmask();
var obj = Ext.decode(response.responseText);
app.openUrl(app.getBaseUrl()+"?corpus="+obj.corpus.id);
// view.mask("Loading new corpus…")
// new Voyant.data.model.Corpus({corpus: obj.corpus.id}).then(function(corpus) {
// view.unmask();
// app.openUrl(app.getBaseUrl()+"/?corpus="+obj.corpus.id)
// app.dispatchEvent('loadedCorpus', app, corpus);
// }).fail(function(message, response) {
// view.unmask();
// app.showErrorResponse({message: message}, response);
// });
},
failure: function(response) {
view.unmask();
Ext.Msg.show({
title: this.localize('error'),
message: this.localize('newCorpusError'),
buttons: Ext.Msg.OK,
icon: Ext.Msg.ERROR
});
},
scope: this
});
// close editing window if we're in modal mode, should happen asynchronously while new corpus is created
var win = this.up("window");
if (win && win.isFloating()) {win.close()}
}
})