Compare commits
	
		
			974 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | f9bce5a5f9 | ||
|  | 797ae096c8 | ||
|  | 6d76918424 | ||
|  | 2aced893c6 | ||
|  | f0373cd789 | ||
|  | 2f88dc64fc | ||
|  | 781ca77794 | ||
|  | c6e453fb00 | ||
|  | a40b3dd377 | ||
|  | 096b3534d8 | ||
|  | 5324244c55 | ||
|  | 993f1dc853 | ||
|  | d8a4e9e1ab | ||
|  | b3ffd33507 | ||
|  | c93870316c | ||
|  | fc9906624e | ||
|  | ba6209ba54 | ||
|  | f9769a73fe | ||
|  | 3a2f56cb95 | ||
|  | a4d33879dc | ||
|  | e2a91d1ea9 | ||
|  | f30f80d117 | ||
|  | 266274135e | ||
|  | a10439b67c | ||
|  | 0fd8d0e2bf | ||
|  | 47e2707fd3 | ||
|  | f7bb4a7d60 | ||
|  | 6102a31a31 | ||
|  | 1692c3b102 | ||
|  | ac60725d2a | ||
|  | 1542f73fa5 | ||
|  | 70a22187f7 | ||
|  | 347e598715 | ||
|  | a737810c50 | ||
|  | 92654a71fb | ||
|  | 18615640e0 | ||
|  | b8c80a2310 | ||
|  | c34c98386e | ||
|  | d8a3d2793f | ||
|  | 360b0d9997 | ||
|  | 356f46aaf4 | ||
|  | 87ac0507d9 | ||
|  | 63657c18e2 | ||
|  | 817f92a50e | ||
|  | 304be96dd6 | ||
|  | 9639081e7e | ||
|  | dca553048a | ||
|  | 6201ed4d55 | ||
|  | 6db2c04585 | ||
|  | f3840512ba | ||
|  | 9a6cf58565 | ||
|  | 78076122ba | ||
|  | 7429f66d6b | ||
|  | e59eff83b9 | ||
|  | 2083d85afa | ||
|  | 4c9f1369c8 | ||
|  | adca1d7855 | ||
|  | dfc4e99560 | ||
|  | 344076c943 | ||
|  | 710f1e2ca0 | ||
|  | 74ea85d19c | ||
|  | dded98e30c | ||
|  | 160c27c15a | ||
|  | a6a9025bab | ||
|  | a780d4463c | ||
|  | 23539ee907 | ||
|  | b515df611d | ||
|  | 0d896fef0b | ||
|  | 283d5c64cb | ||
|  | 3134bc432b | ||
|  | fd93fef73e | ||
|  | 8939a9c786 | ||
|  | 52c0d360b2 | ||
|  | d99432bff1 | ||
|  | 4dd2d3ac7d | ||
|  | aa7fe3668c | ||
|  | 83ebcf1dae | ||
|  | c9317659c5 | ||
|  | 6562c558de | ||
|  | 303f67c036 | ||
|  | 2482d122b8 | ||
|  | 1733c38b5c | ||
|  | 7a1e4e9e99 | ||
|  | e590313297 | ||
|  | b63d243e33 | ||
|  | e9c1216d5c | ||
|  | df9e50445e | ||
|  | 61339face6 | ||
|  | 9cd751e977 | ||
|  | 7aa08ff885 | ||
|  | a824caf712 | ||
|  | 395210e4f0 | ||
|  | e23354b2bb | ||
|  | bc472eb0b3 | ||
|  | 256f8e7226 | ||
|  | f41959537b | ||
|  | c9e05cf9f6 | ||
|  | 82d9a02d92 | ||
|  | dc9fa81346 | ||
|  | b91c178200 | ||
|  | adebdf36a5 | ||
|  | 4f34980c9f | ||
|  | e70766a535 | ||
|  | 55110dfbac | ||
|  | 56405ac903 | ||
|  | 2b2136c468 | ||
|  | f12031ee9e | ||
|  | c26852da77 | ||
|  | d9dc171c28 | ||
|  | d407f31ae5 | ||
|  | f688b8d299 | ||
|  | d8e6a7b687 | ||
|  | 7c42b04eff | ||
|  | f527841c29 | ||
|  | 48a8dc0989 | ||
|  | 7e35c9c754 | ||
|  | 7502a2b1ff | ||
|  | 6c2de40dba | ||
|  | ef90f19eaa | ||
|  | 90ab34591a | ||
|  | 21d3a3dd1e | ||
|  | b44e70115b | ||
|  | ac31957707 | ||
|  | 65e27a268d | ||
|  | 6bd59b10c7 | ||
|  | 6a6a692891 | ||
|  | 479b18354d | ||
|  | 9c6452544b | ||
|  | 0a6ff900da | ||
|  | f54f863611 | ||
|  | 9cc04da7b2 | ||
|  | d7f5b0c9d7 | ||
|  | 9bd4598c6a | ||
|  | e3b052bc38 | ||
|  | f215970649 | ||
|  | dfe1cd4f90 | ||
|  | 3d2e6aea7b | ||
|  | 749b0d7019 | ||
|  | 7978f85f7a | ||
|  | bd14acb68a | ||
|  | 1e9ce550db | ||
|  | 6278dfa77e | ||
|  | 2a3e355437 | ||
|  | f6b0459d27 | ||
|  | 790d6912fd | ||
|  | e69e5b4f50 | ||
|  | 483306e73c | ||
|  | 1148a0b637 | ||
|  | 524021f0fa | ||
|  | 5b5f9aa01d | ||
|  | f97f92c297 | ||
|  | 9d4139085b | ||
|  | 0ee7ffb5e5 | ||
|  | 8a7bb1be9f | ||
|  | d4135e80a6 | ||
|  | a5ade39d7c | ||
|  | f39b4e7d22 | ||
|  | 080469cdf5 | ||
|  | 835ad29417 | ||
|  | c09bea4710 | ||
|  | 879c0f4114 | ||
|  | 5feb07583b | ||
|  | 5388002f54 | ||
|  | c80fa9914b | ||
|  | b43d566968 | ||
|  | 6b4e15dd0f | ||
|  | d9ef32d7e8 | ||
|  | 49389d6f06 | ||
|  | c75dc3cc36 | ||
|  | c0eabf0438 | ||
|  | 7730d0a4f8 | ||
|  | e79da408a8 | ||
|  | 7381784d0f | ||
|  | 085fb283e5 | ||
|  | 61e0e50e7b | ||
|  | 00460d856b | ||
|  | 48958f392f | ||
|  | a84efeb5d5 | ||
|  | 1c8c05ae04 | ||
|  | 401d386812 | ||
|  | 6b07f58e8e | ||
|  | 6e8c978d12 | ||
|  | 5b2296b056 | ||
|  | dbf0486acb | ||
|  | b030e935ce | ||
|  | 29bd43413a | ||
|  | 2249b9449c | ||
|  | 30920b1b78 | ||
|  | 8f92a3e875 | ||
|  | ed1a55d9cd | ||
|  | 93ef84f495 | ||
|  | ccfcbe8526 | ||
|  | 5938143002 | ||
|  | 8135da71bd | ||
|  | a3c73a04c2 | ||
|  | 7f90d31846 | ||
|  | 45fbd22e28 | ||
|  | 4689d56955 | ||
|  | aa1b2808e7 | ||
|  | 40ad4bdbd8 | ||
|  | b6510d66e0 | ||
|  | 4ea33ea482 | ||
|  | e13d410b4a | ||
|  | 72da7e6c54 | ||
|  | fb05960d79 | ||
|  | 7bd0943412 | ||
|  | bb2649d063 | ||
|  | d743bdbf5a | ||
|  | 61890f19bc | ||
|  | b756a8edef | ||
|  | adcb2f1aa8 | ||
|  | e574f4516f | ||
|  | 2ac9c11ec9 | ||
|  | 1c470ab9e3 | ||
|  | 08b8a8e3af | ||
|  | 11ee1a7dcb | ||
|  | a281b8c74e | ||
|  | 5cb37148c6 | ||
|  | 05878d3176 | ||
|  | d1c42262d6 | ||
|  | c54cf26848 | ||
|  | bfb548636e | ||
|  | 36e1b2ba08 | ||
|  | 301ac279ff | ||
|  | 08d21ccba7 | ||
|  | 62876ca377 | ||
|  | 10f94148af | ||
|  | 31502c2ebc | ||
|  | 62b29ecb65 | ||
|  | 67337e013a | ||
|  | f987fa13ea | ||
|  | 73dfe631ce | ||
|  | 83ca8147ca | ||
|  | 1c11e7f97b | ||
|  | aefae79186 | ||
|  | 4b05a9bb6f | ||
|  | 2453719a87 | ||
|  | ea929b00e3 | ||
|  | ede940a398 | ||
|  | 67da853146 | ||
|  | 624befd704 | ||
|  | 203539841d | ||
|  | 262db23f7d | ||
|  | 28ea22f0e1 | ||
|  | 3f349c3531 | ||
|  | 9928e8562a | ||
|  | b1e3fc5761 | ||
|  | b2390f1caf | ||
|  | b9379f2ddf | ||
|  | 38a950a6dc | ||
|  | fb24dca019 | ||
|  | 07d131c945 | ||
|  | 0c1c710afe | ||
|  | 15cd93c30f | ||
|  | a5d9e17a8c | ||
|  | a82926dd0d | ||
|  | 12435b997a | ||
|  | 5945be95cf | ||
|  | 5c2e7ce407 | ||
|  | 834e894b1d | ||
|  | d25dac69d2 | ||
|  | 3cc4173399 | ||
|  | 36ab16c1ed | ||
|  | 5356373681 | ||
|  | f45a2643f2 | ||
|  | e55933706d | ||
|  | 3b3d696e45 | ||
|  | 281351e6b3 | ||
|  | 34089aec70 | ||
|  | 3658d0e039 | ||
|  | 7a10636128 | ||
|  | 604ba7f4bc | ||
|  | 27b7fb54e8 | ||
|  | d351aa842c | ||
|  | 59da705b8f | ||
|  | 99b8f16d88 | ||
|  | 06ffe722d4 | ||
|  | 6264104642 | ||
|  | c97812c340 | ||
|  | bd4c578230 | ||
|  | 6ec2949b6f | ||
|  | 1ff23ebfd9 | ||
|  | 7698990e37 | ||
|  | 17e092afb3 | ||
|  | 2db65b9d1f | ||
|  | c6436f47eb | ||
|  | e88b4a4412 | ||
|  | 01a177adfb | ||
|  | 052b5e0ea8 | ||
|  | 68cd447109 | ||
|  | 4a8a5ed8d4 | ||
|  | 84077505b0 | ||
|  | c4554b71d3 | ||
|  | 63ce743571 | ||
|  | 6cf53c611b | ||
|  | d8720ee325 | ||
|  | 73501f3ad3 | ||
|  | 54ee655472 | ||
|  | 571b9fb8e0 | ||
|  | cdd6b243ff | ||
|  | fca77a868f | ||
|  | 424e854778 | ||
|  | 0979d565bb | ||
|  | f5e6ca3e10 | ||
|  | 2bde07561f | ||
|  | 16c92cc739 | ||
|  | 8b31a918a4 | ||
|  | ee0bd49918 | ||
|  | a625eeeac8 | ||
|  | bfcd795687 | ||
|  | e2a9be9cec | ||
|  | 37dd075309 | ||
|  | 89769fb0e5 | ||
|  | b24fac3dd8 | ||
|  | 4794fe495c | ||
|  | 869fdbcc6a | ||
|  | 702e6d3b51 | ||
|  | 2913e13a30 | ||
|  | 5f1e37b7fa | ||
|  | ec0209b175 | ||
|  | a17dcbde0f | ||
|  | fbd159a23a | ||
|  | 599a6bf050 | ||
|  | 185b16a858 | ||
|  | e7e3ed4923 | ||
|  | 47df5476ba | ||
|  | d7c516ab00 | ||
|  | 50838970ec | ||
|  | 1d15ee7034 | ||
|  | 7029541b4f | ||
|  | ada8e447cc | ||
|  | 1841fc18fa | ||
|  | 94ee465682 | ||
|  | 3e021b3a75 | ||
|  | 0643f149b7 | ||
|  | 939768eec0 | ||
|  | f2235dacdc | ||
|  | 50017c28da | ||
|  | 85b2a03a42 | ||
|  | 829087550d | ||
|  | dd6f71fe85 | ||
|  | 92a928680c | ||
|  | d008b1970c | ||
|  | 4affbb8c6b | ||
|  | ddb2ea4b5f | ||
|  | a69683183f | ||
|  | 8d34f87667 | ||
|  | 128c4fe222 | ||
|  | b10141d71f | ||
|  | 68e0b35364 | ||
|  | 1324f5e59c | ||
|  | 7759aacb35 | ||
|  | fd6f7cd881 | ||
|  | 3fdeb38bb7 | ||
|  | e27f5d0460 | ||
|  | 0720128bd4 | ||
|  | 540472a093 | ||
|  | daca78b6cd | ||
|  | 4195840b2c | ||
|  | 57c529758e | ||
|  | 5ba9a0eb3f | ||
|  | b8888a5d46 | ||
|  | 0857f979ff | ||
|  | 11f4ae019c | ||
|  | 0ffeb0c5af | ||
|  | d6f6b41145 | ||
|  | 64daaeb310 | ||
|  | 0646b0060e | ||
|  | c794ca85fd | ||
|  | 5b4019dd3d | ||
|  | a03ccd7b59 | ||
|  | 4b64aad5ce | ||
|  | d146ff8794 | ||
|  | 5349bf7628 | ||
|  | a79e4d1bb3 | ||
|  | f462435dc2 | ||
|  | 48ad614441 | ||
|  | f699516fdb | ||
|  | ca5cbb640a | ||
|  | 0a96259ddf | ||
|  | d99b9c04e4 | ||
|  | 64d261e053 | ||
|  | eb027d98aa | ||
|  | a95727b654 | ||
|  | 4e636d7eec | ||
|  | 3cd53f617a | ||
|  | b1684e82d8 | ||
|  | a55027b838 | ||
|  | 28678acf74 | ||
|  | ce6594c8cc | ||
|  | 75855d5450 | ||
|  | f248699a30 | ||
|  | 29594726ca | ||
|  | 0a41b07297 | ||
|  | e45cb7fac1 | ||
|  | 489dbfc72a | ||
|  | a89ae7d77a | ||
|  | a1eeff4034 | ||
|  | 0e1013a570 | ||
|  | 4562b06a60 | ||
|  | 3c96218338 | ||
|  | f0a4ea099c | ||
|  | c8d6693fba | ||
|  | 81bbdfe413 | ||
|  | 0e362943bf | ||
|  | 1e37fed90b | ||
|  | aafcfef387 | ||
|  | 4b83d8160f | ||
|  | 73a41707e5 | ||
|  | c989c533e8 | ||
|  | 707dc8c65c | ||
|  | 4c6157a06e | ||
|  | f973396821 | ||
|  | e73216d4c1 | ||
|  | e6de26736b | ||
|  | d131addd63 | ||
|  | 0c7705beff | ||
|  | 08b11addec | ||
|  | 555f96cfaf | ||
|  | 59ffacb3df | ||
|  | 83acb66f00 | ||
|  | 1f9ae45875 | ||
|  | ffa628be2d | ||
|  | 8916f6f829 | ||
|  | 215c8fd261 | ||
|  | 061cc908a7 | ||
|  | 18a519f9ed | ||
|  | 7970c9dbe5 | ||
|  | 5ca0c066e2 | ||
|  | 563728c7b8 | ||
|  | 31a72b6562 | ||
|  | d3dfbc3034 | ||
|  | f143a6ba08 | ||
|  | 28a65923b6 | ||
|  | 4ca3df77b3 | ||
|  | 4cbe264869 | ||
|  | b6b65b6bf7 | ||
|  | e7cc42a927 | ||
|  | bba3ca8cc0 | ||
|  | 8423e2d245 | ||
|  | fc263718a1 | ||
|  | c3a99cf5a4 | ||
|  | f6820ec615 | ||
|  | 226ad3fe22 | ||
|  | a9b17e930c | ||
|  | 932ea7ba8f | ||
|  | c720d78c39 | ||
|  | 8d21e441a0 | ||
|  | 16ecb1a9cb | ||
|  | f68acca427 | ||
|  | 671d7e2beb | ||
|  | 52fc497412 | ||
|  | 2084ad318f | ||
|  | b530c1a43d | ||
|  | f2797a4153 | ||
|  | 659c326f89 | ||
|  | 534b07d120 | ||
|  | de64fc8b8d | ||
|  | 1e234fcb73 | ||
|  | fa9a7e725b | ||
|  | 95b2675f03 | ||
|  | 564902b886 | ||
|  | 071a04595a | ||
|  | eaa4b76ede | ||
|  | 74a1713e99 | ||
|  | 5f5aa0b2f7 | ||
|  | eef59fd40e | ||
|  | 361ff315e9 | ||
|  | eeea8e530e | ||
|  | 8d5286703f | ||
|  | 74f2180fa4 | ||
|  | d042169f2e | ||
|  | 1fd87bf664 | ||
|  | eeaff6b553 | ||
|  | 6efd048fd6 | ||
|  | 6e9e694f66 | ||
|  | 44a0f1b505 | ||
|  | 9790211891 | ||
|  | be18cc9f2d | ||
|  | 8caee09ea4 | ||
|  | 26f5305593 | ||
|  | d33029027f | ||
|  | 339aaaec57 | ||
|  | db2425c473 | ||
|  | 18731f6055 | ||
|  | 34f1f7a31d | ||
|  | 7ef153756b | ||
|  | bf90509526 | ||
|  | d853eca489 | ||
|  | 869ae01da9 | ||
|  | d63996eea1 | ||
|  | 9bbc8eda9d | ||
|  | 9cc1b03c56 | ||
|  | b1ab26e3ad | ||
|  | 96820418b5 | ||
|  | 385d9f16e9 | ||
|  | d56fce37dd | ||
|  | aef2c9e5cf | ||
|  | 89a05c580f | ||
|  | b85e562980 | ||
|  | a0e6628757 | ||
|  | 60a41524f0 | ||
|  | 6042395b81 | ||
|  | 8a5db8ce4b | ||
|  | 196d6e79e2 | ||
|  | 91f16215e5 | ||
|  | 9c675a7847 | ||
|  | f9e09e87d6 | ||
|  | 73574d6293 | ||
|  | 0a5a42b32a | ||
|  | de225205bd | ||
|  | 8a47d36480 | ||
|  | d5f3ba8d8a | ||
|  | 782a06ce84 | ||
|  | 5cdafc50fb | ||
|  | 0ca3cdb9ae | ||
|  | a1d6cbd5fd | ||
|  | 6c36778cac | ||
|  | 1c3a97a71a | ||
|  | 3489fe0cf4 | ||
|  | 74b6d9dff9 | ||
|  | 06ee9aa05c | ||
|  | f0f40a8606 | ||
|  | 1f2c9879bd | ||
|  | d1eb82bdf6 | ||
|  | 8167f623e3 | ||
|  | 9555e296a2 | ||
|  | f460283fa1 | ||
|  | 79da8e5a37 | ||
|  | a35ce22218 | ||
|  | 1c905da8c2 | ||
|  | 2b558768f1 | ||
|  | 7607c4c882 | ||
|  | c9f4813ce1 | ||
|  | 0428e27039 | ||
|  | e30da2168d | ||
|  | 0cd20768f4 | ||
|  | ab31f34862 | ||
|  | 9a4ff5cb43 | ||
|  | f66c91e18e | ||
|  | a235745be7 | ||
|  | 9516da01e3 | ||
|  | 7657bd2375 | ||
|  | 0adcea9e7c | ||
|  | aa8ad60083 | ||
|  | 5d98a86a6b | ||
|  | 4418fdaed6 | ||
|  | c58c45c917 | ||
|  | 45eba5cabd | ||
|  | 3ab0d0d865 | ||
|  | a6803081ab | ||
|  | 8debed805b | ||
|  | fc9835512d | ||
|  | 5f0cab8cc2 | ||
|  | bd391963bc | ||
|  | 97fa28fb10 | ||
|  | 67d5b39c96 | ||
|  | dbceef2581 | ||
|  | 5b22ccfca6 | ||
|  | 714c254bab | ||
|  | 90f4db9158 | ||
|  | eed470ddae | ||
|  | 49f72881f4 | ||
|  | a76674032d | ||
|  | ec392a7f9a | ||
|  | 8a2ae6c480 | ||
|  | b3796a8e24 | ||
|  | b9144ff987 | ||
|  | 5344949c71 | ||
|  | 05cbba9a35 | ||
|  | 325c6135cf | ||
|  | fdea19a45b | ||
|  | fad63c0c18 | ||
|  | f002560616 | ||
|  | 8e7d52e645 | ||
|  | d119594cbf | ||
|  | 84f7da6e93 | ||
|  | 22e1bafe1b | ||
|  | 3f8e42e510 | ||
|  | 9704fb04d9 | ||
|  | dcfaf1e2b9 | ||
|  | 42f7dc1947 | ||
|  | eb1a597456 | ||
|  | 8368815db5 | ||
|  | 9c6295d0d8 | ||
|  | 4d19f881e9 | ||
|  | 3a8820397b | ||
|  | 85b1c1fe97 | ||
|  | a4de9e94dd | ||
|  | 0dd2c7fe24 | ||
|  | f22c3b549e | ||
|  | 3c60b3d2c9 | ||
|  | f2d36b84b5 | ||
|  | 9af08ef26a | ||
|  | b4be1184fd | ||
|  | c60e0d389c | ||
|  | d658fe7709 | ||
|  | 54036a2b4d | ||
|  | 2da9572a45 | ||
|  | 306825aa90 | ||
|  | c797073c05 | ||
|  | d9d65d59d1 | ||
|  | aad29e4487 | ||
|  | b00985f99f | ||
|  | 538a16a5fb | ||
|  | 300a8d3a89 | ||
|  | e3b7c5fce7 | ||
|  | 2e87ebe800 | ||
|  | 7ed9e7cdd4 | ||
|  | 7ff9c2885d | ||
|  | 18c8bbb0fc | ||
|  | 9a49fb9450 | ||
|  | 84457bc7b4 | ||
|  | 15f1e2c85c | ||
|  | 15e828e975 | ||
|  | e4626ee52b | ||
|  | 1866c9c7ef | ||
|  | a0f91aa814 | ||
|  | a89c7b1a70 | ||
|  | ded1376957 | ||
|  | 252040f03b | ||
|  | d29abc2724 | ||
|  | 44c35d2644 | ||
|  | f9b972349d | ||
|  | e06cadd761 | ||
|  | ee45d6b48f | ||
|  | d915b280d4 | ||
|  | 39d90fe881 | ||
|  | b9da1f18b4 | ||
|  | 69a0934173 | ||
|  | 289de85754 | ||
|  | 0ec95041d9 | ||
|  | fcb6f78d54 | ||
|  | 29e9740668 | ||
|  | ea8c6d5cce | ||
|  | e4c951984a | ||
|  | 0071afb205 | ||
|  | d3c7ac75be | ||
|  | 55d7420abf | ||
|  | 489b56456f | ||
|  | 1f24fcb364 | ||
|  | 722b31edee | ||
|  | 765f0393b0 | ||
|  | 6868ef044b | ||
|  | 5dd0622e40 | ||
|  | 48bdab1dcf | ||
|  | aee483e9f1 | ||
|  | 8542b9bf67 | ||
|  | feaf6f2501 | ||
|  | d7d30aa972 | ||
|  | 91c23d1f7d | ||
|  | 57479edc59 | ||
|  | 4b462eaae9 | ||
|  | c60fb3bc25 | ||
|  | b17c34402d | ||
|  | 6ad71bd222 | ||
|  | ccc08be0ee | ||
|  | 2a2fc80931 | ||
|  | 9ebca91775 | ||
|  | 456fc23463 | ||
|  | eb17562f4d | ||
|  | b7dbfd5cfc | ||
|  | cdc7ab562a | ||
|  | e6b5552cba | ||
|  | eecf92183f | ||
|  | 11656382a7 | ||
|  | e4d788ad0b | ||
|  | 3017442702 | ||
|  | ba37db275c | ||
|  | 521e669879 | ||
|  | 12e302c10a | ||
|  | 7220af3ef0 | ||
|  | 42f4e0fa86 | ||
|  | 022d066fe0 | ||
|  | 4c9d7cbeed | ||
|  | 1541e382e4 | ||
|  | 1d9488d24f | ||
|  | 6cbc1afb9b | ||
|  | 3f86b660ed | ||
|  | 4603f2d9ca | ||
|  | da818cf420 | ||
|  | 86a2ed652d | ||
|  | 269761f222 | ||
|  | 53ca3046b3 | ||
|  | f484156d8e | ||
|  | 1da8712a4a | ||
|  | dd47eba88c | ||
|  | 0ade8ff7a2 | ||
|  | 6a528b5fdb | ||
|  | 7f63ddc9ea | ||
|  | d6b326c134 | ||
|  | d944298dd7 | ||
|  | 0136ebd2b4 | ||
|  | 45f8def1ed | ||
|  | 7c6e8eeefc | ||
|  | e81e48cde3 | ||
|  | 8eebb6ea2d | ||
|  | ad8290ebcb | ||
|  | 15b6f6268b | ||
|  | 92d5af7446 | ||
|  | d57425a15e | ||
|  | a457c06500 | ||
|  | 906bbae899 | ||
|  | e360e57a5b | ||
|  | c5753a013c | ||
|  | 691b083364 | ||
|  | b74a35b9d1 | ||
|  | 82269462a4 | ||
|  | d7943aab28 | ||
|  | 446eb8e978 | ||
|  | d91a99c833 | ||
|  | dc00870461 | ||
|  | b8f578862e | ||
|  | dc24c05229 | ||
|  | f62cf6818b | ||
|  | c05e9da9c5 | ||
|  | 6c00194d35 | ||
|  | 6bc3f82afe | ||
|  | 12e46deea2 | ||
|  | 8608d010b8 | ||
|  | 9d4d1acf2d | ||
|  | 23087447f1 | ||
|  | 3008e4e60f | ||
|  | 9d52ed5ff6 | ||
|  | 5f047633c3 | ||
|  | d3be1f1e2c | ||
|  | c3b1cf7c35 | ||
|  | 682345da22 | ||
|  | 82f289c42e | ||
|  | 78eae99bd4 | ||
|  | 9ec7bb8d41 | ||
|  | 2b9bfbc309 | ||
|  | e50d04077b | ||
|  | b6fcaacb77 | ||
|  | 939da4e551 | ||
|  | f30ce1f9eb | ||
|  | 343588b2a0 | ||
|  | 77b13ce9d4 | ||
|  | 7cb41d2ca9 | ||
|  | 8bbc9e6502 | ||
|  | e29a0df3fd | ||
|  | 0eba04aac0 | ||
|  | b78210e3be | ||
|  | 958de21be8 | ||
|  | 0eb4742982 | ||
|  | 78b1bf8f25 | ||
|  | 08f2741871 | ||
|  | 98b24ae630 | ||
|  | 7fc056c8e3 | ||
|  | 0411623857 | ||
|  | 365d71264f | ||
|  | 0d4d51fc39 | ||
|  | b21745808b | ||
|  | e4d5271d58 | ||
|  | 8f2f3bf75d | ||
|  | 9e96eba98f | ||
|  | 0441c83fd7 | ||
|  | d8405052d8 | ||
|  | cc02b07ff0 | ||
|  | 2d6aac7d6f | ||
|  | 589d43f0e5 | ||
|  | 13c1d1df7a | ||
|  | 08ade44dc8 | ||
|  | 8fb1c76247 | ||
|  | 3ad9053d65 | ||
|  | 8fe07e0f07 | ||
|  | 09b069c129 | ||
|  | b2db083f39 | ||
|  | 53e2f3e263 | ||
|  | 945fbbc065 | ||
|  | 4dc9c7714c | ||
|  | 7302ac5871 | ||
|  | 1cfad27d6f | ||
|  | d82fe95076 | ||
|  | 8f8df4971c | ||
|  | fd66569950 | ||
|  | e97d9fb0b2 | ||
|  | 04424c2a7c | ||
|  | 241e2828e7 | ||
|  | 5f6a0141f0 | ||
|  | ef2f71859c | ||
|  | fdaeeb5d01 | ||
|  | e594ffe0f8 | ||
|  | 9f8c32ce8f | ||
|  | 762eb07dd4 | ||
|  | 0300458ba8 | ||
|  | 3959fcdc88 | ||
|  | ea76c18f59 | ||
|  | d125ecc671 | ||
|  | 7d9b90a1f3 | ||
|  | 7402c27b6a | ||
|  | 4e762e2063 | ||
|  | 0afe98b399 | ||
|  | daed059c47 | ||
|  | f1ce0fab8b | ||
|  | b5d3f505e3 | ||
|  | 6c8f688f33 | ||
|  | ed1b601a84 | ||
|  | add541f67f | ||
|  | bea8eb799f | ||
|  | 3cac48e86f | ||
|  | 64722da4a7 | ||
|  | ada1e624d8 | ||
|  | 69f83cb905 | ||
|  | 807873f685 | ||
|  | 8d4be848b0 | ||
|  | 59a7c46482 | ||
|  | eabfeb9502 | ||
|  | 291240dd94 | ||
|  | 2f6ed47168 | ||
|  | 9a73568c7a | ||
|  | acdef87be7 | ||
|  | b14546605d | ||
|  | 5ad46106f4 | ||
|  | 3e9be9eed3 | ||
|  | 7318a7b767 | ||
|  | b78682f413 | ||
|  | e50659af09 | ||
|  | 3454e5ac77 | ||
|  | 9e26aeea1d | ||
|  | d7715b05ee | ||
|  | db433efbef | ||
|  | f1f8c887c6 | ||
|  | 9ae4745ca5 | ||
|  | 726d9c8ec5 | ||
|  | a9bfa4e79b | ||
|  | 8e6bba143a | ||
|  | feeba77f16 | ||
|  | ea41a0e842 | ||
|  | 74b7500181 | ||
|  | 594ff8cd3d | ||
|  | 337f5f9b98 | ||
|  | 41445a1b48 | ||
|  | 269763fa0c | ||
|  | fa90eeac55 | ||
|  | edceffdaaf | ||
|  | ce25fc658b | ||
|  | b27db3e2e7 | ||
|  | 622d4214f7 | ||
|  | 0c53b5310a | ||
|  | 45ff86eae5 | ||
|  | 47316b0fb7 | ||
|  | c09be02e4e | ||
|  | bd59398cab | ||
|  | 8080ebceb4 | ||
|  | 1e2521c37a | ||
|  | b744491dd2 | ||
|  | 2a089f7d90 | ||
|  | 088e3e5374 | ||
|  | bac8a3092f | ||
|  | e56da17957 | ||
|  | 71b2e714ee | ||
|  | 1b06afb81c | ||
|  | 819e48b03a | ||
|  | 1861c1feb6 | ||
|  | 0efccc4758 | ||
|  | a9feeaa1c9 | ||
|  | f9c869f521 | ||
|  | 9c766d76f3 | ||
|  | 333acccff6 | ||
|  | 1790ebf567 | ||
|  | 6354b68bae | ||
|  | 41b10fd5e4 | ||
|  | 4ad540412a | ||
|  | 8916cf273e | ||
|  | b2923d0fc4 | ||
|  | 8fc0018cb9 | ||
|  | d0f57efe0b | ||
|  | 595ff63b72 | ||
|  | 9990046abb | ||
|  | 8dacf72b3c | ||
|  | 2801838ffa | ||
|  | 59b34c2b3f | ||
|  | f55f85aa14 | ||
|  | 627a80419a | ||
|  | 4bc482bc85 | ||
|  | 0a1257a23a | ||
|  | 51d99248d7 | ||
|  | af9aa74337 | ||
|  | 321f5e615b | ||
|  | 95c31f3e17 | ||
|  | cf69dbe1dc | ||
|  | e92241bf97 | ||
|  | 44dc37ef6d | ||
|  | 6b0bef61a5 | ||
|  | 0c227be02d | ||
|  | 08794bad74 | ||
|  | 44693dd23a | ||
|  | 75a7be41eb | ||
|  | 913b09570c | ||
|  | 1c9b5dfd00 | ||
|  | 2954ae917b | ||
|  | 736ddaeca4 | ||
|  | b909e32201 | ||
|  | bcff74327b | ||
|  | e60b63e72f | ||
|  | 2bf5d2b4e5 | ||
|  | e1d09349ff | ||
|  | f07c8108fc | ||
|  | 39f5078d6b | ||
|  | 1d54761d48 | ||
|  | 7cb9b2da66 | ||
|  | b1896e3737 | ||
|  | 6fa78bdb04 | ||
|  | ee96f7d937 | ||
|  | 129ca0e39f | ||
|  | 906703db5f | ||
|  | 0cd4a2b4ec | ||
|  | aef8aaa0bd | ||
|  | 428fbb8622 | ||
|  | b9f03e7d80 | ||
|  | db686388b9 | ||
|  | 626cba4002 | ||
|  | 37d4a6b9e2 | ||
|  | 12c4561aba | ||
|  | fed49e3718 | ||
|  | 3af37d3984 | ||
|  | 0f49a11228 | ||
|  | 27d3e165b0 | ||
|  | e941c22f6c | ||
|  | 7281e4deb6 | ||
|  | f2191e94b3 | ||
|  | 349ebfe4db | ||
|  | 708365c4ac | ||
|  | 0e9ea0aff1 | ||
|  | 63ba05a193 | ||
|  | 4b702815cf | ||
|  | 55e66ebcac | ||
|  | dcd8b3699c | ||
|  | 0e2d13172a | ||
|  | 2e2556fdad | ||
|  | 859a7538e1 | ||
|  | 0d1543ee8a | ||
|  | d3a98dd355 | ||
|  | ad10125303 | ||
|  | b89e866d39 | ||
|  | afbaf1cfe0 | ||
|  | b3be8b30e7 | ||
|  | 8bfab8f73d | ||
|  | c6ad2c9ad2 | ||
|  | 3b44d9972e | ||
|  | af736c98f2 | ||
|  | f1377fa217 | ||
|  | 2ba146b9ff | ||
|  | 2361607aa3 | ||
|  | 86ffc80098 | ||
|  | 7f6915eb59 | ||
|  | d69bcad028 | ||
|  | 4cb45e2712 | ||
|  | b7a0ad703a | ||
|  | 7610b9a975 | ||
|  | 7d95f621df | ||
|  | bba210e112 | ||
|  | 3a97e20bde | ||
|  | 4fe7ea00b0 | ||
|  | 3ec8ecd4de | ||
|  | 401e65e852 | ||
|  | e7c5b691a0 | ||
|  | 9f3ea8da67 | ||
|  | d1269b441d | ||
|  | 7615743aa5 | ||
|  | dcaa0eeea4 | ||
|  | 1d5e2f703e | ||
|  | 4d84d624b1 | ||
|  | 633a6a0ee6 | ||
|  | c7bcd3f438 | ||
|  | d3a29a6f16 | ||
|  | 827711ca89 | ||
|  | 76e98f74fa | ||
|  | fb09f4b22d | ||
|  | bb06585748 | ||
|  | c76ba1dcc7 | ||
|  | a115301b04 | ||
|  | 72917117a9 | 
							
								
								
									
										10
									
								
								.jshintrc
									
									
									
									
									
								
							
							
						
						| @@ -2,12 +2,18 @@ | ||||
|     "asi": true,        // allow missing semicolons | ||||
|     "curly": true,      // require braces | ||||
|     "eqnull": true,     // ignore ==null | ||||
|     //"eqeqeq": true,   // enforce === | ||||
|     "freeze": true,     // don't allow override | ||||
|     "indent": 4,        // default indent of 4 | ||||
|     "forin": true,      // require property filtering in "for in" loops | ||||
|     "immed": true,      // require immediate functions to be wrapped in ( ) | ||||
|     "nonbsp": true,     // warn on unexpected whitespace breaking chars | ||||
|     //"strict": true,   // commented out for now as it causes 100s of warnings, but want to get there eventually | ||||
|     //"unused": true,   // Check for unused functions and variables | ||||
|     "loopfunc": true,   // allow functions to be defined in loops | ||||
|     //"expr": true,       // allow ternery operator syntax... | ||||
|     "sub": true         // don't warn that foo['bar'] should be written as foo.bar | ||||
|     //"expr": true,     // allow ternery operator syntax... | ||||
|     "shadow": true,     // allow variable shadowing (re-use of names...) | ||||
|     "sub": true,        // don't warn that foo['bar'] should be written as foo.bar | ||||
|     "proto": true,      // allow setting of __proto__ in node < v0.12, | ||||
|     "esversion": 6      // allow es6 | ||||
| } | ||||
|   | ||||
							
								
								
									
										11
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						| @@ -9,16 +9,11 @@ addons: | ||||
|     packages: | ||||
|     - g++-4.8 | ||||
|     - gcc-4.8 | ||||
| matrix: | ||||
|   allow_failures: | ||||
|   - node_js: "5" | ||||
| before_install: | ||||
|   - npm install -g npm@latest-2 | ||||
| node_js: | ||||
|   - "5" | ||||
|   - "8" | ||||
|   - "7" | ||||
|   - "6" | ||||
|   - "4" | ||||
|   - "0.12" | ||||
|   - "0.10" | ||||
| script: | ||||
|   - istanbul cover ./node_modules/.bin/grunt --report lcovonly && istanbul report text && ( cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js || true ) && rm -rf coverage | ||||
| before_script: | ||||
|   | ||||
							
								
								
									
										964
									
								
								CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,964 @@ | ||||
| #### 0.17.5: Maintenance Release | ||||
|  | ||||
|  - Add express-session missing dependency for oauth | ||||
|  - Fix improper type tests is core test cases | ||||
|  - File node: recreate write stream when file deleted Fixes #1351 | ||||
|  - Add flow stopping trace messages | ||||
|  - Fix userDir test case when .config.json exists (#1350) | ||||
|  - Do not try to send msg after http request error handled Fixes #1344 | ||||
|  - Fix boundary problem in range node (#1338) | ||||
|  - Modify messages in node properties to refer messages.json (#1339) | ||||
|  - Fix settings.js replacing webSocketVerifyClient by webSocketNodeVerifyClient (#1343) | ||||
|  | ||||
|  | ||||
| #### 0.17.4: Maintenance Release | ||||
|  | ||||
|  - Add request node test case for POSTing 0 | ||||
|  - Allow false and 0 in payload for httprequest (#1334) | ||||
|  - Add file extension into flow name of library automatically (#1331) | ||||
|  - Fix accessing global context from jsonata expressions Fixes #1335 | ||||
|  - Disable editor whilst a deploy is inflight Fixes #1332 | ||||
|  - Replace Unknown nodes with their real versions when node loaded | ||||
|  - Retry auto-install of modules that fail | ||||
|  - Fix column name in link nodes to refer language file (#1330) | ||||
|  - Use namespaces with link node title attributes i18n name Fixes #1329 | ||||
|  - Tidy up GPIO pin table presentation Fixes #1328 | ||||
|  - Join: count of 0 should not send on every msg | ||||
|  - Handle importing only one end of a link node pair | ||||
|  - Make sending to Debug synchronous again Fixes #1323 | ||||
|  - Make send-error behaviour optional in file node | ||||
|  - Restore File In node behaviour of sending msg on error | ||||
|  - Expose context.keys within Function node | ||||
|  - JSON parser default should be not formatting output | ||||
|  | ||||
|  | ||||
| #### 0.17.3: Maintenance Release | ||||
|  | ||||
|  - Fix flow library in menu to support period characters as flow name (#1320) | ||||
|  - editorTheme not setting custom css/scripts properly | ||||
|  - Fix missing icons for some nodes (#1321) | ||||
|  - Add reformat button to JSONata test data editor | ||||
|  - Update delay node status without spawning unnecessary intervals | ||||
|  - Avoid stringify ServerResponse and Socket in Debug node Fixes #1311 | ||||
|  - Fix creating userDir other than system drive on Windows (#1317) | ||||
|  - Trigger node not handling a duration of 0 as block mode Fixes #1316 | ||||
|  - Unable to config GPIO Pin 13 Fixes #1314 | ||||
|  | ||||
| #### 0.17.2: Maintenance Release | ||||
|  | ||||
|  - Fix GPIO node labels | ||||
|  | ||||
| #### 0.17.1: Maintenance Release | ||||
|  | ||||
|  - Fix PI gpio to use BCM | ||||
|  - Prevent event thread contention when sending to Debug node Closes #1311 | ||||
|  - Fix Bug: Can not display node icon when npm package has scope (#1305) (#1309) | ||||
|  - Clear moved flag when nodes are deployed | ||||
|  | ||||
| #### 0.17: Milestone Release | ||||
|  | ||||
| Runtime | ||||
|  | ||||
|  - Return flow rev on reload api when api v2 enabled Closes #1273 | ||||
|  - Provide single endpoint to load all node message catalogs | ||||
|  - Add .trace and .debug to Node prototype | ||||
|  - Rename oauth auth scheme to strategy as it works for openid | ||||
|  - Allow oauth schemes provide a custom verify function | ||||
|  - Add support for oauth adminAuth configs | ||||
|  - Cache auth details to save needlessly recalculating hashes | ||||
|  - Add context.keys function to list top-level keys | ||||
|  - Strip BOM character from JSON files if present Fixes #1239 | ||||
|  - Version check no meta (#1243) | ||||
|  - Ensure all nodes have access to global context Fixes #1230 | ||||
|  - Don't process subscription for unauthenticated comms link Fixes #851 | ||||
|  - Clone credentials when passing to node Fixes #1198 | ||||
|  - Resolve dir argument of getLocalNodeFiles function (#1216) | ||||
|  - Add wait for writing a library entry into a file. (#1186) | ||||
|  - Use correct Buffer.from method rather than constructor | ||||
|  - update core nodes to use newer Buffer syntax | ||||
|  - Treat missing msg properties as undefined rather than throw error Fixes #1167 | ||||
|  - Allows flows to be enabled/disabled in the runtime | ||||
|  - add off option to logging settings comment | ||||
|  - Log error stack traces if verbose flag is set | ||||
|  - Extract line number if available from node load errors | ||||
|  - Add node 8 to travis (with allow failure) | ||||
|  - Shuffle promises for creating default package.json | ||||
|  - Create a package.json file in userDir if one doesn't exist | ||||
|  - autoInstallModules option must honour version/pending_version | ||||
|  - Refuse to update a non-local node module | ||||
|  - Finalise nodeSettings and update tlsConfigDisableLocalFiles | ||||
|  - Allow a node to declare what settings should be made available to the editor. (#1185) | ||||
|  - Add node whitelist function (#1184) | ||||
|  - Allow a node to declare settings that should be exported | ||||
|  - Add test coverage for deleting a flow | ||||
|  - Update tests for oauth -> strategy rename | ||||
|  - Fix the test cases which sometimes fails due to timing. (#1228) | ||||
|  - Extend timeout for the test case of installing non-existant path. (#1191) | ||||
|  - Fix loader test to expect line numbers in load errors | ||||
|  - Update ui_spec for icon module path | ||||
|  - let node installer try to save with ~ version prefix to allow minor updates | ||||
|  - Log error when non-msg-object is returned from a Function | ||||
|  - Timeout a node that fails to close - default 15s timeout | ||||
|  - Pass a 'removed' parameter to node close handler | ||||
|  - Remove event passing for icons/examples from the api layer | ||||
|  - Update general dependencies | ||||
|  | ||||
| Nodes | ||||
|  | ||||
|  - Do not log node errors if handled by a Catch node | ||||
|  - Fix wrong number of double quotes in CSV parsing | ||||
|  - let csv node handle ip addresses without trying to parse | ||||
|  - Update debug node to register the settings it uses | ||||
|  - Handle IncomingMessage/ServerResponse object types in debug Fixes #1202 | ||||
|  - Toggling debug node enabled/disabled state should set state dirty Fixes #1203 | ||||
|  - redo delay node status messages to be interval based | ||||
|  - Update delay node ui | ||||
|  - Add new msg.delay option to delay node | ||||
|  - stop delay node spamming web socket (when in fast rate limit mode) | ||||
|  - Delay/Range node help tidy up | ||||
|  - Bug fix in exec node. White spaces in arguments now works (#1285) | ||||
|  - Make exec node explicitly call SIGTERM for default | ||||
|  - Fix exec node error tests on Windows (#1234) | ||||
|  - update messages for updated exec node | ||||
|  - Make exec node spawn and exec outputs more consistent | ||||
|  - Exec node for windows environment (#1200) | ||||
|  - remove requirement for cmd in exec node config + new style info | ||||
|  - retry exec node tests | ||||
|  - let exec node take msg.kill SIG... param and pid param | ||||
|  - Third output from Exec node must be consistent for success/failure conditions | ||||
|  - exec node returns 0 on the third output if command ended without error. (#1160) | ||||
|  - exec node can be killed on demand | ||||
|  - add "split/stream" ability to file in node | ||||
|  - add port label to file node and update info | ||||
|  - Allow nodes to have translations not in core (#1183) | ||||
|  - fix tcp node new Buffer alloc size 0 | ||||
|  - change pin selection table for pi gpis nodes | ||||
|  - stop using sudo for Pi gpio access | ||||
|  - adding frequency configuration to pwm output (#1206) | ||||
|  - Fix Pi GPIO debounce | ||||
|  - let Hypriot on Pi detect gpio correctly | ||||
|  - More core node info help tidy up | ||||
|  - Tidy up more core node help text | ||||
|  - Tidy up parser node edit dialogs and help text | ||||
|  - yet more core node info updates | ||||
|  - more core node info updates to newer style | ||||
|  - Update some core nodes info | ||||
|  - First pass of new node-info style | ||||
|  - MQTT new style info | ||||
|  - Fix empty extra node help content issue | ||||
|  - Handle HTTP In url that is missing its leading / Fixes #1218 | ||||
|  - Add file upload support to HTTP In node | ||||
|  - HTTP Request node: add info on how to do form encoding | ||||
|  - Prevent unmodified msg.headers from breaking HTTP Request flows Closed #1015 | ||||
|  - Add cookie handling to HTTP Request node | ||||
|  - Add guard against the http-request buffer fix being reverted | ||||
|  - Multipart streaming | ||||
|  - Add http-request node unit tests | ||||
|  - http request node add transport validity check and warn. | ||||
|  - Update follow_redirects to fix http_proxy handling Fixes #1172 | ||||
|  - Allow statusCode/headers to be set directly within HTTP Response node | ||||
|  - let inject "between time" also fire at start - Plus new info | ||||
|  - remove repeat symbol from inject if repeat is 0 | ||||
|  - Add port labels to inject node (to show types) | ||||
|  - Add buffer joiner mode to Join node | ||||
|  - Let join node auto re-assemble buffers | ||||
|  - let join also accumulate strings (and not fail) | ||||
|  - Add Pretty print option to JSON node and | ||||
|  - Fix selection of link nodes | ||||
|  - Add link label value as portLabels | ||||
|  - Add sentence about clearing retained topic on mqtt | ||||
|  - make sure MQTT client closes if redeploy during reconnect | ||||
|  - make sure MQTT client closes if redeploy during reconnect | ||||
|  - slight filed size adjust for mqtt broker port field - allow 5 digits | ||||
|  - Add help info for split node | ||||
|  - split node - in object mode allow msg.complete on its own | ||||
|  - let split of objects use key to set another property (e.g. topic) | ||||
|  - adding streaming modes into split node | ||||
|  - let split node reassemble based on a final packet. (as well as the first) | ||||
|  - Add buffer support to split node | ||||
|  - updated split/join node (split still needs work before release) | ||||
|  - Added a name icon and a description label on edit subflow window. | ||||
|  - Don't display port labels for subflow pseudo-port nodes | ||||
|  - Added a name icon and a description label on edit subflow window. | ||||
|  - tcp request - remove confusing timeout wording from info | ||||
|  - Final TCP node nits - let 0 do it's thing as per every other timeout | ||||
|  - fix tcp port not waiting as per info/previous behaviour | ||||
|  - TCP In: Fix error in timout callback (#1249) | ||||
|  - Make tcp send msg more consistent | ||||
|  - Update 31-tcpin.js (#1235) | ||||
|  - really close tcp node connection right away (if told to) | ||||
|  - clone message before send in stay connected mode | ||||
|  - Better template node help example | ||||
|  - Add option to parse Template result as JSON before sending | ||||
|  - nail trigger test for windows AND linux | ||||
|  - give up on SIGQUIT for widows test | ||||
|  - better tests for windows nodes | ||||
|  - comment out 2nd exec node kill tests | ||||
|  - fixes for grunt files tests on Windows | ||||
|  - Add events to test helper | ||||
|  - Change default value of tlsConfigDisableLocalFiles to false | ||||
|  - Add the node setting tlsConfigDisableLocalFiles for tls node. (#1190) | ||||
|  - UI to upload certificates and keys for TLS node | ||||
|  - Update trigger help | ||||
|  - let trigger node set repeated outputs | ||||
|  - Move udp sock error listener to only be instantiated once. | ||||
|  - Let watch node recurse into subdirectories | ||||
|  - Misconfigured WebSocket nodes should not register msg handlers | ||||
|  - Add websocketVerifyClient option to enable custom websocket auth Fixes #1127 | ||||
|  | ||||
| Editor | ||||
|  | ||||
|  - Bump ACE editor to v1.2.7 | ||||
|  - Add RED.utils.getNodeLabel utility function | ||||
|  - Include module name in requests for node icons | ||||
|  - Change debug message menu icon | ||||
|  - Handle empty array/objects in debug view | ||||
|  - Add per-node filter option to Debug pane | ||||
|  - Ensure debug node marked changed when button pressed | ||||
|  - Fix pop-out debug window for all the recent updates | ||||
|  - Add debug message menu | ||||
|  - Don't include msg. in debug message copied paths | ||||
|  - Format Buffer numbers as hex by default | ||||
|  - Remember formatting choices for dbg msg elements | ||||
|  - Allow debug msg elements to be pinned | ||||
|  - Only show debug tools under the debug tab | ||||
|  - Fix test for valid js identifiers in debug path construction | ||||
|  - Remove unused modified flag on debug messages | ||||
|  - Add copy path/value buttons to debug messages | ||||
|  - dont match only part of the node type (#1242) | ||||
|  - Add editorTheme.logout.redirect to allow redirect on logout Closes #1213 | ||||
|  - Handle logging out and already logged-out editor Fixes #1288 | ||||
|  - Fix bug: Export Subflows (#1282) | ||||
|  - destroy editor to ensure fully removed on close (function, template, comment) | ||||
|  - Don't try to nls status text starting with '.' Fixes #1258 | ||||
|  - Add note of removed flows in diffConfig (#1253) | ||||
|  - Add description to flow same as subflow | ||||
|  - Allow tabs to be enabled/disabled in the editor | ||||
|  - Make H3 sections in node help collapsible | ||||
|  - Add JSON Expression editor | ||||
|  - Expression editor - clear legacy flag for blank expressions | ||||
|  - Ensure node labels are reordered properly to match outputs | ||||
|  - Add 'none' placeholder for empty port label form | ||||
|  - Don't mark a node changed when going from none to blank labels | ||||
|  - Leave a node to nls its own port labels | ||||
|  - Allow a node to override default labels | ||||
|  - Add placeholder text on label inputs and clear buttons | ||||
|  - Add port labels to Subflow nodes | ||||
|  - Keep port label form in sync with output reordering | ||||
|  - Basic node label editor | ||||
|  - Port label editor starting point | ||||
|  - Allow port labels be i18n identifiers | ||||
|  - Add inputLabels and outputLabels to node defn + Update Change node | ||||
|  - Resize port labels based on content | ||||
|  - Initial port label behaviour | ||||
|  - Allow a node to decide for itself if its button should be enabled or not | ||||
|  - Provide feedback when enable/disable node fails | ||||
|  - Add node module update api and expose in palette editor | ||||
|  - Reset palette-manager tabs when settings dialog reopened | ||||
|  - Move palette editor to settings panel | ||||
|  - Move palette editor to userSettings dialog | ||||
|  - Move view and keyboard into user settings dialog | ||||
|  - Add basic user settings panel | ||||
|  - Node status should be on by default | ||||
|  - Make theme able to load custom javascript (#1211) | ||||
|  - Allow tips to be hidden and cycled through | ||||
|  - Add info tips back to the sidebar | ||||
|  - Add buffer mode to typedInput | ||||
|  - Add typedInput binary mode icon | ||||
|  - Ensure all ace editors are destroyed in the expression editors | ||||
|  - Refresh sidebar info when tab is changed | ||||
|  - better spacing for library widget | ||||
|  - Fix gridSize for node width calculation to avoid odd resizing | ||||
|  - Redraw grid properly if gridSize changes | ||||
|  - Scroll sidebar info tab to top when changing content | ||||
|  - Ensure info tab sections are collapsible when set from palette | ||||
|  - Only show tab info if there is an active tab | ||||
|  - Only check for reordered outputs if outputMap defiend | ||||
|  - Avoid circular references when stingifying node objects | ||||
|  - Fix padding of config node edit dialog | ||||
|  - Add force-deploy option when conflict detected | ||||
|  - Hide tip box on startup if disabled | ||||
|  - Track node moves separately to node config changes | ||||
|  - Ensure ace editor instances are freed if edit cancelled | ||||
|  - Clip overly long notification messages | ||||
|  - Use queryCommandSupported not queryCommandEnabled to check for copy support | ||||
|  - Add tip to tab description editor | ||||
|  - Make tab info edit box resizable | ||||
|  - Shrink config node appearance in info table | ||||
|  - Display config nodes in Info sidebar table | ||||
|  - Ensure flow info box updates after editing flow | ||||
|  - Hide Node info section when displaying changelog | ||||
|  - Restructure info tab | ||||
|  - Provide notification when new flows deployed in the background | ||||
|  - Stop some ui elements from clearing url anchor when clicked | ||||
|  - clipboard export text stay highlighted even when button deselected | ||||
|  - ensure export clipboard keeps text selected and formatted | ||||
|  - Defer resizing tray components until they have finished building | ||||
|  - Use pre-calculated values for connection path | ||||
|  - Use textContent to avoid manual escaping | ||||
|  - Add RED.stack as a common ui component | ||||
|  - Numeric validator that accepts blank should accept undefined | ||||
|  - Add visual cue as to whether the workspace is focused | ||||
|  - Allow RED.validators.number to allow blank values as valid | ||||
|  - Support dropping json files into the editor | ||||
|  - NLS Expression/JSON editor and fix their height calculation | ||||
|  - Update JSONata to 1.2.4 Closes #1275 | ||||
|  - Remember test expression data on a per-node basis | ||||
|  - NLS jsonata test messages | ||||
|  - Add JSONata expr tester and improved feedback | ||||
|  - Add $context/$flow/$global functions to jsonata | ||||
|  - Update jsonata | ||||
|  | ||||
| Other | ||||
|  | ||||
|  - add allow es6 to .jshintrc | ||||
|  - travis - don't allow node 8 fails, (and re-add 7) | ||||
|  - ask istanbul for more reports as default | ||||
|  - Add istanbul to Gruntfile.js (#1189) | ||||
|  | ||||
|  | ||||
| #### 0.16.2: Maintenance Release | ||||
|  | ||||
|  - Ensure custom mustache context parent set in Template node fixes #1126 | ||||
|  - Display debug node name in debug panel if its known | ||||
|  - Ensure auth-tokens are removed when no user is specified in settings | ||||
|  - Ensure all a tags have blank target in info sidebar | ||||
|  - Ensure links do not span tabs in the editor | ||||
|  - Avoid creating multiple reconnect timers in websocket node | ||||
|  - Fix inner reference in install fail message catalog entry Fixes #1120 | ||||
|  - Display buffer data properly for truncated buffers under Object property | ||||
|  | ||||
| #### 0.16.1: Maintenance Release | ||||
|  | ||||
|  - Add colour swatches to debug when hex colour matched | ||||
|  - Nodes with hasUsers set to false should not appear unused | ||||
|  - Change hard error to verbose warning if using old node.js level | ||||
|  - Don't filter debug properties starting with _ Fixes #1117 | ||||
|  - Node logged errors not displayed properly in debug pane Fixes #1116 | ||||
|  - Do not look for existing nodes when checking for wires on paste Fixes #1114 | ||||
|  - -v option not enabling verbose mode properly | ||||
|  - Add node.js version check on startup | ||||
|  | ||||
| #### 0.16.0: Milestone Release | ||||
|  | ||||
| Runtime | ||||
|  | ||||
|  - Drop support for node 0.10 and 0.12 | ||||
|  | ||||
| Nodes | ||||
|  | ||||
|  - Add option to colourise debug console output Closes #1103 | ||||
|  - Add property validation to nodes using typedInput | ||||
|  - Add common validator for typedInput fields Closes #1104 | ||||
|  - Update debug node console logging indicator icon Closes #1094 | ||||
|  - Let exec node (spawn) handle commands with spaces in path | ||||
|  - Add symbol to debug node to indicate debugging also to console.log | ||||
|  - Change file node to use node 4 syntax (drops support for 0.8) | ||||
|  - add info for httprequest responseUrl property | ||||
|  - Add res.responseUrl to httprequest node response | ||||
|  - Add support for flow and global context in Template node (#1048) | ||||
|  - Added YAML parser node (#1034) | ||||
|  - node-red-node-serialport removed as a default node | ||||
|  | ||||
| Editor | ||||
|  | ||||
|  - Add install/remove dialog to increase friction Closes #1109 | ||||
|  - Report node catalogue load errors Closes #1009 | ||||
|  - Properly report module remove errors in palette editor Fixes #1043 | ||||
|  - Update rather than hide install button after success install | ||||
|  - Tweak search box styling | ||||
|  - Display info tips slightly longer | ||||
|  - Allow tips to be enabled/disabled via menu option | ||||
|  - Info-tips update | ||||
|  - Make typedInput keyboard navigable | ||||
|  - update Font Awesome to 4.7.0 | ||||
|  - Add expression editor for jsonata | ||||
|  - Overhaul keyboard handling and introduce editor actions | ||||
|  - Add Japanese translation file(editor.json) (#1084) | ||||
|  - Add quick-add node mode with cmd/ctrl-click | ||||
|  - Add cmd/ctrl-click to quick add wires | ||||
|  - Use json-stringify-safe to detect circular references in debug msgs | ||||
|  - debug - format if time if correct length/range | ||||
|  - Make Debug object explorable | ||||
|  - Initial debug pop-out window | ||||
|  - Add proper three-way diff view | ||||
|  - Focus tray body when edit dialog opened | ||||
|  - Hit enter to edit first node in selection | ||||
|  - Add node delete button to edit dialog | ||||
|  - Add notification when runtime stopped due to missing types Part of #832 | ||||
|  | ||||
| Fixes | ||||
|  | ||||
|  - Do not tie debug src loading to needsPermission Fixes #1111 | ||||
|  - Initialise nodeApp regardless of httpAdmin setting Closes #1096 #1095 | ||||
|  - Speed up reveal of search dialogs | ||||
|  - Ensure flows exist before delegating status/error events Fixes #1069 | ||||
|  - Update package dependencies | ||||
|  - Update MQTT to latest 2.2.1 | ||||
|  - Node status not being refreshed properly in the editor | ||||
|  - Try to prevent auto-fill of password fields in node edit tray Fixes #1081 | ||||
|  - Fix whitespace in localfilesystem | ||||
|  - fix bug where savesettings did not honor local settings variables (#1073) | ||||
|  - Tidy up unused/duplicate editor messages Closes #922 | ||||
|  - Property expressions must not be blank | ||||
|  - Tidy up merge commit of validatePropertyExpression | ||||
|  - add port if wires array > number of ports declared. | ||||
|  - Allow quoted property expressions Fixes #1101 | ||||
|  - Index all node properties for node search | ||||
|  - Remove node 0.10 from travis config | ||||
|  - update welcome message to use logger so it can be turned off/on if required (#1083) | ||||
|  - Fix dynamically loading multiple node-sets from palette editor | ||||
|  - Allow a node to reorder its outputs and maintain links Fixes #1031 | ||||
|  | ||||
| #### 0.15.3: Maintenance Release | ||||
|  | ||||
|  - Tcpgetfix: Another small check (#1070) | ||||
|  - TCPGet: Ensure done() is called only once (#1068) | ||||
|  - Allow $ and _ at start of property identifiers Fixes #1063 | ||||
|  - TCPGet: Separated the node.connected property for each instance (#1062) | ||||
|  - Corrected 'overide' typo in XML node help (#1061) | ||||
|  - TCPGet: Last property check (hopefully) (#1059) | ||||
|  - Add additional safety checks to avoid acting on non-existent objects (#1057) | ||||
|  - add --title for process name to command line options | ||||
|  - add indicator for fire once on inject node | ||||
|  - reimplement $(env var) replace to share common code. | ||||
|  - Fix error message for missing node html file, and add test. | ||||
|  - Let credentials also use $(...) substitutions from ENV | ||||
|  - Rename insecureRedirect to requireHttps | ||||
|  - Add setting to cause insecure redirect (#1054) | ||||
|  - Palette editor fixes (#1033) | ||||
|  - Close comms on stopServer in test helper (#1020) | ||||
|  - Tcpgetfix (#1050) | ||||
|  - TCPget: Store incoming messages alongside the client object to keep reference | ||||
|  - Merge remote-tracking branch 'upstream/master' into tcpgetfix | ||||
|  - TCPget can now handle concurrent sessions (#1042) | ||||
|  - Better scope handling | ||||
|  - Add security checks | ||||
|  - small change to udp httpadmin | ||||
|  - Fix comparison to "" in tcpin | ||||
|  - Change scope of clients object | ||||
|  - Works when connection is left open | ||||
|  - First release of multi connection tcpget | ||||
|  - Fix node.error() not printing when passed false (#1037) | ||||
|  - fix test for CSV array input | ||||
|  - different test for Pi (rather than use serial port name) | ||||
|  - Fix missing 0 handling for css node with array input | ||||
|  | ||||
|  | ||||
| #### 0.15.2: Maintenance Release | ||||
|  | ||||
|  - Revert bidi changes to nodes and hide menu option until fixed Fixes #1024 | ||||
|  - Let xml node set options both ways | ||||
|  - Bump serialport to use version 4 | ||||
|  - gpio node handle multiple bits of data returned in one go | ||||
|  - HTTP In should pass application/octet-stream as buffer not string Fixes #1023 | ||||
|  - Handle missing httpNodeRoot setting properly | ||||
|  - Config sidebar not handling node definition error properly | ||||
|  - Add minimum show time to deploy spinner to avoid flicker | ||||
|  - Add work-in-progress update button to palette-editor | ||||
|  - Add log.removeHandler function | ||||
|  - Add Crtl/Shift/p shortcut for manage palette | ||||
|  - Add spinner to deploy button | ||||
|  - Status messages from nodes in subflows not delegated properly Fixes #1016 | ||||
|  - fix spelling in join node info | ||||
|  - Speed up tab scrolling | ||||
|  - Update delay burst test to be more tolerant of timing Fixes #1013 | ||||
|  | ||||
| #### 0.15.1: Maintenance Release | ||||
|  | ||||
|  - Update default palette catalogue to use https | ||||
|  - Disable palette editor if npm not found - and fix for Windows | ||||
|  - Searching package catalogue should be case-insensitive Fixes #1010 | ||||
|  - contenteditable fields not handled in config nodes Fixes #1011 | ||||
|  - Change html link refs from `_new` to `_blank` to be standards compliant | ||||
|  | ||||
| #### 0.15.0: Milestone Release | ||||
|  | ||||
| Runtime | ||||
|  | ||||
|  - Increase default apiMaxLength to 5mb and add to default settings Closes #1001 | ||||
|  - Add v2 /flows api and deploy-overwrite protection | ||||
|  - Encrypt credentials by default | ||||
|  - Ensure errors thrown by RED.events handlers don't percolate up | ||||
|  | ||||
| Editor | ||||
|  | ||||
|  - Mark nodes as changed when they are moved | ||||
|  - Added parent containment option for draggable. (#1006) | ||||
|  - Ignore bidi event handling on non-existent and non-Input elements Closes #999 | ||||
|  - Remove list of flows from menu | ||||
|  - Allow nodes to be imported with their credentials | ||||
|  - Add workspace search option | ||||
|  - Add scrollOnAdd option to editableList | ||||
|  - Add swift markup to editor for open whisk node | ||||
|  - Scrollable tabs 👍 | ||||
|  - Allow linking to individual flow via url hash | ||||
|  - Avoid duplicating existing subflows on import | ||||
|  - Add import-to-new-tab option | ||||
|  - Add new options to export-nodes dialog | ||||
|  - Stop nodes being added beyond the outer bounds of the workspace | ||||
|  - Default config nodes to global scope unless in a subflow Closes #972 | ||||
|  - Bidi support for Text Direction and Structured Text (#961) | ||||
|  - Fix jQuery selector, selecting more than one help pane/popover and displaying incorrectly. (#970) | ||||
|  - Fixes removeItem not passing row data to callback. (#965) | ||||
|  - Move common components and add searchBox | ||||
|  - Add initial palette sidebar | ||||
|  | ||||
| Nodes | ||||
|  | ||||
|  - Inject node label - show topic for timestamp mode if short | ||||
|  - Let change node set type if total match | ||||
|  - Clean up status on close for several core nodes. | ||||
|  - Change node: re-parse JSON set value each time to avoid pass-by-ref | ||||
|  - Better handle HTTP Request header capitalisation | ||||
|  - Enable ES6 parsing in Function editor by default Fixes #985 | ||||
|  - Update debug sidebar to use RED.view.reveal to show debug nodes | ||||
|  - Add full path tip to file node, And tidy up Pi node tips | ||||
|  - Remove WebSocket node maxlistener warning | ||||
|  - Update mqtt-broker node to use fully name-space qualified status messages | ||||
|  - Let UDP node better share same port instance if required | ||||
|  - Add number of units to the delay node (rate) (#994) | ||||
|  - Allow http middleware to skip rawBodyParser | ||||
|  - Let change node move property to sub-property. | ||||
|  - Add info to exec warning about buffered output if using python | ||||
|  - TCP node: pass on latest input msg properties | ||||
|  - Make sure MQTT broker is really set | ||||
|  - Fix escape character catch in TCPGet + support 0x?? sequences | ||||
|  - Fix split character in TCP Request node | ||||
|  - Add CSS highlighting to the template node (#950) | ||||
|  - Only update switch previous value after all rules are run | ||||
|  | ||||
| Other | ||||
|  | ||||
|  - Add npm build/test scripts Closes #946 #660 | ||||
|  - Move travis to node 6 and 7 - drop 5 and 0.12 | ||||
|  | ||||
|  | ||||
| #### 0.14.6: Maintenance Release | ||||
|  | ||||
| Fixes | ||||
|  | ||||
|  - Tell ace about Function node globals. Closes #927 | ||||
|  - Tidy up mqtt nodes - linting and done handling. Closes #935 | ||||
|  - Fix invalid html in TCP and HTML node edit templates | ||||
|  - Add proper help text to link nodes | ||||
|  - Handle importing old mqtt-broker configs that lack properties | ||||
|  - Update ace to 1.2.4 | ||||
|  - Allow config nodes to provide a sort function for their select list | ||||
|  - Add log warning if node module required version cannot be satisfied | ||||
|  - Handle empty credentials file. Closes #937 | ||||
|  - Add RPi.GPIO lib test for ArchLinux | ||||
|  | ||||
| #### 0.14.5: Maintenance Release | ||||
|  | ||||
| Fixes | ||||
|  | ||||
|  - Cannot clear cookies with http nodes | ||||
|  - let HTML parse node allow msg.select set select | ||||
|  - Validate nodes on import after any references have been remapped | ||||
|  - Debug node handles objects without constructor property Fixes #933 | ||||
|  - Ensure 'false' property values are displayed in info panel Fixes #940 | ||||
|  - Fix node enable/disable over restart - load configs after settings init | ||||
|  | ||||
| #### 0.14.4: Maintenance Release | ||||
|  | ||||
| Nodes | ||||
|  | ||||
|  - Update trigger node ui to use typedInputs | ||||
|  - Better handling of quotes in CSV node | ||||
|  - Clarify the MQTT node sends msg.payload - closes #929 | ||||
|  - Inject node should reuse the message it is triggered with Closes #914 | ||||
|  - Stop trigger node re-using old message | ||||
|  - Allow node.status text to be 'falsey' values | ||||
|  | ||||
| Fixes | ||||
|  | ||||
|  - Handle DOMException when embedded in an iframe of different origin Fixes #932 | ||||
|  - Fix double firing of menu actions | ||||
|  - Fix select box handling in Safari - fixes #928 | ||||
|  - Clear context in node test helper Fixes #858 | ||||
|  - Allow node properties to be same as existing object functions Fixes #880 | ||||
|  - Handle comms link closing whilst completing the initial connect | ||||
|  - Protect against node type names that clash with Object property names Fixes #917 | ||||
|  - Clone default node properties to avoid reference leakage | ||||
|  - Strip tab node definition when exporting | ||||
|  - Check for null config properties in editor before over-writing them | ||||
|  - Add hasUsers flag to config nodes | ||||
|  | ||||
| Editor | ||||
|  | ||||
|  - Add sql mode to ace editor | ||||
|  - Keyboard shortcuts dialog update (#923) | ||||
|  - Ensure importing link nodes to a subflow doesn't add outbound links Fixes #921 | ||||
|  - Add updateConfigNodeUsers function to editor | ||||
|  - Scroll to bottom when item added to editableList | ||||
|  - Form input widths behave more consistently when resizing Fixes #919 #920 | ||||
|  | ||||
| #### 0.14.3: Maintenance Release | ||||
|  | ||||
| Fixes | ||||
|  | ||||
|  - Create default setting.js in user-specified directory. Fixes #908 | ||||
|  - MQTT In subscription qos not defaulting properly | ||||
|  - Let exec node handle 0 as well as "0" | ||||
|  | ||||
| #### 0.14.2: Maintenance Release | ||||
|  | ||||
| Fixes | ||||
|  | ||||
|  - Cannot add new twitter credentials. Fixes #913 | ||||
|  - Support array references in Debug property field | ||||
|  | ||||
| #### 0.14.1: Maintenance Release | ||||
|  | ||||
| Fixes | ||||
|  | ||||
|  - Handle undefined property that led to missing wires in the editor | ||||
|  - Remove duplicate 'Delete' entry in keyboard shortcut window. Closes #911 | ||||
|  - Add 'exec' to node-red-pi launch script. Closes #910 | ||||
|  | ||||
| #### 0.14.0: Milestone Release | ||||
|  | ||||
| Editor | ||||
|  | ||||
|  - Replace edit dialog with edit tray | ||||
|  - Enable shift-drag detach of just the selected link | ||||
|  - Allow workspace tabs to be re-ordered | ||||
|  - Scope keyboard shortcuts to dom elements | ||||
|  - Ensure parent nodes marked as changed due to child config node changes | ||||
|  - Validate all edit dialog inputs when one changes | ||||
|  - Add editableList widget and update Switch/Change nodes to use it | ||||
|  - Add option to filter Debug sidebar by flow and highlight subflow-emitting nodes | ||||
|  - Back off comms reconnect attempts after prolonged failures | ||||
|  - Prompt for login if comms reconnect fails authentication | ||||
|  - Change style of nodes in subflow template view | ||||
|  - Add CHANGELOG.md and make it accessible from menu | ||||
|  | ||||
| Runtime | ||||
|  | ||||
|  - Always log node warnings on start without requiring -v | ||||
|  - Add support for loading scoped node modules. Closes #885 | ||||
|  - Add process.env.PORT to settings.js | ||||
|  - Clear node context on deploy. Closes #870 | ||||
|  - Enable finer grained permissions in adminAuth | ||||
|  | ||||
| Nodes | ||||
|  | ||||
|  - Enable config nodes to reference other config nodes | ||||
|  - Add Split/Join nodes | ||||
|  - Add Link nodes | ||||
|  - Add support to HTTP In node for PATCH requests. Closes #904 | ||||
|  - Add cookie handling to HTTP In and HTTP Response nodes | ||||
|  - Add repeat indicator to inject node label. Closes #887 | ||||
|  - Add javascript highlighter to template node | ||||
|  - Add optional timeout to exec node | ||||
|  - Add TLS node and update MQTT/HTTP nodes to use it | ||||
|  - Let trigger node also send last payload to arrive | ||||
|  - Add timestamp as a default typedInput and update Inject and change nodes to match, | ||||
|  - Add QoS option to MQTT In node | ||||
|  - Add status to exec spawn mode | ||||
|  - Add Move capability to Change node | ||||
|  - Update Serial node to support custom baud rates | ||||
|  - Add support for array-syntax in typedInput msg properties | ||||
|  - Add RED.util to Function node sandbox | ||||
|  - Capture error stack on node.error. Closes #879 | ||||
|  | ||||
|  | ||||
| Fixes | ||||
|  | ||||
|  - Add error handling to all node definition api calls | ||||
|  - Handle null return from Function node in array of messages | ||||
|  - Defer loading of token sessions until they are accessed. Fixes #895 | ||||
|  - set pi gpio pin status correctly if set on start | ||||
|  - Prevent parent window scrolling when view is focused. Fixes #635 | ||||
|  - Handle missing tab nodes in a loaded flow config | ||||
|  - Ensure typedInput dropdown doesn't fall off the page | ||||
|  - Protect against node types with reserved names such as toString. Fixes #880 | ||||
|  - Do not rely on the HTML file to identify where nodes are registered from | ||||
|  - Preserve node properties on import | ||||
|  - Fix regression in delay node. topic based queue was emptying all the time instead of spreading out messages. | ||||
|  - Throw an error if a Function node adds an input event listener | ||||
|  - Fix hang on partial deploy with disconnected mqtt node | ||||
|  - TypedInput: preload type icons to ensure width calc correct | ||||
|  - Ensure tcp node creates a buffer of size 1 at least | ||||
|  - Return editorTheme default if value is undefined | ||||
|  - Fix RED.util.compareObjects for Function created objects and Buffers | ||||
|  - Ensure default settings copied to command-line specified userDir | ||||
|  | ||||
|  | ||||
| #### 0.13.4: Maintenance Release | ||||
|  | ||||
|  - Add timed release mode to delay node | ||||
|  - Enable link splicing for when import_dragging nodes. Closes #811 | ||||
|  - Fix uncaught exception on deploy whilst node sending messages | ||||
|  - Deprecate old mqtt client and connection pool modules | ||||
|  - Change node: add bool/num types to change mode Closes #835 | ||||
|  - Validate fields that are `$(env-vars)` Closes #825 | ||||
|  - Handle missing config nodes when validating node properties | ||||
|  - Pi node - don't try to send data if closing | ||||
|  - Load node message catalog when added dynamically | ||||
|  - Split palette labels on spaces and hyphens when laying out | ||||
|  - Warn if editor routes are accessed but runtime not started Closes #816 | ||||
|  - Better handling of zero-length flow files Closes #819 | ||||
|  - Allow runtime calls to RED._ to specify other namespace | ||||
|  - Better right alignment of numerics in delay and trigger nodes | ||||
|  - Allow node modules to include example flows | ||||
|  - Create node_modules in userDir | ||||
|  - Ensure errors in node def functions don't break view rendering Fixes #815 | ||||
|  - Updated Inject node info with instructions for flow and global options | ||||
|  | ||||
|  | ||||
|  | ||||
| #### 0.13.3: Maintenance Release | ||||
|  | ||||
|  - Fix crash on repeated inject of invalid json payload | ||||
|  - Add binary mode to tail node | ||||
|  - Revert Cheerio to somewhat smaller version | ||||
|  - Add os/platform info to default debug | ||||
|  | ||||
|  | ||||
|  | ||||
| #### 0.13.2: Maintenance Release | ||||
|  | ||||
|  - Don't force reconnect mqtt client if message arrives (fixes the MQTT connect/disconnect endless cycle) | ||||
|  - Add -p/--port option to override listening port | ||||
|  - Invert config node filter toggle button colours so state is more obvious | ||||
|  - Add timeout to httprequest node | ||||
|  - Tidy up of all node info content - make style consistent | ||||
|  - Make jquery spinner element css consistent with other inputs | ||||
|  - tcp node add reply (to all) capability | ||||
|  - Allow the template node to be treated as plain text | ||||
|  - Validate MQTT In topics Fixes #792 | ||||
|  - httpNodeAuth should not block http options requests Fixes #793 | ||||
|  - Disable perMessageDeflate on WS servers - fixes 'zlib binding closed' error | ||||
|  - Clear trigger status icon on re-deploy | ||||
|  - Don't default inject payload to blank string | ||||
|  - Trigger node, add configurable reset | ||||
|  - Allow function properties in settings Fixes #790 - fixes use of httpNodeMiddleware | ||||
|  - Fix order of config dialog calls to save/creds/validate | ||||
|  - Add debounce to Pi GPIO node | ||||
|  | ||||
|  | ||||
|  | ||||
| #### 0.13.1: Maintenance Release | ||||
|  | ||||
|  - Revert wrapping of http request object | ||||
|  | ||||
|  | ||||
|  | ||||
| #### 0.13.0: Milestone Release | ||||
|  | ||||
|  - Add 'previous value' option to Switch node | ||||
|  - Allow existing nodes to splice into links on drag | ||||
|  - CORS not properly configured on multiple http routes Fixes #783 | ||||
|  - Restore shift-drag to snap/unsnap to grid | ||||
|  - Moving nodes with keyboard should flag workspace dirty | ||||
|  - Notifications flagged as fixed should not be click-closable | ||||
|  - Rework config sidebar and deploy warning | ||||
|  - Wrap http request object to match http response object | ||||
|  - Add 'view' menu and reorganise a few things | ||||
|  - Allow shift-click to detach existing wires | ||||
|  - Splice nodes dragged from palette into links | ||||
|  - try to trim imported/dragged flows to [ ] | ||||
|  - Move version number as title of NR logo | ||||
|  - Moving nodes mark workspace as dirty | ||||
|  - Ok/Cancel edit dialogs with Ctrl-Enter/Escape | ||||
|  - Handle OSX Meta key when selecting nodes | ||||
|  - Add grid-alignment options | ||||
|  - Add oneditresize function definition | ||||
|  - Rename propertySelect to typedInput and add boolean opt | ||||
|  - Add propertySelect to switch node | ||||
|  - Add propertySelect support to Change node | ||||
|  - Add context/flow/global support to Function node | ||||
|  - Add node context/flow/global | ||||
|  - Add propertySelect jquery widget | ||||
|  - Add add/update/delete flow apis | ||||
|  - Allow core nodes dir to be provided to runtime via settings | ||||
|  - Tidy up API passed to node modules | ||||
|  - Move locale files under api/runtime components | ||||
|  - Add flow reload admin api | ||||
|  | ||||
|  | ||||
|  | ||||
| #### 0.12.5: Maintenance Release | ||||
|  | ||||
|  - Add attribute capability to HTML parser node | ||||
|  - Add Pi Keyboard code node | ||||
|  - Fix for MQTT client connection cycling on partial deploy | ||||
|  - Fix for tcp node properly closing connections | ||||
|  - Update sentiment node dependencies | ||||
|  - Fix for file node handling of UTF8 extended characters | ||||
|  | ||||
|  | ||||
|  | ||||
| #### 0.12.4: Maintenance Release | ||||
|  | ||||
|  - Add readOnly setting to prevent file writes in localfilesystem storage | ||||
|  - Support bcrypt for httpNodeAuth | ||||
|  - Pi no longer needs root workaround to access gpio | ||||
|  - Fix: Input File node will not retain the file name | ||||
|  | ||||
|  | ||||
|  | ||||
| #### 0.12.3: Maintenance Release | ||||
|  | ||||
|  - Fixes for TCP Get node reconnect handling | ||||
|  - Clear delay node status on re-deploy | ||||
|  - Update Font-Awesome to v4.5 | ||||
|  - Fix trigger to block properly until reset | ||||
|  - Update example auth properties in settings.js | ||||
|  - Ensure httpNodeAuth doesn't get applied to admin routes | ||||
|  - TCP Get node not passing on existing msg properties | ||||
|  | ||||
|  | ||||
|  | ||||
| #### 0.12.2: Maintenance Release | ||||
|  | ||||
|  - Enable touch-menu for links so they can be deleted | ||||
|  - Allow nodes to be installed by path name | ||||
|  - Fix basic authentication on httpNode/Admin/Static | ||||
|  - Handle errors thrown in Function node setTimeout/Interval | ||||
|  - Fix mqtt node lifecycle with partial deployments | ||||
|  - Update tcp node status on reconnect after timeout | ||||
|  - Debug node not handling null messages | ||||
|  - Kill processes run with exec node when flows redeployed | ||||
|  - Inject time spinner incrementing value incorrectly | ||||
|  | ||||
|  | ||||
|  | ||||
| #### 0.12.1: Maintenance Release | ||||
|  | ||||
|  - Enable touch-menu for links so they can be deleted | ||||
|  - Allow nodes to be installed by path name | ||||
|  - Fix basic authentication on httpNode/Admin/Static | ||||
|  | ||||
|  | ||||
|  | ||||
| #### 0.12.0: Milestone Release | ||||
|  | ||||
|  - Change/Switch rules now resize with dialog width | ||||
|  - Support for node 4.x | ||||
|  - Move to Express 4.x | ||||
|  - Copy default settings file to user dir on start up | ||||
|  - Config nodes can be scoped to a particular subflow/tab | ||||
|  - Comms link tolerates <5 second breaks in connection before notifying user | ||||
|  - MQTT node overhaul - add will/tls/birth message support | ||||
|  - Status node - to report status events from other nodes | ||||
|  - Error node can be targeted to specific other nodes | ||||
|  - JSON node can encode Array types | ||||
|  - Switch node regular expression rule can now be set to be case-insensitive | ||||
|  - HTTP In node can accept non-UTF8 payloads - will return a Buffer when appropriate | ||||
|  - Exec node configuration consistent regardless of the spawn option | ||||
|  - Function node can now display status icon/text | ||||
|  - CSV node can now handle arrays | ||||
|  - setInterval/clearInterval add to Function node | ||||
|  - Function node automatically clears all timers (setInterval/setTimeout) when the node is stopped | ||||
|  | ||||
|  | ||||
|  | ||||
| #### 0.11.2: Maintenance Release | ||||
|  | ||||
|  - Allow XML parser options be set on the message | ||||
|  - Add 'mobile' category to the palette (no core nodes included) | ||||
|  - Allow a message catalog provide a partial translation | ||||
|  - Fix HTTP Node nls message id | ||||
|  - Remove delay spinner upper limit | ||||
|  - Update debug node output to include length of payload | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| #### 0.11.1: Maintenance Release | ||||
|  | ||||
|  - Fix exclusive config node check when type not registered (prevented HTTP In node from being editable unless the swagger node was also installed) | ||||
|  | ||||
|  | ||||
|  | ||||
| #### 0.11.0: Milestone Release | ||||
|  | ||||
|  - Add Node 0.12 support | ||||
|  - Internationalization support | ||||
|  - Editor UI refresh | ||||
|  - Add RBE node | ||||
|  - File node optionally creates path to file | ||||
|  - Function node can access `clearTimeout` | ||||
|  - Fix: Unable to login with 'read' permission | ||||
|  | ||||
|  | ||||
|  | ||||
| #### 0.10.10: Maintenance Release | ||||
|  | ||||
|  - Fix permissions issue with packaged nrgpio script | ||||
| - Add better help message if deprecated node missing | ||||
|  | ||||
|  | ||||
|  | ||||
| #### 0.10.9: Maintenance Release | ||||
|  | ||||
| Fix packaging of bin scripts | ||||
|  | ||||
|  | ||||
|  | ||||
| #### 0.10.8: Maintenance Release | ||||
|  | ||||
| - Nodes moved out of core | ||||
|   - still included as a dependency: twitter, serial, email, feedparser | ||||
|  - no longer included: mongo, arduino, irc, redis | ||||
| - node icon defn can be a function | ||||
| - http_proxy support | ||||
| - httpNodeMiddleware setting | ||||
| - Trigger node ui refresh | ||||
| - editorTheme setting | ||||
| - Warn on deploy of unused config nodes | ||||
| - catch node prevents error loops | ||||
|  | ||||
|  | ||||
|  | ||||
| #### 0.10.6: Maintenance Release | ||||
|  | ||||
| Changes: | ||||
|  - Performance improvements in editor | ||||
|  - Palette appearance update | ||||
|  - Warn on navigation with undeployed changes | ||||
|  - Disable undeployed node action buttons | ||||
|  - Disable subflow node action buttons | ||||
|  - Add Catch node | ||||
|  - Add logging functions to Function node | ||||
|  - Add send function to Function node | ||||
|  - Update Change node to support multiple rules | ||||
|  | ||||
|  | ||||
|  | ||||
| #### 0.10.4: Maintenance Release | ||||
|  | ||||
| Changes: | ||||
|  | ||||
| - http request node passes on request url as msg.url | ||||
| - handle config nodes appearing out of order in flow file - don't assume they are always at the start | ||||
| - move subflow palette category to the top, to make it more obvious | ||||
| - fix labelling of Raspberry Pi pins | ||||
| - allow email node to mark mail as read | ||||
| - fix saving library content | ||||
| - add node-red and node-red-pi start scripts | ||||
| - use $HOME/.node-red for user data unless specified otherwise (or existing data is found in install dir) | ||||
|  | ||||
|  | ||||
|  | ||||
| #### 0.10.3: Maintenance Release | ||||
|  | ||||
| Fixes: | ||||
|  | ||||
|  - httpAdminAuth was too aggressively deprecated (ie removed); restoring with a console warning when used | ||||
|  - adds reporting of node.js version on start-up | ||||
|  - mongo node skip/limit options can be strings or numbers | ||||
|  - CSV parser passes through provided message object | ||||
|  | ||||
|  | ||||
|  | ||||
| #### 0.10.2: Maintenance Release | ||||
|  | ||||
| Fixes: | ||||
|  - subflow info sidebar more useful | ||||
|  - adds missing font-awesome file | ||||
|  - inject node day selection defaulted to invalid selection | ||||
|  - loading a flow with no tabs failed to add nodes to default tab | ||||
							
								
								
									
										74
									
								
								CODE_OF_CONDUCT.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,74 @@ | ||||
| # Contributor Covenant Code of Conduct | ||||
|  | ||||
| ## Our Pledge | ||||
|  | ||||
| In the interest of fostering an open and welcoming environment, we as | ||||
| contributors and maintainers pledge to making participation in our project and | ||||
| our community a harassment-free experience for everyone, regardless of age, body | ||||
| size, disability, ethnicity, gender identity and expression, level of experience, | ||||
| nationality, personal appearance, race, religion, or sexual identity and | ||||
| orientation. | ||||
|  | ||||
| ## Our Standards | ||||
|  | ||||
| Examples of behavior that contributes to creating a positive environment | ||||
| include: | ||||
|  | ||||
| * Using welcoming and inclusive language | ||||
| * Being respectful of differing viewpoints and experiences | ||||
| * Gracefully accepting constructive criticism | ||||
| * Focusing on what is best for the community | ||||
| * Showing empathy towards other community members | ||||
|  | ||||
| Examples of unacceptable behavior by participants include: | ||||
|  | ||||
| * The use of sexualized language or imagery and unwelcome sexual attention or | ||||
| advances | ||||
| * Trolling, insulting/derogatory comments, and personal or political attacks | ||||
| * Public or private harassment | ||||
| * Publishing others' private information, such as a physical or electronic | ||||
|   address, without explicit permission | ||||
| * Other conduct which could reasonably be considered inappropriate in a | ||||
|   professional setting | ||||
|  | ||||
| ## Our Responsibilities | ||||
|  | ||||
| Project maintainers are responsible for clarifying the standards of acceptable | ||||
| behavior and are expected to take appropriate and fair corrective action in | ||||
| response to any instances of unacceptable behavior. | ||||
|  | ||||
| Project maintainers have the right and responsibility to remove, edit, or | ||||
| reject comments, commits, code, wiki edits, issues, and other contributions | ||||
| that are not aligned to this Code of Conduct, or to ban temporarily or | ||||
| permanently any contributor for other behaviors that they deem inappropriate, | ||||
| threatening, offensive, or harmful. | ||||
|  | ||||
| ## Scope | ||||
|  | ||||
| This Code of Conduct applies both within project spaces and in public spaces | ||||
| when an individual is representing the project or its community. Examples of | ||||
| representing a project or community include using an official project e-mail | ||||
| address, posting via an official social media account, or acting as an appointed | ||||
| representative at an online or offline event. Representation of a project may be | ||||
| further defined and clarified by project maintainers. | ||||
|  | ||||
| ## Enforcement | ||||
|  | ||||
| Instances of abusive, harassing, or otherwise unacceptable behavior may be | ||||
| reported by contacting the project team at team@nodered.org. All | ||||
| complaints will be reviewed and investigated and will result in a response that | ||||
| is deemed necessary and appropriate to the circumstances. The project team is | ||||
| obligated to maintain confidentiality with regard to the reporter of an incident. | ||||
| Further details of specific enforcement policies may be posted separately. | ||||
|  | ||||
| Project maintainers who do not follow or enforce the Code of Conduct in good | ||||
| faith may face temporary or permanent repercussions as determined by other | ||||
| members of the project's leadership. | ||||
|  | ||||
| ## Attribution | ||||
|  | ||||
| This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, | ||||
| available at [http://contributor-covenant.org/version/1/4][version] | ||||
|  | ||||
| [homepage]: http://contributor-covenant.org | ||||
| [version]: http://contributor-covenant.org/version/1/4/ | ||||
| @@ -7,6 +7,10 @@ We welcome contributions, but request you follow these guidelines. | ||||
|  - [Pull-Requests](#pull-requests) | ||||
|    - [Contributor License Agreement](#contributor-license-agreement) | ||||
|  | ||||
| This project adheres to the [Contributor Covenant 1.4](http://contributor-covenant.org/version/1/4/). | ||||
| By participating, you are expected to uphold this code. Please report unacceptable | ||||
| behavior to any of the [project's core team](https://github.com/orgs/node-red/teams/core). | ||||
|  | ||||
| ## Raising issues | ||||
|  | ||||
| Please raise any bug reports on the relevant project's issue tracker. Be sure to | ||||
| @@ -34,21 +38,13 @@ If you want to raise a pull-request with a new feature, or a refactoring | ||||
| of existing code, it may well get rejected if you haven't discussed it on | ||||
| the [mailing list](https://groups.google.com/forum/#!forum/node-red) first. | ||||
|  | ||||
| ### Contributor License Agreement | ||||
| All contributors need to sign the JS Foundation's Contributor License Agreement. | ||||
| It is an online process and quick to do. You can read the details of the agreement | ||||
| here: https://cla.js.foundation/node-red/node-red. | ||||
|  | ||||
| In order for us to accept pull-requests, the contributor must first complete | ||||
| a Contributor License Agreement (CLA). This clarifies the intellectual | ||||
| property license granted with any contribution. It is for your protection as a | ||||
| Contributor as well as the protection of IBM and its customers; it does not | ||||
| change your rights to use your own Contributions for any other purpose. | ||||
| If you raise a pull-request without having signed the CLA, you will be prompted | ||||
| to do so automatically. | ||||
|  | ||||
| You can download the CLAs here: | ||||
|  | ||||
|  - [individual](http://nodered.org/cla/node-red-cla-individual.pdf) | ||||
|  - [corporate](http://nodered.org/cla/node-red-cla-corporate.pdf) | ||||
|  | ||||
| If you are an IBMer, please contact us directly as the contribution process is | ||||
| slightly different. | ||||
|  | ||||
| ### Coding standards | ||||
|  | ||||
|   | ||||
							
								
								
									
										217
									
								
								Gruntfile.js
									
									
									
									
									
								
							
							
						
						| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2013, 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -41,6 +41,17 @@ module.exports = function(grunt) { | ||||
|             core: { src: ["test/_spec.js","test/red/**/*_spec.js"]}, | ||||
|             nodes: { src: ["test/nodes/**/*_spec.js"]} | ||||
|         }, | ||||
|         mocha_istanbul: { | ||||
|             options: { | ||||
|                 globals: ['expect'], | ||||
|                 timeout: 3000, | ||||
|                 ignoreLeaks: false, | ||||
|                 ui: 'bdd', | ||||
|                 reportFormats: ['lcov'], | ||||
|                 print: 'both' | ||||
|             }, | ||||
|             coverage: { src: ['test/**/*_spec.js'] } | ||||
|         }, | ||||
|         jshint: { | ||||
|             options: { | ||||
|                 jshintrc:true | ||||
| @@ -86,7 +97,7 @@ module.exports = function(grunt) { | ||||
|                     src: ['test/**/*.js'] | ||||
|                 }, | ||||
|                 options: { | ||||
| 					"expr": true | ||||
|                     "expr": true | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
| @@ -95,39 +106,54 @@ module.exports = function(grunt) { | ||||
|                 separator: ";", | ||||
|             }, | ||||
|             build: { | ||||
|               src: [ | ||||
|                   // Ensure editor source files are concatenated in | ||||
|                   // the right order | ||||
|                   "editor/js/main.js", | ||||
|                   "editor/js/events.js", | ||||
|                   "editor/js/i18n.js", | ||||
|                   "editor/js/settings.js", | ||||
|                   "editor/js/user.js", | ||||
|                   "editor/js/comms.js", | ||||
|                   "editor/js/ui/state.js", | ||||
|                   "editor/js/nodes.js", | ||||
|                   "editor/js/history.js", | ||||
|                   "editor/js/validators.js", | ||||
|                   "editor/js/ui/deploy.js", | ||||
|                   "editor/js/ui/menu.js", | ||||
|                   "editor/js/ui/keyboard.js", | ||||
|                   "editor/js/ui/tabs.js", | ||||
|                   "editor/js/ui/popover.js", | ||||
|                   "editor/js/ui/workspaces.js", | ||||
|                   "editor/js/ui/view.js", | ||||
|                   "editor/js/ui/sidebar.js", | ||||
|                   "editor/js/ui/palette.js", | ||||
|                   "editor/js/ui/tab-info.js", | ||||
|                   "editor/js/ui/tab-config.js", | ||||
|                   "editor/js/ui/editor.js", | ||||
|                   "editor/js/ui/clipboard.js", | ||||
|                   "editor/js/ui/library.js", | ||||
|                   "editor/js/ui/notifications.js", | ||||
|                   "editor/js/ui/subflow.js", | ||||
|                   "editor/js/ui/touch/radialMenu.js", | ||||
|                   "editor/js/ui/typedInput.js" | ||||
|               ], | ||||
|               dest: "public/red/red.js" | ||||
|                 src: [ | ||||
|                     // Ensure editor source files are concatenated in | ||||
|                     // the right order | ||||
|                     "editor/js/red.js", | ||||
|                     "editor/js/events.js", | ||||
|                     "editor/js/i18n.js", | ||||
|                     "editor/js/settings.js", | ||||
|                     "editor/js/user.js", | ||||
|                     "editor/js/comms.js", | ||||
|                     "editor/js/text/bidi.js", | ||||
|                     "editor/js/text/format.js", | ||||
|                     "editor/js/ui/state.js", | ||||
|                     "editor/js/nodes.js", | ||||
|                     "editor/js/history.js", | ||||
|                     "editor/js/validators.js", | ||||
|                     "editor/js/ui/utils.js", | ||||
|                     "editor/js/ui/common/editableList.js", | ||||
|                     "editor/js/ui/common/checkboxSet.js", | ||||
|                     "editor/js/ui/common/menu.js", | ||||
|                     "editor/js/ui/common/panels.js", | ||||
|                     "editor/js/ui/common/popover.js", | ||||
|                     "editor/js/ui/common/searchBox.js", | ||||
|                     "editor/js/ui/common/tabs.js", | ||||
|                     "editor/js/ui/common/stack.js", | ||||
|                     "editor/js/ui/common/typedInput.js", | ||||
|                     "editor/js/ui/actions.js", | ||||
|                     "editor/js/ui/deploy.js", | ||||
|                     "editor/js/ui/diff.js", | ||||
|                     "editor/js/ui/keyboard.js", | ||||
|                     "editor/js/ui/workspaces.js", | ||||
|                     "editor/js/ui/view.js", | ||||
|                     "editor/js/ui/sidebar.js", | ||||
|                     "editor/js/ui/palette.js", | ||||
|                     "editor/js/ui/tab-info.js", | ||||
|                     "editor/js/ui/tab-config.js", | ||||
|                     "editor/js/ui/palette-editor.js", | ||||
|                     "editor/js/ui/editor.js", | ||||
|                     "editor/js/ui/tray.js", | ||||
|                     "editor/js/ui/clipboard.js", | ||||
|                     "editor/js/ui/library.js", | ||||
|                     "editor/js/ui/notifications.js", | ||||
|                     "editor/js/ui/search.js", | ||||
|                     "editor/js/ui/typeSearch.js", | ||||
|                     "editor/js/ui/subflow.js", | ||||
|                     "editor/js/ui/userSettings.js", | ||||
|                     "editor/js/ui/touch/radialMenu.js" | ||||
|                 ], | ||||
|                 dest: "public/red/red.js" | ||||
|             }, | ||||
|             vendor: { | ||||
|                 files: { | ||||
| @@ -137,14 +163,20 @@ module.exports = function(grunt) { | ||||
|                         "editor/vendor/jquery/js/jquery-ui-1.10.3.custom.min.js", | ||||
|                         "editor/vendor/jquery/js/jquery.ui.touch-punch.min.js", | ||||
|                         "editor/vendor/marked/marked.min.js", | ||||
|                         "editor/vendor/orion/built-editor.min.js", | ||||
|                         "editor/vendor/d3/d3.v3.min.js", | ||||
|                         "editor/vendor/i18next/i18next.min.js" | ||||
|                     ], | ||||
|                     "public/vendor/vendor.css": [ | ||||
|                         "editor/vendor/orion/built-editor.css" | ||||
|                         // TODO: resolve relative resource paths in | ||||
|                         //       bootstrap/FA/jquery | ||||
|                     ], | ||||
|                     "public/vendor/jsonata/jsonata.min.js": [ | ||||
|                         "node_modules/jsonata/jsonata-es5.min.js", | ||||
|                         "editor/vendor/jsonata/formatter.js" | ||||
|                     ], | ||||
|                     "public/vendor/ace/worker-jsonata.js": [ | ||||
|                         "node_modules/jsonata/jsonata-es5.min.js", | ||||
|                         "editor/vendor/jsonata/worker-jsonata.js" | ||||
|                     ] | ||||
|                 } | ||||
|             } | ||||
| @@ -152,7 +184,10 @@ module.exports = function(grunt) { | ||||
|         uglify: { | ||||
|             build: { | ||||
|                 files: { | ||||
|                     'public/red/red.min.js': 'public/red/red.js' | ||||
|                     'public/red/red.min.js': 'public/red/red.js', | ||||
|                     'public/red/main.min.js': 'public/red/main.js', | ||||
|                     'public/vendor/ace/mode-jsonata.js': 'editor/vendor/jsonata/mode-jsonata.js', | ||||
|                     'public/vendor/ace/snippets/jsonata.js': 'editor/vendor/jsonata/snippets-jsonata.js' | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
| @@ -178,12 +213,18 @@ module.exports = function(grunt) { | ||||
|                     'red/api/locales/en-US/editor.json', | ||||
|                     'red/runtime/locales/en-US/runtime.json' | ||||
|                 ] | ||||
|             }, | ||||
|             keymaps: { | ||||
|                 src: [ | ||||
|                     'editor/js/keymap.json' | ||||
|                 ] | ||||
|             } | ||||
|         }, | ||||
|         attachCopyright: { | ||||
|             js: { | ||||
|                 src: [ | ||||
|                     'public/red/red.min.js' | ||||
|                     'public/red/red.min.js', | ||||
|                     'public/red/main.min.js' | ||||
|                 ] | ||||
|             }, | ||||
|             css: { | ||||
| @@ -213,7 +254,7 @@ module.exports = function(grunt) { | ||||
|                 files: [ | ||||
|                     'editor/js/**/*.js' | ||||
|                 ], | ||||
|                 tasks: ['concat','uglify','attachCopyright:js'] | ||||
|                 tasks: ['copy:build','concat','uglify','attachCopyright:js'] | ||||
|             }, | ||||
|             sass: { | ||||
|                 files: [ | ||||
| @@ -228,6 +269,18 @@ module.exports = function(grunt) { | ||||
|                     'red/runtime/locales/en-US/runtime.json' | ||||
|                 ], | ||||
|                 tasks: ['jsonlint:messages'] | ||||
|             }, | ||||
|             keymaps: { | ||||
|                 files: [ | ||||
|                     'editor/js/keymap.json' | ||||
|                 ], | ||||
|                 tasks: ['jsonlint:keymaps','copy:build'] | ||||
|             }, | ||||
|             misc: { | ||||
|                 files: [ | ||||
|                     'CHANGELOG.md' | ||||
|                 ], | ||||
|                 tasks: ['copy:build'] | ||||
|             } | ||||
|         }, | ||||
|  | ||||
| @@ -256,36 +309,50 @@ module.exports = function(grunt) { | ||||
|  | ||||
|         copy: { | ||||
|             build: { | ||||
|                 files:[{ | ||||
|                     cwd: 'editor/images', | ||||
|                     src: '**', | ||||
|                     expand: true, | ||||
|                     dest: 'public/red/images/' | ||||
|                 }, | ||||
|                 { | ||||
|                     cwd: 'editor/vendor', | ||||
|                     src: [ | ||||
|                         'ace/**', | ||||
|                         //'bootstrap/css/**', | ||||
|                         'bootstrap/img/**', | ||||
|                         'jquery/css/**', | ||||
|                         'font-awesome/**' | ||||
|                     ], | ||||
|                     expand: true, | ||||
|                     dest: 'public/vendor/' | ||||
|                 }, | ||||
|                 { | ||||
|                     cwd: 'editor/icons', | ||||
|                     src: '**', | ||||
|                     expand: true, | ||||
|                     dest: 'public/icons/' | ||||
|                 }, | ||||
|                 { | ||||
|                     expand: true, | ||||
|                     src: ['editor/index.html','editor/favicon.ico'], | ||||
|                     dest: 'public/', | ||||
|                     flatten: true | ||||
|                 }] | ||||
|                 files:[ | ||||
|                     { | ||||
|                         src: 'editor/js/main.js', | ||||
|                         dest: 'public/red/main.js' | ||||
|                     }, | ||||
|                     { | ||||
|                         src: 'editor/js/keymap.json', | ||||
|                         dest: 'public/red/keymap.json' | ||||
|                     }, | ||||
|                     { | ||||
|                         cwd: 'editor/images', | ||||
|                         src: '**', | ||||
|                         expand: true, | ||||
|                         dest: 'public/red/images/' | ||||
|                     }, | ||||
|                     { | ||||
|                         cwd: 'editor/vendor', | ||||
|                         src: [ | ||||
|                             'ace/**', | ||||
|                             //'bootstrap/css/**', | ||||
|                             'bootstrap/img/**', | ||||
|                             'jquery/css/**', | ||||
|                             'font-awesome/**' | ||||
|                         ], | ||||
|                         expand: true, | ||||
|                         dest: 'public/vendor/' | ||||
|                     }, | ||||
|                     { | ||||
|                         cwd: 'editor/icons', | ||||
|                         src: '**', | ||||
|                         expand: true, | ||||
|                         dest: 'public/icons/' | ||||
|                     }, | ||||
|                     { | ||||
|                         expand: true, | ||||
|                         src: ['editor/index.html','editor/favicon.ico'], | ||||
|                         dest: 'public/', | ||||
|                         flatten: true | ||||
|                     }, | ||||
|                     { | ||||
|                         src: 'CHANGELOG.md', | ||||
|                         dest: 'public/red/about' | ||||
|                     } | ||||
|                 ] | ||||
|             }, | ||||
|             release: { | ||||
|                 files: [{ | ||||
| @@ -345,11 +412,12 @@ module.exports = function(grunt) { | ||||
|     grunt.loadNpmTasks('grunt-contrib-copy'); | ||||
|     grunt.loadNpmTasks('grunt-chmod'); | ||||
|     grunt.loadNpmTasks('grunt-jsonlint'); | ||||
|     grunt.loadNpmTasks('grunt-mocha-istanbul'); | ||||
|  | ||||
|     grunt.registerMultiTask('attachCopyright', function() { | ||||
|         var files = this.data.src; | ||||
|         var copyright = "/**\n"+ | ||||
|             " * Copyright 2013, 2015 IBM Corp.\n"+ | ||||
|             " * Copyright JS Foundation and other contributors, http://js.foundation\n"+ | ||||
|             " *\n"+ | ||||
|             " * Licensed under the Apache License, Version 2.0 (the \"License\");\n"+ | ||||
|             " * you may not use this file except in compliance with the License.\n"+ | ||||
| @@ -365,7 +433,7 @@ module.exports = function(grunt) { | ||||
|             " **/\n"; | ||||
|  | ||||
|         if (files) { | ||||
|             for (var i=0;i<files.length;i++) { | ||||
|             for (var i=0; i<files.length; i++) { | ||||
|                 var file = files[i]; | ||||
|                 if (!grunt.file.exists(file)) { | ||||
|                     grunt.log.warn('File '+ file + ' not found'); | ||||
| @@ -410,7 +478,7 @@ module.exports = function(grunt) { | ||||
|  | ||||
|     grunt.registerTask('build', | ||||
|         'Builds editor content', | ||||
|         ['clean:build','concat:build','concat:vendor','uglify:build','sass:build','jsonlint:messages','copy:build','attachCopyright']); | ||||
|         ['clean:build','jsonlint','concat:build','concat:vendor','copy:build','uglify:build','sass:build','attachCopyright']); | ||||
|  | ||||
|     grunt.registerTask('dev', | ||||
|         'Developer mode: run node-red, watch for source changes and build/restart', | ||||
| @@ -420,4 +488,7 @@ module.exports = function(grunt) { | ||||
|         'Create distribution zip file', | ||||
|         ['build','clean:release','copy:release','chmod:release','compress:release']); | ||||
|  | ||||
|     grunt.registerTask('coverage', | ||||
|         'Run Istanbul code test coverage task', | ||||
|         ['build','mocha_istanbul']); | ||||
| }; | ||||
|   | ||||
							
								
								
									
										1
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						| @@ -1,3 +1,4 @@ | ||||
| Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|                                  Apache License | ||||
|                            Version 2.0, January 2004 | ||||
|   | ||||
							
								
								
									
										29
									
								
								README.md
									
									
									
									
									
								
							
							
						
						| @@ -29,24 +29,23 @@ For further help, or general discussion, please use the | ||||
|  | ||||
| If you want to run the latest code from git, here's how to get started: | ||||
|  | ||||
| 1. Install grunt, the build tool | ||||
|  | ||||
|         npm install -g grunt-cli | ||||
|  | ||||
| 2. Clone the code: | ||||
| 1. Clone the code: | ||||
|  | ||||
|         git clone https://github.com/node-red/node-red.git | ||||
|         cd node-red | ||||
|  | ||||
| 3. Install the node-red dependencies | ||||
| 2. Install the node-red dependencies | ||||
|  | ||||
|         npm install | ||||
|  | ||||
| 4. Build the code | ||||
| 3. Build the code | ||||
|  | ||||
|         grunt build | ||||
|         npm run build | ||||
|  | ||||
| 5. Run | ||||
| 4. Run | ||||
|  | ||||
|         npm start | ||||
|    or | ||||
|  | ||||
|         node red.js | ||||
|  | ||||
| @@ -55,15 +54,21 @@ If you want to run the latest code from git, here's how to get started: | ||||
| Before raising a pull-request, please read our | ||||
| [contributing guide](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md). | ||||
|  | ||||
| This project adheres to the [Contributor Covenant 1.4](http://contributor-covenant.org/version/1/4/). | ||||
|  By participating, you are expected to uphold this code. Please report unacceptable | ||||
|  behavior to any of the [project's core team](https://github.com/orgs/node-red/teams/core). | ||||
|  | ||||
| ## Authors | ||||
|  | ||||
| Node-RED is a creation of [IBM Emerging Technology](http://ibm.com/blogs/et). | ||||
| Node-RED is a project of the [JS Foundation](http://js.foundation). | ||||
|  | ||||
| It was created by [IBM Emerging Technology](https://www.ibm.com/blogs/emerging-technology/). | ||||
|  | ||||
| * Nick O'Leary [@knolleary](http://twitter.com/knolleary) | ||||
| * Dave Conway-Jones [@ceejay](http://twitter.com/ceejay) | ||||
|  | ||||
| For more open-source projects from IBM, head over [here](http://ibm.github.io). | ||||
|  | ||||
|  | ||||
| ## Copyright and license | ||||
|  | ||||
| Copyright 2013, 2015 IBM Corp. under [the Apache 2.0 license](LICENSE). | ||||
| Copyright JS Foundation and other contributors, http://js.foundation under [the Apache 2.0 license](LICENSE). | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| #!/bin/bash | ||||
| # | ||||
| # Copyright 2015 IBM Corp. | ||||
| # 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. | ||||
| @@ -40,4 +40,4 @@ SCRIPT_PATH="`pwd`"; | ||||
| cd $CURRENT_PATH | ||||
|  | ||||
| # Run Node-RED | ||||
| /usr/bin/env node $OPTIONS $SCRIPT_PATH/../red.js $ARGS | ||||
| exec /usr/bin/env node $OPTIONS $SCRIPT_PATH/../red.js $ARGS | ||||
|   | ||||
| Before Width: | Height: | Size: 609 B After Width: | Height: | Size: 508 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/cog.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 493 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/join.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 253 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/link-out.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 402 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/parser-csv.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 413 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/parser-html.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 393 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/parser-json.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 467 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/parser-xml.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 393 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/parser-yaml.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 423 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/split.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 256 B | 
							
								
								
									
										9
									
								
								editor/images/node-red-icon-black.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,9 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="480" height="480" viewBox="0, 0, 480, 480"> | ||||
|   <g id="Calque_1"> | ||||
|     <path d="M408,16 C438.928,16 464,41.072 464,72 L464,408 C464,438.928 438.928,464 408,464 L72,464 C41.072,464 16,438.928 16,408 L16,296.002 L69.339,296.002 C89.715,296.002 105.993,279.497 105.993,259.12 L105.992,242.19 C190.296,243.397 214.83,265.317 241.661,288.777 C267.502,311.375 296.48,335.662 371.989,336.261 L371.993,344.57 C372.002,364.947 388.693,382 409.069,382 L463.991,382 L463.991,356 L409.069,356 C402.189,356 396.991,351.449 396.991,344.569 L396.991,308.32 C396.991,301.44 402.189,296 409.069,296 L463.991,296 L463.991,272 L409.069,272 C388.693,272 372.002,287.943 371.993,308.32 L371.99,316.908 C300.63,316.672 280.362,296.883 254.41,274.189 C232.267,254.825 206.244,233.534 148.914,225.789 C149.412,225.361 149.872,224.945 150.353,224.505 C161.391,214.382 167.343,202.153 173.167,191.593 C178.99,181.034 184.469,172.221 193.444,166.061 C200.725,161.064 211.08,157.338 226.992,156.647 L226.993,165.123 C226.997,185.5 243.431,202.999 263.808,202.999 L411.141,202.999 C431.517,202.999 447.993,185.5 447.993,165.123 L447.993,128.874 C447.993,108.497 431.517,91.999 411.141,91.999 L263.808,91.999 C243.431,91.999 226.983,108.496 226.993,128.874 L226.998,137.281 C207.794,138.053 193.238,142.713 182.496,150.086 C169.469,159.028 162.277,171.247 156.21,182.247 C150.144,193.247 145.009,203.104 137.25,210.218 C130.497,216.411 121.157,221.193 105.993,222.976 L105.993,222.579 C106.111,202.203 89.715,186.002 69.339,186.002 L16,186.002 L16,72 C16,41.072 41.072,16 72,16 L408,16 z" fill="#000000"/> | ||||
|     <path d="M16,211.002 L69.339,211.002 C76.219,211.002 81.992,215.991 81.992,222.871 L81.992,259.12 C81.992,266 76.219,272.002 69.339,272.002 L16,272.002 L16,211.002 z" fill="#000000"/> | ||||
|     <path d="M411.135,116.997 C418.015,116.997 422.987,121.992 422.987,128.872 L422.987,165.122 C422.987,172.002 418.015,176.998 411.135,176.998 L263.802,176.998 C256.923,176.998 250.99,172.002 250.99,165.122 L250.99,128.872 C250.99,121.993 256.923,116.997 263.802,116.997 L411.135,116.997 z" fill="#000000"/> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 2.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								editor/images/typedInput/bin.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 638 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/images/typedInput/expr.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 563 B | 
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2014, 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -18,13 +18,16 @@ RED.comms = (function() { | ||||
|  | ||||
|     var errornotification = null; | ||||
|     var clearErrorTimer = null; | ||||
|  | ||||
|     var connectCountdownTimer = null; | ||||
|     var connectCountdown = 10; | ||||
|     var subscriptions = {}; | ||||
|     var ws; | ||||
|     var pendingAuth = false; | ||||
|     var reconnectAttempts = 0; | ||||
|     var active = false; | ||||
|  | ||||
|     function connectWS() { | ||||
|         active = true; | ||||
|         var path = location.hostname; | ||||
|         var port = location.port; | ||||
|         if (port.length !== 0) { | ||||
| @@ -62,9 +65,17 @@ RED.comms = (function() { | ||||
|         } | ||||
|         ws.onmessage = function(event) { | ||||
|             var msg = JSON.parse(event.data); | ||||
|             if (pendingAuth && msg.auth == "ok") { | ||||
|                 pendingAuth = false; | ||||
|                 completeConnection(); | ||||
|             if (pendingAuth && msg.auth) { | ||||
|                 if (msg.auth === "ok") { | ||||
|                     pendingAuth = false; | ||||
|                     completeConnection(); | ||||
|                 } else if (msg.auth === "fail") { | ||||
|                     // anything else is an error... | ||||
|                     active = false; | ||||
|                     RED.user.login({updateMenu:true},function() { | ||||
|                         connectWS(); | ||||
|                     }) | ||||
|                 } | ||||
|             } else if (msg.topic) { | ||||
|                 for (var t in subscriptions) { | ||||
|                     if (subscriptions.hasOwnProperty(t)) { | ||||
| @@ -82,14 +93,42 @@ RED.comms = (function() { | ||||
|             } | ||||
|         }; | ||||
|         ws.onclose = function() { | ||||
|             if (reconnectAttempts > 5 && errornotification == null) { | ||||
|                 errornotification = RED.notify(RED._("notification.error",{message:RED._("notification.errors.lostConnection")}),"error",true); | ||||
|             } else if (clearErrorTimer) { | ||||
|             if (!active) { | ||||
|                 return; | ||||
|             } | ||||
|             if (clearErrorTimer) { | ||||
|                 clearTimeout(clearErrorTimer); | ||||
|                 clearErrorTimer = null; | ||||
|             } | ||||
|             reconnectAttempts++; | ||||
|             setTimeout(connectWS,1000); | ||||
|             if (reconnectAttempts < 10) { | ||||
|                 setTimeout(connectWS,1000); | ||||
|                 if (reconnectAttempts > 5 && errornotification == null) { | ||||
|                     errornotification = RED.notify(RED._("notification.errors.lostConnection"),"error",true); | ||||
|                 } | ||||
|             } else if (reconnectAttempts < 20) { | ||||
|                 setTimeout(connectWS,2000); | ||||
|             } else { | ||||
|                 connectCountdown = 60; | ||||
|                 connectCountdownTimer = setInterval(function() { | ||||
|                     connectCountdown--; | ||||
|                     if (connectCountdown === 0) { | ||||
|                         errornotification.update(RED._("notification.errors.lostConnection")); | ||||
|                         clearInterval(connectCountdownTimer); | ||||
|                         connectWS(); | ||||
|                     } else { | ||||
|                         var msg = RED._("notification.errors.lostConnectionReconnect",{time: connectCountdown})+' <a href="#">'+ RED._("notification.errors.lostConnectionTry")+'</a>'; | ||||
|                         errornotification.update(msg); | ||||
|                         $(errornotification).find("a").click(function(e) { | ||||
|                             e.preventDefault(); | ||||
|                             errornotification.update(RED._("notification.errors.lostConnection")); | ||||
|                             clearInterval(connectCountdownTimer); | ||||
|                             connectWS(); | ||||
|                         }) | ||||
|                     } | ||||
|                 },1000); | ||||
|             } | ||||
|  | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -35,7 +35,12 @@ | ||||
|      function emit(evt,arg) { | ||||
|          if (handlers[evt]) { | ||||
|              for (var i=0;i<handlers[evt].length;i++) { | ||||
|                  handlers[evt][i](arg); | ||||
|                  try { | ||||
|                      handlers[evt][i](arg); | ||||
|                  } catch(err) { | ||||
|                      console.log("RED.events.emit error: ["+evt+"] "+(err.toString())); | ||||
|                      console.log(err); | ||||
|                  } | ||||
|              } | ||||
|  | ||||
|          } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2013, 2016 IBM Corp. | ||||
|  * 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. | ||||
| @@ -16,6 +16,289 @@ | ||||
| RED.history = (function() { | ||||
|     var undo_history = []; | ||||
|  | ||||
|     function undoEvent(ev) { | ||||
|         var i; | ||||
|         var len; | ||||
|         var node; | ||||
|         var subflow; | ||||
|         var modifiedTabs = {}; | ||||
|         if (ev) { | ||||
|             if (ev.t == 'multi') { | ||||
|                 len = ev.events.length; | ||||
|                 for (i=len-1;i>=0;i--) { | ||||
|                     undoEvent(ev.events[i]); | ||||
|                 } | ||||
|             } else if (ev.t == 'replace') { | ||||
|                 RED.nodes.clear(); | ||||
|                 var imported = RED.nodes.import(ev.config); | ||||
|                 imported[0].forEach(function(n) { | ||||
|                     if (ev.changed[n.id]) { | ||||
|                         n.changed = true; | ||||
|                     } | ||||
|                 }) | ||||
|  | ||||
|                 RED.nodes.version(ev.rev); | ||||
|             } else if (ev.t == 'add') { | ||||
|                 if (ev.nodes) { | ||||
|                     for (i=0;i<ev.nodes.length;i++) { | ||||
|                         node = RED.nodes.node(ev.nodes[i]); | ||||
|                         if (node.z) { | ||||
|                             modifiedTabs[node.z] = true; | ||||
|                         } | ||||
|                         RED.nodes.remove(ev.nodes[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.links) { | ||||
|                     for (i=0;i<ev.links.length;i++) { | ||||
|                         RED.nodes.removeLink(ev.links[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.workspaces) { | ||||
|                     for (i=0;i<ev.workspaces.length;i++) { | ||||
|                         RED.nodes.removeWorkspace(ev.workspaces[i].id); | ||||
|                         RED.workspaces.remove(ev.workspaces[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.subflows) { | ||||
|                     for (i=0;i<ev.subflows.length;i++) { | ||||
|                         RED.nodes.removeSubflow(ev.subflows[i]); | ||||
|                         RED.workspaces.remove(ev.subflows[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.subflow) { | ||||
|                     if (ev.subflow.instances) { | ||||
|                         ev.subflow.instances.forEach(function(n) { | ||||
|                             var node = RED.nodes.node(n.id); | ||||
|                             if (node) { | ||||
|                                 node.changed = n.changed; | ||||
|                                 node.dirty = true; | ||||
|                             } | ||||
|                         }); | ||||
|                     } | ||||
|                     if (ev.subflow.hasOwnProperty('changed')) { | ||||
|                         subflow = RED.nodes.subflow(ev.subflow.id); | ||||
|                         if (subflow) { | ||||
|                             subflow.changed = ev.subflow.changed; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.removedLinks) { | ||||
|                     for (i=0;i<ev.removedLinks.length;i++) { | ||||
|                         RED.nodes.addLink(ev.removedLinks[i]); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|             } else if (ev.t == "delete") { | ||||
|                 if (ev.workspaces) { | ||||
|                     for (i=0;i<ev.workspaces.length;i++) { | ||||
|                         RED.nodes.addWorkspace(ev.workspaces[i]); | ||||
|                         RED.workspaces.add(ev.workspaces[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.subflow && ev.subflow.subflow) { | ||||
|                     RED.nodes.addSubflow(ev.subflow.subflow); | ||||
|                 } | ||||
|                 if (ev.subflowInputs && ev.subflowInputs.length > 0) { | ||||
|                     subflow = RED.nodes.subflow(ev.subflowInputs[0].z); | ||||
|                     subflow.in.push(ev.subflowInputs[0]); | ||||
|                     subflow.in[0].dirty = true; | ||||
|                 } | ||||
|                 if (ev.subflowOutputs && ev.subflowOutputs.length > 0) { | ||||
|                     subflow = RED.nodes.subflow(ev.subflowOutputs[0].z); | ||||
|                     ev.subflowOutputs.sort(function(a,b) { return a.i-b.i}); | ||||
|                     for (i=0;i<ev.subflowOutputs.length;i++) { | ||||
|                         var output = ev.subflowOutputs[i]; | ||||
|                         subflow.out.splice(output.i,0,output); | ||||
|                         for (var j=output.i+1;j<subflow.out.length;j++) { | ||||
|                             subflow.out[j].i++; | ||||
|                             subflow.out[j].dirty = true; | ||||
|                         } | ||||
|                         RED.nodes.eachLink(function(l) { | ||||
|                             if (l.source.type == "subflow:"+subflow.id) { | ||||
|                                 if (l.sourcePort >= output.i) { | ||||
|                                     l.sourcePort++; | ||||
|                                 } | ||||
|                             } | ||||
|                         }); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.subflow && ev.subflow.hasOwnProperty('instances')) { | ||||
|                     ev.subflow.instances.forEach(function(n) { | ||||
|                         var node = RED.nodes.node(n.id); | ||||
|                         if (node) { | ||||
|                             node.changed = n.changed; | ||||
|                             node.dirty = true; | ||||
|                         } | ||||
|                     }); | ||||
|                 } | ||||
|                 if (subflow) { | ||||
|                     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.nodes) { | ||||
|                     for (i=0;i<ev.nodes.length;i++) { | ||||
|                         RED.nodes.add(ev.nodes[i]); | ||||
|                         modifiedTabs[ev.nodes[i].z] = true; | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.links) { | ||||
|                     for (i=0;i<ev.links.length;i++) { | ||||
|                         RED.nodes.addLink(ev.links[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.changes) { | ||||
|                     for (i in ev.changes) { | ||||
|                         if (ev.changes.hasOwnProperty(i)) { | ||||
|                             node = RED.nodes.node(i); | ||||
|                             if (node) { | ||||
|                                 for (var d in ev.changes[i]) { | ||||
|                                     if (ev.changes[i].hasOwnProperty(d)) { | ||||
|                                         node[d] = ev.changes[i][d]; | ||||
|                                     } | ||||
|                                 } | ||||
|                                 node.dirty = true; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                 } | ||||
|             } else if (ev.t == "move") { | ||||
|                 for (i=0;i<ev.nodes.length;i++) { | ||||
|                     var n = ev.nodes[i]; | ||||
|                     n.n.x = n.ox; | ||||
|                     n.n.y = n.oy; | ||||
|                     n.n.dirty = true; | ||||
|                     n.n.moved = n.moved; | ||||
|                 } | ||||
|                 // A move could have caused a link splice | ||||
|                 if (ev.links) { | ||||
|                     for (i=0;i<ev.links.length;i++) { | ||||
|                         RED.nodes.removeLink(ev.links[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.removedLinks) { | ||||
|                     for (i=0;i<ev.removedLinks.length;i++) { | ||||
|                         RED.nodes.addLink(ev.removedLinks[i]); | ||||
|                     } | ||||
|                 } | ||||
|             } else if (ev.t == "edit") { | ||||
|                 for (i in ev.changes) { | ||||
|                     if (ev.changes.hasOwnProperty(i)) { | ||||
|                         if (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); | ||||
|                             } | ||||
|                             var newConfigNode = RED.nodes.node(ev.changes[i]); | ||||
|                             if (newConfigNode) { | ||||
|                                 newConfigNode.users.push(ev.node); | ||||
|                             } | ||||
|                         } | ||||
|                         ev.node[i] = ev.changes[i]; | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.subflow) { | ||||
|                     if (ev.subflow.hasOwnProperty('inputCount')) { | ||||
|                         if (ev.node.in.length > 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')) { | ||||
|                         if (ev.node.out.length > 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')) { | ||||
|                         ev.subflow.instances.forEach(function(n) { | ||||
|                             var node = RED.nodes.node(n.id); | ||||
|                             if (node) { | ||||
|                                 node.changed = n.changed; | ||||
|                                 node.dirty = true; | ||||
|                             } | ||||
|                         }); | ||||
|                     } | ||||
|                     RED.nodes.filterNodes({type:"subflow:"+ev.node.id}).forEach(function(n) { | ||||
|                         n.inputs = ev.node.in.length; | ||||
|                         n.outputs = ev.node.out.length; | ||||
|                         RED.editor.updateNodeProperties(n); | ||||
|                     }); | ||||
|                 } else { | ||||
|                     var outputMap; | ||||
|                     if (ev.outputMap) { | ||||
|                         outputMap = {}; | ||||
|                         for (var port in ev.outputMap) { | ||||
|                             if (ev.outputMap.hasOwnProperty(port) && ev.outputMap[port] !== "-1") { | ||||
|                                 outputMap[ev.outputMap[port]] = port; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     RED.editor.updateNodeProperties(ev.node,outputMap); | ||||
|                     RED.editor.validateNode(ev.node); | ||||
|                 } | ||||
|                 if (ev.links) { | ||||
|                     for (i=0;i<ev.links.length;i++) { | ||||
|                         RED.nodes.addLink(ev.links[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 ev.node.dirty = true; | ||||
|                 ev.node.changed = ev.changed; | ||||
|             } else if (ev.t == "createSubflow") { | ||||
|                 if (ev.nodes) { | ||||
|                     RED.nodes.filterNodes({z:ev.subflow.subflow.id}).forEach(function(n) { | ||||
|                         n.z = ev.activeWorkspace; | ||||
|                         n.dirty = true; | ||||
|                     }); | ||||
|                     for (i=0;i<ev.nodes.length;i++) { | ||||
|                         RED.nodes.remove(ev.nodes[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.links) { | ||||
|                     for (i=0;i<ev.links.length;i++) { | ||||
|                         RED.nodes.removeLink(ev.links[i]); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 RED.nodes.removeSubflow(ev.subflow.subflow); | ||||
|                 RED.workspaces.remove(ev.subflow.subflow); | ||||
|  | ||||
|                 if (ev.removedLinks) { | ||||
|                     for (i=0;i<ev.removedLinks.length;i++) { | ||||
|                         RED.nodes.addLink(ev.removedLinks[i]); | ||||
|                     } | ||||
|                 } | ||||
|             } else if (ev.t == "reorder") { | ||||
|                 if (ev.order) { | ||||
|                     RED.workspaces.order(ev.order); | ||||
|                 } | ||||
|             } | ||||
|             Object.keys(modifiedTabs).forEach(function(id) { | ||||
|                 var subflow = RED.nodes.subflow(id); | ||||
|                 if (subflow) { | ||||
|                     RED.editor.validateNode(subflow); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|             RED.nodes.dirty(ev.dirty); | ||||
|             RED.view.redraw(true); | ||||
|             RED.palette.refresh(); | ||||
|             RED.workspaces.refresh(); | ||||
|             RED.sidebar.config.refresh(); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         //TODO: this function is a placeholder until there is a 'save' event that can be listened to | ||||
|         markAllDirty: function() { | ||||
| @@ -23,6 +306,9 @@ RED.history = (function() { | ||||
|                 undo_history[i].dirty = true; | ||||
|             } | ||||
|         }, | ||||
|         list: function() { | ||||
|             return undo_history | ||||
|         }, | ||||
|         depth: function() { | ||||
|             return undo_history.length; | ||||
|         }, | ||||
| @@ -31,259 +317,10 @@ RED.history = (function() { | ||||
|         }, | ||||
|         pop: function() { | ||||
|             var ev = undo_history.pop(); | ||||
|             var i; | ||||
|             var node; | ||||
|             var subflow; | ||||
|             var modifiedTabs = {}; | ||||
|             if (ev) { | ||||
|                 if (ev.t == 'add') { | ||||
|                     if (ev.nodes) { | ||||
|                         for (i=0;i<ev.nodes.length;i++) { | ||||
|                             node = RED.nodes.node(ev.nodes[i]); | ||||
|                             if (node.z) { | ||||
|                                 modifiedTabs[node.z] = true; | ||||
|                             } | ||||
|                             RED.nodes.remove(ev.nodes[i]); | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.links) { | ||||
|                         for (i=0;i<ev.links.length;i++) { | ||||
|                             RED.nodes.removeLink(ev.links[i]); | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.workspaces) { | ||||
|                         for (i=0;i<ev.workspaces.length;i++) { | ||||
|                             RED.nodes.removeWorkspace(ev.workspaces[i].id); | ||||
|                             RED.workspaces.remove(ev.workspaces[i]); | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.subflows) { | ||||
|                         for (i=0;i<ev.subflows.length;i++) { | ||||
|                             RED.nodes.removeSubflow(ev.subflows[i]); | ||||
|                             RED.workspaces.remove(ev.subflows[i]); | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.subflow) { | ||||
|                         if (ev.subflow.instances) { | ||||
|                             ev.subflow.instances.forEach(function(n) { | ||||
|                                 var node = RED.nodes.node(n.id); | ||||
|                                 if (node) { | ||||
|                                     node.changed = n.changed; | ||||
|                                     node.dirty = true; | ||||
|                                 } | ||||
|                             }); | ||||
|                         } | ||||
|                         if (ev.subflow.hasOwnProperty('changed')) { | ||||
|                             subflow = RED.nodes.subflow(ev.subflow.id); | ||||
|                             if (subflow) { | ||||
|                                 subflow.changed = ev.subflow.changed; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.removedLinks) { | ||||
|                         for (i=0;i<ev.removedLinks.length;i++) { | ||||
|                             RED.nodes.addLink(ev.removedLinks[i]); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                 } else if (ev.t == "delete") { | ||||
|                     if (ev.workspaces) { | ||||
|                         for (i=0;i<ev.workspaces.length;i++) { | ||||
|                             RED.nodes.addWorkspace(ev.workspaces[i]); | ||||
|                             RED.workspaces.add(ev.workspaces[i]); | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.subflow && ev.subflow.subflow) { | ||||
|                         RED.nodes.addSubflow(ev.subflow.subflow); | ||||
|                     } | ||||
|                     if (ev.subflowInputs && ev.subflowInputs.length > 0) { | ||||
|                         subflow = RED.nodes.subflow(ev.subflowInputs[0].z); | ||||
|                         subflow.in.push(ev.subflowInputs[0]); | ||||
|                         subflow.in[0].dirty = true; | ||||
|                     } | ||||
|                     if (ev.subflowOutputs && ev.subflowOutputs.length > 0) { | ||||
|                         subflow = RED.nodes.subflow(ev.subflowOutputs[0].z); | ||||
|                         ev.subflowOutputs.sort(function(a,b) { return a.i-b.i}); | ||||
|                         for (i=0;i<ev.subflowOutputs.length;i++) { | ||||
|                             var output = ev.subflowOutputs[i]; | ||||
|                             subflow.out.splice(output.i,0,output); | ||||
|                             for (var j=output.i+1;j<subflow.out.length;j++) { | ||||
|                                 subflow.out[j].i++; | ||||
|                                 subflow.out[j].dirty = true; | ||||
|                             } | ||||
|                             RED.nodes.eachLink(function(l) { | ||||
|                                 if (l.source.type == "subflow:"+subflow.id) { | ||||
|                                     if (l.sourcePort >= output.i) { | ||||
|                                         l.sourcePort++; | ||||
|                                     } | ||||
|                                 } | ||||
|                             }); | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.subflow && ev.subflow.hasOwnProperty('instances')) { | ||||
|                         ev.subflow.instances.forEach(function(n) { | ||||
|                             var node = RED.nodes.node(n.id); | ||||
|                             if (node) { | ||||
|                                 node.changed = n.changed; | ||||
|                                 node.dirty = true; | ||||
|                             } | ||||
|                         }); | ||||
|                     } | ||||
|                     if (subflow) { | ||||
|                         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.nodes) { | ||||
|                         for (i=0;i<ev.nodes.length;i++) { | ||||
|                             RED.nodes.add(ev.nodes[i]); | ||||
|                             modifiedTabs[ev.nodes[i].z] = true; | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.links) { | ||||
|                         for (i=0;i<ev.links.length;i++) { | ||||
|                             RED.nodes.addLink(ev.links[i]); | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.changes) { | ||||
|                         for (i in ev.changes) { | ||||
|                             if (ev.changes.hasOwnProperty(i)) { | ||||
|                                 node = RED.nodes.node(i); | ||||
|                                 if (node) { | ||||
|                                     for (var d in ev.changes[i]) { | ||||
|                                         if (ev.changes[i].hasOwnProperty(d)) { | ||||
|                                             node[d] = ev.changes[i][d]; | ||||
|                                         } | ||||
|                                     } | ||||
|                                     node.dirty = true; | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|  | ||||
|                     } | ||||
|                 } else if (ev.t == "move") { | ||||
|                     for (i=0;i<ev.nodes.length;i++) { | ||||
|                         var n = ev.nodes[i]; | ||||
|                         n.n.x = n.ox; | ||||
|                         n.n.y = n.oy; | ||||
|                         n.n.dirty = true; | ||||
|                     } | ||||
|                     // A move could have caused a link splice | ||||
|                     if (ev.links) { | ||||
|                         for (i=0;i<ev.links.length;i++) { | ||||
|                             RED.nodes.removeLink(ev.links[i]); | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.removedLinks) { | ||||
|                         for (i=0;i<ev.removedLinks.length;i++) { | ||||
|                             RED.nodes.addLink(ev.removedLinks[i]); | ||||
|                         } | ||||
|                     } | ||||
|                 } else if (ev.t == "edit") { | ||||
|                     for (i in ev.changes) { | ||||
|                         if (ev.changes.hasOwnProperty(i)) { | ||||
|                             if (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); | ||||
|                                 } | ||||
|                                 var newConfigNode = RED.nodes.node(ev.changes[i]); | ||||
|                                 if (newConfigNode) { | ||||
|                                     newConfigNode.users.push(ev.node); | ||||
|                                 } | ||||
|                             } | ||||
|                             ev.node[i] = ev.changes[i]; | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.subflow) { | ||||
|                         if (ev.subflow.hasOwnProperty('inputCount')) { | ||||
|                             if (ev.node.in.length > 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')) { | ||||
|                             if (ev.node.out.length > 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')) { | ||||
|                             ev.subflow.instances.forEach(function(n) { | ||||
|                                 var node = RED.nodes.node(n.id); | ||||
|                                 if (node) { | ||||
|                                     node.changed = n.changed; | ||||
|                                     node.dirty = true; | ||||
|                                 } | ||||
|                             }); | ||||
|                         } | ||||
|                         RED.nodes.filterNodes({type:"subflow:"+ev.node.id}).forEach(function(n) { | ||||
|                             n.inputs = ev.node.in.length; | ||||
|                             n.outputs = ev.node.out.length; | ||||
|                             RED.editor.updateNodeProperties(n); | ||||
|                         }); | ||||
|  | ||||
|                         if (ev.node.type === 'subflow') { | ||||
|                             $("#menu-item-workspace-menu-"+ev.node.id.replace(".","-")).text(ev.node.name); | ||||
|                         } | ||||
|                     } else { | ||||
|                         RED.editor.updateNodeProperties(ev.node); | ||||
|                         RED.editor.validateNode(ev.node); | ||||
|                     } | ||||
|                     if (ev.links) { | ||||
|                         for (i=0;i<ev.links.length;i++) { | ||||
|                             RED.nodes.addLink(ev.links[i]); | ||||
|                         } | ||||
|                     } | ||||
|                     ev.node.dirty = true; | ||||
|                     ev.node.changed = ev.changed; | ||||
|                 } else if (ev.t == "createSubflow") { | ||||
|                     if (ev.nodes) { | ||||
|                         RED.nodes.filterNodes({z:ev.subflow.subflow.id}).forEach(function(n) { | ||||
|                             n.z = ev.activeWorkspace; | ||||
|                             n.dirty = true; | ||||
|                         }); | ||||
|                         for (i=0;i<ev.nodes.length;i++) { | ||||
|                             RED.nodes.remove(ev.nodes[i]); | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.links) { | ||||
|                         for (i=0;i<ev.links.length;i++) { | ||||
|                             RED.nodes.removeLink(ev.links[i]); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     RED.nodes.removeSubflow(ev.subflow.subflow); | ||||
|                     RED.workspaces.remove(ev.subflow.subflow); | ||||
|  | ||||
|                     if (ev.removedLinks) { | ||||
|                         for (i=0;i<ev.removedLinks.length;i++) { | ||||
|                             RED.nodes.addLink(ev.removedLinks[i]); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 Object.keys(modifiedTabs).forEach(function(id) { | ||||
|                     var subflow = RED.nodes.subflow(id); | ||||
|                     if (subflow) { | ||||
|                         RED.editor.validateNode(subflow); | ||||
|                     } | ||||
|                 }); | ||||
|  | ||||
|                 RED.nodes.dirty(ev.dirty); | ||||
|                 RED.view.redraw(true); | ||||
|                 RED.palette.refresh(); | ||||
|                 RED.workspaces.refresh(); | ||||
|                 RED.sidebar.config.refresh(); | ||||
|             } | ||||
|             undoEvent(ev); | ||||
|         }, | ||||
|         peek: function() { | ||||
|             return undo_history[undo_history.length-1]; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2013, 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -19,11 +19,11 @@ RED.i18n = (function() { | ||||
|     return { | ||||
|         init: function(done) { | ||||
|             i18n.init({ | ||||
|                 resGetPath: 'locales/__ns__', | ||||
|                 resGetPath: 'locales/__ns__?lng=__lng__', | ||||
|                 dynamicLoad: false, | ||||
|                 load:'current', | ||||
|                 ns: { | ||||
|                     namespaces: ["editor","node-red"], | ||||
|                     namespaces: ["editor","node-red","jsonata","infotips"], | ||||
|                     defaultNs: "editor" | ||||
|                 }, | ||||
|                 fallbackLng: ['en-US'], | ||||
| @@ -37,7 +37,50 @@ RED.i18n = (function() { | ||||
|  | ||||
|         }, | ||||
|         loadCatalog: function(namespace,done) { | ||||
|             i18n.loadNamespace(namespace,done); | ||||
|             var languageList = i18n.functions.toLanguages(i18n.detectLanguage()); | ||||
|             var toLoad = languageList.length; | ||||
|             languageList.forEach(function(lang) { | ||||
|                 $.ajax({ | ||||
|                     headers: { | ||||
|                         "Accept":"application/json" | ||||
|                     }, | ||||
|                     cache: false, | ||||
|                     url: 'locales/'+namespace+'?lng='+lang, | ||||
|                     success: function(data) { | ||||
|                         i18n.addResourceBundle(lang,namespace,data); | ||||
|                         toLoad--; | ||||
|                         if (toLoad === 0) { | ||||
|                             done(); | ||||
|                         } | ||||
|                     } | ||||
|                 }); | ||||
|             }) | ||||
|  | ||||
|         }, | ||||
|  | ||||
|         loadNodeCatalogs: function(done) { | ||||
|             var languageList = i18n.functions.toLanguages(i18n.detectLanguage()); | ||||
|             var toLoad = languageList.length; | ||||
|  | ||||
|             languageList.forEach(function(lang) { | ||||
|                 $.ajax({ | ||||
|                     headers: { | ||||
|                         "Accept":"application/json" | ||||
|                     }, | ||||
|                     cache: false, | ||||
|                     url: 'locales/nodes?lng='+lang, | ||||
|                     success: function(data) { | ||||
|                         var namespaces = Object.keys(data); | ||||
|                         namespaces.forEach(function(ns) { | ||||
|                             i18n.addResourceBundle(lang,ns,data[ns]); | ||||
|                         }); | ||||
|                         toLoad--; | ||||
|                         if (toLoad === 0) { | ||||
|                             done(); | ||||
|                         } | ||||
|                     } | ||||
|                 }); | ||||
|             }) | ||||
|         } | ||||
|     } | ||||
| })(); | ||||
|   | ||||
							
								
								
									
										39
									
								
								editor/js/keymap.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,39 @@ | ||||
| { | ||||
|     "*": { | ||||
|         "ctrl-shift-p":"core:manage-palette", | ||||
|         "ctrl-f": "core:search", | ||||
|         "ctrl-=": "core:zoom-in", | ||||
|         "ctrl--": "core:zoom-out", | ||||
|         "ctrl-0": "core:zoom-reset", | ||||
|         "ctrl-enter": "core:confirm-edit-tray", | ||||
|         "ctrl-escape": "core:cancel-edit-tray", | ||||
|         "ctrl-g i": "core:show-info-tab", | ||||
|         "ctrl-g d": "core:show-debug-tab", | ||||
|         "ctrl-g c": "core:show-config-tab", | ||||
|         "ctrl-e": "core:show-export-dialog", | ||||
|         "ctrl-i": "core:show-import-dialog", | ||||
|         "ctrl-space": "core:toggle-sidebar", | ||||
|         "ctrl-,": "core:show-user-settings" | ||||
|     }, | ||||
|     "workspace": { | ||||
|         "backspace": "core:delete-selection", | ||||
|         "delete": "core:delete-selection", | ||||
|         "enter": "core:edit-selected-node", | ||||
|         "ctrl-c": "core:copy-selection-to-internal-clipboard", | ||||
|         "ctrl-x": "core:cut-selection-to-internal-clipboard", | ||||
|         "ctrl-v": "core:paste-from-internal-clipboard", | ||||
|         "ctrl-z": "core:undo", | ||||
|         "ctrl-a": "core:select-all-nodes", | ||||
|         "shift-?": "core:show-help", | ||||
|         "up": "core:move-selection-up", | ||||
|         "right": "core:move-selection-right", | ||||
|         "down": "core:move-selection-down", | ||||
|         "left": "core:move-selection-left", | ||||
|         "shift-up": "core:step-selection-up", | ||||
|         "shift-right": "core:step-selection-right", | ||||
|         "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" | ||||
|      } | ||||
| } | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2013, 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -13,8 +13,7 @@ | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  **/ | ||||
| var RED = (function() { | ||||
|  | ||||
| (function() { | ||||
|  | ||||
|     function loadNodeList() { | ||||
|         $.ajax({ | ||||
| @@ -25,23 +24,7 @@ var RED = (function() { | ||||
|             url: 'nodes', | ||||
|             success: function(data) { | ||||
|                 RED.nodes.setNodeList(data); | ||||
|  | ||||
|                 var nsCount = 0; | ||||
|                 for(var i=0;i<data.length;i++) { | ||||
|                     var ns = data[i]; | ||||
|                     if (ns.module != "node-red") { | ||||
|                         nsCount++; | ||||
|                         RED.i18n.loadCatalog(ns.id, function() { | ||||
|                             nsCount--; | ||||
|                             if (nsCount === 0) { | ||||
|                                 loadNodes(); | ||||
|                             } | ||||
|                         }); | ||||
|                     } | ||||
|                 } | ||||
|                 if (nsCount === 0) { | ||||
|                     loadNodes(); | ||||
|                 } | ||||
|                 RED.i18n.loadNodeCatalogs(loadNodes); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| @@ -56,11 +39,9 @@ var RED = (function() { | ||||
|             success: function(data) { | ||||
|                 $("body").append(data); | ||||
|                 $("body").i18n(); | ||||
|  | ||||
|  | ||||
|                 $(".palette-spinner").hide(); | ||||
|                 $(".palette-scroll").show(); | ||||
|                 $("#palette-search").show(); | ||||
|                 $("#palette > .palette-spinner").hide(); | ||||
|                 $(".palette-scroll").removeClass("hide"); | ||||
|                 $("#palette-search").removeClass("hide"); | ||||
|                 loadFlows(); | ||||
|             } | ||||
|         }); | ||||
| @@ -69,49 +50,79 @@ var RED = (function() { | ||||
|     function loadFlows() { | ||||
|         $.ajax({ | ||||
|             headers: { | ||||
|                 "Accept":"application/json" | ||||
|                 "Accept":"application/json", | ||||
|             }, | ||||
|             cache: false, | ||||
|             url: 'flows', | ||||
|             success: function(nodes) { | ||||
|                 RED.nodes.import(nodes); | ||||
|                 var currentHash = window.location.hash; | ||||
|                 RED.nodes.version(nodes.rev); | ||||
|                 RED.nodes.import(nodes.flows); | ||||
|                 RED.nodes.dirty(false); | ||||
|                 RED.view.redraw(true); | ||||
|                 if (/^#flow\/.+$/.test(currentHash)) { | ||||
|                     RED.workspaces.show(currentHash.substring(6)); | ||||
|                 } | ||||
|  | ||||
|                 var persistentNotifications = {}; | ||||
|                 RED.comms.subscribe("notification/#",function(topic,msg) { | ||||
|                     var parts = topic.split("/"); | ||||
|                     var notificationId = parts[1]; | ||||
|                     if (notificationId === "runtime-deploy") { | ||||
|                         // handled in ui/deploy.js | ||||
|                         return; | ||||
|                     } | ||||
|                     if (notificationId === "node") { | ||||
|                         // handled below | ||||
|                         return; | ||||
|                     } | ||||
|                     if (msg.text) { | ||||
|                         var text = RED._(msg.text,{default:msg.text}); | ||||
|                         if (!persistentNotifications.hasOwnProperty(notificationId)) { | ||||
|                             persistentNotifications[notificationId] = RED.notify(text,msg.type,msg.timeout === undefined,msg.timeout); | ||||
|                         } else { | ||||
|                             persistentNotifications[notificationId].update(text,msg.timeout); | ||||
|                         } | ||||
|                     } else if (persistentNotifications.hasOwnProperty(notificationId)) { | ||||
|                         persistentNotifications[notificationId].close(); | ||||
|                         delete persistentNotifications[notificationId]; | ||||
|                     } | ||||
|                 }); | ||||
|                 RED.comms.subscribe("status/#",function(topic,msg) { | ||||
|                     var parts = topic.split("/"); | ||||
|                     var node = RED.nodes.node(parts[1]); | ||||
|                     if (node) { | ||||
|                         if (msg.text) { | ||||
|                             msg.text = node._(msg.text.toString(),{defaultValue:msg.text.toString()}); | ||||
|                         if (msg.hasOwnProperty("text")) { | ||||
|                             if (msg.text[0] !== ".") { | ||||
|                                 msg.text = node._(msg.text.toString(),{defaultValue:msg.text.toString()}); | ||||
|                             } | ||||
|                         } | ||||
|                         node.status = msg; | ||||
|                         if (statusEnabled) { | ||||
|                             node.dirty = true; | ||||
|                             RED.view.redraw(); | ||||
|                         } | ||||
|                         node.dirty = true; | ||||
|                         RED.view.redraw(); | ||||
|                     } | ||||
|                 }); | ||||
|                 RED.comms.subscribe("node/#",function(topic,msg) { | ||||
|                 RED.comms.subscribe("notification/node/#",function(topic,msg) { | ||||
|                     var i,m; | ||||
|                     var typeList; | ||||
|                     var info; | ||||
|  | ||||
|                     if (topic == "node/added") { | ||||
|                     if (topic == "notification/node/added") { | ||||
|                         var addedTypes = []; | ||||
|                         for (i=0;i<msg.length;i++) { | ||||
|                             m = msg[i]; | ||||
|                         msg.forEach(function(m) { | ||||
|                             var id = m.id; | ||||
|                             RED.nodes.addNodeSet(m); | ||||
|                             addedTypes = addedTypes.concat(m.types); | ||||
|                             $.get('nodes/'+id, function(data) { | ||||
|                                 $("body").append(data); | ||||
|                             RED.i18n.loadCatalog(id, function() { | ||||
|                                 $.get('nodes/'+id, function(data) { | ||||
|                                     $("body").append(data); | ||||
|                                 }); | ||||
|                             }); | ||||
|                         } | ||||
|                         }); | ||||
|                         if (addedTypes.length) { | ||||
|                             typeList = "<ul><li>"+addedTypes.join("</li><li>")+"</li></ul>"; | ||||
|                             RED.notify(RED._("palette.event.nodeAdded", {count:addedTypes.length})+typeList,"success"); | ||||
|                         } | ||||
|                     } else if (topic == "node/removed") { | ||||
|                     } else if (topic == "notification/node/removed") { | ||||
|                         for (i=0;i<msg.length;i++) { | ||||
|                             m = msg[i]; | ||||
|                             info = RED.nodes.removeNodeSet(m.id); | ||||
| @@ -120,7 +131,7 @@ var RED = (function() { | ||||
|                                 RED.notify(RED._("palette.event.nodeRemoved", {count:m.types.length})+typeList,"success"); | ||||
|                             } | ||||
|                         } | ||||
|                     } else if (topic == "node/enabled") { | ||||
|                     } else if (topic == "notification/node/enabled") { | ||||
|                         if (msg.types) { | ||||
|                             info = RED.nodes.getNodeSet(msg.id); | ||||
|                             if (info.added) { | ||||
| @@ -135,79 +146,114 @@ var RED = (function() { | ||||
|                                 }); | ||||
|                             } | ||||
|                         } | ||||
|                     } else if (topic == "node/disabled") { | ||||
|                     } else if (topic == "notification/node/disabled") { | ||||
|                         if (msg.types) { | ||||
|                             RED.nodes.disableNodeSet(msg.id); | ||||
|                             typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>"; | ||||
|                             RED.notify(RED._("palette.event.nodeDisabled", {count:msg.types.length})+typeList,"success"); | ||||
|                         } | ||||
|                     } else if (topic == "node/upgraded") { | ||||
|                         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(); | ||||
|                 }); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     var statusEnabled = false; | ||||
|     function toggleStatus(state) { | ||||
|         statusEnabled = state; | ||||
|         RED.view.status(statusEnabled); | ||||
|     function showAbout() { | ||||
|         $.get('red/about', function(data) { | ||||
|             var aboutHeader = '<div style="text-align:center;">'+ | ||||
|                                 '<img width="50px" src="red/images/node-red-icon.svg" />'+ | ||||
|                               '</div>'; | ||||
|  | ||||
|             RED.sidebar.info.set(aboutHeader+marked(data)); | ||||
|             RED.sidebar.info.show(); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     function loadEditor() { | ||||
|         RED.menu.init({id:"btn-sidemenu", | ||||
|             options: [ | ||||
|                 {id:"menu-item-view-menu",label:RED._("menu.label.view.view"),options:[ | ||||
|                     {id:"menu-item-view-show-grid",label:RED._("menu.label.view.showGrid"),toggle:true,onselect:RED.view.toggleShowGrid}, | ||||
|                     {id:"menu-item-view-snap-grid",label:RED._("menu.label.view.snapGrid"),toggle:true,onselect:RED.view.toggleSnapGrid}, | ||||
|                     {id:"menu-item-status",label:RED._("menu.label.displayStatus"),toggle:true,onselect:toggleStatus, selected: true}, | ||||
|                     null, | ||||
|                     {id:"menu-item-sidebar",label:RED._("menu.label.sidebar.show"),toggle:true,onselect:RED.sidebar.toggleSidebar, selected: true} | ||||
|                 ]}, | ||||
|                 null, | ||||
|                 {id:"menu-item-import",label:RED._("menu.label.import"),options:[ | ||||
|                     {id:"menu-item-import-clipboard",label:RED._("menu.label.clipboard"),onselect:RED.clipboard.import}, | ||||
|                     {id:"menu-item-import-library",label:RED._("menu.label.library"),options:[]} | ||||
|                 ]}, | ||||
|                 {id:"menu-item-export",label:RED._("menu.label.export"),disabled:true,options:[ | ||||
|                     {id:"menu-item-export-clipboard",label:RED._("menu.label.clipboard"),disabled:true,onselect:RED.clipboard.export}, | ||||
|                     {id:"menu-item-export-library",label:RED._("menu.label.library"),disabled:true,onselect:RED.library.export} | ||||
|                 ]}, | ||||
|                 null, | ||||
|                 {id:"menu-item-config-nodes",label:RED._("menu.label.displayConfig"),onselect:function(){}}, | ||||
|                 {id:"menu-item-workspace",label:RED._("menu.label.flows"),options:[ | ||||
|                     {id:"menu-item-workspace-add",label:RED._("menu.label.add"),onselect:RED.workspaces.add}, | ||||
|                     {id:"menu-item-workspace-edit",label:RED._("menu.label.rename"),onselect:RED.workspaces.edit}, | ||||
|                     {id:"menu-item-workspace-delete",label:RED._("menu.label.delete"),onselect:RED.workspaces.remove}, | ||||
|                     null | ||||
|                 ]}, | ||||
|                 {id:"menu-item-subflow",label:RED._("menu.label.subflows"), options: [ | ||||
|                     {id:"menu-item-subflow-create",label:RED._("menu.label.createSubflow"),onselect:RED.subflow.createSubflow}, | ||||
|                     {id:"menu-item-subflow-convert",label:RED._("menu.label.selectionToSubflow"),disabled:true,onselect:RED.subflow.convertToSubflow}, | ||||
|                 ]}, | ||||
|                 null, | ||||
|                 {id:"menu-item-keyboard-shortcuts",label:RED._("menu.label.keyboardShortcuts"),onselect:RED.keyboard.showHelp}, | ||||
|                 {id:"menu-item-help", | ||||
|                     label: RED.settings.theme("menu.menu-item-help.label","Node-RED Website"), | ||||
|                     href: RED.settings.theme("menu.menu-item-help.url","http://nodered.org/docs") | ||||
|                 }, | ||||
|                 {id:"menu-item-node-red-version", label:"v"+RED.settings.version} | ||||
|             ] | ||||
|         var menuOptions = []; | ||||
|         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-sidebar",label:RED._("menu.label.sidebar.show"),toggle:true,onselect:"core:toggle-sidebar", selected: true}, | ||||
|             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"),disabled:true,options:[ | ||||
|             {id:"menu-item-export-clipboard",label:RED._("menu.label.clipboard"),disabled:true,onselect:"core:show-export-dialog"}, | ||||
|             {id:"menu-item-export-library",label:RED._("menu.label.library"),disabled:true,onselect:"core:library-export"} | ||||
|         ]}); | ||||
|         menuOptions.push(null); | ||||
|         menuOptions.push({id:"menu-item-search",label:RED._("menu.label.search"),onselect:"core:search"}); | ||||
|         menuOptions.push(null); | ||||
|         menuOptions.push({id:"menu-item-config-nodes",label:RED._("menu.label.displayConfig"),onselect:"core:show-config-tab"}); | ||||
|         menuOptions.push({id:"menu-item-workspace",label:RED._("menu.label.flows"),options:[ | ||||
|             {id:"menu-item-workspace-add",label:RED._("menu.label.add"),onselect:"core:add-flow"}, | ||||
|             {id:"menu-item-workspace-edit",label:RED._("menu.label.rename"),onselect:"core:edit-flow"}, | ||||
|             {id:"menu-item-workspace-delete",label:RED._("menu.label.delete"),onselect:"core:remove-flow"} | ||||
|         ]}); | ||||
|         menuOptions.push({id:"menu-item-subflow",label:RED._("menu.label.subflows"), options: [ | ||||
|             {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(null); | ||||
|         if (RED.settings.theme('palette.editable') !== false) { | ||||
|             menuOptions.push({id:"menu-item-edit-palette",label:RED._("menu.label.editPalette"),onselect:"core:manage-palette"}); | ||||
|             menuOptions.push(null); | ||||
|         } | ||||
|  | ||||
|         menuOptions.push({id:"menu-item-user-settings",label:RED._("menu.label.userSettings"),onselect:"core:show-user-settings"}); | ||||
|         menuOptions.push(null); | ||||
|  | ||||
|         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","Node-RED website"), | ||||
|             href: RED.settings.theme("menu.menu-item-help.url","http://nodered.org/docs") | ||||
|         }); | ||||
|         menuOptions.push({id:"menu-item-node-red-version", label:"v"+RED.settings.version, onselect: "core:show-about" }); | ||||
|  | ||||
|  | ||||
|         RED.view.init(); | ||||
|         RED.userSettings.init(); | ||||
|         RED.user.init(); | ||||
|  | ||||
|         RED.library.init(); | ||||
|         RED.keyboard.init(); | ||||
|         RED.palette.init(); | ||||
|         if (RED.settings.theme('palette.editable') !== false) { | ||||
|             RED.palette.editor.init(); | ||||
|         } | ||||
|  | ||||
|         RED.sidebar.init(); | ||||
|         RED.subflow.init(); | ||||
|         RED.workspaces.init(); | ||||
|         RED.clipboard.init(); | ||||
|         RED.view.init(); | ||||
|         RED.search.init(); | ||||
|         RED.editor.init(); | ||||
|         RED.diff.init(); | ||||
|  | ||||
|         RED.menu.init({id:"btn-sidemenu",options: menuOptions}); | ||||
|  | ||||
|         RED.deploy.init(RED.settings.theme("deployButton",null)); | ||||
|  | ||||
|         RED.keyboard.add(/* ? */ 191,{shift:true},function(){RED.keyboard.showHelp();d3.event.preventDefault();}); | ||||
|         RED.actions.add("core:show-about", showAbout); | ||||
|         RED.nodes.init(); | ||||
|         RED.comms.connect(); | ||||
|  | ||||
|         $("#main-container").show(); | ||||
| @@ -228,8 +274,4 @@ var RED = (function() { | ||||
|             RED.settings.init(loadEditor); | ||||
|         }) | ||||
|     }); | ||||
|  | ||||
|  | ||||
|     return { | ||||
|     }; | ||||
| })(); | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2013, 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -21,7 +21,11 @@ RED.nodes = (function() { | ||||
|     var links = []; | ||||
|     var defaultWorkspace; | ||||
|     var workspaces = {}; | ||||
|     var workspacesOrder =[]; | ||||
|     var subflows = {}; | ||||
|     var loadedFlowVersion = null; | ||||
|  | ||||
|     var initialLoad; | ||||
|  | ||||
|     var dirty = false; | ||||
|  | ||||
| @@ -31,15 +35,32 @@ RED.nodes = (function() { | ||||
|     } | ||||
|  | ||||
|     var registry = (function() { | ||||
|         var moduleList = {}; | ||||
|         var nodeList = []; | ||||
|         var nodeSets = {}; | ||||
|         var typeToId = {}; | ||||
|         var nodeDefinitions = {}; | ||||
|  | ||||
|         var exports = { | ||||
|             setModulePendingUpdated: function(module,version) { | ||||
|                 moduleList[module].pending_version = version; | ||||
|                 RED.events.emit("registry:module-updated",{module:module,version:version}); | ||||
|             }, | ||||
|             getModule: function(module) { | ||||
|                 return moduleList[module]; | ||||
|             }, | ||||
|             getNodeSetForType: function(nodeType) { | ||||
|                 return exports.getNodeSet(typeToId[nodeType]); | ||||
|             }, | ||||
|             getModuleList: function() { | ||||
|                 return moduleList; | ||||
|             }, | ||||
|             getNodeList: function() { | ||||
|                 return nodeList; | ||||
|             }, | ||||
|             getNodeTypes: function() { | ||||
|                 return Object.keys(nodeDefinitions); | ||||
|             }, | ||||
|             setNodeList: function(list) { | ||||
|                 nodeList = []; | ||||
|                 for(var i=0;i<list.length;i++) { | ||||
| @@ -54,27 +75,36 @@ RED.nodes = (function() { | ||||
|                     typeToId[ns.types[j]] = ns.id; | ||||
|                 } | ||||
|                 nodeList.push(ns); | ||||
|  | ||||
|                 moduleList[ns.module] = moduleList[ns.module] || { | ||||
|                     name:ns.module, | ||||
|                     version:ns.version, | ||||
|                     local:ns.local, | ||||
|                     sets:{} | ||||
|                 }; | ||||
|                 if (ns.pending_version) { | ||||
|                     moduleList[ns.module].pending_version = ns.pending_version; | ||||
|                 } | ||||
|                 moduleList[ns.module].sets[ns.name] = ns; | ||||
|                 RED.events.emit("registry:node-set-added",ns); | ||||
|             }, | ||||
|             removeNodeSet: function(id) { | ||||
|                 var ns = nodeSets[id]; | ||||
|                 for (var j=0;j<ns.types.length;j++) { | ||||
|                     if (ns.added) { | ||||
|                         // TODO: too tightly coupled into palette UI | ||||
|                         RED.palette.remove(ns.types[j]); | ||||
|                         var def = nodeDefinitions[ns.types[j]]; | ||||
|                         if (def.onpaletteremove && typeof def.onpaletteremove === "function") { | ||||
|                             def.onpaletteremove.call(def); | ||||
|                         } | ||||
|                     } | ||||
|                     delete typeToId[ns.types[j]]; | ||||
|                 } | ||||
|                 delete nodeSets[id]; | ||||
|                 for (var i=0;i<nodeList.length;i++) { | ||||
|                     if (nodeList[i].id == id) { | ||||
|                     if (nodeList[i].id === id) { | ||||
|                         nodeList.splice(i,1); | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|                 delete moduleList[ns.module].sets[ns.name]; | ||||
|                 if (Object.keys(moduleList[ns.module].sets).length === 0) { | ||||
|                     delete moduleList[ns.module]; | ||||
|                 } | ||||
|                 RED.events.emit("registry:node-set-removed",ns); | ||||
|                 return ns; | ||||
|             }, | ||||
|             getNodeSet: function(id) { | ||||
| @@ -83,32 +113,20 @@ RED.nodes = (function() { | ||||
|             enableNodeSet: function(id) { | ||||
|                 var ns = nodeSets[id]; | ||||
|                 ns.enabled = true; | ||||
|                 for (var j=0;j<ns.types.length;j++) { | ||||
|                     // TODO: too tightly coupled into palette UI | ||||
|                     RED.palette.show(ns.types[j]); | ||||
|                     var def = nodeDefinitions[ns.types[j]]; | ||||
|                     if (def.onpaletteadd && typeof def.onpaletteadd === "function") { | ||||
|                         def.onpaletteadd.call(def); | ||||
|                     } | ||||
|                 } | ||||
|                 RED.events.emit("registry:node-set-enabled",ns); | ||||
|             }, | ||||
|             disableNodeSet: function(id) { | ||||
|                 var ns = nodeSets[id]; | ||||
|                 ns.enabled = false; | ||||
|                 for (var j=0;j<ns.types.length;j++) { | ||||
|                     // TODO: too tightly coupled into palette UI | ||||
|                     RED.palette.hide(ns.types[j]); | ||||
|                     var def = nodeDefinitions[ns.types[j]]; | ||||
|                     if (def.onpaletteremove && typeof def.onpaletteremove === "function") { | ||||
|                         def.onpaletteremove.call(def); | ||||
|                     } | ||||
|                 } | ||||
|                 RED.events.emit("registry:node-set-disabled",ns); | ||||
|             }, | ||||
|             registerNodeType: function(nt,def) { | ||||
|                 nodeDefinitions[nt] = def; | ||||
|                 def.type = nt; | ||||
|                 if (def.category != "subflows") { | ||||
|                     def.set = nodeSets[typeToId[nt]]; | ||||
|                     nodeSets[typeToId[nt]].added = true; | ||||
|                     nodeSets[typeToId[nt]].enabled = true; | ||||
|  | ||||
|                     var ns; | ||||
|                     if (def.set.module === "node-red") { | ||||
| @@ -118,18 +136,20 @@ RED.nodes = (function() { | ||||
|                     } | ||||
|                     def["_"] = function() { | ||||
|                         var args = Array.prototype.slice.call(arguments, 0); | ||||
|                         var original = args[0]; | ||||
|                         if (args[0].indexOf(":") === -1) { | ||||
|                             args[0] = ns+":"+args[0]; | ||||
|                         } | ||||
|                         return RED._.apply(null,args); | ||||
|                         var result = RED._.apply(null,args); | ||||
|                         if (result === args[0]) { | ||||
|                             result = original; | ||||
|                         } | ||||
|                         return result; | ||||
|                     } | ||||
|  | ||||
|                     // TODO: too tightly coupled into palette UI | ||||
|                 } | ||||
|                 RED.palette.add(nt,def); | ||||
|                 if (def.onpaletteadd && typeof def.onpaletteadd === "function") { | ||||
|                     def.onpaletteadd.call(def); | ||||
|                 } | ||||
|                 RED.events.emit("registry:node-type-added",nt); | ||||
|             }, | ||||
|             removeNodeType: function(nt) { | ||||
|                 if (nt.substring(0,8) != "subflow:") { | ||||
| @@ -137,7 +157,7 @@ RED.nodes = (function() { | ||||
|                     throw new Error("this api is subflow only. called with:",nt); | ||||
|                 } | ||||
|                 delete nodeDefinitions[nt]; | ||||
|                 RED.palette.remove(nt); | ||||
|                 RED.events.emit("registry:node-type-removed",nt); | ||||
|             }, | ||||
|             getNodeType: function(nt) { | ||||
|                 return nodeDefinitions[nt]; | ||||
| @@ -153,36 +173,21 @@ RED.nodes = (function() { | ||||
|     function addNode(n) { | ||||
|         if (n.type.indexOf("subflow") !== 0) { | ||||
|             n["_"] = n._def._; | ||||
|         } else { | ||||
|             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; | ||||
|             var updatedConfigNode = false; | ||||
|             for (var d in n._def.defaults) { | ||||
|                 if (n._def.defaults.hasOwnProperty(d)) { | ||||
|                     var property = n._def.defaults[d]; | ||||
|                     if (property.type) { | ||||
|                         var type = registry.getNodeType(property.type); | ||||
|                         if (type && type.category == "config") { | ||||
|                             var configNode = configNodes[n[d]]; | ||||
|                             if (configNode) { | ||||
|                                 updatedConfigNode = true; | ||||
|                                 configNode.users.push(n); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             if (updatedConfigNode) { | ||||
|                 // TODO: refresh config tab? | ||||
|             } | ||||
|             updateConfigNodeUsers(n); | ||||
|             if (n._def.category == "subflows" && typeof n.i === "undefined") { | ||||
|                 var nextId = 0; | ||||
|                 RED.nodes.eachNode(function(node) { | ||||
| @@ -192,9 +197,7 @@ RED.nodes = (function() { | ||||
|             } | ||||
|             nodes.push(n); | ||||
|         } | ||||
|         if (n._def.onadd) { | ||||
|             n._def.onadd.call(n); | ||||
|         } | ||||
|         RED.events.emit('nodes:add',n); | ||||
|     } | ||||
|     function addLink(l) { | ||||
|         links.push(l); | ||||
| @@ -220,6 +223,7 @@ RED.nodes = (function() { | ||||
|         if (id in configNodes) { | ||||
|             node = configNodes[id]; | ||||
|             delete configNodes[id]; | ||||
|             RED.events.emit('nodes:remove',node); | ||||
|             RED.workspaces.refresh(); | ||||
|         } else { | ||||
|             node = getNode(id); | ||||
| @@ -252,6 +256,7 @@ RED.nodes = (function() { | ||||
|                 if (updatedConfigNode) { | ||||
|                     RED.workspaces.refresh(); | ||||
|                 } | ||||
|                 RED.events.emit('nodes:remove',node); | ||||
|             } | ||||
|         } | ||||
|         if (node && node._def.onremove) { | ||||
| @@ -269,12 +274,23 @@ RED.nodes = (function() { | ||||
|  | ||||
|     function addWorkspace(ws) { | ||||
|         workspaces[ws.id] = ws; | ||||
|         ws._def = { | ||||
|             defaults: { | ||||
|                 label: {value:""}, | ||||
|                 disabled: {value: false}, | ||||
|                 info: {value: ""} | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         workspacesOrder.push(ws.id); | ||||
|     } | ||||
|     function getWorkspace(id) { | ||||
|         return workspaces[id]; | ||||
|     } | ||||
|     function removeWorkspace(id) { | ||||
|         delete workspaces[id]; | ||||
|         workspacesOrder.splice(workspacesOrder.indexOf(id),1); | ||||
|  | ||||
|         var removedNodes = []; | ||||
|         var removedLinks = []; | ||||
|         var n; | ||||
| @@ -317,7 +333,6 @@ RED.nodes = (function() { | ||||
|             }); | ||||
|             sf.name = subflowName; | ||||
|         } | ||||
|  | ||||
|         subflows[sf.id] = sf; | ||||
|         RED.nodes.registerType("subflow:"+sf.id, { | ||||
|             defaults:{name:{value:""}}, | ||||
| @@ -330,12 +345,13 @@ RED.nodes = (function() { | ||||
|             label: function() { return this.name||RED.nodes.subflow(sf.id).name }, | ||||
|             labelStyle: function() { return this.name?"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 }, | ||||
|             set:{ | ||||
|                 module: "node-red" | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|  | ||||
|         sf._def = RED.nodes.getType("subflow:"+sf.id); | ||||
|     } | ||||
|     function getSubflow(id) { | ||||
|         return subflows[id]; | ||||
| @@ -389,15 +405,30 @@ RED.nodes = (function() { | ||||
|         return nns; | ||||
|     } | ||||
|  | ||||
|     function convertWorkspace(n) { | ||||
|         var node = {}; | ||||
|         node.id = n.id; | ||||
|         node.type = n.type; | ||||
|         for (var d in n._def.defaults) { | ||||
|             if (n._def.defaults.hasOwnProperty(d)) { | ||||
|                 node[d] = n[d]; | ||||
|             } | ||||
|         } | ||||
|         return node; | ||||
|     } | ||||
|     /** | ||||
|      * Converts a node to an exportable JSON Object | ||||
|      **/ | ||||
|     function convertNode(n, exportCreds) { | ||||
|         if (n.type === 'tab') { | ||||
|             return convertWorkspace(n); | ||||
|         } | ||||
|         exportCreds = exportCreds || false; | ||||
|         var node = {}; | ||||
|         node.id = n.id; | ||||
|         node.type = n.type; | ||||
|         node.z = n.z; | ||||
|  | ||||
|         if (node.type == "unknown") { | ||||
|             for (var p in n._orig) { | ||||
|                 if (n._orig.hasOwnProperty(p)) { | ||||
| @@ -416,11 +447,12 @@ RED.nodes = (function() { | ||||
|                 for (var cred in n._def.credentials) { | ||||
|                     if (n._def.credentials.hasOwnProperty(cred)) { | ||||
|                         if (n._def.credentials[cred].type == 'password') { | ||||
|                             if (n.credentials["has_"+cred] != n.credentials._["has_"+cred] || | ||||
|                             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[cred] != n.credentials._[cred]) { | ||||
|                         } else if (n.credentials[cred] != null && (!n.credentials._ || n.credentials[cred] != n.credentials._[cred])) { | ||||
|                             credentialSet[cred] = n.credentials[cred]; | ||||
|                         } | ||||
|                     } | ||||
| @@ -444,6 +476,13 @@ RED.nodes = (function() { | ||||
|                     node.wires[w.sourcePort].push(w.target.id); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (n.inputs > 0 && n.inputLabels && !/^\s*$/.test(n.inputLabels.join("")))  { | ||||
|                 node.inputLabels = n.inputLabels.slice(); | ||||
|             } | ||||
|             if (n.outputs > 0 && n.outputLabels && !/^\s*$/.test(n.outputLabels.join(""))) { | ||||
|                 node.outputLabels = n.outputLabels.slice(); | ||||
|             } | ||||
|         } | ||||
|         return node; | ||||
|     } | ||||
| @@ -481,16 +520,23 @@ RED.nodes = (function() { | ||||
|             node.out.push(nOut); | ||||
|         }); | ||||
|  | ||||
|         if (node.in.length > 0 && n.inputLabels && !/^\s*$/.test(n.inputLabels.join("")))  { | ||||
|             node.inputLabels = n.inputLabels.slice(); | ||||
|         } | ||||
|         if (node.out.length > 0 && n.outputLabels && !/^\s*$/.test(n.outputLabels.join(""))) { | ||||
|             node.outputLabels = n.outputLabels.slice(); | ||||
|         } | ||||
|  | ||||
|  | ||||
|         return node; | ||||
|     } | ||||
|     /** | ||||
|      * Converts the current node selection to an exportable JSON Object | ||||
|      **/ | ||||
|     function createExportableNodeSet(set) { | ||||
|     function createExportableNodeSet(set, exportedSubflows, exportedConfigNodes) { | ||||
|         var nns = []; | ||||
|         var exportedConfigNodes = {}; | ||||
|         var exportedSubflows = {}; | ||||
|         exportedConfigNodes = exportedConfigNodes || {}; | ||||
|         exportedSubflows = exportedSubflows || {}; | ||||
|         for (var n=0;n<set.length;n++) { | ||||
|             var node = set[n]; | ||||
|             if (node.type.substring(0,8) == "subflow:") { | ||||
| @@ -504,7 +550,7 @@ RED.nodes = (function() { | ||||
|                             subflowSet.push(n); | ||||
|                         } | ||||
|                     }); | ||||
|                     var exportableSubflow = createExportableNodeSet(subflowSet); | ||||
|                     var exportableSubflow = createExportableNodeSet(subflowSet, exportedSubflows, exportedConfigNodes); | ||||
|                     nns = exportableSubflow.concat(nns); | ||||
|                 } | ||||
|             } | ||||
| @@ -517,7 +563,7 @@ RED.nodes = (function() { | ||||
|                         if ((exportable == null || exportable)) { | ||||
|                             if (!(node[d] in exportedConfigNodes)) { | ||||
|                                 exportedConfigNodes[node[d]] = true; | ||||
|                                 nns.unshift(RED.nodes.convertNode(confNode)); | ||||
|                                 set.push(confNode); | ||||
|                             } | ||||
|                         } else { | ||||
|                             convertedNode[d] = ""; | ||||
| @@ -534,14 +580,15 @@ RED.nodes = (function() { | ||||
|     } | ||||
|  | ||||
|     //TODO: rename this (createCompleteNodeSet) | ||||
|     function createCompleteNodeSet() { | ||||
|     function createCompleteNodeSet(exportCredentials) { | ||||
|         if (exportCredentials === undefined) { | ||||
|             exportCredentials = true; | ||||
|         } | ||||
|         var nns = []; | ||||
|         var i; | ||||
|         for (i in workspaces) { | ||||
|             if (workspaces.hasOwnProperty(i)) { | ||||
|                 if (workspaces[i].type == "tab") { | ||||
|                     nns.push(workspaces[i]); | ||||
|                 } | ||||
|         for (i=0;i<workspacesOrder.length;i++) { | ||||
|             if (workspaces[workspacesOrder[i]].type == "tab") { | ||||
|                 nns.push(convertWorkspace(workspaces[workspacesOrder[i]])); | ||||
|             } | ||||
|         } | ||||
|         for (i in subflows) { | ||||
| @@ -551,16 +598,55 @@ RED.nodes = (function() { | ||||
|         } | ||||
|         for (i in configNodes) { | ||||
|             if (configNodes.hasOwnProperty(i)) { | ||||
|                 nns.push(convertNode(configNodes[i], true)); | ||||
|                 nns.push(convertNode(configNodes[i], exportCredentials)); | ||||
|             } | ||||
|         } | ||||
|         for (i=0;i<nodes.length;i++) { | ||||
|             var node = nodes[i]; | ||||
|             nns.push(convertNode(node, true)); | ||||
|             nns.push(convertNode(node, exportCredentials)); | ||||
|         } | ||||
|         return nns; | ||||
|     } | ||||
|  | ||||
|     function checkForMatchingSubflow(subflow,subflowNodes) { | ||||
|         var i; | ||||
|         var match = null; | ||||
|         try { | ||||
|             RED.nodes.eachSubflow(function(sf) { | ||||
|                 if (sf.name != subflow.name || | ||||
|                     sf.info != subflow.info || | ||||
|                     sf.in.length != subflow.in.length || | ||||
|                     sf.out.length != subflow.out.length) { | ||||
|                         return; | ||||
|                 } | ||||
|                 var sfNodes = RED.nodes.filterNodes({z:sf.id}); | ||||
|                 if (sfNodes.length != subflowNodes.length) { | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                 var subflowNodeSet = [subflow].concat(subflowNodes); | ||||
|                 var sfNodeSet = [sf].concat(sfNodes); | ||||
|  | ||||
|                 var exportableSubflowNodes = JSON.stringify(subflowNodeSet); | ||||
|                 var exportableSFNodes = JSON.stringify(createExportableNodeSet(sfNodeSet)); | ||||
|                 var nodeMap = {}; | ||||
|                 for (i=0;i<sfNodes.length;i++) { | ||||
|                     exportableSubflowNodes = exportableSubflowNodes.replace(new RegExp("\""+subflowNodes[i].id+"\"","g"),'"'+sfNodes[i].id+'"'); | ||||
|                 } | ||||
|                 exportableSubflowNodes = exportableSubflowNodes.replace(new RegExp("\""+subflow.id+"\"","g"),'"'+sf.id+'"'); | ||||
|  | ||||
|                 if (exportableSubflowNodes !== exportableSFNodes) { | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                 match = sf; | ||||
|                 throw new Error(); | ||||
|             }); | ||||
|         } catch(err) { | ||||
|             console.log(err.stack); | ||||
|         } | ||||
|         return match; | ||||
|     } | ||||
|     function compareNodes(nodeA,nodeB,idMustMatch) { | ||||
|         if (idMustMatch && nodeA.id != nodeB.id) { | ||||
|             return false; | ||||
| @@ -590,10 +676,11 @@ RED.nodes = (function() { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     function importNodes(newNodesObj,createNewIds) { | ||||
|     function importNodes(newNodesObj,createNewIds,createMissingWorkspace) { | ||||
|         var i; | ||||
|         var n; | ||||
|         var newNodes; | ||||
|         var nodeZmap = {}; | ||||
|         if (typeof newNodesObj === "string") { | ||||
|             if (newNodesObj === "") { | ||||
|                 return; | ||||
| @@ -612,6 +699,9 @@ RED.nodes = (function() { | ||||
|         if (!$.isArray(newNodes)) { | ||||
|             newNodes = [newNodes]; | ||||
|         } | ||||
|         if (!initialLoad) { | ||||
|             initialLoad = JSON.parse(JSON.stringify(newNodes)); | ||||
|         } | ||||
|         var unknownTypes = []; | ||||
|         for (i=0;i<newNodes.length;i++) { | ||||
|             n = newNodes[i]; | ||||
| @@ -624,6 +714,11 @@ RED.nodes = (function() { | ||||
|                 unknownTypes.indexOf(n.type)==-1) { | ||||
|                     unknownTypes.push(n.type); | ||||
|             } | ||||
|             if (n.z) { | ||||
|                 nodeZmap[n.z] = nodeZmap[n.z] || []; | ||||
|                 nodeZmap[n.z].push(n); | ||||
|             } | ||||
|  | ||||
|         } | ||||
|         if (unknownTypes.length > 0) { | ||||
|             var typeList = "<ul><li>"+unknownTypes.join("</li><li>")+"</li></ul>"; | ||||
| @@ -632,17 +727,19 @@ RED.nodes = (function() { | ||||
|         } | ||||
|  | ||||
|         var activeWorkspace = RED.workspaces.active(); | ||||
|         //TODO: check the z of the subflow instance and check _that_ if it exists | ||||
|         var activeSubflow = getSubflow(activeWorkspace); | ||||
|         if (activeSubflow) { | ||||
|             for (i=0;i<newNodes.length;i++) { | ||||
|                 var m = /^subflow:(.+)$/.exec(newNodes[i].type); | ||||
|                 if (m) { | ||||
|                     var subflowId = m[1]; | ||||
|         for (i=0;i<newNodes.length;i++) { | ||||
|             var m = /^subflow:(.+)$/.exec(newNodes[i].type); | ||||
|             if (m) { | ||||
|                 var subflowId = m[1]; | ||||
|                 var parent = getSubflow(newNodes[i].z || activeWorkspace); | ||||
|                 if (parent) { | ||||
|                     var err; | ||||
|                     if (subflowId === activeSubflow.id) { | ||||
|                     if (subflowId === parent.id) { | ||||
|                         err = new Error(RED._("notification.errors.cannotAddSubflowToItself")); | ||||
|                     } | ||||
|                     if (subflowContains(m[1],activeSubflow.id)) { | ||||
|                     if (subflowContains(subflowId,parent.id)) { | ||||
|                         err = new Error(RED._("notification.errors.cannotAddCircularReference")); | ||||
|                     } | ||||
|                     if (err) { | ||||
| @@ -658,11 +755,17 @@ RED.nodes = (function() { | ||||
|         var workspace_map = {}; | ||||
|         var new_subflows = []; | ||||
|         var subflow_map = {}; | ||||
|         var subflow_blacklist = {}; | ||||
|         var node_map = {}; | ||||
|         var new_nodes = []; | ||||
|         var new_links = []; | ||||
|         var nid; | ||||
|         var def; | ||||
|         var configNode; | ||||
|         var missingWorkspace = null; | ||||
|         var d; | ||||
|  | ||||
|         // Find all tabs and subflow templates | ||||
|         for (i=0;i<newNodes.length;i++) { | ||||
|             n = newNodes[i]; | ||||
|             // TODO: remove workspace in next release+1 | ||||
| @@ -682,30 +785,37 @@ RED.nodes = (function() { | ||||
|                 RED.workspaces.add(n); | ||||
|                 new_workspaces.push(n); | ||||
|             } else if (n.type === "subflow") { | ||||
|                 subflow_map[n.id] = n; | ||||
|                 if (createNewIds) { | ||||
|                     nid = getID(); | ||||
|                     n.id = nid; | ||||
|                 var matchingSubflow = checkForMatchingSubflow(n,nodeZmap[n.id]); | ||||
|                 if (matchingSubflow) { | ||||
|                     subflow_blacklist[n.id] = matchingSubflow; | ||||
|                 } else { | ||||
|                     subflow_map[n.id] = n; | ||||
|                     if (createNewIds) { | ||||
|                         nid = getID(); | ||||
|                         n.id = nid; | ||||
|                     } | ||||
|                     // TODO: handle createNewIds - map old to new subflow ids | ||||
|                     n.in.forEach(function(input,i) { | ||||
|                         input.type = "subflow"; | ||||
|                         input.direction = "in"; | ||||
|                         input.z = n.id; | ||||
|                         input.i = i; | ||||
|                         input.id = getID(); | ||||
|                     }); | ||||
|                     n.out.forEach(function(output,i) { | ||||
|                         output.type = "subflow"; | ||||
|                         output.direction = "out"; | ||||
|                         output.z = n.id; | ||||
|                         output.i = i; | ||||
|                         output.id = getID(); | ||||
|                     }); | ||||
|                     new_subflows.push(n); | ||||
|                     addSubflow(n,createNewIds); | ||||
|                 } | ||||
|                 // TODO: handle createNewIds - map old to new subflow ids | ||||
|                 n.in.forEach(function(input,i) { | ||||
|                     input.type = "subflow"; | ||||
|                     input.direction = "in"; | ||||
|                     input.z = n.id; | ||||
|                     input.i = i; | ||||
|                     input.id = getID(); | ||||
|                 }); | ||||
|                 n.out.forEach(function(output,i) { | ||||
|                     output.type = "subflow"; | ||||
|                     output.direction = "out"; | ||||
|                     output.z = n.id; | ||||
|                     output.i = i; | ||||
|                     output.id = getID(); | ||||
|                 }); | ||||
|                 new_subflows.push(n); | ||||
|                 addSubflow(n,createNewIds); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Add a tab if there isn't one there already | ||||
|         if (defaultWorkspace == null) { | ||||
|             defaultWorkspace = { type:"tab", id:getID(), label:RED._('workspace.defaultName',{number:1})}; | ||||
|             addWorkspace(defaultWorkspace); | ||||
| @@ -714,6 +824,7 @@ RED.nodes = (function() { | ||||
|             activeWorkspace = RED.workspaces.active(); | ||||
|         } | ||||
|  | ||||
|         // Find all config nodes and add them | ||||
|         for (i=0;i<newNodes.length;i++) { | ||||
|             n = newNodes[i]; | ||||
|             def = registry.getNodeType(n.type); | ||||
| @@ -721,12 +832,22 @@ RED.nodes = (function() { | ||||
|                 var existingConfigNode = null; | ||||
|                 if (createNewIds) { | ||||
|                     if (n.z) { | ||||
|                         if (subflow_map[n.z]) { | ||||
|                         if (subflow_blacklist[n.z]) { | ||||
|                             continue; | ||||
|                         } else if (subflow_map[n.z]) { | ||||
|                             n.z = subflow_map[n.z].id; | ||||
|                         } else { | ||||
|                             n.z = workspace_map[n.z]; | ||||
|                             if (!workspaces[n.z]) { | ||||
|                                 n.z = activeWorkspace; | ||||
|                                 if (createMissingWorkspace) { | ||||
|                                     if (missingWorkspace === null) { | ||||
|                                         missingWorkspace = RED.workspaces.add(null,true); | ||||
|                                         new_workspaces.push(missingWorkspace); | ||||
|                                     } | ||||
|                                     n.z = missingWorkspace.id; | ||||
|                                 } else { | ||||
|                                     n.z = activeWorkspace; | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
| @@ -750,10 +871,19 @@ RED.nodes = (function() { | ||||
|                 } | ||||
|  | ||||
|                 if (!existingConfigNode) { //} || !compareNodes(existingConfigNode,n,true) || existingConfigNode._def.exclusive || existingConfigNode.z !== n.z) { | ||||
|                     var configNode = {id:n.id, z:n.z, type:n.type, users:[]}; | ||||
|                     for (var d in def.defaults) { | ||||
|                     configNode = {id:n.id, z:n.z, type:n.type, users:[], _config:{}}; | ||||
|                     for (d in def.defaults) { | ||||
|                         if (def.defaults.hasOwnProperty(d)) { | ||||
|                             configNode[d] = n[d]; | ||||
|                             configNode._config[d] = JSON.stringify(n[d]); | ||||
|                         } | ||||
|                     } | ||||
|                     if (def.hasOwnProperty('credentials') && n.hasOwnProperty('credentials')) { | ||||
|                         configNode.credentials = {}; | ||||
|                         for (d in def.credentials) { | ||||
|                             if (def.credentials.hasOwnProperty(d) && n.credentials.hasOwnProperty(d)) { | ||||
|                                 configNode.credentials[d] = n.credentials[d]; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     configNode.label = def.label; | ||||
| @@ -768,34 +898,63 @@ RED.nodes = (function() { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Find regular flow nodes and subflow instances | ||||
|         for (i=0;i<newNodes.length;i++) { | ||||
|             n = newNodes[i]; | ||||
|             // TODO: remove workspace in next release+1 | ||||
|             if (n.type !== "workspace" && n.type !== "tab" && n.type !== "subflow") { | ||||
|                 def = registry.getNodeType(n.type); | ||||
|                 if (!def || def.category != "config") { | ||||
|                     var node = {x:n.x,y:n.y,z:n.z,type:0,wires:n.wires,changed:false}; | ||||
|                     var node = { | ||||
|                         x:n.x, | ||||
|                         y:n.y, | ||||
|                         z:n.z, | ||||
|                         type:0, | ||||
|                         wires:n.wires, | ||||
|                         inputLabels: n.inputLabels, | ||||
|                         outputLabels: n.outputLabels, | ||||
|                         changed:false, | ||||
|                         _config:{} | ||||
|                     }; | ||||
|                     if (createNewIds) { | ||||
|                         if (subflow_map[node.z]) { | ||||
|                         if (subflow_blacklist[n.z]) { | ||||
|                             continue; | ||||
|                         } else if (subflow_map[node.z]) { | ||||
|                             node.z = subflow_map[node.z].id; | ||||
|                         } else { | ||||
|                             node.z = workspace_map[node.z]; | ||||
|                             if (!workspaces[node.z]) { | ||||
|                                 node.z = activeWorkspace; | ||||
|                                 if (createMissingWorkspace) { | ||||
|                                     if (missingWorkspace === null) { | ||||
|                                         missingWorkspace = RED.workspaces.add(null,true); | ||||
|                                         new_workspaces.push(missingWorkspace); | ||||
|                                     } | ||||
|                                     node.z = missingWorkspace.id; | ||||
|                                 } else { | ||||
|                                     node.z = activeWorkspace; | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                         node.id = getID(); | ||||
|                     } else { | ||||
|                         node.id = n.id; | ||||
|                         if (node.z == null || (!workspaces[node.z] && !subflow_map[node.z])) { | ||||
|                             node.z = activeWorkspace; | ||||
|                             if (createMissingWorkspace) { | ||||
|                                 if (missingWorkspace === null) { | ||||
|                                     missingWorkspace = RED.workspaces.add(null,true); | ||||
|                                     new_workspaces.push(missingWorkspace); | ||||
|                                 } | ||||
|                                 node.z = missingWorkspace.id; | ||||
|                             } else { | ||||
|                                 node.z = activeWorkspace; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     node.type = n.type; | ||||
|                     node._def = def; | ||||
|                     if (n.type.substring(0,7) === "subflow") { | ||||
|                         var parentId = n.type.split(":")[1]; | ||||
|                         var subflow = subflow_map[parentId]||getSubflow(parentId); | ||||
|                         var subflow = subflow_blacklist[parentId]||subflow_map[parentId]||getSubflow(parentId); | ||||
|                         if (createNewIds) { | ||||
|                             parentId = subflow.id; | ||||
|                             node.type = "subflow:"+parentId; | ||||
| @@ -836,16 +995,19 @@ RED.nodes = (function() { | ||||
|                         if (node._def.category != "config") { | ||||
|                             node.inputs = n.inputs||node._def.inputs; | ||||
|                             node.outputs = n.outputs||node._def.outputs; | ||||
|                             for (var d2 in node._def.defaults) { | ||||
|                                 if (node._def.defaults.hasOwnProperty(d2)) { | ||||
|                                     if (node._def.defaults[d2].type) { | ||||
|                                         if (node_map[n[d2]]) { | ||||
|                                             node[d2] = node_map[n[d2]].id; | ||||
|                                         } else { | ||||
|                                             node[d2] = n[d2]; | ||||
|                                         } | ||||
|                                     } else { | ||||
|                                         node[d2] = n[d2]; | ||||
|                             for (d in node._def.defaults) { | ||||
|                                 if (node._def.defaults.hasOwnProperty(d)) { | ||||
|                                     node[d] = n[d]; | ||||
|                                     node._config[d] = JSON.stringify(n[d]); | ||||
|                                 } | ||||
|                             } | ||||
|                             node._config.x = node.x; | ||||
|                             node._config.y = node.y; | ||||
|                             if (node._def.hasOwnProperty('credentials') && n.hasOwnProperty('credentials')) { | ||||
|                                 node.credentials = {}; | ||||
|                                 for (d in node._def.credentials) { | ||||
|                                     if (node._def.credentials.hasOwnProperty(d) && n.credentials.hasOwnProperty(d)) { | ||||
|                                         node.credentials[d] = n.credentials[d]; | ||||
|                                     } | ||||
|                                 } | ||||
|                             } | ||||
| @@ -860,21 +1022,65 @@ RED.nodes = (function() { | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         // TODO: make this a part of the node definition so it doesn't have to | ||||
|         //       be hardcoded here | ||||
|         var nodeTypeArrayReferences = { | ||||
|             "catch":"scope", | ||||
|             "status":"scope", | ||||
|             "link in":"links", | ||||
|             "link out":"links" | ||||
|         } | ||||
|  | ||||
|         // Remap all wires and config node references | ||||
|         for (i=0;i<new_nodes.length;i++) { | ||||
|             n = new_nodes[i]; | ||||
|             if (n.wires) { | ||||
|                 for (var w1=0;w1<n.wires.length;w1++) { | ||||
|                     var wires = (n.wires[w1] instanceof Array)?n.wires[w1]:[n.wires[w1]]; | ||||
|                     for (var w2=0;w2<wires.length;w2++) { | ||||
|                         if (wires[w2] in node_map) { | ||||
|                             var link = {source:n,sourcePort:w1,target:node_map[wires[w2]]}; | ||||
|                             addLink(link); | ||||
|                             new_links.push(link); | ||||
|                         if (node_map.hasOwnProperty(wires[w2])) { | ||||
|                             if (n.z === node_map[wires[w2]].z) { | ||||
|                                 var link = {source:n,sourcePort:w1,target:node_map[wires[w2]]}; | ||||
|                                 addLink(link); | ||||
|                                 new_links.push(link); | ||||
|                             } else { | ||||
|                                 console.log("Warning: dropping link that crosses tabs:",n.id,"->",node_map[wires[w2]].id); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 delete n.wires; | ||||
|             } | ||||
|             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.users.push(n); | ||||
|                         } | ||||
|                     } else if (nodeTypeArrayReferences.hasOwnProperty(n.type) && nodeTypeArrayReferences[n.type] === d3 && n[d3] !== undefined && n[d3] !== null) { | ||||
|                         for (var j = 0;j<n[d3].length;j++) { | ||||
|                             if (node_map[n[d3][j]]) { | ||||
|                                 n[d3][j] = node_map[n[d3][j]].id; | ||||
|                             } | ||||
|                         } | ||||
|  | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             // If importing into a subflow, ensure an outbound-link doesn't | ||||
|             // get added | ||||
|             if (activeSubflow && /^link /.test(n.type) && n.links) { | ||||
|                 n.links = n.links.filter(function(id) { | ||||
|                     var otherNode = RED.nodes.node(id); | ||||
|                     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]; | ||||
| @@ -902,7 +1108,7 @@ RED.nodes = (function() { | ||||
|         } | ||||
|  | ||||
|         RED.workspaces.refresh(); | ||||
|         return [new_nodes,new_links,new_workspaces,new_subflows]; | ||||
|         return [new_nodes,new_links,new_workspaces,new_subflows,missingWorkspace]; | ||||
|     } | ||||
|  | ||||
|     // TODO: supports filter.z|type | ||||
| @@ -950,7 +1156,111 @@ RED.nodes = (function() { | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     // Update any config nodes referenced by the provided node to ensure their 'users' list is correct | ||||
|     function updateConfigNodeUsers(n) { | ||||
|         for (var d in n._def.defaults) { | ||||
|             if (n._def.defaults.hasOwnProperty(d)) { | ||||
|                 var property = n._def.defaults[d]; | ||||
|                 if (property.type) { | ||||
|                     var type = registry.getNodeType(property.type); | ||||
|                     if (type && type.category == "config") { | ||||
|                         var configNode = configNodes[n[d]]; | ||||
|                         if (configNode) { | ||||
|                             if (configNode.users.indexOf(n) === -1) { | ||||
|                                 configNode.users.push(n); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function flowVersion(version) { | ||||
|         if (version !== undefined) { | ||||
|             loadedFlowVersion = version; | ||||
|         } else { | ||||
|             return loadedFlowVersion; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function clear() { | ||||
|         nodes = []; | ||||
|         links = []; | ||||
|         configNodes = {}; | ||||
|         workspacesOrder = []; | ||||
|         var subflowIds = Object.keys(subflows); | ||||
|         subflowIds.forEach(function(id) { | ||||
|             RED.subflow.removeSubflow(id) | ||||
|         }); | ||||
|         var workspaceIds = Object.keys(workspaces); | ||||
|         workspaceIds.forEach(function(id) { | ||||
|             RED.workspaces.remove(workspaces[id]); | ||||
|         }); | ||||
|         defaultWorkspace = null; | ||||
|  | ||||
|         RED.nodes.dirty(true); | ||||
|         RED.view.redraw(true); | ||||
|         RED.palette.refresh(); | ||||
|         RED.workspaces.refresh(); | ||||
|         RED.sidebar.config.refresh(); | ||||
|  | ||||
|         // var node_defs = {}; | ||||
|         // var nodes = []; | ||||
|         // var configNodes = {}; | ||||
|         // var links = []; | ||||
|         // var defaultWorkspace; | ||||
|         // var workspaces = {}; | ||||
|         // var workspacesOrder =[]; | ||||
|         // var subflows = {}; | ||||
|         // var loadedFlowVersion = null; | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         init: function() { | ||||
|             RED.events.on("registry:node-type-added",function(type) { | ||||
|                 var def = registry.getNodeType(type); | ||||
|                 var replaced = false; | ||||
|                 var replaceNodes = []; | ||||
|                 RED.nodes.eachNode(function(n) { | ||||
|                     if (n.type === "unknown" && n.name === type) { | ||||
|                         replaceNodes.push(n); | ||||
|                     } | ||||
|                 }); | ||||
|                 RED.nodes.eachConfig(function(n) { | ||||
|                     if (n.type === "unknown" && n.name === type) { | ||||
|                         replaceNodes.push(n); | ||||
|                     } | ||||
|                 }); | ||||
|  | ||||
|                 if (replaceNodes.length > 0) { | ||||
|                     var reimportList = []; | ||||
|                     replaceNodes.forEach(function(n) { | ||||
|                         if (configNodes.hasOwnProperty(n.id)) { | ||||
|                             delete configNodes[n.id]; | ||||
|                         } else { | ||||
|                             nodes.splice(nodes.indexOf(n),1); | ||||
|                         } | ||||
|                         reimportList.push(convertNode(n)); | ||||
|                     }); | ||||
|                     RED.view.redraw(true); | ||||
|                     var result = importNodes(reimportList,false); | ||||
|                     var newNodeMap = {}; | ||||
|                     result[0].forEach(function(n) { | ||||
|                         newNodeMap[n.id] = n; | ||||
|                     }); | ||||
|                     RED.nodes.eachLink(function(l) { | ||||
|                         if (newNodeMap.hasOwnProperty(l.source.id)) { | ||||
|                             l.source = newNodeMap[l.source.id]; | ||||
|                         } | ||||
|                         if (newNodeMap.hasOwnProperty(l.target.id)) { | ||||
|                             l.target = newNodeMap[l.target.id]; | ||||
|                         } | ||||
|                     }); | ||||
|                     RED.view.redraw(true); | ||||
|                 } | ||||
|             }); | ||||
|         }, | ||||
|         registry:registry, | ||||
|         setNodeList: registry.setNodeList, | ||||
|  | ||||
| @@ -966,12 +1276,15 @@ RED.nodes = (function() { | ||||
|  | ||||
|         add: addNode, | ||||
|         remove: removeNode, | ||||
|         clear: clear, | ||||
|  | ||||
|         addLink: addLink, | ||||
|         removeLink: removeLink, | ||||
|  | ||||
|         addWorkspace: addWorkspace, | ||||
|         removeWorkspace: removeWorkspace, | ||||
|         getWorkspaceOrder: function() { return workspacesOrder }, | ||||
|         setWorkspaceOrder: function(order) { workspacesOrder = order; }, | ||||
|         workspace: getWorkspace, | ||||
|  | ||||
|         addSubflow: addSubflow, | ||||
| @@ -1004,15 +1317,22 @@ RED.nodes = (function() { | ||||
|             } | ||||
|         }, | ||||
|         eachWorkspace: function(cb) { | ||||
|             for (var id in workspaces) { | ||||
|                 if (workspaces.hasOwnProperty(id)) { | ||||
|                     cb(workspaces[id]); | ||||
|                 } | ||||
|             for (var i=0;i<workspacesOrder.length;i++) { | ||||
|                 cb(workspaces[workspacesOrder[i]]); | ||||
|             } | ||||
|         }, | ||||
|  | ||||
|         node: getNode, | ||||
|  | ||||
|         version: flowVersion, | ||||
|         originalFlow: function(flow) { | ||||
|             if (flow === undefined) { | ||||
|                 return initialLoad; | ||||
|             } else { | ||||
|                 initialLoad = flow; | ||||
|             } | ||||
|         }, | ||||
|  | ||||
|         filterNodes: filterNodes, | ||||
|         filterLinks: filterLinks, | ||||
|  | ||||
| @@ -1021,6 +1341,7 @@ RED.nodes = (function() { | ||||
|         getAllFlowNodes: getAllFlowNodes, | ||||
|         createExportableNodeSet: createExportableNodeSet, | ||||
|         createCompleteNodeSet: createCompleteNodeSet, | ||||
|         updateConfigNodeUsers: updateConfigNodeUsers, | ||||
|         id: getID, | ||||
|         dirty: function(d) { | ||||
|             if (d == null) { | ||||
|   | ||||
							
								
								
									
										16
									
								
								editor/js/red.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,16 @@ | ||||
| /** | ||||
|  * 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. | ||||
|  **/ | ||||
| var RED = {}; | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2014 IBM, Antoine Aflalo | ||||
|  * 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. | ||||
| @@ -33,6 +33,7 @@ RED.settings = (function () { | ||||
|         } | ||||
|         localStorage.setItem(key, JSON.stringify(value)); | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * If the key is not set in the localStorage it returns <i>undefined</i> | ||||
|      * Else return the JSON parsed value | ||||
| @@ -83,6 +84,7 @@ RED.settings = (function () { | ||||
|                     if (auth_tokens) { | ||||
|                         jqXHR.setRequestHeader("Authorization","Bearer "+auth_tokens.access_token); | ||||
|                     } | ||||
|                     jqXHR.setRequestHeader("Node-RED-API-Version","v2"); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
| @@ -100,7 +102,7 @@ RED.settings = (function () { | ||||
|             url: 'settings', | ||||
|             success: function (data) { | ||||
|                 setProperties(data); | ||||
|                 if (RED.settings.user && RED.settings.user.anonymous) { | ||||
|                 if (!RED.settings.user || RED.settings.user.anonymous) { | ||||
|                     RED.settings.remove("auth-tokens"); | ||||
|                 } | ||||
|                 console.log("Node-RED: " + data.version); | ||||
| @@ -112,9 +114,9 @@ RED.settings = (function () { | ||||
|                         window.location.search = ""; | ||||
|                     } | ||||
|                     RED.user.login(function() { load(done); }); | ||||
|                  } else { | ||||
|                      console.log("Unexpected error:",jqXHR.status,textStatus); | ||||
|                  } | ||||
|                 } else { | ||||
|                     console.log("Unexpected error:",jqXHR.status,textStatus); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|     }; | ||||
| @@ -129,6 +131,9 @@ RED.settings = (function () { | ||||
|             for (var i=0;i<parts.length;i++) { | ||||
|                 v = v[parts[i]]; | ||||
|             } | ||||
|             if (v === undefined) { | ||||
|                 return defaultValue; | ||||
|             } | ||||
|             return v; | ||||
|         } catch(err) { | ||||
|             return defaultValue; | ||||
| @@ -141,7 +146,6 @@ RED.settings = (function () { | ||||
|         set: set, | ||||
|         get: get, | ||||
|         remove: remove, | ||||
|  | ||||
|         theme: theme | ||||
|     } | ||||
| }) | ||||
|   | ||||
							
								
								
									
										130
									
								
								editor/js/text/bidi.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,130 @@ | ||||
| /** | ||||
|  * 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.text = {}; | ||||
| RED.text.bidi = (function() { | ||||
|     var textDir = ""; | ||||
|     var LRE = "\u202A", | ||||
|         RLE = "\u202B", | ||||
|         PDF = "\u202C"; | ||||
|  | ||||
|     function isRTLValue(stringValue) { | ||||
|         var length = stringValue.length; | ||||
|         for (var i=0;i<length;i++) { | ||||
|             if (isBidiChar(stringValue.charCodeAt(i))) { | ||||
|                 return true; | ||||
|             } | ||||
|             else if(isLatinChar(stringValue.charCodeAt(i))) { | ||||
|                 return false; | ||||
|             } | ||||
|          } | ||||
|          return false; | ||||
|     } | ||||
|  | ||||
|     function isBidiChar(c)  { | ||||
|         return (c >= 0x05d0 && c <= 0x05ff)|| | ||||
|                (c >= 0x0600 && c <= 0x065f)|| | ||||
|                (c >= 0x066a && c <= 0x06ef)|| | ||||
|                (c >= 0x06fa && c <= 0x07ff)|| | ||||
|                (c >= 0xfb1d && c <= 0xfdff)|| | ||||
|                (c >= 0xfe70 && c <= 0xfefc); | ||||
|     } | ||||
|  | ||||
|     function isLatinChar(c){ | ||||
|         return (c > 64 && c < 91)||(c > 96 && c < 123) | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Determines the text direction of a given string. | ||||
|      * @param value - the string | ||||
|      */ | ||||
|     function resolveBaseTextDir(value) { | ||||
|         if (textDir == "auto") { | ||||
|             if (isRTLValue(value)) { | ||||
|                 return "rtl"; | ||||
|             } else { | ||||
|                 return "ltr"; | ||||
|             } | ||||
|         } | ||||
|         else { | ||||
|             return textDir; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function onInputChange() { | ||||
|         $(this).attr("dir", resolveBaseTextDir($(this).val())); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Adds event listeners to the Input to ensure its text-direction attribute | ||||
|      * is properly set based on its content. | ||||
|      * @param input - the input field | ||||
|      */ | ||||
|     function prepareInput(input) { | ||||
|         input.on("keyup",onInputChange).on("paste",onInputChange).on("cut",onInputChange); | ||||
|         // Set the initial text direction | ||||
|         onInputChange.call(input); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Enforces the text direction of a given string by adding | ||||
|      * UCC (Unicode Control Characters) | ||||
|      * @param value - the string | ||||
|      */ | ||||
|     function enforceTextDirectionWithUCC(value) { | ||||
|         if (value) { | ||||
|             var dir = resolveBaseTextDir(value); | ||||
|             if (dir == "ltr") { | ||||
|                return LRE + value + PDF; | ||||
|             } | ||||
|             else if (dir == "rtl") { | ||||
|                return RLE + value + PDF; | ||||
|             } | ||||
|         } | ||||
|         return value; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Enforces the text direction for all the spans with style bidiAware under | ||||
|      * workspace or sidebar div | ||||
|      */ | ||||
|     function enforceTextDirectionOnPage() { | ||||
|         $("#workspace").find('span.bidiAware').each(function() { | ||||
|             $(this).attr("dir", resolveBaseTextDir($(this).html())); | ||||
|         }); | ||||
|         $("#sidebar").find('span.bidiAware').each(function() { | ||||
|             $(this).attr("dir", resolveBaseTextDir($(this).text())); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sets the text direction preference | ||||
|      * @param dir - the text direction preference | ||||
|      */ | ||||
|     function setTextDirection(dir) { | ||||
|         textDir = dir; | ||||
|         RED.nodes.eachNode(function(n) { n.dirty = true;}); | ||||
|         RED.view.redraw(); | ||||
|         RED.palette.refresh(); | ||||
|         enforceTextDirectionOnPage(); | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         setTextDirection: setTextDirection, | ||||
|         enforceTextDirectionWithUCC: enforceTextDirectionWithUCC, | ||||
|         resolveBaseTextDir: resolveBaseTextDir, | ||||
|         prepareInput: prepareInput | ||||
|     } | ||||
| })(); | ||||
							
								
								
									
										1330
									
								
								editor/js/text/format.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										35
									
								
								editor/js/ui/actions.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,35 @@ | ||||
| RED.actions = (function() { | ||||
|     var actions = { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     function addAction(name,handler) { | ||||
|         actions[name] = handler; | ||||
|     } | ||||
|     function removeAction(name) { | ||||
|         delete actions[name]; | ||||
|     } | ||||
|     function getAction(name) { | ||||
|         return actions[name]; | ||||
|     } | ||||
|     function invokeAction(name) { | ||||
|         if (actions.hasOwnProperty(name)) { | ||||
|             actions[name](); | ||||
|         } | ||||
|     } | ||||
|     function listActions() { | ||||
|         var result = []; | ||||
|         Object.keys(actions).forEach(function(action) { | ||||
|             var shortcut = RED.keyboard.getShortcut(action); | ||||
|             result.push({id:action,scope:shortcut?shortcut.scope:undefined,key:shortcut?shortcut.key:undefined,user:shortcut?shortcut.user:undefined}) | ||||
|         }) | ||||
|         return result; | ||||
|     } | ||||
|     return { | ||||
|         add: addAction, | ||||
|         remove: removeAction, | ||||
|         get: getAction, | ||||
|         invoke: invokeAction, | ||||
|         list: listActions | ||||
|     } | ||||
| })(); | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -21,9 +21,10 @@ RED.clipboard = (function() { | ||||
|     var dialogContainer; | ||||
|     var exportNodesDialog; | ||||
|     var importNodesDialog; | ||||
|     var disabled = false; | ||||
|  | ||||
|     function setupDialogs() { | ||||
|         dialog = $('<div id="clipboard-dialog" class="hide"><form class="dialog-form form-horizontal"></form></div>') | ||||
|         dialog = $('<div id="clipboard-dialog" class="hide node-red-dialog"><form class="dialog-form form-horizontal"></form></div>') | ||||
|             .appendTo("body") | ||||
|             .dialog({ | ||||
|                 modal: true, | ||||
| @@ -31,14 +32,6 @@ RED.clipboard = (function() { | ||||
|                 width: 500, | ||||
|                 resizable: false, | ||||
|                 buttons: [ | ||||
|                     { | ||||
|                         id: "clipboard-dialog-ok", | ||||
|                         text: RED._("common.label.ok"), | ||||
|                         click: function() { | ||||
|                             RED.view.importNodes($("#clipboard-import").val()); | ||||
|                             $( this ).dialog( "close" ); | ||||
|                         } | ||||
|                     }, | ||||
|                     { | ||||
|                         id: "clipboard-dialog-cancel", | ||||
|                         text: RED._("common.label.cancel"), | ||||
| @@ -48,35 +41,73 @@ RED.clipboard = (function() { | ||||
|                     }, | ||||
|                     { | ||||
|                         id: "clipboard-dialog-close", | ||||
|                         class: "primary", | ||||
|                         text: RED._("common.label.close"), | ||||
|                         click: function() { | ||||
|                             $( this ).dialog( "close" ); | ||||
|                         } | ||||
|                     }, | ||||
|                     { | ||||
|                         id: "clipboard-dialog-copy", | ||||
|                         class: "primary", | ||||
|                         text: RED._("clipboard.export.copy"), | ||||
|                         click: function() { | ||||
|                             $("#clipboard-export").select(); | ||||
|                             document.execCommand("copy"); | ||||
|                             document.getSelection().removeAllRanges(); | ||||
|                             RED.notify(RED._("clipboard.nodesExported")); | ||||
|                             $( this ).dialog( "close" ); | ||||
|                         } | ||||
|                     }, | ||||
|                     { | ||||
|                         id: "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'); | ||||
|                             $( this ).dialog( "close" ); | ||||
|                         } | ||||
|                     } | ||||
|                 ], | ||||
|                 open: function(e) { | ||||
|                     $(this).parent().find(".ui-dialog-titlebar-close").hide(); | ||||
|                     RED.keyboard.disable(); | ||||
|                 }, | ||||
|                 close: function(e) { | ||||
|                     RED.keyboard.enable(); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|         dialogContainer = dialog.children(".dialog-form"); | ||||
|  | ||||
|         exportNodesDialog = '<div class="form-row">'+ | ||||
|             '<label for="node-input-export" style="display: block; width:100%;"><i class="fa fa-clipboard"></i> '+RED._("clipboard.nodes")+'</label>'+ | ||||
|             '<textarea readonly 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-export" rows="5"></textarea>'+ | ||||
|         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>'+ | ||||
|                 '</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-tips">'+ | ||||
|             RED._("clipboard.selectNodes")+ | ||||
|             '<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>'; | ||||
|  | ||||
|         importNodesDialog = '<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" placeholder="'+ | ||||
|             RED._("clipboard.pasteNodes")+ | ||||
|             '"></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>'+ | ||||
|             '</div>'; | ||||
|     } | ||||
|  | ||||
| @@ -98,49 +129,185 @@ RED.clipboard = (function() { | ||||
|     } | ||||
|  | ||||
|     function importNodes() { | ||||
|         if (disabled) { | ||||
|             return; | ||||
|         } | ||||
|         dialogContainer.empty(); | ||||
|         dialogContainer.append($(importNodesDialog)); | ||||
|         dialogContainer.i18n(); | ||||
|  | ||||
|         $("#clipboard-dialog-ok").show(); | ||||
|         $("#clipboard-dialog-cancel").show(); | ||||
|         $("#clipboard-dialog-close").hide(); | ||||
|         $("#clipboard-dialog-copy").hide(); | ||||
|         $("#clipboard-dialog-ok").button("disable"); | ||||
|         $("#clipboard-import").keyup(validateImport); | ||||
|         $("#clipboard-import").on('paste',function() { setTimeout(validateImport,10)}); | ||||
|  | ||||
|         $("#import-tab > a").click(function(evt) { | ||||
|             evt.preventDefault(); | ||||
|             if ($(this).hasClass('disabled') || $(this).hasClass('selected')) { | ||||
|                 return; | ||||
|             } | ||||
|             $(this).parent().children().removeClass('selected'); | ||||
|             $(this).addClass('selected'); | ||||
|         }); | ||||
|  | ||||
|         dialog.dialog("option","title",RED._("clipboard.importNodes")).dialog("open"); | ||||
|     } | ||||
|  | ||||
|     function exportNodes() { | ||||
|         if (disabled) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         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) { | ||||
|             evt.preventDefault(); | ||||
|             if ($(this).hasClass('disabled') || $(this).hasClass('selected')) { | ||||
|                 $("#clipboard-export").focus(); | ||||
|                 return; | ||||
|             } | ||||
|             $(this).parent().children().removeClass('selected'); | ||||
|             $(this).addClass('selected'); | ||||
|  | ||||
|             var flow = $("#clipboard-export").val(); | ||||
|             if (flow.length > 0) { | ||||
|                 var nodes = JSON.parse(flow); | ||||
|  | ||||
|                 format = $(this).attr('id'); | ||||
|                 if (format === 'export-format-full') { | ||||
|                     flow = JSON.stringify(nodes,null,4); | ||||
|                 } else { | ||||
|                     flow = JSON.stringify(nodes); | ||||
|                 } | ||||
|                 $("#clipboard-export").val(flow); | ||||
|                 $("#clipboard-export").focus(); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         $("#export-range-group > a").click(function(evt) { | ||||
|             evt.preventDefault(); | ||||
|             if ($(this).hasClass('disabled') || $(this).hasClass('selected')) { | ||||
|                 $("#clipboard-export").focus(); | ||||
|                 return; | ||||
|             } | ||||
|             $(this).parent().children().removeClass('selected'); | ||||
|             $(this).addClass('selected'); | ||||
|             var type = $(this).attr('id'); | ||||
|             var flow = ""; | ||||
|             var nodes = null; | ||||
|             if (type === 'export-range-selected') { | ||||
|                 var selection = RED.view.selection(); | ||||
|                 nodes = RED.nodes.createExportableNodeSet(selection.nodes); | ||||
|             } else if (type === 'export-range-flow') { | ||||
|                 var activeWorkspace = RED.workspaces.active(); | ||||
|                 nodes = RED.nodes.filterNodes({z:activeWorkspace}); | ||||
|                 var parentNode = RED.nodes.workspace(activeWorkspace)||RED.nodes.subflow(activeWorkspace); | ||||
|                 nodes.unshift(parentNode); | ||||
|                 nodes = RED.nodes.createExportableNodeSet(nodes); | ||||
|             } else if (type === 'export-range-full') { | ||||
|                 nodes = RED.nodes.createCompleteNodeSet(false); | ||||
|             } | ||||
|             if (nodes !== null) { | ||||
|                 if (format === "export-format-full") { | ||||
|                     flow = JSON.stringify(nodes,null,4); | ||||
|                 } else { | ||||
|                     flow = JSON.stringify(nodes); | ||||
|                 } | ||||
|             } | ||||
|             if (flow.length > 0) { | ||||
|                 $("#export-copy").removeClass('disabled'); | ||||
|             } else { | ||||
|                 $("#export-copy").addClass('disabled'); | ||||
|             } | ||||
|             $("#clipboard-export").val(flow); | ||||
|             $("#clipboard-export").focus(); | ||||
|         }) | ||||
|  | ||||
|         $("#clipboard-dialog-ok").hide(); | ||||
|         $("#clipboard-dialog-cancel").hide(); | ||||
|         $("#clipboard-dialog-close").show(); | ||||
|         $("#clipboard-dialog-copy").hide(); | ||||
|         $("#clipboard-dialog-close").hide(); | ||||
|         var selection = RED.view.selection(); | ||||
|         if (selection.nodes) { | ||||
|             var nns = RED.nodes.createExportableNodeSet(selection.nodes); | ||||
|             $("#clipboard-export") | ||||
|                 .val(JSON.stringify(nns)) | ||||
|                 .focus(function() { | ||||
|                     var textarea = $(this); | ||||
|                     textarea.select(); | ||||
|                     textarea.mouseup(function() { | ||||
|                         textarea.unbind("mouseup"); | ||||
|                         return false; | ||||
|                     }) | ||||
|                 }); | ||||
|             dialog.dialog("option","title",RED._("clipboard.exportNodes")).dialog( "open" ); | ||||
|             $("#export-range-selected").click(); | ||||
|         } else { | ||||
|             $("#export-range-selected").addClass('disabled').removeClass('selected'); | ||||
|             $("#export-range-flow").click(); | ||||
|         } | ||||
|         if (format === "export-format-full") { | ||||
|             $("#export-format-full").click(); | ||||
|         } else { | ||||
|             $("#export-format-mini").click(); | ||||
|         } | ||||
|         $("#clipboard-export") | ||||
|             .focus(function() { | ||||
|                 var textarea = $(this); | ||||
|                 textarea.select(); | ||||
|                 textarea.mouseup(function() { | ||||
|                     textarea.unbind("mouseup"); | ||||
|                     return false; | ||||
|                 }) | ||||
|             }); | ||||
|         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(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function hideDropTarget() { | ||||
|         $("#dropTarget").hide(); | ||||
|         RED.keyboard.remove(/* ESCAPE */ 27); | ||||
|         RED.keyboard.remove("escape"); | ||||
|     } | ||||
|     function copyText(value,element,msg) { | ||||
|         var truncated = false; | ||||
|         if (typeof value !== "string" ) { | ||||
|             value = JSON.stringify(value, function(key,value) { | ||||
|                 if (value !== null && typeof value === 'object') { | ||||
|                     if (value.__encoded__ && value.hasOwnProperty('data') && value.hasOwnProperty('length')) { | ||||
|                         truncated = value.data.length !== value.length; | ||||
|                         return value.data; | ||||
|                     } | ||||
|                 } | ||||
|                 return value; | ||||
|             }); | ||||
|         } | ||||
|         if (truncated) { | ||||
|             msg += "_truncated"; | ||||
|         } | ||||
|         $("#clipboard-hidden").val(value).select(); | ||||
|         var result =  document.execCommand("copy"); | ||||
|         if (result && element) { | ||||
|             var popover = RED.popover.create({ | ||||
|                 target: element, | ||||
|                 direction: 'left', | ||||
|                 size: 'small', | ||||
|                 content: RED._(msg) | ||||
|             }); | ||||
|             setTimeout(function() { | ||||
|                 popover.close(); | ||||
|             },1000); | ||||
|             popover.open(); | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         init: function() { | ||||
|             setupDialogs(); | ||||
|  | ||||
|             $('<input type="text" id="clipboard-hidden">').appendTo("body"); | ||||
|  | ||||
|             RED.events.on("view:selection-changed",function(selection) { | ||||
|                 if (!selection.nodes) { | ||||
|                     RED.menu.setDisabled("menu-item-export",true); | ||||
| @@ -152,18 +319,30 @@ RED.clipboard = (function() { | ||||
|                     RED.menu.setDisabled("menu-item-export-library",false); | ||||
|                 } | ||||
|             }); | ||||
|             RED.keyboard.add(/* e */ 69,{ctrl:true},function(){exportNodes();d3.event.preventDefault();}); | ||||
|             RED.keyboard.add(/* i */ 73,{ctrl:true},function(){importNodes();d3.event.preventDefault();}); | ||||
|  | ||||
|             RED.actions.add("core:show-export-dialog",exportNodes); | ||||
|             RED.actions.add("core:show-import-dialog",importNodes); | ||||
|  | ||||
|  | ||||
|             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; }); | ||||
|  | ||||
|  | ||||
|             $('#chart').on("dragenter",function(event) { | ||||
|                 if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) { | ||||
|                 if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 || | ||||
|                      $.inArray("Files",event.originalEvent.dataTransfer.types) != -1) { | ||||
|                     $("#dropTarget").css({display:'table'}); | ||||
|                     RED.keyboard.add(/* ESCAPE */ 27,hideDropTarget); | ||||
|                     RED.keyboard.add("*", "escape" ,hideDropTarget); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|             $('#dropTarget').on("dragover",function(event) { | ||||
|                 if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) { | ||||
|                 if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 || | ||||
|                      $.inArray("Files",event.originalEvent.dataTransfer.types) != -1) { | ||||
|                     event.preventDefault(); | ||||
|                 } | ||||
|             }) | ||||
| @@ -171,15 +350,30 @@ RED.clipboard = (function() { | ||||
|                 hideDropTarget(); | ||||
|             }) | ||||
|             .on("drop",function(event) { | ||||
|                 var data = event.originalEvent.dataTransfer.getData("text/plain"); | ||||
|                 if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) { | ||||
|                     var data = event.originalEvent.dataTransfer.getData("text/plain"); | ||||
|                     data = data.substring(data.indexOf('['),data.lastIndexOf(']')+1); | ||||
|                     RED.view.importNodes(data); | ||||
|                 } else if ($.inArray("Files",event.originalEvent.dataTransfer.types) != -1) { | ||||
|                     var files = event.originalEvent.dataTransfer.files; | ||||
|                     if (files.length === 1) { | ||||
|                         var file = files[0]; | ||||
|                         var reader = new FileReader(); | ||||
|                         reader.onload = (function(theFile) { | ||||
|                             return function(e) { | ||||
|                                 RED.view.importNodes(e.target.result); | ||||
|                             }; | ||||
|                         })(file); | ||||
|                         reader.readAsText(file); | ||||
|                     } | ||||
|                 } | ||||
|                 hideDropTarget(); | ||||
|                 data = data.substring(data.indexOf('['),data.lastIndexOf(']')+1); | ||||
|                 RED.view.importNodes(data); | ||||
|                 event.preventDefault(); | ||||
|             }); | ||||
|  | ||||
|         }, | ||||
|         import: importNodes, | ||||
|         export: exportNodes | ||||
|         export: exportNodes, | ||||
|         copyText: copyText | ||||
|     } | ||||
| })(); | ||||
|   | ||||
							
								
								
									
										131
									
								
								editor/js/ui/common/checkboxSet.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,131 @@ | ||||
| /** | ||||
|  * Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  **/ | ||||
| (function($) { | ||||
|     $.widget( "nodered.checkboxSet", { | ||||
|         _create: function() { | ||||
|             var that = this; | ||||
|             this.uiElement = this.element.wrap( "<span>" ).parent(); | ||||
|             this.uiElement.addClass("red-ui-checkboxSet"); | ||||
|             if (this.options.parent) { | ||||
|                 this.parent = this.options.parent; | ||||
|                 this.parent.checkboxSet('addChild',this.element); | ||||
|             } | ||||
|             this.children = []; | ||||
|             this.partialFlag = false; | ||||
|             this.stateValue = 0; | ||||
|             var initialState = this.element.prop('checked'); | ||||
|             this.options = [ | ||||
|                 $('<span class="red-ui-checkboxSet-option hide"><i class="fa fa-square-o"></i></span>').appendTo(this.uiElement), | ||||
|                 $('<span class="red-ui-checkboxSet-option hide"><i class="fa fa-check-square-o"></i></span>').appendTo(this.uiElement), | ||||
|                 $('<span class="red-ui-checkboxSet-option hide"><i class="fa fa-minus-square-o"></i></span>').appendTo(this.uiElement) | ||||
|             ]; | ||||
|             if (initialState) { | ||||
|                 this.options[1].show(); | ||||
|             } else { | ||||
|                 this.options[0].show(); | ||||
|             } | ||||
|  | ||||
|             this.element.change(function() { | ||||
|                 if (this.checked) { | ||||
|                     that.options[0].hide(); | ||||
|                     that.options[1].show(); | ||||
|                     that.options[2].hide(); | ||||
|                 } else { | ||||
|                     that.options[1].hide(); | ||||
|                     that.options[0].show(); | ||||
|                     that.options[2].hide(); | ||||
|                 } | ||||
|                 var isChecked = this.checked; | ||||
|                 that.children.forEach(function(child) { | ||||
|                     child.checkboxSet('state',isChecked,false,true); | ||||
|                 }) | ||||
|             }) | ||||
|             this.uiElement.click(function(e) { | ||||
|                 e.stopPropagation(); | ||||
|                 // state returns null for a partial state. Clicking on that should | ||||
|                 // result in false. | ||||
|                 that.state((that.state()===false)?true:false); | ||||
|             }) | ||||
|             if (this.parent) { | ||||
|                 this.parent.checkboxSet('updateChild',this); | ||||
|             } | ||||
|         }, | ||||
|         _destroy: function() { | ||||
|             if (this.parent) { | ||||
|                 this.parent.checkboxSet('removeChild',this.element); | ||||
|             } | ||||
|         }, | ||||
|         addChild: function(child) { | ||||
|             var that = this; | ||||
|             this.children.push(child); | ||||
|         }, | ||||
|         removeChild: function(child) { | ||||
|             var index = this.children.indexOf(child); | ||||
|             if (index > -1) { | ||||
|                 this.children.splice(index,1); | ||||
|             } | ||||
|         }, | ||||
|         updateChild: function(child) { | ||||
|             var checkedCount = 0; | ||||
|             this.children.forEach(function(c,i) { | ||||
|                 if (c.checkboxSet('state') === true) { | ||||
|                     checkedCount++; | ||||
|                 } | ||||
|             }); | ||||
|             if (checkedCount === 0) { | ||||
|  | ||||
|                 this.state(false,true); | ||||
|             } else if (checkedCount === this.children.length) { | ||||
|                 this.state(true,true); | ||||
|             } else { | ||||
|                 this.state(null,true); | ||||
|             } | ||||
|         }, | ||||
|         disable: function() { | ||||
|             this.uiElement.addClass('disabled'); | ||||
|         }, | ||||
|         state: function(state,suppressEvent,suppressParentUpdate) { | ||||
|  | ||||
|             if (arguments.length === 0) { | ||||
|                 return this.partialFlag?null:this.element.is(":checked"); | ||||
|             } else { | ||||
|                 this.partialFlag = (state === null); | ||||
|                 var trueState = this.partialFlag||state; | ||||
|                 this.element.prop('checked',trueState); | ||||
|                 if (state === true) { | ||||
|                     this.options[0].hide(); | ||||
|                     this.options[1].show(); | ||||
|                     this.options[2].hide(); | ||||
|                 } else if (state === false) { | ||||
|                     this.options[2].hide(); | ||||
|                     this.options[1].hide(); | ||||
|                     this.options[0].show(); | ||||
|                 } else if (state === null) { | ||||
|                     this.options[0].hide(); | ||||
|                     this.options[1].hide(); | ||||
|                     this.options[2].show(); | ||||
|                 } | ||||
|                 if (!suppressEvent) { | ||||
|                     this.element.trigger('change',null); | ||||
|                 } | ||||
|                 if (!suppressParentUpdate && this.parent) { | ||||
|                     this.parent.checkboxSet('updateChild',this); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     }) | ||||
|  | ||||
| })(jQuery); | ||||
							
								
								
									
										327
									
								
								editor/js/ui/common/editableList.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,327 @@ | ||||
| /** | ||||
|  * Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  **/ | ||||
| (function($) { | ||||
|  | ||||
| /** | ||||
|  * options: | ||||
|  *   - addButton : boolean|string - text for add label, default 'add' | ||||
|  *   - height : number|'auto' | ||||
|  *   - resize : function - called when list as a whole is resized | ||||
|  *   - resizeItem : function(item) - called to resize individual item | ||||
|  *   - sortable : boolean|string - string is the css selector for handle | ||||
|  *   - sortItems : function(items) - when order of items changes | ||||
|  *   - connectWith : css selector of other sortables | ||||
|  *   - removable : boolean - whether to display delete button on items | ||||
|  *   - addItem : function(row,index,itemData) - when an item is added | ||||
|  *   - removeItem : function(itemData) - called when an item is removed | ||||
|  *   - filter : function(itemData) - called for each item to determine if it should be shown | ||||
|  *   - sort : function(itemDataA,itemDataB) - called to sort items | ||||
|  *   - scrollOnAdd : boolean - whether to scroll to newly added items | ||||
|  * methods: | ||||
|  *   - addItem(itemData) | ||||
|  *   - removeItem(itemData) | ||||
|  *   - width(width) | ||||
|  *   - height(height) | ||||
|  *   - items() | ||||
|  *   - empty() | ||||
|  *   - filter(filter) | ||||
|  *   - sort(sort) | ||||
|  *   - length() | ||||
|  */ | ||||
|     $.widget( "nodered.editableList", { | ||||
|         _create: function() { | ||||
|             var that = this; | ||||
|  | ||||
|             this.element.addClass('red-ui-editableList-list'); | ||||
|             this.uiWidth = this.element.width(); | ||||
|             this.uiContainer = this.element | ||||
|                 .wrap( "<div>" ) | ||||
|                 .parent(); | ||||
|  | ||||
|             if (this.options.header) { | ||||
|                 this.options.header.addClass("red-ui-editableList-header"); | ||||
|                 this.borderContainer = this.uiContainer.wrap("<div>").parent(); | ||||
|                 this.borderContainer.prepend(this.options.header); | ||||
|                 this.topContainer = this.borderContainer.wrap("<div>").parent(); | ||||
|             } else { | ||||
|                 this.topContainer = this.uiContainer.wrap("<div>").parent(); | ||||
|             } | ||||
|             this.topContainer.addClass('red-ui-editableList'); | ||||
|             if (this.options.class) { | ||||
|                 this.topContainer.addClass(this.options.class); | ||||
|             } | ||||
|  | ||||
|             if (this.options.addButton !== false) { | ||||
|                 var addLabel; | ||||
|                 if (typeof this.options.addButton === 'string') { | ||||
|                     addLabel = this.options.addButton | ||||
|                 } else { | ||||
|                     if (RED && RED._) { | ||||
|                         addLabel = RED._("editableList.add"); | ||||
|                     } else { | ||||
|                         addLabel = 'add'; | ||||
|                     } | ||||
|                 } | ||||
|                 $('<a href="#" class="editor-button editor-button-small" style="margin-top: 4px;"><i class="fa fa-plus"></i> '+addLabel+'</a>') | ||||
|                     .appendTo(this.topContainer) | ||||
|                     .click(function(evt) { | ||||
|                         evt.preventDefault(); | ||||
|                         that.addItem({}); | ||||
|                     }); | ||||
|             } | ||||
|             if (this.element.css("position") === "absolute") { | ||||
|                 ["top","left","bottom","right"].forEach(function(s) { | ||||
|                     var v = that.element.css(s); | ||||
|                     if (s!=="auto" && s!=="") { | ||||
|                         that.topContainer.css(s,v); | ||||
|                         that.uiContainer.css(s,"0"); | ||||
|                         that.element.css(s,'auto'); | ||||
|                     } | ||||
|                 }) | ||||
|                 this.element.css("position","static"); | ||||
|                 this.topContainer.css("position","absolute"); | ||||
|                 this.uiContainer.css("position","absolute"); | ||||
|  | ||||
|             } | ||||
|             if (this.options.header) { | ||||
|                 this.borderContainer.addClass("red-ui-editableList-border"); | ||||
|             } else { | ||||
|                 this.uiContainer.addClass("red-ui-editableList-border"); | ||||
|             } | ||||
|             this.uiContainer.addClass("red-ui-editableList-container"); | ||||
|  | ||||
|             this.uiHeight = this.element.height(); | ||||
|  | ||||
|             this.activeFilter = this.options.filter||null; | ||||
|             this.activeSort = this.options.sort||null; | ||||
|             this.scrollOnAdd = this.options.scrollOnAdd; | ||||
|             if (this.scrollOnAdd === undefined) { | ||||
|                 this.scrollOnAdd = true; | ||||
|             } | ||||
|             var minHeight = this.element.css("minHeight"); | ||||
|             if (minHeight !== '0px') { | ||||
|                 this.uiContainer.css("minHeight",minHeight); | ||||
|                 this.element.css("minHeight",0); | ||||
|             } | ||||
|             if (this.options.height !== 'auto') { | ||||
|                 this.uiContainer.css("overflow-y","scroll"); | ||||
|                 if (!isNaN(this.options.height)) { | ||||
|                     this.uiHeight = this.options.height; | ||||
|                 } | ||||
|             } | ||||
|             this.element.height('auto'); | ||||
|  | ||||
|             var attrStyle = this.element.attr('style'); | ||||
|             var m; | ||||
|             if ((m = /width\s*:\s*(\d+%)/i.exec(attrStyle)) !== null) { | ||||
|                 this.element.width('100%'); | ||||
|                 this.uiContainer.width(m[1]); | ||||
|             } | ||||
|             if (this.options.sortable) { | ||||
|                 var handle = (typeof this.options.sortable === 'string')? | ||||
|                                 this.options.sortable : | ||||
|                                 ".red-ui-editableList-item-handle"; | ||||
|                 var sortOptions = { | ||||
|                     axis: "y", | ||||
|                     update: function( event, ui ) { | ||||
|                         if (that.options.sortItems) { | ||||
|                             that.options.sortItems(that.items()); | ||||
|                         } | ||||
|                     }, | ||||
|                     handle:handle, | ||||
|                     cursor: "move", | ||||
|                     tolerance: "pointer", | ||||
|                     forcePlaceholderSize:true, | ||||
|                     placeholder: "red-ui-editabelList-item-placeholder", | ||||
|                     start: function(e, ui){ | ||||
|                         ui.placeholder.height(ui.item.height()-4); | ||||
|                     } | ||||
|                 }; | ||||
|                 if (this.options.connectWith) { | ||||
|                     sortOptions.connectWith = this.options.connectWith; | ||||
|                 } | ||||
|  | ||||
|                 this.element.sortable(sortOptions); | ||||
|             } | ||||
|  | ||||
|             this._resize(); | ||||
|  | ||||
|             // this.menu = this._createMenu(this.types, function(v) { that.type(v) }); | ||||
|             // this.type(this.options.default||this.types[0].value); | ||||
|         }, | ||||
|         _resize: function() { | ||||
|             var currentFullHeight = this.topContainer.height(); | ||||
|             var innerHeight = this.uiContainer.height(); | ||||
|             var delta = currentFullHeight - innerHeight; | ||||
|             if (this.uiHeight !== 0) { | ||||
|                 this.uiContainer.height(this.uiHeight-delta); | ||||
|             } | ||||
|             if (this.options.resize) { | ||||
|                 this.options.resize(); | ||||
|             } | ||||
|             if (this.options.resizeItem) { | ||||
|                 var that = this; | ||||
|                 this.element.children().each(function(i) { | ||||
|                     that.options.resizeItem($(this).find(".red-ui-editableList-item-content"),i); | ||||
|                 }); | ||||
|             } | ||||
|         }, | ||||
|         _destroy: function() { | ||||
|         }, | ||||
|         _refreshFilter: function() { | ||||
|             var that = this; | ||||
|             var count = 0; | ||||
|             if (!this.activeFilter) { | ||||
|                 return this.element.children().show(); | ||||
|             } | ||||
|             var items = this.items(); | ||||
|             items.each(function (i,el) { | ||||
|                 var data = el.data('data'); | ||||
|                 try { | ||||
|                     if (that.activeFilter(data)) { | ||||
|                         el.parent().show(); | ||||
|                         count++; | ||||
|                     } else { | ||||
|                         el.parent().hide(); | ||||
|                     } | ||||
|                 } catch(err) { | ||||
|                     console.log(err); | ||||
|                     el.parent().show(); | ||||
|                     count++; | ||||
|                 } | ||||
|             }); | ||||
|             return count; | ||||
|         }, | ||||
|         _refreshSort: function() { | ||||
|             if (this.activeSort) { | ||||
|                 var items = this.element.children(); | ||||
|                 var that = this; | ||||
|                 items.sort(function(A,B) { | ||||
|                     return that.activeSort($(A).find(".red-ui-editableList-item-content").data('data'),$(B).find(".red-ui-editableList-item-content").data('data')); | ||||
|                 }); | ||||
|                 $.each(items,function(idx,li) { | ||||
|                     that.element.append(li); | ||||
|                 }) | ||||
|             } | ||||
|         }, | ||||
|         width: function(desiredWidth) { | ||||
|             this.uiWidth = desiredWidth; | ||||
|             this._resize(); | ||||
|         }, | ||||
|         height: function(desiredHeight) { | ||||
|             this.uiHeight = desiredHeight; | ||||
|             this._resize(); | ||||
|         }, | ||||
|         addItem: function(data) { | ||||
|             var that = this; | ||||
|             data = data || {}; | ||||
|             var li = $('<li>'); | ||||
|             var added = false; | ||||
|             if (this.activeSort) { | ||||
|                 var items = this.items(); | ||||
|                 var skip = false; | ||||
|                 items.each(function(i,el) { | ||||
|                     if (added) { return } | ||||
|                     var itemData = el.data('data'); | ||||
|                     if (that.activeSort(data,itemData) < 0) { | ||||
|                          li.insertBefore(el.closest("li")); | ||||
|                          added = true; | ||||
|                     } | ||||
|                 }); | ||||
|             } | ||||
|             if (!added) { | ||||
|                 li.appendTo(this.element); | ||||
|             } | ||||
|             var row = $('<div/>').addClass("red-ui-editableList-item-content").appendTo(li); | ||||
|             row.data('data',data); | ||||
|             if (this.options.sortable === true) { | ||||
|                 $('<i class="red-ui-editableList-item-handle fa fa-bars"></i>').appendTo(li); | ||||
|                 li.addClass("red-ui-editableList-item-sortable"); | ||||
|             } | ||||
|             if (this.options.removable) { | ||||
|                 var deleteButton = $('<a/>',{href:"#",class:"red-ui-editableList-item-remove editor-button editor-button-small"}).appendTo(li); | ||||
|                 $('<i/>',{class:"fa fa-remove"}).appendTo(deleteButton); | ||||
|                 li.addClass("red-ui-editableList-item-removable"); | ||||
|                 deleteButton.click(function(evt) { | ||||
|                     evt.preventDefault(); | ||||
|                     var data = row.data('data'); | ||||
|                     li.addClass("red-ui-editableList-item-deleting") | ||||
|                     li.fadeOut(300, function() { | ||||
|                         $(this).remove(); | ||||
|                         if (that.options.removeItem) { | ||||
|                             that.options.removeItem(data); | ||||
|                         } | ||||
|                     }); | ||||
|                 }); | ||||
|             } | ||||
|             if (this.options.addItem) { | ||||
|                 var index = that.element.children().length-1; | ||||
|                 setTimeout(function() { | ||||
|                     that.options.addItem(row,index,data); | ||||
|                     if (that.activeFilter) { | ||||
|                         try { | ||||
|                             if (!that.activeFilter(data)) { | ||||
|                                 li.hide(); | ||||
|                             } | ||||
|                         } catch(err) { | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     if (!that.activeSort && that.scrollOnAdd) { | ||||
|                         setTimeout(function() { | ||||
|                             that.uiContainer.scrollTop(that.element.height()); | ||||
|                         },0); | ||||
|                     } | ||||
|                 },0); | ||||
|             } | ||||
|         }, | ||||
|         addItems: function(items) { | ||||
|             for (var i=0; i<items.length;i++) { | ||||
|                 this.addItem(items[i]); | ||||
|             } | ||||
|         }, | ||||
|         removeItem: function(data) { | ||||
|             var items = this.element.children().filter(function(f) { | ||||
|                 return data === $(this).find(".red-ui-editableList-item-content").data('data'); | ||||
|             }); | ||||
|             items.remove(); | ||||
|             if (this.options.removeItem) { | ||||
|                 this.options.removeItem(data); | ||||
|             } | ||||
|         }, | ||||
|         items: function() { | ||||
|             return this.element.children().map(function(i) { return $(this).find(".red-ui-editableList-item-content"); }); | ||||
|         }, | ||||
|         empty: function() { | ||||
|             this.element.empty(); | ||||
|         }, | ||||
|         filter: function(filter) { | ||||
|             if (filter !== undefined) { | ||||
|                 this.activeFilter = filter; | ||||
|             } | ||||
|             return this._refreshFilter(); | ||||
|         }, | ||||
|         sort: function(sort) { | ||||
|             if (sort !== undefined) { | ||||
|                 this.activeSort = sort; | ||||
|             } | ||||
|             return this._refreshSort(); | ||||
|         }, | ||||
|         length: function() { | ||||
|             return this.element.children().length; | ||||
|         } | ||||
|     }); | ||||
| })(jQuery); | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2014 IBM Corp. | ||||
|  * 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. | ||||
| @@ -13,9 +13,6 @@ | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  **/ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| RED.menu = (function() { | ||||
| 
 | ||||
|     var menuItems = {}; | ||||
| @@ -31,20 +28,30 @@ RED.menu = (function() { | ||||
|         } | ||||
| 
 | ||||
|         function setInitialState() { | ||||
|             var savedStateActive = isSavedStateActive(opt.id); | ||||
|             var savedStateActive = RED.settings.get("menu-" + opt.id); | ||||
|             if (opt.setting) { | ||||
|                 // May need to migrate pre-0.17 setting
 | ||||
| 
 | ||||
|                 if (savedStateActive !== null) { | ||||
|                     RED.settings.set(opt.setting,savedStateActive); | ||||
|                     RED.settings.remove("menu-" + opt.id); | ||||
|                 } else { | ||||
|                     savedStateActive = RED.settings.get(opt.setting); | ||||
|                 } | ||||
|             } | ||||
|             if (savedStateActive) { | ||||
|                 link.addClass("active"); | ||||
|                 opt.onselect.call(opt, true); | ||||
|                 triggerAction(opt.id,true); | ||||
|             } else if (savedStateActive === false) { | ||||
|                 link.removeClass("active"); | ||||
|                 opt.onselect.call(opt, false); | ||||
|                 triggerAction(opt.id,false); | ||||
|             } else if (opt.hasOwnProperty("selected")) { | ||||
|                 if (opt.selected) { | ||||
|                     link.addClass("active"); | ||||
|                 } else { | ||||
|                     link.removeClass("active"); | ||||
|                 } | ||||
|                 opt.onselect.call(opt, opt.selected); | ||||
|                 triggerAction(opt.id,opt.selected); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| @@ -85,7 +92,8 @@ RED.menu = (function() { | ||||
|             menuItems[opt.id] = opt; | ||||
| 
 | ||||
|             if (opt.onselect) { | ||||
|                 link.click(function() { | ||||
|                 link.click(function(e) { | ||||
|                     e.preventDefault(); | ||||
|                     if ($(this).parent().hasClass("disabled")) { | ||||
|                         return; | ||||
|                     } | ||||
| @@ -107,10 +115,12 @@ RED.menu = (function() { | ||||
|                             setSelected(opt.id, !selected); | ||||
|                         } | ||||
|                     } else { | ||||
|                         opt.onselect.call(opt); | ||||
|                         triggerAction(opt.id); | ||||
|                     } | ||||
|                 }); | ||||
|                 setInitialState(); | ||||
|                 if (opt.toggle) { | ||||
|                     setInitialState(); | ||||
|                 } | ||||
|             } else if (opt.href) { | ||||
|                 link.attr("target","_blank").attr("href",opt.href); | ||||
|             } else if (!opt.options) { | ||||
| @@ -141,15 +151,13 @@ RED.menu = (function() { | ||||
|     } | ||||
|     function createMenu(options) { | ||||
| 
 | ||||
|         var button = $("#"+options.id); | ||||
|         var menuParent = $("#"+options.id); | ||||
| 
 | ||||
|         //button.click(function(event) {
 | ||||
|         //    $("#"+options.id+"-submenu").show();
 | ||||
|         //    event.preventDefault();
 | ||||
|         //});
 | ||||
|         var topMenu = $("<ul/>",{id:options.id+"-submenu", class:"dropdown-menu pull-right"}); | ||||
| 
 | ||||
| 
 | ||||
|         var topMenu = $("<ul/>",{id:options.id+"-submenu", class:"dropdown-menu pull-right"}).insertAfter(button); | ||||
|         if (menuParent.length === 1) { | ||||
|             topMenu.insertAfter(menuParent); | ||||
|         } | ||||
| 
 | ||||
|         var lastAddedSeparator = false; | ||||
|         for (var i=0;i<options.options.length;i++) { | ||||
| @@ -162,20 +170,27 @@ RED.menu = (function() { | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return topMenu; | ||||
|     } | ||||
| 
 | ||||
|     function isSavedStateActive(id) { | ||||
|         return RED.settings.get("menu-" + id); | ||||
|     function triggerAction(id, args) { | ||||
|         var opt = menuItems[id]; | ||||
|         var callback = opt.onselect; | ||||
|         if (typeof opt.onselect === 'string') { | ||||
|             callback = RED.actions.get(opt.onselect); | ||||
|         } | ||||
|         if (callback) { | ||||
|             callback.call(opt,args); | ||||
|         } else { | ||||
|             console.log("No callback for",id,opt.onselect); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     function isSelected(id) { | ||||
|         return $("#" + id).hasClass("active"); | ||||
|     } | ||||
| 
 | ||||
|     function setSavedState(id, state) { | ||||
|         RED.settings.set("menu-" + id, state); | ||||
|     } | ||||
| 
 | ||||
|     function setSelected(id,state) { | ||||
|         if (isSelected(id) == state) { | ||||
|             return; | ||||
| @@ -187,9 +202,13 @@ RED.menu = (function() { | ||||
|             $("#"+id).removeClass("active"); | ||||
|         } | ||||
|         if (opt && opt.onselect) { | ||||
|             opt.onselect.call(opt,state); | ||||
|             triggerAction(opt.id,state); | ||||
|         } | ||||
|         setSavedState(id, state); | ||||
|         RED.settings.set(opt.setting||("menu-"+opt.id), state); | ||||
|     } | ||||
| 
 | ||||
|     function toggleSelected(id) { | ||||
|         setSelected(id,!isSelected(id)); | ||||
|     } | ||||
| 
 | ||||
|     function setDisabled(id,state) { | ||||
| @@ -231,16 +250,6 @@ RED.menu = (function() { | ||||
|         var opt = menuItems[id]; | ||||
|         if (opt) { | ||||
|             opt.onselect = action; | ||||
|             $("#"+id).click(function() { | ||||
|                 if ($(this).parent().hasClass("disabled")) { | ||||
|                     return; | ||||
|                 } | ||||
|                 if (menuItems[id].toggle) { | ||||
|                     setSelected(id,!isSelected(id)); | ||||
|                 } else { | ||||
|                     menuItems[id].onselect.call(menuItems[id]); | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @@ -248,6 +257,7 @@ RED.menu = (function() { | ||||
|         init: createMenu, | ||||
|         setSelected: setSelected, | ||||
|         isSelected: isSelected, | ||||
|         toggleSelected: toggleSelected, | ||||
|         setDisabled: setDisabled, | ||||
|         addItem: addItem, | ||||
|         removeItem: removeItem, | ||||
							
								
								
									
										81
									
								
								editor/js/ui/common/panels.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,81 @@ | ||||
| /** | ||||
|  * 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.panels = (function() { | ||||
|  | ||||
|     function createPanel(options) { | ||||
|         var container = options.container || $("#"+options.id); | ||||
|         var children = container.children(); | ||||
|         if (children.length !== 2) { | ||||
|             throw new Error("Container must have exactly two children"); | ||||
|         } | ||||
|  | ||||
|         container.addClass("red-ui-panels"); | ||||
|         var separator = $('<div class="red-ui-panels-separator"></div>').insertAfter(children[0]); | ||||
|         var startPosition; | ||||
|         var panelHeights = []; | ||||
|         var modifiedHeights = false; | ||||
|         var panelRatio; | ||||
|  | ||||
|         separator.draggable({ | ||||
|                 axis: "y", | ||||
|                 containment: container, | ||||
|                 scroll: false, | ||||
|                 start:function(event,ui) { | ||||
|                     var height = container.height(); | ||||
|                     startPosition = ui.position.top; | ||||
|                     panelHeights = [$(children[0]).height(),$(children[1]).height()]; | ||||
|                 }, | ||||
|                 drag: function(event,ui) { | ||||
|                     var height = container.height(); | ||||
|                     var delta = ui.position.top-startPosition; | ||||
|                     var newHeights = [panelHeights[0]+delta,panelHeights[1]-delta]; | ||||
|                     $(children[0]).height(newHeights[0]); | ||||
|                     $(children[1]).height(newHeights[1]); | ||||
|                     if (options.resize) { | ||||
|                         options.resize(newHeights[0],newHeights[1]); | ||||
|                     } | ||||
|                     ui.position.top -= delta; | ||||
|                     panelRatio = newHeights[0]/height; | ||||
|                 }, | ||||
|                 stop:function(event,ui) { | ||||
|                     modifiedHeights = true; | ||||
|                 } | ||||
|         }); | ||||
|  | ||||
|         return { | ||||
|             resize: function(height) { | ||||
|                 var panelHeights = [$(children[0]).height(),$(children[1]).height()]; | ||||
|                 container.height(height); | ||||
|                 if (modifiedHeights) { | ||||
|                     var topPanelHeight = panelRatio*height; | ||||
|                     var bottomPanelHeight = height - topPanelHeight - 48; | ||||
|                     panelHeights = [topPanelHeight,bottomPanelHeight]; | ||||
|                     $(children[0]).height(panelHeights[0]); | ||||
|                     $(children[1]).height(panelHeights[1]); | ||||
|                 } | ||||
|                 if (options.resize) { | ||||
|                     options.resize(panelHeights[0],panelHeights[1]); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         create: createPanel | ||||
|     } | ||||
| })(); | ||||
							
								
								
									
										135
									
								
								editor/js/ui/common/popover.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,135 @@ | ||||
| /** | ||||
|  * 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.popover = (function() { | ||||
|     var deltaSizes = { | ||||
|         "default": { | ||||
|             top: 10, | ||||
|             leftRight: 17, | ||||
|             leftLeft: 25 | ||||
|         }, | ||||
|         "small": { | ||||
|             top: 5, | ||||
|             leftRight: 8, | ||||
|             leftLeft: 16 | ||||
|         } | ||||
|     } | ||||
|     function createPopover(options) { | ||||
|         var target = options.target; | ||||
|         var direction = options.direction || "right"; | ||||
|         var trigger = options.trigger; | ||||
|         var content = options.content; | ||||
|         var delay = options.delay; | ||||
|         var width = options.width||"auto"; | ||||
|         var size = options.size||"default"; | ||||
|         if (!deltaSizes[size]) { | ||||
|             throw new Error("Invalid RED.popover size value:",size); | ||||
|         } | ||||
|  | ||||
|         var timer = null; | ||||
|         var active; | ||||
|         var div; | ||||
|  | ||||
|         var openPopup = function() { | ||||
|             if (active) { | ||||
|                 div = $('<div class="red-ui-popover red-ui-popover-'+direction+'"></div>').appendTo("body"); | ||||
|                 if (size !== "default") { | ||||
|                     div.addClass("red-ui-popover-size-"+size); | ||||
|                 } | ||||
|                 if (typeof content === 'function') { | ||||
|                     content.call(res).appendTo(div); | ||||
|                 } else { | ||||
|                     div.html(content); | ||||
|                 } | ||||
|                 if (width !== "auto") { | ||||
|                     div.width(width); | ||||
|                 } | ||||
|  | ||||
|  | ||||
|                 var targetPos = target.offset(); | ||||
|                 var targetWidth = target.width(); | ||||
|                 var targetHeight = target.height(); | ||||
|  | ||||
|                 var divHeight = div.height(); | ||||
|                 var divWidth = div.width(); | ||||
|                 if (direction === 'right') { | ||||
|                     div.css({top: targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top,left:targetPos.left+targetWidth+deltaSizes[size].leftRight}); | ||||
|                 } else if (direction === 'left') { | ||||
|                     div.css({top: targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top,left:targetPos.left-deltaSizes[size].leftLeft-divWidth}); | ||||
|                 } | ||||
|  | ||||
|                 div.fadeIn("fast"); | ||||
|             } | ||||
|         } | ||||
|         var closePopup = function() { | ||||
|             if (!active) { | ||||
|                 if (div) { | ||||
|                     div.fadeOut("fast",function() { | ||||
|                         $(this).remove(); | ||||
|                     }); | ||||
|                     div = null; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (trigger === 'hover') { | ||||
|  | ||||
|             target.on('mouseenter',function(e) { | ||||
|                 clearTimeout(timer); | ||||
|                 active = true; | ||||
|                 timer = setTimeout(openPopup,delay.show); | ||||
|             }); | ||||
|             target.on('mouseleave', function(e) { | ||||
|                 if (timer) { | ||||
|                     clearTimeout(timer); | ||||
|                 } | ||||
|                 active = false; | ||||
|                 setTimeout(closePopup,delay.hide); | ||||
|             }); | ||||
|         } else if (trigger === 'click') { | ||||
|             target.click(function(e) { | ||||
|                 e.preventDefault(); | ||||
|                 e.stopPropagation(); | ||||
|                 active = !active; | ||||
|                 if (!active) { | ||||
|                     closePopup(); | ||||
|                 } else { | ||||
|                     openPopup(); | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|         var res = { | ||||
|             setContent: function(_content) { | ||||
|                 content = _content; | ||||
|             }, | ||||
|             open: function () { | ||||
|                 active = true; | ||||
|                 openPopup(); | ||||
|             }, | ||||
|             close: function () { | ||||
|                 active = false; | ||||
|                 closePopup(); | ||||
|             } | ||||
|         } | ||||
|         return res; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         create: createPopover | ||||
|     } | ||||
|  | ||||
| })(); | ||||
							
								
								
									
										99
									
								
								editor/js/ui/common/searchBox.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,99 @@ | ||||
| /** | ||||
|  * Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  **/ | ||||
| (function($) { | ||||
|  | ||||
|     $.widget( "nodered.searchBox", { | ||||
|         _create: function() { | ||||
|             var that = this; | ||||
|  | ||||
|             this.currentTimeout = null; | ||||
|             this.lastSent = ""; | ||||
|             this.element.val(""); | ||||
|             this.uiContainer = this.element.wrap("<div>").parent(); | ||||
|             this.uiContainer.addClass("red-ui-searchBox-container"); | ||||
|  | ||||
|             $('<i class="fa fa-search"></i>').prependTo(this.uiContainer); | ||||
|             this.clearButton = $('<a href="#"><i class="fa fa-times"></i></a>').appendTo(this.uiContainer); | ||||
|             this.clearButton.on("click",function(e) { | ||||
|                 e.preventDefault(); | ||||
|                 that.element.val(""); | ||||
|                 that._change("",true); | ||||
|                 that.element.focus(); | ||||
|             }); | ||||
|  | ||||
|             this.resultCount = $('<span>',{class:"red-ui-searchBox-resultCount hide"}).appendTo(this.uiContainer); | ||||
|  | ||||
|             this.element.val(""); | ||||
|             this.element.on("keydown",function(evt) { | ||||
|                 if (evt.keyCode === 27) { | ||||
|                     that.element.val(""); | ||||
|                 } | ||||
|             }) | ||||
|             this.element.on("keyup",function(evt) { | ||||
|                 that._change($(this).val()); | ||||
|             }); | ||||
|  | ||||
|             this.element.on("focus",function() { | ||||
|                 $("body").one("mousedown",function() { | ||||
|                     that.element.blur(); | ||||
|                 }); | ||||
|             }); | ||||
|  | ||||
|         }, | ||||
|         _change: function(val,instant) { | ||||
|             var fireEvent = false; | ||||
|             if (val === "") { | ||||
|                 this.clearButton.hide(); | ||||
|                 fireEvent = true; | ||||
|             } else { | ||||
|                 this.clearButton.show(); | ||||
|                 fireEvent = (val.length >= (this.options.minimumLength||0)); | ||||
|             } | ||||
|             var current = this.element.val(); | ||||
|             fireEvent = fireEvent && current !== this.lastSent; | ||||
|             if (fireEvent) { | ||||
|                 if (!instant && this.options.delay > 0) { | ||||
|                     clearTimeout(this.currentTimeout); | ||||
|                     var that = this; | ||||
|                     this.currentTimeout = setTimeout(function() { | ||||
|                         that.lastSent = that.element.val(); | ||||
|                         that._trigger("change"); | ||||
|                     },this.options.delay); | ||||
|                 } else { | ||||
|                     this._trigger("change"); | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         value: function(val) { | ||||
|             if (val === undefined) { | ||||
|                 return this.element.val(); | ||||
|             } else { | ||||
|                 this.element.val(val); | ||||
|                 this._change(val); | ||||
|             } | ||||
|         }, | ||||
|         count: function(val) { | ||||
|             if (val === undefined || val === null || val === "") { | ||||
|                 this.resultCount.text("").hide(); | ||||
|             } else { | ||||
|                 this.resultCount.text(val).show(); | ||||
|             } | ||||
|         }, | ||||
|         change: function() { | ||||
|             this._trigger("change"); | ||||
|         } | ||||
|     }); | ||||
| })(jQuery); | ||||
							
								
								
									
										119
									
								
								editor/js/ui/common/stack.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,119 @@ | ||||
| /** | ||||
|  * 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.stack = (function() { | ||||
|     function createStack(options) { | ||||
|         var container = options.container; | ||||
|  | ||||
|         var entries = []; | ||||
|  | ||||
|         var visible = true; | ||||
|  | ||||
|         return { | ||||
|             add: function(entry) { | ||||
|                 entries.push(entry); | ||||
|                 entry.container = $('<div class="palette-category">').appendTo(container); | ||||
|                 if (!visible) { | ||||
|                     entry.container.hide(); | ||||
|                 } | ||||
|                 var header = $('<div class="palette-header"></div>').appendTo(entry.container); | ||||
|                 entry.content = $('<div></div>').appendTo(entry.container); | ||||
|                 if (entry.collapsible !== false) { | ||||
|                     header.click(function() { | ||||
|                         if (options.singleExpanded) { | ||||
|                             if (!entry.isExpanded()) { | ||||
|                                 for (var i=0;i<entries.length;i++) { | ||||
|                                     if (entries[i].isExpanded()) { | ||||
|                                         entries[i].collapse(); | ||||
|                                     } | ||||
|                                 } | ||||
|                                 entry.expand(); | ||||
|                             } | ||||
|                         } else { | ||||
|                             entry.toggle(); | ||||
|                         } | ||||
|                     }); | ||||
|                     var icon = $('<i class="fa fa-angle-down"></i>').appendTo(header); | ||||
|  | ||||
|                     if (entry.expanded) { | ||||
|                         icon.addClass("expanded"); | ||||
|                     } else { | ||||
|                         entry.content.hide(); | ||||
|                     } | ||||
|                 } else { | ||||
|                     header.css("cursor","default"); | ||||
|                 } | ||||
|                 entry.title = $('<span></span>').html(entry.title).appendTo(header); | ||||
|  | ||||
|  | ||||
|  | ||||
|                 entry.toggle = function() { | ||||
|                     if (entry.isExpanded()) { | ||||
|                         entry.collapse(); | ||||
|                         return false; | ||||
|                     } else { | ||||
|                         entry.expand(); | ||||
|                         return true; | ||||
|                     } | ||||
|                 }; | ||||
|                 entry.expand = function() { | ||||
|                     if (!entry.isExpanded()) { | ||||
|                         if (entry.onexpand) { | ||||
|                             entry.onexpand.call(entry); | ||||
|                         } | ||||
|                         icon.addClass("expanded"); | ||||
|                         entry.content.slideDown(200); | ||||
|                         return true; | ||||
|                     } | ||||
|                 }; | ||||
|                 entry.collapse = function() { | ||||
|                     if (entry.isExpanded()) { | ||||
|                         icon.removeClass("expanded"); | ||||
|                         entry.content.slideUp(200); | ||||
|                         return true; | ||||
|                     } | ||||
|                 }; | ||||
|                 entry.isExpanded = function() { | ||||
|                     return icon.hasClass("expanded"); | ||||
|                 }; | ||||
|  | ||||
|                 return entry; | ||||
|  | ||||
|             }, | ||||
|  | ||||
|             hide: function() { | ||||
|                 visible = false; | ||||
|                 entries.forEach(function(entry) { | ||||
|                     entry.container.hide(); | ||||
|                 }); | ||||
|                 return this; | ||||
|             }, | ||||
|  | ||||
|             show: function() { | ||||
|                 visible = true; | ||||
|                 entries.forEach(function(entry) { | ||||
|                     entry.container.show(); | ||||
|                 }); | ||||
|                 return this; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         create: createStack | ||||
|     } | ||||
| })(); | ||||
							
								
								
									
										379
									
								
								editor/js/ui/common/tabs.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,379 @@ | ||||
| /** | ||||
|  * 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.tabs = (function() { | ||||
|     function createTabs(options) { | ||||
|         var tabs = {}; | ||||
|         var currentTabWidth; | ||||
|         var currentActiveTabWidth = 0; | ||||
|  | ||||
|         var ul = options.element || $("#"+options.id); | ||||
|         var wrapper = ul.wrap( "<div>" ).parent(); | ||||
|         var scrollContainer = ul.wrap( "<div>" ).parent(); | ||||
|         wrapper.addClass("red-ui-tabs"); | ||||
|         if (options.vertical) { | ||||
|             wrapper.addClass("red-ui-tabs-vertical"); | ||||
|         } | ||||
|         if (options.addButton && typeof options.addButton === 'function') { | ||||
|             wrapper.addClass("red-ui-tabs-add"); | ||||
|             var addButton = $('<div class="red-ui-tab-button"><a href="#"><i class="fa fa-plus"></i></a></div>').appendTo(wrapper); | ||||
|             addButton.find('a').click(function(evt) { | ||||
|                 evt.preventDefault(); | ||||
|                 options.addButton(); | ||||
|             }) | ||||
|  | ||||
|         } | ||||
|         var scrollLeft; | ||||
|         var scrollRight; | ||||
|  | ||||
|         if (options.scrollable) { | ||||
|             wrapper.addClass("red-ui-tabs-scrollable"); | ||||
|             scrollContainer.addClass("red-ui-tabs-scroll-container"); | ||||
|             scrollContainer.scroll(updateScroll); | ||||
|             scrollLeft = $('<div class="red-ui-tab-button red-ui-tab-scroll red-ui-tab-scroll-left"><a href="#" style="display:none;"><i class="fa fa-caret-left"></i></a></div>').appendTo(wrapper).find("a"); | ||||
|             scrollLeft.on('mousedown',function(evt) { scrollEventHandler(evt,'-=150') }).on('click',function(evt){ evt.preventDefault();}); | ||||
|             scrollRight = $('<div class="red-ui-tab-button red-ui-tab-scroll red-ui-tab-scroll-right"><a href="#" style="display:none;"><i class="fa fa-caret-right"></i></a></div>').appendTo(wrapper).find("a"); | ||||
|             scrollRight.on('mousedown',function(evt) { scrollEventHandler(evt,'+=150') }).on('click',function(evt){ evt.preventDefault();}); | ||||
|         } | ||||
|         function scrollEventHandler(evt,dir) { | ||||
|             evt.preventDefault(); | ||||
|             if ($(this).hasClass('disabled')) { | ||||
|                 return; | ||||
|             } | ||||
|             var currentScrollLeft = scrollContainer.scrollLeft(); | ||||
|             scrollContainer.animate( { scrollLeft: dir }, 100); | ||||
|             var interval = setInterval(function() { | ||||
|                 var newScrollLeft = scrollContainer.scrollLeft() | ||||
|                 if (newScrollLeft === currentScrollLeft) { | ||||
|                     clearInterval(interval); | ||||
|                     return; | ||||
|                 } | ||||
|                 currentScrollLeft = newScrollLeft; | ||||
|                 scrollContainer.animate( { scrollLeft: dir }, 100); | ||||
|             },100); | ||||
|             $(this).one('mouseup',function() { | ||||
|                 clearInterval(interval); | ||||
|             }) | ||||
|         } | ||||
|  | ||||
|  | ||||
|         ul.children().first().addClass("active"); | ||||
|         ul.children().addClass("red-ui-tab"); | ||||
|  | ||||
|         function onTabClick() { | ||||
|             if (options.onclick) { | ||||
|                 options.onclick(tabs[$(this).attr('href').slice(1)]); | ||||
|             } | ||||
|             activateTab($(this)); | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         function updateScroll() { | ||||
|             if (ul.children().length !== 0) { | ||||
|                 var sl = scrollContainer.scrollLeft(); | ||||
|                 var scWidth = scrollContainer.width(); | ||||
|                 var ulWidth = ul.width(); | ||||
|                 if (sl === 0) { | ||||
|                     scrollLeft.hide(); | ||||
|                 } else { | ||||
|                     scrollLeft.show(); | ||||
|                 } | ||||
|                 if (sl === ulWidth-scWidth) { | ||||
|                     scrollRight.hide(); | ||||
|                 } else { | ||||
|                     scrollRight.show(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         function onTabDblClick() { | ||||
|             if (options.ondblclick) { | ||||
|                 options.ondblclick(tabs[$(this).attr('href').slice(1)]); | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         function activateTab(link) { | ||||
|             if (typeof link === "string") { | ||||
|                 link = ul.find("a[href='#"+link+"']"); | ||||
|             } | ||||
|             if (link.length === 0) { | ||||
|                 return; | ||||
|             } | ||||
|             if (!link.parent().hasClass("active")) { | ||||
|                 ul.children().removeClass("active"); | ||||
|                 ul.children().css({"transition": "width 100ms"}); | ||||
|                 link.parent().addClass("active"); | ||||
|                 if (options.scrollable) { | ||||
|                     var pos = link.parent().position().left; | ||||
|                     if (pos-21 < 0) { | ||||
|                         scrollContainer.animate( { scrollLeft: '+='+(pos-50) }, 300); | ||||
|                     } else if (pos + 120 > scrollContainer.width()) { | ||||
|                         scrollContainer.animate( { scrollLeft: '+='+(pos + 140-scrollContainer.width()) }, 300); | ||||
|                     } | ||||
|                 } | ||||
|                 if (options.onchange) { | ||||
|                     options.onchange(tabs[link.attr('href').slice(1)]); | ||||
|                 } | ||||
|                 updateTabWidths(); | ||||
|                 setTimeout(function() { | ||||
|                     ul.children().css({"transition": ""}); | ||||
|                 },100); | ||||
|             } | ||||
|         } | ||||
|         function activatePreviousTab() { | ||||
|             var previous = ul.find("li.active").prev(); | ||||
|             if (previous.length > 0) { | ||||
|                 activateTab(previous.find("a")); | ||||
|             } | ||||
|         } | ||||
|         function activateNextTab() { | ||||
|             var next = ul.find("li.active").next(); | ||||
|             if (next.length > 0) { | ||||
|                 activateTab(next.find("a")); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         function updateTabWidths() { | ||||
|             if (options.vertical) { | ||||
|                 return; | ||||
|             } | ||||
|             var tabs = ul.find("li.red-ui-tab"); | ||||
|             var width = wrapper.width(); | ||||
|             var tabCount = tabs.size(); | ||||
|             var tabWidth = (width-12-(tabCount*6))/tabCount; | ||||
|             currentTabWidth = (100*tabWidth/width)+"%"; | ||||
|             currentActiveTabWidth = currentTabWidth+"%"; | ||||
|             if (options.scrollable) { | ||||
|                 tabWidth = Math.max(tabWidth,140); | ||||
|                 currentTabWidth = tabWidth+"px"; | ||||
|                 currentActiveTabWidth = 0; | ||||
|                 var listWidth = Math.max(wrapper.width(),12+(tabWidth+6)*tabCount); | ||||
|                 ul.width(listWidth); | ||||
|                 updateScroll(); | ||||
|             } else if (options.hasOwnProperty("minimumActiveTabWidth")) { | ||||
|                 if (tabWidth < options.minimumActiveTabWidth) { | ||||
|                     tabCount -= 1; | ||||
|                     tabWidth = (width-12-options.minimumActiveTabWidth-(tabCount*6))/tabCount; | ||||
|                     currentTabWidth = (100*tabWidth/width)+"%"; | ||||
|                     currentActiveTabWidth = options.minimumActiveTabWidth+"px"; | ||||
|                 } else { | ||||
|                     currentActiveTabWidth = 0; | ||||
|                 } | ||||
|             } | ||||
|             tabs.css({width:currentTabWidth}); | ||||
|             if (tabWidth < 50) { | ||||
|                 ul.find(".red-ui-tab-close").hide(); | ||||
|                 ul.find(".red-ui-tab-icon").hide(); | ||||
|                 ul.find(".red-ui-tab-label").css({paddingLeft:Math.min(12,Math.max(0,tabWidth-38))+"px"}) | ||||
|             } else { | ||||
|                 ul.find(".red-ui-tab-close").show(); | ||||
|                 ul.find(".red-ui-tab-icon").show(); | ||||
|                 ul.find(".red-ui-tab-label").css({paddingLeft:""}) | ||||
|             } | ||||
|             if (currentActiveTabWidth !== 0) { | ||||
|                 ul.find("li.red-ui-tab.active").css({"width":options.minimumActiveTabWidth}); | ||||
|                 ul.find("li.red-ui-tab.active .red-ui-tab-close").show(); | ||||
|                 ul.find("li.red-ui-tab.active .red-ui-tab-icon").show(); | ||||
|                 ul.find("li.red-ui-tab.active .red-ui-tab-label").css({paddingLeft:""}) | ||||
|             } | ||||
|  | ||||
|         } | ||||
|  | ||||
|         ul.find("li.red-ui-tab a").on("click",onTabClick).on("dblclick",onTabDblClick); | ||||
|         setTimeout(function() { | ||||
|             updateTabWidths(); | ||||
|         },0); | ||||
|  | ||||
|  | ||||
|         function removeTab(id) { | ||||
|             var li = ul.find("a[href='#"+id+"']").parent(); | ||||
|             if (li.hasClass("active")) { | ||||
|                 var tab = li.prev(); | ||||
|                 if (tab.size() === 0) { | ||||
|                     tab = li.next(); | ||||
|                 } | ||||
|                 activateTab(tab.find("a")); | ||||
|             } | ||||
|             li.remove(); | ||||
|             if (options.onremove) { | ||||
|                 options.onremove(tabs[id]); | ||||
|             } | ||||
|             delete tabs[id]; | ||||
|             updateTabWidths(); | ||||
|         } | ||||
|  | ||||
|         return { | ||||
|             addTab: function(tab) { | ||||
|                 tabs[tab.id] = tab; | ||||
|                 var li = $("<li/>",{class:"red-ui-tab"}).appendTo(ul); | ||||
|                 li.attr('id',"red-ui-tab-"+(tab.id.replace(".","-"))); | ||||
|                 li.data("tabId",tab.id); | ||||
|                 var link = $("<a/>",{href:"#"+tab.id, class:"red-ui-tab-label"}).appendTo(li); | ||||
|                 if (tab.icon) { | ||||
|                     $('<img src="'+tab.icon+'" class="red-ui-tab-icon"/>').appendTo(link); | ||||
|                 } | ||||
|                 var span = $('<span/>',{class:"bidiAware"}).text(tab.label).appendTo(link); | ||||
|                 span.attr('dir', RED.text.bidi.resolveBaseTextDir(tab.label)); | ||||
|  | ||||
|                 link.on("click",onTabClick); | ||||
|                 link.on("dblclick",onTabDblClick); | ||||
|                 if (tab.closeable) { | ||||
|                     var closeLink = $("<a/>",{href:"#",class:"red-ui-tab-close"}).appendTo(li); | ||||
|                     closeLink.append('<i class="fa fa-times" />'); | ||||
|  | ||||
|                     closeLink.on("click",function(event) { | ||||
|                         event.preventDefault(); | ||||
|                         removeTab(tab.id); | ||||
|                     }); | ||||
|                 } | ||||
|                 updateTabWidths(); | ||||
|                 if (options.onadd) { | ||||
|                     options.onadd(tab); | ||||
|                 } | ||||
|                 link.attr("title",tab.label); | ||||
|                 if (ul.find("li.red-ui-tab").size() == 1) { | ||||
|                     activateTab(link); | ||||
|                 } | ||||
|                 if (options.onreorder) { | ||||
|                     var originalTabOrder; | ||||
|                     var tabDragIndex; | ||||
|                     var tabElements = []; | ||||
|                     var startDragIndex; | ||||
|  | ||||
|                     li.draggable({ | ||||
|                         axis:"x", | ||||
|                         distance: 20, | ||||
|                         start: function(event,ui) { | ||||
|                             originalTabOrder = []; | ||||
|                             tabElements = []; | ||||
|                             ul.children().each(function(i) { | ||||
|                                 tabElements[i] = { | ||||
|                                     el:$(this), | ||||
|                                     text: $(this).text(), | ||||
|                                     left: $(this).position().left, | ||||
|                                     width: $(this).width() | ||||
|                                 }; | ||||
|                                 if ($(this).is(li)) { | ||||
|                                     tabDragIndex = i; | ||||
|                                     startDragIndex = i; | ||||
|                                 } | ||||
|                                 originalTabOrder.push($(this).data("tabId")); | ||||
|                             }); | ||||
|                             ul.children().each(function(i) { | ||||
|                                 if (i!==tabDragIndex) { | ||||
|                                     $(this).css({ | ||||
|                                         position: 'absolute', | ||||
|                                         left: tabElements[i].left+"px", | ||||
|                                         width: tabElements[i].width+2, | ||||
|                                         transition: "left 0.3s" | ||||
|                                     }); | ||||
|                                 } | ||||
|  | ||||
|                             }) | ||||
|                             if (!li.hasClass('active')) { | ||||
|                                 li.css({'zIndex':1}); | ||||
|                             } | ||||
|                         }, | ||||
|                         drag: function(event,ui) { | ||||
|                             ui.position.left += tabElements[tabDragIndex].left+scrollContainer.scrollLeft(); | ||||
|                             var tabCenter = ui.position.left + tabElements[tabDragIndex].width/2 - scrollContainer.scrollLeft(); | ||||
|                             for (var i=0;i<tabElements.length;i++) { | ||||
|                                 if (i === tabDragIndex) { | ||||
|                                     continue; | ||||
|                                 } | ||||
|                                 if (tabCenter > tabElements[i].left && tabCenter < tabElements[i].left+tabElements[i].width) { | ||||
|                                     if (i < tabDragIndex) { | ||||
|                                         tabElements[i].left += tabElements[tabDragIndex].width+8; | ||||
|                                         tabElements[tabDragIndex].el.detach().insertBefore(tabElements[i].el); | ||||
|                                     } else { | ||||
|                                         tabElements[i].left -= tabElements[tabDragIndex].width+8; | ||||
|                                         tabElements[tabDragIndex].el.detach().insertAfter(tabElements[i].el); | ||||
|                                     } | ||||
|                                     tabElements[i].el.css({left:tabElements[i].left+"px"}); | ||||
|  | ||||
|                                     tabElements.splice(i, 0, tabElements.splice(tabDragIndex, 1)[0]); | ||||
|  | ||||
|                                     tabDragIndex = i; | ||||
|                                     break; | ||||
|                                 } | ||||
|                             } | ||||
|                         }, | ||||
|                         stop: function(event,ui) { | ||||
|                             ul.children().css({position:"relative",left:"",transition:""}); | ||||
|                             if (!li.hasClass('active')) { | ||||
|                                 li.css({zIndex:""}); | ||||
|                             } | ||||
|                             updateTabWidths(); | ||||
|                             if (startDragIndex !== tabDragIndex) { | ||||
|                                 options.onreorder(originalTabOrder, $.makeArray(ul.children().map(function() { return $(this).data('tabId');}))); | ||||
|                             } | ||||
|                             activateTab(tabElements[tabDragIndex].el.data('tabId')); | ||||
|                         } | ||||
|                     }) | ||||
|                 } | ||||
|             }, | ||||
|             removeTab: removeTab, | ||||
|             activateTab: activateTab, | ||||
|             nextTab: activateNextTab, | ||||
|             previousTab: activatePreviousTab, | ||||
|             resize: updateTabWidths, | ||||
|             count: function() { | ||||
|                 return ul.find("li.red-ui-tab").size(); | ||||
|             }, | ||||
|             contains: function(id) { | ||||
|                 return ul.find("a[href='#"+id+"']").length > 0; | ||||
|             }, | ||||
|             renameTab: function(id,label) { | ||||
|                 tabs[id].label = label; | ||||
|                 var tab = ul.find("a[href='#"+id+"']"); | ||||
|                 tab.attr("title",label); | ||||
|                 tab.find("span.bidiAware").text(label).attr('dir', RED.text.bidi.resolveBaseTextDir(label)); | ||||
|                 updateTabWidths(); | ||||
|             }, | ||||
|             order: function(order) { | ||||
|                 var existingTabOrder = $.makeArray(ul.children().map(function() { return $(this).data('tabId');})); | ||||
|                 if (existingTabOrder.length !== order.length) { | ||||
|                     return | ||||
|                 } | ||||
|                 var i; | ||||
|                 var match = true; | ||||
|                 for (i=0;i<order.length;i++) { | ||||
|                     if (order[i] !== existingTabOrder[i]) { | ||||
|                         match = false; | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|                 if (match) { | ||||
|                     return; | ||||
|                 } | ||||
|                 var existingTabMap = {}; | ||||
|                 var existingTabs = ul.children().detach().each(function() { | ||||
|                     existingTabMap[$(this).data("tabId")] = $(this); | ||||
|                 }); | ||||
|                 for (i=0;i<order.length;i++) { | ||||
|                     existingTabMap[order[i]].appendTo(ul); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         create: createTabs | ||||
|     } | ||||
| })(); | ||||
							
								
								
									
										472
									
								
								editor/js/ui/common/typedInput.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,472 @@ | ||||
| /** | ||||
|  * Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  **/ | ||||
| (function($) { | ||||
|     var allOptions = { | ||||
|         msg: {value:"msg",label:"msg.",validate:RED.utils.validatePropertyExpression}, | ||||
|         flow: {value:"flow",label:"flow.",validate:RED.utils.validatePropertyExpression}, | ||||
|         global: {value:"global",label:"global.",validate:RED.utils.validatePropertyExpression}, | ||||
|         str: {value:"str",label:"string",icon:"red/images/typedInput/az.png"}, | ||||
|         num: {value:"num",label:"number",icon:"red/images/typedInput/09.png",validate:/^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$/}, | ||||
|         bool: {value:"bool",label:"boolean",icon:"red/images/typedInput/bool.png",options:["true","false"]}, | ||||
|         json: { | ||||
|             value:"json", | ||||
|             label:"JSON", | ||||
|             icon:"red/images/typedInput/json.png", | ||||
|             validate: function(v) { try{JSON.parse(v);return true;}catch(e){return false;}}, | ||||
|             expand: function() { | ||||
|                 var that = this; | ||||
|                 var value = this.value(); | ||||
|                 try { | ||||
|                     value = JSON.stringify(JSON.parse(value),null,4); | ||||
|                 } catch(err) { | ||||
|                 } | ||||
|                 RED.editor.editJSON({ | ||||
|                     value: value, | ||||
|                     complete: function(v) { | ||||
|                         var value = v; | ||||
|                         try { | ||||
|                             value = JSON.stringify(JSON.parse(v)); | ||||
|                         } catch(err) { | ||||
|                         } | ||||
|                         that.value(value); | ||||
|                     } | ||||
|                 }) | ||||
|             } | ||||
|         }, | ||||
|         re: {value:"re",label:"regular expression",icon:"red/images/typedInput/re.png"}, | ||||
|         date: {value:"date",label:"timestamp",hasValue:false}, | ||||
|         jsonata: { | ||||
|             value: "jsonata", | ||||
|             label: "expression", | ||||
|             icon: "red/images/typedInput/expr.png", | ||||
|             validate: function(v) { try{jsonata(v);return true;}catch(e){return false;}}, | ||||
|             expand:function() { | ||||
|                 var that = this; | ||||
|                 RED.editor.editExpression({ | ||||
|                     value: this.value().replace(/\t/g,"\n"), | ||||
|                     complete: function(v) { | ||||
|                         that.value(v.replace(/\n/g,"\t")); | ||||
|                     } | ||||
|                 }) | ||||
|             } | ||||
|         }, | ||||
|         bin: { | ||||
|             value: "bin", | ||||
|             label: "buffer", | ||||
|             icon: "red/images/typedInput/bin.png", | ||||
|             expand: function() { | ||||
|                 var that = this; | ||||
|                 RED.editor.editBuffer({ | ||||
|                     value: this.value(), | ||||
|                     complete: function(v) { | ||||
|                         that.value(v); | ||||
|                     } | ||||
|                 }) | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
|     var nlsd = false; | ||||
|  | ||||
|     $.widget( "nodered.typedInput", { | ||||
|         _create: function() { | ||||
|             if (!nlsd && RED && RED._) { | ||||
|                 for (var i in allOptions) { | ||||
|                     if (allOptions.hasOwnProperty(i)) { | ||||
|                         allOptions[i].label = RED._("typedInput.type."+i,{defaultValue:allOptions[i].label}); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             nlsd = true; | ||||
|             var that = this; | ||||
|  | ||||
|             this.disarmClick = false; | ||||
|             this.element.addClass('red-ui-typedInput'); | ||||
|             this.uiWidth = this.element.outerWidth(); | ||||
|             this.elementDiv = this.element.wrap("<div>").parent().addClass('red-ui-typedInput-input'); | ||||
|             this.uiSelect = this.elementDiv.wrap( "<div>" ).parent(); | ||||
|             var attrStyle = this.element.attr('style'); | ||||
|             var m; | ||||
|             if ((m = /width\s*:\s*(\d+(%|px))/i.exec(attrStyle)) !== null) { | ||||
|                 this.element.css('width','100%'); | ||||
|                 this.uiSelect.width(m[1]); | ||||
|                 this.uiWidth = null; | ||||
|             } else { | ||||
|                 this.uiSelect.width(this.uiWidth); | ||||
|             } | ||||
|             ["Right","Left"].forEach(function(d) { | ||||
|                 var m = that.element.css("margin"+d); | ||||
|                 that.uiSelect.css("margin"+d,m); | ||||
|                 that.element.css("margin"+d,0); | ||||
|             }); | ||||
|             this.uiSelect.addClass("red-ui-typedInput-container"); | ||||
|  | ||||
|             this.options.types = this.options.types||Object.keys(allOptions); | ||||
|  | ||||
|             this.selectTrigger = $('<button tabindex="0"></button>').prependTo(this.uiSelect); | ||||
|             $('<i class="fa fa-sort-desc"></i>').appendTo(this.selectTrigger); | ||||
|             this.selectLabel = $('<span></span>').appendTo(this.selectTrigger); | ||||
|  | ||||
|             this.types(this.options.types); | ||||
|  | ||||
|             if (this.options.typeField) { | ||||
|                 this.typeField = $(this.options.typeField).hide(); | ||||
|                 var t = this.typeField.val(); | ||||
|                 if (t && this.typeMap[t]) { | ||||
|                     this.options.default = t; | ||||
|                 } | ||||
|             } else { | ||||
|                 this.typeField = $("<input>",{type:'hidden'}).appendTo(this.uiSelect); | ||||
|             } | ||||
|  | ||||
|             this.element.on('focus', function() { | ||||
|                 that.uiSelect.addClass('red-ui-typedInput-focus'); | ||||
|             }); | ||||
|             this.element.on('blur', function() { | ||||
|                 that.uiSelect.removeClass('red-ui-typedInput-focus'); | ||||
|             }); | ||||
|             this.element.on('change', function() { | ||||
|                 that.validate(); | ||||
|             }) | ||||
|             this.selectTrigger.click(function(event) { | ||||
|                 event.preventDefault(); | ||||
|                 that._showTypeMenu(); | ||||
|             }); | ||||
|             this.selectTrigger.on('keydown',function(evt) { | ||||
|                 if (evt.keyCode === 40) { | ||||
|                     // Down | ||||
|                     that._showTypeMenu(); | ||||
|                 } | ||||
|             }).on('focus', function() { | ||||
|                 that.uiSelect.addClass('red-ui-typedInput-focus'); | ||||
|             }) | ||||
|  | ||||
|             // explicitly set optionSelectTrigger display to inline-block otherwise jQ sets it to 'inline' | ||||
|             this.optionSelectTrigger = $('<button tabindex="0" class="red-ui-typedInput-option-trigger" style="display:inline-block"><span class="red-ui-typedInput-option-caret"><i class="fa fa-sort-desc"></i></span></button>').appendTo(this.uiSelect); | ||||
|             this.optionSelectLabel = $('<span class="red-ui-typedInput-option-label"></span>').prependTo(this.optionSelectTrigger); | ||||
|             this.optionSelectTrigger.click(function(event) { | ||||
|                 event.preventDefault(); | ||||
|                 that._showOptionSelectMenu(); | ||||
|             }).on('keydown', function(evt) { | ||||
|                 if (evt.keyCode === 40) { | ||||
|                     // Down | ||||
|                     that._showOptionSelectMenu(); | ||||
|                 } | ||||
|             }).on('blur', function() { | ||||
|                 that.uiSelect.removeClass('red-ui-typedInput-focus'); | ||||
|             }).on('focus', function() { | ||||
|                 that.uiSelect.addClass('red-ui-typedInput-focus'); | ||||
|             }); | ||||
|  | ||||
|             this.optionExpandButton = $('<button tabindex="0" class="red-ui-typedInput-option-expand" style="display:inline-block"><i class="fa fa-ellipsis-h"></i></button>').appendTo(this.uiSelect); | ||||
|  | ||||
|  | ||||
|             this.type(this.options.default||this.typeList[0].value); | ||||
|         }, | ||||
|         _showTypeMenu: function() { | ||||
|             if (this.typeList.length > 1) { | ||||
|                 this._showMenu(this.menu,this.selectTrigger); | ||||
|                 this.menu.find("[value='"+this.propertyType+"']").focus(); | ||||
|             } else { | ||||
|                 this.element.focus(); | ||||
|             } | ||||
|         }, | ||||
|         _showOptionSelectMenu: function() { | ||||
|             if (this.optionMenu) { | ||||
|                 this.optionMenu.css({ | ||||
|                     minWidth:this.optionSelectLabel.width() | ||||
|                 }); | ||||
|  | ||||
|                 this._showMenu(this.optionMenu,this.optionSelectLabel); | ||||
|                 var selectedOption = this.optionMenu.find("[value='"+this.value()+"']"); | ||||
|                 if (selectedOption.length === 0) { | ||||
|                     selectedOption = this.optionMenu.children(":first"); | ||||
|                 } | ||||
|                 selectedOption.focus(); | ||||
|  | ||||
|             } | ||||
|         }, | ||||
|         _hideMenu: function(menu) { | ||||
|             $(document).off("mousedown.close-property-select"); | ||||
|             menu.hide(); | ||||
|             if (this.elementDiv.is(":visible")) { | ||||
|                 this.element.focus(); | ||||
|             } else if (this.optionSelectTrigger.is(":visible")){ | ||||
|                 this.optionSelectTrigger.focus(); | ||||
|             } else { | ||||
|                 this.selectTrigger.focus(); | ||||
|             } | ||||
|         }, | ||||
|         _createMenu: function(opts,callback) { | ||||
|             var that = this; | ||||
|             var menu = $("<div>").addClass("red-ui-typedInput-options"); | ||||
|             opts.forEach(function(opt) { | ||||
|                 if (typeof opt === 'string') { | ||||
|                     opt = {value:opt,label:opt}; | ||||
|                 } | ||||
|                 var op = $('<a href="#"></a>').attr("value",opt.value).appendTo(menu); | ||||
|                 if (opt.label) { | ||||
|                     op.text(opt.label); | ||||
|                 } | ||||
|                 if (opt.icon) { | ||||
|                     $('<img>',{src:opt.icon,style:"margin-right: 4px; height: 18px;"}).prependTo(op); | ||||
|                 } else { | ||||
|                     op.css({paddingLeft: "18px"}); | ||||
|                 } | ||||
|  | ||||
|                 op.click(function(event) { | ||||
|                     event.preventDefault(); | ||||
|                     callback(opt.value); | ||||
|                     that._hideMenu(menu); | ||||
|                 }); | ||||
|             }); | ||||
|             menu.css({ | ||||
|                 display: "none", | ||||
|             }); | ||||
|             menu.appendTo(document.body); | ||||
|  | ||||
|             menu.on('keydown', function(evt) { | ||||
|                 if (evt.keyCode === 40) { | ||||
|                     // DOWN | ||||
|                     $(this).children(":focus").next().focus(); | ||||
|                 } else if (evt.keyCode === 38) { | ||||
|                     // UP | ||||
|                     $(this).children(":focus").prev().focus(); | ||||
|                 } else if (evt.keyCode === 27) { | ||||
|                     that._hideMenu(menu); | ||||
|                 } | ||||
|             }) | ||||
|  | ||||
|  | ||||
|  | ||||
|             return menu; | ||||
|  | ||||
|         }, | ||||
|         _showMenu: function(menu,relativeTo) { | ||||
|             if (this.disarmClick) { | ||||
|                 this.disarmClick = false; | ||||
|                 return | ||||
|             } | ||||
|             var that = this; | ||||
|             var pos = relativeTo.offset(); | ||||
|             var height = relativeTo.height(); | ||||
|             var menuHeight = menu.height(); | ||||
|             var top = (height+pos.top-3); | ||||
|             if (top+menuHeight > $(window).height()) { | ||||
|                 top -= (top+menuHeight)-$(window).height()+5; | ||||
|             } | ||||
|             menu.css({ | ||||
|                 top: top+"px", | ||||
|                 left: (2+pos.left)+"px", | ||||
|             }); | ||||
|             menu.slideDown(100); | ||||
|             this._delay(function() { | ||||
|                 that.uiSelect.addClass('red-ui-typedInput-focus'); | ||||
|                 $(document).on("mousedown.close-property-select", function(event) { | ||||
|                     if(!$(event.target).closest(menu).length) { | ||||
|                         that._hideMenu(menu); | ||||
|                     } | ||||
|                     if ($(event.target).closest(relativeTo).length) { | ||||
|                         that.disarmClick = true; | ||||
|                         event.preventDefault(); | ||||
|                     } | ||||
|                 }) | ||||
|             }); | ||||
|         }, | ||||
|         _getLabelWidth: function(label) { | ||||
|             var labelWidth = label.outerWidth(); | ||||
|             if (labelWidth === 0) { | ||||
|                 var container = $('<div class="red-ui-typedInput-container"></div>').css({ | ||||
|                     position:"absolute", | ||||
|                     top:0, | ||||
|                     left:-1000 | ||||
|                 }).appendTo(document.body); | ||||
|                 var newTrigger = label.clone().appendTo(container); | ||||
|                 labelWidth = newTrigger.outerWidth(); | ||||
|                 container.remove(); | ||||
|             } | ||||
|             return labelWidth; | ||||
|         }, | ||||
|         _resize: function() { | ||||
|             if (this.uiWidth !== null) { | ||||
|                 this.uiSelect.width(this.uiWidth); | ||||
|             } | ||||
|             if (this.typeMap[this.propertyType] && this.typeMap[this.propertyType].hasValue === false) { | ||||
|                 this.selectTrigger.addClass("red-ui-typedInput-full-width"); | ||||
|             } else { | ||||
|                 this.selectTrigger.removeClass("red-ui-typedInput-full-width"); | ||||
|                 var labelWidth = this._getLabelWidth(this.selectTrigger); | ||||
|                 this.elementDiv.css('left',labelWidth+"px"); | ||||
|                 if (this.optionExpandButton.is(":visible")) { | ||||
|                     this.elementDiv.css('right',"22px"); | ||||
|                 } else { | ||||
|                     this.elementDiv.css('right','0'); | ||||
|                 } | ||||
|                 if (this.optionSelectTrigger) { | ||||
|                     this.optionSelectTrigger.css({'left':(labelWidth)+"px",'width':'calc( 100% - '+labelWidth+'px )'}); | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         _destroy: function() { | ||||
|             this.menu.remove(); | ||||
|         }, | ||||
|         types: function(types) { | ||||
|             var that = this; | ||||
|             var currentType = this.type(); | ||||
|             this.typeMap = {}; | ||||
|             this.typeList = types.map(function(opt) { | ||||
|                 var result; | ||||
|                 if (typeof opt === 'string') { | ||||
|                     result = allOptions[opt]; | ||||
|                 } else { | ||||
|                     result = opt; | ||||
|                 } | ||||
|                 that.typeMap[result.value] = result; | ||||
|                 return result; | ||||
|             }); | ||||
|             this.selectTrigger.toggleClass("disabled", this.typeList.length === 1); | ||||
|             if (this.menu) { | ||||
|                 this.menu.remove(); | ||||
|             } | ||||
|             this.menu = this._createMenu(this.typeList, function(v) { that.type(v) }); | ||||
|             if (currentType && !this.typeMap.hasOwnProperty(currentType)) { | ||||
|                 this.type(this.typeList[0].value); | ||||
|             } | ||||
|         }, | ||||
|         width: function(desiredWidth) { | ||||
|             this.uiWidth = desiredWidth; | ||||
|             this._resize(); | ||||
|         }, | ||||
|         value: function(value) { | ||||
|             if (!arguments.length) { | ||||
|                 return this.element.val(); | ||||
|             } else { | ||||
|                 if (this.typeMap[this.propertyType].options) { | ||||
|                     if (this.typeMap[this.propertyType].options.indexOf(value) === -1) { | ||||
|                         value = ""; | ||||
|                     } | ||||
|                     this.optionSelectLabel.text(value); | ||||
|                 } | ||||
|                 this.element.val(value); | ||||
|                 this.element.trigger('change',this.type(),value); | ||||
|             } | ||||
|         }, | ||||
|         type: function(type) { | ||||
|             if (!arguments.length) { | ||||
|                 return this.propertyType; | ||||
|             } else { | ||||
|                 var that = this; | ||||
|                 var opt = this.typeMap[type]; | ||||
|                 if (opt && this.propertyType !== type) { | ||||
|                     this.propertyType = type; | ||||
|                     this.typeField.val(type); | ||||
|                     this.selectLabel.empty(); | ||||
|                     var image; | ||||
|                     if (opt.icon) { | ||||
|                         image = new Image(); | ||||
|                         image.name = opt.icon; | ||||
|                         image.src = opt.icon; | ||||
|                         $('<img>',{src:opt.icon,style:"margin-right: 4px;height: 18px;"}).prependTo(this.selectLabel); | ||||
|                     } else { | ||||
|                         this.selectLabel.text(opt.label); | ||||
|                     } | ||||
|                     if (opt.options) { | ||||
|                         if (this.optionExpandButton) { | ||||
|                             this.optionExpandButton.hide(); | ||||
|                         } | ||||
|                         if (this.optionSelectTrigger) { | ||||
|                             this.optionSelectTrigger.show(); | ||||
|                             this.elementDiv.hide(); | ||||
|                             this.optionMenu = this._createMenu(opt.options,function(v){ | ||||
|                                 that.optionSelectLabel.text(v); | ||||
|                                 that.value(v); | ||||
|                             }); | ||||
|                             var currentVal = this.element.val(); | ||||
|                             if (opt.options.indexOf(currentVal) !== -1) { | ||||
|                                 this.optionSelectLabel.text(currentVal); | ||||
|                             } else { | ||||
|                                 this.value(opt.options[0]); | ||||
|                             } | ||||
|                         } | ||||
|                     } else { | ||||
|                         if (this.optionMenu) { | ||||
|                             this.optionMenu.remove(); | ||||
|                             this.optionMenu = null; | ||||
|                         } | ||||
|                         if (this.optionSelectTrigger) { | ||||
|                             this.optionSelectTrigger.hide(); | ||||
|                         } | ||||
|                         if (opt.hasValue === false) { | ||||
|                             this.oldValue = this.element.val(); | ||||
|                             this.element.val(""); | ||||
|                             this.elementDiv.hide(); | ||||
|                         } else { | ||||
|                             if (this.oldValue !== undefined) { | ||||
|                                 this.element.val(this.oldValue); | ||||
|                                 delete this.oldValue; | ||||
|                             } | ||||
|                             this.elementDiv.show(); | ||||
|                         } | ||||
|                         if (opt.expand && typeof opt.expand === 'function') { | ||||
|                             this.optionExpandButton.show(); | ||||
|                             this.optionExpandButton.off('click'); | ||||
|                             this.optionExpandButton.on('click',function(evt) { | ||||
|                                 evt.preventDefault(); | ||||
|                                 opt.expand.call(that); | ||||
|                             }) | ||||
|                         } else { | ||||
|                             this.optionExpandButton.hide(); | ||||
|                         } | ||||
|                         this.element.trigger('change',this.propertyType,this.value()); | ||||
|                     } | ||||
|                     if (image) { | ||||
|                         image.onload = function() { that._resize(); } | ||||
|                         image.onerror = function() { that._resize(); } | ||||
|                     } else { | ||||
|                         this._resize(); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         validate: function() { | ||||
|             var result; | ||||
|             var value = this.value(); | ||||
|             var type = this.type(); | ||||
|             if (this.typeMap[type] && this.typeMap[type].validate) { | ||||
|                 var val = this.typeMap[type].validate; | ||||
|                 if (typeof val === 'function') { | ||||
|                     result = val(value); | ||||
|                 } else { | ||||
|                     result = val.test(value); | ||||
|                 } | ||||
|             } else { | ||||
|                 result = true; | ||||
|             } | ||||
|             if (result) { | ||||
|                 this.uiSelect.removeClass('input-error'); | ||||
|             } else { | ||||
|                 this.uiSelect.addClass('input-error'); | ||||
|             } | ||||
|             return result; | ||||
|         }, | ||||
|         show: function() { | ||||
|             this.uiSelect.show(); | ||||
|             this._resize(); | ||||
|         }, | ||||
|         hide: function() { | ||||
|             this.uiSelect.hide(); | ||||
|         } | ||||
|     }); | ||||
| })(jQuery); | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2016 IBM Corp. | ||||
|  * 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. | ||||
| @@ -30,12 +30,15 @@ RED.deploy = (function() { | ||||
|  | ||||
|     var deploymentType = "full"; | ||||
|  | ||||
|     var deployInflight = false; | ||||
|  | ||||
|     var currentDiff = null; | ||||
|  | ||||
|     function changeDeploymentType(type) { | ||||
|         deploymentType = type; | ||||
|         $("#btn-deploy img").attr("src",deploymentTypes[type].img); | ||||
|         $("#btn-deploy-icon").attr("src",deploymentTypes[type].img); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * options: | ||||
|      *   type: "default" - Button with drop-down options - no further customisation available | ||||
| @@ -49,7 +52,15 @@ RED.deploy = (function() { | ||||
|  | ||||
|         if (type == "default") { | ||||
|             $('<li><span class="deploy-button-group button-group">'+ | ||||
|               '<a id="btn-deploy" class="deploy-button disabled" href="#"><img id="btn-deploy-icon" src="red/images/deploy-full-o.png"> <span>'+RED._("deploy.deploy")+'</span></a>'+ | ||||
|               '<a id="btn-deploy" class="deploy-button disabled" href="#">'+ | ||||
|                 '<span class="deploy-button-content">'+ | ||||
|                  '<img id="btn-deploy-icon" src="red/images/deploy-full-o.png"> '+ | ||||
|                  '<span>'+RED._("deploy.deploy")+'</span>'+ | ||||
|                 '</span>'+ | ||||
|                 '<span class="deploy-button-spinner hide">'+ | ||||
|                  '<img src="red/images/spin.svg"/>'+ | ||||
|                 '</span>'+ | ||||
|               '</a>'+ | ||||
|               '<a id="btn-deploy-options" data-toggle="dropdown" class="deploy-button" href="#"><i class="fa fa-caret-down"></i></a>'+ | ||||
|               '</span></li>').prependTo(".header-toolbar"); | ||||
|               RED.menu.init({id:"btn-deploy-options", | ||||
| @@ -68,35 +79,77 @@ RED.deploy = (function() { | ||||
|  | ||||
|             $('<li><span class="deploy-button-group button-group">'+ | ||||
|               '<a id="btn-deploy" class="deploy-button disabled" href="#">'+ | ||||
|               (icon?'<img id="btn-deploy-icon" src="'+icon+'"> ':'')+ | ||||
|               '<span>'+label+'</span></a>'+ | ||||
|                 '<span class="deploy-button-content">'+ | ||||
|                   (icon?'<img id="btn-deploy-icon" src="'+icon+'"> ':'')+ | ||||
|                   '<span>'+label+'</span>'+ | ||||
|                 '</span>'+ | ||||
|                 '<span class="deploy-button-spinner hide">'+ | ||||
|                  '<img src="red/images/spin.svg"/>'+ | ||||
|                 '</span>'+ | ||||
|               '</a>'+ | ||||
|               '</span></li>').prependTo(".header-toolbar"); | ||||
|         } | ||||
|  | ||||
|         $('#btn-deploy').click(function() { save(); }); | ||||
|         $('#btn-deploy').click(function(event) { | ||||
|             event.preventDefault(); | ||||
|             save(); | ||||
|         }); | ||||
|  | ||||
|         RED.actions.add("core:deploy-flows",save); | ||||
|  | ||||
|         $( "#node-dialog-confirm-deploy" ).dialog({ | ||||
|                 title: "Confirm deploy", | ||||
|                 title: RED._('deploy.confirm.button.confirm'), | ||||
|                 modal: true, | ||||
|                 autoOpen: false, | ||||
|                 width: 550, | ||||
|                 height: "auto", | ||||
|                 buttons: [ | ||||
|                     { | ||||
|                         text: RED._("common.label.cancel"), | ||||
|                         click: function() { | ||||
|                             $( this ).dialog( "close" ); | ||||
|                         } | ||||
|                     }, | ||||
|                     { | ||||
|                         id: "node-dialog-confirm-deploy-review", | ||||
|                         text: RED._("deploy.confirm.button.review"), | ||||
|                         class: "primary disabled", | ||||
|                         click: function() { | ||||
|                             if (!$("#node-dialog-confirm-deploy-review").hasClass('disabled')) { | ||||
|                                 RED.diff.showRemoteDiff(); | ||||
|                                 $( this ).dialog( "close" ); | ||||
|                             } | ||||
|                         } | ||||
|                     }, | ||||
|                     { | ||||
|                         id: "node-dialog-confirm-deploy-merge", | ||||
|                         text: RED._("deploy.confirm.button.merge"), | ||||
|                         class: "primary disabled", | ||||
|                         click: function() { | ||||
|                             RED.diff.mergeDiff(currentDiff); | ||||
|                             $( this ).dialog( "close" ); | ||||
|                         } | ||||
|                     }, | ||||
|                     { | ||||
|                         id: "node-dialog-confirm-deploy-deploy", | ||||
|                         text: RED._("deploy.confirm.button.confirm"), | ||||
|                         class: "primary", | ||||
|                         click: function() { | ||||
|  | ||||
|                             var ignoreChecked = $( "#node-dialog-confirm-deploy-hide" ).prop("checked"); | ||||
|                             if (ignoreChecked) { | ||||
|                                 ignoreDeployWarnings[$( "#node-dialog-confirm-deploy-type" ).val()] = true; | ||||
|                             } | ||||
|                             save(true); | ||||
|                             save(true,/conflict/.test($("#node-dialog-confirm-deploy-type" ).val())); | ||||
|                             $( this ).dialog( "close" ); | ||||
|                         } | ||||
|                     }, | ||||
|                     { | ||||
|                         text: RED._("deploy.confirm.button.cancel"), | ||||
|                         id: "node-dialog-confirm-deploy-overwrite", | ||||
|                         text: RED._("deploy.confirm.button.overwrite"), | ||||
|                         class: "primary", | ||||
|                         click: function() { | ||||
|                             save(true,/conflict/.test($("#node-dialog-confirm-deploy-type" ).val())); | ||||
|                             $( this ).dialog( "close" ); | ||||
|                         } | ||||
|                     } | ||||
| @@ -108,6 +161,47 @@ RED.deploy = (function() { | ||||
|                                    '<label style="display:inline;" for="node-dialog-confirm-deploy-hide"> do not warn about this again</label>'+ | ||||
|                                    '<input type="hidden" id="node-dialog-confirm-deploy-type">'+ | ||||
|                                    '</div>'); | ||||
|                 }, | ||||
|                 open: function() { | ||||
|                     var deployType = $("#node-dialog-confirm-deploy-type" ).val(); | ||||
|                     if (/conflict/.test(deployType)) { | ||||
|                         $( "#node-dialog-confirm-deploy" ).dialog('option','title', RED._('deploy.confirm.button.review')); | ||||
|                         $("#node-dialog-confirm-deploy-deploy").hide(); | ||||
|                         $("#node-dialog-confirm-deploy-review").addClass('disabled').show(); | ||||
|                         $("#node-dialog-confirm-deploy-merge").addClass('disabled').show(); | ||||
|                         $("#node-dialog-confirm-deploy-overwrite").toggle(deployType === "deploy-conflict"); | ||||
|                         currentDiff = null; | ||||
|                         $("#node-dialog-confirm-deploy-conflict-checking").show(); | ||||
|                         $("#node-dialog-confirm-deploy-conflict-auto-merge").hide(); | ||||
|                         $("#node-dialog-confirm-deploy-conflict-manual-merge").hide(); | ||||
|  | ||||
|                         var now = Date.now(); | ||||
|                         RED.diff.getRemoteDiff(function(diff) { | ||||
|                             var ellapsed = Math.max(1000 - (Date.now()-now), 0); | ||||
|                             currentDiff = diff; | ||||
|                             setTimeout(function() { | ||||
|                                 $("#node-dialog-confirm-deploy-conflict-checking").hide(); | ||||
|                                 var d = Object.keys(diff.conflicts); | ||||
|                                 if (d.length === 0) { | ||||
|                                     $("#node-dialog-confirm-deploy-conflict-auto-merge").show(); | ||||
|                                     $("#node-dialog-confirm-deploy-merge").removeClass('disabled') | ||||
|                                 } else { | ||||
|                                     $("#node-dialog-confirm-deploy-conflict-manual-merge").show(); | ||||
|                                 } | ||||
|                                 $("#node-dialog-confirm-deploy-review").removeClass('disabled') | ||||
|                             },ellapsed); | ||||
|                         }) | ||||
|  | ||||
|  | ||||
|                         $("#node-dialog-confirm-deploy-hide").parent().hide(); | ||||
|                     } else { | ||||
|                         $( "#node-dialog-confirm-deploy" ).dialog('option','title', RED._('deploy.confirm.button.confirm')); | ||||
|                         $("#node-dialog-confirm-deploy-deploy").show(); | ||||
|                         $("#node-dialog-confirm-deploy-overwrite").hide(); | ||||
|                         $("#node-dialog-confirm-deploy-review").hide(); | ||||
|                         $("#node-dialog-confirm-deploy-merge").hide(); | ||||
|                         $("#node-dialog-confirm-deploy-hide").parent().show(); | ||||
|                     } | ||||
|                 } | ||||
|         }); | ||||
|  | ||||
| @@ -122,6 +216,34 @@ RED.deploy = (function() { | ||||
|                 $("#btn-deploy").addClass("disabled"); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         var activeNotifyMessage; | ||||
|         RED.comms.subscribe("notification/runtime-deploy",function(topic,msg) { | ||||
|             if (!activeNotifyMessage) { | ||||
|                 var currentRev = RED.nodes.version(); | ||||
|                 if (currentRev === null || deployInflight || currentRev === msg.revision) { | ||||
|                     return; | ||||
|                 } | ||||
|                 var message = $('<div>'+RED._('deploy.confirm.backgroundUpdate')+ | ||||
|                     '<br><br><div class="ui-dialog-buttonset">'+ | ||||
|                     '<button>'+RED._('deploy.confirm.button.ignore')+'</button>'+ | ||||
|                     '<button class="primary">'+RED._('deploy.confirm.button.review')+'</button>'+ | ||||
|                     '</div></div>'); | ||||
|                 $(message.find('button')[0]).click(function(evt) { | ||||
|                     evt.preventDefault(); | ||||
|                     activeNotifyMessage.close(); | ||||
|                     activeNotifyMessage = null; | ||||
|                 }) | ||||
|                 $(message.find('button')[1]).click(function(evt) { | ||||
|                     evt.preventDefault(); | ||||
|                     activeNotifyMessage.close(); | ||||
|                     var nns = RED.nodes.createCompleteNodeSet(); | ||||
|                     resolveConflict(nns,false); | ||||
|                     activeNotifyMessage = null; | ||||
|                 }) | ||||
|                 activeNotifyMessage = RED.notify(message,null,true); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     function getNodeInfo(node) { | ||||
| @@ -135,13 +257,7 @@ RED.deploy = (function() { | ||||
|                 tabLabel = tab.label; | ||||
|             } | ||||
|         } | ||||
|         var label = ""; | ||||
|         if (typeof node._def.label == "function") { | ||||
|             label = node._def.label.call(node); | ||||
|         } else { | ||||
|             label = node._def.label; | ||||
|         } | ||||
|         label = label || node.id; | ||||
|         var label = RED.utils.getNodeLabel(node,node.id); | ||||
|         return {tab:tabLabel,type:node.type,label:label}; | ||||
|     } | ||||
|     function sortNodeInfo(A,B) { | ||||
| @@ -154,11 +270,18 @@ RED.deploy = (function() { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     function save(force) { | ||||
|         if (RED.nodes.dirty()) { | ||||
|             //$("#debug-tab-clear").click();  // uncomment this to auto clear debug on deploy | ||||
|     function resolveConflict(currentNodes, activeDeploy) { | ||||
|         $( "#node-dialog-confirm-deploy-config" ).hide(); | ||||
|         $( "#node-dialog-confirm-deploy-unknown" ).hide(); | ||||
|         $( "#node-dialog-confirm-deploy-unused" ).hide(); | ||||
|         $( "#node-dialog-confirm-deploy-conflict" ).show(); | ||||
|         $( "#node-dialog-confirm-deploy-type" ).val(activeDeploy?"deploy-conflict":"background-conflict"); | ||||
|         $( "#node-dialog-confirm-deploy" ).dialog( "open" ); | ||||
|     } | ||||
|  | ||||
|             if (!force) { | ||||
|     function save(skipValidation,force) { | ||||
|         if (!$("#btn-deploy").hasClass("disabled")) { | ||||
|             if (!skipValidation) { | ||||
|                 var hasUnknown = false; | ||||
|                 var hasInvalid = false; | ||||
|                 var hasUnusedConfig = false; | ||||
| @@ -181,7 +304,7 @@ RED.deploy = (function() { | ||||
|  | ||||
|                 var unusedConfigNodes = []; | ||||
|                 RED.nodes.eachConfig(function(node) { | ||||
|                     if (node.users.length === 0) { | ||||
|                     if (node.users.length === 0 && (node._def.hasUsers !== false)) { | ||||
|                         unusedConfigNodes.push(getNodeInfo(node)); | ||||
|                         hasUnusedConfig = true; | ||||
|                     } | ||||
| @@ -190,6 +313,7 @@ RED.deploy = (function() { | ||||
|                 $( "#node-dialog-confirm-deploy-config" ).hide(); | ||||
|                 $( "#node-dialog-confirm-deploy-unknown" ).hide(); | ||||
|                 $( "#node-dialog-confirm-deploy-unused" ).hide(); | ||||
|                 $( "#node-dialog-confirm-deploy-conflict" ).hide(); | ||||
|  | ||||
|                 var showWarning = false; | ||||
|  | ||||
| @@ -223,24 +347,36 @@ RED.deploy = (function() { | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|             var nns = RED.nodes.createCompleteNodeSet(); | ||||
|  | ||||
|             $("#btn-deploy-icon").removeClass('fa-download'); | ||||
|             $("#btn-deploy-icon").addClass('spinner'); | ||||
|             RED.nodes.dirty(false); | ||||
|             var startTime = Date.now(); | ||||
|             $(".deploy-button-content").css('opacity',0); | ||||
|             $(".deploy-button-spinner").show(); | ||||
|             $("#btn-deploy").addClass("disabled"); | ||||
|  | ||||
|             var data = {flows:nns}; | ||||
|  | ||||
|             if (!force) { | ||||
|                 data.rev = RED.nodes.version(); | ||||
|             } | ||||
|  | ||||
|             deployInflight = true; | ||||
|             $("#header-shade").show(); | ||||
|             $("#editor-shade").show(); | ||||
|             $("#palette-shade").show(); | ||||
|             $("#sidebar-shade").show(); | ||||
|             $.ajax({ | ||||
|                 url:"flows", | ||||
|                 type: "POST", | ||||
|                 data: JSON.stringify(nns), | ||||
|                 data: JSON.stringify(data), | ||||
|                 contentType: "application/json; charset=utf-8", | ||||
|                 headers: { | ||||
|                     "Node-RED-Deployment-Type":deploymentType | ||||
|                 } | ||||
|             }).done(function(data,textStatus,xhr) { | ||||
|                 RED.nodes.dirty(false); | ||||
|                 RED.nodes.version(data.rev); | ||||
|                 RED.nodes.originalFlow(nns); | ||||
|                 if (hasUnusedConfig) { | ||||
|                     RED.notify( | ||||
|                     '<p>'+RED._("deploy.successfulDeploy")+'</p>'+ | ||||
| @@ -253,33 +389,53 @@ RED.deploy = (function() { | ||||
|                         node.dirty = true; | ||||
|                         node.changed = false; | ||||
|                     } | ||||
|                     if (node.moved) { | ||||
|                         node.dirty = true; | ||||
|                         node.moved = false; | ||||
|                     } | ||||
|                     if(node.credentials) { | ||||
|                         delete node.credentials; | ||||
|                     } | ||||
|                 }); | ||||
|                 RED.nodes.eachConfig(function (confNode) { | ||||
|                     confNode.changed = false; | ||||
|                     if (confNode.credentials) { | ||||
|                         delete confNode.credentials; | ||||
|                     } | ||||
|                 }); | ||||
|                 RED.nodes.eachWorkspace(function(ws) { | ||||
|                     ws.changed = false; | ||||
|                 }) | ||||
|                 // Once deployed, cannot undo back to a clean state | ||||
|                 RED.history.markAllDirty(); | ||||
|                 RED.view.redraw(); | ||||
|                 RED.events.emit("deploy"); | ||||
|             }).fail(function(xhr,textStatus,err) { | ||||
|                 RED.nodes.dirty(true); | ||||
|                 if (xhr.responseText) { | ||||
|                     RED.notify(RED._("notification.error",{message:xhr.responseText}),"error"); | ||||
|                 $("#btn-deploy").removeClass("disabled"); | ||||
|                 if (xhr.status === 401) { | ||||
|                     RED.notify(RED._("deploy.deployFailed",{message:RED._("user.notAuthorized")}),"error"); | ||||
|                 } else if (xhr.status === 409) { | ||||
|                     resolveConflict(nns, true); | ||||
|                 } else if (xhr.responseText) { | ||||
|                     RED.notify(RED._("deploy.deployFailed",{message:xhr.responseText}),"error"); | ||||
|                 } else { | ||||
|                     RED.notify(RED._("notification.error",{message:RED._("deploy.errors.noResponse")}),"error"); | ||||
|                     RED.notify(RED._("deploy.deployFailed",{message:RED._("deploy.errors.noResponse")}),"error"); | ||||
|                 } | ||||
|             }).always(function() { | ||||
|                 $("#btn-deploy-icon").removeClass('spinner'); | ||||
|                 $("#btn-deploy-icon").addClass('fa-download'); | ||||
|                 deployInflight = false; | ||||
|                 var delta = Math.max(0,300-(Date.now()-startTime)); | ||||
|                 setTimeout(function() { | ||||
|                     $(".deploy-button-content").css('opacity',1); | ||||
|                     $(".deploy-button-spinner").hide(); | ||||
|                     $("#header-shade").hide(); | ||||
|                     $("#editor-shade").hide(); | ||||
|                     $("#palette-shade").hide(); | ||||
|                     $("#sidebar-shade").hide(); | ||||
|                 },delta); | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         init: init | ||||
|     } | ||||
|   | ||||
							
								
								
									
										1271
									
								
								editor/js/ui/diff.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2013 IBM Corp. | ||||
|  * 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. | ||||
| @@ -15,107 +15,515 @@ | ||||
|  **/ | ||||
| RED.keyboard = (function() { | ||||
|  | ||||
|     var active = true; | ||||
|     var isMac = /Mac/i.test(window.navigator.platform); | ||||
|  | ||||
|     var handlers = {}; | ||||
|     var partialState; | ||||
|  | ||||
|     var keyMap = { | ||||
|         "left":37, | ||||
|         "up":38, | ||||
|         "right":39, | ||||
|         "down":40, | ||||
|         "escape":27, | ||||
|         "enter": 13, | ||||
|         "backspace": 8, | ||||
|         "delete": 46, | ||||
|         "space": 32, | ||||
|         ";":186, | ||||
|         "=":187, | ||||
|         ",":188, | ||||
|         "-":189, | ||||
|         ".":190, | ||||
|         "/":191, | ||||
|         "\\":220, | ||||
|         "'":222, | ||||
|         "?":191 // <- QWERTY specific | ||||
|     } | ||||
|     var metaKeyCodes = { | ||||
|         16:true, | ||||
|         17:true, | ||||
|         18: true, | ||||
|         91:true, | ||||
|         93: true | ||||
|     } | ||||
|     var actionToKeyMap = {} | ||||
|     var defaultKeyMap = {}; | ||||
|  | ||||
|     // FF generates some different keycodes because reasons. | ||||
|     var firefoxKeyCodeMap = { | ||||
|         59:186, | ||||
|         61:187, | ||||
|         173:189 | ||||
|     } | ||||
|  | ||||
|     function init() { | ||||
|         var userKeymap = RED.settings.get('keymap') || {}; | ||||
|         $.getJSON("red/keymap.json",function(data) { | ||||
|             for (var scope in data) { | ||||
|                 if (data.hasOwnProperty(scope)) { | ||||
|                     var keys = data[scope]; | ||||
|                     for (var key in keys) { | ||||
|                         if (keys.hasOwnProperty(key)) { | ||||
|                             if (!userKeymap.hasOwnProperty(keys[key])) { | ||||
|                                 addHandler(scope,key,keys[key],false); | ||||
|                                 defaultKeyMap[keys[key]] = { | ||||
|                                     scope:scope, | ||||
|                                     key:key, | ||||
|                                     user:false | ||||
|                                 }; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             for (var action in userKeymap) { | ||||
|                 if (userKeymap.hasOwnProperty(action)) { | ||||
|                     var obj = userKeymap[action]; | ||||
|                     if (obj.hasOwnProperty('key')) { | ||||
|                         addHandler(obj.scope, obj.key, action, true); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         RED.userSettings.add({ | ||||
|             id:'keyboard', | ||||
|             title: 'Keyboard', | ||||
|             get: getSettingsPane, | ||||
|             focus: function() { | ||||
|                 setTimeout(function() { | ||||
|                     $("#user-settings-tab-keyboard-filter").focus(); | ||||
|                 },200); | ||||
|             } | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     function revertToDefault(action) { | ||||
|         var currentAction = actionToKeyMap[action]; | ||||
|         if (currentAction) { | ||||
|             removeHandler(currentAction.key); | ||||
|         } | ||||
|         if (defaultKeyMap.hasOwnProperty(action)) { | ||||
|             var obj = defaultKeyMap[action]; | ||||
|             addHandler(obj.scope, obj.key, action, false); | ||||
|         } | ||||
|     } | ||||
|     function parseKeySpecifier(key) { | ||||
|         var parts = key.toLowerCase().split("-"); | ||||
|         var modifiers = {}; | ||||
|         var keycode; | ||||
|         var blank = 0; | ||||
|         for (var i=0;i<parts.length;i++) { | ||||
|             switch(parts[i]) { | ||||
|                 case "ctrl": | ||||
|                 case "cmd": | ||||
|                     modifiers.ctrl = true; | ||||
|                     modifiers.meta = true; | ||||
|                     break; | ||||
|                 case "alt": | ||||
|                     modifiers.alt = true; | ||||
|                     break; | ||||
|                 case "shift": | ||||
|                     modifiers.shift = true; | ||||
|                     break; | ||||
|                 case "": | ||||
|                     blank++; | ||||
|                     keycode = keyMap["-"]; | ||||
|                     break; | ||||
|                 default: | ||||
|                     if (keyMap.hasOwnProperty(parts[i])) { | ||||
|                         keycode = keyMap[parts[i]]; | ||||
|                     } else if (parts[i].length > 1) { | ||||
|                         return null; | ||||
|                     } else { | ||||
|                         keycode = parts[i].toUpperCase().charCodeAt(0); | ||||
|                     } | ||||
|                     break; | ||||
|             } | ||||
|         } | ||||
|         return [keycode,modifiers]; | ||||
|     } | ||||
|  | ||||
|     function resolveKeyEvent(evt) { | ||||
|         var slot = partialState||handlers; | ||||
|         if (evt.ctrlKey || evt.metaKey) { | ||||
|             slot = slot.ctrl; | ||||
|         } | ||||
|         if (slot && evt.shiftKey) { | ||||
|             slot = slot.shift; | ||||
|         } | ||||
|         if (slot && evt.altKey) { | ||||
|             slot = slot.alt; | ||||
|         } | ||||
|         var keyCode = firefoxKeyCodeMap[evt.keyCode] || evt.keyCode; | ||||
|         if (slot && slot[keyCode]) { | ||||
|             var handler = slot[keyCode]; | ||||
|             if (!handler.scope) { | ||||
|                 if (partialState) { | ||||
|                     partialState = null; | ||||
|                     return resolveKeyEvent(evt); | ||||
|                 } else if (Object.keys(handler).length > 0) { | ||||
|                     partialState = handler; | ||||
|                     evt.preventDefault(); | ||||
|                     return null; | ||||
|                 } else { | ||||
|                     return null; | ||||
|                 } | ||||
|             } else if (handler.scope && handler.scope !== "*") { | ||||
|                 var target = evt.target; | ||||
|                 while (target.nodeName !== 'BODY' && target.id !== handler.scope) { | ||||
|                     target = target.parentElement; | ||||
|                 } | ||||
|                 if (target.nodeName === 'BODY') { | ||||
|                     handler = null; | ||||
|                 } | ||||
|             } | ||||
|             partialState = null; | ||||
|             return handler; | ||||
|         } else if (partialState) { | ||||
|             partialState = null; | ||||
|             return resolveKeyEvent(evt); | ||||
|         } | ||||
|     } | ||||
|     d3.select(window).on("keydown",function() { | ||||
|         if (!active) { return; } | ||||
|         var handler = handlers[d3.event.keyCode]; | ||||
|         if (handler && handler.ondown) { | ||||
|             if (!handler.modifiers || | ||||
|                 ((!handler.modifiers.shift || d3.event.shiftKey) && | ||||
|                  (!handler.modifiers.ctrl  || d3.event.ctrlKey || d3.event.metaKey) && | ||||
|                  (!handler.modifiers.alt   || d3.event.altKey) )) { | ||||
|                 handler.ondown(); | ||||
|             } | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     d3.select(window).on("keyup",function() { | ||||
|         if (!active) { return; } | ||||
|         var handler = handlers[d3.event.keyCode]; | ||||
|         if (handler && handler.onup) { | ||||
|             if (!handler.modifiers || | ||||
|                 ((!handler.modifiers.shift || d3.event.shiftKey) && | ||||
|                  (!handler.modifiers.ctrl  || d3.event.ctrlKey || d3.event.metaKey) && | ||||
|                  (!handler.modifiers.alt   || d3.event.altKey) )) { | ||||
|                 handler.onup(); | ||||
|             } | ||||
|         } | ||||
|     }); | ||||
|     function addHandler(key,modifiers,ondown,onup) { | ||||
|         var mod = modifiers; | ||||
|         var cbdown = ondown; | ||||
|         var cbup = onup; | ||||
|         if (typeof modifiers == "function") { | ||||
|             mod = {}; | ||||
|             cbdown = modifiers; | ||||
|             cbup = ondown; | ||||
|         } | ||||
|         handlers[key] = {modifiers:mod, ondown:cbdown, onup:cbup}; | ||||
|     } | ||||
|     function removeHandler(key) { | ||||
|         delete handlers[key]; | ||||
|     } | ||||
|      | ||||
|      | ||||
|     var dialog = null; | ||||
|      | ||||
|     function showKeyboardHelp() { | ||||
|         if (!RED.settings.theme("menu.menu-item-keyboard-shortcuts",true)) { | ||||
|         if (metaKeyCodes[d3.event.keyCode]) { | ||||
|             return; | ||||
|         } | ||||
|         if (!dialog) { | ||||
|             dialog = $('<div id="keyboard-help-dialog" class="hide">'+ | ||||
|                 '<div style="vertical-align: top;display:inline-block; box-sizing: border-box; width:50%; padding: 10px;">'+ | ||||
|                     '<table class="keyboard-shortcuts">'+ | ||||
|                         '<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">a</span></td><td>'+RED._("keyboard.selectAll")+'</td></tr>'+ | ||||
|                         '<tr><td><span class="help-key">Shift</span> + <span class="help-key">Click</span></td><td>'+RED._("keyboard.selectAllConnected")+'</td></tr>'+ | ||||
|                         '<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">Click</span></td><td>'+RED._("keyboard.addRemoveNode")+'</td></tr>'+ | ||||
|                         '<tr><td><span class="help-key">Delete</span></td><td>'+RED._("keyboard.deleteSelected")+'</td></tr>'+ | ||||
|                         '<tr><td> </td><td></td></tr>'+ | ||||
|                         '<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">i</span></td><td>'+RED._("keyboard.importNode")+'</td></tr>'+ | ||||
|                         '<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">e</span></td><td>'+RED._("keyboard.exportNode")+'</td></tr>'+ | ||||
|                     '</table>'+ | ||||
|                 '</div>'+ | ||||
|                 '<div style="vertical-align: top;display:inline-block; box-sizing: border-box; width:50%; padding: 10px;">'+ | ||||
|                     '<table class="keyboard-shortcuts">'+ | ||||
|                         '<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">Space</span></td><td>'+RED._("keyboard.toggleSidebar")+'</td></tr>'+ | ||||
|                         '<tr><td></td><td></td></tr>'+ | ||||
|                         '<tr><td><span class="help-key">Delete</span></td><td>'+RED._("keyboard.deleteNode")+'</td></tr>'+ | ||||
|                         '<tr><td></td><td></td></tr>'+ | ||||
|                         '<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">c</span></td><td>'+RED._("keyboard.copyNode")+'</td></tr>'+ | ||||
|                         '<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">x</span></td><td>'+RED._("keyboard.cutNode")+'</td></tr>'+ | ||||
|                         '<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">v</span></td><td>'+RED._("keyboard.pasteNode")+'</td></tr>'+ | ||||
|                     '</table>'+ | ||||
|                 '</div>'+ | ||||
|                 '</div>') | ||||
|             .appendTo("body") | ||||
|             .dialog({ | ||||
|                 modal: true, | ||||
|                 autoOpen: false, | ||||
|                 width: "800", | ||||
|                 title:"Keyboard shortcuts", | ||||
|                 resizable: false, | ||||
|                 open: function() { | ||||
|                     RED.keyboard.disable(); | ||||
|                 }, | ||||
|                 close: function() { | ||||
|                     RED.keyboard.enable(); | ||||
|                 } | ||||
|             }); | ||||
|         var handler = resolveKeyEvent(d3.event); | ||||
|         if (handler && handler.ondown) { | ||||
|             if (typeof handler.ondown === "string") { | ||||
|                 RED.actions.invoke(handler.ondown); | ||||
|             } else { | ||||
|                 handler.ondown(); | ||||
|             } | ||||
|             d3.event.preventDefault(); | ||||
|         } | ||||
|          | ||||
|         dialog.dialog("open"); | ||||
|     }); | ||||
|  | ||||
|     function addHandler(scope,key,modifiers,ondown) { | ||||
|         var mod = modifiers; | ||||
|         var cbdown = ondown; | ||||
|         if (typeof modifiers == "function" || typeof modifiers === "string") { | ||||
|             mod = {}; | ||||
|             cbdown = modifiers; | ||||
|         } | ||||
|         var keys = []; | ||||
|         var i=0; | ||||
|         if (typeof key === 'string') { | ||||
|             if (typeof cbdown === 'string') { | ||||
|                 actionToKeyMap[cbdown] = {scope:scope,key:key}; | ||||
|                 if (typeof ondown === 'boolean') { | ||||
|                     actionToKeyMap[cbdown].user = ondown; | ||||
|                 } | ||||
|             } | ||||
|             var parts = key.split(" "); | ||||
|             for (i=0;i<parts.length;i++) { | ||||
|                 var parsedKey = parseKeySpecifier(parts[i]); | ||||
|                 if (parsedKey) { | ||||
|                     keys.push(parsedKey); | ||||
|                 } else { | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             keys.push([key,mod]) | ||||
|         } | ||||
|         var slot = handlers; | ||||
|         for (i=0;i<keys.length;i++) { | ||||
|             key = keys[i][0]; | ||||
|             mod = keys[i][1]; | ||||
|             if (mod.ctrl) { | ||||
|                 slot.ctrl = slot.ctrl||{}; | ||||
|                 slot = slot.ctrl; | ||||
|             } | ||||
|             if (mod.shift) { | ||||
|                 slot.shift = slot.shift||{}; | ||||
|                 slot = slot.shift; | ||||
|             } | ||||
|             if (mod.alt) { | ||||
|                 slot.alt = slot.alt||{}; | ||||
|                 slot = slot.alt; | ||||
|             } | ||||
|             slot[key] = slot[key] || {}; | ||||
|             slot = slot[key]; | ||||
|             //slot[key] = {scope: scope, ondown:cbdown}; | ||||
|         } | ||||
|         slot.scope = scope; | ||||
|         slot.ondown = cbdown; | ||||
|     } | ||||
|      | ||||
|  | ||||
|     function removeHandler(key,modifiers) { | ||||
|         var mod = modifiers || {}; | ||||
|         var keys = []; | ||||
|         var i=0; | ||||
|         if (typeof key === 'string') { | ||||
|  | ||||
|             var parts = key.split(" "); | ||||
|             for (i=0;i<parts.length;i++) { | ||||
|                 var parsedKey = parseKeySpecifier(parts[i]); | ||||
|                 if (parsedKey) { | ||||
|                     keys.push(parsedKey); | ||||
|                 } else { | ||||
|                     console.log("Unrecognised key specifier:",key) | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             keys.push([key,mod]) | ||||
|         } | ||||
|         var slot = handlers; | ||||
|         for (i=0;i<keys.length;i++) { | ||||
|             key = keys[i][0]; | ||||
|             mod = keys[i][1]; | ||||
|             if (mod.ctrl) { | ||||
|                 slot = slot.ctrl; | ||||
|             } | ||||
|             if (slot && mod.shift) { | ||||
|                 slot = slot.shift; | ||||
|             } | ||||
|             if (slot && mod.alt) { | ||||
|                 slot = slot.alt; | ||||
|             } | ||||
|             if (!slot[key]) { | ||||
|                 return; | ||||
|             } | ||||
|             slot = slot[key]; | ||||
|         } | ||||
|         if (typeof slot.ondown === "string") { | ||||
|             if (typeof modifiers === 'boolean' && modifiers) { | ||||
|                 actionToKeyMap[slot.ondown] = {user: modifiers} | ||||
|             } else { | ||||
|                 delete actionToKeyMap[slot.ondown]; | ||||
|             } | ||||
|         } | ||||
|         delete slot.scope; | ||||
|         delete slot.ondown; | ||||
|     } | ||||
|  | ||||
|     var cmdCtrlKey = '<span class="help-key">'+(isMac?'⌘':'Ctrl')+'</span>'; | ||||
|  | ||||
|     function formatKey(key) { | ||||
|         var formattedKey = isMac?key.replace(/ctrl-?/,"⌘"):key; | ||||
|         formattedKey = isMac?formattedKey.replace(/alt-?/,"⌥"):key; | ||||
|         formattedKey = formattedKey.replace(/shift-?/,"⇧") | ||||
|         formattedKey = formattedKey.replace(/left/,"←") | ||||
|         formattedKey = formattedKey.replace(/up/,"↑") | ||||
|         formattedKey = formattedKey.replace(/right/,"→") | ||||
|         formattedKey = formattedKey.replace(/down/,"↓") | ||||
|         return '<span class="help-key-block"><span class="help-key">'+formattedKey.split(" ").join('</span> <span class="help-key">')+'</span></span>'; | ||||
|     } | ||||
|  | ||||
|     function validateKey(key) { | ||||
|         key = key.trim(); | ||||
|         var parts = key.split(" "); | ||||
|         for (i=0;i<parts.length;i++) { | ||||
|             var parsedKey = parseKeySpecifier(parts[i]); | ||||
|             if (!parsedKey) { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     function editShortcut(e) { | ||||
|         e.preventDefault(); | ||||
|         var container = $(this); | ||||
|         var object = container.data('data'); | ||||
|  | ||||
|  | ||||
|         if (!container.hasClass('keyboard-shortcut-entry-expanded')) { | ||||
|             endEditShortcut(); | ||||
|  | ||||
|             var key = container.find(".keyboard-shortcut-entry-key"); | ||||
|             var scope = container.find(".keyboard-shortcut-entry-scope"); | ||||
|             container.addClass('keyboard-shortcut-entry-expanded'); | ||||
|  | ||||
|             var keyInput = $('<input type="text">').attr('placeholder',RED._('keyboard.unassigned')).val(object.key||"").appendTo(key); | ||||
|             keyInput.on("keyup",function(e) { | ||||
|                 if (e.keyCode === 13) { | ||||
|                     return endEditShortcut(); | ||||
|                 } | ||||
|                 var currentVal = $(this).val(); | ||||
|                 currentVal = currentVal.trim(); | ||||
|                 var valid = (currentVal === "" || RED.keyboard.validateKey(currentVal)); | ||||
|                 $(this).toggleClass("input-error",!valid); | ||||
|             }) | ||||
|  | ||||
|             var scopeSelect = $('<select><option value="*">global</option><option value="workspace">workspace</option></select>').appendTo(scope); | ||||
|             scopeSelect.val(object.scope||'*'); | ||||
|  | ||||
|             var div = $('<div class="keyboard-shortcut-edit button-group-vertical"></div>').appendTo(scope); | ||||
|             var okButton = $('<button class="editor-button editor-button-small"><i class="fa fa-check"></i></button>').appendTo(div); | ||||
|             var revertButton = $('<button class="editor-button editor-button-small"><i class="fa fa-reply"></i></button>').appendTo(div); | ||||
|  | ||||
|             okButton.click(function(e) { | ||||
|                 e.stopPropagation(); | ||||
|                 endEditShortcut(); | ||||
|             }); | ||||
|             revertButton.click(function(e) { | ||||
|                 e.stopPropagation(); | ||||
|                 RED.keyboard.revertToDefault(object.id); | ||||
|                 container.empty(); | ||||
|                 container.removeClass('keyboard-shortcut-entry-expanded'); | ||||
|                 var shortcut = RED.keyboard.getShortcut(object.id); | ||||
|                 var userKeymap = RED.settings.get('keymap') || {}; | ||||
|                 delete userKeymap[object.id]; | ||||
|                 RED.settings.set('keymap',userKeymap); | ||||
|  | ||||
|                 var obj = { | ||||
|                     id:object.id, | ||||
|                     scope:shortcut?shortcut.scope:undefined, | ||||
|                     key:shortcut?shortcut.key:undefined, | ||||
|                     user:shortcut?shortcut.user:undefined | ||||
|                 } | ||||
|                 buildShortcutRow(container,obj); | ||||
|             }) | ||||
|  | ||||
|             keyInput.focus(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function endEditShortcut(cancel) { | ||||
|         var container = $('.keyboard-shortcut-entry-expanded'); | ||||
|         if (container.length === 1) { | ||||
|             var object = container.data('data'); | ||||
|             var keyInput = container.find(".keyboard-shortcut-entry-key input"); | ||||
|             var scopeSelect = container.find(".keyboard-shortcut-entry-scope select"); | ||||
|             if (!cancel) { | ||||
|                 var key = keyInput.val().trim(); | ||||
|                 var scope = scopeSelect.val(); | ||||
|                 var valid = (key === "" || RED.keyboard.validateKey(key)); | ||||
|                 if (valid) { | ||||
|                     var current = RED.keyboard.getShortcut(object.id); | ||||
|                     if ((!current && key) || (current && (current.scope !== scope || current.key !== key))) { | ||||
|                         var keyDiv = container.find(".keyboard-shortcut-entry-key"); | ||||
|                         var scopeDiv = container.find(".keyboard-shortcut-entry-scope"); | ||||
|                         keyDiv.empty(); | ||||
|                         scopeDiv.empty(); | ||||
|                         if (object.key) { | ||||
|                             RED.keyboard.remove(object.key,true); | ||||
|                         } | ||||
|                         container.find(".keyboard-shortcut-entry-text i").css("opacity",1); | ||||
|                         if (key === "") { | ||||
|                             keyDiv.parent().addClass("keyboard-shortcut-entry-unassigned"); | ||||
|                             keyDiv.append($('<span>').text(RED._('keyboard.unassigned'))  ); | ||||
|                             delete object.key; | ||||
|                             delete object.scope; | ||||
|                         } else { | ||||
|                             keyDiv.parent().removeClass("keyboard-shortcut-entry-unassigned"); | ||||
|                             keyDiv.append(RED.keyboard.formatKey(key)) | ||||
|                             $("<span>").text(scope).appendTo(scopeDiv); | ||||
|                             object.key = key; | ||||
|                             object.scope = scope; | ||||
|                             RED.keyboard.add(object.scope,object.key,object.id,true); | ||||
|                         } | ||||
|                         var userKeymap = RED.settings.get('keymap') || {}; | ||||
|                         userKeymap[object.id] = RED.keyboard.getShortcut(object.id); | ||||
|                         RED.settings.set('keymap',userKeymap); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             keyInput.remove(); | ||||
|             scopeSelect.remove(); | ||||
|             $('.keyboard-shortcut-edit').remove(); | ||||
|             container.removeClass('keyboard-shortcut-entry-expanded'); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function buildShortcutRow(container,object) { | ||||
|         var item = $('<div class="keyboard-shortcut-entry">').appendTo(container); | ||||
|         container.data('data',object); | ||||
|  | ||||
|         var text = object.id.replace(/(^.+:([a-z]))|(-([a-z]))/g,function() { | ||||
|             if (arguments[5] === 0) { | ||||
|                 return arguments[2].toUpperCase(); | ||||
|             } else { | ||||
|                 return " "+arguments[4].toUpperCase(); | ||||
|             } | ||||
|         }); | ||||
|         var label = $('<div>').addClass("keyboard-shortcut-entry-text").text(text).appendTo(item); | ||||
|  | ||||
|         var user = $('<i class="fa fa-user"></i>').prependTo(label); | ||||
|  | ||||
|         if (!object.user) { | ||||
|             user.css("opacity",0); | ||||
|         } | ||||
|  | ||||
|         var key = $('<div class="keyboard-shortcut-entry-key">').appendTo(item); | ||||
|         if (object.key) { | ||||
|             key.append(RED.keyboard.formatKey(object.key)); | ||||
|         } else { | ||||
|             item.addClass("keyboard-shortcut-entry-unassigned"); | ||||
|             key.append($('<span>').text(RED._('keyboard.unassigned'))  ); | ||||
|         } | ||||
|  | ||||
|         var scope = $('<div class="keyboard-shortcut-entry-scope">').appendTo(item); | ||||
|  | ||||
|         $("<span>").text(object.scope === '*'?'global':object.scope||"").appendTo(scope); | ||||
|         container.click(editShortcut); | ||||
|     } | ||||
|  | ||||
|     function getSettingsPane() { | ||||
|         var pane = $('<div id="user-settings-tab-keyboard"></div>'); | ||||
|  | ||||
|         $('<div class="keyboard-shortcut-entry keyboard-shortcut-list-header">'+ | ||||
|         '<div class="keyboard-shortcut-entry-key keyboard-shortcut-entry-text"><input id="user-settings-tab-keyboard-filter" type="text" placeholder="filter actions"></div>'+ | ||||
|         '<div class="keyboard-shortcut-entry-key">shortcut</div>'+ | ||||
|         '<div class="keyboard-shortcut-entry-scope">scope</div>'+ | ||||
|         '</div>').appendTo(pane); | ||||
|  | ||||
|         pane.find("input").searchBox({ | ||||
|             delay: 100, | ||||
|             change: function() { | ||||
|                 var filterValue = $(this).val().trim(); | ||||
|                 if (filterValue === "") { | ||||
|                     shortcutList.editableList('filter', null); | ||||
|                 } else { | ||||
|                     filterValue = filterValue.replace(/\s/g,""); | ||||
|                     shortcutList.editableList('filter', function(data) { | ||||
|                         return data.id.toLowerCase().replace(/^.*:/,"").replace("-","").indexOf(filterValue) > -1; | ||||
|                     }) | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         var shortcutList = $('<ol class="keyboard-shortcut-list"></ol>').css({ | ||||
|             position: "absolute", | ||||
|             top: "32px", | ||||
|             bottom: "0", | ||||
|             left: "0", | ||||
|             right: "0" | ||||
|         }).appendTo(pane).editableList({ | ||||
|             addButton: false, | ||||
|             scrollOnAdd: false, | ||||
|             addItem: function(container,i,object) { | ||||
|                 buildShortcutRow(container,object); | ||||
|             }, | ||||
|  | ||||
|         }); | ||||
|         var shortcuts = RED.actions.list(); | ||||
|         shortcuts.sort(function(A,B) { | ||||
|             var Aid = A.id.replace(/^.*:/,"").replace(/[ -]/g,"").toLowerCase(); | ||||
|             var Bid = B.id.replace(/^.*:/,"").replace(/[ -]/g,"").toLowerCase(); | ||||
|             return Aid.localeCompare(Bid); | ||||
|         }); | ||||
|         shortcuts.forEach(function(s) { | ||||
|             shortcutList.editableList('addItem',s); | ||||
|         }); | ||||
|         return pane; | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         init: init, | ||||
|         add: addHandler, | ||||
|         remove: removeHandler, | ||||
|         disable: function(){ active = false;}, | ||||
|         enable: function(){ active = true; }, | ||||
|          | ||||
|         showHelp: showKeyboardHelp | ||||
|         getShortcut: function(actionName) { | ||||
|             return actionToKeyMap[actionName]; | ||||
|         }, | ||||
|         revertToDefault: revertToDefault, | ||||
|         formatKey: formatKey, | ||||
|         validateKey: validateKey | ||||
|     } | ||||
|  | ||||
| })(); | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2013, 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -27,7 +27,9 @@ RED.library = (function() { | ||||
|                 var li; | ||||
|                 var a; | ||||
|                 var ul = document.createElement("ul"); | ||||
|                 ul.id = "menu-item-import-library-submenu"; | ||||
|                 if (root === "") { | ||||
|                     ul.id = "menu-item-import-library-submenu"; | ||||
|                 } | ||||
|                 ul.className = "dropdown-menu"; | ||||
|                 if (data.d) { | ||||
|                     for (i in data.d) { | ||||
| @@ -36,7 +38,8 @@ RED.library = (function() { | ||||
|                             li.className = "dropdown-submenu pull-left"; | ||||
|                             a = document.createElement("a"); | ||||
|                             a.href="#"; | ||||
|                             a.innerHTML = i; | ||||
|                             var label = i.replace(/^node-red-contrib-/,"").replace(/^node-red-node-/,"").replace(/-/," ").replace(/_/," "); | ||||
|                             a.innerHTML = label; | ||||
|                             li.appendChild(a); | ||||
|                             li.appendChild(buildMenu(data.d[i],root+(root!==""?"/":"")+i)); | ||||
|                             ul.appendChild(li); | ||||
| @@ -53,7 +56,7 @@ RED.library = (function() { | ||||
|                             a.flowName = root+(root!==""?"/":"")+data.f[i]; | ||||
|                             a.onclick = function() { | ||||
|                                 $.get('library/flows/'+this.flowName, function(data) { | ||||
|                                         RED.view.importNodes(data); | ||||
|                                     RED.view.importNodes(data); | ||||
|                                 }); | ||||
|                             }; | ||||
|                             li.appendChild(a); | ||||
| @@ -63,7 +66,17 @@ RED.library = (function() { | ||||
|                 } | ||||
|                 return ul; | ||||
|             }; | ||||
|             var examples; | ||||
|             if (data.d && data.d._examples_) { | ||||
|                 examples = data.d._examples_; | ||||
|                 delete data.d._examples_; | ||||
|             } | ||||
|             var menu = buildMenu(data,""); | ||||
|             $("#menu-item-import-examples").remove(); | ||||
|             if (examples) { | ||||
|                 RED.menu.addItem("menu-item-import",{id:"menu-item-import-examples",label:RED._("menu.label.examples"),options:[]}) | ||||
|                 $("#menu-item-import-examples-submenu").replaceWith(buildMenu(examples,"_examples_")); | ||||
|             } | ||||
|             //TODO: need an api in RED.menu for this | ||||
|             $("#menu-item-import-library-submenu").replaceWith(menu); | ||||
|         }); | ||||
| @@ -97,7 +110,7 @@ RED.library = (function() { | ||||
|         function buildFileList(root,data) { | ||||
|             var ul = document.createElement("ul"); | ||||
|             var li; | ||||
|             for (var i=0;i<data.length;i++) { | ||||
|             for (var i=0; i<data.length; i++) { | ||||
|                 var v = data[i]; | ||||
|                 if (typeof v === "string") { | ||||
|                     // directory | ||||
| @@ -117,7 +130,7 @@ RED.library = (function() { | ||||
|                             $(".active",bc).removeClass("active"); | ||||
|                             bc.append(bcli); | ||||
|                             $.getJSON("library/"+options.url+root+dirName,function(data) { | ||||
|                                     $("#node-select-library").children().first().replaceWith(buildFileList(root+dirName+"/",data)); | ||||
|                                 $("#node-select-library").children().first().replaceWith(buildFileList(root+dirName+"/",data)); | ||||
|                             }); | ||||
|                         } | ||||
|                     })(); | ||||
| @@ -125,26 +138,26 @@ RED.library = (function() { | ||||
|                     ul.appendChild(li); | ||||
|                 } else { | ||||
|                     // file | ||||
|                    li = buildFileListItem(v); | ||||
|                    li.innerHTML = v.name; | ||||
|                    li.onclick = (function() { | ||||
|                        var item = v; | ||||
|                        return function(e) { | ||||
|                            $(".list-selected",ul).removeClass("list-selected"); | ||||
|                            $(this).addClass("list-selected"); | ||||
|                            $.get("library/"+options.url+root+item.fn, function(data) { | ||||
|                                    selectedLibraryItem = item; | ||||
|                                    libraryEditor.setValue(data,-1); | ||||
|                            }); | ||||
|                        } | ||||
|                    })(); | ||||
|                    ul.appendChild(li); | ||||
|                     li = buildFileListItem(v); | ||||
|                     li.innerHTML = v.name; | ||||
|                     li.onclick = (function() { | ||||
|                         var item = v; | ||||
|                         return function(e) { | ||||
|                             $(".list-selected",ul).removeClass("list-selected"); | ||||
|                             $(this).addClass("list-selected"); | ||||
|                             $.get("library/"+options.url+root+item.fn, function(data) { | ||||
|                                 selectedLibraryItem = item; | ||||
|                                 libraryEditor.setValue(data,-1); | ||||
|                             }); | ||||
|                         } | ||||
|                     })(); | ||||
|                     ul.appendChild(li); | ||||
|                 } | ||||
|             } | ||||
|             return ul; | ||||
|         } | ||||
|  | ||||
|         $('#node-input-name').css("width","60%").after( | ||||
|         $('#node-input-name').css("width","66%").after( | ||||
|             '<div class="btn-group" style="margin-left: 5px;">'+ | ||||
|             '<a id="node-input-'+options.type+'-lookup" class="editor-button" data-toggle="dropdown"><i class="fa fa-book"></i> <i class="fa fa-caret-down"></i></a>'+ | ||||
|             '<ul class="dropdown-menu pull-right" role="menu">'+ | ||||
| @@ -153,8 +166,6 @@ RED.library = (function() { | ||||
|             '</ul></div>' | ||||
|         ); | ||||
|  | ||||
|  | ||||
|  | ||||
|         $('#node-input-'+options.type+'-menu-open-library').click(function(e) { | ||||
|             $("#node-select-library").children().remove(); | ||||
|             var bc = $("#node-dialog-library-breadcrumbs"); | ||||
| @@ -241,10 +252,17 @@ RED.library = (function() { | ||||
|             height: 450, | ||||
|             buttons: [ | ||||
|                 { | ||||
|                     text: RED._("common.label.ok"), | ||||
|                     text: RED._("common.label.cancel"), | ||||
|                     click: function() { | ||||
|                         $( this ).dialog( "close" ); | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     text: RED._("common.label.load"), | ||||
|                     class: "primary", | ||||
|                     click: function() { | ||||
|                         if (selectedLibraryItem) { | ||||
|                             for (var i=0;i<options.fields.length;i++) { | ||||
|                             for (var i=0; i<options.fields.length; i++) { | ||||
|                                 var field = options.fields[i]; | ||||
|                                 $("#node-input-"+field).val(selectedLibraryItem[field]); | ||||
|                             } | ||||
| @@ -252,12 +270,6 @@ RED.library = (function() { | ||||
|                         } | ||||
|                         $( this ).dialog( "close" ); | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     text: RED._("common.label.cancel"), | ||||
|                     click: function() { | ||||
|                         $( this ).dialog( "close" ); | ||||
|                     } | ||||
|                 } | ||||
|             ], | ||||
|             open: function(e) { | ||||
| @@ -313,7 +325,7 @@ RED.library = (function() { | ||||
|             } | ||||
|             var queryArgs = []; | ||||
|             var data = {}; | ||||
|             for (var i=0;i<options.fields.length;i++) { | ||||
|             for (var i=0; i<options.fields.length; i++) { | ||||
|                 var field = options.fields[i]; | ||||
|                 if (field == "name") { | ||||
|                     data.name = name; | ||||
| @@ -331,7 +343,11 @@ RED.library = (function() { | ||||
|             }).done(function(data,textStatus,xhr) { | ||||
|                 RED.notify(RED._("library.savedType", {type:options.type}),"success"); | ||||
|             }).fail(function(xhr,textStatus,err) { | ||||
|                 RED.notify(RED._("library.saveFailed",{message:xhr.responseText}),"error"); | ||||
|                 if (xhr.status === 401) { | ||||
|                     RED.notify(RED._("library.saveFailed",{message:RED._("user.notAuthorized")}),"error"); | ||||
|                 } else { | ||||
|                     RED.notify(RED._("library.saveFailed",{message:xhr.responseText}),"error"); | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|         $( "#node-dialog-library-save-confirm" ).dialog({ | ||||
| @@ -342,15 +358,16 @@ RED.library = (function() { | ||||
|             height: 230, | ||||
|             buttons: [ | ||||
|                 { | ||||
|                     text: RED._("common.label.ok"), | ||||
|                     text: RED._("common.label.cancel"), | ||||
|                     click: function() { | ||||
|                         saveToLibrary(true); | ||||
|                         $( this ).dialog( "close" ); | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     text: RED._("common.label.cancel"), | ||||
|                     text: RED._("common.label.save"), | ||||
|                     class: "primary", | ||||
|                     click: function() { | ||||
|                         saveToLibrary(true); | ||||
|                         $( this ).dialog( "close" ); | ||||
|                     } | ||||
|                 } | ||||
| @@ -364,15 +381,16 @@ RED.library = (function() { | ||||
|             height: 230, | ||||
|             buttons: [ | ||||
|                 { | ||||
|                     text: RED._("common.label.ok"), | ||||
|                     text: RED._("common.label.cancel"), | ||||
|                     click: function() { | ||||
|                         saveToLibrary(false); | ||||
|                         $( this ).dialog( "close" ); | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     text: RED._("common.label.cancel"), | ||||
|                     text: RED._("common.label.save"), | ||||
|                     class: "primary", | ||||
|                     click: function() { | ||||
|                         saveToLibrary(false); | ||||
|                         $( this ).dialog( "close" ); | ||||
|                     } | ||||
|                 } | ||||
| @@ -390,6 +408,9 @@ RED.library = (function() { | ||||
|  | ||||
|     return { | ||||
|         init: function() { | ||||
|  | ||||
|             RED.actions.add("core:library-export",exportFlow); | ||||
|  | ||||
|             RED.events.on("view:selection-changed",function(selection) { | ||||
|                 if (!selection.nodes) { | ||||
|                     RED.menu.setDisabled("menu-item-export",true); | ||||
| @@ -415,9 +436,17 @@ RED.library = (function() { | ||||
|                     resizable: false, | ||||
|                     title: RED._("library.exportToLibrary"), | ||||
|                     buttons: [ | ||||
|                         { | ||||
|                             id: "library-dialog-cancel", | ||||
|                             text: RED._("common.label.cancel"), | ||||
|                             click: function() { | ||||
|                                 $( this ).dialog( "close" ); | ||||
|                             } | ||||
|                         }, | ||||
|                         { | ||||
|                             id: "library-dialog-ok", | ||||
|                             text: RED._("common.label.ok"), | ||||
|                             class: "primary", | ||||
|                             text: RED._("common.label.export"), | ||||
|                             click: function() { | ||||
|                                 //TODO: move this to RED.library | ||||
|                                 var flowName = $("#node-input-library-filename").val(); | ||||
| @@ -428,31 +457,26 @@ RED.library = (function() { | ||||
|                                         data: $("#node-input-library-filename").attr('nodes'), | ||||
|                                         contentType: "application/json; charset=utf-8" | ||||
|                                     }).done(function() { | ||||
|                                             RED.library.loadFlowLibrary(); | ||||
|                                             RED.notify(RED._("library.savedNodes"),"success"); | ||||
|                                         RED.library.loadFlowLibrary(); | ||||
|                                         RED.notify(RED._("library.savedNodes"),"success"); | ||||
|                                     }).fail(function(xhr,textStatus,err) { | ||||
|                                         RED.notify(RED._("library.saveFailed",{message:xhr.responseText}),"error"); | ||||
|                                         if (xhr.status === 401) { | ||||
|                                             RED.notify(RED._("library.saveFailed",{message:RED._("user.notAuthorized")}),"error"); | ||||
|                                         } else { | ||||
|                                             RED.notify(RED._("library.saveFailed",{message:xhr.responseText}),"error"); | ||||
|                                         } | ||||
|                                     }); | ||||
|                                 } | ||||
|                                 $( this ).dialog( "close" ); | ||||
|                             } | ||||
|                         }, | ||||
|                         { | ||||
|                             id: "library-dialog-cancel", | ||||
|                             text: RED._("common.label.cancel"), | ||||
|                             click: function() { | ||||
|                                 $( this ).dialog( "close" ); | ||||
|                             } | ||||
|                         } | ||||
|                     ], | ||||
|                     open: function(e) { | ||||
|                         $(this).parent().find(".ui-dialog-titlebar-close").hide(); | ||||
|                         RED.keyboard.disable(); | ||||
|                     }, | ||||
|                     close: function(e) { | ||||
|                         RED.keyboard.enable(); | ||||
|                     } | ||||
|             }); | ||||
|                 }); | ||||
|             exportToLibraryDialog.children(".dialog-form").append($( | ||||
|                 '<div class="form-row">'+ | ||||
|                 '<label for="node-input-library-filename" data-i18n="[append]editor:library.filename"><i class="fa fa-file"></i> </label>'+ | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2013, 2016 IBM Corp. | ||||
|  * 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. | ||||
| @@ -36,7 +36,11 @@ RED.notify = (function() { | ||||
|             n.className = "notification notification-"+type; | ||||
|         } | ||||
|         n.style.display = "none"; | ||||
|         n.innerHTML = msg; | ||||
|         if (typeof msg === "string") { | ||||
|             n.innerHTML = msg; | ||||
|         } else { | ||||
|             $(n).append(msg); | ||||
|         } | ||||
|         $("#notifications").append(n); | ||||
|         $(n).slideDown(300); | ||||
|         n.close = (function() { | ||||
| @@ -48,6 +52,24 @@ RED.notify = (function() { | ||||
|                 }); | ||||
|             }; | ||||
|         })(); | ||||
|  | ||||
|         n.update = (function() { | ||||
|             var nn = n; | ||||
|             return function(msg,timeout) { | ||||
|                 if (typeof msg === "string") { | ||||
|                     nn.innerHTML = msg; | ||||
|                 } else { | ||||
|                     $(nn).empty().append(msg); | ||||
|                 } | ||||
|                 if (timeout !== undefined && timeout > 0) { | ||||
|                     window.clearTimeout(nn.timeoutid); | ||||
|                     nn.timeoutid = window.setTimeout(nn.close,timeout); | ||||
|                 } else { | ||||
|                     window.clearTimeout(nn.timeoutid); | ||||
|                 } | ||||
|             } | ||||
|         })(); | ||||
|  | ||||
|         if (!fixed) { | ||||
|             $(n).click((function() { | ||||
|                 var nn = n; | ||||
|   | ||||
							
								
								
									
										956
									
								
								editor/js/ui/palette-editor.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,956 @@ | ||||
| /** | ||||
|  * 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.palette.editor = (function() { | ||||
|  | ||||
|     var disabled = false; | ||||
|  | ||||
|     var editorTabs; | ||||
|     var filterInput; | ||||
|     var searchInput; | ||||
|     var nodeList; | ||||
|     var packageList; | ||||
|     var loadedList = []; | ||||
|     var filteredList = []; | ||||
|     var loadedIndex = {}; | ||||
|  | ||||
|     var typesInUse = {}; | ||||
|     var nodeEntries = {}; | ||||
|     var eventTimers = {}; | ||||
|     var activeFilter = ""; | ||||
|  | ||||
|     function semVerCompare(A,B) { | ||||
|         var aParts = A.split(".").map(function(m) { return parseInt(m);}); | ||||
|         var bParts = B.split(".").map(function(m) { return parseInt(m);}); | ||||
|         for (var i=0;i<3;i++) { | ||||
|             var j = aParts[i]-bParts[i]; | ||||
|             if (j<0) { return -1 } | ||||
|             if (j>0) { return 1 } | ||||
|         } | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     function delayCallback(start,callback) { | ||||
|         var delta = Date.now() - start; | ||||
|         if (delta < 300) { | ||||
|             delta = 300; | ||||
|         } else { | ||||
|             delta = 0; | ||||
|         } | ||||
|         setTimeout(function() { | ||||
|             callback(); | ||||
|         },delta); | ||||
|     } | ||||
|     function changeNodeState(id,state,shade,callback) { | ||||
|         shade.show(); | ||||
|         var start = Date.now(); | ||||
|         $.ajax({ | ||||
|             url:"nodes/"+id, | ||||
|             type: "PUT", | ||||
|             data: JSON.stringify({ | ||||
|                 enabled: state | ||||
|             }), | ||||
|             contentType: "application/json; charset=utf-8" | ||||
|         }).done(function(data,textStatus,xhr) { | ||||
|             delayCallback(start,function() { | ||||
|                 shade.hide(); | ||||
|                 callback(); | ||||
|             }); | ||||
|         }).fail(function(xhr,textStatus,err) { | ||||
|             delayCallback(start,function() { | ||||
|                 shade.hide(); | ||||
|                 callback(xhr); | ||||
|             }); | ||||
|         }) | ||||
|     } | ||||
|     function installNodeModule(id,version,shade,callback) { | ||||
|         var requestBody = { | ||||
|             module: id | ||||
|         }; | ||||
|         if (callback === undefined) { | ||||
|             callback = shade; | ||||
|             shade = version; | ||||
|         } else { | ||||
|             requestBody.version = version; | ||||
|         } | ||||
|         shade.show(); | ||||
|         $.ajax({ | ||||
|             url:"nodes", | ||||
|             type: "POST", | ||||
|             data: JSON.stringify(requestBody), | ||||
|             contentType: "application/json; charset=utf-8" | ||||
|         }).done(function(data,textStatus,xhr) { | ||||
|             shade.hide(); | ||||
|             callback(); | ||||
|         }).fail(function(xhr,textStatus,err) { | ||||
|             shade.hide(); | ||||
|             callback(xhr); | ||||
|         }); | ||||
|     } | ||||
|     function removeNodeModule(id,callback) { | ||||
|         $.ajax({ | ||||
|             url:"nodes/"+id, | ||||
|             type: "DELETE" | ||||
|         }).done(function(data,textStatus,xhr) { | ||||
|             callback(); | ||||
|         }).fail(function(xhr,textStatus,err) { | ||||
|             callback(xhr); | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     function refreshNodeModuleList() { | ||||
|         for (var id in nodeEntries) { | ||||
|             if (nodeEntries.hasOwnProperty(id)) { | ||||
|                 _refreshNodeModule(id); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function refreshNodeModule(module) { | ||||
|         if (!eventTimers.hasOwnProperty(module)) { | ||||
|             eventTimers[module] = setTimeout(function() { | ||||
|                 delete eventTimers[module]; | ||||
|                 _refreshNodeModule(module); | ||||
|             },100); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     function getContrastingBorder(rgbColor){ | ||||
|         var parts = /^rgba?\(\s*(\d+),\s*(\d+),\s*(\d+)[,)]/.exec(rgbColor); | ||||
|         if (parts) { | ||||
|             var r = parseInt(parts[1]); | ||||
|             var g = parseInt(parts[2]); | ||||
|             var b = parseInt(parts[3]); | ||||
|             var yiq = ((r*299)+(g*587)+(b*114))/1000; | ||||
|             if (yiq > 160) { | ||||
|                 r = Math.floor(r*0.8); | ||||
|                 g = Math.floor(g*0.8); | ||||
|                 b = Math.floor(b*0.8); | ||||
|                 return "rgb("+r+","+g+","+b+")"; | ||||
|             } | ||||
|         } | ||||
|         return rgbColor; | ||||
|     } | ||||
|  | ||||
|     function formatUpdatedAt(dateString) { | ||||
|         var now = new Date(); | ||||
|         var d = new Date(dateString); | ||||
|         var delta = (Date.now() - new Date(dateString).getTime())/1000; | ||||
|  | ||||
|         if (delta < 60) { | ||||
|             return RED._('palette.editor.times.seconds'); | ||||
|         } | ||||
|         delta = Math.floor(delta/60); | ||||
|         if (delta < 10) { | ||||
|             return RED._('palette.editor.times.minutes'); | ||||
|         } | ||||
|         if (delta < 60) { | ||||
|             return RED._('palette.editor.times.minutesV',{count:delta}); | ||||
|         } | ||||
|  | ||||
|         delta = Math.floor(delta/60); | ||||
|  | ||||
|         if (delta < 24) { | ||||
|             return RED._('palette.editor.times.hoursV',{count:delta}); | ||||
|         } | ||||
|  | ||||
|         delta = Math.floor(delta/24); | ||||
|  | ||||
|         if (delta < 7) { | ||||
|             return RED._('palette.editor.times.daysV',{count:delta}) | ||||
|         } | ||||
|         var weeks = Math.floor(delta/7); | ||||
|         var days = delta%7; | ||||
|  | ||||
|         if (weeks < 4) { | ||||
|             return RED._('palette.editor.times.weeksV',{count:weeks}) | ||||
|         } | ||||
|  | ||||
|         var months = Math.floor(weeks/4); | ||||
|         weeks = weeks%4; | ||||
|  | ||||
|         if (months < 12) { | ||||
|             return RED._('palette.editor.times.monthsV',{count:months}) | ||||
|         } | ||||
|         var years = Math.floor(months/12); | ||||
|         months = months%12; | ||||
|  | ||||
|         if (months === 0) { | ||||
|             return RED._('palette.editor.times.yearsV',{count:years}) | ||||
|         } else { | ||||
|             return RED._('palette.editor.times.year'+(years>1?'s':'')+'MonthsV',{y:years,count:months}) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     function _refreshNodeModule(module) { | ||||
|         if (!nodeEntries.hasOwnProperty(module)) { | ||||
|             nodeEntries[module] = {info:RED.nodes.registry.getModule(module)}; | ||||
|             var index = [module]; | ||||
|             for (var s in nodeEntries[module].info.sets) { | ||||
|                 if (nodeEntries[module].info.sets.hasOwnProperty(s)) { | ||||
|                     index.push(s); | ||||
|                     index = index.concat(nodeEntries[module].info.sets[s].types) | ||||
|                 } | ||||
|             } | ||||
|             nodeEntries[module].index = index.join(",").toLowerCase(); | ||||
|             nodeList.editableList('addItem', nodeEntries[module]); | ||||
|         } else { | ||||
|             var moduleInfo = nodeEntries[module].info; | ||||
|             var nodeEntry = nodeEntries[module].elements; | ||||
|             if (nodeEntry) { | ||||
|                 var activeTypeCount = 0; | ||||
|                 var typeCount = 0; | ||||
|                 nodeEntries[module].totalUseCount = 0; | ||||
|                 nodeEntries[module].setUseCount = {}; | ||||
|  | ||||
|                 for (var setName in moduleInfo.sets) { | ||||
|                     if (moduleInfo.sets.hasOwnProperty(setName)) { | ||||
|                         var inUseCount = 0; | ||||
|                         var set = moduleInfo.sets[setName]; | ||||
|                         var setElements = nodeEntry.sets[setName]; | ||||
|  | ||||
|                         if (set.enabled) { | ||||
|                             activeTypeCount += set.types.length; | ||||
|                         } | ||||
|                         typeCount += set.types.length; | ||||
|                         for (var i=0;i<moduleInfo.sets[setName].types.length;i++) { | ||||
|                             var t = moduleInfo.sets[setName].types[i]; | ||||
|                             inUseCount += (typesInUse[t]||0); | ||||
|                             var swatch = setElements.swatches[t]; | ||||
|                             if (set.enabled) { | ||||
|                                 var def = RED.nodes.getType(t); | ||||
|                                 if (def && def.color) { | ||||
|                                     swatch.css({background:def.color}); | ||||
|                                     swatch.css({border: "1px solid "+getContrastingBorder(swatch.css('backgroundColor'))}) | ||||
|  | ||||
|                                 } else { | ||||
|                                     swatch.css({background:"#eee",border:"1px dashed #999"}) | ||||
|                                 } | ||||
|                             } else { | ||||
|                                 swatch.css({background:"#eee",border:"1px dashed #999"}) | ||||
|                             } | ||||
|                         } | ||||
|                         nodeEntries[module].setUseCount[setName] = inUseCount; | ||||
|                         nodeEntries[module].totalUseCount += inUseCount; | ||||
|  | ||||
|                         if (inUseCount > 0) { | ||||
|                             setElements.enableButton.html(RED._('palette.editor.inuse')); | ||||
|                             setElements.enableButton.addClass('disabled'); | ||||
|                         } else { | ||||
|                             setElements.enableButton.removeClass('disabled'); | ||||
|                             if (set.enabled) { | ||||
|                                 setElements.enableButton.html(RED._('palette.editor.disable')); | ||||
|                             } else { | ||||
|                                 setElements.enableButton.html(RED._('palette.editor.enable')); | ||||
|                             } | ||||
|                         } | ||||
|                         setElements.setRow.toggleClass("palette-module-set-disabled",!set.enabled); | ||||
|                     } | ||||
|                 } | ||||
|                 var nodeCount = (activeTypeCount === typeCount)?typeCount:activeTypeCount+" / "+typeCount; | ||||
|                 nodeEntry.setCount.html(RED._('palette.editor.nodeCount',{count:typeCount,label:nodeCount})); | ||||
|  | ||||
|                 if (nodeEntries[module].totalUseCount > 0) { | ||||
|                     nodeEntry.enableButton.html(RED._('palette.editor.inuse')); | ||||
|                     nodeEntry.enableButton.addClass('disabled'); | ||||
|                     nodeEntry.removeButton.hide(); | ||||
|                 } else { | ||||
|                     nodeEntry.enableButton.removeClass('disabled'); | ||||
|                     if (moduleInfo.local) { | ||||
|                         nodeEntry.removeButton.css('display', 'inline-block'); | ||||
|                     } | ||||
|                     if (activeTypeCount === 0) { | ||||
|                         nodeEntry.enableButton.html(RED._('palette.editor.enableall')); | ||||
|                     } else { | ||||
|                         nodeEntry.enableButton.html(RED._('palette.editor.disableall')); | ||||
|                     } | ||||
|                     nodeEntry.container.toggleClass("disabled",(activeTypeCount === 0)); | ||||
|                 } | ||||
|             } | ||||
|             if (moduleInfo.pending_version) { | ||||
|                 nodeEntry.versionSpan.html(moduleInfo.version+' <i class="fa fa-long-arrow-right"></i> '+moduleInfo.pending_version).appendTo(nodeEntry.metaRow) | ||||
|                 nodeEntry.updateButton.html(RED._('palette.editor.updated')).addClass('disabled').show(); | ||||
|             } else if (loadedIndex.hasOwnProperty(module)) { | ||||
|                 if (semVerCompare(loadedIndex[module].version,moduleInfo.version) === 1) { | ||||
|                     nodeEntry.updateButton.show(); | ||||
|                     nodeEntry.updateButton.html(RED._('palette.editor.update',{version:loadedIndex[module].version})); | ||||
|                 } else { | ||||
|                     nodeEntry.updateButton.hide(); | ||||
|                 } | ||||
|             } else { | ||||
|                 nodeEntry.updateButton.hide(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     function filterChange(val) { | ||||
|         activeFilter = val.toLowerCase(); | ||||
|         var visible = nodeList.editableList('filter'); | ||||
|         var size = nodeList.editableList('length'); | ||||
|         if (val === "") { | ||||
|             filterInput.searchBox('count'); | ||||
|         } else { | ||||
|             filterInput.searchBox('count',visible+" / "+size); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     var catalogueCount; | ||||
|     var catalogueLoadStatus = []; | ||||
|     var catalogueLoadStart; | ||||
|     var catalogueLoadErrors = false; | ||||
|  | ||||
|     var activeSort = sortModulesAZ; | ||||
|  | ||||
|     function handleCatalogResponse(err,catalog,index,v) { | ||||
|         catalogueLoadStatus.push(err||v); | ||||
|         if (!err) { | ||||
|             if (v.modules) { | ||||
|                 v.modules.forEach(function(m) { | ||||
|                     loadedIndex[m.id] = m; | ||||
|                     m.index = [m.id]; | ||||
|                     if (m.keywords) { | ||||
|                         m.index = m.index.concat(m.keywords); | ||||
|                     } | ||||
|                     if (m.updated_at) { | ||||
|                         m.timestamp = new Date(m.updated_at).getTime(); | ||||
|                     } else { | ||||
|                         m.timestamp = 0; | ||||
|                     } | ||||
|                     m.index = m.index.join(",").toLowerCase(); | ||||
|                 }) | ||||
|                 loadedList = loadedList.concat(v.modules); | ||||
|             } | ||||
|             searchInput.searchBox('count',loadedList.length); | ||||
|         } else { | ||||
|             catalogueLoadErrors = true; | ||||
|         } | ||||
|         if (catalogueCount > 1) { | ||||
|             $(".palette-module-shade-status").html(RED._('palette.editor.loading')+"<br>"+catalogueLoadStatus.length+"/"+catalogueCount); | ||||
|         } | ||||
|         if (catalogueLoadStatus.length === catalogueCount) { | ||||
|             if (catalogueLoadErrors) { | ||||
|                 RED.notify(RED._('palette.editor.errors.catalogLoadFailed',{url: catalog}),"error",false,8000); | ||||
|             } | ||||
|             var delta = 250-(Date.now() - catalogueLoadStart); | ||||
|             setTimeout(function() { | ||||
|                 $("#palette-module-install-shade").hide(); | ||||
|             },Math.max(delta,0)); | ||||
|  | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function initInstallTab() { | ||||
|         if (loadedList.length === 0) { | ||||
|             loadedList = []; | ||||
|             loadedIndex = {}; | ||||
|             packageList.editableList('empty'); | ||||
|  | ||||
|             $(".palette-module-shade-status").html(RED._('palette.editor.loading')); | ||||
|             var catalogues = RED.settings.theme('palette.catalogues')||['https://catalogue.nodered.org/catalogue.json']; | ||||
|             catalogueLoadStatus = []; | ||||
|             catalogueLoadErrors = false; | ||||
|             catalogueCount = catalogues.length; | ||||
|             if (catalogues.length > 1) { | ||||
|                 $(".palette-module-shade-status").html(RED._('palette.editor.loading')+"<br>0/"+catalogues.length); | ||||
|             } | ||||
|             $("#palette-module-install-shade").show(); | ||||
|             catalogueLoadStart = Date.now(); | ||||
|             var handled = 0; | ||||
|             catalogues.forEach(function(catalog,index) { | ||||
|                 $.getJSON(catalog, {_: new Date().getTime()},function(v) { | ||||
|                     handleCatalogResponse(null,catalog,index,v); | ||||
|                     refreshNodeModuleList(); | ||||
|                 }).fail(function(jqxhr, textStatus, error) { | ||||
|                     handleCatalogResponse(jqxhr,catalog,index); | ||||
|                 }).always(function() { | ||||
|                     handled++; | ||||
|                     if (handled === catalogueCount) { | ||||
|                         searchInput.searchBox('change'); | ||||
|                     } | ||||
|                 }) | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function refreshFilteredItems() { | ||||
|         packageList.editableList('empty'); | ||||
|         var currentFilter = searchInput.searchBox('value').trim(); | ||||
|         if (currentFilter === ""){ | ||||
|             packageList.editableList('addItem',{count:loadedList.length}) | ||||
|             return; | ||||
|         } | ||||
|         filteredList.sort(activeSort); | ||||
|         for (var i=0;i<Math.min(10,filteredList.length);i++) { | ||||
|             packageList.editableList('addItem',filteredList[i]); | ||||
|         } | ||||
|         if (filteredList.length === 0) { | ||||
|             packageList.editableList('addItem',{}); | ||||
|         } | ||||
|  | ||||
|         if (filteredList.length > 10) { | ||||
|             packageList.editableList('addItem',{start:10,more:filteredList.length-10}) | ||||
|         } | ||||
|     } | ||||
|     function sortModulesAZ(A,B) { | ||||
|         return A.info.id.localeCompare(B.info.id); | ||||
|     } | ||||
|     function sortModulesRecent(A,B) { | ||||
|         return -1 * (A.info.timestamp-B.info.timestamp); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     function init() { | ||||
|         if (RED.settings.theme('palette.editable') === false) { | ||||
|             return; | ||||
|         } | ||||
|         createSettingsPane(); | ||||
|  | ||||
|         RED.userSettings.add({ | ||||
|             id:'palette', | ||||
|             title: 'Palette', | ||||
|             get: getSettingsPane, | ||||
|             close: function() { | ||||
|                 settingsPane.detach(); | ||||
|             }, | ||||
|             focus: function() { | ||||
|                 editorTabs.resize(); | ||||
|                 setTimeout(function() { | ||||
|                     filterInput.focus(); | ||||
|                 },200); | ||||
|             } | ||||
|         }) | ||||
|  | ||||
|         RED.actions.add("core:manage-palette",function() { | ||||
|                 RED.userSettings.show('palette'); | ||||
|             }); | ||||
|  | ||||
|         RED.events.on('registry:module-updated', function(ns) { | ||||
|             refreshNodeModule(ns.module); | ||||
|         }); | ||||
|         RED.events.on('registry:node-set-enabled', function(ns) { | ||||
|             refreshNodeModule(ns.module); | ||||
|         }); | ||||
|         RED.events.on('registry:node-set-disabled', function(ns) { | ||||
|             refreshNodeModule(ns.module); | ||||
|         }); | ||||
|         RED.events.on('registry:node-type-added', function(nodeType) { | ||||
|             if (!/^subflow:/.test(nodeType)) { | ||||
|                 var ns = RED.nodes.registry.getNodeSetForType(nodeType); | ||||
|                 refreshNodeModule(ns.module); | ||||
|             } | ||||
|         }); | ||||
|         RED.events.on('registry:node-type-removed', function(nodeType) { | ||||
|             if (!/^subflow:/.test(nodeType)) { | ||||
|                 var ns = RED.nodes.registry.getNodeSetForType(nodeType); | ||||
|                 refreshNodeModule(ns.module); | ||||
|             } | ||||
|         }); | ||||
|         RED.events.on('registry:node-set-added', function(ns) { | ||||
|             refreshNodeModule(ns.module); | ||||
|             for (var i=0;i<filteredList.length;i++) { | ||||
|                 if (filteredList[i].info.id === ns.module) { | ||||
|                     var installButton = filteredList[i].elements.installButton; | ||||
|                     installButton.addClass('disabled'); | ||||
|                     installButton.html(RED._('palette.editor.installed')); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|         RED.events.on('registry:node-set-removed', function(ns) { | ||||
|             var module = RED.nodes.registry.getModule(ns.module); | ||||
|             if (!module) { | ||||
|                 var entry = nodeEntries[ns.module]; | ||||
|                 if (entry) { | ||||
|                     nodeList.editableList('removeItem', entry); | ||||
|                     delete nodeEntries[ns.module]; | ||||
|                     for (var i=0;i<filteredList.length;i++) { | ||||
|                         if (filteredList[i].info.id === ns.module) { | ||||
|                             var installButton = filteredList[i].elements.installButton; | ||||
|                             installButton.removeClass('disabled'); | ||||
|                             installButton.html(RED._('palette.editor.install')); | ||||
|                             break; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|         RED.events.on('nodes:add', function(n) { | ||||
|             if (!/^subflow:/.test(n.type)) { | ||||
|                 typesInUse[n.type] = (typesInUse[n.type]||0)+1; | ||||
|                 if (typesInUse[n.type] === 1) { | ||||
|                     var ns = RED.nodes.registry.getNodeSetForType(n.type); | ||||
|                     refreshNodeModule(ns.module); | ||||
|                 } | ||||
|             } | ||||
|         }) | ||||
|         RED.events.on('nodes:remove', function(n) { | ||||
|             if (typesInUse.hasOwnProperty(n.type)) { | ||||
|                 typesInUse[n.type]--; | ||||
|                 if (typesInUse[n.type] === 0) { | ||||
|                     delete typesInUse[n.type]; | ||||
|                     var ns = RED.nodes.registry.getNodeSetForType(n.type); | ||||
|                     refreshNodeModule(ns.module); | ||||
|                 } | ||||
|             } | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     var settingsPane; | ||||
|  | ||||
|     function getSettingsPane() { | ||||
|         initInstallTab(); | ||||
|         editorTabs.activateTab('nodes'); | ||||
|         return settingsPane; | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     function createSettingsPane() { | ||||
|         settingsPane = $('<div id="user-settings-tab-palette"></div>'); | ||||
|         var content = $('<div id="palette-editor">'+ | ||||
|             '<ul id="palette-editor-tabs"></ul>'+ | ||||
|         '</div>').appendTo(settingsPane); | ||||
|  | ||||
|         editorTabs = RED.tabs.create({ | ||||
|             element: settingsPane.find('#palette-editor-tabs'), | ||||
|             onchange:function(tab) { | ||||
|                 content.find(".palette-editor-tab").hide(); | ||||
|                 tab.content.show(); | ||||
|                 if (filterInput) { | ||||
|                     filterInput.searchBox('value',""); | ||||
|                 } | ||||
|                 if (searchInput) { | ||||
|                     searchInput.searchBox('value',""); | ||||
|                 } | ||||
|                 if (tab.id === 'install') { | ||||
|                     if (searchInput) { | ||||
|                         searchInput.focus(); | ||||
|                     } | ||||
|                 } else { | ||||
|                     if (filterInput) { | ||||
|                         filterInput.focus(); | ||||
|                     } | ||||
|                 } | ||||
|             }, | ||||
|             minimumActiveTabWidth: 110 | ||||
|         }); | ||||
|  | ||||
|  | ||||
|         var modulesTab = $('<div>',{class:"palette-editor-tab"}).appendTo(content); | ||||
|  | ||||
|         editorTabs.addTab({ | ||||
|             id: 'nodes', | ||||
|             label: RED._('palette.editor.tab-nodes'), | ||||
|             content: modulesTab | ||||
|         }) | ||||
|  | ||||
|         var filterDiv = $('<div>',{class:"palette-search"}).appendTo(modulesTab); | ||||
|         filterInput = $('<input type="text" data-i18n="[placeholder]palette.filter"></input>') | ||||
|             .appendTo(filterDiv) | ||||
|             .searchBox({ | ||||
|                 delay: 200, | ||||
|                 change: function() { | ||||
|                     filterChange($(this).val()); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|  | ||||
|         nodeList = $('<ol>',{id:"palette-module-list", style:"position: absolute;top: 35px;bottom: 0;left: 0;right: 0px;"}).appendTo(modulesTab).editableList({ | ||||
|             addButton: false, | ||||
|             scrollOnAdd: false, | ||||
|             sort: function(A,B) { | ||||
|                 return A.info.name.localeCompare(B.info.name); | ||||
|             }, | ||||
|             filter: function(data) { | ||||
|                 if (activeFilter === "" ) { | ||||
|                     return true; | ||||
|                 } | ||||
|  | ||||
|                 return (activeFilter==="")||(data.index.indexOf(activeFilter) > -1); | ||||
|             }, | ||||
|             addItem: function(container,i,object) { | ||||
|                 var entry = object.info; | ||||
|                 if (entry) { | ||||
|                     var headerRow = $('<div>',{class:"palette-module-header"}).appendTo(container); | ||||
|                     var titleRow = $('<div class="palette-module-meta palette-module-name"><i class="fa fa-cube"></i></div>').appendTo(headerRow); | ||||
|                     $('<span>').html(entry.name).appendTo(titleRow); | ||||
|                     var metaRow = $('<div class="palette-module-meta palette-module-version"><i class="fa fa-tag"></i></div>').appendTo(headerRow); | ||||
|                     var versionSpan = $('<span>').html(entry.version).appendTo(metaRow); | ||||
|                     var buttonRow = $('<div>',{class:"palette-module-meta"}).appendTo(headerRow); | ||||
|                     var setButton = $('<a href="#" class="editor-button editor-button-small palette-module-set-button"><i class="fa fa-angle-right palette-module-node-chevron"></i> </a>').appendTo(buttonRow); | ||||
|                     var setCount = $('<span>').appendTo(setButton); | ||||
|                     var buttonGroup = $('<div>',{class:"palette-module-button-group"}).appendTo(buttonRow); | ||||
|  | ||||
|                     var updateButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.update')).appendTo(buttonGroup); | ||||
|                     updateButton.attr('id','up_'+Math.floor(Math.random()*1000000000)); | ||||
|                     updateButton.click(function(evt) { | ||||
|                         evt.preventDefault(); | ||||
|                         if ($(this).hasClass('disabled')) { | ||||
|                             return; | ||||
|                         } | ||||
|                         $("#palette-module-install-confirm").data('module',entry.name); | ||||
|                         $("#palette-module-install-confirm").data('version',loadedIndex[entry.name].version); | ||||
|                         $("#palette-module-install-confirm").data('shade',shade); | ||||
|  | ||||
|                         $("#palette-module-install-confirm-body").html(entry.local? | ||||
|                             RED._("palette.editor.confirm.update.body"): | ||||
|                             RED._("palette.editor.confirm.cannotUpdate.body") | ||||
|                         ); | ||||
|                         $(".palette-module-install-confirm-button-install").hide(); | ||||
|                         $(".palette-module-install-confirm-button-remove").hide(); | ||||
|                         if (entry.local) { | ||||
|                             $(".palette-module-install-confirm-button-update").show(); | ||||
|                         } else { | ||||
|                             $(".palette-module-install-confirm-button-update").hide(); | ||||
|                         } | ||||
|                         $("#palette-module-install-confirm") | ||||
|                             .dialog('option', 'title',RED._("palette.editor.confirm.update.title")) | ||||
|                             .dialog('open'); | ||||
|                     }) | ||||
|  | ||||
|  | ||||
|                     var removeButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.remove')).appendTo(buttonGroup); | ||||
|                     removeButton.attr('id','up_'+Math.floor(Math.random()*1000000000)); | ||||
|                     removeButton.click(function(evt) { | ||||
|                         evt.preventDefault(); | ||||
|  | ||||
|                         $("#palette-module-install-confirm").data('module',entry.name); | ||||
|                         $("#palette-module-install-confirm").data('shade',shade); | ||||
|                         $("#palette-module-install-confirm-body").html(RED._("palette.editor.confirm.remove.body")); | ||||
|                         $(".palette-module-install-confirm-button-install").hide(); | ||||
|                         $(".palette-module-install-confirm-button-remove").show(); | ||||
|                         $(".palette-module-install-confirm-button-update").hide(); | ||||
|                         $("#palette-module-install-confirm") | ||||
|                             .dialog('option', 'title', RED._("palette.editor.confirm.remove.title")) | ||||
|                             .dialog('open'); | ||||
|                     }) | ||||
|                     if (!entry.local) { | ||||
|                         removeButton.hide(); | ||||
|                     } | ||||
|                     var enableButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.disableall')).appendTo(buttonGroup); | ||||
|  | ||||
|                     var contentRow = $('<div>',{class:"palette-module-content"}).appendTo(container); | ||||
|                     var shade = $('<div class="palette-module-shade hide"><img src="red/images/spin.svg" class="palette-spinner"/></div>').appendTo(container); | ||||
|  | ||||
|                     object.elements = { | ||||
|                         updateButton: updateButton, | ||||
|                         removeButton: removeButton, | ||||
|                         enableButton: enableButton, | ||||
|                         setCount: setCount, | ||||
|                         container: container, | ||||
|                         shade: shade, | ||||
|                         versionSpan: versionSpan, | ||||
|                         sets: {} | ||||
|                     } | ||||
|                     setButton.click(function(evt) { | ||||
|                         evt.preventDefault(); | ||||
|                         if (container.hasClass('expanded')) { | ||||
|                             container.removeClass('expanded'); | ||||
|                             contentRow.slideUp(); | ||||
|                         } else { | ||||
|                             container.addClass('expanded'); | ||||
|                             contentRow.slideDown(); | ||||
|                         } | ||||
|                     }) | ||||
|  | ||||
|                     var setList = Object.keys(entry.sets) | ||||
|                     setList.sort(function(A,B) { | ||||
|                         return A.toLowerCase().localeCompare(B.toLowerCase()); | ||||
|                     }); | ||||
|                     setList.forEach(function(setName) { | ||||
|                         var set = entry.sets[setName]; | ||||
|                         var setRow = $('<div>',{class:"palette-module-set"}).appendTo(contentRow); | ||||
|                         var buttonGroup = $('<div>',{class:"palette-module-set-button-group"}).appendTo(setRow); | ||||
|                         var typeSwatches = {}; | ||||
|                         set.types.forEach(function(t) { | ||||
|                             var typeDiv = $('<div>',{class:"palette-module-type"}).appendTo(setRow); | ||||
|                             typeSwatches[t] = $('<span>',{class:"palette-module-type-swatch"}).appendTo(typeDiv); | ||||
|                             $('<span>',{class:"palette-module-type-node"}).html(t).appendTo(typeDiv); | ||||
|                         }) | ||||
|  | ||||
|                         var enableButton = $('<a href="#" class="editor-button editor-button-small"></a>').appendTo(buttonGroup); | ||||
|                         enableButton.click(function(evt) { | ||||
|                             evt.preventDefault(); | ||||
|                             if (object.setUseCount[setName] === 0) { | ||||
|                                 var currentSet = RED.nodes.registry.getNodeSet(set.id); | ||||
|                                 shade.show(); | ||||
|                                 var newState = !currentSet.enabled | ||||
|                                 changeNodeState(set.id,newState,shade,function(xhr){ | ||||
|                                     if (xhr) { | ||||
|                                         if (xhr.responseJSON) { | ||||
|                                             RED.notify(RED._('palette.editor.errors.'+(newState?'enable':'disable')+'Failed',{module: id,message:xhr.responseJSON.message})); | ||||
|                                         } | ||||
|                                     } | ||||
|                                 }); | ||||
|                             } | ||||
|                         }) | ||||
|  | ||||
|                         object.elements.sets[set.name] = { | ||||
|                             setRow: setRow, | ||||
|                             enableButton: enableButton, | ||||
|                             swatches: typeSwatches | ||||
|                         }; | ||||
|                     }); | ||||
|                     enableButton.click(function(evt) { | ||||
|                         evt.preventDefault(); | ||||
|                         if (object.totalUseCount === 0) { | ||||
|                             changeNodeState(entry.name,(container.hasClass('disabled')),shade,function(xhr){ | ||||
|                                 if (xhr) { | ||||
|                                     if (xhr.responseJSON) { | ||||
|                                         RED.notify(RED._('palette.editor.errors.installFailed',{module: id,message:xhr.responseJSON.message})); | ||||
|                                     } | ||||
|                                 } | ||||
|                             }); | ||||
|                         } | ||||
|                     }) | ||||
|                     refreshNodeModule(entry.name); | ||||
|                 } else { | ||||
|                     $('<div>',{class:"red-ui-search-empty"}).html(RED._('search.empty')).appendTo(container); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|  | ||||
|  | ||||
|         var installTab = $('<div>',{class:"palette-editor-tab hide"}).appendTo(content); | ||||
|  | ||||
|         editorTabs.addTab({ | ||||
|             id: 'install', | ||||
|             label: RED._('palette.editor.tab-install'), | ||||
|             content: installTab | ||||
|         }) | ||||
|  | ||||
|         var toolBar = $('<div>',{class:"palette-editor-toolbar"}).appendTo(installTab); | ||||
|  | ||||
|         var searchDiv = $('<div>',{class:"palette-search"}).appendTo(installTab); | ||||
|         searchInput = $('<input type="text" data-i18n="[placeholder]palette.search"></input>') | ||||
|             .appendTo(searchDiv) | ||||
|             .searchBox({ | ||||
|                 delay: 300, | ||||
|                 change: function() { | ||||
|                     var searchTerm = $(this).val().trim().toLowerCase(); | ||||
|                     if (searchTerm.length > 0) { | ||||
|                         filteredList = loadedList.filter(function(m) { | ||||
|                             return (m.index.indexOf(searchTerm) > -1); | ||||
|                         }).map(function(f) { return {info:f}}); | ||||
|                         refreshFilteredItems(); | ||||
|                         searchInput.searchBox('count',filteredList.length+" / "+loadedList.length); | ||||
|                     } else { | ||||
|                         searchInput.searchBox('count',loadedList.length); | ||||
|                         packageList.editableList('empty'); | ||||
|                         packageList.editableList('addItem',{count:loadedList.length}); | ||||
|  | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|  | ||||
|         $('<span>').html(RED._("palette.editor.sort")+' ').appendTo(toolBar); | ||||
|         var sortGroup = $('<span class="button-group"></span>').appendTo(toolBar); | ||||
|         var sortAZ = $('<a href="#" class="sidebar-header-button-toggle selected" data-i18n="palette.editor.sortAZ"></a>').appendTo(sortGroup); | ||||
|         var sortRecent = $('<a href="#" class="sidebar-header-button-toggle" data-i18n="palette.editor.sortRecent"></a>').appendTo(sortGroup); | ||||
|  | ||||
|         sortAZ.click(function(e) { | ||||
|             e.preventDefault(); | ||||
|             if ($(this).hasClass("selected")) { | ||||
|                 return; | ||||
|             } | ||||
|             $(this).addClass("selected"); | ||||
|             sortRecent.removeClass("selected"); | ||||
|             activeSort = sortModulesAZ; | ||||
|             refreshFilteredItems(); | ||||
|         }); | ||||
|  | ||||
|         sortRecent.click(function(e) { | ||||
|             e.preventDefault(); | ||||
|             if ($(this).hasClass("selected")) { | ||||
|                 return; | ||||
|             } | ||||
|             $(this).addClass("selected"); | ||||
|             sortAZ.removeClass("selected"); | ||||
|             activeSort = sortModulesRecent; | ||||
|             refreshFilteredItems(); | ||||
|         }); | ||||
|  | ||||
|  | ||||
|         var refreshSpan = $('<span>').appendTo(toolBar); | ||||
|         var refreshButton = $('<a href="#" class="sidebar-header-button"><i class="fa fa-refresh"></i></a>').appendTo(refreshSpan); | ||||
|         refreshButton.click(function(e) { | ||||
|             e.preventDefault(); | ||||
|             loadedList = []; | ||||
|             loadedIndex = {}; | ||||
|             initInstallTab(); | ||||
|         }) | ||||
|  | ||||
|         packageList = $('<ol>',{style:"position: absolute;top: 78px;bottom: 0;left: 0;right: 0px;"}).appendTo(installTab).editableList({ | ||||
|             addButton: false, | ||||
|             scrollOnAdd: false, | ||||
|             addItem: function(container,i,object) { | ||||
|                 if (object.count) { | ||||
|                     $('<div>',{class:"red-ui-search-empty"}).html(RED._('palette.editor.moduleCount',{count:object.count})).appendTo(container); | ||||
|                     return | ||||
|                 } | ||||
|                 if (object.more) { | ||||
|                     container.addClass('palette-module-more'); | ||||
|                     var moreRow = $('<div>',{class:"palette-module-header palette-module"}).appendTo(container); | ||||
|                     var moreLink = $('<a href="#"></a>').html(RED._('palette.editor.more',{count:object.more})).appendTo(moreRow); | ||||
|                     moreLink.click(function(e) { | ||||
|                         e.preventDefault(); | ||||
|                         packageList.editableList('removeItem',object); | ||||
|                         for (var i=object.start;i<Math.min(object.start+10,object.start+object.more);i++) { | ||||
|                             packageList.editableList('addItem',filteredList[i]); | ||||
|                         } | ||||
|                         if (object.more > 10) { | ||||
|                             packageList.editableList('addItem',{start:object.start+10, more:object.more-10}) | ||||
|                         } | ||||
|                     }) | ||||
|                     return; | ||||
|                 } | ||||
|                 if (object.info) { | ||||
|                     var entry = object.info; | ||||
|                     var headerRow = $('<div>',{class:"palette-module-header"}).appendTo(container); | ||||
|                     var titleRow = $('<div class="palette-module-meta"><i class="fa fa-cube"></i></div>').appendTo(headerRow); | ||||
|                     $('<span>',{class:"palette-module-name"}).html(entry.name||entry.id).appendTo(titleRow); | ||||
|                     $('<a target="_blank" class="palette-module-link"><i class="fa fa-external-link"></i></a>').attr('href',entry.url).appendTo(titleRow); | ||||
|                     var descRow = $('<div class="palette-module-meta"></div>').appendTo(headerRow); | ||||
|                     $('<div>',{class:"palette-module-description"}).html(entry.description).appendTo(descRow); | ||||
|  | ||||
|                     var metaRow = $('<div class="palette-module-meta"></div>').appendTo(headerRow); | ||||
|                     $('<span class="palette-module-version"><i class="fa fa-tag"></i> '+entry.version+'</span>').appendTo(metaRow); | ||||
|                     $('<span class="palette-module-updated"><i class="fa fa-calendar"></i> '+formatUpdatedAt(entry.updated_at)+'</span>').appendTo(metaRow); | ||||
|                     var buttonRow = $('<div>',{class:"palette-module-meta"}).appendTo(headerRow); | ||||
|                     var buttonGroup = $('<div>',{class:"palette-module-button-group"}).appendTo(buttonRow); | ||||
|                     var shade = $('<div class="palette-module-shade hide"><img src="red/images/spin.svg" class="palette-spinner"/></div>').appendTo(container); | ||||
|                     var installButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.install')).appendTo(buttonGroup); | ||||
|                     installButton.click(function(e) { | ||||
|                         e.preventDefault(); | ||||
|                         if (!$(this).hasClass('disabled')) { | ||||
|                             $("#palette-module-install-confirm").data('module',entry.id); | ||||
|                             $("#palette-module-install-confirm").data('version',entry.version); | ||||
|                             $("#palette-module-install-confirm").data('url',entry.url); | ||||
|                             $("#palette-module-install-confirm").data('shade',shade); | ||||
|                             $("#palette-module-install-confirm-body").html(RED._("palette.editor.confirm.install.body")); | ||||
|                             $(".palette-module-install-confirm-button-install").show(); | ||||
|                             $(".palette-module-install-confirm-button-remove").hide(); | ||||
|                             $(".palette-module-install-confirm-button-update").hide(); | ||||
|                             $("#palette-module-install-confirm") | ||||
|                                 .dialog('option', 'title', RED._("palette.editor.confirm.install.title")) | ||||
|                                 .dialog('open'); | ||||
|                         } | ||||
|                     }) | ||||
|                     if (nodeEntries.hasOwnProperty(entry.id)) { | ||||
|                         installButton.addClass('disabled'); | ||||
|                         installButton.html(RED._('palette.editor.installed')); | ||||
|                     } | ||||
|  | ||||
|                     object.elements = { | ||||
|                         installButton:installButton | ||||
|                     } | ||||
|                 } else { | ||||
|                     $('<div>',{class:"red-ui-search-empty"}).html(RED._('search.empty')).appendTo(container); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         $('<div id="palette-module-install-shade" class="palette-module-shade hide"><div class="palette-module-shade-status"></div><img src="red/images/spin.svg" class="palette-spinner"/></div>').appendTo(installTab); | ||||
|  | ||||
|         $('<div id="palette-module-install-confirm" class="hide"><form class="form-horizontal"><div id="palette-module-install-confirm-body" class="node-dialog-confirm-row"></div></form></div>').appendTo(document.body); | ||||
|         $("#palette-module-install-confirm").dialog({ | ||||
|             title: RED._('palette.editor.confirm.title'), | ||||
|             modal: true, | ||||
|             autoOpen: false, | ||||
|             width: 550, | ||||
|             height: "auto", | ||||
|             buttons: [ | ||||
|                 { | ||||
|                     text: RED._("common.label.cancel"), | ||||
|                     click: function() { | ||||
|                         $( this ).dialog( "close" ); | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     text: RED._("palette.editor.confirm.button.review"), | ||||
|                     class: "primary palette-module-install-confirm-button-install", | ||||
|                     click: function() { | ||||
|                         var url = $(this).data('url'); | ||||
|                         window.open(url); | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     text: RED._("palette.editor.confirm.button.install"), | ||||
|                     class: "primary palette-module-install-confirm-button-install", | ||||
|                     click: function() { | ||||
|                         var id = $(this).data('module'); | ||||
|                         var version = $(this).data('version'); | ||||
|                         var shade = $(this).data('shade'); | ||||
|                         installNodeModule(id,version,shade,function(xhr) { | ||||
|                              if (xhr) { | ||||
|                                  if (xhr.responseJSON) { | ||||
|                                      RED.notify(RED._('palette.editor.errors.installFailed',{module: id,message:xhr.responseJSON.message})); | ||||
|                                  } | ||||
|                              } | ||||
|                         }); | ||||
|                         $( this ).dialog( "close" ); | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     text: RED._("palette.editor.confirm.button.remove"), | ||||
|                     class: "primary palette-module-install-confirm-button-remove", | ||||
|                     click: function() { | ||||
|                         var id = $(this).data('module'); | ||||
|                         var shade = $(this).data('shade'); | ||||
|                         shade.show(); | ||||
|                         removeNodeModule(id, function(xhr) { | ||||
|                             shade.hide(); | ||||
|                             if (xhr) { | ||||
|                                 if (xhr.responseJSON) { | ||||
|                                     RED.notify(RED._('palette.editor.errors.removeFailed',{module: id,message:xhr.responseJSON.message})); | ||||
|                                 } | ||||
|                             } | ||||
|                         }) | ||||
|  | ||||
|                         $( this ).dialog( "close" ); | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     text: RED._("palette.editor.confirm.button.update"), | ||||
|                     class: "primary palette-module-install-confirm-button-update", | ||||
|                     click: function() { | ||||
|                         var id = $(this).data('module'); | ||||
|                         var version = $(this).data('version'); | ||||
|                         var shade = $(this).data('shade'); | ||||
|                         shade.show(); | ||||
|                         installNodeModule(id,version,shade,function(xhr) { | ||||
|                              if (xhr) { | ||||
|                                  if (xhr.responseJSON) { | ||||
|                                      RED.notify(RED._('palette.editor.errors.updateFailed',{module: id,message:xhr.responseJSON.message})); | ||||
|                                  } | ||||
|                              } | ||||
|                         }); | ||||
|                         $( this ).dialog( "close" ); | ||||
|                     } | ||||
|                 } | ||||
|             ] | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         init: init | ||||
|     } | ||||
| })(); | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2013, 2016 IBM Corp. | ||||
|  * 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. | ||||
| @@ -17,12 +17,12 @@ | ||||
| RED.palette = (function() { | ||||
|  | ||||
|     var exclusion = ['config','unknown','deprecated']; | ||||
|     var core = ['subflows', 'input', 'output', 'function', 'social', 'mobile', 'storage', 'analysis', 'advanced']; | ||||
|     var coreCategories = ['subflows', 'input', 'output', 'function', 'social', 'mobile', 'storage', 'analysis', 'advanced']; | ||||
|  | ||||
|     var categoryContainers = {}; | ||||
|  | ||||
|     function createCategoryContainer(category, label){ | ||||
|         label = label || category.replace("_", " "); | ||||
|         label = (label || category).replace(/_/g, " "); | ||||
|         var catDiv = $('<div id="palette-container-'+category+'" class="palette-category palette-close hide">'+ | ||||
|             '<div id="palette-header-'+category+'" class="palette-header"><i class="expanded fa fa-angle-down"></i><span>'+label+'</span></div>'+ | ||||
|             '<div class="palette-content" id="palette-base-category-'+category+'">'+ | ||||
| @@ -66,7 +66,7 @@ RED.palette = (function() { | ||||
|         var lineHeight = 20; | ||||
|         var portHeight = 10; | ||||
|  | ||||
|         var words = label.split(" "); | ||||
|         var words = label.split(/[ -]/); | ||||
|  | ||||
|         var displayLines = []; | ||||
|  | ||||
| @@ -91,17 +91,17 @@ RED.palette = (function() { | ||||
|         el.css({height:multiLineNodeHeight+"px"}); | ||||
|  | ||||
|         var labelElement = el.find(".palette_label"); | ||||
|         labelElement.html(lines); | ||||
|         labelElement.html(lines).attr('dir', RED.text.bidi.resolveBaseTextDir(lines)); | ||||
|  | ||||
|         el.find(".palette_port").css({top:(multiLineNodeHeight/2-5)+"px"}); | ||||
|  | ||||
|         var popOverContent; | ||||
|         try { | ||||
|             var l = "<p><b>"+label+"</b></p>"; | ||||
|             var l = "<p><b>"+RED.text.bidi.enforceTextDirectionWithUCC(label)+"</b></p>"; | ||||
|             if (label != type) { | ||||
|                 l = "<p><b>"+label+"</b><br/><i>"+type+"</i></p>"; | ||||
|                 l = "<p><b>"+RED.text.bidi.enforceTextDirectionWithUCC(label)+"</b><br/><i>"+type+"</i></p>"; | ||||
|             } | ||||
|             popOverContent = $(l+(info?info:$("script[data-help-name|='"+type+"']").html()||"<p>"+RED._("palette.noInfo")+"</p>").trim()) | ||||
|             popOverContent = $(l+(info?info:$("script[data-help-name='"+type+"']").html()||"<p>"+RED._("palette.noInfo")+"</p>").trim()) | ||||
|                                 .filter(function(n) { | ||||
|                                     return (this.nodeType == 1 && this.nodeName == "P") || (this.nodeType == 3 && this.textContent.trim().length > 0) | ||||
|                                 }).slice(0,2); | ||||
| @@ -127,31 +127,31 @@ RED.palette = (function() { | ||||
|         } | ||||
|         if (exclusion.indexOf(def.category)===-1) { | ||||
|  | ||||
|             var category = def.category.replace(" ","_"); | ||||
|             var category = def.category.replace(/ /g,"_"); | ||||
|             var rootCategory = category.split("-")[0]; | ||||
|  | ||||
|             var d = document.createElement("div"); | ||||
|             d.id = "palette_node_"+nodeTypeId; | ||||
|             d.type = nt; | ||||
|  | ||||
|             var label; | ||||
|  | ||||
|             if (typeof def.paletteLabel === "undefined") { | ||||
|                 label = /^(.*?)([ -]in|[ -]out)?$/.exec(nt)[1]; | ||||
|             } else { | ||||
|                 label = (typeof def.paletteLabel === "function" ? def.paletteLabel.call(def) : def.paletteLabel)||""; | ||||
|             var label = /^(.*?)([ -]in|[ -]out)?$/.exec(nt)[1]; | ||||
|             if (typeof def.paletteLabel !== "undefined") { | ||||
|                 try { | ||||
|                     label = (typeof def.paletteLabel === "function" ? def.paletteLabel.call(def) : def.paletteLabel)||""; | ||||
|                 } catch(err) { | ||||
|                     console.log("Definition error: "+nt+".paletteLabel",err); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|  | ||||
|             $('<div/>',{class:"palette_label"+(def.align=="right"?" palette_label_right":"")}).appendTo(d); | ||||
|  | ||||
|             d.className="palette_node"; | ||||
|  | ||||
|  | ||||
|             if (def.icon) { | ||||
|                 var icon_url = (typeof def.icon === "function" ? def.icon.call({}) : def.icon); | ||||
|                 var icon_url = RED.utils.getNodeIcon(def); | ||||
|                 var iconContainer = $('<div/>',{class:"palette_icon_container"+(def.align=="right"?" palette_icon_container_right":"")}).appendTo(d); | ||||
|                 $('<div/>',{class:"palette_icon",style:"background-image: url(icons/"+icon_url+")"}).appendTo(iconContainer); | ||||
|                 $('<div/>',{class:"palette_icon",style:"background-image: url("+icon_url+")"}).appendTo(iconContainer); | ||||
|             } | ||||
|  | ||||
|             d.style.backgroundColor = def.color; | ||||
| @@ -169,7 +169,7 @@ RED.palette = (function() { | ||||
|             } | ||||
|  | ||||
|             if ($("#palette-base-category-"+rootCategory).length === 0) { | ||||
|                 if(core.indexOf(rootCategory) !== -1){ | ||||
|                 if(coreCategories.indexOf(rootCategory) !== -1){ | ||||
|                     createCategoryContainer(rootCategory, RED._("node-red:palette.label."+rootCategory, {defaultValue:rootCategory})); | ||||
|                 } else { | ||||
|                     var ns = def.set.id; | ||||
| @@ -185,11 +185,14 @@ RED.palette = (function() { | ||||
|             $("#palette-"+category).append(d); | ||||
|             d.onmousedown = function(e) { e.preventDefault(); }; | ||||
|  | ||||
|             RED.popover.create({ | ||||
|             var popover = RED.popover.create({ | ||||
|                 target:$(d), | ||||
|                 trigger: "hover", | ||||
|                 width: "300px", | ||||
|                 content: "hi", | ||||
|                 delay: { show: 750, hide: 50 } | ||||
|             }); | ||||
|             $(d).data('popover',popover); | ||||
|  | ||||
|             // $(d).popover({ | ||||
|             //     title:d.type, | ||||
| @@ -205,10 +208,9 @@ RED.palette = (function() { | ||||
|                 if (nt.indexOf("subflow:") === 0) { | ||||
|                     helpText = marked(RED.nodes.subflow(nt.substring(8)).info||""); | ||||
|                 } else { | ||||
|                     helpText = $("script[data-help-name|='"+d.type+"']").html()||""; | ||||
|                     helpText = $("script[data-help-name='"+d.type+"']").html()||""; | ||||
|                 } | ||||
|                 var help = '<div class="node-help">'+helpText+"</div>"; | ||||
|                 RED.sidebar.info.set(help); | ||||
|                 RED.sidebar.info.set(helpText); | ||||
|             }); | ||||
|             var chart = $("#chart"); | ||||
|             var chartOffset = chart.offset(); | ||||
| @@ -222,15 +224,19 @@ RED.palette = (function() { | ||||
|                 appendTo: 'body', | ||||
|                 revert: true, | ||||
|                 revertDuration: 50, | ||||
|                 containment:'#main-container', | ||||
|                 start: function() {RED.view.focus();}, | ||||
|                 stop: function() { d3.select('.link_splice').classed('link_splice',false); if (spliceTimer) { clearTimeout(spliceTimer); spliceTimer = null;}}, | ||||
|                 drag: function(e,ui) { | ||||
|  | ||||
|                     // TODO: this is the margin-left of palette node. Hard coding | ||||
|                     // it here makes me sad | ||||
|                     //console.log(ui.helper.position()); | ||||
|                     ui.position.left += 17.5; | ||||
|  | ||||
|                     if (def.inputs > 0 && def.outputs > 0) { | ||||
|                         mouseX = e.clientX - chartOffset.left+chart.scrollLeft(); | ||||
|                         mouseY = e.clientY-chartOffset.top +chart.scrollTop(); | ||||
|                         mouseX = ui.position.left+(ui.helper.width()/2) - chartOffset.left + chart.scrollLeft(); | ||||
|                         mouseY = ui.position.top+(ui.helper.height()/2) - chartOffset.top + chart.scrollTop(); | ||||
|  | ||||
|                         if (!spliceTimer) { | ||||
|                             spliceTimer = setTimeout(function() { | ||||
| @@ -354,15 +360,8 @@ RED.palette = (function() { | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     function filterChange() { | ||||
|         var val = $("#palette-search-input").val(); | ||||
|         if (val === "") { | ||||
|             $("#palette-search-clear").hide(); | ||||
|         } else { | ||||
|             $("#palette-search-clear").show(); | ||||
|         } | ||||
|  | ||||
|         var re = new RegExp(val,'i'); | ||||
|     function filterChange(val) { | ||||
|         var re = new RegExp(val.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'),'i'); | ||||
|         $("#palette-container .palette_node").each(function(i,el) { | ||||
|             var currentLabel = $(el).find(".palette_label").text(); | ||||
|             if (val === "" || re.test(el.id) || re.test(currentLabel)) { | ||||
| @@ -386,40 +385,69 @@ RED.palette = (function() { | ||||
|     } | ||||
|  | ||||
|     function init() { | ||||
|         $(".palette-spinner").show(); | ||||
|  | ||||
|         RED.events.on('registry:node-type-added', function(nodeType) { | ||||
|             var def = RED.nodes.getType(nodeType); | ||||
|             addNodeType(nodeType,def); | ||||
|             if (def.onpaletteadd && typeof def.onpaletteadd === "function") { | ||||
|                 def.onpaletteadd.call(def); | ||||
|             } | ||||
|         }); | ||||
|         RED.events.on('registry:node-type-removed', function(nodeType) { | ||||
|             removeNodeType(nodeType); | ||||
|         }); | ||||
|  | ||||
|         RED.events.on('registry:node-set-enabled', function(nodeSet) { | ||||
|             for (var j=0;j<nodeSet.types.length;j++) { | ||||
|                 showNodeType(nodeSet.types[j]); | ||||
|                 var def = RED.nodes.getType(nodeSet.types[j]); | ||||
|                 if (def.onpaletteadd && typeof def.onpaletteadd === "function") { | ||||
|                     def.onpaletteadd.call(def); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|         RED.events.on('registry:node-set-disabled', function(nodeSet) { | ||||
|             for (var j=0;j<nodeSet.types.length;j++) { | ||||
|                 hideNodeType(nodeSet.types[j]); | ||||
|                 var def = RED.nodes.getType(nodeSet.types[j]); | ||||
|                 if (def.onpaletteremove && typeof def.onpaletteremove === "function") { | ||||
|                     def.onpaletteremove.call(def); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|         RED.events.on('registry:node-set-removed', function(nodeSet) { | ||||
|             if (nodeSet.added) { | ||||
|                 for (var j=0;j<nodeSet.types.length;j++) { | ||||
|                     removeNodeType(nodeSet.types[j]); | ||||
|                     var def = RED.nodes.getType(nodeSet.types[j]); | ||||
|                     if (def.onpaletteremove && typeof def.onpaletteremove === "function") { | ||||
|                         def.onpaletteremove.call(def); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|  | ||||
|         $("#palette > .palette-spinner").show(); | ||||
|  | ||||
|         $("#palette-search input").searchBox({ | ||||
|             delay: 100, | ||||
|             change: function() { | ||||
|                 filterChange($(this).val()); | ||||
|             } | ||||
|         }) | ||||
|  | ||||
|         var categoryList = coreCategories; | ||||
|         if (RED.settings.paletteCategories) { | ||||
|             RED.settings.paletteCategories.forEach(function(category){ | ||||
|                 createCategoryContainer(category, RED._("palette.label."+category,{defaultValue:category})); | ||||
|             }); | ||||
|         } else { | ||||
|             core.forEach(function(category){ | ||||
|                 createCategoryContainer(category, RED._("palette.label."+category,{defaultValue:category})); | ||||
|             }); | ||||
|             categoryList = RED.settings.paletteCategories; | ||||
|         } else if (RED.settings.theme('palette.categories')) { | ||||
|             categoryList = RED.settings.theme('palette.categories'); | ||||
|         } | ||||
|  | ||||
|         $("#palette-search-input").focus(function(e) { | ||||
|             RED.keyboard.disable(); | ||||
|         }); | ||||
|         $("#palette-search-input").blur(function(e) { | ||||
|             RED.keyboard.enable(); | ||||
|         }); | ||||
|  | ||||
|         $("#palette-search-clear").on("click",function(e) { | ||||
|             e.preventDefault(); | ||||
|             $("#palette-search-input").val(""); | ||||
|             filterChange(); | ||||
|             $("#palette-search-input").focus(); | ||||
|         }); | ||||
|  | ||||
|         $("#palette-search-input").val(""); | ||||
|         $("#palette-search-input").on("keyup",function() { | ||||
|             filterChange(); | ||||
|         }); | ||||
|  | ||||
|         $("#palette-search-input").on("focus",function() { | ||||
|             $("body").one("mousedown",function() { | ||||
|                 $("#palette-search-input").blur(); | ||||
|             }); | ||||
|         if (!Array.isArray(categoryList)) { | ||||
|             categoryList = coreCategories | ||||
|         } | ||||
|         categoryList.forEach(function(category){ | ||||
|             createCategoryContainer(category, RED._("palette.label."+category,{defaultValue:category})); | ||||
|         }); | ||||
|  | ||||
|         $("#palette-collapse-all").on("click", function(e) { | ||||
|   | ||||
| @@ -1,79 +0,0 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * | ||||
|  * 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.popover = (function() { | ||||
|  | ||||
|  | ||||
|     function createPopover(options) { | ||||
|         var target = options.target; | ||||
|  | ||||
|         var content = options.content; | ||||
|         var delay = options.delay; | ||||
|         var timer = null; | ||||
|         var active; | ||||
|         var div; | ||||
|  | ||||
|         var openPopup = function() { | ||||
|             if (active) { | ||||
|                 div = $('<div class="red-ui-popover"></div>').html(content).appendTo("body"); | ||||
|                 var targetPos = target.offset(); | ||||
|                 var targetWidth = target.width(); | ||||
|                 var targetHeight = target.height(); | ||||
|  | ||||
|                 var divHeight = div.height(); | ||||
|                 div.css({top: targetPos.top+targetHeight/2-divHeight/2-10,left:targetPos.left+targetWidth+17}); | ||||
|  | ||||
|                 div.fadeIn("fast"); | ||||
|             } | ||||
|         } | ||||
|         var closePopup = function() { | ||||
|             if (!active) { | ||||
|                 if (div) { | ||||
|                     div.fadeOut("fast",function() { | ||||
|                         $(this).remove(); | ||||
|                     }); | ||||
|                     div = null; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         target.on('mouseenter',function(e) { | ||||
|             clearTimeout(timer); | ||||
|             active = true; | ||||
|             timer = setTimeout(openPopup,delay.show); | ||||
|         }); | ||||
|         target.on('mouseleave', function(e) { | ||||
|             if (timer) { | ||||
|                 clearTimeout(timer); | ||||
|             } | ||||
|             active = false; | ||||
|             setTimeout(closePopup,delay.hide); | ||||
|         }); | ||||
|         var res = { | ||||
|             setContent: function(_content) { | ||||
|                 content = _content; | ||||
|             } | ||||
|         } | ||||
|         target.data('popover',res); | ||||
|         return res; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         create: createPopover | ||||
|     } | ||||
|  | ||||
| })(); | ||||
							
								
								
									
										285
									
								
								editor/js/ui/search.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,285 @@ | ||||
| /** | ||||
|  * 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.search = (function() { | ||||
|  | ||||
|     var disabled = false; | ||||
|     var dialog = null; | ||||
|     var searchInput; | ||||
|     var searchResults; | ||||
|     var selected = -1; | ||||
|     var visible = false; | ||||
|  | ||||
|     var index = {}; | ||||
|     var keys = []; | ||||
|     var results = []; | ||||
|  | ||||
|     function indexNode(n) { | ||||
|         var l = RED.utils.getNodeLabel(n); | ||||
|         if (l) { | ||||
|             l = (""+l).toLowerCase(); | ||||
|             index[l] = index[l] || {}; | ||||
|             index[l][n.id] = {node:n,label:l} | ||||
|         } | ||||
|         l = l||n.label||n.name||n.id||""; | ||||
|  | ||||
|  | ||||
|         var properties = ['id','type','name','label','info']; | ||||
|         if (n._def && n._def.defaults) { | ||||
|             properties = properties.concat(Object.keys(n._def.defaults)); | ||||
|         } | ||||
|         for (var i=0;i<properties.length;i++) { | ||||
|             if (n.hasOwnProperty(properties[i])) { | ||||
|                 var v = n[properties[i]]; | ||||
|                 if (typeof v === 'string' || typeof v === 'number') { | ||||
|                     v = (""+v).toLowerCase(); | ||||
|                     index[v] = index[v] || {}; | ||||
|                     index[v][n.id] = {node:n,label:l}; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|  | ||||
|     } | ||||
|     function indexWorkspace() { | ||||
|         index = {}; | ||||
|         RED.nodes.eachWorkspace(indexNode); | ||||
|         RED.nodes.eachSubflow(indexNode); | ||||
|         RED.nodes.eachConfig(indexNode); | ||||
|         RED.nodes.eachNode(indexNode); | ||||
|         keys = Object.keys(index); | ||||
|         keys.sort(); | ||||
|         keys.forEach(function(key) { | ||||
|             index[key] = Object.keys(index[key]).map(function(id) { | ||||
|                 return index[key][id]; | ||||
|             }) | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     function search(val) { | ||||
|         searchResults.editableList('empty'); | ||||
|         selected = -1; | ||||
|         results = []; | ||||
|         if (val.length > 0) { | ||||
|             val = val.toLowerCase(); | ||||
|             var i; | ||||
|             var j; | ||||
|             var list = []; | ||||
|             var nodes = {}; | ||||
|             for (i=0;i<keys.length;i++) { | ||||
|                 var key = keys[i]; | ||||
|                 var kpos = keys[i].indexOf(val); | ||||
|                 if (kpos > -1) { | ||||
|                     for (j=0;j<index[key].length;j++) { | ||||
|                         var node = index[key][j]; | ||||
|                         nodes[node.node.id] = nodes[node.node.id] = node; | ||||
|                         nodes[node.node.id].index = Math.min(nodes[node.node.id].index||Infinity,kpos); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             list = Object.keys(nodes); | ||||
|             list.sort(function(A,B) { | ||||
|                 return nodes[A].index - nodes[B].index; | ||||
|             }); | ||||
|  | ||||
|             for (i=0;i<list.length;i++) { | ||||
|                 results.push(nodes[list[i]]); | ||||
|             } | ||||
|             if (results.length > 0) { | ||||
|                 for (i=0;i<Math.min(results.length,25);i++) { | ||||
|                     searchResults.editableList('addItem',results[i]) | ||||
|                 } | ||||
|             } else { | ||||
|                 searchResults.editableList('addItem',{}); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     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-search",class:"red-ui-search"}).appendTo("#main-container"); | ||||
|         var searchDiv = $("<div>",{class:"red-ui-search-container"}).appendTo(dialog); | ||||
|         searchInput = $('<input type="text" placeholder="search your flows">').appendTo(searchDiv).searchBox({ | ||||
|             delay: 200, | ||||
|             change: function() { | ||||
|                 search($(this).val()); | ||||
|             } | ||||
|         }); | ||||
|         searchInput.on('keydown',function(evt) { | ||||
|             var children; | ||||
|             if (results.length > 0) { | ||||
|                 if (evt.keyCode === 40) { | ||||
|                     // Down | ||||
|                     children = searchResults.children(); | ||||
|                     if (selected < children.length-1) { | ||||
|                         if (selected > -1) { | ||||
|                             $(children[selected]).removeClass('selected'); | ||||
|                         } | ||||
|                         selected++; | ||||
|                     } | ||||
|                     $(children[selected]).addClass('selected'); | ||||
|                     ensureSelectedIsVisible(); | ||||
|                     evt.preventDefault(); | ||||
|                 } else if (evt.keyCode === 38) { | ||||
|                     // Up | ||||
|                     children = searchResults.children(); | ||||
|                     if (selected > 0) { | ||||
|                         if (selected < children.length) { | ||||
|                             $(children[selected]).removeClass('selected'); | ||||
|                         } | ||||
|                         selected--; | ||||
|                     } | ||||
|                     $(children[selected]).addClass('selected'); | ||||
|                     ensureSelectedIsVisible(); | ||||
|                     evt.preventDefault(); | ||||
|                 } else if (evt.keyCode === 13) { | ||||
|                     // Enter | ||||
|                     if (results.length > 0) { | ||||
|                         reveal(results[Math.max(0,selected)].node); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         var searchResultsDiv = $("<div>",{class:"red-ui-search-results-container"}).appendTo(dialog); | ||||
|         searchResults = $('<ol>',{id:"search-result-list", style:"position: absolute;top: 5px;bottom: 5px;left: 5px;right: 5px;"}).appendTo(searchResultsDiv).editableList({ | ||||
|             addButton: false, | ||||
|             addItem: function(container,i,object) { | ||||
|                 var node = object.node; | ||||
|                 if (node === undefined) { | ||||
|                     $('<div>',{class:"red-ui-search-empty"}).html(RED._('search.empty')).appendTo(container); | ||||
|  | ||||
|                 } else { | ||||
|                     var def = node._def; | ||||
|                     var div = $('<a>',{href:'#',class:"red-ui-search-result"}).appendTo(container); | ||||
|  | ||||
|                     var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(div); | ||||
|                     var colour = def.color; | ||||
|                     var icon_url = RED.utils.getNodeIcon(def,node); | ||||
|                     if (node.type === 'tab') { | ||||
|                         colour = "#C0DEED"; | ||||
|                     } | ||||
|                     nodeDiv.css('backgroundColor',colour); | ||||
|  | ||||
|                     var iconContainer = $('<div/>',{class:"palette_icon_container"}).appendTo(nodeDiv); | ||||
|                     $('<div/>',{class:"palette_icon",style:"background-image: url("+icon_url+")"}).appendTo(iconContainer); | ||||
|  | ||||
|                     var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div); | ||||
|                     if (node.z) { | ||||
|                         var workspace = RED.nodes.workspace(node.z); | ||||
|                         if (!workspace) { | ||||
|                             workspace = RED.nodes.subflow(node.z); | ||||
|                             workspace = "subflow:"+workspace.name; | ||||
|                         } else { | ||||
|                             workspace = "flow:"+workspace.label; | ||||
|                         } | ||||
|                         $('<div>',{class:"red-ui-search-result-node-flow"}).html(workspace).appendTo(contentDiv); | ||||
|                     } | ||||
|  | ||||
|                     $('<div>',{class:"red-ui-search-result-node-label"}).html(object.label || node.id).appendTo(contentDiv); | ||||
|                     $('<div>',{class:"red-ui-search-result-node-type"}).html(node.type).appendTo(contentDiv); | ||||
|                     $('<div>',{class:"red-ui-search-result-node-id"}).html(node.id).appendTo(contentDiv); | ||||
|  | ||||
|                     div.click(function(evt) { | ||||
|                         evt.preventDefault(); | ||||
|                         reveal(node); | ||||
|                     }); | ||||
|                 } | ||||
|             }, | ||||
|             scrollOnAdd: false | ||||
|         }); | ||||
|  | ||||
|     } | ||||
|     function reveal(node) { | ||||
|         hide(); | ||||
|         RED.view.reveal(node.id); | ||||
|     } | ||||
|  | ||||
|     function show() { | ||||
|         if (disabled) { | ||||
|             return; | ||||
|         } | ||||
|         if (!visible) { | ||||
|             RED.keyboard.add("*","escape",function(){hide()}); | ||||
|             $("#header-shade").show(); | ||||
|             $("#editor-shade").show(); | ||||
|             $("#palette-shade").show(); | ||||
|             $("#sidebar-shade").show(); | ||||
|             $("#sidebar-separator").hide(); | ||||
|             indexWorkspace(); | ||||
|             if (dialog === null) { | ||||
|                 createDialog(); | ||||
|             } | ||||
|             dialog.slideDown(300); | ||||
|             RED.events.emit("search:open"); | ||||
|             visible = true; | ||||
|         } | ||||
|         searchInput.focus(); | ||||
|     } | ||||
|     function hide() { | ||||
|         if (visible) { | ||||
|             RED.keyboard.remove("escape"); | ||||
|             visible = false; | ||||
|             $("#header-shade").hide(); | ||||
|             $("#editor-shade").hide(); | ||||
|             $("#palette-shade").hide(); | ||||
|             $("#sidebar-shade").hide(); | ||||
|             $("#sidebar-separator").show(); | ||||
|             if (dialog !== null) { | ||||
|                 dialog.slideUp(200,function() { | ||||
|                     searchInput.searchBox('value',''); | ||||
|                 }); | ||||
|             } | ||||
|             RED.events.emit("search:close"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function init() { | ||||
|         RED.actions.add("core:search",show); | ||||
|  | ||||
|         RED.events.on("editor:open",function() { disabled = true; }); | ||||
|         RED.events.on("editor:close",function() { disabled = false; }); | ||||
|         RED.events.on("type-search:open",function() { disabled = true; }); | ||||
|         RED.events.on("type-search:close",function() { disabled = false; }); | ||||
|  | ||||
|  | ||||
|  | ||||
|         $("#header-shade").on('mousedown',hide); | ||||
|         $("#editor-shade").on('mousedown',hide); | ||||
|         $("#palette-shade").on('mousedown',hide); | ||||
|         $("#sidebar-shade").on('mousedown',hide); | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         init: init, | ||||
|         show: show, | ||||
|         hide: hide | ||||
|     }; | ||||
|  | ||||
| })(); | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2013, 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -24,13 +24,13 @@ RED.sidebar = (function() { | ||||
|             if (tab.onchange) { | ||||
|                 tab.onchange.call(tab); | ||||
|             } | ||||
|             $(tab.content).show(); | ||||
|             $(tab.wrapper).show(); | ||||
|             if (tab.toolbar) { | ||||
|                 $(tab.toolbar).show(); | ||||
|             } | ||||
|         }, | ||||
|         onremove: function(tab) { | ||||
|             $(tab.content).hide(); | ||||
|             $(tab.wrapper).hide(); | ||||
|             if (tab.onremove) { | ||||
|                 tab.onremove.call(tab); | ||||
|             } | ||||
| @@ -58,15 +58,18 @@ RED.sidebar = (function() { | ||||
|             options = title; | ||||
|         } | ||||
|  | ||||
|         options.wrapper = $('<div>',{style:"height:100%"}).appendTo("#sidebar-content") | ||||
|         options.wrapper.append(options.content); | ||||
|         options.wrapper.hide(); | ||||
|  | ||||
|         if (!options.enableOnEdit) { | ||||
|             options.shade = $('<div>',{class:"sidebar-shade hide"}).appendTo(options.wrapper); | ||||
|         } | ||||
|  | ||||
|         $("#sidebar-content").append(options.content); | ||||
|         $(options.content).hide(); | ||||
|         if (options.toolbar) { | ||||
|             $("#sidebar-footer").append(options.toolbar); | ||||
|             $(options.toolbar).hide(); | ||||
|         } | ||||
|         $(options.content).hide(); | ||||
|         var id = options.id; | ||||
|  | ||||
|         RED.menu.addItem("menu-item-view-menu",{ | ||||
| @@ -87,7 +90,10 @@ RED.sidebar = (function() { | ||||
|  | ||||
|     function removeTab(id) { | ||||
|         sidebar_tabs.removeTab(id); | ||||
|         $(knownTabs[id].content).remove(); | ||||
|         $(knownTabs[id].wrapper).remove(); | ||||
|         if (knownTabs[id].footer) { | ||||
|             knownTabs[id].footer.remove(); | ||||
|         } | ||||
|         delete knownTabs[id]; | ||||
|         RED.menu.removeItem("menu-item-view-menu-"+id); | ||||
|     } | ||||
| @@ -103,12 +109,12 @@ RED.sidebar = (function() { | ||||
|                 sidebarSeparator.chartWidth = $("#workspace").width(); | ||||
|                 sidebarSeparator.chartRight = winWidth-$("#workspace").width()-$("#workspace").offset().left-2; | ||||
|  | ||||
|  | ||||
|                 if (!RED.menu.isSelected("menu-item-sidebar")) { | ||||
|                     sidebarSeparator.opening = true; | ||||
|                     var newChartRight = 7; | ||||
|                     $("#sidebar").addClass("closing"); | ||||
|                     $("#workspace").css("right",newChartRight); | ||||
|                     $("#editor-stack").css("right",newChartRight+1); | ||||
|                     $("#sidebar").width(0); | ||||
|                     RED.menu.setSelected("menu-item-sidebar",true); | ||||
|                     RED.events.emit("sidebar:resize"); | ||||
| @@ -147,6 +153,7 @@ RED.sidebar = (function() { | ||||
|  | ||||
|                 var newChartRight = sidebarSeparator.chartRight-d; | ||||
|                 $("#workspace").css("right",newChartRight); | ||||
|                 $("#editor-stack").css("right",newChartRight+1); | ||||
|                 $("#sidebar").width(newSidebarWidth); | ||||
|  | ||||
|                 sidebar_tabs.resize(); | ||||
| @@ -159,6 +166,7 @@ RED.sidebar = (function() { | ||||
|                     if ($("#sidebar").width() < 180) { | ||||
|                         $("#sidebar").width(180); | ||||
|                         $("#workspace").css("right",187); | ||||
|                         $("#editor-stack").css("right",188); | ||||
|                     } | ||||
|                 } | ||||
|                 $("#sidebar-separator").css("left","auto"); | ||||
| @@ -194,12 +202,18 @@ RED.sidebar = (function() { | ||||
|     } | ||||
|  | ||||
|     function init () { | ||||
|         RED.keyboard.add(/* SPACE */ 32,{ctrl:true},function(){RED.menu.setSelected("menu-item-sidebar",!RED.menu.isSelected("menu-item-sidebar"));d3.event.preventDefault();}); | ||||
|         RED.actions.add("core:toggle-sidebar",function(state){ | ||||
|             if (state === undefined) { | ||||
|                 RED.menu.toggleSelected("menu-item-sidebar"); | ||||
|             } else { | ||||
|                 toggleSidebar(state); | ||||
|             } | ||||
|         }); | ||||
|         showSidebar(); | ||||
|         RED.sidebar.info.init(); | ||||
|         RED.sidebar.config.init(); | ||||
|         // hide info bar at start if screen rather narrow... | ||||
|         if ($(window).width() < 600) { toggleSidebar(); } | ||||
|         if ($(window).width() < 600) { RED.menu.setSelected("menu-item-sidebar",false); } | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2013 IBM Corp. | ||||
|  * 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. | ||||
| @@ -22,5 +22,6 @@ RED.state = { | ||||
|     EDITING: 5, | ||||
|     EXPORT: 6, | ||||
|     IMPORT: 7, | ||||
|     IMPORT_DRAGGING: 8 | ||||
|     IMPORT_DRAGGING: 8, | ||||
|     QUICK_JOINING: 9 | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -306,50 +306,13 @@ RED.subflow = (function() { | ||||
|  | ||||
|         $("#workspace-subflow-delete").click(function(event) { | ||||
|             event.preventDefault(); | ||||
|             var removedNodes = []; | ||||
|             var removedLinks = []; | ||||
|             var startDirty = RED.nodes.dirty(); | ||||
|             var historyEvent = removeSubflow(RED.workspaces.active()); | ||||
|             historyEvent.t = 'delete'; | ||||
|             historyEvent.dirty = startDirty; | ||||
|  | ||||
|             var activeSubflow = getSubflow(); | ||||
|             RED.history.push(historyEvent); | ||||
|  | ||||
|             RED.nodes.eachNode(function(n) { | ||||
|                 if (n.type == "subflow:"+activeSubflow.id) { | ||||
|                     removedNodes.push(n); | ||||
|                 } | ||||
|                 if (n.z == activeSubflow.id) { | ||||
|                     removedNodes.push(n); | ||||
|                 } | ||||
|             }); | ||||
|             RED.nodes.eachConfig(function(n) { | ||||
|                 if (n.z == activeSubflow.id) { | ||||
|                     removedNodes.push(n); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|             var removedConfigNodes = []; | ||||
|             for (var i=0;i<removedNodes.length;i++) { | ||||
|                 var removedEntities = RED.nodes.remove(removedNodes[i].id); | ||||
|                 removedLinks = removedLinks.concat(removedEntities.links); | ||||
|                 removedConfigNodes = removedConfigNodes.concat(removedEntities.nodes); | ||||
|             } | ||||
|             // TODO: this whole delete logic should be in RED.nodes.removeSubflow.. | ||||
|             removedNodes = removedNodes.concat(removedConfigNodes); | ||||
|  | ||||
|             RED.nodes.removeSubflow(activeSubflow); | ||||
|  | ||||
|             RED.history.push({ | ||||
|                     t:'delete', | ||||
|                     nodes:removedNodes, | ||||
|                     links:removedLinks, | ||||
|                     subflow: { | ||||
|                         subflow: activeSubflow | ||||
|                     }, | ||||
|                     dirty:startDirty | ||||
|             }); | ||||
|  | ||||
|             RED.workspaces.remove(activeSubflow); | ||||
|             RED.nodes.dirty(true); | ||||
|             RED.view.redraw(); | ||||
|         }); | ||||
|  | ||||
|         refreshToolbar(activeSubflow); | ||||
| @@ -362,7 +325,48 @@ RED.subflow = (function() { | ||||
|         $("#chart").css({"margin-top": "0"}); | ||||
|     } | ||||
|  | ||||
|     function removeSubflow(id) { | ||||
|         var removedNodes = []; | ||||
|         var removedLinks = []; | ||||
|  | ||||
|         var activeSubflow = RED.nodes.subflow(id); | ||||
|  | ||||
|         RED.nodes.eachNode(function(n) { | ||||
|             if (n.type == "subflow:"+activeSubflow.id) { | ||||
|                 removedNodes.push(n); | ||||
|             } | ||||
|             if (n.z == activeSubflow.id) { | ||||
|                 removedNodes.push(n); | ||||
|             } | ||||
|         }); | ||||
|         RED.nodes.eachConfig(function(n) { | ||||
|             if (n.z == activeSubflow.id) { | ||||
|                 removedNodes.push(n); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         var removedConfigNodes = []; | ||||
|         for (var i=0;i<removedNodes.length;i++) { | ||||
|             var removedEntities = RED.nodes.remove(removedNodes[i].id); | ||||
|             removedLinks = removedLinks.concat(removedEntities.links); | ||||
|             removedConfigNodes = removedConfigNodes.concat(removedEntities.nodes); | ||||
|         } | ||||
|         // TODO: this whole delete logic should be in RED.nodes.removeSubflow.. | ||||
|         removedNodes = removedNodes.concat(removedConfigNodes); | ||||
|  | ||||
|         RED.nodes.removeSubflow(activeSubflow); | ||||
|         RED.workspaces.remove(activeSubflow); | ||||
|         RED.nodes.dirty(true); | ||||
|         RED.view.redraw(); | ||||
|  | ||||
|         return { | ||||
|             nodes:removedNodes, | ||||
|             links:removedLinks, | ||||
|             subflow: { | ||||
|                 subflow: activeSubflow | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     function init() { | ||||
|         RED.events.on("workspace:change",function(event) { | ||||
|             var activeSubflow = RED.nodes.subflow(event.workspace); | ||||
| @@ -380,6 +384,8 @@ RED.subflow = (function() { | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         RED.actions.add("core:create-subflow",createSubflow); | ||||
|         RED.actions.add("core:convert-to-subflow",convertToSubflow); | ||||
|     } | ||||
|  | ||||
|     function createSubflow() { | ||||
| @@ -420,7 +426,7 @@ RED.subflow = (function() { | ||||
|             RED.notify(RED._("subflow.errors.noNodesSelected"),"error"); | ||||
|             return; | ||||
|         } | ||||
|         var i; | ||||
|         var i,n; | ||||
|         var nodes = {}; | ||||
|         var new_links = []; | ||||
|         var removedLinks = []; | ||||
| @@ -436,7 +442,7 @@ RED.subflow = (function() { | ||||
|             selection.nodes[0].y]; | ||||
|  | ||||
|         for (i=0;i<selection.nodes.length;i++) { | ||||
|             var n = selection.nodes[i]; | ||||
|             n = selection.nodes[i]; | ||||
|             nodes[n.id] = {n:n,outputs:{}}; | ||||
|             boundingBox = [ | ||||
|                 Math.min(boundingBox[0],n.x), | ||||
| @@ -573,7 +579,23 @@ RED.subflow = (function() { | ||||
|         } | ||||
|  | ||||
|         for (i=0;i<selection.nodes.length;i++) { | ||||
|             selection.nodes[i].z = subflow.id; | ||||
|             n = selection.nodes[i]; | ||||
|             if (/^link /.test(n.type)) { | ||||
|                 n.links = n.links.filter(function(id) { | ||||
|                     var isLocalLink = nodes.hasOwnProperty(id); | ||||
|                     if (!isLocalLink) { | ||||
|                         var otherNode = RED.nodes.node(id); | ||||
|                         if (otherNode && otherNode.links) { | ||||
|                             var i = otherNode.links.indexOf(n.id); | ||||
|                             if (i > -1) { | ||||
|                                 otherNode.links.splice(i,1); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     return isLocalLink; | ||||
|                 }); | ||||
|             } | ||||
|             n.z = subflow.id; | ||||
|         } | ||||
|  | ||||
|         RED.history.push({ | ||||
| @@ -589,7 +611,7 @@ RED.subflow = (function() { | ||||
|  | ||||
|             dirty:RED.nodes.dirty() | ||||
|         }); | ||||
|  | ||||
|         RED.view.select(null); | ||||
|         RED.editor.validateNode(subflow); | ||||
|         RED.nodes.dirty(true); | ||||
|         RED.view.redraw(true); | ||||
| @@ -601,6 +623,7 @@ RED.subflow = (function() { | ||||
|         init: init, | ||||
|         createSubflow: createSubflow, | ||||
|         convertToSubflow: convertToSubflow, | ||||
|         removeSubflow: removeSubflow, | ||||
|         refresh: refresh, | ||||
|         removeInput: removeSubflowInput, | ||||
|         removeOutput: removeSubflowOutput | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2013, 2016 IBM Corp. | ||||
|  * 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. | ||||
| @@ -17,11 +17,11 @@ RED.sidebar.config = (function() { | ||||
|  | ||||
|  | ||||
|     var content = document.createElement("div"); | ||||
|     content.className = "sidebar-node-config" | ||||
|     content.className = "sidebar-node-config"; | ||||
|  | ||||
|     $('<div class="button-group sidebar-header">'+ | ||||
|       '<a class="sidebar-header-button selected" id="workspace-config-node-filter-all" href="#"><span data-i18n="sidebar.config.filterAll"></span></a>'+ | ||||
|       '<a class="sidebar-header-button" id="workspace-config-node-filter-unused" href="#"><span data-i18n="sidebar.config.filterUnused"></span></a> '+ | ||||
|       '<a class="sidebar-header-button-toggle selected" id="workspace-config-node-filter-all" href="#"><span data-i18n="sidebar.config.filterAll"></span></a>'+ | ||||
|       '<a class="sidebar-header-button-toggle" id="workspace-config-node-filter-unused" href="#"><span data-i18n="sidebar.config.filterUnused"></span></a> '+ | ||||
|       '</div>' | ||||
|     ).appendTo(content); | ||||
|  | ||||
| @@ -113,7 +113,7 @@ RED.sidebar.config = (function() { | ||||
|         if (showUnusedOnly) { | ||||
|             var hiddenCount = nodes.length; | ||||
|             nodes = nodes.filter(function(n) { | ||||
|                 return n.users.length === 0; | ||||
|                 return n._def.hasUsers!==false && n.users.length === 0; | ||||
|             }) | ||||
|             hiddenCount = hiddenCount - nodes.length; | ||||
|             if (hiddenCount > 0) { | ||||
| @@ -131,24 +131,19 @@ RED.sidebar.config = (function() { | ||||
|         } else { | ||||
|             var currentType = ""; | ||||
|             nodes.forEach(function(node) { | ||||
|                 var label = ""; | ||||
|                 if (typeof node._def.label == "function") { | ||||
|                     label = node._def.label.call(node); | ||||
|                 } else { | ||||
|                     label = node._def.label; | ||||
|                 } | ||||
|                 label = label || node.id; | ||||
|                 var label = RED.utils.getNodeLabel(node,node.id); | ||||
|                 if (node.type != currentType) { | ||||
|                     $('<li class="config_node_type">'+node.type+'</li>').appendTo(list); | ||||
|                     currentType = node.type; | ||||
|                 } | ||||
|  | ||||
|                 var entry = $('<li class="palette_node config_node"></li>').appendTo(list); | ||||
|                 var entry = $('<li class="palette_node config_node palette_node_id_'+node.id.replace(/\./g,"-")+'"></li>').appendTo(list); | ||||
|                 $('<div class="palette_label"></div>').text(label).appendTo(entry); | ||||
|  | ||||
|                 var iconContainer = $('<div/>',{class:"palette_icon_container  palette_icon_container_right"}).text(node.users.length).appendTo(entry); | ||||
|                 if (node.users.length === 0) { | ||||
|                     entry.addClass("config_node_unused"); | ||||
|                 if (node._def.hasUsers !== false) { | ||||
|                     var iconContainer = $('<div/>',{class:"palette_icon_container  palette_icon_container_right"}).text(node.users.length).appendTo(entry); | ||||
|                     if (node.users.length === 0) { | ||||
|                         entry.addClass("config_node_unused"); | ||||
|                     } | ||||
|                 } | ||||
|                 entry.on('click',function(e) { | ||||
|                     RED.sidebar.info.refresh(node); | ||||
| @@ -230,10 +225,7 @@ RED.sidebar.config = (function() { | ||||
|             visible: false, | ||||
|             onchange: function() { refreshConfigNodeList(); } | ||||
|         }); | ||||
|  | ||||
|         RED.menu.setAction('menu-item-config-nodes',function() { | ||||
|             RED.sidebar.show('config'); | ||||
|         }) | ||||
|         RED.actions.add("core:show-config-tab",function() {RED.sidebar.show('config')}); | ||||
|  | ||||
|         $("#workspace-config-node-collapse-all").on("click", function(e) { | ||||
|             e.preventDefault(); | ||||
| @@ -274,15 +266,45 @@ RED.sidebar.config = (function() { | ||||
|  | ||||
|  | ||||
|     } | ||||
|     function show(unused) { | ||||
|         if (unused !== undefined) { | ||||
|             if (unused) { | ||||
|     function show(id) { | ||||
|         if (typeof id === 'boolean') { | ||||
|             if (id) { | ||||
|                 $('#workspace-config-node-filter-unused').click(); | ||||
|             } else { | ||||
|                 $('#workspace-config-node-filter-all').click(); | ||||
|             } | ||||
|         } | ||||
|         refreshConfigNodeList(); | ||||
|         if (typeof id === "string") { | ||||
|             $('#workspace-config-node-filter-all').click(); | ||||
|             id = id.replace(/\./g,"-"); | ||||
|             setTimeout(function() { | ||||
|                 var node = $(".palette_node_id_"+id); | ||||
|                 var y = node.position().top; | ||||
|                 var h = node.height(); | ||||
|                 var scrollWindow = $(".sidebar-node-config"); | ||||
|                 var scrollHeight = scrollWindow.height(); | ||||
|  | ||||
|                 if (y+h > scrollHeight) { | ||||
|                     scrollWindow.animate({scrollTop: '-='+(scrollHeight-(y+h)-30)},150); | ||||
|                 } else if (y<0) { | ||||
|                     scrollWindow.animate({scrollTop: '+='+(y-10)},150); | ||||
|                 } | ||||
|                 var flash = 21; | ||||
|                 var flashFunc = function() { | ||||
|                     if ((flash%2)===0) { | ||||
|                         node.removeClass('node_highlighted'); | ||||
|                     } else { | ||||
|                         node.addClass('node_highlighted'); | ||||
|                     } | ||||
|                     flash--; | ||||
|                     if (flash >= 0) { | ||||
|                         setTimeout(flashFunc,100); | ||||
|                     } | ||||
|                 } | ||||
|                 flashFunc(); | ||||
|             },100); | ||||
|         } | ||||
|         RED.sidebar.show("config"); | ||||
|     } | ||||
|     return { | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2013, 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -26,21 +26,69 @@ RED.sidebar.info = (function() { | ||||
|         smartypants: false | ||||
|     }); | ||||
|  | ||||
|     var content = document.createElement("div"); | ||||
|     content.style.paddingTop = "4px"; | ||||
|     content.style.paddingLeft = "4px"; | ||||
|     content.style.paddingRight = "4px"; | ||||
|     content.className = "sidebar-node-info" | ||||
|     var content; | ||||
|     var sections; | ||||
|     var nodeSection; | ||||
|     var infoSection; | ||||
|     var tipBox; | ||||
|  | ||||
|     var propertiesExpanded = false; | ||||
|     var expandedSections = { | ||||
|         "property": false | ||||
|     }; | ||||
|  | ||||
|     function init() { | ||||
|  | ||||
|         content = document.createElement("div"); | ||||
|         content.className = "sidebar-node-info" | ||||
|  | ||||
|         RED.actions.add("core:show-info-tab",show); | ||||
|  | ||||
|         var stackContainer = $("<div>",{class:"sidebar-node-info-stack"}).appendTo(content); | ||||
|  | ||||
|         sections = RED.stack.create({ | ||||
|             container: stackContainer | ||||
|         }).hide(); | ||||
|  | ||||
|         nodeSection = sections.add({ | ||||
|             title: "Node", | ||||
|             collapsible: false | ||||
|         }); | ||||
|         infoSection = sections.add({ | ||||
|             title: "Information", | ||||
|             collapsible: false | ||||
|         }); | ||||
|         infoSection.content.css("padding","6px"); | ||||
|         infoSection.container.css("border-bottom","none"); | ||||
|  | ||||
|         var tipContainer = $('<div class="node-info-tips"></div>').appendTo(content); | ||||
|         tipBox = $('<div class="node-info-tip"></div>').appendTo(tipContainer); | ||||
|         var tipButtons = $('<div class="node-info-tips-buttons"></div>').appendTo(tipContainer); | ||||
|  | ||||
|         var tipRefresh = $('<a href="#" class="workspace-footer-button"><i class="fa fa-refresh"></a>').appendTo(tipButtons); | ||||
|         tipRefresh.click(function(e) { | ||||
|             e.preventDefault(); | ||||
|             tips.next(); | ||||
|         }) | ||||
|  | ||||
|         var tipClose = $('<a href="#" class="workspace-footer-button"><i class="fa fa-times"></a>').appendTo(tipButtons); | ||||
|         tipClose.click(function(e) { | ||||
|             e.preventDefault(); | ||||
|             RED.actions.invoke("core:toggle-show-tips"); | ||||
|             RED.notify(RED._("sidebar.info.showTips")); | ||||
|         }); | ||||
|  | ||||
|         RED.sidebar.addTab({ | ||||
|             id: "info", | ||||
|             label: RED._("sidebar.info.label"), | ||||
|             name: RED._("sidebar.info.name"), | ||||
|             content: content | ||||
|             content: content, | ||||
|             enableOnEdit: true | ||||
|         }); | ||||
|         if (tips.enabled()) { | ||||
|             tips.start(); | ||||
|         } else { | ||||
|             tips.stop(); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
| @@ -65,116 +113,250 @@ RED.sidebar.info = (function() { | ||||
|         return value; | ||||
|     } | ||||
|  | ||||
|     function refresh(node) { | ||||
|         var table = '<table class="node-info"><tbody>'; | ||||
|         table += '<tr class="blank"><td colspan="2">'+RED._("sidebar.info.node")+'</td></tr>'; | ||||
|         if (node.type != "subflow" && node.name) { | ||||
|             table += "<tr><td>"+RED._("common.label.name")+"</td><td> "+node.name+"</td></tr>"; | ||||
|         } | ||||
|         table += "<tr><td>"+RED._("sidebar.info.type")+"</td><td> "+node.type+"</td></tr>"; | ||||
|         table += "<tr><td>"+RED._("sidebar.info.id")+"</td><td> "+node.id+"</td></tr>"; | ||||
|  | ||||
|         var m = /^subflow(:(.+))?$/.exec(node.type); | ||||
|         var subflowNode; | ||||
|         if (m) { | ||||
|             if (m[2]) { | ||||
|                 subflowNode = RED.nodes.subflow(m[2]); | ||||
|             } else { | ||||
|                 subflowNode = node; | ||||
|     function addTargetToExternalLinks(el) { | ||||
|         $(el).find("a").each(function(el) { | ||||
|             var href = $(this).attr('href'); | ||||
|             if (/^https?:/.test(href)) { | ||||
|                 $(this).attr('target','_blank'); | ||||
|             } | ||||
|         }); | ||||
|         return el; | ||||
|     } | ||||
|     function refresh(node) { | ||||
|         sections.show(); | ||||
|         $(nodeSection.content).empty(); | ||||
|         $(infoSection.content).empty(); | ||||
|  | ||||
|             table += '<tr class="blank"><td colspan="2">'+RED._("sidebar.info.subflow")+'</td></tr>'; | ||||
|         var table = $('<table class="node-info"></table>'); | ||||
|         var tableBody = $('<tbody>').appendTo(table); | ||||
|         var propRow; | ||||
|         var subflowNode; | ||||
|         if (node.type === "tab") { | ||||
|             nodeSection.title.html("Flow"); | ||||
|             propRow = $('<tr class="node-info-node-row"><td>Name</td><td></td></tr>').appendTo(tableBody); | ||||
|             $(propRow.children()[1]).html(' '+(node.label||"")) | ||||
|             propRow = $('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.id")+"</td><td></td></tr>").appendTo(tableBody); | ||||
|             RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]); | ||||
|             propRow = $('<tr class="node-info-node-row"><td>Status</td><td></td></tr>').appendTo(tableBody); | ||||
|             $(propRow.children()[1]).html((!!!node.disabled)?"Enabled":"Disabled") | ||||
|         } else { | ||||
|             nodeSection.title.html("Node"); | ||||
|             if (node.type !== "subflow" && node.name) { | ||||
|                 $('<tr class="node-info-node-row"><td>'+RED._("common.label.name")+'</td><td> <span class="bidiAware" dir="'+RED.text.bidi.resolveBaseTextDir(node.name)+'">'+node.name+'</span></td></tr>').appendTo(tableBody); | ||||
|             } | ||||
|             $('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.type")+"</td><td> "+node.type+"</td></tr>").appendTo(tableBody); | ||||
|             propRow = $('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.id")+"</td><td></td></tr>").appendTo(tableBody); | ||||
|             RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]); | ||||
|  | ||||
|             var userCount = 0; | ||||
|             var subflowType = "subflow:"+subflowNode.id; | ||||
|             RED.nodes.eachNode(function(n) { | ||||
|                 if (n.type === subflowType) { | ||||
|                     userCount++; | ||||
|                 } | ||||
|             }); | ||||
|             table += "<tr><td>"+RED._("common.label.name")+"</td><td>"+subflowNode.name+"</td></tr>"; | ||||
|             table += "<tr><td>"+RED._("sidebar.info.instances")+"</td><td>"+userCount+"</td></tr>"; | ||||
|         } | ||||
|             var m = /^subflow(:(.+))?$/.exec(node.type); | ||||
|  | ||||
|             if (!m && node.type != "subflow" && node.type != "comment") { | ||||
|                 if (node._def) { | ||||
|                     var count = 0; | ||||
|                     var defaults = node._def.defaults; | ||||
|                     for (var n in defaults) { | ||||
|                         if (n != "name" && defaults.hasOwnProperty(n)) { | ||||
|                             var val = node[n]; | ||||
|                             var type = typeof val; | ||||
|                             count++; | ||||
|                             propRow = $('<tr class="node-info-property-row'+(expandedSections.property?"":" hide")+'"><td>'+n+"</td><td></td></tr>").appendTo(tableBody); | ||||
|                             if (defaults[n].type) { | ||||
|                                 var configNode = RED.nodes.node(val); | ||||
|                                 if (!configNode) { | ||||
|                                     RED.utils.createObjectElement(undefined).appendTo(propRow.children()[1]); | ||||
|                                 } else { | ||||
|                                     var configLabel = RED.utils.getNodeLabel(configNode,val); | ||||
|                                     var container = propRow.children()[1]; | ||||
|  | ||||
|                                     var div = $('<span>',{class:""}).appendTo(container); | ||||
|                                     var nodeDiv = $('<div>',{class:"palette_node palette_node_small"}).appendTo(div); | ||||
|                                     var colour = configNode._def.color; | ||||
|                                     var icon_url = RED.utils.getNodeIcon(configNode._def); | ||||
|                                     nodeDiv.css({'backgroundColor':colour, "cursor":"pointer"}); | ||||
|                                     var iconContainer = $('<div/>',{class:"palette_icon_container"}).appendTo(nodeDiv); | ||||
|                                     $('<div/>',{class:"palette_icon",style:"background-image: url("+icon_url+")"}).appendTo(iconContainer); | ||||
|                                     var nodeContainer = $('<span></span>').css({"verticalAlign":"top","marginLeft":"6px"}).html(configLabel).appendTo(container); | ||||
|  | ||||
|                                     nodeDiv.on('dblclick',function() { | ||||
|                                         RED.editor.editConfig("", configNode.type, configNode.id); | ||||
|                                     }) | ||||
|  | ||||
|         if (!m && node.type != "subflow" && node.type != "comment") { | ||||
|             table += '<tr class="blank"><td colspan="2"><a href="#" class="node-info-property-header"><i style="width: 10px; text-align: center;" class="fa fa-caret-'+(propertiesExpanded?"down":"right")+'"></i> '+RED._("sidebar.info.properties")+'</a></td></tr>'; | ||||
|             if (node._def) { | ||||
|                 for (var n in node._def.defaults) { | ||||
|                     if (n != "name" && node._def.defaults.hasOwnProperty(n)) { | ||||
|                         var val = node[n]||""; | ||||
|                         var type = typeof val; | ||||
|                         if (type === "string") { | ||||
|                             if (val.length === 0) { | ||||
|                                 val += '<span style="font-style: italic; color: #ccc;">'+RED._("sidebar.info.blank")+'</span>'; | ||||
|                             } else { | ||||
|                                 if (val.length > 30) { | ||||
|                                     val = val.substring(0,30)+" ..."; | ||||
|                                 } | ||||
|                                 val = val.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"); | ||||
|                             } else { | ||||
|                                 RED.utils.createObjectElement(val).appendTo(propRow.children()[1]); | ||||
|                             } | ||||
|                         } else if (type === "number") { | ||||
|                             val = val.toString(); | ||||
|                         } else if ($.isArray(val)) { | ||||
|                             val = "[<br/>"; | ||||
|                             for (var i=0;i<Math.min(node[n].length,10);i++) { | ||||
|                                 var vv = JSON.stringify(node[n][i],jsonFilter," ").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"); | ||||
|                                 val += " "+i+": "+vv+"<br/>"; | ||||
|                             } | ||||
|                             if (node[n].length > 10) { | ||||
|                                 val += " ... "+RED._("sidebar.info.arrayItems",{count:node[n].length})+"<br/>"; | ||||
|                             } | ||||
|                             val += "]"; | ||||
|                         } else { | ||||
|                             val = JSON.stringify(val,jsonFilter," "); | ||||
|                             val = val.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"); | ||||
|                         } | ||||
|  | ||||
|                         table += '<tr class="node-info-property-row'+(propertiesExpanded?"":" hide")+'"><td>'+n+"</td><td>"+val+"</td></tr>"; | ||||
|                     } | ||||
|                     if (count > 0) { | ||||
|                         $('<tr class="node-info-property-expand blank"><td colspan="2"><a href="#" class=" node-info-property-header'+(expandedSections.property?" expanded":"")+'"><span class="node-info-property-show-more">show more</span><span class="node-info-property-show-less">show less</span> <i class="fa fa-caret-down"></i></a></td></tr>').appendTo(tableBody); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (m) { | ||||
|                 if (m[2]) { | ||||
|                     subflowNode = RED.nodes.subflow(m[2]); | ||||
|                 } else { | ||||
|                     subflowNode = node; | ||||
|                 } | ||||
|  | ||||
|                 $('<tr class="blank"><th colspan="2">'+RED._("sidebar.info.subflow")+'</th></tr>').appendTo(tableBody); | ||||
|  | ||||
|                 var userCount = 0; | ||||
|                 var subflowType = "subflow:"+subflowNode.id; | ||||
|                 RED.nodes.eachNode(function(n) { | ||||
|                     if (n.type === subflowType) { | ||||
|                         userCount++; | ||||
|                     } | ||||
|                 }); | ||||
|                 $('<tr class="node-info-subflow-row"><td>'+RED._("common.label.name")+'</td><td><span class="bidiAware" dir=\"'+RED.text.bidi.resolveBaseTextDir(subflowNode.name)+'">'+subflowNode.name+'</span></td></tr>').appendTo(tableBody); | ||||
|                 $('<tr class="node-info-subflow-row"><td>'+RED._("sidebar.info.instances")+"</td><td>"+userCount+'</td></tr>').appendTo(tableBody); | ||||
|             } | ||||
|         } | ||||
|         table += "</tbody></table><hr/>"; | ||||
|         if (!subflowNode && node.type != "comment") { | ||||
|             var helpText = $("script[data-help-name|='"+node.type+"']").html()||""; | ||||
|             table  += '<div class="node-help">'+helpText+"</div>"; | ||||
|         $(table).appendTo(nodeSection.content); | ||||
|  | ||||
|         var infoText = ""; | ||||
|  | ||||
|         if (!subflowNode && node.type !== "comment" && node.type !== "tab") { | ||||
|             var helpText = $("script[data-help-name='"+node.type+"']").html()||""; | ||||
|             infoText = helpText; | ||||
|         } else if (node.type === "tab") { | ||||
|             infoText = marked(node.info||""); | ||||
|         } | ||||
|  | ||||
|         if (subflowNode) { | ||||
|             table += '<div class="node-help">'+marked(subflowNode.info||"")+'</div>'; | ||||
|             infoText = infoText + marked(subflowNode.info||""); | ||||
|         } else if (node._def && node._def.info) { | ||||
|             var info = node._def.info; | ||||
|             table += '<div class="node-help">'+marked(typeof info === "function" ? info.call(node) : info)+'</div>'; | ||||
|             //table += '<div class="node-help">'+(typeof info === "function" ? info.call(node) : info)+'</div>'; | ||||
|             var textInfo = (typeof info === "function" ? info.call(node) : info); | ||||
|             // TODO: help | ||||
|             infoText = infoText + marked(textInfo); | ||||
|         } | ||||
|         if (infoText) { | ||||
|             setInfoText(infoText); | ||||
|         } | ||||
|  | ||||
|         $(content).html(table); | ||||
|  | ||||
|         $(".node-info-property-header").click(function(e) { | ||||
|             var icon = $(this).find("i"); | ||||
|             if (icon.hasClass("fa-caret-right")) { | ||||
|                 icon.removeClass("fa-caret-right"); | ||||
|                 icon.addClass("fa-caret-down"); | ||||
|                 $(".node-info-property-row").show(); | ||||
|                 propertiesExpanded = true; | ||||
|             } else { | ||||
|                 icon.addClass("fa-caret-right"); | ||||
|                 icon.removeClass("fa-caret-down"); | ||||
|                 $(".node-info-property-row").hide(); | ||||
|                 propertiesExpanded = false; | ||||
|             } | ||||
|  | ||||
|             e.preventDefault(); | ||||
|             expandedSections["property"] = !expandedSections["property"]; | ||||
|             $(this).toggleClass("expanded",expandedSections["property"]); | ||||
|             $(".node-info-property-row").toggle(expandedSections["property"]); | ||||
|         }); | ||||
|     } | ||||
|     function setInfoText(infoText) { | ||||
|         var info = addTargetToExternalLinks($('<div class="node-help"><span class="bidiAware" dir=\"'+RED.text.bidi.resolveBaseTextDir(infoText)+'">'+infoText+'</span></div>')).appendTo(infoSection.content); | ||||
|         info.find(".bidiAware").contents().filter(function() { return this.nodeType === 3 && this.textContent.trim() !== "" }).wrap( "<span></span>" ); | ||||
|         var foldingHeader = "H3"; | ||||
|         info.find(foldingHeader).wrapInner('<a class="node-info-header expanded" href="#"></a>') | ||||
|             .find("a").prepend('<i class="fa fa-angle-right">').click(function(e) { | ||||
|                 e.preventDefault(); | ||||
|                 var isExpanded = $(this).hasClass('expanded'); | ||||
|                 var el = $(this).parent().next(); | ||||
|                 while(el.length === 1 && el[0].nodeName !== foldingHeader) { | ||||
|                     el.toggle(!isExpanded); | ||||
|                     el = el.next(); | ||||
|                 } | ||||
|                 $(this).toggleClass('expanded',!isExpanded); | ||||
|             }) | ||||
|     } | ||||
|     var tips = (function() { | ||||
|         var enabled = true; | ||||
|         var startDelay = 1000; | ||||
|         var cycleDelay = 15000; | ||||
|         var startTimeout; | ||||
|         var refreshTimeout; | ||||
|         var tipCount = -1; | ||||
|  | ||||
|         RED.actions.add("core:toggle-show-tips",function(state) { | ||||
|             if (state === undefined) { | ||||
|                 RED.userSettings.toggle("view-show-tips"); | ||||
|             } else { | ||||
|                 enabled = state; | ||||
|                 if (enabled) { | ||||
|                     startTips(); | ||||
|                 } else { | ||||
|                     stopTips(); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         function setTip() { | ||||
|             var r = Math.floor(Math.random() * tipCount); | ||||
|             var tip = RED._("infotips:info.tip"+r); | ||||
|  | ||||
|             var m; | ||||
|             while ((m=/({{(.*?)}})/.exec(tip))) { | ||||
|                 var shortcut = RED.keyboard.getShortcut(m[2]); | ||||
|                 if (shortcut) { | ||||
|                     tip = tip.replace(m[1],RED.keyboard.formatKey(shortcut.key)); | ||||
|                 } else { | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|             while ((m=/(\[(.*?)\])/.exec(tip))) { | ||||
|                 tip = tip.replace(m[1],RED.keyboard.formatKey(m[2])); | ||||
|             } | ||||
|             tipBox.html(tip).fadeIn(200); | ||||
|             if (startTimeout) { | ||||
|                 startTimeout = null; | ||||
|                 refreshTimeout = setInterval(cycleTips,cycleDelay); | ||||
|             } | ||||
|         } | ||||
|         function cycleTips() { | ||||
|             tipBox.fadeOut(300,function() { | ||||
|                 setTip(); | ||||
|             }) | ||||
|         } | ||||
|         function startTips() { | ||||
|             $(".sidebar-node-info").addClass('show-tips'); | ||||
|             if (enabled) { | ||||
|                 if (!startTimeout && !refreshTimeout) { | ||||
|                     if (tipCount === -1) { | ||||
|                         do { | ||||
|                             tipCount++; | ||||
|                         } while(RED._("infotips:info.tip"+tipCount)!=="infotips:info.tip"+tipCount); | ||||
|                     } | ||||
|                     startTimeout = setTimeout(setTip,startDelay); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         function stopTips() { | ||||
|             $(".sidebar-node-info").removeClass('show-tips'); | ||||
|             clearInterval(refreshTimeout); | ||||
|             clearTimeout(startTimeout); | ||||
|             refreshTimeout = null; | ||||
|             startTimeout = null; | ||||
|         } | ||||
|         function nextTip() { | ||||
|             clearInterval(refreshTimeout); | ||||
|             startTimeout = true; | ||||
|             setTip(); | ||||
|         } | ||||
|         return { | ||||
|             start: startTips, | ||||
|             stop: stopTips, | ||||
|             next: nextTip, | ||||
|             enabled: function() { return enabled; } | ||||
|         } | ||||
|     })(); | ||||
|  | ||||
|     function clear() { | ||||
|         $(content).html(""); | ||||
|         sections.hide(); | ||||
|         // | ||||
|     } | ||||
|  | ||||
|     function set(html) { | ||||
|         $(content).html(html); | ||||
|         // tips.stop(); | ||||
|         sections.show(); | ||||
|         nodeSection.container.hide(); | ||||
|         $(infoSection.content).empty(); | ||||
|         setInfoText(html); | ||||
|         $(".sidebar-node-info-stack").scrollTop(0); | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     RED.events.on("view:selection-changed",function(selection) { | ||||
|         if (selection.nodes) { | ||||
|             if (selection.nodes.length == 1) { | ||||
| @@ -186,11 +368,18 @@ RED.sidebar.info = (function() { | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             var subflow = RED.nodes.subflow(RED.workspaces.active()); | ||||
|             if (subflow) { | ||||
|                 refresh(subflow); | ||||
|             var activeWS = RED.workspaces.active(); | ||||
|  | ||||
|             var flow = RED.nodes.workspace(activeWS) || RED.nodes.subflow(activeWS); | ||||
|             if (flow) { | ||||
|                 refresh(flow); | ||||
|             } else { | ||||
|                 clear(); | ||||
|                 var workspace = RED.nodes.workspace(RED.workspaces.active()); | ||||
|                 if (workspace && workspace.info) { | ||||
|                     refresh(workspace); | ||||
|                 } else { | ||||
|                     clear(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     }); | ||||
| @@ -198,7 +387,7 @@ RED.sidebar.info = (function() { | ||||
|     return { | ||||
|         init: init, | ||||
|         show: show, | ||||
|         refresh:refresh, | ||||
|         refresh: refresh, | ||||
|         clear: clear, | ||||
|         set: set | ||||
|     } | ||||
|   | ||||
| @@ -1,169 +0,0 @@ | ||||
| /** | ||||
|  * Copyright 2013, 2015 IBM Corp. | ||||
|  * | ||||
|  * 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.tabs = (function() { | ||||
|  | ||||
|  | ||||
|     function createTabs(options) { | ||||
|         var tabs = {}; | ||||
|         var currentTabWidth; | ||||
|         var currentActiveTabWidth = 0; | ||||
|  | ||||
|         var ul = $("#"+options.id) | ||||
|         ul.addClass("red-ui-tabs"); | ||||
|         ul.children().first().addClass("active"); | ||||
|         ul.children().addClass("red-ui-tab"); | ||||
|  | ||||
|         function onTabClick() { | ||||
|             activateTab($(this)); | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         function onTabDblClick() { | ||||
|             if (options.ondblclick) { | ||||
|                 options.ondblclick(tabs[$(this).attr('href').slice(1)]); | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         function activateTab(link) { | ||||
|             if (typeof link === "string") { | ||||
|                 link = ul.find("a[href='#"+link+"']"); | ||||
|             } | ||||
|             if (!link.parent().hasClass("active")) { | ||||
|                 ul.children().removeClass("active"); | ||||
|                 ul.children().css({"transition": "width 100ms"}); | ||||
|                 link.parent().addClass("active"); | ||||
|                 if (options.onchange) { | ||||
|                     options.onchange(tabs[link.attr('href').slice(1)]); | ||||
|                 } | ||||
|                 updateTabWidths(); | ||||
|                 setTimeout(function() { | ||||
|                     ul.children().css({"transition": ""}); | ||||
|                 },100); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         function updateTabWidths() { | ||||
|             var tabs = ul.find("li.red-ui-tab"); | ||||
|             var width = ul.width(); | ||||
|             var tabCount = tabs.size(); | ||||
|             var tabWidth = (width-12-(tabCount*6))/tabCount; | ||||
|             currentTabWidth = 100*tabWidth/width; | ||||
|             currentActiveTabWidth = currentTabWidth+"%"; | ||||
|  | ||||
|             if (options.hasOwnProperty("minimumActiveTabWidth")) { | ||||
|                 if (tabWidth < options.minimumActiveTabWidth) { | ||||
|                     tabCount -= 1; | ||||
|                     tabWidth = (width-12-options.minimumActiveTabWidth-(tabCount*6))/tabCount; | ||||
|                     currentTabWidth = 100*tabWidth/width; | ||||
|                     currentActiveTabWidth = options.minimumActiveTabWidth+"px"; | ||||
|                 } else { | ||||
|                     currentActiveTabWidth = 0; | ||||
|                 } | ||||
|             } | ||||
|             tabs.css({width:currentTabWidth+"%"}); | ||||
|             if (tabWidth < 50) { | ||||
|                 ul.find(".red-ui-tab-close").hide(); | ||||
|                 ul.find(".red-ui-tab-icon").hide(); | ||||
|             } else { | ||||
|                 ul.find(".red-ui-tab-close").show(); | ||||
|                 ul.find(".red-ui-tab-icon").show(); | ||||
|             } | ||||
|             if (currentActiveTabWidth !== 0) { | ||||
|                 ul.find("li.red-ui-tab.active").css({"width":options.minimumActiveTabWidth}); | ||||
|                 ul.find("li.red-ui-tab.active .red-ui-tab-close").show(); | ||||
|                 ul.find("li.red-ui-tab.active .red-ui-tab-icon").show(); | ||||
|             } | ||||
|  | ||||
|         } | ||||
|  | ||||
|         ul.find("li.red-ui-tab a").on("click",onTabClick).on("dblclick",onTabDblClick); | ||||
|         updateTabWidths(); | ||||
|  | ||||
|  | ||||
|         function removeTab(id) { | ||||
|             var li = ul.find("a[href='#"+id+"']").parent(); | ||||
|             if (li.hasClass("active")) { | ||||
|                 var tab = li.prev(); | ||||
|                 if (tab.size() === 0) { | ||||
|                     tab = li.next(); | ||||
|                 } | ||||
|                 activateTab(tab.find("a")); | ||||
|             } | ||||
|             li.remove(); | ||||
|             if (options.onremove) { | ||||
|                 options.onremove(tabs[id]); | ||||
|             } | ||||
|             delete tabs[id]; | ||||
|             updateTabWidths(); | ||||
|         } | ||||
|  | ||||
|         return { | ||||
|             addTab: function(tab) { | ||||
|                 tabs[tab.id] = tab; | ||||
|                 var li = $("<li/>",{class:"red-ui-tab"}).appendTo(ul); | ||||
|                 var link = $("<a/>",{href:"#"+tab.id, class:"red-ui-tab-label"}).appendTo(li); | ||||
|                 if (tab.icon) { | ||||
|                     $('<img src="'+tab.icon+'" class="red-ui-tab-icon"/>').appendTo(link); | ||||
|                 } | ||||
|                 $('<span/>').text(tab.label).appendTo(link); | ||||
|  | ||||
|                 link.on("click",onTabClick); | ||||
|                 link.on("dblclick",onTabDblClick); | ||||
|                 if (tab.closeable) { | ||||
|                     var closeLink = $("<a/>",{href:"#",class:"red-ui-tab-close"}).appendTo(li); | ||||
|                     closeLink.append('<i class="fa fa-times" />'); | ||||
|  | ||||
|                     closeLink.on("click",function(event) { | ||||
|                         removeTab(tab.id); | ||||
|                     }); | ||||
|                 } | ||||
|                 updateTabWidths(); | ||||
|                 if (options.onadd) { | ||||
|                     options.onadd(tab); | ||||
|                 } | ||||
|                 link.attr("title",tab.label); | ||||
|                 if (ul.find("li.red-ui-tab").size() == 1) { | ||||
|                     activateTab(link); | ||||
|                 } | ||||
|             }, | ||||
|             removeTab: removeTab, | ||||
|             activateTab: activateTab, | ||||
|             resize: updateTabWidths, | ||||
|             count: function() { | ||||
|                 return ul.find("li.red-ui-tab").size(); | ||||
|             }, | ||||
|             contains: function(id) { | ||||
|                 return ul.find("a[href='#"+id+"']").length > 0; | ||||
|             }, | ||||
|             renameTab: function(id,label) { | ||||
|                 tabs[id].label = label; | ||||
|                 var tab = ul.find("a[href='#"+id+"']"); | ||||
|                 tab.attr("title",label); | ||||
|                 tab.find("span").text(label); | ||||
|                 updateTabWidths(); | ||||
|             } | ||||
|  | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         create: createTabs | ||||
|     } | ||||
| })(); | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2014 IBM Corp. | ||||
|  * 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. | ||||
|   | ||||
							
								
								
									
										259
									
								
								editor/js/ui/tray.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,259 @@ | ||||
| /** | ||||
|  * 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.tray = (function() { | ||||
|  | ||||
|     var stack = []; | ||||
|     var editorStack = $("#editor-stack"); | ||||
|     var openingTray = false; | ||||
|  | ||||
|     function resize() { | ||||
|  | ||||
|     } | ||||
|     function showTray(options) { | ||||
|         var el = $('<div class="editor-tray"></div>'); | ||||
|         var header = $('<div class="editor-tray-header"></div>').appendTo(el); | ||||
|         var bodyWrapper = $('<div class="editor-tray-body-wrapper"></div>').appendTo(el); | ||||
|         var body = $('<div class="editor-tray-body"></div>').appendTo(bodyWrapper); | ||||
|         var footer = $('<div class="editor-tray-footer"></div>').appendTo(el); | ||||
|         var resizer = $('<div class="editor-tray-resize-handle"></div>').appendTo(el); | ||||
|         // var growButton = $('<a class="editor-tray-resize-button" style="cursor: w-resize;"><i class="fa fa-angle-left"></i></a>').appendTo(resizer); | ||||
|         // var shrinkButton = $('<a class="editor-tray-resize-button" style="cursor: e-resize;"><i style="margin-left: 1px;" class="fa fa-angle-right"></i></a>').appendTo(resizer); | ||||
|         if (options.title) { | ||||
|             $('<div class="editor-tray-titlebar">'+options.title+'</div>').appendTo(header); | ||||
|         } | ||||
|         var buttonBar = $('<div class="editor-tray-toolbar"></div>').appendTo(header); | ||||
|         var primaryButton; | ||||
|         if (options.buttons) { | ||||
|             for (var i=0;i<options.buttons.length;i++) { | ||||
|                 var button = options.buttons[i]; | ||||
|                 var b = $('<button>').button().appendTo(buttonBar); | ||||
|                 if (button.id) { | ||||
|                     b.attr('id',button.id); | ||||
|                 } | ||||
|                 if (button.text) { | ||||
|                     b.html(button.text); | ||||
|                 } | ||||
|                 if (button.click) { | ||||
|                     b.click((function(action) { | ||||
|                         return function(evt) { | ||||
|                             if (!$(this).hasClass('disabled')) { | ||||
|                                 action(evt); | ||||
|                             } | ||||
|                         }; | ||||
|                     })(button.click)); | ||||
|                 } | ||||
|                 if (button.class) { | ||||
|                     b.addClass(button.class); | ||||
|                     if (button.class === "primary") { | ||||
|                         primaryButton = button; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         el.appendTo(editorStack); | ||||
|         var tray = { | ||||
|             tray: el, | ||||
|             header: header, | ||||
|             body: body, | ||||
|             footer: footer, | ||||
|             options: options, | ||||
|             primaryButton: primaryButton | ||||
|         }; | ||||
|         stack.push(tray); | ||||
|  | ||||
|         el.draggable({ | ||||
|                 handle: resizer, | ||||
|                 axis: "x", | ||||
|                 start:function(event,ui) { | ||||
|                     el.width('auto'); | ||||
|                 }, | ||||
|                 drag: function(event,ui) { | ||||
|                     var absolutePosition = editorStack.position().left+ui.position.left | ||||
|                     if (absolutePosition < 7) { | ||||
|                         ui.position.left += 7-absolutePosition; | ||||
|                     } else if (ui.position.left > -tray.preferredWidth-1) { | ||||
|                         ui.position.left = -Math.min(editorStack.position().left-7,tray.preferredWidth-1); | ||||
|                     } | ||||
|                     if (tray.options.resize) { | ||||
|                         setTimeout(function() { | ||||
|                             tray.options.resize({width: -ui.position.left}); | ||||
|                         },0); | ||||
|                     } | ||||
|                     tray.width = -ui.position.left; | ||||
|                 }, | ||||
|                 stop:function(event,ui) { | ||||
|                     el.width(-ui.position.left); | ||||
|                     el.css({left:''}); | ||||
|                     if (tray.options.resize) { | ||||
|                         tray.options.resize({width: -ui.position.left}); | ||||
|                     } | ||||
|                     tray.width = -ui.position.left; | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|         function finishBuild() { | ||||
|             $("#header-shade").show(); | ||||
|             $("#editor-shade").show(); | ||||
|             $("#palette-shade").show(); | ||||
|             $(".sidebar-shade").show(); | ||||
|  | ||||
|             tray.preferredWidth = Math.max(el.width(),500); | ||||
|             body.css({"minWidth":tray.preferredWidth-40}); | ||||
|  | ||||
|             if (options.width) { | ||||
|                 if (options.width > $("#editor-stack").position().left-8) { | ||||
|                     options.width = $("#editor-stack").position().left-8; | ||||
|                 } | ||||
|                 el.width(options.width); | ||||
|             } else { | ||||
|                 el.width(tray.preferredWidth); | ||||
|             } | ||||
|  | ||||
|             tray.width = el.width(); | ||||
|             if (tray.width > $("#editor-stack").position().left-8) { | ||||
|                 tray.width = Math.max(0/*tray.preferredWidth*/,$("#editor-stack").position().left-8); | ||||
|                 el.width(tray.width); | ||||
|             } | ||||
|  | ||||
|             // tray.body.parent().width(Math.min($("#editor-stack").position().left-8,tray.width)); | ||||
|  | ||||
|             el.css({ | ||||
|                 right: -(el.width()+10)+"px", | ||||
|                 transition: "right 0.25s ease" | ||||
|             }); | ||||
|             $("#workspace").scrollLeft(0); | ||||
|             handleWindowResize(); | ||||
|             openingTray = true; | ||||
|             setTimeout(function() { | ||||
|                 setTimeout(function() { | ||||
|                     if (!options.width) { | ||||
|                         el.width(Math.min(tray.preferredWidth,$("#editor-stack").position().left-8)); | ||||
|                     } | ||||
|                     if (options.resize) { | ||||
|                         options.resize({width:el.width()}); | ||||
|                     } | ||||
|                     if (options.show) { | ||||
|                         options.show(); | ||||
|                     } | ||||
|                     setTimeout(function() { | ||||
|                         // Delay resetting the flag, so we don't close prematurely | ||||
|                         openingTray = false; | ||||
|                     },200); | ||||
|                     body.find(":focusable:first").focus(); | ||||
|  | ||||
|                 },150); | ||||
|                 el.css({right:0}); | ||||
|             },0); | ||||
|         } | ||||
|         if (options.open) { | ||||
|             if (options.open.length === 1) { | ||||
|                 options.open(el); | ||||
|                 finishBuild(); | ||||
|             } else { | ||||
|                 options.open(el,finishBuild); | ||||
|             } | ||||
|         } else { | ||||
|             finishBuild(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function handleWindowResize() { | ||||
|         if (stack.length > 0) { | ||||
|             var tray = stack[stack.length-1]; | ||||
|             var trayHeight = tray.tray.height()-tray.header.outerHeight()-tray.footer.outerHeight(); | ||||
|             tray.body.height(trayHeight); | ||||
|             if (tray.width > $("#editor-stack").position().left-8) { | ||||
|                 tray.width = $("#editor-stack").position().left-8; | ||||
|                 tray.tray.width(tray.width); | ||||
|                 // tray.body.parent().width(tray.width); | ||||
|             } else if (tray.width < tray.preferredWidth) { | ||||
|                 tray.width = Math.min($("#editor-stack").position().left-8,tray.preferredWidth); | ||||
|                 tray.tray.width(tray.width); | ||||
|                 // tray.body.parent().width(tray.width); | ||||
|             } | ||||
|             if (tray.options.resize) { | ||||
|                 tray.options.resize({width:tray.width, height:trayHeight}); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         init: function init() { | ||||
|             $(window).resize(handleWindowResize); | ||||
|             RED.events.on("sidebar:resize",handleWindowResize); | ||||
|             $("#editor-shade").click(function() { | ||||
|                 if (!openingTray) { | ||||
|                     var tray = stack[stack.length-1]; | ||||
|                     if (tray && tray.primaryButton) { | ||||
|                         tray.primaryButton.click(); | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|         }, | ||||
|         show: function show(options) { | ||||
|             if (stack.length > 0) { | ||||
|                 var oldTray = stack[stack.length-1]; | ||||
|                 oldTray.tray.css({ | ||||
|                     right: -(oldTray.tray.width()+10)+"px" | ||||
|                 }); | ||||
|                 setTimeout(function() { | ||||
|                     oldTray.tray.detach(); | ||||
|                     showTray(options); | ||||
|                 },250) | ||||
|             } else { | ||||
|                 RED.events.emit("editor:open"); | ||||
|                 showTray(options); | ||||
|             } | ||||
|  | ||||
|         }, | ||||
|         close: function close(done) { | ||||
|             if (stack.length > 0) { | ||||
|                 var tray = stack.pop(); | ||||
|                 tray.tray.css({ | ||||
|                     right: -(tray.tray.width()+10)+"px" | ||||
|                 }); | ||||
|                 setTimeout(function() { | ||||
|                     if (tray.options.close) { | ||||
|                         tray.options.close(); | ||||
|                     } | ||||
|                     tray.tray.remove(); | ||||
|                     if (stack.length > 0) { | ||||
|                         var oldTray = stack[stack.length-1]; | ||||
|                         oldTray.tray.appendTo("#editor-stack"); | ||||
|                         setTimeout(function() { | ||||
|                             handleWindowResize(); | ||||
|                             oldTray.tray.css({right:0}); | ||||
|                             if (oldTray.options.show) { | ||||
|                                 oldTray.options.show(); | ||||
|                             } | ||||
|                         },0); | ||||
|                     } | ||||
|                     if (done) { | ||||
|                         done(); | ||||
|                     } | ||||
|                     if (stack.length === 0) { | ||||
|                         $("#header-shade").hide(); | ||||
|                         $("#editor-shade").hide(); | ||||
|                         $("#palette-shade").hide(); | ||||
|                         $(".sidebar-shade").hide(); | ||||
|                         RED.events.emit("editor:close"); | ||||
|                         RED.view.focus(); | ||||
|                     } | ||||
|                 },250) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| })(); | ||||
							
								
								
									
										295
									
								
								editor/js/ui/typeSearch.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,295 @@ | ||||
| RED.typeSearch = (function() { | ||||
|  | ||||
|     var shade; | ||||
|  | ||||
|     var disabled = false; | ||||
|     var dialog = null; | ||||
|     var searchInput; | ||||
|     var searchResults; | ||||
|     var searchResultsDiv; | ||||
|     var selected = -1; | ||||
|     var visible = false; | ||||
|  | ||||
|     var activeFilter = ""; | ||||
|     var addCallback; | ||||
|  | ||||
|     var typesUsed = {}; | ||||
|  | ||||
|     function search(val) { | ||||
|         activeFilter = val.toLowerCase(); | ||||
|         var visible = searchResults.editableList('filter'); | ||||
|         setTimeout(function() { | ||||
|             selected = 0; | ||||
|             searchResults.children().removeClass('selected'); | ||||
|             searchResults.children(":visible:first").addClass('selected'); | ||||
|         },100); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     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() { | ||||
|         //shade = $('<div>',{class:"red-ui-type-search-shade"}).appendTo("#main-container"); | ||||
|         dialog = $("<div>",{id:"red-ui-type-search",class:"red-ui-search red-ui-type-search"}).appendTo("#main-container"); | ||||
|         var searchDiv = $("<div>",{class:"red-ui-search-container"}).appendTo(dialog); | ||||
|         searchInput = $('<input type="text">').attr("placeholder",RED._("search.addNode")).appendTo(searchDiv).searchBox({ | ||||
|             delay: 50, | ||||
|             change: function() { | ||||
|                 search($(this).val()); | ||||
|             } | ||||
|         }); | ||||
|         searchInput.on('keydown',function(evt) { | ||||
|             var children = searchResults.children(":visible"); | ||||
|             if (children.length > 0) { | ||||
|                 if (evt.keyCode === 40) { | ||||
|                     // Down | ||||
|                     if (selected < children.length-1) { | ||||
|                         if (selected > -1) { | ||||
|                             $(children[selected]).removeClass('selected'); | ||||
|                         } | ||||
|                         selected++; | ||||
|                     } | ||||
|                     $(children[selected]).addClass('selected'); | ||||
|                     ensureSelectedIsVisible(); | ||||
|                     evt.preventDefault(); | ||||
|                 } else if (evt.keyCode === 38) { | ||||
|                     // Up | ||||
|                     if (selected > 0) { | ||||
|                         if (selected < children.length) { | ||||
|                             $(children[selected]).removeClass('selected'); | ||||
|                         } | ||||
|                         selected--; | ||||
|                     } | ||||
|                     $(children[selected]).addClass('selected'); | ||||
|                     ensureSelectedIsVisible(); | ||||
|                     evt.preventDefault(); | ||||
|                 } else if (evt.keyCode === 13) { | ||||
|                     // Enter | ||||
|                     var index = Math.max(0,selected); | ||||
|                     if (index < children.length) { | ||||
|                         // TODO: dips into editableList impl details | ||||
|                         confirm($(children[index]).find(".red-ui-editableList-item-content").data('data')); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         searchResultsDiv = $("<div>",{class:"red-ui-search-results-container"}).appendTo(dialog); | ||||
|         searchResults = $('<ol>',{id:"search-result-list", style:"position: absolute;top: 0;bottom: 0;left: 0;right: 0;"}).appendTo(searchResultsDiv).editableList({ | ||||
|             addButton: false, | ||||
|             filter: function(data) { | ||||
|                 if (activeFilter === "" ) { | ||||
|                     return true; | ||||
|                 } | ||||
|                 if (data.recent || data.common) { | ||||
|                     return false; | ||||
|                 } | ||||
|                 return (activeFilter==="")||(data.index.indexOf(activeFilter) > -1); | ||||
|             }, | ||||
|             addItem: function(container,i,object) { | ||||
|                 var def = object.def; | ||||
|                 object.index = object.type.toLowerCase(); | ||||
|                 if (object.separator) { | ||||
|                     container.addClass("red-ui-search-result-separator") | ||||
|                 } | ||||
|                 var div = $('<a>',{href:'#',class:"red-ui-search-result"}).appendTo(container); | ||||
|  | ||||
|                 var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(div); | ||||
|                 var colour = def.color; | ||||
|                 var icon_url = RED.utils.getNodeIcon(def); | ||||
|                 nodeDiv.css('backgroundColor',colour); | ||||
|  | ||||
|                 var iconContainer = $('<div/>',{class:"palette_icon_container"}).appendTo(nodeDiv); | ||||
|                 $('<div/>',{class:"palette_icon",style:"background-image: url("+icon_url+")"}).appendTo(iconContainer); | ||||
|  | ||||
|                 if (def.inputs > 0) { | ||||
|                     $('<div/>',{class:"red-ui-search-result-node-port"}).appendTo(nodeDiv); | ||||
|                 } | ||||
|                 if (def.outputs > 0) { | ||||
|                     $('<div/>',{class:"red-ui-search-result-node-port red-ui-search-result-node-output"}).appendTo(nodeDiv); | ||||
|                 } | ||||
|  | ||||
|                 var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div); | ||||
|  | ||||
|                 var label = object.label; | ||||
|                 object.index += "|"+label.toLowerCase(); | ||||
|  | ||||
|                 $('<div>',{class:"red-ui-search-result-node-label"}).html(label).appendTo(contentDiv); | ||||
|  | ||||
|                 div.click(function(evt) { | ||||
|                     evt.preventDefault(); | ||||
|                     confirm(object); | ||||
|                 }); | ||||
|             }, | ||||
|             scrollOnAdd: false | ||||
|         }); | ||||
|  | ||||
|     } | ||||
|     function confirm(def) { | ||||
|         hide(); | ||||
|         typesUsed[def.type] = Date.now(); | ||||
|         addCallback(def.type); | ||||
|     } | ||||
|  | ||||
|     function handleMouseActivity(evt) { | ||||
|         if (visible) { | ||||
|             var t = $(evt.target); | ||||
|             while (t.prop('nodeName').toLowerCase() !== 'body') { | ||||
|                 if (t.attr('id') === 'red-ui-type-search') { | ||||
|                     return; | ||||
|                 } | ||||
|                 t = t.parent(); | ||||
|             } | ||||
|             hide(true); | ||||
|         } | ||||
|     } | ||||
|     function show(opts) { | ||||
|         if (!visible) { | ||||
|             RED.keyboard.add("*","escape",function(){hide()}); | ||||
|             if (dialog === null) { | ||||
|                 createDialog(); | ||||
|             } | ||||
|             visible = true; | ||||
|             setTimeout(function() { | ||||
|                 $(document).on('mousedown.type-search',handleMouseActivity); | ||||
|                 $(document).on('mouseup.type-search',handleMouseActivity); | ||||
|                 $(document).on('click.type-search',handleMouseActivity); | ||||
|             },200); | ||||
|         } else { | ||||
|             dialog.hide(); | ||||
|             searchResultsDiv.hide(); | ||||
|         } | ||||
|         refreshTypeList(); | ||||
|         addCallback = opts.add; | ||||
|         RED.events.emit("type-search:open"); | ||||
|         //shade.show(); | ||||
|         dialog.css({left:opts.x+"px",top:opts.y+"px"}).show(); | ||||
|         searchResultsDiv.slideDown(300); | ||||
|         setTimeout(function() { | ||||
|             searchResultsDiv.find(".red-ui-editableList-container").scrollTop(0); | ||||
|             searchInput.focus(); | ||||
|         },100); | ||||
|     } | ||||
|     function hide(fast) { | ||||
|         if (visible) { | ||||
|             RED.keyboard.remove("escape"); | ||||
|             visible = false; | ||||
|             if (dialog !== null) { | ||||
|                 searchResultsDiv.slideUp(fast?50:200,function() { | ||||
|                     dialog.hide(); | ||||
|                     searchInput.searchBox('value',''); | ||||
|                 }); | ||||
|                 //shade.hide(); | ||||
|             } | ||||
|             RED.events.emit("type-search:close"); | ||||
|             RED.view.focus(); | ||||
|             $(document).off('mousedown.type-search'); | ||||
|             $(document).off('mouseup.type-search'); | ||||
|             $(document).off('click.type-search'); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function getTypeLabel(type, def) { | ||||
|         var label = type; | ||||
|         if (typeof def.paletteLabel !== "undefined") { | ||||
|             try { | ||||
|                 label = (typeof def.paletteLabel === "function" ? def.paletteLabel.call(def) : def.paletteLabel)||""; | ||||
|                 label += " ("+type+")"; | ||||
|             } catch(err) { | ||||
|                 console.log("Definition error: "+type+".paletteLabel",err); | ||||
|             } | ||||
|         } | ||||
|         return label; | ||||
|     } | ||||
|  | ||||
|     function refreshTypeList() { | ||||
|         var i; | ||||
|         searchResults.editableList('empty'); | ||||
|         searchInput.searchBox('value',''); | ||||
|         selected = -1; | ||||
|         var common = [ | ||||
|             'inject','debug','function','change','switch' | ||||
|         ]; | ||||
|  | ||||
|         var recentlyUsed = Object.keys(typesUsed); | ||||
|         recentlyUsed.sort(function(a,b) { | ||||
|             return typesUsed[b]-typesUsed[a]; | ||||
|         }); | ||||
|         recentlyUsed = recentlyUsed.filter(function(t) { | ||||
|             return common.indexOf(t) === -1; | ||||
|         }); | ||||
|  | ||||
|         var items = []; | ||||
|         RED.nodes.registry.getNodeTypes().forEach(function(t) { | ||||
|             var def = RED.nodes.getType(t); | ||||
|             if (def.category !== 'config' && t !== 'unknown') { | ||||
|                 items.push({type:t,def: def, label:getTypeLabel(t,def)}); | ||||
|             } | ||||
|         }); | ||||
|         items.sort(function(a,b) { | ||||
|             var al = a.label.toLowerCase(); | ||||
|             var bl = b.label.toLowerCase(); | ||||
|             if (al < bl) { | ||||
|                 return -1; | ||||
|             } else if (al === bl) { | ||||
|                 return 0; | ||||
|             } else { | ||||
|                 return 1; | ||||
|             } | ||||
|         }) | ||||
|  | ||||
|         var commonCount = 0; | ||||
|         var item; | ||||
|         for(i=0;i<common.length;i++) { | ||||
|             item = { | ||||
|                 type: common[i], | ||||
|                 common: true, | ||||
|                 def: RED.nodes.getType(common[i]) | ||||
|             }; | ||||
|             item.label = getTypeLabel(item.type,item.def); | ||||
|             if (i === common.length-1) { | ||||
|                 item.separator = true; | ||||
|             } | ||||
|             searchResults.editableList('addItem', item); | ||||
|         } | ||||
|         for(i=0;i<Math.min(5,recentlyUsed.length);i++) { | ||||
|             item = { | ||||
|                 type:recentlyUsed[i], | ||||
|                 def: RED.nodes.getType(recentlyUsed[i]), | ||||
|                 recent: true | ||||
|             }; | ||||
|             item.label = getTypeLabel(item.type,item.def); | ||||
|             if (i === recentlyUsed.length-1) { | ||||
|                 item.separator = true; | ||||
|             } | ||||
|             searchResults.editableList('addItem', item); | ||||
|         } | ||||
|         for (i=0;i<items.length;i++) { | ||||
|             searchResults.editableList('addItem', items[i]); | ||||
|         } | ||||
|         setTimeout(function() { | ||||
|             selected = 0; | ||||
|             searchResults.children(":first").addClass('selected'); | ||||
|         },100); | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         show: show, | ||||
|         hide: hide | ||||
|     }; | ||||
|  | ||||
| })(); | ||||
| @@ -1,306 +0,0 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  **/ | ||||
| (function($) { | ||||
|     var allOptions = { | ||||
|         msg: {value:"msg",label:"msg.",validate:/^[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]+)*/i}, | ||||
|         flow: {value:"flow",label:"flow.",validate:/^[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]+)*/i}, | ||||
|         global: {value:"global",label:"global.",validate:/^[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]+)*/i}, | ||||
|         str: {value:"str",label:"string",icon:"red/images/typedInput/az.png"}, | ||||
|         num: {value:"num",label:"number",icon:"red/images/typedInput/09.png",validate:/^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$/}, | ||||
|         bool: {value:"bool",label:"boolean",icon:"red/images/typedInput/bool.png",options:["true","false"]}, | ||||
|         json: {value:"json",label:"JSON",icon:"red/images/typedInput/json.png", validate: function(v) { try{JSON.parse(v);return true;}catch(e){return false;}}}, | ||||
|         re: {value:"re",label:"regular expression",icon:"red/images/typedInput/re.png"} | ||||
|     }; | ||||
|     var nlsd = false; | ||||
|  | ||||
|     $.widget( "nodered.typedInput", { | ||||
|         _create: function() { | ||||
|             if (!nlsd && RED && RED._) { | ||||
|                 for (var i in allOptions) { | ||||
|                     if (allOptions.hasOwnProperty(i)) { | ||||
|                         allOptions[i].label = RED._("typedInput.type."+i,{defaultValue:allOptions[i].label}); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             nlsd = true; | ||||
|             var that = this; | ||||
|  | ||||
|             this.disarmClick = false; | ||||
|             this.element.addClass('red-ui-typedInput'); | ||||
|             this.uiWidth = this.element.width(); | ||||
|             this.uiSelect = this.element | ||||
|                 .wrap( "<div>" ) | ||||
|                 .parent(); | ||||
|  | ||||
|             ["Right","Left"].forEach(function(d) { | ||||
|                 var m = that.element.css("margin"+d); | ||||
|                 that.uiSelect.css("margin"+d,m); | ||||
|                 that.element.css("margin"+d,0); | ||||
|             }); | ||||
|             this.uiSelect.addClass("red-ui-typedInput-container"); | ||||
|  | ||||
|             this.options.types = this.options.types||Object.keys(allOptions); | ||||
|  | ||||
|             var hasSubOptions = false; | ||||
|             this.typeMap = {}; | ||||
|             this.types = this.options.types.map(function(opt) { | ||||
|                 var result; | ||||
|                 if (typeof opt === 'string') { | ||||
|                     result = allOptions[opt]; | ||||
|                 } else { | ||||
|                     result = opt; | ||||
|                 } | ||||
|                 that.typeMap[result.value] = result; | ||||
|                 if (result.options) { | ||||
|                     hasSubOptions = true; | ||||
|                 } | ||||
|                 return result; | ||||
|             }); | ||||
|  | ||||
|             if (this.options.typeField) { | ||||
|                 this.typeField = $(this.options.typeField).hide(); | ||||
|                 var t = this.typeField.val(); | ||||
|                 if (t && this.typeMap[t]) { | ||||
|                     this.options.default = t; | ||||
|                 } | ||||
|             } else { | ||||
|                 this.typeField = $("<input>",{type:'hidden'}).appendTo(this.uiSelect); | ||||
|             } | ||||
|  | ||||
|             this.selectTrigger = $('<a href="#"><i class="fa fa-sort-desc"></i></a>').prependTo(this.uiSelect); | ||||
|             this.selectLabel = $('<span></span>').appendTo(this.selectTrigger); | ||||
|  | ||||
|             this.element.on('focus', function() { | ||||
|                 that.uiSelect.addClass('red-ui-typedInput-focus'); | ||||
|             }); | ||||
|             this.element.on('blur', function() { | ||||
|                 that.uiSelect.removeClass('red-ui-typedInput-focus'); | ||||
|             }); | ||||
|             this.element.on('change', function() { | ||||
|                 that.validate(); | ||||
|             }) | ||||
|  | ||||
|             this.selectTrigger.click(function(event) { | ||||
|                 event.preventDefault(); | ||||
|                 that._showMenu(that.menu,that.selectTrigger); | ||||
|             }); | ||||
|  | ||||
|  | ||||
|             if (hasSubOptions) { | ||||
|                 // explicitly set optionSelectTrigger display to inline-block otherwise jQ sets it to 'inline' | ||||
|                 this.optionSelectTrigger = $('<a href="#" class="red-ui-typedInput-option-trigger" style="display:inline-block"><i class="fa fa-sort-desc"></i></a>').appendTo(this.uiSelect); | ||||
|                 this.optionSelectLabel = $('<span></span>').prependTo(this.optionSelectTrigger); | ||||
|                 this.optionSelectTrigger.click(function(event) { | ||||
|                     event.preventDefault(); | ||||
|                     if (that.optionMenu) { | ||||
|                         that.optionMenu.css({ | ||||
|                             minWidth:that.optionSelectLabel.width() | ||||
|                         }); | ||||
|  | ||||
|                         that._showMenu(that.optionMenu,that.optionSelectLabel) | ||||
|                     } | ||||
|                 }); | ||||
|             } | ||||
|             this.menu = this._createMenu(this.types, function(v) { that.type(v) }); | ||||
|             this.type(this.options.default||this.types[0].value); | ||||
|         }, | ||||
|         _hideMenu: function(menu) { | ||||
|             $(document).off("mousedown.close-property-select"); | ||||
|             menu.hide(); | ||||
|             this.element.focus(); | ||||
|         }, | ||||
|         _createMenu: function(opts,callback) { | ||||
|             var that = this; | ||||
|             var menu = $("<div>").addClass("red-ui-typedInput-options"); | ||||
|             opts.forEach(function(opt) { | ||||
|                 if (typeof opt === 'string') { | ||||
|                     opt = {value:opt,label:opt}; | ||||
|                 } | ||||
|                 var op = $('<a href="#">').attr("value",opt.value).appendTo(menu); | ||||
|                 if (opt.label) { | ||||
|                     op.text(opt.label); | ||||
|                 } | ||||
|                 if (opt.icon) { | ||||
|                     $('<img>',{src:opt.icon,style:"margin-right: 4px; height: 18px;"}).prependTo(op); | ||||
|                 } else { | ||||
|                     op.css({paddingLeft: "18px"}); | ||||
|                 } | ||||
|  | ||||
|                 op.click(function(event) { | ||||
|                     event.preventDefault(); | ||||
|                     callback(opt.value); | ||||
|                     that._hideMenu(menu); | ||||
|                 }); | ||||
|             }); | ||||
|             menu.css({ | ||||
|                 display: "none", | ||||
|             }); | ||||
|             menu.appendTo(document.body); | ||||
|             return menu; | ||||
|  | ||||
|         }, | ||||
|         _showMenu: function(menu,relativeTo) { | ||||
|             if (this.disarmClick) { | ||||
|                 this.disarmClick = false; | ||||
|                 return | ||||
|             } | ||||
|             var that = this; | ||||
|             var pos = relativeTo.offset(); | ||||
|             var height = relativeTo.height(); | ||||
|             menu.css({ | ||||
|                 top: (height+pos.top-3)+"px", | ||||
|                 left: (2+pos.left)+"px", | ||||
|             }); | ||||
|             menu.slideDown(100); | ||||
|             this._delay(function() { | ||||
|                 that.uiSelect.addClass('red-ui-typedInput-focus'); | ||||
|                 $(document).on("mousedown.close-property-select", function(event) { | ||||
|                     if(!$(event.target).closest(menu).length) { | ||||
|                         that._hideMenu(menu); | ||||
|                     } | ||||
|                     if ($(event.target).closest(relativeTo).length) { | ||||
|                         that.disarmClick = true; | ||||
|                         event.preventDefault(); | ||||
|                     } | ||||
|                 }) | ||||
|             }); | ||||
|         }, | ||||
|         _getLabelWidth: function(label) { | ||||
|             var labelWidth = label.width(); | ||||
|             if (labelWidth === 0) { | ||||
|                 var newTrigger = label.clone(); | ||||
|                 newTrigger.css({ | ||||
|                     position:"absolute", | ||||
|                     top:0, | ||||
|                     left:-1000 | ||||
|                 }).appendTo(document.body); | ||||
|                 labelWidth = newTrigger.width()+4; | ||||
|                 newTrigger.remove(); | ||||
|             } | ||||
|             return labelWidth; | ||||
|         }, | ||||
|         _resize: function() { | ||||
|  | ||||
|             if (this.typeMap[this.propertyType] && this.typeMap[this.propertyType].hasValue === false) { | ||||
|                 this.selectTrigger.width(this.uiWidth+5); | ||||
|             } else { | ||||
|                 this.selectTrigger.width('auto'); | ||||
|                 var labelWidth = this._getLabelWidth(this.selectTrigger); | ||||
|  | ||||
|                 var newWidth = this.uiWidth-labelWidth+4; | ||||
|                 this.element.width(newWidth); | ||||
|  | ||||
|                 if (this.optionSelectTrigger) { | ||||
|                     var triggerWidth = this._getLabelWidth(this.optionSelectTrigger); | ||||
|                     labelWidth = this._getLabelWidth(this.optionSelectLabel)-4; | ||||
|                     this.optionSelectLabel.width(labelWidth+(newWidth-triggerWidth)); | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         _destroy: function() { | ||||
|             this.menu.remove(); | ||||
|         }, | ||||
|         width: function(desiredWidth) { | ||||
|             this.uiWidth = desiredWidth; | ||||
|             this._resize(); | ||||
|         }, | ||||
|         value: function(value) { | ||||
|             if (!arguments.length) { | ||||
|                 return this.element.val(); | ||||
|             } else { | ||||
|                 if (this.typeMap[this.propertyType].options) { | ||||
|                     if (this.typeMap[this.propertyType].options.indexOf(value) === -1) { | ||||
|                         value = ""; | ||||
|                     } | ||||
|                     this.optionSelectLabel.text(value); | ||||
|                 } | ||||
|                 this.element.val(value); | ||||
|                 this.element.trigger('change'); | ||||
|             } | ||||
|         }, | ||||
|         type: function(type) { | ||||
|             if (!arguments.length) { | ||||
|                 return this.propertyType; | ||||
|             } else { | ||||
|                 var opt = this.typeMap[type]; | ||||
|                 if (opt && this.propertyType !== type) { | ||||
|                     this.propertyType = type; | ||||
|                     this.typeField.val(type); | ||||
|                     this.selectLabel.empty(); | ||||
|                     if (opt.icon) { | ||||
|                         $('<img>',{src:opt.icon,style:"margin-right: 4px;height: 18px;"}).prependTo(this.selectLabel); | ||||
|                     } else { | ||||
|                         this.selectLabel.text(opt.label); | ||||
|                     } | ||||
|                     if (opt.options) { | ||||
|                         if (this.optionSelectTrigger) { | ||||
|                             this.optionSelectTrigger.show(); | ||||
|                             this.element.hide(); | ||||
|                             var that = this; | ||||
|                             this.optionMenu = this._createMenu(opt.options,function(v){ | ||||
|                                 that.optionSelectLabel.text(v); | ||||
|                                 that.value(v); | ||||
|                             }); | ||||
|                             var currentVal = this.element.val(); | ||||
|                             if (opt.options.indexOf(currentVal) !== -1) { | ||||
|                                 this.optionSelectLabel.text(currentVal); | ||||
|                             } else { | ||||
|                                 this.value(opt.options[0]); | ||||
|                             } | ||||
|                         } | ||||
|                     } else { | ||||
|                         if (this.optionMenu) { | ||||
|                             this.optionMenu.remove(); | ||||
|                             this.optionMenu = null; | ||||
|                         } | ||||
|                         if (this.optionSelectTrigger) { | ||||
|                             this.optionSelectTrigger.hide(); | ||||
|                         } | ||||
|                         if (opt.hasValue === false) { | ||||
|                             this.element.val(""); | ||||
|                             this.element.hide(); | ||||
|                         } else { | ||||
|                             this.element.show(); | ||||
|                         } | ||||
|                         this.element.trigger('change'); | ||||
|                     } | ||||
|                     this._resize(); | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         validate: function() { | ||||
|             var result; | ||||
|             var value = this.value(); | ||||
|             var type = this.type(); | ||||
|             if (this.typeMap[type] && this.typeMap[type].validate) { | ||||
|                 var val = this.typeMap[type].validate; | ||||
|                 if (typeof val === 'function') { | ||||
|                     result = val(value); | ||||
|                 } else { | ||||
|                     result = val.test(value); | ||||
|                 } | ||||
|             } else { | ||||
|                 result = true; | ||||
|             } | ||||
|             if (result) { | ||||
|                 this.uiSelect.removeClass('input-error'); | ||||
|             } else { | ||||
|                 this.uiSelect.addClass('input-error'); | ||||
|             } | ||||
|             return result; | ||||
|         } | ||||
|     }); | ||||
| })(jQuery); | ||||
							
								
								
									
										223
									
								
								editor/js/ui/userSettings.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,223 @@ | ||||
| /** | ||||
|  * 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.userSettings = (function() { | ||||
|  | ||||
|     var trayWidth = 700; | ||||
|     var settingsVisible = false; | ||||
|  | ||||
|     var panes = []; | ||||
|  | ||||
|     function addPane(options) { | ||||
|         panes.push(options); | ||||
|     } | ||||
|  | ||||
|     function show(initialTab) { | ||||
|         if (settingsVisible) { | ||||
|             return; | ||||
|         } | ||||
|         settingsVisible = true; | ||||
|         var tabContainer; | ||||
|  | ||||
|         var trayOptions = { | ||||
|             title: "User Settings", | ||||
|             buttons: [ | ||||
|                 { | ||||
|                     id: "node-dialog-ok", | ||||
|                     text: RED._("common.label.close"), | ||||
|                     class: "primary", | ||||
|                     click: function() { | ||||
|                         RED.tray.close(); | ||||
|                     } | ||||
|                 } | ||||
|             ], | ||||
|             resize: function(dimensions) { | ||||
|                 trayWidth = dimensions.width; | ||||
|             }, | ||||
|             open: function(tray) { | ||||
|                 var trayBody = tray.find('.editor-tray-body'); | ||||
|                 var settingsContent = $('<div></div>').appendTo(trayBody); | ||||
|                 var tabContainer = $('<div></div>',{id:"user-settings-tabs-container"}).appendTo(settingsContent); | ||||
|  | ||||
|                 $('<ul></ul>',{id:"user-settings-tabs"}).appendTo(tabContainer); | ||||
|                 var settingsTabs = RED.tabs.create({ | ||||
|                     id: "user-settings-tabs", | ||||
|                     vertical: true, | ||||
|                     onchange: function(tab) { | ||||
|                         setTimeout(function() { | ||||
|                             $("#user-settings-tabs-content").children().hide(); | ||||
|                             $("#" + tab.id).show(); | ||||
|                             if (tab.pane.focus) { | ||||
|                                 tab.pane.focus(); | ||||
|                             } | ||||
|                         },50); | ||||
|                     } | ||||
|                 }); | ||||
|                 var tabContents = $('<div></div>',{id:"user-settings-tabs-content"}).appendTo(settingsContent); | ||||
|  | ||||
|                 panes.forEach(function(pane) { | ||||
|                     settingsTabs.addTab({ | ||||
|                         id: "user-settings-tab-"+pane.id, | ||||
|                         label: pane.title, | ||||
|                         pane: pane | ||||
|                     }); | ||||
|                     pane.get().hide().appendTo(tabContents); | ||||
|                 }); | ||||
|                 settingsContent.i18n(); | ||||
|                 settingsTabs.activateTab("user-settings-tab-"+(initialTab||'view')) | ||||
|                 $("#sidebar-shade").show(); | ||||
|             }, | ||||
|             close: function() { | ||||
|                 settingsVisible = false; | ||||
|                 panes.forEach(function(pane) { | ||||
|                     if (pane.close) { | ||||
|                         pane.close(); | ||||
|                     } | ||||
|                 }); | ||||
|                 $("#sidebar-shade").hide(); | ||||
|  | ||||
|             }, | ||||
|             show: function() {} | ||||
|         } | ||||
|         if (trayWidth !== null) { | ||||
|             trayOptions.width = trayWidth; | ||||
|         } | ||||
|         RED.tray.show(trayOptions); | ||||
|     } | ||||
|  | ||||
|     var viewSettings = [ | ||||
|         { | ||||
|             title: "Grid", | ||||
|             options: [ | ||||
|                 {setting:"view-show-grid",oldSetting:"menu-menu-item-view-show-grid",label:"menu.label.view.showGrid",toggle:true,onchange:"core:toggle-show-grid"}, | ||||
|                 {setting:"view-snap-grid",oldSetting:"menu-menu-item-view-snap-grid",label:"menu.label.view.snapGrid",toggle:true,onchange:"core:toggle-snap-grid"}, | ||||
|                 {setting:"view-grid-size",label:"menu.label.view.gridSize",type:"number",default: 20, onchange:RED.view.gridSize} | ||||
|             ] | ||||
|         }, | ||||
|         { | ||||
|             title: "Nodes", | ||||
|             options: [ | ||||
|                 {setting:"view-node-status",oldSetting:"menu-menu-item-status",label:"menu.label.displayStatus",default: true, toggle:true,onchange:"core:toggle-status"} | ||||
|             ] | ||||
|         }, | ||||
|         { | ||||
|             title: "Other", | ||||
|             options: [ | ||||
|                 {setting:"view-show-tips",oldSettings:"menu-menu-item-show-tips",label:"menu.label.showTips",toggle:true,default:true,onchange:"core:toggle-show-tips"} | ||||
|             ] | ||||
|         } | ||||
|     ]; | ||||
|  | ||||
|     var allSettings = {}; | ||||
|  | ||||
|     function createViewPane() { | ||||
|  | ||||
|         var pane = $('<div id="user-settings-tab-view" class="node-help"></div>'); | ||||
|  | ||||
|         viewSettings.forEach(function(section) { | ||||
|             $('<h3></h3>').text(section.title).appendTo(pane); | ||||
|             section.options.forEach(function(opt) { | ||||
|                 var initialState = RED.settings.get(opt.setting); | ||||
|                 var row = $('<div class="user-settings-row"></div>').appendTo(pane); | ||||
|                 var input; | ||||
|                 if (opt.toggle) { | ||||
|                     input = $('<label for="user-settings-'+opt.setting+'"><input id="user-settings-'+opt.setting+'" type="checkbox"> '+RED._(opt.label)+'</label>').appendTo(row).find("input"); | ||||
|                     input.prop('checked',initialState); | ||||
|                 } else { | ||||
|                     $('<label for="user-settings-'+opt.setting+'">'+RED._(opt.label)+'</label>').appendTo(row); | ||||
|                     $('<input id="user-settings-'+opt.setting+'" type="'+(opt.type||"text")+'">').appendTo(row).val(initialState); | ||||
|                 } | ||||
|             }); | ||||
|         }) | ||||
|         return pane; | ||||
|     } | ||||
|  | ||||
|     function setSelected(id, value) { | ||||
|         var opt = allSettings[id]; | ||||
|         RED.settings.set(opt.setting,value); | ||||
|         var callback = opt.onchange; | ||||
|         if (typeof callback === 'string') { | ||||
|             callback = RED.actions.get(callback); | ||||
|         } | ||||
|         if (callback) { | ||||
|             callback.call(opt,value); | ||||
|         } | ||||
|     } | ||||
|     function toggle(id) { | ||||
|         var opt = allSettings[id]; | ||||
|         var state = RED.settings.get(opt.setting); | ||||
|         setSelected(id,!state); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     function init() { | ||||
|         RED.actions.add("core:show-user-settings",show); | ||||
|         RED.actions.add("core:show-help", function() { show('keyboard')}); | ||||
|  | ||||
|         addPane({ | ||||
|             id:'view', | ||||
|             title: 'View', | ||||
|             get: createViewPane, | ||||
|             close: function() { | ||||
|                 viewSettings.forEach(function(section) { | ||||
|                     section.options.forEach(function(opt) { | ||||
|                         var input = $("#user-settings-"+opt.setting); | ||||
|                         if (opt.toggle) { | ||||
|                             setSelected(opt.setting,input.prop('checked')); | ||||
|                         } else { | ||||
|                             setSelected(opt.setting,input.val()); | ||||
|                         } | ||||
|                     }); | ||||
|                 }) | ||||
|             } | ||||
|         }) | ||||
|  | ||||
|         viewSettings.forEach(function(section) { | ||||
|             section.options.forEach(function(opt) { | ||||
|                 if (opt.oldSetting) { | ||||
|                     var oldValue = RED.settings.get(opt.oldSetting); | ||||
|                     if (oldValue !== undefined && oldValue !== null) { | ||||
|                         RED.settings.set(opt.setting,oldValue); | ||||
|                         RED.settings.remove(opt.oldSetting); | ||||
|                     } | ||||
|                 } | ||||
|                 allSettings[opt.setting] = opt; | ||||
|                 if (opt.onchange) { | ||||
|                     var value = RED.settings.get(opt.setting); | ||||
|                     if (value === null && opt.hasOwnProperty('default')) { | ||||
|                         value = opt.default; | ||||
|                         RED.settings.set(opt.setting,value); | ||||
|                     } | ||||
|  | ||||
|                     var callback = opt.onchange; | ||||
|                     if (typeof callback === 'string') { | ||||
|                         callback = RED.actions.get(callback); | ||||
|                     } | ||||
|                     if (callback) { | ||||
|                         callback.call(opt,value); | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|     } | ||||
|     return { | ||||
|         init: init, | ||||
|         toggle: toggle, | ||||
|         show: show, | ||||
|         add: addPane | ||||
|     }; | ||||
| })(); | ||||
							
								
								
									
										621
									
								
								editor/js/ui/utils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,621 @@ | ||||
| /** | ||||
|  * 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.utils = (function() { | ||||
|  | ||||
|     function formatString(str) { | ||||
|         return str.replace(/\r?\n/g,"↵").replace(/\t/g,"→"); | ||||
|     } | ||||
|     function sanitize(m) { | ||||
|         return m.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"); | ||||
|     } | ||||
|  | ||||
|     function buildMessageSummaryValue(value) { | ||||
|         var result; | ||||
|         if (Array.isArray(value)) { | ||||
|             result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('array['+value.length+']'); | ||||
|         } else if (value === null) { | ||||
|             result = $('<span class="debug-message-object-value debug-message-type-null">null</span>'); | ||||
|         } else if (typeof value === 'object') { | ||||
|             if (value.hasOwnProperty('type') && value.type === 'Buffer' && value.hasOwnProperty('data')) { | ||||
|                 result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('buffer['+value.length+']'); | ||||
|             } else if (value.hasOwnProperty('type') && value.type === 'array' && value.hasOwnProperty('data')) { | ||||
|                 result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('array['+value.length+']'); | ||||
|             } else { | ||||
|                 result = $('<span class="debug-message-object-value debug-message-type-meta">object</span>'); | ||||
|             } | ||||
|         } else if (typeof value === 'string') { | ||||
|             var subvalue; | ||||
|             if (value.length > 30) { | ||||
|                 subvalue = sanitize(value.substring(0,30))+"…"; | ||||
|             } else { | ||||
|                 subvalue = sanitize(value); | ||||
|             } | ||||
|             result = $('<span class="debug-message-object-value debug-message-type-string"></span>').html('"'+formatString(subvalue)+'"'); | ||||
|         } else { | ||||
|             result = $('<span class="debug-message-object-value debug-message-type-other"></span>').text(""+value); | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
|     function makeExpandable(el,onexpand,expand) { | ||||
|         el.addClass("debug-message-expandable"); | ||||
|         el.click(function(e) { | ||||
|             var parent = $(this).parent(); | ||||
|             if (parent.hasClass('collapsed')) { | ||||
|                 if (onexpand && !parent.hasClass('built')) { | ||||
|                     onexpand(); | ||||
|                     parent.addClass('built'); | ||||
|                 } | ||||
|                 parent.removeClass('collapsed'); | ||||
|             } else { | ||||
|                 parent.addClass('collapsed'); | ||||
|             } | ||||
|             e.preventDefault(); | ||||
|         }); | ||||
|         if (expand) { | ||||
|             el.click(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     var pinnedPaths = {}; | ||||
|     var formattedPaths = {}; | ||||
|  | ||||
|     function addMessageControls(obj,sourceId,key,msg,rootPath,strippedKey) { | ||||
|         if (!pinnedPaths.hasOwnProperty(sourceId)) { | ||||
|             pinnedPaths[sourceId] = {} | ||||
|         } | ||||
|         var tools = $('<span class="debug-message-tools"></span>').appendTo(obj); | ||||
|         var copyTools = $('<span class="debug-message-tools-copy button-group"></span>').appendTo(tools); | ||||
|         if (!!key) { | ||||
|             var copyPath = $('<button class="editor-button editor-button-small"><i class="fa fa-terminal"></i></button>').appendTo(copyTools).click(function(e) { | ||||
|                 e.preventDefault(); | ||||
|                 e.stopPropagation(); | ||||
|                 RED.clipboard.copyText(key,copyPath,"clipboard.copyMessagePath"); | ||||
|             }) | ||||
|         } | ||||
|         var copyPayload = $('<button class="editor-button editor-button-small"><i class="fa fa-clipboard"></i></button>').appendTo(copyTools).click(function(e) { | ||||
|             e.preventDefault(); | ||||
|             e.stopPropagation(); | ||||
|             RED.clipboard.copyText(msg,copyPayload,"clipboard.copyMessageValue"); | ||||
|         }) | ||||
|         if (strippedKey !== '') { | ||||
|             var isPinned = pinnedPaths[sourceId].hasOwnProperty(strippedKey); | ||||
|  | ||||
|             var pinPath = $('<button class="editor-button editor-button-small debug-message-tools-pin"><i class="fa fa-map-pin"></i></button>').appendTo(tools).click(function(e) { | ||||
|                 e.preventDefault(); | ||||
|                 e.stopPropagation(); | ||||
|                 if (pinnedPaths[sourceId].hasOwnProperty(strippedKey)) { | ||||
|                     delete pinnedPaths[sourceId][strippedKey]; | ||||
|                     $(this).removeClass("selected"); | ||||
|                     obj.removeClass("debug-message-row-pinned"); | ||||
|                 } else { | ||||
|                     var rootedPath = "$"+(strippedKey[0] === '['?"":".")+strippedKey; | ||||
|                     pinnedPaths[sourceId][strippedKey] = normalisePropertyExpression(rootedPath); | ||||
|                     $(this).addClass("selected"); | ||||
|                     obj.addClass("debug-message-row-pinned"); | ||||
|                 } | ||||
|             }).toggleClass("selected",isPinned); | ||||
|             obj.toggleClass("debug-message-row-pinned",isPinned); | ||||
|         } | ||||
|     } | ||||
|     function checkExpanded(strippedKey,expandPaths,minRange,maxRange) { | ||||
|         if (expandPaths && expandPaths.length > 0) { | ||||
|             if (strippedKey === '' && minRange === undefined) { | ||||
|                 return true; | ||||
|             } | ||||
|             for (var i=0;i<expandPaths.length;i++) { | ||||
|                 var p = expandPaths[i]; | ||||
|                 if (p.indexOf(strippedKey) === 0 && (p[strippedKey.length] === "." ||  p[strippedKey.length] === "[") ) { | ||||
|  | ||||
|                     if (minRange !== undefined && p[strippedKey.length] === "[") { | ||||
|                         var subkey = p.substring(strippedKey.length); | ||||
|                         var m = (/\[(\d+)\]/.exec(subkey)); | ||||
|                         if (m) { | ||||
|                             var index = parseInt(m[1]); | ||||
|                             return minRange<=index && index<=maxRange; | ||||
|                         } | ||||
|                     } else { | ||||
|                         return true; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     function formatNumber(element,obj,sourceId,path,cycle,initialFormat) { | ||||
|         var format = (formattedPaths[sourceId] && formattedPaths[sourceId][path]) || initialFormat || "dec"; | ||||
|         if (cycle) { | ||||
|             if (format === 'dec') { | ||||
|                 if ((obj.toString().length===13) && (obj<=2147483647000)) { | ||||
|                     format = 'dateMS'; | ||||
|                 } else if ((obj.toString().length===10) && (obj<=2147483647)) { | ||||
|                     format = 'dateS'; | ||||
|                 } else { | ||||
|                     format = 'hex' | ||||
|                 } | ||||
|             } else if (format === 'dateMS' || format == 'dateS') { | ||||
|                 format = 'hex'; | ||||
|             } else { | ||||
|                 format = 'dec'; | ||||
|             } | ||||
|             formattedPaths[sourceId] = formattedPaths[sourceId]||{}; | ||||
|             formattedPaths[sourceId][path] = format; | ||||
|         } else if (initialFormat !== undefined){ | ||||
|             formattedPaths[sourceId] = formattedPaths[sourceId]||{}; | ||||
|             formattedPaths[sourceId][path] = format; | ||||
|         } | ||||
|         if (format === 'dec') { | ||||
|             element.text(""+obj); | ||||
|         } else if (format === 'dateMS') { | ||||
|             element.text((new Date(obj)).toISOString()); | ||||
|         } else if (format === 'dateS') { | ||||
|             element.text((new Date(obj*1000)).toISOString()); | ||||
|         } else if (format === 'hex') { | ||||
|             element.text("0x"+(obj).toString(16)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function formatBuffer(element,button,sourceId,path,cycle) { | ||||
|         var format = (formattedPaths[sourceId] && formattedPaths[sourceId][path]) || "raw"; | ||||
|         if (cycle) { | ||||
|             if (format === 'raw') { | ||||
|                 format = 'string'; | ||||
|             } else { | ||||
|                 format = 'raw'; | ||||
|             } | ||||
|             formattedPaths[sourceId] = formattedPaths[sourceId]||{}; | ||||
|             formattedPaths[sourceId][path] = format; | ||||
|         } | ||||
|         if (format === 'raw') { | ||||
|             button.text('raw'); | ||||
|             element.removeClass('debug-message-buffer-string').addClass('debug-message-buffer-raw'); | ||||
|         } else if (format === 'string') { | ||||
|             button.text('string'); | ||||
|             element.addClass('debug-message-buffer-string').removeClass('debug-message-buffer-raw'); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function buildMessageElement(obj,key,typeHint,hideKey,path,sourceId,rootPath,expandPaths) { | ||||
|         var i; | ||||
|         var e; | ||||
|         var entryObj; | ||||
|         var header; | ||||
|         var headerHead; | ||||
|         var value; | ||||
|         var strippedKey; | ||||
|         if (path !== undefined && rootPath !== undefined) { | ||||
|              strippedKey = path.substring(rootPath.length+(path[rootPath.length]==="."?1:0)); | ||||
|         } | ||||
|         var element = $('<span class="debug-message-element"></span>'); | ||||
|         element.collapse = function() { | ||||
|             element.find(".debug-message-expandable").parent().addClass("collapsed"); | ||||
|         } | ||||
|         header = $('<span class="debug-message-row"></span>').appendTo(element); | ||||
|         if (sourceId) { | ||||
|             addMessageControls(header,sourceId,path,obj,rootPath,strippedKey); | ||||
|         } | ||||
|         if (!key) { | ||||
|             element.addClass("debug-message-top-level"); | ||||
|             if (sourceId) { | ||||
|                 var pinned = pinnedPaths[sourceId]; | ||||
|                 expandPaths = []; | ||||
|                 if (pinned) { | ||||
|                     for (var pinnedPath in pinned) { | ||||
|                         if (pinned.hasOwnProperty(pinnedPath)) { | ||||
|                             try { | ||||
|                                 var res = getMessageProperty({$:obj},pinned[pinnedPath]); | ||||
|                                 if (res !== undefined) { | ||||
|                                     expandPaths.push(pinnedPath); | ||||
|                                 } | ||||
|                             } catch(err) { | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     expandPaths.sort(); | ||||
|                 } | ||||
|                 element.clearPinned = function() { | ||||
|                     element.find(".debug-message-row-pinned").removeClass("debug-message-row-pinned"); | ||||
|                     pinnedPaths[sourceId] = {}; | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             if (!hideKey) { | ||||
|                 $('<span class="debug-message-object-key"></span>').text(key).appendTo(header); | ||||
|                 $('<span>: </span>').appendTo(header); | ||||
|             } | ||||
|         } | ||||
|         entryObj = $('<span class="debug-message-object-value"></span>').appendTo(header); | ||||
|  | ||||
|         var isArray = Array.isArray(obj); | ||||
|         var isArrayObject = false; | ||||
|         if (obj && typeof obj === 'object' && obj.hasOwnProperty('type') && obj.hasOwnProperty('data') && ((obj.__encoded__ && obj.type === 'array') || obj.type === 'Buffer')) { | ||||
|             isArray = true; | ||||
|             isArrayObject = true; | ||||
|         } | ||||
|  | ||||
|         if (obj === null || obj === undefined) { | ||||
|             $('<span class="debug-message-type-null">'+obj+'</span>').appendTo(entryObj); | ||||
|         } else if (typeof obj === 'string') { | ||||
|             if (/[\t\n\r]/.test(obj)) { | ||||
|                 element.addClass('collapsed'); | ||||
|                 $('<i class="fa fa-caret-right debug-message-object-handle"></i> ').prependTo(header); | ||||
|                 makeExpandable(header, function() { | ||||
|                     $('<span class="debug-message-type-meta debug-message-object-type-header"></span>').html(typeHint||'string').appendTo(header); | ||||
|                     var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(element); | ||||
|                     $('<pre class="debug-message-type-string"></pre>').text(obj).appendTo(row); | ||||
|                 },checkExpanded(strippedKey,expandPaths)); | ||||
|             } | ||||
|             e = $('<span class="debug-message-type-string debug-message-object-header"></span>').html('"'+formatString(sanitize(obj))+'"').appendTo(entryObj); | ||||
|             if (/^#[0-9a-f]{6}$/i.test(obj)) { | ||||
|                 $('<span class="debug-message-type-string-swatch"></span>').css('backgroundColor',obj).appendTo(e); | ||||
|             } | ||||
|  | ||||
|         } else if (typeof obj === 'number') { | ||||
|             e = $('<span class="debug-message-type-number"></span>').appendTo(entryObj); | ||||
|  | ||||
|             if (Number.isInteger(obj) && (obj >= 0)) { // if it's a +ve integer | ||||
|                 e.addClass("debug-message-type-number-toggle"); | ||||
|                 e.click(function(evt) { | ||||
|                     evt.preventDefault(); | ||||
|                     formatNumber($(this), obj, sourceId, path, true); | ||||
|                 }); | ||||
|             } | ||||
|             formatNumber(e,obj,sourceId,path,false,typeHint==='hex'?'hex':undefined); | ||||
|  | ||||
|         } else if (isArray) { | ||||
|             element.addClass('collapsed'); | ||||
|  | ||||
|             var originalLength = obj.length; | ||||
|             if (typeHint) { | ||||
|                 var m = /\[(\d+)\]/.exec(typeHint); | ||||
|                 if (m) { | ||||
|                     originalLength = parseInt(m[1]); | ||||
|                 } | ||||
|             } | ||||
|             var data = obj; | ||||
|             var type = 'array'; | ||||
|             if (isArrayObject) { | ||||
|                 data = obj.data; | ||||
|                 if (originalLength === undefined) { | ||||
|                     originalLength = data.length; | ||||
|                 } | ||||
|                 if (data.__encoded__) { | ||||
|                     data = data.data; | ||||
|                 } | ||||
|                 type = obj.type.toLowerCase(); | ||||
|             } else if (/buffer/.test(typeHint)) { | ||||
|                 type = 'buffer'; | ||||
|             } | ||||
|             var fullLength = data.length; | ||||
|  | ||||
|                 if (originalLength > 0) { | ||||
|                 $('<i class="fa fa-caret-right debug-message-object-handle"></i> ').prependTo(header); | ||||
|                 var arrayRows = $('<div class="debug-message-array-rows"></div>').appendTo(element); | ||||
|                 element.addClass('debug-message-buffer-raw'); | ||||
|             } | ||||
|             if (key) { | ||||
|                 headerHead = $('<span class="debug-message-type-meta"></span>').html(typeHint||(type+'['+originalLength+']')).appendTo(entryObj); | ||||
|             } else { | ||||
|                 headerHead = $('<span class="debug-message-object-header"></span>').appendTo(entryObj); | ||||
|                 $('<span>[ </span>').appendTo(headerHead); | ||||
|                 var arrayLength = Math.min(originalLength,10); | ||||
|                 for (i=0;i<arrayLength;i++) { | ||||
|                     buildMessageSummaryValue(data[i]).appendTo(headerHead); | ||||
|                     if (i < arrayLength-1) { | ||||
|                         $('<span>, </span>').appendTo(headerHead); | ||||
|                     } | ||||
|                 } | ||||
|                 if (originalLength > arrayLength) { | ||||
|                     $('<span> …</span>').appendTo(headerHead); | ||||
|                 } | ||||
|                 if (arrayLength === 0) { | ||||
|                     $('<span class="debug-message-type-meta">empty</span>').appendTo(headerHead); | ||||
|                 } | ||||
|                 $('<span> ]</span>').appendTo(headerHead); | ||||
|             } | ||||
|             if (originalLength > 0) { | ||||
|  | ||||
|                 makeExpandable(header,function() { | ||||
|                     if (!key) { | ||||
|                         headerHead = $('<span class="debug-message-type-meta debug-message-object-type-header"></span>').html(typeHint||(type+'['+originalLength+']')).appendTo(header); | ||||
|                     } | ||||
|                     if (type === 'buffer') { | ||||
|                         var stringRow = $('<div class="debug-message-string-rows"></div>').appendTo(element); | ||||
|                         var sr = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(stringRow); | ||||
|                         var stringEncoding = ""; | ||||
|                         try { | ||||
|                             stringEncoding = String.fromCharCode.apply(null, new Uint16Array(data)) | ||||
|                         } catch(err) { | ||||
|                             console.log(err); | ||||
|                         } | ||||
|                         $('<pre class="debug-message-type-string"></pre>').text(stringEncoding).appendTo(sr); | ||||
|                         var bufferOpts = $('<span class="debug-message-buffer-opts"></span>').appendTo(headerHead); | ||||
|                         var switchFormat = $('<a href="#"></a>').addClass('selected').html('raw').appendTo(bufferOpts).click(function(e) { | ||||
|                             e.preventDefault(); | ||||
|                             e.stopPropagation(); | ||||
|                             formatBuffer(element,$(this),sourceId,path,true); | ||||
|                         }); | ||||
|                         formatBuffer(element,switchFormat,sourceId,path,false); | ||||
|  | ||||
|                     } | ||||
|                     var row; | ||||
|                     if (fullLength <= 10) { | ||||
|                         for (i=0;i<fullLength;i++) { | ||||
|                             row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(arrayRows); | ||||
|                             buildMessageElement(data[i],""+i,type==='buffer'?'hex':false,false,path+"["+i+"]",sourceId,rootPath,expandPaths).appendTo(row); | ||||
|                         } | ||||
|                     } else { | ||||
|                         for (i=0;i<fullLength;i+=10) { | ||||
|                             var minRange = i; | ||||
|                             row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(arrayRows); | ||||
|                             header = $('<span></span>').appendTo(row); | ||||
|                             $('<i class="fa fa-caret-right debug-message-object-handle"></i> ').appendTo(header); | ||||
|                             makeExpandable(header, (function() { | ||||
|                                 var min = minRange; | ||||
|                                 var max = Math.min(fullLength-1,(minRange+9)); | ||||
|                                 var parent = row; | ||||
|                                 return function() { | ||||
|                                     for (var i=min;i<=max;i++) { | ||||
|                                         var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(parent); | ||||
|                                         buildMessageElement(data[i],""+i,type==='buffer'?'hex':false,false,path+"["+i+"]",sourceId,rootPath,expandPaths).appendTo(row); | ||||
|                                     } | ||||
|                                 } | ||||
|                             })(),checkExpanded(strippedKey,expandPaths,minRange,Math.min(fullLength-1,(minRange+9)))); | ||||
|                             $('<span class="debug-message-object-key"></span>').html("["+minRange+" … "+Math.min(fullLength-1,(minRange+9))+"]").appendTo(header); | ||||
|                         } | ||||
|                         if (fullLength < originalLength) { | ||||
|                              $('<div class="debug-message-object-entry collapsed"><span class="debug-message-object-key">['+fullLength+' … '+originalLength+']</span></div>').appendTo(arrayRows); | ||||
|                         } | ||||
|                     } | ||||
|                 },checkExpanded(strippedKey,expandPaths)); | ||||
|             } | ||||
|         } else if (typeof obj === 'object') { | ||||
|             element.addClass('collapsed'); | ||||
|             var keys = Object.keys(obj); | ||||
|             if (key || keys.length > 0) { | ||||
|                 $('<i class="fa fa-caret-right debug-message-object-handle"></i> ').prependTo(header); | ||||
|                 makeExpandable(header, function() { | ||||
|                     if (!key) { | ||||
|                         $('<span class="debug-message-type-meta debug-message-object-type-header"></span>').html('object').appendTo(header); | ||||
|                     } | ||||
|                     for (i=0;i<keys.length;i++) { | ||||
|                         var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(element); | ||||
|                         var newPath = path; | ||||
|                         if (/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(keys[i])) { | ||||
|                             newPath += (newPath.length > 0?".":"")+keys[i]; | ||||
|                         } else { | ||||
|                             newPath += "[\""+keys[i].replace(/"/,"\\\"")+"\"]" | ||||
|                         } | ||||
|                         buildMessageElement(obj[keys[i]],keys[i],false,false,newPath,sourceId,rootPath,expandPaths).appendTo(row); | ||||
|                     } | ||||
|                     if (keys.length === 0) { | ||||
|                         $('<div class="debug-message-object-entry debug-message-type-meta collapsed"></div>').text("empty").appendTo(element); | ||||
|                     } | ||||
|                 },checkExpanded(strippedKey,expandPaths)); | ||||
|             } | ||||
|             if (key) { | ||||
|                 $('<span class="debug-message-type-meta"></span>').html('object').appendTo(entryObj); | ||||
|             } else { | ||||
|                 headerHead = $('<span class="debug-message-object-header"></span>').appendTo(entryObj); | ||||
|                 $('<span>{ </span>').appendTo(headerHead); | ||||
|                 var keysLength = Math.min(keys.length,5); | ||||
|                 for (i=0;i<keysLength;i++) { | ||||
|                     $('<span class="debug-message-object-key"></span>').text(keys[i]).appendTo(headerHead); | ||||
|                     $('<span>: </span>').appendTo(headerHead); | ||||
|                     buildMessageSummaryValue(obj[keys[i]]).appendTo(headerHead); | ||||
|                     if (i < keysLength-1) { | ||||
|                         $('<span>, </span>').appendTo(headerHead); | ||||
|                     } | ||||
|                 } | ||||
|                 if (keys.length > keysLength) { | ||||
|                     $('<span> …</span>').appendTo(headerHead); | ||||
|                 } | ||||
|                 if (keysLength === 0) { | ||||
|                     $('<span class="debug-message-type-meta">empty</span>').appendTo(headerHead); | ||||
|                 } | ||||
|                 $('<span> }</span>').appendTo(headerHead); | ||||
|             } | ||||
|         } else { | ||||
|             $('<span class="debug-message-type-other"></span>').text(""+obj).appendTo(entryObj); | ||||
|         } | ||||
|         return element; | ||||
|     } | ||||
|  | ||||
|     function normalisePropertyExpression(str) { | ||||
|         // This must be kept in sync with validatePropertyExpression | ||||
|         // in editor/js/ui/utils.js | ||||
|  | ||||
|         var length = str.length; | ||||
|         if (length === 0) { | ||||
|             throw new Error("Invalid property expression: zero-length"); | ||||
|         } | ||||
|         var parts = []; | ||||
|         var start = 0; | ||||
|         var inString = false; | ||||
|         var inBox = false; | ||||
|         var quoteChar; | ||||
|         var v; | ||||
|         for (var i=0;i<length;i++) { | ||||
|             var c = str[i]; | ||||
|             if (!inString) { | ||||
|                 if (c === "'" || c === '"') { | ||||
|                     if (i != start) { | ||||
|                         throw new Error("Invalid property expression: unexpected "+c+" at position "+i); | ||||
|                     } | ||||
|                     inString = true; | ||||
|                     quoteChar = c; | ||||
|                     start = i+1; | ||||
|                 } else if (c === '.') { | ||||
|                     if (i===0) { | ||||
|                         throw new Error("Invalid property expression: unexpected . at position 0"); | ||||
|                     } | ||||
|                     if (start != i) { | ||||
|                         v = str.substring(start,i); | ||||
|                         if (/^\d+$/.test(v)) { | ||||
|                             parts.push(parseInt(v)); | ||||
|                         } else { | ||||
|                             parts.push(v); | ||||
|                         } | ||||
|                     } | ||||
|                     if (i===length-1) { | ||||
|                         throw new Error("Invalid property expression: unterminated expression"); | ||||
|                     } | ||||
|                     // Next char is first char of an identifier: a-z 0-9 $ _ | ||||
|                     if (!/[a-z0-9\$\_]/i.test(str[i+1])) { | ||||
|                         throw new Error("Invalid property expression: unexpected "+str[i+1]+" at position "+(i+1)); | ||||
|                     } | ||||
|                     start = i+1; | ||||
|                 } else if (c === '[') { | ||||
|                     if (i === 0) { | ||||
|                         throw new Error("Invalid property expression: unexpected "+c+" at position "+i); | ||||
|                     } | ||||
|                     if (start != i) { | ||||
|                         parts.push(str.substring(start,i)); | ||||
|                     } | ||||
|                     if (i===length-1) { | ||||
|                         throw new Error("Invalid property expression: unterminated expression"); | ||||
|                     } | ||||
|                     // Next char is either a quote or a number | ||||
|                     if (!/["'\d]/.test(str[i+1])) { | ||||
|                         throw new Error("Invalid property expression: unexpected "+str[i+1]+" at position "+(i+1)); | ||||
|                     } | ||||
|                     start = i+1; | ||||
|                     inBox = true; | ||||
|                 } else if (c === ']') { | ||||
|                     if (!inBox) { | ||||
|                         throw new Error("Invalid property expression: unexpected "+c+" at position "+i); | ||||
|                     } | ||||
|                     if (start != i) { | ||||
|                         v = str.substring(start,i); | ||||
|                         if (/^\d+$/.test(v)) { | ||||
|                             parts.push(parseInt(v)); | ||||
|                         } else { | ||||
|                             throw new Error("Invalid property expression: unexpected array expression at position "+start); | ||||
|                         } | ||||
|                     } | ||||
|                     start = i+1; | ||||
|                     inBox = false; | ||||
|                 } else if (c === ' ') { | ||||
|                     throw new Error("Invalid property expression: unexpected ' ' at position "+i); | ||||
|                 } | ||||
|             } else { | ||||
|                 if (c === quoteChar) { | ||||
|                     if (i-start === 0) { | ||||
|                         throw new Error("Invalid property expression: zero-length string at position "+start); | ||||
|                     } | ||||
|                     parts.push(str.substring(start,i)); | ||||
|                     // If inBox, next char must be a ]. Otherwise it may be [ or . | ||||
|                     if (inBox && !/\]/.test(str[i+1])) { | ||||
|                         throw new Error("Invalid property expression: unexpected array expression at position "+start); | ||||
|                     } else if (!inBox && i+1!==length && !/[\[\.]/.test(str[i+1])) { | ||||
|                         throw new Error("Invalid property expression: unexpected "+str[i+1]+" expression at position "+(i+1)); | ||||
|                     } | ||||
|                     start = i+1; | ||||
|                     inString = false; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|         } | ||||
|         if (inBox || inString) { | ||||
|             throw new Error("Invalid property expression: unterminated expression"); | ||||
|         } | ||||
|         if (start < length) { | ||||
|             parts.push(str.substring(start)); | ||||
|         } | ||||
|         return parts; | ||||
|     } | ||||
|  | ||||
|     function validatePropertyExpression(str) { | ||||
|         try { | ||||
|             var parts = normalisePropertyExpression(str); | ||||
|             return true; | ||||
|         } catch(err) { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function getMessageProperty(msg,expr) { | ||||
|         var result = null; | ||||
|         var msgPropParts; | ||||
|  | ||||
|         if (typeof expr === 'string') { | ||||
|             if (expr.indexOf('msg.')===0) { | ||||
|                 expr = expr.substring(4); | ||||
|             } | ||||
|             msgPropParts = normalisePropertyExpression(expr); | ||||
|         } else { | ||||
|             msgPropParts = expr; | ||||
|         } | ||||
|         var m; | ||||
|         msgPropParts.reduce(function(obj, key) { | ||||
|             result = (typeof obj[key] !== "undefined" ? obj[key] : undefined); | ||||
|             if (result === undefined && obj.hasOwnProperty('type') && obj.hasOwnProperty('data')&& obj.hasOwnProperty('length')) { | ||||
|                 result = (typeof obj.data[key] !== "undefined" ? obj.data[key] : undefined); | ||||
|             } | ||||
|             return result; | ||||
|         }, msg); | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     function getNodeIcon(def,node) { | ||||
|         if (def.category === 'config') { | ||||
|             return "icons/node-red/cog.png" | ||||
|         } else if (node && node.type === 'tab') { | ||||
|             return "icons/node-red/subflow.png" | ||||
|         } else if (node && node.type === 'unknown') { | ||||
|             return "icons/node-red/alert.png" | ||||
|         } | ||||
|         var icon_url; | ||||
|         if (typeof def.icon === "function") { | ||||
|             try { | ||||
|                 icon_url = def.icon.call(node); | ||||
|             } catch(err) { | ||||
|                 console.log("Definition error: "+def.type+".icon",err); | ||||
|                 icon_url = "arrow-in.png"; | ||||
|             } | ||||
|         } else { | ||||
|             icon_url = def.icon; | ||||
|         } | ||||
|         return "icons/"+def.set.module+"/"+icon_url; | ||||
|     } | ||||
|  | ||||
|     function getNodeLabel(node,defaultLabel) { | ||||
|         defaultLabel = defaultLabel||""; | ||||
|         var l; | ||||
|         if (node.type === 'tab') { | ||||
|             l = node.label || defaultLabel | ||||
|         } else { | ||||
|             l = node._def.label; | ||||
|             try { | ||||
|                 l = (typeof l === "function" ? l.call(node) : l)||defaultLabel; | ||||
|             } catch(err) { | ||||
|                 console.log("Definition error: "+node.type+".label",err); | ||||
|                 l = defaultLabel; | ||||
|             } | ||||
|         } | ||||
|         return RED.text.bidi.enforceTextDirectionWithUCC(l); | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         createObjectElement: buildMessageElement, | ||||
|         getMessageProperty: getMessageProperty, | ||||
|         normalisePropertyExpression: normalisePropertyExpression, | ||||
|         validatePropertyExpression: validatePropertyExpression, | ||||
|         getNodeIcon: getNodeIcon, | ||||
|         getNodeLabel: getNodeLabel, | ||||
|     } | ||||
| })(); | ||||
							
								
								
									
										1682
									
								
								editor/js/ui/view.js
									
									
									
									
									
								
							
							
						
						| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -20,7 +20,7 @@ RED.workspaces = (function() { | ||||
|     var activeWorkspace = 0; | ||||
|     var workspaceIndex = 0; | ||||
|  | ||||
|     function addWorkspace(ws) { | ||||
|     function addWorkspace(ws,skipHistoryEntry) { | ||||
|         if (ws) { | ||||
|             workspace_tabs.addTab(ws); | ||||
|             workspace_tabs.resize(); | ||||
| @@ -28,59 +28,193 @@ RED.workspaces = (function() { | ||||
|             var tabId = RED.nodes.id(); | ||||
|             do { | ||||
|                 workspaceIndex += 1; | ||||
|             } while($("#workspace-tabs a[title='"+RED._('workspace.defaultName',{number:workspaceIndex})+"']").size() !== 0); | ||||
|             } while ($("#workspace-tabs a[title='"+RED._('workspace.defaultName',{number:workspaceIndex})+"']").size() !== 0); | ||||
|  | ||||
|             ws = {type:"tab",id:tabId,label:RED._('workspace.defaultName',{number:workspaceIndex})}; | ||||
|             RED.nodes.addWorkspace(ws); | ||||
|             workspace_tabs.addTab(ws); | ||||
|             workspace_tabs.activateTab(tabId); | ||||
|             RED.history.push({t:'add',workspaces:[ws],dirty:RED.nodes.dirty()}); | ||||
|             RED.nodes.dirty(true); | ||||
|             if (!skipHistoryEntry) { | ||||
|                 RED.history.push({t:'add',workspaces:[ws],dirty:RED.nodes.dirty()}); | ||||
|                 RED.nodes.dirty(true); | ||||
|             } | ||||
|         } | ||||
|         RED.view.focus(); | ||||
|         return ws; | ||||
|     } | ||||
|     function deleteWorkspace(ws,force) { | ||||
|     function deleteWorkspace(ws) { | ||||
|         if (workspace_tabs.count() == 1) { | ||||
|             return; | ||||
|         } | ||||
|         var nodes = []; | ||||
|         if (!force) { | ||||
|             nodes = RED.nodes.filterNodes({z:ws.id}); | ||||
|         } | ||||
|         if (force || nodes.length === 0) { | ||||
|             removeWorkspace(ws); | ||||
|             var historyEvent = RED.nodes.removeWorkspace(ws.id); | ||||
|             historyEvent.t = 'delete'; | ||||
|             historyEvent.dirty = RED.nodes.dirty(); | ||||
|             historyEvent.workspaces = [ws]; | ||||
|             RED.history.push(historyEvent); | ||||
|             RED.nodes.dirty(true); | ||||
|             RED.sidebar.config.refresh(); | ||||
|         } else { | ||||
|             $( "#node-dialog-delete-workspace" ).dialog('option','workspace',ws); | ||||
|             $( "#node-dialog-delete-workspace-content" ).text(RED._("workspace.delete",{label:ws.label})); | ||||
|             $( "#node-dialog-delete-workspace" ).dialog('open'); | ||||
|         } | ||||
|         removeWorkspace(ws); | ||||
|         var historyEvent = RED.nodes.removeWorkspace(ws.id); | ||||
|         historyEvent.t = 'delete'; | ||||
|         historyEvent.dirty = RED.nodes.dirty(); | ||||
|         historyEvent.workspaces = [ws]; | ||||
|         RED.history.push(historyEvent); | ||||
|         RED.nodes.dirty(true); | ||||
|         RED.sidebar.config.refresh(); | ||||
|     } | ||||
|  | ||||
|     function showRenameWorkspaceDialog(id) { | ||||
|         var ws = RED.nodes.workspace(id); | ||||
|         $( "#node-dialog-rename-workspace" ).dialog("option","workspace",ws); | ||||
|         var workspace = RED.nodes.workspace(id); | ||||
|         RED.view.state(RED.state.EDITING); | ||||
|         var tabflowEditor; | ||||
|         var trayOptions = { | ||||
|             title: RED._("workspace.editFlow",{name:workspace.label}), | ||||
|             buttons: [ | ||||
|                 { | ||||
|                     id: "node-dialog-delete", | ||||
|                     class: 'leftButton'+((workspace_tabs.count() == 1)?" disabled":""), | ||||
|                     text: RED._("common.label.delete"), //'<i class="fa fa-trash"></i>', | ||||
|                     click: function() { | ||||
|                         deleteWorkspace(workspace); | ||||
|                         RED.tray.close(); | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     id: "node-dialog-cancel", | ||||
|                     text: RED._("common.label.cancel"), | ||||
|                     click: function() { | ||||
|                         RED.tray.close(); | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     id: "node-dialog-ok", | ||||
|                     class: "primary", | ||||
|                     text: RED._("common.label.done"), | ||||
|                     click: function() { | ||||
|                         var label = $( "#node-input-name" ).val(); | ||||
|                         var changed = false; | ||||
|                         var changes = {}; | ||||
|                         if (workspace.label != label) { | ||||
|                             changes.label = workspace.label; | ||||
|                             changed = true; | ||||
|                             workspace.label = label; | ||||
|                             workspace_tabs.renameTab(workspace.id,label); | ||||
|                         } | ||||
|                         var disabled = $("#node-input-disabled").prop("checked"); | ||||
|                         if (workspace.disabled !== disabled) { | ||||
|                             changes.disabled = workspace.disabled; | ||||
|                             changed = true; | ||||
|                             workspace.disabled = disabled; | ||||
|                         } | ||||
|                         var info = tabflowEditor.getValue(); | ||||
|                         if (workspace.info !== info) { | ||||
|                             changes.info = workspace.info; | ||||
|                             changed = true; | ||||
|                             workspace.info = info; | ||||
|                         } | ||||
|                         $("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('workspace-disabled',workspace.disabled); | ||||
|                         // $("#workspace").toggleClass("workspace-disabled",workspace.disabled); | ||||
|  | ||||
|         if (workspace_tabs.count() == 1) { | ||||
|             $( "#node-dialog-rename-workspace").next().find(".leftButton") | ||||
|                 .prop('disabled',true) | ||||
|                 .addClass("ui-state-disabled"); | ||||
|         } else { | ||||
|             $( "#node-dialog-rename-workspace").next().find(".leftButton") | ||||
|                 .prop('disabled',false) | ||||
|                 .removeClass("ui-state-disabled"); | ||||
|                         if (changed) { | ||||
|                             var historyEvent = { | ||||
|                                 t: "edit", | ||||
|                                 changes:changes, | ||||
|                                 node: workspace, | ||||
|                                 dirty: RED.nodes.dirty() | ||||
|                             } | ||||
|                             workspace.changed = true; | ||||
|                             RED.history.push(historyEvent); | ||||
|                             RED.nodes.dirty(true); | ||||
|                             RED.sidebar.config.refresh(); | ||||
|                             var selection = RED.view.selection(); | ||||
|                             if (!selection.nodes && !selection.links) { | ||||
|                                 RED.sidebar.info.refresh(workspace); | ||||
|                             } | ||||
|                         } | ||||
|                         RED.tray.close(); | ||||
|                     } | ||||
|                 } | ||||
|             ], | ||||
|             resize: function(dimensions) { | ||||
|                 var rows = $("#dialog-form>div:not(.node-text-editor-row)"); | ||||
|                 var editorRow = $("#dialog-form>div.node-text-editor-row"); | ||||
|                 var height = $("#dialog-form").height(); | ||||
|                 for (var i=0; i<rows.size(); i++) { | ||||
|                     height -= $(rows[i]).outerHeight(true); | ||||
|                 } | ||||
|                 height -= (parseInt($("#dialog-form").css("marginTop"))+parseInt($("#dialog-form").css("marginBottom"))); | ||||
|                 height -= 28; | ||||
|                 $(".node-text-editor").css("height",height+"px"); | ||||
|                 tabflowEditor.resize(); | ||||
|             }, | ||||
|             open: function(tray) { | ||||
|                 var trayBody = tray.find('.editor-tray-body'); | ||||
|                 var dialogForm = $('<form id="dialog-form" class="form-horizontal"></form>').appendTo(trayBody); | ||||
|                 $('<div class="form-row">'+ | ||||
|                     '<label for="node-input-name" data-i18n="[append]editor:common.label.name"><i class="fa fa-tag"></i> </label>'+ | ||||
|                     '<input type="text" id="node-input-name">'+ | ||||
|                 '</div>').appendTo(dialogForm); | ||||
|  | ||||
|                 $('<div class="form-row">'+ | ||||
|                     '<label for="node-input-disabled-btn" data-i18n="editor:workspace.status"></label>'+ | ||||
|                     '<button id="node-input-disabled-btn" class="editor-button"><i class="fa fa-toggle-on"></i> <span id="node-input-disabled-label"></span></button> '+ | ||||
|                     '<input type="checkbox" id="node-input-disabled" style="display: none;"/>'+ | ||||
|                 '</div>').appendTo(dialogForm); | ||||
|  | ||||
|                 $('<div class="form-row node-text-editor-row">'+ | ||||
|                     '<label for="node-input-info" data-i18n="editor:workspace.info" style="width:300px;"></label>'+ | ||||
|                     '<div style="height:250px;" class="node-text-editor" id="node-input-info"></div>'+ | ||||
|                 '</div>').appendTo(dialogForm); | ||||
|                 tabflowEditor = RED.editor.createEditor({ | ||||
|                     id: 'node-input-info', | ||||
|                     mode: 'ace/mode/markdown', | ||||
|                     value: "" | ||||
|                 }); | ||||
|  | ||||
|                 $('<div class="form-tips" data-i18n="editor:workspace.tip"></div>').appendTo(dialogForm); | ||||
|  | ||||
|                 dialogForm.find('#node-input-disabled-btn').on("click",function(e) { | ||||
|                     var i = $(this).find("i"); | ||||
|                     if (i.hasClass('fa-toggle-off')) { | ||||
|                         i.addClass('fa-toggle-on'); | ||||
|                         i.removeClass('fa-toggle-off'); | ||||
|                         $("#node-input-disabled").prop("checked",false); | ||||
|                         $("#node-input-disabled-label").html(RED._("editor:workspace.enabled")); | ||||
|                     } else { | ||||
|                         i.addClass('fa-toggle-off'); | ||||
|                         i.removeClass('fa-toggle-on'); | ||||
|                         $("#node-input-disabled").prop("checked",true); | ||||
|                         $("#node-input-disabled-label").html(RED._("editor:workspace.disabled")); | ||||
|                     } | ||||
|                 }) | ||||
|  | ||||
|                 if (workspace.hasOwnProperty("disabled")) { | ||||
|                     $("#node-input-disabled").prop("checked",workspace.disabled); | ||||
|                     if (workspace.disabled) { | ||||
|                         dialogForm.find("#node-input-disabled-btn i").removeClass('fa-toggle-on').addClass('fa-toggle-off'); | ||||
|                         $("#node-input-disabled-label").html(RED._("editor:workspace.disabled")); | ||||
|                     } else { | ||||
|                         $("#node-input-disabled-label").html(RED._("editor:workspace.enabled")); | ||||
|                     } | ||||
|                 } else { | ||||
|                     workspace.disabled = false; | ||||
|                     $("#node-input-disabled-label").html(RED._("editor:workspace.enabled")); | ||||
|                 } | ||||
|  | ||||
|                 $('<input type="text" style="display: none;" />').prependTo(dialogForm); | ||||
|                 dialogForm.submit(function(e) { e.preventDefault();}); | ||||
|                 $("#node-input-name").val(workspace.label); | ||||
|                 RED.text.bidi.prepareInput($("#node-input-name")); | ||||
|                 tabflowEditor.getSession().setValue(workspace.info || "", -1); | ||||
|                 dialogForm.i18n(); | ||||
|             }, | ||||
|             close: function() { | ||||
|                 if (RED.view.state() != RED.state.IMPORT_DRAGGING) { | ||||
|                     RED.view.state(RED.state.DEFAULT); | ||||
|                 } | ||||
|                 RED.sidebar.info.refresh(workspace); | ||||
|                 tabflowEditor.destroy(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         $( "#node-input-workspace-name" ).val(ws.label); | ||||
|         $( "#node-dialog-rename-workspace" ).dialog("open"); | ||||
|         RED.tray.show(trayOptions); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     var workspace_tabs; | ||||
|     function createWorkspaceTabs(){ | ||||
|     function createWorkspaceTabs() { | ||||
|         workspace_tabs = RED.tabs.create({ | ||||
|             id: "workspace-tabs", | ||||
|             onchange: function(tab) { | ||||
| @@ -89,8 +223,14 @@ RED.workspaces = (function() { | ||||
|                 } | ||||
|                 activeWorkspace = tab.id; | ||||
|                 event.workspace = activeWorkspace; | ||||
|                 // $("#workspace").toggleClass("workspace-disabled",tab.disabled); | ||||
|                 RED.events.emit("workspace:change",event); | ||||
|                 window.location.hash = 'flow/'+tab.id; | ||||
|                 RED.sidebar.config.refresh(); | ||||
|                 RED.view.focus(); | ||||
|             }, | ||||
|             onclick: function(tab) { | ||||
|                 RED.view.focus(); | ||||
|             }, | ||||
|             ondblclick: function(tab) { | ||||
|                 if (tab.type != "subflow") { | ||||
| @@ -100,103 +240,35 @@ RED.workspaces = (function() { | ||||
|                 } | ||||
|             }, | ||||
|             onadd: function(tab) { | ||||
|                 RED.menu.addItem("menu-item-workspace",{ | ||||
|                     id:"menu-item-workspace-menu-"+tab.id.replace(".","-"), | ||||
|                     label:tab.label, | ||||
|                     onselect:function() { | ||||
|                         workspace_tabs.activateTab(tab.id); | ||||
|                     } | ||||
|                 }); | ||||
|                 $('<span class="workspace-disabled-icon"><i class="fa fa-ban"></i> </span>').prependTo("#red-ui-tab-"+(tab.id.replace(".","-"))+" .red-ui-tab-label"); | ||||
|                 if (tab.disabled) { | ||||
|                     $("#red-ui-tab-"+(tab.id.replace(".","-"))).addClass('workspace-disabled'); | ||||
|                 } | ||||
|                 RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() == 1); | ||||
|             }, | ||||
|             onremove: function(tab) { | ||||
|                 RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() == 1); | ||||
|                 RED.menu.removeItem("menu-item-workspace-menu-"+tab.id.replace(".","-")); | ||||
|             }, | ||||
|             minimumActiveTabWidth: 150 | ||||
|         }); | ||||
|  | ||||
|  | ||||
|         $("#node-dialog-rename-workspace form" ).submit(function(e) { e.preventDefault();}); | ||||
|         $( "#node-dialog-rename-workspace" ).dialog({ | ||||
|             modal: true, | ||||
|             autoOpen: false, | ||||
|             width: 500, | ||||
|             title: RED._("workspace.renameSheet"), | ||||
|             buttons: [ | ||||
|                 { | ||||
|                     class: 'leftButton', | ||||
|                     text: RED._("common.label.delete"), | ||||
|                     click: function() { | ||||
|                         var workspace = $(this).dialog('option','workspace'); | ||||
|                         $( this ).dialog( "close" ); | ||||
|                         deleteWorkspace(workspace); | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     text: RED._("common.label.ok"), | ||||
|                     click: function() { | ||||
|                         var workspace = $(this).dialog('option','workspace'); | ||||
|                         var label = $( "#node-input-workspace-name" ).val(); | ||||
|                         if (workspace.label != label) { | ||||
|                             workspace_tabs.renameTab(workspace.id,label); | ||||
|                             RED.nodes.dirty(true); | ||||
|                             RED.sidebar.config.refresh(); | ||||
|                             $("#menu-item-workspace-menu-"+workspace.id.replace(".","-")).text(label); | ||||
|                         } | ||||
|                         $( this ).dialog( "close" ); | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     text: RED._("common.label.cancel"), | ||||
|                     click: function() { | ||||
|                         $( this ).dialog( "close" ); | ||||
|                     } | ||||
|                 } | ||||
|             ], | ||||
|             open: function(e) { | ||||
|                 RED.keyboard.disable(); | ||||
|             onreorder: function(oldOrder, newOrder) { | ||||
|                 RED.history.push({t:'reorder',order:oldOrder,dirty:RED.nodes.dirty()}); | ||||
|                 RED.nodes.dirty(true); | ||||
|                 setWorkspaceOrder(newOrder); | ||||
|             }, | ||||
|             close: function(e) { | ||||
|                 RED.keyboard.enable(); | ||||
|             minimumActiveTabWidth: 150, | ||||
|             scrollable: true, | ||||
|             addButton: function() { | ||||
|                 addWorkspace(); | ||||
|             } | ||||
|         }); | ||||
|         $( "#node-dialog-delete-workspace" ).dialog({ | ||||
|             modal: true, | ||||
|             autoOpen: false, | ||||
|             width: 500, | ||||
|             title: RED._("workspace.confirmDelete"), | ||||
|             buttons: [ | ||||
|                 { | ||||
|                     text: RED._("common.label.ok"), | ||||
|                     click: function() { | ||||
|                         var workspace = $(this).dialog('option','workspace'); | ||||
|                         deleteWorkspace(workspace,true); | ||||
|                         $( this ).dialog( "close" ); | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     text: RED._("common.label.cancel"), | ||||
|                     click: function() { | ||||
|                         $( this ).dialog( "close" ); | ||||
|                     } | ||||
|                 } | ||||
|             ], | ||||
|             open: function(e) { | ||||
|                 RED.keyboard.disable(); | ||||
|             }, | ||||
|             close: function(e) { | ||||
|                 RED.keyboard.enable(); | ||||
|             } | ||||
|  | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     function init() { | ||||
|         createWorkspaceTabs(); | ||||
|         $('#btn-workspace-add-tab').on("click",function(e) {addWorkspace(); e.preventDefault()}); | ||||
|         RED.events.on("sidebar:resize",workspace_tabs.resize); | ||||
|  | ||||
|         RED.actions.add("core:show-next-tab",workspace_tabs.nextTab); | ||||
|         RED.actions.add("core:show-previous-tab",workspace_tabs.previousTab); | ||||
|  | ||||
|         RED.menu.setAction('menu-item-workspace-delete',function() { | ||||
|             deleteWorkspace(RED.nodes.workspace(activeWorkspace)); | ||||
|         }); | ||||
| @@ -204,6 +276,14 @@ RED.workspaces = (function() { | ||||
|         $(window).resize(function() { | ||||
|             workspace_tabs.resize(); | ||||
|         }); | ||||
|  | ||||
|         RED.actions.add("core:add-flow",addWorkspace); | ||||
|         RED.actions.add("core:edit-flow",editWorkspace); | ||||
|         RED.actions.add("core:remove-flow",removeWorkspace); | ||||
|     } | ||||
|  | ||||
|     function editWorkspace(id) { | ||||
|         showRenameWorkspaceDialog(id||activeWorkspace); | ||||
|     } | ||||
|  | ||||
|     function removeWorkspace(ws) { | ||||
| @@ -216,14 +296,19 @@ RED.workspaces = (function() { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function setWorkspaceOrder(order) { | ||||
|         RED.nodes.setWorkspaceOrder(order.filter(function(id) { | ||||
|             return RED.nodes.workspace(id) !== undefined; | ||||
|         })); | ||||
|         workspace_tabs.order(order); | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         init: init, | ||||
|         add: addWorkspace, | ||||
|         remove: removeWorkspace, | ||||
|  | ||||
|         edit: function(id) { | ||||
|             showRenameWorkspaceDialog(id||activeWorkspace); | ||||
|         }, | ||||
|         order: setWorkspaceOrder, | ||||
|         edit: editWorkspace, | ||||
|         contains: function(id) { | ||||
|             return workspace_tabs.contains(id); | ||||
|         }, | ||||
| @@ -238,11 +323,17 @@ RED.workspaces = (function() { | ||||
|                 var sf = RED.nodes.subflow(id); | ||||
|                 if (sf) { | ||||
|                     addWorkspace({type:"subflow",id:id,icon:"red/images/subflow_tab.png",label:sf.name, closeable: true}); | ||||
|                 } else { | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|             workspace_tabs.activateTab(id); | ||||
|         }, | ||||
|         refresh: function() { | ||||
|             RED.nodes.eachWorkspace(function(ws) { | ||||
|                 workspace_tabs.renameTab(ws.id,ws.label); | ||||
|  | ||||
|             }) | ||||
|             RED.nodes.eachSubflow(function(sf) { | ||||
|                 if (workspace_tabs.contains(sf.id)) { | ||||
|                     workspace_tabs.renameTab(sf.id,sf.name); | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2014, 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -32,7 +32,7 @@ RED.user = (function() { | ||||
|             autoOpen: false, | ||||
|             dialogClass: "ui-dialog-no-close", | ||||
|             modal: true, | ||||
|             closeOnEscape: false, | ||||
|             closeOnEscape: !!opts.cancelable, | ||||
|             width: 600, | ||||
|             resizable: false, | ||||
|             draggable: false | ||||
| @@ -43,17 +43,13 @@ RED.user = (function() { | ||||
|             dataType: "json", | ||||
|             url: "auth/login", | ||||
|             success: function(data) { | ||||
|                 if (data.type == "credentials") { | ||||
|                     var i=0; | ||||
|                 var i=0; | ||||
|  | ||||
|                 if (data.type == "credentials") { | ||||
|  | ||||
|                     if (data.image) { | ||||
|                         $("#node-dialog-login-image").attr("src",data.image); | ||||
|                     } else { | ||||
|                         $("#node-dialog-login-image").attr("src","red/images/node-red-256.png"); | ||||
|                     } | ||||
|                     for (;i<data.prompts.length;i++) { | ||||
|                         var field = data.prompts[i]; | ||||
|                         var row = $("<div/>",{id:"rrr"+i,class:"form-row"}); | ||||
|                         var row = $("<div/>",{class:"form-row"}); | ||||
|                         $('<label for="node-dialog-login-'+field.id+'">'+field.label+':</label><br/>').appendTo(row); | ||||
|                         var input = $('<input style="width: 100%" id="node-dialog-login-'+field.id+'" type="'+field.type+'" tabIndex="'+(i+1)+'"/>').appendTo(row); | ||||
|  | ||||
| @@ -99,6 +95,9 @@ RED.user = (function() { | ||||
|                         }).done(function(data,textStatus,xhr) { | ||||
|                             RED.settings.set("auth-tokens",data); | ||||
|                             $("#node-dialog-login").dialog('destroy').remove(); | ||||
|                             if (opts.updateMenu) { | ||||
|                                 updateUserMenu(); | ||||
|                             } | ||||
|                             done(); | ||||
|                         }).fail(function(jqXHR,textStatus,errorThrown) { | ||||
|                             RED.settings.remove("auth-tokens"); | ||||
| @@ -109,31 +108,77 @@ RED.user = (function() { | ||||
|                         }); | ||||
|                         event.preventDefault(); | ||||
|                     }); | ||||
|                     if (opts.cancelable) { | ||||
|                         $("#node-dialog-login-cancel").button().click(function( event ) { | ||||
|                             $("#node-dialog-login").dialog('destroy').remove(); | ||||
|  | ||||
|                 } else if (data.type == "strategy") { | ||||
|                     i = 0; | ||||
|                     for (;i<data.prompts.length;i++) { | ||||
|                         var field = data.prompts[i]; | ||||
|                         var row = $("<div/>",{class:"form-row",style:"text-align: center"}).appendTo("#node-dialog-login-fields"); | ||||
|  | ||||
|                         var loginButton = $('<a href="#"></a>',{style: "padding: 10px"}).appendTo(row).click(function() { | ||||
|                             document.location = field.url; | ||||
|                         }); | ||||
|                         if (field.image) { | ||||
|                             $("<img>",{src:field.image}).appendTo(loginButton); | ||||
|                         } else if (field.label) { | ||||
|                             var label = $('<span></span>').text(field.label); | ||||
|                             if (field.icon) { | ||||
|                                 $('<i></i>',{class: "fa fa-2x "+field.icon, style:"vertical-align: middle"}).appendTo(loginButton); | ||||
|                                 label.css({ | ||||
|                                     "verticalAlign":"middle", | ||||
|                                     "marginLeft":"8px" | ||||
|                                 }); | ||||
|  | ||||
|                             } | ||||
|                             label.appendTo(loginButton); | ||||
|                         } | ||||
|                         loginButton.button(); | ||||
|                     } | ||||
|  | ||||
|  | ||||
|                 } | ||||
|                 dialog.dialog("open"); | ||||
|                 if (opts.cancelable) { | ||||
|                     $("#node-dialog-login-cancel").button().click(function( event ) { | ||||
|                         $("#node-dialog-login").dialog('destroy').remove(); | ||||
|                     }); | ||||
|                 } | ||||
|  | ||||
|                 var loginImageSrc = data.image || "red/images/node-red-256.png"; | ||||
|  | ||||
|                 $("#node-dialog-login-image").load(function() { | ||||
|                     dialog.dialog("open"); | ||||
|                 }).attr("src",loginImageSrc); | ||||
|  | ||||
|  | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     function logout() { | ||||
|         var tokens = RED.settings.get("auth-tokens"); | ||||
|         var token = tokens?tokens.access_token:""; | ||||
|         $.ajax({ | ||||
|             url: "auth/revoke", | ||||
|             type: "POST", | ||||
|             data: {token:RED.settings.get("auth-tokens").access_token}, | ||||
|             success: function() { | ||||
|                 RED.settings.remove("auth-tokens"); | ||||
|             data: {token:token} | ||||
|         }).done(function(data,textStatus,xhr) { | ||||
|             RED.settings.remove("auth-tokens"); | ||||
|             if (data && data.redirect) { | ||||
|                 document.location.href = data.redirect; | ||||
|             } else { | ||||
|                 document.location.reload(true); | ||||
|             } | ||||
|         }).fail(function(jqXHR,textStatus,errorThrown) { | ||||
|             if (jqXHR.status === 401) { | ||||
|                 document.location.reload(true); | ||||
|             } else { | ||||
|                 console.log(textStatus); | ||||
|             } | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     function updateUserMenu() { | ||||
|         $("#usermenu-submenu li").remove(); | ||||
|         $("#btn-usermenu-submenu li").remove(); | ||||
|         if (RED.settings.user.anonymous) { | ||||
|             RED.menu.addItem("btn-usermenu",{ | ||||
|                 id:"usermenu-item-login", | ||||
| @@ -163,14 +208,19 @@ RED.user = (function() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     function init() { | ||||
|         if (RED.settings.user) { | ||||
|             if (!RED.settings.editorTheme || !RED.settings.editorTheme.hasOwnProperty("userMenu")) { | ||||
|  | ||||
|                 $('<li><a id="btn-usermenu" class="button hide" data-toggle="dropdown" href="#"><i class="fa fa-user"></i></a></li>') | ||||
|                 var userMenu = $('<li><a id="btn-usermenu" class="button hide" data-toggle="dropdown" href="#"></a></li>') | ||||
|                     .prependTo(".header-toolbar"); | ||||
|                 if (RED.settings.user.image) { | ||||
|                     $('<span class="user-profile"></span>').css({ | ||||
|                         backgroundImage: "url("+RED.settings.user.image+")", | ||||
|                     }).appendTo(userMenu.find("a")); | ||||
|                 } else { | ||||
|                     $('<i class="fa fa-user"></i>').appendTo(userMenu.find("a")); | ||||
|                 } | ||||
|  | ||||
|                 RED.menu.init({id:"btn-usermenu", | ||||
|                     options: [] | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2013 IBM Corp. | ||||
|  * 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. | ||||
| @@ -14,6 +14,22 @@ | ||||
|  * limitations under the License. | ||||
|  **/ | ||||
| RED.validators = { | ||||
|     number: function(){return function(v) { return v!=='' && !isNaN(v);}}, | ||||
|     regex: function(re){return function(v) { return re.test(v);}} | ||||
|     number: function(blankAllowed){return function(v) { return (blankAllowed&&(v===''||v===undefined)) || (v!=='' && !isNaN(v));}}, | ||||
|     regex: function(re){return function(v) { return re.test(v);}}, | ||||
|     typedInput: function(ptypeName,isConfig) { return function(v) { | ||||
|         var ptype = $("#node-"+(isConfig?"config-":"")+"input-"+ptypeName).val() || this[ptypeName]; | ||||
|         if (ptype === 'json') { | ||||
|             try { | ||||
|                 JSON.parse(v); | ||||
|                 return true; | ||||
|             } catch(err) { | ||||
|                 return false; | ||||
|             } | ||||
|         } else if (ptype === 'msg' || ptype === 'flow' || ptype === 'global' ) { | ||||
|             return RED.utils.validatePropertyExpression(v); | ||||
|         } else if (ptype === 'num') { | ||||
|             return /^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$/.test(v); | ||||
|         } | ||||
|         return true; | ||||
|     }} | ||||
| }; | ||||
|   | ||||
							
								
								
									
										8
									
								
								editor/sass/ace.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,8 @@ | ||||
| .ace_gutter { | ||||
|     border-top-left-radius: 4px; | ||||
|     border-bottom-left-radius: 4px; | ||||
| } | ||||
| .ace_scroller { | ||||
|     border-top-right-radius: 4px; | ||||
|     border-bottom-right-radius: 4px; | ||||
| } | ||||
							
								
								
									
										2
									
								
								editor/sass/bootstrap.scss
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -14,15 +14,20 @@ | ||||
|  * limitations under the License. | ||||
|  **/ | ||||
|  | ||||
| $background-color: #f3f3f3; | ||||
|  | ||||
| $form-placeholder-color: #bbbbbb; | ||||
| $form-text-color: #444; | ||||
| $form-input-focus-color:  rgba(85,150,230,0.8); | ||||
| $form-input-border-color:  #ccc; | ||||
| $form-input-border-selected-color:  #aaa; | ||||
|  | ||||
|  | ||||
| $node-selected-color: #ff7f0e; | ||||
| $port-selected-color: #ff7f0e; | ||||
| $link-color: #888; | ||||
| $link-link-color: #ccc; | ||||
| $link-link-active-color: #ff7f0e; | ||||
| $link-subflow-color: #bbb; | ||||
| $link-unknown-color: #f00; | ||||
|  | ||||
| @@ -38,13 +43,27 @@ $palette-header-background: #f3f3f3; | ||||
| $workspace-button-background: #fff; | ||||
| $workspace-button-background-hover: #ddd; | ||||
| $workspace-button-background-active: #efefef; | ||||
| $workspace-button-color: #999; | ||||
| $workspace-button-color: #888; | ||||
| $workspace-button-color-disabled: #ccc; | ||||
| $workspace-button-color-focus: #999; | ||||
| $workspace-button-color-hover: #666; | ||||
| $workspace-button-color-active: #666; | ||||
| $workspace-button-color-selected: #AAA; | ||||
|  | ||||
| $workspace-button-toggle-color: #999; | ||||
| $workspace-button-toggle-color-selected: #888; | ||||
| $workspace-button-toggle-color-disabled: #ddd; | ||||
|  | ||||
| $workspace-button-color-focus-outline: rgba(85,150,230,0.2); | ||||
|  | ||||
| $typedInput-button-background: #efefef; | ||||
| $typedInput-button-background-hover: #ddd; | ||||
| $typedInput-button-background-active: #e3e3e3; | ||||
| $typedInput-button-background-active: #ddd; | ||||
|  | ||||
| $editor-button-color-primary: #eee; | ||||
| $editor-button-background-primary: #AD1625; | ||||
| $editor-button-background-primary-hover: #6E0A1E; | ||||
| $editor-button-color: #999; | ||||
| $editor-button-background: #fff; | ||||
|  | ||||
| $shade-color: rgba(200,200,200,0.5); | ||||
|   | ||||
							
								
								
									
										265
									
								
								editor/sass/debug.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,265 @@ | ||||
| /** | ||||
|  * 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. | ||||
|  **/ | ||||
|  | ||||
| .debug-window { | ||||
|     padding:0; | ||||
|     margin:0; | ||||
|     background: #fff; | ||||
|     line-height: 20px; | ||||
| } | ||||
| .debug-window .debug-message-payload { | ||||
|     font-size: 14px; | ||||
| } | ||||
| .debug-content { | ||||
|     position: absolute; | ||||
|     top: 43px; | ||||
|     bottom: 0px; | ||||
|     left:0px; | ||||
|     right: 0px; | ||||
|     overflow-y: scroll; | ||||
| } | ||||
| .debug-filter-box { | ||||
|     position:absolute; | ||||
|     top: 42px; | ||||
|     left: 0px; | ||||
|     right: 0px; | ||||
|     z-index: 20; | ||||
|     background: #f9f9f9; | ||||
|     padding: 10px; | ||||
|     border-bottom: 1px solid #ddd; | ||||
|     box-shadow: 0 2px 6px rgba(0,0,0,0.1); | ||||
| } | ||||
| .debug-filter-row { | ||||
|     .red-ui-nodeList { | ||||
|         margin: 10px 0; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .debug-message { | ||||
|     position: relative; | ||||
|     border-bottom: 1px solid #eee; | ||||
|     border-left: 8px solid #eee; | ||||
|     border-right: 8px solid #eee; | ||||
|     padding: 2px; | ||||
|     &>.debug-message-meta .debug-message-tools { | ||||
|         display: none; | ||||
|     } | ||||
|  | ||||
|     &.debug-message-hover { | ||||
|         border-right-color: #999; | ||||
|         &>.debug-message-meta .debug-message-tools { | ||||
|             display: inline-block; | ||||
|         } | ||||
|     } | ||||
|     .debug-message-row { | ||||
|         .debug-message-tools-pin { | ||||
|             display: none; | ||||
|         } | ||||
|         &.debug-message-row-pinned .debug-message-tools-pin { | ||||
|             display: inline-block; | ||||
|         } | ||||
|         &:hover { | ||||
|             background: #f3f3f3; | ||||
|             &>.debug-message-tools { | ||||
|                 .debug-message-tools-copy { | ||||
|                     display: inline-block; | ||||
|                 } | ||||
|                 .debug-message-tools-pin { | ||||
|                     display: inline-block; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| .debug-message-meta .debug-message-tools { | ||||
|     .editor-button-small { | ||||
|         font-size: 11px; | ||||
|     } | ||||
| } | ||||
| .debug-message-tools { | ||||
|     .button-group:not(:last-child) { | ||||
|         margin-right: 3px; | ||||
|     } | ||||
|     .editor-button-small { | ||||
|         height: 16px; | ||||
|         line-height: 14px; | ||||
|         font-size: 8px; | ||||
|         border-radius: 1px; | ||||
|         padding: 0 3px; | ||||
|         min-width: 18px; | ||||
|         i.fa-terminal { | ||||
|             // terminal icon is a bit thin, so darken its color for better contrast | ||||
|             color: darken($editor-button-color, 30%) !important; | ||||
|         } | ||||
|         &.selected { | ||||
|             color: darken($workspace-button-color-selected, 10%) !important; | ||||
|             background: darken($workspace-button-background-active,10%); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| .debug-message-meta { | ||||
|     background: #fff; | ||||
|     font-size: 10px; | ||||
|     color: #777; | ||||
| } | ||||
| .debug-message-date { | ||||
|     padding: 1px 5px 1px 1px; | ||||
| } | ||||
| .debug-message-topic { | ||||
|     display: block; | ||||
|     color: #a66; | ||||
| } | ||||
| .debug-message-name { | ||||
|     padding: 1px 5px; | ||||
|     color: #777; | ||||
| } | ||||
| .debug-message-tools { | ||||
|     position: absolute; | ||||
|     top: 3px; | ||||
|     right: 1px; | ||||
|     .debug-message-tools-copy { | ||||
|         display: none; | ||||
|     } | ||||
| } | ||||
| .debug-message-payload { | ||||
|     display: block; | ||||
|     padding: 2px; | ||||
|     background: #fff; | ||||
| } | ||||
| .debug-message-level-log { | ||||
|     border-left-color: #eee; | ||||
|     border-right-color: #eee; | ||||
| } | ||||
| .debug-message-level-30 { | ||||
|     border-left-color: #ffdf9d; | ||||
|     border-right-color: #ffdf9d; | ||||
| } | ||||
| .debug-message-level-20 { | ||||
|     border-left-color: #f99; | ||||
|     border-right-color: #f99; | ||||
| } | ||||
| .debug-message-object-entry { | ||||
|     position: relative; | ||||
|     padding-left: 15px; | ||||
| } | ||||
| .debug-message-element { | ||||
|     color: #333; | ||||
|     font-family: Menlo, monospace; | ||||
|     font-size: 12px !important; | ||||
|     line-height: 1.3em; | ||||
| } | ||||
| .debug-message-object-key { | ||||
|     color: #792e90; | ||||
| } | ||||
| .debug-message-object-value { | ||||
|  | ||||
| } | ||||
| .debug-message-object-handle { | ||||
|     color: #666; | ||||
|     font-size: 1em; | ||||
|     width: 1em; | ||||
|     text-align: center; | ||||
|     transition: transform 0.1s ease-in-out; | ||||
|     transform: rotate(90deg); | ||||
| } | ||||
| .debug-message-element:not(.debug-message-top-level)>.debug-message-expandable>.debug-message-object-handle { | ||||
|     margin-left: -1em; | ||||
| } | ||||
| .debug-message-object-entry>.debug-message-expandable>.debug-message-object-handle { | ||||
|     margin-left: -1em; | ||||
| } | ||||
| .debug-message-object-entry.collapsed>span>.debug-message-object-handle { | ||||
|     transform: rotate(0deg); | ||||
| } | ||||
| .debug-message-element.collapsed>span>.debug-message-object-handle { | ||||
|     transform: rotate(0deg); | ||||
| } | ||||
|  | ||||
| .debug-message-object-entry.collapsed > .debug-message-object-entry { | ||||
|     display:none; | ||||
| } | ||||
|  | ||||
| .debug-message-element.collapsed .debug-message-object-entry { | ||||
|     display:none; | ||||
| } | ||||
| .debug-message-element:not(.collapsed)>.debug-message-expandable>.debug-message-object-value>.debug-message-object-header { | ||||
|     display:none; | ||||
| } | ||||
| .debug-message-element.collapsed .debug-message-buffer-opts { | ||||
|     display: none; | ||||
| } | ||||
|  | ||||
| .debug-message-element.collapsed .debug-message-object-type-header { | ||||
|     display:none; | ||||
| } | ||||
| .debug-message-object-entry pre { | ||||
|     font-family: Menlo, monospace; | ||||
|     font-size: 12px; | ||||
|     line-height: 1.4em; | ||||
|     margin: 0 0 0 -1em; | ||||
| } | ||||
|  | ||||
| .debug-message-type-other { color: #2033d6; } | ||||
| .debug-message-type-string { color: #b72828; } | ||||
| .debug-message-type-null { color: #666; font-style: italic;} | ||||
| .debug-message-type-meta { color: #666; font-style: italic;} | ||||
| .debug-message-type-number { color: #2033d6; }; | ||||
| .debug-message-type-number-toggle { cursor: pointer;} | ||||
|  | ||||
| .debug-message-row { | ||||
|     display: block; | ||||
|     padding: 4px 2px 2px; | ||||
|     position: relative; | ||||
|     &.debug-message-row-pinned { | ||||
|         background: #f6f6f6; | ||||
|     } | ||||
| } | ||||
| .debug-message-expandable { | ||||
|     cursor: pointer; | ||||
| } | ||||
| .debug-message-expandable:hover .debug-message-object-handle { | ||||
|     color: #b72828 !important; | ||||
| } | ||||
|  | ||||
| .debug-message-buffer-opts a { | ||||
|     font-size: 9px; | ||||
|     color: #bbb; | ||||
|     border: 1px solid #bbb; | ||||
|     border-radius: 2px; | ||||
|     padding: 2px 5px; | ||||
|     margin-left: 5px; | ||||
| } | ||||
| .debug-message-buffer-opts a:hover { | ||||
|     text-decoration: none; | ||||
|     color: #999; | ||||
|     border: 1px solid #999; | ||||
|     background: #f3f3f3; | ||||
| } | ||||
| .debug-message-buffer-raw > .debug-message-string-rows { | ||||
|     display: none; | ||||
| } | ||||
| .debug-message-buffer-string > .debug-message-array-rows { | ||||
|     display: none; | ||||
| } | ||||
| .debug-message-type-string-swatch { | ||||
|     display: inline-block; | ||||
|     width: 1.1em; | ||||
|     height: 0.9em; | ||||
|     vertical-align: middle; | ||||
|     border-radius: 3px; | ||||
|     margin: 0 4px; | ||||
| } | ||||
							
								
								
									
										516
									
								
								editor/sass/diff.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,516 @@ | ||||
| /** | ||||
|  * 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. | ||||
|  **/ | ||||
|  | ||||
|  | ||||
| #node-dialog-view-diff { | ||||
|     height: 600px; | ||||
|  | ||||
|     .red-ui-editableList-container { | ||||
|         border-radius:1px; | ||||
|         padding:0; | ||||
|         background: #f9f9f9; | ||||
|     } | ||||
|     #node-dialog-view-diff-diff { | ||||
|         position: absolute; | ||||
|         top:80px; | ||||
|         bottom:10px; | ||||
|         left:10px; | ||||
|         right:10px; | ||||
|         li { | ||||
|             background: #f9f9f9; | ||||
|             padding: 0px; | ||||
|             border: none; | ||||
|             min-height: 0; | ||||
|         } | ||||
|  | ||||
|     } | ||||
|     .red-ui-editableList-item-content { | ||||
|         padding: 5px; | ||||
|         // padding-bottom: 5px; | ||||
|     } | ||||
| } | ||||
| #node-dialog-view-diff-headers { | ||||
|     position: absolute; | ||||
|     left:17px; | ||||
|     right:32px; | ||||
|     top: 55px; | ||||
|     height: 25px; | ||||
|     .node-diff-node-entry-cell:not(:first-child) { | ||||
|         background: #f9f9f9; | ||||
|         text-align: center; | ||||
|         border-top: 1px solid $secondary-border-color; | ||||
|         border-color:$secondary-border-color; | ||||
|     } | ||||
|     .node-diff-node-entry-cell:last-child { | ||||
|         border-right: 1px solid $secondary-border-color; | ||||
|  | ||||
|     } | ||||
| } | ||||
|  | ||||
| .node-diff-toolbar { | ||||
|     position:absolute; | ||||
|     top:0; | ||||
|     left:0; | ||||
|     right:0; | ||||
|     height: 43px; | ||||
|     box-sizing: border-box; | ||||
|     color: #666; | ||||
|     text-align: right; | ||||
|     padding: 8px 10px; | ||||
|     background: #f3f3f3; | ||||
|     border-bottom: 1px solid $secondary-border-color; | ||||
|     white-space: nowrap; | ||||
| } | ||||
| .node-diff-tab { | ||||
|     background: #fff; | ||||
|     border: 1px solid #ddd; | ||||
|     border-radius: 1px; | ||||
|     overflow: hidden; | ||||
|  | ||||
|     &.collapsed { | ||||
|         .node-diff-tab-title .node-diff-chevron { | ||||
|             transform: rotate(-90deg); | ||||
|         } | ||||
|         .node-diff-node-entry { | ||||
|             display: none; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| .node-diff-tab-stats { | ||||
|     font-size: 0.9em; | ||||
| } | ||||
|  | ||||
| .node-diff-chevron { | ||||
|     display: inline-block; | ||||
|     width: 15px; | ||||
|     text-align: center; | ||||
|     margin-left: 3px; | ||||
|     transition: transform 0.1s ease-in-out; | ||||
|  | ||||
| } | ||||
| .node-diff-node-entry { | ||||
|     margin-left: 20px; | ||||
|     font-size: 0.9em; | ||||
|  | ||||
|     &:first-child { | ||||
|         border-top: 1px solid #eee; | ||||
|     } | ||||
|     &:not(:last-child) { | ||||
|         border-bottom: 1px solid #eee; | ||||
|     } | ||||
|  | ||||
|     &.collapsed { | ||||
|         .node-diff-chevron { | ||||
|             transform: rotate(-90deg); | ||||
|         } | ||||
|         .node-diff-node-entry-properties { | ||||
|             display: none; | ||||
|         } | ||||
|     } | ||||
|     &:not(.collapsed) { | ||||
|         .node-diff-node-entry-cell:not(:first-child) { | ||||
|             //display: none; | ||||
|         } | ||||
|         .node-diff-node-entry-cell:first-child { | ||||
|             //width: 100% | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     table { | ||||
|         border-collapse: collapse; | ||||
|         table-layout:fixed; | ||||
|          | ||||
|         // Fix for table-layout: fixed on safari: | ||||
|         max-width: none; | ||||
|         width: auto; | ||||
|         min-width: 100%; | ||||
|     } | ||||
|     td, th { | ||||
|         border: 1px solid $secondary-border-color; | ||||
|         padding: 0 0 0 3px; | ||||
|         text-align: left; | ||||
|         overflow-x: auto; | ||||
|     } | ||||
|     tr { | ||||
|         vertical-align: top; | ||||
|         &:first-child td { | ||||
|             white-space:nowrap; | ||||
|             overflow:hidden; | ||||
|         } | ||||
|     } | ||||
|     td:first-child { | ||||
|         width: 140px; | ||||
|     } | ||||
|     td:not(:first-child) { | ||||
|         width: calc( 100% - 140px); | ||||
|     } | ||||
|     td  { | ||||
|         .node-diff-status { | ||||
|             margin-left: 0; | ||||
|         } | ||||
|     } | ||||
|     tr:not(.node-diff-property-header) { | ||||
|         .node-diff-status { | ||||
|             width: 12px; | ||||
|             margin-left: 0; | ||||
|             margin-top: 0; | ||||
|             margin-bottom: 0; | ||||
|             margin-right: 5px; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| .node-diff-three-way { | ||||
|     .node-diff-node-entry-cell { | ||||
|         width: calc((100% - 220px) / 2); | ||||
|         &:first-child { | ||||
|             width: 220px; | ||||
|         } | ||||
|     } | ||||
|     td:not(:first-child) { | ||||
|         width: calc( (100% - 140px) / 2); | ||||
|     } | ||||
|  | ||||
|     .node-diff-node-entry { | ||||
|         .node-diff-node-entry-cell { | ||||
|             width: calc((100% + 20px - 220px) / 2); | ||||
|             &:first-child { | ||||
|                 width: 200px; | ||||
|             } | ||||
|  | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| .node-diff-column { | ||||
|     display:inline-block; | ||||
|     height:100%; | ||||
|     width:50%; | ||||
|     box-sizing: border-box; | ||||
|     white-space:nowrap; | ||||
|     overflow: hidden; | ||||
|     &:first-child { | ||||
|         border-right: 1px solid $secondary-border-color | ||||
|     } | ||||
| } | ||||
|  | ||||
| .node-diff-tab-title { | ||||
|     cursor: pointer; | ||||
|     padding: 0; | ||||
|     // background: #f6f6f6; | ||||
| } | ||||
| .node-diff-tab-title-meta { | ||||
|     vertical-align: middle; | ||||
|     display: inline-block; | ||||
|     padding-top: 2px; | ||||
| } | ||||
| .node-diff-node-entry-header { | ||||
|     cursor: pointer; | ||||
| } | ||||
| .node-diff-node-entry-node { | ||||
|     vertical-align: middle; | ||||
|     display: inline-block; | ||||
|     margin: 5px; | ||||
|     width: 18px; | ||||
|     height: 15px; | ||||
|     background: #ddd; | ||||
|     border-radius: 2px; | ||||
|     border: 1px solid #999; | ||||
|     background-position: 5% 50%; | ||||
|     background-repeat: no-repeat; | ||||
|     background-size: contain; | ||||
|     position: relative; | ||||
|  | ||||
|     .palette_icon { | ||||
|         background-position: 49% 50%; | ||||
|         width: 15px; | ||||
|     } | ||||
|     .palette_icon_container { | ||||
|         width: 18px; | ||||
|     } | ||||
| } | ||||
| .node-diff-tab-empty { | ||||
|     .node-diff-chevron i { | ||||
|         display: none; | ||||
|     } | ||||
|     .node-diff-tab-title { | ||||
|         cursor: default; | ||||
|     } | ||||
| } | ||||
| .node-diff-node-deleted { | ||||
|     //background: #fadddd; | ||||
|     cursor: default !important; | ||||
|     .node-diff-status { | ||||
|         color: #f80000; | ||||
|     } | ||||
|     .node-diff-node-entry-node { | ||||
|         opacity: 0.5; | ||||
|     } | ||||
|     .node-diff-node-description { | ||||
|         opacity: 0.5; | ||||
|         text-decoration: line-through; | ||||
|     } | ||||
| } | ||||
| .node-diff-node-added { | ||||
|     //background: #eefaee; | ||||
|     cursor: default !important; | ||||
|     .node-diff-status { | ||||
|         color: #009900; | ||||
|     } | ||||
| } | ||||
| .node-diff-node-moved { | ||||
|     //background: #eefaee; | ||||
|     .node-diff-status { | ||||
|         color: #3f81b3; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .node-diff-node-changed { | ||||
|     //background: #fff2ca; | ||||
|     .node-diff-status { | ||||
|         color: #f89406; | ||||
|     } | ||||
| } | ||||
| .node-diff-node-unchanged { | ||||
|     //background: #fff2ca; | ||||
|     .node-diff-status { | ||||
|         color: #bbb; | ||||
|     } | ||||
| } | ||||
| .node-diff-node-conflict { | ||||
|     .node-diff-status { | ||||
|         color: #9b45ce; | ||||
|     } | ||||
| } | ||||
| .node-diff-node-entry-title { | ||||
|     display: inline-block; | ||||
|     .node-diff-status { | ||||
|         margin-left: 15px; | ||||
|     } | ||||
| } | ||||
| .node-diff-node-entry-properties { | ||||
|     margin: 5px ; | ||||
|     color: #666; | ||||
| } | ||||
| .node-diff-status { | ||||
|     display: inline-block; | ||||
|     height: 20px; | ||||
|     margin-left: 5px; | ||||
|     vertical-align: top; | ||||
|     margin-top: 6px; | ||||
|     margin-bottom: 6px; | ||||
|     text-align: center; | ||||
| } | ||||
|  | ||||
| .node-diff-node-description { | ||||
|     color: $form-text-color; | ||||
|     margin-right: 5px; | ||||
|     padding-top: 5px; | ||||
|     display: inline-block; | ||||
|     &:after { | ||||
|         content: ""; | ||||
|         display: table; | ||||
|         clear: both; | ||||
|     } | ||||
| } | ||||
| .node-diff-node-meta { | ||||
|     float: right; | ||||
|     //font-size: 0.9em; | ||||
|     color: #999; | ||||
|     margin-top: 7px; | ||||
|     margin-right: 10px; | ||||
| } | ||||
|  | ||||
| .node-diff-count { color: #999} | ||||
| .node-diff-added { color: #009900} | ||||
| .node-diff-deleted { color: #f80000} | ||||
| .node-diff-changed { color: #f89406} | ||||
| .node-diff-conflicted { color: purple} | ||||
|  | ||||
|  | ||||
| .node-diff-node-entry-cell { | ||||
|     display: inline-block; | ||||
|     vertical-align: top; | ||||
|     box-sizing: border-box; | ||||
|     width: calc( (100% - 20px) / 2); | ||||
|     height: 32px; | ||||
|     border-left: 1px solid #eee; | ||||
|     padding-top: 2px; | ||||
|     white-space: nowrap; | ||||
|     overflow: hidden; | ||||
|     position: relative; | ||||
| } | ||||
| .node-diff-empty { | ||||
|     background: #f3f3f3; | ||||
|     background: repeating-linear-gradient( | ||||
|         20deg, | ||||
|         #fff, #fff 5px, | ||||
|         #f6f6f6 5px, | ||||
|         #f6f6f6 10px | ||||
|         ); | ||||
| } | ||||
| .node-diff-node-entry-cell:first-child { | ||||
|     border-left: none; | ||||
| } | ||||
| .node-diff-property-cell-label { | ||||
|     margin-left: 20px; | ||||
|     vertical-align: top; | ||||
|     box-sizing: border-box; | ||||
|     padding-left: 8px; | ||||
|     width: 120px; | ||||
| } | ||||
| .node-diff-property-wires { | ||||
|     display: inline-block; | ||||
|     .node-diff-node-entry-node { | ||||
|         width: 18px; | ||||
|         height: 15px; | ||||
|     } | ||||
|     .palette_icon_container { | ||||
|         width: 18px; | ||||
|     } | ||||
|     .palette_icon { | ||||
|         width: 15px; | ||||
|     } | ||||
|     ul,li,ol { | ||||
|         background: none !important; | ||||
|     } | ||||
|     ul { | ||||
|         vertical-align: middle; | ||||
|         display: inline-block; | ||||
|         margin-left: 5px; | ||||
|     } | ||||
|     li { | ||||
|         list-style-type: none !important; | ||||
|     } | ||||
|     ol { | ||||
|         font-size: 0.9em; | ||||
|         margin: 0; | ||||
|         & > span { | ||||
|             vertical-align: middle; | ||||
|             display: inline-block; | ||||
|             width: 30px; | ||||
|             text-align: center; | ||||
|         } | ||||
|         & > li:not(:last-child) { | ||||
|             border-bottom: 1px solid #999; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| .node-diff-node-props .node-diff-node-entry-cell:first-child { | ||||
|     padding: 6px 0px; | ||||
|     span:not(.node-diff-chevron) { | ||||
|         margin-left: 5px; | ||||
|     } | ||||
|  | ||||
| } | ||||
| .node-diff-property-cell { | ||||
|     // vertical-align: top; | ||||
|     // display:inline-block; | ||||
|     // | ||||
|     // box-sizing: border-box; | ||||
|     // padding: 1px 5px; | ||||
|     //min-height: 30px; | ||||
|  | ||||
|     &.node-diff-node-changed { | ||||
|         background: #fff2e1 !important; | ||||
|     } | ||||
|     &.node-diff-node-conflict { | ||||
|         background: #ffdad4 !important; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .node-diff-selectbox { | ||||
|     position: absolute; | ||||
|     top:0; | ||||
|     right:0; | ||||
|     bottom:0; | ||||
|     width: 35px; | ||||
|     text-align: center; | ||||
|     border-left: 1px solid #eee; | ||||
|     margin:0; | ||||
|     input { | ||||
|         margin-top: 8px; | ||||
|     } | ||||
|  | ||||
|     &:hover { | ||||
|         background: #f3f3f3; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .node-diff-node-entry-conflict.node-diff-select-remote { | ||||
|     .node-diff-node-remote { | ||||
|         background: #e7ffe3; | ||||
|         label { | ||||
|             border-left-color: #b8daad; | ||||
|         } | ||||
|     } | ||||
|     .node-diff-node-local { | ||||
|         background: #ffe1e1; | ||||
|         label { | ||||
|             border-left-color: #e4bcbc; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| .node-diff-node-entry-conflict.node-diff-select-local { | ||||
|     .node-diff-node-local { | ||||
|         background: #e7ffe3; | ||||
|         label { | ||||
|             border-left-color: #b8daad; | ||||
|         } | ||||
|     } | ||||
|     .node-diff-node-remote { | ||||
|         background: #ffe1e1; | ||||
|         label { | ||||
|             border-left-color: #e4bcbc; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| #node-dialog-confirm-deploy { | ||||
|     .node-dialog-confirm-row { | ||||
|         text-align: left; padding-top: 10px; | ||||
|     } | ||||
|     ul { | ||||
|         font-size: 0.9em; | ||||
|         width: 400px; | ||||
|         margin: 10px auto; | ||||
|         text-align: left; | ||||
|     } | ||||
|     .node-dialog-confirm-conflict-row { | ||||
|         img { | ||||
|             vertical-align:middle; | ||||
|             height: 30px; | ||||
|             margin-right: 10px; | ||||
|         } | ||||
|         i { | ||||
|              vertical-align:middle; | ||||
|              text-align: center; | ||||
|              font-size: 30px; | ||||
|              width: 30px; | ||||
|              margin-right: 10px; | ||||
|         } | ||||
|         div { | ||||
|             vertical-align: middle; | ||||
|             width: calc(100% - 60px); | ||||
|             display:inline-block; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #node-diff-toolbar-resolved-conflicts .node-diff-status { | ||||
|     margin:0; | ||||
| } | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -23,6 +23,7 @@ | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     display: none; | ||||
|     z-index:100; | ||||
| } | ||||
| #dropTarget div { | ||||
|     display: table-cell; | ||||
| @@ -34,4 +35,3 @@ | ||||
| #dropTarget div i { | ||||
|     font-size: 80px; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -14,8 +14,148 @@ | ||||
|  * limitations under the License. | ||||
|  **/ | ||||
|  | ||||
| .dialog-form, #dialog-form, #dialog-config-form { | ||||
|  | ||||
| #editor-stack { | ||||
|     position: absolute; | ||||
|     margin: 0; | ||||
|     top: 0; | ||||
|     bottom: 0px; | ||||
|     right: 323px; | ||||
|     width: 0; | ||||
|     z-index: 5; | ||||
| } | ||||
| .editor-tray { | ||||
|     position:absolute; | ||||
|     margin: 0; | ||||
|     top: 0; | ||||
|     //min-width: 500px; | ||||
|     width: auto; | ||||
|     right: -1000px; | ||||
|     bottom: 0; | ||||
|     background: #fff; | ||||
|     border-left: 1px solid $secondary-border-color; | ||||
|     border-bottom: 1px solid $primary-border-color; | ||||
|     box-sizing: content-box; | ||||
| } | ||||
| .editor-tray.open { | ||||
|     right: 0; | ||||
| } | ||||
| .editor-tray-body-wrapper { | ||||
|     width: 100%; | ||||
|     box-sizing: border-box; | ||||
|     overflow: auto; | ||||
| } | ||||
| .editor-tray-body { | ||||
|     position: relative; | ||||
|     box-sizing: border-box; | ||||
|     padding: 0.1px; // prevent margin collapsing | ||||
|     .dialog-form,#dialog-form, #node-config-dialog-edit-form { | ||||
|         margin: 20px; | ||||
|         height: calc(100% - 40px); | ||||
|     } | ||||
| } | ||||
| .editor-tray-content { | ||||
|     overflow: auto; | ||||
| } | ||||
| .editor-tray-header { | ||||
|     @include disable-selection; | ||||
|     position: relative; | ||||
|     box-sizing: border-box; | ||||
|     font-weight: bold; | ||||
|     border-bottom: 1px solid $secondary-border-color; | ||||
|     background: $palette-header-background; | ||||
|     &:after { | ||||
|         content: ""; | ||||
|         display: table; | ||||
|         clear: both; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .editor-tray-footer { | ||||
|     @include component-footer; | ||||
|     height: 35px; | ||||
|  | ||||
|     button { | ||||
|         @include editor-button; | ||||
|         padding: 3px 7px; | ||||
|         font-size: 11px; | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| .editor-tray-toolbar { | ||||
|     text-align: right; | ||||
|     padding: 6px; | ||||
|  | ||||
|     button { | ||||
|         @include editor-button; | ||||
|         &.toggle { | ||||
|             @include workspace-button-toggle; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| .editor-tray-titlebar { | ||||
|     border-bottom: 1px solid $secondary-border-color; | ||||
|     padding: 8px; | ||||
| } | ||||
| .editor-tray-breadcrumbs { | ||||
|     list-style-type: none; | ||||
|     margin: 0; | ||||
|     padding:0; | ||||
|  | ||||
|     li { | ||||
|         display: inline-block; | ||||
|         padding:0; | ||||
|         margin:0; | ||||
|  | ||||
|         &:not(:last-child) { | ||||
|             color: $editor-button-color; | ||||
|             font-weight: normal; | ||||
|  | ||||
|             &:after { | ||||
|                 display: inline-block; | ||||
|                 content: '>'; | ||||
|                 margin: 0 5px; | ||||
|             } | ||||
|  | ||||
|         } | ||||
|     } | ||||
| } | ||||
| .editor-tray-resize-handle { | ||||
|     position: absolute; | ||||
|     top: 0px; | ||||
|     bottom: 0px; | ||||
|     width: 7px; | ||||
|     left: -9px; | ||||
|     background: $background-color url(images/grip.png) no-repeat 50% 50%; | ||||
|     cursor: col-resize; | ||||
|     border-left: 1px solid $primary-border-color; | ||||
|     box-shadow: -1px 0 6px rgba(0,0,0,0.1); | ||||
| } | ||||
| .editor-tray-resize-button { | ||||
|     @include workspace-button; | ||||
|     display: block; | ||||
|     height: 37px; | ||||
|     line-height: 35px; | ||||
|     border: none; | ||||
|     border-bottom: 1px solid $secondary-border-color; | ||||
|     margin: 0; | ||||
|     background: $background-color; | ||||
|     color: $workspace-button-color; | ||||
| } | ||||
| #palette-shade, #editor-shade, #header-shade, #sidebar-shade  { | ||||
|     @include shade; | ||||
|     z-index: 2; | ||||
| } | ||||
| #sidebar-shade  { | ||||
|     left: -8px; | ||||
|     top: -1px; | ||||
|     bottom: -1px; | ||||
| } | ||||
|  | ||||
|  | ||||
| .dialog-form,#dialog-form, #node-config-dialog-edit-form { | ||||
|     height: 100%; | ||||
| } | ||||
|  | ||||
| @@ -23,10 +163,6 @@ | ||||
|     border-color: rgb(214, 97, 95) !important; | ||||
| } | ||||
|  | ||||
| .ui-dialog .ui-dialog-buttonpane button.leftButton { | ||||
|     margin-right: 40px; | ||||
| } | ||||
|  | ||||
| .form-row { | ||||
|     clear: both; | ||||
|     color: $form-text-color; | ||||
| @@ -36,7 +172,7 @@ | ||||
|     display: inline-block; | ||||
|     width: 100px; | ||||
| } | ||||
| .form-row input { | ||||
| .form-row input, .form-row div[contenteditable="true"] { | ||||
|     width:70%; | ||||
| } | ||||
|  | ||||
| @@ -70,7 +206,12 @@ | ||||
|     font-size: 13px; | ||||
|     border-radius: 4px; | ||||
|     padding: 0 10px; | ||||
|     &.toggle { | ||||
|         @include workspace-button-toggle; | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| .editor-button-small { | ||||
|     height: 20px; | ||||
|     line-height: 18px; | ||||
| @@ -83,6 +224,7 @@ | ||||
|     cursor: auto; | ||||
|     float: right; | ||||
|     font-size: 12px !important; | ||||
|     line-height: 35px; | ||||
| } | ||||
| #node-config-dialog-scope-warning { | ||||
|     display: inline-block; | ||||
| @@ -94,13 +236,98 @@ | ||||
|     margin: 1px 0 0 0; | ||||
|     padding: 0; | ||||
|     height: 22px; | ||||
|     width: 110px; | ||||
|     width: 200px; | ||||
|  | ||||
| } | ||||
| #node-config-dialog-user-count { | ||||
|     vertical-align: middle; | ||||
|     display:inline-block; | ||||
|     margin-top: 10px; | ||||
|     margin-right: 20px; | ||||
|     float:left; | ||||
|     font-size: 12px; | ||||
|     line-height: 35px; | ||||
| } | ||||
| .node-input-expression-editor #dialog-form { | ||||
|     margin: 0; | ||||
|     height: 100%; | ||||
|     .red-ui-panel { | ||||
|         &:first-child { | ||||
|             padding: 20px 20px 0; | ||||
|         } | ||||
|         &:last-child { | ||||
|             padding-bottom: 20px; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| .node-input-expression-tab-content { | ||||
|     position: relative; | ||||
|     padding: 0 20px; | ||||
| } | ||||
|  | ||||
| #node-input-expression-help { | ||||
|     position: absolute; | ||||
|     top: 35px; | ||||
|     left:0; | ||||
|     right: 0; | ||||
|     bottom:0; | ||||
|     padding: 0 20px; | ||||
|     overflow: auto; | ||||
|     box-sizing: border-box; | ||||
| } | ||||
| #node-input-expression-panel-info { | ||||
|     & > .form-row { | ||||
|         margin: 0; | ||||
|         & > div:first-child { | ||||
|             margin-top: 10px; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| .node-input-expression-legacy, .node-input-buffer-type { | ||||
|     font-size: 0.8em; | ||||
|     float: left; | ||||
|     cursor: pointer; | ||||
|     border: 1px solid white; | ||||
|     padding: 2px 5px; | ||||
|     border-radius: 2px; | ||||
|     &:hover { | ||||
|         border-color: $form-input-border-color; | ||||
|     } | ||||
| } | ||||
| .node-input-buffer-type { | ||||
|     float: none; | ||||
|     text-align: right; | ||||
| } | ||||
|  | ||||
| #clipboard-hidden { | ||||
|     position: absolute; | ||||
|     top: -3000px; | ||||
| } | ||||
| .node-label-form-row { | ||||
|     margin: 5px 0; | ||||
|     label { | ||||
|         margin-right: 20px; | ||||
|         text-align: right; | ||||
|         width: 30px; | ||||
|     } | ||||
|     button { | ||||
|         margin-left: 10px; | ||||
|     } | ||||
|     input { | ||||
|         width: calc(100% - 100px); | ||||
|     } | ||||
| } | ||||
| .node-label-form-none { | ||||
|     span { | ||||
|         padding-left: 50px; | ||||
|         width: 100px; | ||||
|         color: #999; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .ace_read-only { | ||||
|     background: #eee !important; | ||||
|     .ace_cursor { | ||||
|        color: transparent !important; | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -129,7 +129,6 @@ | ||||
|     fill-opacity: 0.5; | ||||
| } | ||||
|  | ||||
|  | ||||
| .node_error { | ||||
|     stroke: #ff0000; | ||||
|     stroke-width: 2; | ||||
| @@ -158,6 +157,8 @@ | ||||
|     stroke: $node-selected-color !important; | ||||
| } | ||||
| .node_highlighted { | ||||
|     border-color: #dd1616 !important; | ||||
|     border-style: dashed !important; | ||||
|     stroke: #dd1616; | ||||
|     stroke-width: 2; | ||||
|     stroke-dasharray: 10, 4; | ||||
| @@ -165,6 +166,15 @@ | ||||
| .node_hovered { | ||||
| } | ||||
|  | ||||
| .node_subflow .node { | ||||
|     stroke-dasharray:8, 3; | ||||
| } | ||||
|  | ||||
|  | ||||
| .node_quickadd * { | ||||
|     stroke-dasharray: 12,3; | ||||
| } | ||||
|  | ||||
| .node_status_label { | ||||
|     @include disable-selection; | ||||
|     stroke-width: 0; | ||||
| @@ -178,6 +188,13 @@ | ||||
|     stroke: $port-selected-color; | ||||
|     fill:  $port-selected-color; | ||||
| } | ||||
|  | ||||
| .port_quick_link { | ||||
|     stroke: $port-selected-color; | ||||
|     fill:  $port-selected-color; | ||||
| } | ||||
|  | ||||
|  | ||||
| .subflowport { | ||||
|     stroke-dasharray: 5,5; | ||||
|     fill: #eee; | ||||
| @@ -204,7 +221,25 @@ | ||||
|     fill: none; | ||||
|     pointer-events: none; | ||||
| } | ||||
|  | ||||
| .link_link { | ||||
|     stroke-width: 2; | ||||
|     stroke-dasharray: 10,5; | ||||
|     stroke: $link-link-color; | ||||
|     fill: none; | ||||
|     stroke-dasharray: 15,2; | ||||
|     pointer-events: none; | ||||
| } | ||||
| .link_port { | ||||
|     fill: #fff; | ||||
|     stroke: $link-link-color; | ||||
|     stroke-width: 1; | ||||
| } | ||||
| .link_group_active .link_port { | ||||
|     stroke: $link-link-active-color; | ||||
| } | ||||
| .link_group:hover { | ||||
|     cursor: pointer; | ||||
| } | ||||
| .link_subflow { | ||||
|     stroke: $link-subflow-color; | ||||
|     stroke-dasharray: 10,5; | ||||
| @@ -237,3 +272,25 @@ g.link_unknown path.link_line { | ||||
|     stroke-width: 2; | ||||
|     stroke-dasharray: 10, 4; | ||||
| } | ||||
|  | ||||
| @keyframes port_tooltip_fadeIn { from { opacity:0; } to { opacity:1; } } | ||||
|  | ||||
| .port_tooltip { | ||||
|     opacity:0; | ||||
|     animation: 0.1s ease-in 0s 1 normal forwards port_tooltip_fadeIn; | ||||
|     pointer-events: none; | ||||
|  | ||||
|     path { | ||||
|         fill: white; | ||||
|         stroke: #999; | ||||
|         stroke-width: 1; | ||||
|     } | ||||
| } | ||||
| .port_tooltip_label { | ||||
|     stroke-width: 0; | ||||
|     fill: #666; | ||||
|     font-size: 12px; | ||||
|     pointer-events: none; | ||||
|     -webkit-touch-callout: none; | ||||
|     @include disable-selection; | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -26,6 +26,7 @@ | ||||
| button, | ||||
| input, | ||||
| select, | ||||
| div[contenteditable="true"], | ||||
| textarea { | ||||
|   margin: 0; | ||||
|   font-size: 100%; | ||||
| @@ -33,12 +34,14 @@ textarea { | ||||
| } | ||||
|  | ||||
| button, | ||||
| div[contenteditable="true"], | ||||
| input { | ||||
|   *overflow: visible; | ||||
|   line-height: normal; | ||||
| } | ||||
|  | ||||
| button::-moz-focus-inner, | ||||
| div[contenteditable="true"]::-moz-focus-inner, | ||||
| input::-moz-focus-inner { | ||||
|   padding: 0; | ||||
|   border: 0; | ||||
| @@ -110,6 +113,7 @@ legend small { | ||||
|  | ||||
| label, | ||||
| input, | ||||
| div[contenteditable="true"], | ||||
| button, | ||||
| select, | ||||
| textarea { | ||||
| @@ -119,6 +123,7 @@ textarea { | ||||
| } | ||||
|  | ||||
| input, | ||||
| div[contenteditable="true"], | ||||
| button, | ||||
| select, | ||||
| textarea { | ||||
| @@ -146,9 +151,11 @@ input[type="url"], | ||||
| input[type="search"], | ||||
| input[type="tel"], | ||||
| input[type="color"], | ||||
| div[contenteditable="true"], | ||||
| .uneditable-input { | ||||
|   box-sizing: border-box; | ||||
|   display: inline-block; | ||||
|   height: 20px; | ||||
|   height: 34px; | ||||
|   padding: 6px 6px; | ||||
|   margin-bottom: 10px; | ||||
|   font-size: 14px; | ||||
| @@ -160,6 +167,7 @@ input[type="color"], | ||||
|  | ||||
| input, | ||||
| textarea, | ||||
| div[contenteditable="true"], | ||||
| .uneditable-input { | ||||
|   width: 206px; | ||||
| } | ||||
| @@ -183,6 +191,7 @@ input[type="url"], | ||||
| input[type="search"], | ||||
| input[type="tel"], | ||||
| input[type="color"], | ||||
| div[contenteditable="true"], | ||||
| .uneditable-input { | ||||
|   background-color: #ffffff; | ||||
|   border: 1px solid $form-input-border-color; | ||||
| @@ -206,6 +215,7 @@ input[type="url"]:focus, | ||||
| input[type="search"]:focus, | ||||
| input[type="tel"]:focus, | ||||
| input[type="color"]:focus, | ||||
| div[contenteditable="true"]:focus, | ||||
| .uneditable-input:focus { | ||||
|   border-color: $form-input-focus-color; | ||||
|   outline: 0; | ||||
| @@ -293,11 +303,13 @@ textarea:-moz-placeholder { | ||||
| } | ||||
|  | ||||
| input:-ms-input-placeholder, | ||||
| div[contenteditable="true"]:-ms-input-placeholder, | ||||
| textarea:-ms-input-placeholder { | ||||
|   color: $form-placeholder-color; | ||||
| } | ||||
|  | ||||
| input::-webkit-input-placeholder, | ||||
| div[contenteditable="true"]::-webkit-input-placeholder, | ||||
| textarea::-webkit-input-placeholder { | ||||
|   color: $form-placeholder-color; | ||||
| } | ||||
| @@ -383,6 +395,7 @@ textarea[class*="span"], | ||||
|  | ||||
| input, | ||||
| textarea, | ||||
| div[contenteditable="true"], | ||||
| .uneditable-input { | ||||
|   margin-left: 0; | ||||
| } | ||||
| @@ -514,12 +527,14 @@ input[type="checkbox"][readonly] { | ||||
| .control-group.warning .checkbox, | ||||
| .control-group.warning .radio, | ||||
| .control-group.warning input, | ||||
| .control-group.warning div[contenteditable="true"], | ||||
| .control-group.warning select, | ||||
| .control-group.warning textarea { | ||||
|   color: #c09853; | ||||
| } | ||||
|  | ||||
| .control-group.warning input, | ||||
| .control-group.warning div[contenteditable="true"], | ||||
| .control-group.warning select, | ||||
| .control-group.warning textarea { | ||||
|   border-color: #c09853; | ||||
| @@ -529,6 +544,7 @@ input[type="checkbox"][readonly] { | ||||
| } | ||||
|  | ||||
| .control-group.warning input:focus, | ||||
| .control-group.warning div[contenteditable="true"]:focus, | ||||
| .control-group.warning select:focus, | ||||
| .control-group.warning textarea:focus { | ||||
|   border-color: #a47e3c; | ||||
| @@ -553,12 +569,14 @@ input[type="checkbox"][readonly] { | ||||
| .control-group.error .checkbox, | ||||
| .control-group.error .radio, | ||||
| .control-group.error input, | ||||
| .control-group.error div[contenteditable="true"], | ||||
| .control-group.error select, | ||||
| .control-group.error textarea { | ||||
|   color: #b94a48; | ||||
| } | ||||
|  | ||||
| .control-group.error input, | ||||
| .control-group.error div[contenteditable="true"], | ||||
| .control-group.error select, | ||||
| .control-group.error textarea { | ||||
|   border-color: #b94a48; | ||||
| @@ -568,6 +586,7 @@ input[type="checkbox"][readonly] { | ||||
| } | ||||
|  | ||||
| .control-group.error input:focus, | ||||
| .control-group.error div[contenteditable="true"]:focus, | ||||
| .control-group.error select:focus, | ||||
| .control-group.error textarea:focus { | ||||
|   border-color: #953b39; | ||||
| @@ -592,12 +611,14 @@ input[type="checkbox"][readonly] { | ||||
| .control-group.success .checkbox, | ||||
| .control-group.success .radio, | ||||
| .control-group.success input, | ||||
| .control-group.success div[contenteditable="true"], | ||||
| .control-group.success select, | ||||
| .control-group.success textarea { | ||||
|   color: #468847; | ||||
| } | ||||
|  | ||||
| .control-group.success input, | ||||
| .control-group.success div[contenteditable="true"], | ||||
| .control-group.success select, | ||||
| .control-group.success textarea { | ||||
|   border-color: #468847; | ||||
| @@ -607,6 +628,7 @@ input[type="checkbox"][readonly] { | ||||
| } | ||||
|  | ||||
| .control-group.success input:focus, | ||||
| .control-group.success div[contenteditable="true"]:focus, | ||||
| .control-group.success select:focus, | ||||
| .control-group.success textarea:focus { | ||||
|   border-color: #356635; | ||||
| @@ -631,12 +653,14 @@ input[type="checkbox"][readonly] { | ||||
| .control-group.info .checkbox, | ||||
| .control-group.info .radio, | ||||
| .control-group.info input, | ||||
| .control-group.info div[contenteditable="true"], | ||||
| .control-group.info select, | ||||
| .control-group.info textarea { | ||||
|   color: #3a87ad; | ||||
| } | ||||
|  | ||||
| .control-group.info input, | ||||
| .control-group.info div[contenteditable="true"], | ||||
| .control-group.info select, | ||||
| .control-group.info textarea { | ||||
|   border-color: #3a87ad; | ||||
| @@ -646,6 +670,7 @@ input[type="checkbox"][readonly] { | ||||
| } | ||||
|  | ||||
| .control-group.info input:focus, | ||||
| .control-group.info div[contenteditable="true"]:focus, | ||||
| .control-group.info select:focus, | ||||
| .control-group.info textarea:focus { | ||||
|   border-color: #2d6987; | ||||
| @@ -662,6 +687,7 @@ input[type="checkbox"][readonly] { | ||||
| } | ||||
|  | ||||
| input:focus:invalid, | ||||
| div[contenteditable="true"]:focus:invalid, | ||||
| textarea:focus:invalid, | ||||
| select:focus:invalid { | ||||
|   color: #b94a48; | ||||
| @@ -669,6 +695,7 @@ select:focus:invalid { | ||||
| } | ||||
|  | ||||
| input:focus:invalid:focus, | ||||
| div[contenteditable="true"]:focus:invalid:focus, | ||||
| textarea:focus:invalid:focus, | ||||
| select:focus:invalid:focus { | ||||
|   border-color: #e9322d; | ||||
| @@ -726,6 +753,8 @@ select:focus:invalid:focus { | ||||
|  | ||||
| .input-append input, | ||||
| .input-prepend input, | ||||
| .input-append div[contenteditable="true"], | ||||
| .input-prepend div[contenteditable="true"], | ||||
| .input-append select, | ||||
| .input-prepend select, | ||||
| .input-append .uneditable-input, | ||||
| @@ -739,6 +768,8 @@ select:focus:invalid:focus { | ||||
|  | ||||
| .input-append input, | ||||
| .input-prepend input, | ||||
| .input-append div[contenteditable="true"], | ||||
| .input-prepend div[contenteditable="true"], | ||||
| .input-append select, | ||||
| .input-prepend select, | ||||
| .input-append .uneditable-input, | ||||
| @@ -754,6 +785,8 @@ select:focus:invalid:focus { | ||||
|  | ||||
| .input-append input:focus, | ||||
| .input-prepend input:focus, | ||||
| .input-append div[contenteditable="true"]:focus, | ||||
| .input-prepend div[contenteditable="true"]:focus, | ||||
| .input-append select:focus, | ||||
| .input-prepend select:focus, | ||||
| .input-append .uneditable-input:focus, | ||||
| @@ -808,6 +841,7 @@ select:focus:invalid:focus { | ||||
| } | ||||
|  | ||||
| .input-append input, | ||||
| .input-append div[contenteditable="true"], | ||||
| .input-append select, | ||||
| .input-append .uneditable-input { | ||||
|   -webkit-border-radius: 4px 0 0 4px; | ||||
| @@ -838,6 +872,7 @@ select:focus:invalid:focus { | ||||
| } | ||||
|  | ||||
| .input-prepend.input-append input, | ||||
| .input-prepend.input-append div[contenteditable="true"], | ||||
| .input-prepend.input-append select, | ||||
| .input-prepend.input-append .uneditable-input { | ||||
|   -webkit-border-radius: 0; | ||||
| @@ -922,6 +957,9 @@ input.search-query { | ||||
| .form-search input, | ||||
| .form-inline input, | ||||
| .form-horizontal input, | ||||
| .form-search div[contenteditable="true"], | ||||
| .form-inline div[contenteditable="true"], | ||||
| .form-horizontal div[contenteditable="true"], | ||||
| .form-search textarea, | ||||
| .form-inline textarea, | ||||
| .form-horizontal textarea, | ||||
| @@ -1044,3 +1082,8 @@ legend + .control-group { | ||||
| .form-horizontal .form-actions { | ||||
|   padding-left: 180px; | ||||
| } | ||||
|  | ||||
| .form-row div[contenteditable="true"] { | ||||
|    white-space: nowrap; | ||||
|    overflow: hidden; | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -111,6 +111,7 @@ span.logo { | ||||
| } | ||||
| #header .button-group > a { | ||||
|     display: inline-block; | ||||
|     position: relative; | ||||
|     float: left; | ||||
|     line-height: 22px; | ||||
|     font-size: 14px; | ||||
| @@ -133,6 +134,20 @@ span.logo { | ||||
|     } | ||||
| } | ||||
|  | ||||
| .deploy-button-spinner { | ||||
|     position: absolute; | ||||
|     left: 0; | ||||
|     top: 0; | ||||
|     right: 0; | ||||
|     bottom: 0; | ||||
|     text-align: center; | ||||
|  | ||||
|     img { | ||||
|         opacity: 0.8; | ||||
|         height: 100%; | ||||
|     } | ||||
| } | ||||
|  | ||||
| #btn-deploy { | ||||
|  | ||||
|     padding: 4px 12px; | ||||
| @@ -142,7 +157,7 @@ span.logo { | ||||
|         background: $deployDisabledButton; | ||||
|         color: #999 !important; | ||||
|  | ||||
|         img { | ||||
|         .deploy-button-content>img { | ||||
|             opacity: 0.3; | ||||
|         } | ||||
|  | ||||
| @@ -158,7 +173,7 @@ span.logo { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     img { | ||||
|     .deploy-button-content>img { | ||||
|         margin-right: 8px; | ||||
|     } | ||||
| } | ||||
| @@ -264,3 +279,13 @@ span.logo { | ||||
|     font-size: 16px; | ||||
|     color: #fff; | ||||
| } | ||||
|  | ||||
| #btn-usermenu .user-profile { | ||||
|     background-position: center center; | ||||
|     background-repeat: no-repeat; | ||||
|     background-size: contain; | ||||
|     display: inline-block; | ||||
|     width: 40px; | ||||
|     height: 35px; | ||||
|     vertical-align: middle; | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -18,11 +18,11 @@ | ||||
|     font-size: 14px !important; | ||||
|     font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif !important; | ||||
| } | ||||
| .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { | ||||
| .ui-widget input, .ui-widget div[contenteditable="true"], .ui-widget select, .ui-widget textarea, .ui-widget button { | ||||
|     font-size: 14px !important; | ||||
|     font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif !important; | ||||
| } | ||||
| .ui-widget input { | ||||
| .ui-widget input, .ui-widget div[contenteditable="true"] { | ||||
|     box-shadow: none; | ||||
| } | ||||
|  | ||||
| @@ -73,6 +73,72 @@ | ||||
| .ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { | ||||
|     float: none; | ||||
| } | ||||
|  | ||||
| .ui-dialog-buttonset button { | ||||
|     @include workspace-button; | ||||
|     font-size: 14px; | ||||
|     padding: 6px 14px; | ||||
|     margin-right: 8px; | ||||
|     color: $editor-button-color; | ||||
|     background: $editor-button-background; | ||||
|  | ||||
|     &.leftButton { | ||||
|         float: left; | ||||
|         margin-top: 7px; | ||||
|     } | ||||
|     &:not(.leftButton):not(:last-child) { | ||||
|         margin-right: 16px; | ||||
|     } | ||||
|  | ||||
|     &.primary { | ||||
|         border-color: $editor-button-background-primary; | ||||
|         color: $editor-button-color-primary !important; | ||||
|         background: $editor-button-background-primary; | ||||
|         &:not(.disabled):hover { | ||||
|             border-color: $editor-button-background-primary-hover; | ||||
|             background: $editor-button-background-primary-hover; | ||||
|             color: $editor-button-color-primary !important; | ||||
|         } | ||||
|         &.disabled { | ||||
|             border-color: $form-input-border-color; | ||||
|             color: $workspace-button-color-disabled !important; | ||||
|             background: $editor-button-background; | ||||
|         } | ||||
|     } | ||||
|     &.disabled { | ||||
|         background: none; | ||||
|     } | ||||
|     &.disabled { | ||||
|         background: none; | ||||
|     } | ||||
|     &.disabled:focus { | ||||
|         outline: none; | ||||
|     } | ||||
|     .ui-button-text { | ||||
|         padding: 0; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .ui-dialog .ui-dialog-buttonpane { | ||||
|     padding: .3em 1em .5em 1em; | ||||
| } | ||||
|  | ||||
| .ui-spinner { | ||||
|     border-radius: 4px; | ||||
|     padding: 0; | ||||
|     border: 1px solid $form-input-border-color; | ||||
| } | ||||
| .ui-spinner input { | ||||
|     margin: 0 17px 0 0; | ||||
|     padding: 6px; | ||||
|     border: none; | ||||
|     border-top-right-radius: 0px; | ||||
|     border-bottom-right-radius: 0px; | ||||
|  | ||||
|     -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); | ||||
|        -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); | ||||
|             box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); | ||||
|     &:focus { | ||||
|         outline: none; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -16,18 +16,112 @@ | ||||
|  | ||||
| #keyboard-help-dialog { | ||||
|     font-size: 0.9em; | ||||
|     padding-top: 10px; | ||||
|  | ||||
| } | ||||
| .keyboard-shortcuts { | ||||
|     padding: 10px; | ||||
|  | ||||
| #user-settings-tab-keyboard .red-ui-editableList-container { | ||||
|     border-radius: 0; | ||||
|     border: none; | ||||
|     padding: 0; | ||||
| } | ||||
| .keyboard-shortcuts td  { | ||||
|     padding: 7px 5px; | ||||
|     margin-bottom: 10px; | ||||
|     white-space: pre; | ||||
|  | ||||
|  | ||||
| .keyboard-shortcut-entry.keyboard-shortcut-list-header { | ||||
|     padding:0 5px 0 5px; | ||||
|     div { | ||||
|         color: #666 !important; | ||||
|     } | ||||
|     .red-ui-searchBox-container { | ||||
|         width: calc(100% - 20px); | ||||
|     } | ||||
|     .keyboard-shortcut-entry-scope { | ||||
|         text-align: center; | ||||
|     } | ||||
| } | ||||
| .keyboard-shortcuts td:first-child { | ||||
|  | ||||
| .keyboard-shortcut-list-header { | ||||
|     border-bottom: 1px solid $primary-border-color; | ||||
|  | ||||
| } | ||||
| .keyboard-shortcut-list { | ||||
|     position: absolute; | ||||
|     top:30px; | ||||
|     left:10px; | ||||
|     right:10px; | ||||
|     bottom:10px; | ||||
|     li { | ||||
|         padding: 0; | ||||
|         .red-ui-editableList-item-content { | ||||
|             padding: 8px; | ||||
|             cursor: pointer; | ||||
|         } | ||||
|     } | ||||
|     li:hover { | ||||
|         background: #f6f6f6; | ||||
|     } | ||||
| } | ||||
| .keyboard-shortcut-entry { | ||||
|     div { | ||||
|         display: inline-block; | ||||
|     } | ||||
|     // white-space: nowrap; | ||||
|  | ||||
|     select { | ||||
|         margin: 0; | ||||
|         width: calc(100% - 30px); | ||||
|         font-size: 0.9em; | ||||
|         margin-right: 5px; | ||||
|     } | ||||
| } | ||||
| .keyboard-shortcut-entry-key { | ||||
|     width:160px; | ||||
|     vertical-align: middle; | ||||
|     input { | ||||
|         margin:0; | ||||
|         width: calc(100% - 5px); | ||||
|     } | ||||
| } | ||||
| .keyboard-shortcut-entry-text { | ||||
|     vertical-align: middle; | ||||
|     width: calc(100% - 160px - 100px - 10px); | ||||
|     overflow: hidden; | ||||
|     i { | ||||
|         color: #ccc; | ||||
|         margin-right: 5px; | ||||
|     } | ||||
| } | ||||
| .keyboard-shortcut-entry-scope { | ||||
|     width:100px; | ||||
|     color: #999; | ||||
|     vertical-align: middle; | ||||
|     text-align: right; | ||||
|     padding-right: 10px; | ||||
| } | ||||
| .keyboard-shortcut-entry:not(.keyboard-shortcut-list-header) { | ||||
|     .keyboard-shortcut-entry-scope { | ||||
|         font-size: 0.8em; | ||||
|     } | ||||
| } | ||||
| .keyboard-shortcut-entry-unassigned { | ||||
|     color: #999; | ||||
|     .keyboard-shortcut-entry-key { | ||||
|         font-style: italic; | ||||
|     } | ||||
| } | ||||
| .keyboard-shortcut-entry-expanded { | ||||
|     .keyboard-shortcut-entry-key { | ||||
|         width: 150px; | ||||
|     } | ||||
|     .keyboard-shortcut-entry-text { | ||||
|     } | ||||
|     .keyboard-shortcut-entry-scope { | ||||
|         width: 110px; | ||||
|     } | ||||
|     span { | ||||
|         display: none; | ||||
|     } | ||||
| } | ||||
| .keyboard-shortcut-edit  { | ||||
| } | ||||
| .help-key { | ||||
|     border: 1px solid #ddd; | ||||
| @@ -37,4 +131,6 @@ | ||||
|     font-family: Courier, monospace; | ||||
|     box-shadow: #999 1px 1px 1px; | ||||
| } | ||||
|  | ||||
| .help-key-block { | ||||
|     white-space: nowrap; | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -22,6 +22,14 @@ | ||||
|     user-select: none; | ||||
| } | ||||
|  | ||||
| @mixin enable-selection { | ||||
|     -webkit-user-select: auto; | ||||
|     -khtml-user-select: auto; | ||||
|     -moz-user-select: auto; | ||||
|     -ms-user-select: auto; | ||||
|     user-select: auto; | ||||
| } | ||||
|  | ||||
| @mixin component-border { | ||||
|    border: 1px solid $primary-border-color; | ||||
|    box-sizing: border-box; | ||||
| @@ -30,41 +38,135 @@ | ||||
|  | ||||
| @mixin workspace-button { | ||||
|     @include disable-selection; | ||||
|     color: $workspace-button-color; | ||||
|     box-sizing: border-box; | ||||
|     display: inline-block; | ||||
|     color: $workspace-button-color !important; | ||||
|     background: $workspace-button-background; | ||||
|     border: 1px solid $secondary-border-color; | ||||
|     border: 1px solid $form-input-border-color; | ||||
|     text-align: center; | ||||
|     margin:0; | ||||
|     text-decoration: none; | ||||
|     cursor:pointer; | ||||
|  | ||||
|     &.disabled { | ||||
|         cursor: default; | ||||
|         color: $workspace-button-color-disabled; | ||||
|         color: $workspace-button-color-disabled !important; | ||||
|     } | ||||
|     &:hover, &:focus { | ||||
|         text-decoration: none; | ||||
|     } | ||||
|     &:not(.disabled):hover { | ||||
|         text-decoration: none; | ||||
|         color: $workspace-button-color-hover; | ||||
|         color: $workspace-button-color-hover !important; | ||||
|         background: $workspace-button-background-hover; | ||||
|     } | ||||
|     &:not(.disabled):focus { | ||||
|         color: $workspace-button-color-focus; | ||||
|         text-decoration: none; | ||||
|         color: $workspace-button-color-focus !important; | ||||
|     } | ||||
|     &:not(.disabled):active { | ||||
|         color: $workspace-button-color-active; | ||||
|         color: $workspace-button-color-active !important; | ||||
|         background: $workspace-button-background-active; | ||||
|         text-decoration: none; | ||||
|     } | ||||
|     &.selected:not(.disabled) { | ||||
|         color: $workspace-button-color-selected; | ||||
|         color: $workspace-button-color-selected !important; | ||||
|         background: $workspace-button-background-active; | ||||
|         cursor: default; | ||||
|     } | ||||
|  | ||||
|     .button-group &:not(:first-child) { | ||||
|         border-left: none; | ||||
|         border-top-left-radius: 0; | ||||
|         border-bottom-left-radius: 0; | ||||
|     } | ||||
|     .button-group &:not(:last-child) { | ||||
|         border-top-right-radius: 0; | ||||
|         border-bottom-right-radius: 0; | ||||
|     } | ||||
|     .button-group-vertical & { | ||||
|         display: block; | ||||
|         min-width: 22px; | ||||
|     } | ||||
|     .button-group-vertical &:not(:first-child) { | ||||
|         border-top: none; | ||||
|         border-top-left-radius: 0; | ||||
|         border-top-right-radius: 0; | ||||
|     } | ||||
|     .button-group-vertical &:not(:last-child) { | ||||
|         border-bottom-left-radius: 0; | ||||
|         border-bottom-right-radius: 0; | ||||
|     } | ||||
|  | ||||
|     &:focus { | ||||
|         outline: 1px solid $workspace-button-color-focus-outline; | ||||
|     } | ||||
| } | ||||
| .button-group-vertical { | ||||
|     display: inline-block; | ||||
|     vertical-align: middle; | ||||
| } | ||||
| .button-group:not(:last-child) { | ||||
|     margin-right: 10px; | ||||
| } | ||||
|  | ||||
|  | ||||
| @mixin workspace-button-toggle { | ||||
|     @include workspace-button; | ||||
|     color: $workspace-button-toggle-color !important; | ||||
|     background:$workspace-button-background-active; | ||||
|     margin-bottom: 1px; | ||||
|     &.selected:not(.disabled) { | ||||
|         color: $workspace-button-toggle-color-selected !important; | ||||
|         background: $workspace-button-background; | ||||
|         border-bottom-width: 2px; | ||||
|         border-bottom-color: $form-input-border-selected-color; | ||||
|         margin-bottom: 0; | ||||
|         cursor: default; | ||||
|     } | ||||
|     &.disabled { | ||||
|         color: $workspace-button-toggle-color-disabled !important; | ||||
|     } | ||||
| } | ||||
| @mixin editor-button { | ||||
|     @include workspace-button; | ||||
|     font-size: 14px; | ||||
|     padding: 6px 14px; | ||||
|     margin-right: 8px; | ||||
|     color: $editor-button-color !important; | ||||
|     background: $editor-button-background; | ||||
|  | ||||
|     &.primary { | ||||
|         border-color: $editor-button-background-primary; | ||||
|         color: $editor-button-color-primary !important; | ||||
|         background: $editor-button-background-primary; | ||||
|         &.disabled, &.ui-state-disabled { | ||||
|             background: none; | ||||
|             color: $editor-button-color !important; | ||||
|             border-color: $form-input-border-color; | ||||
|         } | ||||
|         &:not(.disabled):not(.ui-button-disabled):hover { | ||||
|             border-color: $editor-button-background-primary-hover; | ||||
|             background: $editor-button-background-primary-hover; | ||||
|             color: $editor-button-color-primary !important; | ||||
|         } | ||||
|     } | ||||
|     &:not(.disabled):hover { | ||||
|         //color: $editor-button-color; | ||||
|     } | ||||
|     &.disabled { | ||||
|         background: none; | ||||
|     } | ||||
|     &.disabled:focus { | ||||
|         outline: none; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     &.leftButton { | ||||
|         float: left; | ||||
|         margin-top: 1px; | ||||
|     } | ||||
|     &:not(.leftButton):not(:last-child) { | ||||
|         margin-right: 16px; | ||||
|     } | ||||
|     &.ui-state-disabled { | ||||
|         opacity: 1; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -79,6 +181,12 @@ | ||||
|     height: 25px; | ||||
|     line-height: 23px; | ||||
|     padding: 0 10px; | ||||
|  | ||||
|  | ||||
|     .button-group:not(:last-child) { | ||||
|         margin-right: 5px; | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| @mixin component-footer-button { | ||||
| @@ -92,9 +200,28 @@ | ||||
|         padding: 0 5px; | ||||
|     } | ||||
| } | ||||
| @mixin component-footer-button-toggle { | ||||
|     @include workspace-button-toggle; | ||||
|     font-size: 11px; | ||||
|     line-height: 17px; | ||||
|     height: 18px; | ||||
|     &.text-button { | ||||
|         width: auto; | ||||
|         padding: 0 5px; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @mixin component-shadow { | ||||
|     border: 1px solid $secondary-border-color; | ||||
|     box-shadow: 1px 1px 4px rgba(0,0,0,0.2); | ||||
|  | ||||
| } | ||||
|  | ||||
| @mixin shade { | ||||
|     position: absolute; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     bottom: 0; | ||||
|     right: 0; | ||||
|     background: $shade-color; | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -32,6 +32,7 @@ | ||||
|     color: #666; | ||||
|     border: 1px solid #325C80; | ||||
|     border-left-width: 16px; | ||||
|     overflow: hidden; | ||||
| } | ||||
| .notification a { | ||||
|     text-decoration: none; | ||||
|   | ||||
							
								
								
									
										226
									
								
								editor/sass/palette-editor.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,226 @@ | ||||
| /** | ||||
|  * 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. | ||||
|  **/ | ||||
|  | ||||
| #user-settings-tab-palette { | ||||
|     height: 100%; | ||||
| } | ||||
|  | ||||
| #palette-editor { | ||||
|     text-align: left; | ||||
|     position: absolute; | ||||
|     top: 0px; | ||||
|     right: 0; | ||||
|     bottom: 0; | ||||
|     left:0; | ||||
|     padding: 0; | ||||
|     box-sizing:border-box; | ||||
|     background: #fff; | ||||
|  | ||||
|     .red-ui-editableList-container { | ||||
|         border: none; | ||||
|         border-radius: 0; | ||||
|         padding: 0px; | ||||
|  | ||||
|  | ||||
|         li { | ||||
|             // border: none; | ||||
|             // border-top: 1px solid $primary-border-color; | ||||
|             padding: 0px; | ||||
|             .disabled { | ||||
|                 background: #f3f3f3; | ||||
|  | ||||
|                 .palette-module-name { | ||||
|                     font-style: italic; | ||||
|                     color: #aaa; | ||||
|                 } | ||||
|                 .palette-module-version { | ||||
|                     color: #aaa; | ||||
|                 } | ||||
|  | ||||
|  | ||||
|  | ||||
|             } | ||||
|             .red-ui-editableList-item-content { | ||||
|                 padding: 12px 16px; | ||||
|             } | ||||
|             &:last-child { | ||||
|                 // border-bottom: 1px solid $primary-border-color; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     } | ||||
|     .palette-editor-tab { | ||||
|         position:absolute; | ||||
|         top:35px; | ||||
|         left:0; | ||||
|         right:0; | ||||
|         bottom:0 | ||||
|     } | ||||
|     .palette-editor-toolbar { | ||||
|         background: #f3f3f3; | ||||
|         box-sizing: border-box; | ||||
|         padding: 8px 10px; | ||||
|         border-bottom: 1px solid $primary-border-color; | ||||
|         text-align: right; | ||||
|     } | ||||
|     .palette-module-button-group { | ||||
|         position: absolute; | ||||
|         right: 0; | ||||
|         bottom: 0; | ||||
|         a { | ||||
|             margin-left: 5px; | ||||
|         } | ||||
|     } | ||||
|     .palette-module-shade { | ||||
|         @include shade; | ||||
|         text-align: center; | ||||
|         padding-top: 20px; | ||||
|     } | ||||
|     #palette-module-install-shade { | ||||
|         padding-top: 80px; | ||||
|     } | ||||
|     .palette-module-shade-status { | ||||
|         color: #666; | ||||
|     } | ||||
|  | ||||
|     .palette-module-meta { | ||||
|         color: #666; | ||||
|         position: relative; | ||||
|         &.disabled { | ||||
|             color: #ccc; | ||||
|         } | ||||
|  | ||||
|         .fa { | ||||
|             width: 15px; | ||||
|             text-align: center; | ||||
|             margin-right: 5px; | ||||
|         } | ||||
|     } | ||||
|     .palette-module-name { | ||||
|         white-space: nowrap; | ||||
|         @include enable-selection; | ||||
|     } | ||||
|     .palette-module-version, .palette-module-updated, .palette-module-link { | ||||
|         font-style:italic; | ||||
|         font-size: 0.8em; | ||||
|         @include enable-selection; | ||||
|     } | ||||
|     .palette-module-updated { | ||||
|         margin-left: 10px; | ||||
|     } | ||||
|     .palette-module-link { | ||||
|         margin-left: 5px; | ||||
|     } | ||||
|  | ||||
|     .palette-module-description { | ||||
|         margin-left: 20px; | ||||
|         font-size: 0.9em; | ||||
|         color: #999; | ||||
|     } | ||||
|     .palette-module-link { | ||||
|     } | ||||
|     .palette-module-set-button-group { | ||||
|     } | ||||
|     .palette-module-count { | ||||
|         border-radius: 4px; | ||||
|         background: #eee; | ||||
|         padding: 2px 8px; | ||||
|         font-size: 12px; | ||||
|     } | ||||
|     .palette-module-content { | ||||
|         display: none; | ||||
|         padding: 10px 3px; | ||||
|     } | ||||
|     i.fa.palette-module-node-chevron { | ||||
|         width: 8px; | ||||
|         margin-right: 0; | ||||
|         transform: rotate(0deg); | ||||
|         transition: transform 0.2s ease-in-out; | ||||
|     } | ||||
|     .expanded { | ||||
|         i.fa.palette-module-node-chevron { | ||||
|             transform: rotate(90deg); | ||||
|         } | ||||
|  | ||||
|         .palette-module-set-button { | ||||
|             background:#f3f3f3 !important; | ||||
|         } | ||||
|     } | ||||
|     .palette-module-set { | ||||
|         border:1px solid $secondary-border-color; | ||||
|         border-radius: 0; | ||||
|         padding: 5px; | ||||
|         position: relative; | ||||
|         &:not(:last-child) { | ||||
|             border-bottom: none; | ||||
|         } | ||||
|         &:first-child { | ||||
|             border-top-right-radius: 2px; | ||||
|             border-top-left-radius: 2px; | ||||
|         } | ||||
|         &:last-child { | ||||
|             border-bottom-right-radius: 2px; | ||||
|             border-bottom-left-radius: 2px; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     .palette-module-type { | ||||
|         color: #666; | ||||
|         padding-left: 5px; | ||||
|         font-size: 0.9em; | ||||
|         @include enable-selection; | ||||
|     } | ||||
|     .palette-module-type-swatch { | ||||
|         display: inline-block; | ||||
|         width: 12px; | ||||
|         height: 12px; | ||||
|         border-radius: 3px; | ||||
|         vertical-align: middle; | ||||
|         margin-right: 5px; | ||||
|         background: #fff; | ||||
|         border: 1px solid #fff; | ||||
|     } | ||||
|     .palette-module-set-button-group { | ||||
|         position: absolute; | ||||
|         right: 4px; | ||||
|         top: 4px; | ||||
|     } | ||||
|  | ||||
|     .palette-module-set-disabled { | ||||
|         background: #eee; | ||||
|         .palette-module-type { | ||||
|             color: #999; | ||||
|         } | ||||
|     } | ||||
|     .palette-module-more { | ||||
|         padding: 0 !important; | ||||
|         margin-top: 10px; | ||||
|         margin-bottom: 10px; | ||||
|         background: $tab-background-inactive; | ||||
|         a { | ||||
|             display: block; | ||||
|             text-align: center; | ||||
|             padding: 12px 8px; | ||||
|             color: #AD1625; | ||||
|  | ||||
|             &:hover { | ||||
|                 text-decoration: none; | ||||
|                 background: $tab-background-hover; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -25,10 +25,25 @@ | ||||
|     text-align: center; | ||||
|     @include disable-selection; | ||||
|     @include component-border; | ||||
|  | ||||
|     transition: width 0.2s ease-in-out; | ||||
| } | ||||
|  | ||||
| .palette-expanded { | ||||
|     & #palette { | ||||
|         width: 380px; | ||||
|         box-shadow: 1px 0 6px rgba(0,0,0,0.1); | ||||
|     } | ||||
|     & #workspace { left: 379px !important; } | ||||
|     & #palette-collapse-all { display: none; } | ||||
|     & #palette-expand-all { display: none; } | ||||
|     & #palette-container { display: none !important; } | ||||
|     & #palette-search { display: none !important; } | ||||
|     & #palette-edit { background: $workspace-button-background-active } | ||||
|     & #palette-editor { display: block !important } | ||||
| } | ||||
|  | ||||
|  | ||||
| .palette-scroll { | ||||
|     display: none; | ||||
|     position: absolute; | ||||
|     top: 35px; | ||||
|     right: 0; | ||||
| @@ -38,15 +53,11 @@ | ||||
|     overflow-y: auto; | ||||
|     box-sizing:border-box; | ||||
| } | ||||
| .palette-spinner { | ||||
|     padding-top: 40px; | ||||
| #palette > .palette-spinner { | ||||
|     padding-top: 80px; | ||||
| } | ||||
| #palette-search { | ||||
|     position: absolute; | ||||
|     display: none; | ||||
|     top: 0; | ||||
|     left:0; | ||||
|     right:0; | ||||
| .palette-search { | ||||
|     position: relative; | ||||
|     overflow: hidden; | ||||
|     background: #ffffff; | ||||
|     text-align: center; | ||||
| @@ -55,48 +66,7 @@ | ||||
|     border-bottom: 1px solid $primary-border-color; | ||||
|     box-sizing:border-box; | ||||
| } | ||||
| #palette-search i { | ||||
|     font-size: 10px; | ||||
|     color: #666; | ||||
| } | ||||
| #palette-search i.fa-search { | ||||
|     position: absolute; | ||||
|     pointer-events: none; | ||||
|     left: 12px; | ||||
|     top: 12px; | ||||
| } | ||||
| #palette-search i.fa-times { | ||||
|     position: absolute; | ||||
|     right: 7px; | ||||
|     top: 12px; | ||||
| } | ||||
|  | ||||
| #palette-search-clear { | ||||
|     position: absolute; | ||||
|     right: 0; | ||||
|     top: 0; | ||||
|     bottom: 0; | ||||
|     width: 20px; | ||||
|     display: none; | ||||
| } | ||||
|  | ||||
| #palette-search input { | ||||
|     border-radius: 0; | ||||
|     border: none; | ||||
|     width: 100%; | ||||
|     box-shadow: none; | ||||
|     -webkit-box-shadow: none; | ||||
|     padding: 3px 17px 3px 22px; | ||||
|     margin: 0px; | ||||
|     height: 30px; | ||||
|     box-sizing:border-box; | ||||
| } | ||||
|  | ||||
| #palette-search input:focus { | ||||
|     border: none; | ||||
|     box-shadow: none; | ||||
|     -webkit-box-shadow: none; | ||||
| } | ||||
| #palette-footer { | ||||
|     @include component-footer; | ||||
| } | ||||
| @@ -144,16 +114,18 @@ | ||||
| } | ||||
| .palette_label { | ||||
|     font-size: 13px; | ||||
|     margin: 4px 0 4px 28px; | ||||
|     margin: 4px 0 4px 32px; | ||||
|     line-height: 20px; | ||||
|     overflow: hidden; | ||||
|     text-align: center; | ||||
|     @include disable-selection; | ||||
| } | ||||
| .palette_label_right { | ||||
|     margin: 4px 28px 4px 0; | ||||
|     margin: 4px 32px 4px 0; | ||||
| } | ||||
|  | ||||
| .palette_node { | ||||
|     display: block; | ||||
|     cursor:move; | ||||
|     background: #ddd; | ||||
|     margin: 10px auto; | ||||
| @@ -215,3 +187,22 @@ | ||||
|     background-size: contain; | ||||
|     background-repeat: no-repeat; | ||||
| } | ||||
|  | ||||
| .palette_node_small { | ||||
|     display: inline-block; | ||||
|     position: relative; | ||||
|     width: 18px; | ||||
|     height: 15px; | ||||
|     margin: 3px 0px; | ||||
|     vertical-align: middle; | ||||
|     cursor: default; | ||||
|  | ||||
|     .palette_icon_container { | ||||
|         width: 18px; | ||||
|         border-right: none; | ||||
|     } | ||||
|     .palette_icon { | ||||
|         margin-left: -1px; | ||||
|         width: 15px; | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										40
									
								
								editor/sass/panels.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,40 @@ | ||||
| /** | ||||
|  * 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-ui-panels { | ||||
|     position: relative; | ||||
|  | ||||
|     & > div { | ||||
|         // border: 1px solid red; | ||||
|         box-sizing: border-box; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .red-ui-panels-separator { | ||||
|     border-top: 1px solid $secondary-border-color; | ||||
|     border-bottom: 1px solid $secondary-border-color; | ||||
|     height: 7px; | ||||
|     box-sizing: border-box; | ||||
|     cursor: ns-resize; | ||||
|     background: $background-color url(images/grip.png) no-repeat 50% 50%; | ||||
| } | ||||
|  | ||||
|  | ||||
| .red-ui-panel { | ||||
|     overflow: auto; | ||||
|     height: calc(50% - 4px); | ||||
| } | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -15,39 +15,82 @@ | ||||
|  **/ | ||||
|  | ||||
|  | ||||
|  .red-ui-popover { | ||||
|      display: none; | ||||
|      position: absolute; | ||||
|      width: 300px; | ||||
|      padding: 10px; | ||||
|      height: auto; | ||||
|      background: #fff; | ||||
|       | ||||
|      z-index: 1000; | ||||
|      font-size: 14px; | ||||
|      line-height: 1.4em; | ||||
|      @include component-shadow; | ||||
|  } | ||||
|  .red-ui-popover:after, .red-ui-popover:before { | ||||
|  	right: 100%; | ||||
|  	top: 50%; | ||||
|  	border: solid transparent; | ||||
|  	content: " "; | ||||
|  	height: 0; | ||||
|  	width: 0; | ||||
|  	position: absolute; | ||||
|  	pointer-events: none; | ||||
|  } | ||||
| .red-ui-popover { | ||||
|     display: none; | ||||
|     position: absolute; | ||||
|     width: auto; | ||||
|     padding: 10px; | ||||
|     height: auto; | ||||
|     background: #fff; | ||||
|  | ||||
|  .red-ui-popover:after { | ||||
|  	border-color: rgba(136, 183, 213, 0); | ||||
|  	border-right-color: #fff; | ||||
|  	border-width: 10px; | ||||
|  	margin-top: -10px; | ||||
|  } | ||||
|  .red-ui-popover:before { | ||||
|  	border-color: rgba(194, 225, 245, 0); | ||||
|  	border-right-color: $primary-border-color; | ||||
|  	border-width: 11px; | ||||
|  	margin-top: -11px; | ||||
|  } | ||||
|     z-index: 1000; | ||||
|     font-size: 14px; | ||||
|     line-height: 1.4em; | ||||
|     @include component-shadow; | ||||
| } | ||||
|  | ||||
| .red-ui-popover:after, .red-ui-popover:before { | ||||
|     top: 50%; | ||||
|     border: solid transparent; | ||||
|     content: " "; | ||||
|     height: 0; | ||||
|     width: 0; | ||||
|     position: absolute; | ||||
|     pointer-events: none; | ||||
| } | ||||
| .red-ui-popover.red-ui-popover-right:after, .red-ui-popover.red-ui-popover-right:before { | ||||
|     right: 100%; | ||||
| } | ||||
| .red-ui-popover.red-ui-popover-left:after, .red-ui-popover.red-ui-popover-left:before { | ||||
|     left: 100%; | ||||
| } | ||||
|  | ||||
|  | ||||
| .red-ui-popover.red-ui-popover-right:after { | ||||
|     border-color: rgba(136, 183, 213, 0); | ||||
|     border-right-color: #fff; | ||||
|     border-width: 10px; | ||||
|     margin-top: -10px; | ||||
| } | ||||
| .red-ui-popover.red-ui-popover-right:before { | ||||
|     border-color: rgba(194, 225, 245, 0); | ||||
|     border-right-color: $primary-border-color; | ||||
|     border-width: 11px; | ||||
|     margin-top: -11px; | ||||
| } | ||||
|  | ||||
| .red-ui-popover.red-ui-popover-left:after { | ||||
|     border-color: rgba(136, 183, 213, 0); | ||||
|     border-left-color: #fff; | ||||
|     border-width: 10px; | ||||
|     margin-top: -10px; | ||||
| } | ||||
| .red-ui-popover.red-ui-popover-left:before { | ||||
|     border-color: rgba(194, 225, 245, 0); | ||||
|     border-left-color: $primary-border-color; | ||||
|     border-width: 11px; | ||||
|     margin-top: -11px; | ||||
| } | ||||
|  | ||||
| .red-ui-popover-size-small { | ||||
|     font-size: 11px; | ||||
|     padding: 5px; | ||||
|  | ||||
|     &.red-ui-popover-right:after { | ||||
|         border-width: 5px; | ||||
|         margin-top: -5px; | ||||
|     } | ||||
|     &.red-ui-popover-right:before { | ||||
|         border-width: 6px; | ||||
|         margin-top: -6px; | ||||
|     } | ||||
|  | ||||
|     &.red-ui-popover-left:after { | ||||
|         border-width: 5px; | ||||
|         margin-top: -5px; | ||||
|     } | ||||
|     &.red-ui-popover-left:before { | ||||
|         border-width: 6px; | ||||
|         margin-top: -6px; | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										192
									
								
								editor/sass/search.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,192 @@ | ||||
| /** | ||||
|  * 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-ui-search { | ||||
|     z-index:1000; | ||||
|     display: none; | ||||
|     position: absolute; | ||||
|     width: 500px; | ||||
|     background: white; | ||||
|     left: 50%; | ||||
|     margin-left: -250px; | ||||
|     top: 0px; | ||||
|     border: 1px solid $primary-border-color; | ||||
|     box-shadow: 0 0 10px rgba(0,0,0,0.4); | ||||
|  | ||||
|     ol { | ||||
|     } | ||||
| } | ||||
| .red-ui-type-search-shade { | ||||
|     @include shade; | ||||
|     z-index: 20; | ||||
|     position: fixed; | ||||
|     background: rgba(255,255,255,0.05); | ||||
| } | ||||
| .red-ui-type-search { | ||||
|     box-shadow: 0 1px 6px -3px black; | ||||
|     background: none; | ||||
|     width: 300px; | ||||
|     margin-left: 0px; | ||||
|     //height: 75px; | ||||
|     border: none; | ||||
|     .red-ui-search-container { | ||||
|         border-top-left-radius: 5px; | ||||
|         border-top-right-radius: 5px; | ||||
|         border: 1px dashed #aaa; | ||||
|         border-bottom: none; | ||||
|         padding: 0; | ||||
|     } | ||||
|     .red-ui-search-results-container { | ||||
|         display: none; | ||||
|         height: 150px; | ||||
|         .red-ui-editableList-container { | ||||
|             border: 1px dashed #aaa; | ||||
|             border-top: 1px solid #ccc; | ||||
|         } | ||||
|     } | ||||
|     .red-ui-search-result { | ||||
|         padding: 2px 2px 2px 5px; | ||||
|         font-size: 13px; | ||||
|         border-left-width: 3px; | ||||
|         border-right-width: 3px; | ||||
|     } | ||||
|     .red-ui-search-result-separator { | ||||
|         border-bottom: 3px solid #ddd; | ||||
|     } | ||||
|     .red-ui-search-result-node { | ||||
|         position: relative; | ||||
|         width: 18px; | ||||
|         height: 15px; | ||||
|         margin-top: 1px; | ||||
|     } | ||||
|     .red-ui-search-result-node-port { | ||||
|         position: absolute; | ||||
|         border-radius: 2px; | ||||
|         border: 1px solid #999; | ||||
|         width: 6px; | ||||
|         height: 7px; | ||||
|         top:4px; | ||||
|         left:-4px; | ||||
|         background: #eee; | ||||
|         box-sizing: border-box; | ||||
|     } | ||||
|     .red-ui-search-result-node-output{ | ||||
|         left: 16px; | ||||
|     } | ||||
|     .palette_icon_container { | ||||
|         width: 18px; | ||||
|     } | ||||
|     .palette_icon { | ||||
|         width: 15px; | ||||
|     } | ||||
|     .red-ui-search-result-description { | ||||
|         margin-left:28px; | ||||
|     } | ||||
|     .red-ui-search-result-node-label { | ||||
|         color: #999; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .red-ui-search-container { | ||||
|     padding: 3px; | ||||
|     border-bottom: 1px solid $secondary-border-color; | ||||
| } | ||||
| .red-ui-search-results-container { | ||||
|     position:relative; | ||||
|     height: 300px; | ||||
|     padding: 5px; | ||||
|     background: #f9f9f9; | ||||
|  | ||||
|     .red-ui-editableList-container { | ||||
|         background: white; | ||||
|         padding: 0; | ||||
|         background: #f9f9f9; | ||||
|         li { | ||||
|             padding: 0; | ||||
|             &.selected { | ||||
|                 background: #efefef; | ||||
|                 .red-ui-search-result { | ||||
|                     border-left-color:#999; | ||||
|                     border-right-color:#999; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| .red-ui-search-result { | ||||
|     padding: 8px 2px 8px 5px; | ||||
|     display: block; | ||||
|     cursor: pointer; | ||||
|     color: $form-text-color; | ||||
|     border-left: 3px solid #fff; | ||||
|     border-right: 3px solid #fff; | ||||
|     &:hover { | ||||
|         text-decoration: none; | ||||
|         color: $form-text-color; | ||||
|         background: #efefef; | ||||
|         border-left-color:#efefef; | ||||
|         border-right-color:#efefef; | ||||
|     } | ||||
|     &:after { | ||||
|         content: ""; | ||||
|         display: table; | ||||
|         clear: both; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .red-ui-search-result-node { | ||||
|     display: inline-block; | ||||
|     width: 30px; | ||||
|     float:left; | ||||
|     height: 25px; | ||||
|     background: #ddd; | ||||
|     border-radius: 5px; | ||||
|     border: 1px solid #999; | ||||
|     background-position: 5% 50%; | ||||
|     background-repeat: no-repeat; | ||||
|     background-size: contain; | ||||
|     position: relative; | ||||
|  | ||||
|     .palette_icon_container { | ||||
|         border-right: none; | ||||
|     } | ||||
|  | ||||
| } | ||||
| .red-ui-search-result-description { | ||||
|     margin-left: 40px; | ||||
|     margin-right: 5px; | ||||
| } | ||||
| .red-ui-search-result-node-label { | ||||
|     color: #222; | ||||
| } | ||||
| .red-ui-search-result-node-type { | ||||
|     font-style: italic; | ||||
|     font-size: 0.9em; | ||||
| } | ||||
| .red-ui-search-result-node-flow { | ||||
|     float:right; | ||||
|     font-size: 0.8em; | ||||
| } | ||||
| .red-ui-search-result-node-id { | ||||
|     display:none; | ||||
|     font-size: 0.8em; | ||||
| } | ||||
| .red-ui-search-empty { | ||||
|     padding: 10px; | ||||
|     text-align: center; | ||||
|     font-style: italic; | ||||
|     color: $form-placeholder-color; | ||||
| } | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -22,6 +22,7 @@ | ||||
|     width: 315px; | ||||
|     background: #fff; | ||||
|     box-sizing: border-box; | ||||
|     z-index: 10; | ||||
|     @include component-border; | ||||
| } | ||||
|  | ||||
| @@ -46,13 +47,15 @@ | ||||
|     right: 315px; | ||||
|     bottom:10px; | ||||
|     width: 7px; | ||||
|     background: url(images/grip.png) no-repeat 50% 50%; | ||||
|     z-index: 11; | ||||
|     background: $background-color url(images/grip.png) no-repeat 50% 50%; | ||||
|     cursor: col-resize; | ||||
| } | ||||
|  | ||||
| .sidebar-closed > #sidebar { display: none; } | ||||
| .sidebar-closed > #sidebar-separator { right: 0px !important; } | ||||
| .sidebar-closed > #workspace { right: 7px !important; } | ||||
| .sidebar-closed > #editor-stack { right: 8px !important; } | ||||
|  | ||||
| #sidebar .button { | ||||
|     @include workspace-button; | ||||
| @@ -68,6 +71,7 @@ | ||||
|     padding: 8px 10px; | ||||
|     background: #f3f3f3; | ||||
|     border-bottom: 1px solid $secondary-border-color; | ||||
|     white-space: nowrap; | ||||
| } | ||||
|  | ||||
| #sidebar-footer { | ||||
| @@ -77,12 +81,25 @@ | ||||
| .sidebar-footer-button { | ||||
|     @include component-footer-button; | ||||
| } | ||||
| .sidebar-footer-button-toggle { | ||||
|     @include component-footer-button-toggle; | ||||
| } | ||||
| .sidebar-header-button { | ||||
|     @include workspace-button; | ||||
|     font-size: 13px; | ||||
|     line-height: 13px; | ||||
|     padding: 5px 8px; | ||||
| } | ||||
| .sidebar-header-button-toggle { | ||||
|     @include workspace-button-toggle; | ||||
|     font-size: 13px; | ||||
|     line-height: 13px; | ||||
|     padding: 5px 8px; | ||||
| } | ||||
| .sidebar-header-button:not(:first-child) { | ||||
|     border-left: none; | ||||
| } | ||||
|  | ||||
| .sidebar-shade { | ||||
|     @include shade; | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2013, 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -21,6 +21,7 @@ | ||||
|  | ||||
| @import "jquery"; | ||||
| @import "bootstrap"; | ||||
| @import "ace"; | ||||
|  | ||||
| @import "dropdownMenu"; | ||||
|  | ||||
| @@ -34,25 +35,37 @@ | ||||
|  | ||||
| @import "editor"; | ||||
| @import "library"; | ||||
| @import "search"; | ||||
|  | ||||
| @import "panels"; | ||||
| @import "tabs"; | ||||
| @import "tab-config"; | ||||
| @import "tab-info"; | ||||
| @import "popover"; | ||||
| @import "flow"; | ||||
| @import "palette-editor"; | ||||
| @import "diff"; | ||||
|  | ||||
| @import "typedInput"; | ||||
| @import "userSettings"; | ||||
|  | ||||
|  | ||||
| @import "ui/common/editableList"; | ||||
| @import "ui/common/searchBox"; | ||||
| @import "ui/common/typedInput"; | ||||
| @import "ui/common/nodeList"; | ||||
| @import "ui/common/checkboxSet"; | ||||
|  | ||||
| @import "dragdrop"; | ||||
|  | ||||
| @import "keyboard"; | ||||
|  | ||||
| @import "debug"; | ||||
|  | ||||
| body { | ||||
|     font-size: 14px; | ||||
|     font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif; | ||||
|     padding-top: 100px; | ||||
|     background: #f3f3f3; | ||||
|     background: $background-color; | ||||
| } | ||||
|  | ||||
| #main-container { | ||||
| @@ -81,11 +94,13 @@ code, pre { | ||||
| } | ||||
|  | ||||
| code { | ||||
|   padding: 0px 4px; | ||||
|   padding: 0px 3px 2px 3px; | ||||
|   margin: 1px; | ||||
|   color: #AD1625; | ||||
|   white-space: nowrap; | ||||
|   background-color: #f7f7f9; | ||||
|   border: 1px solid #e1e1e8; | ||||
|   border-radius: 2px; | ||||
| } | ||||
|  | ||||
| pre { | ||||
| @@ -111,3 +126,7 @@ pre code { | ||||
|   background-color: transparent; | ||||
|   border: 0; | ||||
| } | ||||
|  | ||||
| .hide { | ||||
|     display: none; | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -15,6 +15,7 @@ | ||||
|  **/ | ||||
|  | ||||
| .sidebar-node-config { | ||||
|     position: relative; | ||||
|     background: #f3f3f3; | ||||
|     height: 100%; | ||||
|     overflow-y:auto; | ||||
| @@ -24,6 +25,22 @@ | ||||
|  .config-node-list { | ||||
|      margin: 0; | ||||
|      list-style-type: none; | ||||
|  | ||||
|           .palette_label { | ||||
|               margin-left: 8px; | ||||
|               line-height: 24px; | ||||
|               text-align: left; | ||||
|               white-space: nowrap; | ||||
|               overflow: hidden; | ||||
|               text-overflow: ellipsis; | ||||
|           } | ||||
|           .palette_icon_container { | ||||
|               font-size: 12px; | ||||
|               line-height: 30px; | ||||
|               background-color: #e8e8e8; | ||||
|               border-top-right-radius: 4px; | ||||
|               border-bottom-right-radius: 4px; | ||||
|           } | ||||
|  } | ||||
|  .config_node { | ||||
|      width: 160px; | ||||
| @@ -31,22 +48,6 @@ | ||||
|      background: #f3f3f3; | ||||
|      color: #666; | ||||
|      cursor: pointer; | ||||
|  | ||||
|      .palette_label { | ||||
|          margin-left: 8px; | ||||
|          line-height: 24px; | ||||
|          text-align: left; | ||||
|          white-space: nowrap; | ||||
|          overflow: hidden; | ||||
|          text-overflow: ellipsis; | ||||
|      } | ||||
|      .palette_icon_container { | ||||
|          font-size: 12px; | ||||
|          line-height: 30px; | ||||
|          background-color: #e8e8e8; | ||||
|          border-top-right-radius: 4px; | ||||
|          border-bottom-right-radius: 4px; | ||||
|      } | ||||
| } | ||||
| .config_node_type { | ||||
|     color: #999; | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -19,65 +19,248 @@ | ||||
| } | ||||
| table.node-info { | ||||
|     font-size: 14px; | ||||
|     margin: 0px; | ||||
|     width: 97%; | ||||
|     margin: 0 0 10px; | ||||
|     width: 100%; | ||||
| } | ||||
| table.node-info tr { | ||||
|     border: 1px solid #ddd; | ||||
| table.node-info tr:not(.blank) { | ||||
|     border-top: 1px solid #ddd; | ||||
|     border-bottom: 1px solid #ddd; | ||||
| } | ||||
| .node-info-property-expand  { | ||||
|     font-size: 0.8em; | ||||
|     text-align: right; | ||||
|     line-height: 0.9em; | ||||
|     a { | ||||
|         padding-bottom: 5px; | ||||
|     } | ||||
|  | ||||
| } | ||||
| table.node-info tr.blank { | ||||
|     border: none; | ||||
|     th { | ||||
|         text-align: left; | ||||
|         font-weight: 500; | ||||
|         color: #444; | ||||
|         padding: 6px 3px 3px; | ||||
|     } | ||||
|     >* { | ||||
|         padding-top: 8px; | ||||
|         border: none; | ||||
|         padding-left: 0px; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     a { | ||||
|         display: block; | ||||
|         color: #666; | ||||
|         &:hover,&:focus { | ||||
|             color: #666; | ||||
|             text-decoration: none; | ||||
|         } | ||||
|         &:not(.expanded) { | ||||
|             .node-info-property-show-more { | ||||
|                 display: inline; | ||||
|             } | ||||
|             .node-info-property-show-less { | ||||
|                 display: none; | ||||
|             } | ||||
|         } | ||||
|         i { | ||||
|             width: 10px; | ||||
|             text-align: center; | ||||
|             transition: transform 0.2s ease-in-out; | ||||
|         } | ||||
|  | ||||
|         &.expanded { | ||||
|             .node-info-property-show-more { | ||||
|                 display: none; | ||||
|             } | ||||
|             .node-info-property-show-less { | ||||
|                 display: inline; | ||||
|             } | ||||
|             i { | ||||
|                 transform: rotate(180deg); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     &.node-info-info-row > td { | ||||
|         padding-left: 5px; | ||||
|     } | ||||
| } | ||||
| table.node-info tr.blank td { | ||||
|     padding-top: 8px; | ||||
|     border: none; | ||||
|     font-weight: bold; | ||||
|     padding-left: 0px; | ||||
| } | ||||
| table.node-info td:first-child{ | ||||
|     color: #000; | ||||
|  | ||||
| table.node-info tr:not(.blank) td:first-child{ | ||||
|     color: #666; | ||||
|     vertical-align: top; | ||||
|     width: 90px; | ||||
|     padding: 3px; | ||||
|     padding: 3px 3px 3px 6px; | ||||
|     border-right: 1px solid #ddd; | ||||
| } | ||||
| table.node-info td:last-child{ | ||||
|     padding-left: 5px; | ||||
| table.node-info tr:not(.blank) td:last-child{ | ||||
|     padding: 3px 3px 3px 6px; | ||||
|     color: #666; | ||||
| } | ||||
| div.node-info { | ||||
|     margin: 5px; | ||||
| } | ||||
| .node-info-property-header { | ||||
|     color: #666; | ||||
| } | ||||
| .node-info-property-header:hover, | ||||
| .node-info-property-header:focus { | ||||
|     color: #666; | ||||
|     text-decoration: none; | ||||
| } | ||||
| .node-help { | ||||
|     font-size: 14px; | ||||
|     line-height: 1.5em; | ||||
|     h1 { | ||||
|         font-weight: normal; | ||||
|         font-size: 23px; | ||||
|         font-weight: 500; | ||||
|         font-size: 1.296em; | ||||
|         line-height: 1.3em; | ||||
|         margin: 8px auto; | ||||
|     } | ||||
|     h2 { | ||||
|         font-weight: normal; | ||||
|         font-size: 18px; | ||||
|         font-weight: 500; | ||||
|         font-size: 1.215em; | ||||
|         margin: 8px auto; | ||||
|         line-height: 1.3em; | ||||
|     } | ||||
|     h3 { | ||||
|         font-weight: normal; | ||||
|         font-size: 16px; | ||||
|         margin: 8px auto; | ||||
|         font-weight: 500; | ||||
|         font-size: 1.138em; | ||||
|         margin: 7px auto 5px; | ||||
|         line-height: 1.3em; | ||||
|     } | ||||
|     h4, | ||||
|     h5 { | ||||
|         font-weight: normal; | ||||
|         font-size: 14px; | ||||
|         margin: 8px auto; | ||||
|         font-weight: 500; | ||||
|         font-size: 1.067em; | ||||
|         line-height: 1.3em; | ||||
|         margin: 8px auto 5px; | ||||
|     } | ||||
|     & > span > p:first-child { | ||||
|     } | ||||
|     dl.message-properties { | ||||
|         border: 1px solid #ddd; | ||||
|         border-radius: 2px; | ||||
|  | ||||
|         margin: 5px auto 10px; | ||||
|         &>dt { | ||||
|             padding: 0px 3px 2px 3px; | ||||
|             font-family: monospace; | ||||
|             font-weight: normal; | ||||
|             margin: 5px 3px 1px; | ||||
|             color: #AD1625; | ||||
|             white-space: nowrap; | ||||
|             &.optional { | ||||
|                 font-style: italic; | ||||
|  | ||||
|             } | ||||
|             .property-type { | ||||
|                 font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif; | ||||
|                 color: #666; | ||||
|                 font-style: italic; | ||||
|                 font-size: 11px; | ||||
|                 float: right; | ||||
|             } | ||||
|             &:after { | ||||
|                 content: ""; | ||||
|                 display: table; | ||||
|                 clear: both; | ||||
|             } | ||||
|         } | ||||
|         &>dd { | ||||
|             margin: 0px 8px 2px 13px; | ||||
|             vertical-align: top; | ||||
|         } | ||||
|     } | ||||
|     ol.node-ports { | ||||
|         margin: 0; | ||||
|         li { | ||||
|             border: 1px solid #ddd; | ||||
|             border-radius: 2px; | ||||
|             list-style-position: inside; | ||||
|             padding: 3px; | ||||
|             margin-bottom: 5px; | ||||
|             dl.message-properties { | ||||
|                 border: none; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     .node-info-header { | ||||
|         i { | ||||
|             width: 10px; | ||||
|             text-align: center; | ||||
|             transition: transform 0.2s ease-in-out; | ||||
|             margin-right: 4px; | ||||
|         } | ||||
|         color: #333; | ||||
|         &:hover, &:focus { | ||||
|             text-decoration: none; | ||||
|         } | ||||
|         &.expanded { | ||||
|             i { | ||||
|                 transform: rotate(90deg); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| .sidebar-node-info-stack { | ||||
|     position: absolute; | ||||
|     top: 0; | ||||
|     bottom: 0; | ||||
|     left: 0; | ||||
|     right: 0; | ||||
|     overflow-y: scroll; | ||||
| } | ||||
| .node-info-tips { | ||||
|     display: none; | ||||
|     position: absolute; | ||||
|     left:0; | ||||
|     right:0; | ||||
|     bottom: 0; | ||||
|     height: 150px; | ||||
|     box-sizing: border-box; | ||||
|     border-top: 1px solid $secondary-border-color; | ||||
|     background-color: #fff; | ||||
|     padding: 20px; | ||||
|     box-shadow: 0 5px 20px 0px rgba(0, 0, 0, 0.3); | ||||
|     overflow-y: auto; | ||||
| } | ||||
| .sidebar-node-info.show-tips { | ||||
|     .sidebar-node-info-stack { | ||||
|         bottom: 150px; | ||||
|     } | ||||
|     .node-info-tips { | ||||
|         display: block; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .node-info-tips:before { | ||||
|   content: ''; | ||||
|   display: inline-block; | ||||
|   height: 100%; | ||||
|   vertical-align: middle; | ||||
|   margin-right: -0.25em; /* Adjusts for spacing */ | ||||
| } | ||||
|  | ||||
| .node-info-tip { | ||||
|     display: inline-block; | ||||
|     vertical-align: middle; | ||||
|     width: 100%; | ||||
|     font-size: 16px; | ||||
|     text-align: center; | ||||
|     line-height: 1.9em; | ||||
|     color : #bbb; | ||||
|     @include disable-selection; | ||||
|     cursor: default; | ||||
| } | ||||
| .node-info-tips-buttons { | ||||
|     position: absolute; | ||||
|     top: 4px; | ||||
|     right: 6px; | ||||
|     a { | ||||
|         color: #ddd !important; | ||||
|         border-color: #d9d9d9 !important; | ||||
|         margin-left: 4px; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .node-info-property-config-node { | ||||
|     border: 1px solid #eee; | ||||
|     border-radius: 4px; | ||||
|     padding: 2px 4px 2px; | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /** | ||||
|  * Copyright 2015 IBM Corp. | ||||
|  * 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. | ||||
| @@ -14,48 +14,241 @@ | ||||
|  * limitations under the License. | ||||
|  **/ | ||||
|  | ||||
| ul.red-ui-tabs { | ||||
|     list-style-type: none; | ||||
|     padding:0; | ||||
|     margin: 0; | ||||
|     display: block; | ||||
|     height: 35px; | ||||
|     box-sizing:border-box; | ||||
|     white-space: nowrap; | ||||
|     border-bottom: 1px solid $primary-border-color; | ||||
|     background: #fff; | ||||
|     @include disable-selection; | ||||
| } | ||||
|  | ||||
| ul.red-ui-tabs li { | ||||
|     box-sizing: border-box; | ||||
|     display: inline-block; | ||||
|     border-left: 1px solid  $primary-border-color; | ||||
|     border-top: 1px solid  $primary-border-color; | ||||
|     border-right: 1px solid $primary-border-color; | ||||
|     border-bottom: 1px solid $primary-border-color; | ||||
|     background: $tab-background-inactive; | ||||
|     margin: 3px 3px 0 3px; | ||||
|     height: 32px; | ||||
|     line-height: 29px; | ||||
|     max-width: 200px; | ||||
|     width: 14%; | ||||
|     overflow: hidden; | ||||
|     white-space: nowrap; | ||||
| } | ||||
|  | ||||
| ul.red-ui-tabs li a.red-ui-tab-label { | ||||
|     display: block; | ||||
|     font-size: 14px; | ||||
|     padding-left: 12px; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     color: #666; | ||||
| } | ||||
| ul.red-ui-tabs li { | ||||
| .red-ui-tabs { | ||||
|     position: relative; | ||||
|     background: #fff; | ||||
|     overflow: hidden; | ||||
|     height: 35px; | ||||
|     box-sizing: border-box; | ||||
|  | ||||
|     .red-ui-tabs-scroll-container { | ||||
|         height: 60px; | ||||
|         overflow-x: scroll; | ||||
|         overflow-y: hidden; | ||||
|         &::-webkit-scrollbar { | ||||
|             display: none; | ||||
|         } | ||||
|     } | ||||
|     & ul { | ||||
|         //background: #9999ff; | ||||
|         list-style-type: none; | ||||
|         padding:0; | ||||
|         margin: 0; | ||||
|         display: block; | ||||
|         height: 35px; | ||||
|         box-sizing:border-box; | ||||
|         border-bottom: 1px solid $primary-border-color; | ||||
|         white-space: nowrap; | ||||
|         @include disable-selection; | ||||
|  | ||||
|         li { | ||||
|             box-sizing: border-box; | ||||
|             display: inline-block; | ||||
|             border-left: 1px solid  $primary-border-color; | ||||
|             border-top: 1px solid  $primary-border-color; | ||||
|             border-right: 1px solid $primary-border-color; | ||||
|             border-bottom: 1px solid $primary-border-color; | ||||
|             background: $tab-background-inactive; | ||||
|             margin: 3px 3px 0 3px; | ||||
|             height: 32px; | ||||
|             line-height: 29px; | ||||
|             max-width: 200px; | ||||
|             width: 14%; | ||||
|             overflow: hidden; | ||||
|             white-space: nowrap; | ||||
|             position: relative; | ||||
|  | ||||
|             a.red-ui-tab-label { | ||||
|                 display: block; | ||||
|                 font-size: 14px; | ||||
|                 padding-left: 12px; | ||||
|                 width: 100%; | ||||
|                 height: 100%; | ||||
|                 color: #666; | ||||
|             } | ||||
|             a:hover { | ||||
|                 text-decoration: none; | ||||
|             } | ||||
|             a:focus { | ||||
|                 text-decoration: none; | ||||
|             } | ||||
|  | ||||
|             &:not(.active) a:hover+a.red-ui-tab-close { | ||||
|                 background: $tab-background-hover; | ||||
|             } | ||||
|             &.active { | ||||
|                 background: $tab-background-active; | ||||
|                 font-weight: bold; | ||||
|                 border-bottom: 1px solid #fff; | ||||
|                 z-index: 2; | ||||
|  | ||||
|                 a { | ||||
|                     color: #333; | ||||
|                 } | ||||
|                 a.red-ui-tab-close { | ||||
|                     color: #aaa; | ||||
|                     background: $tab-background-active; | ||||
|                     &:hover { | ||||
|                         background: $workspace-button-background-hover !important; | ||||
|                         color: $workspace-button-color-hover; | ||||
|                     } | ||||
|                 } | ||||
|                 .red-ui-tab-icon { | ||||
|                     opacity: 0.2; | ||||
|                 } | ||||
|             } | ||||
|             &:not(.active) a:hover { | ||||
|                 color: $workspace-button-color-hover; | ||||
|                 background: $tab-background-hover; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     &.red-ui-tabs-scrollable { | ||||
|         padding-left: 21px; | ||||
|         padding-right: 21px; | ||||
|     } | ||||
|     &.red-ui-tabs-add { | ||||
|         padding-right: 35px; | ||||
|     } | ||||
|     &.red-ui-tabs-add.red-ui-tabs-scrollable { | ||||
|         padding-right: 59px; | ||||
|     } | ||||
|  | ||||
|     &.red-ui-tabs-vertical { | ||||
|         box-sizing: border-box; | ||||
|         height: 100%; | ||||
|         border-right: 1px solid $primary-border-color; | ||||
|         margin: 0; | ||||
|         background: #f3f3f3; | ||||
|         overflow: visible; | ||||
|  | ||||
|         .red-ui-tabs-scroll-container { | ||||
|             height: auto; | ||||
|             overflow-x:visible; | ||||
|             overflow-y: scroll; | ||||
|         } | ||||
|  | ||||
|         & ul { | ||||
|             padding: 0; | ||||
|             height: auto; | ||||
|             border: none; | ||||
|             width: calc(100% + 1px); | ||||
|             li { | ||||
|                 width: 100%; | ||||
|                 display: block; | ||||
|                 margin: 0; | ||||
|                 border: none; | ||||
|                 border-right: 1px solid $primary-border-color; | ||||
|                 height: auto; | ||||
|                 &:not(:first-child) { | ||||
|                     border-top: 1px solid  $secondary-border-color; | ||||
|                 } | ||||
|                 &:last-child { | ||||
|                     border-bottom: 1px solid  $secondary-border-color; | ||||
|                 } | ||||
|  | ||||
|                 a.red-ui-tab-label { | ||||
|                     padding: 9px; | ||||
|                 } | ||||
|  | ||||
|                 &.active { | ||||
|                     border-right: 1px solid #fff; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| .red-ui-tab-button { | ||||
|     position: absolute; | ||||
|     box-sizing: border-box; | ||||
|     top: 0; | ||||
|     right: 0; | ||||
|     height: 35px; | ||||
|     background: #fff; | ||||
|     border-bottom: 1px solid $primary-border-color; | ||||
|     z-index: 2; | ||||
|  | ||||
|     a { | ||||
|         @include workspace-button; | ||||
|         line-height: 32px; | ||||
|         height: 32px; | ||||
|         width: 32px; | ||||
|         margin-top: 3px; | ||||
|         margin-right:3px; | ||||
|         margin-left:3px; | ||||
|         border: 1px solid $primary-border-color; | ||||
|         z-index: 2; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .red-ui-tab-scroll { | ||||
|     width: 21px; | ||||
|     top: 0; | ||||
|     a { | ||||
|         height: 35px; | ||||
|         width: 21px; | ||||
|         display: block; | ||||
|         color: $link-color; | ||||
|         font-size: 22px; | ||||
|         text-align: center; | ||||
|         margin:0; | ||||
|         border-left: none; | ||||
|         border-right: none; | ||||
|         border-top: none; | ||||
|     } | ||||
| } | ||||
| .red-ui-tab-scroll-left { | ||||
|     left:0; | ||||
|     a { | ||||
|         border-right: 1px solid $primary-border-color; | ||||
|         // box-shadow: 8px 0px 5px -2px rgba(0,0,0,0.1); | ||||
|     } | ||||
| } | ||||
| .red-ui-tab-scroll-right { | ||||
|     right: 0px; | ||||
|     a { | ||||
|         border-left: 1px solid $primary-border-color; | ||||
|         // box-shadow: -8px 0px 5px -2px rgba(0,0,0,0.1); | ||||
|     } | ||||
|  | ||||
| } | ||||
| .red-ui-tabs.red-ui-tabs-add .red-ui-tab-scroll-right { | ||||
|     right: 38px; | ||||
| } | ||||
|  | ||||
| .red-ui-tab-icon { | ||||
|     margin-left: -8px; | ||||
|     margin-right: 3px; | ||||
|     margin-top: -2px; | ||||
|     opacity: 0.1; | ||||
|     width: 20px; | ||||
|     height: 20px; | ||||
|     vertical-align: middle; | ||||
| } | ||||
|  | ||||
| .red-ui-tabs-badges { | ||||
|     position: absolute; | ||||
|     top:2px; | ||||
|     right:2px; | ||||
| } | ||||
| .red-ui-tab-closeable .red-ui-tabs-badges { | ||||
|     right: 22px; | ||||
| } | ||||
|  | ||||
| .red-ui-tab.node_changed img.node_changed { | ||||
|     display: inline-block; | ||||
| } | ||||
| .red-ui-tab.node_error img.node_error { | ||||
|     display: inline-block; | ||||
| } | ||||
|  | ||||
| .red-ui-tabs-badges img { | ||||
|     width: 10px; | ||||
|     height: 10px; | ||||
|     margin-right: 2px; | ||||
|     vertical-align: top; | ||||
|  | ||||
| } | ||||
| .red-ui-tab-close { | ||||
|     background: $tab-background-inactive; | ||||
|     opacity: 0.8; | ||||
| @@ -74,50 +267,3 @@ ul.red-ui-tabs li { | ||||
|         opacity: 1; | ||||
|     } | ||||
| } | ||||
| ul.red-ui-tabs li:not(.active) a:hover+a.red-ui-tab-close { | ||||
|     background: $tab-background-hover; | ||||
| } | ||||
|  | ||||
| ul.red-ui-tabs li.active a.red-ui-tab-close { | ||||
|     color: #aaa; | ||||
|     background: $tab-background-active; | ||||
|     &:hover { | ||||
|         background: $workspace-button-background-hover !important; | ||||
|         color: $workspace-button-color-hover; | ||||
|     } | ||||
| } | ||||
|  | ||||
| ul.red-ui-tabs li a:hover { | ||||
|     text-decoration: none; | ||||
| } | ||||
|  | ||||
| ul.red-ui-tabs li:not(.active) a:hover { | ||||
|     color: $workspace-button-color-hover; | ||||
|     background: $tab-background-hover; | ||||
| } | ||||
|  | ||||
| ul.red-ui-tabs li a:focus { | ||||
|     text-decoration: none; | ||||
| } | ||||
|  | ||||
| ul.red-ui-tabs li.active { | ||||
|     background: $tab-background-active; | ||||
|     font-weight: bold; | ||||
|     border-bottom: 1px solid #fff; | ||||
| } | ||||
| ul.red-ui-tabs li.active a { | ||||
|     color: #333; | ||||
| } | ||||
|  | ||||
| ul.red-ui-tabs li img { | ||||
|     margin-left: -8px; | ||||
|     margin-right: 3px; | ||||
|     margin-top: -2px; | ||||
|     opacity: 0.1; | ||||
|     width: 20px; | ||||
|     height: 20px; | ||||
|     vertical-align: middle; | ||||
| } | ||||
| ul.red-ui-tabs li.active img { | ||||
|     opacity: 0.2; | ||||
| } | ||||
|   | ||||
							
								
								
									
										29
									
								
								editor/sass/ui/common/checkboxSet.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,29 @@ | ||||
| /** | ||||
|  * 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-ui-checkboxSet { | ||||
|     width: 15px; | ||||
|     display: inline-block; | ||||
|     color: #888; | ||||
|     cursor: pointer; | ||||
|     input { | ||||
|         display:none; | ||||
|     } | ||||
|  | ||||
|     &.disabled { | ||||
|         pointer-events: none; | ||||
|         color: #ddd; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										75
									
								
								editor/sass/ui/common/editableList.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,75 @@ | ||||
| /** | ||||
|  * 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-ui-editableList-border { | ||||
|     border: 1px solid $form-input-border-color; | ||||
|     border-radius: 4px; | ||||
|     .red-ui-editableList-header { | ||||
|         border-bottom: 1px solid $form-input-border-color; | ||||
|         padding: 2px 16px 2px 4px; | ||||
|         font-size: 0.9em; | ||||
|     } | ||||
| } | ||||
| .red-ui-editableList-container { | ||||
|     padding: 5px; | ||||
|     margin: 0; | ||||
|     vertical-align: middle; | ||||
|     box-sizing: border-box; | ||||
|     .red-ui-editableList-list { | ||||
|         list-style-type:none; | ||||
|         margin: 0; | ||||
|     } | ||||
|     .red-ui-editabelList-item-placeholder { | ||||
|         border: 2px dashed $secondary-border-color !important; | ||||
|     } | ||||
|     li { | ||||
|         box-sizing: border-box; | ||||
|         position: relative; | ||||
|         background: #fff; | ||||
|         margin:0; | ||||
|         padding:8px 0px; | ||||
|         border-bottom: 1px solid $secondary-border-color; | ||||
|         min-height: 20px; | ||||
|         .red-ui-editableList-item-handle { | ||||
|             position: absolute; | ||||
|             top: 50%; | ||||
|             left: 2px; | ||||
|             margin-top: -7px; | ||||
|             color: #eee; | ||||
|             cursor: move; | ||||
|         } | ||||
|         .red-ui-editableList-item-remove { | ||||
|             position: absolute; | ||||
|             top: 50%; | ||||
|             right: 0px; | ||||
|             margin-top: -9px; | ||||
|         } | ||||
|         &.ui-sortable-helper { | ||||
|             border-top: 1px solid $secondary-border-color; | ||||
|         } | ||||
|         //.red-ui-editableList-item-content { outline: 1px solid red} | ||||
|  | ||||
|         &.red-ui-editableList-item-sortable .red-ui-editableList-item-content { | ||||
|             margin-left: 22px; | ||||
|         } | ||||
|         &.red-ui-editableList-item-removable .red-ui-editableList-item-content { | ||||
|             margin-right: 28px; | ||||
|         } | ||||
|         &.red-ui-editableList-item-deleting { | ||||
|             background: #fee; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
							
								
								
									
										65
									
								
								editor/sass/ui/common/nodeList.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,65 @@ | ||||
| /** | ||||
|  * 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-ui-nodeList { | ||||
|     .red-ui-editableList-container { | ||||
|         padding: 0; | ||||
|         li { | ||||
|             padding: 2px 5px; | ||||
|             margin: 0; | ||||
|             white-space: nowrap; | ||||
|             border: none; | ||||
|             background: #fefefe; | ||||
|             &:hover { | ||||
|                 background: #f0f0f0; | ||||
|             } | ||||
|  | ||||
|             i.fa-angle-right { | ||||
|                 text-align: center; | ||||
|                 width: 15px; | ||||
|                 transition: transform 0.1s ease-in-out; | ||||
|             } | ||||
|             .expandable { | ||||
|                 cursor: pointer; | ||||
|             } | ||||
|             .expanded i.fa-angle-right { | ||||
|                 transform: rotate(90deg); | ||||
|             } | ||||
|             .meta { | ||||
|                 float: right; | ||||
|                 input[type="checkbox"] { | ||||
|                     margin: 0; | ||||
|                 } | ||||
|             } | ||||
|             .red-ui-editableList-item-content.disabled { | ||||
|                 color: #ccc; | ||||
|             } | ||||
|             &.red-ui-editableList-section-header { | ||||
|                 background: #f0f0f0; | ||||
|                 .red-ui-editableList-item-content.disabled { | ||||
|                     color: #bbb; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|         } | ||||
|     } | ||||
|     .red-ui-editableList-header { | ||||
|         text-align: left; | ||||
|         &>span:last-child { | ||||
|             float: right; | ||||
|             font-size: 14px; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										70
									
								
								editor/sass/ui/common/searchBox.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,70 @@ | ||||
| /** | ||||
|  * 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-ui-searchBox-container { | ||||
|     position: relative; | ||||
|     i { | ||||
|         font-size: 10px; | ||||
|         color: #666; | ||||
|     } | ||||
|     i.fa-search { | ||||
|         position: absolute; | ||||
|         pointer-events: none; | ||||
|         left: 8px; | ||||
|         top: 9px; | ||||
|     } | ||||
|     i.fa-times { | ||||
|         position: absolute; | ||||
|         right: 5px; | ||||
|         top: 9px; | ||||
|     } | ||||
|     input { | ||||
|         border-radius: 0; | ||||
|         border: none; | ||||
|         width: 100%; | ||||
|         box-shadow: none; | ||||
|         -webkit-box-shadow: none; | ||||
|         padding: 3px 17px 3px 22px; | ||||
|         margin: 0px; | ||||
|         height: 30px; | ||||
|         box-sizing:border-box; | ||||
|  | ||||
|         &:focus { | ||||
|             border: none; | ||||
|             box-shadow: none; | ||||
|             -webkit-box-shadow: none; | ||||
|         } | ||||
|     } | ||||
|     a { | ||||
|         position: absolute; | ||||
|         right: 0; | ||||
|         top: 0; | ||||
|         bottom: 0; | ||||
|         width: 20px; | ||||
|         display: none; | ||||
|     } | ||||
|     .red-ui-searchBox-resultCount { | ||||
|         position: absolute; | ||||
|         right: 18px; | ||||
|         top: 4px; | ||||
|         background: #eee; | ||||
|         color: #666; | ||||
|         padding: 1px 8px; | ||||
|         font-size: 9px; | ||||
|         border-radius: 4px; | ||||
|     } | ||||
| } | ||||