mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-06-06 18:30:57 +00:00
Merge branch 'main' into session_2025_03_22
This commit is contained in:
commit
b68a3dfd6b
@ -112,7 +112,7 @@
|
|||||||
"ms-python.flake8", // Flake8 linter for Python to enforce code quality
|
"ms-python.flake8", // Flake8 linter for Python to enforce code quality
|
||||||
"ms-python.python", // Official Microsoft Python extension with IntelliSense, debugging, and Jupyter support
|
"ms-python.python", // Official Microsoft Python extension with IntelliSense, debugging, and Jupyter support
|
||||||
"ms-vscode-remote.vscode-remote-extensionpack", // Remote Development Pack for SSH, WSL, and Containers
|
"ms-vscode-remote.vscode-remote-extensionpack", // Remote Development Pack for SSH, WSL, and Containers
|
||||||
"Oracle.oracle-java", // Oracle Java extension with additional features for Java development
|
// "Oracle.oracle-java", // Oracle Java extension with additional features for Java development
|
||||||
"streetsidesoftware.code-spell-checker", // Spell checker for code to avoid typos
|
"streetsidesoftware.code-spell-checker", // Spell checker for code to avoid typos
|
||||||
"vmware.vscode-boot-dev-pack", // Developer tools for Spring Boot by VMware
|
"vmware.vscode-boot-dev-pack", // Developer tools for Spring Boot by VMware
|
||||||
"vscjava.vscode-java-pack", // Java Extension Pack with essential Java tools for VS Code
|
"vscjava.vscode-java-pack", // Java Extension Pack with essential Java tools for VS Code
|
||||||
|
2
.vscode/extensions.json
vendored
2
.vscode/extensions.json
vendored
@ -6,7 +6,7 @@
|
|||||||
"ms-python.flake8", // Flake8 linter for Python to enforce code quality
|
"ms-python.flake8", // Flake8 linter for Python to enforce code quality
|
||||||
"ms-python.python", // Official Microsoft Python extension with IntelliSense, debugging, and Jupyter support
|
"ms-python.python", // Official Microsoft Python extension with IntelliSense, debugging, and Jupyter support
|
||||||
"ms-vscode-remote.vscode-remote-extensionpack", // Remote Development Pack for SSH, WSL, and Containers
|
"ms-vscode-remote.vscode-remote-extensionpack", // Remote Development Pack for SSH, WSL, and Containers
|
||||||
"Oracle.oracle-java", // Oracle Java extension with additional features for Java development
|
// "Oracle.oracle-java", // Oracle Java extension with additional features for Java development
|
||||||
"streetsidesoftware.code-spell-checker", // Spell checker for code to avoid typos
|
"streetsidesoftware.code-spell-checker", // Spell checker for code to avoid typos
|
||||||
"vmware.vscode-boot-dev-pack", // Developer tools for Spring Boot by VMware
|
"vmware.vscode-boot-dev-pack", // Developer tools for Spring Boot by VMware
|
||||||
"vscjava.vscode-java-pack", // Java Extension Pack with essential Java tools for VS Code
|
"vscjava.vscode-java-pack", // Java Extension Pack with essential Java tools for VS Code
|
||||||
|
@ -11,6 +11,7 @@ import stirling.software.SPDF.EE.KeygenLicenseVerifier.License;
|
|||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.model.ApplicationProperties.EnterpriseEdition;
|
import stirling.software.SPDF.model.ApplicationProperties.EnterpriseEdition;
|
||||||
import stirling.software.SPDF.model.ApplicationProperties.Premium;
|
import stirling.software.SPDF.model.ApplicationProperties.Premium;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties.Premium.ProFeatures.GoogleDrive;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||||
@ -43,6 +44,17 @@ public class EEAppConfig {
|
|||||||
return applicationProperties.getPremium().getProFeatures().isSsoAutoLogin();
|
return applicationProperties.getPremium().getProFeatures().isSsoAutoLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean(name = "GoogleDriveEnabled")
|
||||||
|
public boolean googleDriveEnabled() {
|
||||||
|
return runningProOrHigher()
|
||||||
|
&& applicationProperties.getPremium().getProFeatures().getGoogleDrive().isEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean(name = "GoogleDriveConfig")
|
||||||
|
public GoogleDrive googleDriveConfig() {
|
||||||
|
return applicationProperties.getPremium().getProFeatures().getGoogleDrive();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Remove post migration
|
// TODO: Remove post migration
|
||||||
public void migrateEnterpriseSettingsToPremium(ApplicationProperties applicationProperties) {
|
public void migrateEnterpriseSettingsToPremium(ApplicationProperties applicationProperties) {
|
||||||
EnterpriseEdition enterpriseEdition = applicationProperties.getEnterpriseEdition();
|
EnterpriseEdition enterpriseEdition = applicationProperties.getEnterpriseEdition();
|
||||||
|
@ -394,6 +394,7 @@ public class ApplicationProperties {
|
|||||||
|
|
||||||
// TODO: Remove post migration
|
// TODO: Remove post migration
|
||||||
@Data
|
@Data
|
||||||
|
@Deprecated(since = "0.45.0")
|
||||||
public static class EnterpriseEdition {
|
public static class EnterpriseEdition {
|
||||||
private boolean enabled;
|
private boolean enabled;
|
||||||
@ToString.Exclude private String key;
|
@ToString.Exclude private String key;
|
||||||
@ -430,6 +431,7 @@ public class ApplicationProperties {
|
|||||||
public static class ProFeatures {
|
public static class ProFeatures {
|
||||||
private boolean ssoAutoLogin;
|
private boolean ssoAutoLogin;
|
||||||
private CustomMetadata customMetadata = new CustomMetadata();
|
private CustomMetadata customMetadata = new CustomMetadata();
|
||||||
|
private GoogleDrive googleDrive = new GoogleDrive();
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public static class CustomMetadata {
|
public static class CustomMetadata {
|
||||||
@ -448,6 +450,26 @@ public class ApplicationProperties {
|
|||||||
: producer;
|
: producer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class GoogleDrive {
|
||||||
|
private boolean enabled;
|
||||||
|
private String clientId;
|
||||||
|
private String apiKey;
|
||||||
|
private String appId;
|
||||||
|
|
||||||
|
public String getClientId() {
|
||||||
|
return clientId == null || clientId.trim().isEmpty() ? "" : clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApiKey() {
|
||||||
|
return apiKey == null || apiKey.trim().isEmpty() ? "" : apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAppId() {
|
||||||
|
return appId == null || appId.trim().isEmpty() ? "" : appId;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@ -234,29 +234,29 @@ adminUserSettings.totalUsers=Skupno število uporabnikov:
|
|||||||
adminUserSettings.lastRequest=Zadnja zahteva
|
adminUserSettings.lastRequest=Zadnja zahteva
|
||||||
adminUserSettings.usage=View Usage
|
adminUserSettings.usage=View Usage
|
||||||
|
|
||||||
endpointStatistics.title=Endpoint Statistics
|
endpointStatistics.title=Statistika končne točke
|
||||||
endpointStatistics.header=Endpoint Statistics
|
endpointStatistics.header=Statistika končne točke
|
||||||
endpointStatistics.top10=Top 10
|
endpointStatistics.top10=10 najboljših
|
||||||
endpointStatistics.top20=Top 20
|
endpointStatistics.top20=20 najboljših
|
||||||
endpointStatistics.all=All
|
endpointStatistics.all=Vse
|
||||||
endpointStatistics.refresh=Refresh
|
endpointStatistics.refresh=Osveži
|
||||||
endpointStatistics.includeHomepage=Include Homepage ('/')
|
endpointStatistics.includeHomepage=Vključi domačo stran ('/')
|
||||||
endpointStatistics.includeLoginPage=Include Login Page ('/login')
|
endpointStatistics.includeLoginPage=Vključi prijavno stran ('/login')
|
||||||
endpointStatistics.totalEndpoints=Total Endpoints
|
endpointStatistics.totalEndpoints=Skupno končnih točk
|
||||||
endpointStatistics.totalVisits=Total Visits
|
endpointStatistics.totalVisits=Skupno število obiskov
|
||||||
endpointStatistics.showing=Showing
|
endpointStatistics.showing=Prikaz
|
||||||
endpointStatistics.selectedVisits=Selected Visits
|
endpointStatistics.selectedVisits=Izbrani obiski
|
||||||
endpointStatistics.endpoint=Endpoint
|
endpointStatistics.endpoint=Končna točka
|
||||||
endpointStatistics.visits=Visits
|
endpointStatistics.visits=Obiski
|
||||||
endpointStatistics.percentage=Percentage
|
endpointStatistics.percentage=Odstotek
|
||||||
endpointStatistics.loading=Loading...
|
endpointStatistics.loading=Nalaganje...
|
||||||
endpointStatistics.failedToLoad=Failed to load endpoint data. Please try refreshing.
|
endpointStatistics.failedToLoad=Nalaganje podatkov končne točke ni uspelo. Poskusite osvežiti.
|
||||||
endpointStatistics.home=Home
|
endpointStatistics.home=Domača stran
|
||||||
endpointStatistics.login=Login
|
endpointStatistics.login=Prijava
|
||||||
endpointStatistics.top=Top
|
endpointStatistics.top=Na vrh
|
||||||
endpointStatistics.numberOfVisits=Number of Visits
|
endpointStatistics.numberOfVisits=Število obiskov
|
||||||
endpointStatistics.visitsTooltip=Visits: {0} ({1}% of total)
|
endpointStatistics.visitsTooltip=Obiski: {0} ({1}% vseh)
|
||||||
endpointStatistics.retry=Retry
|
endpointStatistics.retry=Poskusi znova
|
||||||
|
|
||||||
database.title=Uvoz/izvoz baze podatkov
|
database.title=Uvoz/izvoz baze podatkov
|
||||||
database.header=Uvoz/izvoz baze podatkov
|
database.header=Uvoz/izvoz baze podatkov
|
||||||
@ -291,14 +291,14 @@ home.viewPdf.title=View/Edit PDF
|
|||||||
home.viewPdf.desc=Oglejte si, komentirajte, dodajte besedilo ali slike
|
home.viewPdf.desc=Oglejte si, komentirajte, dodajte besedilo ali slike
|
||||||
viewPdf.tags=ogled, branje, opomba, besedilo, slika
|
viewPdf.tags=ogled, branje, opomba, besedilo, slika
|
||||||
|
|
||||||
home.setFavorites=Set Favourites
|
home.setFavorites=Nastavi priljubljene
|
||||||
home.hideFavorites=Hide Favourites
|
home.hideFavorites=Skrij priljubljene
|
||||||
home.showFavorites=Show Favourites
|
home.showFavorites=Prikaži priljubljene
|
||||||
home.legacyHomepage=Old homepage
|
home.legacyHomepage=Stara domača stran
|
||||||
home.newHomePage=Try our new homepage!
|
home.newHomePage=Preizkusite našo novo domačo stran!
|
||||||
home.alphabetical=Alphabetical
|
home.alphabetical=Abecedno
|
||||||
home.globalPopularity=Global Popularity
|
home.globalPopularity=Globalna priljubljenost
|
||||||
home.sortBy=Sort by:
|
home.sortBy=Razvrsti po:
|
||||||
|
|
||||||
home.multiTool.title=PDF Multi Tool
|
home.multiTool.title=PDF Multi Tool
|
||||||
home.multiTool.desc=Spoji, zavrti, prerazporedi, razdeli in odstrani strani
|
home.multiTool.desc=Spoji, zavrti, prerazporedi, razdeli in odstrani strani
|
||||||
@ -552,7 +552,7 @@ splitPdfByChapters.tags=razdeli,poglavja,zaznamki,organiziraj
|
|||||||
|
|
||||||
home.validateSignature.title=Preveri podpis PDF
|
home.validateSignature.title=Preveri podpis PDF
|
||||||
home.validateSignature.desc=Preveri digitalne podpise in potrdila v dokumentih PDF
|
home.validateSignature.desc=Preveri digitalne podpise in potrdila v dokumentih PDF
|
||||||
validateSignature.tags=podpis,verify,validate,pdf,certificate,digitalni podpis,Validate Signature,Validate certificate
|
validateSignature.tags=podpis,preveri,validiraj,pdf,certificate,digitalni podpis,Preveri podpis,Preveri certifikat
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Napredne barvne možnosti
|
replace-color.title=Napredne barvne možnosti
|
||||||
@ -787,7 +787,7 @@ autoSplitPDF.selectText.3=Naložite eno veliko optično prebrano datoteko PDF in
|
|||||||
autoSplitPDF.selectText.4=Ločilne strani so samodejno zaznane in odstranjene, kar zagotavlja čist končni dokument.
|
autoSplitPDF.selectText.4=Ločilne strani so samodejno zaznane in odstranjene, kar zagotavlja čist končni dokument.
|
||||||
autoSplitPDF.formPrompt=Pošljite PDF, ki vsebuje razdelilnike strani Stirling-PDF:
|
autoSplitPDF.formPrompt=Pošljite PDF, ki vsebuje razdelilnike strani Stirling-PDF:
|
||||||
autoSplitPDF.duplexMode=Dupleksni način (skeniranje spredaj in zadaj)
|
autoSplitPDF.duplexMode=Dupleksni način (skeniranje spredaj in zadaj)
|
||||||
autoSplitPDF.dividerDownload2=Prenesi 'Auto Splitter Divider (z navodili).pdf'
|
autoSplitPDF.dividerDownload2=Prenesi 'Samodejni razdelilnik (z navodili).pdf'
|
||||||
autoSplitPDF.submit=Pošlji
|
autoSplitPDF.submit=Pošlji
|
||||||
|
|
||||||
|
|
||||||
@ -886,8 +886,8 @@ sign.last=Zadnja stran
|
|||||||
sign.next=Naslednja stran
|
sign.next=Naslednja stran
|
||||||
sign.previous=Prejšnja stran
|
sign.previous=Prejšnja stran
|
||||||
sign.maintainRatio=Preklopi ohranjanje razmerja stranic
|
sign.maintainRatio=Preklopi ohranjanje razmerja stranic
|
||||||
sign.undo=Undo
|
sign.undo=Razveljavi
|
||||||
sign.redo=Redo
|
sign.redo=Ponovi
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Popravilo
|
repair.title=Popravilo
|
||||||
@ -958,8 +958,8 @@ compress.title=Stisnite
|
|||||||
compress.header=Stisnite PDF
|
compress.header=Stisnite PDF
|
||||||
compress.credit=Ta storitev uporablja qpdf za stiskanje/optimizacijo PDF.
|
compress.credit=Ta storitev uporablja qpdf za stiskanje/optimizacijo PDF.
|
||||||
compress.grayscale.label=Uporabi sivinsko lestvico za stiskanje
|
compress.grayscale.label=Uporabi sivinsko lestvico za stiskanje
|
||||||
compress.selectText.1=Compression Settings
|
compress.selectText.1=Nastavitve stiskanja
|
||||||
compress.selectText.1.1=1-3 PDF compression,</br> 4-6 lite image compression,</br> 7-9 intense image compression Will dramatically reduce image quality
|
compress.selectText.1.1=1-3 stiskanje PDF,</br> 4-6 enostavno stiskanje slik,</br> 7-9 intenzivno stiskanje slik Bo dramatično zmanjšalo kakovost slike
|
||||||
compress.selectText.2=Raven optimizacije:
|
compress.selectText.2=Raven optimizacije:
|
||||||
compress.selectText.4=Samodejni način - Samodejno prilagodi kakovost, da dobi PDF na natančno velikost
|
compress.selectText.4=Samodejni način - Samodejno prilagodi kakovost, da dobi PDF na natančno velikost
|
||||||
compress.selectText.5=Pričakovana velikost PDF (npr. 25 MB, 10,8 MB, 25 KB)
|
compress.selectText.5=Pričakovana velikost PDF (npr. 25 MB, 10,8 MB, 25 KB)
|
||||||
@ -1307,15 +1307,15 @@ survey.please=Prosimo, razmislite o sodelovanju v naši anketi, če želite pris
|
|||||||
survey.disabled=(Pojavno okno ankete bo v naslednjih posodobitvah onemogočeno, vendar na voljo na dnu strani)
|
survey.disabled=(Pojavno okno ankete bo v naslednjih posodobitvah onemogočeno, vendar na voljo na dnu strani)
|
||||||
survey.button=Izpolnite anketo
|
survey.button=Izpolnite anketo
|
||||||
survey.dontShowAgain=Ne prikaži več
|
survey.dontShowAgain=Ne prikaži več
|
||||||
survey.meeting.1=If you're using Stirling PDF at work, we'd love to speak to you. We're offering technical support sessions in exchange for a 15 minute user discovery session.
|
survey.meeting.1=Če v službi uporabljate Stirling PDF, bi radi govorili z vami. Ponujamo seje tehnične podpore v zameno za 15-minutno sejo odkrivanja uporabnikov.
|
||||||
survey.meeting.2=This is a chance to:
|
survey.meeting.2=To je priložnost za:
|
||||||
survey.meeting.3=Get help with deployment, integrations, or troubleshooting
|
survey.meeting.3=Poiščite pomoč pri uvajanju, integracijah ali odpravljanju težav
|
||||||
survey.meeting.4=Provide direct feedback on performance, edge cases, and feature gaps
|
survey.meeting.4=Zagotovite neposredne povratne informacije o zmogljivosti, robnih primerih in vrzeli v funkcijah
|
||||||
survey.meeting.5=Help us refine Stirling PDF for real-world enterprise use
|
survey.meeting.5=Pomagajte nam izboljšati Stirling PDF za uporabo v podjetju v resničnem svetu
|
||||||
survey.meeting.6=If you're interested, you can book time with our team directly. (English speaking only)
|
survey.meeting.6=Če ste zainteresirani, si lahko rezervirate čas neposredno pri naši ekipi. (samo angleško govoreči)
|
||||||
survey.meeting.7=Looking forward to digging into your use cases and making Stirling PDF even better!
|
survey.meeting.7=Veselimo se poglobitve v vaše primere uporabe in izboljšanja Stirling PDF-ja!
|
||||||
survey.meeting.notInterested=Not a business and/or interested in a meeting?
|
survey.meeting.notInterested=Niste podjetje in/ali vas zanima srečanje?
|
||||||
survey.meeting.button=Book meeting
|
survey.meeting.button=Rezerviraj srečanje
|
||||||
|
|
||||||
#error
|
#error
|
||||||
error.sorry=Oprostite za težavo!
|
error.sorry=Oprostite za težavo!
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
# If you want to override with environment parameter follow parameter naming SECURITY_INITIALLOGIN_USERNAME #
|
# If you want to override with environment parameter follow parameter naming SECURITY_INITIALLOGIN_USERNAME #
|
||||||
#############################################################################################################
|
#############################################################################################################
|
||||||
|
|
||||||
|
|
||||||
security:
|
security:
|
||||||
enableLogin: false # set to 'true' to enable login
|
enableLogin: false # set to 'true' to enable login
|
||||||
csrfDisabled: false # set to 'true' to disable CSRF protection (not recommended for production)
|
csrfDisabled: false # set to 'true' to disable CSRF protection (not recommended for production)
|
||||||
@ -61,7 +60,6 @@ security:
|
|||||||
privateKey: classpath:saml-private-key.key # Your private key. Generated from your keypair
|
privateKey: classpath:saml-private-key.key # Your private key. Generated from your keypair
|
||||||
spCert: classpath:saml-public-cert.crt # Your signing certificate. Generated from your keypair
|
spCert: classpath:saml-public-cert.crt # Your signing certificate. Generated from your keypair
|
||||||
|
|
||||||
|
|
||||||
premium:
|
premium:
|
||||||
key: 00000000-0000-0000-0000-000000000000
|
key: 00000000-0000-0000-0000-000000000000
|
||||||
enabled: false # Enable license key checks for pro/enterprise features
|
enabled: false # Enable license key checks for pro/enterprise features
|
||||||
@ -72,6 +70,11 @@ premium:
|
|||||||
author: username
|
author: username
|
||||||
creator: Stirling-PDF
|
creator: Stirling-PDF
|
||||||
producer: Stirling-PDF
|
producer: Stirling-PDF
|
||||||
|
googleDrive:
|
||||||
|
enabled: false
|
||||||
|
clientId: ''
|
||||||
|
apiKey: ''
|
||||||
|
appId: ''
|
||||||
|
|
||||||
legal:
|
legal:
|
||||||
termsAndConditions: https://www.stirlingpdf.com/terms-and-conditions # URL to the terms and conditions of your application (e.g. https://example.com/terms). Empty string to disable or filename to load from local file in static folder
|
termsAndConditions: https://www.stirlingpdf.com/terms-and-conditions # URL to the terms and conditions of your application (e.g. https://example.com/terms). Empty string to disable or filename to load from local file in static folder
|
||||||
@ -102,13 +105,11 @@ system:
|
|||||||
name: postgres # set the name of your database. Should match the name of the database you create
|
name: postgres # set the name of your database. Should match the name of the database you create
|
||||||
customPaths:
|
customPaths:
|
||||||
pipeline:
|
pipeline:
|
||||||
watchedFoldersDir: "" #Defaults to /pipeline/watchedFolders
|
watchedFoldersDir: '' #Defaults to /pipeline/watchedFolders
|
||||||
finishedFoldersDir: "" #Defaults to /pipeline/finishedFolders
|
finishedFoldersDir: '' #Defaults to /pipeline/finishedFolders
|
||||||
operations:
|
operations:
|
||||||
weasyprint: "" #Defaults to /opt/venv/bin/weasyprint
|
weasyprint: '' #Defaults to /opt/venv/bin/weasyprint
|
||||||
unoconvert: "" #Defaults to /opt/venv/bin/unoconvert
|
unoconvert: '' #Defaults to /opt/venv/bin/unoconvert
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ui:
|
ui:
|
||||||
appName: '' # application's visible name
|
appName: '' # application's visible name
|
||||||
@ -130,7 +131,7 @@ AutomaticallyGenerated:
|
|||||||
appVersion: 0.35.0
|
appVersion: 0.35.0
|
||||||
|
|
||||||
processExecutor:
|
processExecutor:
|
||||||
sessionLimit: # Process executor instances limits
|
sessionLimit: # Process executor instances limits
|
||||||
libreOfficeSessionLimit: 1
|
libreOfficeSessionLimit: 1
|
||||||
pdfToHtmlSessionLimit: 1
|
pdfToHtmlSessionLimit: 1
|
||||||
qpdfSessionLimit: 4
|
qpdfSessionLimit: 4
|
||||||
@ -139,7 +140,7 @@ processExecutor:
|
|||||||
weasyPrintSessionLimit: 16
|
weasyPrintSessionLimit: 16
|
||||||
installAppSessionLimit: 1
|
installAppSessionLimit: 1
|
||||||
calibreSessionLimit: 1
|
calibreSessionLimit: 1
|
||||||
timeoutMinutes: # Process executor timeout in minutes
|
timeoutMinutes: # Process executor timeout in minutes
|
||||||
libreOfficetimeoutMinutes: 30
|
libreOfficetimeoutMinutes: 30
|
||||||
pdfToHtmltimeoutMinutes: 20
|
pdfToHtmltimeoutMinutes: 20
|
||||||
pythonOpenCvtimeoutMinutes: 30
|
pythonOpenCvtimeoutMinutes: 30
|
||||||
|
@ -271,3 +271,28 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.google-drive-button {
|
||||||
|
width: 2.5rem;
|
||||||
|
pointer-events: auto;
|
||||||
|
cursor: pointer;
|
||||||
|
transition-duration: 0.4s;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
box-shadow: 0 0 5px var(--md-sys-color-on-surface-variant);
|
||||||
|
background-color: var(--md-sys-color-on-surface-container-high)
|
||||||
|
}
|
||||||
|
|
||||||
|
.horizontal-divider {
|
||||||
|
width: 85%;
|
||||||
|
border-top: 1px dashed;
|
||||||
|
padding: 0px;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.google-drive-button img {
|
||||||
|
width:100%
|
||||||
|
}
|
||||||
|
|
||||||
|
.google-drive-button:hover {
|
||||||
|
background-color: var(--md-sys-color-on-surface-variant)
|
||||||
|
}
|
||||||
|
1
src/main/resources/static/images/google-drive.svg
Normal file
1
src/main/resources/static/images/google-drive.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><path fill="#1e88e5" d="M38.59,39c-0.535,0.93-0.298,1.68-1.195,2.197C36.498,41.715,35.465,42,34.39,42H13.61 c-1.074,0-2.106-0.285-3.004-0.802C9.708,40.681,9.945,39.93,9.41,39l7.67-9h13.84L38.59,39z"/><path fill="#fbc02d" d="M27.463,6.999c1.073-0.002,2.104-0.716,3.001-0.198c0.897,0.519,1.66,1.27,2.197,2.201l10.39,17.996 c0.537,0.93,0.807,1.967,0.808,3.002c0.001,1.037-1.267,2.073-1.806,3.001l-11.127-3.005l-6.924-11.993L27.463,6.999z"/><path fill="#e53935" d="M43.86,30c0,1.04-0.27,2.07-0.81,3l-3.67,6.35c-0.53,0.78-1.21,1.4-1.99,1.85L30.92,30H43.86z"/><path fill="#4caf50" d="M5.947,33.001c-0.538-0.928-1.806-1.964-1.806-3c0.001-1.036,0.27-2.073,0.808-3.004l10.39-17.996 c0.537-0.93,1.3-1.682,2.196-2.2c0.897-0.519,1.929,0.195,3.002,0.197l3.459,11.009l-6.922,11.989L5.947,33.001z"/><path fill="#1565c0" d="M17.08,30l-6.47,11.2c-0.78-0.45-1.46-1.07-1.99-1.85L4.95,33c-0.54-0.93-0.81-1.96-0.81-3H17.08z"/><path fill="#2e7d32" d="M30.46,6.8L24,18L17.53,6.8c0.78-0.45,1.66-0.73,2.6-0.79L27.46,6C28.54,6,29.57,6.28,30.46,6.8z"/></svg>
|
After Width: | Height: | Size: 1.1 KiB |
@ -35,6 +35,7 @@ function setupFileInput(chooser) {
|
|||||||
const pdfPrompt = chooser.getAttribute('data-bs-pdf-prompt');
|
const pdfPrompt = chooser.getAttribute('data-bs-pdf-prompt');
|
||||||
const inputContainerId = chooser.getAttribute('data-bs-element-container-id');
|
const inputContainerId = chooser.getAttribute('data-bs-element-container-id');
|
||||||
const showUploads = chooser.getAttribute('data-bs-show-uploads') === "true";
|
const showUploads = chooser.getAttribute('data-bs-show-uploads') === "true";
|
||||||
|
const name = chooser.getAttribute('data-bs-unique-id')
|
||||||
const noFileSelectedPrompt = chooser.getAttribute('data-bs-no-file-selected');
|
const noFileSelectedPrompt = chooser.getAttribute('data-bs-no-file-selected');
|
||||||
|
|
||||||
let inputContainer = document.getElementById(inputContainerId);
|
let inputContainer = document.getElementById(inputContainerId);
|
||||||
@ -87,6 +88,21 @@ function setupFileInput(chooser) {
|
|||||||
overlay = false;
|
overlay = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const googleDriveFileListener = function (e) {
|
||||||
|
const googleDriveFiles = e.detail;
|
||||||
|
|
||||||
|
const fileInput = document.getElementById(elementId);
|
||||||
|
if (fileInput?.hasAttribute('multiple')) {
|
||||||
|
pushFileListTo(googleDriveFiles, allFiles);
|
||||||
|
} else if (fileInput) {
|
||||||
|
allFiles = [googleDriveFiles[0]];
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataTransfer = new DataTransfer();
|
||||||
|
allFiles.forEach((file) => dataTransfer.items.add(file));
|
||||||
|
fileInput.files = dataTransfer.files;
|
||||||
|
fileInput.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { source: 'drag-drop' } }));
|
||||||
|
}
|
||||||
|
|
||||||
const dropListener = function (e) {
|
const dropListener = function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -137,6 +153,7 @@ function setupFileInput(chooser) {
|
|||||||
document.body.addEventListener('dragenter', dragenterListener);
|
document.body.addEventListener('dragenter', dragenterListener);
|
||||||
document.body.addEventListener('dragleave', dragleaveListener);
|
document.body.addEventListener('dragleave', dragleaveListener);
|
||||||
document.body.addEventListener('drop', dropListener);
|
document.body.addEventListener('drop', dropListener);
|
||||||
|
document.body.addEventListener(name + 'GoogleDriveDrivePicked', googleDriveFileListener);
|
||||||
|
|
||||||
$('#' + elementId).on('change', async function (e) {
|
$('#' + elementId).on('change', async function (e) {
|
||||||
let element = e.target;
|
let element = e.target;
|
||||||
|
158
src/main/resources/static/js/googleFilePicker.js
Normal file
158
src/main/resources/static/js/googleFilePicker.js
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
const SCOPES = "https://www.googleapis.com/auth/drive.readonly";
|
||||||
|
const SESSION_STORAGE_ID = "googleDrivePickerAccessToken";
|
||||||
|
|
||||||
|
let tokenClient;
|
||||||
|
let accessToken = sessionStorage.getItem(SESSION_STORAGE_ID);
|
||||||
|
|
||||||
|
let isScriptExecuted = false;
|
||||||
|
if (!isScriptExecuted) {
|
||||||
|
isScriptExecuted = true;
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
document.querySelectorAll(".google-drive-button").forEach(setupGoogleDrivePicker);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function gisLoaded() {
|
||||||
|
tokenClient = google.accounts.oauth2.initTokenClient({
|
||||||
|
client_id: window.stirlingPDF.GoogleDriveClientId,
|
||||||
|
scope: SCOPES,
|
||||||
|
callback: "", // defined later
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// add more as needed.
|
||||||
|
// Google picker is limited on what mimeTypes are supported
|
||||||
|
// Wild card are not supported
|
||||||
|
const expandableMimeTypes = {
|
||||||
|
"image/*" : ["image/jpeg", "image/png","image/svg+xml" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
function fileInputToGooglePickerMimeTypes(accept) {
|
||||||
|
|
||||||
|
if(accept == null || accept == "" || accept.includes("*/*")){
|
||||||
|
|
||||||
|
// Setting null will accept all supported mimetypes
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mimeTypes = [];
|
||||||
|
accept.split(',').forEach(part => {
|
||||||
|
if(!(part in expandableMimeTypes)){
|
||||||
|
mimeTypes.push(part);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
expandableMimeTypes[part].forEach(mimeType => {
|
||||||
|
mimeTypes.push(mimeType);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const mimeString = mimeTypes.join(",").replace(/\s+/g, '');
|
||||||
|
console.log([accept, "became", mimeString]);
|
||||||
|
return mimeString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback after api.js is loaded.
|
||||||
|
*/
|
||||||
|
function gapiLoaded() {
|
||||||
|
gapi.load("client:picker", initializePicker);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback after the API client is loaded. Loads the
|
||||||
|
* discovery doc to initialize the API.
|
||||||
|
*/
|
||||||
|
async function initializePicker() {
|
||||||
|
await gapi.client.load("https://www.googleapis.com/discovery/v1/apis/drive/v3/rest");
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupGoogleDrivePicker(picker) {
|
||||||
|
|
||||||
|
const name = picker.getAttribute('data-name');
|
||||||
|
const accept = picker.getAttribute('data-accept');
|
||||||
|
const multiple = picker.getAttribute('data-multiple') === "true";
|
||||||
|
const mimeTypes = fileInputToGooglePickerMimeTypes(accept);
|
||||||
|
|
||||||
|
picker.addEventListener("click", onGoogleDriveButtonClick);
|
||||||
|
|
||||||
|
function onGoogleDriveButtonClick(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
tokenClient.callback = (response) => {
|
||||||
|
if (response.error !== undefined) {
|
||||||
|
throw response;
|
||||||
|
}
|
||||||
|
accessToken = response.access_token;
|
||||||
|
sessionStorage.setItem(SESSION_STORAGE_ID, accessToken);
|
||||||
|
createGooglePicker();
|
||||||
|
};
|
||||||
|
|
||||||
|
tokenClient.requestAccessToken({ prompt: accessToken === null ? "consent" : "" });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sign out the user upon button click.
|
||||||
|
*/
|
||||||
|
function signOut() {
|
||||||
|
if (accessToken) {
|
||||||
|
sessionStorage.removeItem(SESSION_STORAGE_ID);
|
||||||
|
google.accounts.oauth2.revoke(accessToken);
|
||||||
|
accessToken = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createGooglePicker() {
|
||||||
|
let builder = new google.picker.PickerBuilder()
|
||||||
|
.setDeveloperKey(window.stirlingPDF.GoogleDriveApiKey)
|
||||||
|
.setAppId(window.stirlingPDF.GoogleDriveAppId)
|
||||||
|
.setOAuthToken(accessToken)
|
||||||
|
.addView(
|
||||||
|
new google.picker.DocsView()
|
||||||
|
.setIncludeFolders(true)
|
||||||
|
.setMimeTypes(mimeTypes)
|
||||||
|
)
|
||||||
|
.addView(
|
||||||
|
new google.picker.DocsView()
|
||||||
|
.setIncludeFolders(true)
|
||||||
|
.setEnableDrives(true)
|
||||||
|
.setMimeTypes(mimeTypes)
|
||||||
|
)
|
||||||
|
.setCallback(pickerCallback);
|
||||||
|
|
||||||
|
if(multiple) {
|
||||||
|
builder.enableFeature(google.picker.Feature.MULTISELECT_ENABLED);
|
||||||
|
}
|
||||||
|
const picker = builder.build();
|
||||||
|
|
||||||
|
picker.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the file details of the user's selection.
|
||||||
|
* @param {object} data - Containers the user selection from the picker
|
||||||
|
*/
|
||||||
|
async function pickerCallback(data) {
|
||||||
|
if (data.action === google.picker.Action.PICKED) {
|
||||||
|
const files = await Promise.all(
|
||||||
|
data[google.picker.Response.DOCUMENTS].map(async (pickedFile) => {
|
||||||
|
const fileId = pickedFile[google.picker.Document.ID];
|
||||||
|
console.log(fileId);
|
||||||
|
const res = await gapi.client.drive.files.get({
|
||||||
|
fileId: fileId,
|
||||||
|
alt: "media",
|
||||||
|
});
|
||||||
|
|
||||||
|
let file = new File([new Uint8Array(res.body.length).map((_, i) => res.body.charCodeAt(i))], pickedFile.name, {
|
||||||
|
type: pickedFile.mimeType,
|
||||||
|
lastModified: pickedFile.lastModified,
|
||||||
|
endings: pickedFile.endings,
|
||||||
|
});
|
||||||
|
return file;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
document.body.dispatchEvent(new CustomEvent(name+"GoogleDriveDrivePicked", { detail: files }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -228,8 +228,9 @@
|
|||||||
loading: '[[#{loading}]]'
|
loading: '[[#{loading}]]'
|
||||||
};</script>
|
};</script>
|
||||||
<div class="custom-file-chooser mb-3"
|
<div class="custom-file-chooser mb-3"
|
||||||
|
|
||||||
th:attr="data-bs-unique-id=${name}, data-bs-element-id=${name+'-input'}, data-bs-element-container-id=${name+'-input-container'}, data-bs-show-uploads=${showUploads}, data-bs-files-selected=#{filesSelected}, data-bs-pdf-prompt=#{pdfPrompt}, data-bs-no-file-selected=#{noFileSelected}">
|
th:attr="data-bs-unique-id=${name}, data-bs-element-id=${name+'-input'}, data-bs-element-container-id=${name+'-input-container'}, data-bs-show-uploads=${showUploads}, data-bs-files-selected=#{filesSelected}, data-bs-pdf-prompt=#{pdfPrompt}, data-bs-no-file-selected=#{noFileSelected}">
|
||||||
<div class="mb-3 d-flex flex-row justify-content-center align-items-center flex-wrap input-container"
|
<div class="mb-3 d-flex flex-column justify-content-center align-items-center flex-wrap input-container"
|
||||||
th:name="${name}+'-input'" th:id="${name}+'-input-container'" th:data-text="#{fileChooser.hoveredDragAndDrop}">
|
th:name="${name}+'-input'" th:id="${name}+'-input-container'" th:data-text="#{fileChooser.hoveredDragAndDrop}">
|
||||||
<label class="file-input-btn d-none">
|
<label class="file-input-btn d-none">
|
||||||
<input type="file" class="form-control"
|
<input type="file" class="form-control"
|
||||||
@ -240,10 +241,16 @@
|
|||||||
th:required="${notRequired} ? null : 'required'">
|
th:required="${notRequired} ? null : 'required'">
|
||||||
Browse
|
Browse
|
||||||
</label>
|
</label>
|
||||||
<div class="d-flex justify-content-start align-items-center" id="fileInputText">
|
<div class="d-flex flex-column align-items-center">
|
||||||
<div th:text="#{fileChooser.click}" style="margin-right: 5px"></div>
|
<div class="d-flex justify-content-start align-items-center" id="fileInputText">
|
||||||
<div th:text="#{fileChooser.or}" style="margin-right: 5px"></div>
|
<div th:text="#{fileChooser.click}" style="margin-right: 5px"></div>
|
||||||
<div th:text="#{fileChooser.dragAndDrop}" id="dragAndDrop"></div>
|
<div th:text="#{fileChooser.or}" style="margin-right: 5px"></div>
|
||||||
|
<div th:text="#{fileChooser.dragAndDrop}" id="dragAndDrop"></div>
|
||||||
|
</div>
|
||||||
|
<hr th:if="${@GoogleDriveEnabled == true}" class="horizontal-divider" >
|
||||||
|
</div>
|
||||||
|
<div th:if="${@GoogleDriveEnabled == true}" th:id="${name}+'-google-drive-button'" class="google-drive-button" th:attr="data-name=${name}, data-multiple=${!disableMultipleFiles}, data-accept=${accept}" >
|
||||||
|
<img th:src="@{'/images/google-drive.svg'}" alt="google drive">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="selected-files flex-wrap"></div>
|
<div class="selected-files flex-wrap"></div>
|
||||||
@ -258,4 +265,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script th:src="@{'/js/fileInput.js'}" type="module"></script>
|
<script th:src="@{'/js/fileInput.js'}" type="module"></script>
|
||||||
|
|
||||||
|
<div th:if="${@GoogleDriveEnabled == true}" >
|
||||||
|
<script type="text/javascript" th:src="@{'/js/googleFilePicker.js'}"></script>
|
||||||
|
<script async defer src="https://apis.google.com/js/api.js" onload="gapiLoaded()"></script>
|
||||||
|
<script async defer src="https://accounts.google.com/gsi/client" onload="gisLoaded()"></script>
|
||||||
|
|
||||||
|
<script th:inline="javascript">
|
||||||
|
window.stirlingPDF.GoogleDriveClientId = /*[[${@GoogleDriveConfig.getClientId()}]]*/ null;
|
||||||
|
window.stirlingPDF.GoogleDriveApiKey = /*[[${@GoogleDriveConfig.getApiKey()}]]*/ null;
|
||||||
|
window.stirlingPDF.GoogleDriveAppId = /*[[${@GoogleDriveConfig.getAppId()}]]*/ null;
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
</th:block>
|
</th:block>
|
Loading…
x
Reference in New Issue
Block a user