- 1 :
/**
- 2 :
* Each member of Tools is available for use with the {@link Spyral.Corpus#tool} method.
- 3 :
* @namespace Tools
- 4 :
*/
- 5 :
- 6 :
/**
- 7 :
* The base class for Voyant tool panels.
- 8 :
*
- 9 :
* @class Panel
- 10 :
* @memberof Tools
- 11 :
*/
- 12 :
Ext.define('Voyant.panel.Panel', {
- 13 :
mixins: ['Voyant.util.Localization','Voyant.util.Api','Voyant.util.Toolable','Voyant.util.DetailedError'],
- 14 :
requires: ['Voyant.widget.QuerySearchField','Voyant.widget.StopListOption','Voyant.categories.CategoriesOption','Voyant.widget.TotalPropertyStatus'],
- 15 :
alias: 'widget.voyantpanel',
- 16 :
statics: {
- 17 :
i18n: {
- 18 :
},
- 19 :
config: {
- 20 :
corpusValidated: false
- 21 :
},
- 22 :
// typedefs for commonly used API params
- 23 :
/**
- 24 :
* @typedef {String} stopList A comma-separated list of words, a named list or a URL to a plain text list, one word per line.
- 25 :
* By default this is set to 'auto' which auto-detects the document's language and loads an appropriate list (if available for that language). Set this to blank to not use the default stopList.
- 26 :
* For more information see the [Stopwords documentation]{@tutorial stopwords}.
- 27 :
*/
- 28 :
- 29 :
/**
- 30 :
* @typedef {String|String[]} query A query or array of queries (queries can be separated by a comma).
- 31 :
* For query syntax, see the [search documentation]{@tutorial search}.
- 32 :
*/
- 33 :
- 34 :
/**
- 35 :
* @typedef {String|String[]} docId The document ID(s) to restrict the results to.
- 36 :
*/
- 37 :
- 38 :
/**
- 39 :
* @typedef {Number|Number[]} docIndex The document index(es) to restrict the results to.
- 40 :
*/
- 41 :
- 42 :
/**
- 43 :
* @typedef {String} categories The categories ID to use. For more information see the [Categories documentation]{@tutorial categories}.
- 44 :
*/
- 45 :
- 46 :
/**
- 47 :
* @typedef {Number} bins The number of "bins" to divide the result into.
- 48 :
*/
- 49 :
- 50 :
/**
- 51 :
* @typedef {Number} start The index of the item to start the results at.
- 52 :
*/
- 53 :
- 54 :
/**
- 55 :
* @typedef {Number} limit The number of items to limit the result to.
- 56 :
*/
- 57 :
- 58 :
/**
- 59 :
* @typedef {Number} context The number of terms to consider on each side of the keyword.
- 60 :
*/
- 61 :
- 62 :
/**
- 63 :
* @typedef {String} withDistributions Determines whether to show "raw" or "relative" frequencies (those are the two valid values).
- 64 :
* The default value is "relative" (unless there's only one document in the corpus, in which case raw frequencies are shown).
- 65 :
*/
- 66 :
- 67 :
/**
- 68 :
* @typedef {String} termColors Which term colors to show in the grid.
- 69 :
* By default this is set to 'categories' which shows the term color only if it's been assigned by a category.
- 70 :
* The other alternatives are 'terms' which shows all terms colors, and '' or undefined which shows no term colors.
- 71 :
*/
- 72 :
- 73 :
/**
- 74 :
* @typedef {String|String[]} columns One or more column data indexes to display, separated by a comma.
- 75 :
* Use this to modify the default set of visible columns.
- 76 :
*/
- 77 :
- 78 :
/**
- 79 :
* @typedef {String} sort The column to sort the results by
- 80 :
*/
- 81 :
- 82 :
/**
- 83 :
* @typedef {String} dir The direction in which to sort the results: 'asc' or 'desc'
- 84 :
*/
- 85 :
api: {
- 86 :
/**
- 87 :
* @memberof Tools.Panel
- 88 :
* @instance
- 89 :
* @property {String} corpus The ID of the corpus to use.
- 90 :
*/
- 91 :
corpus: undefined,
- 92 :
- 93 :
/**
- 94 :
* @memberof Tools.Panel
- 95 :
* @instance
- 96 :
* @property {String|String[]} input Use to directly provide input, instead of specifying a corpus. Can be: one or more URLs, one or more chunks of text.
- 97 :
*/
- 98 :
input: undefined,
- 99 :
- 100 :
/**
- 101 :
* @memberof Tools.Panel
- 102 :
* @instance
- 103 :
* @property {String} inputFormat The input format of the provided input (the default is auto-detect).
- 104 :
*/
- 105 :
inputFormat: undefined,
- 106 :
- 107 :
/**
- 108 :
* @memberof Tools.Panel
- 109 :
* @instance
- 110 :
* @property {String} subtitle Specify a subtitle to display in the tool's header.
- 111 :
*/
- 112 :
subtitle: undefined
- 113 :
}
- 114 :
},
- 115 :
config: {
- 116 :
corpus: undefined
- 117 :
},
- 118 :
constructor: function(config) {
- 119 :
this.mixins['Voyant.util.Api'].constructor.apply(this, arguments);
- 120 :
this.mixins['Voyant.util.Toolable'].constructor.apply(this, arguments);
- 121 :
if (!this.glyph) {
- 122 :
this.glyph = Ext.ClassManager.getClass(this).glyph
- 123 :
}
- 124 :
- 125 :
this.on("afterrender", function() {
- 126 :
if (this.getXType()!='facet' && this.getApiParam('subtitle') && this.getTitle()) {
- 127 :
this.setTitle(this.getTitle()+" <i style='font-size: smaller;'>"+this.getApiParam('subtitle')+"</i>")
- 128 :
}
- 129 :
if (this.isXType("grid")) {
- 130 :
this.on('boxready', function() {
- 131 :
var columns = this.getApiParam('columns');
- 132 :
if (columns !== undefined) {
- 133 :
if (Array.isArray(columns) === false) {
- 134 :
columns = columns.split(',');
- 135 :
}
- 136 :
if (columns.length > 0) {
- 137 :
var anyMatch = false;
- 138 :
this.getColumns().forEach(function(gcol) {
- 139 :
var match = columns.indexOf(gcol.dataIndex) !== -1;
- 140 :
anyMatch = match || anyMatch;
- 141 :
gcol.setVisible(match);
- 142 :
});
- 143 :
if (!anyMatch) {
- 144 :
this.getColumns().forEach(function(gcol) {
- 145 :
gcol.setVisible(gcol.initialConfig.hidden !== undefined ? !gcol.initialConfig.hidden : true);
- 146 :
});
- 147 :
}
- 148 :
}
- 149 :
}
- 150 :
}, this);
- 151 :
- 152 :
this.getSelectionModel().on("selectionchange", function(store, records) {
- 153 :
// console.warn(records, this.selectedRecordsToRemember)
- 154 :
// this.selectedRecordsToRemember = records;
- 155 :
}, this);
- 156 :
this.getStore().on("beforeload", function() {
- 157 :
this.selectedRecordsToRemember = this.getSelection();
- 158 :
}, this)
- 159 :
this.getStore().on("load", function(store, records) {
- 160 :
if (Ext.Array.from(this.selectedRecordsToRemember).length>0) {
- 161 :
// combine contents of store with contents of remembered items, filtering out duplicates
- 162 :
var seen = {}
- 163 :
var mergedRecords = Ext.Array.merge(this.selectedRecordsToRemember, records).filter(function(item) {
- 164 :
if (!(item.getId() in seen)) {
- 165 :
seen[item.getId()]=true;
- 166 :
return true
- 167 :
} else {
- 168 :
return false;
- 169 :
}
- 170 :
});
- 171 :
if (store.isBufferedStore) {
- 172 :
if (store.currentPage==1) {
- 173 :
store.data.addAll(mergedRecords);
- 174 :
store.totalCount = mergedRecords.length;
- 175 :
store.fireEvent('refresh', store);
- 176 :
}
- 177 :
} else {
- 178 :
store.loadRecords(mergedRecords);
- 179 :
this.getSelectionModel().select(this.selectedRecordsToRemember);
- 180 :
store.fireEvent('refresh', store);
- 181 :
this.selectedRecordsToRemember = [];
- 182 :
}
- 183 :
}
- 184 :
}, this);
- 185 :
}
- 186 :
}, this);
- 187 :
- 188 :
this.on({
- 189 :
loadedCorpus: {
- 190 :
fn: function(src, corpus) {
- 191 :
// make sure API is updated if we had a corpus and it's changed, this should be registered first, so hopefully be fired before tools receive notification
- 192 :
this.setApiParam("corpus", corpus.getAliasOrId());
- 193 :
this.setCorpus(corpus);
- 194 :
},
- 195 :
priority: 999, // very high priority
- 196 :
scope: this
- 197 :
}
- 198 :
});
- 199 :
},
- 200 :
- 201 :
getApplication: function() {
- 202 :
return Voyant.application;
- 203 :
},
- 204 :
- 205 :
getBaseUrl: function() {
- 206 :
return this.getApplication().getBaseUrl();
- 207 :
},
- 208 :
- 209 :
openUrl: function(url) {
- 210 :
this.getApplication().openUrl.apply(this, arguments);
- 211 :
},
- 212 :
- 213 :
getTromboneUrl: function() {
- 214 :
return this.getApplication().getTromboneUrl();
- 215 :
},
- 216 :
- 217 :
dispatchEvent: function() {
- 218 :
var application = this.getApplication();
- 219 :
application.dispatchEvent.apply(application, arguments);
- 220 :
},
- 221 :
- 222 :
showError: function(config, response) {
- 223 :
if (Ext.isString(config)) {
- 224 :
config = {
- 225 :
message: config
- 226 :
}
- 227 :
}
- 228 :
Ext.applyIf(config, {
- 229 :
title: this.localize("error")+" ("+this.localize("title")+")"
- 230 :
})
- 231 :
this.getApplication().showError(config, response)
- 232 :
},
- 233 :
- 234 :
showResponseError: function(config, response) {
- 235 :
this.getApplication().showResponseError(config, response)
- 236 :
},
- 237 :
- 238 :
toastError: function(config) {
- 239 :
if (Ext.isString(config)) {
- 240 :
config = {html: config}
- 241 :
}
- 242 :
Ext.applyIf(config, {
- 243 :
glyph: 'xf071@FontAwesome',
- 244 :
title: this.localize("error")
- 245 :
})
- 246 :
this.toast(config);
- 247 :
},
- 248 :
- 249 :
toastInfo: function(config) {
- 250 :
if (Ext.isString(config)) {
- 251 :
config = {html: config}
- 252 :
}
- 253 :
Ext.applyIf(config, {
- 254 :
glyph: 'xf05a@FontAwesome',
- 255 :
title: this.localize("info")
- 256 :
})
- 257 :
this.toast(config);
- 258 :
},
- 259 :
- 260 :
toast: function(config) {
- 261 :
if (Ext.isString(config)) {
- 262 :
config = {html: config}
- 263 :
}
- 264 :
Ext.applyIf(config, {
- 265 :
slideInDuration: 500,
- 266 :
shadow: true,
- 267 :
align: 'b',
- 268 :
anchor: this.getTargetEl()
- 269 :
})
- 270 :
Ext.toast(config);
- 271 :
},
- 272 :
- 273 :
/**
- 274 :
* Checks to see if we have access to this corpus, first by checking the application's
- 275 :
* access setting for the corpus, then by checking the corpus setting.
- 276 :
* @private
- 277 :
*/
- 278 :
hasCorpusAccess: function(corpus) {
- 279 :
var app = this.getApplication();
- 280 :
var corpusAccess = app.getCorpusAccess(); // undefined: corpus is unprotected, ACCESS: user entered the access password, ADMIN: user entered there admin password, LIMITED: no password entered
- 281 :
if (corpusAccess === 'ADMIN' || corpusAccess === 'ACCESS') return true;
- 282 :
if (!corpus) {
- 283 :
corpus = this.getCorpus();
- 284 :
if (!corpus) {
- 285 :
corpus = app.getCorpus();
- 286 :
}
- 287 :
}
- 288 :
return corpus.getNoPasswordAccess() === 'NORMAL'; // NORMAL: corpus is unprotected, NONE: corpus cannot be accessed except by password, NONCONSUMPTIVE: limited access without password
- 289 :
},
- 290 :
- 291 :
/**
- 292 :
* Checks to see if the user can modify the corpus.
- 293 :
* @private
- 294 :
*/
- 295 :
hasModifyCorpusAccess: function(corpus) {
- 296 :
var allowDownload = this.getApplication().getAllowDownload();
- 297 :
if (!allowDownload) return false;
- 298 :
- 299 :
var allowInput = this.getApplication().getAllowInput();
- 300 :
if (!allowInput) return false;
- 301 :
- 302 :
var corpusAccess = this.getApplication().getCorpusAccess();
- 303 :
var noPasswordAccess = corpus.getNoPasswordAccess();
- 304 :
- 305 :
var canModify = (corpusAccess === undefined && noPasswordAccess === 'NORMAL') || corpusAccess === 'ADMIN';
- 306 :
- 307 :
return canModify;
- 308 :
}
- 309 :
});