Compare commits
	
		
			595 Commits
		
	
	
		
			0.20.0-bet
			...
			1.0.2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 07fe5b247b | ||
|  | c1c694035d | ||
|  | 147d2a02be | ||
|  | 6f91786f4d | ||
|  | f62a933d1c | ||
|  | 451835fbeb | ||
|  | 547e7a1b21 | ||
|  | 053e3ba923 | ||
|  | bf65dcd49b | ||
|  | a1d186112a | ||
|  | ca7a298509 | ||
|  | ff4d58f648 | ||
|  | a1e10e99fa | ||
|  | 16bda530f6 | ||
|  | bf9e04d9db | ||
|  | 8df86a75b1 | ||
|  | 5056203023 | ||
|  | a0026e66ce | ||
|  | f75dd2209d | ||
|  | e35f6d9e35 | ||
|  | 3cb00ce4e0 | ||
|  | 8e18cf5986 | ||
|  | 81f80600f5 | ||
|  | 895156675f | ||
|  | 1c424e2e0a | ||
|  | 0124bb17e8 | ||
|  | 2c89b2d262 | ||
|  | c7bbe2f1fe | ||
|  | 88609a8829 | ||
|  | 329beb166c | ||
|  | e36f3d937c | ||
|  | 1395092ca6 | ||
|  | c09004dbc8 | ||
|  | 7efe4a2776 | ||
|  | b763e0b0cb | ||
|  | ddd0d1bef3 | ||
|  | dbca2178c0 | ||
|  | af742ea536 | ||
|  | 14c1a86b9b | ||
|  | ee3dc8c4cd | ||
|  | 1ed148aaf5 | ||
|  | 3327adb1ae | ||
|  | 4d5f771f9f | ||
|  | aa69d663ed | ||
|  | 29d1894f9a | ||
|  | e5738d608c | ||
|  | 9775d3a33d | ||
|  | ad4cf8d631 | ||
|  | a27e8777aa | ||
|  | d23edcc0b5 | ||
|  | 52373e5bef | ||
|  | bb70e796a1 | ||
|  | 3365d26b40 | ||
|  | d3c111b533 | ||
|  | ec876eb102 | ||
|  | dddfb1ec08 | ||
|  | 6fc9c03d70 | ||
|  | 199ff071e8 | ||
|  | 7e4a06044a | ||
|  | d047b75cb7 | ||
|  | 6fb6b13037 | ||
|  | 460c5a1ae3 | ||
|  | 9955bcc339 | ||
|  | 0a3ab996eb | ||
|  | 46f912a6f9 | ||
|  | 01e0f24752 | ||
|  | 7178c63e10 | ||
|  | 30c402eb83 | ||
|  | 2601cc898c | ||
|  | d2a8823808 | ||
|  | 6b61fa9f6f | ||
|  | 247052df5f | ||
|  | 8eb28555bc | ||
|  | 73132475dc | ||
|  | 42c6487ff3 | ||
|  | 8d2ca25fd6 | ||
|  | 5c5919a7eb | ||
|  | 34cdbfc852 | ||
|  | 1bc50194aa | ||
|  | 4a75236e74 | ||
|  | 64b2f881c4 | ||
|  | 4709ddea5d | ||
|  | 6ef49152f3 | ||
|  | 1c44b0bc98 | ||
|  | 11bce8c17c | ||
|  | b42fff1055 | ||
|  | 1b2e442513 | ||
|  | a4d48077ba | ||
|  | 901e2527d8 | ||
|  | f0839571d0 | ||
|  | 89d0d6ec93 | ||
|  | 922ab1d17b | ||
|  | 7c7be378bc | ||
|  | ec01f8f54b | ||
|  | 5a094b44c4 | ||
|  | 3c657a6645 | ||
|  | 3129d44ff1 | ||
|  | 00306f82c5 | ||
|  | 7def676a17 | ||
|  | 6c48735854 | ||
|  | a0b1831cdb | ||
|  | db9fb8480a | ||
|  | c138e2ffb4 | ||
|  | 473c45794e | ||
|  | a12aa81d73 | ||
|  | 0033e279f1 | ||
|  | a25e98d0cb | ||
|  | bc65480f27 | ||
|  | 8582cda124 | ||
|  | d963dfdbb6 | ||
|  | f7e9c109f6 | ||
|  | 30c3004f27 | ||
|  | 4f049fd94b | ||
|  | f98d1c95cc | ||
|  | a2b5c0247b | ||
|  | 28bda9fa41 | ||
|  | 18aeeab041 | ||
|  | c7427a5f7c | ||
|  | 03aa6c7d3a | ||
|  | 10077ae750 | ||
|  | 74eec25285 | ||
|  | b6055479a1 | ||
|  | 69b781419f | ||
|  | da6db24f9e | ||
|  | 2b66723d42 | ||
|  | 00a3e25714 | ||
|  | 8ccbd2d8f9 | ||
|  | 8307f26099 | ||
|  | c686f7eefc | ||
|  | 311c7b1158 | ||
|  | a17325f028 | ||
|  | b734097d16 | ||
|  | afaf077aca | ||
|  | bf14af6a1f | ||
|  | e72faef839 | ||
|  | b274bafe8e | ||
|  | 7bed967755 | ||
|  | 944b81b71c | ||
|  | cd529d53ae | ||
|  | 0d680a58f3 | ||
|  | b30d519523 | ||
|  | 83932e1725 | ||
|  | 4ce0e39760 | ||
|  | 84232f25f0 | ||
|  | 2daedf8fd5 | ||
|  | fe084a4478 | ||
|  | 5bf9646a76 | ||
|  | 2b1f28e6c2 | ||
|  | 5b8bd6e64f | ||
|  | 426fd499ce | ||
|  | 17d3a5840d | ||
|  | be49e1d383 | ||
|  | daa98e8925 | ||
|  | 58784b7568 | ||
|  | 419a183167 | ||
|  | 675b4bde14 | ||
|  | ee6ee99577 | ||
|  | 3bc1f69e75 | ||
|  | 5b9df6d5f2 | ||
|  | 9f062ec1b8 | ||
|  | b52a47bd03 | ||
|  | 5e20134f4f | ||
|  | 89d267d6a2 | ||
|  | 607bc42f59 | ||
|  | 880757fb5d | ||
|  | c8acc6a12e | ||
|  | 7d4c2442da | ||
|  | e5255b0c7c | ||
|  | ac3ef9b6fc | ||
|  | 7b5a41c3ff | ||
|  | d5b0d2a886 | ||
|  | 4d60447242 | ||
|  | 78bee3dc59 | ||
|  | e2db958510 | ||
|  | 16440072fb | ||
|  | be2dd6dc32 | ||
|  | 189bde7c9c | ||
|  | 6a4760e291 | ||
|  | c082bb97e0 | ||
|  | c8e14f91e7 | ||
|  | 6032d096ec | ||
|  | defa9a2270 | ||
|  | 77a913f858 | ||
|  | 6e3fa974ba | ||
|  | 7926055b97 | ||
|  | ffd10e656e | ||
|  | 59c1828078 | ||
|  | 6164271fe8 | ||
|  | 26ba35933d | ||
|  | 87359937c9 | ||
|  | 9b938f6515 | ||
|  | 6c3913785d | ||
|  | 542cf3147d | ||
|  | fb9828badc | ||
|  | 2505ac3f98 | ||
|  | fde8548166 | ||
|  | fe91295704 | ||
|  | 15b99c5749 | ||
|  | 9d66ca4a49 | ||
|  | b749a27f86 | ||
|  | 083212cffe | ||
|  | c4e8756210 | ||
|  | 3a6448f727 | ||
|  | fe18df25ba | ||
|  | db65460ec0 | ||
|  | 0ad3eceb82 | ||
|  | a376d6e361 | ||
|  | 45c7f3f3ca | ||
|  | 238de59a2a | ||
|  | 96255e51d2 | ||
|  | 18c3223105 | ||
|  | b9e97792f3 | ||
|  | cbce9b8637 | ||
|  | 5ab90b85da | ||
|  | f3e1e8a2c7 | ||
|  | e41b292e54 | ||
|  | 86928bbb2d | ||
|  | 2f5ec8b5bf | ||
|  | 14ac6446de | ||
|  | 260a9723a4 | ||
|  | 4e7b000dcd | ||
|  | 2254e4c57e | ||
|  | 25a27733b9 | ||
|  | 6ab520984c | ||
|  | 04d7106956 | ||
|  | db5589f2aa | ||
|  | d06dbbb4bd | ||
|  | b7a62bd9e7 | ||
|  | 93ad9a3aa6 | ||
|  | f1855174f0 | ||
|  | a2dedba0ef | ||
|  | 5a65f445f0 | ||
|  | f52289b2c3 | ||
|  | 3b5ea0f15f | ||
|  | 238bcb8698 | ||
|  | 3ee8bcad8c | ||
|  | f0a51bafbe | ||
|  | 944f3bd329 | ||
|  | 8bb7b2e88b | ||
|  | aab0b0b4bf | ||
|  | 083d6c5125 | ||
|  | c2167a2c5f | ||
|  | 1a695e0451 | ||
|  | 8847f325ed | ||
|  | 94c9da468e | ||
|  | 24b38407e4 | ||
|  | f49d1ae860 | ||
|  | 8b3b541a56 | ||
|  | a974e84ad1 | ||
|  | c4f4115bcb | ||
|  | 3c5adbee31 | ||
|  | 55645e3730 | ||
|  | d918bb568c | ||
|  | b1bff62bf7 | ||
|  | d11d389ae4 | ||
|  | a73c159160 | ||
|  | 7adf102d8d | ||
|  | e4d3ff623a | ||
|  | 2433d59f00 | ||
|  | 8c68e76c3e | ||
|  | 0b204de5a9 | ||
|  | 93c811ab70 | ||
|  | 3ff861099a | ||
|  | f22762539f | ||
|  | 677442a3c0 | ||
|  | b73f12cdba | ||
|  | 28fbb61e81 | ||
|  | c1104d1cd6 | ||
|  | e346702292 | ||
|  | 90887779ea | ||
|  | a941b1437c | ||
|  | 04bdcbd490 | ||
|  | 87a815fd6f | ||
|  | d623848c87 | ||
|  | 46abd0cc42 | ||
|  | e315325d91 | ||
|  | f3fc083330 | ||
|  | 92cb57eb7b | ||
|  | d645fbff2f | ||
|  | 8486f4d43a | ||
|  | 60b1a05894 | ||
|  | f955d63707 | ||
|  | f106019938 | ||
|  | 2473249c8b | ||
|  | d13dc4fba3 | ||
|  | 41a0af032c | ||
|  | 70cf7b0c5a | ||
|  | 14f6788ab9 | ||
|  | bb67049d90 | ||
|  | ae2162beaf | ||
|  | 19f2c5e07f | ||
|  | 8abc5b3889 | ||
|  | 4d37c28bc7 | ||
|  | cc0933eee4 | ||
|  | 2de9a804a0 | ||
|  | ffeb2e91f4 | ||
|  | 8cf5ec9e5a | ||
|  | ea0526f29a | ||
|  | cfcb3a69e5 | ||
|  | e3e0378857 | ||
|  | ccc3809daa | ||
|  | c97786e12c | ||
|  | 400071879f | ||
|  | 4cd6e20c91 | ||
|  | 460e3ad395 | ||
|  | 6f08bd6fc5 | ||
|  | eed3a749db | ||
|  | 6587d12fbd | ||
|  | f8dd68ecc4 | ||
|  | f0aef2b853 | ||
|  | 7d27df1b97 | ||
|  | 457ec86c25 | ||
|  | a24c66958f | ||
|  | 617628b886 | ||
|  | 6b7e623d33 | ||
|  | 5ca85b7e83 | ||
|  | 5965bf3332 | ||
|  | baf2dd293b | ||
|  | 2cc19e7e32 | ||
|  | 53ab6f8569 | ||
|  | cf8faac7ef | ||
|  | 86947a384d | ||
|  | 22855279bd | ||
|  | e56fdecdc6 | ||
|  | dc75a5812f | ||
|  | 33e20c9969 | ||
|  | 109204897f | ||
|  | 3b3a2d62f8 | ||
|  | b1b4b3fb63 | ||
|  | d583c68de5 | ||
|  | d360f30af6 | ||
|  | ed033565a4 | ||
|  | 2d6acfae1b | ||
|  | 10da894124 | ||
|  | 6dda8f21e4 | ||
|  | 1a9d759002 | ||
|  | df24e13eb5 | ||
|  | 2ab19937af | ||
|  | 390b86cd8e | ||
|  | 423aba5bab | ||
|  | dc0b9231cd | ||
|  | 3b177bedf8 | ||
|  | 12ce719213 | ||
|  | 320433b1bf | ||
|  | 7f35e2280e | ||
|  | c514d988df | ||
|  | 749a080397 | ||
|  | b105a12505 | ||
|  | abaf363ddd | ||
|  | 16db9d4290 | ||
|  | a694b0364d | ||
|  | b68835f171 | ||
|  | 32714c5dac | ||
|  | 245e06f026 | ||
|  | e0111d3fe6 | ||
|  | a71d4223ff | ||
|  | 20cba6411b | ||
|  | 502a8112b5 | ||
|  | 308c6ee4da | ||
|  | cae003d4fa | ||
|  | b9b900e908 | ||
|  | 8bdba9178a | ||
|  | 97f11e38cd | ||
|  | c4f5df0cd0 | ||
|  | 9ed3a6748a | ||
|  | 359c0354f6 | ||
|  | fc77c089fa | ||
|  | 137a7ac48c | ||
|  | 42b60aef4e | ||
|  | 5ab7380ad1 | ||
|  | afa25df1af | ||
|  | 5cb888328e | ||
|  | 78aeb94917 | ||
|  | 5f3e9a19ea | ||
|  | 420e8c001b | ||
|  | c63b8a4ebc | ||
|  | 5f5feaed5f | ||
|  | 87a1f616b0 | ||
|  | cc051544f9 | ||
|  | 85a438a40f | ||
|  | 877260a243 | ||
|  | 83d99043a8 | ||
|  | 6a57d25f4a | ||
|  | 91473e731e | ||
|  | 1d91ac1169 | ||
|  | 2850477a71 | ||
|  | 651b1c92c3 | ||
|  | 77e74eb37b | ||
|  | 5bb2bc7077 | ||
|  | 98a001a8ca | ||
|  | 0d75ff336d | ||
|  | 8567f1655e | ||
|  | 68b94737ed | ||
|  | 094c92ed85 | ||
|  | 42ab6deff1 | ||
|  | 3a257e1e00 | ||
|  | 2bf9a353a6 | ||
|  | bbe41febf1 | ||
|  | 031362a633 | ||
|  | 4418f8bfce | ||
|  | 364175fa9d | ||
|  | 13cf2b48e1 | ||
|  | e4f6694223 | ||
|  | 59093f1721 | ||
|  | db5e79a19b | ||
|  | f0b1585b52 | ||
|  | 50228c5970 | ||
|  | b98e85016a | ||
|  | bc540eefb6 | ||
|  | 3f1c4b4117 | ||
|  | 5e7689a151 | ||
|  | 42845cfcc0 | ||
|  | caad0eca67 | ||
|  | 67f8ec7f87 | ||
|  | d8d37a66e4 | ||
|  | 69db23f2f6 | ||
|  | c3f6bcad56 | ||
|  | ab1521bf26 | ||
|  | fafe8b88c2 | ||
|  | 9276988ff6 | ||
|  | 85179edf1b | ||
|  | 2f1ba6cf1f | ||
|  | 93674b4e29 | ||
|  | 20851664e8 | ||
|  | 38c87a056c | ||
|  | ad77565508 | ||
|  | 0e02e21967 | ||
|  | 1e35a6ce5e | ||
|  | 90b167eba1 | ||
|  | 5b1defad9f | ||
|  | 8dc1ad8168 | ||
|  | 126a42056d | ||
|  | 5866dad79a | ||
|  | 9dac679b72 | ||
|  | 12ff3abeda | ||
|  | 0f07fb4479 | ||
|  | d9d98439b2 | ||
|  | d251a30cb8 | ||
|  | a2632fdcc8 | ||
|  | 10c818474c | ||
|  | 5e8279cf51 | ||
|  | 4c8c081c31 | ||
|  | bad2baba7f | ||
|  | b5da6f9c74 | ||
|  | 7ec999475e | ||
|  | 742bf85a89 | ||
|  | c9c6f41aad | ||
|  | b0d93df387 | ||
|  | 3e20892fdf | ||
|  | 369f8b3fe0 | ||
|  | 337dfba2b8 | ||
|  | 493687b5bb | ||
|  | c7587960fb | ||
|  | 5c962aa899 | ||
|  | 3e9d2a8062 | ||
|  | c2aa8a206a | ||
|  | 6d8ea2b6a4 | ||
|  | b581e33611 | ||
|  | 5e43a02cd3 | ||
|  | 6f37d5ca5c | ||
|  | 3263008379 | ||
|  | 4588089bd6 | ||
|  | 44b75f0b92 | ||
|  | 162bd6a8c3 | ||
|  | 0c13603185 | ||
|  | ed2a45e975 | ||
|  | 0fa165c606 | ||
|  | fe63ab1242 | ||
|  | faf808da69 | ||
|  | 71709cd662 | ||
|  | d92040b804 | ||
|  | 3662fbb462 | ||
|  | d89ae3ebbf | ||
|  | 6175fecdd8 | ||
|  | fab632da62 | ||
|  | c1e3b0d971 | ||
|  | 7b15ba31ea | ||
|  | f11d4ccd45 | ||
|  | fbec803129 | ||
|  | 0f57d1a433 | ||
|  | 63829b6382 | ||
|  | 8ac3899ddc | ||
|  | 59fb4ea6f8 | ||
|  | 92bb9bb3c3 | ||
|  | 1795c491a8 | ||
|  | ea333c19f7 | ||
|  | 28ef879c07 | ||
|  | 10839abf24 | ||
|  | 9832394f8e | ||
|  | dd89ea3731 | ||
|  | 5d9fd6dc3b | ||
|  | f7c87e26db | ||
|  | f98f4085bf | ||
|  | 543519d055 | ||
|  | 5a9fcd9267 | ||
|  | fe2360883f | ||
|  | b45ddadb09 | ||
|  | a3cbe80a36 | ||
|  | ee6c6266cc | ||
|  | d6bd35287f | ||
|  | 962a29110c | ||
|  | a242475b38 | ||
|  | d59bf84470 | ||
|  | 161ee17f45 | ||
|  | 8aa00b0cfc | ||
|  | afe89c3621 | ||
|  | bdf68311b4 | ||
|  | afa69f4c0e | ||
|  | 6fe2b24592 | ||
|  | 7442b356e3 | ||
|  | 1d7be6457f | ||
|  | c9ff05ba80 | ||
|  | faae184f1c | ||
|  | 515a8a9bbb | ||
|  | 58914e5c5f | ||
|  | c944eaab5c | ||
|  | d3d9533493 | ||
|  | 9c474cc089 | ||
|  | 3f1b0b986f | ||
|  | 28e08ebaf5 | ||
|  | 3213c03754 | ||
|  | 4447288a4c | ||
|  | eee4e83a1e | ||
|  | a67b492620 | ||
|  | 6062ff2748 | ||
|  | 3b11195caa | ||
|  | 9946ea111c | ||
|  | 7074d66f8e | ||
|  | 008b26f329 | ||
|  | b246f0779f | ||
|  | dc89218702 | ||
|  | 3c013b3533 | ||
|  | fe0d0f08e4 | ||
|  | 38b5063038 | ||
|  | e55481a454 | ||
|  | 7063a88513 | ||
|  | a9bf3d0226 | ||
|  | 781b3aff1b | ||
|  | b011b9203b | ||
|  | 39344fcae5 | ||
|  | a046b357da | ||
|  | d8e4020cec | ||
|  | f80b172022 | ||
|  | 66fc4b536c | ||
|  | 1f97ccdddb | ||
|  | 308d6889a7 | ||
|  | c3b9982c44 | ||
|  | fab796e4e4 | ||
|  | 749db6ba82 | ||
|  | 12d6c4ddf5 | ||
|  | 430a03bb14 | ||
|  | 43f21fc7aa | ||
|  | b27da3d1a0 | ||
|  | 4463a8e3b2 | ||
|  | 9e74ddac48 | ||
|  | 5f62e41d62 | ||
|  | 19a103d3a0 | ||
|  | 8fb6bc059e | ||
|  | 8f61a0d258 | ||
|  | 7fa589e430 | ||
|  | 6d8d826764 | ||
|  | a40e84e1f6 | ||
|  | 4844c2123f | ||
|  | 236d437430 | ||
|  | ae726c199b | ||
|  | e7f54f005c | ||
|  | e7b1ec6904 | ||
|  | f4f664a4a2 | ||
|  | fec52a8151 | ||
|  | d8b4c1e209 | ||
|  | eac853c7dd | ||
|  | a04337a270 | ||
|  | 50d7e16365 | ||
|  | ef7bc931b7 | ||
|  | 41de771074 | ||
|  | 2ebdd6c5cb | ||
|  | b51cfcc753 | ||
|  | 91cc03dd80 | ||
|  | 9d673a213e | ||
|  | 97e789538e | ||
|  | e05ff01d57 | ||
|  | 0748dff355 | ||
|  | 28d4084aa0 | ||
|  | afd2ccfb4f | ||
|  | 057127f4de | ||
|  | 2937b25d6d | ||
|  | 419f26db87 | ||
|  | be1b9c0e43 | ||
|  | 894d28c60b | ||
|  | 06cc08d9f7 | ||
|  | 75393c0b28 | ||
|  | bdc1da70c1 | ||
|  | 7cef990ba6 | ||
|  | a713c92530 | ||
|  | 1db1ec7b5e | 
							
								
								
									
										2
									
								
								.github/ISSUE_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -28,7 +28,7 @@ To help us understand the issue, please fill-in as much of the following informa | ||||
| ### Please tell us about your environment: | ||||
|  | ||||
| - [ ] Node-RED version: | ||||
| - [ ] node.js version: | ||||
| - [ ] Node.js version: | ||||
| - [ ] npm version: | ||||
| - [ ] Platform/OS: | ||||
| - [ ] Browser: | ||||
|   | ||||
							
								
								
									
										39
									
								
								.github/ISSUE_TEMPLATE/--bug_report.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,39 @@ | ||||
| --- | ||||
| name: Bug report | ||||
| about: Reproducable software issues in the core of Node-RED | ||||
| title: '' | ||||
| labels: '' | ||||
| assignees: '' | ||||
|  | ||||
| --- | ||||
|  | ||||
| <!-- | ||||
| This issue tracker is for problems with the Node-RED runtime, the editor or the core nodes. | ||||
|  | ||||
| If your issue is: | ||||
|   - a general 'how-to' type question, | ||||
|   - a feature request or suggestion for a change, | ||||
|   - or problems with 3rd party (`node-red-contrib-`) nodes | ||||
|  | ||||
| please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack). | ||||
|  | ||||
| You could also consider asking a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/node-red) and tag it `node-red`. | ||||
|  | ||||
| That way the whole Node-RED user community can help, rather than rely on the core development team. | ||||
|  | ||||
| To help us understand the issue, please fill-in as much of the following information as you can: | ||||
| --> | ||||
|  | ||||
| ### What are the steps to reproduce? | ||||
|  | ||||
| ### What happens? | ||||
|  | ||||
| ### What do you expect to happen? | ||||
|  | ||||
| ### Please tell us about your environment: | ||||
|  | ||||
| - [ ] Node-RED version: | ||||
| - [ ] Node.js version: | ||||
| - [ ] npm version: | ||||
| - [ ] Platform/OS: | ||||
| - [ ] Browser: | ||||
							
								
								
									
										17
									
								
								.github/ISSUE_TEMPLATE/-anything-else.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,17 @@ | ||||
| --- | ||||
| name: Anything Else | ||||
| about: Something that is not a bug report | ||||
| title: '' | ||||
| labels: '' | ||||
| assignees: '' | ||||
|  | ||||
| --- | ||||
|  | ||||
| Please DO NOT raise an issue. | ||||
|  | ||||
| We DO NOT use the issue tracker for general support or feature requests. Only bug reports should be raised here using the 'Bug report' template. | ||||
|  | ||||
| For general support, please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack). You could also consider asking a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/node-red) and tag it `node-red`.  | ||||
| That way the whole Node-RED user community can help, rather than rely on the core development team. | ||||
|  | ||||
| For feature requests, please use the Node-RED Forum](https://discourse.nodered.org). Many ideas have already been discussed there and you should search that for your request before starting a new discussion. | ||||
| @@ -2,6 +2,7 @@ sudo: false | ||||
| language: node_js | ||||
| matrix: | ||||
|   include: | ||||
|     - node_js: "12" | ||||
|     - node_js: "10" | ||||
|       script: | ||||
|         - ./node_modules/.bin/grunt && istanbul report text && ( cat coverage/lcov.info | $(npm get prefix)/bin/coveralls || true ) && rm -rf coverage | ||||
|   | ||||
							
								
								
									
										15
									
								
								API.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,15 @@ | ||||
| Node-RED Modules | ||||
| --- | ||||
|  | ||||
| Node-RED provides a set of node modules that implement different parts of the | ||||
| application. | ||||
|  | ||||
| Module | Description | ||||
| -------|------- | ||||
| [node-red](node-red.html) | the main module that pulls together all of the internal modules and provides the executable version of Node-RED | ||||
| [@node-red/editor-api](@node-red_editor-api.html) | an Express application that serves the Node-RED editor and provides the Admin HTTP API | ||||
| [@node-red/runtime](@node-red_runtime.html) | the core runtime of Node-RED | ||||
| [@node-red/util](@node-red_util.html) | common utilities for the Node-RED runtime and editor modules | ||||
| @node-red/registry | the internal node registry | ||||
| @node-red/nodes | the default set of core nodes | ||||
| @node-red/editor-client | the client-side resources of the Node-RED editor application | ||||
							
								
								
									
										343
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						| @@ -1,3 +1,341 @@ | ||||
| #### 1.0.2: Maintenance Release | ||||
|  | ||||
| Runtime | ||||
|  - Allow node.status() to be passed number/bool types | ||||
|  - Allow node emitted events to have multiple arguments | ||||
|  - #2323 Fixed docstrings to have them match the function signature (name of parameters). | ||||
|  - #2318 NLS: Unify translations of "boolean" | ||||
|  | ||||
| Editor | ||||
|  - Ensure node status is refreshed whenever node is edited | ||||
|  - #2315 #2316 Ensure z property included in full message debug payload | ||||
|  - #2321 Fixed editor.json (JA nls) | ||||
|  - #2313 Fix element to collapse items in visual JSON editor | ||||
|  - #2314 Insert divider in menu by calling RED.menu.addItem('id', null); | ||||
|  | ||||
| Nodes | ||||
|  - Change: Fixup use of node.done | ||||
|  - #2322 Template: Fix invalid JSON data in template node docs | ||||
|  - #2320 File: Fixed a typo in 10-file.html (JA nls) | ||||
|  - #2312 Template: Remove unnecessary comma in help text | ||||
|  - #2319 Inject: Interval of inject node should be 596 hours or less. | ||||
|  | ||||
| #### 1.0.1: Maintenance Release | ||||
|  | ||||
| Runtime | ||||
|  - #2301 Add env vars to enable safe mode and projects | ||||
|    - `NODE_RED_ENABLE_SAFE_MODE` | ||||
|    - `NODE_RED_ENABLE_PROJECTS` | ||||
|  | ||||
| Editor | ||||
|  - #2308 Fix grid setting | ||||
|  - #2306 i18n support in tooltips | ||||
|  - Fix error when setting typedInput to boolean true/false | ||||
|  - #2299 Fix SVG icons in IE11 | ||||
|  - #2303 Fix issue where subflow color did not update when not on a flow | ||||
|  | ||||
| Nodes | ||||
|  - #2297 TLS: Allow TLS config node to provide just CA cert | ||||
|  - #2307 Inject: Fix width on inject node property | ||||
|  - #2305 Switch: Let switch node between rule work both ways round | ||||
|  - Range: Add example to range node info and make use of target consistent | ||||
|  - Join: node must clone group message before sending | ||||
|  | ||||
|  | ||||
| #### 1.0.0: Milestone Release | ||||
|  | ||||
| Editor | ||||
|  - Add click-on-tooltip to close | ||||
|  - Fix node draggable handling | ||||
|  - Ensure complete node scope property is remapped on import | ||||
|  - Update i18n for project feature | ||||
|  - Fix menu hiding function for flow editor | ||||
|  - Normalise default subflow color references | ||||
|  - Hide header text of very small screens to deploy is visible | ||||
|  - Fix tab access on touch screens | ||||
|  - Update radialMenu to use standard theme colours | ||||
|  - Fix undefined reference loading on mobile | ||||
|  - Allow word breaking of node name with long word | ||||
|  - Enable wrap mode in Markdown editor | ||||
|  - Maximize the size of markdown editor | ||||
|  | ||||
| Nodes | ||||
|  - remove legacy error option from file in mode | ||||
|  - Change MQTT node default 3.1 compatibility mode to false | ||||
|  - Show clear debug shortcut in tooltip | ||||
|  - Fix file-in port labels for all 4 options | ||||
|  - Add extra comment re Mustache escapes to Template info | ||||
|  - Fix typo in complete node | ||||
|  - Allow Function node output input to go to 0 | ||||
|  | ||||
| #### 1.0.0-beta.4: Beta Release | ||||
|  | ||||
| Runtime | ||||
|  - Clone the first message passed to node.send in Function node | ||||
|  | ||||
| Editor | ||||
|  - Move flow-status button to footer for consistency | ||||
|  - Fix node hover effect to prevent jumping position | ||||
|  - Filter quick-add properly when splicing a wire | ||||
|  - Mark workspace dirty when deleting link node link Fixes #2274 | ||||
|  - Add red-ui-button class to strategy login button | ||||
|  - Fix padding of subflow locale select Closes #2276 | ||||
|  - Update info text of complete node & add JP text | ||||
|  - Add class red-ui-button to cancel button | ||||
|  - Add css class to login submit button (#2275) | ||||
|  - Realign subflow output port labels | ||||
|  - Move context sidebar auto-refresh option to individual sections | ||||
|  - Update Japanese message catalogue | ||||
|  - Fix subflow UI for select | ||||
|  - remove padding before label text for SUBFLOW UI row | ||||
|  - Allow SUBFLOW UI label row without variable name | ||||
|  | ||||
| Nodes | ||||
|  - Remove old rc option from exec node for 1.0 | ||||
|  - Add python and SQL to template language options | ||||
|  - Fix Switch node display of jsonata_exp type | ||||
|  - Remove sentiment from core nodes | ||||
|  | ||||
| #### 1.0.0-beta.3: Beta Release | ||||
|  | ||||
| Runtime | ||||
|  - [FEATURE] Add Node Done API - make message passing async | ||||
|  - Ensure the subflow stop promise is waiting for before restarting | ||||
|  - Limit the regex for the /nodes/ api end points | ||||
|  - Add error event handler to ssh-keygen child_process Fixes #2255 | ||||
|  - Fix default value handling on context array access Fixes #2252 | ||||
|  - Remove all ui test dependencies from package.json | ||||
|  - Add req back to audit log events and extend to Projects api | ||||
|  - Ensure 2nd arg to node.error is an object Fixes #2228 | ||||
|  - Use a more atomic process for writing context files Fixes #2271 | ||||
|  | ||||
|  | ||||
| Editor | ||||
|  - [FEATURE] Change core node categories | ||||
|  - [FEATURE] Subflow Instance property UI (#2236) | ||||
|  - [FEATURE] Add visual JSON editor | ||||
|  - [FEATURE] Add Action List dialog | ||||
|  - [FEATURE] Add new shortcut to clear debug message list - ctrl-alt-l | ||||
|  - [FEATURE] Add show-library dialog actions | ||||
|  - [FEATURE] Add shift-cursor handling for moving quick-add dialog | ||||
|  - [FEATURE] Add enable/disable-flow actions | ||||
|  - [FEATURE] Add actions to change deploy type | ||||
|  - [FEATURE] Allow config nodes to be disabled, tidy css and add actions | ||||
|  - [FEATURE] Add default shortcut (ctrl-d) for deploy | ||||
|  - [FEATURE] Initial implementation of redo (un-undo) - ctrl-y | ||||
|  - [FEATURE] add support for specifying subflow template color | ||||
|  - [FEATURE] Use ctrl-click on wire to splice node in place | ||||
|  - [FEATURE] Allow search results to show more than 25 results | ||||
|  - [FEATURE] Allow a node to change if it has an input port Closes #2268 | ||||
|  - Revealing node position needs to account for zoom level Fixes #2172 | ||||
|  - Fix typedInput option selection Fixes #2174 | ||||
|  - Fix palette node id handling so search works Fixes #2173 | ||||
|  - Add popover tooltips to debug sidebar,function and template | ||||
|  - Add popovers to context sidebar mini buttons | ||||
|  - Ensure node status icon is shown when value set | ||||
|  - Revert treeList children function signature change | ||||
|  - Restore tray component css for compatibility. Mark as deprecated | ||||
|  - fix function name & string compare function | ||||
|  - Handle empty list of example flows Fixes #2171 | ||||
|  - Ensure library list has an item selected when opened | ||||
|  - Ensure tooltip popover doesn't replace normal popover | ||||
|  - Fix clipboard export download button | ||||
|  - Ensure input box has focus on repeated quick add | ||||
|  - Fix width calculation of typedInput | ||||
|  - Remove some hardcoded css colors | ||||
|  - Fix display of node help when clicking in palette Fixes #2194 | ||||
|  - Ensure node help is loaded in the right language Fixes #2195 | ||||
|  - Do not allow tab focus on clipboard hidden element | ||||
|  - Fix undefined error on typedInput due to valueLabel used before being added | ||||
|  - Fix undo of flow disable state change | ||||
|  - Fix select-all action in main view | ||||
|  - Fix delete-all action on config node sidebar | ||||
|  - Update UI tests for new editor css | ||||
|  - Add insertItemAt doc to editableList | ||||
|  - Ensure focus returns to the right element after dialogs shown | ||||
|  - Set autocomplete to disabled in form input elements | ||||
|  - Update all node icons to SVG | ||||
|  - Handle png/svg fallback for def.icon values. Remove old pngs | ||||
|  - Ignore empty examples directories (don't add to import menu) | ||||
|  - better handle example file at any depth - #2222 | ||||
|  - Properly escape node types in palette | ||||
|  - Ensure session expiry timeout doesn't exceed limit | ||||
|  - Use node/tab map to make filterNodes more efficient | ||||
|  - Rearrange contents of subflow template settings tab | ||||
|  - Handle undefined node.\_def in edit stack title. | ||||
|  - fix converting selection to subflow | ||||
|  - Fix inserting new subflow node to existing wire between nodes | ||||
|  - Support displaying falsey node status values Fixes #2246 | ||||
|  - Remove tab menu from node property UI for subflow and config nodes | ||||
|  - Mark workspace dirty when shift-click-drag detaches wires Fixes #2260 | ||||
|  - Fix subflow category change on palette | ||||
|  | ||||
|  | ||||
| Nodes | ||||
|  - Remove pi gpi, twitter, email and feedparser nodes from core | ||||
|  - Fix error handling in Websocket broadcast function Fixes #2182 | ||||
|  - Handle websocket item being parseable but not an object better | ||||
|  - stop join tripping up if last message of buffer is blank. | ||||
|  - Add support for env var propety in switch node | ||||
|  - Improve handling of file upload in request node | ||||
|  - Add "has key" rule to  switch node + tests | ||||
|  - Optimise generation of switch node edit dialog | ||||
|  - Add keep-alive option to HTTP Request - #2261 | ||||
|  | ||||
| #### 1.0.0-beta.2: Beta Release | ||||
|  | ||||
| Runtime | ||||
|  - Fix length calculation when loading library file | ||||
|  | ||||
| #### 1.0.0-beta.1: Beta Release | ||||
|  | ||||
| Runtime | ||||
|  - Update runtime apis to support multiple libraries | ||||
|  - Add Node 12 to travis (allow_failures) | ||||
|  - Bump all dependencies Fixes #2152 | ||||
|  | ||||
| Editor | ||||
|  - [BREAKING] complete overhaul of editor DOM/CSS structure | ||||
|  - [BREAKING] Get rid of Bootstrap | ||||
|  - Simplify index.mst to a single div to insert the editor | ||||
|  - Append node configs to div rather than body | ||||
|  - Only redraw node status when it has changed | ||||
|  - Minimise work done to calculate node label widths | ||||
|  - Allow script tags with src to reference esm modules | ||||
|  - Upgrade to jq 3.4.1 / jq-ui 1.12.1 | ||||
|  - Allow editor language to be chosen in editor settings | ||||
|  - Only NLS status text that starts with a letter Fixes #2128 | ||||
|  - Fix display of link node list within subflow Fixes #2140 | ||||
|  - Blur the active element when closing edit dialog via action Fixes #2097 | ||||
|  - Trigger change evnt on typedInput when type changes and options present Fixes #2160 | ||||
|  - Move library import/export to single dialog | ||||
|  - Move type-library dialogs to new style dialog | ||||
|  - Fix node drag and drop animation | ||||
|  - let status be simple text if wanted | ||||
|  - Add workspace statusBar | ||||
|  - Complete refresh of German translations | ||||
|  - Fix memory leak in Debug sidebar #2163 | ||||
|  - Introduce toggleButton and move flow-disabled to use it | ||||
|  - Allow RED.settings.get/set to use full property desc | ||||
|  - Add auto-refresh toggle to context sidebar | ||||
|  - Add build-custom-theme script | ||||
|  - Add RED.view.selectNodes api for node selection whilst editing | ||||
|  - Add node-select to typedInput | ||||
|  | ||||
| Nodes | ||||
|  - http request node: warn user if msg.requestTimeout == 0 | ||||
|  - hide delay node reset label on deploy | ||||
|  - Fix CSV regex to treat strings starting e as text | ||||
|  - Add "don't parse numbers" option to csv node | ||||
|  - Add expand editor button to Template node | ||||
|  - Update catch/status nodes to use selectNodes api and treeList | ||||
|  | ||||
| #### 0.20.8: Maintenance Release | ||||
|  | ||||
|  - Sanitize tab name in edit dialog | ||||
|  - Pass httpServer to runtime even when httpAdmin disabled Fixes #2272 | ||||
|  | ||||
| #### 0.20.7: Maintenance Release | ||||
|  | ||||
|  - Update jsonata to 1.6.5 which should fix #2183 | ||||
|  - Ensure the subflow stop promise is waiting for before restarting | ||||
|  - Properly escape node types in palette | ||||
|  | ||||
| #### 0.20.6: Maintenance Release | ||||
|  | ||||
|  - Revealing node position needs to account for zoom level Fixes #2172 | ||||
|  - stop join tripping up if last message of buffer is blank. | ||||
|  - Improve handling of file upload in request node | ||||
|  - Handle subflow internal node wired to a non-existant node Fixes #2202 | ||||
|  - Do not save subflow env vars with blank names | ||||
|  - Don't allow a link node virtual wire to connect to normal port | ||||
|  - Clear HTTP Request node authType when auth disabled Fixes #2215 | ||||
|  - Fix parsing of content-type header Fixes #2216 | ||||
|  - Fix join node reset issue with merging objects | ||||
|  - Copy data-i18n attribute on TypedInput Fixes #2211 | ||||
|  | ||||
| #### 0.20.5: Maintenance Release | ||||
|  | ||||
|  - Revert error handling in palette manager | ||||
|  | ||||
| #### 0.20.4: Maintenance Release | ||||
|  | ||||
| - Switch media-typer to content-type module Fixes #2122 #2123 | ||||
| - Use userObj.username and not .name for ssh key lookup Closes #2109 | ||||
| - Ensure mqtt message handlers are tidied up properly on partial deploy | ||||
| - Update package dependencies | ||||
| - Fix encoding menu in file node #2125 | ||||
| - Update ACE to 1.4.3-src-min-noconflict Fixes #2106 | ||||
| - Fix creating missing package.json when existing project imported Fixes #2115 | ||||
| - Allow subflow instance to override env var with falsey values Fixes #2113 | ||||
| - Prevent wire from normal node to link virtual port Fixes #2114 | ||||
| - Add explanation to the help text on the new feature to build query string from msg.payload #2116 | ||||
| - Bump bcrypt to latest | ||||
| - Add Korean locales files for nodes #2100 | ||||
| - Add error message if catalog is invalid json | ||||
| - Reduce udp out timeout to be less than default inject at start #2127 | ||||
|  | ||||
| #### 0.20.3: Maintenance Release | ||||
|  | ||||
| - Do not dynamically add/remove upgrade listener in ws nodes | ||||
| - Avoid env var reference loops and support $parent. prefix Fixes #2099 | ||||
| - Ensure config.\_flow is non-enumerable so is ignored by JSON.stringify | ||||
| - Block loading ACE from cdn | ||||
|  | ||||
| #### 0.20.2: Maintenance Release | ||||
|  | ||||
|  - Filter out duplicate nodes when importing a flow | ||||
|  - Handle node configs with multiple external scripts properly | ||||
|  | ||||
| #### 0.20.1: Maintenance Release | ||||
|  | ||||
|  - Ensure all subflow instances are stopped when flow stopping Fixes #2095 | ||||
|  - modify name of korean locale forders #2091 | ||||
|  - Ensure node names are sanitized before being presented | ||||
|  - Subflow status node must pass status to parent flow Fixes #2087 | ||||
|  - fix problem on displaying option label on Firefox #2090 | ||||
|  | ||||
| #### 0.20.0: Milestone Release | ||||
|  | ||||
| Runtime | ||||
|  - Pass complete status to Status node and filter to editor | ||||
|  - Ensure flows wait for all nodes to close before restarting Fixes #2067 | ||||
|  - Fix git clone with password protected key | ||||
|  - Allow a project to be located below the root of repo | ||||
|  - Detect the cloning of an empty git repo properly | ||||
|  - Fix use of custom auth strategy plugins | ||||
|  - Remove remnants of when library in git/index Fixes #2057 | ||||
|  - Clear subflow status on close | ||||
|  - Add exportGlobalContextKeys to prevent exposing functionGlobalContext keys | ||||
|  - Add --no-audit and --no-update-notifier flags to npm commands to reduce workload | ||||
|  - Add envVarExcludes setting to block named env vars | ||||
|  - Update settings.js docs on userDir to match reality Fixes #2082 | ||||
|  - Add Korean Language | ||||
|  | ||||
|  | ||||
| Editor | ||||
|  - Automatic placing of node icon according to input/output counts | ||||
|  - Transfer placeholder and type to generated TypedInput field | ||||
|  - Hitting enter in Comment node name field clicks markdown button | ||||
|  - Shift status text left if no shape specified | ||||
|  - Better align node status text to status dot | ||||
|  - Handle treeList labels as text not html | ||||
|  - Change subflow edit dialog titles | ||||
|  - Resize subflow edit dialog properly | ||||
|  - Add flow list button to tab bar | ||||
|  - Handle node name as unsanitized text in debug sidebar | ||||
|  | ||||
| Nodes | ||||
|  | ||||
|  - HTTP Request: Add Digest and Bearer Auth modes to http request node (#2061) | ||||
|  - HTTP Request: Add multipart/form-data support to http request node (#2076) | ||||
|  - TCP: include session/event info in status events | ||||
|  - WebSocket: include session/event info in status events | ||||
|  - Add i18n support for port label of inject/exec/httprequest/file nodes | ||||
|  - Join node: handle merged objects with repeated properties and honour parts | ||||
|  - JSON node: handle single booleans and numbers | ||||
|  - File node: add encoding support to file in/out node (#2066) | ||||
|  | ||||
| #### 0.20.0-beta.5: Beta Release | ||||
|  | ||||
| Runtime | ||||
| @@ -194,6 +532,9 @@ Nodes | ||||
|  - Watch: add msg.filename so can feed direct to file in node | ||||
|  - WebSocket: preserve \_session on msg but don't send as part of wholemsg | ||||
|  | ||||
| #### 0.19.6: Maintenance Release | ||||
|  | ||||
|  - Fix encoding of file node from binary to utf8 - #2051 | ||||
|  | ||||
| #### 0.19.5: Maintenance Release | ||||
|  | ||||
| @@ -573,7 +914,7 @@ Nodes | ||||
|  - Initial support of sequence rules for SWITCH node (#1545) | ||||
|  - initial support of SORT node (#1500) | ||||
|  - Inject node - let once delay be editable (#1541) | ||||
|  - Introduce `nodeMaxMessageBufferLength` setting for msg sequence nodes | ||||
|  - Introduce `nodeMessageBufferMaxLength` setting for msg sequence nodes | ||||
|  - Let CSV correct parts if we remove header row. | ||||
|  - let default apply if msg.delay not set in override mode. (#1397) | ||||
|  - let trigger node be reset by boolean message (#1554) | ||||
|   | ||||
| @@ -26,7 +26,7 @@ relevant nodes, press Ctrl-E and copy the flow data from the Export dialog. | ||||
| At a minimum, please include: | ||||
|  | ||||
|  - Version of Node-RED - either release number if you downloaded a zip, or the first few lines of `git log` if you are cloning the repository directly. | ||||
|  - Version of node.js - what does `node -v` say? | ||||
|  - Version of Node.js - what does `node -v` say? | ||||
|  | ||||
| ## Feature requests | ||||
|  | ||||
|   | ||||
							
								
								
									
										60
									
								
								Gruntfile.js
									
									
									
									
									
								
							
							
						
						| @@ -145,11 +145,13 @@ module.exports = function(grunt) { | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/common/tabs.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/common/stack.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/common/toggleButton.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/actions.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/diff.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/keyboard.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/statusBar.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/view.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/view-navigator.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/view-tools.js", | ||||
| @@ -167,6 +169,7 @@ module.exports = function(grunt) { | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/library.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/notifications.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/search.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/actionList.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/userSettings.js", | ||||
| @@ -181,22 +184,22 @@ module.exports = function(grunt) { | ||||
|             vendor: { | ||||
|                 files: { | ||||
|                     "packages/node_modules/@node-red/editor-client/public/vendor/vendor.js": [ | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-1.11.3.min.js", | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/bootstrap/js/bootstrap.min.js", | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-ui-1.10.3.custom.min.js", | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-3.4.1.min.js", | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-migrate-3.0.1.min.js", | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-ui.min.js", | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery.ui.touch-punch.min.js", | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/marked/marked.min.js", | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/d3/d3.v3.min.js", | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/i18next/i18next.min.js" | ||||
|                     ], | ||||
|                     "packages/node_modules/@node-red/editor-client/public/vendor/vendor.css": [ | ||||
|                         // TODO: resolve relative resource paths in | ||||
|                         //       bootstrap/FA/jquery | ||||
|                     ], | ||||
|                     "packages/node_modules/@node-red/editor-client/public/vendor/jsonata/jsonata.min.js": [ | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/i18next/i18next.min.js", | ||||
|                         "node_modules/jsonata/jsonata-es5.min.js", | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/jsonata/formatter.js" | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/jsonata/formatter.js", | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/ace/ace.js", | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/ace/ext-language_tools.js", | ||||
|                     ], | ||||
|                     // "packages/node_modules/@node-red/editor-client/public/vendor/vendor.css": [ | ||||
|                     //     // TODO: resolve relative resource paths in | ||||
|                     //     //       bootstrap/FA/jquery | ||||
|                     // ], | ||||
|                     "packages/node_modules/@node-red/editor-client/public/vendor/ace/worker-jsonata.js": [ | ||||
|                         "node_modules/jsonata/jsonata-es5.min.js", | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/jsonata/worker-jsonata.js" | ||||
| @@ -222,10 +225,6 @@ module.exports = function(grunt) { | ||||
|                 files: [{ | ||||
|                     dest: 'packages/node_modules/@node-red/editor-client/public/red/style.min.css', | ||||
|                     src: 'packages/node_modules/@node-red/editor-client/src/sass/style.scss' | ||||
|                 }, | ||||
|                 { | ||||
|                     dest: 'packages/node_modules/@node-red/editor-client/public/vendor/bootstrap/css/bootstrap.min.css', | ||||
|                     src: 'packages/node_modules/@node-red/editor-client/src/vendor/bootstrap/css/bootstrap.css' | ||||
|                 }] | ||||
|             } | ||||
|         }, | ||||
| @@ -277,7 +276,7 @@ module.exports = function(grunt) { | ||||
|                 files: [ | ||||
|                     'packages/node_modules/@node-red/editor-client/src/js/**/*.js' | ||||
|                 ], | ||||
|                 tasks: ['copy:build','concat','uglify','attachCopyright:js'] | ||||
|                 tasks: ['copy:build','concat',/*'uglify',*/ 'attachCopyright:js'] | ||||
|             }, | ||||
|             sass: { | ||||
|                 files: [ | ||||
| @@ -352,9 +351,7 @@ module.exports = function(grunt) { | ||||
|                         cwd: 'packages/node_modules/@node-red/editor-client/src/vendor', | ||||
|                         src: [ | ||||
|                             'ace/**', | ||||
|                             //'bootstrap/css/**', | ||||
|                             'bootstrap/img/**', | ||||
|                             'jquery/css/**', | ||||
|                             'jquery/css/base/**', | ||||
|                             'font-awesome/**' | ||||
|                         ], | ||||
|                         expand: true, | ||||
| @@ -438,6 +435,7 @@ module.exports = function(grunt) { | ||||
|         jsdoc : { | ||||
|             modules: { | ||||
|                 src: [ | ||||
|                     'API.md', | ||||
|                     'packages/node_modules/node-red/lib/red.js', | ||||
|                     'packages/node_modules/@node-red/runtime/lib/index.js', | ||||
|                     'packages/node_modules/@node-red/runtime/lib/api/*.js', | ||||
| @@ -451,7 +449,7 @@ module.exports = function(grunt) { | ||||
|                     configure: './jsdoc.json' | ||||
|                 } | ||||
|             }, | ||||
|             editor: { | ||||
|             _editor: { | ||||
|                 src: [ | ||||
|                     'packages/node_modules/@node-red/editor-client/src/js' | ||||
|                     ], | ||||
| @@ -498,7 +496,9 @@ module.exports = function(grunt) { | ||||
|     grunt.loadNpmTasks('grunt-chmod'); | ||||
|     grunt.loadNpmTasks('grunt-jsonlint'); | ||||
|     grunt.loadNpmTasks('grunt-mocha-istanbul'); | ||||
|     grunt.loadNpmTasks('grunt-webdriver'); | ||||
|     if (fs.existsSync(path.join("node_modules", "grunt-webdriver"))) { | ||||
|         grunt.loadNpmTasks('grunt-webdriver'); | ||||
|     } | ||||
|     grunt.loadNpmTasks('grunt-jsdoc'); | ||||
|     grunt.loadNpmTasks('grunt-jsdoc-to-markdown'); | ||||
|     grunt.loadNpmTasks('grunt-npm-command'); | ||||
| @@ -557,8 +557,8 @@ module.exports = function(grunt) { | ||||
|     }); | ||||
|  | ||||
|     grunt.registerTask('verifyUiTestDependencies', function() { | ||||
|         if (!fs.existsSync(path.join("node_modules", "chromedriver"))) { | ||||
|             grunt.fail.fatal('You need to run "npm install chromedriver@2" before running UI test.'); | ||||
|         if (!fs.existsSync(path.join("node_modules", "grunt-webdriver"))) { | ||||
|             grunt.fail.fatal('You need to install the UI test dependencies first.\nUse the script in "scripts/install-ui-test-dependencies.sh"'); | ||||
|             return false; | ||||
|         } | ||||
|     }); | ||||
| @@ -581,9 +581,15 @@ module.exports = function(grunt) { | ||||
|         'Runs code style check on editor code', | ||||
|         ['jshint:editor']); | ||||
|  | ||||
|     grunt.registerTask('test-ui', | ||||
|         'Builds editor content then runs unit tests on editor ui', | ||||
|         ['verifyUiTestDependencies','build','jshint:editor','webdriver:all']); | ||||
|     if (!fs.existsSync(path.join("node_modules", "grunt-webdriver"))) { | ||||
|         grunt.registerTask('test-ui', | ||||
|             'Builds editor content then runs unit tests on editor ui', | ||||
|             ['verifyUiTestDependencies']); | ||||
|     } else { | ||||
|         grunt.registerTask('test-ui', | ||||
|             'Builds editor content then runs unit tests on editor ui', | ||||
|             ['verifyUiTestDependencies','build','jshint:editor','webdriver:all']); | ||||
|     } | ||||
|  | ||||
|     grunt.registerTask('test-nodes', | ||||
|         'Runs unit tests on core nodes', | ||||
| @@ -612,5 +618,5 @@ module.exports = function(grunt) { | ||||
|  | ||||
|     grunt.registerTask('docs', | ||||
|         'Generates API documentation', | ||||
|         ['jsdoc','jsdoc2md']); | ||||
|         ['jsdoc']); | ||||
| }; | ||||
|   | ||||
| @@ -5,9 +5,9 @@ http://nodered.org | ||||
| [](https://travis-ci.org/node-red/node-red) | ||||
| [](https://coveralls.io/r/node-red/node-red?branch=master) | ||||
|  | ||||
| A visual tool for wiring the Internet of Things. | ||||
| Low-code programming for event-driven applications. | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| ## Quick Start | ||||
|  | ||||
| @@ -56,7 +56,7 @@ This project adheres to the [Contributor Covenant 1.4](http://contributor-covena | ||||
|  | ||||
| ## Authors | ||||
|  | ||||
| Node-RED is a project of the [JS Foundation](http://js.foundation). | ||||
| Node-RED is a project of the [OpenJS Foundation](https://openjsf.org). | ||||
|  | ||||
| It was created by [IBM Emerging Technology](https://www.ibm.com/blogs/emerging-technology/). | ||||
|  | ||||
| @@ -67,4 +67,4 @@ It was created by [IBM Emerging Technology](https://www.ibm.com/blogs/emerging-t | ||||
|  | ||||
| ## Copyright and license | ||||
|  | ||||
| Copyright JS Foundation and other contributors, http://js.foundation under [the Apache 2.0 license](LICENSE). | ||||
| Copyright JS Foundation and other contributors, https://openjsf.org under [the Apache 2.0 license](LICENSE). | ||||
|   | ||||
							
								
								
									
										13
									
								
								SECURITY.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,13 @@ | ||||
| # Security Policy | ||||
|  | ||||
| ## Supported Versions | ||||
|  | ||||
| | Version | Supported          | | ||||
| | ------- | ------------------ | | ||||
| | 1.0.0   | :white_check_mark: | | ||||
| | 0.20.x  | :white_check_mark: | | ||||
|  | ||||
|  | ||||
| ## Reporting a Vulnerability | ||||
|  | ||||
| Please report any potential security issues to `team@nodered.org`. This will notify the core project team who will respond accordingly. | ||||
							
								
								
									
										84
									
								
								package.json
									
									
									
									
									
								
							
							
						
						| @@ -1,7 +1,7 @@ | ||||
| { | ||||
|     "name": "node-red", | ||||
|     "version": "0.20.0-beta.5", | ||||
|     "description": "A visual tool for wiring the Internet of Things", | ||||
|     "version": "1.0.2", | ||||
|     "description": "Low-code programming for event-driven applications", | ||||
|     "homepage": "http://nodered.org", | ||||
|     "license": "Apache-2.0", | ||||
|     "repository": { | ||||
| @@ -24,79 +24,77 @@ | ||||
|         } | ||||
|     ], | ||||
|     "dependencies": { | ||||
|         "ajv": "6.8.1", | ||||
|         "ajv": "6.10.2", | ||||
|         "basic-auth": "2.0.1", | ||||
|         "bcryptjs": "2.4.3", | ||||
|         "body-parser": "1.18.3", | ||||
|         "body-parser": "1.19.0", | ||||
|         "cheerio": "0.22.0", | ||||
|         "clone": "2.1.2", | ||||
|         "cookie": "0.3.1", | ||||
|         "cookie-parser": "1.4.3", | ||||
|         "content-type": "1.0.4", | ||||
|         "cookie": "0.4.0", | ||||
|         "cookie-parser": "1.4.4", | ||||
|         "cors": "2.8.5", | ||||
|         "cron": "1.6.0", | ||||
|         "denque": "1.4.0", | ||||
|         "express": "4.16.4", | ||||
|         "express-session": "1.15.6", | ||||
|         "fs-extra": "7.0.1", | ||||
|         "cron": "1.7.1", | ||||
|         "denque": "1.4.1", | ||||
|         "express": "4.17.1", | ||||
|         "express-session": "1.16.2", | ||||
|         "fs-extra": "8.1.0", | ||||
|         "fs.notify": "0.0.4", | ||||
|         "hash-sum": "1.0.2", | ||||
|         "https-proxy-agent": "2.2.1", | ||||
|         "i18next": "14.1.1", | ||||
|         "hash-sum": "2.0.0", | ||||
|         "https-proxy-agent": "2.2.2", | ||||
|         "i18next": "15.1.2", | ||||
|         "iconv-lite": "0.5.0", | ||||
|         "is-utf8": "0.2.1", | ||||
|         "js-yaml": "3.12.1", | ||||
|         "js-yaml": "3.13.1", | ||||
|         "json-stringify-safe": "5.0.1", | ||||
|         "jsonata": "1.6.4", | ||||
|         "media-typer": "1.0.1", | ||||
|         "memorystore": "1.6.0", | ||||
|         "mime": "2.4.0", | ||||
|         "jsonata": "1.6.5", | ||||
|         "media-typer": "1.1.0", | ||||
|         "memorystore": "1.6.1", | ||||
|         "mime": "2.4.4", | ||||
|         "mqtt": "2.18.8", | ||||
|         "multer": "1.4.1", | ||||
|         "mustache": "3.0.1", | ||||
|         "node-red-node-email": "1.0.*", | ||||
|         "node-red-node-feedparser": "^0.1.14", | ||||
|         "node-red-node-rbe": "0.2.*", | ||||
|         "node-red-node-sentiment": "^0.1.0", | ||||
|         "node-red-node-tail": "^0.0.2", | ||||
|         "node-red-node-twitter": "^1.1.0", | ||||
|         "multer": "1.4.2", | ||||
|         "mustache": "3.0.2", | ||||
|         "node-red-node-rbe": "^0.2.5", | ||||
|         "node-red-node-sentiment": "^0.1.4", | ||||
|         "node-red-node-tail": "^0.0.3", | ||||
|         "nopt": "4.0.1", | ||||
|         "oauth2orize": "1.11.0", | ||||
|         "on-headers": "1.0.1", | ||||
|         "on-headers": "1.0.2", | ||||
|         "passport": "0.4.0", | ||||
|         "passport-http-bearer": "1.0.1", | ||||
|         "passport-oauth2-client-password": "0.1.2", | ||||
|         "raw-body": "2.3.3", | ||||
|         "raw-body": "2.4.1", | ||||
|         "request": "2.88.0", | ||||
|         "semver": "5.6.0", | ||||
|         "uglify-js": "3.4.9", | ||||
|         "semver": "6.3.0", | ||||
|         "uglify-js": "3.6.0", | ||||
|         "when": "3.7.8", | ||||
|         "ws": "6.1.3", | ||||
|         "ws": "6.2.1", | ||||
|         "xml2js": "0.4.19" | ||||
|     }, | ||||
|     "optionalDependencies": { | ||||
|         "bcrypt": "~2.0.0" | ||||
|         "bcrypt": "3.0.6" | ||||
|     }, | ||||
|     "devDependencies": { | ||||
|         "grunt": "~1.0.3", | ||||
|         "grunt": "~1.0.4", | ||||
|         "grunt-chmod": "~1.1.1", | ||||
|         "grunt-cli": "~1.3.2", | ||||
|         "grunt-concurrent": "~2.3.1", | ||||
|         "grunt-contrib-clean": "~1.1.0", | ||||
|         "grunt-contrib-compress": "~1.4.0", | ||||
|         "grunt-contrib-clean": "~2.0.0", | ||||
|         "grunt-contrib-compress": "~1.5.0", | ||||
|         "grunt-contrib-concat": "~1.0.1", | ||||
|         "grunt-contrib-copy": "~1.0.0", | ||||
|         "grunt-contrib-jshint": "~1.1.0", | ||||
|         "grunt-contrib-uglify": "~3.4.0", | ||||
|         "grunt-contrib-jshint": "~2.1.0", | ||||
|         "grunt-contrib-uglify": "~4.0.1", | ||||
|         "grunt-contrib-watch": "~1.1.0", | ||||
|         "grunt-jsdoc": "^2.2.1", | ||||
|         "grunt-jsdoc-to-markdown": "^4.0.0", | ||||
|         "grunt-jsonlint": "~1.1.0", | ||||
|         "grunt-jsonlint": "~2.0.0", | ||||
|         "grunt-mkdir": "~1.0.0", | ||||
|         "grunt-mocha-istanbul": "5.0.2", | ||||
|         "grunt-nodemon": "~0.4.2", | ||||
|         "grunt-npm-command": "~0.1.2", | ||||
|         "grunt-sass": "~2.0.0", | ||||
|         "grunt-simple-mocha": "~0.4.1", | ||||
|         "grunt-webdriver": "^2.0.3", | ||||
|         "http-proxy": "^1.16.2", | ||||
|         "istanbul": "0.4.5", | ||||
|         "minami": "1.2.3", | ||||
| @@ -106,11 +104,7 @@ | ||||
|         "sinon": "1.17.7", | ||||
|         "stoppable": "^1.1.0", | ||||
|         "supertest": "3.4.2", | ||||
|         "wdio-chromedriver-service": "^0.1.5", | ||||
|         "wdio-mocha-framework": "^0.6.4", | ||||
|         "wdio-spec-reporter": "^0.1.5", | ||||
|         "webdriverio": "^4.14.1", | ||||
|         "node-red-node-test-helper": "node-red/node-red-node-test-helper", | ||||
|         "node-red-node-test-helper": "^0.2.3", | ||||
|         "jsdoc-nr-template": "node-red/jsdoc-nr-template" | ||||
|     }, | ||||
|     "engines": { | ||||
|   | ||||
| @@ -30,7 +30,8 @@ module.exports = { | ||||
|             scope: req.params.scope, | ||||
|             id: req.params.id, | ||||
|             key: req.params[0], | ||||
|             store: req.query['store'] | ||||
|             store: req.query['store'], | ||||
|             req: apiUtils.getRequestLogObject(req) | ||||
|         } | ||||
|         runtimeAPI.context.getValue(opts).then(function(result) { | ||||
|             res.json(result); | ||||
| @@ -45,7 +46,8 @@ module.exports = { | ||||
|             scope: req.params.scope, | ||||
|             id: req.params.id, | ||||
|             key: req.params[0], | ||||
|             store: req.query['store'] | ||||
|             store: req.query['store'], | ||||
|             req: apiUtils.getRequestLogObject(req) | ||||
|         } | ||||
|         runtimeAPI.context.delete(opts).then(function(result) { | ||||
|             res.status(204).end(); | ||||
|   | ||||
| @@ -24,7 +24,8 @@ module.exports = { | ||||
|     get: function(req,res) { | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             id: req.params.id | ||||
|             id: req.params.id, | ||||
|             req: apiUtils.getRequestLogObject(req) | ||||
|         } | ||||
|         runtimeAPI.flows.getFlow(opts).then(function(result) { | ||||
|             return res.json(result); | ||||
| @@ -35,7 +36,8 @@ module.exports = { | ||||
|     post: function(req,res) { | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             flow: req.body | ||||
|             flow: req.body, | ||||
|             req: apiUtils.getRequestLogObject(req) | ||||
|         } | ||||
|         runtimeAPI.flows.addFlow(opts).then(function(id) { | ||||
|             return res.json({id:id}); | ||||
| @@ -47,7 +49,8 @@ module.exports = { | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             id: req.params.id, | ||||
|             flow: req.body | ||||
|             flow: req.body, | ||||
|             req: apiUtils.getRequestLogObject(req) | ||||
|         } | ||||
|         runtimeAPI.flows.updateFlow(opts).then(function(id) { | ||||
|             return res.json({id:id}); | ||||
| @@ -58,7 +61,8 @@ module.exports = { | ||||
|     delete: function(req,res) { | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             id: req.params.id | ||||
|             id: req.params.id, | ||||
|             req: apiUtils.getRequestLogObject(req) | ||||
|         } | ||||
|         runtimeAPI.flows.deleteFlow(opts).then(function() { | ||||
|             res.status(204).end(); | ||||
|   | ||||
| @@ -27,7 +27,8 @@ module.exports = { | ||||
|             return res.status(400).json({code:"invalid_api_version", message:"Invalid API Version requested"}); | ||||
|         } | ||||
|         var opts = { | ||||
|             user: req.user | ||||
|             user: req.user, | ||||
|             req: apiUtils.getRequestLogObject(req) | ||||
|         } | ||||
|         runtimeAPI.flows.getFlows(opts).then(function(result) { | ||||
|             if (version === "v1") { | ||||
| @@ -46,7 +47,8 @@ module.exports = { | ||||
|         } | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             deploymentType: req.get("Node-RED-Deployment-Type")||"full" | ||||
|             deploymentType: req.get("Node-RED-Deployment-Type")||"full", | ||||
|             req: apiUtils.getRequestLogObject(req) | ||||
|         } | ||||
|  | ||||
|         if (opts.deploymentType !== 'reload') { | ||||
|   | ||||
| @@ -48,13 +48,13 @@ module.exports = { | ||||
|         // Nodes | ||||
|         adminApp.get("/nodes",needsPermission("nodes.read"),nodes.getAll,apiUtil.errorHandler); | ||||
|         adminApp.post("/nodes",needsPermission("nodes.write"),nodes.post,apiUtil.errorHandler); | ||||
|         adminApp.get(/\/nodes\/messages/,needsPermission("nodes.read"),nodes.getModuleCatalogs,apiUtil.errorHandler); | ||||
|         adminApp.get(/\/nodes\/((@[^\/]+\/)?[^\/]+\/[^\/]+)\/messages/,needsPermission("nodes.read"),nodes.getModuleCatalog,apiUtil.errorHandler); | ||||
|         adminApp.get(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.read"),nodes.getModule,apiUtil.errorHandler); | ||||
|         adminApp.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.write"),nodes.putModule,apiUtil.errorHandler); | ||||
|         adminApp.delete(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.write"),nodes.delete,apiUtil.errorHandler); | ||||
|         adminApp.get(/\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,needsPermission("nodes.read"),nodes.getSet,apiUtil.errorHandler); | ||||
|         adminApp.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,needsPermission("nodes.write"),nodes.putSet,apiUtil.errorHandler); | ||||
|         adminApp.get(/^\/nodes\/messages/,needsPermission("nodes.read"),nodes.getModuleCatalogs,apiUtil.errorHandler); | ||||
|         adminApp.get(/^\/nodes\/((@[^\/]+\/)?[^\/]+\/[^\/]+)\/messages/,needsPermission("nodes.read"),nodes.getModuleCatalog,apiUtil.errorHandler); | ||||
|         adminApp.get(/^\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.read"),nodes.getModule,apiUtil.errorHandler); | ||||
|         adminApp.put(/^\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.write"),nodes.putModule,apiUtil.errorHandler); | ||||
|         adminApp.delete(/^\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.write"),nodes.delete,apiUtil.errorHandler); | ||||
|         adminApp.get(/^\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,needsPermission("nodes.read"),nodes.getSet,apiUtil.errorHandler); | ||||
|         adminApp.put(/^\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,needsPermission("nodes.write"),nodes.putSet,apiUtil.errorHandler); | ||||
|  | ||||
|         // Context | ||||
|         adminApp.get("/context/:scope(global)",needsPermission("context.read"),context.get,apiUtil.errorHandler); | ||||
|   | ||||
| @@ -24,7 +24,8 @@ module.exports = { | ||||
|     }, | ||||
|     getAll: function(req,res) { | ||||
|         var opts = { | ||||
|             user: req.user | ||||
|             user: req.user, | ||||
|             req: apiUtils.getRequestLogObject(req) | ||||
|         } | ||||
|         if (req.get("accept") == "application/json") { | ||||
|             runtimeAPI.nodes.getNodeList(opts).then(function(list) { | ||||
| @@ -42,7 +43,8 @@ module.exports = { | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             module: req.body.module, | ||||
|             version: req.body.version | ||||
|             version: req.body.version, | ||||
|             req: apiUtils.getRequestLogObject(req) | ||||
|         } | ||||
|         runtimeAPI.nodes.addModule(opts).then(function(info) { | ||||
|             res.json(info); | ||||
| @@ -54,7 +56,8 @@ module.exports = { | ||||
|     delete: function(req,res) { | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             module: req.params[0] | ||||
|             module: req.params[0], | ||||
|             req: apiUtils.getRequestLogObject(req) | ||||
|         } | ||||
|         runtimeAPI.nodes.removeModule(opts).then(function() { | ||||
|             res.status(204).end(); | ||||
| @@ -66,7 +69,8 @@ module.exports = { | ||||
|     getSet: function(req,res) { | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             id: req.params[0] + "/" + req.params[2] | ||||
|             id: req.params[0] + "/" + req.params[2], | ||||
|             req: apiUtils.getRequestLogObject(req) | ||||
|         } | ||||
|         if (req.get("accept") === "application/json") { | ||||
|             runtimeAPI.nodes.getNodeInfo(opts).then(function(result) { | ||||
| @@ -87,7 +91,8 @@ module.exports = { | ||||
|     getModule: function(req,res) { | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             module: req.params[0] | ||||
|             module: req.params[0], | ||||
|             req: apiUtils.getRequestLogObject(req) | ||||
|         } | ||||
|         runtimeAPI.nodes.getModuleInfo(opts).then(function(result) { | ||||
|             res.send(result); | ||||
| @@ -106,7 +111,8 @@ module.exports = { | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             id: req.params[0] + "/" + req.params[2], | ||||
|             enabled: body.enabled | ||||
|             enabled: body.enabled, | ||||
|             req: apiUtils.getRequestLogObject(req) | ||||
|         } | ||||
|         runtimeAPI.nodes.setNodeSetState(opts).then(function(result) { | ||||
|             res.send(result); | ||||
| @@ -125,7 +131,8 @@ module.exports = { | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             module: req.params[0], | ||||
|             enabled: body.enabled | ||||
|             enabled: body.enabled, | ||||
|             req: apiUtils.getRequestLogObject(req) | ||||
|         } | ||||
|         runtimeAPI.nodes.setModuleState(opts).then(function(result) { | ||||
|             res.send(result); | ||||
| @@ -139,7 +146,8 @@ module.exports = { | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             module: req.params[0], | ||||
|             lang: req.query.lng | ||||
|             lang: req.query.lng, | ||||
|             req: apiUtils.getRequestLogObject(req) | ||||
|         } | ||||
|         runtimeAPI.nodes.getModuleCatalog(opts).then(function(result) { | ||||
|             res.json(result); | ||||
| @@ -152,7 +160,8 @@ module.exports = { | ||||
|     getModuleCatalogs: function(req,res) { | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             lang: req.query.lng | ||||
|             lang: req.query.lng, | ||||
|             req: apiUtils.getRequestLogObject(req) | ||||
|         } | ||||
|         runtimeAPI.nodes.getModuleCatalogs(opts).then(function(result) { | ||||
|             res.json(result); | ||||
| @@ -164,7 +173,8 @@ module.exports = { | ||||
|  | ||||
|     getIcons: function(req,res) { | ||||
|         var opts = { | ||||
|             user: req.user | ||||
|             user: req.user, | ||||
|             req: apiUtils.getRequestLogObject(req) | ||||
|         } | ||||
|         runtimeAPI.nodes.getIconList(opts).then(function(list) { | ||||
|             res.json(list); | ||||
|   | ||||
| @@ -199,7 +199,7 @@ function genericStrategy(adminApp,strategy) { | ||||
|     if (/^post$/i.test(options.callbackMethod)) { | ||||
|         callbackMethodFunc = adminApp.post; | ||||
|     } | ||||
|     callbackMethodFunc('/auth/strategy/callback', | ||||
|     callbackMethodFunc.call(adminApp,'/auth/strategy/callback', | ||||
|         passport.authenticate(strategy.name, {session:false, failureRedirect: settings.httpAdminRoot }), | ||||
|         completeGenerateStrategyAuth | ||||
|     ); | ||||
|   | ||||
| @@ -56,7 +56,7 @@ function expireSessions() { | ||||
|     } | ||||
|     if (nextExpiry < Number.MAX_SAFE_INTEGER) { | ||||
|         // Allow 5 seconds grace | ||||
|         expiryTimeout = setTimeout(expireSessions,(nextExpiry - Date.now()) + 5000) | ||||
|         expiryTimeout = setTimeout(expireSessions,Math.min(2147483647,(nextExpiry - Date.now()) + 5000)) | ||||
|     } | ||||
|     if (modified) { | ||||
|         return storage.saveSessions(sessions); | ||||
| @@ -129,7 +129,7 @@ module.exports = { | ||||
|             sessions[accessToken] = session; | ||||
|  | ||||
|             if (!expiryTimeout) { | ||||
|                 expiryTimeout = setTimeout(expireSessions,(accessTokenExpiresAt - Date.now()) + 5000) | ||||
|                 expiryTimeout = setTimeout(expireSessions,Math.min(2147483647,(accessTokenExpiresAt - Date.now()) + 5000)) | ||||
|             } | ||||
|  | ||||
|             return storage.saveSessions(sessions).then(function() { | ||||
|   | ||||
| @@ -25,8 +25,8 @@ var auth = require("../auth"); | ||||
| var nodes = require("../admin/nodes"); // TODO: move /icons into here | ||||
| var needsPermission; | ||||
| var runtimeAPI; | ||||
| var log = require("@node-red/util").log; // TODO: separate module | ||||
| var i18n = require("@node-red/util").i18n; // TODO: separate module | ||||
| var log = require("@node-red/util").log; | ||||
| var i18n = require("@node-red/util").i18n; | ||||
|  | ||||
| var apiUtil = require("../util"); | ||||
|  | ||||
| @@ -93,9 +93,8 @@ module.exports = { | ||||
|             // Library | ||||
|             var library = require("./library"); | ||||
|             library.init(runtimeAPI); | ||||
|             editorApp.get("/library/flows",needsPermission("library.read"),library.getAll,apiUtil.errorHandler); | ||||
|             editorApp.get(/library\/([^\/]+)(?:$|\/(.*))/,needsPermission("library.read"),library.getEntry); | ||||
|             editorApp.post(/library\/([^\/]+)\/(.*)/,needsPermission("library.write"),library.saveEntry); | ||||
|             editorApp.get(/library\/([^\/]+)\/([^\/]+)(?:$|\/(.*))/,needsPermission("library.read"),library.getEntry); | ||||
|             editorApp.post(/library\/([^\/]+)\/([^\/]+)\/(.*)/,needsPermission("library.write"),library.saveEntry); | ||||
|  | ||||
|  | ||||
|             // Credentials | ||||
|   | ||||
| @@ -25,23 +25,12 @@ module.exports = { | ||||
|     init: function(_runtimeAPI) { | ||||
|         runtimeAPI = _runtimeAPI; | ||||
|     }, | ||||
|  | ||||
|     getAll: function(req,res) { | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             type: 'flows' | ||||
|         } | ||||
|         runtimeAPI.library.getEntries(opts).then(function(result) { | ||||
|             res.json(result); | ||||
|         }).catch(function(err) { | ||||
|             apiUtils.rejectHandler(req,res,err); | ||||
|         }); | ||||
|     }, | ||||
|     getEntry: function(req,res) { | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             type: req.params[0], | ||||
|             path: req.params[1]||"" | ||||
|             library: req.params[0], | ||||
|             type: req.params[1], | ||||
|             path: req.params[2]||"" | ||||
|         } | ||||
|         runtimeAPI.library.getEntry(opts).then(function(result) { | ||||
|             if (typeof result === "string") { | ||||
| @@ -62,8 +51,9 @@ module.exports = { | ||||
|     saveEntry: function(req,res) { | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             type: req.params[0], | ||||
|             path: req.params[1]||"" | ||||
|             library: req.params[0], | ||||
|             type: req.params[1], | ||||
|             path: req.params[2]||"" | ||||
|         } | ||||
|         // TODO: horrible inconsistencies between flows and all other types | ||||
|         if (opts.type === "flows") { | ||||
|   | ||||
| @@ -22,7 +22,8 @@ var needsPermission = require("../auth").needsPermission; | ||||
|  | ||||
| function listProjects(req,res) { | ||||
|     var opts = { | ||||
|         user: req.user | ||||
|         user: req.user, | ||||
|         req: apiUtils.getRequestLogObject(req) | ||||
|     } | ||||
|     runtimeAPI.projects.listProjects(opts).then(function(result) { | ||||
|         res.json(result); | ||||
| @@ -33,7 +34,8 @@ function listProjects(req,res) { | ||||
| function getProject(req,res) { | ||||
|     var opts = { | ||||
|         user: req.user, | ||||
|         id: req.params.id | ||||
|         id: req.params.id, | ||||
|         req: apiUtils.getRequestLogObject(req) | ||||
|     } | ||||
|     runtimeAPI.projects.getProject(opts).then(function(data) { | ||||
|         if (data) { | ||||
| @@ -49,7 +51,8 @@ function getProjectStatus(req,res) { | ||||
|     var opts = { | ||||
|         user: req.user, | ||||
|         id: req.params.id, | ||||
|         remote: req.query.remote | ||||
|         remote: req.query.remote, | ||||
|         req: apiUtils.getRequestLogObject(req) | ||||
|     } | ||||
|     runtimeAPI.projects.getStatus(opts).then(function(data){ | ||||
|         if (data) { | ||||
| @@ -64,7 +67,8 @@ function getProjectStatus(req,res) { | ||||
| function getProjectRemotes(req,res) { | ||||
|     var opts = { | ||||
|         user: req.user, | ||||
|         id: req.params.id | ||||
|         id: req.params.id, | ||||
|         req: apiUtils.getRequestLogObject(req) | ||||
|     } | ||||
|     runtimeAPI.projects.getRemotes(opts).then(function(data) { | ||||
|         res.json(data); | ||||
| @@ -98,7 +102,8 @@ module.exports = { | ||||
|         app.post("/", needsPermission("projects.write"), function(req,res) { | ||||
|             var opts = { | ||||
|                 user: req.user, | ||||
|                 project: req.body | ||||
|                 project: req.body, | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.createProject(opts).then(function(result) { | ||||
|                 res.json(result); | ||||
| @@ -112,7 +117,8 @@ module.exports = { | ||||
|             var opts = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id, | ||||
|                 project: req.body | ||||
|                 project: req.body, | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|  | ||||
|             if (req.body.active) { | ||||
| @@ -150,7 +156,8 @@ module.exports = { | ||||
|         app.delete("/:id", needsPermission("projects.write"), function(req,res) { | ||||
|             var opts = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id | ||||
|                 id: req.params.id, | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.deleteProject(opts).then(function() { | ||||
|                 res.status(204).end(); | ||||
| @@ -168,7 +175,8 @@ module.exports = { | ||||
|         app.get("/:id/files", needsPermission("projects.read"), function(req,res) { | ||||
|             var opts = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id | ||||
|                 id: req.params.id, | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.getFiles(opts).then(function(data) { | ||||
|                 res.json(data); | ||||
| @@ -185,7 +193,8 @@ module.exports = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id, | ||||
|                 path: req.params[0], | ||||
|                 tree: req.params.treeish | ||||
|                 tree: req.params.treeish, | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.getFile(opts).then(function(data) { | ||||
|                 res.json({content:data}); | ||||
| @@ -199,7 +208,8 @@ module.exports = { | ||||
|             var opts = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id, | ||||
|                 path: req.params[0] | ||||
|                 path: req.params[0], | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|  | ||||
|             runtimeAPI.projects.revertFile(opts).then(function() { | ||||
| @@ -214,7 +224,8 @@ module.exports = { | ||||
|             var opts = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id, | ||||
|                 path: req.params[0] | ||||
|                 path: req.params[0], | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.stageFile(opts).then(function() { | ||||
|                 getProjectStatus(req,res); | ||||
| @@ -228,7 +239,8 @@ module.exports = { | ||||
|             var opts = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id, | ||||
|                 path: req.body.files | ||||
|                 path: req.body.files, | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.stageFile(opts).then(function() { | ||||
|                 getProjectStatus(req,res); | ||||
| @@ -242,7 +254,8 @@ module.exports = { | ||||
|             var opts = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id, | ||||
|                 message: req.body.message | ||||
|                 message: req.body.message, | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.commit(opts).then(function() { | ||||
|                 getProjectStatus(req,res); | ||||
| @@ -256,7 +269,8 @@ module.exports = { | ||||
|             var opts = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id, | ||||
|                 path: req.params[0] | ||||
|                 path: req.params[0], | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.unstageFile(opts).then(function() { | ||||
|                 getProjectStatus(req,res); | ||||
| @@ -269,7 +283,8 @@ module.exports = { | ||||
|         app.delete("/:id/stage", needsPermission("projects.write"), function(req, res) { | ||||
|             var opts = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id | ||||
|                 id: req.params.id, | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.unstageFile(opts).then(function() { | ||||
|                 getProjectStatus(req,res); | ||||
| @@ -284,7 +299,8 @@ module.exports = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id, | ||||
|                 path: req.params[0], | ||||
|                 type: req.params.type | ||||
|                 type: req.params.type, | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.getFileDiff(opts).then(function(data) { | ||||
|                 res.json({ | ||||
| @@ -301,7 +317,8 @@ module.exports = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id, | ||||
|                 limit: req.query.limit || 20, | ||||
|                 before: req.query.before | ||||
|                 before: req.query.before, | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.getCommits(opts).then(function(data) { | ||||
|                 res.json(data); | ||||
| @@ -315,7 +332,8 @@ module.exports = { | ||||
|             var opts = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id, | ||||
|                 sha: req.params.sha | ||||
|                 sha: req.params.sha, | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.getCommit(opts).then(function(data) { | ||||
|                 res.json({commit:data}); | ||||
| @@ -330,7 +348,8 @@ module.exports = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id, | ||||
|                 remote: req.params[0], | ||||
|                 track: req.query.u | ||||
|                 track: req.query.u, | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.push(opts).then(function(data) { | ||||
|                 res.status(204).end(); | ||||
| @@ -346,7 +365,8 @@ module.exports = { | ||||
|                 id: req.params.id, | ||||
|                 remote: req.params[0], | ||||
|                 track: req.query.setUpstream, | ||||
|                 allowUnrelatedHistories: req.query.allowUnrelatedHistories | ||||
|                 allowUnrelatedHistories: req.query.allowUnrelatedHistories, | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.pull(opts).then(function(data) { | ||||
|                 res.status(204).end(); | ||||
| @@ -359,7 +379,8 @@ module.exports = { | ||||
|         app.delete("/:id/merge", needsPermission("projects.write"), function(req, res) { | ||||
|             var opts = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id | ||||
|                 id: req.params.id, | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.abortMerge(opts).then(function() { | ||||
|                 res.status(204).end(); | ||||
| @@ -374,7 +395,8 @@ module.exports = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id, | ||||
|                 path: req.params[0], | ||||
|                 resolution: req.body.resolutions | ||||
|                 resolution: req.body.resolutions, | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.resolveMerge(opts).then(function() { | ||||
|                 res.status(204).end(); | ||||
| @@ -388,7 +410,8 @@ module.exports = { | ||||
|             var opts = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id, | ||||
|                 remote: false | ||||
|                 remote: false, | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.getBranches(opts).then(function(data) { | ||||
|                 res.json(data); | ||||
| @@ -403,7 +426,8 @@ module.exports = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id, | ||||
|                 branch: req.params.branchName, | ||||
|                 force: !!req.query.force | ||||
|                 force: !!req.query.force, | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.deleteBranch(opts).then(function(data) { | ||||
|                 res.status(204).end(); | ||||
| @@ -417,7 +441,8 @@ module.exports = { | ||||
|             var opts = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id, | ||||
|                 remote: true | ||||
|                 remote: true, | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.getBranches(opts).then(function(data) { | ||||
|                 res.json(data); | ||||
| @@ -431,7 +456,8 @@ module.exports = { | ||||
|             var opts = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id, | ||||
|                 branch: req.params[0] | ||||
|                 branch: req.params[0], | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.getBranchStatus(opts).then(function(data) { | ||||
|                 res.json(data); | ||||
| @@ -446,7 +472,8 @@ module.exports = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id, | ||||
|                 branch: req.body.name, | ||||
|                 create: req.body.create | ||||
|                 create: req.body.create, | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.setBranch(opts).then(function(data) { | ||||
|                 res.json(data); | ||||
| @@ -463,7 +490,8 @@ module.exports = { | ||||
|             var opts = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id, | ||||
|                 remote: req.body | ||||
|                 remote: req.body, | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             if (/^https?:\/\/[^/]+@/i.test(req.body.url)) { | ||||
|                 res.status(400).json({error:"unexpected_error", message:"Git http url must not include username/password"}); | ||||
| @@ -481,7 +509,8 @@ module.exports = { | ||||
|             var opts = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id, | ||||
|                 remote: req.params.remoteName | ||||
|                 remote: req.params.remoteName, | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.removeRemote(opts).then(function(data) { | ||||
|                 getProjectRemotes(req,res); | ||||
| @@ -497,7 +526,8 @@ module.exports = { | ||||
|             var opts = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id, | ||||
|                 remote: remote | ||||
|                 remote: remote, | ||||
|                 req: apiUtils.getRequestLogObject(req) | ||||
|             } | ||||
|             runtimeAPI.projects.updateRemote(opts).then(function() { | ||||
|                 res.status(204).end(); | ||||
|   | ||||
| @@ -19,6 +19,8 @@ var sshkeys = require("./sshkeys"); | ||||
| var theme = require("./theme"); | ||||
| var clone = require("clone"); | ||||
|  | ||||
| var i18n = require("@node-red/util").i18n | ||||
|  | ||||
| function extend(target, source) { | ||||
|     var keys = Object.keys(source); | ||||
|     var i = keys.length; | ||||
| @@ -53,12 +55,14 @@ module.exports = { | ||||
|             user: req.user | ||||
|         } | ||||
|         runtimeAPI.settings.getRuntimeSettings(opts).then(function(result) { | ||||
|             result.editorTheme = result.editorTheme||{}; | ||||
|             var themeSettings = theme.settings(); | ||||
|             if (themeSettings) { | ||||
|                 // result.editorTheme may already exist with the palette | ||||
|                 // disabled. Need to merge that into the receive settings | ||||
|                 result.editorTheme = extend(clone(themeSettings),result.editorTheme||{}); | ||||
|                 result.editorTheme = extend(clone(themeSettings),result.editorTheme); | ||||
|             } | ||||
|             result.editorTheme.languages = i18n.availableLanguages("editor"); | ||||
|             res.json(result); | ||||
|         }); | ||||
|     }, | ||||
|   | ||||
| @@ -28,7 +28,7 @@ var defaultContext = { | ||||
|     }, | ||||
|     header: { | ||||
|         title: "Node-RED", | ||||
|         image: "red/images/node-red.png" | ||||
|         image: "red/images/node-red.svg" | ||||
|     }, | ||||
|     asset: { | ||||
|         red: (process.env.NODE_ENV == "development")? "red/red.js":"red/red.min.js", | ||||
| @@ -169,6 +169,9 @@ module.exports = { | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         themeApp.get("/", function(req,res) { | ||||
|             res.json(themeContext); | ||||
|         }) | ||||
|  | ||||
|         if (theme.hasOwnProperty("menu")) { | ||||
|             themeSettings.menu = theme.menu; | ||||
|   | ||||
| @@ -25,7 +25,7 @@ var theme = require("./theme"); | ||||
|  | ||||
| var runtimeAPI; | ||||
| var editorClientDir = path.dirname(require.resolve("@node-red/editor-client")); | ||||
| var defaultNodeIcon = path.join(editorClientDir,"public","red","images","icons","arrow-in.png"); | ||||
| var defaultNodeIcon = path.join(editorClientDir,"public","red","images","icons","arrow-in.svg"); | ||||
| var editorTemplatePath = path.join(editorClientDir,"templates","index.mst"); | ||||
| var editorTemplate; | ||||
|  | ||||
|   | ||||
| @@ -47,5 +47,12 @@ module.exports = { | ||||
|             code: err.code||"unexpected_error", | ||||
|             message: err.message||err.toString() | ||||
|         }); | ||||
|     }, | ||||
|     getRequestLogObject: function(req) { | ||||
|         return { | ||||
|             user: req.user, | ||||
|             path: req.path, | ||||
|             ip: (req.headers && req.headers['x-forwarded-for']) || (req.connection && req.connection.remoteAddress) || undefined | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@node-red/editor-api", | ||||
|     "version": "0.20.0-beta.5", | ||||
|     "version": "1.0.2", | ||||
|     "license": "Apache-2.0", | ||||
|     "main": "./lib/index.js", | ||||
|     "repository": { | ||||
| @@ -16,22 +16,25 @@ | ||||
|         } | ||||
|     ], | ||||
|     "dependencies": { | ||||
|         "@node-red/util": "0.20.0-beta.5", | ||||
|         "@node-red/editor-client": "0.20.0-beta.5", | ||||
|         "@node-red/util": "1.0.2", | ||||
|         "@node-red/editor-client": "1.0.2", | ||||
|         "bcryptjs": "2.4.3", | ||||
|         "body-parser": "1.18.3", | ||||
|         "body-parser": "1.19.0", | ||||
|         "clone": "2.1.2", | ||||
|         "cors": "2.8.5", | ||||
|         "express-session": "1.15.6", | ||||
|         "express": "4.16.4", | ||||
|         "memorystore": "1.6.0", | ||||
|         "mime": "2.4.0", | ||||
|         "mustache": "3.0.1", | ||||
|         "express-session": "1.16.2", | ||||
|         "express": "4.17.1", | ||||
|         "memorystore": "1.6.1", | ||||
|         "mime": "2.4.4", | ||||
|         "mustache": "3.0.2", | ||||
|         "oauth2orize": "1.11.0", | ||||
|         "passport-http-bearer": "1.0.1", | ||||
|         "passport-oauth2-client-password": "0.1.2", | ||||
|         "passport": "0.4.0", | ||||
|         "when": "3.7.8", | ||||
|         "ws": "6.1.3" | ||||
|         "ws": "6.2.1" | ||||
|     }, | ||||
|     "optionalDependencies": { | ||||
|         "bcrypt": "3.0.6" | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -26,8 +26,7 @@ | ||||
|     "status" : "Status", | ||||
|     "enabled" : "Aktiviert", | ||||
|     "disabled" : "Inaktiviert", | ||||
|     "info" : "Beschreibung", | ||||
|     "tip" : "Beschreibung akzeptiert Markdown und wird auf der Registerkarte Info angezeigt." | ||||
|     "info" : "Beschreibung" | ||||
|   }, | ||||
|   "menu" : { | ||||
|     "label" : { | ||||
| @@ -48,16 +47,13 @@ | ||||
|       }, | ||||
|       "settings" : "Einstellungen", | ||||
|       "userSettings" : "Benutzereinstellungen", | ||||
|       "nodes" : "Knoten", | ||||
|       "displayStatus" : "Knotenstatus anzeigen", | ||||
|       "displayConfig" : "Konfigurationsknoten", | ||||
|       "nodes" : "Nodes", | ||||
|       "displayStatus" : "Nodestatus anzeigen", | ||||
|       "displayConfig" : "Konfigurations-Node", | ||||
|       "import" : "Import", | ||||
|       "export" : "Exportieren", | ||||
|       "search" : "Flows durchsuchen", | ||||
|       "searchInput" : "durchsuchen Sie Ihre Flows", | ||||
|       "clipboard" : "Zwischenablage", | ||||
|       "library" : "Bibliothek", | ||||
|       "examples" : "Beispiele", | ||||
|       "subflows" : "Subflow", | ||||
|       "createSubflow" : "Subflow erstellen", | ||||
|       "selectionToSubflow" : "Auswahl für Subflow", | ||||
| @@ -87,17 +83,17 @@ | ||||
|     "notAuthorized" : "Keine Berechtigung", | ||||
|     "errors" : { | ||||
|       "settings" : "Sie müssen angemeldet sein, um auf die Einstellungen zuzugreifen.", | ||||
|       "deploy" : "Sie müssen angemeldet sein, um Änderungen implementieren zu können.", | ||||
|       "deploy" : "Sie müssen angemeldet sein, um Änderungen anwenden zu können.", | ||||
|       "notAuthorized" : "Sie müssen angemeldet sein, um diese Aktion ausführen zu können." | ||||
|     } | ||||
|   }, | ||||
|   "notification" : { | ||||
|     "warning" : "<strong> Warnung </strong>: __message__", | ||||
|     "warnings" : { | ||||
|       "undeployedChanges" : "Knoten hat nicht implementierte Änderungen", | ||||
|       "nodeActionDisabled" : "In Subflow inaktivierte Knotenaktionen", | ||||
|       "missing-types" : "<p> Die Flows wurden aufgrund fehlender Knotentypen gestoppt. </p>", | ||||
|       "restartRequired" : "Knoten-RED muss erneut gestartet werden, damit aufgerüstete Module aktiviert werden können", | ||||
|       "undeployedChanges" : "Node hat nicht implementierte Änderungen", | ||||
|       "nodeActionDisabled" : "In Subflow inaktivierte Nodeaktionen", | ||||
|       "missing-types" : "<p> Die Flows wurden aufgrund fehlender Nodetypen gestoppt. </p>", | ||||
|       "restartRequired" : "Node-RED muss erneut gestartet werden, damit aufgerüstete Module aktiviert werden können", | ||||
|       "credentials_load_failed" : "<p> Die Flows wurden gestoppt, da die Berechtigungsnachweise nicht entschlüsselt werden konnten. </p> <p> Die Datei mit dem Datenflowberechtigungsnachweis ist verschlüsselt, aber der Verschlüsselungsschlüssel des Projekts fehlt oder ist ungültig. </p>", | ||||
|       "credentials_load_failed_reset" : "<p> Die Berechtigungsnachweise konnten nicht entschlüsselt werden </p> <p> Die Datei mit dem Flow-Berechtigungsnachweis ist verschlüsselt, aber der Chiffrierschlüssel des Projekts fehlt oder ist ungültig. </p> <p> Die Datei des Flow-Berechtigungsnachweises wird bei der nächsten Implementierung zurückgesetzt. Alle vorhandenen Datenflowberechtigungsnachweise werden gelöscht. </p>", | ||||
|       "missing_flow_file" : "<p> Die Projektflowdatei wurde nicht gefunden. </p> <p> Das Projekt ist nicht mit einer Flow-Datei konfiguriert. </p>", | ||||
| @@ -136,19 +132,19 @@ | ||||
|     } | ||||
|   }, | ||||
|   "clipboard" : { | ||||
|     "nodes" : "Knoten", | ||||
|     "selectNodes" : "Wählen Sie den Text oben aus, und kopieren Sie die Datei in die Zwischenablage.", | ||||
|     "pasteNodes" : "Knoten hier einfügen", | ||||
|     "importNodes" : "Knoten importieren", | ||||
|     "exportNodes" : "Knoten in Zwischenablage exportieren", | ||||
|     "clipboard" : "Zwischenablage", | ||||
|     "nodes" : "Nodes", | ||||
|     "pasteNodes" : "Nodes hier einfügen", | ||||
|     "importNodes" : "Nodes importieren", | ||||
|     "exportNodes" : "Nodes in Zwischenablage exportieren", | ||||
|     "importUnrecognised" : "Importierter Typ nicht erkannt:", | ||||
|     "importUnrecognised_plural" : "Importierte Typen nicht erkannt:", | ||||
|     "nodesExported" : "Knoten, die in die Zwischenablage exportiert wurden", | ||||
|     "nodeCopied" : "__count__ Knoten kopiert", | ||||
|     "nodeCopied_plural" : "__count__ Knoten kopiert", | ||||
|     "nodesExported" : "Nodes, die in die Zwischenablage exportiert wurden", | ||||
|     "nodeCopied" : "__count__ Node kopiert", | ||||
|     "nodeCopied_plural" : "__count__ Nodes kopiert", | ||||
|     "invalidFlow" : "Ungültiger Nachrichtenflow: __message__", | ||||
|     "export" : { | ||||
|       "selected" : "Ausgewählte Knoten", | ||||
|       "selected" : "Ausgewählte Nodes", | ||||
|       "current" : "Aktueller Flow", | ||||
|       "all" : "alle Flows", | ||||
|       "compact" : "kompakt", | ||||
| @@ -164,16 +160,16 @@ | ||||
|     "copyMessageValue_truncated" : "Abgeschnittene Wert kopiert" | ||||
|   }, | ||||
|   "deploy" : { | ||||
|     "deploy" : "Implementieren", | ||||
|     "deploy" : "deploy", | ||||
|     "full" : "Voll", | ||||
|     "fullDesc" : "Implementiert alles im Arbeitsbereich", | ||||
|     "modifiedFlows" : "Geänderte Flows", | ||||
|     "modifiedFlowsDesc" : "Implementiert nur Flows, die geänderte Knoten enthalten.", | ||||
|     "modifiedNodes" : "Geänderte Knoten", | ||||
|     "modifiedNodesDesc" : "Implementiert nur Knoten, die sich geändert haben.", | ||||
|     "modifiedFlowsDesc" : "Implementiert nur Flows, die geänderte Nodes enthalten.", | ||||
|     "modifiedNodes" : "Geänderte Nodes", | ||||
|     "modifiedNodesDesc" : "Implementiert nur Nodes, die sich geändert haben.", | ||||
|     "successfulDeploy" : "Erfolgreich implementiert", | ||||
|     "deployFailed" : "Implementieren fehlgeschlagen: __message__", | ||||
|     "unusedConfigNodes" : "Sie haben einige nicht verwendete Konfigurationsknoten.", | ||||
|     "deployFailed" : "Deploy fehlgeschlagen: __message__", | ||||
|     "unusedConfigNodes" : "Sie haben einige nicht verwendete Konfigurations-Nodes.", | ||||
|     "unusedConfigNodesLink" : "Klicken Sie hier, um sie zu sehen", | ||||
|     "errors" : { | ||||
|       "noResponse" : "Keine Antwort vom Server" | ||||
| @@ -181,16 +177,16 @@ | ||||
|     "confirm" : { | ||||
|       "button" : { | ||||
|         "ignore" : "Ignorieren", | ||||
|         "confirm" : "Implementieren bestätigen", | ||||
|         "confirm" : "Deploy bestätigen", | ||||
|         "review" : "Änderungen prüfen", | ||||
|         "cancel" : "Abbrechen", | ||||
|         "merge" : "Zusammenführen", | ||||
|         "overwrite" : "Ignorieren & implementieren" | ||||
|         "overwrite" : "Ignorieren & deployen" | ||||
|       }, | ||||
|       "undeployedChanges" : "Sie haben nicht implementierte Änderungen.\n\nWenn Sie diese Seite verlassen, gehen diese Änderungen verloren.", | ||||
|       "improperlyConfigured" : "Der Arbeitsbereich enthält einige Knoten, die nicht ordnungsgemäß konfiguriert sind:", | ||||
|       "unknown" : "Der Arbeitsbereich enthält einige unbekannte Knotentypen:", | ||||
|       "confirm" : "Sind Sie sicher, dass Sie implementieren möchten?", | ||||
|       "improperlyConfigured" : "Der Arbeitsbereich enthält einige Nodes, die nicht ordnungsgemäß konfiguriert sind:", | ||||
|       "unknown" : "Der Arbeitsbereich enthält einige unbekannte Node-Typen:", | ||||
|       "confirm" : "Sind Sie sicher, dass Sie deployen möchten?", | ||||
|       "doNotWarn" : "warnen Sie nicht noch einmal.", | ||||
|       "conflict" : "Auf dem Server wird eine aktuellere Gruppe von Datenflüssen ausgeführt.", | ||||
|       "backgroundUpdate" : "Die Datenflüsse auf dem Server wurden aktualisiert.", | ||||
| @@ -203,7 +199,7 @@ | ||||
|   "diff" : { | ||||
|     "unresolvedCount" : "__count__ unaufgelöster Konflikt", | ||||
|     "unresolvedCount_plural" : "__count__ unaufgelöste Konflikte", | ||||
|     "globalNodes" : "Globale Knoten", | ||||
|     "globalNodes" : "Globale Nodes", | ||||
|     "flowProperties" : "Flow-Eigenschaften", | ||||
|     "type" : { | ||||
|       "added" : "hinzugefügt", | ||||
| @@ -215,8 +211,8 @@ | ||||
|       "movedTo" : "verschoben zu __id__", | ||||
|       "movedFrom" : "verschoben von __id__" | ||||
|     }, | ||||
|     "nodeCount" : "__count__, Knoten", | ||||
|     "nodeCount_plural" : "__count__-Knoten", | ||||
|     "nodeCount" : "__count__, Node", | ||||
|     "nodeCount_plural" : "__count__-Nodes", | ||||
|     "local" : "Lokale Änderungen", | ||||
|     "remote" : "Ferne Änderungen", | ||||
|     "reviewChanges" : "Änderungen prüfen", | ||||
| @@ -240,9 +236,8 @@ | ||||
|     "deleteSubflow" : "Subflow löschen", | ||||
|     "info" : "Beschreibung", | ||||
|     "category" : "Kategorie", | ||||
|     "format" : "Markdown-Format", | ||||
|     "errors" : { | ||||
|       "noNodesSelected" : "<strong> Subflow kann nicht erstellt werden </strong>: Es wurden keine Knoten ausgewählt.", | ||||
|       "noNodesSelected" : "<strong> Subflow kann nicht erstellt werden </strong>: Es wurden keine Nodes ausgewählt.", | ||||
|       "multipleInputsToSelection" : "<strong> Subflow kann nicht erstellt werden </strong>: Mehrere Eingaben zur Auswahl" | ||||
|     } | ||||
|   }, | ||||
| @@ -252,13 +247,13 @@ | ||||
|     "configUpdate" : "Aktualisieren", | ||||
|     "configDelete" : "Löschen", | ||||
|     "nodesUse" : "__count__node verwendet diese Konfiguration", | ||||
|     "nodesUse_plural" : "__count__ -Knoten verwenden diese Konfiguration", | ||||
|     "addNewConfig" : "Neuen __type__config-Knoten hinzufügen", | ||||
|     "editNode" : "__type__ Knoten bearbeiten", | ||||
|     "editConfig" : "__type__config-Knoten bearbeiten", | ||||
|     "nodesUse_plural" : "__count__ -Nodes verwenden diese Konfiguration", | ||||
|     "addNewConfig" : "Neuen __type__config-Node hinzufügen", | ||||
|     "editNode" : "__type__ Node bearbeiten", | ||||
|     "editConfig" : "__type__config-Node bearbeiten", | ||||
|     "addNewType" : "Neuen __type__ hinzufügen ...", | ||||
|     "nodeProperties" : "Knoteneigenschaften", | ||||
|     "portLabels" : "Knoteneinstellungen", | ||||
|     "nodeProperties" : "Node-Eigenschaften", | ||||
|     "portLabels" : "Node-Einstellungen", | ||||
|     "labelInputs" : "Eingänge", | ||||
|     "labelOutputs" : "Ausgänge", | ||||
|     "settingIcon" : "Symbol", | ||||
| @@ -267,7 +262,7 @@ | ||||
|     "searchIcons" : "Suchsymbole", | ||||
|     "useDefault" : "Standardwert verwenden", | ||||
|     "errors" : { | ||||
|       "scopeChange" : "Wenn Sie den Geltungsbereich ändern, wird er für Knoten in anderen Nachrichtenflüssen, die ihn verwenden, nicht verfügbar sein." | ||||
|       "scopeChange" : "Wenn Sie den Geltungsbereich ändern, wird er für Nodes in anderen Nachrichtenflüssen, die ihn verwenden, nicht verfügbar sein." | ||||
|     } | ||||
|   }, | ||||
|   "keyboard" : { | ||||
| @@ -279,48 +274,45 @@ | ||||
|     "unassigned" : "Nicht zugeordnet", | ||||
|     "global" : "global", | ||||
|     "workspace" : "Arbeitsbereich", | ||||
|     "selectAll" : "Alle Knoten auswählen", | ||||
|     "selectAllConnected" : "Alle verbundenen Knoten auswählen", | ||||
|     "addRemoveNode" : "Knoten aus Auswahl hinzufügen/entfernen", | ||||
|     "editSelected" : "Ausgewählten Knoten bearbeiten", | ||||
|     "deleteSelected" : "Ausgewählte Knoten oder ausgewählten Link löschen", | ||||
|     "importNode" : "Knoten importieren", | ||||
|     "exportNode" : "Knoten exportieren", | ||||
|     "nudgeNode" : "Ausgewählte Knoten verschieben (1px)", | ||||
|     "moveNode" : "Ausgewählte Knoten verschieben (20px)", | ||||
|     "selectAll" : "Alle Nodes auswählen", | ||||
|     "selectAllConnected" : "Alle verbundenen Nodes auswählen", | ||||
|     "addRemoveNode" : "Node aus Auswahl hinzufügen/entfernen", | ||||
|     "editSelected" : "Ausgewählten Node bearbeiten", | ||||
|     "deleteSelected" : "Ausgewählte Node oder ausgewählten Link löschen", | ||||
|     "importNode" : "Node importieren", | ||||
|     "exportNode" : "Node exportieren", | ||||
|     "nudgeNode" : "Ausgewählte Nodes verschieben (1px)", | ||||
|     "moveNode" : "Ausgewählte Nodes verschieben (20px)", | ||||
|     "toggleSidebar" : "Seitenleiste ein-/ausschalten", | ||||
|     "copyNode" : "Ausgewählte Knoten kopieren", | ||||
|     "cutNode" : "Ausgewählte Knoten ausschneiden", | ||||
|     "pasteNode" : "Knoten einfügen", | ||||
|     "copyNode" : "Ausgewählte Nodes kopieren", | ||||
|     "cutNode" : "Ausgewählte Nodes ausschneiden", | ||||
|     "pasteNode" : "Node einfügen", | ||||
|     "undoChange" : "Letzte Änderung rückgängig machen", | ||||
|     "searchBox" : "Suchfeld öffnen", | ||||
|     "managePalette" : "Palette verwalten" | ||||
|   }, | ||||
|   "library" : { | ||||
|     "library" : "Bibliothek", | ||||
|     "openLibrary" : "Bibliothek öffnen ...", | ||||
|     "saveToLibrary" : "In Bibliothek speichern ...", | ||||
|     "typeLibrary" : "__type__, Bibliothek", | ||||
|     "unnamedType" : "Unbenannt __type__", | ||||
|     "exportToLibrary" : "Knoten in Bibliothek exportieren", | ||||
|     "dialogSaveOverwrite" : "Ein __libraryType__ mit dem Namen __libraryName__ ist bereits vorhanden. Überschreiben?", | ||||
|     "invalidFilename" : "Ungültiger Dateiname", | ||||
|     "savedNodes" : "Gespeicherte Knoten", | ||||
|     "savedNodes" : "Gespeicherte Nodes", | ||||
|     "savedType" : "Gespeichert __type__", | ||||
|     "saveFailed" : "Speichern fehlgeschlagen: __message__", | ||||
|     "filename" : "Name der Datei", | ||||
|     "folder" : "Ordner", | ||||
|     "filenamePlaceholder" : "Datei", | ||||
|     "fullFilenamePlaceholder" : "a/b/Datei", | ||||
|     "folderPlaceholder" : "a/b", | ||||
|     "breadcrumb" : "Bibliothek" | ||||
|     "types": { | ||||
|         "examples" : "Beispiele" | ||||
|     } | ||||
|   }, | ||||
|   "palette" : { | ||||
|     "noInfo" : "Keine Informationen verfügbar", | ||||
|     "filter" : "Filterknoten", | ||||
|     "filter" : "Filter Nodes", | ||||
|     "search" : "Suchmodule", | ||||
|     "addCategory" : "Neu hinzufügen ...", | ||||
|     "label" : { | ||||
|       "subflows" : "untergeordnete Nachrichtenflüsse", | ||||
|       "subflows" : "Subflows", | ||||
|       "input" : "Eingabe", | ||||
|       "output" : "Ausgabe", | ||||
|       "function" : "Funktion", | ||||
| @@ -330,15 +322,15 @@ | ||||
|       "advanced" : "fortgeschritten" | ||||
|     }, | ||||
|     "event" : { | ||||
|       "nodeAdded" : "Knoten zur Palette hinzugefügt:", | ||||
|       "nodeAdded_plural" : "Die Palette wurde der Palette hinzugefügt.", | ||||
|       "nodeRemoved" : "Knoten aus Palette entfernt:", | ||||
|       "nodeRemoved_plural" : "Knoten aus Palette entfernt:", | ||||
|       "nodeEnabled" : "Knoten aktiviert:", | ||||
|       "nodeEnabled_plural" : "Knoten aktiviert:", | ||||
|       "nodeDisabled" : "Knoten inaktiviert:", | ||||
|       "nodeDisabled_plural" : "Knoten inaktiviert:", | ||||
|       "nodeUpgraded" : "Knotenmodul __module__ aktualisiert auf Version __version__" | ||||
|       "nodeAdded" : "Node zur Palette hinzugefügt:", | ||||
|       "nodeAdded_plural" : "Die Nodes wurde der Palette hinzugefügt.", | ||||
|       "nodeRemoved" : "Node aus Palette entfernt:", | ||||
|       "nodeRemoved_plural" : "Nodes aus Palette entfernt:", | ||||
|       "nodeEnabled" : "Node aktiviert:", | ||||
|       "nodeEnabled_plural" : "Nodes aktiviert:", | ||||
|       "nodeDisabled" : "Node inaktiviert:", | ||||
|       "nodeDisabled_plural" : "Nodes inaktiviert:", | ||||
|       "nodeUpgraded" : "Node-Modul __module__ aktualisiert auf Version __version__" | ||||
|     }, | ||||
|     "editor" : { | ||||
|       "title" : "Palette verwalten", | ||||
| @@ -362,8 +354,8 @@ | ||||
|         "yearsMonthsV" : "____ Jahre, __count__ Monat vor", | ||||
|         "yearsMonthsV_plural" : "____ Jahre, __count__ Monaten" | ||||
|       }, | ||||
|       "nodeCount" : "__label__, Knoten", | ||||
|       "nodeCount_plural" : "__label__ Knoten", | ||||
|       "nodeCount" : "__label__, Node", | ||||
|       "nodeCount_plural" : "__label__ Nodes", | ||||
|       "moduleCount" : "__count__ Modul verfügbar", | ||||
|       "moduleCount_plural" : "__count__-Module verfügbar", | ||||
|       "inuse" : "im Gebrauch", | ||||
| @@ -377,14 +369,14 @@ | ||||
|       "install" : "installieren", | ||||
|       "installed" : "installiert", | ||||
|       "loading" : "Kataloge werden geladen ...", | ||||
|       "tab-nodes" : "Knoten", | ||||
|       "tab-nodes" : "Nodes", | ||||
|       "tab-install" : "installieren", | ||||
|       "sort" : "Sortierung:", | ||||
|       "sortAZ" : "a-z", | ||||
|       "sortRecent" : "kürzlich", | ||||
|       "more" : "+ __count__ mehr", | ||||
|       "errors" : { | ||||
|         "catalogLoadFailed" : "<p> Fehler beim Laden des Knotenkatalogs. </p> <p> Weitere Informationen finden Sie in der Browserkonsole. </p>", | ||||
|         "catalogLoadFailed" : "<p> Fehler beim Laden des Node-Katalogs. </p> <p> Weitere Informationen finden Sie in der Browserkonsole. </p>", | ||||
|         "installFailed" : "<p> Installation fehlgeschlagen: __module__ </p> <p> __message__ </p> <p> Überprüfen Sie das Protokoll auf weitere Informationen. </p>", | ||||
|         "removeFailed" : "<p> Entfernen fehlgeschlagen: __module__ </p> <p> __message__ </p> <p> Überprüfen Sie das Protokoll auf weitere Informationen. </p>", | ||||
|         "updateFailed" : "<p> Aktualisierung fehlgeschlagen: __module__ </p> <p> __message__ </p> <p> Überprüfen Sie das Protokoll auf weitere Informationen. </p>", | ||||
| @@ -393,22 +385,22 @@ | ||||
|       }, | ||||
|       "confirm" : { | ||||
|         "install" : { | ||||
|           "body" : "<p> Installieren von '__module__' </p> <p> Vor der Installation von lesen Sie bitte die Dokumentation des Knotens. Einige Knoten haben Abhängigkeiten, die nicht automatisch aufgelöst werden können und einen Neustart von 'Node-RED' erfordern. </p>", | ||||
|           "title" : "Knoten installieren" | ||||
|           "body" : "<p> Installieren von '__module__' </p> <p> Vor der Installation von lesen Sie bitte die Dokumentation des Nodes. Einige Nodes haben Abhängigkeiten, die nicht automatisch aufgelöst werden können und einen Neustart von 'Node-RED' erfordern. </p>", | ||||
|           "title" : "Nodes installieren" | ||||
|         }, | ||||
|         "remove" : { | ||||
|           "body" : "<p> Entfernen von '__module__' </p> <p>-Der Knoten deinstalliert ihn aus Node-RED. Der Knoten kann weiterhin Ressourcen verwenden, bis Node-RED erneut gestartet wird. </p>", | ||||
|           "title" : "Knoten entfernen" | ||||
|           "body" : "<p> Entfernen von '__module__' </p> <p>-Der Node deinstalliert ihn aus Node-RED. Der Node kann weiterhin Ressourcen verwenden, bis Node-RED erneut gestartet wird. </p>", | ||||
|           "title" : "Nodes entfernen" | ||||
|         }, | ||||
|         "update" : { | ||||
|           "body" : "<p> Aktualisieren von '__module__' </p> <p> Für die Aktualisierung des Knotens ist ein Neustart von 'Node-RED' erforderlich, damit die Aktualisierung abgeschlossen werden kann. Dies muss manuell geschehen. </p>", | ||||
|           "title" : "Knoten aktualisieren" | ||||
|           "body" : "<p> Aktualisieren von '__module__' </p> <p> Für die Aktualisierung des Nodes ist ein Neustart von 'Node-RED' erforderlich, damit die Aktualisierung abgeschlossen werden kann. Dies muss manuell geschehen. </p>", | ||||
|           "title" : "Nodes aktualisieren" | ||||
|         }, | ||||
|         "cannotUpdate" : { | ||||
|           "body" : "Es ist eine Aktualisierung für diesen Knoten verfügbar, aber sie ist nicht an einer Position installiert, die vom Palettenmanager aktualisiert werden kann. <br/> <br/> Weitere Informationen zum Aktualisieren dieses Knotens finden Sie in der Dokumentation." | ||||
|           "body" : "Es ist eine Aktualisierung für diesen Node verfügbar, aber sie ist nicht an einer Position installiert, die vom Palettenmanager aktualisiert werden kann. <br/> <br/> Weitere Informationen zum Aktualisieren dieses Nodes finden Sie in der Dokumentation." | ||||
|         }, | ||||
|         "button" : { | ||||
|           "review" : "Knoteninformationen öffnen", | ||||
|           "review" : "Node-Informationen öffnen", | ||||
|           "install" : "installieren", | ||||
|           "remove" : "Entfernen", | ||||
|           "update" : "Aktualisieren" | ||||
| @@ -418,10 +410,10 @@ | ||||
|   }, | ||||
|   "sidebar" : { | ||||
|     "info" : { | ||||
|       "name" : "Knoteninformationen", | ||||
|       "name" : "Node-Informationen", | ||||
|       "tabName" : "Name", | ||||
|       "label" : "info", | ||||
|       "node" : "Knoten", | ||||
|       "node" : "Node", | ||||
|       "type" : "Typ", | ||||
|       "id" : "ID", | ||||
|       "status" : "Status", | ||||
| @@ -437,23 +429,23 @@ | ||||
|       "showLess" : "Weniger anzeigen", | ||||
|       "flow" : "Flow", | ||||
|       "selection" : "Auswahl", | ||||
|       "nodes" : "__count__ Knoten", | ||||
|       "nodes" : "__count__ Nodes", | ||||
|       "flowDesc" : "Beschreibung des Flows", | ||||
|       "subflowDesc" : "Beschreibung des Subflows", | ||||
|       "nodeHelp" : "Knotenhilfe", | ||||
|       "nodeHelp" : "Node-Hilfe", | ||||
|       "none" : "Keine", | ||||
|       "arrayItems" : "__count__ items", | ||||
|       "showTips" : "Sie können die Tipps in der Anzeige \"Einstellungen\" öffnen." | ||||
|     }, | ||||
|     "config" : { | ||||
|       "name" : "Konfigurationsknoten", | ||||
|       "name" : "Konfigurations-Node", | ||||
|       "label" : "Konfiguration", | ||||
|       "global" : "Bei allen Flows", | ||||
|       "none" : "keine", | ||||
|       "subflows" : "Subflows", | ||||
|       "flows" : "Flows", | ||||
|       "filterUnused" : "Nicht verwendet", | ||||
|       "filterAll" : "alle", | ||||
|       "filterUnused" : "Nicht verwendet", | ||||
|       "filtered" : "__count__ verdeckt" | ||||
|     }, | ||||
|     "context" : { | ||||
| @@ -462,7 +454,7 @@ | ||||
|       "none" : "keine ausgewählt", | ||||
|       "refresh" : "Aktualisierung zum Laden", | ||||
|       "empty" : "leer", | ||||
|       "node" : "Knoten", | ||||
|       "node" : "Node", | ||||
|       "flow" : "Flow", | ||||
|       "global" : "Global" | ||||
|     }, | ||||
| @@ -610,13 +602,13 @@ | ||||
|   }, | ||||
|   "typedInput" : { | ||||
|     "type" : { | ||||
|       "str" : "Zeichenfolge", | ||||
|       "num" : "Anzahl", | ||||
|       "str" : "String", | ||||
|       "num" : "Number", | ||||
|       "re" : "Regulärer Ausdruck", | ||||
|       "bool" : "boolean", | ||||
|       "json" : "JSON", | ||||
|       "bin" : "Puffer", | ||||
|       "date" : "Zeitmarke", | ||||
|       "bin" : "Buffer", | ||||
|       "date" : "timestamp", | ||||
|       "jsonata" : "Ausdruck", | ||||
|       "env" : "env, Variable" | ||||
|     } | ||||
| @@ -626,7 +618,7 @@ | ||||
|   }, | ||||
|   "search" : { | ||||
|     "empty" : "Keine Übereinstimmungen gefunden", | ||||
|     "addNode" : "Knoten hinzufügen ..." | ||||
|     "addNode" : "Node hinzufügen ..." | ||||
|   }, | ||||
|   "expressionEditor" : { | ||||
|     "functions" : "Funktionen", | ||||
| @@ -658,10 +650,10 @@ | ||||
|     "title" : "Markdown-Editor" | ||||
|   }, | ||||
|   "bufferEditor" : { | ||||
|     "title" : "Puffereditor", | ||||
|     "title" : "Buffereditor", | ||||
|     "modeString" : "Als UTF-8-Zeichenfolge bearbeiten", | ||||
|     "modeArray" : "Als JSON-Array bearbeiten", | ||||
|     "modeDesc" : "<h3> Puffereditor </h3> <p> Der Puffertyp wird als JSON-Array mit Bytewerten gespeichert. Der Editor versucht, den eingegebenen Wert als JSON-Array zu parsen. Wenn es sich nicht um ein gültiges JSON handelt, wird es als UTF-8-Zeichenfolge behandelt und in ein Array der einzelnen Zeichencodepunkte konvertiert. </p> <p> Beispiel: Der Wert  <code> Hello World </code>  wird in das JSON-Array konvertiert: <pre> [ 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100] </pre> </p>" | ||||
|     "modeDesc" : "<h3> Buffereditor </h3> <p> Der Buffertyp wird als JSON-Array mit Bytewerten gespeichert. Der Editor versucht, den eingegebenen Wert als JSON-Array zu parsen. Wenn es sich nicht um ein gültiges JSON handelt, wird es als UTF-8-Zeichenfolge behandelt und in ein Array der einzelnen Zeichencodepunkte konvertiert. </p> <p> Beispiel: Der Wert  <code> Hello World </code>  wird in das JSON-Array konvertiert: <pre> [ 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100] </pre> </p>" | ||||
|   }, | ||||
|   "projects" : { | ||||
|     "config-git" : "Git-Client konfigurieren", | ||||
| @@ -826,4 +818,4 @@ | ||||
|       "code" : "code" | ||||
|     } | ||||
|   } | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -1,23 +1,23 @@ | ||||
| { | ||||
|   "info" : { | ||||
|     "tip0" : "Sie können die ausgewählten Knoten oder Verbindungen mit {{ core:delete-selection }} entfernen.", | ||||
|     "tip1" : "Suche nach Knoten mit {{ core:search }}", | ||||
|     "tip0" : "Sie können die ausgewählten Nodes oder Verbindungen mit {{ core:delete-selection }} entfernen.", | ||||
|     "tip1" : "Suche nach Nodes mit {{ core:search }}", | ||||
|     "tip2" : "{{ core:toggle-sidebar }} schaltet die Ansicht dieser Seitenleiste ein.", | ||||
|     "tip3" : "Sie können Ihre Palette von Knoten mit {{ core:manage-palette }} verwalten.", | ||||
|     "tip4" : "Ihre Flow-Konfigurationsknoten werden in der Seitenleiste angezeigt. Es kann über das Menü oder mit {{ core:show-config-tab }} aufgerufen werden.", | ||||
|     "tip3" : "Sie können Ihre Palette von Nodes mit {{ core:manage-palette }} verwalten.", | ||||
|     "tip4" : "Ihre Flow-Konfigurations-Nodes werden in der Seitenleiste angezeigt. Es kann über das Menü oder mit {{ core:show-config-tab }} aufgerufen werden.", | ||||
|     "tip5" : "Aktiviert oder inaktiviert diese Tipps von der Option in den Einstellungen", | ||||
|     "tip6" : "Verschieben Sie die ausgewählten Knoten mit Hilfe der [left] [up] [down] und [right] Tasten. Halten Sie [Shift] gedrückt, um das Fenster weiter zu schieben", | ||||
|     "tip7" : "Wenn Sie einen Knoten auf eine Verbindung ziehen, wird er in die Verbindung eingefügt.", | ||||
|     "tip8" : "Die ausgewählten Knoten exportieren oder die aktuelle Registerkarte mit {{ core:show-export-dialog }}", | ||||
|     "tip6" : "Verschieben Sie die ausgewählten Nodes mit Hilfe der [left] [up] [down] und [right] Tasten. Halten Sie [Shift] gedrückt, um das Fenster weiter zu schieben", | ||||
|     "tip7" : "Wenn Sie einen Node auf eine Verbindung ziehen, wird er in die Verbindung eingefügt.", | ||||
|     "tip8" : "Die ausgewählten Nodes exportieren oder die aktuelle Registerkarte mit {{ core:show-export-dialog }}", | ||||
|     "tip9" : "Importieren Sie einen Flow, indem Sie sein JSON in den Editor ziehen oder mit {{ core:show-import-dialog }}.", | ||||
|     "tip10" : "[Umschalt] [Klicken] und ziehen Sie auf einen Knotenanschluss, um alle angeschlossenen Verbindungen oder nur die ausgewählte zu verschieben.", | ||||
|     "tip10" : "[Umschalt] [Klicken] und ziehen Sie auf einen Node-Anschluss, um alle angeschlossenen Verbindungen oder nur die ausgewählte zu verschieben.", | ||||
|     "tip11" : "Die Registerkarte \"Info\" mit {{ core:show-info-tab }} oder der Registerkarte \"Debug\" mit {{ core:show-debug-tab }} anzeigen", | ||||
|     "tip12" : "[ctrl] [Klicken] in den Arbeitsbereich, um den Schnellhinzufügedialog zu öffnen.", | ||||
|     "tip13" : "Halten Sie [ctrl] gedrückt, wenn Sie auf einem Knotenanschluss klicken, um eine Schnellverbindung zu aktivieren.", | ||||
|     "tip14" : "Halten Sie [Umschalt] gedrückt, wenn Sie auf einen Knoten klicken, um auch alle verbundenen Knoten auszuwählen.", | ||||
|     "tip15" : "Halten Sie [ctrl] gedrückt, wenn Sie auf einen Knoten klicken, um ihn aus der aktuellen Auswahl hinzuzufügen oder zu entfernen.", | ||||
|     "tip13" : "Halten Sie [ctrl] gedrückt, wenn Sie auf einem Node-Anschluss klicken, um eine Schnellverbindung zu aktivieren.", | ||||
|     "tip14" : "Halten Sie [Umschalt] gedrückt, wenn Sie auf einen Node klicken, um auch alle verbundenen Nodes auszuwählen.", | ||||
|     "tip15" : "Halten Sie [ctrl] gedrückt, wenn Sie auf einen Node klicken, um ihn aus der aktuellen Auswahl hinzuzufügen oder zu entfernen.", | ||||
|     "tip16" : "Indexzungen wechseln mit {{ core:show-previous-tab }} und {{ core:show-next-tab }}", | ||||
|     "tip17" : "Sie können die Änderungen im Editierrahmen des Knotens mit {{ core:confirm-edit-tray }} bestätigen oder sie mit {{ core:cancel-edit-tray }} abbrechen.", | ||||
|     "tip18" : "Durch Drücken von {{ core:edit-selected-node }} wird der erste Knoten in der aktuellen Auswahl bearbeitet." | ||||
|     "tip17" : "Sie können die Änderungen im Editierrahmen des Nodes mit {{ core:confirm-edit-tray }} bestätigen oder sie mit {{ core:cancel-edit-tray }} abbrechen.", | ||||
|     "tip18" : "Durch Drücken von {{ core:edit-selected-node }} wird der erste Node in der aktuellen Auswahl bearbeitet." | ||||
|   } | ||||
| } | ||||
| @@ -53,7 +53,7 @@ | ||||
|   }, | ||||
|   "$now" : { | ||||
|     "args" : "", | ||||
|     "desc" : "Generiert eine Zeitmarke im ISO-8601-kompatiblen Format und gibt sie als Zeichenfolge zurück." | ||||
|     "desc" : "Generiert einen Zeitstempel im ISO-8601-kompatiblen Format und gibt sie als Zeichenfolge zurück." | ||||
|   }, | ||||
|   "$base64encode" : { | ||||
|     "args" : "Zeichenfolge", | ||||
| @@ -201,7 +201,7 @@ | ||||
|   }, | ||||
|   "$fromMillis" : { | ||||
|     "args" : "Anzahl", | ||||
|     "desc" : "Konvertieren Sie eine Zahl, die Millisekunden seit der Unix-Epoche (1. Januar 1970 (UTC)) in eine Zeitmarkenzeichenfolge im ISO 8601-Format darstellt." | ||||
|     "desc" : "Konvertieren Sie eine Zahl, die Millisekunden seit der Unix-Epoche (1. Januar 1970 (UTC)) enthält in eine Zeitangabe im ISO 8601-Format." | ||||
|   }, | ||||
|   "$formatNumber" : { | ||||
|     "args" : "Zahl, Bild [, Optionen]", | ||||
| @@ -212,8 +212,8 @@ | ||||
|     "desc" : "Transformiere die `Zahl` in eine Zeichenfolge und formatiert sie in eine ganze Zahl, die in der durch das `radix` -Argument angegebenen Zahlenbasis dargestellt wird. Wenn 'radix' nicht angegeben wird, wird standardmäßig die Basis 10 verwendet. 'radix` kann zwischen 2 und 36 liegen, andernfalls wird ein Fehler ausgelöst." | ||||
|   }, | ||||
|   "$toMillis" : { | ||||
|     "args" : "Zeitmarke", | ||||
|     "desc" : "Konvertieren Sie eine Zeichenfolge `Zeitmarke' im ISO 8601-Format in die Anzahl der Millisekunden seit der Unix-Epoche (1. Januar 1970 (UTC)) als Zahl. Es wird ein Fehler ausgelöst, wenn die Zeichenfolge nicht das richtige Format hat." | ||||
|     "args" : "timestamp", | ||||
|     "desc" : "Konvertieren Sie eine Zeitangabe im ISO 8601-Format in die Anzahl der Millisekunden seit der Unix-Epoche (1. Januar 1970 (UTC)) als Zahl. Es wird ein Fehler ausgelöst, wenn die Zeichenfolge nicht das richtige Format hat." | ||||
|   }, | ||||
|   "$env" : { | ||||
|     "args" : "arg", | ||||
|   | ||||
| @@ -24,10 +24,12 @@ | ||||
|         "delete": "Are you sure you want to delete '__label__'?", | ||||
|         "dropFlowHere": "Drop the flow here", | ||||
|         "addFlow": "Add Flow", | ||||
|         "listFlows": "List Flows", | ||||
|         "status": "Status", | ||||
|         "enabled": "Enabled", | ||||
|         "disabled":"Disabled", | ||||
|         "info": "Description" | ||||
|         "info": "Description", | ||||
|         "selectNodes": "Click nodes to select" | ||||
|     }, | ||||
|     "menu": { | ||||
|         "label": { | ||||
| @@ -41,7 +43,9 @@ | ||||
|                 "defaultDir": "Default", | ||||
|                 "ltr": "Left-to-right", | ||||
|                 "rtl": "Right-to-left", | ||||
|                 "auto": "Contextual" | ||||
|                 "auto": "Contextual", | ||||
|                 "language": "Language", | ||||
|                 "browserDefault": "Browser default" | ||||
|             }, | ||||
|             "sidebar": { | ||||
|                 "show": "Show sidebar" | ||||
| @@ -58,9 +62,6 @@ | ||||
|             "export": "Export", | ||||
|             "search": "Search flows", | ||||
|             "searchInput": "search your flows", | ||||
|             "clipboard": "Clipboard", | ||||
|             "library": "Library", | ||||
|             "examples": "Examples", | ||||
|             "subflows": "Subflows", | ||||
|             "createSubflow": "Create Subflow", | ||||
|             "selectionToSubflow": "Selection to Subflow", | ||||
| @@ -135,7 +136,12 @@ | ||||
|             "updated": "Project '__project__' updated", | ||||
|             "pull": "Project '__project__' reloaded", | ||||
|             "revert": "Project '__project__' reverted", | ||||
|             "merge-complete": "Git merge completed" | ||||
|             "merge-complete": "Git merge completed", | ||||
|             "setupCredentials": "Setup credentials", | ||||
|             "setupProjectFiles": "Setup project files", | ||||
|             "no": "No thanks", | ||||
|             "createDefault": "Create default project files", | ||||
|             "mergeConflict": "Show merge conflicts" | ||||
|         }, | ||||
|         "label": { | ||||
|             "manage-project-dep": "Manage project dependencies", | ||||
| @@ -148,6 +154,7 @@ | ||||
|         } | ||||
|     }, | ||||
|     "clipboard": { | ||||
|         "clipboard": "Clipboard", | ||||
|         "nodes": "Nodes", | ||||
|         "node": "__count__ node", | ||||
|         "node_plural": "__count__ nodes", | ||||
| @@ -157,7 +164,6 @@ | ||||
|         "flow_plural": "__count__ flows", | ||||
|         "subflow": "__count__ subflow", | ||||
|         "subflow_plural": "__count__ subflows", | ||||
|         "selectNodes": "Select the text above and copy to the clipboard.", | ||||
|         "pasteNodes": "Paste flow json or", | ||||
|         "selectFile": "select a file to import", | ||||
|         "importNodes": "Import nodes", | ||||
| @@ -176,7 +182,11 @@ | ||||
|             "all":"all flows", | ||||
|             "compact":"compact", | ||||
|             "formatted":"formatted", | ||||
|             "copy": "Export to clipboard" | ||||
|             "copy": "Copy to clipboard", | ||||
|             "export": "Export to library", | ||||
|             "exportAs": "Export as", | ||||
|             "overwrite": "Replace", | ||||
|             "exists": "<p><b>\"__file__\"</b> already exists.</p><p>Do you want to replace it?</p>" | ||||
|         }, | ||||
|         "import": { | ||||
|             "import": "Import to", | ||||
| @@ -266,8 +276,9 @@ | ||||
|         "newVersionError": "New Version doesn't contain valid JSON:" | ||||
|     }, | ||||
|     "subflow": { | ||||
|         "editSubflow": "Edit flow template: __name__", | ||||
|         "edit": "Edit flow template", | ||||
|         "editSubflowInstance": "Edit subflow instance: __name__", | ||||
|         "editSubflow": "Edit subflow template: __name__", | ||||
|         "edit": "Edit subflow template", | ||||
|         "subflowInstances": "There is __count__ instance of this subflow template", | ||||
|         "subflowInstances_plural": "There are __count__ instances of this subflow template", | ||||
|         "editSubflowProperties": "edit properties", | ||||
| @@ -299,10 +310,12 @@ | ||||
|         "addNewType": "Add new __type__...", | ||||
|         "nodeProperties": "node properties", | ||||
|         "label": "Label", | ||||
|         "color": "Color", | ||||
|         "portLabels": "Port labels", | ||||
|         "labelInputs": "Inputs", | ||||
|         "labelOutputs": "Outputs", | ||||
|         "settingIcon": "Icon", | ||||
|         "default": "default", | ||||
|         "noDefaultLabel": "none", | ||||
|         "defaultLabel": "use default label", | ||||
|         "searchIcons": "Search icons", | ||||
| @@ -310,8 +323,43 @@ | ||||
|         "description": "Description", | ||||
|         "show": "Show", | ||||
|         "hide": "Hide", | ||||
|         "locale": "Select UI Language", | ||||
|         "icon": "Icon", | ||||
|         "inputType": "Input type", | ||||
|         "inputs" : { | ||||
|             "input": "input", | ||||
|             "select": "select", | ||||
|             "checkbox": "checkbox", | ||||
|             "spinner": "spinner", | ||||
|             "none": "none", | ||||
|             "hidden": "hide property" | ||||
|         }, | ||||
|         "types": { | ||||
|             "str": "string", | ||||
|             "num": "number", | ||||
|             "bool": "bool", | ||||
|             "json": "JSON", | ||||
|             "bin": "buffer", | ||||
|             "env": "env variable" | ||||
|         }, | ||||
|         "menu": { | ||||
|             "input": "input", | ||||
|             "select": "select", | ||||
|             "checkbox": "checkbox", | ||||
|             "spinner": "spinner", | ||||
|             "hidden": "label only" | ||||
|         }, | ||||
|         "select": { | ||||
|             "label": "Label", | ||||
|             "value": "Value" | ||||
|         }, | ||||
|         "spinner": { | ||||
|             "min": "Minimum", | ||||
|             "max": "Maximum" | ||||
|         }, | ||||
|         "errors": { | ||||
|             "scopeChange": "Changing the scope will make it unavailable to nodes in other flows that use it" | ||||
|             "scopeChange": "Changing the scope will make it unavailable to nodes in other flows that use it", | ||||
|             "invalidProperties": "Invalid properties:" | ||||
|         } | ||||
|     }, | ||||
|     "keyboard": { | ||||
| @@ -339,25 +387,26 @@ | ||||
|         "pasteNode": "Paste nodes", | ||||
|         "undoChange": "Undo the last change performed", | ||||
|         "searchBox": "Open search box", | ||||
|         "managePalette": "Manage palette" | ||||
|         "managePalette": "Manage palette", | ||||
|         "actionList":"Action list" | ||||
|     }, | ||||
|     "library": { | ||||
|         "library": "Library", | ||||
|         "openLibrary": "Open Library...", | ||||
|         "saveToLibrary": "Save to Library...", | ||||
|         "typeLibrary": "__type__ library", | ||||
|         "unnamedType": "Unnamed __type__", | ||||
|         "exportToLibrary": "Export nodes to library", | ||||
|         "exportedToLibrary": "Nodes exported to library", | ||||
|         "dialogSaveOverwrite": "A __libraryType__ called __libraryName__ already exists. Overwrite?", | ||||
|         "invalidFilename": "Invalid filename", | ||||
|         "savedNodes": "Saved nodes", | ||||
|         "savedType": "Saved __type__", | ||||
|         "saveFailed": "Save failed: __message__", | ||||
|         "filename": "Filename", | ||||
|         "folder": "Folder", | ||||
|         "filenamePlaceholder": "file", | ||||
|         "fullFilenamePlaceholder": "a/b/file", | ||||
|         "folderPlaceholder": "a/b", | ||||
|         "breadcrumb": "Library" | ||||
|         "newFolder": "New folder", | ||||
|         "types": { | ||||
|             "local": "Local", | ||||
|             "examples": "Examples" | ||||
|         } | ||||
|     }, | ||||
|     "palette": { | ||||
|         "noInfo": "no information available", | ||||
| @@ -366,9 +415,13 @@ | ||||
|         "addCategory": "Add new...", | ||||
|         "label": { | ||||
|             "subflows": "subflows", | ||||
|             "network": "network", | ||||
|             "common": "common", | ||||
|             "input": "input", | ||||
|             "output": "output", | ||||
|             "function": "function", | ||||
|             "sequence": "sequence", | ||||
|             "parser": "parser", | ||||
|             "social": "social", | ||||
|             "storage": "storage", | ||||
|             "analysis": "analysis", | ||||
| @@ -505,8 +558,10 @@ | ||||
|             "none": "none", | ||||
|             "subflows": "subflows", | ||||
|             "flows": "flows", | ||||
|             "filterUnused":"unused", | ||||
|             "filterAll":"all", | ||||
|             "filterAll": "all", | ||||
|             "showAllConfigNodes": "Show all config nodes", | ||||
|             "filterUnused": "unused", | ||||
|             "showAllUnusedConfigNodes": "Show all unused config nodes", | ||||
|             "filtered": "__count__ hidden" | ||||
|         }, | ||||
|         "context": { | ||||
| @@ -518,7 +573,10 @@ | ||||
|             "node": "Node", | ||||
|             "flow": "Flow", | ||||
|             "global": "Global", | ||||
|             "deleteConfirm": "Are you sure you want to delete this item?" | ||||
|             "deleteConfirm": "Are you sure you want to delete this item?", | ||||
|             "autoRefresh": "Refresh on selection change", | ||||
|             "refrsh": "Refresh", | ||||
|             "delete": "Delete" | ||||
|         }, | ||||
|         "palette": { | ||||
|             "name": "Palette management", | ||||
| @@ -533,6 +591,7 @@ | ||||
|             "noSummaryAvailable": "No summary available", | ||||
|             "editDescription": "Edit project description", | ||||
|             "editDependencies": "Edit project dependencies", | ||||
|             "noDescriptionAvailable": "No description available", | ||||
|             "editReadme": "Edit README.md", | ||||
|             "showProjectSettings": "Show project settings", | ||||
|             "projectSettings": { | ||||
| @@ -543,14 +602,19 @@ | ||||
|                 "removeFromProject": "remove from project", | ||||
|                 "addToProject": "add to project", | ||||
|                 "files": "Files", | ||||
|                 "package": "Package", | ||||
|                 "flow": "Flow", | ||||
|                 "credentials": "Credentials", | ||||
|                 "package":"Package", | ||||
|                 "packageCreate":"File will be created when changes are saved", | ||||
|                 "fileNotExist":"File does not exist", | ||||
|                 "selectFile": "Select File", | ||||
|                 "invalidEncryptionKey": "Invalid encryption key", | ||||
|                 "encryptionEnabled": "Encryption enabled", | ||||
|                 "encryptionDisabled": "Encryption disabled", | ||||
|                 "setTheEncryptionKey": "Set the encryption key:", | ||||
|                 "resetTheEncryptionKey": "Reset the encryption key:", | ||||
|                 "changeTheEncryptionKey": "Change the encryption key:", | ||||
|                 "setTheEncryptionKey": "Set the encryption key", | ||||
|                 "resetTheEncryptionKey": "Reset the encryption key", | ||||
|                 "changeTheEncryptionKey": "Change the encryption key", | ||||
|                 "currentKey": "Current key", | ||||
|                 "newKey": "New key", | ||||
|                 "credentialsAlert": "This will delete all existing credentials", | ||||
| @@ -714,9 +778,21 @@ | ||||
|     "jsEditor": { | ||||
|         "title": "JavaScript editor" | ||||
|     }, | ||||
|     "textEditor": { | ||||
|         "title": "Text editor" | ||||
|     }, | ||||
|     "jsonEditor": { | ||||
|         "title": "JSON editor", | ||||
|         "format": "format JSON" | ||||
|         "format": "format JSON", | ||||
|         "rawMode": "Edit JSON", | ||||
|         "uiMode": "Visual editor", | ||||
|         "insertAbove": "Insert above", | ||||
|         "insertBelow": "Insert below", | ||||
|         "addItem": "Add item", | ||||
|         "copyPath": "Copy path to item", | ||||
|         "expandItems": "Expand items", | ||||
|         "collapseItems": "Collapse items", | ||||
|         "duplicate": "Duplicate" | ||||
|     }, | ||||
|     "markdownEditor": { | ||||
|         "title": "Markdown editor", | ||||
| @@ -749,6 +825,7 @@ | ||||
|             "desc2": "If you are not sure, you can skip this for now. You will still be able to create your first project from the 'Projects' menu at any time.", | ||||
|             "create": "Create Project", | ||||
|             "clone": "Clone Repository", | ||||
|             "openExistingProject": "Open existing project", | ||||
|             "not-right-now": "Not right now" | ||||
|         }, | ||||
|         "git-config": { | ||||
| @@ -905,8 +982,17 @@ | ||||
|     }, | ||||
|     "editor-tab": { | ||||
|         "properties": "Properties", | ||||
|         "envProperties": "Environment Variables", | ||||
|         "description": "Description", | ||||
|         "appearance": "Appearance", | ||||
|         "env": "Environment Variables" | ||||
|         "preview": "UI Preview", | ||||
|         "defaultValue": "Default value" | ||||
|     }, | ||||
|     "languages" : { | ||||
|         "de": "German", | ||||
|         "en-US": "English", | ||||
|         "ja": "Japanese", | ||||
|         "ko": "Korean", | ||||
|         "zh-CN": "Chinese(Simplified)" | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										2
									
								
								packages/node_modules/@node-red/editor-client/locales/en-US/infotips.json
									
									
									
									
										vendored
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						| @@ -4,7 +4,7 @@ | ||||
|         "tip1" : "Search for nodes using {{core:search}}", | ||||
|         "tip2" : "{{core:toggle-sidebar}} will toggle the view of this sidebar", | ||||
|         "tip3" : "You can manage your palette of nodes with {{core:manage-palette}}", | ||||
|         "tip4" : "Your flow configuration nodes are listed in the sidebar panel. It can been accessed from the menu or with {{core:show-config-tab}}", | ||||
|         "tip4" : "Your flow configuration nodes are listed in the sidebar panel. It can be accessed from the menu or with {{core:show-config-tab}}", | ||||
|         "tip5" : "Enable or disable these tips from the option in the settings", | ||||
|         "tip6" : "Move the selected nodes using the [left] [up] [down] and [right] keys. Hold [shift] to nudge them further", | ||||
|         "tip7" : "Dragging a node onto a wire will splice it into the link", | ||||
|   | ||||
| @@ -24,10 +24,12 @@ | ||||
|         "delete": "本当に '__label__' を削除しますか?", | ||||
|         "dropFlowHere": "ここにフローをドロップしてください", | ||||
|         "addFlow": "フローの追加", | ||||
|         "listFlows": "フロー一覧", | ||||
|         "status": "状態", | ||||
|         "enabled": "有効", | ||||
|         "disabled": "無効", | ||||
|         "info": "詳細" | ||||
|         "info": "詳細", | ||||
|         "selectNodes": "ノードをクリックして選択" | ||||
|     }, | ||||
|     "menu": { | ||||
|         "label": { | ||||
| @@ -41,7 +43,9 @@ | ||||
|                 "defaultDir": "標準", | ||||
|                 "ltr": "左から右", | ||||
|                 "rtl": "右から左", | ||||
|                 "auto": "文脈" | ||||
|                 "auto": "文脈", | ||||
|                 "language": "表示言語", | ||||
|                 "browserDefault": "ブラウザのデフォルト" | ||||
|             }, | ||||
|             "sidebar": { | ||||
|                 "show": "サイドバーを表示" | ||||
| @@ -58,9 +62,6 @@ | ||||
|             "export": "書き出し", | ||||
|             "search": "ノードを検索", | ||||
|             "searchInput": "ノードを検索", | ||||
|             "clipboard": "クリップボード", | ||||
|             "library": "ライブラリ", | ||||
|             "examples": "サンプル", | ||||
|             "subflows": "サブフロー", | ||||
|             "createSubflow": "サブフローを作成", | ||||
|             "selectionToSubflow": "選択部分をサブフロー化", | ||||
| @@ -79,7 +80,7 @@ | ||||
|             "projects-new": "新規", | ||||
|             "projects-open": "開く", | ||||
|             "projects-settings": "設定", | ||||
|             "showNodeLabelDefault": "追加したノードのラベルを表示する" | ||||
|             "showNodeLabelDefault": "追加したノードのラベルを表示" | ||||
|         } | ||||
|     }, | ||||
|     "actions": { | ||||
| @@ -107,7 +108,7 @@ | ||||
|             "undeployedChanges": "ノードの変更をデプロイしていません", | ||||
|             "nodeActionDisabled": "ノードのアクションは無効になっています", | ||||
|             "nodeActionDisabledSubflow": "ノードのアクションは、サブフロー内で無効になっています", | ||||
|             "missing-types": "不明なノードが存在するため、フローを停止しました。詳細はログを確認してください。", | ||||
|             "missing-types": "<p>不明なノードが存在するため、フローを停止しました。</p>", | ||||
|             "safe-mode": "<p>セーフモードでフローを停止しました</p><p>フローを変更し、再起動するために変更をデプロイできます</p>", | ||||
|             "restartRequired": "更新されたモジュールを有効化するため、Node-REDを再起動する必要があります", | ||||
|             "credentials_load_failed": "<p>認証情報を復号できないため、フローを停止しました</p><p>フローの認証情報ファイルは暗号化されています。しかし、プロジェクトの暗号鍵が存在しない、または不正です</p>", | ||||
| @@ -125,7 +126,7 @@ | ||||
|             "lostConnectionTry": "すぐに接続", | ||||
|             "cannotAddSubflowToItself": "サブフロー自身を追加できません", | ||||
|             "cannotAddCircularReference": "循環参照を検出したため、サブフローを追加できません", | ||||
|             "unsupportedVersion": "<p>サポートされていないバージョンのNode.jsを使用しています。</p><p><br/>最新のNode.js LTSに更新してください。</p>", | ||||
|             "unsupportedVersion": "<p>サポートされていないバージョンのNode.jsを使用しています。</p><p>最新のNode.js LTSに更新してください。</p>", | ||||
|             "failedToAppendNode": "<p>'__module__'がロードできませんでした。</p><p>__error__</p>" | ||||
|         }, | ||||
|         "project": { | ||||
| @@ -135,7 +136,12 @@ | ||||
|             "updated": "プロジェクト'__project__'を更新しました", | ||||
|             "pull": "プロジェクト'__project__'を再ロードしました", | ||||
|             "revert": "プロジェクト'__project__'を取り消しました", | ||||
|             "merge-complete": "Gitマージが完了しました" | ||||
|             "merge-complete": "Gitマージが完了しました", | ||||
|             "setupCredentials": "認証情報を設定", | ||||
|             "setupProjectFiles": "プロジェクトファイルの設定", | ||||
|             "no": "結構です", | ||||
|             "createDefault": "デフォルトのプロジェクトファイルを作成", | ||||
|             "mergeConflict": "マージの衝突を表示" | ||||
|         }, | ||||
|         "label": { | ||||
|             "manage-project-dep": "プロジェクトの依存関係の管理", | ||||
| @@ -148,6 +154,7 @@ | ||||
|         } | ||||
|     }, | ||||
|     "clipboard": { | ||||
|         "clipboard": "クリップボード", | ||||
|         "nodes": "ノード", | ||||
|         "node": "__count__ 個のノード", | ||||
|         "node_plural": "__count__ 個のノード", | ||||
| @@ -157,7 +164,6 @@ | ||||
|         "flow_plural": "__count__ 個のフロー", | ||||
|         "subflow": "__count__ 個のサブフロー", | ||||
|         "subflow_plural": "__count__ 個のサブフロー", | ||||
|         "selectNodes": "上のテキストを選択し、クリップボードへコピーしてください", | ||||
|         "pasteNodes": "JSON形式のフローデータを貼り付けてください", | ||||
|         "selectFile": "読み込むファイルを選択してください", | ||||
|         "importNodes": "フローをクリップボートから読み込み", | ||||
| @@ -176,7 +182,11 @@ | ||||
|             "all": "全てのタブ", | ||||
|             "compact": "インデントのないJSONフォーマット", | ||||
|             "formatted": "インデント付きのJSONフォーマット", | ||||
|             "copy": "書き出し" | ||||
|             "copy": "書き出し", | ||||
|             "export": "ライブラリに書き出し", | ||||
|             "exportAs": "書き出し先", | ||||
|             "overwrite": "更新", | ||||
|             "exists": "<p><b>\"__file__\"</b>は既に存在します。</p><p>更新しますか?</p>" | ||||
|         }, | ||||
|         "import": { | ||||
|             "import": "読み込み先", | ||||
| @@ -266,8 +276,9 @@ | ||||
|         "newVersionError": "新しいバージョンは正しいJSON形式ではありません:" | ||||
|     }, | ||||
|     "subflow": { | ||||
|         "editSubflow": "フローのテンプレートを編集: __name__", | ||||
|         "edit": "フローのテンプレートを編集", | ||||
|         "editSubflowInstance": "サブフローインスタンスを編集: __name__", | ||||
|         "editSubflow": "サブフローのテンプレートを編集: __name__", | ||||
|         "edit": "サブフローのテンプレートを編集", | ||||
|         "subflowInstances": "このサブフローのテンプレートのインスタンスが __count__ 個存在します", | ||||
|         "subflowInstances_plural": "このサブフローのテンプレートのインスタンスが __count__ 個存在します", | ||||
|         "editSubflowProperties": "プロパティを編集", | ||||
| @@ -299,10 +310,12 @@ | ||||
|         "addNewType": "新規に __type__ を追加...", | ||||
|         "nodeProperties": "プロパティ", | ||||
|         "label": "ラベル", | ||||
|         "color": "色", | ||||
|         "portLabels": "ポートラベル", | ||||
|         "labelInputs": "入力", | ||||
|         "labelOutputs": "出力", | ||||
|         "settingIcon": "アイコン", | ||||
|         "default": "デフォルト", | ||||
|         "noDefaultLabel": "なし", | ||||
|         "defaultLabel": "既定のラベルを使用", | ||||
|         "searchIcons": "アイコンを検索", | ||||
| @@ -310,8 +323,43 @@ | ||||
|         "description": "詳細", | ||||
|         "show": "表示", | ||||
|         "hide": "非表示", | ||||
|         "locale": "UI言語の選択", | ||||
|         "icon": "記号", | ||||
|         "inputType": "入力形式", | ||||
|         "inputs": { | ||||
|             "input": "入力", | ||||
|             "select": "メニュー", | ||||
|             "checkbox": "チェックボックス", | ||||
|             "spinner": "スピナー", | ||||
|             "none": "無し", | ||||
|             "hidden": "非表示" | ||||
|         }, | ||||
|         "types": { | ||||
|             "str": "文字列", | ||||
|             "num": "数値", | ||||
|             "bool": "真偽", | ||||
|             "json": "JSON", | ||||
|             "bin": "バッファ", | ||||
|             "env": "環境変数" | ||||
|         }, | ||||
|         "menu": { | ||||
|             "input": "入力", | ||||
|             "select": "選択", | ||||
|             "checkbox": "チェックボックス", | ||||
|             "spinner": "数値", | ||||
|             "hidden": "ラベルのみ" | ||||
|         }, | ||||
|         "select": { | ||||
|             "label": "ラベル", | ||||
|             "value": "値" | ||||
|         }, | ||||
|         "spinner": { | ||||
|             "min": "最小値", | ||||
|             "max": "最大値" | ||||
|         }, | ||||
|         "errors": { | ||||
|             "scopeChange": "スコープの変更は、他のフローで使われているノードを無効にします" | ||||
|             "scopeChange": "スコープの変更は、他のフローで使われているノードを無効にします", | ||||
|             "invalidProperties": "プロパティが不正です:" | ||||
|         } | ||||
|     }, | ||||
|     "keyboard": { | ||||
| @@ -339,25 +387,26 @@ | ||||
|         "pasteNode": "ノードを貼り付け", | ||||
|         "undoChange": "変更操作を戻す", | ||||
|         "searchBox": "ノードを検索", | ||||
|         "managePalette": "パレットの管理" | ||||
|         "managePalette": "パレットの管理", | ||||
|         "actionList": "動作一覧" | ||||
|     }, | ||||
|     "library": { | ||||
|         "library": "ライブラリ", | ||||
|         "openLibrary": "ライブラリを開く", | ||||
|         "saveToLibrary": "ライブラリへ保存", | ||||
|         "typeLibrary": "__type__ ライブラリ", | ||||
|         "unnamedType": "名前なし __type__", | ||||
|         "exportToLibrary": "ライブラリへフローを書き出す", | ||||
|         "exportedToLibrary": "ライブラリにノードを書き出しました", | ||||
|         "dialogSaveOverwrite": "__libraryName__ という __libraryType__ は既に存在しています 上書きしますか?", | ||||
|         "invalidFilename": "不正なファイル名", | ||||
|         "savedNodes": "フローを保存しました", | ||||
|         "savedType": "__type__ を保存しました", | ||||
|         "saveFailed": "保存に失敗しました: __message__", | ||||
|         "filename": "ファイル名", | ||||
|         "folder": "フォルダ", | ||||
|         "filenamePlaceholder": "ファイル", | ||||
|         "fullFilenamePlaceholder": "a/b/file", | ||||
|         "folderPlaceholder": "a/b", | ||||
|         "breadcrumb": "ライブラリ" | ||||
|         "newFolder": "新規フォルダ", | ||||
|         "types": { | ||||
|             "local": "ローカル", | ||||
|             "examples": "サンプル" | ||||
|         } | ||||
|     }, | ||||
|     "palette": { | ||||
|         "noInfo": "情報がありません", | ||||
| @@ -366,9 +415,13 @@ | ||||
|         "addCategory": "新規追加...", | ||||
|         "label": { | ||||
|             "subflows": "サブフロー", | ||||
|             "network": "ネットワーク", | ||||
|             "common": "共通", | ||||
|             "input": "入力", | ||||
|             "output": "出力", | ||||
|             "function": "機能", | ||||
|             "sequence": "シーケンス", | ||||
|             "parser": "パーサ", | ||||
|             "social": "ソーシャル", | ||||
|             "storage": "ストレージ", | ||||
|             "analysis": "分析", | ||||
| @@ -436,7 +489,7 @@ | ||||
|             "more": "+ さらに __count__ 個", | ||||
|             "errors": { | ||||
|                 "catalogLoadFailed": "<p>ノードのカタログの読み込みに失敗しました。</p><p>詳細はブラウザのコンソールを確認してください。</p>", | ||||
|                 "installFailed": "<p.追加処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>", | ||||
|                 "installFailed": "<p>追加処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>", | ||||
|                 "removeFailed": "<p>削除処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>", | ||||
|                 "updateFailed": "<p>更新処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>", | ||||
|                 "enableFailed": "<p>有効化処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>", | ||||
| @@ -505,8 +558,10 @@ | ||||
|             "none": "なし", | ||||
|             "subflows": "サブフロー", | ||||
|             "flows": "フロー", | ||||
|             "filterUnused": "未使用", | ||||
|             "filterAll": "全て", | ||||
|             "showAllConfigNodes": "全設定ノードを表示", | ||||
|             "filterUnused": "未使用", | ||||
|             "showAllUnusedConfigNodes": "未使用の全設定ノードを表示", | ||||
|             "filtered": "__count__ 個が無効" | ||||
|         }, | ||||
|         "context": { | ||||
| @@ -515,10 +570,13 @@ | ||||
|             "none": "選択されていません", | ||||
|             "refresh": "読み込みのため更新してください", | ||||
|             "empty": "データが存在しません", | ||||
|             "node": "Node", | ||||
|             "flow": "Flow", | ||||
|             "global": "Global", | ||||
|             "deleteConfirm": "データを削除しても良いですか?" | ||||
|             "node": "ノード", | ||||
|             "flow": "フロー", | ||||
|             "global": "グローバル", | ||||
|             "deleteConfirm": "データを削除しても良いですか?", | ||||
|             "autoRefresh": "選択対象が変化した場合更新", | ||||
|             "refrsh": "更新", | ||||
|             "delete": "削除" | ||||
|         }, | ||||
|         "palette": { | ||||
|             "name": "パレットの管理", | ||||
| @@ -530,9 +588,10 @@ | ||||
|             "description": "詳細", | ||||
|             "dependencies": "依存関係", | ||||
|             "settings": "設定", | ||||
|             "noSummaryAvailable": "サマリが存在しません", | ||||
|             "noSummaryAvailable": "要約が存在しません", | ||||
|             "editDescription": "プロジェクトの詳細を編集", | ||||
|             "editDependencies": "プロジェクトの依存関係を編集", | ||||
|             "noDescriptionAvailable": "詳細が存在しません", | ||||
|             "editReadme": "README.mdを編集", | ||||
|             "showProjectSettings": "プロジェクト設定を表示", | ||||
|             "projectSettings": { | ||||
| @@ -543,14 +602,18 @@ | ||||
|                 "removeFromProject": "プロジェクトから削除", | ||||
|                 "addToProject": "プロジェクトへ追加", | ||||
|                 "files": "ファイル", | ||||
|                 "package": "パッケージ", | ||||
|                 "flow": "フロー", | ||||
|                 "credentials": "認証情報", | ||||
|                 "packageCreate": "変更が保存された時にファイルが作成されます", | ||||
|                 "fileNotExist": "ファイルが存在しません", | ||||
|                 "selectFile": "ファイルを選択", | ||||
|                 "invalidEncryptionKey": "不正な暗号化キー", | ||||
|                 "encryptionEnabled": "暗号化が有効になっています", | ||||
|                 "encryptionDisabled": "暗号化が無効になっています", | ||||
|                 "setTheEncryptionKey": "暗号化キーを設定:", | ||||
|                 "resetTheEncryptionKey": "暗号化キーを初期化:", | ||||
|                 "changeTheEncryptionKey": "暗号化キーを変更:", | ||||
|                 "setTheEncryptionKey": "暗号化キーを設定", | ||||
|                 "resetTheEncryptionKey": "暗号化キーを初期化", | ||||
|                 "changeTheEncryptionKey": "暗号化キーを変更", | ||||
|                 "currentKey": "現在のキー", | ||||
|                 "newKey": "新規のキー", | ||||
|                 "credentialsAlert": "既存の認証情報は全て削除されます", | ||||
| @@ -714,9 +777,21 @@ | ||||
|     "jsEditor": { | ||||
|         "title": "JavaScriptエディタ" | ||||
|     }, | ||||
|     "textEditor": { | ||||
|         "title": "テキストエディタ" | ||||
|     }, | ||||
|     "jsonEditor": { | ||||
|         "title": "JSONエディタ", | ||||
|         "format": "JSONフォーマット" | ||||
|         "format": "JSONフォーマット", | ||||
|         "rawMode": "JSONを編集", | ||||
|         "uiMode": "ビジュアルエディタ", | ||||
|         "insertAbove": "上に挿入", | ||||
|         "insertBelow": "下に挿入", | ||||
|         "addItem": "要素を追加", | ||||
|         "copyPath": "要素のパスをコピー", | ||||
|         "expandItems": "要素を展開", | ||||
|         "collapseItems": "要素を折り畳む", | ||||
|         "duplicate": "複製" | ||||
|     }, | ||||
|     "markdownEditor": { | ||||
|         "title": "マークダウンエディタ", | ||||
| @@ -749,6 +824,7 @@ | ||||
|             "desc2": "とりあえずこの処理をスキップしてもかまいません。「プロジェクト」メニューから、いつでもプロジェクトの作成を開始できます。", | ||||
|             "create": "プロジェクトの作成", | ||||
|             "clone": "プロジェクトのクローン", | ||||
|             "openExistingProject": "既存のプロジェクトを開く", | ||||
|             "not-right-now": "後にする" | ||||
|         }, | ||||
|         "git-config": { | ||||
| @@ -879,7 +955,7 @@ | ||||
|             "confirm": "<p>デプロイされていない変更は失われます。</p><p>続けますか?</p>" | ||||
|         }, | ||||
|         "send-req": { | ||||
|             "auth-req": "リポジトリ対する認証が必要です", | ||||
|             "auth-req": "リポジトリに対する認証が必要です", | ||||
|             "username": "ユーザ名", | ||||
|             "password": "パスワード", | ||||
|             "passphrase": "パスフレーズ", | ||||
| @@ -905,8 +981,17 @@ | ||||
|     }, | ||||
|     "editor-tab": { | ||||
|         "properties": "プロパティ", | ||||
|         "envProperties": "環境変数", | ||||
|         "description": "説明", | ||||
|         "appearance": "外観", | ||||
|         "env": "環境変数" | ||||
|         "preview": "UIプレビュー", | ||||
|         "defaultValue": "デフォルト値" | ||||
|     }, | ||||
|     "languages": { | ||||
|         "de": "ドイツ語", | ||||
|         "en-US": "英語", | ||||
|         "ja": "日本語", | ||||
|         "ko": "韓国語", | ||||
|         "zh-CN": "中国語(簡体)" | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										2
									
								
								packages/node_modules/@node-red/editor-client/locales/ja/jsonata.json
									
									
									
									
										vendored
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						| @@ -221,7 +221,7 @@ | ||||
|     }, | ||||
|     "$eval": { | ||||
|         "args": "expr [, context]", | ||||
|         "desc": "JSONリテラルもしくはJSONata式を表す`expr`を評価します。評価の際には現在のコンテクストをコンテクストして用います。" | ||||
|         "desc": "JSONリテラルもしくはJSONata式を表す`expr`を評価します。評価の際には現在のコンテキストをコンテキストとして用います。" | ||||
|     }, | ||||
|     "$formatInteger": { | ||||
|         "args": "number, picture", | ||||
|   | ||||
							
								
								
									
										900
									
								
								packages/node_modules/@node-red/editor-client/locales/ko/editor.json
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						| @@ -0,0 +1,900 @@ | ||||
| { | ||||
|   "common": { | ||||
|     "label": { | ||||
|       "name": "이름", | ||||
|       "ok": "확인", | ||||
|       "done": "완료", | ||||
|       "cancel": "취소", | ||||
|       "delete": "삭제", | ||||
|       "close": "닫기", | ||||
|       "load": "열기", | ||||
|       "save": "저장", | ||||
|       "import": "가져오기", | ||||
|       "export": "내보내기", | ||||
|       "back": "뒤로", | ||||
|       "next": "앞으로", | ||||
|       "clone": "프로젝트 복제", | ||||
|       "cont": "계속하기" | ||||
|     } | ||||
|   }, | ||||
|   "workspace": { | ||||
|     "defaultName": "플로우 __number__", | ||||
|     "editFlow": "플로우 수정 : __name__", | ||||
|     "confirmDelete": "삭제 확인", | ||||
|     "delete": "정말로 '__label__' 을(를) 삭제하시겠습니까?", | ||||
|     "dropFlowHere": "플로우를 이곳에 가져오세요", | ||||
|     "addFlow": "플로우 추가", | ||||
|     "status": "상태", | ||||
|     "enabled": "사용가능", | ||||
|     "disabled": "사용불가능", | ||||
|     "info": "상세내역" | ||||
|   }, | ||||
|   "menu": { | ||||
|     "label": { | ||||
|       "view": { | ||||
|         "view": "창", | ||||
|         "grid": "눈금선", | ||||
|         "showGrid": "눈금선 보이기", | ||||
|         "snapGrid": "노드 배치 보조 켜기", | ||||
|         "gridSize": "눈금선 크기", | ||||
|         "textDir": "텍스트 방향", | ||||
|         "defaultDir": "기본", | ||||
|         "ltr": "왼쪽 -> 오른쪽", | ||||
|         "rtl": "오른쪽 -> 왼쪽", | ||||
|         "auto": "자동배분" | ||||
|       }, | ||||
|       "sidebar": { | ||||
|         "show": "우측사이드바 보이기" | ||||
|       }, | ||||
|       "palette": { | ||||
|         "show": "팔렛트 보이기" | ||||
|       }, | ||||
|       "settings": "설정", | ||||
|       "userSettings": "사용자 설정", | ||||
|       "nodes": "노드설정", | ||||
|       "displayStatus": "노드상태 보이기", | ||||
|       "displayConfig": "설정노드 보기", | ||||
|       "import": "가져오기", | ||||
|       "export": "내보내기", | ||||
|       "search": "플로우 겅색", | ||||
|       "searchInput": "플로우 검색", | ||||
|       "subflows": "보조 플로우", | ||||
|       "createSubflow": "보조 플로우 생성", | ||||
|       "selectionToSubflow": "보조 플로우 선택", | ||||
|       "flows": "플로우", | ||||
|       "add": "추가", | ||||
|       "rename": "이름변경", | ||||
|       "delete": "삭제", | ||||
|       "keyboardShortcuts": "단축키", | ||||
|       "login": "로그인", | ||||
|       "logout": "로그아웃", | ||||
|       "editPalette": "팔렛트 관리", | ||||
|       "other": "기타", | ||||
|       "showTips": "Tip 보기", | ||||
|       "help": "Node-RED 웹사이트", | ||||
|       "projects": "프로젝트", | ||||
|       "projects-new": "신규", | ||||
|       "projects-open": "열기", | ||||
|       "projects-settings": "프로젝트 설정", | ||||
|       "showNodeLabelDefault": "새로 추가된 노드의 라벨 보이기" | ||||
|     } | ||||
|   }, | ||||
|   "actions": { | ||||
|     "toggle-navigator": "네비게이터 표시/비표시", | ||||
|     "zoom-out": "축소하기", | ||||
|     "zoom-reset": "확대/축소 초기화", | ||||
|     "zoom-in": "확대하기" | ||||
|   }, | ||||
|   "user": { | ||||
|     "loggedInAs": "__name__ 에 로그인됨", | ||||
|     "username": "사용자명", | ||||
|     "password": "비밀번호", | ||||
|     "login": "로그인", | ||||
|     "loginFailed": "로그인 실패", | ||||
|     "notAuthorized": "권한이 없습니다", | ||||
|     "errors": { | ||||
|       "settings": "로그인 후 설정이 가능합니다", | ||||
|       "deploy": "로그인 후 배포가 가능합니다", | ||||
|       "notAuthorized": "이 기능은 로그인 후 사용가능합니다" | ||||
|     } | ||||
|   }, | ||||
|   "notification": { | ||||
|     "warning": "<strong>경고</strong>: __message__", | ||||
|     "warnings": { | ||||
|       "undeployedChanges": "변경사항 배포가 취소되었습니다", | ||||
|       "nodeActionDisabled": "노드 실행이 비활성화 되었습니다", | ||||
|       "nodeActionDisabledSubflow": "보조 플로우에서 노드 실행이 비활성화 되었습니다", | ||||
|       "missing-types": "<p>타입이 없는 노드로인해 플로우가 중지되었습니다</p>", | ||||
|       "safe-mode": "<p>[안전모드] 플로우가 정지되었습니다.</p><p>플로우의 수정과 배포가 가능합니다. 다시 배포버튼을 누르세요.</p>", | ||||
|       "restartRequired": "업그레이드한 모듈을 유효화하기 위해 Node-RED를 재시작 합니다 ", | ||||
|       "credentials_load_failed": "<p>인증정보 복호화에 실패하여 플로우가 멈췄습니다. </p><p>인증정보는 암호화 되어있습니다. 프로젝트의 암호화 키가 깨졌거나 정상적이지 않습니다.</p>", | ||||
|       "credentials_load_failed_reset": "<p>인증정보를 복호화할 수 없습니다</p><p>인증정보는 암호화 되어있습니다. 프로젝트의 암호화 키가 깨졌거나 정상적이지 않습니다.</p><p>다음 배포시 플로우의 인증정보는 초기화 될것입니다. 기존 모든 플로우의 인증정보가 지워집니다.</p>", | ||||
|       "missing_flow_file": "<p>프로젝트 플로우 파일을 찾을 수 없습니다</p><p>프로젝트의 플로우 파일이 설정되지 않았습니다</p>", | ||||
|       "missing_package_file": "<p>프로젝트 패키지 파일을 찾을 수 없습니다</p><p>프로젝트의 package.json 파일이 없습니다</p>", | ||||
|       "project_empty": "<p>프로젝트가 누락되어 있습니다.</p><p>기본 프로젝트 파일을 만드시겠습니까?<br/>그렇지 않으면 수동으로 편집가 외부에 프로젝트 파일을 만드셔야 합니다.</p>", | ||||
|       "project_not_found": "<p>'__project__' 가 없습니다.</p>", | ||||
|       "git_merge_conflict": "<p>변경사항 자동병합에 실패했습니다.</p><p>병합되지 않은 충돌을 수정 후 재등록 하세요.</p>" | ||||
|     }, | ||||
|     "error": "<strong>에러</strong>: __message__", | ||||
|     "errors": { | ||||
|       "lostConnection": "서버와 연결이 끊어졌습니다. 재접속을 시도합니다 ...", | ||||
|       "lostConnectionReconnect": "서버와 연결이 끊어졌습니다. __time__ 초 안에 재접속을 시도합니다.", | ||||
|       "lostConnectionTry": "지금 재접속", | ||||
|       "cannotAddSubflowToItself": "서브플로우 자기자신을 추가할 수 없습니다", | ||||
|       "cannotAddCircularReference": "순환참조가 발견되었습니다. 서브플로우를 추가할 수 없습니다", | ||||
|       "unsupportedVersion": "<p>지원하지 않는 Node.js를 사용하고 있습니다</p><p>Node.js LTS 버전을 사용해 주세요</p>", | ||||
|       "failedToAppendNode": "<p>'__module__' 읽어오기 실패</p><p>__error__</p>" | ||||
|     }, | ||||
|     "project": { | ||||
|       "change-branch": "로컬지점으로 '__project__' 변경", | ||||
|       "merge-abort": "Git 병합을 중지했습니다.", | ||||
|       "loaded": "'__project__' 프로젝트를 열었습니다", | ||||
|       "updated": "'__project__'가 변경 되었습니다", | ||||
|       "pull": "'__project__'를 다시 가져왔습니다", | ||||
|       "revert": "'__project__'를 취소했습니다", | ||||
|       "merge-complete": "Git 병합이 완료되었습니다" | ||||
|     }, | ||||
|     "label": { | ||||
|       "manage-project-dep": "프로젝트 의존성 관리", | ||||
|       "setup-cred": "인증정보 설정", | ||||
|       "setup-project": "프로젝트 파일 설정", | ||||
|       "create-default-package": "기본 패키지 파일 생성", | ||||
|       "no-thanks": "괜찮습니다", | ||||
|       "create-default-project": "기본 프로젝트 파일 생성", | ||||
|       "show-merge-conflicts": "병합 충돌 보여주기" | ||||
|     } | ||||
|   }, | ||||
|   "clipboard": { | ||||
|     "clipboard": "클립보드", | ||||
|     "nodes": "노드", | ||||
|     "node": "__count__ 개의 노드", | ||||
|     "node_plural": "__count__ 개의 노드", | ||||
|     "configNode": "__count__ 개의 설정 노드", | ||||
|     "configNode_plural": "__count__ 개의 설정 노드", | ||||
|     "flow": "__count__ 개의 플로우", | ||||
|     "flow_plural": "__count__ 개의 플로우", | ||||
|     "subflow": "__count__ 개의 서브 플로우", | ||||
|     "subflow_plural": "__count__ 개의 서브 플로우", | ||||
|     "pasteNodes": "여기에 노드를 붙여넣기 하세요", | ||||
|     "selectFile": "불러올 파일을 선택하세요", | ||||
|     "importNodes": "노드 불러오기", | ||||
|     "exportNodes": "클립보드에 노드 내보내기", | ||||
|     "download": "다운로드", | ||||
|     "importUnrecognised": "알 수 없는 형식 :", | ||||
|     "importUnrecognised_plural": "알 수 없는 형식 :", | ||||
|     "nodesExported": "클립보드에 노드 내보내기", | ||||
|     "nodesImported": "불러오기 : ", | ||||
|     "nodeCopied": "__count__개의 노드가 복사 되었습니다", | ||||
|     "nodeCopied_plural": "__count__개의 노드가 복사 되었습니다", | ||||
|     "invalidFlow": "정상적지 않은 플로우 : __message__", | ||||
|     "export": { | ||||
|       "selected": "선택된 노드", | ||||
|       "current": "현재 플로우", | ||||
|       "all": "모든 플로우", | ||||
|       "compact": "압축형식", | ||||
|       "formatted": "서식유지", | ||||
|       "copy": "클립보드로 내보내기" | ||||
|     }, | ||||
|     "import": { | ||||
|       "import": "가져올 위치 : ", | ||||
|       "newFlow": "새로운 플로우", | ||||
|       "errors": { | ||||
|         "notArray": "입력이 JSON 배열이 아닙니다", | ||||
|         "itemNotObject": "입력이 올바른 플로우가 아닙니다 - __index__는 노드 오브젝트가 아닙니다", | ||||
|         "missingId": "입력이 올바른 플로우가 아닙니다 - __index__의 'id' 속성이 없습니다", | ||||
|         "missingType": "입력이 올바른 플로우가 아닙니다 - __index__의 'type' 속성이 없습니다" | ||||
|       } | ||||
|     }, | ||||
|     "copyMessagePath": "Path가 복사 되었습니다", | ||||
|     "copyMessageValue": "Value가 복사 되었습니다", | ||||
|     "copyMessageValue_truncated": "Truncated value가 복사 되었습니다" | ||||
|   }, | ||||
|   "deploy": { | ||||
|     "deploy": "배포하기", | ||||
|     "full": "전체", | ||||
|     "fullDesc": "작업공간 내 모든 플로우를 배포합니다", | ||||
|     "modifiedFlows": "변경된 플로우", | ||||
|     "modifiedFlowsDesc": "변경사항이 있는 플로우만 배포합니다", | ||||
|     "modifiedNodes": "변경된 노드", | ||||
|     "modifiedNodesDesc": "변경사항이 있는 노드만 배포합니다", | ||||
|     "restartFlows": "플로우 재시작", | ||||
|     "restartFlowsDesc": "현재 배포된 플로우를 재시작합니다", | ||||
|     "successfulDeploy": "배포가 성공했습니다", | ||||
|     "successfulRestart": "플로우 재시작을 성공했습니다", | ||||
|     "deployFailed": "배포 실패 : __message__", | ||||
|     "unusedConfigNodes": "사용되지 않는 설정노드가 있습니다", | ||||
|     "unusedConfigNodesLink": "여기를 클릭하면 볼 수 있습니다", | ||||
|     "errors": { | ||||
|       "noResponse": "서버의 응답이 없습니다" | ||||
|     }, | ||||
|     "confirm": { | ||||
|       "button": { | ||||
|         "ignore": "무시", | ||||
|         "confirm": "배포 확인", | ||||
|         "review": "변경사항 보기", | ||||
|         "cancel": "취소", | ||||
|         "merge": "병합", | ||||
|         "overwrite": "무시하고 배포하기" | ||||
|       }, | ||||
|       "undeployedChanges": "배포되지 않은 변경사항이 있습니다.\n\n이 페이지를 떠나면 변경사항이 사라집니다", | ||||
|       "improperlyConfigured": "작업공간에 올바르게 구성되지 않은 노드가 있습니다 :", | ||||
|       "unknown": "작업공간에 알려지지 않는 노드타입이 있습니다 :", | ||||
|       "confirm": "배포하시겠습니까?", | ||||
|       "doNotWarn": "이 경고를 무시", | ||||
|       "conflict": "서버가 최신 플로우를 사용중입니다", | ||||
|       "backgroundUpdate": "플로우가 변경되었습니다", | ||||
|       "conflictChecking": "변경사항이 자동으로 병합될 수 있는지 확인", | ||||
|       "conflictAutoMerge": "변경사항에 충돌이 없습니다. 자동병합이 가능합니다", | ||||
|       "conflictManualMerge": "변경사항에 충돌이 있습니다. 배포하기 전에 충돌을 해결하세요", | ||||
|       "plusNMore": "+ __count__ 개 더보기" | ||||
|     } | ||||
|   }, | ||||
|   "eventLog": { | ||||
|     "title": "이벤트 로그", | ||||
|     "view": "로그 보기" | ||||
|   }, | ||||
|   "diff": { | ||||
|     "unresolvedCount": "__count__개의 충돌이 해결되지 않음", | ||||
|     "unresolvedCount_plural": "__count__개의 충돌이 해결되지 않음", | ||||
|     "globalNodes": "Global 노드", | ||||
|     "flowProperties": "플로우 속성", | ||||
|     "type": { | ||||
|       "added": "추가됨", | ||||
|       "changed": "변경됨", | ||||
|       "unchanged": "변경없음", | ||||
|       "deleted": "삭제됨", | ||||
|       "flowDeleted": "플로우 삭제됨", | ||||
|       "flowAdded": "플로우 추가됨", | ||||
|       "movedTo": "__id__로 이동됨", | ||||
|       "movedFrom": "__id__로 부터 이동됨" | ||||
|     }, | ||||
|     "nodeCount": "__count__ 개의 노드", | ||||
|     "nodeCount_plural": "__count__ 개의 노드", | ||||
|     "local": "로컬 변경사항", | ||||
|     "remote": "원격 변경사항", | ||||
|     "reviewChanges": "변경사항 살펴보기", | ||||
|     "noBinaryFileShowed": "바이너리파일 내용을 볼수 없습니다", | ||||
|     "viewCommitDiff": "변경사항 보기", | ||||
|     "compareChanges": "변경사항 비교", | ||||
|     "saveConflict": "충돌 해결내용 저장", | ||||
|     "conflictHeader": "<span>__unresolved__</span> 개 중 <span>__resolved__</span> 충돌이 해결됨", | ||||
|     "commonVersionError": "Common Version의 JSON 형식이 올바르지 않습니다 :", | ||||
|     "oldVersionError": "Old Version의 JSON 형식이 올바르지 않습니다 :", | ||||
|     "newVersionError": "New Version의 JSON 형식이 올바르지 않습니다 :" | ||||
|   }, | ||||
|   "subflow": { | ||||
|     "editSubflow": "플로우 템플릿 수정 : __name__", | ||||
|     "edit": "플로우 템플릿 수정", | ||||
|     "subflowInstances": "서브 플로우 템플릿에 __count__개의 인스턴스가 있습니다", | ||||
|     "subflowInstances_plural": "서브 플로우 템플릿에 __count__개의 인스턴스가 있습니다", | ||||
|     "editSubflowProperties": "속성 수정", | ||||
|     "input": "입력:", | ||||
|     "output": "출력:", | ||||
|     "deleteSubflow": "서브 플로우 삭제", | ||||
|     "info": "상세내역", | ||||
|     "category": "카테고리", | ||||
|     "errors": { | ||||
|       "noNodesSelected": "<strong>서브 플로우를 생성할 수 없습니다</strong> : 노드가 선택되지 않았습니다", | ||||
|       "multipleInputsToSelection": "<strong>서브 플로우를 생성할 수 없습니다</strong> : 복수의 입력이 선택되었습니다" | ||||
|     } | ||||
|   }, | ||||
|   "editor": { | ||||
|     "configEdit": "수정", | ||||
|     "configAdd": "추가", | ||||
|     "configUpdate": "변경", | ||||
|     "configDelete": "삭제", | ||||
|     "nodesUse": "__count__개의 노드가 이 설정을 사용중입니다", | ||||
|     "nodesUse_plural": "__count__개의 노드가 이 설정을 사용중입니다", | ||||
|     "addNewConfig": "__type__의 설정노드 추가", | ||||
|     "editNode": "__type__의 노드 수정", | ||||
|     "editConfig": "__type__의 설정노드 수정", | ||||
|     "addNewType": "__type__의 노드타입 추가 ...", | ||||
|     "nodeProperties": "노드 속성", | ||||
|     "label": "명칭", | ||||
|     "portLabels": "포트 설정", | ||||
|     "labelInputs": "입력", | ||||
|     "labelOutputs": "출력", | ||||
|     "settingIcon": "아이콘", | ||||
|     "noDefaultLabel": "없음", | ||||
|     "defaultLabel": "기본 명칭", | ||||
|     "searchIcons": "아이콘 조회", | ||||
|     "useDefault": "기본설정 사용", | ||||
|     "description": "상세 내역", | ||||
|     "show": "보이기", | ||||
|     "hide": "숨기기", | ||||
|     "errors": { | ||||
|       "scopeChange": "범위를 변경하게 되면 다른 플로우의 노드가 사용이 불가능해 집니다." | ||||
|     } | ||||
|   }, | ||||
|   "keyboard": { | ||||
|     "title": "키보드 단축키", | ||||
|     "keyboard": "키보드", | ||||
|     "filterActions": "필터", | ||||
|     "shortcut": "단축키", | ||||
|     "scope": "범위", | ||||
|     "unassigned": "미할당", | ||||
|     "global": "글로벌", | ||||
|     "workspace": "작업공간", | ||||
|     "selectAll": "모든 노드 선택", | ||||
|     "selectAllConnected": "모든 연결된 노드 선택", | ||||
|     "addRemoveNode": "노드 추가/삭제", | ||||
|     "editSelected": "선택된 노드 수정", | ||||
|     "deleteSelected": "선택된 노드나 링크를 삭제", | ||||
|     "importNode": "노드 불러오기", | ||||
|     "exportNode": "노드 내보내기", | ||||
|     "nudgeNode": "선택된 노드 이동 (1px)", | ||||
|     "moveNode": "선택된 노드 이동 (20px)", | ||||
|     "toggleSidebar": "사이드바 표시/비표시", | ||||
|     "togglePalette": "팔렛트 표시/비표시", | ||||
|     "copyNode": "선택된 노드 복사", | ||||
|     "cutNode": "선택된 노드 잘라내기", | ||||
|     "pasteNode": "노드 붙여넣기", | ||||
|     "undoChange": "마지막 변경 되돌리기", | ||||
|     "searchBox": "검색창 열기", | ||||
|     "managePalette": "팔렛트 관리" | ||||
|   }, | ||||
|   "library": { | ||||
|     "library": "라이브러리", | ||||
|     "openLibrary": "라이브러리 열기...", | ||||
|     "saveToLibrary": "라이브러리로 저장...", | ||||
|     "typeLibrary": "__type__ 라이브러리", | ||||
|     "unnamedType": "이름없는 __type__", | ||||
|     "dialogSaveOverwrite": "__libraryType__이 __libraryName__으로 이미 등록되어있습니다. 덮어쓸까요?", | ||||
|     "invalidFilename": "파일명이 올바르지 않습니다", | ||||
|     "savedNodes": "저장된 노드", | ||||
|     "savedType": "저장된 __type__", | ||||
|     "saveFailed": "저장 실패 : __message__", | ||||
|     "types": { | ||||
|         "examples": "예시" | ||||
|     } | ||||
|   }, | ||||
|   "palette": { | ||||
|     "noInfo": "정보 없음", | ||||
|     "filter": "필터", | ||||
|     "search": "모듈 검색", | ||||
|     "addCategory": "추가 ...", | ||||
|     "label": { | ||||
|       "subflows": "서브 플로우", | ||||
|       "input": "입력", | ||||
|       "output": "출력", | ||||
|       "function": "기능", | ||||
|       "social": "소셜", | ||||
|       "storage": "저장", | ||||
|       "analysis": "분석", | ||||
|       "advanced": "그 외" | ||||
|     }, | ||||
|     "actions": { | ||||
|       "collapse-all": "모든 카테고리 접기", | ||||
|       "expand-all": "모든 카테고리 펼치기" | ||||
|     }, | ||||
|     "event": { | ||||
|       "nodeAdded": "팔렛트에 노드가 추가되었습니다:", | ||||
|       "nodeAdded_plural": "팔렛트에 노드가 추가되었습니다:", | ||||
|       "nodeRemoved": "팔렛트에서 노드가 삭제되었습니다:", | ||||
|       "nodeRemoved_plural": "팔렛트에서 노드가 삭제되었습니다:", | ||||
|       "nodeEnabled": "노드가 활성화 되었습니다:", | ||||
|       "nodeEnabled_plural": "노드가 활성화 되었습니다:", | ||||
|       "nodeDisabled": "노드가 비활성화 되었습니다:", | ||||
|       "nodeDisabled_plural": "노드가 비활성화 되었습니다:", | ||||
|       "nodeUpgraded": "__module__ 노드모듈이 __version__으로 업그레이드 되었습니다" | ||||
|     }, | ||||
|     "editor": { | ||||
|       "title": "팔렛트 관리", | ||||
|       "palette": "팔렛트", | ||||
|       "times": { | ||||
|         "seconds": "몇초 전", | ||||
|         "minutes": "몇분 전", | ||||
|         "minutesV": "__count__분 전", | ||||
|         "hoursV": "__count__시간 전", | ||||
|         "hoursV_plural": "__count__시간 전", | ||||
|         "daysV": "__count__일 전", | ||||
|         "daysV_plural": "__count__일 전", | ||||
|         "weeksV": "__count__주 전", | ||||
|         "weeksV_plural": "__count__주 전", | ||||
|         "monthsV": "__count__달 전", | ||||
|         "monthsV_plural": "__count__달 전", | ||||
|         "yearsV": "__count__년 전", | ||||
|         "yearsV_plural": "__count__년 전", | ||||
|         "yearMonthsV": "__y__년, __count__월 전", | ||||
|         "yearMonthsV_plural": "__y__년, __count__월 전", | ||||
|         "yearsMonthsV": "__y__년, __count__월 전", | ||||
|         "yearsMonthsV_plural": "__y__년, __count__월 전" | ||||
|       }, | ||||
|       "nodeCount": "__label__ 개의 노드", | ||||
|       "nodeCount_plural": "__label__ 개의 노드", | ||||
|       "moduleCount": "__count__ 개의 모듈 사용가능", | ||||
|       "moduleCount_plural": "__count__ 개의 모듈 사용가능", | ||||
|       "inuse": "사용중", | ||||
|       "enableall": "모두 활성화", | ||||
|       "disableall": "모두 비활성화", | ||||
|       "enable": "활성화", | ||||
|       "disable": "비활성화", | ||||
|       "remove": "삭제", | ||||
|       "update": "__version__으로 업데이트", | ||||
|       "updated": "업데이트 됨", | ||||
|       "install": "설치", | ||||
|       "installed": "설치됨", | ||||
|       "conflict": "충돌", | ||||
|       "conflictTip": "<p>노드타입이 이미 설치 되어 있습니다.<br/>/p><p>충돌모듈 : <code>__module__</code></p>", | ||||
|       "loading": "카탈로그 여는중...", | ||||
|       "tab-nodes": "설치된 노드", | ||||
|       "tab-install": "설치가능한 노드", | ||||
|       "sort": "정렬:", | ||||
|       "sortAZ": "a-z", | ||||
|       "sortRecent": "최근", | ||||
|       "more": "+ __count__ 개 더 보기", | ||||
|       "errors": { | ||||
|         "catalogLoadFailed": "<p>노드 카탈로그를 설치하지 못했습니다.</p><p>브라우저 콘솔로그를 참고하세요.</p>", | ||||
|         "installFailed": "<p>설치 실패 : __module__</p><p>__message__</p><p>브라우저 콘솔로그를 참고하세요.</p>", | ||||
|         "removeFailed": "<p>삭제 실패 : __module__</p><p>__message__</p><p>브라우저 콘솔로그를 참고하세요.</p>", | ||||
|         "updateFailed": "<p>업데이트 실패 : __module__</p><p>__message__</p><p>브라우저 콘솔로그를 참고하세요.</p>", | ||||
|         "enableFailed": "<p>활성화 실패 : __module__</p><p>__message__</p><p>브라우저 콘솔로그를 참고하세요.</p>", | ||||
|         "disableFailed": "<p>비활성화 실패 : __module__</p><p>__message__</p><p>브라우저 콘솔로그를 참고하세요.</p>" | ||||
|       }, | ||||
|       "confirm": { | ||||
|         "install": { | ||||
|           "body": "<p>'__module__' 설치중</p><p>설치하기 전 노드 설명서를 읽으세요. 어떤 노드은 의존성이 자동으로 해결되지 않거나, Node-RED의 재시작이 필요할 수 있습니다.</p>", | ||||
|           "title": "노드 설치" | ||||
|         }, | ||||
|         "remove": { | ||||
|           "body": "<p>'__module__' 삭제중</p><p>Node-RED에서 노드를 제거합니다. Node-RED가 재시작되기까지 리소스가 계속 사용될 수도 있습니다.</p>", | ||||
|           "title": "노드 삭제" | ||||
|         }, | ||||
|         "update": { | ||||
|           "body": "<p>'__module__' 업데이트중</p><p>업데이트 반영을 위해 Node-RED를 수동으로 재시작해야 할 경우도 있습니다.</p>", | ||||
|           "title": "노드 변경" | ||||
|         }, | ||||
|         "cannotUpdate": { | ||||
|           "body": "이 노드에 대한 업데이트가 있지만, 팔레트 관리자가 변경할 수 있는 위치에 설치되지 않았습니다.<br/><br/>이 노드를 변경하는 방법은 설명서를 참조하세요" | ||||
|         }, | ||||
|         "button": { | ||||
|           "review": "노드정보 열기", | ||||
|           "install": "설치", | ||||
|           "remove": "삭제", | ||||
|           "update": "업데이트" | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "sidebar": { | ||||
|     "info": { | ||||
|       "name": "노드정보", | ||||
|       "tabName": "이름", | ||||
|       "label": "정보", | ||||
|       "node": "노드", | ||||
|       "type": "타입", | ||||
|       "module": "모듈", | ||||
|       "id": "ID", | ||||
|       "status": "상태", | ||||
|       "enabled": "활성화", | ||||
|       "disabled": "비활성화", | ||||
|       "subflow": "서브 플로우", | ||||
|       "instances": "인스턴스", | ||||
|       "properties": "속성", | ||||
|       "info": "정보", | ||||
|       "desc": "상세 내역", | ||||
|       "blank": "공백", | ||||
|       "null": "null", | ||||
|       "showMore": "더 보기", | ||||
|       "showLess": "간단히", | ||||
|       "flow": "플로우", | ||||
|       "selection": "선택", | ||||
|       "nodes": "__count__ 개의 노드", | ||||
|       "flowDesc": "플로우 상세내역", | ||||
|       "subflowDesc": "서브 플로우 상세내역", | ||||
|       "nodeHelp": "노드 도움말", | ||||
|       "none": "없음", | ||||
|       "arrayItems": "__count__ 개의 항목", | ||||
|       "showTips": "설정에서 도움말을 열 수 있습니다. " | ||||
|     }, | ||||
|     "config": { | ||||
|       "name": "노드 설정", | ||||
|       "label": "설정", | ||||
|       "global": "모든 플로우", | ||||
|       "none": "없음", | ||||
|       "subflows": "보조 플로우", | ||||
|       "flows": "플로우", | ||||
|       "filterAll": "전체", | ||||
|       "filterUnused": "미사용", | ||||
|       "filtered": "__count__ 개 숨김" | ||||
|     }, | ||||
|     "context": { | ||||
|       "name": "Context 데이터", | ||||
|       "label": "context", | ||||
|       "none": "선택 없음", | ||||
|       "refresh": "새로고침", | ||||
|       "empty": "공백", | ||||
|       "node": "노드", | ||||
|       "flow": "플로우", | ||||
|       "global": "Global", | ||||
|       "deleteConfirm": "정말로 이 아이템을 지우시겠습니까?" | ||||
|     }, | ||||
|     "palette": { | ||||
|       "name": "팔레트 관리", | ||||
|       "label": "팔레트" | ||||
|     }, | ||||
|     "project": { | ||||
|       "label": "프로젝트", | ||||
|       "name": "프로젝트", | ||||
|       "description": "상세내역", | ||||
|       "dependencies": "의존성", | ||||
|       "settings": "설정", | ||||
|       "noSummaryAvailable": "요약 없음", | ||||
|       "editDescription": "프로젝트 상세내역 수정", | ||||
|       "editDependencies": "프로젝트 의존성 수정", | ||||
|       "editReadme": "README.md 수정", | ||||
|       "showProjectSettings": "프로젝트 설정 보이기", | ||||
|       "projectSettings": { | ||||
|         "title": "프로젝트 설정", | ||||
|         "edit": "수정", | ||||
|         "none": "없음", | ||||
|         "install": "설치", | ||||
|         "removeFromProject": "프로젝트에서 삭제", | ||||
|         "addToProject": "프로젝트에 추가", | ||||
|         "files": "파일", | ||||
|         "flow": "플로우", | ||||
|         "credentials": "인증정보", | ||||
|         "invalidEncryptionKey": "잘못된 암호화 키", | ||||
|         "encryptionEnabled": "암호화 활성화", | ||||
|         "encryptionDisabled": "암호화 비활성화", | ||||
|         "setTheEncryptionKey": "암호화 키 설정 :", | ||||
|         "resetTheEncryptionKey": "암호화 키 초기화 :", | ||||
|         "changeTheEncryptionKey": "암호화 키 변경:", | ||||
|         "currentKey": "현재 키", | ||||
|         "newKey": "새로운 키", | ||||
|         "credentialsAlert": "모든 인증정보를 삭제합니다", | ||||
|         "versionControl": "버전 관리", | ||||
|         "branches": "브랜치", | ||||
|         "noBranches": "브랜치 없음", | ||||
|         "deleteConfirm": "다시 되돌릴 수 없습니다. '__name__'의 로컬 브랜치를 삭제 히시겠습니까?", | ||||
|         "unmergedConfirm": "'__name__'의 병합되지 않은 수정사항을 잃어버릴 수 있습니다. 그래도 삭제 하시겠습니까?", | ||||
|         "deleteUnmergedBranch": "미병합 브랜치 삭제", | ||||
|         "gitRemotes": "Git 원격", | ||||
|         "addRemote": "원격 추가", | ||||
|         "addRemote2": "원격 추가", | ||||
|         "remoteName": "원격 이름", | ||||
|         "nameRule": "A-Z 0-9 _ -의 문자만 사용이 가능합니다", | ||||
|         "url": "URL", | ||||
|         "urlRule": "https://, ssh:// or file://", | ||||
|         "urlRule2": "URL안에 사용자아이디/비밀번호를 사용하지 마세요", | ||||
|         "noRemotes": "원격 없음", | ||||
|         "deleteRemoteConfrim": "원격 '__name__'를 정말로 삭제하시겠습니까?", | ||||
|         "deleteRemote": "원격 삭제" | ||||
|       }, | ||||
|       "userSettings": { | ||||
|         "committerDetail": "Committer 상세내역", | ||||
|         "committerTip": "시스템 기본값을 사용하려면 비워두세요", | ||||
|         "userName": "사용자명", | ||||
|         "email": "이메일", | ||||
|         "sshKeys": "SSH키", | ||||
|         "sshKeysTip": "원격저장소에 대한 보안연결을 허용합니다", | ||||
|         "add": "키 추가", | ||||
|         "addSshKey": "SSH키 추가", | ||||
|         "addSshKeyTip": "public/private 키쌍을 추가합니다", | ||||
|         "name": "이름", | ||||
|         "nameRule": "A-Z 0-9 _ -의 문자만 사용이 가능합니다", | ||||
|         "passphrase": "암호", | ||||
|         "passphraseShort": "암호가 너무 짧습니다", | ||||
|         "optional": "선택항목", | ||||
|         "cancel": "취소", | ||||
|         "generate": "Key 생성", | ||||
|         "noSshKeys": "SSH키 없음", | ||||
|         "copyPublicKey": "클립보드로 public key 복사", | ||||
|         "delete": "키 삭제", | ||||
|         "gitConfig": "Git 설정", | ||||
|         "deleteConfirm": "다시 되돌릴 수 없습니다. __name__의 SSH키를 삭제하시겠습니까?" | ||||
|       }, | ||||
|       "versionControl": { | ||||
|         "unstagedChanges": "변경사항을 언스테이징", | ||||
|         "stagedChanges": "스테이징된 변경사항", | ||||
|         "unstageChange": "스테이징 되지않은 변경사항", | ||||
|         "stageChange": "변경사항을 스테이징", | ||||
|         "unstageAllChange": "모든 변경사항 언스테이징", | ||||
|         "stageAllChange": "모든 변경사항 스테이징", | ||||
|         "commitChanges": "변경사항 커밋", | ||||
|         "resolveConflicts": "충돌 해결", | ||||
|         "head": "HEAD", | ||||
|         "staged": "스테이징 됨", | ||||
|         "unstaged": "스테이징 안됨", | ||||
|         "local": "로컬", | ||||
|         "remote": "리모트", | ||||
|         "revert": "다시 복원할 수 없습니다. '__file__'을 되돌리시겠습니까?", | ||||
|         "revertChanges": "변경사항 되돌리기", | ||||
|         "localChanges": "로컬 변경사항", | ||||
|         "none": "없음", | ||||
|         "conflictResolve": "모든 충돌이 해결되었습니다. 변경사항을 적용하여 병합을 완료하세요", | ||||
|         "localFiles": "로컬 파일", | ||||
|         "all": "전체", | ||||
|         "unmergedChanges": "병합되지 않은 변경사항", | ||||
|         "abortMerge": "병합 중단", | ||||
|         "commit": "커밋", | ||||
|         "changeToCommit": "커밋 변경사항", | ||||
|         "commitPlaceholder": "커밋 메시지를 입력하세요", | ||||
|         "cancelCapital": "취소", | ||||
|         "commitCapital": "커밋", | ||||
|         "commitHistory": "커밋 이력", | ||||
|         "branch": "브랜치 :", | ||||
|         "moreCommits": "커밋 더보기", | ||||
|         "changeLocalBranch": "로컬 브랜치 변경", | ||||
|         "createBranchPlaceholder": "브렌치 찾기/생성", | ||||
|         "upstream": "업스트림", | ||||
|         "localOverwrite": "브랜치에 반영할 변경사항이 있습니다. 변경사항을 커밋하거나, 변경내역을 취소해야 합니다", | ||||
|         "manageRemoteBranch": "원격 브랜치 관리", | ||||
|         "unableToAccess": "원격저장소에 접근할 수 없습니다", | ||||
|         "retry": "재시도", | ||||
|         "setUpstreamBranch": "업스트림 브랜치로 설정", | ||||
|         "createRemoteBranchPlaceholder": "리모드 브랜치 찾기/생성", | ||||
|         "trackedUpstreamBranch": "생성된 브랜치는 트래킹된 업스트림 브랜치로 설정됩니다", | ||||
|         "selectUpstreamBranch": "브랜치가 생성될 것입니다. 트래킹된 업스트림 브랜치로 설정하세요", | ||||
|         "pushFailed": "리모트에 최신 커밋이 있기 때문에 push할 수 없습니다. 먼저 pull과 병합을 하신 후 push하세요", | ||||
|         "push": "push", | ||||
|         "pull": "pull", | ||||
|         "unablePull": "<p>원격저장소의 변경사항을 가져올 수 없습니다, 당신의 unstaged 로컬 변경사항을 덮어씁니다.</p><p>변경사항을 적용하고 다시 시도하세요</p>", | ||||
|         "showUnstagedChanges": "unstaged 변경사항 보여주기", | ||||
|         "connectionFailed": "원격저장소 연결 불가 : ", | ||||
|         "pullUnrelatedHistory": "<p>원격저장소에 연관없는 커밋 기록이 있습니다.</p><p>모든 변경사항을 로컬 저장소로 가져 오시겠습니까?</p>", | ||||
|         "pullChanges": "Pull 변경사항", | ||||
|         "history": "이력", | ||||
|         "projectHistory": "프로젝트 이력", | ||||
|         "daysAgo": "__count__일 전", | ||||
|         "daysAgo_plural": "__count__일 전", | ||||
|         "hoursAgo": "__count__시간 전", | ||||
|         "hoursAgo_plural": "__count__시간 전", | ||||
|         "minsAgo": "__count__분 전", | ||||
|         "minsAgo_plural": "__count__분 전", | ||||
|         "secondsAgo": "몇초 전", | ||||
|         "notTracking": "당신의 로컬 브랜치는 원격브랜치를 트래킹하고 있지 않습니다", | ||||
|         "statusUnmergedChanged": "당신의 저장소는 병합되지 않은 변경사항을 가지고 있습니다. 충돌을 수정하고 결과를 커밋하세요", | ||||
|         "repositoryUpToDate": "당신의 저장소는 최신상태 입니다", | ||||
|         "commitsAhead": "당신의 저장소가 원격지보다 __count__ 커밋을 앞서 있습니다. 이제 커밋 할 수 있습니다.", | ||||
|         "commitsAhead_plural": "당신의 저장소가 원격지보다  __count__ 커밋을 앞서 있습니다. 지금 커밋할 수 있습니다.", | ||||
|         "commitsBehind": "당신의 저장소가 원격지보다 __count__ 커밋이 늦습니다. 이제 pull 할 수 있습니다.", | ||||
|         "commitsBehind_plural": "당신의 저장소가 원격지보다 __count__ 커밋이 늦습니다. 이제 pull 할 수 있습니다.", | ||||
|         "commitsAheadAndBehind1": "당신의 저장소가 __count__ 커밋이 늦고, ", | ||||
|         "commitsAheadAndBehind1_plural": "당신의 저장소가 __count__ 커밋이 늦고 ", | ||||
|         "commitsAheadAndBehind2": "__count__ 커밋이 원격지보다 앞서 있습니다. ", | ||||
|         "commitsAheadAndBehind2_plural": "__count__ 커밋이 원격지보다 앞서 있습니다.", | ||||
|         "commitsAheadAndBehind3": "push하기전에 리모트 저장소에서 pull을 먼저 수행하세요.", | ||||
|         "commitsAheadAndBehind3_plural": "push하기전에 리모트 저장소에서 pull을 먼저 수행하세요.", | ||||
|         "refreshCommitHistory": "커밋 기록 새로고침", | ||||
|         "refreshChanges": "변경사항 새로고침" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "typedInput": { | ||||
|     "type": { | ||||
|       "str": "string", | ||||
|       "num": "number", | ||||
|       "re": "regular expression", | ||||
|       "bool": "boolean", | ||||
|       "json": "JSON", | ||||
|       "bin": "buffer", | ||||
|       "date": "timestamp", | ||||
|       "jsonata": "expression", | ||||
|       "env": "env variable" | ||||
|     } | ||||
|   }, | ||||
|   "editableList": { | ||||
|     "add": "추가" | ||||
|   }, | ||||
|   "search": { | ||||
|     "empty": "결과 없음", | ||||
|     "addNode": "노드 추가 ..." | ||||
|   }, | ||||
|   "expressionEditor": { | ||||
|     "functions": "기능", | ||||
|     "functionReference": "기능 참조", | ||||
|     "insert": "삽입", | ||||
|     "title": "JSONata 형식 에디터", | ||||
|     "test": "테스트", | ||||
|     "data": "예제 메세지", | ||||
|     "result": "결과", | ||||
|     "format": "형식", | ||||
|     "compatMode": "호환모드 사용", | ||||
|     "compatModeDesc": "<h3>JSONata호환 모드</h3><p> 입력된 형식은 <code>msg</code> 를 참조하고 있어, 호환모드로 평가합니다. 이 모드는 후에 폐지될 예정이니, <code>msg</code> 를 사용하지 않도록 해 주시길 바랍니다. </p><p> JSONata를 Node-RED에서 처음 지원했을 때에는 <code>msg</code> 오브젝트의 참조가 필요했습니다. 예를 들어 <code>msg.payload</code> 는 payload를 참고하기 위해 사용되었습니다. </p><p> 직접 메시지에 대하여 식을 평가하도록 되었기에, 이 형식은 사용할 수 없게 됩니다. payload를 참조하려면 단순히 <code>payload</code> 로 지정해 주십시오. </p>", | ||||
|     "noMatch": "결과 없음", | ||||
|     "errors": { | ||||
|       "invalid-expr": "유효하지 않은 JSONata 형식 :\n  __message__", | ||||
|       "invalid-msg": "유효하지 않은  예시 JSON 메세지 :\n  __message__", | ||||
|       "context-unsupported": "컨텍스트 기능을 테스트 할 수 없습니다.\n $flowContext 또는 $globalContext", | ||||
|       "eval": "형식 오류 :\n  __message__" | ||||
|     } | ||||
|   }, | ||||
|   "jsEditor": { | ||||
|     "title": "자바스크립트 에디터" | ||||
|   }, | ||||
|   "jsonEditor": { | ||||
|     "title": "JSON 에디터", | ||||
|     "format": "JSON 형식" | ||||
|   }, | ||||
|   "markdownEditor": { | ||||
|     "title": "Markdown 에디터", | ||||
|     "format": "Markdown 형식", | ||||
|     "heading1": "제목 레벨1", | ||||
|     "heading2": "제목 레벨2", | ||||
|     "heading3": "제목 레벨3", | ||||
|     "bold": "강조", | ||||
|     "italic": "이탤릭", | ||||
|     "code": "코드", | ||||
|     "ordered-list": "번호 목차", | ||||
|     "unordered-list": "목차", | ||||
|     "quote": "인용", | ||||
|     "link": "링크", | ||||
|     "horizontal-rule": "나눔줄", | ||||
|     "toggle-preview": "미리보기 전환" | ||||
|   }, | ||||
|   "bufferEditor": { | ||||
|     "title": "Buffer 에디터", | ||||
|     "modeString": "UTF-8 문자열로 처리", | ||||
|     "modeArray": "JSON 배열로 처리", | ||||
|     "modeDesc": "<h3>Buffer 에디터</h3><p>버퍼타입은 byet값의 JSON배열로 저장됩니다. 이 에디터는 입력된 값을 JSON 배열로 구문분석 합니다. 만약 유효한 JSON이 아닌경우 UTF-8 문자열로 처리되어 각 문자코드 번호의 배열로 변환됩니다.</p><p>예를들어 <code>Hello World</code> 라는 값은 다음의 JSON 배열로 변환됩니다.<pre>[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]</pre></p>" | ||||
|   }, | ||||
|   "projects": { | ||||
|     "config-git": "Git client 설정", | ||||
|     "welcome": { | ||||
|       "hello": "안녕하세요. Node-RED에서 프로젝트 기능을 이용할 수 있게 되었습니다.", | ||||
|       "desc0": "플로우 파일을 관리하는 새로운 방법이며, 버전을 관리할 수 도 있습니다.", | ||||
|       "desc1": "무선 프로젝트를 작성하거나 기존의 Git저장소에서 프로젝트를 복제할 수 있습니다.", | ||||
|       "desc2": "이 기능을 건너뛰어도 상관없습니다. 언제든지 프로젝트 메뉴에서 첫번째 프로젝트를 만들 수 있습니다.", | ||||
|       "create": "프로젝트 생성", | ||||
|       "clone": "프로젝트 복제", | ||||
|       "not-right-now": "나중에" | ||||
|     }, | ||||
|     "git-config": { | ||||
|       "setup": "버전관리 클라이언트를 설정합니다", | ||||
|       "desc0": "Node-RED는 오픈소스 Git로 버전관리를 할 수 있습니다. 프로젝트 파일의 변경사항을 추적하고 원격저장소로 push할 수 있습니다.", | ||||
|       "desc1": "당신이 변경사항을 커밋하면 git은 누가 변경사항을 만들었는지 사용자명과 이메일 정보를 기록합니다. 사용자명은 꼭 당신의 실명일 필요는 없습니다.", | ||||
|       "desc2": "당신의 Git 클라이언트는 아래와 같이 이미 설정되었습니다.", | ||||
|       "desc3": "당신은 git config의 설정탭에서 설정을 변경할 수 있습니다.", | ||||
|       "username": "사용자명", | ||||
|       "email": "이메일" | ||||
|     }, | ||||
|     "project-details": { | ||||
|       "create": "프로젝트 생성", | ||||
|       "desc0": "프로젝트는 Git 저장소로 관리되어집니다. 다른 사람과 협업하거나 공유하기 쉬워집니다.", | ||||
|       "desc1": "당신은 여러 개의 프로젝트를 생성할 수 있고 에디터에서 프로젝트를 선택할 수 있습니다.", | ||||
|       "desc2": "시작하려면 프로젝트 이름과 프로젝트의 상세설명이 필요합니다.", | ||||
|       "already-exists": "프로젝트가 이미 존재합니다", | ||||
|       "must-contain": "A-Z 0-9 _ -의 문자만 사용이 가능합니다", | ||||
|       "project-name": "프로젝트명", | ||||
|       "desc": "상세설명", | ||||
|       "opt": "옵션" | ||||
|     }, | ||||
|     "clone-project": { | ||||
|       "clone": "프로젝트 복제", | ||||
|       "desc0": "프로젝트가 있는 저장소를 가지고 있다면, 즉시 복제하여 사용할 수 있습니다.", | ||||
|       "already-exists": "프로젝트가 이미 존재합니다", | ||||
|       "must-contain": "A-Z 0-9 _ -의 문자만 사용이 가능합니다", | ||||
|       "project-name": "프로젝트명", | ||||
|       "no-info-in-url": "URL안에 사용자아이디/비밀번호를 사용하지 마세요", | ||||
|       "git-url": "Git 저장소 URL", | ||||
|       "protocols": "https://, ssh:// 혹은 file://", | ||||
|       "auth-failed": "인증 실패", | ||||
|       "username": "사용자명", | ||||
|       "passwd": "패스워드", | ||||
|       "ssh-key": "SSH키", | ||||
|       "passphrase": "패스워드", | ||||
|       "ssh-key-desc": "저장소를 복제하기 전에 접속을 위해 SSH키를 먼저 추가하세요.", | ||||
|       "ssh-key-add": "ssh키 추가", | ||||
|       "credential-key": "인증 암호화 키", | ||||
|       "cant-get-ssh-key": "에러! 선택한 SSH키 경로를 가져올 수 없습니다", | ||||
|       "already-exists2": "이미 존재합니다", | ||||
|       "git-error": "git 에러", | ||||
|       "connection-failed": "접속 실패", | ||||
|       "not-git-repo": "Git저장소가 아닙니다", | ||||
|       "repo-not-found": "저장소가 없습니다" | ||||
|     }, | ||||
|     "default-files": { | ||||
|       "create": "프로젝트 파일 생성", | ||||
|       "desc0": "프로젝트는 당신의 플로우, README, package.json 파일을 포함합니다.", | ||||
|       "desc1": "Git 저장소에서 관리하고 싶은 다른 파일들을 포함할 수 있습니다.", | ||||
|       "desc2": "당신이 이미 가지고 있는 flow, 자격증명파일이 프로젝트로 복사될 것입니다.", | ||||
|       "flow-file": "플로우 파일", | ||||
|       "credentials-file": "자격증명 파일" | ||||
|     }, | ||||
|     "encryption-config": { | ||||
|       "setup": "자격인증 파일의 암호화 설정", | ||||
|       "desc0": "플로우의 자격인증 파일 암호화를 통해 내용을 안전하게 유지할 수 있습니다.", | ||||
|       "desc1": "자격증명을 공용 Git저장소에 저장하려면 비밀키 구문을 제공하여 암호화 해야 합니다", | ||||
|       "desc2": "당신의 플로우 자격인증 파일은 암호화 되어 있지 않습니다.", | ||||
|       "desc3": "즉, 암호 및 액세스 토큰과 같은 내용을 파일에 액세스 할 수있는 모든 사람이 열람할 수 있습니다.", | ||||
|       "desc4": "자격증명을 공용 Git저장소에 저장하려면 비밀키 구문을 제공하여 암호화 해야 합니다", | ||||
|       "desc5": "당신의 플로우 자격증명파일은 setting파일의 credentialSecret속성으로 암호화되어 있습니다.", | ||||
|       "desc6": "당신의 플로우 자격증명파일은 시스템이 생성된 키에 의해 암호화 되어있습니다. 이 프로젝트용 새로운 비밀키를 지정해 주세요.", | ||||
|       "desc7": "키는 프로젝트파일과는 별개로 보존됩니다. 다른 Node-RED에서 이 프로젝트를 이용하려면 이 프로젝트의 키가 필요합니다.", | ||||
|       "credentials": "자격인증", | ||||
|       "enable": "암호화 활성화", | ||||
|       "disable": "암호화 비활성화", | ||||
|       "disabled": "비활성화됨", | ||||
|       "copy": "기존 키를 복사", | ||||
|       "use-custom": "커스텀키 사용", | ||||
|       "desc8": "자격증명 파일이 암호화되어 있지 않아, 간단히 해당내용이 열람될 수 있습니다.", | ||||
|       "create-project-files": "프로젝트 생성", | ||||
|       "create-project": "프로젝트 생성", | ||||
|       "already-exists": "이미 존재합니다.", | ||||
|       "git-error": "git 에러", | ||||
|       "git-auth-error": "git 인증 에러" | ||||
|     }, | ||||
|     "create-success": { | ||||
|       "success": "당신의 첫번째 프로젝트 생성이 성공하였습니다.", | ||||
|       "desc0": "앞으로 이와 같이 Node-RED를 사용할 수 있습니다.", | ||||
|       "desc1": "사이드바의 '정보'탭은 현재 활성화된 프로젝트를 보여줍니다. 이름 옆에 있는 버틀을 사용하여 프로젝트 설정화면을 불러올 수 있습니다.", | ||||
|       "desc2": "사이드바의 '이력'탭은 프로젝트의 변경된 파일을 확인하고 커밋할 수 있습니다. 커밋의 전체 기록을 보여주고 변경사항을 원격 저장소에 push할 수 있습니다." | ||||
|     }, | ||||
|     "create": { | ||||
|       "projects": "프로젝트", | ||||
|       "already-exists": "프로젝트가 이미 존재합니다", | ||||
|       "must-contain": "A-Z 0-9 _ -의 문자만 사용이 가능합니다", | ||||
|       "no-info-in-url": "URL안에 사용자아이디/비밀번호를 사용하지 마세요", | ||||
|       "open": "프로젝트 열기", | ||||
|       "create": "프로젝트 생성", | ||||
|       "clone": "프로젝트 복제", | ||||
|       "project-name": "프로젝트명", | ||||
|       "desc": "상세내역", | ||||
|       "opt": "옵션", | ||||
|       "flow-file": "플로우 파일", | ||||
|       "credentials": "자격증명", | ||||
|       "enable-encryption": "암호화 활성화", | ||||
|       "disable-encryption": "암호화 비활성화", | ||||
|       "encryption-key": "암호화 키", | ||||
|       "desc0": "자격증명 정보를 안전하게 하는 문구", | ||||
|       "desc1": "자격증명 파일이 암호화되어 있지 않아, 간단히 해당내용이 열람될 수 있습니다.", | ||||
|       "git-url": "Git 저장소 URL", | ||||
|       "protocols": "https://, ssh:// 혹은 file://", | ||||
|       "auth-failed": "인증 실패", | ||||
|       "username": "사용자명", | ||||
|       "password": "패스워드", | ||||
|       "ssh-key": "SSH키", | ||||
|       "passphrase": "패스워드", | ||||
|       "desc2": "저장소를 복제하기 전에 접속을 위해 SSH키를 먼저 추가하세요.", | ||||
|       "add-ssh-key": "ssh키 추가", | ||||
|       "credentials-encryption-key": "자격인증 암호화 키", | ||||
|       "already-exists-2": "이미 존재합니다", | ||||
|       "git-error": "git 에러", | ||||
|       "con-failed": "접속 실패", | ||||
|       "not-git": "git 저장소가 아닙니다", | ||||
|       "no-resource": "저장소아 없습니다", | ||||
|       "cant-get-ssh-key-path": "에러! 선택한 SSH키 경로를 가져올 수 없습니다.", | ||||
|       "unexpected_error": "예기치 않은 에러" | ||||
|     }, | ||||
|     "delete": { | ||||
|       "confirm": "프로젝트를 정말 지우시겠습니까?" | ||||
|     }, | ||||
|     "create-project-list": { | ||||
|       "search": "프로젝트 검색", | ||||
|       "current": "현재" | ||||
|     }, | ||||
|     "require-clean": { | ||||
|       "confirm": "<p>변경사항을 배포하지 않아 내용이 손실될 수 있습니다.</p><p>계속 할까요?</p>" | ||||
|     }, | ||||
|     "send-req": { | ||||
|       "auth-req": "저장소에 대한 인증이 필요합니다.", | ||||
|       "username": "사용자명", | ||||
|       "password": "패스워드", | ||||
|       "passphrase": "패스워드", | ||||
|       "retry": "재시도", | ||||
|       "update-failed": "인증 변경 실패", | ||||
|       "unhandled": "오류 응답 미처리" | ||||
|     }, | ||||
|     "create-branch-list": { | ||||
|       "invalid": "올바르지 않은 브랜치", | ||||
|       "create": "브랜치 생성", | ||||
|       "current": "현재" | ||||
|     }, | ||||
|     "create-default-file-set": { | ||||
|       "no-active": "활성화된 프로젝트 없이 기본 파일을 만들 수 없습니다.", | ||||
|       "no-empty": "비어있지 않은 프로젝트에 기본 파일을 만들 수 없습니다.", | ||||
|       "git-error": "git 에러" | ||||
|     }, | ||||
|     "errors": { | ||||
|       "no-username-email": "당신의 Git 클라이언트에 사용자명/이메일이 설정되지 않았습니다.", | ||||
|       "unexpected": "예기치 않은 에러가 발생했습니다.", | ||||
|       "code": "코드" | ||||
|     } | ||||
|   }, | ||||
|   "editor-tab": { | ||||
|     "properties": "속성", | ||||
|     "description": "상세 내역", | ||||
|     "appearance": "모양" | ||||
|   } | ||||
| } | ||||
							
								
								
									
										23
									
								
								packages/node_modules/@node-red/editor-client/locales/ko/infotips.json
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						| @@ -0,0 +1,23 @@ | ||||
| { | ||||
|     "info": { | ||||
|         "tip0": "{{core:delete-selection}}를 사용하여 선택된 노드나 링크를 삭제할 수 있습니다.", | ||||
|         "tip1": "{{core:search}}를 활용하여 노드를 검색할 수 있습니다.", | ||||
|         "tip2": "{{core:toggle-sidebar}}를 사용하여 사이드바를 표시/비표시 전환 할 수 있습니다.", | ||||
|         "tip3": "{{core:manage-palette}}를 사용하여 노드 팔레트를 관리 할 수 있습니다.", | ||||
|         "tip4": "플로우 안의 설정노드가 사이드바에 표시됩니다. 메뉴 혹은 {{core:show-config-tab}}를 사용하여 엑세스 할 수 있습니다.", | ||||
|         "tip5": "설정에서 이 팁을 활성화/비활성화 할 수 있습니다.", | ||||
|         "tip6": "[left] [up] [down] [right] 키를 사용하여 선택된 노드를 움직일 수 있습니다. [shift]키를 누른 채로 움직이면 이동폭이 늘어납니다.", | ||||
|         "tip7": "노드를 와이어 사이로 드래그 하여 연결할 수도 있습니다.", | ||||
|         "tip8": "{{core:show-export-dialog}}를 사용하여 선택한 노드 또는 현재탭을 내보낼 수 있습니다.", | ||||
|         "tip9": "JSON파일을 에디터로 드래그하거나 {{core:show-import-dialog}}를 사용하여 플로우 가져올 수 있습니다.", | ||||
|         "tip10": "[shift] [click] 하고서 드래그하여 선택한 와이어를 이동할 수 있습니다.", | ||||
|         "tip11": "{{core:show-info-tab}}를 사용하여 정보탭을 표시하거나 {{core:show-debug-tab}}를 사용하여 디버그탭을 표시할 수 있습니다.", | ||||
|         "tip12": "작업공간에서 [ctrl] [click]을 사용하여 빠른추가 대회상자를 열 수 있습니다.", | ||||
|         "tip13": "[ctrl]을 누른 상태로 노드의 포트를 클릭하여 빠르게 연결할 수 있습니다.", | ||||
|         "tip14": "[shift]를 누른 상태로 노드를 클릭하여 연결된 모든 노드를 선택할 수 있습니다.", | ||||
|         "tip15": "[ctrl]을 누른 상태로 노드를 클릭하여 현재 선택영역에 노드를 추가/제거 할 수 있습니다.", | ||||
|         "tip16": "{{core:show-previous-tab}}와 {{core:show-next-tab}}를 사용하여 탭을 전환할 수 있습니다.", | ||||
|         "tip17": "노드 편집 창에서 {{core : confirm-edit-tray}}로 변경 사항을 확인하거나 {{core : cancel-edit-tray}}로 취소 할 수 있습니다.", | ||||
|         "tip18": "{{core : edit-selected-node}}를 누르면 현재 선택 영역의 첫 번째 노드가 편집됩니다." | ||||
|     } | ||||
| } | ||||
							
								
								
									
										222
									
								
								packages/node_modules/@node-red/editor-client/locales/ko/jsonata.json
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						| @@ -0,0 +1,222 @@ | ||||
| { | ||||
|     "$string": { | ||||
|         "args": "arg", | ||||
|         "desc": "다음과 같은 규칙을 사용하여 인수 *arg*를 문자열로 변환합니다. \n\n - 문자열은 변경되지 않습니다. \n - 함수는 빈 문자열로 변환됩니다. \n - 무한대와 NaN은 JSON수치로 표현할 수 없기 때문에 오류처리 됩니다. \n - 다른 모든 값은 `JSON.stringify` 함수를 사용하여 JSON 문자열로 변환됩니다." | ||||
|     }, | ||||
|     "$length": { | ||||
|         "args": "str", | ||||
|         "desc": "문자열 `str`의 문자 수를 반환합니다. `str`가 문자열이 아닌 경우 에러를 반환합니다." | ||||
|     }, | ||||
|     "$substring": { | ||||
|         "args": "str, start[, length]", | ||||
|         "desc": "(zero-offset)의 `start`에서 시작하는 첫번째 인수 `str`의 문자열을 반환합니다. 만약 `length`가 지정된 경우, 부분 문자열은 최대 `length`의 크기를 갖습니다. 만약 `start` 인수가 음수이면 `str`의 끝에서부터의 문자수를 나타냅니다." | ||||
|     }, | ||||
|     "$substringBefore": { | ||||
|         "args": "str, chars", | ||||
|         "desc": "`str`에 `chars`문자가 처음으로 나오기 전까지의 부분문자열을 반환합니다. 만약 `chars`가 없으면 `str`을 반환합니다." | ||||
|     }, | ||||
|     "$substringAfter": { | ||||
|         "args": "str, chars", | ||||
|         "desc": "`str`에 `chars`문자가 처음으로 나온 이후의 부분문자열을 반환합니다. 만약 `chars`가 없으면 `str`을 반환합니다." | ||||
|     }, | ||||
|     "$uppercase": { | ||||
|         "args": "str", | ||||
|         "desc": "`str`의 문자를 대문자로 반환합니다." | ||||
|     }, | ||||
|     "$lowercase": { | ||||
|         "args": "str", | ||||
|         "desc": "`str`의 문자를 소문자로 반환합니다." | ||||
|     }, | ||||
|     "$trim": { | ||||
|         "args": "str", | ||||
|         "desc": "다음의 순서대로 `str`의 모든 공백을 자르고 정규화 합니다:\n\n - 모든 탭, 캐리지 리턴 및 줄 바꿈은 공백으로 대체됩니다. \n- 연속된 공백은 하나로 줄입니다.\n- 후행 및 선행 공백은 삭제됩니다.\n\n 만일 `str`이 지정되지 않으면 (예: 이 함수를 인수없이 호출), context값을 `str`의 값으로 사용합니다. `str`이 문자열이 아니면 에러가 발생합니다." | ||||
|     }, | ||||
|     "$contains": { | ||||
|         "args": "str, pattern", | ||||
|         "desc": "`str`이 `pattern`과 일치하면 `true`를, 일치하지 않으면 `false`를 반환합니다. 만약 `str`이 지정되지 않으면 (예: 이 함수를 인수없이 호출), context값을 `str`의 값으로 사용합니다. `pattern` 인수는 문자열이나 정규표현으로 할 수 있습니다." | ||||
|     }, | ||||
|     "$split": { | ||||
|         "args": "str[, separator][, limit]", | ||||
|         "desc": "`str`인수를 분할하여 부분문자열로 배열합니다. `str`이 문자열이 아니면 에러가 발생합니다. 생략가능한 인수 `separator`는 `str`을 분할하는 문자를 문자열 또는 정규표현으로 지정합니다. `separator`를 지정하지 않은 경우, 공백의 문자열로 간주하여 `str`은 단일 문자의 배열로 분리됩니다. `separator`가 문자열이 아니면 에러가 발생합니다. 생략가능한 인수 'limit`는 결과의 배열이 갖는 부분문자열의 최대수를 지정합니다. 이 수를 넘는 부분문자열은 파기됩니다. `limit`가 지정되지 않으면`str`은 결과 배열의 크기의 제한없이 완전히 분리됩니다. `limit`이 음수인 경우 에러가 발생합니다." | ||||
|     }, | ||||
|     "$join": { | ||||
|         "args": "array[, separator]", | ||||
|         "desc": "문자열의 배열을 생략가능한 인수 `separator`로 구분한 하나의 문자열로 연결합니다. 배열 `array`가 문자열이 아닌 요소를 포함하는 경우, 에러가 발생합니다. `separator`를 지정하지 않은 경우, 공백의 문자열로 간주합니다(예: 문자열간의 `separator`없음). `separator`가 문자열이 아닌 경우, 에러가 발생합니다." | ||||
|     }, | ||||
|     "$match": { | ||||
|         "args": "str, pattern [, limit]", | ||||
|         "desc": "`str`문자열에 `pattern`를 적용하여, 오브젝트 배열을 반환합니다. 배열요소의 오브젝트는 `str`중 일치하는 부분의 정보를 보유합니다." | ||||
|     }, | ||||
|     "$replace": { | ||||
|         "args": "str, pattern, replacement [, limit]", | ||||
|         "desc": "`str`문자열에서 `pattern` 패턴을 검색하여, `replacement`로 대체합니다.\n\n임의이ㅡ 인수 `limit`는 대체 횟수의 상한값을 지정합니다." | ||||
|     }, | ||||
|     "$now": { | ||||
|         "args": "", | ||||
|         "desc": "ISO 8601 호환 형식으로 타임 스탬프를 생성하고 이를 문자열로 반환합니다." | ||||
|     }, | ||||
|     "$base64encode": { | ||||
|         "args": "string", | ||||
|         "desc": "ASCII 문자열을 base 64 표현으로 변환합니다. 문자열의 각 문자는 이진 데이터의 바이트로 처리됩니다. 이렇게 하려면 문자열의 모든 문자가 URI로 인코딩 된 문자열을 포함하고, 0x00에서 0xFF 범위에 있어야합니다. 해당 범위를 벗어난 유니 코드 문자는 지원되지 않습니다" | ||||
|     }, | ||||
|     "$base64decode": { | ||||
|         "args": "string", | ||||
|         "desc": "UTF-8코드페이지를 이용하여, Base 64형식의 바이트값을 문자열로 변환합니다." | ||||
|     }, | ||||
|     "$number": { | ||||
|         "args": "arg", | ||||
|         "desc": "`arg`를 다음과 같은 규칙을 사요하여 숫자로 변환합니다. :\n\n - 숫자는 변경되지 않습니다.\n – 올바른 JSON의 숫자는 숫자 그대로 변환됩니다.\n – 그 외의 형식은 에러를 발생합니다." | ||||
|     }, | ||||
|     "$abs": { | ||||
|         "args": "number", | ||||
|         "desc": "`number`의 절대값을 반환합니다." | ||||
|     }, | ||||
|     "$floor": { | ||||
|         "args": "number", | ||||
|         "desc": "`number`를 `number`보다 같거나 작은 정수로 내림하여 반환합니다." | ||||
|     }, | ||||
|     "$ceil": { | ||||
|         "args": "number", | ||||
|         "desc": "`number`를 `number`와 같거나 큰 정수로 올림하여 반환합니다." | ||||
|     }, | ||||
|     "$round": { | ||||
|         "args": "number [, precision]", | ||||
|         "desc": "인수 `number`를 반올림한 값을 반환합니다. 임의의 인수 `precision`에는 반올립에서 사용할 소수점이하의 자릿수를 지정합니다." | ||||
|     }, | ||||
|     "$power": { | ||||
|         "args": "base, exponent", | ||||
|         "desc": "기수 `base`의 값을 지수 `exponent`만큼의 거듭 제곱으로 반환합니다." | ||||
|     }, | ||||
|     "$sqrt": { | ||||
|         "args": "number", | ||||
|         "desc": "인수 `number`의 제곱근을 반환합니다." | ||||
|     }, | ||||
|     "$random": { | ||||
|         "args": "", | ||||
|         "desc": "0이상 1미만의 의사난수를 반환합니다." | ||||
|     }, | ||||
|     "$millis": { | ||||
|         "args": "", | ||||
|         "desc": "Unix Epoch (1970 년 1 월 1 일 UTC)부터 경과된 밀리 초 수를 숫자로 반환합니다. 평가대상식에 포함되는 $millis()의 모든 호출은 모두 같은 값을 반환합니다." | ||||
|     }, | ||||
|     "$sum": { | ||||
|         "args": "array", | ||||
|         "desc": "숫자 배열 `array`의 합계를 반환합니다. `array`에 숫자가 아닌 요소가 있는 경우, 에러가 발생합니다." | ||||
|     }, | ||||
|     "$max": { | ||||
|         "args": "array", | ||||
|         "desc": "숫자 배열 `array`에서 최대값을 반환합니다. `array`에 숫자가 아닌 요소가 있는 경우, 에러가 발생합니다." | ||||
|     }, | ||||
|     "$min": { | ||||
|         "args": "array", | ||||
|         "desc": "숫자 배열 `array`에서 최소값을 반환합니다. `array`에 숫자가 아닌 요소가 있는 경우, 에러가 발생합니다." | ||||
|     }, | ||||
|     "$average": { | ||||
|         "args": "array", | ||||
|         "desc": "숫자 배열 `array`에서 평균값을 반환합니다. `array`에 숫자가 아닌 요소가 있는 경우, 에러가 발생합니다." | ||||
|     }, | ||||
|     "$boolean": { | ||||
|         "args": "arg", | ||||
|         "desc": "`arg` 값을 다음의 규칙에 의해 Boolean으로 변환합니다::\n\n - `Boolean` : 변환하지 않음\n - `string`: 비어있음 : `false`\n - `string`: 비어있지 않음 : `true`\n - `number`: `0` : `false`\n - `number`: 0이 아님 : `true`\n - `null` : `false`\n - `array`: 비어있음 : `false`\n - `array`: `true`로 변환된 요소를 가짐 : `true`\n - `array`: 모든 요소가 `false`로 변환 : `false`\n - `object`: 비어있음 : `false`\n - `object`: 비어있지 않음 : `true`\n - `function` : `false`" | ||||
|     }, | ||||
|     "$not": { | ||||
|         "args": "arg", | ||||
|         "desc": "인수의 부정을 Boolean으로 변환합니다. `arg`는 가장먼저boolean으로 변환됩니다." | ||||
|     }, | ||||
|     "$exists": { | ||||
|         "args": "arg", | ||||
|         "desc": "`arg` 식의 평가값이 존재하는 경우 `true`, 식의 평가결과가 미정의인 경우 (예: 존재하지 않는 참조필드로의 경로)는 `false`를 반환합니다." | ||||
|     }, | ||||
|     "$count": { | ||||
|         "args": "array", | ||||
|         "desc": "`array`의 요소 갯수를 반환합니다." | ||||
|     }, | ||||
|     "$append": { | ||||
|         "args": "array, array", | ||||
|         "desc": "두개의 `array`를 병합합니다." | ||||
|     }, | ||||
|     "$sort": { | ||||
|         "args": "array [, function]", | ||||
|         "desc": "배열 `array`의 모든 값을 순서대로 정렬하여 반환합니다. \n\n 비교함수 `function`을 이용하는 경우, 비교함수는 아래와 같은 두개의 인수를 가져야 합니다. \n\n `function(left,right)` \n\n 비교함수는 left와 right의 두개의 값을 비교하기에, 값을 정렬하는 처리에서 호출됩니다. 만약 요구되는 정렬에서 left값을 right값보다 뒤로 두고싶은 경우에는, 비교함수는 치환을 나타내는 Boolean형의 ``true`를, 그렇지 않은 경우에는 `false`를 반환해야 합니다." | ||||
|     }, | ||||
|     "$reverse": { | ||||
|         "args": "array", | ||||
|         "desc": "`array`에 포함된 모든 값의 순서를 역순으로 변환하여 반환합니다." | ||||
|     }, | ||||
|     "$shuffle": { | ||||
|         "args": "array", | ||||
|         "desc": "`array`에 포함된 모든 값의 순서를 랜덤으로 반환합니다." | ||||
|     }, | ||||
|     "$zip": { | ||||
|         "args": "array, ...", | ||||
|         "desc": "배열 `array1` ... arrayN`의 위치 0, 1, 2…. 의 값으로 구성된 convolved (zipped) 배열을 반환합니다." | ||||
|     }, | ||||
|     "$keys": { | ||||
|         "args": "object", | ||||
|         "desc": "`object` 키를 포함하는 배열을 반환합니다. 인수가 오브젝트의 배열이면 반환되는 배열은 모든 오브젝트에있는 모든 키의 중복되지 않은 목록이 됩니다." | ||||
|     }, | ||||
|     "$lookup": { | ||||
|         "args": "object, key", | ||||
|         "desc": "`object` 내의 `key`가 갖는 값을 반환합니다. 최초의 인수가 객체의 배열 인 경우, 배열 내의 모든 오브젝트를 검색하여, 존재하는 모든 키가 갖는 값을 반환합니다." | ||||
|     }, | ||||
|     "$spread": { | ||||
|         "args": "object", | ||||
|         "desc": "`object`의 키/값 쌍별로 각 요소가 하나인 오브젝트 배열로 분할합니다. 만일 오브젝트 배열인 경우, 배열의 결과는 각 오브젝트에서 얻은 키/값 쌍의 오브젝트를 갖습니다." | ||||
|     }, | ||||
|     "$merge": { | ||||
|         "args": "array<object>", | ||||
|         "desc": "`object`배열을 하나의 `object`로 병합합니다. 병합결과의 오브젝트는 입력배열내의 각 오브젝트의 키/값 쌍을 포함합니다. 입력 오브젝트가 같은 키를 가질경우, 반환 된 `object`에는 배열 마지막의 오브젝트의 키/값이 격납됩니다. 입력 배열이 오브젝트가 아닌 요소를 포함하는 경우, 에러가 발생합니다." | ||||
|     }, | ||||
|     "$sift": { | ||||
|         "args": "object, function", | ||||
|         "desc": "함수 `function`을 충족시키는 `object` 인수 키/값 쌍만 포함하는 오브젝트를 반환합니다. \n\n 함수 `function` 다음과 같은 인수를 가져야 합니다 : \n\n `function(value [, key [, object]])`" | ||||
|     }, | ||||
|     "$each": { | ||||
|         "args": "object, function", | ||||
|         "desc": "`object`의 각 키/값 쌍에, 함수`function`을 적용한 값의 배열을 반환합니다." | ||||
|     }, | ||||
|     "$map": { | ||||
|         "args": "array, function", | ||||
|         "desc": "`array`의 각 값에 `function`을 적용한 결과로 이루어진 배열을 반환합니다. \n\n 함수 `function`은 다음과 같은 인수를 가져야 합니다.  \n\n `function(value[, index[, array]])`" | ||||
|     }, | ||||
|     "$filter": { | ||||
|         "args": "array, function", | ||||
|         "desc": "`array`의 값중, 함수 `function`의 조건을 만족하는 값으로 이루어진 배열을 반환합니다. \n\n 함수 `function`은 다음과 같은 형식을 가져야 합니다.  \n\n `function(value[, index[, array]])`" | ||||
|     }, | ||||
|     "$reduce": { | ||||
|         "args": "array, function [, init]", | ||||
|         "desc": "배열의 각 요소값에 함수 `function`을 연속적으로 적용하여 얻어지는 집계값을 반환합니다. `function`의 적용에는 직전의 `function`의 적용결과와 요소값이 인수로 주어집니다. \n\n 함수 `function`은 인수를 두개 뽑아, 배열의 각 요소 사이에 배치하는 중치연산자처럼 작용해야 합니다. \n\n 임의의 인수 `init`에는 집약시의 초기값을 설정합니다." | ||||
|     }, | ||||
|     "$flowContext": { | ||||
|         "args": "string[, string]", | ||||
|         "desc": "플로우 컨텍스트 속성을 취득합니다." | ||||
|     }, | ||||
|     "$globalContext": { | ||||
|         "args": "string[, string]", | ||||
|         "desc": "플로우의 글로벌 컨텍스트 속성을 취득합니다." | ||||
|     }, | ||||
|     "$pad": { | ||||
|         "args": "string, width [, char]", | ||||
|         "desc": "문자수가 인수 `width`의 절대값이상이 되도록, 필요한 경우 여분의 패딩을 사용하여 `string`의 복사본을 반환합니다. \n\n `width`가 양수인 경우, 오른쪽으로 채워지고, 음수이면 왼쪽으로 채워집니다. \n\n 임의의 `char`인수에는 이 함수에서 사용할 패딩을 지정합니다. 지정하지 않는 경우에는, 기본값으로 공백을 사용합니다." | ||||
|     }, | ||||
|     "$fromMillis": { | ||||
|         "args": "number", | ||||
|         "desc": "Unix Epoch (1970 년 1 월 1 일 UTC) 이후의 밀리 초를 나타내는 숫자를 ISO 8601 형식의 타임 스탬프 문자열로 변환합니다." | ||||
|     }, | ||||
|     "$formatNumber": { | ||||
|         "args": "number, picture [, options]", | ||||
|         "desc": "`number`를 문자열로 변환하고 `picture` 문자열에 지정된 표현으로 서식을 변경합니다. \n\n 이 함수의 동작은 XPath F&O 3.1사양에 정의된 XPath/XQuery함수의 fn:format-number의 동작과 같습니다. 인수의 문자열 picture은 fn:format-number 과 같은 구문으로 수치의 서식을 정의합니다. \n\n 임의의 제3 인수 `option`은 소수점기호와 같은 기본 로케일 고유의 서식설정문자를 덮어쓰는데에 사용됩니다. 이 인수를 지정할 경우, XPath F&O 3.1사양의 수치형식에 기술되어있는 name/value 쌍을 포함하는 오브젝트여야 합니다." | ||||
|     }, | ||||
|     "$formatBase": { | ||||
|         "args": "number [, radix]", | ||||
|         "desc": "`number`를 인수 `radix`에 지정한 값을 기수로하는 문자열로 변환합니다. `radix`가 지정되지 않은 경우, 기수 10이 기본값으로 설정됩니다. `radix`에는 2~36의 값을 설정할 수 있고, 그 외의 값의 경우에는 에러가 발생합니다." | ||||
|     }, | ||||
|     "$toMillis": { | ||||
|         "args": "timestamp", | ||||
|         "desc": "ISO 8601 형식의 `timestamp`를 Unix Epoch (1970 년 1 월 1 일 UTC) 이후의 밀리 초 수로 변환합니다. 문자열이 올바른 형식이 아닌 경우 에러가 발생합니다." | ||||
|     }, | ||||
|     "$env": { | ||||
|         "args": "arg", | ||||
|         "desc": "환경변수를 값으로 반환합니다.\n\n 이 함수는 Node-RED 정의 함수입니다." | ||||
|     } | ||||
| } | ||||
| @@ -50,9 +50,6 @@ | ||||
|             "export": "导出", | ||||
|             "search": "查找流程", | ||||
|             "searchInput": "查找流程", | ||||
|             "clipboard": "剪贴板", | ||||
|             "library": "库", | ||||
|             "examples": "例子", | ||||
|             "subflows": "子流程", | ||||
|             "createSubflow": "新建子流程", | ||||
|             "selectionToSubflow": "将选择部分更改为子流程", | ||||
| @@ -100,8 +97,8 @@ | ||||
|         } | ||||
|     }, | ||||
|     "clipboard": { | ||||
|         "clipboard": "剪贴板", | ||||
|         "nodes": "节点", | ||||
|         "selectNodes": "选择上面的文本并复制到剪贴板", | ||||
|         "pasteNodes": "在这里粘贴节点", | ||||
|         "importNodes": "导入节点", | ||||
|         "exportNodes": "导出节点至剪贴板", | ||||
| @@ -237,6 +234,7 @@ | ||||
|         "managePalette": "管理面板" | ||||
|     }, | ||||
|     "library": { | ||||
|         "library": "库", | ||||
|         "openLibrary": "打开库...", | ||||
|         "saveToLibrary": "保存到库...", | ||||
|         "typeLibrary": "__type__类型库", | ||||
| @@ -247,12 +245,9 @@ | ||||
|         "savedNodes": "保存的节点", | ||||
|         "savedType": "已保存__type__", | ||||
|         "saveFailed": "保存失败: __message__", | ||||
|         "filename": "文件名", | ||||
|         "folder": "文件夹", | ||||
|         "filenamePlaceholder": "文件", | ||||
|         "fullFilenamePlaceholder": "a/b/文件", | ||||
|         "folderPlaceholder": "a/b", | ||||
|         "breadcrumb": "库" | ||||
|         "types": { | ||||
|             "examples": "例子" | ||||
|         } | ||||
|     }, | ||||
|     "palette": { | ||||
|         "noInfo": "无可用信息", | ||||
| @@ -390,8 +385,8 @@ | ||||
|             "none": "无", | ||||
|             "subflows": "子流程", | ||||
|             "flows": "流程", | ||||
|             "filterUnused": "未使用", | ||||
|             "filterAll": "所有", | ||||
|             "filterUnused": "未使用", | ||||
|             "filtered": "__count__ 个隐藏" | ||||
|         }, | ||||
|         "palette": { | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@node-red/editor-client", | ||||
|     "version": "0.20.0-beta.5", | ||||
|     "version": "1.0.2", | ||||
|     "license": "Apache-2.0", | ||||
|     "repository": { | ||||
|         "type": "git", | ||||
|   | ||||
| Before Width: | Height: | Size: 291 B | 
							
								
								
									
										1
									
								
								packages/node_modules/@node-red/editor-client/src/images/deploy-flows-o.svg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| <svg width="27" height="18" xmlns="http://www.w3.org/2000/svg"><g color="#000"><path fill="#fff" d="M0 5.002h10v5H0zM17 .002h10v5H17z"/><path d="M17 13.002h10v5H17z"/></g><path d="M9.5 7.502h2l4-5h2" fill="none" stroke="#fff" stroke-width="1.5"/></svg> | ||||
| After Width: | Height: | Size: 252 B | 
| Before Width: | Height: | Size: 386 B | 
							
								
								
									
										1
									
								
								packages/node_modules/@node-red/editor-client/src/images/deploy-flows.svg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| <svg width="32" height="32" xmlns="http://www.w3.org/2000/svg"><path color="#000" fill="#8c101c" d="M0 .002h32v32H0z"/><g color="#000"><path fill="#fff" d="M2 13.002h10v5H2zM19 8.002h10v5H19z"/><path d="M19 21.002h10v5H19z"/></g><path d="M11.5 15.502h2l4-5h2" fill="none" stroke="#fff" stroke-width="1.5"/></svg> | ||||
| After Width: | Height: | Size: 312 B | 
| Before Width: | Height: | Size: 289 B | 
							
								
								
									
										1
									
								
								packages/node_modules/@node-red/editor-client/src/images/deploy-full-o.svg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| <svg width="27" height="18" xmlns="http://www.w3.org/2000/svg"><g fill="#fff" color="#000"><path d="M0 5h10v5H0zM17 0h10v5H17zM17 13h10v5H17z"/></g><path d="M9.5 7.5h2l4-5h2" fill="none" stroke="#fff" stroke-width="1.5"/></svg> | ||||
| After Width: | Height: | Size: 227 B | 
| Before Width: | Height: | Size: 368 B | 
							
								
								
									
										1
									
								
								packages/node_modules/@node-red/editor-client/src/images/deploy-full.svg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| <svg width="32" height="32" xmlns="http://www.w3.org/2000/svg"><path color="#000" fill="#8c101c" d="M0 0h32v32H0z"/><g fill="#fff" color="#000"><path d="M2 13h10v5H2zM19 8h10v5H19zM19 21h10v5H19z"/></g><path d="M11.5 15.5h2l4-5h2" fill="none" stroke="#fff" stroke-width="1.5"/></svg> | ||||
| After Width: | Height: | Size: 283 B | 
| Before Width: | Height: | Size: 290 B | 
							
								
								
									
										1
									
								
								packages/node_modules/@node-red/editor-client/src/images/deploy-nodes-o.svg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| <svg width="27" height="18" xmlns="http://www.w3.org/2000/svg"><path color="#000" d="M0 5.002h10v5H0zM17 13.002h10v5H17z"/><path d="M9.5 7.502h2l4-5h2" fill="none" stroke="#000" stroke-width="1.5"/><path color="#000" fill="#fff" d="M17 .002h10v5H17z"/></svg> | ||||
| After Width: | Height: | Size: 258 B | 
| Before Width: | Height: | Size: 392 B | 
							
								
								
									
										1
									
								
								packages/node_modules/@node-red/editor-client/src/images/deploy-nodes.svg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| <svg width="32" height="32" xmlns="http://www.w3.org/2000/svg"><path color="#000" fill="#8c101c" d="M0 .002h32v32H0z"/><path color="#000" d="M2 13.002h10v5H2zM19 21.002h10v5H19z"/><path d="M11.5 15.502h2l4-5h2" fill="none" stroke="#000" stroke-width="1.5"/><path color="#000" fill="#fff" d="M19 8.002h10v5H19z"/></svg> | ||||
| After Width: | Height: | Size: 318 B | 
| Before Width: | Height: | Size: 1015 B | 
							
								
								
									
										1
									
								
								packages/node_modules/@node-red/editor-client/src/images/deploy-reload.svg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| <svg width="32" height="32" xmlns="http://www.w3.org/2000/svg"><g color="#000"><path fill="#8c101c" d="M0 .006h32v32H0z"/><path d="M11.81 25.429a10.02 10.02 0 0 0 4.19.914c5.562 0 10.107-4.545 10.107-10.106S21.562 6.131 16 6.131 5.895 10.676 5.895 16.237h3.368c0-3.74 2.997-6.737 6.738-6.737s6.737 2.996 6.737 6.737-2.996 6.738-6.737 6.738a6.775 6.775 0 0 1-2.533-.486l1.43-3.48-6.947 1.317 2.13 8.485z" fill="#fff" style="isolation:auto;mix-blend-mode:normal;text-decoration-color:#000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-transform:none;white-space:normal"/></g></svg> | ||||
| After Width: | Height: | Size: 606 B | 
| Before Width: | Height: | Size: 393 B | 
							
								
								
									
										1
									
								
								packages/node_modules/@node-red/editor-client/src/images/icons/arrow-in.svg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| <svg width="40" height="60" viewBox="0, 0, 40, 60" xmlns="http://www.w3.org/2000/svg"><path d="M18 5v12H7v26h11v12l14-25z" fill="#fff"/></svg> | ||||
| After Width: | Height: | Size: 143 B | 
| Before Width: | Height: | Size: 386 B | 
| Before Width: | Height: | Size: 386 B | 
| Before Width: | Height: | Size: 1019 B | 
							
								
								
									
										1
									
								
								packages/node_modules/@node-red/editor-client/src/images/node-red.svg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| <svg width="46.994" height="18.006" xmlns="http://www.w3.org/2000/svg"><g stroke="#d6d6d6"><g fill="#9e3131" stroke-linejoin="round" stroke-width="3.847" transform="matrix(.25848 0 0 .2614 -63.87 -108.483)"><rect x="249.04" y="435.92" width="50.294" height="22.953" ry="6.608"/><rect x="345.63" y="416.93" width="50.294" height="22.953" ry="6.608"/><rect x="376.71" y="459.01" width="50.294" height="22.953" ry="6.608"/></g><path d="M301.04 447.43c24.406.184 7.107-18.84 42.708-19.03M374.82 470.48c-46.966.538-28.989-22.664-73.619-22.944" fill="none" stroke-width="5.771" transform="matrix(.25848 0 0 .2614 -63.87 -108.483)"/></g></svg> | ||||
| After Width: | Height: | Size: 636 B | 
| Before Width: | Height: | Size: 600 B | 
| Before Width: | Height: | Size: 410 B | 
							
								
								
									
										1
									
								
								packages/node_modules/@node-red/editor-client/src/images/subflow_tab.svg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| <svg width="40" height="40" viewBox="0, 0, 40, 40" xmlns="http://www.w3.org/2000/svg"><path d="M25 16h7c.58 0 1-.42 1-1v-2c0-.58-.42-1-1-1h-7c-.58 0-1 .42-1 1v2c0 .58.42 1 1 1zM8 28h7c.58 0 1-.42 1-1v-2c0-.58-.42-1-1-1H8c-.58 0-1 .42-1 1v2c0 .58.42 1 1 1zm-.416 11C5.624 39 4 37.375 4 35.416V4.582C4 2.622 5.625 1 7.584 1h24.832C34.376 1 36 2.623 36 4.582v30.834C36 37.376 34.375 39 32.416 39zM32 27H19c0 2.19-1.81 4-4 4H7v4.416c0 .35.235.584.584.584h24.832c.35 0 .584-.235.584-.584v-8.417zm1-2v-6h-8c-2.19 0-4-1.81-4-4h-1c-4.333-.002-8.667.004-13 0v6h8c2.19 0 4 1.81 4 4h13zm0-16V4.582c0-.35-.235-.582-.584-.582H7.584C7.234 4 7 4.233 7 4.582v8.417c4.333.002 8.667.001 13 .001h1c0-2.19 1.81-4 4-4z" color="#000" fill="#333"/></svg> | ||||
| After Width: | Height: | Size: 732 B | 
| Before Width: | Height: | Size: 638 B | 
							
								
								
									
										1
									
								
								packages/node_modules/@node-red/editor-client/src/images/typedInput/09.svg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| <svg width="26" height="36" viewBox="0, 0, 26, 36" xmlns="http://www.w3.org/2000/svg"><path d="M14.16 27.38l1.555-.144c.132.731.383 1.261.755 1.591.371.33.848.494 1.429.494.497 0 .931-.114 1.303-.341.377-.228.686-.53.926-.908.24-.383.44-.899.602-1.546a8.122 8.122 0 0 0 .233-2.3 3.732 3.732 0 0 1-1.33 1.258 3.605 3.605 0 0 1-1.815.476c-1.09 0-2.013-.395-2.768-1.186s-1.133-1.834-1.133-3.128c0-1.336.393-2.411 1.178-3.226.79-.815 1.78-1.223 2.966-1.223.856 0 1.638.231 2.345.692.713.462 1.253 1.12 1.618 1.978.372.85.557 2.085.557 3.702 0 1.684-.182 3.026-.548 4.027-.365.994-.91 1.752-1.636 2.274-.719.52-1.563.781-2.534.781-1.03 0-1.872-.284-2.525-.853-.654-.576-1.046-1.381-1.178-2.418zm6.624-5.815c0-.928-.249-1.666-.746-2.21-.492-.546-1.085-.819-1.78-.819-.719 0-1.345.294-1.878.881s-.8 1.348-.8 2.283c0 .839.252 1.522.755 2.05.51.52 1.135.781 1.878.781.75 0 1.363-.26 1.843-.782.485-.527.728-1.255.728-2.184zM4.858 10.466c0-1.558.158-2.81.476-3.757.324-.952.8-1.686 1.429-2.201.635-.516 1.432-.773 2.39-.773.708 0 1.328.143 1.861.431.533.282.974.692 1.321 1.231.348.534.62 1.187.818 1.96.198.767.297 1.803.297 3.11 0 1.545-.16 2.794-.477 3.747-.317.947-.794 1.68-1.429 2.202-.629.515-1.426.773-2.39.773-1.27 0-2.268-.456-2.993-1.366-.869-1.097-1.303-2.882-1.303-5.357zm1.662 0c0 2.163.252 3.604.755 4.323.51.713 1.136 1.07 1.879 1.07.743 0 1.366-.36 1.87-1.079.508-.719.763-2.157.763-4.314 0-2.169-.255-3.61-.764-4.323-.503-.713-1.132-1.07-1.887-1.07-.743 0-1.336.315-1.78.944-.557.803-.836 2.286-.836 4.45z" fill="#444"/></svg> | ||||
| After Width: | Height: | Size: 1.5 KiB | 
| Before Width: | Height: | Size: 546 B | 
							
								
								
									
										1
									
								
								packages/node_modules/@node-red/editor-client/src/images/typedInput/az.svg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| <svg width="26" height="36" viewBox="0, 0, 26, 36" xmlns="http://www.w3.org/2000/svg"><path d="M13.27 29.15l6.733-8.143h-6.235V19.3h8.8v1.559l-6.69 8.09h6.892v1.707h-9.5zm4.909-10.125zM6.577 12.58q0 .827.604 1.304.605.478 1.432.478 1.007 0 1.95-.467 1.59-.774 1.59-2.534V9.824q-.349.222-.9.37-.552.15-1.082.213l-1.155.148q-1.04.138-1.56.435-.88.498-.88 1.59zM11.2 8.721q.657-.085.88-.551.127-.255.127-.732 0-.975-.7-1.41-.689-.445-1.983-.445-1.495 0-2.12.805-.35.446-.456 1.326H5.167q.053-2.1 1.357-2.916 1.315-.827 3.043-.827 2.004 0 3.255.763 1.24.764 1.24 2.375v6.542q0 .297.117.477.127.18.52.18.127 0 .286-.01.159-.021.34-.053v1.41q-.446.127-.68.16-.233.031-.636.031-.986 0-1.43-.7-.234-.37-.33-1.05-.583.764-1.675 1.326t-2.407.562q-1.58 0-2.587-.954-.996-.965-.996-2.407 0-1.58.986-2.45.986-.869 2.587-1.07zm-1.58-4.75z" fill="#444"/></svg> | ||||
| After Width: | Height: | Size: 846 B | 
| Before Width: | Height: | Size: 638 B | 
							
								
								
									
										1
									
								
								packages/node_modules/@node-red/editor-client/src/images/typedInput/bin.svg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| <svg width="26" height="36" viewBox="0, 0, 26, 36" xmlns="http://www.w3.org/2000/svg"><path d="M18.8 33.9c3.328 0 4.776-2.603 4.776-7.066s-1.448-7.066-4.776-7.066-4.776 2.603-4.776 7.066S15.473 33.9 18.8 33.9zm0-1.429c-2.192 0-3.073-1.781-3.073-4.522v-2.23c0-2.741.88-4.523 3.073-4.523s3.073 1.782 3.073 4.522v2.231c0 2.74-.88 4.522-3.073 4.522zm-6.306 1.194v-1.429H8.892V20.002H6.328l-3.621 3.386.959 1.038 3.445-3.21h.137v11.02H3.333v1.429zm11.2-17.7v-1.429h-3.602V2.302h-2.564l-3.621 3.386.959 1.038 3.445-3.21h.137v11.02h-3.915v1.429zM7.5 16.2c3.327 0 4.776-2.603 4.776-7.066S10.828 2.068 7.5 2.068 2.725 4.67 2.725 9.134 4.173 16.2 7.5 16.2zm0-1.429c-2.193 0-3.074-1.781-3.074-4.522V8.02c0-2.741.881-4.523 3.074-4.523s3.073 1.782 3.073 4.522v2.231c0 2.74-.881 4.522-3.073 4.522z" fill="#444"/></svg> | ||||
| After Width: | Height: | Size: 805 B | 
| Before Width: | Height: | Size: 646 B | 
							
								
								
									
										1
									
								
								packages/node_modules/@node-red/editor-client/src/images/typedInput/bool.svg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| <svg width="26" height="36" viewBox="0, 0, 26, 36" xmlns="http://www.w3.org/2000/svg"><path d="M9.96 21.98a5 5 0 1 1 6.11-7.917zm3.035-13.973c-5.512 0-10 4.488-10 10s4.488 9.998 10 9.998 10-4.486 10-9.998-4.488-10-10-10zm0 1.816c4.53 0 8.182 3.655 8.182 8.184s-3.652 8.182-8.182 8.182-8.181-3.653-8.181-8.182 3.652-8.184 8.181-8.184z" color="#000" fill="#444"/></svg> | ||||
| After Width: | Height: | Size: 368 B | 
| Before Width: | Height: | Size: 809 B | 
							
								
								
									
										1
									
								
								packages/node_modules/@node-red/editor-client/src/images/typedInput/env.svg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| <svg width="26" height="36" viewBox="0, 0, 26, 36" xmlns="http://www.w3.org/2000/svg"><path d="M14.33 27.19q2.916-.136 4.024-2.131.58-1.024.58-2.37 0-2.132-1.569-3.24-.904-.648-3.035-1.228zM8.55 10.736q0 1.688 1.108 2.643 1.125.955 3.018 1.33V6.695q-2.234.085-3.189 1.364-.937 1.279-.937 2.677zm-3.07.205q0-2.592 1.893-4.672 1.91-2.08 5.337-2.115V1.887h1.62V4.12q3.393.239 5.2 2.012 1.825 1.757 1.91 4.655h-2.984q-.119-1.296-.699-2.233-1.074-1.723-3.427-1.808v8.287q3.956 1.108 5.371 2.08 2.302 1.603 2.302 4.74 0 4.536-2.95 6.446-1.637 1.057-4.723 1.398v3.308h-1.62v-3.308q-4.962-.324-6.735-3.513-.972-1.722-.972-4.655h3.018q.136 2.336.733 3.41 1.057 1.927 3.922 2.166v-9.293q-3.683-.699-5.44-2.336Q5.48 13.84 5.48 10.941z" fill="#444"/></svg> | ||||
| After Width: | Height: | Size: 745 B | 
| Before Width: | Height: | Size: 563 B | 
							
								
								
									
										1
									
								
								packages/node_modules/@node-red/editor-client/src/images/typedInput/expr.svg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| <svg width="26" height="36" viewBox="0, 0, 26, 36" xmlns="http://www.w3.org/2000/svg"><g transform="translate(-337.103 -913.25) scale(1.2585)" fill="#444" stroke-width=".795"><circle cx="284.36" cy="733.68" r="1.5" color="#000" style="isolation:auto;mix-blend-mode:normal"/><circle cx="284.33" cy="740.74" r="1.5" color="#000" style="isolation:auto;mix-blend-mode:normal"/><path d="M276.18 727.78l4.396-1.565v18.515c-.711 2.606-2.922 4.394-5.812 5.812l-4.135 1.974-.559-1.192 3.353-1.639c1.459-.724 2.689-1.87 2.869-4.955z" fill-rule="evenodd"/></g></svg> | ||||
| After Width: | Height: | Size: 556 B | 
| Before Width: | Height: | Size: 588 B | 
							
								
								
									
										1
									
								
								packages/node_modules/@node-red/editor-client/src/images/typedInput/json.svg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| <svg width="26" height="36" viewBox="0, 0, 26, 36" xmlns="http://www.w3.org/2000/svg"><path d="M15 5.225v-1.92h2.24q.608 0 1.216.288.608.256 1.12.8.48.512.8 1.312.32.768.32 1.792v5.824q0 .832.224 1.536t.608 1.216q.352.48.832.768.48.256.992.256v2.176q-.512 0-.992.256t-.832.736q-.384.48-.608 1.184t-.224 1.568v5.792q0 1.024-.32 1.792-.32.8-.8 1.312-.512.544-1.12.8-.608.288-1.216.288H15v-1.92h1.6q.48 0 .768-.256.288-.224.48-.64.16-.384.224-.896.064-.48.064-.96v-5.824q0-1.216.352-2.016.32-.8.768-1.28.448-.512.928-.736.448-.224.736-.256v-.096q-.288-.064-.736-.32-.48-.256-.928-.768t-.768-1.28q-.352-.8-.352-1.92V7.977q0-.512-.064-.992-.064-.512-.224-.896-.192-.384-.48-.608-.288-.256-.768-.256zm-3.648 0v-1.92h-2.24q-.608 0-1.216.288-.608.256-1.12.8-.48.512-.8 1.312-.32.768-.32 1.792v5.824q0 .832-.224 1.536t-.608 1.216q-.352.48-.832.768-.48.256-.992.256v2.176q.512 0 .992.256t.832.736q.384.48.608 1.184t.224 1.568v5.792q0 1.024.32 1.792.32.8.8 1.312.512.544 1.12.8.608.288 1.216.288h2.24v-1.92h-1.6q-.48 0-.768-.256-.288-.224-.48-.64-.16-.384-.224-.896-.064-.48-.064-.96v-5.824q0-1.216-.352-2.016-.32-.8-.768-1.28-.448-.512-.928-.736-.448-.224-.736-.256v-.096q.288-.064.736-.32.48-.256.928-.768t.768-1.28q.352-.8.352-1.92V7.977q0-.512.064-.992.064-.512.224-.896.192-.384.48-.608.288-.256.768-.256z" fill="#444"/></svg> | ||||
| After Width: | Height: | Size: 1.3 KiB | 
| Before Width: | Height: | Size: 502 B | 
							
								
								
									
										1
									
								
								packages/node_modules/@node-red/editor-client/src/images/typedInput/re.svg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| <svg width="26" height="36" viewBox="0, 0, 26, 36" xmlns="http://www.w3.org/2000/svg"><path d="M2 19h5v5H2zm16.099-3.304v-5.659h-2.654v5.66l-5.309-2.004-.901 2.404L14.543 18l-3.255 4.557 2.254 1.553 3.255-4.808 3.455 4.808 2.054-1.553L19 18l5.46-1.903-1.002-2.404z" color="#000" fill="#444444"/></svg> | ||||
| After Width: | Height: | Size: 302 B | 
							
								
								
									
										1
									
								
								packages/node_modules/@node-red/editor-client/src/images/typedInput/target.svg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| <svg width="26" height="36" viewBox="0, 0, 26, 36" xmlns="http://www.w3.org/2000/svg"><path d="M11 5v5.77a7.542 7.542 0 0 0-5.234 5.25L1 16c-1.432 1.397-1.232 2.722 0 4l4.75-.078a7.542 7.542 0 0 0 5.22 5.297L11 31c1.316 1.303 2.649 1.363 4 0l.009-5.775A7.542 7.542 0 0 0 20.228 20H25c1.261-1.294 1.404-2.623 0-4l-4.774-.01a7.542 7.542 0 0 0-5.23-5.22L15 5c-1.3-1.273-2.63-1.393-4 0zm2 7.499c3.05 0 5.5 2.45 5.5 5.5s-2.45 5.5-5.5 5.5-5.5-2.45-5.5-5.5 2.45-5.5 5.5-5.5z" color="#000" fill="#444"/></svg> | ||||
| After Width: | Height: | Size: 502 B | 
| @@ -143,7 +143,7 @@ RED.comms = (function() { | ||||
|                     } else { | ||||
|                         var msg = RED._("notification.errors.lostConnectionReconnect",{time: connectCountdown})+' <a href="#">'+ RED._("notification.errors.lostConnectionTry")+'</a>'; | ||||
|                         errornotification.update(msg,{silent:true}); | ||||
|                         $(errornotification).find("a").click(function(e) { | ||||
|                         $(errornotification).find("a").on("click", function(e) { | ||||
|                             e.preventDefault(); | ||||
|                             errornotification.update(RED._("notification.errors.lostConnection"),{silent:true}); | ||||
|                             clearInterval(connectCountdownTimer); | ||||
|   | ||||
| @@ -14,7 +14,8 @@ | ||||
|  * limitations under the License. | ||||
|  **/ | ||||
| RED.history = (function() { | ||||
|     var undo_history = []; | ||||
|     var undoHistory = []; | ||||
|     var redoHistory = []; | ||||
|  | ||||
|     function undoEvent(ev) { | ||||
|         var i; | ||||
| @@ -22,52 +23,81 @@ RED.history = (function() { | ||||
|         var node; | ||||
|         var subflow; | ||||
|         var modifiedTabs = {}; | ||||
|         var inverseEv; | ||||
|         if (ev) { | ||||
|             if (ev.t == 'multi') { | ||||
|                 inverseEv = { | ||||
|                     t: 'multi', | ||||
|                     events: [] | ||||
|                 }; | ||||
|                 len = ev.events.length; | ||||
|                 for (i=len-1;i>=0;i--) { | ||||
|                     undoEvent(ev.events[i]); | ||||
|                     var r = undoEvent(ev.events[i]); | ||||
|                     inverseEv.events.push(r); | ||||
|                 } | ||||
|             } else if (ev.t == 'replace') { | ||||
|                 inverseEv = { | ||||
|                     t: 'replace', | ||||
|                     config: RED.nodes.createCompleteNodeSet(), | ||||
|                     changed: [], | ||||
|                     rev: RED.nodes.version() | ||||
|                 }; | ||||
|                 RED.nodes.clear(); | ||||
|                 var imported = RED.nodes.import(ev.config); | ||||
|                 imported[0].forEach(function(n) { | ||||
|                     if (ev.changed[n.id]) { | ||||
|                         n.changed = true; | ||||
|                         inverseEv.changed[n.id] = true; | ||||
|                     } | ||||
|                 }) | ||||
|  | ||||
|                 RED.nodes.version(ev.rev); | ||||
|             } else if (ev.t == 'add') { | ||||
|                 inverseEv = { | ||||
|                     t: "delete", | ||||
|                 }; | ||||
|                 if (ev.nodes) { | ||||
|                     inverseEv.nodes = []; | ||||
|                     for (i=0;i<ev.nodes.length;i++) { | ||||
|                         node = RED.nodes.node(ev.nodes[i]); | ||||
|                         if (node.z) { | ||||
|                             modifiedTabs[node.z] = true; | ||||
|                         } | ||||
|                         inverseEv.nodes.push(node); | ||||
|                         RED.nodes.remove(ev.nodes[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.links) { | ||||
|                     inverseEv.links = []; | ||||
|                     for (i=0;i<ev.links.length;i++) { | ||||
|                         inverseEv.links.push(ev.links[i]); | ||||
|                         RED.nodes.removeLink(ev.links[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.workspaces) { | ||||
|                     inverseEv.workspaces = []; | ||||
|                     for (i=0;i<ev.workspaces.length;i++) { | ||||
|                         var workspaceOrder = RED.nodes.getWorkspaceOrder(); | ||||
|                         ev.workspaces[i]._index = workspaceOrder.indexOf(ev.workspaces[i].id); | ||||
|                         inverseEv.workspaces.push(ev.workspaces[i]); | ||||
|                         RED.nodes.removeWorkspace(ev.workspaces[i].id); | ||||
|                         RED.workspaces.remove(ev.workspaces[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.subflows) { | ||||
|                     inverseEv.subflows = []; | ||||
|                     for (i=0;i<ev.subflows.length;i++) { | ||||
|                         inverseEv.subflows.push(ev.subflows[i]); | ||||
|                         RED.nodes.removeSubflow(ev.subflows[i]); | ||||
|                         RED.workspaces.remove(ev.subflows[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.subflow) { | ||||
|                     inverseEv.subflow = {}; | ||||
|                     if (ev.subflow.instances) { | ||||
|                         inverseEv.subflow.instances = []; | ||||
|                         ev.subflow.instances.forEach(function(n) { | ||||
|                             inverseEv.subflow.instances.push(n); | ||||
|                             var node = RED.nodes.node(n.id); | ||||
|                             if (node) { | ||||
|                                 node.changed = n.changed; | ||||
| @@ -83,21 +113,30 @@ RED.history = (function() { | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.removedLinks) { | ||||
|                     inverseEv.createdLinks = []; | ||||
|                     for (i=0;i<ev.removedLinks.length;i++) { | ||||
|                         inverseEv.createdLinks.push(ev.removedLinks[i]); | ||||
|                         RED.nodes.addLink(ev.removedLinks[i]); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|             } else if (ev.t == "delete") { | ||||
|                 inverseEv = { | ||||
|                     t: "add" | ||||
|                 }; | ||||
|                 if (ev.workspaces) { | ||||
|                     inverseEv.workspaces = []; | ||||
|                     for (i=0;i<ev.workspaces.length;i++) { | ||||
|                         inverseEv.workspaces.push(ev.workspaces[i]); | ||||
|                         RED.nodes.addWorkspace(ev.workspaces[i],ev.workspaces[i]._index); | ||||
|                         RED.workspaces.add(ev.workspaces[i],undefined,ev.workspaces[i]._index); | ||||
|                         delete ev.workspaces[i]._index; | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.subflows) { | ||||
|                     inverseEv.subflows = []; | ||||
|                     for (i=0;i<ev.subflows.length;i++) { | ||||
|                         inverseEv.subflows.push(ev.subflows[i]); | ||||
|                         RED.nodes.addSubflow(ev.subflows[i]); | ||||
|                     } | ||||
|                 } | ||||
| @@ -126,8 +165,11 @@ RED.history = (function() { | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.subflow) { | ||||
|                     inverseEv.subflow = {}; | ||||
|                     if (ev.subflow.hasOwnProperty('instances')) { | ||||
|                         inverseEv.subflow.instances = []; | ||||
|                         ev.subflow.instances.forEach(function(n) { | ||||
|                             inverseEv.subflow.instances.push(n); | ||||
|                             var node = RED.nodes.node(n.id); | ||||
|                             if (node) { | ||||
|                                 node.changed = n.changed; | ||||
| @@ -152,14 +194,25 @@ RED.history = (function() { | ||||
|                     }); | ||||
|                 } | ||||
|                 if (ev.nodes) { | ||||
|                     inverseEv.nodes = []; | ||||
|                     for (i=0;i<ev.nodes.length;i++) { | ||||
|                         RED.nodes.add(ev.nodes[i]); | ||||
|                         modifiedTabs[ev.nodes[i].z] = true; | ||||
|                         inverseEv.nodes.push(ev.nodes[i].id); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.links) { | ||||
|                     inverseEv.links = []; | ||||
|                     for (i=0;i<ev.links.length;i++) { | ||||
|                         RED.nodes.addLink(ev.links[i]); | ||||
|                         inverseEv.links.push(ev.links[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.createdLinks) { | ||||
|                     inverseEv.removedLinks = []; | ||||
|                     for (i=0;i<ev.createdLinks.length;i++) { | ||||
|                         inverseEv.removedLinks.push(ev.createdLinks[i]); | ||||
|                         RED.nodes.removeLink(ev.createdLinks[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.changes) { | ||||
| @@ -179,8 +232,14 @@ RED.history = (function() { | ||||
|  | ||||
|                 } | ||||
|             } else if (ev.t == "move") { | ||||
|                 inverseEv = { | ||||
|                     t: 'move', | ||||
|                     nodes: [] | ||||
|                 }; | ||||
|                 for (i=0;i<ev.nodes.length;i++) { | ||||
|                     var n = ev.nodes[i]; | ||||
|                     var rn = {n: n.n, ox: n.n.x, oy: n.n.y, dirty: true, moved: n.moved}; | ||||
|                     inverseEv.nodes.push(rn); | ||||
|                     n.n.x = n.ox; | ||||
|                     n.n.y = n.oy; | ||||
|                     n.n.dirty = true; | ||||
| @@ -188,18 +247,28 @@ RED.history = (function() { | ||||
|                 } | ||||
|                 // A move could have caused a link splice | ||||
|                 if (ev.links) { | ||||
|                     inverseEv.removedLinks = []; | ||||
|                     for (i=0;i<ev.links.length;i++) { | ||||
|                         inverseEv.removedLinks.push(ev.links[i]); | ||||
|                         RED.nodes.removeLink(ev.links[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.removedLinks) { | ||||
|                     inverseEv.links = []; | ||||
|                     for (i=0;i<ev.removedLinks.length;i++) { | ||||
|                         inverseEv.links.push(ev.removedLinks[i]); | ||||
|                         RED.nodes.addLink(ev.removedLinks[i]); | ||||
|                     } | ||||
|                 } | ||||
|             } else if (ev.t == "edit") { | ||||
|                 inverseEv = { | ||||
|                     t: "edit", | ||||
|                     changes: {} | ||||
|                 }; | ||||
|                 inverseEv.node = ev.node; | ||||
|                 for (i in ev.changes) { | ||||
|                     if (ev.changes.hasOwnProperty(i)) { | ||||
|                         inverseEv.changes[i] = ev.node[i]; | ||||
|                         if (ev.node._def.defaults && ev.node._def.defaults[i] && ev.node._def.defaults[i].type) { | ||||
|                             // This is a config node property | ||||
|                             var currentConfigNode = RED.nodes.node(ev.node[i]); | ||||
| @@ -214,23 +283,34 @@ RED.history = (function() { | ||||
|                         ev.node[i] = ev.changes[i]; | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.node.type === 'tab' && ev.changes.hasOwnProperty('disabled')) { | ||||
|                     $("#red-ui-tab-"+(ev.node.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!ev.node.disabled); | ||||
|                     $("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!ev.node.disabled); | ||||
|                 } | ||||
|                 if (ev.subflow) { | ||||
|                     inverseEv.subflow = {}; | ||||
|                     if (ev.subflow.hasOwnProperty('inputCount')) { | ||||
|                         inverseEv.subflow.inputCount = ev.node.in.length; | ||||
|                         if (ev.node.in.length > ev.subflow.inputCount) { | ||||
|                             inverseEv.subflow.inputs = ev.node.in.slice(ev.subflow.inputCount); | ||||
|                             ev.node.in.splice(ev.subflow.inputCount); | ||||
|                         } else if (ev.subflow.inputs.length > 0) { | ||||
|                             ev.node.in = ev.node.in.concat(ev.subflow.inputs); | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.subflow.hasOwnProperty('outputCount')) { | ||||
|                         inverseEv.subflow.outputCount = ev.node.out.length; | ||||
|                         if (ev.node.out.length > ev.subflow.outputCount) { | ||||
|                             inverseEv.subflow.outputs = ev.node.out.slice(ev.subflow.outputCount); | ||||
|                             ev.node.out.splice(ev.subflow.outputCount); | ||||
|                         } else if (ev.subflow.outputs.length > 0) { | ||||
|                             ev.node.out = ev.node.out.concat(ev.subflow.outputs); | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.subflow.hasOwnProperty('instances')) { | ||||
|                         inverseEv.subflow.instances = []; | ||||
|                         ev.subflow.instances.forEach(function(n) { | ||||
|                             inverseEv.subflow.instances.push(n); | ||||
|                             var node = RED.nodes.node(n.id); | ||||
|                             if (node) { | ||||
|                                 node.changed = n.changed; | ||||
| @@ -254,9 +334,11 @@ RED.history = (function() { | ||||
|                     var outputMap; | ||||
|                     if (ev.outputMap) { | ||||
|                         outputMap = {}; | ||||
|                         inverseEv.outputMap = {}; | ||||
|                         for (var port in ev.outputMap) { | ||||
|                             if (ev.outputMap.hasOwnProperty(port) && ev.outputMap[port] !== "-1") { | ||||
|                                 outputMap[ev.outputMap[port]] = port; | ||||
|                                 inverseEv.outputMap[ev.outputMap[port]] = port; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
| @@ -264,39 +346,107 @@ RED.history = (function() { | ||||
|                     RED.editor.validateNode(ev.node); | ||||
|                 } | ||||
|                 if (ev.links) { | ||||
|                     inverseEv.createdLinks = []; | ||||
|                     for (i=0;i<ev.links.length;i++) { | ||||
|                         RED.nodes.addLink(ev.links[i]); | ||||
|                         inverseEv.createdLinks.push(ev.links[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.createdLinks) { | ||||
|                     inverseEv.links = []; | ||||
|                     for (i=0;i<ev.createdLinks.length;i++) { | ||||
|                         RED.nodes.removeLink(ev.createdLinks[i]); | ||||
|                         inverseEv.links.push(ev.createdLinks[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 ev.node.dirty = true; | ||||
|                 ev.node.changed = ev.changed; | ||||
|             } else if (ev.t == "createSubflow") { | ||||
|                 inverseEv = { | ||||
|                     t: "deleteSubflow", | ||||
|                     activeWorkspace: ev.activeWorkspace, | ||||
|                     dirty: RED.nodes.dirty() | ||||
|                 }; | ||||
|                 if (ev.nodes) { | ||||
|                     inverseEv.movedNodes = []; | ||||
|                     var z = ev.activeWorkspace; | ||||
|                     RED.nodes.filterNodes({z:ev.subflow.subflow.id}).forEach(function(n) { | ||||
|                         n.x += ev.subflow.offsetX; | ||||
|                         n.y += ev.subflow.offsetY; | ||||
|                         n.z = ev.activeWorkspace; | ||||
|                         n.dirty = true; | ||||
|                         inverseEv.movedNodes.push(n.id); | ||||
|                         RED.nodes.moveNodeToTab(n, z); | ||||
|                     }); | ||||
|                     inverseEv.subflows = []; | ||||
|                     for (i=0;i<ev.nodes.length;i++) { | ||||
|                         inverseEv.subflows.push(RED.nodes.node(ev.nodes[i])); | ||||
|                         RED.nodes.remove(ev.nodes[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.links) { | ||||
|                     inverseEv.links = []; | ||||
|                     for (i=0;i<ev.links.length;i++) { | ||||
|                         inverseEv.links.push(ev.links[i]); | ||||
|                         RED.nodes.removeLink(ev.links[i]); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 inverseEv.subflow = ev.subflow; | ||||
|                 RED.nodes.removeSubflow(ev.subflow.subflow); | ||||
|                 RED.workspaces.remove(ev.subflow.subflow); | ||||
|  | ||||
|                 if (ev.removedLinks) { | ||||
|                     inverseEv.createdLinks = []; | ||||
|                     for (i=0;i<ev.removedLinks.length;i++) { | ||||
|                         inverseEv.createdLinks.push(ev.removedLinks[i]); | ||||
|                         RED.nodes.addLink(ev.removedLinks[i]); | ||||
|                     } | ||||
|                 } | ||||
|             } else if (ev.t == "deleteSubflow") { | ||||
|                 inverseEv = { | ||||
|                     t: "createSubflow", | ||||
|                     activeWorkspace: ev.activeWorkspace, | ||||
|                     dirty: RED.nodes.dirty(), | ||||
|                 }; | ||||
|                 if (ev.subflow) { | ||||
|                     RED.nodes.addSubflow(ev.subflow.subflow); | ||||
|                     inverseEv.subflow = ev.subflow; | ||||
|                 } | ||||
|                 if (ev.subflows) { | ||||
|                     inverseEv.nodes = []; | ||||
|                     for (i=0;i<ev.subflows.length;i++) { | ||||
|                         RED.nodes.add(ev.subflows[i]); | ||||
|                         inverseEv.nodes.push(ev.subflows[i].id); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.movedNodes) { | ||||
|                     ev.movedNodes.forEach(function(nid) { | ||||
|                         nn = RED.nodes.node(nid); | ||||
|                         nn.x -= ev.subflow.offsetX; | ||||
|                         nn.y -= ev.subflow.offsetY; | ||||
|                         nn.dirty = true; | ||||
|                         RED.nodes.moveNodeToTab(nn, ev.subflow.subflow.id); | ||||
|                     }); | ||||
|                 } | ||||
|                 if (ev.links) { | ||||
|                     inverseEv.links = []; | ||||
|                     for (i=0;i<ev.links.length;i++) { | ||||
|                         inverseEv.links.push(ev.links[i]); | ||||
|                         RED.nodes.addLink(ev.links[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if  (ev.createdLinks) { | ||||
|                     inverseEv.removedLinks = []; | ||||
|                     for (i=0;i<ev.createdLinks.length;i++) { | ||||
|                         inverseEv.removedLinks.push(ev.createdLinks[i]); | ||||
|                         RED.nodes.removeLink(ev.createdLinks[i]); | ||||
|                     } | ||||
|                 } | ||||
|             } else if (ev.t == "reorder") { | ||||
|                 inverseEv = { | ||||
|                     t: 'reorder', | ||||
|                     order: RED.nodes.getWorkspaceOrder() | ||||
|                 }; | ||||
|                 if (ev.order) { | ||||
|                     RED.workspaces.order(ev.order); | ||||
|                 } | ||||
| @@ -316,6 +466,8 @@ RED.history = (function() { | ||||
|             RED.workspaces.refresh(); | ||||
|             RED.sidebar.config.refresh(); | ||||
|             RED.subflow.refresh(); | ||||
|  | ||||
|             return inverseEv; | ||||
|         } | ||||
|  | ||||
|     } | ||||
| @@ -323,28 +475,42 @@ RED.history = (function() { | ||||
|     return { | ||||
|         //TODO: this function is a placeholder until there is a 'save' event that can be listened to | ||||
|         markAllDirty: function() { | ||||
|             for (var i=0;i<undo_history.length;i++) { | ||||
|                 undo_history[i].dirty = true; | ||||
|             for (var i=0;i<undoHistory.length;i++) { | ||||
|                 undoHistory[i].dirty = true; | ||||
|             } | ||||
|         }, | ||||
|         list: function() { | ||||
|             return undo_history | ||||
|             return undoHistory; | ||||
|         }, | ||||
|         depth: function() { | ||||
|             return undo_history.length; | ||||
|             return undoHistory.length; | ||||
|         }, | ||||
|         push: function(ev) { | ||||
|             undo_history.push(ev); | ||||
|             undoHistory.push(ev); | ||||
|             redoHistory = []; | ||||
|         }, | ||||
|         pop: function() { | ||||
|             var ev = undo_history.pop(); | ||||
|             undoEvent(ev); | ||||
|             var ev = undoHistory.pop(); | ||||
|             var rev = undoEvent(ev); | ||||
|             if (rev) { | ||||
|                 redoHistory.push(rev); | ||||
|             } | ||||
|         }, | ||||
|         peek: function() { | ||||
|             return undo_history[undo_history.length-1]; | ||||
|             return undoHistory[undoHistory.length-1]; | ||||
|         }, | ||||
|         clear: function() { | ||||
|             undo_history = []; | ||||
|             undoHistory = []; | ||||
|             redoHistory = []; | ||||
|         }, | ||||
|         redo: function() { | ||||
|             var ev = redoHistory.pop(); | ||||
|             if (ev) { | ||||
|                 var uev = undoEvent(ev); | ||||
|                 if (uev) { | ||||
|                     undoHistory.push(uev); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -21,7 +21,8 @@ RED.i18n = (function() { | ||||
|     return { | ||||
|         init: function(options, done) { | ||||
|             apiRootUrl = options.apiRootUrl||""; | ||||
|             i18n.init({ | ||||
|             var preferredLanguage = localStorage.getItem("editor-language"); | ||||
|             var opts = { | ||||
|                 resGetPath: apiRootUrl+'locales/__ns__?lng=__lng__', | ||||
|                 dynamicLoad: false, | ||||
|                 load:'current', | ||||
| @@ -32,7 +33,11 @@ RED.i18n = (function() { | ||||
|                 fallbackLng: ['en-US'], | ||||
|                 useCookie: false, | ||||
|                 returnObjectTrees: true | ||||
|             },function() { | ||||
|             }; | ||||
|             if (preferredLanguage) { | ||||
|                 opts.lng = preferredLanguage; | ||||
|             } | ||||
|             i18n.init(opts,function() { | ||||
|                 done(); | ||||
|             }); | ||||
|             RED["_"] = function() { | ||||
| @@ -45,8 +50,21 @@ RED.i18n = (function() { | ||||
|             } | ||||
|  | ||||
|         }, | ||||
|         lang: function() { | ||||
|             // Gets the active message catalog language. This is based on what | ||||
|             // locale the editor is using and what languages are available. | ||||
|             // | ||||
|             var preferredLangs = i18n.functions.toLanguages(localStorage.getItem("editor-language")||i18n.detectLanguage()); | ||||
|             var knownLangs = RED.settings.theme("languages")||["en-US"]; | ||||
|             for (var i=0;i<preferredLangs.length;i++) { | ||||
|                 if (knownLangs.indexOf(preferredLangs[i]) > -1) { | ||||
|                     return preferredLangs[i] | ||||
|                 } | ||||
|             } | ||||
|             return 'end-US' | ||||
|         }, | ||||
|         loadNodeCatalog: function(namespace,done) { | ||||
|             var languageList = i18n.functions.toLanguages(i18n.detectLanguage()); | ||||
|             var languageList = i18n.functions.toLanguages(localStorage.getItem("editor-language")||i18n.detectLanguage()); | ||||
|             var toLoad = languageList.length; | ||||
|             languageList.forEach(function(lang) { | ||||
|                 $.ajax({ | ||||
| @@ -68,7 +86,7 @@ RED.i18n = (function() { | ||||
|         }, | ||||
|  | ||||
|         loadNodeCatalogs: function(done) { | ||||
|             var languageList = i18n.functions.toLanguages(i18n.detectLanguage()); | ||||
|             var languageList = i18n.functions.toLanguages(localStorage.getItem("editor-language")||i18n.detectLanguage()); | ||||
|             var toLoad = languageList.length; | ||||
|  | ||||
|             languageList.forEach(function(lang) { | ||||
|   | ||||
| @@ -1,12 +1,14 @@ | ||||
| { | ||||
|     "*": { | ||||
|         "ctrl-shift-p":"core:manage-palette", | ||||
|         "alt-shift-p":"core:manage-palette", | ||||
|         "ctrl-f": "core:search", | ||||
|         "ctrl-shift-f": "core:list-flows", | ||||
|         "ctrl-=": "core:zoom-in", | ||||
|         "ctrl--": "core:zoom-out", | ||||
|         "ctrl-0": "core:zoom-reset", | ||||
|         "ctrl-enter": "core:confirm-edit-tray", | ||||
|         "ctrl-escape": "core:cancel-edit-tray", | ||||
|         "ctrl-d": "core:deploy-flows", | ||||
|         "ctrl-g i": "core:show-info-tab", | ||||
|         "ctrl-g d": "core:show-debug-tab", | ||||
|         "ctrl-g c": "core:show-config-tab", | ||||
| @@ -16,19 +18,22 @@ | ||||
|         "ctrl-space": "core:toggle-sidebar", | ||||
|         "ctrl-p": "core:toggle-palette", | ||||
|         "ctrl-,": "core:show-user-settings", | ||||
|         "ctrl-alt-l": "core:clear-debug-messages", | ||||
|         "ctrl-alt-r": "core:show-remote-diff", | ||||
|         "ctrl-alt-n": "core:new-project", | ||||
|         "ctrl-alt-o": "core:open-project", | ||||
|         "ctrl-g v": "core:show-version-control-tab", | ||||
|         "ctrl-shift-l": "core:show-event-log" | ||||
|         "ctrl-shift-l": "core:show-event-log", | ||||
|         "ctrl-shift-p":"core:show-action-list" | ||||
|     }, | ||||
|     "sidebar-node-config": { | ||||
|     "red-ui-sidebar-node-config": { | ||||
|         "backspace": "core:delete-config-selection", | ||||
|         "delete": "core:delete-config-selection", | ||||
|         "ctrl-a": "core:select-all-config-nodes", | ||||
|         "ctrl-z": "core:undo" | ||||
|         "ctrl-z": "core:undo", | ||||
|         "ctrl-y": "core:redo" | ||||
|     }, | ||||
|     "workspace": { | ||||
|     "red-ui-workspace": { | ||||
|         "backspace": "core:delete-selection", | ||||
|         "delete": "core:delete-selection", | ||||
|         "enter": "core:edit-selected-node", | ||||
| @@ -36,6 +41,7 @@ | ||||
|         "ctrl-x": "core:cut-selection-to-internal-clipboard", | ||||
|         "ctrl-v": "core:paste-from-internal-clipboard", | ||||
|         "ctrl-z": "core:undo", | ||||
|         "ctrl-y": "core:redo", | ||||
|         "ctrl-a": "core:select-all-nodes", | ||||
|         "shift-?": "core:show-help", | ||||
|         "up": "core:move-selection-up", | ||||
|   | ||||
| @@ -17,6 +17,8 @@ RED.nodes = (function() { | ||||
|  | ||||
|     var node_defs = {}; | ||||
|     var nodes = []; | ||||
|     var nodeTabMap = {}; | ||||
|  | ||||
|     var configNodes = {}; | ||||
|     var links = []; | ||||
|     var defaultWorkspace; | ||||
| @@ -213,6 +215,11 @@ RED.nodes = (function() { | ||||
|                 n.i = nextId+1; | ||||
|             } | ||||
|             nodes.push(n); | ||||
|             if (nodeTabMap[n.z]) { | ||||
|                 nodeTabMap[n.z][n.id] = n; | ||||
|             } else { | ||||
|                 console.warn("Node added to unknown tab/subflow:",n); | ||||
|             } | ||||
|         } | ||||
|         RED.events.emit('nodes:add',n); | ||||
|     } | ||||
| @@ -246,6 +253,9 @@ RED.nodes = (function() { | ||||
|             node = getNode(id); | ||||
|             if (node) { | ||||
|                 nodes.splice(nodes.indexOf(node),1); | ||||
|                 if (nodeTabMap[node.z]) { | ||||
|                     delete nodeTabMap[node.z][node.id]; | ||||
|                 } | ||||
|                 removedLinks = links.filter(function(l) { return (l.source === node) || (l.target === node); }); | ||||
|                 removedLinks.forEach(function(l) {links.splice(links.indexOf(l), 1); }); | ||||
|                 var updatedConfigNode = false; | ||||
| @@ -291,6 +301,17 @@ RED.nodes = (function() { | ||||
|         return {links:removedLinks,nodes:removedNodes}; | ||||
|     } | ||||
|  | ||||
|     function moveNodeToTab(node, z) { | ||||
|         if (nodeTabMap[node.z]) { | ||||
|             delete nodeTabMap[node.z][node.id]; | ||||
|         } | ||||
|         if (!nodeTabMap[z]) { | ||||
|             nodeTabMap[z] = {}; | ||||
|         } | ||||
|         nodeTabMap[z][node.id] = node; | ||||
|         node.z = z; | ||||
|     } | ||||
|  | ||||
|     function removeLink(l) { | ||||
|         var index = links.indexOf(l); | ||||
|         if (index != -1) { | ||||
| @@ -300,6 +321,8 @@ RED.nodes = (function() { | ||||
|  | ||||
|     function addWorkspace(ws,targetIndex) { | ||||
|         workspaces[ws.id] = ws; | ||||
|         nodeTabMap[ws.id] = {}; | ||||
|  | ||||
|         ws._def = RED.nodes.getType('tab'); | ||||
|         if (targetIndex === undefined) { | ||||
|             workspacesOrder.push(ws.id); | ||||
| @@ -312,6 +335,7 @@ RED.nodes = (function() { | ||||
|     } | ||||
|     function removeWorkspace(id) { | ||||
|         delete workspaces[id]; | ||||
|         delete nodeTabMap[id]; | ||||
|         workspacesOrder.splice(workspacesOrder.indexOf(id),1); | ||||
|  | ||||
|         var removedNodes = []; | ||||
| @@ -357,30 +381,32 @@ RED.nodes = (function() { | ||||
|             sf.name = subflowName; | ||||
|         } | ||||
|         subflows[sf.id] = sf; | ||||
|         nodeTabMap[sf.id] = {}; | ||||
|  | ||||
|         RED.nodes.registerType("subflow:"+sf.id, { | ||||
|             defaults:{ | ||||
|                 name:{value:""}, | ||||
|                 env:{value:[]} | ||||
|             }, | ||||
|             icon: function() { return sf.icon||"subflow.png" }, | ||||
|             icon: function() { return sf.icon||"subflow.svg" }, | ||||
|             category: sf.category || "subflows", | ||||
|             inputs: sf.in.length, | ||||
|             outputs: sf.out.length, | ||||
|             color: "#da9", | ||||
|             color: sf.color || "#DDAA99", | ||||
|             label: function() { return this.name||RED.nodes.subflow(sf.id).name }, | ||||
|             labelStyle: function() { return this.name?"node_label_italic":""; }, | ||||
|             labelStyle: function() { return this.name?"red-ui-flow-node-label-italic":""; }, | ||||
|             paletteLabel: function() { return RED.nodes.subflow(sf.id).name }, | ||||
|             inputLabels: function(i) { return sf.inputLabels?sf.inputLabels[i]:null }, | ||||
|             outputLabels: function(i) { return sf.outputLabels?sf.outputLabels[i]:null }, | ||||
|             oneditresize: function(size) { | ||||
|                 var rows = $("#dialog-form>div:not(.node-input-env-container-row)"); | ||||
|                 // var rows = $(".dialog-form>div:not(.node-input-env-container-row)"); | ||||
|                 var height = size.height; | ||||
|                 for (var i=0; i<rows.size(); i++) { | ||||
|                     height -= $(rows[i]).outerHeight(true); | ||||
|                 } | ||||
|                 var editorRow = $("#dialog-form>div.node-input-env-container-row"); | ||||
|                 height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom"))); | ||||
|                 $("#node-input-env-container").editableList('height',height-80); | ||||
|                 // for (var i=0; i<rows.size(); i++) { | ||||
|                 //     height -= $(rows[i]).outerHeight(true); | ||||
|                 // } | ||||
|                 // var editorRow = $("#dialog-form>div.node-input-env-container-row"); | ||||
|                 // height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom"))); | ||||
|                 $("ol.red-ui-editor-subflow-env-list").editableList('height',height); | ||||
|             }, | ||||
|             set:{ | ||||
|                 module: "node-red" | ||||
| @@ -393,6 +419,7 @@ RED.nodes = (function() { | ||||
|     } | ||||
|     function removeSubflow(sf) { | ||||
|         delete subflows[sf.id]; | ||||
|         delete nodeTabMap[sf.id]; | ||||
|         registry.removeNodeType("subflow:"+sf.id); | ||||
|     } | ||||
|  | ||||
| @@ -463,7 +490,9 @@ RED.nodes = (function() { | ||||
|         node.id = n.id; | ||||
|         node.type = n.type; | ||||
|         node.z = n.z; | ||||
|  | ||||
|         if (n.d === true) { | ||||
|             node.d = true; | ||||
|         } | ||||
|         if (node.type == "unknown") { | ||||
|             for (var p in n._orig) { | ||||
|                 if (n._orig.hasOwnProperty(p)) { | ||||
| @@ -549,6 +578,7 @@ RED.nodes = (function() { | ||||
|         node.in = []; | ||||
|         node.out = []; | ||||
|         node.env = n.env; | ||||
|         node.color = n.color; | ||||
|  | ||||
|         n.in.forEach(function(p) { | ||||
|             var nIn = {x:p.x,y:p.y,wires:[]}; | ||||
| @@ -581,7 +611,7 @@ RED.nodes = (function() { | ||||
|             node.outputLabels = n.outputLabels.slice(); | ||||
|         } | ||||
|         if (n.icon) { | ||||
|             if (n.icon !== "node-red/subflow.png") { | ||||
|             if (n.icon !== "node-red/subflow.svg") { | ||||
|                 node.icon = n.icon; | ||||
|             } | ||||
|         } | ||||
| @@ -766,6 +796,20 @@ RED.nodes = (function() { | ||||
|         if (!$.isArray(newNodes)) { | ||||
|             newNodes = [newNodes]; | ||||
|         } | ||||
|  | ||||
|         // Scan for any duplicate nodes and remove them. This is a temporary | ||||
|         // fix to help resolve corrupted flows caused by 0.20.0 where multiple | ||||
|         // copies of the flow would get loaded at the same time. | ||||
|         // If the user hit deploy they would have saved those duplicates. | ||||
|         var seenIds = {}; | ||||
|         newNodes = newNodes.filter(function(n) { | ||||
|             if (seenIds[n.id]) { | ||||
|                 return false; | ||||
|             } | ||||
|             seenIds[n.id] = true; | ||||
|             return true; | ||||
|         }) | ||||
|  | ||||
|         var isInitialLoad = false; | ||||
|         if (!initialLoad) { | ||||
|             isInitialLoad = true; | ||||
| @@ -953,6 +997,9 @@ RED.nodes = (function() { | ||||
|                         users:[], | ||||
|                         _config:{} | ||||
|                     }; | ||||
|                     if (n.hasOwnProperty('d')) { | ||||
|                         configNode.d = n.d; | ||||
|                     } | ||||
|                     for (d in def.defaults) { | ||||
|                         if (def.defaults.hasOwnProperty(d)) { | ||||
|                             configNode[d] = n[d]; | ||||
| @@ -1002,6 +1049,9 @@ RED.nodes = (function() { | ||||
|                     if (n.hasOwnProperty('l')) { | ||||
|                         node.l = n.l; | ||||
|                     } | ||||
|                     if (n.hasOwnProperty('d')) { | ||||
|                         node.d = n.d; | ||||
|                     } | ||||
|                     if (createNewIds) { | ||||
|                         if (subflow_blacklist[n.z]) { | ||||
|                             continue; | ||||
| @@ -1058,7 +1108,7 @@ RED.nodes = (function() { | ||||
|                                     color:"#fee", | ||||
|                                     defaults: {}, | ||||
|                                     label: "unknown: "+n.type, | ||||
|                                     labelStyle: "node_label_italic", | ||||
|                                     labelStyle: "red-ui-flow-node-label-italic", | ||||
|                                     outputs: n.outputs||n.wires.length, | ||||
|                                     set: registry.getNodeSet("node-red/unknown") | ||||
|                                 } | ||||
| @@ -1144,6 +1194,7 @@ RED.nodes = (function() { | ||||
|         var nodeTypeArrayReferences = { | ||||
|             "catch":"scope", | ||||
|             "status":"scope", | ||||
|             "complete": "scope", | ||||
|             "link in":"links", | ||||
|             "link out":"links" | ||||
|         } | ||||
| @@ -1244,13 +1295,22 @@ RED.nodes = (function() { | ||||
|     // TODO: supports filter.z|type | ||||
|     function filterNodes(filter) { | ||||
|         var result = []; | ||||
|         var searchSet = nodes; | ||||
|         var doZFilter = false; | ||||
|         if (filter.hasOwnProperty("z")) { | ||||
|             if (Object.hasOwnProperty("values") && nodeTabMap.hasOwnProperty(filter.z) ) { | ||||
|                 searchSet = Object.values(nodeTabMap[filter.z]); | ||||
|             } else { | ||||
|                 doZFilter = true; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         for (var n=0;n<nodes.length;n++) { | ||||
|             var node = nodes[n]; | ||||
|             if (filter.hasOwnProperty("z") && node.z !== filter.z) { | ||||
|         for (var n=0;n<searchSet.length;n++) { | ||||
|             var node = searchSet[n]; | ||||
|             if (filter.hasOwnProperty("type") && node.type !== filter.type) { | ||||
|                 continue; | ||||
|             } | ||||
|             if (filter.hasOwnProperty("type") && node.type !== filter.type) { | ||||
|             if (doZFilter && node.z !== filter.z) { | ||||
|                 continue; | ||||
|             } | ||||
|             result.push(node); | ||||
| @@ -1317,6 +1377,7 @@ RED.nodes = (function() { | ||||
|     function clear() { | ||||
|         nodes = []; | ||||
|         links = []; | ||||
|         nodeTabMap = {}; | ||||
|         configNodes = {}; | ||||
|         workspacesOrder = []; | ||||
|         var subflowIds = Object.keys(subflows); | ||||
| @@ -1426,6 +1487,8 @@ RED.nodes = (function() { | ||||
|         remove: removeNode, | ||||
|         clear: clear, | ||||
|  | ||||
|         moveNodeToTab: moveNodeToTab, | ||||
|  | ||||
|         addLink: addLink, | ||||
|         removeLink: removeLink, | ||||
|  | ||||
|   | ||||
| @@ -28,19 +28,40 @@ var RED = (function() { | ||||
|             var hasDeferred = false; | ||||
|  | ||||
|             var nodeConfigEls = $("<div>"+nodeConfig+"</div>"); | ||||
|             nodeConfigEls.find("script").each(function(i,el) { | ||||
|             var scripts = nodeConfigEls.find("script"); | ||||
|             var scriptCount = scripts.length; | ||||
|             scripts.each(function(i,el) { | ||||
|                 var srcUrl = $(el).attr('src'); | ||||
|                 if (srcUrl && !/^\s*(https?:|\/|\.)/.test(srcUrl)) { | ||||
|                     $(el).remove(); | ||||
|                     var newScript = document.createElement("script"); | ||||
|                     newScript.onload = function() { $("body").append(nodeConfigEls); done() } | ||||
|                     $('body').append(newScript); | ||||
|                     newScript.onload = function() { | ||||
|                         scriptCount--; | ||||
|                         if (scriptCount === 0) { | ||||
|                             $("#red-ui-editor-node-configs").append(nodeConfigEls); | ||||
|                             done() | ||||
|                         } | ||||
|                     } | ||||
|                     if ($(el).attr('type') === "module") { | ||||
|                         newScript.type = "module"; | ||||
|                     } | ||||
|                     $("#red-ui-editor-node-configs").append(newScript); | ||||
|                     newScript.src = RED.settings.apiRootUrl+srcUrl; | ||||
|                     hasDeferred = true; | ||||
|                 } else { | ||||
|                     if (/\/ace.js$/.test(srcUrl) || /\/ext-language_tools.js$/.test(srcUrl)) { | ||||
|                         // Block any attempts to load ace.js from a CDN - this will | ||||
|                         // break the version of ace included in the editor. | ||||
|                         // At the time of commit, the contrib-python nodes did this. | ||||
|                         // This is a crude fix until the python nodes are fixed. | ||||
|                         console.warn("Blocked attempt to load",srcUrl,"by",moduleId) | ||||
|                         $(el).remove(); | ||||
|                     } | ||||
|                     scriptCount--; | ||||
|                 } | ||||
|             }) | ||||
|             if (!hasDeferred) { | ||||
|                 $("body").append(nodeConfigEls); | ||||
|                 $("#red-ui-editor-node-configs").append(nodeConfigEls); | ||||
|                 done(); | ||||
|             } | ||||
|         } catch(err) { | ||||
| @@ -86,9 +107,12 @@ var RED = (function() { | ||||
|     } | ||||
|  | ||||
|     function loadNodes() { | ||||
|         var lang = localStorage.getItem("editor-language")||i18n.detectLanguage(); | ||||
|  | ||||
|         $.ajax({ | ||||
|             headers: { | ||||
|                 "Accept":"text/html" | ||||
|                 "Accept":"text/html", | ||||
|                 "Accept-Language": lang | ||||
|             }, | ||||
|             cache: false, | ||||
|             url: 'nodes', | ||||
| @@ -96,10 +120,10 @@ var RED = (function() { | ||||
|                 var configs = data.trim().split(/(?=<!-- --- \[red-module:\S+\] --- -->)/); | ||||
|                 var stepConfig = function() { | ||||
|                     if (configs.length === 0) { | ||||
|                         $("body").i18n(); | ||||
|                         $("#palette > .palette-spinner").hide(); | ||||
|                         $(".palette-scroll").removeClass("hide"); | ||||
|                         $("#palette-search").removeClass("hide"); | ||||
|                         $("#red-ui-editor").i18n(); | ||||
|                         $("#red-ui-palette > .red-ui-palette-spinner").hide(); | ||||
|                         $(".red-ui-palette-scroll").removeClass("hide"); | ||||
|                         $("#red-ui-palette-search").removeClass("hide"); | ||||
|                         loadFlows(function() { | ||||
|                             if (RED.settings.theme("projects.enabled",false)) { | ||||
|                                 RED.projects.refresh(function(activeProject) { | ||||
| @@ -211,7 +235,7 @@ var RED = (function() { | ||||
|                             } | ||||
|                         ] | ||||
|                     } else if (msg.error === "missing-types") { | ||||
|                         text+="<ul><li>"+msg.types.join("</li><li>")+"</li></ul>"; | ||||
|                         text+="<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>"; | ||||
|                         if (!!RED.projects.getActiveProject()) { | ||||
|                             options.buttons = [ | ||||
|                                 { | ||||
| @@ -239,7 +263,7 @@ var RED = (function() { | ||||
|                             if (RED.user.hasPermission("projects.write")) { | ||||
|                                 options.buttons = [ | ||||
|                                     { | ||||
|                                         text: "Setup credentials", | ||||
|                                         text: RED._("notification.project.setupCredentials"), | ||||
|                                         click: function() { | ||||
|                                             persistentNotifications[notificationId].hideNotification(); | ||||
|                                             RED.projects.showCredentialsPrompt(); | ||||
| @@ -250,7 +274,7 @@ var RED = (function() { | ||||
|                         } else { | ||||
|                             options.buttons = [ | ||||
|                                 { | ||||
|                                     text: "Close", | ||||
|                                     text: RED._("common.label.close"), | ||||
|                                     click: function() { | ||||
|                                         persistentNotifications[notificationId].hideNotification(); | ||||
|                                     } | ||||
| @@ -261,7 +285,7 @@ var RED = (function() { | ||||
|                         if (RED.user.hasPermission("projects.write")) { | ||||
|                             options.buttons = [ | ||||
|                                 { | ||||
|                                     text: "Setup project files", | ||||
|                                     text: RED._("notification.project.setupProjectFiles"), | ||||
|                                     click: function() { | ||||
|                                         persistentNotifications[notificationId].hideNotification(); | ||||
|                                         RED.projects.showFilesPrompt(); | ||||
| @@ -273,10 +297,10 @@ var RED = (function() { | ||||
|                         if (RED.user.hasPermission("projects.write")) { | ||||
|                             options.buttons = [ | ||||
|                                 { | ||||
|                                     text: "Create default package file", | ||||
|                                     text: RED._("notification.project.setupProjectFiles"), | ||||
|                                     click: function() { | ||||
|                                         persistentNotifications[notificationId].hideNotification(); | ||||
|                                         RED.projects.createDefaultPackageFile(); | ||||
|                                         RED.projects.showFilesPrompt(); | ||||
|                                     } | ||||
|                                 } | ||||
|                             ] | ||||
| @@ -285,13 +309,13 @@ var RED = (function() { | ||||
|                         if (RED.user.hasPermission("projects.write")) { | ||||
|                             options.buttons = [ | ||||
|                                 { | ||||
|                                     text: "No thanks", | ||||
|                                     text: RED._("notification.project.no"), | ||||
|                                     click: function() { | ||||
|                                         persistentNotifications[notificationId].hideNotification(); | ||||
|                                     } | ||||
|                                 }, | ||||
|                                 { | ||||
|                                     text: "Create default project files", | ||||
|                                     text: RED._("notification.project.createDefault"), | ||||
|                                     click: function() { | ||||
|                                         persistentNotifications[notificationId].hideNotification(); | ||||
|                                         RED.projects.createDefaultFileSet(); | ||||
| @@ -305,7 +329,7 @@ var RED = (function() { | ||||
|                         if (RED.user.hasPermission("projects.write")) { | ||||
|                             options.buttons = [ | ||||
|                                 { | ||||
|                                     text: "Show merge conflicts", | ||||
|                                     text: RED._("notification.project.mergeConflict"), | ||||
|                                     click: function() { | ||||
|                                         persistentNotifications[notificationId].hideNotification(); | ||||
|                                         RED.sidebar.versionControl.showLocalChanges(); | ||||
| @@ -329,12 +353,11 @@ var RED = (function() { | ||||
|             var parts = topic.split("/"); | ||||
|             var node = RED.nodes.node(parts[1]); | ||||
|             if (node) { | ||||
|                 if (msg.hasOwnProperty("text")) { | ||||
|                     if (msg.text[0] !== ".") { | ||||
|                         msg.text = node._(msg.text.toString(),{defaultValue:msg.text.toString()}); | ||||
|                     } | ||||
|                 if (msg.hasOwnProperty("text") && /^[a-zA-Z]/.test(msg.text)) { | ||||
|                     msg.text = node._(msg.text.toString(),{defaultValue:msg.text.toString()}); | ||||
|                 } | ||||
|                 node.status = msg; | ||||
|                 node.dirtyStatus = true; | ||||
|                 node.dirty = true; | ||||
|                 RED.view.redraw(); | ||||
|             } | ||||
| @@ -415,7 +438,7 @@ var RED = (function() { | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     function loadEditor() { | ||||
|     function buildMainMenu() { | ||||
|         var menuOptions = []; | ||||
|         if (RED.settings.theme("projects.enabled",false)) { | ||||
|             menuOptions.push({id:"menu-item-projects-menu",label:RED._("menu.label.projects"),options:[ | ||||
| @@ -424,34 +447,20 @@ var RED = (function() { | ||||
|                 {id:"menu-item-projects-settings",label:RED._("menu.label.projects-settings"),disabled:false,onselect:"core:show-project-settings"} | ||||
|             ]}); | ||||
|         } | ||||
|  | ||||
|  | ||||
|         menuOptions.push({id:"menu-item-view-menu",label:RED._("menu.label.view.view"),options:[ | ||||
|             // {id:"menu-item-view-show-grid",setting:"view-show-grid",label:RED._("menu.label.view.showGrid"),toggle:true,onselect:"core:toggle-show-grid"}, | ||||
|             // {id:"menu-item-view-snap-grid",setting:"view-snap-grid",label:RED._("menu.label.view.snapGrid"),toggle:true,onselect:"core:toggle-snap-grid"}, | ||||
|             // {id:"menu-item-status",setting:"node-show-status",label:RED._("menu.label.displayStatus"),toggle:true,onselect:"core:toggle-status", selected: true}, | ||||
|             //null, | ||||
|             // {id:"menu-item-bidi",label:RED._("menu.label.view.textDir"),options:[ | ||||
|             //     {id:"menu-item-bidi-default",toggle:"text-direction",label:RED._("menu.label.view.defaultDir"),selected: true, onselect:function(s) { if(s){RED.text.bidi.setTextDirection("")}}}, | ||||
|             //     {id:"menu-item-bidi-ltr",toggle:"text-direction",label:RED._("menu.label.view.ltr"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("ltr")}}}, | ||||
|             //     {id:"menu-item-bidi-rtl",toggle:"text-direction",label:RED._("menu.label.view.rtl"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("rtl")}}}, | ||||
|             //     {id:"menu-item-bidi-auto",toggle:"text-direction",label:RED._("menu.label.view.auto"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("auto")}}} | ||||
|             // ]}, | ||||
|             // null, | ||||
|             {id:"menu-item-palette",label:RED._("menu.label.palette.show"),toggle:true,onselect:"core:toggle-palette", selected: true}, | ||||
|             {id:"menu-item-sidebar",label:RED._("menu.label.sidebar.show"),toggle:true,onselect:"core:toggle-sidebar", selected: true}, | ||||
|             {id:"menu-item-event-log",label:RED._("eventLog.title"),onselect:"core:show-event-log"}, | ||||
|             {id:"menu-item-action-list",label:RED._("keyboard.actionList"),onselect:"core:show-action-list"}, | ||||
|             null | ||||
|         ]}); | ||||
|         menuOptions.push(null); | ||||
|         menuOptions.push({id:"menu-item-import",label:RED._("menu.label.import"),options:[ | ||||
|             {id:"menu-item-import-clipboard",label:RED._("menu.label.clipboard"),onselect:"core:show-import-dialog"}, | ||||
|             {id:"menu-item-import-library",label:RED._("menu.label.library"),options:[]} | ||||
|         ]}); | ||||
|         menuOptions.push({id:"menu-item-export",label:RED._("menu.label.export"),options:[ | ||||
|             {id:"menu-item-export-clipboard",label:RED._("menu.label.clipboard"),onselect:"core:show-export-dialog"}, | ||||
|             {id:"menu-item-export-library",label:RED._("menu.label.library"),disabled:true,onselect:"core:library-export"} | ||||
|         ]}); | ||||
|         if (RED.settings.theme("menu.menu-item-import-library", true)) { | ||||
|             menuOptions.push({id: "menu-item-import", label: RED._("menu.label.import"), onselect: "core:show-import-dialog"}); | ||||
|         } | ||||
|         if (RED.settings.theme("menu.menu-item-export-library", true)) { | ||||
|             menuOptions.push({id: "menu-item-export", label: RED._("menu.label.export"), onselect: "core:show-export-dialog"}); | ||||
|         } | ||||
|         menuOptions.push(null); | ||||
|         menuOptions.push({id:"menu-item-search",label:RED._("menu.label.search"),onselect:"core:search"}); | ||||
|         menuOptions.push(null); | ||||
| @@ -474,7 +483,9 @@ var RED = (function() { | ||||
|         menuOptions.push({id:"menu-item-user-settings",label:RED._("menu.label.settings"),onselect:"core:show-user-settings"}); | ||||
|         menuOptions.push(null); | ||||
|  | ||||
|         menuOptions.push({id:"menu-item-keyboard-shortcuts",label:RED._("menu.label.keyboardShortcuts"),onselect:"core:show-help"}); | ||||
|         if (RED.settings.theme("menu.menu-item-keyboard-shortcuts", true)) { | ||||
|             menuOptions.push({id: "menu-item-keyboard-shortcuts", label: RED._("menu.label.keyboardShortcuts"), onselect: "core:show-help"}); | ||||
|         } | ||||
|         menuOptions.push({id:"menu-item-help", | ||||
|             label: RED.settings.theme("menu.menu-item-help.label",RED._("menu.label.help")), | ||||
|             href: RED.settings.theme("menu.menu-item-help.url","http://nodered.org/docs") | ||||
| @@ -482,13 +493,24 @@ var RED = (function() { | ||||
|         menuOptions.push({id:"menu-item-node-red-version", label:"v"+RED.settings.version, onselect: "core:show-about" }); | ||||
|  | ||||
|  | ||||
|         $('<li><a id="red-ui-header-button-sidemenu" class="button" href="#"><i class="fa fa-bars"></i></a></li>').appendTo(".red-ui-header-toolbar") | ||||
|         RED.menu.init({id:"red-ui-header-button-sidemenu",options: menuOptions}); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     function loadEditor() { | ||||
|  | ||||
|         RED.workspaces.init(); | ||||
|         RED.statusBar.init(); | ||||
|         RED.view.init(); | ||||
|         RED.userSettings.init(); | ||||
|         RED.user.init(); | ||||
|         RED.notifications.init(); | ||||
|         RED.library.init(); | ||||
|         RED.keyboard.init(); | ||||
|         RED.palette.init(); | ||||
|         RED.eventLog.init(); | ||||
|  | ||||
|         if (RED.settings.theme('palette.editable') !== false) { | ||||
|             RED.palette.editor.init(); | ||||
|         } else { | ||||
| @@ -504,27 +526,57 @@ var RED = (function() { | ||||
|         } | ||||
|  | ||||
|         RED.subflow.init(); | ||||
|         RED.workspaces.init(); | ||||
|         RED.clipboard.init(); | ||||
|         RED.search.init(); | ||||
|         RED.actionList.init(); | ||||
|         RED.editor.init(); | ||||
|         RED.diff.init(); | ||||
|  | ||||
|         RED.menu.init({id:"btn-sidemenu",options: menuOptions}); | ||||
|  | ||||
|         RED.deploy.init(RED.settings.theme("deployButton",null)); | ||||
|         RED.notifications.init(); | ||||
|  | ||||
|         RED.actions.add("core:show-about", showAbout); | ||||
|         buildMainMenu(); | ||||
|  | ||||
|         RED.nodes.init(); | ||||
|         RED.comms.connect(); | ||||
|  | ||||
|         $("#main-container").show(); | ||||
|         $(".header-toolbar").show(); | ||||
|         $("#red-ui-main-container").show(); | ||||
|         $(".red-ui-header-toolbar").show(); | ||||
|  | ||||
|         RED.actions.add("core:show-about", showAbout); | ||||
|  | ||||
|         loadNodeList(); | ||||
|     } | ||||
|  | ||||
|     function buildEditor(options) { | ||||
|         var header = $('<div id="red-ui-header"></div>').appendTo(options.target); | ||||
|         var logo = $('<span class="red-ui-header-logo"></span>').appendTo(header); | ||||
|         $('<ul class="red-ui-header-toolbar hide"></ul>').appendTo(header); | ||||
|         $('<div id="red-ui-header-shade" class="hide"></div>').appendTo(header); | ||||
|         $('<div id="red-ui-main-container" class="red-ui-sidebar-closed hide">'+ | ||||
|             '<div id="red-ui-workspace"></div>'+ | ||||
|             '<div id="red-ui-editor-stack"></div>'+ | ||||
|             '<div id="red-ui-palette"></div>'+ | ||||
|             '<div id="red-ui-sidebar"></div>'+ | ||||
|             '<div id="red-ui-sidebar-separator"></div>'+ | ||||
|         '</div>').appendTo(options.target); | ||||
|         $('<div id="red-ui-editor-node-configs"></div>').appendTo(options.target); | ||||
|         $('<div id="red-ui-full-shade" class="hide"></div>').appendTo(options.target); | ||||
|         $.getJSON(options.apiRootUrl+"theme", function(theme) { | ||||
|             if (theme.header) { | ||||
|                 if (theme.header.url) { | ||||
|                     logo = $("<a>",{href:theme.header.url}).appendTo(logo); | ||||
|                 } | ||||
|                 if (theme.header.image) { | ||||
|                     $('<img>',{src:theme.header.image}).appendTo(logo); | ||||
|                 } | ||||
|                 if (theme.header.title) { | ||||
|                     $('<span>').html(theme.header.title).appendTo(logo); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     var initialised = false; | ||||
|  | ||||
|     function init(options) { | ||||
| @@ -538,6 +590,10 @@ var RED = (function() { | ||||
|         if (options.apiRootUrl && !/\/$/.test(options.apiRootUrl)) { | ||||
|             options.apiRootUrl = options.apiRootUrl+"/"; | ||||
|         } | ||||
|         options.target = $("#red-ui-editor"); | ||||
|         options.target.addClass("red-ui-editor"); | ||||
|  | ||||
|         buildEditor(options); | ||||
|         RED.i18n.init(options, function() { | ||||
|             RED.settings.init(options, loadEditor); | ||||
|         }) | ||||
|   | ||||
| @@ -37,7 +37,7 @@ RED.settings = (function () { | ||||
|         if (key === "auth-tokens") { | ||||
|             localStorage.setItem(key, JSON.stringify(value)); | ||||
|         } else { | ||||
|             userSettings[key] = value; | ||||
|             RED.utils.setMessageProperty(userSettings,key,value); | ||||
|             saveUserSettings(); | ||||
|         } | ||||
|     }; | ||||
| @@ -46,16 +46,25 @@ RED.settings = (function () { | ||||
|      * If the key is not set in the localStorage it returns <i>undefined</i> | ||||
|      * Else return the JSON parsed value | ||||
|      * @param key | ||||
|      * @param defaultIfUndefined | ||||
|      * @returns {*} | ||||
|      */ | ||||
|     var get = function (key) { | ||||
|     var get = function (key,defaultIfUndefined) { | ||||
|         if (!hasLocalStorage()) { | ||||
|             return undefined; | ||||
|         } | ||||
|         if (key === "auth-tokens") { | ||||
|             return JSON.parse(localStorage.getItem(key)); | ||||
|         } else { | ||||
|             return userSettings[key]; | ||||
|             try { | ||||
|                 var v = RED.utils.getMessageProperty(userSettings,key); | ||||
|                 if (v === undefined) { | ||||
|                     v = defaultIfUndefined; | ||||
|                 } | ||||
|             } catch(err) { | ||||
|                 v = defaultIfUndefined; | ||||
|             } | ||||
|             return v; | ||||
|         } | ||||
|     }; | ||||
|  | ||||
| @@ -131,6 +140,12 @@ RED.settings = (function () { | ||||
|                     RED.settings.remove("auth-tokens"); | ||||
|                 } | ||||
|                 console.log("Node-RED: " + data.version); | ||||
|                 console.groupCollapsed("Versions"); | ||||
|                 console.log("jQuery",$().jquery) | ||||
|                 console.log("jQuery UI",$.ui.version); | ||||
|                 console.log("ACE",ace.version); | ||||
|                 console.log("D3",d3.version); | ||||
|                 console.groupEnd(); | ||||
|                 loadUserSettings(done); | ||||
|             }, | ||||
|             error: function(jqXHR,textStatus,errorThrown) { | ||||
|   | ||||
| @@ -97,14 +97,14 @@ RED.text.bidi = (function() { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Enforces the text direction for all the spans with style bidiAware under | ||||
|      * Enforces the text direction for all the spans with style red-ui-text-bidi-aware under | ||||
|      * workspace or sidebar div | ||||
|      */ | ||||
|     function enforceTextDirectionOnPage() { | ||||
|         $("#workspace").find('span.bidiAware').each(function() { | ||||
|         $("#red-ui-workspace").find('span.red-ui-text-bidi-aware').each(function() { | ||||
|             $(this).attr("dir", resolveBaseTextDir($(this).html())); | ||||
|         }); | ||||
|         $("#sidebar").find('span.bidiAware').each(function() { | ||||
|         $("#red-ui-sidebar").find('span.red-ui-text-bidi-aware').each(function() { | ||||
|             $(this).attr("dir", resolveBaseTextDir($(this).text())); | ||||
|         }); | ||||
|     } | ||||
|   | ||||
							
								
								
									
										230
									
								
								packages/node_modules/@node-red/editor-client/src/js/ui/actionList.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,230 @@ | ||||
| /** | ||||
|  * Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  **/ | ||||
| RED.actionList = (function() { | ||||
|  | ||||
|     var disabled = false; | ||||
|     var dialog = null; | ||||
|     var searchInput; | ||||
|     var searchResults; | ||||
|     var selected = -1; | ||||
|     var visible = false; | ||||
|  | ||||
|     var filterTerm = ""; | ||||
|     var filterTerms = []; | ||||
|     var previousActiveElement; | ||||
|  | ||||
|     function ensureSelectedIsVisible() { | ||||
|         var selectedEntry = searchResults.find("li.selected"); | ||||
|         if (selectedEntry.length === 1) { | ||||
|             var scrollWindow = searchResults.parent(); | ||||
|             var scrollHeight = scrollWindow.height(); | ||||
|             var scrollOffset = scrollWindow.scrollTop(); | ||||
|             var y = selectedEntry.position().top; | ||||
|             var h = selectedEntry.height(); | ||||
|             if (y+h > scrollHeight) { | ||||
|                 scrollWindow.animate({scrollTop: '-='+(scrollHeight-(y+h)-10)},50); | ||||
|             } else if (y<0) { | ||||
|                 scrollWindow.animate({scrollTop: '+='+(y-10)},50); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function createDialog() { | ||||
|         dialog = $("<div>",{id:"red-ui-actionList",class:"red-ui-search"}).appendTo("#red-ui-main-container"); | ||||
|         var searchDiv = $("<div>",{class:"red-ui-search-container"}).appendTo(dialog); | ||||
|         searchInput = $('<input type="text" data-i18n="[placeholder]keyboard.filterActions">').appendTo(searchDiv).searchBox({ | ||||
|             change: function() { | ||||
|                 filterTerm = $(this).val().trim(); | ||||
|                 filterTerms = filterTerm.split(" "); | ||||
|                 searchResults.editableList('filter'); | ||||
|                 searchResults.find("li.selected").removeClass("selected"); | ||||
|                 var children = searchResults.children(":visible"); | ||||
|                 if (children.length) { | ||||
|                     $(children[0]).addClass('selected'); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         searchInput.on('keydown',function(evt) { | ||||
|             var selectedChild; | ||||
|             if (evt.keyCode === 40) { | ||||
|                 // Down | ||||
|                 selectedChild = searchResults.find("li.selected"); | ||||
|                 if (!selectedChild.length) { | ||||
|                     var children = searchResults.children(":visible"); | ||||
|                     if (children.length) { | ||||
|                         $(children[0]).addClass('selected'); | ||||
|                     } | ||||
|                 } else { | ||||
|                     var nextChild = selectedChild.nextAll(":visible").first(); | ||||
|                     if (nextChild.length) { | ||||
|                         selectedChild.removeClass('selected'); | ||||
|                         nextChild.addClass('selected'); | ||||
|                     } | ||||
|                 } | ||||
|                 ensureSelectedIsVisible(); | ||||
|                 evt.preventDefault(); | ||||
|             } else if (evt.keyCode === 38) { | ||||
|                 // Up | ||||
|                 selectedChild = searchResults.find("li.selected"); | ||||
|                 var nextChild = selectedChild.prevAll(":visible").first(); | ||||
|                 if (nextChild.length) { | ||||
|                     selectedChild.removeClass('selected'); | ||||
|                     nextChild.addClass('selected'); | ||||
|                 } | ||||
|                 ensureSelectedIsVisible(); | ||||
|                 evt.preventDefault(); | ||||
|             } else if (evt.keyCode === 13) { | ||||
|                 // Enter | ||||
|                 selectedChild = searchResults.find("li.selected"); | ||||
|                 selectCommand(searchResults.editableList('getItem',selectedChild)); | ||||
|             } | ||||
|         }); | ||||
|         searchInput.i18n(); | ||||
|  | ||||
|         var searchResultsDiv = $("<div>",{class:"red-ui-search-results-container"}).appendTo(dialog); | ||||
|         searchResults = $('<ol>',{style:"position: absolute;top: 5px;bottom: 5px;left: 5px;right: 5px;"}).appendTo(searchResultsDiv).editableList({ | ||||
|             addButton: false, | ||||
|             addItem: function(container,i,action) { | ||||
|                 if (action.id === undefined) { | ||||
|                     $('<div>',{class:"red-ui-search-empty"}).text(RED._('search.empty')).appendTo(container); | ||||
|                 } else { | ||||
|                     var div = $('<a>',{href:'#',class:"red-ui-search-result"}).appendTo(container); | ||||
|                     var contentDiv = $('<div>',{class:"red-ui-search-result-action"}).appendTo(div); | ||||
|  | ||||
|  | ||||
|                     $('<div>').text(action.label).appendTo(contentDiv); | ||||
|                     // $('<div>',{class:"red-ui-search-result-node-type"}).text(node.type).appendTo(contentDiv); | ||||
|                     // $('<div>',{class:"red-ui-search-result-node-id"}).text(node.id).appendTo(contentDiv); | ||||
|                     if (action.key) { | ||||
|                         $('<div>',{class:"red-ui-search-result-action-key"}).html(RED.keyboard.formatKey(action.key)).appendTo(contentDiv); | ||||
|                     } | ||||
|                     div.on("click", function(evt) { | ||||
|                         evt.preventDefault(); | ||||
|                         selectCommand(action); | ||||
|                     }); | ||||
|                 } | ||||
|             }, | ||||
|             scrollOnAdd: false, | ||||
|             filter: function(item) { | ||||
|                 if (filterTerm !== "") { | ||||
|                     var pos=0; | ||||
|                     for (var i=0;i<filterTerms.length;i++) { | ||||
|                         var j = item._label.indexOf(filterTerms[i],pos); | ||||
|                         if (j > -1) { | ||||
|                             pos = j; | ||||
|                         } else { | ||||
|                             return false; | ||||
|                         } | ||||
|                     } | ||||
|                     return true; | ||||
|                 } | ||||
|                 return true; | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     function selectCommand(command) { | ||||
|         hide(); | ||||
|         if (command) { | ||||
|             RED.actions.invoke(command.id); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function show(v) { | ||||
|         if (disabled) { | ||||
|             return; | ||||
|         } | ||||
|         if (!visible) { | ||||
|             previousActiveElement = document.activeElement; | ||||
|             RED.keyboard.add("*","escape",function(){hide()}); | ||||
|             $("#red-ui-header-shade").show(); | ||||
|             $("#red-ui-editor-shade").show(); | ||||
|             $("#red-ui-palette-shade").show(); | ||||
|             $("#red-ui-sidebar-shade").show(); | ||||
|             $("#red-ui-sidebar-separator").hide(); | ||||
|             if (dialog === null) { | ||||
|                 createDialog(); | ||||
|             } | ||||
|             dialog.slideDown(300); | ||||
|             searchInput.searchBox('value',v) | ||||
|             searchResults.editableList('empty'); | ||||
|             results = []; | ||||
|             var actions = RED.actions.list(); | ||||
|             actions.sort(function(A,B) { | ||||
|                 return A.id.localeCompare(B.id); | ||||
|             }); | ||||
|             actions.forEach(function(action) { | ||||
|                 action.label = action.id.replace(/:/,": ").replace(/-/g," ").replace(/(^| )./g,function() { return arguments[0].toUpperCase()}); | ||||
|                 action._label = action.label.toLowerCase(); | ||||
|                 searchResults.editableList('addItem',action) | ||||
|             }) | ||||
|             RED.events.emit("actionList:open"); | ||||
|             visible = true; | ||||
|         } | ||||
|         searchInput.trigger("focus"); | ||||
|         var children = searchResults.children(":visible"); | ||||
|         if (children.length) { | ||||
|             $(children[0]).addClass('selected'); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function hide() { | ||||
|         if (visible) { | ||||
|             RED.keyboard.remove("escape"); | ||||
|             visible = false; | ||||
|             $("#red-ui-header-shade").hide(); | ||||
|             $("#red-ui-editor-shade").hide(); | ||||
|             $("#red-ui-palette-shade").hide(); | ||||
|             $("#red-ui-sidebar-shade").hide(); | ||||
|             $("#red-ui-sidebar-separator").show(); | ||||
|             if (dialog !== null) { | ||||
|                 dialog.slideUp(200,function() { | ||||
|                     searchInput.searchBox('value',''); | ||||
|                 }); | ||||
|             } | ||||
|             RED.events.emit("actionList:close"); | ||||
|             if (previousActiveElement) { | ||||
|                 $(previousActiveElement).trigger("focus"); | ||||
|                 previousActiveElement = null; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function init() { | ||||
|         RED.actions.add("core:show-action-list",show); | ||||
|  | ||||
|         RED.events.on("editor:open",function() { disabled = true; }); | ||||
|         RED.events.on("editor:close",function() { disabled = false; }); | ||||
|         RED.events.on("search:open",function() { disabled = true; }); | ||||
|         RED.events.on("search:close",function() { disabled = false; }); | ||||
|         RED.events.on("type-search:open",function() { disabled = true; }); | ||||
|         RED.events.on("type-search:close",function() { disabled = false; }); | ||||
|  | ||||
|         $("#red-ui-header-shade").on('mousedown',hide); | ||||
|         $("#red-ui-editor-shade").on('mousedown',hide); | ||||
|         $("#red-ui-palette-shade").on('mousedown',hide); | ||||
|         $("#red-ui-sidebar-shade").on('mousedown',hide); | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         init: init, | ||||
|         show: show, | ||||
|         hide: hide | ||||
|     }; | ||||
|  | ||||
| })(); | ||||
| @@ -24,38 +24,38 @@ RED.clipboard = (function() { | ||||
|     var disabled = false; | ||||
|     var popover; | ||||
|     var currentPopoverError; | ||||
|     var activeTab; | ||||
|     var libraryBrowser; | ||||
|     var examplesBrowser; | ||||
|  | ||||
|     function setupDialogs() { | ||||
|         dialog = $('<div id="clipboard-dialog" class="hide node-red-dialog"><form class="dialog-form form-horizontal"></form></div>') | ||||
|             .appendTo("body") | ||||
|         dialog = $('<div id="red-ui-clipboard-dialog" class="hide"><form class="dialog-form form-horizontal"></form></div>') | ||||
|             .appendTo("#red-ui-editor") | ||||
|             .dialog({ | ||||
|                 modal: true, | ||||
|                 autoOpen: false, | ||||
|                 width: 500, | ||||
|                 width: 700, | ||||
|                 resizable: false, | ||||
|                 classes: { | ||||
|                     "ui-dialog": "red-ui-editor-dialog", | ||||
|                     "ui-dialog-titlebar-close": "hide", | ||||
|                     "ui-widget-overlay": "red-ui-editor-dialog" | ||||
|                 }, | ||||
|                 buttons: [ | ||||
|                     { | ||||
|                         id: "clipboard-dialog-cancel", | ||||
|                         id: "red-ui-clipboard-dialog-cancel", | ||||
|                         text: RED._("common.label.cancel"), | ||||
|                         click: function() { | ||||
|                             $( this ).dialog( "close" ); | ||||
|                         } | ||||
|                     }, | ||||
|                     { | ||||
|                         id: "clipboard-dialog-close", | ||||
|                         class: "primary", | ||||
|                         text: RED._("common.label.close"), | ||||
|                         click: function() { | ||||
|                             $( this ).dialog( "close" ); | ||||
|                         } | ||||
|                     }, | ||||
|                     { | ||||
|                         id: "clipboard-dialog-download", | ||||
|                         id: "red-ui-clipboard-dialog-download", | ||||
|                         class: "primary", | ||||
|                         text: RED._("clipboard.download"), | ||||
|                         click: function() { | ||||
|                             var element = document.createElement('a'); | ||||
|                             element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent($("#clipboard-export").val())); | ||||
|                             element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent($("#red-ui-clipboard-dialog-export-text").val())); | ||||
|                             element.setAttribute('download', "flows.json"); | ||||
|                             element.style.display = 'none'; | ||||
|                             document.body.appendChild(element); | ||||
| @@ -65,30 +65,100 @@ RED.clipboard = (function() { | ||||
|                         } | ||||
|                     }, | ||||
|                     { | ||||
|                         id: "clipboard-dialog-copy", | ||||
|                         id: "red-ui-clipboard-dialog-export", | ||||
|                         class: "primary", | ||||
|                         text: RED._("clipboard.export.copy"), | ||||
|                         click: function() { | ||||
|                             $("#clipboard-export").select(); | ||||
|                             document.execCommand("copy"); | ||||
|                             document.getSelection().removeAllRanges(); | ||||
|                             RED.notify(RED._("clipboard.nodesExported"),{id:"clipboard"}); | ||||
|                             $( this ).dialog( "close" ); | ||||
|                             if (activeTab === "red-ui-clipboard-dialog-export-tab-clipboard") { | ||||
|                                 $("#red-ui-clipboard-dialog-export-text").select(); | ||||
|                                 document.execCommand("copy"); | ||||
|                                 document.getSelection().removeAllRanges(); | ||||
|                                 RED.notify(RED._("clipboard.nodesExported"),{id:"clipboard"}); | ||||
|                                 $( this ).dialog( "close" ); | ||||
|                             } else { | ||||
|                                 var flowToExport = $("#red-ui-clipboard-dialog-export-text").val(); | ||||
|                                 var selectedPath = libraryBrowser.getSelected(); | ||||
|                                 if (!selectedPath.children) { | ||||
|                                     selectedPath = selectedPath.parent; | ||||
|                                 } | ||||
|                                 var filename = $("#red-ui-clipboard-dialog-tab-library-name").val().trim(); | ||||
|                                 var saveFlow = function() { | ||||
|                                     $.ajax({ | ||||
|                                         url:'library/'+selectedPath.library+'/'+selectedPath.type+'/'+selectedPath.path + filename, | ||||
|                                         type: "POST", | ||||
|                                         data: flowToExport, | ||||
|                                         contentType: "application/json; charset=utf-8" | ||||
|                                     }).done(function() { | ||||
|                                         $(dialog).dialog( "close" ); | ||||
|                                         RED.notify(RED._("library.exportedToLibrary"),"success"); | ||||
|                                     }).fail(function(xhr,textStatus,err) { | ||||
|                                         if (xhr.status === 401) { | ||||
|                                             RED.notify(RED._("library.saveFailed",{message:RED._("user.notAuthorized")}),"error"); | ||||
|                                         } else { | ||||
|                                             RED.notify(RED._("library.saveFailed",{message:xhr.responseText}),"error"); | ||||
|                                         } | ||||
|                                     }); | ||||
|                                 } | ||||
|                                 if (selectedPath.children) { | ||||
|                                     var exists = false; | ||||
|                                     selectedPath.children.forEach(function(f) { | ||||
|                                         if (f.label === filename) { | ||||
|                                             exists = true; | ||||
|                                         } | ||||
|                                     }); | ||||
|                                     if (exists) { | ||||
|                                         dialog.dialog("close"); | ||||
|                                         var notification = RED.notify(RED._("clipboard.export.exists",{file:RED.utils.sanitize(filename)}),{ | ||||
|                                             type: "warning", | ||||
|                                             fixed: true, | ||||
|                                             buttons: [{ | ||||
|                                                 text: RED._("common.label.cancel"), | ||||
|                                                 click: function() { | ||||
|                                                     notification.hideNotification() | ||||
|                                                     dialog.dialog( "open" ); | ||||
|                                                 } | ||||
|                                             },{ | ||||
|                                                 text: RED._("clipboard.export.overwrite"), | ||||
|                                                 click: function() { | ||||
|                                                     notification.hideNotification() | ||||
|                                                     saveFlow(); | ||||
|                                                 } | ||||
|                                             }] | ||||
|                                         }); | ||||
|                                     } else { | ||||
|                                         saveFlow(); | ||||
|                                     } | ||||
|                                 } else { | ||||
|                                     saveFlow(); | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     }, | ||||
|                     { | ||||
|                         id: "clipboard-dialog-ok", | ||||
|                         id: "red-ui-clipboard-dialog-ok", | ||||
|                         class: "primary", | ||||
|                         text: RED._("common.label.import"), | ||||
|                         click: function() { | ||||
|                             RED.view.importNodes($("#clipboard-import").val(),$("#import-tab > a.selected").attr('id') === 'import-tab-new'); | ||||
|                             var addNewFlow = ($("#red-ui-clipboard-dialog-import-opt > a.selected").attr('id') === 'red-ui-clipboard-dialog-import-opt-new'); | ||||
|                             if (activeTab === "red-ui-clipboard-dialog-import-tab-clipboard") { | ||||
|                                 RED.view.importNodes($("#red-ui-clipboard-dialog-import-text").val(),addNewFlow); | ||||
|                             } else { | ||||
|                                 var selectedPath; | ||||
|                                 if (activeTab === "red-ui-clipboard-dialog-import-tab-library") { | ||||
|                                     selectedPath = libraryBrowser.getSelected(); | ||||
|                                 } else { | ||||
|                                     selectedPath = examplesBrowser.getSelected(); | ||||
|                                 } | ||||
|                                 if (selectedPath.path) { | ||||
|                                     $.get('library/'+selectedPath.library+'/'+selectedPath.type+'/'+selectedPath.path, function(data) { | ||||
|                                         RED.view.importNodes(data,addNewFlow); | ||||
|                                     }); | ||||
|                                 } | ||||
|                             } | ||||
|                             $( this ).dialog( "close" ); | ||||
|                         } | ||||
|                     } | ||||
|                 ], | ||||
|                 open: function(e) { | ||||
|                     $(this).parent().find(".ui-dialog-titlebar-close").hide(); | ||||
|                 }, | ||||
|                 close: function(e) { | ||||
|                     if (popover) { | ||||
|                         popover.close(true); | ||||
| @@ -101,152 +171,281 @@ RED.clipboard = (function() { | ||||
|  | ||||
|         exportNodesDialog = | ||||
|             '<div class="form-row">'+ | ||||
|                 '<label style="width:auto;margin-right: 10px;" data-i18n="clipboard.export.copy"></label>'+ | ||||
|                 '<span id="export-range-group" class="button-group">'+ | ||||
|                     '<a id="export-range-selected" class="editor-button toggle" href="#" data-i18n="clipboard.export.selected"></a>'+ | ||||
|                     '<a id="export-range-flow" class="editor-button toggle" href="#" data-i18n="clipboard.export.current"></a>'+ | ||||
|                     '<a id="export-range-full" class="editor-button toggle" href="#" data-i18n="clipboard.export.all"></a>'+ | ||||
|                 '<label style="width:auto;margin-right: 10px;" data-i18n="common.label.export"></label>'+ | ||||
|                 '<span id="red-ui-clipboard-dialog-export-rng-group" class="button-group">'+ | ||||
|                     '<a id="red-ui-clipboard-dialog-export-rng-selected" class="red-ui-button toggle" href="#" data-i18n="clipboard.export.selected"></a>'+ | ||||
|                     '<a id="red-ui-clipboard-dialog-export-rng-flow" class="red-ui-button toggle" href="#" data-i18n="clipboard.export.current"></a>'+ | ||||
|                     '<a id="red-ui-clipboard-dialog-export-rng-full" class="red-ui-button toggle" href="#" data-i18n="clipboard.export.all"></a>'+ | ||||
|                 '</span>'+ | ||||
|             '</div>'+ | ||||
|             '<div class="form-row">'+ | ||||
|                 '<textarea readonly style="resize: none; width: 100%; border-radius: 4px;font-family: monospace; font-size: 12px; background:#f3f3f3; padding-left: 0.5em; box-sizing:border-box;" id="clipboard-export" rows="5"></textarea>'+ | ||||
|             '</div>'+ | ||||
|             '<div class="form-row" style="text-align: right;">'+ | ||||
|                 '<span id="export-format-group" class="button-group">'+ | ||||
|                     '<a id="export-format-mini" class="editor-button editor-button-small toggle" href="#" data-i18n="clipboard.export.compact"></a>'+ | ||||
|                     '<a id="export-format-full" class="editor-button editor-button-small toggle" href="#" data-i18n="clipboard.export.formatted"></a>'+ | ||||
|                 '</span>'+ | ||||
|             '</div>'; | ||||
|             '<div class="red-ui-clipboard-dialog-box">'+ | ||||
|                 '<div class="red-ui-clipboard-dialog-tabs">'+ | ||||
|                     '<ul id="red-ui-clipboard-dialog-export-tabs"></ul>'+ | ||||
|                 '</div>'+ | ||||
|                 '<div id="red-ui-clipboard-dialog-export-tabs-content" class="red-ui-clipboard-dialog-tabs-content">'+ | ||||
|                     '<div id="red-ui-clipboard-dialog-export-tab-clipboard" class="red-ui-clipboard-dialog-tab-clipboard">'+ | ||||
|                         '<div class="form-row">'+ | ||||
|                             '<textarea readonly id="red-ui-clipboard-dialog-export-text"></textarea>'+ | ||||
|                         '</div>'+ | ||||
|                         '<div class="form-row" style="text-align: right;">'+ | ||||
|                             '<span id="red-ui-clipboard-dialog-export-fmt-group" class="button-group">'+ | ||||
|                                 '<a id="red-ui-clipboard-dialog-export-fmt-mini" class="red-ui-button red-ui-button-small toggle" href="#" data-i18n="clipboard.export.compact"></a>'+ | ||||
|                                 '<a id="red-ui-clipboard-dialog-export-fmt-full" class="red-ui-button red-ui-button-small toggle" href="#" data-i18n="clipboard.export.formatted"></a>'+ | ||||
|                             '</span>'+ | ||||
|                         '</div>'+ | ||||
|                     '</div>'+ | ||||
|                     '<div id="red-ui-clipboard-dialog-export-tab-library" class="red-ui-clipboard-dialog-tab-library">'+ | ||||
|                         '<div id="red-ui-clipboard-dialog-export-tab-library-browser"></div>'+ | ||||
|                         '<div class="form-row">'+ | ||||
|                             '<label data-i18n="clipboard.export.exportAs"></label><input id="red-ui-clipboard-dialog-tab-library-name" type="text">'+ | ||||
|                         '</div>'+ | ||||
|                     '</div>'+ | ||||
|                 '</div>'+ | ||||
|             '</div>' | ||||
|             ; | ||||
|  | ||||
|  | ||||
|         importNodesDialog = | ||||
|             '<div class="form-row"><span data-i18n="clipboard.pasteNodes"></span>'+ | ||||
|                 ' <a class="editor-button" id="import-file-upload-btn"><i class="fa fa-upload"></i> <span data-i18n="clipboard.selectFile"></span></a>'+ | ||||
|                 '<input type="file" id="import-file-upload" accept=".json" style="display:none">'+ | ||||
|             '<div class="red-ui-clipboard-dialog-box" style="margin-bottom: 12px">'+ | ||||
|                 '<div class="red-ui-clipboard-dialog-tabs">'+ | ||||
|                     '<ul id="red-ui-clipboard-dialog-import-tabs"></ul>'+ | ||||
|                 '</div>'+ | ||||
|                 '<div id="red-ui-clipboard-dialog-import-tabs-content" class="red-ui-clipboard-dialog-tabs-content">'+ | ||||
|                     '<div id="red-ui-clipboard-dialog-import-tab-clipboard" class="red-ui-clipboard-dialog-tab-clipboard">'+ | ||||
|                         '<div class="form-row"><span data-i18n="clipboard.pasteNodes"></span>'+ | ||||
|                             ' <a class="red-ui-button" id="red-ui-clipboard-dialog-import-file-upload-btn"><i class="fa fa-upload"></i> <span data-i18n="clipboard.selectFile"></span></a>'+ | ||||
|                             '<input type="file" id="red-ui-clipboard-dialog-import-file-upload" accept=".json" style="display:none">'+ | ||||
|                         '</div>'+ | ||||
|                         '<div class="form-row">'+ | ||||
|                             '<textarea id="red-ui-clipboard-dialog-import-text"></textarea>'+ | ||||
|                         '</div>'+ | ||||
|                     '</div>'+ | ||||
|                     '<div id="red-ui-clipboard-dialog-import-tab-library" class="red-ui-clipboard-dialog-tab-library"></div>'+ | ||||
|                     '<div id="red-ui-clipboard-dialog-import-tab-examples" class="red-ui-clipboard-dialog-tab-library"></div>'+ | ||||
|                 '</div>'+ | ||||
|             '</div>'+ | ||||
|             '<div class="form-row">'+ | ||||
|                 '<textarea style="resize: none; width: 100%; border-radius: 0px;font-family: monospace; font-size: 12px; background:#eee; padding-left: 0.5em; box-sizing:border-box;" id="clipboard-import" rows="5"></textarea>'+ | ||||
|             '</div>'+ | ||||
|             '<div class="form-row">'+ | ||||
|             '<label style="width:auto;margin-right: 10px;" data-i18n="clipboard.import.import"></label>'+ | ||||
|             '<span id="import-tab" class="button-group">'+ | ||||
|                 '<a id="import-tab-current" class="editor-button toggle selected" href="#" data-i18n="clipboard.export.current"></a>'+ | ||||
|                 '<a id="import-tab-new" class="editor-button toggle" href="#" data-i18n="clipboard.import.newFlow"></a>'+ | ||||
|             '</span>'+ | ||||
|                 '<label style="width:auto;margin-right: 10px;" data-i18n="clipboard.import.import"></label>'+ | ||||
|                 '<span id="red-ui-clipboard-dialog-import-opt" class="button-group">'+ | ||||
|                     '<a id="red-ui-clipboard-dialog-import-opt-current" class="red-ui-button toggle selected" href="#" data-i18n="clipboard.export.current"></a>'+ | ||||
|                     '<a id="red-ui-clipboard-dialog-import-opt-new" class="red-ui-button toggle" href="#" data-i18n="clipboard.import.newFlow"></a>'+ | ||||
|                 '</span>'+ | ||||
|             '</div>'; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     var validateImportTimeout; | ||||
|  | ||||
|     function validateImport() { | ||||
|         if (validateImportTimeout) { | ||||
|             clearTimeout(validateImportTimeout); | ||||
|     var validateExportFilenameTimeout | ||||
|     function validateExportFilename() { | ||||
|         if (validateExportFilenameTimeout) { | ||||
|             clearTimeout(validateExportFilenameTimeout); | ||||
|         } | ||||
|         validateImportTimeout = setTimeout(function() { | ||||
|             var importInput = $("#clipboard-import"); | ||||
|             var v = importInput.val().trim(); | ||||
|             if (v === "") { | ||||
|                 popover.close(true); | ||||
|                 currentPopoverError = null; | ||||
|                 importInput.removeClass("input-error"); | ||||
|                 $("#clipboard-dialog-ok").button("disable"); | ||||
|                 return; | ||||
|             } | ||||
|             try { | ||||
|                 if (!/^\[[\s\S]*\]$/m.test(v)) { | ||||
|                     throw new Error(RED._("clipboard.import.errors.notArray")); | ||||
|                 } | ||||
|                 var res = JSON.parse(v); | ||||
|                 for (var i=0;i<res.length;i++) { | ||||
|                     if (typeof res[i] !== "object") { | ||||
|                         throw new Error(RED._("clipboard.import.errors.itemNotObject",{index:i})); | ||||
|                     } | ||||
|                     if (!res[i].hasOwnProperty('id')) { | ||||
|                         throw new Error(RED._("clipboard.import.errors.missingId",{index:i})); | ||||
|                     } | ||||
|                     if (!res[i].hasOwnProperty('type')) { | ||||
|                         throw new Error(RED._("clipboard.import.errors.missingType",{index:i})); | ||||
|                     } | ||||
|                 } | ||||
|                 currentPopoverError = null; | ||||
|                 popover.close(true); | ||||
|                 importInput.removeClass("input-error"); | ||||
|                 importInput.val(v); | ||||
|                 $("#clipboard-dialog-ok").button("enable"); | ||||
|             } catch(err) { | ||||
|                 if (v !== "") { | ||||
|                     importInput.addClass("input-error"); | ||||
|                     var errString = err.toString(); | ||||
|                     if (errString !== currentPopoverError) { | ||||
|                         // Display the error as-is. | ||||
|                         // Error messages are only in English. Each browser has its | ||||
|                         // own set of messages with very little consistency. | ||||
|                         // To provide translated messages this code will either need to: | ||||
|                         // - reduce everything down to 'unexpected token at position x' | ||||
|                         //   which is the least useful, but most consistent message | ||||
|                         // - use a custom/library parser that gives consistent messages | ||||
|                         //   which can be translated. | ||||
|                         var message = $('<div class="clipboard-import-error"></div>').text(errString); | ||||
|                         var errorPos; | ||||
|                         // Chrome error messages | ||||
|                         var m = /at position (\d+)/i.exec(errString); | ||||
|                         if (m) { | ||||
|                             errorPos = parseInt(m[1]); | ||||
|                         } else { | ||||
|                             // Firefox error messages | ||||
|                             m = /at line (\d+) column (\d+)/i.exec(errString); | ||||
|                             if (m) { | ||||
|                                 var line = parseInt(m[1])-1; | ||||
|                                 var col = parseInt(m[2])-1; | ||||
|                                 var lines = v.split("\n"); | ||||
|                                 errorPos = 0; | ||||
|                                 for (var i=0;i<line;i++) { | ||||
|                                     errorPos += lines[i].length+1; | ||||
|                                 } | ||||
|                                 errorPos += col; | ||||
|                             } else { | ||||
|                                 // Safari doesn't provide any position information | ||||
|                                 // IE: tbd | ||||
|                             } | ||||
|                         } | ||||
|  | ||||
|                         if (errorPos !== undefined) { | ||||
|                             v = v.replace(/\n/g,"↵"); | ||||
|                             var index = parseInt(m[1]); | ||||
|                             var parseError = $('<div>').appendTo(message); | ||||
|                             var code = $('<pre>').appendTo(parseError); | ||||
|                             $('<span>').text(v.substring(errorPos-12,errorPos)).appendTo(code) | ||||
|                             $('<span class="error">').text(v.charAt(errorPos)).appendTo(code); | ||||
|                             $('<span>').text(v.substring(errorPos+1,errorPos+12)).appendTo(code); | ||||
|                         } | ||||
|                         popover.close(true).setContent(message).open(); | ||||
|                         currentPopoverError = errString; | ||||
|                     } | ||||
|                 } else { | ||||
|                     currentPopoverError = null; | ||||
|                 } | ||||
|                 $("#clipboard-dialog-ok").button("disable"); | ||||
|         validateExportFilenameTimeout = setTimeout(function() { | ||||
|             var filenameInput = $("#red-ui-clipboard-dialog-tab-library-name"); | ||||
|             var filename = filenameInput.val().trim(); | ||||
|             var valid = filename.length > 0 && !/[\/\\]/.test(filename); | ||||
|             if (valid) { | ||||
|                 filenameInput.removeClass("input-error"); | ||||
|                 $("#red-ui-clipboard-dialog-export").button("enable"); | ||||
|             } else { | ||||
|                 filenameInput.addClass("input-error"); | ||||
|                 $("#red-ui-clipboard-dialog-export").button("disable"); | ||||
|             } | ||||
|         },100); | ||||
|     } | ||||
|  | ||||
|     function importNodes() { | ||||
|     var validateImportTimeout; | ||||
|     function validateImport() { | ||||
|         if (activeTab === "red-ui-clipboard-dialog-import-tab-clipboard") { | ||||
|             if (validateImportTimeout) { | ||||
|                 clearTimeout(validateImportTimeout); | ||||
|             } | ||||
|             validateImportTimeout = setTimeout(function() { | ||||
|                 var importInput = $("#red-ui-clipboard-dialog-import-text"); | ||||
|                 var v = importInput.val().trim(); | ||||
|                 if (v === "") { | ||||
|                     popover.close(true); | ||||
|                     currentPopoverError = null; | ||||
|                     importInput.removeClass("input-error"); | ||||
|                     $("#red-ui-clipboard-dialog-ok").button("disable"); | ||||
|                     return; | ||||
|                 } | ||||
|                 try { | ||||
|                     if (!/^\[[\s\S]*\]$/m.test(v)) { | ||||
|                         throw new Error(RED._("clipboard.import.errors.notArray")); | ||||
|                     } | ||||
|                     var res = JSON.parse(v); | ||||
|                     for (var i=0;i<res.length;i++) { | ||||
|                         if (typeof res[i] !== "object") { | ||||
|                             throw new Error(RED._("clipboard.import.errors.itemNotObject",{index:i})); | ||||
|                         } | ||||
|                         if (!res[i].hasOwnProperty('id')) { | ||||
|                             throw new Error(RED._("clipboard.import.errors.missingId",{index:i})); | ||||
|                         } | ||||
|                         if (!res[i].hasOwnProperty('type')) { | ||||
|                             throw new Error(RED._("clipboard.import.errors.missingType",{index:i})); | ||||
|                         } | ||||
|                     } | ||||
|                     currentPopoverError = null; | ||||
|                     popover.close(true); | ||||
|                     importInput.removeClass("input-error"); | ||||
|                     importInput.val(v); | ||||
|                     $("#red-ui-clipboard-dialog-ok").button("enable"); | ||||
|                 } catch(err) { | ||||
|                     if (v !== "") { | ||||
|                         importInput.addClass("input-error"); | ||||
|                         var errString = err.toString(); | ||||
|                         if (errString !== currentPopoverError) { | ||||
|                             // Display the error as-is. | ||||
|                             // Error messages are only in English. Each browser has its | ||||
|                             // own set of messages with very little consistency. | ||||
|                             // To provide translated messages this code will either need to: | ||||
|                             // - reduce everything down to 'unexpected token at position x' | ||||
|                             //   which is the least useful, but most consistent message | ||||
|                             // - use a custom/library parser that gives consistent messages | ||||
|                             //   which can be translated. | ||||
|                             var message = $('<div class="red-ui-clipboard-import-error"></div>').text(errString); | ||||
|                             var errorPos; | ||||
|                             // Chrome error messages | ||||
|                             var m = /at position (\d+)/i.exec(errString); | ||||
|                             if (m) { | ||||
|                                 errorPos = parseInt(m[1]); | ||||
|                             } else { | ||||
|                                 // Firefox error messages | ||||
|                                 m = /at line (\d+) column (\d+)/i.exec(errString); | ||||
|                                 if (m) { | ||||
|                                     var line = parseInt(m[1])-1; | ||||
|                                     var col = parseInt(m[2])-1; | ||||
|                                     var lines = v.split("\n"); | ||||
|                                     errorPos = 0; | ||||
|                                     for (var i=0;i<line;i++) { | ||||
|                                         errorPos += lines[i].length+1; | ||||
|                                     } | ||||
|                                     errorPos += col; | ||||
|                                 } else { | ||||
|                                     // Safari doesn't provide any position information | ||||
|                                     // IE: tbd | ||||
|                                 } | ||||
|                             } | ||||
|  | ||||
|                             if (errorPos !== undefined) { | ||||
|                                 v = v.replace(/\n/g,"↵"); | ||||
|                                 var index = parseInt(m[1]); | ||||
|                                 var parseError = $('<div>').appendTo(message); | ||||
|                                 var code = $('<pre>').appendTo(parseError); | ||||
|                                 $('<span>').text(v.substring(errorPos-12,errorPos)).appendTo(code) | ||||
|                                 $('<span class="error">').text(v.charAt(errorPos)).appendTo(code); | ||||
|                                 $('<span>').text(v.substring(errorPos+1,errorPos+12)).appendTo(code); | ||||
|                             } | ||||
|                             popover.close(true).setContent(message).open(); | ||||
|                             currentPopoverError = errString; | ||||
|                         } | ||||
|                     } else { | ||||
|                         currentPopoverError = null; | ||||
|                     } | ||||
|                     $("#red-ui-clipboard-dialog-ok").button("disable"); | ||||
|                 } | ||||
|             },100); | ||||
|         } else { | ||||
|             var file = libraryBrowser.getSelected(); | ||||
|             if (file && file.label && !file.children) { | ||||
|                 $("#red-ui-clipboard-dialog-ok").button("enable"); | ||||
|             } else { | ||||
|                 $("#red-ui-clipboard-dialog-ok").button("disable"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function importNodes(mode) { | ||||
|         if (disabled) { | ||||
|             return; | ||||
|         } | ||||
|         mode = mode || "clipboard"; | ||||
|  | ||||
|         dialogContainer.empty(); | ||||
|         dialogContainer.append($(importNodesDialog)); | ||||
|  | ||||
|         var tabs = RED.tabs.create({ | ||||
|             id: "red-ui-clipboard-dialog-import-tabs", | ||||
|             vertical: true, | ||||
|             onchange: function(tab) { | ||||
|                 $("#red-ui-clipboard-dialog-import-tabs-content").children().hide(); | ||||
|                 $("#" + tab.id).show(); | ||||
|                 activeTab = tab.id; | ||||
|                 if (popover) { | ||||
|                     popover.close(true); | ||||
|                     currentPopoverError = null; | ||||
|                 } | ||||
|                 if (tab.id === "red-ui-clipboard-dialog-import-tab-clipboard") { | ||||
|                     $("#red-ui-clipboard-dialog-import-text").trigger("focus"); | ||||
|                 } else { | ||||
|                     libraryBrowser.focus(); | ||||
|                 } | ||||
|                 validateImport(); | ||||
|             } | ||||
|         }); | ||||
|         tabs.addTab({ | ||||
|             id: "red-ui-clipboard-dialog-import-tab-clipboard", | ||||
|             label: RED._("clipboard.clipboard") | ||||
|         }); | ||||
|         tabs.addTab({ | ||||
|             id: "red-ui-clipboard-dialog-import-tab-library", | ||||
|             label: RED._("library.library") | ||||
|         }); | ||||
|         tabs.addTab({ | ||||
|             id: "red-ui-clipboard-dialog-import-tab-examples", | ||||
|             label: RED._("library.types.examples") | ||||
|         }); | ||||
|  | ||||
|         $("#red-ui-clipboard-dialog-tab-library-name").on("keyup", validateExportFilename); | ||||
|         $("#red-ui-clipboard-dialog-tab-library-name").on('paste',function() { setTimeout(validateExportFilename,10)}); | ||||
|         $("#red-ui-clipboard-dialog-export").button("enable"); | ||||
|  | ||||
|         libraryBrowser = RED.library.createBrowser({ | ||||
|             container: $("#red-ui-clipboard-dialog-import-tab-library"), | ||||
|             onselect: function(file) { | ||||
|                 if (file && file.label && !file.children) { | ||||
|                     $("#red-ui-clipboard-dialog-ok").button("enable"); | ||||
|                 } else { | ||||
|                     $("#red-ui-clipboard-dialog-ok").button("disable"); | ||||
|                 } | ||||
|             }, | ||||
|             onconfirm: function(item) { | ||||
|                 if (item && item.label && !item.children) { | ||||
|                     $("#red-ui-clipboard-dialog-ok").trigger("click"); | ||||
|                 } | ||||
|             } | ||||
|         }) | ||||
|         loadFlowLibrary(libraryBrowser,"local",RED._("library.types.local")); | ||||
|  | ||||
|         examplesBrowser = RED.library.createBrowser({ | ||||
|             container: $("#red-ui-clipboard-dialog-import-tab-examples"), | ||||
|             onselect: function(file) { | ||||
|                 if (file && file.label && !file.children) { | ||||
|                     $("#red-ui-clipboard-dialog-ok").button("enable"); | ||||
|                 } else { | ||||
|                     $("#red-ui-clipboard-dialog-ok").button("disable"); | ||||
|                 } | ||||
|             }, | ||||
|             onconfirm: function(item) { | ||||
|                 if (item && item.label && !item.children) { | ||||
|                     $("#red-ui-clipboard-dialog-ok").trigger("click"); | ||||
|                 } | ||||
|             } | ||||
|         }) | ||||
|         loadFlowLibrary(examplesBrowser,"_examples_",RED._("library.types.examples")); | ||||
|  | ||||
|  | ||||
|         dialogContainer.i18n(); | ||||
|  | ||||
|         $("#clipboard-dialog-ok").show(); | ||||
|         $("#clipboard-dialog-cancel").show(); | ||||
|         $("#clipboard-dialog-close").hide(); | ||||
|         $("#clipboard-dialog-copy").hide(); | ||||
|         $("#clipboard-dialog-download").hide(); | ||||
|         $("#clipboard-dialog-ok").button("disable"); | ||||
|         $("#clipboard-import").keyup(validateImport); | ||||
|         $("#clipboard-import").on('paste',function() { setTimeout(validateImport,10)}); | ||||
|         $("#red-ui-clipboard-dialog-ok").show(); | ||||
|         $("#red-ui-clipboard-dialog-cancel").show(); | ||||
|         $("#red-ui-clipboard-dialog-export").hide(); | ||||
|         $("#red-ui-clipboard-dialog-download").hide(); | ||||
|         $("#red-ui-clipboard-dialog-ok").button("disable"); | ||||
|         $("#red-ui-clipboard-dialog-import-text").on("keyup", validateImport); | ||||
|         $("#red-ui-clipboard-dialog-import-text").on('paste',function() { setTimeout(validateImport,10)}); | ||||
|  | ||||
|         $("#import-tab > a").click(function(evt) { | ||||
|         $("#red-ui-clipboard-dialog-import-opt > a").on("click", function(evt) { | ||||
|             evt.preventDefault(); | ||||
|             if ($(this).hasClass('disabled') || $(this).hasClass('selected')) { | ||||
|                 return; | ||||
| @@ -255,66 +454,122 @@ RED.clipboard = (function() { | ||||
|             $(this).addClass('selected'); | ||||
|         }); | ||||
|  | ||||
|         $("#import-file-upload").change(function() { | ||||
|         $("#red-ui-clipboard-dialog-import-file-upload").on("change", function() { | ||||
|             var fileReader = new FileReader(); | ||||
|             fileReader.onload = function () { | ||||
|                 $("#clipboard-import").val(fileReader.result); | ||||
|                 $("#red-ui-clipboard-dialog-import-text").val(fileReader.result); | ||||
|                 validateImport(); | ||||
|             }; | ||||
|             fileReader.readAsText($(this).prop('files')[0]); | ||||
|         }) | ||||
|         $("#import-file-upload-btn").click(function(evt) { | ||||
|         $("#red-ui-clipboard-dialog-import-file-upload-btn").on("click", function(evt) { | ||||
|             evt.preventDefault(); | ||||
|             $("#import-file-upload").click(); | ||||
|             $("#red-ui-clipboard-dialog-import-file-upload").trigger("click"); | ||||
|         }) | ||||
|  | ||||
|         tabs.activateTab("red-ui-clipboard-dialog-import-tab-"+mode); | ||||
|         if (mode === 'clipboard') { | ||||
|             setTimeout(function() { | ||||
|                 $("#red-ui-clipboard-dialog-import-text").trigger("focus"); | ||||
|             },100) | ||||
|         } | ||||
|  | ||||
|  | ||||
|         dialog.dialog("option","title",RED._("clipboard.importNodes")).dialog("open"); | ||||
|         popover = RED.popover.create({ | ||||
|             target: $("#clipboard-import"), | ||||
|             target: $("#red-ui-clipboard-dialog-import-text"), | ||||
|             trigger: "manual", | ||||
|             direction: "bottom", | ||||
|             content: "" | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     function exportNodes() { | ||||
|     function exportNodes(mode) { | ||||
|         if (disabled) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         mode = mode || "clipboard"; | ||||
|  | ||||
|         dialogContainer.empty(); | ||||
|         dialogContainer.append($(exportNodesDialog)); | ||||
|         dialogContainer.i18n(); | ||||
|         var format = RED.settings.flowFilePretty ? "export-format-full" : "export-format-mini"; | ||||
|  | ||||
|         $("#export-format-group > a").click(function(evt) { | ||||
|         var tabs = RED.tabs.create({ | ||||
|             id: "red-ui-clipboard-dialog-export-tabs", | ||||
|             vertical: true, | ||||
|             onchange: function(tab) { | ||||
|                 $("#red-ui-clipboard-dialog-export-tabs-content").children().hide(); | ||||
|                 $("#" + tab.id).show(); | ||||
|                 activeTab = tab.id; | ||||
|                 if (tab.id === "red-ui-clipboard-dialog-export-tab-clipboard") { | ||||
|                     $("#red-ui-clipboard-dialog-export").button("option","label", RED._("clipboard.export.copy")) | ||||
|                     $("#red-ui-clipboard-dialog-download").show(); | ||||
|                 } else { | ||||
|                     $("#red-ui-clipboard-dialog-export").button("option","label", RED._("clipboard.export.export")) | ||||
|                     $("#red-ui-clipboard-dialog-download").hide(); | ||||
|                     libraryBrowser.focus(); | ||||
|                 } | ||||
|  | ||||
|             } | ||||
|         }); | ||||
|         tabs.addTab({ | ||||
|             id: "red-ui-clipboard-dialog-export-tab-clipboard", | ||||
|             label: RED._("clipboard.clipboard") | ||||
|         }); | ||||
|         tabs.addTab({ | ||||
|             id: "red-ui-clipboard-dialog-export-tab-library", | ||||
|             label: RED._("library.library") | ||||
|         }); | ||||
|  | ||||
|         $("#red-ui-clipboard-dialog-tab-library-name").on("keyup", validateExportFilename); | ||||
|         $("#red-ui-clipboard-dialog-tab-library-name").on('paste',function() { setTimeout(validateExportFilename,10)}); | ||||
|         $("#red-ui-clipboard-dialog-export").button("enable"); | ||||
|  | ||||
|         libraryBrowser = RED.library.createBrowser({ | ||||
|             container: $("#red-ui-clipboard-dialog-export-tab-library-browser"), | ||||
|             folderTools: true, | ||||
|             onselect: function(file) { | ||||
|                 if (file && file.label && !file.children) { | ||||
|                     $("#red-ui-clipboard-dialog-tab-library-name").val(file.label); | ||||
|                 } | ||||
|             } | ||||
|         }) | ||||
|         loadFlowLibrary(libraryBrowser,"local",RED._("library.types.local")); | ||||
|  | ||||
|         $("#red-ui-clipboard-dialog-tab-library-name").val("flows.json").select(); | ||||
|  | ||||
|         dialogContainer.i18n(); | ||||
|         var format = RED.settings.flowFilePretty ? "red-ui-clipboard-dialog-export-fmt-full" : "red-ui-clipboard-dialog-export-fmt-mini"; | ||||
|  | ||||
|         $("#red-ui-clipboard-dialog-export-fmt-group > a").on("click", function(evt) { | ||||
|             evt.preventDefault(); | ||||
|             if ($(this).hasClass('disabled') || $(this).hasClass('selected')) { | ||||
|                 $("#clipboard-export").focus(); | ||||
|                 $("#red-ui-clipboard-dialog-export-text").trigger("focus"); | ||||
|                 return; | ||||
|             } | ||||
|             $(this).parent().children().removeClass('selected'); | ||||
|             $(this).addClass('selected'); | ||||
|  | ||||
|             var flow = $("#clipboard-export").val(); | ||||
|             var flow = $("#red-ui-clipboard-dialog-export-text").val(); | ||||
|             if (flow.length > 0) { | ||||
|                 var nodes = JSON.parse(flow); | ||||
|  | ||||
|                 format = $(this).attr('id'); | ||||
|                 if (format === 'export-format-full') { | ||||
|                 if (format === 'red-ui-clipboard-dialog-export-fmt-full') { | ||||
|                     flow = JSON.stringify(nodes,null,4); | ||||
|                 } else { | ||||
|                     flow = JSON.stringify(nodes); | ||||
|                 } | ||||
|                 $("#clipboard-export").val(flow); | ||||
|                 $("#clipboard-export").focus(); | ||||
|                 $("#red-ui-clipboard-dialog-export-text").val(flow); | ||||
|                 setTimeout(function() { $("#red-ui-clipboard-dialog-export-text").scrollTop(0); },50); | ||||
|  | ||||
|                 $("#red-ui-clipboard-dialog-export-text").trigger("focus"); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         $("#export-range-group > a").click(function(evt) { | ||||
|         $("#red-ui-clipboard-dialog-export-rng-group > a").on("click", function(evt) { | ||||
|             evt.preventDefault(); | ||||
|             if ($(this).hasClass('disabled') || $(this).hasClass('selected')) { | ||||
|                 $("#clipboard-export").focus(); | ||||
|                 return; | ||||
|             } | ||||
|             $(this).parent().children().removeClass('selected'); | ||||
| @@ -322,7 +577,7 @@ RED.clipboard = (function() { | ||||
|             var type = $(this).attr('id'); | ||||
|             var flow = ""; | ||||
|             var nodes = null; | ||||
|             if (type === 'export-range-selected') { | ||||
|             if (type === 'red-ui-clipboard-dialog-export-rng-selected') { | ||||
|                 var selection = RED.workspaces.selection(); | ||||
|                 if (selection.length > 0) { | ||||
|                     nodes = []; | ||||
| @@ -335,77 +590,97 @@ RED.clipboard = (function() { | ||||
|                 } | ||||
|                 // Don't include the subflow meta-port nodes in the exported selection | ||||
|                 nodes = RED.nodes.createExportableNodeSet(nodes.filter(function(n) { return n.type !== 'subflow'})); | ||||
|             } else if (type === 'export-range-flow') { | ||||
|             } else if (type === 'red-ui-clipboard-dialog-export-rng-flow') { | ||||
|                 var activeWorkspace = RED.workspaces.active(); | ||||
|                 nodes = RED.nodes.filterNodes({z:activeWorkspace}); | ||||
|                 var parentNode = RED.nodes.workspace(activeWorkspace)||RED.nodes.subflow(activeWorkspace); | ||||
|                 nodes.unshift(parentNode); | ||||
|                 nodes = RED.nodes.createExportableNodeSet(nodes); | ||||
|             } else if (type === 'export-range-full') { | ||||
|             } else if (type === 'red-ui-clipboard-dialog-export-rng-full') { | ||||
|                 nodes = RED.nodes.createCompleteNodeSet(false); | ||||
|             } | ||||
|             if (nodes !== null) { | ||||
|                 if (format === "export-format-full") { | ||||
|                 if (format === "red-ui-clipboard-dialog-export-fmt-full") { | ||||
|                     flow = JSON.stringify(nodes,null,4); | ||||
|                 } else { | ||||
|                     flow = JSON.stringify(nodes); | ||||
|                 } | ||||
|             } | ||||
|             if (flow.length > 0) { | ||||
|                 $("#export-copy").removeClass('disabled'); | ||||
|                 $("#red-ui-clipboard-dialog-export").removeClass('disabled'); | ||||
|             } else { | ||||
|                 $("#export-copy").addClass('disabled'); | ||||
|                 $("#red-ui-clipboard-dialog-export").addClass('disabled'); | ||||
|             } | ||||
|             $("#clipboard-export").val(flow); | ||||
|             $("#clipboard-export").focus(); | ||||
|             $("#red-ui-clipboard-dialog-export-text").val(flow); | ||||
|             setTimeout(function() { $("#red-ui-clipboard-dialog-export-text").scrollTop(0); },50); | ||||
|             $("#red-ui-clipboard-dialog-export-text").trigger("focus"); | ||||
|         }) | ||||
|  | ||||
|         $("#clipboard-dialog-ok").hide(); | ||||
|         $("#clipboard-dialog-cancel").hide(); | ||||
|         $("#clipboard-dialog-copy").hide(); | ||||
|         $("#clipboard-dialog-close").hide(); | ||||
|         $("#red-ui-clipboard-dialog-ok").hide(); | ||||
|         $("#red-ui-clipboard-dialog-cancel").hide(); | ||||
|         $("#red-ui-clipboard-dialog-export").hide(); | ||||
|         var selection = RED.workspaces.selection(); | ||||
|         if (selection.length > 0) { | ||||
|             $("#export-range-selected").click(); | ||||
|             $("#red-ui-clipboard-dialog-export-rng-selected").trigger("click"); | ||||
|         } else { | ||||
|             selection = RED.view.selection(); | ||||
|             if (selection.nodes) { | ||||
|                 $("#export-range-selected").click(); | ||||
|                 $("#red-ui-clipboard-dialog-export-rng-selected").trigger("click"); | ||||
|             } else { | ||||
|                 $("#export-range-selected").addClass('disabled').removeClass('selected'); | ||||
|                 $("#export-range-flow").click(); | ||||
|                 $("#red-ui-clipboard-dialog-export-rng-selected").addClass('disabled').removeClass('selected'); | ||||
|                 $("#red-ui-clipboard-dialog-export-rng-flow").trigger("click"); | ||||
|             } | ||||
|         } | ||||
|         if (format === "export-format-full") { | ||||
|             $("#export-format-full").click(); | ||||
|         if (format === "red-ui-clipboard-dialog-export-fmt-full") { | ||||
|             $("#red-ui-clipboard-dialog-export-fmt-full").trigger("click"); | ||||
|         } else { | ||||
|             $("#export-format-mini").click(); | ||||
|             $("#red-ui-clipboard-dialog-export-fmt-mini").trigger("click"); | ||||
|         } | ||||
|         $("#clipboard-export") | ||||
|             .focus(function() { | ||||
|                 var textarea = $(this); | ||||
|                 textarea.select(); | ||||
|                 textarea.mouseup(function() { | ||||
|                     textarea.unbind("mouseup"); | ||||
|                     return false; | ||||
|                 }) | ||||
|             }); | ||||
|         tabs.activateTab("red-ui-clipboard-dialog-export-tab-"+mode); | ||||
|         dialog.dialog("option","title",RED._("clipboard.exportNodes")).dialog( "open" ); | ||||
|  | ||||
|         $("#clipboard-export").focus(); | ||||
|         if (!document.queryCommandSupported("copy")) { | ||||
|             $("#clipboard-dialog-cancel").hide(); | ||||
|             $("#clipboard-dialog-close").show(); | ||||
|         } else { | ||||
|             $("#clipboard-dialog-cancel").show(); | ||||
|             $("#clipboard-dialog-copy").show(); | ||||
|         } | ||||
|         $("#clipboard-dialog-download").show(); | ||||
|         $("#red-ui-clipboard-dialog-export-text").trigger("focus"); | ||||
|         $("#red-ui-clipboard-dialog-cancel").show(); | ||||
|         $("#red-ui-clipboard-dialog-export").show(); | ||||
|         $("#red-ui-clipboard-dialog-download").show(); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     function loadFlowLibrary(browser,library,label) { | ||||
|         // if (includeExamples) { | ||||
|         //     listing.push({ | ||||
|         //         library: "_examples_", | ||||
|         //         type: "flows", | ||||
|         //         icon: 'fa fa-hdd-o', | ||||
|         //         label: RED._("library.types.examples"), | ||||
|         //         path: "", | ||||
|         //         children: function(done,item) { | ||||
|         //             RED.library.loadLibraryFolder("_examples_","flows","",function(children) { | ||||
|         //                 item.children = children; | ||||
|         //                 done(children); | ||||
|         //             }) | ||||
|         //         } | ||||
|         //     }) | ||||
|         // } | ||||
|         browser.data([{ | ||||
|             library: library, | ||||
|             type: "flows", | ||||
|             icon: 'fa fa-hdd-o', | ||||
|             label: label, | ||||
|             path: "", | ||||
|             expanded: true, | ||||
|             children: function(done, item) { | ||||
|                 RED.library.loadLibraryFolder(library,"flows","",function(children) { | ||||
|                     item.children = children; | ||||
|                     done(children); | ||||
|                 }) | ||||
|             } | ||||
|         }], true); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     function hideDropTarget() { | ||||
|         $("#dropTarget").hide(); | ||||
|         $("#red-ui-drop-target").hide(); | ||||
|         RED.keyboard.remove("escape"); | ||||
|     } | ||||
|     function copyText(value,element,msg) { | ||||
| @@ -435,7 +710,7 @@ RED.clipboard = (function() { | ||||
|         if (truncated) { | ||||
|             msg += "_truncated"; | ||||
|         } | ||||
|         $("#clipboard-hidden").val(value).select(); | ||||
|         $("#red-ui-clipboard-hidden").val(value).select(); | ||||
|         var result =  document.execCommand("copy"); | ||||
|         if (result && element) { | ||||
|             var popover = RED.popover.create({ | ||||
| @@ -455,29 +730,34 @@ RED.clipboard = (function() { | ||||
|         init: function() { | ||||
|             setupDialogs(); | ||||
|  | ||||
|             $('<input type="text" id="clipboard-hidden">').appendTo("body"); | ||||
|             $('<input type="text" id="red-ui-clipboard-hidden" tabIndex="-1">').appendTo("#red-ui-editor"); | ||||
|  | ||||
|             RED.actions.add("core:show-export-dialog",exportNodes); | ||||
|             RED.actions.add("core:show-import-dialog",importNodes); | ||||
|  | ||||
|             RED.actions.add("core:show-library-export-dialog",function() { exportNodes('library') }); | ||||
|             RED.actions.add("core:show-library-import-dialog",function() { importNodes('library') }); | ||||
|  | ||||
|             RED.events.on("editor:open",function() { disabled = true; }); | ||||
|             RED.events.on("editor:close",function() { disabled = false; }); | ||||
|             RED.events.on("search:open",function() { disabled = true; }); | ||||
|             RED.events.on("search:close",function() { disabled = false; }); | ||||
|             RED.events.on("actionList:open",function() { disabled = true; }); | ||||
|             RED.events.on("actionList:close",function() { disabled = false; }); | ||||
|             RED.events.on("type-search:open",function() { disabled = true; }); | ||||
|             RED.events.on("type-search:close",function() { disabled = false; }); | ||||
|  | ||||
|             $('<div id="red-ui-drop-target"><div data-i18n="[append]workspace.dropFlowHere"><i class="fa fa-download"></i><br></div></div>').appendTo('#red-ui-editor'); | ||||
|  | ||||
|             $('#chart').on("dragenter",function(event) { | ||||
|             $('#red-ui-workspace-chart').on("dragenter",function(event) { | ||||
|                 if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 || | ||||
|                      $.inArray("Files",event.originalEvent.dataTransfer.types) != -1) { | ||||
|                     $("#dropTarget").css({display:'table'}); | ||||
|                     $("#red-ui-drop-target").css({display:'table'}); | ||||
|                     RED.keyboard.add("*", "escape" ,hideDropTarget); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|             $('#dropTarget').on("dragover",function(event) { | ||||
|             $('#red-ui-drop-target').on("dragover",function(event) { | ||||
|                 if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 || | ||||
|                      $.inArray("Files",event.originalEvent.dataTransfer.types) != -1) { | ||||
|                     event.preventDefault(); | ||||
|   | ||||
| @@ -38,7 +38,7 @@ | ||||
|                 this.options[0].show(); | ||||
|             } | ||||
|  | ||||
|             this.element.change(function() { | ||||
|             this.element.on("change", function() { | ||||
|                 if (this.checked) { | ||||
|                     that.options[0].hide(); | ||||
|                     that.options[1].show(); | ||||
| @@ -53,7 +53,7 @@ | ||||
|                     child.checkboxSet('state',isChecked,false,true); | ||||
|                 }) | ||||
|             }) | ||||
|             this.uiElement.click(function(e) { | ||||
|             this.uiElement.on("click", function(e) { | ||||
|                 e.stopPropagation(); | ||||
|                 // state returns null for a partial state. Clicking on that should | ||||
|                 // result in false. | ||||
|   | ||||
| @@ -32,7 +32,10 @@ | ||||
|  *   - scrollOnAdd : boolean - whether to scroll to newly added items | ||||
|  * methods: | ||||
|  *   - addItem(itemData) | ||||
|  *   - insertItemAt : function(data,index) - add an item at the specified index | ||||
|  *   - removeItem(itemData) | ||||
|  *   - getItemAt(index) | ||||
|  *   - indexOf(itemData) | ||||
|  *   - width(width) | ||||
|  *   - height(height) | ||||
|  *   - items() | ||||
| @@ -75,9 +78,9 @@ | ||||
|                         addLabel = 'add'; | ||||
|                     } | ||||
|                 } | ||||
|                 $('<a href="#" class="editor-button editor-button-small red-ui-editableList-addButton" style="margin-top: 4px;"><i class="fa fa-plus"></i> '+addLabel+'</a>') | ||||
|                 $('<a href="#" class="red-ui-button red-ui-button-small red-ui-editableList-addButton" style="margin-top: 4px;"><i class="fa fa-plus"></i> '+addLabel+'</a>') | ||||
|                     .appendTo(this.topContainer) | ||||
|                     .click(function(evt) { | ||||
|                     .on("click", function(evt) { | ||||
|                         evt.preventDefault(); | ||||
|                         that.addItem({}); | ||||
|                     }); | ||||
| @@ -185,6 +188,11 @@ | ||||
|             } | ||||
|         }, | ||||
|         _destroy: function() { | ||||
|             if (this.topContainer) { | ||||
|                 var tc = this.topContainer; | ||||
|                 delete this.topContainer; | ||||
|                 tc.remove(); | ||||
|             } | ||||
|         }, | ||||
|         _refreshFilter: function() { | ||||
|             var that = this; | ||||
| @@ -230,7 +238,24 @@ | ||||
|             this.uiHeight = desiredHeight; | ||||
|             this._resize(); | ||||
|         }, | ||||
|         addItem: function(data) { | ||||
|         getItemAt: function(index) { | ||||
|             var items = this.items(); | ||||
|             if (index >= 0 && index < items.length) { | ||||
|                 return $(items[index]).data('data'); | ||||
|             } else { | ||||
|                 return; | ||||
|             } | ||||
|         }, | ||||
|         indexOf: function(data) { | ||||
|             var items = this.items(); | ||||
|             for (var i=0;i<items.length;i++) { | ||||
|                 if ($(items[i]).data('data') === data) { | ||||
|                     return i | ||||
|                 } | ||||
|             } | ||||
|             return -1 | ||||
|         }, | ||||
|         insertItemAt: function(data,index) { | ||||
|             var that = this; | ||||
|             data = data || {}; | ||||
|             var li = $('<li>'); | ||||
| @@ -248,7 +273,13 @@ | ||||
|                 }); | ||||
|             } | ||||
|             if (!added) { | ||||
|                 li.appendTo(this.element); | ||||
|                 if (index <= 0) { | ||||
|                     li.prependTo(this.element); | ||||
|                 } else if (index > that.element.children().length-1) { | ||||
|                     li.appendTo(this.element); | ||||
|                 } else { | ||||
|                     li.insertBefore(this.element.children().eq(index)); | ||||
|                 } | ||||
|             } | ||||
|             var row = $('<div/>').addClass("red-ui-editableList-item-content").appendTo(li); | ||||
|             row.data('data',data); | ||||
| @@ -257,10 +288,10 @@ | ||||
|                 li.addClass("red-ui-editableList-item-sortable"); | ||||
|             } | ||||
|             if (this.options.removable) { | ||||
|                 var deleteButton = $('<a/>',{href:"#",class:"red-ui-editableList-item-remove editor-button editor-button-small"}).appendTo(li); | ||||
|                 var deleteButton = $('<a/>',{href:"#",class:"red-ui-editableList-item-remove red-ui-button red-ui-button-small"}).appendTo(li); | ||||
|                 $('<i/>',{class:"fa fa-remove"}).appendTo(deleteButton); | ||||
|                 li.addClass("red-ui-editableList-item-removable"); | ||||
|                 deleteButton.click(function(evt) { | ||||
|                 deleteButton.on("click", function(evt) { | ||||
|                     evt.preventDefault(); | ||||
|                     var data = row.data('data'); | ||||
|                     li.addClass("red-ui-editableList-item-deleting") | ||||
| @@ -293,6 +324,9 @@ | ||||
|                 },0); | ||||
|             } | ||||
|         }, | ||||
|         addItem: function(data) { | ||||
|             this.insertItemAt(data,this.element.children().length) | ||||
|         }, | ||||
|         addItems: function(items) { | ||||
|             for (var i=0; i<items.length;i++) { | ||||
|                 this.addItem(items[i]); | ||||
| @@ -312,6 +346,7 @@ | ||||
|         }, | ||||
|         empty: function() { | ||||
|             this.element.empty(); | ||||
|             this.uiContainer.scrollTop(0); | ||||
|         }, | ||||
|         filter: function(filter) { | ||||
|             if (filter !== undefined) { | ||||
| @@ -335,6 +370,14 @@ | ||||
|             if (items.length > 0) { | ||||
|                 this.uiContainer.scrollTop(this.uiContainer.scrollTop()+items.position().top) | ||||
|             } | ||||
|         }, | ||||
|         getItem: function(li) { | ||||
|             var el = li.find(".red-ui-editableList-item-content"); | ||||
|             if (el.length) { | ||||
|                 return el.data('data'); | ||||
|             } else { | ||||
|                 return null; | ||||
|             } | ||||
|         } | ||||
|     }); | ||||
| })(jQuery); | ||||
|   | ||||
| @@ -56,12 +56,12 @@ RED.menu = (function() { | ||||
|         } | ||||
|  | ||||
|         if (opt === null) { | ||||
|             item = $('<li class="divider"></li>'); | ||||
|             item = $('<li class="red-ui-menu-divider"></li>'); | ||||
|         } else { | ||||
|             item = $('<li></li>'); | ||||
|  | ||||
|             if (opt.group) { | ||||
|                 item.addClass("menu-group-"+opt.group); | ||||
|                 item.addClass("red-ui-menu-group-"+opt.group); | ||||
|  | ||||
|             } | ||||
|             var linkContent = '<a '+(opt.id?'id="'+opt.id+'" ':'')+'tabindex="-1" href="#">'; | ||||
| @@ -71,7 +71,7 @@ RED.menu = (function() { | ||||
|  | ||||
|             } | ||||
|             if (opt.icon !== undefined) { | ||||
|                 if (/\.png/.test(opt.icon)) { | ||||
|                 if (/\.(png|svg)/.test(opt.icon)) { | ||||
|                     linkContent += '<img src="'+opt.icon+'"/> '; | ||||
|                 } else { | ||||
|                     linkContent += '<i class="'+(opt.icon?opt.icon:'" style="display: inline-block;"')+'"></i> '; | ||||
| @@ -79,10 +79,10 @@ RED.menu = (function() { | ||||
|             } | ||||
|  | ||||
|             if (opt.sublabel) { | ||||
|                 linkContent += '<span class="menu-label-container"><span class="menu-label">'+opt.label+'</span>'+ | ||||
|                                '<span class="menu-sublabel">'+opt.sublabel+'</span></span>' | ||||
|                 linkContent += '<span class="red-ui-menu-label-container"><span class="red-ui-menu-label">'+opt.label+'</span>'+ | ||||
|                                '<span class="red-ui-menu-sublabel">'+opt.sublabel+'</span></span>' | ||||
|             } else { | ||||
|                 linkContent += '<span class="menu-label">'+opt.label+'</span>' | ||||
|                 linkContent += '<span class="red-ui-menu-label">'+opt.label+'</span>' | ||||
|             } | ||||
|  | ||||
|             linkContent += '</a>'; | ||||
| @@ -92,27 +92,16 @@ RED.menu = (function() { | ||||
|             menuItems[opt.id] = opt; | ||||
|  | ||||
|             if (opt.onselect) { | ||||
|                 link.click(function(e) { | ||||
|                 link.on("click", function(e) { | ||||
|                     e.preventDefault(); | ||||
|                     if ($(this).parent().hasClass("disabled")) { | ||||
|                         return; | ||||
|                     } | ||||
|                     if (opt.toggle) { | ||||
|                         var selected = isSelected(opt.id); | ||||
|                         if (typeof opt.toggle === "string") { | ||||
|                             if (!selected) { | ||||
|                                 for (var m in menuItems) { | ||||
|                                     if (menuItems.hasOwnProperty(m)) { | ||||
|                                         var mi = menuItems[m]; | ||||
|                                         if (mi.id != opt.id && opt.toggle == mi.toggle) { | ||||
|                                             setSelected(mi.id,false); | ||||
|                                         } | ||||
|                                     } | ||||
|                                 } | ||||
|                                 setSelected(opt.id,true); | ||||
|                             } | ||||
|                         if (opt.toggle === true) { | ||||
|                             setSelected(opt.id, !isSelected(opt.id)); | ||||
|                         } else { | ||||
|                             setSelected(opt.id, !selected); | ||||
|                             setSelected(opt.id, true); | ||||
|                         } | ||||
|                     } else { | ||||
|                         triggerAction(opt.id); | ||||
| @@ -125,13 +114,13 @@ RED.menu = (function() { | ||||
|                 link.attr("target","_blank").attr("href",opt.href); | ||||
|             } else if (!opt.options) { | ||||
|                 item.addClass("disabled"); | ||||
|                 link.click(function(event) { | ||||
|                 link.on("click", function(event) { | ||||
|                     event.preventDefault(); | ||||
|                 }); | ||||
|             } | ||||
|             if (opt.options) { | ||||
|                 item.addClass("dropdown-submenu pull-left"); | ||||
|                 var submenu = $('<ul id="'+opt.id+'-submenu" class="dropdown-menu"></ul>').appendTo(item); | ||||
|                 item.addClass("red-ui-menu-dropdown-submenu pull-left"); | ||||
|                 var submenu = $('<ul id="'+opt.id+'-submenu" class="red-ui-menu-dropdown"></ul>').appendTo(item); | ||||
|  | ||||
|                 for (var i=0;i<opt.options.length;i++) { | ||||
|                     var li = createMenuItem(opt.options[i]); | ||||
| @@ -150,13 +139,29 @@ RED.menu = (function() { | ||||
|  | ||||
|     } | ||||
|     function createMenu(options) { | ||||
|         var topMenu = $("<ul/>",{class:"dropdown-menu pull-right"}); | ||||
|         var topMenu = $("<ul/>",{class:"red-ui-menu red-ui-menu-dropdown pull-right"}); | ||||
|  | ||||
|         if (options.id) { | ||||
|             topMenu.attr({id:options.id+"-submenu"}); | ||||
|             var menuParent = $("#"+options.id); | ||||
|             if (menuParent.length === 1) { | ||||
|                 topMenu.insertAfter(menuParent); | ||||
|                 menuParent.on("click", function(evt) { | ||||
|                     evt.stopPropagation(); | ||||
|                     evt.preventDefault(); | ||||
|                     if (topMenu.is(":visible")) { | ||||
|                         $(document).off("click.red-ui-menu"); | ||||
|                         topMenu.hide(); | ||||
|                     } else { | ||||
|                         $(document).on("click.red-ui-menu", function(evt) { | ||||
|                             $(document).off("click.red-ui-menu"); | ||||
|                             activeMenu = null; | ||||
|                             topMenu.hide(); | ||||
|                         }); | ||||
|                         $(".red-ui-menu").hide(); | ||||
|                         topMenu.show(); | ||||
|                     } | ||||
|                 }) | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -193,8 +198,9 @@ RED.menu = (function() { | ||||
|     } | ||||
|  | ||||
|     function setSelected(id,state) { | ||||
|         var alreadySet = false; | ||||
|         if (isSelected(id) == state) { | ||||
|             return; | ||||
|             alreadySet = true; | ||||
|         } | ||||
|         var opt = menuItems[id]; | ||||
|         if (state) { | ||||
| @@ -202,10 +208,26 @@ RED.menu = (function() { | ||||
|         } else { | ||||
|             $("#"+id).removeClass("active"); | ||||
|         } | ||||
|         if (opt && opt.onselect) { | ||||
|             triggerAction(opt.id,state); | ||||
|         if (opt) { | ||||
|             if (opt.toggle && typeof opt.toggle === "string") { | ||||
|                 if (state) { | ||||
|                     for (var m in menuItems) { | ||||
|                         if (menuItems.hasOwnProperty(m)) { | ||||
|                             var mi = menuItems[m]; | ||||
|                             if (mi.id != opt.id && opt.toggle == mi.toggle) { | ||||
|                                 setSelected(mi.id,false); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             if (!alreadySet && opt.onselect) { | ||||
|                 triggerAction(opt.id,state); | ||||
|             } | ||||
|             if (!opt.local && !alreadySet) { | ||||
|                 RED.settings.set(opt.setting||("menu-"+opt.id), state); | ||||
|             } | ||||
|         } | ||||
|         RED.settings.set(opt.setting||("menu-"+opt.id), state); | ||||
|     } | ||||
|  | ||||
|     function toggleSelected(id) { | ||||
| @@ -222,14 +244,14 @@ RED.menu = (function() { | ||||
|  | ||||
|     function addItem(id,opt) { | ||||
|         var item = createMenuItem(opt); | ||||
|         if (opt.group) { | ||||
|             var groupItems = $("#"+id+"-submenu").children(".menu-group-"+opt.group); | ||||
|         if (opt !== null && opt.group) { | ||||
|             var groupItems = $("#"+id+"-submenu").children(".red-ui-menu-group-"+opt.group); | ||||
|             if (groupItems.length === 0) { | ||||
|                 item.appendTo("#"+id+"-submenu"); | ||||
|             } else { | ||||
|                 for (var i=0;i<groupItems.length;i++) { | ||||
|                     var groupItem = groupItems[i]; | ||||
|                     var label = $(groupItem).find(".menu-label").html(); | ||||
|                     var label = $(groupItem).find(".red-ui-menu-label").html(); | ||||
|                     if (opt.label < label) { | ||||
|                         $(groupItem).before(item); | ||||
|                         break; | ||||
| @@ -263,6 +285,5 @@ RED.menu = (function() { | ||||
|         addItem: addItem, | ||||
|         removeItem: removeItem, | ||||
|         setAction: setAction | ||||
|         //TODO: add an api for replacing a submenu - see library.js:loadFlowLibrary | ||||
|     } | ||||
| })(); | ||||
|   | ||||
| @@ -21,6 +21,7 @@ RED.panels = (function() { | ||||
|         var container = options.container || $("#"+options.id); | ||||
|         var children = container.children(); | ||||
|         if (children.length !== 2) { | ||||
|             console.log(options.id); | ||||
|             throw new Error("Container must have exactly two children"); | ||||
|         } | ||||
|         var vertical = (!options.dir || options.dir === "vertical"); | ||||
| @@ -86,10 +87,10 @@ RED.panels = (function() { | ||||
|             resize: function(size) { | ||||
|                 var panelSizes; | ||||
|                 if (vertical) { | ||||
|                     panelSizes = [$(children[0]).height(),$(children[1]).height()]; | ||||
|                     panelSizes = [$(children[0]).outerHeight(),$(children[1]).outerHeight()]; | ||||
|                     container.height(size); | ||||
|                 } else { | ||||
|                     panelSizes = [$(children[0]).width(),$(children[1]).width()]; | ||||
|                     panelSizes = [$(children[0]).outerWidth(),$(children[1]).outerWidth()]; | ||||
|                     container.width(size); | ||||
|                 } | ||||
|                 if (modifiedSizes) { | ||||
| @@ -105,6 +106,11 @@ RED.panels = (function() { | ||||
|                     } | ||||
|                 } | ||||
|                 if (options.resize) { | ||||
|                     if (vertical) { | ||||
|                         panelSizes = [$(children[0]).height(),$(children[1]).height()]; | ||||
|                     } else { | ||||
|                         panelSizes = [$(children[0]).width(),$(children[1]).width()]; | ||||
|                     } | ||||
|                     options.resize(panelSizes[0],panelSizes[1]); | ||||
|                 } | ||||
|             } | ||||
|   | ||||
| @@ -52,6 +52,11 @@ RED.popover = (function() { | ||||
|  | ||||
|         var openPopup = function(instant) { | ||||
|             if (active) { | ||||
|                 var existingPopover = target.data("red-ui-popover"); | ||||
|                 if (options.tooltip && existingPopover) { | ||||
|                     active = false; | ||||
|                     return; | ||||
|                 } | ||||
|                 div = $('<div class="red-ui-popover"></div>'); | ||||
|                 if (size !== "default") { | ||||
|                     div.addClass("red-ui-popover-size-"+size); | ||||
| @@ -122,7 +127,15 @@ RED.popover = (function() { | ||||
|                     } | ||||
|                 } | ||||
|                 div.addClass('red-ui-popover-'+d).css({top: top, left: left}); | ||||
|  | ||||
|                 if (existingPopover) { | ||||
|                     existingPopover.close(true); | ||||
|                 } | ||||
|                 target.data("red-ui-popover",res) | ||||
|                 if (options.tooltip) { | ||||
|                     div.on("mousedown", function(evt) { | ||||
|                         closePopup(true); | ||||
|                     }); | ||||
|                 } | ||||
|                 if (instant) { | ||||
|                     div.show(); | ||||
|                 } else { | ||||
| @@ -131,7 +144,7 @@ RED.popover = (function() { | ||||
|             } | ||||
|         } | ||||
|         var closePopup = function(instant) { | ||||
|             $(document).off('mousedown.modal-popover-close'); | ||||
|             $(document).off('mousedown.red-ui-popover'); | ||||
|             if (!active) { | ||||
|                 if (div) { | ||||
|                     if (instant) { | ||||
| @@ -142,6 +155,7 @@ RED.popover = (function() { | ||||
|                         }); | ||||
|                     } | ||||
|                     div = null; | ||||
|                     target.removeData("red-ui-popover",res) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @@ -162,7 +176,7 @@ RED.popover = (function() { | ||||
|                 } | ||||
|             }); | ||||
|         } else if (trigger === 'click') { | ||||
|             target.click(function(e) { | ||||
|             target.on("click", function(e) { | ||||
|                 e.preventDefault(); | ||||
|                 e.stopPropagation(); | ||||
|                 active = !active; | ||||
| @@ -185,7 +199,7 @@ RED.popover = (function() { | ||||
|             } | ||||
|  | ||||
|         } else if (trigger === 'modal') { | ||||
|             $(document).on('mousedown.modal-popover-close', function (event) { | ||||
|             $(document).on('mousedown.red-ui-popover', function (event) { | ||||
|                 var target = event.target; | ||||
|                 while (target.nodeName !== 'BODY' && target !== div[0]) { | ||||
|                     target = target.parentElement; | ||||
| @@ -236,6 +250,7 @@ RED.popover = (function() { | ||||
|                 } | ||||
|             } | ||||
|             return RED.popover.create({ | ||||
|                 tooltip: true, | ||||
|                 target:target, | ||||
|                 trigger: "hover", | ||||
|                 size: "small", | ||||
| @@ -243,6 +258,71 @@ RED.popover = (function() { | ||||
|                 content: label, | ||||
|                 delay: { show: 750, hide: 50 } | ||||
|             }); | ||||
|         }, | ||||
|         panel: function(content) { | ||||
|             var panel = $('<div class="red-ui-editor-dialog red-ui-popover-panel"></div>'); | ||||
|             panel.css({ display: "none" }); | ||||
|             panel.appendTo(document.body); | ||||
|             content.appendTo(panel); | ||||
|             var closeCallback; | ||||
|  | ||||
|             function hide() { | ||||
|                 $(document).off("mousedown.red-ui-popover-panel-close"); | ||||
|                 panel.hide(); | ||||
|                 panel.css({ | ||||
|                     height: "auto" | ||||
|                 }); | ||||
|                 panel.remove(); | ||||
|             } | ||||
|             function show(options) { | ||||
|                 var closeCallback = options.onclose; | ||||
|                 var target = options.target; | ||||
|                 var align = options.align || "left"; | ||||
|  | ||||
|                 var pos = target.offset(); | ||||
|                 var targetWidth = target.width(); | ||||
|                 var targetHeight = target.height(); | ||||
|                 var panelHeight = panel.height(); | ||||
|                 var panelWidth = panel.width(); | ||||
|  | ||||
|                 var top = (targetHeight+pos.top); | ||||
|                 if (top+panelHeight > $(window).height()) { | ||||
|                     top -= (top+panelHeight)-$(window).height() + 5; | ||||
|                 } | ||||
|                 if (top < 0) { | ||||
|                     panelHeight.height(panelHeight+top) | ||||
|                     top = 0; | ||||
|                 } | ||||
|                 if (align === "left") { | ||||
|                     panel.css({ | ||||
|                         top: top+"px", | ||||
|                         left: (pos.left)+"px", | ||||
|                     }); | ||||
|                 } else if(align === "right") { | ||||
|                     panel.css({ | ||||
|                         top: top+"px", | ||||
|                         left: (pos.left-panelWidth)+"px", | ||||
|                     }); | ||||
|                 } | ||||
|                 panel.slideDown(100); | ||||
|  | ||||
|                 $(document).on("mousedown.red-ui-popover-panel-close", function(event) { | ||||
|                     if(!$(event.target).closest(panel).length && !$(event.target).closest(".red-ui-editor-dialog").length) { | ||||
|                         if (closeCallback) { | ||||
|                             closeCallback(); | ||||
|                         } | ||||
|                         hide(); | ||||
|                     } | ||||
|                     // if ($(event.target).closest(target).length) { | ||||
|                     //     event.preventDefault(); | ||||
|                     // } | ||||
|                 }) | ||||
|             } | ||||
|             return  { | ||||
|                 container: panel, | ||||
|                 show:show, | ||||
|                 hide:hide | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -15,6 +15,19 @@ | ||||
|  **/ | ||||
| (function($) { | ||||
|  | ||||
| /** | ||||
|  * options: | ||||
|  *   - minimumLength : the minimum length of text before firing a change event | ||||
|  *   - delay : delay, in ms, after a keystroke before firing change event | ||||
|  * | ||||
|  * methods: | ||||
|  *   - value([val]) - gets the current value, or, if `val` is provided, sets the value | ||||
|  *   - count - sets or clears a sub-label on the input. This can be used to provide | ||||
|  *             a feedback on the number of matches, or number of available entries to search | ||||
|  *   - change - trigger a change event | ||||
|  * | ||||
|  */ | ||||
|  | ||||
|     $.widget( "nodered.searchBox", { | ||||
|         _create: function() { | ||||
|             var that = this; | ||||
| @@ -22,6 +35,7 @@ | ||||
|             this.currentTimeout = null; | ||||
|             this.lastSent = ""; | ||||
|             this.element.val(""); | ||||
|             this.element.addClass("red-ui-searchBox-input"); | ||||
|             this.uiContainer = this.element.wrap("<div>").parent(); | ||||
|             this.uiContainer.addClass("red-ui-searchBox-container"); | ||||
|  | ||||
| @@ -31,7 +45,7 @@ | ||||
|                 e.preventDefault(); | ||||
|                 that.element.val(""); | ||||
|                 that._change("",true); | ||||
|                 that.element.focus(); | ||||
|                 that.element.trigger("focus"); | ||||
|             }); | ||||
|  | ||||
|             this.resultCount = $('<span>',{class:"red-ui-searchBox-resultCount hide"}).appendTo(this.uiContainer); | ||||
| @@ -47,7 +61,7 @@ | ||||
|             }); | ||||
|  | ||||
|             this.element.on("focus",function() { | ||||
|                 $("body").one("mousedown",function() { | ||||
|                 $(document).one("mousedown",function() { | ||||
|                     that.element.blur(); | ||||
|                 }); | ||||
|             }); | ||||
| @@ -73,6 +87,7 @@ | ||||
|                         that._trigger("change"); | ||||
|                     },this.options.delay); | ||||
|                 } else { | ||||
|                     this.lastSent = this.element.val(); | ||||
|                     this._trigger("change"); | ||||
|                 } | ||||
|             } | ||||
|   | ||||
| @@ -39,17 +39,17 @@ RED.stack = (function() { | ||||
|             } | ||||
|         } | ||||
|         if (options.fill && options.singleExpanded) { | ||||
|             $(window).resize(resizeStack); | ||||
|             $(window).focus(resizeStack); | ||||
|             $(window).on("resize", resizeStack); | ||||
|             $(window).on("focus", resizeStack); | ||||
|         } | ||||
|         return { | ||||
|             add: function(entry) { | ||||
|                 entries.push(entry); | ||||
|                 entry.container = $('<div class="palette-category">').appendTo(container); | ||||
|                 entry.container = $('<div class="red-ui-palette-category">').appendTo(container); | ||||
|                 if (!visible) { | ||||
|                     entry.container.hide(); | ||||
|                 } | ||||
|                 var header = $('<div class="palette-header"></div>').appendTo(entry.container); | ||||
|                 var header = $('<div class="red-ui-palette-header"></div>').appendTo(entry.container); | ||||
|                 entry.header = header; | ||||
|                 entry.contentWrap = $('<div></div>',{style:"position:relative"}).appendTo(entry.container); | ||||
|                 if (options.fill) { | ||||
| @@ -57,7 +57,7 @@ RED.stack = (function() { | ||||
|                 } | ||||
|                 entry.content = $('<div></div>').appendTo(entry.contentWrap); | ||||
|                 if (entry.collapsible !== false) { | ||||
|                     header.click(function() { | ||||
|                     header.on("click", function() { | ||||
|                         if (options.singleExpanded) { | ||||
|                             if (!entry.isExpanded()) { | ||||
|                                 for (var i=0;i<entries.length;i++) { | ||||
| @@ -82,7 +82,7 @@ RED.stack = (function() { | ||||
|                     var icon = $('<i class="fa fa-angle-down"></i>').appendTo(header); | ||||
|  | ||||
|                     if (entry.expanded) { | ||||
|                         entry.container.addClass("palette-category-expanded"); | ||||
|                         entry.container.addClass("expanded"); | ||||
|                         icon.addClass("expanded"); | ||||
|                     } else { | ||||
|                         entry.contentWrap.hide(); | ||||
| @@ -118,7 +118,7 @@ RED.stack = (function() { | ||||
|                         } | ||||
|  | ||||
|                         icon.addClass("expanded"); | ||||
|                         entry.container.addClass("palette-category-expanded"); | ||||
|                         entry.container.addClass("expanded"); | ||||
|                         entry.contentWrap.slideDown(200); | ||||
|                         return true; | ||||
|                     } | ||||
| @@ -126,13 +126,13 @@ RED.stack = (function() { | ||||
|                 entry.collapse = function() { | ||||
|                     if (entry.isExpanded()) { | ||||
|                         icon.removeClass("expanded"); | ||||
|                         entry.container.removeClass("palette-category-expanded"); | ||||
|                         entry.container.removeClass("expanded"); | ||||
|                         entry.contentWrap.slideUp(200); | ||||
|                         return true; | ||||
|                     } | ||||
|                 }; | ||||
|                 entry.isExpanded = function() { | ||||
|                     return entry.container.hasClass("palette-category-expanded"); | ||||
|                     return entry.container.hasClass("expanded"); | ||||
|                 }; | ||||
|                 if (options.fill && options.singleExpanded) { | ||||
|                     resizeStack(); | ||||
|   | ||||
| @@ -19,6 +19,9 @@ | ||||
| RED.tabs = (function() { | ||||
|  | ||||
|     var defaultTabIcon = "fa fa-lemon-o"; | ||||
|     var dragActive = false; | ||||
|     var dblClickTime; | ||||
|     var dblClickArmed = false; | ||||
|  | ||||
|     function createTabs(options) { | ||||
|         var tabs = {}; | ||||
| @@ -36,8 +39,8 @@ RED.tabs = (function() { | ||||
|         } | ||||
|         if (options.addButton) { | ||||
|             wrapper.addClass("red-ui-tabs-add"); | ||||
|             var addButton = $('<div class="red-ui-tab-button"><a href="#"><i class="fa fa-plus"></i></a></div>').appendTo(wrapper); | ||||
|             addButton.find('a').click(function(evt) { | ||||
|             var addButton = $('<div class="red-ui-tab-button red-ui-tabs-add"><a href="#"><i class="fa fa-plus"></i></a></div>').appendTo(wrapper); | ||||
|             addButton.find('a').on("click", function(evt) { | ||||
|                 evt.preventDefault(); | ||||
|                 if (typeof options.addButton === 'function') { | ||||
|                     options.addButton(); | ||||
| @@ -69,7 +72,25 @@ RED.tabs = (function() { | ||||
|                     RED.actions.invoke(options.addButton,{index:targetIndex}); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|         } | ||||
|         if (options.searchButton) { | ||||
|             wrapper.addClass("red-ui-tabs-search"); | ||||
|             var searchButton = $('<div class="red-ui-tab-button red-ui-tabs-search"><a href="#"><i class="fa fa-list-ul"></i></a></div>').appendTo(wrapper); | ||||
|             searchButton.find('a').on("click", function(evt) { | ||||
|                 evt.preventDefault(); | ||||
|                 if (typeof options.searchButton === 'function') { | ||||
|                     options.searchButton() | ||||
|                 } else if (typeof options.searchButton === 'string') { | ||||
|                     RED.actions.invoke(options.searchButton); | ||||
|                 } | ||||
|             }) | ||||
|             if (typeof options.searchButton === 'string') { | ||||
|                 var l = options.searchButton; | ||||
|                 if (options.searchButtonCaption) { | ||||
|                     l = options.searchButtonCaption | ||||
|                 } | ||||
|                 RED.popover.tooltip(searchButton,l,options.searchButton); | ||||
|             } | ||||
|  | ||||
|         } | ||||
|         var scrollLeft; | ||||
| @@ -78,7 +99,7 @@ RED.tabs = (function() { | ||||
|         if (options.scrollable) { | ||||
|             wrapper.addClass("red-ui-tabs-scrollable"); | ||||
|             scrollContainer.addClass("red-ui-tabs-scroll-container"); | ||||
|             scrollContainer.scroll(updateScroll); | ||||
|             scrollContainer.on("scroll",updateScroll); | ||||
|             scrollLeft = $('<div class="red-ui-tab-button red-ui-tab-scroll red-ui-tab-scroll-left"><a href="#" style="display:none;"><i class="fa fa-caret-left"></i></a></div>').appendTo(wrapper).find("a"); | ||||
|             scrollLeft.on('mousedown',function(evt) { scrollEventHandler(evt,'-=150') }).on('click',function(evt){ evt.preventDefault();}); | ||||
|             scrollRight = $('<div class="red-ui-tab-button red-ui-tab-scroll red-ui-tab-scroll-right"><a href="#" style="display:none;"><i class="fa fa-caret-right"></i></a></div>').appendTo(wrapper).find("a"); | ||||
| @@ -95,7 +116,7 @@ RED.tabs = (function() { | ||||
|             if (options.menu !== false) { | ||||
|                 var selectButton = $('<a href="#"><i class="fa fa-caret-down"></i></a>').appendTo(collapsedButtonsRow); | ||||
|                 selectButton.addClass("red-ui-tab-link-button-menu") | ||||
|                 selectButton.click(function(evt) { | ||||
|                 selectButton.on("click", function(evt) { | ||||
|                     evt.stopPropagation(); | ||||
|                     evt.preventDefault(); | ||||
|                     if (!collapsibleMenu) { | ||||
| @@ -118,7 +139,7 @@ RED.tabs = (function() { | ||||
|                             } | ||||
|                         }); | ||||
|                         options = pinnedOptions.concat(options); | ||||
|                         collapsibleMenu = RED.menu.init({id:"debug-message-option-menu",options: options}); | ||||
|                         collapsibleMenu = RED.menu.init({options: options}); | ||||
|                         collapsibleMenu.css({ | ||||
|                             position: "absolute" | ||||
|                         }) | ||||
| @@ -130,10 +151,11 @@ RED.tabs = (function() { | ||||
|                         left: (elementPos.left - collapsibleMenu.width() + selectButton.width())+"px" | ||||
|                     }) | ||||
|                     if (collapsibleMenu.is(":visible")) { | ||||
|                         $(document).off("click.tabmenu"); | ||||
|                         $(document).off("click.red-ui-tabmenu"); | ||||
|                     } else { | ||||
|                         $(document).on("click.tabmenu", function(evt) { | ||||
|                             $(document).off("click.tabmenu"); | ||||
|                         $(".red-ui-menu").hide(); | ||||
|                         $(document).on("click.red-ui-tabmenu", function(evt) { | ||||
|                             $(document).off("click.red-ui-tabmenu"); | ||||
|                             collapsibleMenu.hide(); | ||||
|                         }); | ||||
|                     } | ||||
| @@ -182,7 +204,16 @@ RED.tabs = (function() { | ||||
|         } | ||||
|  | ||||
|         function onTabClick(evt) { | ||||
|             evt.preventDefault(); | ||||
|             if (dragActive) { | ||||
|                 return | ||||
|             } | ||||
|             if (dblClickTime && Date.now()-dblClickTime < 400) { | ||||
|                 dblClickTime = 0; | ||||
|                 dblClickArmed = true; | ||||
|                 return onTabDblClick.call(this,evt); | ||||
|             } | ||||
|             dblClickTime = Date.now(); | ||||
|  | ||||
|             var currentTab = ul.find("li.red-ui-tab.active"); | ||||
|             var thisTab = $(this).parent(); | ||||
|             var fireSelectionChanged = false; | ||||
| @@ -248,7 +279,6 @@ RED.tabs = (function() { | ||||
|             if (fireSelectionChanged) { | ||||
|                 selectionChanged(); | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         function updateScroll() { | ||||
| @@ -270,7 +300,6 @@ RED.tabs = (function() { | ||||
|         } | ||||
|         function onTabDblClick(evt) { | ||||
|             evt.preventDefault(); | ||||
|             evt.stopPropagation(); | ||||
|             if (evt.metaKey || evt.shiftKey) { | ||||
|                 return; | ||||
|             } | ||||
| @@ -330,7 +359,7 @@ RED.tabs = (function() { | ||||
|             } | ||||
|             var tabs = ul.find("li.red-ui-tab"); | ||||
|             var width = wrapper.width(); | ||||
|             var tabCount = tabs.size(); | ||||
|             var tabCount = tabs.length; | ||||
|             var tabWidth; | ||||
|  | ||||
|             if (options.collapsible) { | ||||
| @@ -399,7 +428,11 @@ RED.tabs = (function() { | ||||
|  | ||||
|         } | ||||
|  | ||||
|         ul.find("li.red-ui-tab a").on("click",onTabClick).on("dblclick",onTabDblClick); | ||||
|         ul.find("li.red-ui-tab a") | ||||
|             .on("mouseup",onTabClick) | ||||
|             .on("click", function(evt) {evt.preventDefault(); }) | ||||
|             .on("dblclick", function(evt) {evt.stopPropagation(); evt.preventDefault(); }) | ||||
|  | ||||
|         setTimeout(function() { | ||||
|             updateTabWidths(); | ||||
|         },0); | ||||
| @@ -416,7 +449,7 @@ RED.tabs = (function() { | ||||
|             var li = ul.find("a[href='#"+id+"']").parent(); | ||||
|             if (li.hasClass("active")) { | ||||
|                 var tab = li.prev(); | ||||
|                 if (tab.size() === 0) { | ||||
|                 if (tab.length === 0) { | ||||
|                     tab = li.next(); | ||||
|                 } | ||||
|                 activateTab(tab.find("a")); | ||||
| @@ -430,7 +463,10 @@ RED.tabs = (function() { | ||||
|             } | ||||
|             delete tabs[id]; | ||||
|             updateTabWidths(); | ||||
|             collapsibleMenu = null; | ||||
|             if (collapsibleMenu) { | ||||
|                 collapsibleMenu.remove(); | ||||
|                 collapsibleMenu = null; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return { | ||||
| @@ -466,7 +502,7 @@ RED.tabs = (function() { | ||||
|                 } else if (tab.iconClass) { | ||||
|                     $('<i>',{class:"red-ui-tab-icon "+tab.iconClass}).appendTo(link); | ||||
|                 } | ||||
|                 var span = $('<span/>',{class:"bidiAware"}).text(tab.label).appendTo(link); | ||||
|                 var span = $('<span/>',{class:"red-ui-text-bidi-aware"}).text(tab.label).appendTo(link); | ||||
|                 span.attr('dir', RED.text.bidi.resolveBaseTextDir(tab.label)); | ||||
|                 if (options.collapsible) { | ||||
|                     li.addClass("red-ui-tab-pinned"); | ||||
| @@ -491,7 +527,7 @@ RED.tabs = (function() { | ||||
|                     } else { | ||||
|                         $('<i>',{class:defaultTabIcon}).appendTo(pinnedLink); | ||||
|                     } | ||||
|                     pinnedLink.click(function(evt) { | ||||
|                     pinnedLink.on("click", function(evt) { | ||||
|                         evt.preventDefault(); | ||||
|                         activateTab(tab.id); | ||||
|                     }); | ||||
| @@ -502,8 +538,9 @@ RED.tabs = (function() { | ||||
|                     RED.popover.tooltip($(pinnedLink), tab.name, tab.action); | ||||
|  | ||||
|                 } | ||||
|                 link.on("click",onTabClick); | ||||
|                 link.on("dblclick",onTabDblClick); | ||||
|                 link.on("mouseup",onTabClick); | ||||
|                 link.on("click", function(evt) { evt.preventDefault(); }) | ||||
|                 link.on("dblclick", function(evt) { evt.stopPropagation(); evt.preventDefault(); }) | ||||
|  | ||||
|  | ||||
|                 if (tab.closeable) { | ||||
| @@ -525,7 +562,7 @@ RED.tabs = (function() { | ||||
|                     options.onadd(tab); | ||||
|                 } | ||||
|                 link.attr("title",tab.label); | ||||
|                 if (ul.find("li.red-ui-tab").size() == 1) { | ||||
|                 if (ul.find("li.red-ui-tab").length == 1) { | ||||
|                     activateTab(link); | ||||
|                 } | ||||
|                 if (options.onreorder) { | ||||
| @@ -538,6 +575,8 @@ RED.tabs = (function() { | ||||
|                         axis:"x", | ||||
|                         distance: 20, | ||||
|                         start: function(event,ui) { | ||||
|                             if (dblClickArmed) { dblClickArmed = false; return false } | ||||
|                             dragActive = true; | ||||
|                             originalTabOrder = []; | ||||
|                             tabElements = []; | ||||
|                             ul.children().each(function(i) { | ||||
| @@ -593,6 +632,7 @@ RED.tabs = (function() { | ||||
|                             } | ||||
|                         }, | ||||
|                         stop: function(event,ui) { | ||||
|                             dragActive = false; | ||||
|                             ul.children().css({position:"relative",left:"",transition:""}); | ||||
|                             if (!li.hasClass('active')) { | ||||
|                                 li.css({zIndex:""}); | ||||
| @@ -608,7 +648,10 @@ RED.tabs = (function() { | ||||
|                 setTimeout(function() { | ||||
|                     updateTabWidths(); | ||||
|                 },10); | ||||
|                 collapsibleMenu = null; | ||||
|                 if (collapsibleMenu) { | ||||
|                     collapsibleMenu.remove(); | ||||
|                     collapsibleMenu = null; | ||||
|                 } | ||||
|             }, | ||||
|             removeTab: removeTab, | ||||
|             activateTab: activateTab, | ||||
| @@ -616,7 +659,7 @@ RED.tabs = (function() { | ||||
|             previousTab: activatePreviousTab, | ||||
|             resize: updateTabWidths, | ||||
|             count: function() { | ||||
|                 return ul.find("li.red-ui-tab").size(); | ||||
|                 return ul.find("li.red-ui-tab").length; | ||||
|             }, | ||||
|             contains: function(id) { | ||||
|                 return ul.find("a[href='#"+id+"']").length > 0; | ||||
| @@ -625,7 +668,7 @@ RED.tabs = (function() { | ||||
|                 tabs[id].label = label; | ||||
|                 var tab = ul.find("a[href='#"+id+"']"); | ||||
|                 tab.attr("title",label); | ||||
|                 tab.find("span.bidiAware").text(label).attr('dir', RED.text.bidi.resolveBaseTextDir(label)); | ||||
|                 tab.find("span.red-ui-text-bidi-aware").text(label).attr('dir', RED.text.bidi.resolveBaseTextDir(label)); | ||||
|                 updateTabWidths(); | ||||
|             }, | ||||
|             selection: getSelection, | ||||
|   | ||||
							
								
								
									
										100
									
								
								packages/node_modules/@node-red/editor-client/src/js/ui/common/toggleButton.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,100 @@ | ||||
| /** | ||||
|  * Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  **/ | ||||
| (function($) { | ||||
|  | ||||
| /** | ||||
|  * options: | ||||
|  *   - invertState   : boolean - if "true" the button will show "enabled" when the | ||||
|  *                             checkbox is not selected and vice versa. | ||||
|  *   - enabledIcon   : string - the icon for "enabled" state, default "fa-check-square-o" | ||||
|  *   - enabledLabel  : string - the label for "enabled" state, default "Enabled" ("editor:workspace.enabled") | ||||
|  *   - disabledIcon  : string - the icon for "disabled" state, default "fa-square-o" | ||||
|  *   - disabledLabel : string - the label for "disabled" state, default "Disabled" ("editor:workspace.disabled") | ||||
|  *   - baseClass     : string - the base css class to apply, default "red-ui-button" (alternative eg "red-ui-sidebar-header-button") | ||||
|  *   - class         : string - additional classes to apply to the button - eg "red-ui-button-small" | ||||
|  * methods: | ||||
|  *   - | ||||
|  */ | ||||
|     $.widget( "nodered.toggleButton", { | ||||
|         _create: function() { | ||||
|             var that = this; | ||||
|  | ||||
|             var invertState = false; | ||||
|             if (this.options.hasOwnProperty("invertState")) { | ||||
|                 invertState = this.options.invertState; | ||||
|             } | ||||
|             var baseClass = this.options.baseClass || "red-ui-button"; | ||||
|             var enabledIcon = this.options.enabledIcon || "fa-check-square-o"; | ||||
|             var disabledIcon = this.options.disabledIcon || "fa-square-o"; | ||||
|             var enabledLabel = this.options.hasOwnProperty('enabledLabel') ? this.options.enabledLabel : RED._("editor:workspace.enabled"); | ||||
|             var disabledLabel = this.options.hasOwnProperty('disabledLabel') ? this.options.disabledLabel : RED._("editor:workspace.disabled"); | ||||
|  | ||||
|             this.element.css("display","none"); | ||||
|             this.element.on("focus", function() { | ||||
|                 that.button.focus(); | ||||
|             }); | ||||
|             this.button = $('<button type="button" class="red-ui-toggleButton '+baseClass+' toggle single"><i class="fa"></i> <span></span></button>'); | ||||
|             if (this.options.class) { | ||||
|                 this.button.addClass(this.options.class) | ||||
|             } | ||||
|             this.element.after(this.button); | ||||
|             this.buttonIcon = this.button.find("i"); | ||||
|             this.buttonLabel = this.button.find("span"); | ||||
|  | ||||
|             // Quick hack to find the maximum width of the button | ||||
|             this.button.addClass("selected"); | ||||
|             this.buttonIcon.addClass(enabledIcon); | ||||
|             this.buttonLabel.text(enabledLabel); | ||||
|             var width = this.button.width(); | ||||
|             this.button.removeClass("selected"); | ||||
|             this.buttonIcon.removeClass(enabledIcon); | ||||
|             that.buttonIcon.addClass(disabledIcon); | ||||
|             that.buttonLabel.text(disabledLabel); | ||||
|             width = Math.max(width,this.button.width()); | ||||
|             this.buttonIcon.removeClass(disabledIcon); | ||||
|  | ||||
|             // Fix the width of the button so it doesn't jump around when toggled | ||||
|             if (width > 0) { | ||||
|                 this.button.width(Math.ceil(width)); | ||||
|             } | ||||
|  | ||||
|             this.button.on("click",function(e) { | ||||
|                 e.stopPropagation(); | ||||
|                 if (that.buttonIcon.hasClass(disabledIcon)) { | ||||
|                     that.element.prop("checked",!invertState); | ||||
|                 } else { | ||||
|                     that.element.prop("checked",invertState); | ||||
|                 } | ||||
|                 that.element.trigger("change"); | ||||
|             }) | ||||
|  | ||||
|             this.element.on("change", function(e) { | ||||
|                 if ($(this).prop("checked") !== invertState) { | ||||
|                     that.button.addClass("selected"); | ||||
|                     that.buttonIcon.addClass(enabledIcon); | ||||
|                     that.buttonIcon.removeClass(disabledIcon); | ||||
|                     that.buttonLabel.text(enabledLabel); | ||||
|                 } else { | ||||
|                     that.button.removeClass("selected"); | ||||
|                     that.buttonIcon.addClass(disabledIcon); | ||||
|                     that.buttonIcon.removeClass(enabledIcon); | ||||
|                     that.buttonLabel.text(disabledLabel); | ||||
|                 } | ||||
|             }) | ||||
|             this.element.trigger("change"); | ||||
|         } | ||||
|     }); | ||||
| })(jQuery); | ||||
| @@ -18,32 +18,70 @@ | ||||
| /** | ||||
|  * options: | ||||
|  *   - data : array - initial items to display in tree | ||||
|  *   - multi : boolean - if true, .selected will return an array of results | ||||
|  *                       otherwise, returns the first selected item | ||||
|  *   - sortable: boolean/string - TODO: see editableList | ||||
|  *   - rootSortable: boolean - if 'sortable' is set, then setting this to | ||||
|  *                             false, prevents items being sorted to the | ||||
|  *                             top level of the tree | ||||
|  * | ||||
|  * methods: | ||||
|  *   - data(items) - clears existing items and replaces with new data | ||||
|  * | ||||
|  * events: | ||||
|  *   - treelistselect : function(event, item) {} | ||||
|  * | ||||
|  *   - treelistconfirm : function(event,item) {} | ||||
|  *   - treelistchangeparent: function(event,item, oldParent, newParent) {} | ||||
|  * | ||||
|  * data: | ||||
|  * [ | ||||
|  *     { | ||||
|  *         label: 'Local', // label for the item | ||||
|  *         sublabel: 'Local', // a sub-label for the item | ||||
|  *         icon: 'fa fa-rocket', // (optional) icon for the item | ||||
|  *         selected: true/false, // (optional) if present, display checkbox accordingly | ||||
|  *         children: [] | function(done) // (optional) an array of child items, or a function | ||||
|  *         children: [] | function(done,item) // (optional) an array of child items, or a function | ||||
|  *                                       // that will call the `done` callback with an array | ||||
|  *                                       // of child items | ||||
|  *         expanded: true/false, // show the child items by default | ||||
|  *         deferBuild: true/false, // don't build any ui elements for the item's children | ||||
|  *                                    until it is expanded by the user. | ||||
|  *         element: // custom dom element to use for the item - ignored if `label` is set | ||||
|  *     } | ||||
|  * ] | ||||
|  * | ||||
|  * | ||||
|  * | ||||
|  * var treeList = $("<div>").css({width: "100%", height: "100%"}).treeList({data:[...]}) | ||||
|  * treeList.on('treelistselect', function(e,item) { console.log(item)}) | ||||
|  * treeList.treeList('data',[ ... ] ) | ||||
|  * | ||||
|  * | ||||
|  * After `data` has been added to the tree, each item is augmented the following | ||||
|  * properties and functions: | ||||
|  * | ||||
|  *   item.parent - set to the parent item | ||||
|  *   item.treeList.container | ||||
|  *   item.treeList.label - the label element for the item | ||||
|  *   item.treeList.depth - the depth in the tree (0 == root) | ||||
|  *   item.treeList.parentList  - the editableList instance this item is in | ||||
|  *   item.treeList.remove() - removes the item from the tree | ||||
|  *   item.treeList.makeLeaf(detachChildElements) - turns an element with children into a leaf node, | ||||
|  *                                                 removing the UI decoration etc. | ||||
|  *                                                 detachChildElements - any children with custom | ||||
|  *                                                 elements will be detached rather than removed | ||||
|  *                                                 so jQuery event handlers are preserved in case | ||||
|  *                                                 the child elements need to be reattached later | ||||
|  *   item.treeList.makeParent(children) - turns an element into a parent node, adding the necessary | ||||
|  *                                        UI decoration. | ||||
|  *   item.treeList.insertChildAt(newItem,position,select) - adds a child item an the specified position. | ||||
|  *                                                          Optionally selects the item after adding. | ||||
|  *   item.treeList.addChild(newItem,select) - appends a child item. | ||||
|  *                                            Optionally selects the item after adding. | ||||
|  *   item.treeList.expand(done) - expands the parent item to show children. Optional 'done' callback. | ||||
|  *   item.treeList.collapse() - collapse the parent item to hide children. | ||||
|  * | ||||
|  * | ||||
|  * | ||||
|  * | ||||
|  */ | ||||
|  | ||||
|     $.widget( "nodered.treeList", { | ||||
| @@ -51,110 +89,449 @@ | ||||
|             var that = this; | ||||
|  | ||||
|             this.element.addClass('red-ui-treeList'); | ||||
|             this.element.attr("tabIndex",0); | ||||
|             var wrapper = $('<div>',{class:'red-ui-treeList-container'}).appendTo(this.element); | ||||
|             this.element.on('keydown', function(evt) { | ||||
|                 var selected = that._topList.find(".selected").parent().data('data'); | ||||
|                 if (!selected && (evt.keyCode === 40 || evt.keyCode === 38)) { | ||||
|                     that.select(that._data[0]); | ||||
|                     return; | ||||
|                 } | ||||
|                 var target; | ||||
|                 switch(evt.keyCode) { | ||||
|                     case 13: // ENTER | ||||
|                         if (selected.children) { | ||||
|                             if (selected.treeList.container.hasClass("expanded")) { | ||||
|                                 selected.treeList.collapse() | ||||
|                             } else { | ||||
|                                 selected.treeList.expand() | ||||
|                             } | ||||
|                         } else { | ||||
|                             that._trigger("confirm",null,selected) | ||||
|                         } | ||||
|  | ||||
|                     break; | ||||
|                     case 37: // LEFT | ||||
|                         if (selected.children&& selected.treeList.container.hasClass("expanded")) { | ||||
|                             selected.treeList.collapse() | ||||
|                         } else if (selected.parent) { | ||||
|                             target = selected.parent; | ||||
|                         } | ||||
|                     break; | ||||
|                     case 38: // UP | ||||
|                         target = that._getPreviousSibling(selected); | ||||
|                         if (target) { | ||||
|                             target = that._getLastDescendant(target); | ||||
|                         } | ||||
|                         if (!target && selected.parent) { | ||||
|                             target = selected.parent; | ||||
|                         } | ||||
|                     break; | ||||
|                     case 39: // RIGHT | ||||
|                         if (selected.children) { | ||||
|                             if (!selected.treeList.container.hasClass("expanded")) { | ||||
|                                 selected.treeList.expand() | ||||
|                             } | ||||
|                         } | ||||
|                     break | ||||
|                     case 40: //DOWN | ||||
|                         if (selected.children && Array.isArray(selected.children) && selected.children.length > 0 && selected.treeList.container.hasClass("expanded")) { | ||||
|                             target = selected.children[0]; | ||||
|                         } else { | ||||
|                             target = that._getNextSibling(selected); | ||||
|                             while (!target && selected.parent) { | ||||
|                                 selected = selected.parent; | ||||
|                                 target = that._getNextSibling(selected); | ||||
|                             } | ||||
|                         } | ||||
|                     break | ||||
|                 } | ||||
|                 if (target) { | ||||
|                     that.select(target); | ||||
|                 } | ||||
|             }); | ||||
|             this._data = []; | ||||
|  | ||||
|             this._topList = $('<ol>').css({ | ||||
|             this._topList = $('<ol class="red-ui-treeList-list">').css({ | ||||
|                 position:'absolute', | ||||
|                 top: 0, | ||||
|                 left:0, | ||||
|                 right:0, | ||||
|                 bottom:0 | ||||
|             }).appendTo(wrapper).editableList({ | ||||
|             }).appendTo(wrapper); | ||||
|  | ||||
|             var topListOptions = { | ||||
|                 addButton: false, | ||||
|                 scrollOnAdd: false, | ||||
|                 height: '100%', | ||||
|                 addItem: function(container,i,item) { | ||||
|                     that._addSubtree(container,item,0); | ||||
|                     that._addSubtree(that._topList,container,item,0); | ||||
|                 } | ||||
|             }); | ||||
|             }; | ||||
|             if (this.options.rootSortable !== false && !!this.options.sortable) { | ||||
|                 topListOptions.sortable = this.options.sortable; | ||||
|                 topListOptions.connectWith = '.red-ui-treeList-sortable'; | ||||
|                 this._topList.addClass('red-ui-treeList-sortable'); | ||||
|             } | ||||
|             this._topList.editableList(topListOptions) | ||||
|  | ||||
|  | ||||
|             if (this.options.data) { | ||||
|                 this.data(this.options.data); | ||||
|             } | ||||
|         }, | ||||
|         _addChildren: function(container,children,depth) { | ||||
|         _getLastDescendant: function(item) { | ||||
|             // Gets the last visible descendant of the item | ||||
|             if (!item.children || !item.treeList.container.hasClass("expanded") || item.children.length === 0) { | ||||
|                 return item; | ||||
|             } | ||||
|             return this._getLastDescendant(item.children[item.children.length-1]); | ||||
|         }, | ||||
|         _getPreviousSibling: function(item) { | ||||
|             var candidates; | ||||
|             if (!item.parent) { | ||||
|                 candidates = this._data; | ||||
|             } else { | ||||
|                 candidates = item.parent.children; | ||||
|             } | ||||
|             var index = candidates.indexOf(item); | ||||
|             if (index === 0) { | ||||
|                 return null; | ||||
|             } else { | ||||
|                 return candidates[index-1]; | ||||
|             } | ||||
|         }, | ||||
|         _getNextSibling: function(item) { | ||||
|             var candidates; | ||||
|             if (!item.parent) { | ||||
|                 candidates = this._data; | ||||
|             } else { | ||||
|                 candidates = item.parent.children; | ||||
|             } | ||||
|             var index = candidates.indexOf(item); | ||||
|             if (index === candidates.length - 1) { | ||||
|                 return null; | ||||
|             } else { | ||||
|                 return candidates[index+1]; | ||||
|             } | ||||
|         }, | ||||
|         _addChildren: function(container,parent,children,depth) { | ||||
|             var that = this; | ||||
|             var subtree = $('<ol>').appendTo(container).editableList({ | ||||
|             var subtree = $('<ol class="red-ui-treeList-list">').appendTo(container).editableList({ | ||||
|                 connectWith: ".red-ui-treeList-sortable", | ||||
|                 sortable: that.options.sortable, | ||||
|                 addButton: false, | ||||
|                 scrollOnAdd: false, | ||||
|                 height: 'auto', | ||||
|                 addItem: function(container,i,item) { | ||||
|                     that._addSubtree(container,item,depth+1); | ||||
|                     that._addSubtree(subtree,container,item,depth+1); | ||||
|                 }, | ||||
|                 sortItems: function(data) { | ||||
|                     var children = []; | ||||
|                     var reparented = []; | ||||
|                     data.each(function() { | ||||
|                         var child = $(this).data('data'); | ||||
|                         children.push(child); | ||||
|                         var evt = that._fixDepths(parent,child); | ||||
|                         if (evt) { | ||||
|                             reparented.push(evt); | ||||
|                         } | ||||
|                     }) | ||||
|                     if (Array.isArray(parent.children)) { | ||||
|                         parent.children = children; | ||||
|                     } | ||||
|                     reparented.forEach(function(evt) { | ||||
|                         that._trigger("changeparent",null,evt); | ||||
|                     }); | ||||
|                     that._trigger("sort",null,parent); | ||||
|                 } | ||||
|             }); | ||||
|             if (!!that.options.sortable) { | ||||
|                 subtree.addClass('red-ui-treeList-sortable'); | ||||
|             } | ||||
|             for (var i=0;i<children.length;i++) { | ||||
|                 children[i].parent = parent; | ||||
|                 subtree.editableList('addItem',children[i]) | ||||
|             } | ||||
|             return subtree; | ||||
|         }, | ||||
|         _addSubtree: function(container, item, depth) { | ||||
|         _fixDepths: function(parent,child) { | ||||
|             // If child has just been moved into parent in the UI | ||||
|             // this will fix up the internal data structures to match. | ||||
|             // The calling function must take care of getting child | ||||
|             // into the parent.children array. The rest is up to us. | ||||
|             var that = this; | ||||
|             var labelNodeType = "<label>"; | ||||
|             if (item.children && item.hasOwnProperty('selected')) { | ||||
|                 labelNodeType = "<div>"; | ||||
|             var reparentedEvent = null; | ||||
|             if (child.parent !== parent) { | ||||
|                 reparented = true; | ||||
|                 var oldParent = child.parent; | ||||
|                 child.parent = parent; | ||||
|                 reparentedEvent = { | ||||
|                     item: child, | ||||
|                     old: oldParent, | ||||
|                 } | ||||
|             } | ||||
|             var label = $(labelNodeType,{tabindex:"0",class:"red-ui-treeList-label"}).appendTo(container); | ||||
|             if (child.depth !== parent.depth+1) { | ||||
|                 child.depth = parent.depth+1; | ||||
|                 var labelPaddingWidth = ((child.gutter?child.gutter.width()+2:0)+(child.depth*20)); | ||||
|                 child.treeList.labelPadding.width(labelPaddingWidth+'px'); | ||||
|                 if (child.element) { | ||||
|                     $(child.element).css({ | ||||
|                         width: "calc(100% - "+(labelPaddingWidth+20+(child.icon?20:0))+"px)" | ||||
|                     }) | ||||
|                 } | ||||
|                 // This corrects all child item depths | ||||
|                 if (child.children && Array.isArray(child.children)) { | ||||
|                     child.children.forEach(function(item) { | ||||
|                         that._fixDepths(child,item); | ||||
|                     }) | ||||
|                 } | ||||
|             } | ||||
|             return reparentedEvent; | ||||
|         }, | ||||
|         _addSubtree: function(parentList, container, item, depth) { | ||||
|             var that = this; | ||||
|             item.treeList = {}; | ||||
|             item.treeList.depth = depth; | ||||
|             item.treeList.container = container; | ||||
|  | ||||
|             item.treeList.parentList = parentList; | ||||
|             item.treeList.remove = function() { | ||||
|                 parentList.editableList('removeItem',item); | ||||
|                 if (item.parent) { | ||||
|                     var index = item.parent.children.indexOf(item); | ||||
|                     item.parent.children.splice(index,1) | ||||
|                     that._trigger("sort",null,item.parent); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             var label = $("<div>",{class:"red-ui-treeList-label"}).appendTo(container); | ||||
|             item.treeList.label = label; | ||||
|             if (item.class) { | ||||
|                 label.addClass(item.class); | ||||
|             } | ||||
|             label.css({ | ||||
|                 paddingLeft: (depth*15)+'px' | ||||
|             }) | ||||
|             if (item.gutter) { | ||||
|                 item.gutter.css({ | ||||
|                     position: 'absolute' | ||||
|                 }).appendTo(label) | ||||
|  | ||||
|             } | ||||
|             var labelPaddingWidth = (item.gutter?item.gutter.width()+2:0)+(depth*20); | ||||
|             item.treeList.labelPadding = $('<span>').css({ | ||||
|                 display: "inline-block", | ||||
|                 width:  labelPaddingWidth+'px' | ||||
|             }).appendTo(label); | ||||
|  | ||||
|             label.on('mouseover',function(e) { that._trigger('itemmouseover',e,item); }) | ||||
|             label.on('mouseout',function(e) { that._trigger('itemmouseout',e,item); }) | ||||
|             label.on('mouseenter',function(e) { that._trigger('itemmouseenter',e,item); }) | ||||
|             label.on('mouseleave',function(e) { that._trigger('itemmouseleave',e,item); }) | ||||
|  | ||||
|             if (item.children) { | ||||
|                 $('<span class="red-ui-treeList-icon"><i class="fa fa-angle-right" /></span>').appendTo(label); | ||||
|             item.treeList.makeLeaf = function(detachChildElements) { | ||||
|                 if (!treeListIcon.children().length) { | ||||
|                     // Already a leaf | ||||
|                     return | ||||
|                 } | ||||
|                 if (detachChildElements && item.children) { | ||||
|                     var detachChildren = function(item) { | ||||
|                         if (item.children) { | ||||
|                             item.children.forEach(function(child) { | ||||
|                                 if (child.element) { | ||||
|                                     child.element.detach(); | ||||
|                                 } | ||||
|                                 if (child.gutter) { | ||||
|                                     child.gutter.detach(); | ||||
|                                 } | ||||
|                                 detachChildren(child); | ||||
|                             }); | ||||
|                         } | ||||
|                     } | ||||
|                     detachChildren(item); | ||||
|                 } | ||||
|                 treeListIcon.empty(); | ||||
|                 if (!item.deferBuild) { | ||||
|                     item.treeList.childList.remove(); | ||||
|                     delete item.treeList.childList; | ||||
|                 } | ||||
|                 label.off("click.red-ui-treeList-expand"); | ||||
|                 treeListIcon.off("click.red-ui-treeList-expand"); | ||||
|                 delete item.children; | ||||
|                 container.removeClass("expanded"); | ||||
|             } | ||||
|             item.treeList.makeParent = function(children) { | ||||
|                 if (treeListIcon.children().length) { | ||||
|                     // Already a parent because we've got the angle-right icon | ||||
|                     return; | ||||
|                 } | ||||
|                 $('<i class="fa fa-angle-right" />').appendTo(treeListIcon); | ||||
|                 treeListIcon.on("click.red-ui-treeList-expand", function(e) { | ||||
|                         e.stopPropagation(); | ||||
|                         e.preventDefault(); | ||||
|                         if (container.hasClass("expanded")) { | ||||
|                             item.treeList.collapse(); | ||||
|                         } else { | ||||
|                             item.treeList.expand(); | ||||
|                         } | ||||
|                     }); | ||||
|                 // $('<span class="red-ui-treeList-icon"><i class="fa fa-folder-o" /></span>').appendTo(label); | ||||
|                 label.click(function(e) { | ||||
|                     if (!container.hasClass("built") && typeof item.children === 'function') { | ||||
|                         container.addClass('built'); | ||||
|                         var childrenAdded = false; | ||||
|                         var spinner; | ||||
|                         item.children(function(children) { | ||||
|                             childrenAdded = true; | ||||
|                             that._addChildren(container,children,depth); | ||||
|                 label.on("click.red-ui-treeList-expand", function(e) { | ||||
|                     if (container.hasClass("expanded")) { | ||||
|                         if (item.hasOwnProperty('selected') || label.hasClass("selected")) { | ||||
|                             item.treeList.collapse(); | ||||
|                         } | ||||
|                     } else { | ||||
|                         item.treeList.expand(); | ||||
|                     } | ||||
|                 }) | ||||
|                 if (!item.children) { | ||||
|                     item.children = children||[]; | ||||
|                     item.treeList.childList = that._addChildren(container,item,item.children,depth).hide(); | ||||
|                 } | ||||
|             } | ||||
|             item.treeList.insertChildAt = function(newItem,position,select) { | ||||
|                 newItem.parent = item; | ||||
|                 item.children.splice(position,0,newItem); | ||||
|  | ||||
|                 if (!item.deferBuild) { | ||||
|                     item.treeList.childList.editableList('insertItemAt',newItem,position) | ||||
|                     if (select) { | ||||
|                         setTimeout(function() { | ||||
|                             that.select(newItem) | ||||
|                         },100); | ||||
|                     } | ||||
|                     that._trigger("sort",null,item); | ||||
|                 } | ||||
|             } | ||||
|             item.treeList.addChild = function(newItem,select) { | ||||
|                 item.treeList.insertChildAt(newItem,item.children.length,select); | ||||
|             } | ||||
|             item.treeList.expand = function(done) { | ||||
|                 if (!item.children) { | ||||
|                     return; | ||||
|                 } | ||||
|                 if (container.hasClass("expanded")) { | ||||
|                     done && done(); | ||||
|                     return; | ||||
|                 } | ||||
|                 if (!container.hasClass("built") && (item.deferBuild || typeof item.children === 'function')) { | ||||
|                     container.addClass('built'); | ||||
|                     var childrenAdded = false; | ||||
|                     var spinner; | ||||
|                     var startTime = 0; | ||||
|                     var completeBuild = function(children) { | ||||
|                         childrenAdded = true; | ||||
|                         item.treeList.childList = that._addChildren(container,item,children,depth).hide(); | ||||
|                         var delta = Date.now() - startTime; | ||||
|                         if (delta < 400) { | ||||
|                             setTimeout(function() { | ||||
|                                 item.treeList.childList.slideDown('fast'); | ||||
|                                 if (spinner) { | ||||
|                                     spinner.remove(); | ||||
|                                 } | ||||
|                             },400-delta); | ||||
|                         } else { | ||||
|                             item.treeList.childList.slideDown('fast'); | ||||
|                             if (spinner) { | ||||
|                                 spinner.remove(); | ||||
|                             } | ||||
|                         }); | ||||
|                         if (!childrenAdded) { | ||||
|                             spinner = $('<div class="red-ui-treeList-spinner">').css({ | ||||
|                                 "background-position": (35+depth*15)+'px 50%' | ||||
|                             }).appendTo(container); | ||||
|                         } | ||||
|  | ||||
|                         done && done(); | ||||
|                         that._trigger("childrenloaded",null,item) | ||||
|                     } | ||||
|                     container.toggleClass("expanded"); | ||||
|                 }) | ||||
|             } else { | ||||
|                 $('<span class="red-ui-treeList-icon"></span>').appendTo(label); | ||||
|                     if (typeof item.children === 'function') { | ||||
|                         item.children(completeBuild,item); | ||||
|                     } else { | ||||
|                         delete item.deferBuild; | ||||
|                         completeBuild(item.children); | ||||
|                     } | ||||
|                     if (!childrenAdded) { | ||||
|                         startTime = Date.now(); | ||||
|                         spinner = $('<div class="red-ui-treeList-spinner">').css({ | ||||
|                             "background-position": (35+depth*20)+'px 50%' | ||||
|                         }).appendTo(container); | ||||
|                     } | ||||
|  | ||||
|                 } else { | ||||
|                     if (that._loadingData) { | ||||
|                         item.treeList.childList.show(); | ||||
|                     } else { | ||||
|                         item.treeList.childList.slideDown('fast'); | ||||
|                     } | ||||
|                     done && done(); | ||||
|                 } | ||||
|                 container.addClass("expanded"); | ||||
|             } | ||||
|             item.treeList.collapse = function() { | ||||
|                 if (!item.children) { | ||||
|                     return; | ||||
|                 } | ||||
|                 item.treeList.childList.slideUp('fast'); | ||||
|                 container.removeClass("expanded"); | ||||
|             } | ||||
|  | ||||
|             var treeListIcon = $('<span class="red-ui-treeList-icon"></span>').appendTo(label); | ||||
|             if (item.children) { | ||||
|                 item.treeList.makeParent(); | ||||
|             } | ||||
|  | ||||
|             if (item.hasOwnProperty('selected')) { | ||||
|                 var selectWrapper = $('<span class="red-ui-treeList-icon"></span>').appendTo(label); | ||||
|                 var cb = $('<input type="checkbox">').prop('checked',item.selected).appendTo(selectWrapper); | ||||
|                 var cb = $('<input class="red-ui-treeList-checkbox" type="checkbox">').prop('checked',item.selected).appendTo(selectWrapper); | ||||
|                 label.toggleClass("selected",item.selected); | ||||
|                 cb.on('click', function(e) { | ||||
|                     e.stopPropagation(); | ||||
|                 }); | ||||
|                 cb.on('change', function(e) { | ||||
|                     item.selected = this.checked; | ||||
|                     label.toggleClass("selected",this.checked); | ||||
|                     that._trigger("select",e,item); | ||||
|                 }) | ||||
|             } else if (!item.children) { | ||||
|                 label.click(function(e) { | ||||
|                 if (!item.children) { | ||||
|                     label.on("click", function(e) { | ||||
|                         e.stopPropagation(); | ||||
|                         cb.trigger("click"); | ||||
|                     }) | ||||
|                 } | ||||
|                 item.treeList.select = function(v) { | ||||
|                     if (v !== item.selected) { | ||||
|                         cb.trigger("click"); | ||||
|                     } | ||||
|                 } | ||||
|             } else { | ||||
|                 label.on("click", function(e) { | ||||
|                     that._topList.find(".selected").removeClass("selected"); | ||||
|                     label.addClass("selected"); | ||||
|                     that._trigger("select",e,item) | ||||
|                 }) | ||||
|                 label.on("dblclick", function(e) { | ||||
|                     if (!item.children) { | ||||
|                         that._trigger("confirm",e,item); | ||||
|                     } | ||||
|                 }) | ||||
|             } | ||||
|             if (item.icon) { | ||||
|                 $('<span class="red-ui-treeList-icon"><i class="'+item.icon+'" /></span>').appendTo(label); | ||||
|             } | ||||
|             $('<span class="red-ui-treeList-label-text"></span>').html(item.label).appendTo(label); | ||||
|             if (item.hasOwnProperty('label') || item.hasOwnProperty('sublabel')) { | ||||
|                 if (item.hasOwnProperty('label')) { | ||||
|                     $('<span class="red-ui-treeList-label-text"></span>').text(item.label).appendTo(label); | ||||
|                 } | ||||
|                 if (item.hasOwnProperty('sublabel')) { | ||||
|                     $('<span class="red-ui-treeList-sublabel-text"></span>').text(item.sublabel).appendTo(label); | ||||
|                 } | ||||
|  | ||||
|             } else if (item.element) { | ||||
|                 $(item.element).appendTo(label); | ||||
|                 $(item.element).css({ | ||||
|                     width: "calc(100% - "+(labelPaddingWidth+20+(item.icon?20:0))+"px)" | ||||
|                 }) | ||||
|             } | ||||
|             if (item.children) { | ||||
|                 if (Array.isArray(item.children)) { | ||||
|                     that._addChildren(container,item.children,depth); | ||||
|                 if (Array.isArray(item.children) && !item.deferBuild) { | ||||
|                     item.treeList.childList = that._addChildren(container,item,item.children,depth).hide(); | ||||
|                 } | ||||
|                 if (item.expanded) { | ||||
|                     label.click(); | ||||
|                     item.treeList.expand(); | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
| @@ -162,12 +539,19 @@ | ||||
|             this._topList.editableList('empty'); | ||||
|         }, | ||||
|         data: function(items) { | ||||
|             var that = this; | ||||
|             if (items !== undefined) { | ||||
|                 this._data = items; | ||||
|                 this._topList.editableList('empty'); | ||||
|                 this._loadingData = true; | ||||
|                 for (var i=0; i<items.length;i++) { | ||||
|                     this._topList.editableList('addItem',items[i]); | ||||
|                 } | ||||
|                 setTimeout(function() { | ||||
|                     delete that._loadingData; | ||||
|                 },200); | ||||
|                 this._trigger("select") | ||||
|  | ||||
|             } else { | ||||
|                 return this._data; | ||||
|             } | ||||
| @@ -178,6 +562,27 @@ | ||||
|                     this._topList.editableList('show',this._data[i]); | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         select: function(item) { | ||||
|             this._topList.find(".selected").removeClass("selected"); | ||||
|             item.treeList.label.addClass("selected"); | ||||
|             this._trigger("select",null,item) | ||||
|  | ||||
|         }, | ||||
|         selected: function() { | ||||
|             var s = this._topList.find(".selected"); | ||||
|             if (this.options.multi) { | ||||
|                 var res = []; | ||||
|                 s.each(function() { | ||||
|                     res.push($(this).parent().data('data')); | ||||
|                 }) | ||||
|                 return res; | ||||
|             } | ||||
|             if (s.length) { | ||||
|                 return s.parent().data('data'); | ||||
|             } else { | ||||
|                 return undefined; | ||||
|             } | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|   | ||||
| @@ -32,6 +32,12 @@ | ||||
|             return v; | ||||
|         } | ||||
|     } | ||||
|     var mapDeprecatedIcon = function(icon) { | ||||
|         if (/^red\/images\/typedInput\/.+\.png$/.test(icon)) { | ||||
|             icon = icon.replace(/.png$/,".svg"); | ||||
|         } | ||||
|         return icon; | ||||
|     } | ||||
|     var allOptions = { | ||||
|         msg: {value:"msg",label:"msg.",validate:RED.utils.validatePropertyExpression}, | ||||
|         flow: {value:"flow",label:"flow.",hasValue:true, | ||||
| @@ -46,13 +52,13 @@ | ||||
|             parse: contextParse, | ||||
|             export: contextExport | ||||
|         }, | ||||
|         str: {value:"str",label:"string",icon:"red/images/typedInput/az.png"}, | ||||
|         num: {value:"num",label:"number",icon:"red/images/typedInput/09.png",validate:/^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$/}, | ||||
|         bool: {value:"bool",label:"boolean",icon:"red/images/typedInput/bool.png",options:["true","false"]}, | ||||
|         str: {value:"str",label:"string",icon:"red/images/typedInput/az.svg"}, | ||||
|         num: {value:"num",label:"number",icon:"red/images/typedInput/09.svg",validate:/^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$/}, | ||||
|         bool: {value:"bool",label:"boolean",icon:"red/images/typedInput/bool.svg",options:["true","false"]}, | ||||
|         json: { | ||||
|             value:"json", | ||||
|             label:"JSON", | ||||
|             icon:"red/images/typedInput/json.png", | ||||
|             icon:"red/images/typedInput/json.svg", | ||||
|             validate: function(v) { try{JSON.parse(v);return true;}catch(e){return false;}}, | ||||
|             expand: function() { | ||||
|                 var that = this; | ||||
| @@ -74,12 +80,12 @@ | ||||
|                 }) | ||||
|             } | ||||
|         }, | ||||
|         re: {value:"re",label:"regular expression",icon:"red/images/typedInput/re.png"}, | ||||
|         date: {value:"date",label:"timestamp",hasValue:false}, | ||||
|         re: {value:"re",label:"regular expression",icon:"red/images/typedInput/re.svg"}, | ||||
|         date: {value:"date",label:"timestamp",icon:"fa fa-clock-o",hasValue:false}, | ||||
|         jsonata: { | ||||
|             value: "jsonata", | ||||
|             label: "expression", | ||||
|             icon: "red/images/typedInput/expr.png", | ||||
|             icon: "red/images/typedInput/expr.svg", | ||||
|             validate: function(v) { try{jsonata(v);return true;}catch(e){return false;}}, | ||||
|             expand:function() { | ||||
|                 var that = this; | ||||
| @@ -94,7 +100,7 @@ | ||||
|         bin: { | ||||
|             value: "bin", | ||||
|             label: "buffer", | ||||
|             icon: "red/images/typedInput/bin.png", | ||||
|             icon: "red/images/typedInput/bin.svg", | ||||
|             expand: function() { | ||||
|                 var that = this; | ||||
|                 RED.editor.editBuffer({ | ||||
| @@ -108,7 +114,56 @@ | ||||
|         env: { | ||||
|             value: "env", | ||||
|             label: "env variable", | ||||
|             icon: "red/images/typedInput/env.png" | ||||
|             icon: "red/images/typedInput/env.svg" | ||||
|         }, | ||||
|         node: { | ||||
|             value: "node", | ||||
|             label: "node", | ||||
|             icon: "red/images/typedInput/target.svg", | ||||
|             valueLabel: function(container,value) { | ||||
|                 var node = RED.nodes.node(value); | ||||
|                 var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).css({ | ||||
|                     "margin-top": "2px", | ||||
|                     "margin-left": "3px" | ||||
|                 }).appendTo(container); | ||||
|                 var nodeLabel = $('<span>').css({ | ||||
|                     "line-height": "32px", | ||||
|                     "margin-left": "6px" | ||||
|                 }).appendTo(container); | ||||
|                 if (node) { | ||||
|                     var colour = RED.utils.getNodeColor(node.type,node._def); | ||||
|                     var icon_url = RED.utils.getNodeIcon(node._def,node); | ||||
|                     if (node.type === 'tab') { | ||||
|                         colour = "#C0DEED"; | ||||
|                     } | ||||
|                     nodeDiv.css('backgroundColor',colour); | ||||
|                     var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv); | ||||
|                     RED.utils.createIconElement(icon_url, iconContainer, true); | ||||
|                     var l = RED.utils.getNodeLabel(node,node.id); | ||||
|                     nodeLabel.text(l); | ||||
|                 } else { | ||||
|                     nodeDiv.css({ | ||||
|                         'backgroundColor': '#eee', | ||||
|                         'border-style' : 'dashed' | ||||
|                     }); | ||||
|  | ||||
|                 } | ||||
|             }, | ||||
|             expand: function() { | ||||
|                 var that = this; | ||||
|                 RED.tray.hide(); | ||||
|                 RED.view.selectNodes({ | ||||
|                     single: true, | ||||
|                     selected: [that.value()], | ||||
|                     onselect: function(selection) { | ||||
|                         that.value(selection.id); | ||||
|                         RED.tray.show(); | ||||
|                     }, | ||||
|                     oncancel: function() { | ||||
|                         RED.tray.show(); | ||||
|                     } | ||||
|                 }) | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
|     var nlsd = false; | ||||
| @@ -124,7 +179,7 @@ | ||||
|                 } | ||||
|                 var contextStores = RED.settings.context.stores; | ||||
|                 var contextOptions = contextStores.map(function(store) { | ||||
|                     return {value:store,label: store, icon:'<i class="red-ui-typedInput-icon fa fa-database" style="color: #'+(store==='memory'?'ddd':'777')+'"></i>'} | ||||
|                     return {value:store,label: store, icon:'<i class="red-ui-typedInput-icon fa fa-database"></i>'} | ||||
|                 }) | ||||
|                 if (contextOptions.length < 2) { | ||||
|                     allOptions.flow.options = []; | ||||
| @@ -138,12 +193,12 @@ | ||||
|             var that = this; | ||||
|  | ||||
|             this.disarmClick = false; | ||||
|             this.input = $('<input type="text"></input>'); | ||||
|             this.input = $('<input class="red-ui-typedInput-input" type="text"></input>'); | ||||
|             this.input.insertAfter(this.element); | ||||
|             this.input.val(this.element.val()); | ||||
|             this.element.addClass('red-ui-typedInput'); | ||||
|             this.uiWidth = this.element.outerWidth(); | ||||
|             this.elementDiv = this.input.wrap("<div>").parent().addClass('red-ui-typedInput-input'); | ||||
|             this.elementDiv = this.input.wrap("<div>").parent().addClass('red-ui-typedInput-input-wrap'); | ||||
|             this.uiSelect = this.elementDiv.wrap( "<div>" ).parent(); | ||||
|             var attrStyle = this.element.attr('style'); | ||||
|             var m; | ||||
| @@ -160,17 +215,24 @@ | ||||
|                 that.input.css("margin"+d,0); | ||||
|             }); | ||||
|  | ||||
|             ["type","placeholder","autocomplete","data-i18n"].forEach(function(d) { | ||||
|                 var m = that.element.attr(d); | ||||
|                 that.input.attr(d,m); | ||||
|             }); | ||||
|  | ||||
|             this.uiSelect.addClass("red-ui-typedInput-container"); | ||||
|  | ||||
|             this.element.attr('type','hidden'); | ||||
|  | ||||
|             this.options.types = this.options.types||Object.keys(allOptions); | ||||
|  | ||||
|             this.selectTrigger = $('<button tabindex="0"></button>').prependTo(this.uiSelect); | ||||
|             $('<i class="red-ui-typedInput-icon fa fa-sort-desc"></i>').toggle(this.options.types.length > 1).appendTo(this.selectTrigger); | ||||
|             this.selectTrigger = $('<button class="red-ui-typedInput-type-select" tabindex="0"></button>').prependTo(this.uiSelect); | ||||
|             $('<i class="red-ui-typedInput-icon fa fa-caret-down"></i>').toggle(this.options.types.length > 1).appendTo(this.selectTrigger); | ||||
|  | ||||
|             this.selectLabel = $('<span class="red-ui-typedInput-type-label"></span>').appendTo(this.selectTrigger); | ||||
|  | ||||
|             this.valueLabelContainer = $('<div class="red-ui-typedInput-value-label">').appendTo(this.uiSelect) | ||||
|  | ||||
|             this.types(this.options.types); | ||||
|  | ||||
|             if (this.options.typeField) { | ||||
| @@ -193,9 +255,15 @@ | ||||
|                 that.validate(); | ||||
|                 that.element.val(that.value()); | ||||
|                 that.element.trigger('change',that.propertyType,that.value()); | ||||
|             }); | ||||
|             this.input.on('keydown', function(evt) { | ||||
|                 if (evt.keyCode >= 37 && evt.keyCode <= 40) { | ||||
|                     evt.stopPropagation(); | ||||
|                 } | ||||
|             }) | ||||
|             this.selectTrigger.click(function(event) { | ||||
|             this.selectTrigger.on("click", function(event) { | ||||
|                 event.preventDefault(); | ||||
|                 event.stopPropagation(); | ||||
|                 that._showTypeMenu(); | ||||
|             }); | ||||
|             this.selectTrigger.on('keydown',function(evt) { | ||||
| @@ -203,31 +271,35 @@ | ||||
|                     // Down | ||||
|                     that._showTypeMenu(); | ||||
|                 } | ||||
|                 evt.stopPropagation(); | ||||
|             }).on('focus', function() { | ||||
|                 that.uiSelect.addClass('red-ui-typedInput-focus'); | ||||
|             }) | ||||
|  | ||||
|             // explicitly set optionSelectTrigger display to inline-block otherwise jQ sets it to 'inline' | ||||
|             this.optionSelectTrigger = $('<button tabindex="0" class="red-ui-typedInput-option-trigger" style="display:inline-block"><span class="red-ui-typedInput-option-caret"><i class="red-ui-typedInput-icon fa fa-sort-desc"></i></span></button>').appendTo(this.uiSelect); | ||||
|             this.optionSelectTrigger = $('<button tabindex="0" class="red-ui-typedInput-option-trigger" style="display:inline-block"><span class="red-ui-typedInput-option-caret"><i class="red-ui-typedInput-icon fa fa-caret-down"></i></span></button>').appendTo(this.uiSelect); | ||||
|             this.optionSelectLabel = $('<span class="red-ui-typedInput-option-label"></span>').prependTo(this.optionSelectTrigger); | ||||
|             RED.popover.tooltip(this.optionSelectLabel,function() { | ||||
|                 return that.optionValue; | ||||
|             }); | ||||
|             this.optionSelectTrigger.click(function(event) { | ||||
|             this.optionSelectTrigger.on("click", function(event) { | ||||
|                 event.preventDefault(); | ||||
|                 event.stopPropagation(); | ||||
|                 that._showOptionSelectMenu(); | ||||
|             }).on('keydown', function(evt) { | ||||
|                 if (evt.keyCode === 40) { | ||||
|                     // Down | ||||
|                     that._showOptionSelectMenu(); | ||||
|                 } | ||||
|                 evt.stopPropagation(); | ||||
|             }).on('blur', function() { | ||||
|                 that.uiSelect.removeClass('red-ui-typedInput-focus'); | ||||
|             }).on('focus', function() { | ||||
|                 that.uiSelect.addClass('red-ui-typedInput-focus'); | ||||
|             }); | ||||
|  | ||||
|             this.optionExpandButton = $('<button tabindex="0" class="red-ui-typedInput-option-expand" style="display:inline-block"><i class="red-ui-typedInput-icon fa fa-ellipsis-h"></i></button>').appendTo(this.uiSelect); | ||||
|             this.optionExpandButton = $('<button tabindex="0" class="red-ui-typedInput-option-expand" style="display:inline-block"></button>').appendTo(this.uiSelect); | ||||
|             this.optionExpandButtonIcon = $('<i class="red-ui-typedInput-icon fa fa-ellipsis-h"></i>').appendTo(this.optionExpandButton); | ||||
|             this.type(this.options.default||this.typeList[0].value); | ||||
|         }catch(err) { | ||||
|             console.log(err.stack); | ||||
| @@ -236,9 +308,12 @@ | ||||
|         _showTypeMenu: function() { | ||||
|             if (this.typeList.length > 1) { | ||||
|                 this._showMenu(this.menu,this.selectTrigger); | ||||
|                 this.menu.find("[value='"+this.propertyType+"']").focus(); | ||||
|                 var selected = this.menu.find("[value='"+this.propertyType+"']"); | ||||
|                 setTimeout(function() { | ||||
|                     selected.trigger("focus"); | ||||
|                 },120); | ||||
|             } else { | ||||
|                 this.input.focus(); | ||||
|                 this.input.trigger("focus"); | ||||
|             } | ||||
|         }, | ||||
|         _showOptionSelectMenu: function() { | ||||
| @@ -252,25 +327,41 @@ | ||||
|                 if (selectedOption.length === 0) { | ||||
|                     selectedOption = this.optionMenu.children(":first"); | ||||
|                 } | ||||
|                 selectedOption.focus(); | ||||
|                 selectedOption.trigger("focus"); | ||||
|  | ||||
|             } | ||||
|         }, | ||||
|         _hideMenu: function(menu) { | ||||
|             $(document).off("mousedown.close-property-select"); | ||||
|             $(document).off("mousedown.red-ui-typedInput-close-property-select"); | ||||
|             menu.hide(); | ||||
|             menu.css({ | ||||
|                 height: "auto" | ||||
|             }); | ||||
|  | ||||
|             if (menu.opts.multiple) { | ||||
|                 var selected = []; | ||||
|                 menu.find('input[type="checkbox"]').each(function() { | ||||
|                     if ($(this).prop("checked")) { | ||||
|                         selected.push($(this).data('value')) | ||||
|                     } | ||||
|                 }) | ||||
|                 menu.callback(selected); | ||||
|             } | ||||
|  | ||||
|             if (this.elementDiv.is(":visible")) { | ||||
|                 this.input.focus(); | ||||
|                 this.input.trigger("focus"); | ||||
|             } else if (this.optionSelectTrigger.is(":visible")){ | ||||
|                 this.optionSelectTrigger.focus(); | ||||
|                 this.optionSelectTrigger.trigger("focus"); | ||||
|             } else { | ||||
|                 this.selectTrigger.focus(); | ||||
|                 this.selectTrigger.trigger("focus"); | ||||
|             } | ||||
|         }, | ||||
|         _createMenu: function(opts,callback) { | ||||
|         _createMenu: function(menuOptions,opts,callback) { | ||||
|             var that = this; | ||||
|             var menu = $("<div>").addClass("red-ui-typedInput-options"); | ||||
|             opts.forEach(function(opt) { | ||||
|             var menu = $("<div>").addClass("red-ui-typedInput-options red-ui-editor-dialog"); | ||||
|             menu.opts = opts; | ||||
|             menu.callback = callback; | ||||
|             menuOptions.forEach(function(opt) { | ||||
|                 if (typeof opt === 'string') { | ||||
|                     opt = {value:opt,label:opt}; | ||||
|                 } | ||||
| @@ -282,7 +373,7 @@ | ||||
|                     if (opt.icon.indexOf("<") === 0) { | ||||
|                         $(opt.icon).prependTo(op); | ||||
|                     } else if (opt.icon.indexOf("/") !== -1) { | ||||
|                         $('<img>',{src:opt.icon,style:"margin-right: 4px; height: 18px;"}).prependTo(op); | ||||
|                         $('<img>',{src:mapDeprecatedIcon(opt.icon),style:"margin-right: 4px; height: 18px;"}).prependTo(op); | ||||
|                     } else { | ||||
|                         $('<i>',{class:"red-ui-typedInput-icon "+opt.icon}).prependTo(op); | ||||
|                     } | ||||
| @@ -292,32 +383,43 @@ | ||||
|                 if (!opt.icon && !opt.label) { | ||||
|                     op.text(opt.value); | ||||
|                 } | ||||
|                 var cb; | ||||
|                 if (opts.multiple) { | ||||
|                     cb = $('<input type="checkbox">').css("pointer-events","none").data('value',opt.value).prependTo(op).on("mousedown", function(evt) { evt.preventDefault() }); | ||||
|                 } | ||||
|  | ||||
|                 op.click(function(event) { | ||||
|                 op.on("click", function(event) { | ||||
|                     event.preventDefault(); | ||||
|                     callback(opt.value); | ||||
|                     that._hideMenu(menu); | ||||
|                     event.stopPropagation(); | ||||
|                     if (!opts.multiple) { | ||||
|                         callback(opt.value); | ||||
|                         that._hideMenu(menu); | ||||
|                     } else { | ||||
|                         cb.prop("checked",!cb.prop("checked")); | ||||
|                     } | ||||
|                 }); | ||||
|             }); | ||||
|             menu.css({ | ||||
|                 display: "none", | ||||
|                 display: "none" | ||||
|             }); | ||||
|             menu.appendTo(document.body); | ||||
|  | ||||
|             menu.on('keydown', function(evt) { | ||||
|                 if (evt.keyCode === 40) { | ||||
|                     evt.preventDefault(); | ||||
|                     // DOWN | ||||
|                     $(this).children(":focus").next().focus(); | ||||
|                     $(this).children(":focus").next().trigger("focus"); | ||||
|                 } else if (evt.keyCode === 38) { | ||||
|                     evt.preventDefault(); | ||||
|                     // UP | ||||
|                     $(this).children(":focus").prev().focus(); | ||||
|                     $(this).children(":focus").prev().trigger("focus"); | ||||
|                 } else if (evt.keyCode === 27) { | ||||
|                     // ESCAPE | ||||
|                     evt.preventDefault(); | ||||
|                     that._hideMenu(menu); | ||||
|                 } | ||||
|                 evt.stopPropagation(); | ||||
|             }) | ||||
|  | ||||
|  | ||||
|  | ||||
|             return menu; | ||||
|  | ||||
|         }, | ||||
| @@ -326,22 +428,37 @@ | ||||
|                 this.disarmClick = false; | ||||
|                 return | ||||
|             } | ||||
|             if (menu.opts.multiple) { | ||||
|                 var selected = {}; | ||||
|                  this.value().split(",").forEach(function(f) { | ||||
|                      selected[f] = true; | ||||
|                  }) | ||||
|                 menu.find('input[type="checkbox"]').each(function() { | ||||
|                     $(this).prop("checked",selected[$(this).data('value')]) | ||||
|                 }) | ||||
|             } | ||||
|  | ||||
|  | ||||
|             var that = this; | ||||
|             var pos = relativeTo.offset(); | ||||
|             var height = relativeTo.height(); | ||||
|             var menuHeight = menu.height(); | ||||
|             var top = (height+pos.top-3); | ||||
|             var top = (height+pos.top); | ||||
|             if (top+menuHeight > $(window).height()) { | ||||
|                 top -= (top+menuHeight)-$(window).height()+5; | ||||
|             } | ||||
|             if (top < 0) { | ||||
|                 menu.height(menuHeight+top) | ||||
|                 top = 0; | ||||
|             } | ||||
|             menu.css({ | ||||
|                 top: top+"px", | ||||
|                 left: (2+pos.left)+"px", | ||||
|                 left: (pos.left)+"px", | ||||
|             }); | ||||
|             menu.slideDown(100); | ||||
|             this._delay(function() { | ||||
|                 that.uiSelect.addClass('red-ui-typedInput-focus'); | ||||
|                 $(document).on("mousedown.close-property-select", function(event) { | ||||
|                 $(document).on("mousedown.red-ui-typedInput-close-property-select", function(event) { | ||||
|                     if(!$(event.target).closest(menu).length) { | ||||
|                         that._hideMenu(menu); | ||||
|                     } | ||||
| @@ -352,21 +469,27 @@ | ||||
|                 }) | ||||
|             }); | ||||
|         }, | ||||
|         _getLabelWidth: function(label) { | ||||
|         _getLabelWidth: function(label, done) { | ||||
|             var labelWidth = label.outerWidth(); | ||||
|             if (labelWidth === 0) { | ||||
|                 var container = $('<div class="red-ui-typedInput-container"></div>').css({ | ||||
|                 var wrapper = $('<div class="red-ui-editor"></div>').css({ | ||||
|                     position:"absolute", | ||||
|                     top:0, | ||||
|                     left:-1000 | ||||
|                     "white-space": "nowrap", | ||||
|                     top:-2000 | ||||
|                 }).appendTo(document.body); | ||||
|                 var container = $('<div class="red-ui-typedInput-container"></div>').appendTo(wrapper); | ||||
|                 var newTrigger = label.clone().appendTo(container); | ||||
|                 labelWidth = newTrigger.outerWidth(); | ||||
|                 container.remove(); | ||||
|                 setTimeout(function() { | ||||
|                     labelWidth = newTrigger.outerWidth(); | ||||
|                     wrapper.remove(); | ||||
|                     done(labelWidth); | ||||
|                 },50) | ||||
|             } else { | ||||
|                 done(labelWidth); | ||||
|             } | ||||
|             return labelWidth; | ||||
|         }, | ||||
|         _resize: function() { | ||||
|             var that = this; | ||||
|             if (this.uiWidth !== null) { | ||||
|                 this.uiSelect.width(this.uiWidth); | ||||
|             } | ||||
| @@ -375,68 +498,78 @@ | ||||
|                 this.selectTrigger.addClass("red-ui-typedInput-full-width"); | ||||
|             } else { | ||||
|                 this.selectTrigger.removeClass("red-ui-typedInput-full-width"); | ||||
|                 var labelWidth = this._getLabelWidth(this.selectTrigger); | ||||
|                 this.elementDiv.css('left',labelWidth+"px"); | ||||
|                 if (this.optionExpandButton.is(":visible")) { | ||||
|                     this.elementDiv.css('right',"22px"); | ||||
|                 } else { | ||||
|                     this.elementDiv.css('right','0'); | ||||
|                     this.input.css({ | ||||
|                         'border-top-right-radius': '4px', | ||||
|                         'border-bottom-right-radius': '4px' | ||||
|                     }); | ||||
|                 } | ||||
|  | ||||
|                 // if (this.optionSelectTrigger) { | ||||
|                 //     this.optionSelectTrigger.css({'left':(labelWidth)+"px",'width':'calc( 100% - '+labelWidth+'px )'}); | ||||
|                 // } | ||||
|  | ||||
|                 if (this.optionSelectTrigger) { | ||||
|                     if (type && type.options && type.hasValue === true) { | ||||
|                         this.optionSelectLabel.css({'left':'auto'}) | ||||
|                         var lw = this._getLabelWidth(this.optionSelectLabel); | ||||
|                         this.optionSelectTrigger.css({'width':(23+lw)+"px"}); | ||||
|                         this.elementDiv.css('right',(23+lw)+"px"); | ||||
|                         this.input.css({ | ||||
|                             'border-top-right-radius': 0, | ||||
|                             'border-bottom-right-radius': 0 | ||||
|                         }); | ||||
|                 this._getLabelWidth(this.selectTrigger, function(labelWidth) { | ||||
|                     that.elementDiv.css('left',labelWidth+"px"); | ||||
|                     that.valueLabelContainer.css('left',labelWidth+"px"); | ||||
|                     if (that.optionExpandButton.shown) { | ||||
|                         that.elementDiv.css('right',"22px"); | ||||
|                         that.valueLabelContainer.css('right',"22px"); | ||||
|                     } else { | ||||
|                         this.optionSelectLabel.css({'left':'0'}) | ||||
|                         this.optionSelectTrigger.css({'width':'calc( 100% - '+labelWidth+'px )'}); | ||||
|                         if (!this.optionExpandButton.is(":visible")) { | ||||
|                             this.elementDiv.css({'right':0}); | ||||
|                             this.input.css({ | ||||
|                                 'border-top-right-radius': '4px', | ||||
|                                 'border-bottom-right-radius': '4px' | ||||
|                         that.elementDiv.css('right','0'); | ||||
|                         that.valueLabelContainer.css('right','0'); | ||||
|                         that.input.css({ | ||||
|                             'border-top-right-radius': '4px', | ||||
|                             'border-bottom-right-radius': '4px' | ||||
|                         }); | ||||
|                     } | ||||
|                     if (that.optionSelectTrigger) { | ||||
|                         if (type && type.options && type.hasValue === true) { | ||||
|                             that.optionSelectLabel.css({'left':'auto'}) | ||||
|                             that._getLabelWidth(that.optionSelectLabel, function(lw) { | ||||
|                                 that.optionSelectTrigger.css({'width':(23+lw)+"px"}); | ||||
|                                 that.elementDiv.css('right',(23+lw)+"px"); | ||||
|                                 that.input.css({ | ||||
|                                     'border-top-right-radius': 0, | ||||
|                                     'border-bottom-right-radius': 0 | ||||
|                                 }); | ||||
|                             }); | ||||
|                         } else { | ||||
|                             that.optionSelectLabel.css({'left':'0'}) | ||||
|                             that.optionSelectTrigger.css({'width':'calc( 100% - '+labelWidth+'px )'}); | ||||
|                             if (!that.optionExpandButton.shown) { | ||||
|                                 that.elementDiv.css({'right':0}); | ||||
|                                 that.input.css({ | ||||
|                                     'border-top-right-radius': '4px', | ||||
|                                     'border-bottom-right-radius': '4px' | ||||
|                                 }); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 }); | ||||
|             } | ||||
|         }, | ||||
|         _updateOptionSelectLabel: function(o) { | ||||
|             var opt = this.typeMap[this.propertyType]; | ||||
|             this.optionSelectLabel.empty(); | ||||
|             if (o.icon) { | ||||
|                 if (o.icon.indexOf("<") === 0) { | ||||
|                     $(o.icon).prependTo(this.optionSelectLabel); | ||||
|                 } else if (o.icon.indexOf("/") !== -1) { | ||||
|                     // url | ||||
|                     $('<img>',{src:o.icon,style:"height: 18px;"}).prependTo(this.optionSelectLabel); | ||||
|             if (this.typeMap[this.propertyType].valueLabel) { | ||||
|                 if (opt.multiple) { | ||||
|                     this.typeMap[this.propertyType].valueLabel.call(this,this.optionSelectLabel,o); | ||||
|                 } else { | ||||
|                     // icon class | ||||
|                     $('<i>',{class:"red-ui-typedInput-icon "+o.icon}).prependTo(this.optionSelectLabel); | ||||
|                     this.typeMap[this.propertyType].valueLabel.call(this,this.optionSelectLabel,o.value); | ||||
|                 } | ||||
|             } else if (!opt.multiple) { | ||||
|                 if (o.icon) { | ||||
|                     if (o.icon.indexOf("<") === 0) { | ||||
|                         $(o.icon).prependTo(this.optionSelectLabel); | ||||
|                     } else if (o.icon.indexOf("/") !== -1) { | ||||
|                         // url | ||||
|                         $('<img>',{src:mapDeprecatedIcon(o.icon),style:"height: 18px;"}).prependTo(this.optionSelectLabel); | ||||
|                     } else { | ||||
|                         // icon class | ||||
|                         $('<i>',{class:"red-ui-typedInput-icon "+o.icon}).prependTo(this.optionSelectLabel); | ||||
|                     } | ||||
|                 } else if (o.label) { | ||||
|                     this.optionSelectLabel.text(o.label); | ||||
|                 } else { | ||||
|                     this.optionSelectLabel.text(o.value); | ||||
|                 } | ||||
|                 if (opt.hasValue) { | ||||
|                     this.optionValue = o.value; | ||||
|                     this._resize(); | ||||
|                     this.input.trigger('change',this.propertyType,this.value()); | ||||
|                 } | ||||
|             } else if (o.label) { | ||||
|                 this.optionSelectLabel.text(o.label); | ||||
|             } else { | ||||
|                 this.optionSelectLabel.text(o.value); | ||||
|             } | ||||
|             if (opt.hasValue) { | ||||
|                 this.optionValue = o.value; | ||||
|                 this._resize(); | ||||
|                 this.input.trigger('change',this.propertyType,this.value()); | ||||
|                 this.optionSelectLabel.text(o.length+" selected"); | ||||
|             } | ||||
|         }, | ||||
|         _destroy: function() { | ||||
| @@ -444,6 +577,7 @@ | ||||
|                 this.optionMenu.remove(); | ||||
|             } | ||||
|             this.menu.remove(); | ||||
|             this.uiSelect.remove(); | ||||
|         }, | ||||
|         types: function(types) { | ||||
|             var that = this; | ||||
| @@ -460,11 +594,11 @@ | ||||
|                 return result; | ||||
|             }); | ||||
|             this.selectTrigger.toggleClass("disabled", this.typeList.length === 1); | ||||
|             this.selectTrigger.find(".fa-sort-desc").toggle(this.typeList.length > 1) | ||||
|             this.selectTrigger.find(".fa-caret-down").toggle(this.typeList.length > 1) | ||||
|             if (this.menu) { | ||||
|                 this.menu.remove(); | ||||
|             } | ||||
|             this.menu = this._createMenu(this.typeList, function(v) { that.type(v) }); | ||||
|             this.menu = this._createMenu(this.typeList,{},function(v) { that.type(v) }); | ||||
|             if (currentType && !this.typeMap.hasOwnProperty(currentType)) { | ||||
|                 this.type(this.typeList[0].value); | ||||
|             } else { | ||||
| @@ -478,33 +612,52 @@ | ||||
|             this._resize(); | ||||
|         }, | ||||
|         value: function(value) { | ||||
|             var that = this; | ||||
|             var opt = this.typeMap[this.propertyType]; | ||||
|             if (!arguments.length) { | ||||
|                 var v = this.input.val(); | ||||
|                 if (this.typeMap[this.propertyType].export) { | ||||
|                     v = this.typeMap[this.propertyType].export(v,this.optionValue) | ||||
|                 if (opt.export) { | ||||
|                     v = opt.export(v,this.optionValue) | ||||
|                 } | ||||
|                 return v; | ||||
|             } else { | ||||
|                 var selectedOption; | ||||
|                 if (this.typeMap[this.propertyType].options) { | ||||
|                     for (var i=0;i<this.typeMap[this.propertyType].options.length;i++) { | ||||
|                         var op = this.typeMap[this.propertyType].options[i]; | ||||
|                         if (typeof op === "string") { | ||||
|                             if (op === value) { | ||||
|                                 selectedOption = this.activeOptions[op]; | ||||
|                 var selectedOption = []; | ||||
|                 if (opt.options) { | ||||
|                     var checkValues = [value]; | ||||
|                     if (opt.multiple) { | ||||
|                         selectedOption = []; | ||||
|                         checkValues = value.split(","); | ||||
|                     } | ||||
|                     checkValues.forEach(function(value) { | ||||
|                         for (var i=0;i<opt.options.length;i++) { | ||||
|                             var op = opt.options[i]; | ||||
|                             if (typeof op === "string") { | ||||
|                                 if (op === value || op === ""+value) { | ||||
|                                     selectedOption.push(that.activeOptions[op]); | ||||
|                                     break; | ||||
|                                 } | ||||
|                             } else if (op.value === value) { | ||||
|                                 selectedOption.push(op); | ||||
|                                 break; | ||||
|                             } | ||||
|                         } else if (op.value === value) { | ||||
|                             selectedOption = op; | ||||
|                             break; | ||||
|                         } | ||||
|                     }) | ||||
|                     this.input.val(value); | ||||
|                     if (!opt.multiple) { | ||||
|                         if (selectedOption.length === 0) { | ||||
|                             selectedOption = [{value:""}]; | ||||
|                         } | ||||
|                         this._updateOptionSelectLabel(selectedOption[0]) | ||||
|                     } else { | ||||
|                         this._updateOptionSelectLabel(selectedOption) | ||||
|                     } | ||||
|                     if (!selectedOption) { | ||||
|                         selectedOption = {value:""} | ||||
|                 } else { | ||||
|                     this.input.val(value); | ||||
|                     if (opt.valueLabel) { | ||||
|                         this.valueLabelContainer.empty(); | ||||
|                         opt.valueLabel.call(this,this.valueLabelContainer,value); | ||||
|                     } | ||||
|                     this._updateOptionSelectLabel(selectedOption) | ||||
|                 } | ||||
|                 this.input.val(value); | ||||
|                 this.input.trigger('change',this.type(),value); | ||||
|             } | ||||
|         }, | ||||
| @@ -521,20 +674,23 @@ | ||||
|                     } | ||||
|                     this.selectLabel.empty(); | ||||
|                     var image; | ||||
|                     if (opt.icon) { | ||||
|                     if (opt.icon && opt.showLabel !== false) { | ||||
|                         if (opt.icon.indexOf("<") === 0) { | ||||
|                             $(opt.icon).prependTo(this.selectLabel); | ||||
|                         } | ||||
|                         else if (opt.icon.indexOf("/") !== -1) { | ||||
|                             image = new Image(); | ||||
|                             image.onload = function() { that._resize(); } | ||||
|                             image.onerror = function() { that._resize(); } | ||||
|                             image.name = opt.icon; | ||||
|                             image.src = opt.icon; | ||||
|                             $('<img>',{src:opt.icon,style:"margin-right: 4px;height: 18px;"}).prependTo(this.selectLabel); | ||||
|                             image.src = mapDeprecatedIcon(opt.icon); | ||||
|                             $('<img>',{src:mapDeprecatedIcon(opt.icon),style:"margin-right: 4px;height: 18px;"}).prependTo(this.selectLabel); | ||||
|                         } | ||||
|                         else { | ||||
|                             $('<i>',{class:"red-ui-typedInput-icon "+opt.icon}).prependTo(this.selectLabel); | ||||
|                         } | ||||
|                     } else { | ||||
|                     } | ||||
|                     if (opt.hasValue === false || (opt.showLabel !== false && !opt.icon)) { | ||||
|                         this.selectLabel.text(opt.label); | ||||
|                     } | ||||
|                     if (this.optionMenu) { | ||||
| @@ -544,13 +700,16 @@ | ||||
|                     if (opt.options) { | ||||
|                         if (this.optionExpandButton) { | ||||
|                             this.optionExpandButton.hide(); | ||||
|                             this.optionExpandButton.shown = false; | ||||
|                         } | ||||
|                         if (this.optionSelectTrigger) { | ||||
|                             this.optionSelectTrigger.show(); | ||||
|                             if (!opt.hasValue) { | ||||
|                                 this.elementDiv.hide(); | ||||
|                                 this.valueLabelContainer.hide(); | ||||
|                             } else { | ||||
|                                 this.elementDiv.show(); | ||||
|                                 this.valueLabelContainer.hide(); | ||||
|                             } | ||||
|                             this.activeOptions = {}; | ||||
|                             opt.options.forEach(function(o) { | ||||
| @@ -564,36 +723,50 @@ | ||||
|                             if (!that.activeOptions.hasOwnProperty(that.optionValue)) { | ||||
|                                 that.optionValue = null; | ||||
|                             } | ||||
|                             this.optionMenu = this._createMenu(opt.options,function(v){ | ||||
|                                 that._updateOptionSelectLabel(that.activeOptions[v]); | ||||
|                                 if (!opt.hasValue) { | ||||
|                                     that.value(that.activeOptions[v].value) | ||||
|                                 } | ||||
|                             }); | ||||
|  | ||||
|                             var op; | ||||
|                             if (!opt.hasValue) { | ||||
|                                 var currentVal = this.input.val(); | ||||
|                                 var validValue = false; | ||||
|                                 for (var i=0;i<opt.options.length;i++) { | ||||
|                                     op = opt.options[i]; | ||||
|                                     if (typeof op === "string" && op === currentVal) { | ||||
|                                         that._updateOptionSelectLabel({value:currentVal}); | ||||
|                                         validValue = true; | ||||
|                                         break; | ||||
|                                     } else if (op.value === currentVal) { | ||||
|                                         that._updateOptionSelectLabel(op); | ||||
|                                         validValue = true; | ||||
|                                         break; | ||||
|                                 var currentVal = this.input.val(); | ||||
|                                 if (!opt.multiple) { | ||||
|                                     for (var i=0;i<opt.options.length;i++) { | ||||
|                                         op = opt.options[i]; | ||||
|                                         if (typeof op === "string" && op === currentVal) { | ||||
|                                             that._updateOptionSelectLabel({value:currentVal}); | ||||
|                                             validValue = true; | ||||
|                                             break; | ||||
|                                         } else if (op.value === currentVal) { | ||||
|                                             that._updateOptionSelectLabel(op); | ||||
|                                             validValue = true; | ||||
|                                             break; | ||||
|                                         } | ||||
|                                     } | ||||
|                                 } | ||||
|                                 if (!validValue) { | ||||
|                                     op = opt.options[0]; | ||||
|                                     if (typeof op === "string") { | ||||
|                                         this.value(op); | ||||
|                                         that._updateOptionSelectLabel({value:op}); | ||||
|                                     } else { | ||||
|                                         this.value(op.value); | ||||
|                                         that._updateOptionSelectLabel(op); | ||||
|                                     if (!validValue) { | ||||
|                                         op = opt.options[0]; | ||||
|                                         if (typeof op === "string") { | ||||
|                                             this.value(op); | ||||
|                                             that._updateOptionSelectLabel({value:op}); | ||||
|                                         } else { | ||||
|                                             this.value(op.value); | ||||
|                                             that._updateOptionSelectLabel(op); | ||||
|                                         } | ||||
|                                     } | ||||
|                                 } else { | ||||
|                                     // Check to see if value is a valid csv of | ||||
|                                     // options. | ||||
|                                     var currentValues = {}; | ||||
|                                     currentVal.split(",").forEach(function(v) { | ||||
|                                         if (v) { | ||||
|                                             currentValues[v] = true; | ||||
|                                         } | ||||
|                                     }); | ||||
|                                     for (var i=0;i<opt.options.length;i++) { | ||||
|                                         op = opt.options[i]; | ||||
|                                         delete currentValues[op.value||op]; | ||||
|                                     } | ||||
|                                     if (!$.isEmptyObject(currentValues)) { | ||||
|                                         // Invalid, set to default/empty | ||||
|                                         this.value((opt.default||[]).join(",")); | ||||
|                                     } | ||||
|                                 } | ||||
|                             } else { | ||||
| @@ -629,7 +802,22 @@ | ||||
|                                     this.optionSelectTrigger.hide(); | ||||
|                                 } | ||||
|                             } | ||||
|                             this.optionMenu = this._createMenu(opt.options,opt,function(v){ | ||||
|                                 if (!opt.multiple) { | ||||
|                                     that._updateOptionSelectLabel(that.activeOptions[v]); | ||||
|                                     if (!opt.hasValue) { | ||||
|                                         that.value(that.activeOptions[v].value) | ||||
|                                     } | ||||
|                                 } else { | ||||
|                                     that._updateOptionSelectLabel(v); | ||||
|                                     if (!opt.hasValue) { | ||||
|                                         that.value(v.join(",")) | ||||
|                                     } | ||||
|                                 } | ||||
|                             }); | ||||
|                         } | ||||
|                         this._trigger("typechange",null,this.propertyType); | ||||
|                         this.input.trigger('change',this.propertyType,this.value()); | ||||
|                     } else { | ||||
|                         if (this.optionSelectTrigger) { | ||||
|                             this.optionSelectTrigger.hide(); | ||||
| @@ -638,31 +826,62 @@ | ||||
|                             this.oldValue = this.input.val(); | ||||
|                             this.input.val(""); | ||||
|                             this.elementDiv.hide(); | ||||
|                             this.valueLabelContainer.hide(); | ||||
|                         } else if (opt.valueLabel) { | ||||
|                             this.valueLabelContainer.show(); | ||||
|                             this.valueLabelContainer.empty(); | ||||
|                             opt.valueLabel.call(this,this.valueLabelContainer,this.input.val()); | ||||
|                             this.elementDiv.hide(); | ||||
|                         } else { | ||||
|                             if (this.oldValue !== undefined) { | ||||
|                                 this.input.val(this.oldValue); | ||||
|                                 delete this.oldValue; | ||||
|                             } | ||||
|                             this.valueLabelContainer.hide(); | ||||
|                             this.elementDiv.show(); | ||||
|                         } | ||||
|                         if (this.optionExpandButton) { | ||||
|                             if (opt.expand && typeof opt.expand === 'function') { | ||||
|                             if (opt.expand) { | ||||
|                                 if (opt.expand.icon) { | ||||
|                                     this.optionExpandButtonIcon.removeClass().addClass("red-ui-typedInput-icon fa "+opt.expand.icon) | ||||
|                                 } else { | ||||
|                                     this.optionExpandButtonIcon.removeClass().addClass("red-ui-typedInput-icon fa fa-ellipsis-h") | ||||
|                                 } | ||||
|                                 this.optionExpandButton.shown = true; | ||||
|                                 this.optionExpandButton.show(); | ||||
|                                 this.optionExpandButton.off('click'); | ||||
|                                 this.optionExpandButton.on('click',function(evt) { | ||||
|                                     evt.preventDefault(); | ||||
|                                     opt.expand.call(that); | ||||
|                                     if (typeof opt.expand === 'function') { | ||||
|                                         opt.expand.call(that); | ||||
|                                     } else { | ||||
|                                         var container = $('<div>'); | ||||
|                                         var content = opt.expand.content.call(that,container); | ||||
|                                         var panel = RED.popover.panel(container); | ||||
|                                         panel.container.css({ | ||||
|                                             width:that.valueLabelContainer.width() | ||||
|                                         }); | ||||
|                                         if (opt.expand.minWidth) { | ||||
|                                             panel.container.css({ | ||||
|                                                 minWidth: opt.expand.minWidth+"px" | ||||
|                                             }); | ||||
|                                         } | ||||
|                                         panel.show({ | ||||
|                                             target:that.optionExpandButton, | ||||
|                                             onclose:content.onclose, | ||||
|                                             align: "right" | ||||
|                                         }); | ||||
|                                     } | ||||
|                                 }) | ||||
|                             } else { | ||||
|                                 this.optionExpandButton.shown = false; | ||||
|                                 this.optionExpandButton.hide(); | ||||
|                             } | ||||
|                         } | ||||
|                         this._trigger("typechange",null,this.propertyType); | ||||
|                         this.input.trigger('change',this.propertyType,this.value()); | ||||
|                     } | ||||
|                     if (image) { | ||||
|                         image.onload = function() { that._resize(); } | ||||
|                         image.onerror = function() { that._resize(); } | ||||
|                     } else { | ||||
|                     if (!image) { | ||||
|                         this._resize(); | ||||
|                     } | ||||
|                 } | ||||
|   | ||||
| @@ -17,9 +17,9 @@ | ||||
| RED.deploy = (function() { | ||||
|  | ||||
|     var deploymentTypes = { | ||||
|         "full":{img:"red/images/deploy-full-o.png"}, | ||||
|         "nodes":{img:"red/images/deploy-nodes-o.png"}, | ||||
|         "flows":{img:"red/images/deploy-flows-o.png"} | ||||
|         "full":{img:"red/images/deploy-full-o.svg"}, | ||||
|         "nodes":{img:"red/images/deploy-nodes-o.svg"}, | ||||
|         "flows":{img:"red/images/deploy-flows-o.svg"} | ||||
|     } | ||||
|  | ||||
|     var ignoreDeployWarnings = { | ||||
| @@ -36,7 +36,7 @@ RED.deploy = (function() { | ||||
|  | ||||
|     function changeDeploymentType(type) { | ||||
|         deploymentType = type; | ||||
|         $("#btn-deploy-icon").attr("src",deploymentTypes[type].img); | ||||
|         $("#red-ui-header-button-deploy-icon").attr("src",deploymentTypes[type].img); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -44,62 +44,68 @@ RED.deploy = (function() { | ||||
|      *   type: "default" - Button with drop-down options - no further customisation available | ||||
|      *   type: "simple"  - Button without dropdown. Customisations: | ||||
|      *      label: the text to display - default: "Deploy" | ||||
|      *      icon : the icon to use. Null removes the icon. default: "red/images/deploy-full-o.png" | ||||
|      *      icon : the icon to use. Null removes the icon. default: "red/images/deploy-full-o.svg" | ||||
|      */ | ||||
|     function init(options) { | ||||
|         options = options || {}; | ||||
|         var type = options.type || "default"; | ||||
|  | ||||
|         if (type == "default") { | ||||
|             $('<li><span class="deploy-button-group button-group">'+ | ||||
|               '<a id="btn-deploy" class="deploy-button disabled" href="#">'+ | ||||
|                 '<span class="deploy-button-content">'+ | ||||
|                  '<img id="btn-deploy-icon" src="red/images/deploy-full-o.png"> '+ | ||||
|             $('<li><span class="red-ui-deploy-button-group button-group">'+ | ||||
|               '<a id="red-ui-header-button-deploy" class="red-ui-deploy-button disabled" href="#">'+ | ||||
|                 '<span class="red-ui-deploy-button-content">'+ | ||||
|                  '<img id="red-ui-header-button-deploy-icon" src="red/images/deploy-full-o.svg"> '+ | ||||
|                  '<span>'+RED._("deploy.deploy")+'</span>'+ | ||||
|                 '</span>'+ | ||||
|                 '<span class="deploy-button-spinner hide">'+ | ||||
|                 '<span class="red-ui-deploy-button-spinner hide">'+ | ||||
|                  '<img src="red/images/spin.svg"/>'+ | ||||
|                 '</span>'+ | ||||
|               '</a>'+ | ||||
|               '<a id="btn-deploy-options" data-toggle="dropdown" class="deploy-button" href="#"><i class="fa fa-caret-down"></i></a>'+ | ||||
|               '</span></li>').prependTo(".header-toolbar"); | ||||
|               RED.menu.init({id:"btn-deploy-options", | ||||
|               '<a id="red-ui-header-button-deploy-options" class="red-ui-deploy-button" href="#"><i class="fa fa-caret-down"></i></a>'+ | ||||
|               '</span></li>').prependTo(".red-ui-header-toolbar"); | ||||
|               RED.menu.init({id:"red-ui-header-button-deploy-options", | ||||
|                   options: [ | ||||
|                       {id:"deploymenu-item-full",toggle:"deploy-type",icon:"red/images/deploy-full.png",label:RED._("deploy.full"),sublabel:RED._("deploy.fullDesc"),selected: true, onselect:function(s) { if(s){changeDeploymentType("full")}}}, | ||||
|                       {id:"deploymenu-item-flow",toggle:"deploy-type",icon:"red/images/deploy-flows.png",label:RED._("deploy.modifiedFlows"),sublabel:RED._("deploy.modifiedFlowsDesc"), onselect:function(s) {if(s){changeDeploymentType("flows")}}}, | ||||
|                       {id:"deploymenu-item-node",toggle:"deploy-type",icon:"red/images/deploy-nodes.png",label:RED._("deploy.modifiedNodes"),sublabel:RED._("deploy.modifiedNodesDesc"),onselect:function(s) { if(s){changeDeploymentType("nodes")}}}, | ||||
|                       {id:"deploymenu-item-full",toggle:"deploy-type",icon:"red/images/deploy-full.svg",label:RED._("deploy.full"),sublabel:RED._("deploy.fullDesc"),selected: true, onselect:function(s) { if(s){changeDeploymentType("full")}}}, | ||||
|                       {id:"deploymenu-item-flow",toggle:"deploy-type",icon:"red/images/deploy-flows.svg",label:RED._("deploy.modifiedFlows"),sublabel:RED._("deploy.modifiedFlowsDesc"), onselect:function(s) {if(s){changeDeploymentType("flows")}}}, | ||||
|                       {id:"deploymenu-item-node",toggle:"deploy-type",icon:"red/images/deploy-nodes.svg",label:RED._("deploy.modifiedNodes"),sublabel:RED._("deploy.modifiedNodesDesc"),onselect:function(s) { if(s){changeDeploymentType("nodes")}}}, | ||||
|                       null, | ||||
|                       {id:"deploymenu-item-reload", icon:"red/images/deploy-reload.png",label:RED._("deploy.restartFlows"),sublabel:RED._("deploy.restartFlowsDesc"),onselect:"core:restart-flows"}, | ||||
|                       {id:"deploymenu-item-reload", icon:"red/images/deploy-reload.svg",label:RED._("deploy.restartFlows"),sublabel:RED._("deploy.restartFlowsDesc"),onselect:"core:restart-flows"}, | ||||
|  | ||||
|                   ] | ||||
|               }); | ||||
|         } else if (type == "simple") { | ||||
|             var label = options.label || RED._("deploy.deploy"); | ||||
|             var icon = 'red/images/deploy-full-o.png'; | ||||
|             var icon = 'red/images/deploy-full-o.svg'; | ||||
|             if (options.hasOwnProperty('icon')) { | ||||
|                 icon = options.icon; | ||||
|             } | ||||
|  | ||||
|             $('<li><span class="deploy-button-group button-group">'+ | ||||
|               '<a id="btn-deploy" class="deploy-button disabled" href="#">'+ | ||||
|                 '<span class="deploy-button-content">'+ | ||||
|                   (icon?'<img id="btn-deploy-icon" src="'+icon+'"> ':'')+ | ||||
|             $('<li><span class="red-ui-deploy-button-group button-group">'+ | ||||
|               '<a id="red-ui-header-button-deploy" class="red-ui-deploy-button disabled" href="#">'+ | ||||
|                 '<span class="red-ui-deploy-button-content">'+ | ||||
|                   (icon?'<img id="red-ui-header-button-deploy-icon" src="'+icon+'"> ':'')+ | ||||
|                   '<span>'+label+'</span>'+ | ||||
|                 '</span>'+ | ||||
|                 '<span class="deploy-button-spinner hide">'+ | ||||
|                 '<span class="red-ui-deploy-button-spinner hide">'+ | ||||
|                  '<img src="red/images/spin.svg"/>'+ | ||||
|                 '</span>'+ | ||||
|               '</a>'+ | ||||
|               '</span></li>').prependTo(".header-toolbar"); | ||||
|               '</span></li>').prependTo(".red-ui-header-toolbar"); | ||||
|         } | ||||
|  | ||||
|         $('#btn-deploy').click(function(event) { | ||||
|         $('#red-ui-header-button-deploy').on("click", function(event) { | ||||
|             event.preventDefault(); | ||||
|             save(); | ||||
|         }); | ||||
|  | ||||
|         RED.actions.add("core:deploy-flows",save); | ||||
|         RED.actions.add("core:restart-flows",restart); | ||||
|         if (type === "default") { | ||||
|             RED.actions.add("core:restart-flows",restart); | ||||
|             RED.actions.add("core:set-deploy-type-to-full",function() { RED.menu.setSelected("deploymenu-item-full",true);}); | ||||
|             RED.actions.add("core:set-deploy-type-to-modified-flows",function() { RED.menu.setSelected("deploymenu-item-flow",true); }); | ||||
|             RED.actions.add("core:set-deploy-type-to-modified-nodes",function() { RED.menu.setSelected("deploymenu-item-node",true); }); | ||||
|         } | ||||
|  | ||||
|  | ||||
|  | ||||
|         RED.events.on('nodes:change',function(state) { | ||||
| @@ -107,10 +113,10 @@ RED.deploy = (function() { | ||||
|                 window.onbeforeunload = function() { | ||||
|                     return RED._("deploy.confirm.undeployedChanges"); | ||||
|                 } | ||||
|                 $("#btn-deploy").removeClass("disabled"); | ||||
|                 $("#red-ui-header-button-deploy").removeClass("disabled"); | ||||
|             } else { | ||||
|                 window.onbeforeunload = null; | ||||
|                 $("#btn-deploy").addClass("disabled"); | ||||
|                 $("#red-ui-header-button-deploy").addClass("disabled"); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
| @@ -176,14 +182,14 @@ RED.deploy = (function() { | ||||
|     function resolveConflict(currentNodes, activeDeploy) { | ||||
|         var message = $('<div>'); | ||||
|         $('<p data-i18n="deploy.confirm.conflict"></p>').appendTo(message); | ||||
|         var conflictCheck = $('<div id="node-dialog-confirm-deploy-conflict-checking" class="node-dialog-confirm-conflict-row">'+ | ||||
|         var conflictCheck = $('<div class="red-ui-deploy-dialog-confirm-conflict-row">'+ | ||||
|             '<img src="red/images/spin.svg"/><div data-i18n="deploy.confirm.conflictChecking"></div>'+ | ||||
|         '</div>').appendTo(message); | ||||
|         var conflictAutoMerge = $('<div class="node-dialog-confirm-conflict-row">'+ | ||||
|             '<i style="color: #3a3;" class="fa fa-check"></i><div data-i18n="deploy.confirm.conflictAutoMerge"></div>'+ | ||||
|         var conflictAutoMerge = $('<div class="red-ui-deploy-dialog-confirm-conflict-row">'+ | ||||
|             '<i class="fa fa-check"></i><div data-i18n="deploy.confirm.conflictAutoMerge"></div>'+ | ||||
|             '</div>').hide().appendTo(message); | ||||
|         var conflictManualMerge = $('<div id="node-dialog-confirm-deploy-conflict-manual-merge" class="node-dialog-confirm-conflict-row">'+ | ||||
|             '<i style="color: #999;" class="fa fa-exclamation"></i><div data-i18n="deploy.confirm.conflictManualMerge"></div>'+ | ||||
|         var conflictManualMerge = $('<div class="red-ui-deploy-dialog-confirm-conflict-row">'+ | ||||
|             '<i class="fa fa-exclamation"></i><div data-i18n="deploy.confirm.conflictManualMerge"></div>'+ | ||||
|             '</div>').hide().appendTo(message); | ||||
|  | ||||
|         message.i18n(); | ||||
| @@ -196,22 +202,22 @@ RED.deploy = (function() { | ||||
|                 } | ||||
|             }, | ||||
|             { | ||||
|                 id: "node-dialog-confirm-deploy-review", | ||||
|                 id: "red-ui-deploy-dialog-confirm-deploy-review", | ||||
|                 text: RED._("deploy.confirm.button.review"), | ||||
|                 class: "primary disabled", | ||||
|                 click: function() { | ||||
|                     if (!$("#node-dialog-confirm-deploy-review").hasClass('disabled')) { | ||||
|                     if (!$("#red-ui-deploy-dialog-confirm-deploy-review").hasClass('disabled')) { | ||||
|                         RED.diff.showRemoteDiff(); | ||||
|                         conflictNotification.close(); | ||||
|                     } | ||||
|                 } | ||||
|             }, | ||||
|             { | ||||
|                 id: "node-dialog-confirm-deploy-merge", | ||||
|                 id: "red-ui-deploy-dialog-confirm-deploy-merge", | ||||
|                 text: RED._("deploy.confirm.button.merge"), | ||||
|                 class: "primary disabled", | ||||
|                 click: function() { | ||||
|                     if (!$("#node-dialog-confirm-deploy-merge").hasClass('disabled')) { | ||||
|                     if (!$("#red-ui-deploy-dialog-confirm-deploy-merge").hasClass('disabled')) { | ||||
|                         RED.diff.mergeDiff(currentDiff); | ||||
|                         conflictNotification.close(); | ||||
|                     } | ||||
| @@ -220,7 +226,7 @@ RED.deploy = (function() { | ||||
|         ]; | ||||
|         if (activeDeploy) { | ||||
|             buttons.push({ | ||||
|                 id: "node-dialog-confirm-deploy-overwrite", | ||||
|                 id: "red-ui-deploy-dialog-confirm-deploy-overwrite", | ||||
|                 text: RED._("deploy.confirm.button.overwrite"), | ||||
|                 class: "primary", | ||||
|                 click: function() { | ||||
| @@ -245,11 +251,11 @@ RED.deploy = (function() { | ||||
|                 var d = Object.keys(diff.conflicts); | ||||
|                 if (d.length === 0) { | ||||
|                     conflictAutoMerge.show(); | ||||
|                     $("#node-dialog-confirm-deploy-merge").removeClass('disabled') | ||||
|                     $("#red-ui-deploy-dialog-confirm-deploy-merge").removeClass('disabled') | ||||
|                 } else { | ||||
|                     conflictManualMerge.show(); | ||||
|                 } | ||||
|                 $("#node-dialog-confirm-deploy-review").removeClass('disabled') | ||||
|                 $("#red-ui-deploy-dialog-confirm-deploy-review").removeClass('disabled') | ||||
|             },ellapsed); | ||||
|         }) | ||||
|     } | ||||
| @@ -266,15 +272,15 @@ RED.deploy = (function() { | ||||
|     } | ||||
|     function restart() { | ||||
|         var startTime = Date.now(); | ||||
|         $(".deploy-button-content").css('opacity',0); | ||||
|         $(".deploy-button-spinner").show(); | ||||
|         var deployWasEnabled = !$("#btn-deploy").hasClass("disabled"); | ||||
|         $("#btn-deploy").addClass("disabled"); | ||||
|         $(".red-ui-deploy-button-content").css('opacity',0); | ||||
|         $(".red-ui-deploy-button-spinner").show(); | ||||
|         var deployWasEnabled = !$("#red-ui-header-button-deploy").hasClass("disabled"); | ||||
|         $("#red-ui-header-button-deploy").addClass("disabled"); | ||||
|         deployInflight = true; | ||||
|         $("#header-shade").show(); | ||||
|         $("#editor-shade").show(); | ||||
|         $("#palette-shade").show(); | ||||
|         $("#sidebar-shade").show(); | ||||
|         $("#red-ui-header-shade").show(); | ||||
|         $("#red-ui-editor-shade").show(); | ||||
|         $("#red-ui-palette-shade").show(); | ||||
|         $("#red-ui-sidebar-shade").show(); | ||||
|  | ||||
|         $.ajax({ | ||||
|             url:"flows", | ||||
| @@ -284,12 +290,12 @@ RED.deploy = (function() { | ||||
|             } | ||||
|         }).done(function(data,textStatus,xhr) { | ||||
|             if (deployWasEnabled) { | ||||
|                 $("#btn-deploy").removeClass("disabled"); | ||||
|                 $("#red-ui-header-button-deploy").removeClass("disabled"); | ||||
|             } | ||||
|             RED.notify('<p>'+RED._("deploy.successfulRestart")+'</p>',"success"); | ||||
|         }).fail(function(xhr,textStatus,err) { | ||||
|             if (deployWasEnabled) { | ||||
|                 $("#btn-deploy").removeClass("disabled"); | ||||
|                 $("#red-ui-header-button-deploy").removeClass("disabled"); | ||||
|             } | ||||
|             if (xhr.status === 401) { | ||||
|                 RED.notify(RED._("deploy.deployFailed",{message:RED._("user.notAuthorized")}),"error"); | ||||
| @@ -304,17 +310,17 @@ RED.deploy = (function() { | ||||
|             deployInflight = false; | ||||
|             var delta = Math.max(0,300-(Date.now()-startTime)); | ||||
|             setTimeout(function() { | ||||
|                 $(".deploy-button-content").css('opacity',1); | ||||
|                 $(".deploy-button-spinner").hide(); | ||||
|                 $("#header-shade").hide(); | ||||
|                 $("#editor-shade").hide(); | ||||
|                 $("#palette-shade").hide(); | ||||
|                 $("#sidebar-shade").hide(); | ||||
|                 $(".red-ui-deploy-button-content").css('opacity',1); | ||||
|                 $(".red-ui-deploy-button-spinner").hide(); | ||||
|                 $("#red-ui-header-shade").hide(); | ||||
|                 $("#red-ui-editor-shade").hide(); | ||||
|                 $("#red-ui-palette-shade").hide(); | ||||
|                 $("#red-ui-sidebar-shade").hide(); | ||||
|             },delta); | ||||
|         }); | ||||
|     } | ||||
|     function save(skipValidation,force) { | ||||
|         if (!$("#btn-deploy").hasClass("disabled")) { | ||||
|         if (!$("#red-ui-header-button-deploy").hasClass("disabled")) { | ||||
|             if (!RED.user.hasPermission("flows.write")) { | ||||
|                 RED.notify(RED._("user.errors.deploy"),"error"); | ||||
|                 return; | ||||
| @@ -355,13 +361,13 @@ RED.deploy = (function() { | ||||
|                 if (hasUnknown && !ignoreDeployWarnings.unknown) { | ||||
|                     showWarning = true; | ||||
|                     notificationMessage = "<p>"+RED._('deploy.confirm.unknown')+"</p>"+ | ||||
|                         '<ul class="node-dialog-configm-deploy-list"><li>'+cropList(unknownNodes).map(function(n) { return sanitize(n) }).join("</li><li>")+"</li></ul><p>"+ | ||||
|                         '<ul class="red-ui-deploy-dialog-confirm-list"><li>'+cropList(unknownNodes).map(function(n) { return sanitize(n) }).join("</li><li>")+"</li></ul><p>"+ | ||||
|                         RED._('deploy.confirm.confirm')+ | ||||
|                         "</p>"; | ||||
|  | ||||
|                     notificationButtons= [ | ||||
|                         { | ||||
|                             id: "node-dialog-confirm-deploy-deploy", | ||||
|                             id: "red-ui-deploy-dialog-confirm-deploy-deploy", | ||||
|                             text: RED._("deploy.confirm.button.confirm"), | ||||
|                             class: "primary", | ||||
|                             click: function() { | ||||
| @@ -375,12 +381,12 @@ RED.deploy = (function() { | ||||
|                     invalidNodes.sort(sortNodeInfo); | ||||
|  | ||||
|                     notificationMessage = "<p>"+RED._('deploy.confirm.improperlyConfigured')+"</p>"+ | ||||
|                         '<ul class="node-dialog-configm-deploy-list"><li>'+cropList(invalidNodes.map(function(A) { return sanitize( (A.tab?"["+A.tab+"] ":"")+A.label+" ("+A.type+")")})).join("</li><li>")+"</li></ul><p>"+ | ||||
|                         '<ul class="red-ui-deploy-dialog-confirm-list"><li>'+cropList(invalidNodes.map(function(A) { return sanitize( (A.tab?"["+A.tab+"] ":"")+A.label+" ("+A.type+")")})).join("</li><li>")+"</li></ul><p>"+ | ||||
|                         RED._('deploy.confirm.confirm')+ | ||||
|                         "</p>"; | ||||
|                     notificationButtons= [ | ||||
|                         { | ||||
|                             id: "node-dialog-confirm-deploy-deploy", | ||||
|                             id: "red-ui-deploy-dialog-confirm-deploy-deploy", | ||||
|                             text: RED._("deploy.confirm.button.confirm"), | ||||
|                             class: "primary", | ||||
|                             click: function() { | ||||
| @@ -411,9 +417,9 @@ RED.deploy = (function() { | ||||
|             var nns = RED.nodes.createCompleteNodeSet(); | ||||
|  | ||||
|             var startTime = Date.now(); | ||||
|             $(".deploy-button-content").css('opacity',0); | ||||
|             $(".deploy-button-spinner").show(); | ||||
|             $("#btn-deploy").addClass("disabled"); | ||||
|             $(".red-ui-deploy-button-content").css('opacity',0); | ||||
|             $(".red-ui-deploy-button-spinner").show(); | ||||
|             $("#red-ui-header-button-deploy").addClass("disabled"); | ||||
|  | ||||
|             var data = {flows:nns}; | ||||
|  | ||||
| @@ -422,10 +428,10 @@ RED.deploy = (function() { | ||||
|             } | ||||
|  | ||||
|             deployInflight = true; | ||||
|             $("#header-shade").show(); | ||||
|             $("#editor-shade").show(); | ||||
|             $("#palette-shade").show(); | ||||
|             $("#sidebar-shade").show(); | ||||
|             $("#red-ui-header-shade").show(); | ||||
|             $("#red-ui-editor-shade").show(); | ||||
|             $("#red-ui-palette-shade").show(); | ||||
|             $("#red-ui-sidebar-shade").show(); | ||||
|             $.ajax({ | ||||
|                 url:"flows", | ||||
|                 type: "POST", | ||||
| @@ -476,7 +482,7 @@ RED.deploy = (function() { | ||||
|                 RED.events.emit("deploy"); | ||||
|             }).fail(function(xhr,textStatus,err) { | ||||
|                 RED.nodes.dirty(true); | ||||
|                 $("#btn-deploy").removeClass("disabled"); | ||||
|                 $("#red-ui-header-button-deploy").removeClass("disabled"); | ||||
|                 if (xhr.status === 401) { | ||||
|                     RED.notify(RED._("deploy.deployFailed",{message:RED._("user.notAuthorized")}),"error"); | ||||
|                 } else if (xhr.status === 409) { | ||||
| @@ -490,12 +496,12 @@ RED.deploy = (function() { | ||||
|                 deployInflight = false; | ||||
|                 var delta = Math.max(0,300-(Date.now()-startTime)); | ||||
|                 setTimeout(function() { | ||||
|                     $(".deploy-button-content").css('opacity',1); | ||||
|                     $(".deploy-button-spinner").hide(); | ||||
|                     $("#header-shade").hide(); | ||||
|                     $("#editor-shade").hide(); | ||||
|                     $("#palette-shade").hide(); | ||||
|                     $("#sidebar-shade").hide(); | ||||
|                     $(".red-ui-deploy-button-content").css('opacity',1); | ||||
|                     $(".red-ui-deploy-button-spinner").hide(); | ||||
|                     $("#red-ui-header-shade").hide(); | ||||
|                     $("#red-ui-editor-shade").hide(); | ||||
|                     $("#red-ui-palette-shade").hide(); | ||||
|                     $("#red-ui-sidebar-shade").hide(); | ||||
|                 },delta); | ||||
|             }); | ||||
|         } | ||||
|   | ||||