Compare commits
	
		
			1146 Commits
		
	
	
		
			0.20.3
			...
			outliner-c
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | b65e4d5794 | ||
|  | 7599e865fd | ||
|  | ebca8c0217 | ||
|  | 752a080876 | ||
|  | 0541d9189d | ||
|  | 0e454b08c8 | ||
|  | 2d0ca20a03 | ||
|  | 61d9ccf263 | ||
|  | 1c30584153 | ||
|  | 5c5bebd689 | ||
|  | 93211470d1 | ||
|  | b5800205c4 | ||
|  | eeebf04509 | ||
|  | f4f99f594d | ||
|  | 5e8e739f78 | ||
|  | a15adc43af | ||
|  | 07556592c1 | ||
|  | 7694349078 | ||
|  | 4f3cb3103e | ||
|  | 842cd1ecf0 | ||
|  | 81a4f42673 | ||
|  | 152e695f4c | ||
|  | 5a0c10b80e | ||
|  | 7be824640c | ||
|  | c061487a16 | ||
|  | 97fd34150f | ||
|  | 6d294a0c74 | ||
|  | fe4ef354ac | ||
|  | d28b8b5e8d | ||
|  | f2b30d9a3f | ||
|  | 0a614f2741 | ||
|  | a9fb50787b | ||
|  | ce7d7a8e01 | ||
|  | 7006c00233 | ||
|  | 21866634b3 | ||
|  | 34dfd50702 | ||
|  | d9502a6c00 | ||
|  | 95f7b9205a | ||
|  | d14d4944a0 | ||
|  | b4b2729e96 | ||
|  | 299b81f51b | ||
|  | ad6b18e66f | ||
|  | 091a462a42 | ||
|  | cb218a57f1 | ||
|  | ba8649117d | ||
|  | 20daebd965 | ||
|  | 7c2786969a | ||
|  | 565aae5967 | ||
|  | 16a634063a | ||
|  | 4c28b5b227 | ||
|  | a7a949377b | ||
|  | c048b1a25b | ||
|  | f7e7f7ed01 | ||
|  | 5dfcb80de8 | ||
|  | c8f6100a6a | ||
|  | c0f4e07e10 | ||
|  | 3c259b2c22 | ||
|  | 3b3a2d4edc | ||
|  | e930098b51 | ||
|  | 43d5df4a12 | ||
|  | 914cfdbc55 | ||
|  | aa8f4af339 | ||
|  | b6fbe7d07d | ||
|  | bf9d6c7ac4 | ||
|  | 139ae547c6 | ||
|  | 8b252b458c | ||
|  | efecfa328b | ||
|  | 5651e7107f | ||
|  | b6b3ceef4d | ||
|  | 3e74d75f28 | ||
|  | 6d737b9e4c | ||
|  | dec82589d1 | ||
|  | f0193b0f67 | ||
|  | fdf8eb0657 | ||
|  | 2ce424b567 | ||
|  | 8995fa9ed1 | ||
|  | dc412b305c | ||
|  | d7505da997 | ||
|  | 4b54a81dfd | ||
|  | 132254b3a5 | ||
|  | 9128b12960 | ||
|  | e9104df047 | ||
|  | bae52613ab | ||
|  | 18af906fd3 | ||
|  | d45415ab22 | ||
|  | c6c42740c5 | ||
|  | a8d8540346 | ||
|  | cbf1afc9fe | ||
|  | 8a798e620a | ||
|  | 774751a25c | ||
|  | 13718032f6 | ||
|  | 1b497b340b | ||
|  | bb41ab482c | ||
|  | 215aab0fe4 | ||
|  | 666822cf51 | ||
|  | 40101df6ec | ||
|  | 4adcb9c439 | ||
|  | a6cd0bf7e9 | ||
|  | 8158744829 | ||
|  | 70c0c7bc14 | ||
|  | fdda29f048 | ||
|  | 95cc8ea80d | ||
|  | 18f8dde712 | ||
|  | effff3405b | ||
|  | 9d8cbcb993 | ||
|  | 3345f2f3b8 | ||
|  | bcf1d986a4 | ||
|  | a51e74bfa1 | ||
|  | cf00acac04 | ||
|  | 876a7a4646 | ||
|  | 95d1b7bc36 | ||
|  | d4ae0b0a2e | ||
|  | 36739fb444 | ||
|  | 7906c28abb | ||
|  | f87b40941f | ||
|  | 05f816fc5d | ||
|  | f9a157fe18 | ||
|  | ca213589ac | ||
|  | c5ca9fafee | ||
|  | 82b3a97d99 | ||
|  | 1c94064c57 | ||
|  | 7969dd431f | ||
|  | 22e7ddcb1d | ||
|  | b1eafac67a | ||
|  | 5d81cec00c | ||
|  | 9512450d7c | ||
|  | ed1998162f | ||
|  | ac2a21f992 | ||
|  | ad78ce0eb6 | ||
|  | 8ce49c25d4 | ||
|  | 4c24bd4ab9 | ||
|  | 0de49e2a75 | ||
|  | 05c3f459ad | ||
|  | 50aaef5103 | ||
|  | 38872049fd | ||
|  | 5dc1cc54d5 | ||
|  | 57f0fbbb98 | ||
|  | 977fef03b0 | ||
|  | 7d67e6a276 | ||
|  | 0832be5970 | ||
|  | 2343fbd86a | ||
|  | 367ebc1dd4 | ||
|  | 15cc88de6c | ||
|  | 64b3c11682 | ||
|  | b8784185e8 | ||
|  | fdc721baa1 | ||
|  | 03b64bc493 | ||
|  | a6a781f67c | ||
|  | fe1f8ca0a8 | ||
|  | a600feb5de | ||
|  | 1f2c0a78c2 | ||
|  | e4b9c6a2ee | ||
|  | a69db4d572 | ||
|  | 12c92072d0 | ||
|  | e674d9246b | ||
|  | b71f81af57 | ||
|  | b3535281ef | ||
|  | 5f5e6ea845 | ||
|  | 64d2e80690 | ||
|  | b6e0568e76 | ||
|  | dca5b3b2a0 | ||
|  | 243915516e | ||
|  | bc3683d8f6 | ||
|  | 1d36ce0fdf | ||
|  | 88d4d306f3 | ||
|  | 184d928cf7 | ||
|  | fbd911ed27 | ||
|  | dec3762b7a | ||
|  | a849872c21 | ||
|  | 1d71fb3554 | ||
|  | 0d3bf0cd00 | ||
|  | 6c766eba86 | ||
|  | cc760acb62 | ||
|  | f4d4bf8779 | ||
|  | 90f62e5e4a | ||
|  | f1bd3e1711 | ||
|  | 01dde8bea5 | ||
|  | 341c66a199 | ||
|  | bc1fb2770b | ||
|  | 9f1373945b | ||
|  | 266ee2ca81 | ||
|  | 35738cc1a3 | ||
|  | ff310f89bd | ||
|  | 9189db5531 | ||
|  | bfa5f39b6d | ||
|  | 15f97bbf26 | ||
|  | 90ba761325 | ||
|  | ddd428f76e | ||
|  | 0c83fa7060 | ||
|  | f2e2c7e4d0 | ||
|  | 717bfffa63 | ||
|  | a764a4a44b | ||
|  | 247fa0ce7c | ||
|  | 13932b2cfb | ||
|  | 0bd0540d2f | ||
|  | 9a17cc503c | ||
|  | 89a048e5fa | ||
|  | 88bc022e2a | ||
|  | 00e080459e | ||
|  | 5b197adf33 | ||
|  | 9019c31f91 | ||
|  | 2e14703b16 | ||
|  | f87698438d | ||
|  | 4af1cf1d1f | ||
|  | d6ad7dc6eb | ||
|  | f25e4ea520 | ||
|  | 17891d373b | ||
|  | 9f29149d87 | ||
|  | 010e20989a | ||
|  | ee13cd10fe | ||
|  | b0f9bf2c62 | ||
|  | 9fbfc3d677 | ||
|  | 189389f96a | ||
|  | 2af7066512 | ||
|  | 9cbc40a229 | ||
|  | 18bf220ca4 | ||
|  | 8750c4b121 | ||
|  | 417d2cb40a | ||
|  | 36b0698432 | ||
|  | 0edc57f0e3 | ||
|  | 3d76137247 | ||
|  | df9d231389 | ||
|  | e2aebaf0e7 | ||
|  | 20e84a847a | ||
|  | ad4779e32f | ||
|  | 90537e42ba | ||
|  | 4615465599 | ||
|  | 95418724fa | ||
|  | 989cb05257 | ||
|  | d7df20413d | ||
|  | f7e0f55c13 | ||
|  | e16f48c9fd | ||
|  | 4694644043 | ||
|  | f468d6e947 | ||
|  | 9a19477796 | ||
|  | 00d41c6de2 | ||
|  | fc2a9a85ff | ||
|  | 78c86880e4 | ||
|  | aca61c0354 | ||
|  | 73dde4de51 | ||
|  | 597c4a2e4f | ||
|  | 4245c0a0ad | ||
|  | 25aadc690a | ||
|  | 12dc4ab1fa | ||
|  | 55a5917282 | ||
|  | a5b33d11fc | ||
|  | d2d872f51c | ||
|  | 5c0b500f48 | ||
|  | 28418288e3 | ||
|  | 0150769c17 | ||
|  | 2eaea02489 | ||
|  | 1a9c4b7714 | ||
|  | d9f710aa52 | ||
|  | 2069cc4392 | ||
|  | f78be9050a | ||
|  | feb5d13e1c | ||
|  | a3b0448f53 | ||
|  | 3dfbefb9f5 | ||
|  | 9f6bac1b1b | ||
|  | 0f2ed14d16 | ||
|  | 3e898c487a | ||
|  | efb9dce92f | ||
|  | f024e0bbed | ||
|  | 3f1bb6771a | ||
|  | 0b3ced5203 | ||
|  | 373267c53b | ||
|  | ae3e250269 | ||
|  | 33200b2d08 | ||
|  | b032e00d01 | ||
|  | fda95dfc5d | ||
|  | bc96f2d0cb | ||
|  | c649e1b4a2 | ||
|  | f54ed8ebd1 | ||
|  | b82167fefa | ||
|  | 2efc2bc186 | ||
|  | f572c11912 | ||
|  | 4595a77c41 | ||
|  | 7c1853431a | ||
|  | e26eb85718 | ||
|  | 821b5686f2 | ||
|  | c989f466ed | ||
|  | 97c771f93a | ||
|  | 54dbdde9cb | ||
|  | 513957eea1 | ||
|  | 5eed4672ed | ||
|  | aafa4fe0b9 | ||
|  | 572c03631d | ||
|  | 2f869a55e2 | ||
|  | 161f6090c1 | ||
|  | efad7270b7 | ||
|  | 24eb78d137 | ||
|  | e969a1c97c | ||
|  | 4f31632863 | ||
|  | 1d417c07cd | ||
|  | 344c9fe57e | ||
|  | 9d4400349b | ||
|  | 24f7000918 | ||
|  | 6ff3286d78 | ||
|  | f058de8bcd | ||
|  | fbfc74e5ca | ||
|  | 1b5654001c | ||
|  | e0f3e94e2b | ||
|  | 5da89892b4 | ||
|  | a6ecb54cc4 | ||
|  | 04da13eaf9 | ||
|  | 7fa4df082e | ||
|  | ae001c5e82 | ||
|  | e7f942eda7 | ||
|  | fa8236ee2c | ||
|  | 08ec04c889 | ||
|  | e5150ea012 | ||
|  | 222ece2533 | ||
|  | 294696daf5 | ||
|  | d099356207 | ||
|  | 5c06761b1a | ||
|  | 05fc3c5eca | ||
|  | 9d4e2adde4 | ||
|  | a8db3d8dd3 | ||
|  | 6ae7c51dc5 | ||
|  | 84771f5864 | ||
|  | 4304d44851 | ||
|  | 1018c0e8a5 | ||
|  | b1d0013214 | ||
|  | 94ef25bbb9 | ||
|  | 13830ffc9c | ||
|  | e0bef941b4 | ||
|  | 03e9522d98 | ||
|  | 1bdbd31b96 | ||
|  | ef9db701f8 | ||
|  | afb564a4fc | ||
|  | 3e7f58dedd | ||
|  | e46d8345db | ||
|  | 2e364b6d9a | ||
|  | b4177836a8 | ||
|  | 5b2ee21204 | ||
|  | 9b6e798eb6 | ||
|  | 7c91c4ae5a | ||
|  | 7bc3b662e4 | ||
|  | 64af1f7e9b | ||
|  | f0038e9796 | ||
|  | 768aa4ac92 | ||
|  | f61c137ea3 | ||
|  | 20a8059758 | ||
|  | 58696c6ad4 | ||
|  | b5ed018bae | ||
|  | 91b7dd988e | ||
|  | b0c3c78899 | ||
|  | 282f00e091 | ||
|  | 5cd2791506 | ||
|  | 9b2e9ec41a | ||
|  | 08ef9ee682 | ||
|  | a8bc753720 | ||
|  | 266df86d98 | ||
|  | 85a1f59a93 | ||
|  | 43258ee816 | ||
|  | c4ca0b6e91 | ||
|  | 1bf3b3077e | ||
|  | c9194c3635 | ||
|  | 27c462fee9 | ||
|  | 7886e5d57c | ||
|  | 6912dec166 | ||
|  | b8e610e1b6 | ||
|  | 421b5846f2 | ||
|  | 6a30f2cbc8 | ||
|  | a8b1e91843 | ||
|  | 20f97d0d13 | ||
|  | 4c78f06c2b | ||
|  | c700d5c922 | ||
|  | a9508a2c04 | ||
|  | 09d55a0cbd | ||
|  | b165129388 | ||
|  | 0ef3471f8f | ||
|  | 9ba9998bd6 | ||
|  | 72126730ef | ||
|  | fd2213232c | ||
|  | 369c5754f2 | ||
|  | fc3d0ab053 | ||
|  | 1c63d7ff31 | ||
|  | de971fa53f | ||
|  | d005eb46cf | ||
|  | d1dd7d1d51 | ||
|  | b78ef006ec | ||
|  | 134c68c98e | ||
|  | 82539fc420 | ||
|  | 7a5604697f | ||
|  | 84d2b8ad6d | ||
|  | 9a0c843f29 | ||
|  | 4d96d95370 | ||
|  | 51ea5dc342 | ||
|  | 97d58e34f2 | ||
|  | 86ce5c591b | ||
|  | dea47a6e3d | ||
|  | 7621cf3377 | ||
|  | 5090b01b8e | ||
|  | 6675fdf3c2 | ||
|  | 491812fac5 | ||
|  | 8a82552bdc | ||
|  | bd4fc2e5cc | ||
|  | 32aa4c41ce | ||
|  | 2a6bedbd8d | ||
|  | 83942c2551 | ||
|  | 458d794f52 | ||
|  | 95982ad464 | ||
|  | 7723ff461b | ||
|  | 0ca36a89e3 | ||
|  | cc5fdd9844 | ||
|  | d09ee6611f | ||
|  | bba6855872 | ||
|  | 43970b404e | ||
|  | 1868289b71 | ||
|  | 37bcd5c603 | ||
|  | c9ad5bea93 | ||
|  | a09b3bb6c7 | ||
|  | 3d6170be5e | ||
|  | 00477fd67a | ||
|  | 21c57f968a | ||
|  | f7d2314d64 | ||
|  | 5ecf8c83db | ||
|  | 608834eafb | ||
|  | 1fd4b2b9fc | ||
|  | 01a143cd5a | ||
|  | 6321b21a1a | ||
|  | 8405826fab | ||
|  | 22de8855c1 | ||
|  | 1830478ec3 | ||
|  | 6d98b93135 | ||
|  | 54978e4d64 | ||
|  | 9d567d61fe | ||
|  | 79feb691bd | ||
|  | e16fe1e6a5 | ||
|  | 04d3981921 | ||
|  | 40c3099e4e | ||
|  | 3f86fd7176 | ||
|  | 9e6bc46540 | ||
|  | 5e892f222b | ||
|  | 2da1554caa | ||
|  | a53d0c091e | ||
|  | f88bfa059d | ||
|  | 2e38999506 | ||
|  | 42b841cb78 | ||
|  | c0d007ffa9 | ||
|  | 127b361979 | ||
|  | e3dab3cf20 | ||
|  | 569b9f3d06 | ||
|  | d6b5494625 | ||
|  | f76edf74f9 | ||
|  | 5c199d3bb4 | ||
|  | 634a51635c | ||
|  | 4f9395e881 | ||
|  | 8035531a27 | ||
|  | cc177533e8 | ||
|  | cd210d9fbf | ||
|  | 87b9b56b65 | ||
|  | bffcaa1c17 | ||
|  | 33cbb2ada8 | ||
|  | d08e77cf36 | ||
|  | 1f8ed9dcb9 | ||
|  | 53b127902c | ||
|  | 389cbf4900 | ||
|  | 80d100f3f9 | ||
|  | a05589c5a6 | ||
|  | 7d32636133 | ||
|  | 3db5f928ee | ||
|  | 797da3bc8e | ||
|  | 1e8d695311 | ||
|  | 00eb474e02 | ||
|  | ad6104baeb | ||
|  | cd552ab202 | ||
|  | bbd471ad93 | ||
|  | 0f1ca1c7cf | ||
|  | 62fc554d25 | ||
|  | 84dc34e68f | ||
|  | 0bb77bfa7f | ||
|  | b6702a0c3b | ||
|  | a781a1dd4d | ||
|  | d771527f77 | ||
|  | 3d9945b60c | ||
|  | 5897045f24 | ||
|  | b2f53a183e | ||
|  | be3dd63360 | ||
|  | f951fe6939 | ||
|  | 0622be843b | ||
|  | 272fbc0cb0 | ||
|  | 36bf2a3c38 | ||
|  | 663ed9833a | ||
|  | fcf757f715 | ||
|  | 88e729664a | ||
|  | c03abdb5e7 | ||
|  | 6d3eb7bb4b | ||
|  | 7ffd37d9cb | ||
|  | 87aacb4270 | ||
|  | 3f756aac21 | ||
|  | 504d13943d | ||
|  | 59b1466e5d | ||
|  | d5d9ac5c76 | ||
|  | bb12ec702a | ||
|  | 82490b0a58 | ||
|  | 2cbf625483 | ||
|  | 44f2a986a2 | ||
|  | c3df1c6cde | ||
|  | 6b52206186 | ||
|  | 9d4238e5cc | ||
|  | c16c119a7d | ||
|  | b49835c72f | ||
|  | ee6f6ae391 | ||
|  | 95a51aafdc | ||
|  | 5e7cd79ed9 | ||
|  | aba6173e23 | ||
|  | 468beee045 | ||
|  | 70ad66bcff | ||
|  | e2c3b35391 | ||
|  | 448de23f59 | ||
|  | 74a015c329 | ||
|  | 44a07c74fd | ||
|  | 0f8af4ba1c | ||
|  | 214d788029 | ||
|  | 530bf22bd5 | ||
|  | ccc98370eb | ||
|  | 7640bc029c | ||
|  | 3f72eb51a0 | ||
|  | 8801ace247 | ||
|  | faf46e4447 | ||
|  | 63978e226b | ||
|  | b96164d4f5 | ||
|  | 944070dfb1 | ||
|  | f0584df1d0 | ||
|  | ba209c2bdd | ||
|  | c6e2f28b97 | ||
|  | 2436bb0128 | ||
|  | 9c4640e010 | ||
|  | 1ee43113b1 | ||
|  | 902f477ee3 | ||
|  | 9c1d46ff92 | ||
|  | fe0d4f08f3 | ||
|  | 9cbd0fceea | ||
|  | b22a4f94ab | ||
|  | 14c2005bbc | ||
|  | a4c351fd4f | ||
|  | a364d4950d | ||
|  | d017dd75cd | ||
|  | 021df83c3f | ||
|  | 7805974736 | ||
|  | c1dae95f71 | ||
|  | e7c2ff3bd2 | ||
|  | 25459b52a1 | ||
|  | d45274494d | ||
|  | b81be8f358 | ||
|  | aa6c0b9d6e | ||
|  | 64580237d5 | ||
|  | b93165592e | ||
|  | 83c1e44925 | ||
|  | 3088115aba | ||
|  | fc93e502b8 | ||
|  | e90e6eaac3 | ||
|  | 2f4dcba54d | ||
|  | 683c6a748e | ||
|  | 175a871ee0 | ||
|  | b4e2061e85 | ||
|  | 2aef99c440 | ||
|  | 6c125e125f | ||
|  | 88cbc32abc | ||
|  | 8f45e8f84a | ||
|  | 21635aadfe | ||
|  | d5234888b3 | ||
|  | f478afb58a | ||
|  | a54ca699b5 | ||
|  | 1f5ff0c6d3 | ||
|  | 2a2541df59 | ||
|  | cd629c1699 | ||
|  | ff96773295 | ||
|  | 4d6828ec14 | ||
|  | dae1d6057e | ||
|  | 6726c42cc8 | ||
|  | 4f6023e44c | ||
|  | 9e16d7f433 | ||
|  | aa86cfc55f | ||
|  | 6931cb9895 | ||
|  | d32d04bd4e | ||
|  | 0b3e9bf5e2 | ||
|  | a4af7b8e21 | ||
|  | 72deee5d74 | ||
|  | 5e9e523d4c | ||
|  | c54509df3d | ||
|  | 63cc9adeaa | ||
|  | 74d760a46d | ||
|  | d46531def8 | ||
|  | eb09ec6834 | ||
|  | 9bd9c6a400 | ||
|  | 7321e206c5 | ||
|  | 2c7917f0ca | ||
|  | d94b20a908 | ||
|  | b1b1fe21dd | ||
|  | 1db3af7c8e | ||
|  | 397fe31f97 | ||
|  | bc283aa025 | ||
|  | 9dbdf0947b | ||
|  | 7c21bf4555 | ||
|  | 361dc194ee | ||
|  | 8c1aa83d12 | ||
|  | d2755a8049 | ||
|  | 1b78bd1684 | ||
|  | 5f67f1f078 | ||
|  | 07061928df | ||
|  | 18ff2df65c | ||
|  | 7b1411d171 | ||
|  | 3a1d0f3695 | ||
|  | 2cd5e1d3c5 | ||
|  | 000765fb77 | ||
|  | 0ff324b0db | ||
|  | a96d5096fe | ||
|  | e8ef476a6d | ||
|  | 22b9df62d1 | ||
|  | 6026da867b | ||
|  | 4d58902ba7 | ||
|  | 4dc1343445 | ||
|  | 080487cb33 | ||
|  | 0febcf4f9e | ||
|  | cd23f711ed | ||
|  | f9b147af42 | ||
|  | 775f1110d3 | ||
|  | 57649a9b81 | ||
|  | 72a268b70a | ||
|  | f86a171dff | ||
|  | e022b782a9 | ||
|  | bd67731bb7 | ||
|  | 25de4e4782 | ||
|  | c590247afa | ||
|  | 5d36539271 | ||
|  | 0d673486a3 | ||
|  | 29f1651a18 | ||
|  | dd20a3e685 | ||
|  | 75a5b1354c | ||
|  | dae9ac8173 | ||
|  | 78b735276b | ||
|  | e10dd54e2b | ||
|  | cb8deab1f9 | ||
|  | e5c27d0236 | ||
|  | faf6fa9450 | ||
|  | 873bdc6733 | ||
|  | 8a40b075b5 | ||
|  | 56c41374bf | ||
|  | a08c2c6437 | ||
|  | e94634544c | ||
|  | 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 | ||
|  | 7957ec4369 | ||
|  | 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 | ||
|  | 17653761b9 | ||
|  | 4f049fd94b | ||
|  | f98d1c95cc | ||
|  | a2b5c0247b | ||
|  | bca9b5d8c0 | ||
|  | bc789c7f9f | ||
|  | 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 | ||
|  | a42d7d867e | ||
|  | 14ac6446de | ||
|  | 260a9723a4 | ||
|  | 4e7b000dcd | ||
|  | 2254e4c57e | ||
|  | d517697564 | ||
|  | 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 | ||
|  | d6bd35287f | 
							
								
								
									
										3
									
								
								.github/ISSUE_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -28,7 +28,8 @@ 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: | ||||
