mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 19:49:01 +01:00 
			
		
		
		
	Merge remote-tracking branch 'origin/develop' into feature/in_app_help
This commit is contained in:
		
						commit
						cecd7eccad
					
				
							
								
								
									
										13
									
								
								.github/actions/build-electron/action.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								.github/actions/build-electron/action.yml
									
									
									
									
										vendored
									
									
								
							| @ -15,13 +15,22 @@ runs: | ||||
|       if: ${{ inputs.os == 'macos' }} | ||||
|       shell: bash | ||||
|       run: brew install python-setuptools | ||||
|     - name: Install rpm on Ubuntu for RPM package building | ||||
|     - name: Install dependencies for RPM and Flatpak package building | ||||
|       if: ${{ inputs.os == 'linux' }} | ||||
|       shell: bash | ||||
|       run: sudo apt install rpm | ||||
|       run: | | ||||
|         sudo apt-get update && sudo apt-get install rpm flatpak-builder elfutils | ||||
|         flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo | ||||
|         FLATPAK_ARCH=$(if [[ ${{ inputs.arch }} = 'arm64' ]]; then echo 'aarch64'; else echo 'x86_64'; fi) | ||||
|         FLATPAK_VERSION='24.08' | ||||
|         flatpak install --user --no-deps --arch $FLATPAK_ARCH --assumeyes runtime/org.freedesktop.Platform/$FLATPAK_ARCH/$FLATPAK_VERSION runtime/org.freedesktop.Sdk/$FLATPAK_ARCH/$FLATPAK_VERSION org.electronjs.Electron2.BaseApp/$FLATPAK_ARCH/$FLATPAK_VERSION | ||||
|     - name: Install dependencies | ||||
|       shell: bash | ||||
|       run: npm ci | ||||
|     - name: Temporary Flatpak arm64 workaround till https://github.com/electron/forge/pull/3839 is merged | ||||
|       if: ${{ inputs.os == 'linux' && inputs.arch == 'arm64' }} | ||||
|       shell: bash | ||||
|       run:  sed -e "s/case 'armv7l'/case 'arm64'/g" -e "s/return 'arm'/return 'aarch64'/g" -i node_modules/@electron-forge/maker-flatpak/dist/MakerFlatpak.js | ||||
|     - name: Update build info | ||||
|       shell: bash | ||||
|       run: npm run update-build-info | ||||
|  | ||||
							
								
								
									
										2
									
								
								.github/actions/build-server/action.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/actions/build-server/action.yml
									
									
									
									
										vendored
									
									
								
							| @ -25,4 +25,4 @@ runs: | ||||
|       run: | | ||||
|         mkdir -p upload | ||||
|         file=$(find dist -name '*.tar.xz' -print -quit) | ||||
|         cp "$file" "upload/TriliumNextNotes-linux-${{ inputs.arch }}-${{ github.ref_name }}.tar.xz" | ||||
|         cp "$file" "upload/TriliumNextNotes-Server-${{ github.ref_name }}-${{ inputs.os }}-${{ inputs.arch }}.tar.xz" | ||||
|  | ||||
							
								
								
									
										3
									
								
								.github/workflows/main.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.github/workflows/main.yml
									
									
									
									
										vendored
									
									
								
							| @ -26,7 +26,7 @@ jobs: | ||||
|             extension: [dmg, zip] | ||||
|           - name: linux | ||||
|             image: ubuntu-latest | ||||
|             extension: [deb, rpm, zip] | ||||
|             extension: [deb, rpm, zip, flatpak] | ||||
|           - name: windows | ||||
|             image: windows-latest | ||||
|             extension: exe | ||||
| @ -53,6 +53,7 @@ jobs: | ||||
|         with: | ||||
|           name: TriliumNextNotes ${{ matrix.os.name }} ${{ matrix.arch }}.${{matrix.os.extension}} | ||||
|           path: upload/*.${{ matrix.os.extension }} | ||||
| 
 | ||||
|   build_linux_server: | ||||
|     name: Build Linux Server | ||||
|     strategy: | ||||
|  | ||||
							
								
								
									
										11
									
								
								.github/workflows/nightly.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								.github/workflows/nightly.yml
									
									
									
									
										vendored
									
									
								
							| @ -23,7 +23,7 @@ jobs: | ||||
|             extension: [dmg, zip] | ||||
|           - name: linux | ||||
|             image: ubuntu-latest | ||||
|             extension: [deb, rpm, zip] | ||||
|             extension: [deb, rpm, zip, flatpak] | ||||
|           - name: windows | ||||
|             image: windows-latest | ||||
|             extension: exe | ||||
| @ -49,11 +49,14 @@ jobs: | ||||
|       - name: Publish release | ||||
|         uses: softprops/action-gh-release@v2 | ||||
|         with: | ||||
|           draft: true | ||||
|           make_latest: false | ||||
|           prerelease: true | ||||
|           draft: false | ||||
|           fail_on_unmatched_files: true | ||||
|           files: upload/*.* | ||||
|           tag_name: nightly | ||||
|           name: Nightly Build | ||||
| 
 | ||||
|   nightly-server: | ||||
|     name: Deploy server nightly | ||||
|     strategy: | ||||
| @ -77,7 +80,9 @@ jobs: | ||||
|       - name: Publish release | ||||
|         uses: softprops/action-gh-release@v2 | ||||
|         with: | ||||
|           draft: true | ||||
|           make_latest: false | ||||
|           prerelease: true | ||||
|           draft: false | ||||
|           fail_on_unmatched_files: true | ||||
|           files: upload/*.* | ||||
|           tag_name: nightly | ||||
|  | ||||
							
								
								
									
										3
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @ -23,7 +23,7 @@ jobs: | ||||
|             extension: [dmg, zip] | ||||
|           - name: linux | ||||
|             image: ubuntu-latest | ||||
|             extension: [deb, rpm, zip] | ||||
|             extension: [deb, rpm, zip, flatpak] | ||||
|           - name: windows | ||||
|             image: windows-latest | ||||
|             extension: exe | ||||
| @ -46,6 +46,7 @@ jobs: | ||||
|           draft: true | ||||
|           fail_on_unmatched_files: true | ||||
|           files: upload/*.* | ||||
| 
 | ||||
|   build_linux_server-x64: | ||||
|     name: Build Linux Server | ||||
|     strategy: | ||||
|  | ||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -7,6 +7,7 @@ src/public/app-dist/ | ||||
| npm-debug.log | ||||
| yarn-error.log | ||||
| po-*/ | ||||
| .flatpak-builder/ | ||||
| 
 | ||||
