From db57efeaf1dd7e88dd2058dc3acc5ce4a6f8d5e9 Mon Sep 17 00:00:00 2001 From: kovacsv Date: Mon, 29 Nov 2021 19:48:12 +0100 Subject: [PATCH] Select file to import when there are more importable files #176 --- sandbox/embed_iframe.html | 4 +-- sandbox/embed_iframe_selector.html | 18 +++++++++++ sandbox/node_example/example.js | 2 +- source/import/importer.js | 50 ++++++++++++++++++----------- source/threejs/threemodelloader.js | 7 ++++ test/tests/exportimport_test.js | 2 +- test/tests/importer_test.js | 4 +-- website/o3dv/css/dialogs.css | 19 ++++++++--- website/o3dv/js/exportdialog.js | 11 +++---- website/o3dv/js/loader.js | 51 ++++++++++++++++++++++++++++-- 10 files changed, 130 insertions(+), 38 deletions(-) create mode 100644 sandbox/embed_iframe_selector.html diff --git a/sandbox/embed_iframe.html b/sandbox/embed_iframe.html index 50fc946..953647d 100644 --- a/sandbox/embed_iframe.html +++ b/sandbox/embed_iframe.html @@ -22,7 +22,7 @@ src="../../website/embed.html#model=../test/testfiles/3ds/cube_four_instances.3ds,../test/testfiles/3ds/texture.png$camera=3.929421317669367,6.153966358575169,2.7076091223424714,1.5,1.5,0.5,0,0,1" width=360 height=240 style="border:1px solid #eeeeee;"> - + + diff --git a/sandbox/embed_iframe_selector.html b/sandbox/embed_iframe_selector.html new file mode 100644 index 0000000..c1d0513 --- /dev/null +++ b/sandbox/embed_iframe_selector.html @@ -0,0 +1,18 @@ + + + + + + + Online 3D Viewer + + + + + + + diff --git a/sandbox/node_example/example.js b/sandbox/node_example/example.js index 091bf3a..2235077 100644 --- a/sandbox/node_example/example.js +++ b/sandbox/node_example/example.js @@ -54,7 +54,7 @@ global.FileReader = class }; let settings = new OV.ImportSettings (); -importer.ImportFilesFromFileObjects (files, settings, { +importer.ImportFiles (files, OV.FileSource.File, settings, { onFilesLoaded : function () { }, diff --git a/source/import/importer.js b/source/import/importer.js index 3d7ea41..fa788f3 100644 --- a/source/import/importer.js +++ b/source/import/importer.js @@ -103,16 +103,6 @@ OV.Importer = class this.importers.push (importer); } - ImportFilesFromUrls (urlList, settings, callbacks) - { - this.ImportFiles (urlList, OV.FileSource.Url, settings, callbacks); - } - - ImportFilesFromFileObjects (fileList, settings, callbacks) - { - this.ImportFiles (fileList, OV.FileSource.File, settings, callbacks); - } - ImportFiles (fileList, fileSource, settings, callbacks) { this.LoadFiles (fileList, fileSource, () => { @@ -132,7 +122,7 @@ OV.Importer = class newFileList.FillFromFileObjects (fileList); } let reset = false; - if (this.HasMainFile (newFileList)) { + if (this.HasImportableFile (newFileList)) { reset = true; } else { let foundMissingFile = false; @@ -162,7 +152,29 @@ OV.Importer = class ImportLoadedFiles (settings, callbacks) { - let mainFile = this.GetMainFile (this.fileList); + let importableFiles = this.GetImportableFiles (this.fileList); + if (importableFiles.length === 0) { + callbacks.onImportError (new OV.ImportError (OV.ImportErrorCode.NoImportableFile, null)); + return; + } + + if (importableFiles.length === 1 || !callbacks.onSelectMainFile) { + let mainFile = importableFiles[0]; + this.ImportLoadedMainFile (mainFile, settings, callbacks); + } else { + callbacks.onSelectMainFile (importableFiles, (mainFileIndex) => { + if (mainFileIndex === null) { + callbacks.onImportError (new OV.ImportError (OV.ImportErrorCode.NoImportableFile, null)); + return; + } + let mainFile = importableFiles[mainFileIndex]; + this.ImportLoadedMainFile (mainFile, settings, callbacks); + }); + } + } + + ImportLoadedMainFile (mainFile, settings, callbacks) + { if (mainFile === null || mainFile.file === null || mainFile.file.content === null) { callbacks.onImportError (new OV.ImportError (OV.ImportErrorCode.NoImportableFile, null)); return; @@ -256,12 +268,13 @@ OV.Importer = class return this.fileList; } - HasMainFile (fileList) + HasImportableFile (fileList) { - return this.GetMainFile (fileList) !== null; + let importableFiles = this.GetImportableFiles (fileList); + return importableFiles.length > 0; } - GetMainFile (fileList) + GetImportableFiles (fileList) { function FindImporter (file, importers) { @@ -274,18 +287,19 @@ OV.Importer = class return null; } + let importableFiles = []; let files = fileList.GetFiles (); for (let fileIndex = 0; fileIndex < files.length; fileIndex++) { let file = files[fileIndex]; let importer = FindImporter (file, this.importers); if (importer !== null) { - return { + importableFiles.push ({ file : file, importer : importer - }; + }); } } - return null; + return importableFiles; } RevokeModelUrls () diff --git a/source/threejs/threemodelloader.js b/source/threejs/threemodelloader.js index 02fd571..3a82f5b 100644 --- a/source/threejs/threemodelloader.js +++ b/source/threejs/threemodelloader.js @@ -36,6 +36,13 @@ OV.ThreeModelLoader = class onFilesLoaded : () => { this.callbacks.onImportStart (); }, + onSelectMainFile : (files, selectFile) => { + if (!this.callbacks.onSelectMainFile) { + selectFile (0); + } else { + this.callbacks.onSelectMainFile (files, selectFile); + } + }, onImportSuccess : (importResult) => { this.OnModelImported (importResult); }, diff --git a/test/tests/exportimport_test.js b/test/tests/exportimport_test.js index 8977c27..43c2ee9 100644 --- a/test/tests/exportimport_test.js +++ b/test/tests/exportimport_test.js @@ -12,7 +12,7 @@ function ExportImport (model, format, extension, onReady) } let importer = new OV.Importer (); let settings = new OV.ImportSettings (); - importer.ImportFilesFromFileObjects (fileObjects, settings, { + importer.ImportFiles (fileObjects, OV.FileSource.File, settings, { onFilesLoaded : function () { }, diff --git a/test/tests/importer_test.js b/test/tests/importer_test.js index 6e392ab..754ea40 100644 --- a/test/tests/importer_test.js +++ b/test/tests/importer_test.js @@ -4,7 +4,7 @@ var path = require ('path'); function ImportFilesWithImporter (importer, files, callbacks) { let settings = new OV.ImportSettings (); - importer.ImportFilesFromFileObjects (files, settings, { + importer.ImportFiles (files, OV.FileSource.File, settings, { onFilesLoaded : function () { }, @@ -254,7 +254,7 @@ describe ('Importer Test', function () { let theImporter = new OV.Importer (); let settings = new OV.ImportSettings (); settings.defaultColor = new OV.Color (200, 0, 0); - theImporter.ImportFilesFromFileObjects (files, settings, { + theImporter.ImportFiles (files, OV.FileSource.File, settings, { onFilesLoaded : function () { }, diff --git a/website/o3dv/css/dialogs.css b/website/o3dv/css/dialogs.css index c864902..cbcad2b 100644 --- a/website/o3dv/css/dialogs.css +++ b/website/o3dv/css/dialogs.css @@ -116,22 +116,31 @@ div.ov_dialog div.ov_dialog_file_list overflow: auto; } -div.ov_dialog a.ov_dialog_file_link +div.ov_dialog div.ov_dialog_import_file_list { + max-height: 300px; + overflow: auto; +} + +div.ov_dialog div.ov_dialog_file_link +{ + color: var(--ov_button_color); padding: 5px; display: block; overflow: auto; border-radius: 5px; + cursor: pointer; } -div.ov_dialog a.ov_dialog_file_link div.ov_file_link_img +div.ov_dialog div.ov_dialog_file_link div.ov_file_link_img { color: var(--ov_button_color); + margin-top: 2px; margin-right: 10px; float: left; } -div.ov_dialog a.ov_dialog_file_link div.ov_dialog_file_link_text +div.ov_dialog div.ov_dialog_file_link div.ov_dialog_file_link_text { float: left; } @@ -234,13 +243,13 @@ div.ov_progress div.ov_progress_text @media (hover) { -div.ov_dialog a.ov_dialog_file_link:hover +div.ov_dialog div.ov_dialog_file_link:hover { color: var(--ov_hover_text_color); background: var(--ov_hover_color); } -div.ov_dialog a.ov_dialog_file_link:hover div.ov_file_link_img +div.ov_dialog div.ov_dialog_file_link:hover div.ov_file_link_img { color: var(--ov_hover_text_color); } diff --git a/website/o3dv/js/exportdialog.js b/website/o3dv/js/exportdialog.js index 0a2f783..e61c0c6 100644 --- a/website/o3dv/js/exportdialog.js +++ b/website/o3dv/js/exportdialog.js @@ -212,14 +212,13 @@ OV.ExportDialog = class let fileListSection = OV.AddDiv (contentDiv, 'ov_dialog_section'); let fileList = OV.AddDiv (fileListSection, 'ov_dialog_file_list ov_thin_scrollbar'); - for (let i = 0; i < files.length; i++) { - let file = files[i]; - let url = OV.CreateObjectUrl (file.GetBufferContent ()); - let fileLink = OV.AddDomElement (fileList, 'a', 'ov_dialog_file_link'); - fileLink.setAttribute ('href', url); - fileLink.setAttribute ('download', file.GetName ()); + for (let file of files) { + let fileLink = OV.AddDiv (fileList, 'ov_dialog_file_link'); OV.AddSvgIconElement (fileLink, 'file_download', 'ov_file_link_img'); OV.AddDiv (fileLink, 'ov_dialog_file_link_text', file.GetName ()); + fileLink.addEventListener ('click', () => { + OV.DownloadArrayBufferAsFile (file.GetBufferContent (), file.GetName ()); + }); } dialog.Show (); diff --git a/website/o3dv/js/loader.js b/website/o3dv/js/loader.js index 7350dcf..109670f 100644 --- a/website/o3dv/js/loader.js +++ b/website/o3dv/js/loader.js @@ -23,6 +23,44 @@ OV.InitModelLoader = function (modelLoader, callbacks) } } + function ShowFileSelectorDialog (files, onSelect) + { + let dialog = new OV.ButtonDialog (); + let contentDiv = dialog.Init ('Select Model', [ + { + name : 'Cancel', + subClass : 'outline', + onClick () { + dialog.Hide (); + } + } + ]); + dialog.SetCloseHandler (() => { + onSelect (null); + }); + + let text = 'Multiple importable models found. Select the model you would like to import from the list below.'; + OV.AddDiv (contentDiv, 'ov_dialog_message', text); + + let fileListSection = OV.AddDiv (contentDiv, 'ov_dialog_section'); + let fileList = OV.AddDiv (fileListSection, 'ov_dialog_import_file_list ov_thin_scrollbar'); + + for (let i = 0; i < files.length; i++) { + let file = files[i]; + let fileLink = OV.AddDiv (fileList, 'ov_dialog_file_link'); + OV.AddSvgIconElement (fileLink, 'meshes', 'ov_file_link_img'); + OV.AddDiv (fileLink, 'ov_dialog_file_link_text', file.file.name); + fileLink.addEventListener ('click', () => { + dialog.SetCloseHandler (null); + dialog.Hide (); + onSelect (i); + }); + } + + dialog.Show (); + return dialog; + } + function CloseDialogIfOpen (dialog) { if (dialog !== null) { @@ -31,16 +69,23 @@ OV.InitModelLoader = function (modelLoader, callbacks) } } - let errorDialog = null; + let modalDialog = null; let progressDialog = null; modelLoader.Init ({ onLoadStart : () => { - CloseDialogIfOpen (errorDialog); + CloseDialogIfOpen (modalDialog); callbacks.onStart (); progressDialog = new OV.ProgressDialog (); progressDialog.Init ('Loading Model'); progressDialog.Show (); }, + onSelectMainFile : (files, selectFile) => { + progressDialog.Hide (); + modalDialog = ShowFileSelectorDialog (files, (index) => { + progressDialog.Show (); + selectFile (index); + }); + }, onImportStart : () => { progressDialog.SetText ('Importing Model'); }, @@ -57,7 +102,7 @@ OV.InitModelLoader = function (modelLoader, callbacks) onLoadError : (importError) => { progressDialog.Hide (); callbacks.onError (importError); - errorDialog = OpenErrorDialog (importError); + modalDialog = OpenErrorDialog (importError); }, }); };