| - [ ] running in Docker: | ||||
|   | ||||
							
								
								
									
										4
									
								
								.github/ISSUE_TEMPLATE/--bug_report.md
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -1,6 +1,6 @@ | ||||
| --- | ||||
| name: Bug report | ||||
| about: Reproducable software issues in the core of Node-RED | ||||
| about: Reproducible software issues in the core of Node-RED | ||||
| title: '' | ||||
| labels: '' | ||||
| assignees: '' | ||||
| @@ -33,7 +33,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: | ||||
|   | ||||
							
								
								
									
										7
									
								
								.github/ISSUE_TEMPLATE/-anything-else.md
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -7,8 +7,11 @@ assignees: '' | ||||
|  | ||||
| --- | ||||
|  | ||||
| Please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack). | ||||
| Please DO NOT raise an issue. | ||||
|  | ||||
| You could also consider asking a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/node-red) and tag it `node-red`. | ||||
| 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
									
								
								.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -29,6 +29,6 @@ the [forum](https://discourse.nodered.org) or | ||||
| <!-- Put an `x` in the boxes that apply --> | ||||
|  | ||||
| - [ ] I have read the [contribution guidelines](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md) | ||||
| - [ ] For non-bugfix PRs, I have discussed this change on the mailing list/slack team. | ||||
| - [ ] For non-bugfix PRs, I have discussed this change on the forum/slack team. | ||||
| - [ ] I have run `grunt` to verify the unit tests pass | ||||
| - [ ] I have added suitable unit tests to cover the new/changed functionality | ||||
|   | ||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -22,3 +22,4 @@ packages/node_modules/@node-red/editor-client/public | ||||
| !test/**/node_modules | ||||
| docs | ||||
| !packages/node_modules/**/docs | ||||
| .vscode | ||||
| @@ -2,6 +2,8 @@ sudo: false | ||||
| language: node_js | ||||
| matrix: | ||||
|   include: | ||||
|     - node_js: "14" | ||||
|     - 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 | ||||
|   | ||||
							
								
								
									
										885
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						| @@ -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 | ||||
|  | ||||
|   | ||||
							
								
								
									
										116
									
								
								Gruntfile.js
									
									
									
									
									
								
							
							
						
						| @@ -16,6 +16,7 @@ | ||||
|  | ||||
| var path = require("path"); | ||||
| var fs = require("fs-extra"); | ||||
| var sass = require("node-sass"); | ||||
|  | ||||
| module.exports = function(grunt) { | ||||
|  | ||||
| @@ -25,9 +26,13 @@ module.exports = function(grunt) { | ||||
|         nodemonArgs.push(flowFile); | ||||
|     } | ||||
|  | ||||
|     var browserstack = grunt.option('browserstack'); | ||||
|     if (browserstack) { | ||||
|         process.env.BROWSERSTACK = true; | ||||
|     } | ||||
|     var nonHeadless = grunt.option('non-headless'); | ||||
|     if (nonHeadless) { | ||||
|         process.env.NODE_RED_NON_HEADLESS = 'true'; | ||||
|         process.env.NODE_RED_NON_HEADLESS = true; | ||||
|     } | ||||
|     grunt.initConfig({ | ||||
|         pkg: grunt.file.readJSON('package.json'), | ||||
| @@ -79,20 +84,20 @@ module.exports = function(grunt) { | ||||
|                 //"loopfunc": true, // allow functions to be defined in loops | ||||
|                 //"sub": true       // don't warn that foo['bar'] should be written as foo.bar | ||||
|             }, | ||||
|             all: [ | ||||
|                 'Gruntfile.js', | ||||
|                 'red.js', | ||||
|                 'packages/**/*.js' | ||||
|             ], | ||||
|             core: { | ||||
|                 files: { | ||||
|                     src: [ | ||||
|                         'Gruntfile.js', | ||||
|                         'red.js', | ||||
|                         'packages/**/*.js', | ||||
|                     ] | ||||
|                 } | ||||
|             }, | ||||
|             // all: [ | ||||
|             //     'Gruntfile.js', | ||||
|             //     'red.js', | ||||
|             //     'packages/**/*.js' | ||||
|             // ], | ||||
|             // core: { | ||||
|             //     files: { | ||||
|             //         src: [ | ||||
|             //             'Gruntfile.js', | ||||
|             //             'red.js', | ||||
|             //             'packages/**/*.js', | ||||
|             //         ] | ||||
|             //     } | ||||
|             // }, | ||||
|             nodes: { | ||||
|                 files: { | ||||
|                     src: [ 'nodes/core/*/*.js' ] | ||||
| @@ -100,7 +105,7 @@ module.exports = function(grunt) { | ||||
|             }, | ||||
|             editor: { | ||||
|                 files: { | ||||
|                     src: [ 'editor/js/**/*.js' ] | ||||
|                     src: [ 'packages/node_modules/@node-red/editor-client/src/js/**/*.js' ] | ||||
|                 } | ||||
|             }, | ||||
|             tests: { | ||||
| @@ -120,6 +125,7 @@ module.exports = function(grunt) { | ||||
|                 src: [ | ||||
|                     // Ensure editor source files are concatenated in | ||||
|                     // the right order | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/polyfills.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/jquery-addons.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/red.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/events.js", | ||||
| @@ -145,17 +151,22 @@ 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/common/colorPicker.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", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/sidebar.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/palette.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/tab-info-outliner.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/tab-help.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/tab-context.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js", | ||||
| @@ -167,8 +178,10 @@ 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/group.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/userSettings.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/projects/projects.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js", | ||||
| @@ -181,22 +194,23 @@ 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.5.1.min.js", | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-migrate-3.3.0.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", | ||||
|                         "node_modules/marked/marked.min.js", | ||||
|                         "node_modules/dompurify/dist/purify.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" | ||||
| @@ -217,15 +231,12 @@ module.exports = function(grunt) { | ||||
|         sass: { | ||||
|             build: { | ||||
|                 options: { | ||||
|                     implementation: sass, | ||||
|                     outputStyle: 'compressed' | ||||
|                 }, | ||||
|                 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 +288,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 +363,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, | ||||
| @@ -499,7 +508,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'); | ||||
| @@ -558,12 +569,25 @@ 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; | ||||
|         } | ||||
|     }); | ||||
|     grunt.registerTask('generatePublishScript', | ||||
|         'Generates a script to publish build output to npm', | ||||
|             function () { | ||||
|                 const done = this.async(); | ||||
|                 const generatePublishScript = require("./scripts/generate-publish-script.js"); | ||||
|                 generatePublishScript().then(function(output) { | ||||
|                     grunt.log.writeln(output); | ||||
|  | ||||
|                     const filePath = path.join(grunt.config.get('paths.dist'),"modules","publish.sh"); | ||||
|                     grunt.file.write(filePath,output); | ||||
|  | ||||
|                     done(); | ||||
|                 }); | ||||
|             }); | ||||
|     grunt.registerTask('setDevEnv', | ||||
|         'Sets NODE_ENV=development so non-minified assets are used', | ||||
|             function () { | ||||
| @@ -582,9 +606,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', | ||||
| @@ -600,7 +630,7 @@ module.exports = function(grunt) { | ||||
|  | ||||
|     grunt.registerTask('release', | ||||
|         'Create distribution zip file', | ||||
|         ['build','verifyPackageDependencies','clean:release','mkdir:release','chmod:release','compress:release','pack-modules']); | ||||
|         ['build','verifyPackageDependencies','clean:release','mkdir:release','chmod:release','compress:release','pack-modules','generatePublishScript']); | ||||
|  | ||||
|     grunt.registerTask('pack-modules', | ||||
|         'Create module pack files for release', | ||||
|   | ||||
| @@ -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. | ||||
							
								
								
									
										103
									
								
								package.json
									
									
									
									
									
								
							
							
						
						| @@ -1,7 +1,7 @@ | ||||
| { | ||||
|     "name": "node-red", | ||||
|     "version": "0.20.3", | ||||
|     "description": "A visual tool for wiring the Internet of Things", | ||||
|     "version": "1.1.0-beta.1", | ||||
|     "description": "Low-code programming for event-driven applications", | ||||
|     "homepage": "http://nodered.org", | ||||
|     "license": "Apache-2.0", | ||||
|     "repository": { | ||||
| @@ -24,95 +24,94 @@ | ||||
|         } | ||||
|     ], | ||||
|     "dependencies": { | ||||
|         "ajv": "6.10.0", | ||||
|         "ajv": "6.12.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.4", | ||||
|         "content-type": "1.0.4", | ||||
|         "cookie": "0.4.1", | ||||
|         "cookie-parser": "1.4.5", | ||||
|         "cors": "2.8.5", | ||||
|         "cron": "1.7.0", | ||||
|         "denque": "1.4.0", | ||||
|         "express": "4.16.4", | ||||
|         "express-session": "1.15.6", | ||||
|         "fs-extra": "7.0.1", | ||||
|         "cron": "1.7.2", | ||||
|         "denque": "1.4.1", | ||||
|         "express": "4.17.1", | ||||
|         "express-session": "1.17.1", | ||||
|         "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": "5.0.0", | ||||
|         "i18next": "15.1.2", | ||||
|         "iconv-lite": "0.5.1", | ||||
|         "is-utf8": "0.2.1", | ||||
|         "js-yaml": "3.12.2", | ||||
|         "js-yaml": "3.14.0", | ||||
|         "json-stringify-safe": "5.0.1", | ||||
|         "jsonata": "1.6.4", | ||||
|         "media-typer": "1.0.1", | ||||
|         "memorystore": "1.6.1", | ||||
|         "mime": "2.4.0", | ||||
|         "jsonata": "1.8.3", | ||||
|         "lodash.clonedeep": "^4.5.0", | ||||
|         "media-typer": "1.1.0", | ||||
|         "memorystore": "1.6.2", | ||||
|         "mime": "2.4.6", | ||||
|         "moment-timezone": "^0.5.31", | ||||
|         "mqtt": "2.18.8", | ||||
|         "multer": "1.4.1", | ||||
|         "mustache": "3.0.1", | ||||
|         "node-red-node-email": "1.*", | ||||
|         "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", | ||||
|         "nopt": "4.0.1", | ||||
|         "multer": "1.4.2", | ||||
|         "mustache": "4.0.1", | ||||
|         "node-red-admin": "^0.2.6", | ||||
|         "node-red-node-rbe": "^0.2.9", | ||||
|         "node-red-node-sentiment": "^0.1.6", | ||||
|         "node-red-node-tail": "^0.1.0", | ||||
|         "nopt": "4.0.3", | ||||
|         "oauth2orize": "1.11.0", | ||||
|         "on-headers": "1.0.2", | ||||
|         "passport": "0.4.0", | ||||
|         "passport": "0.4.1", | ||||
|         "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.9.4", | ||||
|         "when": "3.7.8", | ||||
|         "ws": "6.2.0", | ||||
|         "xml2js": "0.4.19", | ||||
|         "iconv-lite": "0.4.24" | ||||
|         "ws": "6.2.1", | ||||
|         "xml2js": "0.4.23" | ||||
|     }, | ||||
|     "optionalDependencies": { | ||||
|         "bcrypt": "~2.0.0" | ||||
|         "bcrypt": "3.0.8" | ||||
|     }, | ||||
|     "devDependencies": { | ||||
|         "grunt": "~1.0.3", | ||||
|         "marked": "0.8.2", | ||||
|         "dompurify": "2.0.11", | ||||
|         "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-sass": "~3.1.0", | ||||
|         "grunt-simple-mocha": "~0.4.1", | ||||
|         "grunt-webdriver": "^2.0.3", | ||||
|         "http-proxy": "^1.16.2", | ||||
|         "http-proxy": "1.18.1", | ||||
|         "istanbul": "0.4.5", | ||||
|         "jsdoc-nr-template": "github:node-red/jsdoc-nr-template", | ||||
|         "minami": "1.2.3", | ||||
|         "mocha": "^5.2.0", | ||||
|         "mosca": "^2.8.3", | ||||
|         "node-red-node-test-helper": "^0.2.5", | ||||
|         "node-sass": "^4.14.1", | ||||
|         "should": "^8.4.0", | ||||
|         "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", | ||||
|         "jsdoc-nr-template": "node-red/jsdoc-nr-template" | ||||
|         "supertest": "3.4.2" | ||||
|     }, | ||||
|     "engines": { | ||||
|         "node": ">=8" | ||||
|   | ||||
| @@ -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,9 @@ module.exports = { | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             module: req.body.module, | ||||
|             version: req.body.version | ||||
|             version: req.body.version, | ||||
|             url: req.body.url, | ||||
|             req: apiUtils.getRequestLogObject(req) | ||||
|         } | ||||
|         runtimeAPI.nodes.addModule(opts).then(function(info) { | ||||
|             res.json(info); | ||||
| @@ -54,7 +57,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 +70,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 +92,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 +112,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 +132,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 +147,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 +161,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 +174,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); | ||||
|   | ||||
| @@ -36,6 +36,7 @@ var log = require("@node-red/util").log; // TODO: separate module | ||||
| passport.use(strategies.bearerStrategy.BearerStrategy); | ||||
| passport.use(strategies.clientPasswordStrategy.ClientPasswordStrategy); | ||||
| passport.use(strategies.anonymousStrategy); | ||||
| passport.use(strategies.tokensStrategy); | ||||
|  | ||||
| var server = oauth2orize.createServer(); | ||||
|  | ||||
| @@ -60,7 +61,7 @@ function init(_settings,storage) { | ||||
| function needsPermission(permission) { | ||||
|     return function(req,res,next) { | ||||
|         if (settings && settings.adminAuth) { | ||||
|             return passport.authenticate(['bearer','anon'],{ session: false })(req,res,function() { | ||||
|             return passport.authenticate(['bearer','tokens','anon'],{ session: false })(req,res,function() { | ||||
|                 if (!req.user) { | ||||
|                     return next(); | ||||
|                 } | ||||
| @@ -100,7 +101,10 @@ function login(req,res) { | ||||
|             } | ||||
|         } else if (mergedAdminAuth.type === "strategy") { | ||||
|  | ||||
|             var urlPrefix = (settings.httpAdminRoot==='/')?"":settings.httpAdminRoot; | ||||
|             var urlPrefix = (settings.httpAdminRoot||"").replace(/\/$/,""); | ||||
|             if (urlPrefix.length > 0) { | ||||
|                 urlPrefix += "/"; | ||||
|             } | ||||
|             response = { | ||||
|                 "type":"strategy", | ||||
|                 "prompts":[{type:"button",label:mergedAdminAuth.strategy.label, url: urlPrefix + "auth/strategy"}] | ||||
|   | ||||
| @@ -123,9 +123,38 @@ AnonymousStrategy.prototype.authenticate = function(req) { | ||||
|     }); | ||||
| } | ||||
|  | ||||
| function TokensStrategy() { | ||||
|   passport.Strategy.call(this); | ||||
|   this.name = 'tokens'; | ||||
| } | ||||
| util.inherits(TokensStrategy, passport.Strategy); | ||||
| TokensStrategy.prototype.authenticate = function(req) { | ||||
|     var self = this; | ||||
|     var token = null; | ||||
|     if (Users.tokenHeader() === 'authorization') {   | ||||
|         if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') { | ||||
|             token = req.headers.authorization.split(' ')[1]; | ||||
|         } | ||||
|     } else { | ||||
|         token = req.headers[Users.tokenHeader()]; | ||||
|     } | ||||
|     if (token) { | ||||
|         Users.tokens(token).then(function(admin) { | ||||
|             if (admin) { | ||||
|                 self.success(admin,{scope:admin.permissions}); | ||||
|             } else { | ||||
|                 self.fail(401); | ||||
|             } | ||||
|         }); | ||||
|     } else { | ||||
|         self.fail(401); | ||||
|     } | ||||
| } | ||||
|  | ||||
| module.exports = { | ||||
|     bearerStrategy: bearerStrategy, | ||||
|     clientPasswordStrategy: clientPasswordStrategy, | ||||
|     passwordTokenExchange: passwordTokenExchange, | ||||
|     anonymousStrategy: new AnonymousStrategy() | ||||
|     anonymousStrategy: new AnonymousStrategy(), | ||||
|     tokensStrategy: new TokensStrategy() | ||||
| } | ||||
|   | ||||
| @@ -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() { | ||||
|   | ||||
| @@ -59,7 +59,9 @@ function getDefaultUser() { | ||||
| var api = { | ||||
|     get: get, | ||||
|     authenticate: authenticate, | ||||
|     default: getDefaultUser | ||||
|     default: getDefaultUser, | ||||
|     tokens: getDefaultUser, | ||||
|     tokenHeader: "authorization" | ||||
| } | ||||
|  | ||||
| function init(config) { | ||||
| @@ -105,6 +107,12 @@ function init(config) { | ||||
|     } else { | ||||
|         api.default = getDefaultUser; | ||||
|     } | ||||
|     if (config.tokens && typeof config.tokens === "function") { | ||||
|         api.tokens = config.tokens; | ||||
|         if (config.tokenHeader && typeof config.tokenHeader === "string") { | ||||
|             api.tokenHeader = config.tokenHeader.toLowerCase(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| function cleanUser(user) { | ||||
|     if (user && user.hasOwnProperty('password')) { | ||||
| @@ -118,5 +126,7 @@ module.exports = { | ||||
|     init: init, | ||||
|     get: function(username) { return api.get(username).then(cleanUser)}, | ||||
|     authenticate: function() { return api.authenticate.apply(null, arguments) }, | ||||
|     default: function() { return api.default(); } | ||||
|     default: function() { return api.default(); }, | ||||
|     tokens: function(token) { return api.tokens(token); }, | ||||
|     tokenHeader: function() { return api.tokenHeader } | ||||
| }; | ||||
|   | ||||
| @@ -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"); | ||||
|  | ||||
| @@ -88,14 +88,13 @@ module.exports = { | ||||
|             // Locales | ||||
|             var locales = require("./locales"); | ||||
|             locales.init(runtimeAPI); | ||||
|             editorApp.get(/locales\/(.+)\/?$/,locales.get,apiUtil.errorHandler); | ||||
|             editorApp.get(/^\/locales\/(.+)\/?$/,locales.get,apiUtil.errorHandler); | ||||
|  | ||||
|             // 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") { | ||||
|   | ||||
| @@ -15,7 +15,7 @@ | ||||
|  **/ | ||||
| var fs = require('fs'); | ||||
| var path = require('path'); | ||||
| //var apiUtil = require('../util'); | ||||
| // var apiUtil = require('../util'); | ||||
|  | ||||
| var i18n = require("@node-red/util").i18n; // TODO: separate module | ||||
|  | ||||
| @@ -41,7 +41,7 @@ module.exports = { | ||||
|         var namespace = req.params[0]; | ||||
|         var lngs = req.query.lng; | ||||
|         namespace = namespace.replace(/\.json$/,""); | ||||
|         var lang = req.query.lng; //apiUtil.determineLangFromHeaders(req.acceptsLanguages() || []); | ||||
|         var lang = req.query.lng || i18n.defaultLang; //apiUtil.determineLangFromHeaders(req.acceptsLanguages() || []); | ||||
|         var prevLang = i18n.i.language; | ||||
|         // Trigger a load from disk of the language if it is not the default | ||||
|         i18n.i.changeLanguage(lang, function(){ | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
|   | ||||
| @@ -42,7 +42,7 @@ var editor; | ||||
| /** | ||||
|  * Initialise the module. | ||||
|  * @param  {Object}     settings   The runtime settings | ||||
|  * @param  {HTTPServer} server     An instance of HTTP Server | ||||
|  * @param  {HTTPServer} _server     An instance of HTTP Server | ||||
|  * @param  {Storage}    storage    An instance of Node-RED Storage | ||||
|  * @param  {Runtime}    runtimeAPI An instance of Node-RED Runtime | ||||
|  * @memberof @node-red/editor-api | ||||
| @@ -59,6 +59,12 @@ function init(settings,_server,storage,runtimeAPI) { | ||||
|         }); | ||||
|         adminApp.use(corsHandler); | ||||
|  | ||||
|         if (settings.httpAdminMiddleware) { | ||||
|             if (typeof settings.httpAdminMiddleware === "function") { | ||||
|                 adminApp.use(settings.httpAdminMiddleware) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         auth.init(settings,storage); | ||||
|  | ||||
|         var maxApiRequestSize = settings.apiMaxLength || '5mb'; | ||||
|   | ||||
| @@ -43,9 +43,22 @@ module.exports = { | ||||
|     rejectHandler: function(req,res,err) { | ||||
|         //TODO: why this when errorHandler also?! | ||||
|         log.audit({event: "api.error",error:err.code||"unexpected_error",message:err.message||err.toString()},req); | ||||
|         res.status(err.status||400).json({ | ||||
|         var response = { | ||||
|             code: err.code||"unexpected_error", | ||||
|             message: err.message||err.toString() | ||||
|         }); | ||||
|         }; | ||||
|         // Handle auth failures on a specific remote | ||||
|         // TODO: don't hardcode this here - allow users of rejectHandler to identify extra props to send | ||||
|         if (err.remote) { | ||||
|             response.remote = err.remote; | ||||
|         } | ||||
|         res.status(err.status||400).json(response); | ||||
|     }, | ||||
|     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.3", | ||||
|     "version": "1.1.0-beta.1", | ||||
|     "license": "Apache-2.0", | ||||
|     "main": "./lib/index.js", | ||||
|     "repository": { | ||||
| @@ -16,22 +16,25 @@ | ||||
|         } | ||||
|     ], | ||||
|     "dependencies": { | ||||
|         "@node-red/util": "0.20.3", | ||||
|         "@node-red/editor-client": "0.20.3", | ||||
|         "@node-red/util": "1.1.0-beta.1", | ||||
|         "@node-red/editor-client": "1.1.0-beta.1", | ||||
|         "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.1", | ||||
|         "mime": "2.4.0", | ||||
|         "mustache": "3.0.1", | ||||
|         "express-session": "1.17.1", | ||||
|         "express": "4.17.1", | ||||
|         "memorystore": "1.6.2", | ||||
|         "mime": "2.4.6", | ||||
|         "mustache": "4.0.1", | ||||
|         "oauth2orize": "1.11.0", | ||||
|         "passport-http-bearer": "1.0.1", | ||||
|         "passport-oauth2-client-password": "0.1.2", | ||||
|         "passport": "0.4.0", | ||||
|         "passport": "0.4.1", | ||||
|         "when": "3.7.8", | ||||
|         "ws": "6.2.0" | ||||
|         "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" : { | ||||
| @@ -35,11 +34,11 @@ | ||||
|         "view" : "Ansicht", | ||||
|         "grid" : "Gitter", | ||||
|         "showGrid" : "Raster anzeigen", | ||||
|         "snapGrid" : "Einrasten am Raster", | ||||
|         "snapGrid" : "Am Raster ausrichten", | ||||
|         "gridSize" : "Rastergröße", | ||||
|         "textDir" : "Textrichtung", | ||||
|         "defaultDir" : "Standard", | ||||
|         "ltr" : "Links-nach-rechts", | ||||
|         "ltr" : "Von links nach rechts", | ||||
|         "rtl" : "Von rechts nach links", | ||||
|         "auto" : "Kontextuell" | ||||
|       }, | ||||
| @@ -48,24 +47,21 @@ | ||||
|       }, | ||||
|       "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", | ||||
|       "searchInput" : "Flows durchsuchen", | ||||
|       "subflows" : "Subflow", | ||||
|       "createSubflow" : "Subflow erstellen", | ||||
|       "selectionToSubflow" : "Auswahl für Subflow", | ||||
|       "selectionToSubflow" : "Auswahl zu Subflow", | ||||
|       "flows" : "Flows", | ||||
|       "add" : "Hinzufügen", | ||||
|       "rename" : "Umbenennen", | ||||
|       "delete" : "Löschen", | ||||
|       "keyboardShortcuts" : "Tastaturkurzbefehle", | ||||
|       "keyboardShortcuts" : "Tastenkürzel", | ||||
|       "login" : "Anmelden", | ||||
|       "logout" : "Abmelden", | ||||
|       "editPalette" : "Palette verwalten", | ||||
| @@ -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,13 +211,13 @@ | ||||
|       "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", | ||||
|     "noBinaryFileShowed" : "Der Inhalt der Binärdatei kann nicht angezeigt", | ||||
|     "viewCommitDiff" : "Änderungen festschreiben", | ||||
|     "viewCommitDiff" : "Änderungen committen", | ||||
|     "compareChanges" : "Änderungen vergleichen", | ||||
|     "saveConflict" : "Konfliktlösung speichern", | ||||
|     "conflictHeader" : "<span> __resolved__ </span>  von  <span> __unresolved__ </span>  -Konflikten behoben", | ||||
| @@ -230,8 +226,8 @@ | ||||
|     "newVersionError" : "Neue Version enthält keine gültige JSON-Datei:" | ||||
|   }, | ||||
|   "subflow" : { | ||||
|     "editSubflow" : "Flowschablone bearbeiten: __name__", | ||||
|     "edit" : "Flowsschablone bearbeiten", | ||||
|     "editSubflow" : "Subflow bearbeiten: __name__", | ||||
|     "edit" : "Subflow bearbeiten", | ||||
|     "subflowInstances" : "Es ist __count__ Instanz dieser Subflow-Vorlage vorhanden.", | ||||
|     "subflowInstances_plural" : "Es gibt __count__ Instanzen dieser Subflow-Vorlage.", | ||||
|     "editSubflowProperties" : "Eigenschaften bearbeiten", | ||||
| @@ -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,11 +262,11 @@ | ||||
|     "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" : { | ||||
|     "title" : "Tastaturkurzbefehle", | ||||
|     "title" : "Tastenkürzel", | ||||
|     "keyboard" : "Tastatur", | ||||
|     "filterActions" : "Filteraktionen", | ||||
|     "shortcut" : "Direktaufruf", | ||||
| @@ -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)", | ||||
|     "toggleSidebar" : "Seitenleiste ein-/ausschalten", | ||||
|     "copyNode" : "Ausgewählte Knoten kopieren", | ||||
|     "cutNode" : "Ausgewählte Knoten ausschneiden", | ||||
|     "pasteNode" : "Knoten einfügen", | ||||
|     "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-/ausblenden", | ||||
|     "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" : "Nodes filtern", | ||||
|     "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", | ||||
| @@ -374,17 +366,17 @@ | ||||
|       "remove" : "entfernen", | ||||
|       "update" : "Update auf __version__", | ||||
|       "updated" : "aktualisiert", | ||||
|       "install" : "installieren", | ||||
|       "installed" : "installiert", | ||||
|       "install" : "Installieren", | ||||
|       "installed" : "Installiert", | ||||
|       "loading" : "Kataloge werden geladen ...", | ||||
|       "tab-nodes" : "Knoten", | ||||
|       "tab-install" : "installieren", | ||||
|       "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,32 +429,32 @@ | ||||
|       "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" : { | ||||
|       "name" : "Kontextdaten", | ||||
|       "label" : "Kontext", | ||||
|       "none" : "keine ausgewählt", | ||||
|       "refresh" : "Aktualisierung zum Laden", | ||||
|       "refresh" : "Zum Aktualisieren neu laden", | ||||
|       "empty" : "leer", | ||||
|       "node" : "Knoten", | ||||
|       "node" : "Node", | ||||
|       "flow" : "Flow", | ||||
|       "global" : "Global" | ||||
|     }, | ||||
| @@ -485,7 +477,7 @@ | ||||
|         "none" : "Keine", | ||||
|         "install" : "installieren", | ||||
|         "removeFromProject" : "Aus Projekt entfernen", | ||||
|         "addToProject" : "zu Projekt hinzufügen", | ||||
|         "addToProject" : "Zu Projekt hinzufügen", | ||||
|         "files" : "Dateien", | ||||
|         "flow" : "Flow", | ||||
|         "credentials" : "Berechtigungsnachweis", | ||||
| @@ -518,7 +510,7 @@ | ||||
|       }, | ||||
|       "userSettings" : { | ||||
|         "committerDetail" : "Committer-Details", | ||||
|         "committerTip" : "Leer Wert für Systemstandardwert belassen", | ||||
|         "committerTip" : "Leer lassen für Systemstandard", | ||||
|         "userName" : "Benutzername", | ||||
|         "email" : "E-Mail", | ||||
|         "sshKeys" : "SSH-Schlüssel", | ||||
| @@ -552,7 +544,7 @@ | ||||
|         "revertChanges" : "Änderungen zurücksetzen", | ||||
|         "localChanges" : "Lokale Änderungen", | ||||
|         "none" : "Keine", | ||||
|         "conflictResolve" : "Alle Konflikte wurden aufgelöst. Festschreiben der Änderungen, um den Mischvorgang abzuschließen.", | ||||
|         "conflictResolve" : "Alle Konflikte wurden aufgelöst. Committe die Änderungen, um den Merge Request abzuschließen.", | ||||
|         "localFiles" : "Lokale Dateien", | ||||
|         "all" : "alle", | ||||
|         "unmergedChanges" : "Nicht zusammengeführte Änderungen", | ||||
| @@ -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", | ||||
|   | ||||
| @@ -14,9 +14,35 @@ | ||||
|             "back": "Back", | ||||
|             "next": "Next", | ||||
|             "clone": "Clone project", | ||||
|             "cont": "Continue" | ||||
|             "cont": "Continue", | ||||
|             "style": "Style", | ||||
|             "line": "Outline", | ||||
|             "fill": "Fill", | ||||
|             "label": "Label", | ||||
|             "color": "Color", | ||||
|             "position": "Position", | ||||
|             "enable": "Enable", | ||||
|             "disable": "Disable" | ||||
|         }, | ||||
|         "type": { | ||||
|             "string": "string", | ||||
|             "number": "number", | ||||
|             "boolean": "boolean", | ||||
|             "array": "array", | ||||
|             "buffer": "buffer", | ||||
|             "object": "object", | ||||
|             "jsonString": "JSON string", | ||||
|             "undefined": "undefined", | ||||
|             "null": "null" | ||||
|         } | ||||
|     }, | ||||
|     "event": { | ||||
|         "loadPalette": "Loading Palette", | ||||
|         "loadNodeCatalogs": "Loading Node catalogs", | ||||
|         "loadNodes": "Loading Nodes __count__", | ||||
|         "loadFlows": "Loading Flows", | ||||
|         "importFlows": "Adding Flows to workspace" | ||||
|     }, | ||||
|     "workspace": { | ||||
|         "defaultName": "Flow __number__", | ||||
|         "editFlow": "Edit flow: __name__", | ||||
| @@ -28,7 +54,8 @@ | ||||
|         "status": "Status", | ||||
|         "enabled": "Enabled", | ||||
|         "disabled":"Disabled", | ||||
|         "info": "Description" | ||||
|         "info": "Description", | ||||
|         "selectNodes": "Click nodes to select" | ||||
|     }, | ||||
|     "menu": { | ||||
|         "label": { | ||||
| @@ -42,7 +69,9 @@ | ||||
|                 "defaultDir": "Default", | ||||
|                 "ltr": "Left-to-right", | ||||
|                 "rtl": "Right-to-left", | ||||
|                 "auto": "Contextual" | ||||
|                 "auto": "Contextual", | ||||
|                 "language": "Language", | ||||
|                 "browserDefault": "Browser default" | ||||
|             }, | ||||
|             "sidebar": { | ||||
|                 "show": "Show sidebar" | ||||
| @@ -59,9 +88,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", | ||||
| @@ -80,7 +106,12 @@ | ||||
|             "projects-new": "New", | ||||
|             "projects-open": "Open", | ||||
|             "projects-settings": "Project Settings", | ||||
|             "showNodeLabelDefault": "Show label of newly added nodes" | ||||
|             "showNodeLabelDefault": "Show label of newly added nodes", | ||||
|             "groups": "Groups", | ||||
|             "groupSelection": "Group selection", | ||||
|             "ungroupSelection": "Ungroup selection", | ||||
|             "groupMergeSelection": "Merge selection", | ||||
|             "groupRemoveSelection": "Remove from group" | ||||
|         } | ||||
|     }, | ||||
|     "actions": { | ||||
| @@ -154,16 +185,18 @@ | ||||
|         } | ||||
|     }, | ||||
|     "clipboard": { | ||||
|         "clipboard": "Clipboard", | ||||
|         "nodes": "Nodes", | ||||
|         "node": "__count__ node", | ||||
|         "node_plural": "__count__ nodes", | ||||
|         "configNode": "__count__ configuration node", | ||||
|         "configNode_plural": "__count__ configuration nodes", | ||||
|         "group": "__count__ group", | ||||
|         "group_plural": "__count__ groups", | ||||
|         "flow": "__count__ flow", | ||||
|         "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", | ||||
| @@ -175,6 +208,9 @@ | ||||
|         "nodesImported": "Imported:", | ||||
|         "nodeCopied": "__count__ node copied", | ||||
|         "nodeCopied_plural": "__count__ nodes copied", | ||||
|         "groupCopied": "__count__ group copied", | ||||
|         "groupCopied_plural": "__count__ groups copied", | ||||
|         "groupStyleCopied": "Group style copied", | ||||
|         "invalidFlow": "Invalid flow: __message__", | ||||
|         "export": { | ||||
|             "selected":"selected nodes", | ||||
| @@ -182,7 +218,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", | ||||
| @@ -293,6 +333,13 @@ | ||||
|             "multipleInputsToSelection": "<strong>Cannot create subflow</strong>: multiple inputs to selection" | ||||
|         } | ||||
|     }, | ||||
|     "group": { | ||||
|         "editGroup": "Edit group: __name__", | ||||
|         "errors": { | ||||
|             "cannotCreateDiffGroups": "Cannot create group using nodes from different groups", | ||||
|             "cannotAddSubflowPorts": "Cannot add subflow ports to a group" | ||||
|         } | ||||
|     }, | ||||
|     "editor": { | ||||
|         "configEdit": "Edit", | ||||
|         "configAdd": "Add", | ||||
| @@ -306,10 +353,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", | ||||
| @@ -317,8 +366,44 @@ | ||||
|         "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", | ||||
|             "cred": "credential" | ||||
|         }, | ||||
|         "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": { | ||||
| @@ -346,25 +431,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", | ||||
| @@ -373,9 +459,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", | ||||
| @@ -476,11 +566,12 @@ | ||||
|     }, | ||||
|     "sidebar": { | ||||
|         "info": { | ||||
|             "name": "Node information", | ||||
|             "name": "Information", | ||||
|             "tabName": "Name", | ||||
|             "label": "info", | ||||
|             "node": "Node", | ||||
|             "type": "Type", | ||||
|             "group": "Group", | ||||
|             "module": "Module", | ||||
|             "id": "ID", | ||||
|             "status": "Status", | ||||
| @@ -503,7 +594,29 @@ | ||||
|             "nodeHelp": "Node Help", | ||||
|             "none":"None", | ||||
|             "arrayItems": "__count__ items", | ||||
|             "showTips":"You can open the tips from the settings panel" | ||||
|             "showTips":"You can open the tips from the settings panel", | ||||
|             "outline": "Outline", | ||||
|             "empty": "empty", | ||||
|             "globalConfig": "Global Configuration Nodes", | ||||
|             "triggerAction": "Trigger action", | ||||
|             "find": "Find in workspace", | ||||
|             "search": { | ||||
|                 "configNodes": "Configuration nodes", | ||||
|                 "unusedConfigNodes": "Unused configuration nodes", | ||||
|                 "invalidNodes": "Invalid nodes", | ||||
|                 "uknownNodes": "Unknown nodes", | ||||
|                 "unusedSubflows": "Unused subflows" | ||||
|             } | ||||
|         }, | ||||
|         "help": { | ||||
|             "name": "Help", | ||||
|             "label": "help", | ||||
|             "search": "Search help", | ||||
|             "nodeHelp": "Node Help", | ||||
|             "showHelp": "Show help", | ||||
|             "showInOutline": "Show in outline", | ||||
|             "showTopics": "Show topics", | ||||
|             "noHelp": "No help topic selected" | ||||
|         }, | ||||
|         "config": { | ||||
|             "name": "Configuration nodes", | ||||
| @@ -512,8 +625,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": { | ||||
| @@ -525,7 +640,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", | ||||
| @@ -540,6 +658,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": { | ||||
| @@ -550,7 +669,6 @@ | ||||
|                 "removeFromProject": "remove from project", | ||||
|                 "addToProject": "add to project", | ||||
|                 "files": "Files", | ||||
|                 "package": "Package", | ||||
|                 "flow": "Flow", | ||||
|                 "credentials": "Credentials", | ||||
|                 "package":"Package", | ||||
| @@ -694,7 +812,8 @@ | ||||
|             "bin": "buffer", | ||||
|             "date": "timestamp", | ||||
|             "jsonata": "expression", | ||||
|             "env": "env variable" | ||||
|             "env": "env variable", | ||||
|             "cred": "credential" | ||||
|         } | ||||
|     }, | ||||
|     "editableList": { | ||||
| @@ -726,12 +845,28 @@ | ||||
|     "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", | ||||
|         "error": { | ||||
|             "invalidJSON": "Invalid JSON: " | ||||
|         } | ||||
|     }, | ||||
|     "markdownEditor": { | ||||
|         "title": "Markdown editor", | ||||
|         "expand": "Expand", | ||||
|         "format": "Formatted with markdown", | ||||
|         "heading1": "Heading 1", | ||||
|         "heading2": "Heading 2", | ||||
| @@ -898,7 +1033,8 @@ | ||||
|             "passphrase": "Passphrase", | ||||
|             "retry": "Retry", | ||||
|             "update-failed": "Failed to update auth", | ||||
|             "unhandled": "Unhandled error response" | ||||
|             "unhandled": "Unhandled error response", | ||||
|             "host-key-verify-failed": "<p>Host key verification failed.</p><p>The repository host key could not be verified. Please update your <code>known_hosts</code> file and try again.</p>" | ||||
|         }, | ||||
|         "create-branch-list": { | ||||
|             "invalid": "Invalid branch", | ||||
| @@ -918,8 +1054,18 @@ | ||||
|     }, | ||||
|     "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)", | ||||
|         "zh-TW": "Chinese(Traditional)" | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| { | ||||
|     "$string": { | ||||
|         "args": "arg", | ||||
|         "desc": "Casts the *arg* parameter to a string using the following casting rules:\n\n - Strings are unchanged\n - Functions are converted to an empty string\n - Numeric infinity and NaN throw an error because they cannot be represented as a JSON number\n - All other values are converted to a JSON string using the `JSON.stringify` function" | ||||
|         "args": "arg[, prettify]", | ||||
|         "desc": "Casts the `arg` parameter to a string using the following casting rules:\n\n - Strings are unchanged\n - Functions are converted to an empty string\n - Numeric infinity and NaN throw an error because they cannot be represented as a JSON number\n - All other values are converted to a JSON string using the `JSON.stringify` function.  If `prettify` is true, then \"prettified\" JSON is produced. i.e One line per field and lines will be indented based on the field depth." | ||||
|     }, | ||||
|     "$length": { | ||||
|         "args": "str", | ||||
| @@ -185,7 +185,7 @@ | ||||
|     }, | ||||
|     "$reduce": { | ||||
|         "args":"array, function [, init]", | ||||
|         "desc":"Returns an aggregated value derived from applying the `function` parameter successively to each value in `array` in combination with the result of the previous application of the function.\n\nThe function must accept two arguments, and behaves like an infix operator between each value within the `array`.\n\nThe optional `init` parameter is used as the initial value in the aggregation." | ||||
|         "desc":"Returns an aggregated value derived from applying the `function` parameter successively to each value in `array` in combination with the result of the previous application of the function.\n\nThe function must accept two arguments, and behaves like an infix operator between each value within the `array`. The signature of `function` must be of the form: `myfunc($accumulator, $value[, $index[, $array]])`\n\nThe optional `init` parameter is used as the initial value in the aggregation." | ||||
|     }, | ||||
|     "$flowContext": { | ||||
|         "args": "string[, string]", | ||||
| @@ -230,6 +230,45 @@ | ||||
|     "$parseInteger": { | ||||
|         "args": "string, picture", | ||||
|         "desc": "Parses the contents of the `string` parameter to an integer (as a JSON number) using the format specified by the `picture` string. The `picture` string parameter has the same format as `$formatInteger`." | ||||
|  | ||||
|     }, | ||||
|     "$error": { | ||||
|         "args": "[str]", | ||||
|         "desc": "Throws an error with a message.  The optional `str` will replace the default message of `$error() function evaluated`" | ||||
|     }, | ||||
|     "$assert": { | ||||
|         "args": "arg, str", | ||||
|         "desc": "If `arg` is true the function returns undefined.  If `arg` is false an exception is thrown with `str` as the message of the exception." | ||||
|     }, | ||||
|     "$single": { | ||||
|         "args": "array, function", | ||||
|         "desc": "Returns the one and only value in the `array` parameter that satisfies the `function` predicate (i.e. the `function` returns Boolean `true` when passed the value).  Throws an exception if the number of matching values is not exactly one.\n\nThe function should be supplied in the following signature: `function(value [, index [, array]])` where value is each input of the array, index is the position of that value and the whole array is passed as the third argument" | ||||
|     }, | ||||
|     "$encodeUrl": { | ||||
|         "args": "str", | ||||
|         "desc": "Encodes a Uniform Resource Locator (URL) component by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character.\n\nExample: `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`" | ||||
|     }, | ||||
|     "$encodeUrlComponent": { | ||||
|         "args": "str", | ||||
|         "desc": "Encodes a Uniform Resource Locator (URL) by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character. \n\nExample: `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`" | ||||
|     }, | ||||
|     "$decodeUrl": { | ||||
|         "args": "str", | ||||
|         "desc": "Decodes a Uniform Resource Locator (URL) component previously created by encodeUrlComponent. \n\nExample: `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`" | ||||
|     }, | ||||
|     "$decodeUrlComponent": { | ||||
|         "args": "str", | ||||
|         "desc": "Decodes a Uniform Resource Locator (URL) previously created by encodeUrl. \n\nExample: `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`" | ||||
|     }, | ||||
|     "$distinct": { | ||||
|         "args": "array", | ||||
|         "desc": "Returns an array with duplicate values removed from `array`" | ||||
|     }, | ||||
|     "$type": { | ||||
|         "args": "value", | ||||
|         "desc": "Returns the type of `value` as a string. If `value` is undefined, this will return `undefined`" | ||||
|     }, | ||||
|     "$moment": { | ||||
|         "args": "[str]", | ||||
|         "desc": "Gets a date object using the Moment library." | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										200
									
								
								packages/node_modules/@node-red/editor-client/locales/ja/editor.json
									
									
									
									
										vendored
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						| @@ -14,9 +14,33 @@ | ||||
|             "back": "戻る", | ||||
|             "next": "進む", | ||||
|             "clone": "プロジェクトをクローン", | ||||
|             "cont": "続ける" | ||||
|             "cont": "続ける", | ||||
|             "style": "形式", | ||||
|             "line": "線", | ||||
|             "fill": "塗りつぶし", | ||||
|             "label": "ラベル", | ||||
|             "color": "色", | ||||
|             "position": "配置" | ||||
|         }, | ||||
|         "type": { | ||||
|             "string": "文字列", | ||||
|             "number": "数値", | ||||
|             "boolean": "真偽値", | ||||
|             "array": "配列", | ||||
|             "buffer": "バッファ", | ||||
|             "object": "オブジェクト", | ||||
|             "jsonString": "JSON文字列", | ||||
|             "undefined": "undefined", | ||||
|             "null": "null" | ||||
|         } | ||||
|     }, | ||||
|     "event": { | ||||
|         "loadPalette": "パレットを読み込み中", | ||||
|         "loadNodeCatalogs": "ノードカタログを読み込み中", | ||||
|         "loadNodes": "ノードを読み込み中 __count__", | ||||
|         "loadFlows": "フローを読み込み中", | ||||
|         "importFlows": "ワークスペースにフローを追加中" | ||||
|     }, | ||||
|     "workspace": { | ||||
|         "defaultName": "フロー __number__", | ||||
|         "editFlow": "フローを編集: __name__", | ||||
| @@ -28,7 +52,8 @@ | ||||
|         "status": "状態", | ||||
|         "enabled": "有効", | ||||
|         "disabled": "無効", | ||||
|         "info": "詳細" | ||||
|         "info": "詳細", | ||||
|         "selectNodes": "ノードをクリックして選択" | ||||
|     }, | ||||
|     "menu": { | ||||
|         "label": { | ||||
| @@ -42,7 +67,9 @@ | ||||
|                 "defaultDir": "標準", | ||||
|                 "ltr": "左から右", | ||||
|                 "rtl": "右から左", | ||||
|                 "auto": "文脈" | ||||
|                 "auto": "文脈", | ||||
|                 "language": "表示言語", | ||||
|                 "browserDefault": "ブラウザのデフォルト" | ||||
|             }, | ||||
|             "sidebar": { | ||||
|                 "show": "サイドバーを表示" | ||||
| @@ -53,15 +80,12 @@ | ||||
|             "settings": "設定", | ||||
|             "userSettings": "ユーザ設定", | ||||
|             "nodes": "ノード", | ||||
|             "displayStatus": "ノードの状態を表示", | ||||
|             "displayStatus": "ノードのステータスを表示", | ||||
|             "displayConfig": "ノードの設定", | ||||
|             "import": "読み込み", | ||||
|             "export": "書き出し", | ||||
|             "search": "ノードを検索", | ||||
|             "searchInput": "ノードを検索", | ||||
|             "clipboard": "クリップボード", | ||||
|             "library": "ライブラリ", | ||||
|             "examples": "サンプル", | ||||
|             "subflows": "サブフロー", | ||||
|             "createSubflow": "サブフローを作成", | ||||
|             "selectionToSubflow": "選択部分をサブフロー化", | ||||
| @@ -80,7 +104,12 @@ | ||||
|             "projects-new": "新規", | ||||
|             "projects-open": "開く", | ||||
|             "projects-settings": "設定", | ||||
|             "showNodeLabelDefault": "追加したノードのラベルを表示する" | ||||
|             "showNodeLabelDefault": "追加したノードのラベルを表示", | ||||
|             "groups": "グループ", | ||||
|             "groupSelection": "選択部分をグループ化", | ||||
|             "ungroupSelection": "選択部分をグループ解除", | ||||
|             "groupMergeSelection": "選択部分をマージ", | ||||
|             "groupRemoveSelection": "グループから削除" | ||||
|         } | ||||
|     }, | ||||
|     "actions": { | ||||
| @@ -154,16 +183,18 @@ | ||||
|         } | ||||
|     }, | ||||
|     "clipboard": { | ||||
|         "clipboard": "クリップボード", | ||||
|         "nodes": "ノード", | ||||
|         "node": "__count__ 個のノード", | ||||
|         "node_plural": "__count__ 個のノード", | ||||
|         "configNode": "__count__ 個の設定ノード", | ||||
|         "configNode_plural": "__count__ 個の設定ノード", | ||||
|         "group": "__count__ 個のグループ", | ||||
|         "group_plural": "__count__ 個のグループ", | ||||
|         "flow": "__count__ 個のフロー", | ||||
|         "flow_plural": "__count__ 個のフロー", | ||||
|         "subflow": "__count__ 個のサブフロー", | ||||
|         "subflow_plural": "__count__ 個のサブフロー", | ||||
|         "selectNodes": "上のテキストを選択し、クリップボードへコピーしてください", | ||||
|         "pasteNodes": "JSON形式のフローデータを貼り付けてください", | ||||
|         "selectFile": "読み込むファイルを選択してください", | ||||
|         "importNodes": "フローをクリップボートから読み込み", | ||||
| @@ -175,6 +206,9 @@ | ||||
|         "nodesImported": "読み込みました:", | ||||
|         "nodeCopied": "__count__ 個のノードをコピーしました", | ||||
|         "nodeCopied_plural": "__count__ 個のノードをコピーしました", | ||||
|         "groupCopied": "__count__ 個のグループをコピーしました", | ||||
|         "groupCopied_plural": "__count__ 個のグループをコピーしました", | ||||
|         "groupStyleCopied": "グループの形式をコピーしました", | ||||
|         "invalidFlow": "不正なフロー: __message__", | ||||
|         "export": { | ||||
|             "selected": "選択したフロー", | ||||
| @@ -182,7 +216,11 @@ | ||||
|             "all": "全てのタブ", | ||||
|             "compact": "インデントのないJSONフォーマット", | ||||
|             "formatted": "インデント付きのJSONフォーマット", | ||||
|             "copy": "書き出し" | ||||
|             "copy": "書き出し", | ||||
|             "export": "ライブラリに書き出し", | ||||
|             "exportAs": "書き出し先", | ||||
|             "overwrite": "更新", | ||||
|             "exists": "<p><b>\"__file__\"</b>は既に存在します。</p><p>更新しますか?</p>" | ||||
|         }, | ||||
|         "import": { | ||||
|             "import": "読み込み先", | ||||
| @@ -293,6 +331,13 @@ | ||||
|             "multipleInputsToSelection": "<strong>サブフローを作成できません</strong>: 複数の入力が選択されています" | ||||
|         } | ||||
|     }, | ||||
|     "group": { | ||||
|         "editGroup": "__name__ グループを編集", | ||||
|         "errors": { | ||||
|             "cannotCreateDiffGroups": "異なるグループのノードを使用してグループを作成することはできません", | ||||
|             "cannotAddSubflowPorts": "グループにサブフローの端子を追加できません" | ||||
|         } | ||||
|     }, | ||||
|     "editor": { | ||||
|         "configEdit": "編集", | ||||
|         "configAdd": "追加", | ||||
| @@ -306,10 +351,12 @@ | ||||
|         "addNewType": "新規に __type__ を追加...", | ||||
|         "nodeProperties": "プロパティ", | ||||
|         "label": "ラベル", | ||||
|         "color": "色", | ||||
|         "portLabels": "ポートラベル", | ||||
|         "labelInputs": "入力", | ||||
|         "labelOutputs": "出力", | ||||
|         "settingIcon": "アイコン", | ||||
|         "default": "デフォルト", | ||||
|         "noDefaultLabel": "なし", | ||||
|         "defaultLabel": "既定のラベルを使用", | ||||
|         "searchIcons": "アイコンを検索", | ||||
| @@ -317,8 +364,44 @@ | ||||
|         "description": "詳細", | ||||
|         "show": "表示", | ||||
|         "hide": "非表示", | ||||
|         "locale": "UI言語の選択", | ||||
|         "icon": "記号", | ||||
|         "inputType": "入力形式", | ||||
|         "inputs": { | ||||
|             "input": "入力", | ||||
|             "select": "メニュー", | ||||
|             "checkbox": "チェックボックス", | ||||
|             "spinner": "スピナー", | ||||
|             "none": "無し", | ||||
|             "hidden": "非表示" | ||||
|         }, | ||||
|         "types": { | ||||
|             "str": "文字列", | ||||
|             "num": "数値", | ||||
|             "bool": "真偽", | ||||
|             "json": "JSON", | ||||
|             "bin": "バッファ", | ||||
|             "env": "環境変数", | ||||
|             "cred": "認証情報" | ||||
|         }, | ||||
|         "menu": { | ||||
|             "input": "入力", | ||||
|             "select": "選択", | ||||
|             "checkbox": "チェックボックス", | ||||
|             "spinner": "数値", | ||||
|             "hidden": "ラベルのみ" | ||||
|         }, | ||||
|         "select": { | ||||
|             "label": "ラベル", | ||||
|             "value": "値" | ||||
|         }, | ||||
|         "spinner": { | ||||
|             "min": "最小値", | ||||
|             "max": "最大値" | ||||
|         }, | ||||
|         "errors": { | ||||
|             "scopeChange": "スコープの変更は、他のフローで使われているノードを無効にします" | ||||
|             "scopeChange": "スコープの変更は、他のフローで使われているノードを無効にします", | ||||
|             "invalidProperties": "プロパティが不正です:" | ||||
|         } | ||||
|     }, | ||||
|     "keyboard": { | ||||
| @@ -346,25 +429,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": "情報がありません", | ||||
| @@ -373,9 +457,13 @@ | ||||
|         "addCategory": "新規追加...", | ||||
|         "label": { | ||||
|             "subflows": "サブフロー", | ||||
|             "network": "ネットワーク", | ||||
|             "common": "共通", | ||||
|             "input": "入力", | ||||
|             "output": "出力", | ||||
|             "function": "機能", | ||||
|             "sequence": "シーケンス", | ||||
|             "parser": "パーサ", | ||||
|             "social": "ソーシャル", | ||||
|             "storage": "ストレージ", | ||||
|             "analysis": "分析", | ||||
| @@ -481,6 +569,7 @@ | ||||
|             "label": "情報", | ||||
|             "node": "ノード", | ||||
|             "type": "型", | ||||
|             "group": "グループ", | ||||
|             "module": "モジュール", | ||||
|             "id": "ID", | ||||
|             "status": "状態", | ||||
| @@ -503,7 +592,20 @@ | ||||
|             "nodeHelp": "ノードのヘルプ", | ||||
|             "none": "なし", | ||||
|             "arrayItems": "__count__ 要素", | ||||
|             "showTips": "設定からヒントを表示できます" | ||||
|             "showTips": "設定からヒントを表示できます", | ||||
|             "outline": "アウトライン", | ||||
|             "empty": "空", | ||||
|             "globalConfig": "グローバル設定ノード" | ||||
|         }, | ||||
|         "help": { | ||||
|             "name": "ヘルプ", | ||||
|             "label": "ヘルプ", | ||||
|             "search": "ヘルプを検索", | ||||
|             "nodeHelp": "ノードヘルプ", | ||||
|             "showHelp": "ヘルプを表示", | ||||
|             "showInOutline": "アウトラインに表示", | ||||
|             "showTopics": "トピックを表示", | ||||
|             "noHelp": "ヘルプのトピックが未選択" | ||||
|         }, | ||||
|         "config": { | ||||
|             "name": "ノードの設定を表示", | ||||
| @@ -512,8 +614,10 @@ | ||||
|             "none": "なし", | ||||
|             "subflows": "サブフロー", | ||||
|             "flows": "フロー", | ||||
|             "filterUnused": "未使用", | ||||
|             "filterAll": "全て", | ||||
|             "showAllConfigNodes": "全設定ノードを表示", | ||||
|             "filterUnused": "未使用", | ||||
|             "showAllUnusedConfigNodes": "未使用の全設定ノードを表示", | ||||
|             "filtered": "__count__ 個が無効" | ||||
|         }, | ||||
|         "context": { | ||||
| @@ -522,10 +626,13 @@ | ||||
|             "none": "選択されていません", | ||||
|             "refresh": "読み込みのため更新してください", | ||||
|             "empty": "データが存在しません", | ||||
|             "node": "Node", | ||||
|             "flow": "Flow", | ||||
|             "global": "Global", | ||||
|             "deleteConfirm": "データを削除しても良いですか?" | ||||
|             "node": "ノード", | ||||
|             "flow": "フロー", | ||||
|             "global": "グローバル", | ||||
|             "deleteConfirm": "データを削除しても良いですか?", | ||||
|             "autoRefresh": "選択対象が変化した場合更新", | ||||
|             "refrsh": "更新", | ||||
|             "delete": "削除" | ||||
|         }, | ||||
|         "palette": { | ||||
|             "name": "パレットの管理", | ||||
| @@ -537,9 +644,10 @@ | ||||
|             "description": "詳細", | ||||
|             "dependencies": "依存関係", | ||||
|             "settings": "設定", | ||||
|             "noSummaryAvailable": "サマリが存在しません", | ||||
|             "noSummaryAvailable": "要約が存在しません", | ||||
|             "editDescription": "プロジェクトの詳細を編集", | ||||
|             "editDependencies": "プロジェクトの依存関係を編集", | ||||
|             "noDescriptionAvailable": "詳細が存在しません", | ||||
|             "editReadme": "README.mdを編集", | ||||
|             "showProjectSettings": "プロジェクト設定を表示", | ||||
|             "projectSettings": { | ||||
| @@ -550,9 +658,9 @@ | ||||
|                 "removeFromProject": "プロジェクトから削除", | ||||
|                 "addToProject": "プロジェクトへ追加", | ||||
|                 "files": "ファイル", | ||||
|                 "package": "パッケージ", | ||||
|                 "flow": "フロー", | ||||
|                 "credentials": "認証情報", | ||||
|                 "package": "パッケージ", | ||||
|                 "packageCreate": "変更が保存された時にファイルが作成されます", | ||||
|                 "fileNotExist": "ファイルが存在しません", | ||||
|                 "selectFile": "ファイルを選択", | ||||
| @@ -693,7 +801,8 @@ | ||||
|             "bin": "バッファ", | ||||
|             "date": "日時", | ||||
|             "jsonata": "JSONata式", | ||||
|             "env": "環境変数" | ||||
|             "env": "環境変数", | ||||
|             "cred": "認証情報" | ||||
|         } | ||||
|     }, | ||||
|     "editableList": { | ||||
| @@ -725,12 +834,28 @@ | ||||
|     "jsEditor": { | ||||
|         "title": "JavaScriptエディタ" | ||||
|     }, | ||||
|     "textEditor": { | ||||
|         "title": "テキストエディタ" | ||||
|     }, | ||||
|     "jsonEditor": { | ||||
|         "title": "JSONエディタ", | ||||
|         "format": "JSONフォーマット" | ||||
|         "format": "JSONフォーマット", | ||||
|         "rawMode": "JSONを編集", | ||||
|         "uiMode": "ビジュアルエディタ", | ||||
|         "insertAbove": "上に挿入", | ||||
|         "insertBelow": "下に挿入", | ||||
|         "addItem": "要素を追加", | ||||
|         "copyPath": "要素のパスをコピー", | ||||
|         "expandItems": "要素を展開", | ||||
|         "collapseItems": "要素を折り畳む", | ||||
|         "duplicate": "複製", | ||||
|         "error": { | ||||
|             "invalidJSON": "不正なJSON: " | ||||
|         } | ||||
|     }, | ||||
|     "markdownEditor": { | ||||
|         "title": "マークダウンエディタ", | ||||
|         "expand": "拡大", | ||||
|         "format": "マークダウン形式で記述", | ||||
|         "heading1": "見出しレベル1", | ||||
|         "heading2": "見出しレベル2", | ||||
| @@ -891,13 +1016,14 @@ | ||||
|             "confirm": "<p>デプロイされていない変更は失われます。</p><p>続けますか?</p>" | ||||
|         }, | ||||
|         "send-req": { | ||||
|             "auth-req": "リポジトリ対する認証が必要です", | ||||
|             "auth-req": "リポジトリに対する認証が必要です", | ||||
|             "username": "ユーザ名", | ||||
|             "password": "パスワード", | ||||
|             "passphrase": "パスフレーズ", | ||||
|             "retry": "リトライ", | ||||
|             "update-failed": "認証の更新に失敗しました", | ||||
|             "unhandled": "エラー応答が処理されませんでした" | ||||
|             "unhandled": "エラー応答が処理されませんでした", | ||||
|             "host-key-verify-failed": "<p>ホストキーの検証に失敗</p><p>リポジトリのホストキーを検証できませんでした。<code>known_hosts</code>ファイルを更新して、もう一度試してください。</p>" | ||||
|         }, | ||||
|         "create-branch-list": { | ||||
|             "invalid": "不正なブランチ", | ||||
| @@ -917,8 +1043,18 @@ | ||||
|     }, | ||||
|     "editor-tab": { | ||||
|         "properties": "プロパティ", | ||||
|         "envProperties": "環境変数", | ||||
|         "description": "説明", | ||||
|         "appearance": "外観", | ||||
|         "env": "環境変数" | ||||
|         "preview": "UIプレビュー", | ||||
|         "defaultValue": "デフォルト値" | ||||
|     }, | ||||
|     "languages": { | ||||
|         "de": "ドイツ語", | ||||
|         "en-US": "英語", | ||||
|         "ja": "日本語", | ||||
|         "ko": "韓国語", | ||||
|         "zh-CN": "中国語(簡体)", | ||||
|         "zh-TW": "中国語(繁体)" | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| { | ||||
|     "$string": { | ||||
|         "args": "arg", | ||||
|         "desc": "以下の型変換ルールを用いて、引数 *arg* を文字列へ型変換します。:\n\n - 文字列は変換しません。\n - 関数は空の文字列に変換します。\n - JSONの数値として表現できないため、無限大やNaNはエラーになります。\n - 他の値は `JSON.stringify` 関数を用いて、JSONの文字列へ変換します。" | ||||
|         "args": "arg[, prettify]", | ||||
|         "desc": "以下の型変換ルールを用いて、引数 *arg* を文字列へ型変換します。:\n\n - 文字列は変換しません。\n - 関数は空の文字列に変換します。\n - JSONの数値として表現できないため、無限大やNaNはエラーになります。\n - 他の値は `JSON.stringify` 関数を用いて、JSONの文字列へ変換します。`prettify`が真の場合、JSONを整形出力します。フィールドを1行毎に出力。フィールドのネスト深さによってインデントを行います。" | ||||
|     }, | ||||
|     "$length": { | ||||
|         "args": "str", | ||||
| @@ -185,7 +185,7 @@ | ||||
|     }, | ||||
|     "$reduce": { | ||||
|         "args": "array, function [, init]", | ||||
|         "desc": "配列の各要素値に関数 `function` を連続的に適用して得られる集約値を返します。 `function` の適用の際には、直前の `function` の適用結果と要素値が引数として与えられます。\n\n関数 `function` は引数を2つ取り、配列の各要素の間に配置する中置演算子のように作用しなくてはなりません。\n\n任意の引数 `init` には、集約時の初期値を設定します。" | ||||
|         "desc": "配列の各要素値に関数 `function` を連続的に適用して得られる集約値を返します。 `function` の適用の際には、直前の `function` の適用結果と要素値が引数として与えられます。\n\n関数 `function` は引数を2つ取り、配列の各要素の間に配置する中置演算子のように作用しなくてはなりません。関数`function`のシグネチャは`myfunc($accumulator, $value[, $index[, $array]])`という形式でなければなりません。\n\n任意の引数 `init` には、集約時の初期値を設定します。" | ||||
|     }, | ||||
|     "$flowContext": { | ||||
|         "args": "string", | ||||
| @@ -230,5 +230,41 @@ | ||||
|     "$parseInteger": { | ||||
|         "args": "string, picture", | ||||
|         "desc": "`picture`文字列の指定に従って、`string`パラメータを整数(JSON数値)に変換します。`picture`文字列は`$formatInteger`と同じ形式です。" | ||||
|     }, | ||||
|     "$error": { | ||||
|         "args": "[str]", | ||||
|         "desc": "メッセージを指定して例外を送出します。メッセージ`str`を省略した場合は`$error() function evaluated`をメッセージとします。" | ||||
|     }, | ||||
|     "$assert": { | ||||
|         "args": "arg, str", | ||||
|         "desc": "`arg`が真の場合、undefinedを返します。偽の場合、`str`をメッセージとする例外を送出します。" | ||||
|     }, | ||||
|     "$single": { | ||||
|         "args": "array, function", | ||||
|         "desc": "`array`の要素のうち、条件判定関数`function`を満たす(`function`に与えた場合に真偽値`true`を返す)要素が1つのみである場合、それを返します。マッチする要素が1つのみでない場合、例外を送出します。\n\n指定する関数は`function(value [, index [, array]])`というシグネチャでなければなりません。ここで、`value`は`array`の要素値、`index`は要素の添字、第三引数には配列全体を渡します。" | ||||
|     }, | ||||
|     "$encodeUrl": { | ||||
|         "args": "str", | ||||
|         "desc": "Uniform Resource Locator (URL)を構成する文字を1、2、3、もしくは、4文字エスケープシーケンスのUTF-8文字エンコーディングで置換します。\n\n例: `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`" | ||||
|     }, | ||||
|     "$encodeUrlComponent": { | ||||
|         "args": "str", | ||||
|         "desc": "Uniform Resource Locator (URL)要素を構成する文字を1、2、3、もしくは、4文字エスケープシーケンスのUTF-8文字エンコーディングで置換します。\n\n例: `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`" | ||||
|     }, | ||||
|     "$decodeUrl": { | ||||
|         "args": "str", | ||||
|         "desc": "encodeUrlComponentで置換したUniform Resource Locator (URL)をデコードします。\n\n例: `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`" | ||||
|     }, | ||||
|     "$decodeUrlComponent": { | ||||
|         "args": "str", | ||||
|         "desc": "encodeUrlで置換したUniform Resource Locator (URL)要素をデコードします。 \n\n例: `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`" | ||||
|     }, | ||||
|     "$distinct": { | ||||
|         "args": "array", | ||||
|         "desc": "配列`array`から重複要素を削除した配列を返します。" | ||||
|     }, | ||||
|     "$type": { | ||||
|         "args": "value", | ||||
|         "desc": "`value` の型を文字列として返します。もし `value` が未定義の場合、 `undefined` が返されます。" | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -58,9 +58,6 @@ | ||||
|       "export": "내보내기", | ||||
|       "search": "플로우 겅색", | ||||
|       "searchInput": "플로우 검색", | ||||
|       "clipboard": "클립보드", | ||||
|       "library": "라이브러리", | ||||
|       "examples": "예시", | ||||
|       "subflows": "보조 플로우", | ||||
|       "createSubflow": "보조 플로우 생성", | ||||
|       "selectionToSubflow": "보조 플로우 선택", | ||||
| @@ -148,6 +145,7 @@ | ||||
|     } | ||||
|   }, | ||||
|   "clipboard": { | ||||
|     "clipboard": "클립보드", | ||||
|     "nodes": "노드", | ||||
|     "node": "__count__ 개의 노드", | ||||
|     "node_plural": "__count__ 개의 노드", | ||||
| @@ -157,7 +155,6 @@ | ||||
|     "flow_plural": "__count__ 개의 플로우", | ||||
|     "subflow": "__count__ 개의 서브 플로우", | ||||
|     "subflow_plural": "__count__ 개의 서브 플로우", | ||||
|     "selectNodes": "텍스트를 선택하고 클립보드에 복사하세요", | ||||
|     "pasteNodes": "여기에 노드를 붙여넣기 하세요", | ||||
|     "selectFile": "불러올 파일을 선택하세요", | ||||
|     "importNodes": "노드 불러오기", | ||||
| @@ -276,7 +273,6 @@ | ||||
|     "deleteSubflow": "서브 플로우 삭제", | ||||
|     "info": "상세내역", | ||||
|     "category": "카테고리", | ||||
|     "format": "Markdown 형식", | ||||
|     "errors": { | ||||
|       "noNodesSelected": "<strong>서브 플로우를 생성할 수 없습니다</strong> : 노드가 선택되지 않았습니다", | ||||
|       "multipleInputsToSelection": "<strong>서브 플로우를 생성할 수 없습니다</strong> : 복수의 입력이 선택되었습니다" | ||||
| @@ -338,22 +334,19 @@ | ||||
|     "managePalette": "팔렛트 관리" | ||||
|   }, | ||||
|   "library": { | ||||
|     "library": "라이브러리", | ||||
|     "openLibrary": "라이브러리 열기...", | ||||
|     "saveToLibrary": "라이브러리로 저장...", | ||||
|     "typeLibrary": "__type__ 라이브러리", | ||||
|     "unnamedType": "이름없는 __type__", | ||||
|     "exportToLibrary": "라이브러리로 노드 내보내기", | ||||
|     "dialogSaveOverwrite": "__libraryType__이 __libraryName__으로 이미 등록되어있습니다. 덮어쓸까요?", | ||||
|     "invalidFilename": "파일명이 올바르지 않습니다", | ||||
|     "savedNodes": "저장된 노드", | ||||
|     "savedType": "저장된 __type__", | ||||
|     "saveFailed": "저장 실패 : __message__", | ||||
|     "filename": "파일명", | ||||
|     "folder": "폴더명", | ||||
|     "filenamePlaceholder": "파일", | ||||
|     "fullFilenamePlaceholder": "a/b/file", | ||||
|     "folderPlaceholder": "a/b", | ||||
|     "breadcrumb": "라이브러리" | ||||
|     "types": { | ||||
|         "examples": "예시" | ||||
|     } | ||||
|   }, | ||||
|   "palette": { | ||||
|     "noInfo": "정보 없음", | ||||
| @@ -501,8 +494,8 @@ | ||||
|       "none": "없음", | ||||
|       "subflows": "보조 플로우", | ||||
|       "flows": "플로우", | ||||
|       "filterUnused": "미사용", | ||||
|       "filterAll": "전체", | ||||
|       "filterUnused": "미사용", | ||||
|       "filtered": "__count__ 개 숨김" | ||||
|     }, | ||||
|     "context": { | ||||
| @@ -904,4 +897,4 @@ | ||||
|     "description": "상세 내역", | ||||
|     "appearance": "모양" | ||||
|   } | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -10,7 +10,22 @@ | ||||
|             "load": "读取", | ||||
|             "save": "保存", | ||||
|             "import": "导入", | ||||
|             "export": "导出" | ||||
|             "export": "导出", | ||||
|             "back": "后退", | ||||
|             "next": "下一个", | ||||
|             "clone": "克隆项目", | ||||
|             "cont": "继续" | ||||
|         }, | ||||
|         "type": { | ||||
|             "string": "字符串", | ||||
|             "number": "数字", | ||||
|             "boolean": "布尔值", | ||||
|             "array": "数组", | ||||
|             "buffer": "buffer", | ||||
|             "object": "对象", | ||||
|             "jsonString": "JSON字符串", | ||||
|             "undefined": "未定义", | ||||
|             "null": "空" | ||||
|         } | ||||
|     }, | ||||
|     "workspace": { | ||||
| @@ -19,10 +34,13 @@ | ||||
|         "confirmDelete": "确认删除", | ||||
|         "delete": "你确定想删除 '__label__'?", | ||||
|         "dropFlowHere": "把流程放到这里", | ||||
|         "addFlow": "添加流程", | ||||
|         "listFlows": "流程一览", | ||||
|         "status": "状态", | ||||
|         "enabled": "有效", | ||||
|         "disabled": "无效", | ||||
|         "info": "详细描述" | ||||
|         "info": "详细描述", | ||||
|         "selectNodes": "点击节点来选择" | ||||
|     }, | ||||
|     "menu": { | ||||
|         "label": { | ||||
| @@ -36,11 +54,16 @@ | ||||
|                 "defaultDir": "默认方向", | ||||
|                 "ltr": "从左到右", | ||||
|                 "rtl": "从右到左", | ||||
|                 "auto": "上下文" | ||||
|                 "auto": "上下文", | ||||
|                 "language": "语言", | ||||
|                 "browserDefault": "浏览器默认" | ||||
|             }, | ||||
|             "sidebar": { | ||||
|                 "show": "显示侧边栏" | ||||
|             }, | ||||
|             "palette": { | ||||
|                 "show": "显示控制板" | ||||
|             }, | ||||
|             "settings": "设置", | ||||
|             "userSettings": "用户设置", | ||||
|             "nodes": "节点", | ||||
| @@ -50,9 +73,6 @@ | ||||
|             "export": "导出", | ||||
|             "search": "查找流程", | ||||
|             "searchInput": "查找流程", | ||||
|             "clipboard": "剪贴板", | ||||
|             "library": "库", | ||||
|             "examples": "例子", | ||||
|             "subflows": "子流程", | ||||
|             "createSubflow": "新建子流程", | ||||
|             "selectionToSubflow": "将选择部分更改为子流程", | ||||
| @@ -63,11 +83,23 @@ | ||||
|             "keyboardShortcuts": "键盘快捷方式", | ||||
|             "login": "登陆", | ||||
|             "logout": "退出", | ||||
|             "editPalette":"节点管理", | ||||
|             "editPalette": "节点管理", | ||||
|             "other": "其他", | ||||
|             "showTips": "显示小提示" | ||||
|             "showTips": "显示小提示", | ||||
|             "help": "Node-RED网页", | ||||
|             "projects": "项目", | ||||
|             "projects-new": "新建", | ||||
|             "projects-open": "打开", | ||||
|             "projects-settings": "项目设定", | ||||
|             "showNodeLabelDefault": "显示新添加的节点的标签" | ||||
|         } | ||||
|     }, | ||||
|     "actions": { | ||||
|         "toggle-navigator": "切换导航器", | ||||
|         "zoom-out": "缩小", | ||||
|         "zoom-reset": "重设缩放", | ||||
|         "zoom-in": "放大" | ||||
|     }, | ||||
|     "user": { | ||||
|         "loggedInAs": "作为__name__登陆", | ||||
|         "username": "账号", | ||||
| @@ -85,29 +117,73 @@ | ||||
|         "warning": "<strong>警告</strong>: __message__", | ||||
|         "warnings": { | ||||
|             "undeployedChanges": "节点中存在未部署的更改", | ||||
|             "nodeActionDisabled": "节点操作已禁用", | ||||
|             "nodeActionDisabledSubflow": "节点动作在子流程中被禁用", | ||||
|             "missing-types": "流程由于缺少节点类型而停止。请检查日志的详细信息", | ||||
|             "restartRequired": "Node-RED必须重新启动,以启用升级的模块" | ||||
|             "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>Error</strong>: __message__", | ||||
|         "error": "<strong>错误</strong>: __message__", | ||||
|         "errors": { | ||||
|             "lostConnection": "丢失与服务器的连接,重新连接...", | ||||
|             "lostConnectionReconnect": "丢失与服务器的连接,__time__秒后重新连接", | ||||
|             "lostConnectionTry": "现在尝试", | ||||
|             "cannotAddSubflowToItself": "无法向其自身添加子流程", | ||||
|             "cannotAddCircularReference": "无法添加子流程 - 循环引用", | ||||
|             "unsupportedVersion": "您正在使用不受支持的Node.js版本<br/>请升级到最新版本的Node.js LTS" | ||||
|             "unsupportedVersion": "您正在使用不受支持的Node.js版本<br/>请升级到最新版本的Node.js LTS", | ||||
|             "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合并完成", | ||||
|             "setupCredentials": "设定证书", | ||||
|             "setupProjectFiles": "设置项目文件", | ||||
|             "no": "不了,谢谢", | ||||
|             "createDefault": "创建默认项目文件", | ||||
|             "mergeConflict": "显示合并冲突" | ||||
|         }, | ||||
|         "label": { | ||||
|             "manage-project-dep": "管理项目依赖性", | ||||
|             "setup-cred": "设定证书", | ||||
|             "setup-project": "设置项目文件", | ||||
|             "create-default-package": "创建默认的包文件", | ||||
|             "no-thanks": "不了,谢谢", | ||||
|             "create-default-project": "创建默认项目文件", | ||||
|             "show-merge-conflicts": "显示合并冲突" | ||||
|         } | ||||
|     }, | ||||
|     "clipboard": { | ||||
|         "clipboard": "剪贴板", | ||||
|         "nodes": "节点", | ||||
|         "selectNodes": "选择上面的文本并复制到剪贴板", | ||||
|         "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__", | ||||
| @@ -117,11 +193,21 @@ | ||||
|             "all": "所有流程", | ||||
|             "compact": "紧凑", | ||||
|             "formatted": "已格式化", | ||||
|             "copy": "导出到剪贴板" | ||||
|             "copy": "导出到剪贴板", | ||||
|             "export": "到处到库", | ||||
|             "exportAs": "导出为", | ||||
|             "overwrite": "替换", | ||||
|             "exists": "<p><b>\"__file__\"</b>已存在</p><p>是否要替换它?</p>" | ||||
|         }, | ||||
|         "import": { | ||||
|             "import": "导入到", | ||||
|             "newFlow": "新流程" | ||||
|             "newFlow": "新流程", | ||||
|             "errors": { | ||||
|                 "notArray": "输入的不是JSON数组", | ||||
|                 "itemNotObject": "输入的流无效 - 项目__index__不是节点对象", | ||||
|                 "missingId": "输入的流无效-项 __index__ 缺少'id'属性", | ||||
|                 "missingType": "输入的流程无效-项__index__缺少'类型'属性" | ||||
|             } | ||||
|         }, | ||||
|         "copyMessagePath": "已复制路径", | ||||
|         "copyMessageValue": "已复制数值", | ||||
| @@ -135,7 +221,10 @@ | ||||
|         "modifiedFlowsDesc": "只部署包含已更改节点的流", | ||||
|         "modifiedNodes": "已更改的节点", | ||||
|         "modifiedNodesDesc": "只部署已经更改的节点", | ||||
|         "restartFlows": "重启流程", | ||||
|         "restartFlowsDesc": "重新启动当前部署的流程", | ||||
|         "successfulDeploy": "部署成功", | ||||
|         "successfulRestart": "成功重启流程", | ||||
|         "deployFailed": "部署失败: __message__", | ||||
|         "unusedConfigNodes": "您有一些未使用的配置节点", | ||||
|         "unusedConfigNodesLink": "点击此处查看它们", | ||||
| @@ -155,16 +244,24 @@ | ||||
|             "improperlyConfigured": "工作区包含一些未正确配置的节点:", | ||||
|             "unknown": "工作区包含一些未知的节点类型:", | ||||
|             "confirm": "你确定要部署吗?", | ||||
|             "doNotWarn": "不要再对此发出警告", | ||||
|             "conflict": "服务器正在运行较新的一组流程。", | ||||
|             "backgroundUpdate": "服务器上的流程已更新。", | ||||
|             "conflictChecking": "检查是否可以自动合并更改", | ||||
|             "conflictAutoMerge": "此更改不包括冲突,可以自动合并", | ||||
|             "conflictManualMerge": "这些更改包括了在部署之前必须解决的冲突。" | ||||
|             "conflictManualMerge": "这些更改包括了在部署之前必须解决的冲突。", | ||||
|             "plusNMore": "+ __count__更多" | ||||
|         } | ||||
|     }, | ||||
|     "eventLog": { | ||||
|         "title": "事件记录日志", | ||||
|         "view": "查看日志" | ||||
|     }, | ||||
|     "diff": { | ||||
|         "unresolvedCount": "__count__个未解决的冲突", | ||||
|         "unresolvedCount_plural": "__count__个未解决的冲突", | ||||
|         "globalNodes": "全局节点", | ||||
|         "flowProperties": "流程属性", | ||||
|         "type": { | ||||
|             "added": "已添加", | ||||
|             "changed": "已更改", | ||||
| @@ -178,9 +275,19 @@ | ||||
|         "nodeCount": "__count__个节点", | ||||
|         "nodeCount_plural": "__count__个节点", | ||||
|         "local": "本地", | ||||
|         "remote": "远程" | ||||
|         "remote": "远程", | ||||
|         "reviewChanges": "查看变更", | ||||
|         "noBinaryFileShowed": "无法显示二进制文件内容", | ||||
|         "viewCommitDiff": "查看提交更改", | ||||
|         "compareChanges": "比较变更", | ||||
|         "saveConflict": "保存冲突解决", | ||||
|         "conflictHeader": "已解决<span>__unresolved__</span>中的<span>__resolved__</span>个冲突", | ||||
|         "commonVersionError": "通用版本不包含有效的JSON:", | ||||
|         "oldVersionError": "旧版本不包含有效的JSON:", | ||||
|         "newVersionError": "新版本不包含有效的JSON:" | ||||
|     }, | ||||
|     "subflow": { | ||||
|         "editSubflowInstance": "编辑子流实例:__name__", | ||||
|         "editSubflow": "编辑流程模板: __name__", | ||||
|         "edit": "编辑流程模板", | ||||
|         "subflowInstances": "这个子流程模板有__count__个实例", | ||||
| @@ -188,8 +295,14 @@ | ||||
|         "editSubflowProperties": "编辑属性", | ||||
|         "input": "输入:", | ||||
|         "output": "输出:", | ||||
|         "status": "状态节点", | ||||
|         "deleteSubflow": "删除子流程", | ||||
|         "info": "详细描述", | ||||
|         "category": "类别", | ||||
|         "env": { | ||||
|             "restore": "恢复为默认子流", | ||||
|             "remove": "删除环境变量" | ||||
|         }, | ||||
|         "errors": { | ||||
|             "noNodesSelected": "<strong>无法创建子流程</strong>: 未选择节点", | ||||
|             "multipleInputsToSelection": "<strong>无法创建子流程</strong>: 多个输入到了选择" | ||||
| @@ -207,18 +320,68 @@ | ||||
|         "editConfig": "编辑__type__配置", | ||||
|         "addNewType": "添加新的__type__节点", | ||||
|         "nodeProperties": "节点属性", | ||||
|         "label": "标签", | ||||
|         "color": "颜色", | ||||
|         "portLabels": "端口标签", | ||||
|         "labelInputs": "输入", | ||||
|         "labelOutputs": "输出", | ||||
|         "settingIcon": "图标", | ||||
|         "default": "默认", | ||||
|         "noDefaultLabel": "无", | ||||
|         "defaultLabel": "使用默认标签", | ||||
|         "searchIcons": "搜索图标", | ||||
|         "useDefault": "使用默认", | ||||
|         "description": "描述", | ||||
|         "show": "显示", | ||||
|         "hide": "隐藏", | ||||
|         "locale": "选择界面语言", | ||||
|         "icon": "图标", | ||||
|         "inputType": "输入类型", | ||||
|         "inputs": { | ||||
|             "input": "输入", | ||||
|             "select": "选择", | ||||
|             "checkbox": "复选框", | ||||
|             "spinner": "微调器", | ||||
|             "none": "空", | ||||
|             "hidden": "隐藏属性" | ||||
|         }, | ||||
|         "types": { | ||||
|             "str": "字符串", | ||||
|             "num": "数字", | ||||
|             "bool": "布尔", | ||||
|             "json": "JSON", | ||||
|             "bin": "buffer", | ||||
|             "env": "环境变量" | ||||
|         }, | ||||
|         "menu": { | ||||
|             "input": "输入", | ||||
|             "select": "选择", | ||||
|             "checkbox": "复选框", | ||||
|             "spinner": "微调器", | ||||
|             "hidden": "仅标签" | ||||
|         }, | ||||
|         "select": { | ||||
|             "label": "标签", | ||||
|             "value": "值" | ||||
|         }, | ||||
|         "spinner": { | ||||
|             "min": "最小值", | ||||
|             "max": "最大值" | ||||
|         }, | ||||
|         "errors": { | ||||
|             "scopeChange": "更改范围将使其他流中的节点无法使用" | ||||
|             "scopeChange": "更改范围将使其他流中的节点无法使用", | ||||
|             "invalidProperties": "无效的属性:" | ||||
|         } | ||||
|     }, | ||||
|     "keyboard": { | ||||
|         "title": "键盘快捷键", | ||||
|         "keyboard": "键盘", | ||||
|         "filterActions": "筛选动作", | ||||
|         "shortcut": "快捷键", | ||||
|         "scope": "范围", | ||||
|         "unassigned": "未分配", | ||||
|         "global": "全局", | ||||
|         "workspace": "工作组", | ||||
|         "selectAll": "选择所有节点", | ||||
|         "selectAllConnected": "选择所有连接的节点", | ||||
|         "addRemoveNode": "从选择中添加/删除节点", | ||||
| @@ -229,45 +392,57 @@ | ||||
|         "nudgeNode": "移动所选节点(1px)", | ||||
|         "moveNode": "移动所选节点(20px)", | ||||
|         "toggleSidebar": "切换侧边栏", | ||||
|         "togglePalette": "切换控制板", | ||||
|         "copyNode": "复制所选节点", | ||||
|         "cutNode": "剪切所选节点", | ||||
|         "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/文件", | ||||
|         "folderPlaceholder": "a/b", | ||||
|         "breadcrumb": "库" | ||||
|         "newFolder": "新文件夹", | ||||
|         "types": { | ||||
|             "local": "本地的", | ||||
|             "examples": "例子" | ||||
|         }, | ||||
|         "exportToLibrary": "将节点导出到库" | ||||
|     }, | ||||
|     "palette": { | ||||
|         "noInfo": "无可用信息", | ||||
|         "filter": "过滤节点", | ||||
|         "search": "搜索模块", | ||||
|         "addCategory": "添加新的...", | ||||
|         "label": { | ||||
|             "subflows": "子流程", | ||||
|             "network": "网络", | ||||
|             "common": "共通", | ||||
|             "input": "输入", | ||||
|             "output": "输出", | ||||
|             "function": "功能", | ||||
|             "sequence": "序列", | ||||
|             "parser": "解析", | ||||
|             "social": "社交", | ||||
|             "storage": "存储", | ||||
|             "analysis": "分析", | ||||
|             "advanced": "高级" | ||||
|         }, | ||||
|         "actions": { | ||||
|             "collapse-all": "收起所有类别", | ||||
|             "expand-all": "展开所有类别" | ||||
|         }, | ||||
|         "event": { | ||||
|             "nodeAdded": "添加到面板中的节点:", | ||||
|             "nodeAdded_plural": "添加到面板中的多个节点", | ||||
| @@ -281,6 +456,7 @@ | ||||
|         }, | ||||
|         "editor": { | ||||
|             "title": "面板管理", | ||||
|             "palette": "控制板", | ||||
|             "times": { | ||||
|                 "seconds": "秒前", | ||||
|                 "minutes": "分前", | ||||
| @@ -314,6 +490,8 @@ | ||||
|             "updated": "已更新", | ||||
|             "install": "安装", | ||||
|             "installed": "已安装", | ||||
|             "conflict": "冲突", | ||||
|             "conflictTip": "<p>无法安装此模块,因为它包含已安装的<br/>节点类型</p><p>与<code>__module__</code>冲突</p>", | ||||
|             "loading": "加载目录...", | ||||
|             "tab-nodes": "节点", | ||||
|             "tab-install": "安装", | ||||
| @@ -361,6 +539,7 @@ | ||||
|             "label": "信息", | ||||
|             "node": "节点", | ||||
|             "type": "类型", | ||||
|             "module": "模组", | ||||
|             "id": "ID", | ||||
|             "status": "状态", | ||||
|             "enabled": "启用", | ||||
| @@ -369,17 +548,18 @@ | ||||
|             "instances": "实例", | ||||
|             "properties": "属性", | ||||
|             "info": "信息", | ||||
|             "desc": "描述", | ||||
|             "blank": "空白", | ||||
|             "null": "空", | ||||
|             "showMore": "展开", | ||||
|             "showLess": "收起", | ||||
|             "flow": "流程", | ||||
|             "selection":"选择", | ||||
|             "nodes":"__count__ 个节点", | ||||
|             "selection": "选择", | ||||
|             "nodes": "__count__ 个节点", | ||||
|             "flowDesc": "流程描述", | ||||
|             "subflowDesc": "子流程描述", | ||||
|             "nodeHelp": "节点帮助", | ||||
|             "none":"无", | ||||
|             "none": "无", | ||||
|             "arrayItems": "__count__个项目", | ||||
|             "showTips": "您可以从设置面板启用提示信息" | ||||
|         }, | ||||
| @@ -390,10 +570,26 @@ | ||||
|             "none": "无", | ||||
|             "subflows": "子流程", | ||||
|             "flows": "流程", | ||||
|             "filterUnused": "未使用", | ||||
|             "filterAll": "所有", | ||||
|             "showAllConfigNodes": "显示所有配置节点", | ||||
|             "filterUnused": "未使用", | ||||
|             "showAllUnusedConfigNodes": "显示所有未使用的配置节点", | ||||
|             "filtered": "__count__ 个隐藏" | ||||
|         }, | ||||
|         "context": { | ||||
|             "name": "上下文数据", | ||||
|             "label": "上下午", | ||||
|             "none": "未选择", | ||||
|             "refresh": "刷新以加载", | ||||
|             "empty": "空", | ||||
|             "node": "节点", | ||||
|             "flow": "流程", | ||||
|             "global": "全局", | ||||
|             "deleteConfirm": "你确定要删除这个项目吗?", | ||||
|             "autoRefresh": "刷新选择更改", | ||||
|             "refrsh": "刷新", | ||||
|             "delete": "删除" | ||||
|         }, | ||||
|         "palette": { | ||||
|             "name": "节点管理", | ||||
|             "label": "节点" | ||||
| @@ -404,8 +600,151 @@ | ||||
|             "description": "描述", | ||||
|             "dependencies": "依赖", | ||||
|             "settings": "设置", | ||||
|             "noSummaryAvailable": "无可用摘要", | ||||
|             "editDescription": "编辑项目描述", | ||||
|             "editDependencies": "编辑项目依赖" | ||||
|             "editDependencies": "编辑项目依赖", | ||||
|             "noDescriptionAvailable": "没有可用的描述", | ||||
|             "editReadme": "编辑README.md", | ||||
|             "showProjectSettings": "显示项目设置", | ||||
|             "projectSettings": { | ||||
|                 "title": "项目设置", | ||||
|                 "edit": "编辑", | ||||
|                 "none": "空", | ||||
|                 "install": "安装", | ||||
|                 "removeFromProject": "从项目中删除", | ||||
|                 "addToProject": "添加到项目", | ||||
|                 "files": "文件", | ||||
|                 "package": "包", | ||||
|                 "flow": "流程", | ||||
|                 "credentials": "证书", | ||||
|                 "packageCreate": "保存更改后将创建文件", | ||||
|                 "fileNotExist": "文件不存在", | ||||
|                 "selectFile": "选择文件", | ||||
|                 "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": "网址中不能包含用户名/密码", | ||||
|                 "noRemotes": "没有远程仓库", | ||||
|                 "deleteRemoteConfrim": "您确定要删除远程仓库'__name__'吗?", | ||||
|                 "deleteRemote": "删除远程仓库" | ||||
|             }, | ||||
|             "userSettings": { | ||||
|                 "committerDetail": "提交者详细信息", | ||||
|                 "committerTip": "保留空白以使用系统默认值", | ||||
|                 "userName": "用户名", | ||||
|                 "email": "电子邮件", | ||||
|                 "sshKeys": "SSH密钥", | ||||
|                 "sshKeysTip": "允许您创建到远程git存储库的安全连接。", | ||||
|                 "add": "添加密钥", | ||||
|                 "addSshKey": "添加SSH密钥", | ||||
|                 "addSshKeyTip": "生成新的公钥/私钥对", | ||||
|                 "name": "名字", | ||||
|                 "nameRule": "只能包含A-Z 0-9 _ -", | ||||
|                 "passphrase": "密码短语", | ||||
|                 "passphraseShort": "密码短语过短", | ||||
|                 "optional": "可选的", | ||||
|                 "cancel": "取消", | ||||
|                 "generate": "生成密钥", | ||||
|                 "noSshKeys": "没有SSH密钥", | ||||
|                 "copyPublicKey": "将公钥复制到剪贴板", | ||||
|                 "delete": "删除密钥", | ||||
|                 "gitConfig": "Git配置", | ||||
|                 "deleteConfirm": "您确定要删除SSH密钥__name__吗?这不能被撤消。" | ||||
|             }, | ||||
|             "versionControl": { | ||||
|                 "unstagedChanges": "未暂存的变更", | ||||
|                 "stagedChanges": "暂存的变更", | ||||
|                 "unstageChange": "取消变更的暂存", | ||||
|                 "stageChange": "暂存变更", | ||||
|                 "unstageAllChange": "取消所有变更的暂存", | ||||
|                 "stageAllChange": "暂存所有变更", | ||||
|                 "commitChanges": "提交变更", | ||||
|                 "resolveConflicts": "解决冲突", | ||||
|                 "head": "HEAD", | ||||
|                 "staged": "暂存的", | ||||
|                 "unstaged": "未暂存的", | ||||
|                 "local": "本地的", | ||||
|                 "remote": "远程的", | ||||
|                 "revert": "您确定要将更改恢复为'__file__'吗?这不能被撤消。", | ||||
|                 "revertChanges": "还原变更", | ||||
|                 "localChanges": "本地变更", | ||||
|                 "none": "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": "拉取", | ||||
|                 "unablePull": "<p>无法提取远程更改;您未暂存的本地更改将被覆盖。</p><p>请先提交更改,然后重试。</p>", | ||||
|                 "showUnstagedChanges": "显示未暂存的更改", | ||||
|                 "connectionFailed": "无法连接到远程存储库:", | ||||
|                 "pullUnrelatedHistory": "<p>远程有无关的提交历史</p><p>您确定要将这些更改拉入本地仓库吗?</p>", | ||||
|                 "pullChanges": "拉取更改", | ||||
|                 "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__次提交。您现在可以拉取这些提交。", | ||||
|                 "commitsBehind_plural": "您的存储库落后远程仓库__count__次提交。您现在可以拉取这些提交。", | ||||
|                 "commitsAheadAndBehind1": "您的存储库落后远程仓库__count__次提交", | ||||
|                 "commitsAheadAndBehind1_plural": "您的存储库落后远程仓库__count__次提交", | ||||
|                 "commitsAheadAndBehind2": "领先远程仓库__count__次提交。", | ||||
|                 "commitsAheadAndBehind2_plural": "领先远程仓库__count__次提交。", | ||||
|                 "commitsAheadAndBehind3": "您必须先拉取远程提交,然后才能进行推送。", | ||||
|                 "commitsAheadAndBehind3_plural": "您必须先拉取远程提交,然后才能进行推送。", | ||||
|                 "refreshCommitHistory": "刷新提交历史", | ||||
|                 "refreshChanges": "刷新更改" | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     "typedInput": { | ||||
| @@ -413,10 +752,12 @@ | ||||
|             "str": "文字列", | ||||
|             "num": "数字", | ||||
|             "re": "正则表达式", | ||||
|             "bool": "布尔", | ||||
|             "bool": "布尔值", | ||||
|             "json": "JSON", | ||||
|             "bin": "二进制流", | ||||
|             "date": "时间戳" | ||||
|             "date": "时间戳", | ||||
|             "jsonata": "表达式", | ||||
|             "env": "环境变量" | ||||
|         } | ||||
|     }, | ||||
|     "editableList": { | ||||
| @@ -428,8 +769,10 @@ | ||||
|     }, | ||||
|     "expressionEditor": { | ||||
|         "functions": "功能", | ||||
|         "functionReference": "功能reference", | ||||
|         "insert": "插入", | ||||
|         "title": "JSONata表达式编辑器", | ||||
|         "test": "测试", | ||||
|         "data": "示例消息", | ||||
|         "result": "结果", | ||||
|         "format": "格式表达方法", | ||||
| @@ -443,14 +786,229 @@ | ||||
|             "eval": "评估表达式错误:\n  __message__" | ||||
|         } | ||||
|     }, | ||||
|     "jsEditor": { | ||||
|         "title": "JavaScript编辑器" | ||||
|     }, | ||||
|     "textEditor": { | ||||
|         "title": "文本编辑器" | ||||
|     }, | ||||
|     "jsonEditor": { | ||||
|         "title": "JSON编辑器", | ||||
|         "format": "格式化JSON" | ||||
|         "format": "格式化JSON", | ||||
|         "rawMode": "编辑 JSON", | ||||
|         "uiMode": "Visual编辑器", | ||||
|         "insertAbove": "在上方插入", | ||||
|         "insertBelow": "在下方插入", | ||||
|         "addItem": "添加项目", | ||||
|         "copyPath": "复制路径到项目", | ||||
|         "expandItems": "展开项目", | ||||
|         "collapseItems": "收合项目", | ||||
|         "duplicate": "重复", | ||||
|         "error": { | ||||
|             "invalidJSON": "无效的JSON: " | ||||
|         } | ||||
|     }, | ||||
|     "markdownEditor": { | ||||
|         "title": "Markdown编辑器", | ||||
|         "expand": "展开", | ||||
|         "format": "格式化为markdown", | ||||
|         "heading1": "标题 1", | ||||
|         "heading2": "标题 2", | ||||
|         "heading3": "标题 3", | ||||
|         "bold": "粗体", | ||||
|         "italic": "斜体", | ||||
|         "code": "代码", | ||||
|         "ordered-list": "排序的列表", | ||||
|         "unordered-list": "非排序的列表", | ||||
|         "quote": "引用", | ||||
|         "link": "链接", | ||||
|         "horizontal-rule": "水平线", | ||||
|         "toggle-preview": "切换预览" | ||||
|     }, | ||||
|     "bufferEditor": { | ||||
|         "title": "缓冲区编辑器", | ||||
|         "modeString": "作为UTF-8字符串处理", | ||||
|         "modeArray": "作为JSON数组处理", | ||||
|         "modeDesc": "<h3>缓冲区编辑器</h3><p>缓冲区类型被存储为字节值的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客户端", | ||||
|         "welcome": { | ||||
|             "hello": "你好! 我们已经将“项目”引入了Node-RED。", | ||||
|             "desc0": "这是一种用于管理流程文件的新方法,并且包括对流程的版本控制。", | ||||
|             "desc1": "首先,您可以创建您的第一个项目或从git存储库克隆现有项目。", | ||||
|             "desc2": "如果不确定,可以暂时跳过此步骤。您仍然可以随时通过“项目”菜单创建第一个项目。", | ||||
|             "create": "建立专案", | ||||
|             "clone": "克隆仓库", | ||||
|             "openExistingProject": "打开现有项目", | ||||
|             "not-right-now": "不是现在" | ||||
|         }, | ||||
|         "git-config": { | ||||
|             "setup": "设置您的版本控制客户端", | ||||
|             "desc0": "Node-RED使用开源工具Git进行版本控制。它跟踪对项目文件的更改,并允许您将其推送到远程存储库。", | ||||
|             "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": "如果您已经有一个包含项目的git仓库,则可以对其进行克隆以开始使用。", | ||||
|             "already-exists": "项目已存在", | ||||
|             "must-contain": "只能包含A-Z 0-9 _ -", | ||||
|             "project-name": "项目名", | ||||
|             "no-info-in-url": "网址中不要包含用户名/密码", | ||||
|             "git-url": "Git仓库的url", | ||||
|             "protocols": "https://, ssh:// or file://", | ||||
|             "auth-failed": "认证失败", | ||||
|             "username": "用户名", | ||||
|             "passwd": "秘密啊", | ||||
|             "ssh-key": "SSH密钥", | ||||
|             "passphrase": "密码短语", | ||||
|             "ssh-key-desc": "在通过ssh克隆仓库之前,必须添加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-file": "流程文件", | ||||
|             "credentials-file": "证书文件" | ||||
|         }, | ||||
|         "encryption-config": { | ||||
|             "setup": "设置证书文件的加密", | ||||
|             "desc0": "您的流程证书文件可以被加密以确保其内容安全。", | ||||
|             "desc1": "如果要将这些证书存储在公共Git存储库中,则必须通过提供密钥短语来对它们进行加密。", | ||||
|             "desc2": "您的流程证书文件当前未加密。", | ||||
|             "desc3": "这意味着任何有权访问该文件的人都可以读取其内容,例如密码和访问令牌。", | ||||
|             "desc4": "如果要将这些证书存储在公共Git仓库中,则必须通过提供密钥短语来对它们进行加密。", | ||||
|             "desc5": "当前,使用设置文件中的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": "侧栏中的“历史记录”标签可用于查看项目中已更改的文件并提交。它向您显示了提交的完整历史记录,并允许您将更改推送到远程存储库。" | ||||
|         }, | ||||
|         "create": { | ||||
|             "projects": "项目", | ||||
|             "already-exists": "项目已存在", | ||||
|             "must-contain": "只能包含A-Z 0-9 _ -", | ||||
|             "no-info-in-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:// or file://", | ||||
|             "auth-failed": "验证失败", | ||||
|             "username": "用户名", | ||||
|             "password": "密码", | ||||
|             "ssh-key": "SSH密钥", | ||||
|             "passphrase": "密码短语", | ||||
|             "desc2": "在通过ssh克隆存储库之前,必须添加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": "属性", | ||||
|         "envProperties": "环境变量", | ||||
|         "description": "描述", | ||||
|         "appearance": "外观", | ||||
|         "preview": "UI预览", | ||||
|         "defaultValue": "默认值" | ||||
|     }, | ||||
|     "languages": { | ||||
|         "de": "德语", | ||||
|         "en-US": "英文", | ||||
|         "ja": "日语", | ||||
|         "ko": "韩文", | ||||
|         "zh-CN": "简体中文", | ||||
|         "zh-TW": "繁体中文" | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -214,5 +214,57 @@ | ||||
|     "$toMillis": { | ||||
|         "args": "timestamp", | ||||
|         "desc": "将ISO 8601格式的字符串`timestamp`转换为从UNIX时间 (1970年1月1日 UTC/GMT的午夜)开始到现在的毫秒数。如果该字符串的格式不正确,则抛出错误。" | ||||
|     }, | ||||
|     "$env": { | ||||
|         "args": "arg", | ||||
|         "desc": "返回环境变量的值。\n\n这是Node-RED定义的函数。" | ||||
|     }, | ||||
|     "$eval": { | ||||
|         "args": "expr [, context]", | ||||
|         "desc": "使用当前上下文来作为评估依据,分析并评估字符串`expr`,其中包含文字JSON或JSONata表达式。" | ||||
|     }, | ||||
|     "$formatInteger": { | ||||
|         "args": "number, picture", | ||||
|         "desc": "将“数字”转换为字符串,并将其格式化为“图片”字符串指定的整数表示形式。图片字符串参数定义了数字的格式,并具有与XPath F&O 3.1 规范中的fn:format-integer相同的语法。" | ||||
|     }, | ||||
|     "$parseInteger": { | ||||
|         "args": "string, picture", | ||||
|         "desc": "使用“图片”字符串指定的格式将“字符串”参数的内容解析为整数(作为JSON数字)。图片字符串参数与$formatInteger格式相同。." | ||||
|     }, | ||||
|     "$error": { | ||||
|         "args": "[str]", | ||||
|         "desc": "引发错误并显示一条消息。 可选的`str`将替代$error()函数评估的默认消息。" | ||||
|     }, | ||||
|     "$assert": { | ||||
|         "args": "arg, str", | ||||
|         "desc": "如果`arg`为真,则该函数返回。 如果arg为假,则抛出带有str的异常作为异常消息。" | ||||
|     }, | ||||
|     "$single": { | ||||
|         "args": "array, function", | ||||
|         "desc": "返回满足参数function谓语的array参数中的唯一值 (比如:传递值时,函数返回布尔值“true”)。如果匹配值的数量不唯一时,则抛出异常。\n\n应在以下签名中提供函数:`function(value [,index [,array []]])`其中value是数组的每个输入,index是该值的位置,整个数组作为第三个参数传递。" | ||||
|     }, | ||||
|     "$encodeUrl": { | ||||
|         "args": "str", | ||||
|         "desc": "通过用表示字符的UTF-8编码的一个,两个,三个或四个转义序列替换某些字符的每个实例,对统一资源定位符(URL)组件进行编码。\n\n示例:`$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`" | ||||
|     }, | ||||
|     "$encodeUrlComponent": { | ||||
|         "args": "str", | ||||
|         "desc": "通过用表示字符的UTF-8编码的一个,两个,三个或四个转义序列替换某些字符的每个实例,对统一资源定位符(URL)进行编码。\n\n示例: `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`" | ||||
|     }, | ||||
|     "$decodeUrl": { | ||||
|         "args": "str", | ||||
|         "desc": "解码以前由encodeUrlComponent创建的统一资源定位器(URL)组件。 \n\n示例: `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`" | ||||
|     }, | ||||
|     "$decodeUrlComponent": { | ||||
|         "args": "str", | ||||
|         "desc": "解码先前由encodeUrl创建的统一资源定位符(URL)。 \n\n示例: `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`" | ||||
|     }, | ||||
|     "$distinct": { | ||||
|         "args": "array", | ||||
|         "desc": "返回一个数组,其中重复的值已从`数组`中删除" | ||||
|     }, | ||||
|     "$type": { | ||||
|         "args": "value", | ||||
|         "desc": "以字符串形式返回`值`的类型。 如果该`值`未定义,则将返回`未定义`" | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										1015
									
								
								packages/node_modules/@node-red/editor-client/locales/zh-TW/editor.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										23
									
								
								packages/node_modules/@node-red/editor-client/locales/zh-TW/infotips.json
									
									
									
									
										vendored
									
									
										Normal 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]後按一下並拖動節點可以將該節點的多個連接一併移動到其他節點的埠。", | ||||
|         "tip11": "{{core:show-info-tab}} 可以顯示「資訊」標籤頁。 {{core:show-debug-tab}} 可以顯示「調試」標籤頁。", | ||||
|         "tip12": "按住[ctrl]的同時點擊工作介面可以在節點的對話欄中快速添加節點。", | ||||
|         "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}} 來顯示被選中節點的屬性設置畫面。" | ||||
|     } | ||||
| } | ||||
							
								
								
									
										270
									
								
								packages/node_modules/@node-red/editor-client/locales/zh-TW/jsonata.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,270 @@ | ||||
| { | ||||
|     "$string": { | ||||
|         "args": "arg", | ||||
|         "desc": "通過以下的類型轉換規則將參數*arg*轉換成字串:\n\n - 字串不轉換。\n -函數轉換成空的字串。\n - JSON的值無法用數字表示所以用無限大或者NaN(非數)表示。\n - 用’JSON.stringify’函數將其他值轉換成JSON字串。" | ||||
|     }, | ||||
|     "$length": { | ||||
|         "args": "str", | ||||
|         "desc": "輸出字串’str’的字數。如果’str’不是字串,拋出錯誤。" | ||||
|     }, | ||||
|     "$substring": { | ||||
|         "args": "str, start[, length]", | ||||
|         "desc": "輸出`start`位置後的的首次出現的包括`str`的子字串。 如果`length`被指定,那麼的字串中將只包括前`length`個文字。如果`start`是負數則輸出從`str`末尾開始的`length`個文字" | ||||
|     }, | ||||
|     "$substringBefore": { | ||||
|         "args": "str, chars", | ||||
|         "desc": "輸出’str’中首次出現的’chars’之前的子字串,如果’str’中不包括’chars’則輸出’str’。" | ||||
|     }, | ||||
|     "$substringAfter": { | ||||
|         "args": "str, chars", | ||||
|         "desc": "輸出’str’中首次出現的’chars’之後的子字串,如果’str’中不包括’chars’則輸出’str’。" | ||||
|     }, | ||||
|     "$uppercase": { | ||||
|         "args": "str", | ||||
|         "desc": "`將’str’中的所有字母變為大寫後輸出。" | ||||
|     }, | ||||
|     "$lowercase": { | ||||
|         "args": "str", | ||||
|         "desc": "將’str’中的所有字母變為小寫後輸出。" | ||||
|     }, | ||||
|     "$trim": { | ||||
|         "args": "str", | ||||
|         "desc": "將以下步驟應用於`str`來去除所有空白文字並實現標準化。\n\n – 將全部tab定位字元、Enter鍵、換行字元用空白代替。\n- 將連續的空白文字變成一個空白文字。\n- 消除開頭和末尾的空白文字。\n\n如果`str`沒有被指定(即在無輸入參數的情況下調用本函數),將上下文的值作為`str`來使用。 如果`str` 不是字串則拋出錯誤。" | ||||
|     }, | ||||
|     "$contains": { | ||||
|         "args": "str, pattern", | ||||
|         "desc": "字串`str` 和 `pattern`匹配的話輸出`true`,不匹配的情況下輸出 `false`。 不指定`str`的情況下(比如用一個參數調用本函數時)、將上下文的值作為`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`的值小的最大整數。" | ||||
|     }, | ||||
|     "$ceil": { | ||||
|         "args": "number", | ||||
|         "desc": "輸出比`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時間 (1970年1月1日 UTC/GMT的午夜)開始到現在的毫秒數。在同一個運算式的測試中所有對`$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": "用下述規則將資料轉換成布林值。:\n\n - 不轉換布林值`Boolean`。\n – 將空的字串`string`轉換為`false`\n – 將不為空的字串`string`轉換為`true`\n – 將為0的數位`number`轉換成`false`\n –將不為0的數位`number`轉換成`true`\n –將`null`轉換成`false`\n –將空的陣列`array`轉換成`false`\n –如果陣列`array`中含有可以轉換成`true`的要素則轉換成`true`\n –如果`array`中沒有可轉換成`true`的要素則轉換成`false`\n – 空的物件`object`轉換成`false`\n – 非空的物件`object`轉換成`true`\n –將函數`function`轉換成`false`" | ||||
|     }, | ||||
|     "$not": { | ||||
|         "args": "arg", | ||||
|         "desc": "輸出做反轉運算後的布林值。首先將`arg`轉換為布林值。" | ||||
|     }, | ||||
|     "$exists": { | ||||
|         "args": "arg", | ||||
|         "desc": "如果算式`arg`的值存在則輸出`true`。如果算式的值不存在(比如指向不存在區域的引用)則輸出`false`。" | ||||
|     }, | ||||
|     "$count": { | ||||
|         "args": "array", | ||||
|         "desc": "輸出陣列中的元素數。" | ||||
|     }, | ||||
|     "$append": { | ||||
|         "args": "array, array", | ||||
|         "desc": "將兩個陣列連接。" | ||||
|     }, | ||||
|     "$sort": { | ||||
|         "args": "array [, function]", | ||||
|         "desc": "輸出排序後的陣列`array`。\n\n如果使用了比較函數`function`,則下述兩個參數需要被指定。\n\n`function(left, right)`\n\n該比較函數是為了比較left和right兩個值而被排序演算法調用的。如果使用者希望left的值被置於right的值之後,那麼該函數必須輸出布林值`true`來表示位置交換。而在不需要位置交換時函數必須輸出`false`。" | ||||
|     }, | ||||
|     "$reverse": { | ||||
|         "args": "array", | ||||
|         "desc": "輸出倒序後的陣列`array`。" | ||||
|     }, | ||||
|     "$shuffle": { | ||||
|         "args": "array", | ||||
|         "desc": "輸出隨機排序後的陣列 `array`。" | ||||
|     }, | ||||
|     "$zip": { | ||||
|         "args": "array, ...", | ||||
|         "desc": "將陣列中的值按索引順序打包後輸出。" | ||||
|     }, | ||||
|     "$keys": { | ||||
|         "args": "object", | ||||
|         "desc": "輸出由物件內的鍵組成的陣列。如果參數是物件的陣列則輸出由所有物件中的鍵去重後組成的佇列。" | ||||
|     }, | ||||
|     "$lookup": { | ||||
|         "args": "object, key", | ||||
|         "desc": "輸出對象中與參數`key`對應的值。如果第一個參數`object`是陣列,那麼陣列中所有的物件都將被搜索並輸出這些物件中與參數`key`對應的值。" | ||||
|     }, | ||||
|     "$spread": { | ||||
|         "args": "object", | ||||
|         "desc": "將物件中的鍵值對分隔成每個要素中只含有一個鍵值對的陣列。如果參數`object`是陣列,那麼返回值的陣列中包含所有物件中的鍵值對。" | ||||
|     }, | ||||
|     "$merge": { | ||||
|         "args": "array<object>", | ||||
|         "desc": "將輸入陣列`objects`中所有的鍵值對合併到一個`object`中並返回。如果輸入陣列的要素中含有重複的鍵,則返回的`object`中將只包含陣列中最後出現要素的值。如果輸入陣列中包括物件以外的元素,則拋出錯誤。" | ||||
|     }, | ||||
|     "$sift": { | ||||
|         "args": "object, function", | ||||
|         "desc": "輸出參數`object`中符合`function`的鍵值對。\n\n`function`必須含有下述參數。\n\n`function(value [, key [, object]])`" | ||||
|     }, | ||||
|     "$each": { | ||||
|         "args": "object, function", | ||||
|         "desc": "將函數`function`應用於`object`中的所有鍵值對並輸出由所有返回值組成的陣列。" | ||||
|     }, | ||||
|     "$map": { | ||||
|         "args": "array, function", | ||||
|         "desc": "將函數`function`應用於陣列`array`中所有的值並輸出由返回值組成的陣列。\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`依次應用於陣列中的各要素值。 其中,前一個要素值的計算結果將參與到下一次的函數運算中。。\n\n函數`function`接受兩個參數並作為中綴標記法中的操作符。\n\n可省略的參數`init`將作為運算的初始值。" | ||||
|     }, | ||||
|     "$flowContext": { | ||||
|         "args": "string", | ||||
|         "desc": "獲取流上下文(流等級的上下文,可以讓所有節點共用)的屬性。" | ||||
|     }, | ||||
|     "$globalContext": { | ||||
|         "args": "string", | ||||
|         "desc": "獲取全域上下文的屬性。" | ||||
|     }, | ||||
|     "$pad": { | ||||
|         "args": "string, width [, char]", | ||||
|         "desc": "根據需要,向字串`string`的副本中填充文字使該字串的字數達到`width`的絕對值並返回填充文字後的字串。\n\n如果`width`的值為正,則向字串`string`的右側填充文字,如果`width`為負,則向字串`string`的左側填充文字。\n\n可選參數`char`用來指定填充的文字。如果未指定該參數,則填充空白文字。" | ||||
|     }, | ||||
|     "$fromMillis": { | ||||
|         "args": "number", | ||||
|         "desc": "將表示從UNIX時間 (1970年1月1日 UTC/GMT的午夜)開始到現在的毫秒數的數值轉換成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可選的第三參數`options`用來覆蓋預設的局部環境格式,如小數點分隔符號。如果指定該參數,那麼該參數必須是包含name/value對的物件,並且name/value對必須符合XPath F&O 3.1規格中記述的數值格式。" | ||||
|     }, | ||||
|     "$formatBase": { | ||||
|         "args": "number [, radix]", | ||||
|         "desc": "將`number`變換為以參數`radix`的值為基數形式的字串。如果不指定`radix`的值,則默認基數為10。指定的`radix`值必須在2~36之間,否則拋出錯誤。" | ||||
|     }, | ||||
|     "$toMillis": { | ||||
|         "args": "timestamp", | ||||
|         "desc": "將ISO 8601格式的字串`timestamp`轉換為從UNIX時間 (1970年1月1日 UTC/GMT的午夜)開始到現在的毫秒數。如果該字串的格式不正確,則拋出錯誤。" | ||||
|     }, | ||||
|     "$env": { | ||||
|         "args": "arg", | ||||
|         "desc": "返回環境變量的值。\n\n這是Node-RED定義的函數。" | ||||
|     }, | ||||
|     "$eval": { | ||||
|         "args": "expr [, context]", | ||||
|         "desc": "使用當前上下文來作為評估依據,分析並評估字符串`expr`,其中包含文字JSON或JSONata表達式。" | ||||
|     }, | ||||
|     "$formatInteger": { | ||||
|         "args": "number, picture", | ||||
|         "desc": "將“數字”轉換為字符串,並將其格式化為“圖片”字符串指定的整數表示形式。圖片字符串參數定義了數字的格式,並具有與XPath F&O 3.1 規範中的fn:format-integer相同的語法。" | ||||
|     }, | ||||
|     "$parseInteger": { | ||||
|         "args": "string, picture", | ||||
|         "desc": "使用“圖片”字符串指定的格式將“字符串”參數的內容解析為整數(作為JSON數字)。圖片字符串參數與$formatInteger格式相同。." | ||||
|     }, | ||||
|     "$error": { | ||||
|         "args": "[str]", | ||||
|         "desc": "引發錯誤並顯示一條消息。 可選的`str`將替代$error()函數評估的默認消息。" | ||||
|     }, | ||||
|     "$assert": { | ||||
|         "args": "arg, str", | ||||
|         "desc": "如果`arg`為真,則該函數返回。 如果arg為假,則拋出帶有str的異常作為異常消息。" | ||||
|     }, | ||||
|     "$single": { | ||||
|         "args": "array, function", | ||||
|         "desc": "返回滿足參數function謂語的array參數中的唯一值 (比如:傳遞值時,函數返回布林值“true”)。如果匹配值的數量不唯一時,則拋出異常。\n\n應在以下簽名中提供函數:`function(value [,index [,array []]])`其中value是數組的每個輸入,index是該值的位置,整個數組作為第三個參數傳遞。" | ||||
|     }, | ||||
|     "$encodeUrl": { | ||||
|         "args": "str", | ||||
|         "desc": "通過用表示字符的UTF-8編碼的一個,兩個,三個或四個轉義序列替換某些字符的每個實例,對統一資源定位符(URL)組件進行編碼。\n\n示例:`$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`" | ||||
|     }, | ||||
|     "$encodeUrlComponent": { | ||||
|         "args": "str", | ||||
|         "desc": "通過用表示字符的UTF-8編碼的一個,兩個,三個或四個轉義序列替換某些字符的每個實例,對統一資源定位符(URL)進行編碼。\n\n示例: `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`" | ||||
|     }, | ||||
|     "$decodeUrl": { | ||||
|         "args": "str", | ||||
|         "desc": "解碼以前由encodeUrlComponent創建的統一資源定位器(URL)組件。 \n\n示例: `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`" | ||||
|     }, | ||||
|     "$decodeUrlComponent": { | ||||
|         "args": "str", | ||||
|         "desc": "解碼先前由encodeUrl創建的統一資源定位符(URL)。 \n\n示例: `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`" | ||||
|     }, | ||||
|     "$distinct": { | ||||
|         "args": "array", | ||||
|         "desc": "返回一個數組,其中重復的值已從`數組`中刪除" | ||||
|     }, | ||||
|     "$type": { | ||||
|         "args": "value", | ||||
|         "desc": "以字符串形式返回`值`的類型。 如果該`值`未定義,則將返回`未定義`" | ||||
|     } | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@node-red/editor-client", | ||||
|     "version": "0.20.3", | ||||
|     "version": "1.1.0-beta.1", | ||||
|     "license": "Apache-2.0", | ||||
|     "repository": { | ||||
|         "type": "git", | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| ace.define("ace/snippets/nrjavascript",[],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="nrjavascript"}); | ||||
| ace.define("ace/snippets/nrjavascript",[],function(e,t,n){"use strict";t.snippetText='# Prototype\nsnippet proto\n	${1:class_name}.prototype.${2:method_name} = function(${3:first_argument}) {\n		${4:// body...}\n	};\n# Function\nsnippet fun\n	function ${1?:function_name}(${2:argument}) {\n		${3:// body...}\n	}\n# Anonymous Function\nregex /((=)\\s*|(:)\\s*|(\\()|\\b)/f/(\\))?/\nsnippet f\n	function${M1?: ${1:functionName}}($2) {\n		${0:$TM_SELECTED_TEXT}\n	}${M2?;}${M3?,}${M4?)}\n# Immediate function\ntrigger \\(?f\\(\nendTrigger \\)?\nsnippet f(\n	(function(${1}) {\n		${0:${TM_SELECTED_TEXT:/* code */}}\n	}(${1}));\n# if\nsnippet if\n	if (${1:true}) {\n		${0}\n	}\n# if ... else\nsnippet ife\n	if (${1:true}) {\n		${2}\n	} else {\n		${0}\n	}\n# tertiary conditional\nsnippet ter\n	${1:/* condition */} ? ${2:a} : ${3:b}\n# switch\nsnippet switch\n	switch (${1:expression}) {\n		case \'${3:case}\':\n			${4:// code}\n			break;\n		${5}\n		default:\n			${2:// code}\n	}\n# case\nsnippet case\n	case \'${1:case}\':\n		${2:// code}\n		break;\n	${3}\n\n# while (...) {...}\nsnippet wh\n	while (${1:/* condition */}) {\n		${0:/* code */}\n	}\n# try\nsnippet try\n	try {\n		${0:/* code */}\n	} catch (e) {}\n# do...while\nsnippet do\n	do {\n		${2:/* code */}\n	} while (${1:/* condition */});\n# Object Method\nsnippet :f\nregex /([,{[])|^\\s*/:f/\n	${1:method_name}: function(${2:attribute}) {\n		${0}\n	}${3:,}\n# setTimeout function\nsnippet setTimeout\nregex /\\b/st|timeout|setTimeo?u?t?/\n	setTimeout(function() {${3:$TM_SELECTED_TEXT}}, ${1:10});\n# console.log (Firebug)\nsnippet cl\n	console.log(${1});\n# return\nsnippet ret\n	return ${1:result}\n# for (property in object ) { ... }\nsnippet fori\n	for (var ${1:prop} in ${2:Things}) {\n		${0:$2[$1]}\n	}\n# hasOwnProperty\nsnippet has\n	hasOwnProperty(${1})\n# docstring\nsnippet /**\n	/**\n	 * ${1:description}\n	 *\n	 */\nsnippet @par\nregex /^\\s*\\*\\s*/@(para?m?)?/\n	@param {${1:type}} ${2:name} ${3:description}\nsnippet @ret\n	@return {${1:type}} ${2:description}\n# JSON.parse\nsnippet jsonp\n	JSON.parse(${1:jstr});\n# JSON.stringify\nsnippet jsons\n	JSON.stringify(${1:object});\n# self-defining function\nsnippet sdf\n	var ${1:function_name} = function(${2:argument}) {\n		${3:// initial code ...}\n\n		$1 = function($2) {\n			${4:// main code}\n		};\n	}\n# \nsnippet for-\n	for (var ${1:i} = ${2:Things}.length; ${1:i}--; ) {\n		${0:${2:Things}[${1:i}];}\n	}\n# for (...) {...}\nsnippet for\n	for (var ${1:i} = 0; $1 < ${2:Things}.length; $1++) {\n		${3:$2[$1]}$0\n	}\n# for (...) {...} (Improved Native For-Loop)\nsnippet forr\n	for (var ${1:i} = ${2:Things}.length - 1; $1 >= 0; $1--) {\n		${3:$2[$1]}$0\n	}\n# Node-RED Specific Funcs\nsnippet nodes\n	node.send(${1:msg})\nsnippet clone\n	RED.util.cloneMessage(${1:msg})\nsnippet nodel\n	node.log($1)\nsnippet nodew\n	node.warn($1)\nsnippet nodee\n	node.error($1)\nsnippet noded\n	node.debug($1)\nsnippet done\n	node.done($1)\nsnippet flowg\n	flow.get($1)\nsnippet flows\n	flow.set($1, $2)\nsnippet globalg\n	global.get($1)\nsnippet globals\n	global.set($1, $2)\n',t.scope="nrjavascript"}); | ||||
|                 (function() { | ||||
|                     ace.require(["ace/snippets/nrjavascript"], function(m) { | ||||
|                         if (typeof module == "object" && typeof exports == "object" && module) { | ||||
| @@ -6,4 +6,3 @@ ace.define("ace/snippets/nrjavascript",[],function(e,t,n){"use strict";t.snippet | ||||
|                         } | ||||
|                     }); | ||||
|                 })(); | ||||
|              | ||||
| 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); | ||||
|   | ||||
| @@ -32,14 +32,19 @@ | ||||
|              } | ||||
|          } | ||||
|      } | ||||
|      function emit(evt,arg) { | ||||
|      function emit() { | ||||
|          var evt = arguments[0] | ||||
|          var args = Array.prototype.slice.call(arguments,1); | ||||
|          if (RED.events.DEBUG) { | ||||
|              console.warn(evt,args); | ||||
|          } | ||||
|          if (handlers[evt]) { | ||||
|              for (var i=0;i<handlers[evt].length;i++) { | ||||
|                  try { | ||||
|                      handlers[evt][i](arg); | ||||
|                      handlers[evt][i].apply(null, args); | ||||
|                  } catch(err) { | ||||
|                      console.log("RED.events.emit error: ["+evt+"] "+(err.toString())); | ||||
|                      console.log(err); | ||||
|                      console.warn("RED.events.emit error: ["+evt+"] "+(err.toString())); | ||||
|                      console.warn(err); | ||||
|                  } | ||||
|              } | ||||
|  | ||||
|   | ||||
| @@ -14,60 +14,110 @@ | ||||
|  * limitations under the License. | ||||
|  **/ | ||||
| RED.history = (function() { | ||||
|     var undo_history = []; | ||||
|     var undoHistory = []; | ||||
|     var redoHistory = []; | ||||
|  | ||||
|     function undoEvent(ev) { | ||||
|         var i; | ||||
|         var len; | ||||
|         var node; | ||||
|         var group; | ||||
|         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 (node.g) { | ||||
|                             var group = RED.nodes.group(node.g); | ||||
|                             var index = group.nodes.indexOf(node); | ||||
|                             if (index !== -1) { | ||||
|                                 group.nodes.splice(index,1); | ||||
|                                 RED.group.markDirty(group); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 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.groups) { | ||||
|                     inverseEv.groups = []; | ||||
|                     for (i=0;i<ev.groups.length;i++) { | ||||
|                         group = ev.groups[i]; | ||||
|                         modifiedTabs[group.z] = true; | ||||
|                         // The order of groups is important | ||||
|                         //  - to invert the action, the order is reversed | ||||
|                         inverseEv.groups.unshift(group); | ||||
|                         RED.nodes.removeGroup(group); | ||||
|                     } | ||||
|                 } | ||||
|                 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 +133,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 +185,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; | ||||
| @@ -144,22 +206,60 @@ RED.history = (function() { | ||||
|                     RED.nodes.filterNodes({type:"subflow:"+subflow.id}).forEach(function(n) { | ||||
|                         n.inputs = subflow.in.length; | ||||
|                         n.outputs = subflow.out.length; | ||||
|                         while (n.outputs > n.ports.length) { | ||||
|                             n.ports.push(n.ports.length); | ||||
|                         } | ||||
|                         n.resize = true; | ||||
|                         n.dirty = true; | ||||
|                     }); | ||||
|                 } | ||||
|                 if (ev.groups) { | ||||
|                     inverseEv.groups = []; | ||||
|                     var groupsToAdd = {}; | ||||
|                     ev.groups.forEach(function(g) { groupsToAdd[g.id] = g; }); | ||||
|                     for (i=0;i<ev.groups.length;i++) { | ||||
|                         RED.nodes.addGroup(ev.groups[i]) | ||||
|                         modifiedTabs[ev.groups[i].z] = true; | ||||
|                         // The order of groups is important | ||||
|                         //  - to invert the action, the order is reversed | ||||
|                         inverseEv.groups.unshift(ev.groups[i]); | ||||
|                         if (ev.groups[i].g) { | ||||
|                             if (!groupsToAdd[ev.groups[i].g]) { | ||||
|                                 group = RED.nodes.group(ev.groups[i].g); | ||||
|                             } else { | ||||
|                                 group = groupsToAdd[ev.groups[i].g]; | ||||
|                             } | ||||
|                             if (group.nodes.indexOf(ev.groups[i]) === -1) { | ||||
|                                 group.nodes.push(ev.groups[i]); | ||||
|                             } | ||||
|                             RED.group.markDirty(ev.groups[i]) | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 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.nodes[i].g) { | ||||
|                             group = RED.nodes.group(ev.nodes[i].g); | ||||
|                             if (group.nodes.indexOf(ev.nodes[i]) === -1) { | ||||
|                                 group.nodes.push(ev.nodes[i]); | ||||
|                             } | ||||
|                             RED.group.markDirty(group) | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 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) { | ||||
| @@ -174,13 +274,22 @@ RED.history = (function() { | ||||
|                                 } | ||||
|                                 node.dirty = true; | ||||
|                             } | ||||
|                             RED.events.emit("nodes:change",node); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                 } | ||||
|                 if (subflow) { | ||||
|                     RED.events.emit("subflows:change", subflow); | ||||
|                 } | ||||
|             } 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,49 +297,90 @@ 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]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.addToGroup) { | ||||
|                     RED.group.removeFromGroup(ev.addToGroup,ev.nodes.map(function(n) { return n.n }),false); | ||||
|                     inverseEv.removeFromGroup = ev.addToGroup; | ||||
|                 } else if (ev.removeFromGroup) { | ||||
|                     RED.group.addToGroup(ev.removeFromGroup,ev.nodes.map(function(n) { return n.n })); | ||||
|                     inverseEv.addToGroup = ev.removeFromGroup; | ||||
|                 } | ||||
|             } 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]); | ||||
|                             if (currentConfigNode) { | ||||
|                                 currentConfigNode.users.splice(currentConfigNode.users.indexOf(ev.node),1); | ||||
|                                 RED.events.emit("nodes:change",currentConfigNode); | ||||
|                             } | ||||
|                             var newConfigNode = RED.nodes.node(ev.changes[i]); | ||||
|                             if (newConfigNode) { | ||||
|                                 newConfigNode.users.push(ev.node); | ||||
|                                 RED.events.emit("nodes:change",newConfigNode); | ||||
|                             } | ||||
|                         } | ||||
|                         ev.node[i] = ev.changes[i]; | ||||
|                     } | ||||
|                 } | ||||
|                 var eventType; | ||||
|                 switch(ev.node.type) { | ||||
|                     case 'tab': eventType = "flows"; break; | ||||
|                     case 'group': eventType = "groups"; break; | ||||
|                     case 'subflow': eventType = "subflows"; break; | ||||
|                     default: eventType = "nodes"; break; | ||||
|                 } | ||||
|                 eventType += ":change"; | ||||
|                 RED.events.emit(eventType,ev.node); | ||||
|  | ||||
|  | ||||
|                 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,52 +404,185 @@ 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; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     ev.node.__outputs = inverseEv.changes.outputs; | ||||
|                     RED.editor.updateNodeProperties(ev.node,outputMap); | ||||
|                     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) { | ||||
|                     RED.nodes.filterNodes({z:ev.subflow.subflow.id}).forEach(function(n) { | ||||
|                     inverseEv.movedNodes = []; | ||||
|                     var z = ev.activeWorkspace; | ||||
|                     var fullNodeList = RED.nodes.filterNodes({z:ev.subflow.subflow.id}); | ||||
|                     fullNodeList = fullNodeList.concat(RED.nodes.groups(ev.subflow.subflow.id)) | ||||
|                     fullNodeList.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.subflow.subflow.g) { | ||||
|                         RED.group.addToGroup(RED.nodes.group(ev.subflow.subflow.g),ev.subflow.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); | ||||
|                         if (!nn) { | ||||
|                             nn = RED.nodes.group(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); | ||||
|                 } | ||||
|             } else if (ev.t == "createGroup") { | ||||
|                 inverseEv = { | ||||
|                     t: "ungroup", | ||||
|                     dirty: RED.nodes.dirty(), | ||||
|                     groups: [] | ||||
|                 } | ||||
|                 if (ev.groups) { | ||||
|                     for (i=0;i<ev.groups.length;i++) { | ||||
|                         inverseEv.groups.push(ev.groups[i]); | ||||
|                         RED.group.ungroup(ev.groups[i]); | ||||
|                     } | ||||
|                 } | ||||
|             } else if (ev.t == "ungroup") { | ||||
|                 inverseEv = { | ||||
|                     t: "createGroup", | ||||
|                     dirty: RED.nodes.dirty(), | ||||
|                     groups: [] | ||||
|                 } | ||||
|                 if (ev.groups) { | ||||
|                     for (i=0;i<ev.groups.length;i++) { | ||||
|                         inverseEv.groups.push(ev.groups[i]); | ||||
|                         var nodes = ev.groups[i].nodes.slice(); | ||||
|                         ev.groups[i].nodes = []; | ||||
|                         RED.nodes.addGroup(ev.groups[i]); | ||||
|                         RED.group.addToGroup(ev.groups[i],nodes); | ||||
|                     } | ||||
|                 } | ||||
|             } else if (ev.t == "addToGroup") { | ||||
|                 inverseEv = { | ||||
|                     t: "removeFromGroup", | ||||
|                     dirty: RED.nodes.dirty(), | ||||
|                     group: ev.group, | ||||
|                     nodes: ev.nodes, | ||||
|                     reparent: ev.reparent | ||||
|                 } | ||||
|                 if (ev.nodes) { | ||||
|                     RED.group.removeFromGroup(ev.group,ev.nodes,(ev.hasOwnProperty('reparent')&&ev.hasOwnProperty('reparent')!==undefined)?ev.reparent:true); | ||||
|                 } | ||||
|             } else if (ev.t == "removeFromGroup") { | ||||
|                 inverseEv = { | ||||
|                     t: "addToGroup", | ||||
|                     dirty: RED.nodes.dirty(), | ||||
|                     group: ev.group, | ||||
|                     nodes: ev.nodes, | ||||
|                     reparent: ev.reparent | ||||
|                 } | ||||
|                 if (ev.nodes) { | ||||
|                     RED.group.addToGroup(ev.group,ev.nodes); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if(ev.callback && typeof ev.callback === 'function') { | ||||
|                 inverseEv.callback = ev.callback; | ||||
|                 ev.callback(ev); | ||||
|             } | ||||
|  | ||||
|             Object.keys(modifiedTabs).forEach(function(id) { | ||||
| @@ -310,12 +593,13 @@ RED.history = (function() { | ||||
|             }); | ||||
|  | ||||
|             RED.nodes.dirty(ev.dirty); | ||||
|             RED.view.updateActive(); | ||||
|             RED.view.select(null); | ||||
|             RED.view.redraw(true); | ||||
|             RED.palette.refresh(); | ||||
|             RED.workspaces.refresh(); | ||||
|             RED.sidebar.config.refresh(); | ||||
|             RED.subflow.refresh(); | ||||
|  | ||||
|             return inverseEv; | ||||
|         } | ||||
|  | ||||
|     } | ||||
| @@ -323,28 +607,45 @@ 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; | ||||
|         }, | ||||
|         listRedo: function() { | ||||
|             return redoHistory; | ||||
|         }, | ||||
|         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,6 +1,6 @@ | ||||
| { | ||||
|     "*": { | ||||
|         "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", | ||||
| @@ -8,6 +8,7 @@ | ||||
|         "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", | ||||
| @@ -17,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", | ||||
| @@ -37,8 +41,17 @@ | ||||
|         "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", | ||||
|         "w": "core:scroll-view-up", | ||||
|         "d": "core:scroll-view-right", | ||||
|         "s": "core:scroll-view-down", | ||||
|         "a": "core:scroll-view-left", | ||||
|         "shift-w": "core:step-view-up", | ||||
|         "shift-d": "core:step-view-right", | ||||
|         "shift-s": "core:step-view-down", | ||||
|         "shift-a": "core:step-view-left", | ||||
|         "up": "core:move-selection-up", | ||||
|         "right": "core:move-selection-right", | ||||
|         "down": "core:move-selection-down", | ||||
| @@ -48,6 +61,10 @@ | ||||
|         "shift-down": "core:step-selection-down", | ||||
|         "shift-left": "core:step-selection-left", | ||||
|         "ctrl-shift-j": "core:show-previous-tab", | ||||
|         "ctrl-shift-k": "core:show-next-tab" | ||||
|         "ctrl-shift-k": "core:show-next-tab", | ||||
|         "ctrl-shift-g": "core:group-selection", | ||||
|         "ctrl-shift-u": "core:ungroup-selection", | ||||
|         "ctrl-shift-c": "core:copy-group-style", | ||||
|         "ctrl-shift-v": "core:paste-group-style" | ||||
|      } | ||||
| } | ||||
|   | ||||
| @@ -17,6 +17,8 @@ RED.nodes = (function() { | ||||
|  | ||||
|     var node_defs = {}; | ||||
|     var nodes = []; | ||||
|     var nodeTabMap = {}; | ||||
|  | ||||
|     var configNodes = {}; | ||||
|     var links = []; | ||||
|     var defaultWorkspace; | ||||
| @@ -25,13 +27,16 @@ RED.nodes = (function() { | ||||
|     var subflows = {}; | ||||
|     var loadedFlowVersion = null; | ||||
|  | ||||
|     var groups = {}; | ||||
|     var groupsByZ = {}; | ||||
|  | ||||
|     var initialLoad; | ||||
|  | ||||
|     var dirty = false; | ||||
|  | ||||
|     function setDirty(d) { | ||||
|         dirty = d; | ||||
|         RED.events.emit("nodes:change",{dirty:dirty}); | ||||
|         RED.events.emit("workspace:dirty",{dirty:dirty}); | ||||
|     } | ||||
|  | ||||
|     var registry = (function() { | ||||
| @@ -191,18 +196,17 @@ RED.nodes = (function() { | ||||
|         if (n.type.indexOf("subflow") !== 0) { | ||||
|             n["_"] = n._def._; | ||||
|         } else { | ||||
|             var subflowId = n.type.substring(8); | ||||
|             var sf = RED.nodes.subflow(subflowId); | ||||
|             if (sf) { | ||||
|                 sf.instances.push(sf); | ||||
|             } | ||||
|             n["_"] = RED._; | ||||
|         } | ||||
|         if (n._def.category == "config") { | ||||
|             configNodes[n.id] = n; | ||||
|         } else { | ||||
|             n.ports = []; | ||||
|             if (n.wires && (n.wires.length > n.outputs)) { n.outputs = n.wires.length; } | ||||
|             if (n.outputs) { | ||||
|                 for (var i=0;i<n.outputs;i++) { | ||||
|                     n.ports.push(i); | ||||
|                 } | ||||
|             } | ||||
|             n.dirty = true; | ||||
|             updateConfigNodeUsers(n); | ||||
|             if (n._def.category == "subflows" && typeof n.i === "undefined") { | ||||
| @@ -213,11 +217,17 @@ 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); | ||||
|     } | ||||
|     function addLink(l) { | ||||
|         links.push(l); | ||||
|         RED.events.emit("links:add",l); | ||||
|     } | ||||
|  | ||||
|     function getNode(id) { | ||||
| @@ -246,8 +256,11 @@ 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); }); | ||||
|                 removedLinks.forEach(removeLink); | ||||
|                 var updatedConfigNode = false; | ||||
|                 for (var d in node._def.defaults) { | ||||
|                     if (node._def.defaults.hasOwnProperty(d)) { | ||||
| @@ -270,6 +283,15 @@ RED.nodes = (function() { | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 if (node.type.indexOf("subflow:") === 0) { | ||||
|                     var subflowId = node.type.substring(8); | ||||
|                     var sf = RED.nodes.subflow(subflowId); | ||||
|                     if (sf) { | ||||
|                         sf.instances.splice(sf.instances.indexOf(node),1); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 if (updatedConfigNode) { | ||||
|                     RED.workspaces.refresh(); | ||||
|                 } | ||||
| @@ -283,6 +305,9 @@ RED.nodes = (function() { | ||||
|                 RED.events.emit('nodes:remove',node); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|  | ||||
|  | ||||
|         if (node && node._def.onremove) { | ||||
|             // Deprecated: never documented but used by some early nodes | ||||
|             console.log("Deprecated API warning: node type ",node.type," has an onremove function - should be oneditremove - please report"); | ||||
| @@ -291,52 +316,105 @@ RED.nodes = (function() { | ||||
|         return {links:removedLinks,nodes:removedNodes}; | ||||
|     } | ||||
|  | ||||
|     function moveNodeToTab(node, z) { | ||||
|         if (node.type === "group") { | ||||
|             moveGroupToTab(node,z); | ||||
|             return; | ||||
|         } | ||||
|         if (nodeTabMap[node.z]) { | ||||
|             delete nodeTabMap[node.z][node.id]; | ||||
|         } | ||||
|         if (!nodeTabMap[z]) { | ||||
|             nodeTabMap[z] = {}; | ||||
|         } | ||||
|         nodeTabMap[z][node.id] = node; | ||||
|         node.z = z; | ||||
|         RED.events.emit("nodes:change",node); | ||||
|     } | ||||
|     function moveGroupToTab(group, z) { | ||||
|         var index = groupsByZ[group.z].indexOf(group); | ||||
|         groupsByZ[group.z].splice(index,1); | ||||
|         groupsByZ[z] = groupsByZ[z] || []; | ||||
|         groupsByZ[z].push(group); | ||||
|         group.z = z; | ||||
|         RED.events.emit("groups:change",group); | ||||
|     } | ||||
|  | ||||
|     function removeLink(l) { | ||||
|         var index = links.indexOf(l); | ||||
|         if (index != -1) { | ||||
|             links.splice(index,1); | ||||
|         } | ||||
|         RED.events.emit("links:remove",l); | ||||
|     } | ||||
|  | ||||
|     function addWorkspace(ws,targetIndex) { | ||||
|         workspaces[ws.id] = ws; | ||||
|         nodeTabMap[ws.id] = {}; | ||||
|  | ||||
|         ws._def = RED.nodes.getType('tab'); | ||||
|         if (targetIndex === undefined) { | ||||
|             workspacesOrder.push(ws.id); | ||||
|         } else { | ||||
|             workspacesOrder.splice(targetIndex,0,ws.id); | ||||
|         } | ||||
|         RED.events.emit('flows:add',ws); | ||||
|         if (targetIndex !== undefined) { | ||||
|             RED.events.emit('flows:reorder',workspacesOrder) | ||||
|         } | ||||
|     } | ||||
|     function getWorkspace(id) { | ||||
|         return workspaces[id]; | ||||
|     } | ||||
|     function removeWorkspace(id) { | ||||
|         delete workspaces[id]; | ||||
|         workspacesOrder.splice(workspacesOrder.indexOf(id),1); | ||||
|  | ||||
|         var ws = workspaces[id]; | ||||
|         var removedNodes = []; | ||||
|         var removedLinks = []; | ||||
|         var n; | ||||
|         var node; | ||||
|         for (n=0;n<nodes.length;n++) { | ||||
|             node = nodes[n]; | ||||
|             if (node.z == id) { | ||||
|                 removedNodes.push(node); | ||||
|             } | ||||
|         } | ||||
|         for(n in configNodes) { | ||||
|             if (configNodes.hasOwnProperty(n)) { | ||||
|                 node = configNodes[n]; | ||||
|         var removedGroups = []; | ||||
|         if (ws) { | ||||
|             delete workspaces[id]; | ||||
|             delete nodeTabMap[id]; | ||||
|             workspacesOrder.splice(workspacesOrder.indexOf(id),1); | ||||
|             var i; | ||||
|             var node; | ||||
|             for (i=0;i<nodes.length;i++) { | ||||
|                 node = nodes[i]; | ||||
|                 if (node.z == id) { | ||||
|                     removedNodes.push(node); | ||||
|                 } | ||||
|             } | ||||
|             for(i in configNodes) { | ||||
|                 if (configNodes.hasOwnProperty(i)) { | ||||
|                     node = configNodes[i]; | ||||
|                     if (node.z == id) { | ||||
|                         removedNodes.push(node); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             for (i=0;i<removedNodes.length;i++) { | ||||
|                 var result = removeNode(removedNodes[i].id); | ||||
|                 removedLinks = removedLinks.concat(result.links); | ||||
|             } | ||||
|  | ||||
|             // Must get 'removedGroups' in the right order. | ||||
|             //  - start with the top-most groups | ||||
|             //  - then recurse into them | ||||
|             removedGroups = (groupsByZ[id] || []).filter(function(g) { return !g.g; }); | ||||
|             for (i=0;i<removedGroups.length;i++) { | ||||
|                 removedGroups[i].nodes.forEach(function(n) { | ||||
|                     if (n.type === "group") { | ||||
|                         removedGroups.push(n); | ||||
|                     } | ||||
|                 }); | ||||
|             } | ||||
|             // Now remove them in the reverse order | ||||
|             for (i=removedGroups.length-1; i>=0; i--) { | ||||
|                 removeGroup(removedGroups[i]); | ||||
|             } | ||||
|             RED.events.emit('flows:remove',ws); | ||||
|         } | ||||
|         for (n=0;n<removedNodes.length;n++) { | ||||
|             var result = removeNode(removedNodes[n].id); | ||||
|             removedLinks = removedLinks.concat(result.links); | ||||
|         } | ||||
|         return {nodes:removedNodes,links:removedLinks}; | ||||
|         return {nodes:removedNodes,links:removedLinks, groups: removedGroups}; | ||||
|     } | ||||
|  | ||||
|     function addSubflow(sf, createNewIds) { | ||||
| @@ -357,43 +435,55 @@ 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 }, | ||||
|             oneditprepare: function() { | ||||
|                 RED.subflow.buildEditForm("subflow",this); | ||||
|                 RED.subflow.buildPropertiesForm(this); | ||||
|             }, | ||||
|             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" | ||||
|             } | ||||
|         }); | ||||
|         sf.instances = []; | ||||
|         sf._def = RED.nodes.getType("subflow:"+sf.id); | ||||
|         RED.events.emit("subflows:add",sf); | ||||
|     } | ||||
|     function getSubflow(id) { | ||||
|         return subflows[id]; | ||||
|     } | ||||
|     function removeSubflow(sf) { | ||||
|         delete subflows[sf.id]; | ||||
|         registry.removeNodeType("subflow:"+sf.id); | ||||
|         if (subflows[sf.id]) { | ||||
|             delete subflows[sf.id]; | ||||
|             delete nodeTabMap[sf.id]; | ||||
|             registry.removeNodeType("subflow:"+sf.id); | ||||
|             RED.events.emit("subflows:remove",sf); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function subflowContains(sfid,nodeid) { | ||||
| @@ -463,7 +553,12 @@ RED.nodes = (function() { | ||||
|         node.id = n.id; | ||||
|         node.type = n.type; | ||||
|         node.z = n.z; | ||||
|  | ||||
|         if (n.d === true) { | ||||
|             node.d = true; | ||||
|         } | ||||
|         if (n.g) { | ||||
|             node.g = n.g; | ||||
|         } | ||||
|         if (node.type == "unknown") { | ||||
|             for (var p in n._orig) { | ||||
|                 if (n._orig.hasOwnProperty(p)) { | ||||
| @@ -476,19 +571,33 @@ RED.nodes = (function() { | ||||
|                     node[d] = n[d]; | ||||
|                 } | ||||
|             } | ||||
|             if(exportCreds && n.credentials) { | ||||
|             if (exportCreds) { | ||||
|                 var credentialSet = {}; | ||||
|                 node.credentials = {}; | ||||
|                 for (var cred in n._def.credentials) { | ||||
|                     if (n._def.credentials.hasOwnProperty(cred)) { | ||||
|                         if (n._def.credentials[cred].type == 'password') { | ||||
|                 if (/^subflow:/.test(node.type) && n.credentials) { | ||||
|                     // A subflow instance node can have arbitrary creds | ||||
|                     for (var sfCred in n.credentials) { | ||||
|                         if (n.credentials.hasOwnProperty(sfCred)) { | ||||
|                             if (!n.credentials._ || | ||||
|                                 n.credentials["has_"+cred] != n.credentials._["has_"+cred] || | ||||
|                                 (n.credentials["has_"+cred] && n.credentials[cred])) { | ||||
|                                 n.credentials["has_"+sfCred] != n.credentials._["has_"+sfCred] || | ||||
|                                 (n.credentials["has_"+sfCred] && n.credentials[sfCred])) { | ||||
|                                 credentialSet[sfCred] = n.credentials[sfCred]; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } else if (n.credentials) { | ||||
|                     node.credentials = {}; | ||||
|                     // All other nodes have a well-defined list of possible credentials | ||||
|                     for (var cred in n._def.credentials) { | ||||
|                         if (n._def.credentials.hasOwnProperty(cred)) { | ||||
|                             if (n._def.credentials[cred].type == 'password') { | ||||
|                                 if (!n.credentials._ || | ||||
|                                     n.credentials["has_"+cred] != n.credentials._["has_"+cred] || | ||||
|                                     (n.credentials["has_"+cred] && n.credentials[cred])) { | ||||
|                                     credentialSet[cred] = n.credentials[cred]; | ||||
|                                 } | ||||
|                             } else if (n.credentials[cred] != null && (!n.credentials._ || n.credentials[cred] != n.credentials._[cred])) { | ||||
|                                 credentialSet[cred] = n.credentials[cred]; | ||||
|                             } | ||||
|                         } else if (n.credentials[cred] != null && (!n.credentials._ || n.credentials[cred] != n.credentials._[cred])) { | ||||
|                             credentialSet[cred] = n.credentials[cred]; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
| @@ -497,6 +606,13 @@ RED.nodes = (function() { | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         if (n.type === "group") { | ||||
|             node.x = n.x; | ||||
|             node.y = n.y; | ||||
|             node.w = n.w; | ||||
|             node.h = n.h; | ||||
|             node.nodes = node.nodes.map(function(n) { return n.id }); | ||||
|         } | ||||
|         if (n._def.category != "config") { | ||||
|             node.x = n.x; | ||||
|             node.y = n.y; | ||||
| @@ -539,7 +655,7 @@ RED.nodes = (function() { | ||||
|         return node; | ||||
|     } | ||||
|  | ||||
|     function convertSubflow(n) { | ||||
|     function convertSubflow(n, exportCreds) { | ||||
|         var node = {}; | ||||
|         node.id = n.id; | ||||
|         node.type = n.type; | ||||
| @@ -550,6 +666,25 @@ RED.nodes = (function() { | ||||
|         node.out = []; | ||||
|         node.env = n.env; | ||||
|  | ||||
|         if (exportCreds) { | ||||
|             var credentialSet = {}; | ||||
|             // A subflow node can have arbitrary creds | ||||
|             for (var sfCred in n.credentials) { | ||||
|                 if (n.credentials.hasOwnProperty(sfCred)) { | ||||
|                     if (!n.credentials._ || | ||||
|                         n.credentials["has_"+sfCred] != n.credentials._["has_"+sfCred] || | ||||
|                         (n.credentials["has_"+sfCred] && n.credentials[sfCred])) { | ||||
|                         credentialSet[sfCred] = n.credentials[sfCred]; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             if (Object.keys(credentialSet).length > 0) { | ||||
|                 node.credentials = credentialSet; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         node.color = n.color; | ||||
|  | ||||
|         n.in.forEach(function(p) { | ||||
|             var nIn = {x:p.x,y:p.y,wires:[]}; | ||||
|             var wires = links.filter(function(d) { return d.source === p }); | ||||
| @@ -581,7 +716,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; | ||||
|             } | ||||
|         } | ||||
| @@ -603,8 +738,18 @@ RED.nodes = (function() { | ||||
|     /** | ||||
|      * Converts the current node selection to an exportable JSON Object | ||||
|      **/ | ||||
|     function createExportableNodeSet(set, exportedSubflows, exportedConfigNodes) { | ||||
|     function createExportableNodeSet(set, exportedIds, exportedSubflows, exportedConfigNodes) { | ||||
|         var nns = []; | ||||
|  | ||||
|         exportedIds = exportedIds || {}; | ||||
|         set = set.filter(function(n) { | ||||
|             if (exportedIds[n.id]) { | ||||
|                 return false; | ||||
|             } | ||||
|             exportedIds[n.id] = true; | ||||
|             return true; | ||||
|         }) | ||||
|  | ||||
|         exportedConfigNodes = exportedConfigNodes || {}; | ||||
|         exportedSubflows = exportedSubflows || {}; | ||||
|         for (var n=0;n<set.length;n++) { | ||||
| @@ -620,11 +765,11 @@ RED.nodes = (function() { | ||||
|                             subflowSet.push(n); | ||||
|                         } | ||||
|                     }); | ||||
|                     var exportableSubflow = createExportableNodeSet(subflowSet, exportedSubflows, exportedConfigNodes); | ||||
|                     var exportableSubflow = createExportableNodeSet(subflowSet, exportedIds, exportedSubflows, exportedConfigNodes); | ||||
|                     nns = exportableSubflow.concat(nns); | ||||
|                 } | ||||
|             } | ||||
|             if (node.type != "subflow") { | ||||
|             if (node.type !== "subflow") { | ||||
|                 var convertedNode = RED.nodes.convertNode(node); | ||||
|                 for (var d in node._def.defaults) { | ||||
|                     if (node._def.defaults[d].type && node[d] in configNodes) { | ||||
| @@ -641,6 +786,9 @@ RED.nodes = (function() { | ||||
|                     } | ||||
|                 } | ||||
|                 nns.push(convertedNode); | ||||
|                 if (node.type === "group") { | ||||
|                     nns = nns.concat(createExportableNodeSet(node.nodes, exportedIds, exportedSubflows, exportedConfigNodes)); | ||||
|                 } | ||||
|             } else { | ||||
|                 var convertedSubflow = convertSubflow(node); | ||||
|                 nns.push(convertedSubflow); | ||||
| @@ -663,7 +811,12 @@ RED.nodes = (function() { | ||||
|         } | ||||
|         for (i in subflows) { | ||||
|             if (subflows.hasOwnProperty(i)) { | ||||
|                 nns.push(convertSubflow(subflows[i])); | ||||
|                 nns.push(convertSubflow(subflows[i], exportCredentials)); | ||||
|             } | ||||
|         } | ||||
|         for (i in groups) { | ||||
|             if (groups.hasOwnProperty(i)) { | ||||
|                 nns.push(convertNode(groups[i])); | ||||
|             } | ||||
|         } | ||||
|         for (i in configNodes) { | ||||
| @@ -792,6 +945,7 @@ RED.nodes = (function() { | ||||
|             if (n.type != "workspace" && | ||||
|                 n.type != "tab" && | ||||
|                 n.type != "subflow" && | ||||
|                 n.type != "group" && | ||||
|                 !registry.getNodeType(n.type) && | ||||
|                 n.type.substring(0,8) != "subflow:" && | ||||
|                 unknownTypes.indexOf(n.type)==-1) { | ||||
| @@ -815,7 +969,7 @@ RED.nodes = (function() { | ||||
|             var m = /^subflow:(.+)$/.exec(newNodes[i].type); | ||||
|             if (m) { | ||||
|                 var subflowId = m[1]; | ||||
|                 var parent = getSubflow(newNodes[i].z || activeWorkspace); | ||||
|                 var parent = getSubflow(activeWorkspace); | ||||
|                 if (parent) { | ||||
|                     var err; | ||||
|                     if (subflowId === parent.id) { | ||||
| @@ -841,6 +995,7 @@ RED.nodes = (function() { | ||||
|         var node_map = {}; | ||||
|         var new_nodes = []; | ||||
|         var new_links = []; | ||||
|         var new_groups = []; | ||||
|         var nid; | ||||
|         var def; | ||||
|         var configNode; | ||||
| @@ -967,6 +1122,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]; | ||||
| @@ -988,7 +1146,6 @@ RED.nodes = (function() { | ||||
|                     } | ||||
|                     node_map[n.id] = configNode; | ||||
|                     new_nodes.push(configNode); | ||||
|                     RED.nodes.add(configNode); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @@ -1005,17 +1162,25 @@ RED.nodes = (function() { | ||||
|                         y:parseFloat(n.y || 0), | ||||
|                         z:n.z, | ||||
|                         type:0, | ||||
|                         wires:n.wires||[], | ||||
|                         inputLabels: n.inputLabels, | ||||
|                         outputLabels: n.outputLabels, | ||||
|                         icon: n.icon, | ||||
|                         info: n.info, | ||||
|                         changed:false, | ||||
|                         _config:{} | ||||
|                     }; | ||||
|                     } | ||||
|                     if (n.type !== "group") { | ||||
|                         node.wires = n.wires||[]; | ||||
|                         node.inputLabels = n.inputLabels; | ||||
|                         node.outputLabels = n.outputLabels; | ||||
|                         node.icon = n.icon; | ||||
|                     } | ||||
|                     if (n.hasOwnProperty('l')) { | ||||
|                         node.l = n.l; | ||||
|                     } | ||||
|                     if (n.hasOwnProperty('d')) { | ||||
|                         node.d = n.d; | ||||
|                     } | ||||
|                     if (n.hasOwnProperty('g')) { | ||||
|                         node.g = n.g; | ||||
|                     } | ||||
|                     if (createNewIds) { | ||||
|                         if (subflow_blacklist[n.z]) { | ||||
|                             continue; | ||||
| @@ -1052,7 +1217,17 @@ RED.nodes = (function() { | ||||
|                     } | ||||
|                     node.type = n.type; | ||||
|                     node._def = def; | ||||
|                     if (n.type.substring(0,7) === "subflow") { | ||||
|                     if (node.type === "group") { | ||||
|                         node._def = RED.group.def; | ||||
|                         for (d in node._def.defaults) { | ||||
|                             if (node._def.defaults.hasOwnProperty(d) && d !== 'inputs' && d !== 'outputs') { | ||||
|                                 node[d] = n[d]; | ||||
|                                 node._config[d] = JSON.stringify(n[d]); | ||||
|                             } | ||||
|                         } | ||||
|                         node._config.x = node.x; | ||||
|                         node._config.y = node.y; | ||||
|                     } else if (n.type.substring(0,7) === "subflow") { | ||||
|                         var parentId = n.type.split(":")[1]; | ||||
|                         var subflow = subflow_blacklist[parentId]||subflow_map[parentId]||getSubflow(parentId); | ||||
|                         if (createNewIds) { | ||||
| @@ -1072,8 +1247,8 @@ RED.nodes = (function() { | ||||
|                                     color:"#fee", | ||||
|                                     defaults: {}, | ||||
|                                     label: "unknown: "+n.type, | ||||
|                                     labelStyle: "node_label_italic", | ||||
|                                     outputs: n.outputs||n.wires.length, | ||||
|                                     labelStyle: "red-ui-flow-node-label-italic", | ||||
|                                     outputs: n.outputs|| (n.wires && n.wires.length) || 0, | ||||
|                                     set: registry.getNodeSet("node-red/unknown") | ||||
|                                 } | ||||
|                             } else { | ||||
| @@ -1142,13 +1317,13 @@ RED.nodes = (function() { | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     addNode(node); | ||||
|                     RED.editor.validateNode(node); | ||||
|                     node_map[n.id] = node; | ||||
|                     // If an 'unknown' config node, it will not have been caught by the | ||||
|                     // proper config node handling, so needs adding to new_nodes here | ||||
|                     if (node.type === "unknown" || node._def.category !== "config") { | ||||
|                         new_nodes.push(node); | ||||
|                     } else if (node.type === "group") { | ||||
|                         new_groups.push(node); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| @@ -1158,6 +1333,7 @@ RED.nodes = (function() { | ||||
|         var nodeTypeArrayReferences = { | ||||
|             "catch":"scope", | ||||
|             "status":"scope", | ||||
|             "complete": "scope", | ||||
|             "link in":"links", | ||||
|             "link out":"links" | ||||
|         } | ||||
| @@ -1182,12 +1358,17 @@ RED.nodes = (function() { | ||||
|                 } | ||||
|                 delete n.wires; | ||||
|             } | ||||
|             if (n.g && node_map[n.g]) { | ||||
|                 n.g = node_map[n.g].id; | ||||
|             } else { | ||||
|                 delete n.g | ||||
|             } | ||||
|             for (var d3 in n._def.defaults) { | ||||
|                 if (n._def.defaults.hasOwnProperty(d3)) { | ||||
|                     if (n._def.defaults[d3].type && node_map[n[d3]]) { | ||||
|                         n[d3] = node_map[n[d3]].id; | ||||
|                         configNode = RED.nodes.node(n[d3]); | ||||
|                         if (configNode && configNode.users.indexOf(n) === -1) { | ||||
|                         configNode = node_map[n[d3]]; | ||||
|                         n[d3] = configNode.id; | ||||
|                         if (configNode.users.indexOf(n) === -1) { | ||||
|                             configNode.users.push(n); | ||||
|                         } | ||||
|                     } else if (nodeTypeArrayReferences.hasOwnProperty(n.type) && nodeTypeArrayReferences[n.type] === d3 && n[d3] !== undefined && n[d3] !== null) { | ||||
| @@ -1208,10 +1389,6 @@ RED.nodes = (function() { | ||||
|                     return (otherNode && otherNode.z === activeWorkspace) | ||||
|                 }); | ||||
|             } | ||||
|  | ||||
|             // With all properties now remapped to point at valid nodes, | ||||
|             // we can validate the node | ||||
|             RED.editor.validateNode(n); | ||||
|         } | ||||
|         for (i=0;i<new_subflows.length;i++) { | ||||
|             n = new_subflows[i]; | ||||
| @@ -1250,21 +1427,54 @@ RED.nodes = (function() { | ||||
|                 delete n.status.wires; | ||||
|             } | ||||
|         } | ||||
|         for (i=0;i<new_groups.length;i++) { | ||||
|             n = new_groups[i]; | ||||
|             if (n.g && node_map[n.g]) { | ||||
|                 n.g = node_map[n.g].id; | ||||
|             } else { | ||||
|                 delete n.g; | ||||
|             } | ||||
|             n.nodes = n.nodes.map(function(id) { | ||||
|                 return node_map[id]; | ||||
|             }) | ||||
|             addGroup(n); | ||||
|         } | ||||
|         // Now the nodes have been fully updated, add them. | ||||
|         for (i=0;i<new_nodes.length;i++) { | ||||
|             var node = new_nodes[i]; | ||||
|             addNode(node); | ||||
|         } | ||||
|         // Finally validate them all. | ||||
|         // This has to be done after everything is added so that any checks for | ||||
|         // dependent config nodes will pass | ||||
|         for (i=0;i<new_nodes.length;i++) { | ||||
|             var node = new_nodes[i]; | ||||
|             RED.editor.validateNode(node); | ||||
|         } | ||||
|  | ||||
|         RED.workspaces.refresh(); | ||||
|         return [new_nodes,new_links,new_workspaces,new_subflows,missingWorkspace]; | ||||
|         return [new_nodes,new_links,new_groups,new_workspaces,new_subflows,missingWorkspace]; | ||||
|     } | ||||
|  | ||||
|     // 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); | ||||
| @@ -1331,8 +1541,12 @@ RED.nodes = (function() { | ||||
|     function clear() { | ||||
|         nodes = []; | ||||
|         links = []; | ||||
|         nodeTabMap = {}; | ||||
|         configNodes = {}; | ||||
|         workspacesOrder = []; | ||||
|         groups = {}; | ||||
|         groupsByZ = {}; | ||||
|  | ||||
|         var subflowIds = Object.keys(subflows); | ||||
|         subflowIds.forEach(function(id) { | ||||
|             RED.subflow.removeSubflow(id) | ||||
| @@ -1344,12 +1558,14 @@ RED.nodes = (function() { | ||||
|         defaultWorkspace = null; | ||||
|         initialLoad = null; | ||||
|         RED.nodes.dirty(false); | ||||
|         RED.view.redraw(true); | ||||
|         RED.view.redraw(true, true); | ||||
|         RED.palette.refresh(); | ||||
|         RED.workspaces.refresh(); | ||||
|         RED.sidebar.config.refresh(); | ||||
|         RED.sidebar.info.refresh(); | ||||
|  | ||||
|         RED.events.emit("workspace:clear"); | ||||
|  | ||||
|         // var node_defs = {}; | ||||
|         // var nodes = []; | ||||
|         // var configNodes = {}; | ||||
| @@ -1361,6 +1577,31 @@ RED.nodes = (function() { | ||||
|         // var loadedFlowVersion = null; | ||||
|     } | ||||
|  | ||||
|     function addGroup(group) { | ||||
|         groupsByZ[group.z] = groupsByZ[group.z] || []; | ||||
|         groupsByZ[group.z].push(group); | ||||
|         groups[group.id] = group; | ||||
|         RED.events.emit("groups:add",group); | ||||
|     } | ||||
|     function removeGroup(group) { | ||||
|         var i = groupsByZ[group.z].indexOf(group); | ||||
|         groupsByZ[group.z].splice(i,1); | ||||
|         if (groupsByZ[group.z].length === 0) { | ||||
|             delete groupsByZ[group.z]; | ||||
|         } | ||||
|         if (group.g) { | ||||
|             if (groups[group.g]) { | ||||
|                 var index = groups[group.g].nodes.indexOf(group); | ||||
|                 groups[group.g].nodes.splice(index,1); | ||||
|             } | ||||
|         } | ||||
|         RED.group.markDirty(group); | ||||
|  | ||||
|         delete groups[group.id]; | ||||
|         RED.events.emit("groups:remove",group); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     return { | ||||
|         init: function() { | ||||
|             RED.events.on("registry:node-type-added",function(type) { | ||||
| @@ -1387,6 +1628,9 @@ RED.nodes = (function() { | ||||
|                             delete configNodes[n.id]; | ||||
|                         } else { | ||||
|                             nodes.splice(nodes.indexOf(n),1); | ||||
|                             if (nodeTabMap[n.z]) { | ||||
|                                 delete nodeTabMap[n.z][n.id]; | ||||
|                             } | ||||
|                         } | ||||
|                         reimportList.push(convertNode(n)); | ||||
|                     }); | ||||
| @@ -1401,8 +1645,9 @@ RED.nodes = (function() { | ||||
|                     }); | ||||
|                     removeLinks.forEach(removeLink); | ||||
|  | ||||
|  | ||||
|                     RED.view.redraw(true); | ||||
|                     // Force the redraw to be synchronous so the view updates | ||||
|                     // *now* and removes the unknown node | ||||
|                     RED.view.redraw(true, true); | ||||
|                     var result = importNodes(reimportList,false); | ||||
|                     var newNodeMap = {}; | ||||
|                     result[0].forEach(function(n) { | ||||
| @@ -1440,6 +1685,8 @@ RED.nodes = (function() { | ||||
|         remove: removeNode, | ||||
|         clear: clear, | ||||
|  | ||||
|         moveNodeToTab: moveNodeToTab, | ||||
|  | ||||
|         addLink: addLink, | ||||
|         removeLink: removeLink, | ||||
|  | ||||
| @@ -1454,6 +1701,11 @@ RED.nodes = (function() { | ||||
|         subflow: getSubflow, | ||||
|         subflowContains: subflowContains, | ||||
|  | ||||
|         addGroup: addGroup, | ||||
|         removeGroup: removeGroup, | ||||
|         group: function(id) { return groups[id] }, | ||||
|         groups: function(z) { return groupsByZ[z]||[] }, | ||||
|  | ||||
|         eachNode: function(cb) { | ||||
|             for (var n=0;n<nodes.length;n++) { | ||||
|                 if (cb(nodes[n]) === false) { | ||||
|   | ||||
							
								
								
									
										41
									
								
								packages/node_modules/@node-red/editor-client/src/js/polyfills.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,41 @@ | ||||
| (function() { | ||||
|     var isIE11 = !!window.MSInputMethodContext && !!document.documentMode; | ||||
|  | ||||
|     if (isIE11) { | ||||
|         // IE11 DOMTokenList.toggle does not support the two-argument variety | ||||
|         window.DOMTokenList.prototype.toggle = function(cl,bo) { | ||||
|             if (arguments.length === 1) { | ||||
|                 bo = !this.contains(cl); | ||||
|             } | ||||
|             this[!!bo?"add":"remove"](cl); | ||||
|         } | ||||
|  | ||||
|         // IE11 does not provide classList on SVGElements | ||||
|         if (! ("classList" in SVGElement.prototype)) { | ||||
|             Object.defineProperty(SVGElement.prototype, 'classList', Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'classList')); | ||||
|         } | ||||
|  | ||||
|         // IE11 does not provide children on SVGElements | ||||
|         if (! ("children" in SVGElement.prototype)) { | ||||
|             Object.defineProperty(SVGElement.prototype, 'children', Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'children')); | ||||
|         } | ||||
|  | ||||
|         Array.from = function() { | ||||
|             if (arguments.length > 1) { | ||||
|                 throw new Error("Node-RED's IE11 Array.from polyfill doesn't support multiple arguments"); | ||||
|             } | ||||
|             var arrayLike = arguments[0] | ||||
|             var result = []; | ||||
|             if (arrayLike.forEach) { | ||||
|                 arrayLike.forEach(function(i) { | ||||
|                     result.push(i); | ||||
|                 }) | ||||
|             } else { | ||||
|                 for (var i=0;i<arrayLike.length;i++) { | ||||
|                     result.push(arrayList[i]); | ||||
|                 } | ||||
|             } | ||||
|             return result; | ||||
|         } | ||||
|     } | ||||
| })(); | ||||
| @@ -38,11 +38,14 @@ var RED = (function() { | ||||
|                     newScript.onload = function() { | ||||
|                         scriptCount--; | ||||
|                         if (scriptCount === 0) { | ||||
|                             $("body").append(nodeConfigEls); | ||||
|                             $("#red-ui-editor-node-configs").append(nodeConfigEls); | ||||
|                             done() | ||||
|                         } | ||||
|                     } | ||||
|                     $('body').append(newScript); | ||||
|                     if ($(el).attr('type') === "module") { | ||||
|                         newScript.type = "module"; | ||||
|                     } | ||||
|                     $("#red-ui-editor-node-configs").append(newScript); | ||||
|                     newScript.src = RED.settings.apiRootUrl+srcUrl; | ||||
|                     hasDeferred = true; | ||||
|                 } else { | ||||
| @@ -58,7 +61,7 @@ var RED = (function() { | ||||
|                 } | ||||
|             }) | ||||
|             if (!hasDeferred) { | ||||
|                 $("body").append(nodeConfigEls); | ||||
|                 $("#red-ui-editor-node-configs").append(nodeConfigEls); | ||||
|                 done(); | ||||
|             } | ||||
|         } catch(err) { | ||||
| @@ -72,6 +75,7 @@ var RED = (function() { | ||||
|     } | ||||
|  | ||||
|     function loadNodeList() { | ||||
|         loader.reportProgress(RED._("event.loadPalette"), 20) | ||||
|         $.ajax({ | ||||
|             headers: { | ||||
|                 "Accept":"application/json" | ||||
| @@ -80,6 +84,7 @@ var RED = (function() { | ||||
|             url: 'nodes', | ||||
|             success: function(data) { | ||||
|                 RED.nodes.setNodeList(data); | ||||
|                 loader.reportProgress(RED._("event.loadNodeCatalogs"), 25) | ||||
|                 RED.i18n.loadNodeCatalogs(function() { | ||||
|                     loadIconList(loadNodes); | ||||
|                 }); | ||||
| @@ -104,23 +109,31 @@ var RED = (function() { | ||||
|     } | ||||
|  | ||||
|     function loadNodes() { | ||||
|         loader.reportProgress(RED._("event.loadNodes",{count:""}), 30) | ||||
|         var lang = localStorage.getItem("editor-language")||i18n.detectLanguage(); | ||||
|  | ||||
|         $.ajax({ | ||||
|             headers: { | ||||
|                 "Accept":"text/html" | ||||
|                 "Accept":"text/html", | ||||
|                 "Accept-Language": lang | ||||
|             }, | ||||
|             cache: false, | ||||
|             url: 'nodes', | ||||
|             success: function(data) { | ||||
|                 var configs = data.trim().split(/(?=<!-- --- \[red-module:\S+\] --- -->)/); | ||||
|                 var totalCount = configs.length; | ||||
|  | ||||
|                 var stepConfig = function() { | ||||
|                     loader.reportProgress(RED._("event.loadNodes",{count:(totalCount-configs.length)+"/"+totalCount}), 30 + ((totalCount-configs.length)/totalCount)*40 ) | ||||
|  | ||||
|                     if (configs.length === 0) { | ||||
|                         $("body").i18n(); | ||||
|                         $("#palette > .palette-spinner").hide(); | ||||
|                         $(".palette-scroll").removeClass("hide"); | ||||
|                         $("#palette-search").removeClass("hide"); | ||||
|                         loadFlows(function() { | ||||
|                             if (RED.settings.theme("projects.enabled",false)) { | ||||
|                                 RED.projects.refresh(function(activeProject) { | ||||
|                         $("#red-ui-editor").i18n(); | ||||
|                         $("#red-ui-palette > .red-ui-palette-spinner").hide(); | ||||
|                         $(".red-ui-palette-scroll").removeClass("hide"); | ||||
|                         $("#red-ui-palette-search").removeClass("hide"); | ||||
|                         if (RED.settings.theme("projects.enabled",false)) { | ||||
|                             RED.projects.refresh(function(activeProject) { | ||||
|                                 loadFlows(function() { | ||||
|                                     RED.sidebar.info.refresh() | ||||
|                                     if (!activeProject) { | ||||
|                                         // Projects enabled but no active project | ||||
| @@ -134,12 +147,14 @@ var RED = (function() { | ||||
|                                     } | ||||
|                                     completeLoad(); | ||||
|                                 }); | ||||
|                             } else { | ||||
|                             }); | ||||
|                         } else { | ||||
|                             loadFlows(function() { | ||||
|                                 // Projects disabled by the user | ||||
|                                 RED.sidebar.info.refresh() | ||||
|                                 completeLoad(); | ||||
|                             } | ||||
|                         }); | ||||
|                             }); | ||||
|                         } | ||||
|                     } else { | ||||
|                         var config = configs.shift(); | ||||
|                         appendNodeConfig(config,stepConfig); | ||||
| @@ -151,6 +166,7 @@ var RED = (function() { | ||||
|     } | ||||
|  | ||||
|     function loadFlows(done) { | ||||
|         loader.reportProgress(RED._("event.loadFlows"),80 ) | ||||
|         $.ajax({ | ||||
|             headers: { | ||||
|                 "Accept":"application/json", | ||||
| @@ -161,6 +177,7 @@ var RED = (function() { | ||||
|                 if (nodes) { | ||||
|                     var currentHash = window.location.hash; | ||||
|                     RED.nodes.version(nodes.rev); | ||||
|                     loader.reportProgress(RED._("event.importFlows"),90 ) | ||||
|                     RED.nodes.import(nodes.flows); | ||||
|                     RED.nodes.dirty(false); | ||||
|                     RED.view.redraw(true); | ||||
| @@ -187,6 +204,7 @@ var RED = (function() { | ||||
|                 return; | ||||
|             } | ||||
|             if (notificationId === "project-update") { | ||||
|                 loader.start("Loading project",0) | ||||
|                 RED.nodes.clear(); | ||||
|                 RED.history.clear(); | ||||
|                 RED.view.redraw(true); | ||||
| @@ -202,6 +220,7 @@ var RED = (function() { | ||||
|                             "revert": RED._("notification.project.revert", {project: msg.project}), | ||||
|                             "merge-complete": RED._("notification.project.merge-complete") | ||||
|                         }[msg.action]; | ||||
|                         loader.end() | ||||
|                         RED.notify("<p>"+message+"</p>"); | ||||
|                         RED.sidebar.info.refresh() | ||||
|                     }); | ||||
| @@ -347,12 +366,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") && msg.text !== null && /^[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(); | ||||
|             } | ||||
| @@ -413,13 +431,17 @@ var RED = (function() { | ||||
|                 RED.notify(RED._("palette.event.nodeUpgraded", {module:msg.module,version:msg.version}),"success"); | ||||
|                 RED.nodes.registry.setModulePendingUpdated(msg.module,msg.version); | ||||
|             } | ||||
|             // Refresh flow library to ensure any examples are updated | ||||
|             RED.library.loadFlowLibrary(); | ||||
|         }); | ||||
|         RED.comms.subscribe("event-log/#", function(topic,payload) { | ||||
|             var id = topic.substring(9); | ||||
|             RED.eventLog.log(id,payload); | ||||
|         }); | ||||
|  | ||||
|         $(".red-ui-header-toolbar").show(); | ||||
|  | ||||
|         setTimeout(function() { | ||||
|             loader.end(); | ||||
|         },100); | ||||
|     } | ||||
|  | ||||
|     function showAbout() { | ||||
| @@ -428,12 +450,11 @@ var RED = (function() { | ||||
|             '<img width="50px" src="red/images/node-red-icon.svg" />'+ | ||||
|             '</div>'; | ||||
|  | ||||
|             RED.sidebar.info.set(aboutHeader+marked(data)); | ||||
|             RED.sidebar.info.show(); | ||||
|             RED.sidebar.help.set(aboutHeader+RED.utils.renderMarkdown(data)); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     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:[ | ||||
| @@ -442,34 +463,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); | ||||
| @@ -483,6 +490,14 @@ var RED = (function() { | ||||
|             {id:"menu-item-subflow-create",label:RED._("menu.label.createSubflow"),onselect:"core:create-subflow"}, | ||||
|             {id:"menu-item-subflow-convert",label:RED._("menu.label.selectionToSubflow"),disabled:true,onselect:"core:convert-to-subflow"}, | ||||
|         ]}); | ||||
|         menuOptions.push({id:"menu-item-group",label:RED._("menu.label.groups"), options: [ | ||||
|             {id:"menu-item-group-group",label:RED._("menu.label.groupSelection"),disabled:true,onselect:"core:group-selection"}, | ||||
|             {id:"menu-item-group-ungroup",label:RED._("menu.label.ungroupSelection"),disabled:true,onselect:"core:ungroup-selection"}, | ||||
|             null, | ||||
|             {id:"menu-item-group-merge",label:RED._("menu.label.groupMergeSelection"),disabled:true,onselect:"core:merge-selection-to-group"}, | ||||
|             {id:"menu-item-group-remove",label:RED._("menu.label.groupRemoveSelection"),disabled:true,onselect:"core:remove-selection-from-group"} | ||||
|         ]}); | ||||
|  | ||||
|         menuOptions.push(null); | ||||
|         if (RED.settings.theme('palette.editable') !== false) { | ||||
|             menuOptions.push({id:"menu-item-edit-palette",label:RED._("menu.label.editPalette"),onselect:"core:manage-palette"}); | ||||
| @@ -492,7 +507,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") | ||||
| @@ -500,13 +517,23 @@ 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 { | ||||
| @@ -522,27 +549,63 @@ var RED = (function() { | ||||
|         } | ||||
|  | ||||
|         RED.subflow.init(); | ||||
|         RED.workspaces.init(); | ||||
|         RED.group.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.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); | ||||
|  | ||||
|         loader.init().appendTo("#red-ui-main-container"); | ||||
|         loader.start("...",0); | ||||
|  | ||||
|         $.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) { | ||||
| @@ -556,12 +619,43 @@ 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); | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     var loader = { | ||||
|         init: function() { | ||||
|             var wrapper = $('<div id="red-ui-loading-progress"></div>').hide(); | ||||
|             var container = $('<div>').appendTo(wrapper); | ||||
|             var label = $('<div>',{class:"red-ui-loading-bar-label"}).appendTo(container); | ||||
|             var bar = $('<div>',{class:"red-ui-loading-bar"}).appendTo(container); | ||||
|             var fill =$('<span>').appendTo(bar); | ||||
|             return wrapper; | ||||
|         }, | ||||
|         start: function(text, prcnt) { | ||||
|             if (text) { | ||||
|                 loader.reportProgress(text,prcnt) | ||||
|             } | ||||
|             $("#red-ui-loading-progress").show(); | ||||
|         }, | ||||
|         reportProgress: function(text, prcnt) { | ||||
|             $(".red-ui-loading-bar-label").text(text); | ||||
|             $(".red-ui-loading-bar span").width(prcnt+"%") | ||||
|         }, | ||||
|         end: function() { | ||||
|             $("#red-ui-loading-progress").hide(); | ||||
|             loader.reportProgress("",0); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         init: init | ||||
|         init: init, | ||||
|         loader: loader | ||||
|     } | ||||
| })(); | ||||
|   | ||||
| @@ -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,26 @@ 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]; | ||||
|             var v; | ||||
|             try { | ||||
|                 v = RED.utils.getMessageProperty(userSettings,key); | ||||
|                 if (v === undefined) { | ||||
|                     v = defaultIfUndefined; | ||||
|                 } | ||||
|             } catch(err) { | ||||
|                 v = defaultIfUndefined; | ||||
|             } | ||||
|             return v; | ||||
|         } | ||||
|     }; | ||||
|  | ||||
| @@ -131,6 +141,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" style="height:calc(100% - 30px)">'+ | ||||
|                             '<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" style="height:calc(100% - 47px)">'+ | ||||
|                             '<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,128 @@ 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) | ||||
|         } | ||||
|  | ||||
|         var dialogHeight = 400; | ||||
|         var winHeight = $(window).height(); | ||||
|         if (winHeight < 600) { | ||||
|             dialogHeight = 400 - (600 - winHeight); | ||||
|         } | ||||
|         $(".red-ui-clipboard-dialog-box").height(dialogHeight); | ||||
|  | ||||
|         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,12 +583,13 @@ 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 = []; | ||||
|                     selection.forEach(function(n) { | ||||
|                         nodes.push(n); | ||||
|                         nodes = nodes.concat(RED.nodes.groups(n.id)); | ||||
|                         nodes = nodes.concat(RED.nodes.filterNodes({z:n.id})); | ||||
|                     }); | ||||
|                 } else { | ||||
| @@ -335,77 +597,106 @@ 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}); | ||||
|                 nodes = RED.nodes.groups(activeWorkspace); | ||||
|                 nodes = nodes.concat(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); | ||||
|  | ||||
|         var dialogHeight = 400; | ||||
|         var winHeight = $(window).height(); | ||||
|         if (winHeight < 600) { | ||||
|             dialogHeight = 400 - (600 - winHeight); | ||||
|         } | ||||
|         $(".red-ui-clipboard-dialog-box").height(dialogHeight); | ||||
|  | ||||
|         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 +726,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 +746,36 @@ 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.actions.add("core:show-examples-import-dialog",function() { importNodes('examples') }); | ||||
|  | ||||
|             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. | ||||
|   | ||||
							
								
								
									
										203
									
								
								packages/node_modules/@node-red/editor-client/src/js/ui/common/colorPicker.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,203 @@ | ||||
| RED.colorPicker = (function() { | ||||
|  | ||||
|     function create(options) { | ||||
|         var color = options.value; | ||||
|         var id = options.id; | ||||
|         var colorPalette = options.palette || []; | ||||
|         var width = options.cellWidth || 30; | ||||
|         var height = options.cellHeight || 30; | ||||
|         var margin = options.cellMargin || 2; | ||||
|         var perRow = options.cellPerRow || 6; | ||||
|  | ||||
|         var container = $("<div>",{style:"display:inline-block"}); | ||||
|         var colorHiddenInput = $("<input/>", { id: id, type: "hidden", value: color }).appendTo(container); | ||||
|         var opacityHiddenInput = $("<input/>", { id: id+"-opacity", type: "hidden", value: options.hasOwnProperty('opacity')?options.opacity:"1" }).appendTo(container); | ||||
|  | ||||
|         var colorButton = $('<button type="button" class="red-ui-button red-ui-editor-node-appearance-button">').appendTo(container); | ||||
|         $('<i class="fa fa-caret-down"></i>').appendTo(colorButton); | ||||
|  | ||||
|         var colorDispContainer = $('<div>',{class:"red-ui-search-result-node"}).appendTo(colorButton); | ||||
|         $('<div>',{class:"red-ui-color-picker-cell-none"}).appendTo(colorDispContainer); | ||||
|         var colorDisp = $('<div>',{class:"red-ui-color-picker-swatch"}).appendTo(colorDispContainer); | ||||
|  | ||||
|  | ||||
|         var refreshDisplay = function(color) { | ||||
|             if (color === "none") { | ||||
|                 colorDisp.addClass('red-ui-color-picker-cell-none').css({ | ||||
|                     "background-color": "", | ||||
|                     opacity: 1 | ||||
|                 }); | ||||
|                 colorDispContainer.css({ | ||||
|                     "border-color":"" | ||||
|                 }) | ||||
|             } else { | ||||
|                 var opacity = parseFloat(opacityHiddenInput.val()) | ||||
|                 colorDisp.removeClass('red-ui-color-picker-cell-none').css({ | ||||
|                     "background-color": color, | ||||
|                     "opacity": opacity | ||||
|                 }); | ||||
|                 var border = RED.utils.getDarkerColor(color); | ||||
|                 if (border[0] === '#') { | ||||
|                     border += Math.round(255*Math.floor(opacity*100)/100).toString(16); | ||||
|                 } else { | ||||
|                     border = ""; | ||||
|                 } | ||||
|  | ||||
|                 colorDispContainer.css({ | ||||
|                     "border-color": border | ||||
|                 }) | ||||
|             } | ||||
|             if (options.hasOwnProperty('opacity')) { | ||||
|                 $(".red-ui-color-picker-opacity-slider-overlay").css({ | ||||
|                     "background-image": "linear-gradient(90deg, transparent 0%, "+color+" 100%)" | ||||
|                 }) | ||||
|             } | ||||
|  | ||||
|  | ||||
|         } | ||||
|  | ||||
|         colorButton.on("click", function (e) { | ||||
|             var numColors = colorPalette.length; | ||||
|  | ||||
|             var picker = $("<div/>", { | ||||
|                 class: "red-ui-color-picker" | ||||
|             }).css({ | ||||
|                 width: ((width+margin+margin)*perRow)+"px", | ||||
|                 height: Math.ceil(numColors/perRow)*(height+margin+margin)+"+px" | ||||
|             }); | ||||
|             var count = 0; | ||||
|             var row = null; | ||||
|             row = $("<div/>").appendTo(picker); | ||||
|  | ||||
|             var colorInput = $('<input>',{ | ||||
|                 type:"text", | ||||
|                 value:colorHiddenInput.val() | ||||
|             }).appendTo(row); | ||||
|  | ||||
|             colorInput.on("change", function (e) { | ||||
|                 var color = colorInput.val(); | ||||
|                 colorHiddenInput.val(color).trigger('change'); | ||||
|                 refreshDisplay(color); | ||||
|             }); | ||||
|             // if (options.hasOwnProperty('opacity')) { | ||||
|             //     var sliderContainer = $("<div>",{class:"red-ui-color-picker-opacity-slider" | ||||
|             // } | ||||
|  | ||||
|             if (options.none) { | ||||
|                 row = $("<div/>").appendTo(picker); | ||||
|                 var button = $("<button/>", { | ||||
|                     class:"red-ui-color-picker-cell red-ui-color-picker-cell-none" | ||||
|                 }).css({ | ||||
|                     width: width+"px", | ||||
|                     height: height+"px", | ||||
|                     margin: margin+"px" | ||||
|                 }).appendTo(row); | ||||
|                 button.on("click",  function (e) { | ||||
|                     e.preventDefault(); | ||||
|                     colorInput.val("none"); | ||||
|                     colorInput.trigger("change"); | ||||
|                 }); | ||||
|             } | ||||
|  | ||||
|  | ||||
|             colorPalette.forEach(function (col) { | ||||
|                 if ((count % perRow) == 0) { | ||||
|                     row = $("<div/>").appendTo(picker); | ||||
|                 } | ||||
|                 var button = $("<button/>", { | ||||
|                     class:"red-ui-color-picker-cell" | ||||
|                 }).css({ | ||||
|                     width: width+"px", | ||||
|                     height: height+"px", | ||||
|                     margin: margin+"px", | ||||
|                     backgroundColor: col, | ||||
|                     "border-color": RED.utils.getDarkerColor(col) | ||||
|                 }).appendTo(row); | ||||
|                 button.on("click",  function (e) { | ||||
|                     e.preventDefault(); | ||||
|                     // colorPanel.hide(); | ||||
|                     colorInput.val(col); | ||||
|                     colorInput.trigger("change"); | ||||
|                 }); | ||||
|                 count++; | ||||
|             }); | ||||
|             if (options.none || options.hasOwnProperty('opacity')) { | ||||
|                 row = $("<div/>").appendTo(picker); | ||||
|                 // if (options.none) { | ||||
|                 //     var button = $("<button/>", { | ||||
|                 //         class:"red-ui-color-picker-cell red-ui-color-picker-cell-none" | ||||
|                 //     }).css({ | ||||
|                 //         width: width+"px", | ||||
|                 //         height: height+"px", | ||||
|                 //         margin: margin+"px" | ||||
|                 //     }).appendTo(row); | ||||
|                 //     button.on("click",  function (e) { | ||||
|                 //         e.preventDefault(); | ||||
|                 //         colorPanel.hide(); | ||||
|                 //         selector.val("none"); | ||||
|                 //         selector.trigger("change"); | ||||
|                 //     }); | ||||
|                 // } | ||||
|                 if (options.hasOwnProperty('opacity')) { | ||||
|                     var sliderContainer = $("<div>",{class:"red-ui-color-picker-opacity-slider"}).appendTo(row); | ||||
|                     sliderContainer.on("mousedown", function(evt) { | ||||
|                         if (evt.target === sliderHandle[0]) { | ||||
|                             return; | ||||
|                         } | ||||
|                         var v = evt.offsetX/sliderContainer.width(); | ||||
|                         sliderHandle.css({ | ||||
|                             left: ( v*(sliderContainer.width() - sliderHandle.outerWidth()))+"px" | ||||
|                         }); | ||||
|                         v = Math.floor(100*v) | ||||
|                         opacityHiddenInput.val(v/100) | ||||
|                         opacityLabel.text(v+"%"); | ||||
|                         refreshDisplay(colorHiddenInput.val()); | ||||
|                     }) | ||||
|                      $("<div>",{class:"red-ui-color-picker-opacity-slider-overlay"}).appendTo(sliderContainer); | ||||
|                     var sliderHandle = $("<div>",{class:"red-ui-color-picker-opacity-slider-handle red-ui-button red-ui-button-small"}).appendTo(sliderContainer).draggable({ | ||||
|                         containment: "parent", | ||||
|                         axis: "x", | ||||
|                         drag: function( event, ui ) { | ||||
|                             var v = Math.max(0,ui.position.left/($(this).parent().width()-$(this).outerWidth())); | ||||
|                             // Odd bug that if it is loaded with a non-0 value, the first time | ||||
|                             // it is dragged it ranges -1 to 99. But every other time, its 0 to 100. | ||||
|                             // The Math.max above makes the -1 disappear. The follow hack ensures | ||||
|                             // it always maxes out at a 100, at the cost of not allowing 99% exactly. | ||||
|                             v = Math.floor(100*v) | ||||
|                             if ( v === 99 ) { | ||||
|                                 v = 100; | ||||
|                             } | ||||
|                             // console.log("uip",ui.position.left); | ||||
|                             opacityHiddenInput.val(v/100) | ||||
|                             opacityLabel.text(v+"%"); | ||||
|                             refreshDisplay(colorHiddenInput.val()); | ||||
|                         } | ||||
|                     }); | ||||
|                     var opacityLabel = $('<small></small>').appendTo(row); | ||||
|                     setTimeout(function() { | ||||
|                         sliderHandle.css({ | ||||
|                             left: (parseFloat(opacityHiddenInput.val())*(sliderContainer.width() - sliderHandle.outerWidth()))+"px" | ||||
|                         }) | ||||
|                         opacityLabel.text(Math.floor(opacityHiddenInput.val()*100)+"%"); | ||||
|                     },50); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             var colorPanel = RED.popover.panel(picker); | ||||
|             setTimeout(function() { | ||||
|                 refreshDisplay(colorHiddenInput.val()) | ||||
|             },50); | ||||
|             colorPanel.show({ | ||||
|                 target: colorButton | ||||
|             }) | ||||
|         }); | ||||
|         setTimeout(function() { | ||||
|             refreshDisplay(colorHiddenInput.val()) | ||||
|         },50); | ||||
|         return container; | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         create: create | ||||
|     } | ||||
| })(); | ||||