| *.db | ||||
| !integration-tests/db/document.db | ||||
|  | ||||
| @ -118,8 +118,10 @@ Head on over to our [Docs repo](https://github.com/TriliumNext/Docs) | ||||
| 
 | ||||
| ## 🤝 Support | ||||
| 
 | ||||
| You can support the original Trilium developer using GitHub Sponsors, [PayPal](https://paypal.me/za4am) or Bitcoin (bitcoin:bc1qv3svjn40v89mnkre5vyvs2xw6y8phaltl385d2). | ||||
| Support for the TriliumNext organization will be possible in the near future. | ||||
| Support for the TriliumNext organization will be possible in the near future. For now, you can: | ||||
| - Support continued development on TriliumNext by supporting our developers: [eliandoran](https://github.com/sponsors/eliandoran) (See the [repository insights]([developers]([url](https://github.com/TriliumNext/Notes/graphs/contributors))) for a full list) | ||||
| - Show a token of gratitude to the original Trilium developer ([zadam](https://github.com/sponsors/zadam)) via [PayPal](https://paypal.me/za4am) or Bitcoin (bitcoin:bc1qv3svjn40v89mnkre5vyvs2xw6y8phaltl385d2). | ||||
| 
 | ||||
| 
 | ||||
| ## 🔑 License | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								db/demo.zip
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								db/demo.zip
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| @ -7,6 +7,7 @@ const extraResourcesForPlatform = getExtraResourcesForPlatform(); | ||||
| const baseLinuxMakerConfigOptions = { | ||||
|   icon: "./images/app-icons/png/128x128.png", | ||||
|   desktopTemplate: path.resolve("./bin/electron-forge/desktop.ejs"), | ||||
|   categories: ["Office", "Utility"] | ||||
| }; | ||||
| 
 | ||||
| module.exports = { | ||||
| @ -59,6 +60,29 @@ module.exports = { | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         { | ||||
|             name: "@electron-forge/maker-flatpak", | ||||
|             config: { | ||||
|                 options: { | ||||
|                     ...baseLinuxMakerConfigOptions, | ||||
|                     id: "com.triliumnext.notes", | ||||
|                     runtimeVersion: "24.08", | ||||
|                     base: "org.electronjs.Electron2.BaseApp", | ||||
|                     baseVersion: "24.08", | ||||
|                     baseFlatpakref: "https://flathub.org/repo/flathub.flatpakrepo", | ||||
|                     modules: [ | ||||
|                         { | ||||
|                             name: "zypak", | ||||
|                             sources: { | ||||
|                                 type: "git", | ||||
|                                 url: "https://github.com/refi64/zypak", | ||||
|                                 tag: "v2024.01.17" | ||||
|                             } | ||||
|                         } | ||||
|                     ] | ||||
|                 }, | ||||
|             } | ||||
|         }, | ||||
|         { | ||||
|             name: "@electron-forge/maker-rpm", | ||||
|             config: { | ||||
|  | ||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 109 KiB | 
| @ -1,124 +1,125 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 256 256" style="enable-background:new 0 0 256 256;" xml:space="preserve"> | ||||
| <style type="text/css"> | ||||
| 	.st0{fill:#686768;} | ||||
| 	.st1{fill:#808080;} | ||||
| 	.st2{fill:url(#SVGID_1_);} | ||||
| 	.st3{fill:url(#SVGID_2_);} | ||||
| 	.st4{fill:url(#SVGID_3_);} | ||||
| 	.st5{fill:#D9D9D9;} | ||||
| 	.st6{fill:url(#SVGID_4_);} | ||||
| 	.st7{opacity:0.47;} | ||||
| 	.st8{fill:#5B5A5A;} | ||||
| 	.st9{fill:#95C980;} | ||||
| 	.st10{fill:#72B755;} | ||||
| 	.st11{fill:#4FA52B;} | ||||
| 	.st12{fill:#EE8C89;} | ||||
| 	.st13{fill:#E96562;} | ||||
| 	.st14{fill:#E33F3B;} | ||||
| 	.st15{fill:#EFB075;} | ||||
| 	.st16{fill:#E99547;} | ||||
| 	.st17{fill:#E47B19;} | ||||
| 	.st18{opacity:0.38;fill:url(#SVGID_5_);} | ||||
| </style> | ||||
| <g id="Layer_1"> | ||||
| 	<g id="Layer_1_1_"> | ||||
| 	</g> | ||||
| </g> | ||||
| <g id="Layer_2"> | ||||
| 	<polygon class="st0" points="86.3,63.2 86.2,99.4 33.1,101.1 32.5,99.9 53.9,67.1 	"/> | ||||
| 	<path class="st1" d="M86.3,61.9l-0.2,37.5c0,0-53.9,0.8-53.7,0.5l21.2-34L86.3,61.9z"/> | ||||
| 	 | ||||
| 		<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="86.3479" y1="130.1949" x2="208.0555" y2="130.1949" gradientTransform="matrix(1 0 0 -1 0 258)"> | ||||
| 		<stop  offset="0" style="stop-color:#E3E3E3"/> | ||||
| 		<stop  offset="1" style="stop-color:#F4F4F4"/> | ||||
| 	</linearGradient> | ||||
| 	<polygon class="st2" points="86.3,61.9 207.8,68.9 208.1,188.4 86.7,193.7 	"/> | ||||
| 	 | ||||
| 		<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="53.6067" y1="130.1949" x2="86.6402" y2="130.1949" gradientTransform="matrix(1 0 0 -1 0 258)"> | ||||
| 		<stop  offset="0" style="stop-color:#D9D9D9"/> | ||||
| 		<stop  offset="1" style="stop-color:#D4D4D4"/> | ||||
| 	</linearGradient> | ||||
| 	<polygon class="st3" points="53.6,65.8 86.3,61.9 86.6,193.7 53.6,189.9 	"/> | ||||
| 	 | ||||
| 		<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="154.1068" y1="201.7921" x2="146.7211" y2="271.9565" gradientTransform="matrix(0.9941 1.431752e-03 -1.431754e-03 -1.1143 -2.6949 323.3557)"> | ||||
| 		<stop  offset="0" style="stop-color:#B3B3B3"/> | ||||
| 		<stop  offset="0.4752" style="stop-color:#B5B5B5"/> | ||||
| 		<stop  offset="0.6464" style="stop-color:#BCBCBC"/> | ||||
| 		<stop  offset="0.7685" style="stop-color:#C7C7C7"/> | ||||
| 		<stop  offset="0.8671" style="stop-color:#D8D8D8"/> | ||||
| 		<stop  offset="0.9506" style="stop-color:#EEEEEE"/> | ||||
| 		<stop  offset="1" style="stop-color:#FFFFFF"/> | ||||
| 	</linearGradient> | ||||
| 	<polygon class="st4" points="208.1,103.8 109,99.5 86.3,62.2 207.8,68.9 	"/> | ||||
| 	<polygon class="st1" points="112.8,93.1 234.1,99.3 235.4,97.8 88.5,63.5 86.3,61.9 	"/> | ||||
| 	<polygon class="st5" points="235.4,97.8 133.9,92.5 112.8,91.1 86.6,62.2 208,68.9 219.8,81.8 235,97.4 235,97.4 	"/> | ||||
| 	 | ||||
| 		<radialGradient id="SVGID_4_" cx="480.8341" cy="689.2393" r="3.2653" gradientTransform="matrix(0.5088 -4.329579e-03 -0.1464 -14.7395 -56.4799 10295.6123)" gradientUnits="userSpaceOnUse"> | ||||
| 		<stop  offset="0" style="stop-color:#FFFFFF"/> | ||||
| 		<stop  offset="6.758273e-02" style="stop-color:#FFFFFF;stop-opacity:0.9324"/> | ||||
| 		<stop  offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/> | ||||
| 	</radialGradient> | ||||
| 	<path class="st6" d="M88.5,147.7c0.2,21.3,0.7,34.5,0.1,34.5c-0.7,0-1.2-5.1-2-26.3c-0.9-21.2-1.1-69.1-0.4-69.2 | ||||
| 		C86.8,86.5,88.3,126.5,88.5,147.7z"/> | ||||
| 	<g class="st7"> | ||||
| 		<path class="st8" d="M53.5,189.5l16.6,1.7c2.7,0.3,5.6,0.5,8.3,0.9l8.3,1h-0.1l60.7-2.6l30.4-1.4l7.6-0.3c2.5-0.1,5.1-0.2,7.6-0.3 | ||||
| 			l15.2-0.4l-15.2,1c-2.5,0.2-5.1,0.3-7.6,0.4l-7.6,0.3l-30.4,1.4l-60.6,2.6l0,0l0,0l-8.3-1c-2.7-0.3-5.5-0.7-8.3-1.1L53.5,189.5z" | ||||
| 			/> | ||||
| 		<path class="st1" d="M53.1,189.5c2.7,0.2,5.5,0.3,8.4,0.5c2.9,0.2,5.8,0.4,8.6,0.7l8.3,0.9l8.3,1l-0.1,0.9l-0.1,0l0-0.9l60.8-2.5 | ||||
| 			l30.4-1.3l15.2-0.6l15.2-0.4l0,0.5l-15.2,0.9l-7.6,0.4l-7.6,0.3l-30.4,1.3l-60.7,2.5l0,0l0,0l-8.3-1l-8.3-1.1l-16.6-2.2 | ||||
| 			L53.1,189.5z M54.5,189.7l15.6,2l8.3,1.1l8.3,1l0,0l60.7-2.7l30.4-1.4l7.6-0.3l7.6-0.4l15.2-1l0,0.5l-15.2,0.4l-15.2,0.6 | ||||
| 			l-30.4,1.4l-60.7,2.7l0-0.9l0.1,0l-0.1,0.9l-8.3-1l-8.3-0.9c-2.7-0.3-5.3-0.5-7.9-0.9C59.6,190.4,57.1,190,54.5,189.7z"/> | ||||
| 	</g> | ||||
| 	<g> | ||||
| 		<g> | ||||
| 			<g> | ||||
| 				<path class="st9" d="M177.3,134.6c-7.1,5.5-19.1,6.6-27.5,4.5c2.1-1.9,3.1-2.8,5.1-4.7c2-1.8,2.9-2.6,4.9-4.4 | ||||
| 					c6.8-6,10.2-8.8,16.8-14.4c-6.9,5.2-10.5,7.8-17.6,13.3c-2,1.6-3,2.3-5,3.9c-2.1,1.6-3.1,2.5-5.2,4.1c-0.4-7.7,0.9-18,8.4-23.5 | ||||
| 					c0.6-0.5,1.4-0.9,2.1-1.4c1-0.5,2-1.1,3.2-1.5c9.3-3.6,20.2-6.1,30.3-4.8c0.6,5.3-4,15.4-9.6,22.9c-0.8,1-1.5,2-2.3,2.9 | ||||
| 					C179.6,132.6,178.4,133.7,177.3,134.6z"/> | ||||
| 				<path class="st10" d="M180.7,131.4c-7.5,4.9-18.4,4.7-25.8,3c2-1.8,2.9-2.6,4.9-4.4c6.8-6,10.2-8.8,16.8-14.4 | ||||
| 					c-6.9,5.2-10.5,7.8-17.6,13.3c-2,1.6-3,2.3-5,3.9c-0.4-6.4,0.3-15,5.3-20.7c1-0.5,2-1.1,3.2-1.5c9.3-3.7,20.2-6.1,30.3-4.8 | ||||
| 					c0.6,5.3-4,15.4-9.6,22.9C182.3,129.5,181.5,130.5,180.7,131.4z"/> | ||||
| 				<path class="st11" d="M183.1,128.5c-7.2,3.4-16.7,3.1-23.2,1.5c6.8-6,10.2-8.8,16.8-14.4c-6.9,5.2-10.5,7.8-17.6,13.3 | ||||
| 					c-0.4-5.5,0-12.8,3.5-18.4c9.3-3.6,20.2-6.1,30.3-4.8C193.4,111,188.8,121.2,183.1,128.5z"/> | ||||
| 			</g> | ||||
| 			<g> | ||||
| 				<path class="st12" d="M144,161.3c-2.9-7.2,0.4-15.9,3.8-21.1c0.9,2,1.3,3,2.2,4.9c0.9,1.9,1.3,2.8,2.1,4.6 | ||||
| 					c3,6.4,4.5,9.6,7.6,15.6c-2.5-6.2-3.8-9.4-6.4-16c-0.7-1.8-1.1-2.7-1.8-4.5c-0.8-1.9-1.2-2.9-1.9-4.9c6,1.8,13.7,5.4,16.5,12.2 | ||||
| 					c0.2,0.6,0.4,1.2,0.6,1.8c0.2,0.8,0.4,1.7,0.5,2.6c1.2,7.8-0.7,18.7-3.6,22.8c-4.5-0.7-11.8-6.3-16.3-12.3 | ||||
| 					c-0.6-0.8-1.2-1.6-1.7-2.4C145,163.5,144.5,162.4,144,161.3z"/> | ||||
| 				<path class="st13" d="M145.7,164.6c-1.9-6.8,1.2-14.7,4.4-19.5c0.9,1.9,1.3,2.8,2.1,4.6c3,6.4,4.5,9.6,7.6,15.6 | ||||
| 					c-2.5-6.2-3.8-9.4-6.4-16c-0.7-1.8-1.1-2.7-1.8-4.5c5.1,1.4,11.7,4.2,15.2,9.2c0.2,0.8,0.4,1.7,0.5,2.6 | ||||
| 					c1.2,7.8-0.7,18.7-3.6,22.7c-4.5-0.7-11.8-6.3-16.3-12.3C146.8,166.2,146.3,165.4,145.7,164.6z"/> | ||||
| 				<path class="st14" d="M147.4,167c-0.9-6.1,2-13,4.8-17.3c3,6.4,4.5,9.6,7.6,15.6c-2.5-6.2-3.8-9.4-6.4-16 | ||||
| 					c4.5,1.1,10.2,3.3,14,7.2c1.2,7.8-0.7,18.7-3.6,22.7C159.1,178.5,151.9,173,147.4,167z"/> | ||||
| 			</g> | ||||
| 			<g> | ||||
| 				<path class="st15" d="M132.2,118.5c8.5,3.5,13.4,12.5,15.3,19c-2.4-0.8-3.5-1.1-5.9-1.9c-2.3-0.7-3.4-1.1-5.6-1.8 | ||||
| 					c-7.9-2.6-11.8-4-19.4-6.7c7.4,3.1,11.1,4.7,18.8,7.8c2.1,0.9,3.2,1.3,5.3,2.2c2.2,0.9,3.3,1.3,5.6,2.2c-6,3.4-15,6.8-23,3.7 | ||||
| 					c-0.6-0.2-1.4-0.6-2.1-1c-0.8-0.5-1.8-1-2.7-1.7c-6.9-4.9-14.3-13.6-17-21.8c4-2.8,14.3-3.4,23-1.9c1.2,0.2,2.3,0.4,3.5,0.7 | ||||
| 					C129.6,117.5,130.9,117.9,132.2,118.5z"/> | ||||
| 				<path class="st16" d="M128,117.1c7.4,3.9,11.8,12.2,13.6,18.4c-2.3-0.7-3.4-1.1-5.6-1.8c-7.9-2.6-11.8-4-19.4-6.7 | ||||
| 					c7.4,3.1,11.1,4.7,18.7,7.8c2.1,0.9,3.2,1.3,5.3,2.2c-5,2.9-12.5,6-19.4,4.9c-0.8-0.5-1.8-1-2.7-1.7c-6.9-4.9-14.3-13.6-17-21.8 | ||||
| 					c4-2.8,14.3-3.4,23-1.9C125.8,116.6,126.9,116.7,128,117.1z"/> | ||||
| 				<path class="st17" d="M124.6,116.3c6.1,4.3,9.8,11.7,11.4,17.3c-7.9-2.6-11.8-4-19.4-6.7c7.4,3.1,11.1,4.7,18.8,7.8 | ||||
| 					c-4.4,2.6-10.6,5.4-16.8,5.3c-6.9-4.9-14.3-13.6-17-21.8C105.6,115.4,115.8,114.8,124.6,116.3z"/> | ||||
| 			</g> | ||||
| 		</g> | ||||
| 	</g> | ||||
| 	<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="226.3925" y1="147.1083" x2="159.9567" y2="186.9981"> | ||||
| 		<stop  offset="0.1721" style="stop-color:#C7C7C7"/> | ||||
| 		<stop  offset="0.3798" style="stop-color:#D8D8D8"/> | ||||
| 		<stop  offset="0.6814" style="stop-color:#DADADA"/> | ||||
| 		<stop  offset="0.7898" style="stop-color:#E1E1E1"/> | ||||
| 		<stop  offset="0.867" style="stop-color:#ECECEC"/> | ||||
| 		<stop  offset="0.8745" style="stop-color:#EEEEEE"/> | ||||
| 		<stop  offset="1" style="stop-color:#FFFFFF"/> | ||||
| 	</linearGradient> | ||||
| 	<path class="st18" d="M208,128c-0.8,0.3-2.7,12.8-3,15.6c-0.6,4.7-3.2,23.3-9,33.5c-5.9,10.4-12.8,11.1-13.3,11.9l25.3-0.7 | ||||
| 		C208,169.3,208,146.9,208,128L208,128z"/> | ||||
| </g> | ||||
| </svg> | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 256 256" style="enable-background:new 0 0 256 256;" xml:space="preserve"> | ||||
| <style type="text/css"> | ||||
| 	.st0{fill:#686768;} | ||||
| 	.st1{fill:#808080;} | ||||
| 	.st2{fill:url(#SVGID_1_);} | ||||
| 	.st3{fill:url(#SVGID_2_);} | ||||
| 	.st4{fill:url(#SVGID_3_);} | ||||
| 	.st5{fill:#D9D9D9;} | ||||
| 	.st6{fill:url(#SVGID_4_);} | ||||
| 	.st7{opacity:0.47;} | ||||
| 	.st8{fill:#5B5A5A;} | ||||
| 	.st9{fill:#95C980;} | ||||
| 	.st10{fill:#72B755;} | ||||
| 	.st11{fill:#4FA52B;} | ||||
| 	.st12{fill:#EE8C89;} | ||||
| 	.st13{fill:#E96562;} | ||||
| 	.st14{fill:#E33F3B;} | ||||
| 	.st15{fill:#EFB075;} | ||||
| 	.st16{fill:#E99547;} | ||||
| 	.st17{fill:#E47B19;} | ||||
| 	.st18{opacity:0.38;fill:url(#SVGID_5_);enable-background:new    ;} | ||||
| </style> | ||||
| <g id="Layer_1_2_"> | ||||
| 	<g id="Layer_1_1_"> | ||||
| 	</g> | ||||
| </g> | ||||
| <g id="Layer_2_1_"> | ||||
| 	<polygon class="st0" points="69.5,48.6 69.3,93.1 4,95.2 3.3,93.7 29.6,53.4 	"/> | ||||
| 	<path class="st1" d="M69.5,47l-0.2,46.1c0,0-66.3,1-66,0.6l26.1-41.8L69.5,47z"/> | ||||
| 	 | ||||
| 		<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="69.458" y1="120.0202" x2="219.2576" y2="120.0202" gradientTransform="matrix(1 0 0 1 0 8)"> | ||||
| 		<stop  offset="0" style="stop-color:#E3E3E3"/> | ||||
| 		<stop  offset="1" style="stop-color:#F4F4F4"/> | ||||
| 	</linearGradient> | ||||
| 	<polygon class="st2" points="69.5,47 218.9,55.6 219.3,202.6 69.9,209.1 	"/> | ||||
| 	 | ||||
| 		<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="29.2408" y1="120.0202" x2="69.8681" y2="120.0202" gradientTransform="matrix(1 0 0 1 0 8)"> | ||||
| 		<stop  offset="0" style="stop-color:#D9D9D9"/> | ||||
| 		<stop  offset="1" style="stop-color:#D4D4D4"/> | ||||
| 	</linearGradient> | ||||
| 	<polygon class="st3" points="29.2,51.8 69.5,47 69.8,209.1 29.2,204.4 	"/> | ||||
| 	 | ||||
| 		<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="151.9309" y1="42.7213" x2="142.8473" y2="-43.5726" gradientTransform="matrix(0.9941 1.431752e-03 1.431754e-03 1.1143 -3.0394 44.4335)"> | ||||
| 		<stop  offset="0" style="stop-color:#B3B3B3"/> | ||||
| 		<stop  offset="0.4752" style="stop-color:#B5B5B5"/> | ||||
| 		<stop  offset="0.6464" style="stop-color:#BCBCBC"/> | ||||
| 		<stop  offset="0.7685" style="stop-color:#C7C7C7"/> | ||||
| 		<stop  offset="0.8671" style="stop-color:#D8D8D8"/> | ||||
| 		<stop  offset="0.9506" style="stop-color:#EEEEEE"/> | ||||
| 		<stop  offset="1" style="stop-color:#FFFFFF"/> | ||||
| 	</linearGradient> | ||||
| 	<polygon class="st4" points="219.3,98.5 97.4,93.2 69.5,47.3 218.9,55.6 	"/> | ||||
| 	<polygon class="st1" points="102,85.3 251.2,93 252.8,91.1 72.2,48.9 69.5,47 	"/> | ||||
| 	<polygon class="st5" points="252.8,91.1 128,84.6 102,82.9 69.8,47.3 219.1,55.6 233.6,71.4 252.3,90.6 252.3,90.6 	"/> | ||||
| 	 | ||||
| 		<radialGradient id="SVGID_4_" cx="445.2994" cy="-436.338" r="4.0179" gradientTransform="matrix(0.5088 -4.329579e-03 0.1464 14.7395 -92.0455 6569.5317)" gradientUnits="userSpaceOnUse"> | ||||
| 		<stop  offset="0" style="stop-color:#FFFFFF"/> | ||||
| 		<stop  offset="6.758273e-02" style="stop-color:#FFFFFF;stop-opacity:0.9324"/> | ||||
| 		<stop  offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/> | ||||
| 	</radialGradient> | ||||
| 	<path class="st6" d="M72.2,152.5c0.2,26.2,0.9,42.4,0.1,42.4c-0.9,0-1.5-6.3-2.5-32.3c-1.1-26.1-1.4-85-0.5-85.1 | ||||
| 		C70.1,77.2,71.9,126.4,72.2,152.5z"/> | ||||
| 	<g class="st7"> | ||||
| 		<path class="st8" d="M29.1,203.9l20.4,2.1c3.3,0.4,6.9,0.6,10.2,1.1l10.2,1.2h-0.1l74.7-3.2l37.4-1.7l9.3-0.4 | ||||
| 			c3.1-0.1,6.3-0.2,9.3-0.4l18.7-0.5l-18.7,1.2c-3.1,0.2-6.3,0.4-9.3,0.5l-9.3,0.4l-37.4,1.7l-74.5,3.2l0,0l0,0L59.7,208 | ||||
| 			c-3.3-0.4-6.8-0.9-10.2-1.4L29.1,203.9z"/> | ||||
| 		<path class="st1" d="M28.6,203.9c3.3,0.2,6.8,0.4,10.3,0.6s7.1,0.5,10.6,0.9l10.2,1.1l10.2,1.2l-0.1,1.1h-0.1v-1.1l74.8-3.1 | ||||
| 			l37.4-1.6l18.7-0.7l18.7-0.5v0.6l-18.7,1.1l-9.3,0.5l-9.3,0.4l-37.4,1.6l-74.7,3.1l0,0l0,0l-10.2-1.2l-10.2-1.4L29,203.8 | ||||
| 			L28.6,203.9z M30.3,204.1l19.2,2.5l10.2,1.4l10.2,1.2l0,0l74.7-3.3l37.4-1.7l9.3-0.4l9.3-0.5l18.7-1.2v0.6l-18.7,0.5l-18.7,0.7 | ||||
| 			l-37.4,1.7l-74.7,3.3v-1.1h0.1l-0.1,1.1l-10.2-1.2l-10.2-1.1c-3.3-0.4-6.5-0.6-9.7-1.1C36.6,205,33.5,204.5,30.3,204.1z"/> | ||||
| 	</g> | ||||
| 	<g> | ||||
| 		<g> | ||||
| 			<g> | ||||
| 				<path class="st9" d="M181.4,136.4c-8.7,6.8-23.5,8.1-33.8,5.5c2.6-2.3,3.8-3.4,6.3-5.8c2.5-2.2,3.6-3.2,6-5.4 | ||||
| 					c8.4-7.4,12.5-10.8,20.7-17.7c-8.5,6.4-12.9,9.6-21.6,16.4c-2.5,2-3.7,2.8-6.1,4.8c-2.6,2-3.8,3.1-6.4,5 | ||||
| 					c-0.5-9.5,1.1-22.1,10.3-28.9c0.7-0.6,1.7-1.1,2.6-1.7c1.2-0.6,2.5-1.4,3.9-1.8c11.4-4.4,24.8-7.5,37.3-5.9 | ||||
| 					c0.7,6.5-4.9,18.9-11.8,28.2c-1,1.2-1.8,2.5-2.8,3.6C184.2,133.9,182.7,135.3,181.4,136.4z"/> | ||||
| 				<path class="st10" d="M185.6,132.4c-9.2,6-22.6,5.8-31.7,3.7c2.5-2.2,3.6-3.2,6-5.4c8.4-7.4,12.5-10.8,20.7-17.7 | ||||
| 					c-8.5,6.4-12.9,9.6-21.6,16.4c-2.5,2-3.7,2.8-6.1,4.8c-0.5-7.9,0.4-18.4,6.5-25.5c1.2-0.6,2.5-1.4,3.9-1.8 | ||||
| 					c11.4-4.6,24.8-7.5,37.3-5.9c0.7,6.5-4.9,18.9-11.8,28.2C187.5,130.1,186.5,131.3,185.6,132.4z"/> | ||||
| 				<path class="st11" d="M188.5,128.9c-8.9,4.2-20.5,3.8-28.5,1.8c8.4-7.4,12.5-10.8,20.7-17.7c-8.5,6.4-12.9,9.6-21.6,16.4 | ||||
| 					c-0.5-6.8,0-15.7,4.3-22.6c11.4-4.4,24.8-7.5,37.3-5.9C201.2,107.4,195.5,119.9,188.5,128.9z"/> | ||||
| 			</g> | ||||
| 			<g> | ||||
| 				<path class="st12" d="M140.4,169.2c-3.6-8.9,0.5-19.6,4.7-26c1.1,2.5,1.6,3.7,2.7,6c1.1,2.3,1.6,3.4,2.6,5.7 | ||||
| 					c3.7,7.9,5.5,11.8,9.3,19.2c-3.1-7.6-4.7-11.6-7.9-19.7c-0.9-2.2-1.4-3.3-2.2-5.5c-1-2.3-1.5-3.6-2.3-6 | ||||
| 					c7.4,2.2,16.8,6.6,20.3,15c0.2,0.7,0.5,1.5,0.7,2.2c0.2,1,0.5,2.1,0.6,3.2c1.5,9.6-0.9,23-4.4,28c-5.5-0.9-14.5-7.7-20-15.1 | ||||
| 					c-0.7-1-1.5-2-2.1-3C141.7,171.9,141,170.6,140.4,169.2z"/> | ||||
| 				<path class="st13" d="M142.5,173.3c-2.3-8.4,1.5-18.1,5.4-24c1.1,2.3,1.6,3.4,2.6,5.7c3.7,7.9,5.5,11.8,9.3,19.2 | ||||
| 					c-3.1-7.6-4.7-11.6-7.9-19.7c-0.9-2.2-1.4-3.3-2.2-5.5c6.3,1.7,14.4,5.2,18.7,11.3c0.2,1,0.5,2.1,0.6,3.2 | ||||
| 					c1.5,9.6-0.9,23-4.4,27.9c-5.5-0.9-14.5-7.7-20-15.1C143.9,175.2,143.3,174.3,142.5,173.3z"/> | ||||
| 				<path class="st14" d="M144.6,176.2c-1.1-7.5,2.5-16,5.9-21.3c3.7,7.9,5.5,11.8,9.3,19.2c-3.1-7.6-4.7-11.6-7.9-19.7 | ||||
| 					c5.5,1.4,12.5,4.1,17.2,8.9c1.5,9.6-0.9,23-4.4,27.9C159,190.4,150.1,183.6,144.6,176.2z"/> | ||||
| 			</g> | ||||
| 			<g> | ||||
| 				<path class="st15" d="M125.9,116.6c10.5,4.3,16.5,15.4,18.8,23.4c-3-1-4.3-1.4-7.3-2.3c-2.8-0.9-4.2-1.4-6.9-2.2 | ||||
| 					c-9.7-3.2-14.5-4.9-23.9-8.2c9.1,3.8,13.7,5.8,23.1,9.6c2.6,1.1,3.9,1.6,6.5,2.7c2.7,1.1,4.1,1.6,6.9,2.7 | ||||
| 					c-7.4,4.2-18.4,8.4-28.3,4.6c-0.7-0.2-1.7-0.7-2.6-1.2c-1-0.6-2.2-1.2-3.3-2.1c-8.5-6-17.6-16.7-20.9-26.8 | ||||
| 					c4.9-3.4,17.6-4.2,28.3-2.3c1.5,0.2,2.8,0.5,4.3,0.9C122.7,115.4,124.3,115.8,125.9,116.6z"/> | ||||
| 				<path class="st16" d="M120.7,114.9c9.1,4.8,14.5,15,16.7,22.6c-2.8-0.9-4.2-1.4-6.9-2.2c-9.7-3.2-14.5-4.9-23.9-8.2 | ||||
| 					c9.1,3.8,13.7,5.8,23,9.6c2.6,1.1,3.9,1.6,6.5,2.7c-6.1,3.6-15.4,7.4-23.9,6c-1-0.6-2.2-1.2-3.3-2.1c-8.5-6-17.6-16.7-20.9-26.8 | ||||
| 					c4.9-3.4,17.6-4.2,28.3-2.3C118,114.2,119.4,114.4,120.7,114.9z"/> | ||||
| 				<path class="st17" d="M116.6,113.9c7.5,5.3,12.1,14.4,14,21.3c-9.7-3.2-14.5-4.9-23.9-8.2c9.1,3.8,13.7,5.8,23.1,9.6 | ||||
| 					c-5.4,3.2-13,6.6-20.7,6.5c-8.5-6-17.6-16.7-20.9-26.8C93.2,112.8,105.7,112,116.6,113.9z"/> | ||||
| 			</g> | ||||
| 		</g> | ||||
| 	</g> | ||||
| 	 | ||||
| 		<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="241.7537" y1="104.2354" x2="160.0455" y2="55.1756" gradientTransform="matrix(1 0 0 -1 0 256)"> | ||||
| 		<stop  offset="0.1721" style="stop-color:#C7C7C7"/> | ||||
| 		<stop  offset="0.3798" style="stop-color:#D8D8D8"/> | ||||
| 		<stop  offset="0.6814" style="stop-color:#DADADA"/> | ||||
| 		<stop  offset="0.7898" style="stop-color:#E1E1E1"/> | ||||
| 		<stop  offset="0.867" style="stop-color:#ECECEC"/> | ||||
| 		<stop  offset="0.8745" style="stop-color:#EEEEEE"/> | ||||
| 		<stop  offset="1" style="stop-color:#FFFFFF"/> | ||||
| 	</linearGradient> | ||||
| 	<path class="st18" d="M219.1,128.3c-1,0.4-3.3,15.7-3.7,19.2c-0.7,5.8-3.9,28.7-11.1,41.2c-7.3,12.8-15.7,13.7-16.4,14.6l31.1-0.9 | ||||
| 		C219.1,179.1,219.1,151.5,219.1,128.3L219.1,128.3z"/> | ||||
| </g> | ||||
| </svg> | ||||
|  | ||||
| Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.6 KiB | 
							
								
								
									
										258
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										258
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -108,6 +108,7 @@ | ||||
|         "@electron-forge/cli": "7.6.1", | ||||
|         "@electron-forge/maker-deb": "7.6.1", | ||||
|         "@electron-forge/maker-dmg": "7.6.1", | ||||
|         "@electron-forge/maker-flatpak": "7.6.1", | ||||
|         "@electron-forge/maker-rpm": "7.6.1", | ||||
|         "@electron-forge/maker-squirrel": "7.6.1", | ||||
|         "@electron-forge/maker-zip": "7.6.1", | ||||
| @ -152,7 +153,7 @@ | ||||
|         "@types/yargs": "17.0.33", | ||||
|         "@vitest/coverage-v8": "3.0.5", | ||||
|         "cross-env": "7.0.3", | ||||
|         "electron": "34.0.2", | ||||
|         "electron": "34.1.0", | ||||
|         "esm": "3.2.25", | ||||
|         "jasmine": "5.5.0", | ||||
|         "jsdoc": "4.0.4", | ||||
| @ -781,6 +782,52 @@ | ||||
|         "graceful-fs": "^4.1.6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@electron-forge/maker-flatpak": { | ||||
|       "version": "7.6.1", | ||||
|       "resolved": "https://registry.npmjs.org/@electron-forge/maker-flatpak/-/maker-flatpak-7.6.1.tgz", | ||||
|       "integrity": "sha512-a9EekF8cNzjizwMs8HObxRii2tkLrTcTNMvWNhQqcJohEkJV81zNOLu9l/OdIMlKQ9cF5SuRvA4/m2bQGfT80w==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@electron-forge/maker-base": "7.6.1", | ||||
|         "@electron-forge/shared-types": "7.6.1", | ||||
|         "fs-extra": "^10.0.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">= 16.4.0" | ||||
|       }, | ||||
|       "optionalDependencies": { | ||||
|         "@malept/electron-installer-flatpak": "^0.11.4" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@electron-forge/maker-flatpak/node_modules/fs-extra": { | ||||
|       "version": "10.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", | ||||
|       "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "graceful-fs": "^4.2.0", | ||||
|         "jsonfile": "^6.0.1", | ||||
|         "universalify": "^2.0.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=12" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@electron-forge/maker-flatpak/node_modules/jsonfile": { | ||||
|       "version": "6.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", | ||||
|       "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "universalify": "^2.0.0" | ||||
|       }, | ||||
|       "optionalDependencies": { | ||||
|         "graceful-fs": "^4.1.6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@electron-forge/maker-rpm": { | ||||
|       "version": "7.6.1", | ||||
|       "resolved": "https://registry.npmjs.org/@electron-forge/maker-rpm/-/maker-rpm-7.6.1.tgz", | ||||
| @ -2752,6 +2799,203 @@ | ||||
|         "node": ">= 12.13.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@malept/electron-installer-flatpak": { | ||||
|       "version": "0.11.4", | ||||
|       "resolved": "https://registry.npmjs.org/@malept/electron-installer-flatpak/-/electron-installer-flatpak-0.11.4.tgz", | ||||
|       "integrity": "sha512-ZdwhT4WeeJWdnsmALUtQ7bn4pzYVh0Vg+4NnF1S3n3OACc9IWg+B+LxI5gT3XSXIrxogouqkjM6gD8S592awyA==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "optional": true, | ||||
|       "os": [ | ||||
|         "darwin", | ||||
|         "linux" | ||||
|       ], | ||||
|       "dependencies": { | ||||
|         "@malept/flatpak-bundler": "^0.4.0", | ||||
|         "debug": "^4.1.1", | ||||
|         "electron-installer-common": "^0.10.0", | ||||
|         "lodash": "^4.17.15", | ||||
|         "semver": "^7.1.1", | ||||
|         "yargs": "^16.0.0" | ||||
|       }, | ||||
|       "bin": { | ||||
|         "electron-installer-flatpak": "bin/electron-installer-flatpak.js" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">= 10.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@malept/electron-installer-flatpak/node_modules/ansi-regex": { | ||||
|       "version": "5.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", | ||||
|       "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "optional": true, | ||||
|       "engines": { | ||||
|         "node": ">=8" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@malept/electron-installer-flatpak/node_modules/cliui": { | ||||
|       "version": "7.0.4", | ||||
|       "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", | ||||
|       "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", | ||||
|       "dev": true, | ||||
|       "license": "ISC", | ||||
|       "optional": true, | ||||
|       "dependencies": { | ||||
|         "string-width": "^4.2.0", | ||||
|         "strip-ansi": "^6.0.0", | ||||
|         "wrap-ansi": "^7.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@malept/electron-installer-flatpak/node_modules/emoji-regex": { | ||||
|       "version": "8.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", | ||||
|       "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "node_modules/@malept/electron-installer-flatpak/node_modules/is-fullwidth-code-point": { | ||||
|       "version": "3.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", | ||||
|       "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "optional": true, | ||||
|       "engines": { | ||||
|         "node": ">=8" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@malept/electron-installer-flatpak/node_modules/string-width": { | ||||
|       "version": "4.2.3", | ||||
|       "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", | ||||
|       "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "optional": true, | ||||
|       "dependencies": { | ||||
|         "emoji-regex": "^8.0.0", | ||||
|         "is-fullwidth-code-point": "^3.0.0", | ||||
|         "strip-ansi": "^6.0.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=8" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@malept/electron-installer-flatpak/node_modules/strip-ansi": { | ||||
|       "version": "6.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", | ||||
|       "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "optional": true, | ||||
|       "dependencies": { | ||||
|         "ansi-regex": "^5.0.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=8" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@malept/electron-installer-flatpak/node_modules/wrap-ansi": { | ||||
|       "version": "7.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", | ||||
|       "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "optional": true, | ||||
|       "dependencies": { | ||||
|         "ansi-styles": "^4.0.0", | ||||
|         "string-width": "^4.1.0", | ||||
|         "strip-ansi": "^6.0.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=10" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://github.com/chalk/wrap-ansi?sponsor=1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@malept/electron-installer-flatpak/node_modules/yargs": { | ||||
|       "version": "16.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", | ||||
|       "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "optional": true, | ||||
|       "dependencies": { | ||||
|         "cliui": "^7.0.2", | ||||
|         "escalade": "^3.1.1", | ||||
|         "get-caller-file": "^2.0.5", | ||||
|         "require-directory": "^2.1.1", | ||||
|         "string-width": "^4.2.0", | ||||
|         "y18n": "^5.0.5", | ||||
|         "yargs-parser": "^20.2.2" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=10" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@malept/electron-installer-flatpak/node_modules/yargs-parser": { | ||||
|       "version": "20.2.9", | ||||
|       "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", | ||||
|       "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", | ||||
|       "dev": true, | ||||
|       "license": "ISC", | ||||
|       "optional": true, | ||||
|       "engines": { | ||||
|         "node": ">=10" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@malept/flatpak-bundler": { | ||||
|       "version": "0.4.0", | ||||
|       "resolved": "https://registry.npmjs.org/@malept/flatpak-bundler/-/flatpak-bundler-0.4.0.tgz", | ||||
|       "integrity": "sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "optional": true, | ||||
|       "dependencies": { | ||||
|         "debug": "^4.1.1", | ||||
|         "fs-extra": "^9.0.0", | ||||
|         "lodash": "^4.17.15", | ||||
|         "tmp-promise": "^3.0.2" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">= 10.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@malept/flatpak-bundler/node_modules/fs-extra": { | ||||
|       "version": "9.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", | ||||
|       "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "optional": true, | ||||
|       "dependencies": { | ||||
|         "at-least-node": "^1.0.0", | ||||
|         "graceful-fs": "^4.2.0", | ||||
|         "jsonfile": "^6.0.1", | ||||
|         "universalify": "^2.0.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=10" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@malept/flatpak-bundler/node_modules/jsonfile": { | ||||
|       "version": "6.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", | ||||
|       "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "optional": true, | ||||
|       "dependencies": { | ||||
|         "universalify": "^2.0.0" | ||||
|       }, | ||||
|       "optionalDependencies": { | ||||
|         "graceful-fs": "^4.1.6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@mermaid-js/layout-elk": { | ||||
|       "version": "0.1.7", | ||||
|       "resolved": "https://registry.npmjs.org/@mermaid-js/layout-elk/-/layout-elk-0.1.7.tgz", | ||||
| @ -7666,9 +7910,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/electron": { | ||||
|       "version": "34.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/electron/-/electron-34.0.2.tgz", | ||||
|       "integrity": "sha512-u3F+DSUlg9NaGS+9qnYmSRN8VjAnc3LJDDk1ye1uISJnh4gjG76y3681qLowsPMx4obvCP2eBINnmbLo0yT5WA==", | ||||
|       "version": "34.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/electron/-/electron-34.1.0.tgz", | ||||
|       "integrity": "sha512-ZUid8XrGPA0dfes97PPADc8ecWOUX/qYRNp1glze9coZLEYc+PsMvgjVDCHSvjfHfiI+V3unwngSVpBouX71YQ==", | ||||
|       "hasInstallScript": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
| @ -8387,9 +8631,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/electron/node_modules/@types/node": { | ||||
|       "version": "20.17.16", | ||||
|       "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.16.tgz", | ||||
|       "integrity": "sha512-vOTpLduLkZXePLxHiHsBLp98mHGnl8RptV4YAO3HfKO5UHjDvySGbxKtpYfy8Sx5+WKcgc45qNreJJRVM3L6mw==", | ||||
|       "version": "20.17.17", | ||||
|       "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.17.tgz", | ||||
|       "integrity": "sha512-/WndGO4kIfMicEQLTi/mDANUu/iVUhT7KboZPdEqqHQ4aTS+3qT3U5gIqWDFV+XouorjfgGqvKILJeHhuQgFYg==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "undici-types": "~6.19.2" | ||||
|  | ||||
| @ -150,6 +150,7 @@ | ||||
|     "@electron-forge/cli": "7.6.1", | ||||
|     "@electron-forge/maker-deb": "7.6.1", | ||||
|     "@electron-forge/maker-dmg": "7.6.1", | ||||
|     "@electron-forge/maker-flatpak": "7.6.1", | ||||
|     "@electron-forge/maker-rpm": "7.6.1", | ||||
|     "@electron-forge/maker-squirrel": "7.6.1", | ||||
|     "@electron-forge/maker-zip": "7.6.1", | ||||
| @ -194,7 +195,7 @@ | ||||
|     "@types/yargs": "17.0.33", | ||||
|     "@vitest/coverage-v8": "3.0.5", | ||||
|     "cross-env": "7.0.3", | ||||
|     "electron": "34.0.2", | ||||
|     "electron": "34.1.0", | ||||
|     "esm": "3.2.25", | ||||
|     "jasmine": "5.5.0", | ||||
|     "jsdoc": "4.0.4", | ||||
|  | ||||
| @ -4,14 +4,14 @@ import BAttribute from "../../src/becca/entities/battribute.js"; | ||||
| import becca from "../../src/becca/becca.js"; | ||||
| import randtoken from "rand-token"; | ||||
| import type SearchResult from "../../src/services/search/search_result.js"; | ||||
| import type { NoteType } from "../../src/becca/entities/rows.js"; | ||||
| import type { NoteRow, NoteType } from "../../src/becca/entities/rows.js"; | ||||
| randtoken.generator({ source: "crypto" }); | ||||
| 
 | ||||
| function findNoteByTitle(searchResults: Array<SearchResult>, title: string): BNote | undefined { | ||||
| export function findNoteByTitle(searchResults: Array<SearchResult>, title: string): BNote | undefined { | ||||
|     return searchResults.map((sr) => becca.notes[sr.noteId]).find((note) => note.title === title); | ||||
| } | ||||
| 
 | ||||
| class NoteBuilder { | ||||
| export class NoteBuilder { | ||||
|     note: BNote; | ||||
|     constructor(note: BNote) { | ||||
|         this.note = note; | ||||
| @ -55,11 +55,11 @@ class NoteBuilder { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function id() { | ||||
| export function id() { | ||||
|     return randtoken.generate(10); | ||||
| } | ||||
| 
 | ||||
| function note(title: string, extraParams = {}) { | ||||
| export function note(title: string, extraParams: Partial<NoteRow> = {}) { | ||||
|     const row = Object.assign( | ||||
|         { | ||||
|             noteId: id(), | ||||
| @ -74,9 +74,3 @@ function note(title: string, extraParams = {}) { | ||||
| 
 | ||||
|     return new NoteBuilder(note); | ||||
| } | ||||
| 
 | ||||
| export default { | ||||
|     NoteBuilder, | ||||
|     findNoteByTitle, | ||||
|     note | ||||
| }; | ||||
|  | ||||
| @ -79,7 +79,7 @@ async function renderAttributes(attributes: FAttribute[], renderIsInheritable: b | ||||
|     return $container; | ||||
| } | ||||
| 
 | ||||
| const HIDDEN_ATTRIBUTES = ["originalFileName", "fileSize", "template", "inherit", "cssClass", "iconClass", "pageSize", "viewType"]; | ||||
| const HIDDEN_ATTRIBUTES = ["originalFileName", "fileSize", "template", "inherit", "cssClass", "iconClass", "pageSize", "viewType", "geolocation"]; | ||||
| 
 | ||||
| async function renderNormalAttributes(note: FNote) { | ||||
|     const promotedDefinitionAttributes = note.getPromotedDefinitionAttributes(); | ||||
|  | ||||
| @ -238,12 +238,16 @@ async function renderMermaid(note: FNote, $renderedContent: JQuery<HTMLElement>) | ||||
|  * @param {FNote} note | ||||
|  * @returns {Promise<void>} | ||||
|  */ | ||||
| async function renderChildrenList($renderedContent: JQuery<HTMLElement>, note: FNote) { | ||||
| async function renderChildrenList($renderedContent: JQuery<HTMLElement>, note: FNote) {     | ||||
|     let childNoteIds = note.getChildNoteIds(); | ||||
| 
 | ||||
|     if (!childNoteIds.length) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     $renderedContent.css("padding", "10px"); | ||||
|     $renderedContent.addClass("text-with-ellipsis"); | ||||
| 
 | ||||
|     let childNoteIds = note.getChildNoteIds(); | ||||
| 
 | ||||
|     if (childNoteIds.length > 10) { | ||||
|         childNoteIds = childNoteIds.slice(0, 10); | ||||
|     } | ||||
|  | ||||
| @ -376,6 +376,10 @@ function linkContextMenu(e: PointerEvent) { | ||||
|     const $link = $(e.target as any).closest("a"); | ||||
|     const url = $link.attr("href") || $link.attr("data-href"); | ||||
| 
 | ||||
|     if ($link.attr("data-no-context-menu")) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const { notePath, viewScope } = parseNavigationStateFromUrl(url); | ||||
| 
 | ||||
|     if (!notePath) { | ||||
|  | ||||
| @ -140,10 +140,6 @@ async function renderTooltip(note: FNote | null) { | ||||
|     } | ||||
| 
 | ||||
|     const noteTitleWithPathAsSuffix = await treeService.getNoteTitleWithPathAsSuffix(bestNotePath); | ||||
|     let content = ""; | ||||
|     if (noteTitleWithPathAsSuffix) { | ||||
|         content = `<h5 class="note-tooltip-title">${noteTitleWithPathAsSuffix.prop("outerHTML")}</h5>`; | ||||
|     } | ||||
| 
 | ||||
|     const { $renderedAttributes } = await attributeRenderer.renderNormalAttributes(note); | ||||
| 
 | ||||
| @ -151,8 +147,21 @@ async function renderTooltip(note: FNote | null) { | ||||
|         tooltip: true, | ||||
|         trim: true | ||||
|     }); | ||||
|     const isContentEmpty = ($renderedContent[0].innerHTML.length === 0); | ||||
| 
 | ||||
|     content = `${content}<div class="note-tooltip-attributes">${$renderedAttributes[0].outerHTML}</div>${$renderedContent[0].outerHTML}`; | ||||
|     let content = ""; | ||||
|     if (noteTitleWithPathAsSuffix) { | ||||
|         const classes = [ "note-tooltip-title" ]; | ||||
|         if (isContentEmpty) { | ||||
|             classes.push("note-no-content"); | ||||
|         } | ||||
|         content = `<h5 class="${classes.join(" ")}"><a href="#${note.noteId}" data-no-context-menu="true">${noteTitleWithPathAsSuffix.prop("outerHTML")}</a></h5>`; | ||||
|     } | ||||
| 
 | ||||
|     content = `${content}<div class="note-tooltip-attributes">${$renderedAttributes[0].outerHTML}</div>`; | ||||
|     if (!isContentEmpty) { | ||||
|         content += $renderedContent[0].outerHTML; | ||||
|     } | ||||
| 
 | ||||
|     return content; | ||||
| } | ||||
|  | ||||
| @ -13,7 +13,7 @@ import appContext from "../../components/app_context.js"; | ||||
| import type { Attribute } from "../../services/attribute_parser.js"; | ||||
| 
 | ||||
| const TPL = ` | ||||
| <div class="attr-detail"> | ||||
| <div class="attr-detail tn-tool-dialog"> | ||||
|     <style> | ||||
|         .attr-detail { | ||||
|             display: block; | ||||
| @ -48,10 +48,14 @@ const TPL = ` | ||||
|             text-align: left; | ||||
|         } | ||||
| 
 | ||||
|         .attr-edit-table td input { | ||||
|         .attr-edit-table td input[not(type="checkbox")] { | ||||
|             width: 100%; | ||||
|         } | ||||
| 
 | ||||
|         .attr-edit-table td input[type="checkbox"] { | ||||
|             display: inline-block; | ||||
|         } | ||||
| 
 | ||||
|         .close-attr-detail-button { | ||||
|             font-size: x-large; | ||||
|             cursor: pointer; | ||||
| @ -76,7 +80,7 @@ const TPL = ` | ||||
|     <div style="display: flex; justify-content: space-between; margin-bottom: 8px;"> | ||||
|         <h5 class="attr-detail-title">${t("attribute_detail.attr_detail_title")}</h5> | ||||
| 
 | ||||
|         <span class="bx bx-x close-attr-detail-button" title="${t("attribute_detail.close_button_title")}"></span> | ||||
|         <span class="bx bx-x close-attr-detail-button tn-tool-button" title="${t("attribute_detail.close_button_title")}"></span> | ||||
|     </div> | ||||
| 
 | ||||
|     <div class="attr-is-owned-by">${t("attribute_detail.attr_is_owned_by")}</div> | ||||
| @ -104,7 +108,7 @@ const TPL = ` | ||||
|             <th></th> | ||||
|             <td> | ||||
|                 <label class="tn-checkbox"> | ||||
|                     <input type="checkbox" class="attr-input-promoted form-check" /> | ||||
|                     <input type="checkbox" class="attr-input-promoted" /> | ||||
|                     ${t("attribute_detail.promoted")} | ||||
|                 </label> | ||||
|             </td> | ||||
| @ -161,7 +165,7 @@ const TPL = ` | ||||
|             <th></th> | ||||
|             <td> | ||||
|                 <label class="tn-checkbox"> | ||||
|                     <input type="checkbox" class="attr-input-inheritable form-check" /> | ||||
|                     <input type="checkbox" class="attr-input-inheritable" /> | ||||
|                     ${t("attribute_detail.inheritable")} | ||||
|                 </label> | ||||
|             </td> | ||||
|  | ||||
| @ -33,9 +33,9 @@ const DROPDOWN_TPL = ` | ||||
| 
 | ||||
|     <div class="calendar-header"> | ||||
|         <div class="calendar-month-selector"> | ||||
|             <button class="calendar-btn bx bx-chevron-left" data-calendar-toggle="previous"></button> | ||||
|             <button class="calendar-btn tn-tool-button bx bx-chevron-left" data-calendar-toggle="previous"></button> | ||||
| 
 | ||||
|             <button class="btn dropdown-toggle" type="button" | ||||
|             <button class="btn dropdown-toggle select-button" type="button" | ||||
|                 data-bs-toggle="dropdown" data-bs-auto-close="true" | ||||
|                 aria-expanded="false" | ||||
|                 data-calendar-input="month"></button> | ||||
| @ -45,15 +45,15 @@ const DROPDOWN_TPL = ` | ||||
|                     .join("")} | ||||
|             </ul> | ||||
| 
 | ||||
|             <button class="calendar-btn bx bx-chevron-right" data-calendar-toggle="next"></button> | ||||
|             <button class="calendar-btn tn-tool-button bx bx-chevron-right" data-calendar-toggle="next"></button> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="calendar-year-selector"> | ||||
|             <button class="calendar-btn bx bx-chevron-left" data-calendar-toggle="previousYear"></button> | ||||
|             <button class="calendar-btn tn-tool-button bx bx-chevron-left" data-calendar-toggle="previousYear"></button> | ||||
| 
 | ||||
|             <input type="number" min="1900" max="2999" step="1" data-calendar-input="year" /> | ||||
| 
 | ||||
|             <button class="calendar-btn bx bx-chevron-right" data-calendar-toggle="nextYear"></button> | ||||
|             <button class="calendar-btn tn-tool-button bx bx-chevron-right" data-calendar-toggle="nextYear"></button> | ||||
|         </div> | ||||
|     </div> | ||||
| 
 | ||||
|  | ||||
| @ -18,7 +18,9 @@ const TPL = ` | ||||
|                     <div class="form-group"> | ||||
|                         <label for="import-file-upload-input"><strong>${t("import.chooseImportFile")}</strong></label> | ||||
| 
 | ||||
|                         <input type="file" class="import-file-upload-input form-control-file" multiple /> | ||||
|                         <label class="tn-file-input tn-input-field"> | ||||
|                             <input type="file" class="import-file-upload-input form-control-file" multiple /> | ||||
|                         </label> | ||||
| 
 | ||||
|                         <p>${t("import.importDescription")} <strong class="import-note-title"></strong>. | ||||
|                     </div> | ||||
|  | ||||
| @ -17,14 +17,16 @@ const TPL = ` | ||||
|                 <div class="modal-body"> | ||||
|                     <div class="form-group"> | ||||
|                         <label for="upload-attachment-file-upload-input"><strong>${t("upload_attachments.choose_files")}</strong></label> | ||||
|                         <input type="file" class="upload-attachment-file-upload-input form-control-file" multiple /> | ||||
|                             <label class="tn-file-input tn-input-field"> | ||||
|                                 <input type="file" class="upload-attachment-file-upload-input form-control-file" multiple /> | ||||
|                             </label> | ||||
|                         <p>${t("upload_attachments.files_will_be_uploaded")} <strong class="upload-attachment-note-title"></strong>.</p> | ||||
|                     </div> | ||||
| 
 | ||||
|                     <div class="form-group"> | ||||
|                         <strong>${t("upload_attachments.options")}:</strong> | ||||
|                         <div class="checkbox"> | ||||
|                             <label data-bs-toggle="tooltip" title="${escapeQuotes(t("upload_attachments.tooltip"))}"> | ||||
|                             <label class="tn-checkbox" data-bs-toggle="tooltip" title="${escapeQuotes(t("upload_attachments.tooltip"))}"> | ||||
|                                 <input class="shrink-images-checkbox form-check-input" value="1" type="checkbox" checked> <span>${t("upload_attachments.shrink_images")}</span> | ||||
|                             </label> | ||||
|                         </div> | ||||
|  | ||||
| @ -14,10 +14,14 @@ const TPL = ` | ||||
|     } | ||||
| 
 | ||||
|     .editability-dropdown .dropdown-item { | ||||
|         display: block !important; | ||||
|         display: flex !importamt; | ||||
|     } | ||||
| 
 | ||||
|     .editability-dropdown .dropdown-item div { | ||||
|     .editability-dropdown .dropdown-item > div { | ||||
|         margin-left: 10px; | ||||
|     } | ||||
| 
 | ||||
|     .editability-dropdown .description { | ||||
|         font-size: small; | ||||
|         color: var(--muted-text-color); | ||||
|         white-space: normal; | ||||
| @ -30,18 +34,24 @@ const TPL = ` | ||||
|     <div class="editability-dropdown dropdown-menu dropdown-menu-right tn-dropdown-list"> | ||||
|         <a class="dropdown-item" href="#" data-editability="auto"> | ||||
|             <span class="check">✓</span> | ||||
|             ${t("editability_select.auto")} | ||||
|             <div>${t("editability_select.note_is_editable")}</div> | ||||
|             <div> | ||||
|                 ${t("editability_select.auto")} | ||||
|                 <div class="description">${t("editability_select.note_is_editable")}</div> | ||||
|             </div> | ||||
|         </a> | ||||
|         <a class="dropdown-item" href="#" data-editability="readOnly"> | ||||
|             <span class="check">✓</span> | ||||
|             ${t("editability_select.read_only")} | ||||
|             <div>${t("editability_select.note_is_read_only")}</div> | ||||
|             <div> | ||||
|                 ${t("editability_select.read_only")} | ||||
|                 <div class="description">${t("editability_select.note_is_read_only")}</div> | ||||
|             </div> | ||||
|         </a> | ||||
|         <a class="dropdown-item" href="#" data-editability="autoReadOnlyDisabled"> | ||||
|             <span class="check">✓</span> | ||||
|             ${t("editability_select.always_editable")} | ||||
|             <div>${t("editability_select.note_is_always_editable")}</div> | ||||
|             <div> | ||||
|                 ${t("editability_select.always_editable")} | ||||
|                 <div class="description">${t("editability_select.note_is_always_editable")}</div> | ||||
|             </div> | ||||
|         </a> | ||||
|     </div> | ||||
| </div> | ||||
|  | ||||
| @ -5,24 +5,39 @@ import dialogService from "../services/dialog.js"; | ||||
| import { t } from "../services/i18n.js"; | ||||
| 
 | ||||
| const NOTE_TYPES = [ | ||||
|     { type: "file", title: t("note_types.file"), selectable: false }, | ||||
|     { type: "image", title: t("note_types.image"), selectable: false }, | ||||
|     { type: "search", title: t("note_types.saved-search"), selectable: false }, | ||||
|     { type: "noteMap", mime: "", title: t("note_types.note-map"), selectable: false }, | ||||
|     { type: "launcher", mime: "", title: t("note_types.launcher"), selectable: false }, | ||||
|     { type: "doc", mime: "", title: t("note_types.doc"), selectable: false }, | ||||
|     { type: "contentWidget", mime: "", title: t("note_types.widget"), selectable: false }, | ||||
|     // The suggested note type ordering method: insert the item into the corresponding group,
 | ||||
|     // then ensure the items within the group are ordered alphabetically.
 | ||||
| 
 | ||||
|     // The default note type (always the first item)
 | ||||
|     { type: "text", mime: "text/html", title: t("note_types.text"), selectable: true }, | ||||
|     { type: "relationMap", mime: "application/json", title: t("note_types.relation-map"), selectable: true }, | ||||
|     { type: "mindMap", mime: "application/json", title: t("note_types.mind-map"), selectable: true }, | ||||
|     { type: "render", mime: "", title: t("note_types.render-note"), selectable: true }, | ||||
| 
 | ||||
|     // Text notes group
 | ||||
|     { type: "book", mime: "", title: t("note_types.book"), selectable: true }, | ||||
| 
 | ||||
|     // Graphic notes
 | ||||
|     { type: "canvas", mime: "application/json", title: t("note_types.canvas"), selectable: true }, | ||||
|     { type: "mermaid", mime: "text/mermaid", title: t("note_types.mermaid-diagram"), selectable: true }, | ||||
|     { type: "book", mime: "", title: t("note_types.book"), selectable: true }, | ||||
| 
 | ||||
|     // Map notes
 | ||||
|     { type: "geoMap", mime: "application/json", title: t("note_types.geo-map"), isBeta: true, selectable: true }, | ||||
|     { type: "mindMap", mime: "application/json", title: t("note_types.mind-map"), selectable: true }, | ||||
|     { type: "relationMap", mime: "application/json", title: t("note_types.relation-map"), selectable: true }, | ||||
| 
 | ||||
|     // Misc note types
 | ||||
|     { type: "render", mime: "", title: t("note_types.render-note"), selectable: true }, | ||||
|     { type: "webView", mime: "", title: t("note_types.web-view"), selectable: true }, | ||||
|     { type: "geoMap", mime: "application/json", title: t("note_types.geo-map"), selectable: true }, | ||||
|     { type: "code", mime: "text/plain", title: t("note_types.code"), selectable: true } | ||||
| 
 | ||||
|     // Code notes
 | ||||
|     { type: "code", mime: "text/plain", title: t("note_types.code"), selectable: true }, | ||||
| 
 | ||||
|     // Reserved types (cannot be created by the user)
 | ||||
|     { type: "contentWidget", mime: "", title: t("note_types.widget"), selectable: false }, | ||||
|     { type: "doc", mime: "", title: t("note_types.doc"), selectable: false }, | ||||
|     { type: "file", title: t("note_types.file"), selectable: false }, | ||||
|     { type: "image", title: t("note_types.image"), selectable: false }, | ||||
|     { type: "launcher", mime: "", title: t("note_types.launcher"), selectable: false }, | ||||
|     { type: "noteMap", mime: "", title: t("note_types.note-map"), selectable: false }, | ||||
|     { type: "search", title: t("note_types.saved-search"), selectable: false } | ||||
| ]; | ||||
| 
 | ||||
| const NOT_SELECTABLE_NOTE_TYPES = NOTE_TYPES.filter((nt) => !nt.selectable).map((nt) => nt.type); | ||||
| @ -30,11 +45,18 @@ const NOT_SELECTABLE_NOTE_TYPES = NOTE_TYPES.filter((nt) => !nt.selectable).map( | ||||
| const TPL = ` | ||||
| <div class="dropdown note-type-widget"> | ||||
|     <style> | ||||
|     .note-type-dropdown { | ||||
|         max-height: 500px; | ||||
|         overflow-y: auto; | ||||
|         overflow-x: hidden; | ||||
|     } | ||||
|         .note-type-dropdown { | ||||
|             max-height: 500px; | ||||
|             overflow-y: auto; | ||||
|             overflow-x: hidden; | ||||
|         } | ||||
| 
 | ||||
|         .note-type-dropdown .badge { | ||||
|             margin-left: 8px; | ||||
|             background: var(--accented-background-color); | ||||
|             font-weight: normal; | ||||
|             color: var(--menu-text-color); | ||||
|         } | ||||
|     </style> | ||||
|     <button type="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" class="btn btn-sm dropdown-toggle select-button note-type-button"> | ||||
|         <span class="note-type-desc"></span> | ||||
| @ -74,11 +96,16 @@ export default class NoteTypeWidget extends NoteContextAwareWidget { | ||||
|         for (const noteType of NOTE_TYPES.filter((nt) => nt.selectable)) { | ||||
|             let $typeLink; | ||||
| 
 | ||||
|             const $title = $("<span>").text(noteType.title); | ||||
|             if (noteType.isBeta) { | ||||
|                 $title.append($(`<span class="badge">`).text(t("note_types.beta-feature"))); | ||||
|             } | ||||
| 
 | ||||
|             if (noteType.type !== "code") { | ||||
|                 $typeLink = $('<a class="dropdown-item">') | ||||
|                     .attr("data-note-type", noteType.type) | ||||
|                     .append('<span class="check">✓</span> ') | ||||
|                     .append($("<span>").text(noteType.title)) | ||||
|                     .append($title) | ||||
|                     .on("click", (e) => { | ||||
|                         const type = $typeLink.attr("data-note-type"); | ||||
|                         const noteType = NOTE_TYPES.find((nt) => nt.type === type); | ||||
|  | ||||
| @ -42,6 +42,7 @@ const TAB_ROW_TPL = ` | ||||
|         width: 100%; | ||||
|         background: var(--main-background-color); | ||||
|         overflow: hidden; | ||||
|         user-select: none; | ||||
|     } | ||||
| 
 | ||||
|     .tab-row-widget.full-width { | ||||
|  | ||||
| @ -48,11 +48,12 @@ export default class AttachmentDetailTypeWidget extends TypeWidget { | ||||
|         this.$wrapper.empty(); | ||||
|         this.children = []; | ||||
| 
 | ||||
|         const $helpButton = $( | ||||
|             '<button class="attachment-help-button" type="button" data-help-page="attachments.html" title="' + | ||||
|                 t("attachment_detail.open_help_page") + | ||||
|                 '"><span class="bx bx-help-circle"></span></button>' | ||||
|         ); | ||||
|         const $helpButton = $(` | ||||
|             <button class="attachment-help-button icon-action bx bx-help-circle" | ||||
|                      type="button" data-help-page="attachments.html" | ||||
|                      title="${t("attachment_detail.open_help_page")}" | ||||
|             </button> | ||||
|         `);
 | ||||
|         utils.initHelpButtons($helpButton); | ||||
| 
 | ||||
|         this.$linksWrapper.empty().append( | ||||
|  | ||||
| @ -40,11 +40,12 @@ export default class AttachmentListTypeWidget extends TypeWidget { | ||||
|     } | ||||
| 
 | ||||
|     async doRefresh(note) { | ||||
|         const $helpButton = $( | ||||
|             '<button class="attachment-help-button" type="button" data-help-page="attachments.html" title="' + | ||||
|                 t("attachment_list.open_help_page") + | ||||
|                 '"><span class="bx bx-help-circle"></span></button>' | ||||
|         ); | ||||
|         const $helpButton = $(` | ||||
|             <button class="attachment-help-button icon-action bx bx-help-circle" | ||||
|                      type="button" data-help-page="attachments.html" | ||||
|                      title="${t("attachment_list.open_help_page")}"> | ||||
|             </button> | ||||
|         `);
 | ||||
|         utils.initHelpButtons($helpButton); | ||||
| 
 | ||||
|         const noteLink = await linkService.createLink(this.noteId); // do separately to avoid race condition between empty() and .append()
 | ||||
| @ -52,7 +53,7 @@ export default class AttachmentListTypeWidget extends TypeWidget { | ||||
| 
 | ||||
|         this.$linksWrapper.empty().append( | ||||
|             $("<div>").append(t("attachment_list.owning_note"), noteLink), | ||||
|             $("<div>").append( | ||||
|             $(`<div class="attachment-actions-toolbar">`).append( | ||||
|                 $('<button class="btn btn-sm">') | ||||
|                     .text(t("attachment_list.upload_attachments")) | ||||
|                     .on("click", () => this.triggerCommand("showUploadAttachmentsDialog", { noteId: this.noteId })), | ||||
|  | ||||
| @ -12,6 +12,7 @@ import asset_path from "../../../../services/asset_path.js"; | ||||
| import openContextMenu from "./geo_map_context_menu.js"; | ||||
| import link from "../../services/link.js"; | ||||
| import note_tooltip from "../../services/note_tooltip.js"; | ||||
| import appContext from "../../components/app_context.js"; | ||||
| 
 | ||||
| const TPL = `\ | ||||
| <div class="note-detail-geo-map note-detail-printable"> | ||||
| @ -229,7 +230,15 @@ export default class GeoMapTypeWidget extends TypeWidget { | ||||
|             .on("moveend", e => { | ||||
|                 this.moveMarker(note.noteId, (e.target as Marker).getLatLng()); | ||||
|             }); | ||||
| 
 | ||||
|         marker.on("mousedown", ({ originalEvent }) => { | ||||
|             // Middle click to open in new tab
 | ||||
|             if (originalEvent.button === 1) { | ||||
|                 const hoistedNoteId = this.hoistedNoteId; | ||||
|                 //@ts-ignore, fix once tab manager is ported.
 | ||||
|                 appContext.tabManager.openInNewTab(note.noteId, hoistedNoteId); | ||||
|                 return true; | ||||
|             } | ||||
|         }); | ||||
|         marker.on("contextmenu", (e) => { | ||||
|             openContextMenu(note.noteId, e.originalEvent); | ||||
|         }); | ||||
|  | ||||
| @ -41,25 +41,41 @@ | ||||
|     flex-grow: 1; | ||||
| } | ||||
| 
 | ||||
| .calendar-dropdown-widget .calendar-header input[type="number"] { | ||||
|     appearance: textfield !important; | ||||
| } | ||||
| 
 | ||||
| .calendar-dropdown-widget .calendar-header input[type="number"]::-webkit-outer-spin-button, | ||||
| .calendar-dropdown-widget .calendar-header input[type="number"]::-webkit-inner-spin-button { | ||||
|     -webkit-appearance: none; | ||||
|     margin: 0; | ||||
| } | ||||
| 
 | ||||
| .calendar-dropdown-widget .calendar-header select { | ||||
|     cursor: pointer; | ||||
| } | ||||
| 
 | ||||
| .calendar-dropdown-widget .calendar-header input, | ||||
| .calendar-dropdown-widget .calendar-header select { | ||||
| .calendar-dropdown-widget .calendar-header .dropdown-toggle { | ||||
|     appearance: none; | ||||
|     text-align: center; | ||||
|     border: 0; | ||||
|     border-bottom: 1px solid var(--button-border-color); | ||||
|     background-color: var(--menu-background-color) !important; | ||||
|     border-left: unset; | ||||
|     background-color: var(--menu-background-color); | ||||
|     font-weight: bold; | ||||
|     outline: 0; | ||||
| } | ||||
| 
 | ||||
| .calendar-dropdown-widget .calendar-header .dropdown-toggle::after { | ||||
|     border: unset; /* Disable the dropdown arrow */ | ||||
| } | ||||
| 
 | ||||
| .calendar-dropdown-widget .calendar-week { | ||||
|     display: flex; | ||||
|     flex-wrap: wrap; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| .calendar-dropdown-widget .calendar-week span { | ||||
|     flex-direction: column; | ||||
|     flex: 0 0 14.28%; | ||||
| @ -69,6 +85,7 @@ | ||||
|     padding-top: 5px; | ||||
|     padding-bottom: 5px; | ||||
|     text-align: center; | ||||
|     text-transform: uppercase; | ||||
| } | ||||
| 
 | ||||
| .calendar-dropdown-widget .calendar-body { | ||||
| @ -79,7 +96,6 @@ | ||||
| .calendar-dropdown-widget .calendar-date { | ||||
|     align-items: center; | ||||
|     color: var(--main-text-color); | ||||
|     background-color: var(--main-background-color); | ||||
|     display: flex; | ||||
|     flex-direction: column; | ||||
|     flex: 0 0 14.28%; | ||||
| @ -91,6 +107,7 @@ | ||||
| .calendar-dropdown-widget .calendar-date:hover { | ||||
|     color: var(--hover-item-text-color); | ||||
|     background-color: var(--hover-item-background-color); | ||||
|     text-decoration: underline; | ||||
| } | ||||
| 
 | ||||
| .calendar-dropdown-widget .calendar-date-active { | ||||
|  | ||||
| @ -1536,15 +1536,16 @@ textarea { | ||||
|     display: none !important; | ||||
| } | ||||
| 
 | ||||
| .attachment-actions-toolbar { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
| } | ||||
| 
 | ||||
| .attachment-help-button { | ||||
|     font-size: xx-large; | ||||
|     border: 0; | ||||
|     background: none; | ||||
|     cursor: pointer; | ||||
|     color: var(--main-text-color); | ||||
|     margin-left: 20px; | ||||
|     position: relative; | ||||
|     top: 8px; | ||||
|     display: inline-block; | ||||
|     margin-left: 10px; | ||||
|     vertical-align: middle; | ||||
|     font-size: 1em; | ||||
| } | ||||
| 
 | ||||
| .jump-to-note-dialog .modal-header { | ||||
|  | ||||
| @ -19,6 +19,9 @@ | ||||
| 
 | ||||
|     --accented-background-color: #555; | ||||
| 
 | ||||
|     --tool-dialog-background-color: #262626; | ||||
|     --tool-dialog-shadow-color: black; | ||||
| 
 | ||||
|     --button-text-color: currentColor; | ||||
| 
 | ||||
|     --cmd-button-background-color: #ffffff28; | ||||
|  | ||||
| @ -19,6 +19,9 @@ | ||||
| 
 | ||||
|     --accented-background-color: #f5f5f5; | ||||
| 
 | ||||
|     --tool-dialog-background-color: white; | ||||
|     --tool-dialog-shadow-color: #00000070; | ||||
| 
 | ||||
|     --button-text-color: currentColor; | ||||
| 
 | ||||
|     --cmd-button-background-color: #0000000f; | ||||
| @ -75,7 +78,7 @@ | ||||
|     --menu-text-color: #272727; | ||||
|     --menu-background-color: #ffffffd9; | ||||
|     --menu-item-icon-color: #727272; | ||||
|     --menu-item-disabled-opacity: 0.5; | ||||
|     --menu-item-disabled-opacity: 0.6; | ||||
|     --menu-item-keyboard-shortcut-color: #666666a8; | ||||
|     --menu-item-arrow-color: #00000080; | ||||
|     --menu-item-delimiter-color: #00000030; | ||||
|  | ||||
| @ -67,6 +67,14 @@ | ||||
|     --tab-note-icons: true; | ||||
| } | ||||
| 
 | ||||
| /* Tool dialogs - small dialogs without a backdrop */ | ||||
| div.tn-tool-dialog { | ||||
|     border-radius: 10px; | ||||
|     background: var(--tool-dialog-background-color) !important; | ||||
|     user-select: none; | ||||
|     box-shadow: 10px 10px 93px -25px var(--tool-dialog-shadow-color); | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * Note search suggestions | ||||
|  */ | ||||
|  | ||||
| @ -141,10 +141,12 @@ input[type="text"], | ||||
| input[type="number"], | ||||
| input[type="password"], | ||||
| textarea.form-control, | ||||
| textarea { | ||||
| textarea, | ||||
| .tn-input-field { | ||||
|     outline: 3px solid transparent; | ||||
|     outline-offset: 6px; | ||||
|     border: unset; | ||||
|     border-radius: var(--bs-border-radius); | ||||
|     background: var(--input-background-color); | ||||
|     color: var(--input-text-color); | ||||
| } | ||||
| @ -154,7 +156,8 @@ input[type="text"]:hover, | ||||
| input[type="number"]:hover, | ||||
| input[type="password"]:hover, | ||||
| textarea.form-control:hover, | ||||
| textarea:hover { | ||||
| textarea:hover, | ||||
| .tn-input-field:hover { | ||||
|     background: var(--input-hover-background); | ||||
|     color: var(--input-hover-color); | ||||
| } | ||||
| @ -164,7 +167,9 @@ input[type="text"]:focus, | ||||
| input[type="number"]:focus, | ||||
| input[type="password"]:focus, | ||||
| textarea.form-control:focus, | ||||
| textarea:focus { | ||||
| textarea:focus, | ||||
| .tn-input-field:focus, | ||||
| .tn-input-field:focus-within { | ||||
|     box-shadow: unset; | ||||
|     outline: 3px solid var(--input-focus-outline-color); | ||||
|     outline-offset: 0; | ||||
| @ -337,6 +342,53 @@ optgroup { | ||||
|     line-height: 40px; | ||||
| } | ||||
| 
 | ||||
| /*  | ||||
|  * File input | ||||
|  * | ||||
|  * <label class="tn-file-input tn-input-field"> | ||||
|  *     <input type="file" /> | ||||
|  * </label> | ||||
|  */ | ||||
| 
 | ||||
|  .tn-file-input { | ||||
|     position: relative; | ||||
|     padding: .375rem 2.25rem .375rem .75rem; | ||||
| } | ||||
| 
 | ||||
| .tn-file-input input[type="file"] { | ||||
|     background: transparent; | ||||
| } | ||||
| 
 | ||||
| .tn-file-input input[type="file"]::file-selector-button { | ||||
|     /* Hide the "Browse..." button */ | ||||
|     display: none; | ||||
| } | ||||
| 
 | ||||
| .tn-file-input:hover input[type="file"] { | ||||
|     color: var(--input-hover-color); | ||||
| } | ||||
| 
 | ||||
| .tn-file-input input[type="file"]:focus, | ||||
| .tn-file-input input[type="file"]:active { | ||||
|     outline: none; | ||||
|     color: var(--input-focus-color); | ||||
| } | ||||
| 
 | ||||
| /* The browse icon */ | ||||
| .tn-file-input::before { | ||||
|     display: flex; | ||||
|     position: absolute; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|     content: "\eae1"; | ||||
|     width: 2em; | ||||
|     height: 100%; | ||||
|     right: 0; | ||||
|     top: 0; | ||||
|     font-size: 1.2em; | ||||
|     font-family: boxicons; | ||||
| } | ||||
| 
 | ||||
| /* Check boxes and radio buttons */ | ||||
| 
 | ||||
| @supports selector(label:has(*)) { | ||||
|  | ||||
| @ -1,3 +1,29 @@ | ||||
| /* | ||||
|  * Basic properties | ||||
|  */ | ||||
| 
 | ||||
| /* Note type dropdown */ | ||||
| 
 | ||||
| div.note-type-dropdown .check { | ||||
|     margin-right: 6px; | ||||
| } | ||||
| 
 | ||||
|  /* Editability dropdown */ | ||||
| 
 | ||||
| div.editability-dropdown a.dropdown-item { | ||||
|     padding: 4px 16px 4px 0; | ||||
|     align-items: start !important; | ||||
| } | ||||
| 
 | ||||
| .editability-dropdown .dropdown-item .check { | ||||
|     margin-left: 4px; | ||||
| } | ||||
| 
 | ||||
| .editability-dropdown .dropdown-item .description { | ||||
|     opacity: .75; | ||||
|     font-size: .85em; | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * Owned attributes | ||||
|  */ | ||||
| @ -11,6 +37,11 @@ | ||||
|     right: 30px; | ||||
| } | ||||
| 
 | ||||
| /* Note path in attribute detail dialog */ | ||||
| .attr-detail .note-path { | ||||
|     margin-left: 8px; | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * Similar notes | ||||
|  */ | ||||
|  | ||||
| @ -79,4 +79,10 @@ | ||||
| .detail-font-size-input-group, | ||||
| .monospace-font-size-input-group { | ||||
|     width: fit-content; | ||||
| } | ||||
| 
 | ||||
| /* Advanced */ | ||||
| 
 | ||||
| .options-section ul.existing-anonymized-databases { | ||||
|     margin: 1em; | ||||
| } | ||||
| @ -956,7 +956,7 @@ body.mobile .note-title { | ||||
|  * supported when this class is used. | ||||
|  */ | ||||
| 
 | ||||
| .dropdown-menu { | ||||
| .dropdown-menu:not(.static) { | ||||
|     border-radius: var(--dropdown-border-radius); | ||||
|     padding: var(--menu-padding-size) !important; | ||||
|     font-size: 0.9rem !important; | ||||
| @ -1034,7 +1034,8 @@ body.mobile .dropdown-submenu:hover { | ||||
|     background: transparent !important; | ||||
| } | ||||
| 
 | ||||
| html body .dropdown-item.disabled { | ||||
| html body .dropdown-item.disabled, | ||||
| html body .dropdown-item[disabled] { | ||||
|     color: var(--menu-text-color) !important; | ||||
|     opacity: var(--menu-item-disabled-opacity); | ||||
| } | ||||
| @ -1087,6 +1088,20 @@ html body .dropdown-item.disabled { | ||||
|     color: var(--menu-item-arrow-color) !important; | ||||
| } | ||||
| 
 | ||||
| /* Static menus (used as a list, such as on the note revisions dialog) */ | ||||
| body.desktop .dropdown-menu.static { | ||||
|     box-shadow: unset; | ||||
|     border-radius: 4px; | ||||
|     border: unset; | ||||
|     background-color: var(--card-background-color) !important; | ||||
|     padding: var(--menu-padding-size) !important; | ||||
|     user-select: none; | ||||
| } | ||||
| 
 | ||||
| body.desktop .dropdown-menu.static .dropdown-item.active { | ||||
|     --active-item-text-color: var(--menu-text-color); | ||||
| } | ||||
| 
 | ||||
| body.desktop .dropdown-menu .dropdown-toggle::after { | ||||
|     height: 100%; | ||||
| } | ||||
| @ -1104,34 +1119,38 @@ body.mobile .dropdown-menu .dropdown-item.submenu-open .dropdown-toggle::after { | ||||
|  */ | ||||
| 
 | ||||
| .calendar-dropdown-widget { | ||||
|     width: unset !important; | ||||
|     padding: 12px; | ||||
|     color: var(--calendar-color); | ||||
|     user-select: none; | ||||
| } | ||||
| 
 | ||||
| .calendar-dropdown-widget .calendar-header { | ||||
|     padding: 8px 0 20px 0; | ||||
| } | ||||
| 
 | ||||
| .calendar-dropdown-widget .calendar-header input[type="number"] { | ||||
|     appearance: textfield !important; | ||||
| } | ||||
| 
 | ||||
| .calendar-dropdown-widget .calendar-header input[type="number"]::-webkit-outer-spin-button, | ||||
| .calendar-dropdown-widget .calendar-header input[type="number"]::-webkit-inner-spin-button { | ||||
|     -webkit-appearance: none; | ||||
|     margin: 0; | ||||
|     gap: 10px; | ||||
| } | ||||
| 
 | ||||
| .calendar-dropdown-widget .calendar-header input, | ||||
| .calendar-dropdown-widget .calendar-header [data-calendar-input="month"] { | ||||
|     /* TODO: Provide styling for background and states */ | ||||
|     background: transparent !important; | ||||
|     border: unset; | ||||
|     --input-background-color: transparent; | ||||
|     --menu-background-color: transparent; | ||||
| 
 | ||||
|     text-align: center; | ||||
|     font-size: 1.4em; | ||||
|     font-weight: 300; | ||||
| } | ||||
| 
 | ||||
| .calendar-dropdown-widget .calendar-header input:not(:focus) { | ||||
|     outline: 3px solid transparent; | ||||
| } | ||||
| 
 | ||||
| .calendar-dropdown-widget .calendar-header .calendar-month-selector .select-button { | ||||
|     --select-arrow-svg: ""; /* Disable the dropdown arrow */ | ||||
| 
 | ||||
|     min-width: 120px; | ||||
|     padding: 0 10px; | ||||
| } | ||||
| 
 | ||||
| .calendar-dropdown-widget .calendar-header .dropdown-toggle::after { | ||||
|     content: unset !important; | ||||
| } | ||||
| @ -1174,6 +1193,7 @@ body .calendar-dropdown-widget .calendar-body a:hover { | ||||
|     border-radius: 6px; | ||||
|     background: var(--calendar-day-hover-background); | ||||
|     color: var(--calendar-day-hover-color) !important; | ||||
|     text-decoration: unset; | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| @ -1186,13 +1206,25 @@ body .calendar-dropdown-widget .calendar-body a:hover { | ||||
| 
 | ||||
| .note-tooltip-content { | ||||
|     padding: 8px; | ||||
|     min-height: 56px; | ||||
| } | ||||
| 
 | ||||
| .note-tooltip-content .note-title-with-path { | ||||
| .note-tooltip-title .note-title-with-path { | ||||
|     display: flex; | ||||
|     flex-direction: column-reverse; | ||||
|     border-bottom: 2px solid currentColor; | ||||
| } | ||||
| 
 | ||||
| .note-tooltip-title a { | ||||
|     color: inherit !important; | ||||
| } | ||||
| 
 | ||||
| .note-tooltip-title.note-no-content { | ||||
|     margin: 0; | ||||
| } | ||||
| 
 | ||||
| .note-tooltip-title:not(.note-no-content) .note-title-with-path { | ||||
|     padding-bottom: 6px; | ||||
|     border-bottom: 2px solid currentColor; | ||||
| } | ||||
| 
 | ||||
| .note-tooltip-content .note-path { | ||||
|  | ||||
| @ -1415,7 +1415,8 @@ | ||||
|     "doc": "Doc", | ||||
|     "widget": "Widget", | ||||
|     "confirm-change": "It is not recommended to change note type when note content is not empty. Do you want to continue anyway?", | ||||
|     "geo-map": "Geo Map (beta)" | ||||
|     "geo-map": "Geo Map", | ||||
|     "beta-feature": "Beta" | ||||
|   }, | ||||
|   "protect_note": { | ||||
|     "toggle-on": "Protect the note", | ||||
|  | ||||
| @ -1381,7 +1381,8 @@ | ||||
|     "launcher": "Scurtătură", | ||||
|     "widget": "Widget", | ||||
|     "confirm-change": "Nu se recomandă schimbarea tipului notiței atunci când ea are un conținut. Procedați oricum?", | ||||
|     "geo-map": "Hartă geografică (beta)" | ||||
|     "geo-map": "Hartă geografică", | ||||
|     "beta-feature": "Beta" | ||||
|   }, | ||||
|   "protect_note": { | ||||
|     "toggle-off": "Deprotejează notița", | ||||
|  | ||||
| @ -5,7 +5,7 @@ import BBranch from "../../../becca/entities/bbranch.js"; | ||||
| import SearchContext from "../search_context.js"; | ||||
| import dateUtils from "../../date_utils.js"; | ||||
| import becca from "../../../becca/becca.js"; | ||||
| import becca_mocking from "../../../../spec/support/becca_mocking.js"; | ||||
| import { findNoteByTitle, note, NoteBuilder } from "../../../../spec/support/becca_mocking.js"; | ||||
| 
 | ||||
| describe("Search", () => { | ||||
|     let rootNote: any; | ||||
| @ -13,7 +13,7 @@ describe("Search", () => { | ||||
|     beforeEach(() => { | ||||
|         becca.reset(); | ||||
| 
 | ||||
|         rootNote = new becca_mocking.NoteBuilder(new BNote({ noteId: "root", title: "root", type: "text" })); | ||||
|         rootNote = new NoteBuilder(new BNote({ noteId: "root", title: "root", type: "text" })); | ||||
|         new BBranch({ | ||||
|             branchId: "none_root", | ||||
|             noteId: "root", | ||||
| @ -23,18 +23,18 @@ describe("Search", () => { | ||||
|     }); | ||||
| 
 | ||||
|     it.skip("simple path match", () => { | ||||
|         rootNote.child(becca_mocking.note("Europe").child(becca_mocking.note("Austria"))); | ||||
|         rootNote.child(note("Europe").child(note("Austria"))); | ||||
| 
 | ||||
|         const searchContext = new SearchContext(); | ||||
|         const searchResults = searchService.findResultsWithQuery("europe austria", searchContext); | ||||
| 
 | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it.skip("normal search looks also at attributes", () => { | ||||
|         const austria = becca_mocking.note("Austria"); | ||||
|         const vienna = becca_mocking.note("Vienna"); | ||||
|         const austria = note("Austria"); | ||||
|         const vienna = note("Vienna"); | ||||
| 
 | ||||
|         rootNote.child(austria.relation("capital", vienna.note)).child(vienna.label("inhabitants", "1888776")); | ||||
| 
 | ||||
| @ -42,27 +42,27 @@ describe("Search", () => { | ||||
|         let searchResults = searchService.findResultsWithQuery("capital", searchContext); | ||||
| 
 | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
| 
 | ||||
|         searchResults = searchService.findResultsWithQuery("inhabitants", searchContext); | ||||
| 
 | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Vienna")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Vienna")).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it.skip("normal search looks also at type and mime", () => { | ||||
|         rootNote.child(becca_mocking.note("Effective Java", { type: "book", mime: "" })).child(becca_mocking.note("Hello World.java", { type: "code", mime: "text/x-java" })); | ||||
|         rootNote.child(note("Effective Java", { type: "book", mime: "" })).child(note("Hello World.java", { type: "code", mime: "text/x-java" })); | ||||
| 
 | ||||
|         const searchContext = new SearchContext(); | ||||
|         let searchResults = searchService.findResultsWithQuery("book", searchContext); | ||||
| 
 | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Effective Java")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Effective Java")).toBeTruthy(); | ||||
| 
 | ||||
|         searchResults = searchService.findResultsWithQuery("text", searchContext); // should match mime
 | ||||
| 
 | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Hello World.java")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Hello World.java")).toBeTruthy(); | ||||
| 
 | ||||
|         searchResults = searchService.findResultsWithQuery("java", searchContext); | ||||
| 
 | ||||
| @ -70,110 +70,104 @@ describe("Search", () => { | ||||
|     }); | ||||
| 
 | ||||
|     it.skip("only end leafs are results", () => { | ||||
|         rootNote.child(becca_mocking.note("Europe").child(becca_mocking.note("Austria"))); | ||||
|         rootNote.child(note("Europe").child(note("Austria"))); | ||||
| 
 | ||||
|         const searchContext = new SearchContext(); | ||||
|         const searchResults = searchService.findResultsWithQuery("europe", searchContext); | ||||
| 
 | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Europe")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Europe")).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it.skip("only end leafs are results", () => { | ||||
|         rootNote.child(becca_mocking.note("Europe").child(becca_mocking.note("Austria").label("capital", "Vienna"))); | ||||
|         rootNote.child(note("Europe").child(note("Austria").label("capital", "Vienna"))); | ||||
| 
 | ||||
|         const searchContext = new SearchContext(); | ||||
| 
 | ||||
|         const searchResults = searchService.findResultsWithQuery("Vienna", searchContext); | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it("label comparison with short syntax", () => { | ||||
|         rootNote.child(becca_mocking.note("Europe").child(becca_mocking.note("Austria").label("capital", "Vienna")).child(becca_mocking.note("Czech Republic").label("capital", "Prague"))); | ||||
|         rootNote.child(note("Europe").child(note("Austria").label("capital", "Vienna")).child(note("Czech Republic").label("capital", "Prague"))); | ||||
| 
 | ||||
|         const searchContext = new SearchContext(); | ||||
| 
 | ||||
|         let searchResults = searchService.findResultsWithQuery("#capital=Vienna", searchContext); | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
| 
 | ||||
|         // case sensitivity:
 | ||||
|         searchResults = searchService.findResultsWithQuery("#CAPITAL=VIENNA", searchContext); | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
| 
 | ||||
|         searchResults = searchService.findResultsWithQuery("#caPItal=vienNa", searchContext); | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it("label comparison with full syntax", () => { | ||||
|         rootNote.child(becca_mocking.note("Europe").child(becca_mocking.note("Austria").label("capital", "Vienna")).child(becca_mocking.note("Czech Republic").label("capital", "Prague"))); | ||||
|         rootNote.child(note("Europe").child(note("Austria").label("capital", "Vienna")).child(note("Czech Republic").label("capital", "Prague"))); | ||||
| 
 | ||||
|         const searchContext = new SearchContext(); | ||||
| 
 | ||||
|         let searchResults = searchService.findResultsWithQuery("# note.labels.capital=Prague", searchContext); | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it("numeric label comparison", () => { | ||||
|         rootNote.child( | ||||
|             becca_mocking | ||||
|                 .note("Europe") | ||||
|         rootNote.child(note("Europe") | ||||
|                 .label("country", "", true) | ||||
|                 .child(becca_mocking.note("Austria").label("population", "8859000")) | ||||
|                 .child(becca_mocking.note("Czech Republic").label("population", "10650000")) | ||||
|                 .child(note("Austria").label("population", "8859000")) | ||||
|                 .child(note("Czech Republic").label("population", "10650000")) | ||||
|         ); | ||||
| 
 | ||||
|         const searchContext = new SearchContext(); | ||||
| 
 | ||||
|         const searchResults = searchService.findResultsWithQuery("#country #population >= 10000000", searchContext); | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it.skip("inherited label comparison", () => { | ||||
|         rootNote.child(becca_mocking.note("Europe").label("country", "", true).child(becca_mocking.note("Austria")).child(becca_mocking.note("Czech Republic"))); | ||||
|         rootNote.child(note("Europe").label("country", "", true).child(note("Austria")).child(note("Czech Republic"))); | ||||
| 
 | ||||
|         const searchContext = new SearchContext(); | ||||
| 
 | ||||
|         const searchResults = searchService.findResultsWithQuery("austria #country", searchContext); | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it("numeric label comparison fallback to string comparison", () => { | ||||
|         // dates should not be coerced into numbers which would then give wrong numbers
 | ||||
| 
 | ||||
|         rootNote.child( | ||||
|             becca_mocking | ||||
|                 .note("Europe") | ||||
|         rootNote.child(note("Europe") | ||||
|                 .label("country", "", true) | ||||
|                 .child(becca_mocking.note("Austria").label("established", "1955-07-27")) | ||||
|                 .child(becca_mocking.note("Czech Republic").label("established", "1993-01-01")) | ||||
|                 .child(becca_mocking.note("Hungary").label("established", "1920-06-04")) | ||||
|                 .child(note("Austria").label("established", "1955-07-27")) | ||||
|                 .child(note("Czech Republic").label("established", "1993-01-01")) | ||||
|                 .child(note("Hungary").label("established", "1920-06-04")) | ||||
|         ); | ||||
| 
 | ||||
|         const searchContext = new SearchContext(); | ||||
| 
 | ||||
|         let searchResults = searchService.findResultsWithQuery('#established <= "1955-01-01"', searchContext); | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Hungary")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Hungary")).toBeTruthy(); | ||||
| 
 | ||||
|         searchResults = searchService.findResultsWithQuery('#established > "1955-01-01"', searchContext); | ||||
|         expect(searchResults.length).toEqual(2); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it("smart date comparisons", () => { | ||||
|         // dates should not be coerced into numbers which would then give wrong numbers
 | ||||
| 
 | ||||
|         rootNote.child( | ||||
|             becca_mocking | ||||
|                 .note("My note", { dateCreated: dateUtils.localNowDateTime() }) | ||||
|         rootNote.child(note("My note", { dateCreated: dateUtils.localNowDateTime() }) | ||||
|                 .label("year", new Date().getFullYear().toString()) | ||||
|                 .label("month", dateUtils.localNowDate().substr(0, 7)) | ||||
|                 .label("date", dateUtils.localNowDate()) | ||||
| @ -188,7 +182,7 @@ describe("Search", () => { | ||||
|                 .toEqual(expectedResultCount); | ||||
| 
 | ||||
|             if (expectedResultCount === 1) { | ||||
|                 expect(becca_mocking.findNoteByTitle(searchResults, "My note")).toBeTruthy(); | ||||
|                 expect(findNoteByTitle(searchResults, "My note")).toBeTruthy(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| @ -225,30 +219,26 @@ describe("Search", () => { | ||||
|     }); | ||||
| 
 | ||||
|     it("logical or", () => { | ||||
|         rootNote.child( | ||||
|             becca_mocking | ||||
|                 .note("Europe") | ||||
|         rootNote.child(note("Europe") | ||||
|                 .label("country", "", true) | ||||
|                 .child(becca_mocking.note("Austria").label("languageFamily", "germanic")) | ||||
|                 .child(becca_mocking.note("Czech Republic").label("languageFamily", "slavic")) | ||||
|                 .child(becca_mocking.note("Hungary").label("languageFamily", "finnougric")) | ||||
|                 .child(note("Austria").label("languageFamily", "germanic")) | ||||
|                 .child(note("Czech Republic").label("languageFamily", "slavic")) | ||||
|                 .child(note("Hungary").label("languageFamily", "finnougric")) | ||||
|         ); | ||||
| 
 | ||||
|         const searchContext = new SearchContext(); | ||||
| 
 | ||||
|         const searchResults = searchService.findResultsWithQuery("#languageFamily = slavic OR #languageFamily = germanic", searchContext); | ||||
|         expect(searchResults.length).toEqual(2); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it("fuzzy attribute search", () => { | ||||
|         rootNote.child( | ||||
|             becca_mocking | ||||
|                 .note("Europe") | ||||
|         rootNote.child(note("Europe") | ||||
|                 .label("country", "", true) | ||||
|                 .child(becca_mocking.note("Austria").label("languageFamily", "germanic")) | ||||
|                 .child(becca_mocking.note("Czech Republic").label("languageFamily", "slavic")) | ||||
|                 .child(note("Austria").label("languageFamily", "germanic")) | ||||
|                 .child(note("Czech Republic").label("languageFamily", "slavic")) | ||||
|         ); | ||||
| 
 | ||||
|         let searchContext = new SearchContext({ fuzzyAttributeSearch: false }); | ||||
| @ -266,147 +256,135 @@ describe("Search", () => { | ||||
| 
 | ||||
|         searchResults = searchService.findResultsWithQuery("#languageFamily=ger", searchContext); | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it("filter by note property", () => { | ||||
|         rootNote.child(becca_mocking.note("Europe").child(becca_mocking.note("Austria")).child(becca_mocking.note("Czech Republic"))); | ||||
|         rootNote.child(note("Europe").child(note("Austria")).child(note("Czech Republic"))); | ||||
| 
 | ||||
|         const searchContext = new SearchContext(); | ||||
| 
 | ||||
|         const searchResults = searchService.findResultsWithQuery("# note.title =* czech", searchContext); | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it("filter by note's parent", () => { | ||||
|         rootNote | ||||
|             .child( | ||||
|                 becca_mocking | ||||
|                     .note("Europe") | ||||
|                     .child(becca_mocking.note("Austria")) | ||||
|                     .child(becca_mocking.note("Czech Republic").child(becca_mocking.note("Prague"))) | ||||
|             .child(note("Europe") | ||||
|                     .child(note("Austria")) | ||||
|                     .child(note("Czech Republic").child(note("Prague"))) | ||||
|             ) | ||||
|             .child(becca_mocking.note("Asia").child(becca_mocking.note("Taiwan"))); | ||||
|             .child(note("Asia").child(note("Taiwan"))); | ||||
| 
 | ||||
|         const searchContext = new SearchContext(); | ||||
| 
 | ||||
|         let searchResults = searchService.findResultsWithQuery("# note.parents.title = Europe", searchContext); | ||||
|         expect(searchResults.length).toEqual(2); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); | ||||
| 
 | ||||
|         searchResults = searchService.findResultsWithQuery("# note.parents.title = Asia", searchContext); | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Taiwan")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Taiwan")).toBeTruthy(); | ||||
| 
 | ||||
|         searchResults = searchService.findResultsWithQuery("# note.parents.parents.title = Europe", searchContext); | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Prague")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Prague")).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it("filter by note's ancestor", () => { | ||||
|         rootNote | ||||
|             .child( | ||||
|                 becca_mocking | ||||
|                     .note("Europe") | ||||
|                     .child(becca_mocking.note("Austria")) | ||||
|                     .child(becca_mocking.note("Czech Republic").child(becca_mocking.note("Prague").label("city"))) | ||||
|             .child(note("Europe") | ||||
|                     .child(note("Austria")) | ||||
|                     .child(note("Czech Republic").child(note("Prague").label("city"))) | ||||
|             ) | ||||
|             .child(becca_mocking.note("Asia").child(becca_mocking.note("Taiwan").child(becca_mocking.note("Taipei").label("city")))); | ||||
|             .child(note("Asia").child(note("Taiwan").child(note("Taipei").label("city")))); | ||||
| 
 | ||||
|         const searchContext = new SearchContext(); | ||||
| 
 | ||||
|         let searchResults = searchService.findResultsWithQuery("#city AND note.ancestors.title = Europe", searchContext); | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Prague")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Prague")).toBeTruthy(); | ||||
| 
 | ||||
|         searchResults = searchService.findResultsWithQuery("#city AND note.ancestors.title = Asia", searchContext); | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Taipei")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Taipei")).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it("filter by note's child", () => { | ||||
|         rootNote | ||||
|             .child( | ||||
|                 becca_mocking | ||||
|                     .note("Europe") | ||||
|                     .child(becca_mocking.note("Austria").child(becca_mocking.note("Vienna"))) | ||||
|                     .child(becca_mocking.note("Czech Republic").child(becca_mocking.note("Prague"))) | ||||
|             .child(note("Europe") | ||||
|                     .child(note("Austria").child(note("Vienna"))) | ||||
|                     .child(note("Czech Republic").child(note("Prague"))) | ||||
|             ) | ||||
|             .child(becca_mocking.note("Oceania").child(becca_mocking.note("Australia"))); | ||||
|             .child(note("Oceania").child(note("Australia"))); | ||||
| 
 | ||||
|         const searchContext = new SearchContext(); | ||||
| 
 | ||||
|         let searchResults = searchService.findResultsWithQuery("# note.children.title =* Aust", searchContext); | ||||
|         expect(searchResults.length).toEqual(2); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Europe")).toBeTruthy(); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Oceania")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Europe")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Oceania")).toBeTruthy(); | ||||
| 
 | ||||
|         searchResults = searchService.findResultsWithQuery("# note.children.title =* Aust AND note.children.title *= republic", searchContext); | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Europe")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Europe")).toBeTruthy(); | ||||
| 
 | ||||
|         searchResults = searchService.findResultsWithQuery("# note.children.children.title = Prague", searchContext); | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Europe")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Europe")).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it("filter by relation's note properties using short syntax", () => { | ||||
|         const austria = becca_mocking.note("Austria"); | ||||
|         const portugal = becca_mocking.note("Portugal"); | ||||
|         const austria = note("Austria"); | ||||
|         const portugal = note("Portugal"); | ||||
| 
 | ||||
|         rootNote.child( | ||||
|             becca_mocking | ||||
|                 .note("Europe") | ||||
|         rootNote.child(note("Europe") | ||||
|                 .child(austria) | ||||
|                 .child(becca_mocking.note("Czech Republic").relation("neighbor", austria.note)) | ||||
|                 .child(note("Czech Republic").relation("neighbor", austria.note)) | ||||
|                 .child(portugal) | ||||
|                 .child(becca_mocking.note("Spain").relation("neighbor", portugal.note)) | ||||
|                 .child(note("Spain").relation("neighbor", portugal.note)) | ||||
|         ); | ||||
| 
 | ||||
|         const searchContext = new SearchContext(); | ||||
| 
 | ||||
|         let searchResults = searchService.findResultsWithQuery("# ~neighbor.title = Austria", searchContext); | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); | ||||
| 
 | ||||
|         searchResults = searchService.findResultsWithQuery("# ~neighbor.title = Portugal", searchContext); | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Spain")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Spain")).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it("filter by relation's note properties using long syntax", () => { | ||||
|         const austria = becca_mocking.note("Austria"); | ||||
|         const portugal = becca_mocking.note("Portugal"); | ||||
|         const austria = note("Austria"); | ||||
|         const portugal = note("Portugal"); | ||||
| 
 | ||||
|         rootNote.child( | ||||
|             becca_mocking | ||||
|                 .note("Europe") | ||||
|         rootNote.child(note("Europe") | ||||
|                 .child(austria) | ||||
|                 .child(becca_mocking.note("Czech Republic").relation("neighbor", austria.note)) | ||||
|                 .child(note("Czech Republic").relation("neighbor", austria.note)) | ||||
|                 .child(portugal) | ||||
|                 .child(becca_mocking.note("Spain").relation("neighbor", portugal.note)) | ||||
|                 .child(note("Spain").relation("neighbor", portugal.note)) | ||||
|         ); | ||||
| 
 | ||||
|         const searchContext = new SearchContext(); | ||||
| 
 | ||||
|         const searchResults = searchService.findResultsWithQuery("# note.relations.neighbor.title = Austria", searchContext); | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it("filter by multiple level relation", () => { | ||||
|         const austria = becca_mocking.note("Austria"); | ||||
|         const slovakia = becca_mocking.note("Slovakia"); | ||||
|         const italy = becca_mocking.note("Italy"); | ||||
|         const ukraine = becca_mocking.note("Ukraine"); | ||||
|         const austria = note("Austria"); | ||||
|         const slovakia = note("Slovakia"); | ||||
|         const italy = note("Italy"); | ||||
|         const ukraine = note("Ukraine"); | ||||
| 
 | ||||
|         rootNote.child( | ||||
|             becca_mocking | ||||
|                 .note("Europe") | ||||
|         rootNote.child(note("Europe") | ||||
|                 .child(austria.relation("neighbor", italy.note).relation("neighbor", slovakia.note)) | ||||
|                 .child(becca_mocking.note("Czech Republic").relation("neighbor", austria.note).relation("neighbor", slovakia.note)) | ||||
|                 .child(note("Czech Republic").relation("neighbor", austria.note).relation("neighbor", slovakia.note)) | ||||
|                 .child(slovakia.relation("neighbor", ukraine.note)) | ||||
|                 .child(ukraine) | ||||
|         ); | ||||
| @ -415,25 +393,25 @@ describe("Search", () => { | ||||
| 
 | ||||
|         let searchResults = searchService.findResultsWithQuery("# note.relations.neighbor.relations.neighbor.title = Italy", searchContext); | ||||
|         expect(searchResults.length).toEqual(1); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); | ||||
| 
 | ||||
|         searchResults = searchService.findResultsWithQuery("# note.relations.neighbor.relations.neighbor.title = Ukraine", searchContext); | ||||
|         expect(searchResults.length).toEqual(2); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); | ||||
|         expect(becca_mocking.findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); | ||||
|         expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it("test note properties", () => { | ||||
|         const austria = becca_mocking.note("Austria"); | ||||
|         const austria = note("Austria"); | ||||
| 
 | ||||
|         austria.relation("myself", austria.note); | ||||
|         austria.label("capital", "Vienna"); | ||||
|         austria.label("population", "8859000"); | ||||
| 
 | ||||
|         rootNote | ||||
|             .child(becca_mocking.note("Asia")) | ||||
|             .child(becca_mocking.note("Europe").child(austria.child(becca_mocking.note("Vienna")).child(becca_mocking.note("Sebastian Kurz")))) | ||||
|             .child(becca_mocking.note("Mozart").child(austria)); | ||||
|             .child(note("Asia")) | ||||
|             .child(note("Europe").child(austria.child(note("Vienna")).child(note("Sebastian Kurz")))) | ||||
|             .child(note("Mozart").child(austria)); | ||||
| 
 | ||||
|         austria.note.isProtected = false; | ||||
|         austria.note.dateCreated = "2020-05-14 12:11:42.001+0200"; | ||||
| @ -490,12 +468,12 @@ describe("Search", () => { | ||||
|     }); | ||||
| 
 | ||||
|     it("test order by", () => { | ||||
|         const italy = becca_mocking.note("Italy").label("capital", "Rome"); | ||||
|         const slovakia = becca_mocking.note("Slovakia").label("capital", "Bratislava"); | ||||
|         const austria = becca_mocking.note("Austria").label("capital", "Vienna"); | ||||
|         const ukraine = becca_mocking.note("Ukraine").label("capital", "Kiev"); | ||||
|         const italy = note("Italy").label("capital", "Rome"); | ||||
|         const slovakia = note("Slovakia").label("capital", "Bratislava"); | ||||
|         const austria = note("Austria").label("capital", "Vienna"); | ||||
|         const ukraine = note("Ukraine").label("capital", "Kiev"); | ||||
| 
 | ||||
|         rootNote.child(becca_mocking.note("Europe").child(ukraine).child(slovakia).child(austria).child(italy)); | ||||
|         rootNote.child(note("Europe").child(ukraine).child(slovakia).child(austria).child(italy)); | ||||
| 
 | ||||
|         const searchContext = new SearchContext(); | ||||
| 
 | ||||
| @ -533,10 +511,10 @@ describe("Search", () => { | ||||
|     }); | ||||
| 
 | ||||
|     it("test not(...)", () => { | ||||
|         const italy = becca_mocking.note("Italy").label("capital", "Rome"); | ||||
|         const slovakia = becca_mocking.note("Slovakia").label("capital", "Bratislava"); | ||||
|         const italy = note("Italy").label("capital", "Rome"); | ||||
|         const slovakia = note("Slovakia").label("capital", "Bratislava"); | ||||
| 
 | ||||
|         rootNote.child(becca_mocking.note("Europe").child(slovakia).child(italy)); | ||||
|         rootNote.child(note("Europe").child(slovakia).child(italy)); | ||||
| 
 | ||||
|         const searchContext = new SearchContext(); | ||||
| 
 | ||||
| @ -550,10 +528,10 @@ describe("Search", () => { | ||||
|     }); | ||||
| 
 | ||||
|     it.skip("test note.text *=* something", () => { | ||||
|         const italy = becca_mocking.note("Italy").label("capital", "Rome"); | ||||
|         const slovakia = becca_mocking.note("Slovakia").label("capital", "Bratislava"); | ||||
|         const italy = note("Italy").label("capital", "Rome"); | ||||
|         const slovakia = note("Slovakia").label("capital", "Bratislava"); | ||||
| 
 | ||||
|         rootNote.child(becca_mocking.note("Europe").child(slovakia).child(italy)); | ||||
|         rootNote.child(note("Europe").child(slovakia).child(italy)); | ||||
| 
 | ||||
|         const searchContext = new SearchContext(); | ||||
| 
 | ||||
| @ -563,10 +541,10 @@ describe("Search", () => { | ||||
|     }); | ||||
| 
 | ||||
|     it.skip("test that fulltext does not match archived notes", () => { | ||||
|         const italy = becca_mocking.note("Italy").label("capital", "Rome"); | ||||
|         const slovakia = becca_mocking.note("Slovakia").label("capital", "Bratislava"); | ||||
|         const italy = note("Italy").label("capital", "Rome"); | ||||
|         const slovakia = note("Slovakia").label("capital", "Bratislava"); | ||||
| 
 | ||||
|         rootNote.child(becca_mocking.note("Reddit").label("archived", "", true).child(becca_mocking.note("Post X")).child(becca_mocking.note("Post Y"))).child(becca_mocking.note("Reddit is bad")); | ||||
|         rootNote.child(note("Reddit").label("archived", "", true).child(note("Post X")).child(note("Post Y"))).child(note("Reddit is bad")); | ||||
| 
 | ||||
|         const searchContext = new SearchContext({ includeArchivedNotes: false }); | ||||
| 
 | ||||
| @ -579,14 +557,14 @@ describe("Search", () => { | ||||
| 
 | ||||
|     // it("comparison between labels", () => {
 | ||||
|     //     rootNote
 | ||||
|     //         .child(becca_mocking.note("Europe")
 | ||||
|     //             .child(becca_mocking.note("Austria")
 | ||||
|     //         .child(note("Europe")
 | ||||
|     //             .child(note("Austria")
 | ||||
|     //                 .label('capital', 'Vienna')
 | ||||
|     //                 .label('largestCity', 'Vienna'))
 | ||||
|     //             .child(becca_mocking.note("Canada")
 | ||||
|     //             .child(note("Canada")
 | ||||
|     //                 .label('capital', 'Ottawa')
 | ||||
|     //                 .label('largestCity', 'Toronto'))
 | ||||
|     //             .child(becca_mocking.note("Czech Republic")
 | ||||
|     //             .child(note("Czech Republic")
 | ||||
|     //                 .label('capital', 'Prague')
 | ||||
|     //                 .label('largestCity', 'Prague'))
 | ||||
|     //         );
 | ||||
| @ -595,7 +573,7 @@ describe("Search", () => { | ||||
|     //
 | ||||
|     //     const searchResults = searchService.findResultsWithQuery('#capital = #largestCity', searchContext);
 | ||||
|     //     expect(searchResults.length).toEqual(2);
 | ||||
|     //     expect(becca_mocking.findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy();
 | ||||
|     //     expect(becca_mocking.findNoteByTitle(searchResults, "Austria")).toBeTruthy();
 | ||||
|     //     expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy();
 | ||||
|     //     expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy();
 | ||||
|     // })
 | ||||
| }); | ||||
|  | ||||
| @ -1,8 +1,8 @@ | ||||
| import { describe, it, expect, beforeEach } from "vitest"; | ||||
| import becca_mocking from "../../../spec/support/becca_mocking.js"; | ||||
| import ValueExtractor from "./value_extractor.js"; | ||||
| import becca from "../../becca/becca.js"; | ||||
| import SearchContext from "./search_context.js"; | ||||
| import { note } from "../../../spec/support/becca_mocking.js"; | ||||
| 
 | ||||
| const dsc = new SearchContext(); | ||||
| 
 | ||||
| @ -12,7 +12,7 @@ describe("Value extractor", () => { | ||||
|     }); | ||||
| 
 | ||||
|     it("simple title extraction", async () => { | ||||
|         const europe = becca_mocking.note("Europe").note; | ||||
|         const europe = note("Europe").note; | ||||
| 
 | ||||
|         const valueExtractor = new ValueExtractor(dsc, ["note", "title"]); | ||||
| 
 | ||||
| @ -21,7 +21,7 @@ describe("Value extractor", () => { | ||||
|     }); | ||||
| 
 | ||||
|     it("label extraction", async () => { | ||||
|         const austria = becca_mocking.note("Austria").label("Capital", "Vienna").note; | ||||
|         const austria = note("Austria").label("Capital", "Vienna").note; | ||||
| 
 | ||||
|         let valueExtractor = new ValueExtractor(dsc, ["note", "labels", "capital"]); | ||||
| 
 | ||||
| @ -35,8 +35,8 @@ describe("Value extractor", () => { | ||||
|     }); | ||||
| 
 | ||||
|     it("parent/child property extraction", async () => { | ||||
|         const vienna = becca_mocking.note("Vienna"); | ||||
|         const europe = becca_mocking.note("Europe").child(becca_mocking.note("Austria").child(vienna)); | ||||
|         const vienna = note("Vienna"); | ||||
|         const europe = note("Europe").child(note("Austria").child(vienna)); | ||||
| 
 | ||||
|         let valueExtractor = new ValueExtractor(dsc, ["note", "children", "children", "title"]); | ||||
| 
 | ||||
| @ -50,9 +50,9 @@ describe("Value extractor", () => { | ||||
|     }); | ||||
| 
 | ||||
|     it("extract through relation", async () => { | ||||
|         const czechRepublic = becca_mocking.note("Czech Republic").label("capital", "Prague"); | ||||
|         const slovakia = becca_mocking.note("Slovakia").label("capital", "Bratislava"); | ||||
|         const austria = becca_mocking.note("Austria").relation("neighbor", czechRepublic.note).relation("neighbor", slovakia.note); | ||||
|         const czechRepublic = note("Czech Republic").label("capital", "Prague"); | ||||
|         const slovakia = note("Slovakia").label("capital", "Bratislava"); | ||||
|         const austria = note("Austria").relation("neighbor", czechRepublic.note).relation("neighbor", slovakia.note); | ||||
| 
 | ||||
|         let valueExtractor = new ValueExtractor(dsc, ["note", "relations", "neighbor", "labels", "capital"]); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										72
									
								
								src/services/tree.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/services/tree.spec.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,72 @@ | ||||
| import { beforeEach, describe, expect, it, vi } from "vitest"; | ||||
| import { note, NoteBuilder } from "../../spec/support/becca_mocking.js"; | ||||
| import becca from "../becca/becca.js"; | ||||
| import BBranch from "../becca/entities/bbranch.js"; | ||||
| import BNote from "../becca/entities/bnote.js"; | ||||
| import tree from "./tree.js"; | ||||
| import cls from "./cls.js"; | ||||
| 
 | ||||
| describe("Tree", () => { | ||||
|     let rootNote!: NoteBuilder; | ||||
| 
 | ||||
|     beforeEach(() => { | ||||
|         becca.reset(); | ||||
| 
 | ||||
|         rootNote = new NoteBuilder(new BNote({ | ||||
|             noteId: "root", | ||||
|             title: "root", | ||||
|             type: "text" | ||||
|         })) | ||||
|         new BBranch({ | ||||
|             branchId: "none_root", | ||||
|             noteId: "root", | ||||
|             parentNoteId: "none", | ||||
|             notePosition: 10 | ||||
|         }); | ||||
| 
 | ||||
|         vi.mock("./sql.js", () => { | ||||
|             return { | ||||
|                 default: { | ||||
|                     transactional: (cb: Function) => { | ||||
|                         cb(); | ||||
|                     }, | ||||
|                     execute: () => { }, | ||||
|                     replace: () => { }, | ||||
|                     getMap: () => { } | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         vi.mock("./sql_init.js", () => { | ||||
|             return { | ||||
|                 dbReady: () => { console.log("Hello world") } | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
| 
 | ||||
|     it("custom sort order is idempotent", () => { | ||||
|         rootNote.label("sorted", "order"); | ||||
| 
 | ||||
|         // Add values which have a defined order.
 | ||||
|         for (let i=0; i<=5; i++) { | ||||
|             rootNote.child(note(String(i)).label("order", String(i))); | ||||
|         } | ||||
| 
 | ||||
|         // Add a few values which have no defined order.
 | ||||
|         for (let i=6; i<10; i++) { | ||||
|             rootNote.child(note(String(i))); | ||||
|         } | ||||
| 
 | ||||
|         const expectedOrder = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ]; | ||||
| 
 | ||||
|         // Sort a few times to ensure that the resulting order is the same.
 | ||||
|         for (let i=0; i<5; i++) { | ||||
|             cls.init(() => { | ||||
|                 tree.sortNotesIfNeeded(rootNote.note.noteId); | ||||
|             }); | ||||
| 
 | ||||
|             const order = rootNote.note.children.map((child) => child.title); | ||||
|             expect(order).toStrictEqual(expectedOrder); | ||||
|         } | ||||
|     }); | ||||
| }); | ||||
| @ -145,8 +145,8 @@ function sortNotes(parentNoteId: string, customSortBy: string = "title", reverse | ||||
|                 return compare(bottomBEl, bottomAEl) * (reverse ? -1 : 1); | ||||
|             } | ||||
| 
 | ||||
|             const customAEl = fetchValue(a, customSortBy); | ||||
|             const customBEl = fetchValue(b, customSortBy); | ||||
|             const customAEl = fetchValue(a, customSortBy) ?? fetchValue(a, "title"); | ||||
|             const customBEl = fetchValue(b, customSortBy) ?? fetchValue(b, "title"); | ||||
| 
 | ||||
|             if (customAEl !== customBEl) { | ||||
|                 return compare(customAEl, customBEl); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Elian Doran
						Elian Doran