importWizard.js (9146B)
1 var Zotero_Import_Wizard = { 2 _wizard: null, 3 _dbs: null, 4 _file: null, 5 _translation: null, 6 7 8 init: async function () { 9 this._wizard = document.getElementById('import-wizard'); 10 11 var dbs = await Zotero_File_Interface.findMendeleyDatabases(); 12 if (dbs.length) { 13 document.getElementById('radio-import-source-mendeley').hidden = false; 14 } 15 16 // If no existing collections or non-trash items in the library, don't create a new 17 // collection by default 18 var args = window.arguments[0].wrappedJSObject; 19 if (args && args.libraryID) { 20 let sql = "SELECT ROWID FROM collections WHERE libraryID=?1 " 21 + "UNION " 22 + "SELECT ROWID FROM items WHERE libraryID=?1 " 23 // Not in trash 24 + "AND itemID NOT IN (SELECT itemID FROM deletedItems) " 25 // And not a child item (which doesn't necessarily show up in the trash) 26 + "AND itemID NOT IN (SELECT itemID FROM itemNotes WHERE parentItemID IS NOT NULL) " 27 + "AND itemID NOT IN (SELECT itemID FROM itemAttachments WHERE parentItemID IS NOT NULL) " 28 + "LIMIT 1"; 29 if (!await Zotero.DB.valueQueryAsync(sql, args.libraryID)) { 30 document.getElementById('create-collection-checkbox').removeAttribute('checked'); 31 } 32 } 33 34 Zotero.Translators.init(); // async 35 }, 36 37 38 onModeChosen: async function () { 39 var wizard = this._wizard; 40 41 var mode = document.getElementById('import-source').selectedItem.id; 42 try { 43 switch (mode) { 44 case 'radio-import-source-file': 45 await this.chooseFile(); 46 break; 47 48 case 'radio-import-source-mendeley': 49 this._dbs = await Zotero_File_Interface.findMendeleyDatabases(); 50 // This shouldn't happen, because we only show the wizard if there are databases 51 if (!this._dbs.length) { 52 throw new Error("No databases found"); 53 } 54 this._populateFileList(this._dbs); 55 document.getElementById('file-options-header').textContent 56 = Zotero.getString('fileInterface.chooseAppDatabaseToImport', 'Mendeley') 57 wizard.goTo('page-file-list'); 58 wizard.canRewind = true; 59 this._enableCancel(); 60 break; 61 62 default: 63 throw new Error(`Unknown mode ${mode}`); 64 } 65 } 66 catch (e) { 67 this._onDone( 68 Zotero.getString('general.error'), 69 Zotero.getString('fileInterface.importError'), 70 true 71 ); 72 throw e; 73 } 74 }, 75 76 77 goToStart: function () { 78 this._wizard.goTo('page-start'); 79 this._wizard.canAdvance = true; 80 return false; 81 }, 82 83 84 chooseFile: async function (translation) { 85 var translation = new Zotero.Translate.Import(); 86 var translators = await translation.getTranslators(); 87 const nsIFilePicker = Components.interfaces.nsIFilePicker; 88 var fp = Components.classes["@mozilla.org/filepicker;1"] 89 .createInstance(nsIFilePicker); 90 fp.init(window, Zotero.getString("fileInterface.import"), nsIFilePicker.modeOpen); 91 92 fp.appendFilters(nsIFilePicker.filterAll); 93 94 var collation = Zotero.getLocaleCollation(); 95 96 // Add Mendeley DB, which isn't a translator 97 var mendeleyFilter = { 98 label: "Mendeley Database", // TODO: Localize 99 target: "*.sqlite" 100 }; 101 var filters = [...translators]; 102 filters.push(mendeleyFilter); 103 104 filters.sort((a, b) => collation.compareString(1, a.label, b.label)); 105 for (let filter of filters) { 106 fp.appendFilter(filter.label, "*." + filter.target); 107 } 108 109 var rv = fp.show(); 110 if (rv !== nsIFilePicker.returnOK && rv !== nsIFilePicker.returnReplace) { 111 return false; 112 } 113 114 Zotero.debug(`File is ${fp.file.path}`); 115 116 this._file = fp.file.path; 117 this._wizard.canAdvance = true; 118 this._wizard.goTo('page-options'); 119 }, 120 121 122 /** 123 * When a file is clicked on in the file list 124 */ 125 onFileSelected: async function () { 126 var index = document.getElementById('file-list').selectedIndex; 127 if (index != -1) { 128 this._file = this._dbs[index].path; 129 this._wizard.canAdvance = true; 130 } 131 else { 132 this._file = null; 133 this._wizard.canAdvance = false; 134 } 135 }, 136 137 138 /** 139 * When the user clicks "Other…" to choose a file not in the list 140 */ 141 chooseMendeleyDB: async function () { 142 document.getElementById('file-list').selectedIndex = -1; 143 const nsIFilePicker = Components.interfaces.nsIFilePicker; 144 var fp = Components.classes["@mozilla.org/filepicker;1"] 145 .createInstance(nsIFilePicker); 146 fp.init(window, Zotero.getString('fileInterface.import'), nsIFilePicker.modeOpen); 147 fp.appendFilter("Mendeley Database", "*.sqlite"); // TODO: Localize 148 var rv = fp.show(); 149 if (rv != nsIFilePicker.returnOK) { 150 return false; 151 } 152 this._file = fp.file.path; 153 this._wizard.canAdvance = true; 154 this._wizard.advance(); 155 }, 156 157 158 onOptionsShown: function () { 159 160 }, 161 162 163 onImportStart: async function () { 164 if (!this._file) { 165 let index = document.getElementById('file-list').selectedIndex; 166 this._file = this._dbs[index].path; 167 } 168 this._disableCancel(); 169 this._wizard.canRewind = false; 170 this._wizard.canAdvance = false; 171 await this.doImport({ 172 createNewCollection: document.getElementById('create-collection-checkbox').hasAttribute('checked') 173 }); 174 }, 175 176 177 onBeforeImport: async function (translation) { 178 // Unrecognized translator 179 if (!translation) { 180 // Allow error dialog to be displayed, and then close window 181 setTimeout(function () { 182 window.close(); 183 }); 184 return; 185 } 186 187 this._translation = translation; 188 189 // Switch to progress pane 190 this._wizard.goTo('page-progress'); 191 var pm = document.getElementById('import-progressmeter'); 192 193 translation.setHandler('itemDone', function () { 194 pm.value = translation.getProgress(); 195 }); 196 }, 197 198 199 doImport: async function (options) { 200 try { 201 let result = await Zotero_File_Interface.importFile({ 202 file: this._file, 203 onBeforeImport: this.onBeforeImport.bind(this), 204 addToLibraryRoot: !options.createNewCollection 205 }); 206 207 // Cancelled by user or due to error 208 if (!result) { 209 window.close(); 210 return; 211 } 212 213 let numItems = this._translation.newItems.length; 214 this._onDone( 215 Zotero.getString('fileInterface.importComplete'), 216 Zotero.getString(`fileInterface.itemsWereImported`, numItems, numItems) 217 ); 218 } 219 catch (e) { 220 if (e.message == 'Encrypted Mendeley database') { 221 let url = 'https://www.zotero.org/support/kb/mendeley_import'; 222 this._onDone( 223 Zotero.getString('general.error'), 224 // TODO: Localize 225 `The selected Mendeley database cannot be read, likely because it is encrypted. ` 226 + `See <a href="${url}" class="text-link">How do I import a Mendeley library ` 227 + `into Zotero?</a> for more information.` 228 ); 229 } 230 else { 231 this._onDone( 232 Zotero.getString('general.error'), 233 Zotero.getString('fileInterface.importError'), 234 true 235 ); 236 } 237 throw e; 238 } 239 }, 240 241 242 reportError: function () { 243 Zotero.getActiveZoteroPane().reportErrors(); 244 window.close(); 245 }, 246 247 248 _populateFileList: async function (files) { 249 var listbox = document.getElementById('file-list'); 250 251 // Remove existing entries 252 var items = listbox.getElementsByTagName('listitem'); 253 for (let item of items) { 254 listbox.removeChild(item); 255 } 256 257 for (let file of files) { 258 let li = document.createElement('listitem'); 259 260 let name = document.createElement('listcell'); 261 // Simply filenames 262 let nameStr = file.name 263 .replace(/\.sqlite$/, '') 264 .replace(/@www\.mendeley\.com$/, ''); 265 if (nameStr == 'online') { 266 nameStr = Zotero.getString('dataDir.default', 'online.sqlite'); 267 } 268 name.setAttribute('label', nameStr + ' '); 269 li.appendChild(name); 270 271 let lastModified = document.createElement('listcell'); 272 lastModified.setAttribute('label', file.lastModified.toLocaleString() + ' '); 273 li.appendChild(lastModified); 274 275 let size = document.createElement('listcell'); 276 size.setAttribute( 277 'label', 278 Zotero.getString('general.nMegabytes', (file.size / 1024 / 1024).toFixed(1)) + ' ' 279 ); 280 li.appendChild(size); 281 282 listbox.appendChild(li); 283 } 284 285 if (files.length == 1) { 286 listbox.selectedIndex = 0; 287 } 288 }, 289 290 291 _enableCancel: function () { 292 this._wizard.getButton('cancel').disabled = false; 293 }, 294 295 296 _disableCancel: function () { 297 this._wizard.getButton('cancel').disabled = true; 298 }, 299 300 301 _onDone: function (label, description, showReportErrorButton) { 302 var wizard = this._wizard; 303 wizard.getPageById('page-done').setAttribute('label', label); 304 305 var xulElem = document.getElementById('result-description'); 306 var htmlElem = document.getElementById('result-description-html'); 307 308 if (description.includes('href')) { 309 htmlElem.innerHTML = description; 310 Zotero.Utilities.Internal.updateHTMLInXUL(htmlElem); 311 xulElem.hidden = true; 312 htmlElem.setAttribute('display', 'block'); 313 } 314 else { 315 xulElem.textContent = description; 316 xulElem.hidden = false; 317 htmlElem.setAttribute('display', 'none'); 318 } 319 document.getElementById('result-description') 320 321 if (showReportErrorButton) { 322 let button = document.getElementById('result-report-error'); 323 button.setAttribute('label', Zotero.getString('errorReport.reportError')); 324 button.hidden = false; 325 } 326 327 // When done, move to last page and allow closing 328 wizard.canAdvance = true; 329 wizard.goTo('page-done'); 330 wizard.canRewind = false; 331 } 332 };