From ffbb309ba21a6d002c0f18dfea1a8c6097d60f26 Mon Sep 17 00:00:00 2001 From: xevidos Date: Tue, 17 Jul 2018 13:32:22 -0400 Subject: [PATCH] Fixed dev branch sync --- components/filemanager/class.filemanager.php | 2 +- components/filemanager/dialog.php | 15 + components/filemanager/init.js | 85 +- data/cache/Codiad-Archives-master.current | 0 data/cache/Codiad-AutoPrefixer-master.current | 0 data/cache/Codiad-CodeGit-master.current | 0 data/cache/Codiad-CodeSettings-master.current | 0 .../cache/Codiad-Collaborative-master.current | 0 data/cache/Codiad-ColorPicker-master.current | 0 data/cache/Codiad-DragDrop-master.current | 0 data/cache/Codiad-Duplicate-master.current | 0 data/cache/Codiad-Macro-master.current | 0 data/cache/Codiad-Permissions-master.current | 0 data/cache/Codiad-Terminal-master.current | 0 data/cache/Codiad-Together-master.current | 0 data/cache/auto_save.current | 0 data/cache/market.current | 0 data/cache/market.last | 0 .../color/0fc47e267342f898f0694de8c66fe02a | 1 - .../color/9325ce6c6b09562de60b7db96a7fb8fa | 1 - .../color/d66c63e2c42ddc53c20116c7f4dd67d2 | 1 - data/collaborative/color/index.db | 0 .../521a72d0c807e2f9d68b250337d72b6f | 1 - data/collaborative/heartbeat/index.db | 1 - .../00f67b79a2f9c0defb5cb9e35a1eedc9 | 1 - .../0231def7a6a1608f8242d5dfeee17fec | 1 - .../0502dab6244f6cf47a408682bde2da19 | 1 - .../06b4bf234c856dfc262ab9a104e7515d | 1 - .../10cd3ff020218b98a70ae382ac763cba | 1 - .../142ce5a5e09022f6b27c33c5bab75df2 | 1 - .../19d575f3f3ce8f2aa9001aa4833228a1 | 1 - .../1e7e459cde205d91c481b9015511414b | 1 - .../23843b6cae13d579283d820ae8604f11 | 1 - .../2d9e916777b9f877e8c43fdc5820f3ed | 1 - .../357768ee57f499a81982c891d2e8212d | 1 - .../39d5e786f59a5b05c3d7e4296ea42a76 | 1 - .../3bad7b063c15d3531895bc5ad94efae5 | 1 - .../3c0811e1791db35b940af5330f4ea307 | 1 - .../3cee2d164d3de51fe4c83d4954105eb5 | 1 - .../3fa8e3235f78fded26b0a95b3550a30c | 1 - .../40f6a41afa74ace596bc5735f4133b27 | 1 - .../42b6da74b138c81b431dd486e605d7a1 | 1 - .../45f16dcf5deda7c1cfb3ba414bbf37a0 | 1 - .../46e202c38d2c8a4216b81c0007276f38 | 1 - .../48f9526f719a68de0bfb94ccd4284528 | 1 - .../58b9c53d2f43d2a924386e0fc7f1a364 | 1 - .../5a6ea387fe176a5ee685311d1368bdbf | 1 - .../5e6656bf1b6fd77c4f86ab277cc0988b | 1 - .../6117d79a736608652f0e2b84f18c2ee6 | 1 - .../64054ac5cf0355c0c7a54a47a753e918 | 1 - .../6cddbc005f97f76483eaf7397644de3b | 1 - .../72670089ea1a80f64d41b30ab5abb317 | 1 - .../77df941f7befd27ec8acf4166d618539 | 1 - .../83e043f141603a9150e0718bc09bdac0 | 1 - .../869e192baaf4f39d39c181279dffa05f | 1 - .../8de74798a6eade7a47588beedfd958f4 | 1 - .../97e1bfaa42d9fd93e5a8996f400585bd | 1 - .../9cbc99f31b556308807390b4655cabf9 | 1 - .../a07ab47d2665186a3e41f4f730ec7683 | 1 - .../a25fdf5bb2a3722799c1dd377f337c6a | 1 - .../a2962a947d6d5fcbc65facb728e37051 | 1 - .../a2c548e3c41867b8373761249047ecb0 | 1 - .../a65fec1802fb6a7362b302cfc0d3dacc | 1 - .../ad20d395c6cbf9716cdccffe8776952e | 1 - .../c411bfdc2e7d453914f61c6ac1113793 | 1 - .../c8a4d866e1e889520d0e31839e0854e3 | 1 - .../d63bfda1e19a710e4869b47822cbabf1 | 1 - .../dcbd2e14b07c72b85ad7b5cd989cfd09 | 1 - .../df0d7fda7f488203b2a32d3f9f6f8822 | 1 - .../e1d97e7fc378fc2d6bae15b009dfe6b2 | 1 - .../e2693b5a21a0545b9c1d44f2647703d0 | 1 - .../e811c035b4fd6345836647c699408f91 | 1 - .../eaacf5898c2cc7e26f68fe871e166773 | 1 - .../ec2c158db3453f8ce0e25d234ead42b7 | 1 - .../f3895333c762ec423739ab7db5496006 | 1 - .../fbf7364839635641f96c195cbdcb7669 | 1 - .../feb6db58347bafc0959a719eb8787268 | 1 - data/collaborative/registered/index.db | 53 - .../22f1d2494993531e6b1a016a8d8b6438 | 1 - .../2741708a0ee997fc889e4770f0a3b8ea | 1 - .../51640228b7c95ec21668deae8e14fd37 | 1 - .../6e2f31eef830626055498ba7ba41f3dc | 1 - .../8ca94770f4850fd864af830a177c90aa | 1 - .../92e0d8216f938e9f6450634e2ac0d0da | 1 - .../a0debe38b2118dc397cfe4898ab46b9e | 1 - .../cc91755cde6ab90a7f2aada55994f97b | 1 - .../ddd0681a0e90f0480910b3fb7719dde7 | 1 - .../e6ca864b939a36765d43aa4ae3e8503e | 1 - .../eceb4e0876fe71ea018f446d0d34eca1 | 1 - .../f46fc66fdb891a570f1a03add3c166cc | 1 - data/collaborative/selection/index.db | 12 - .../shadow/0231def7a6a1608f8242d5dfeee17fec | 66 - .../shadow/045f3b992ba538f82bbed4df39459fa9 | 1143 -- .../shadow/07a6a7a936469108b7eb1d5595405b41 | 577 - .../shadow/08791dea727327b5a0481e2a8fb350ff | 55 - .../shadow/09f6bedc033ef7c069a54c82fa8c7e62 | 773 -- .../shadow/0b1d76a6acf247da79040a128cc3a528 | 26 - .../shadow/0bde8ce947815fedb4f056ef7111cc47 | 73 - .../shadow/0c7b6f96afab6e8fda974eea5a93e5c0 | 30 - .../shadow/1972a2c94075705efcb5226d1ac9889b | 26 - .../shadow/1dbc3b6b9a38f3065d2276656017f3f9 | 190 - .../shadow/1fad7d7bf81e5524143caee6f21cdfcf | 367 - .../shadow/1fe1266a755f7810fe2c73344d75770e | 28 - .../shadow/22f1d2494993531e6b1a016a8d8b6438 | 76 - .../shadow/23295112670db74d060930018ea19538 | 7 - .../shadow/2497b873b6c596aa0da54c628cb5fbd5 | 65 - .../shadow/2741708a0ee997fc889e4770f0a3b8ea | 28 - .../shadow/29a1edb2a360ce477af0bf0ecb5a2447 | 18 - .../shadow/2e951e1c04a09a48fa2ccc2c730cc7fd | 7 - .../shadow/3403458d3f9421a02e422cfe62741852 | 3 - .../shadow/37663faf229dd1ba5c77f60047934098 | 76 - .../shadow/3acf50a01e367e57cdfb32a08ac50fd0 | 85 - .../shadow/3ba13a3d4c97cda98f8675c7bccd82fe | 27 - .../shadow/3cd97ad18d409c51b5578b0b34c80ce6 | 236 - .../shadow/3e7c9f851da2aad425970b0be26f77ac | 53 - .../shadow/41118f97725e869c87455be694a53fe5 | 55 - .../shadow/41bbb319169d502d14088dd0ef762533 | 27 - .../shadow/45c06d935cb54cb6c59260028d5bb91c | 58 - .../shadow/49f589063ce4ea454204ce70b134a893 | 1005 -- .../shadow/4b5e696279610e8b11147b869777b685 | 16 - .../shadow/4e259f0bb87191d1f975f535dae106ea | 59 - .../shadow/51108580d8b1830f9d7e48021d6bde46 | 33 - .../shadow/51640228b7c95ec21668deae8e14fd37 | 33 - .../shadow/52e4730d2a0be9abffbc2bdea2204b5e | 33 - .../shadow/5456a19d342557d417efd28aced31c16 | 577 - .../shadow/57e91e0d3a50e23bca8a00a5e7539758 | 30 - .../shadow/5b9b38f2e267013b0042f802a120442b | 68 - .../shadow/5bb4642abdf3f7aa35eafebcba91df17 | 1005 -- .../shadow/5e7826f99928dc790d9cba5022cc30b4 | 773 -- .../shadow/62da00833cc673ea3506e8c74cc03010 | 65 - .../shadow/64029b02e9eba9c858cf99ac5488be14 | 1 - .../shadow/65dd434e2ad28232ea285fab94ddfb75 | 1 - .../shadow/6a4b62d9024b66e2e6b0601593581d96 | 576 - .../shadow/6c9195df1db60f35f1cdb2d9ee97e4bf | 34 - .../shadow/6e2f31eef830626055498ba7ba41f3dc | 33 - .../shadow/6f1528298858cf4548f52302b9b3df09 | 60 - .../shadow/74153bbd75415243bee04ba5be3e0975 | 576 - .../shadow/74dea1994cc8087e93aa43126d0609fb | 27 - .../shadow/76a80f9d3d1f00f202f5b6a01af0fe82 | 34 - .../shadow/76e43d7b712f43510dae0cbf50e40bc9 | 76 - .../shadow/7c998484eb7cf6925bb4c8c12d9da2fc | 1 - .../shadow/7ed2ef8c2f8f09385af754d69279db57 | 401 - .../shadow/7f444cf225792632b9816fd7c212e785 | 192 - .../shadow/7f86659d402c096aeedb08e84283f596 | 48 - .../shadow/7fa8be2ce86bf557e18b4d8ffe01ab67 | 12 - .../shadow/7ff97b3475c197f26cad514f22ceb86b | 577 - .../shadow/81996f949129f48e0128cdb7b3cb7716 | 1 - .../shadow/870b887e9a5909882cbcebb4ba14b794 | 59 - .../shadow/8ca94770f4850fd864af830a177c90aa | 27 - .../shadow/92e0d8216f938e9f6450634e2ac0d0da | 27 - .../shadow/9412cdcf8b955c57d704e4994234d890 | 102 - .../shadow/941568d6e728e0f58bf59a686509defa | 69 - .../shadow/97d4726a27b0dc089ff2a1ebd49794c6 | 28 - .../shadow/9efb45e0fb52aae6da0f0aafa65a2485 | 136 - .../shadow/a0debe38b2118dc397cfe4898ab46b9e | 71 - .../shadow/a2a72e21333cf981f4a2281f1504cea3 | 1 - .../shadow/a6c8c908850fdd2fba740ab39de66cd2 | 460 - .../shadow/a7591bf8af26986d68f36815a5ea5273 | 33 - .../shadow/a7f6228ec1c43e9c52f5e91d07d4b453 | 3 - .../shadow/a8419f9f1457039c7fbc9740927be4e0 | 174 - .../shadow/a86d8153e2f67aeb9590093a5c30a149 | 70 - .../shadow/a8774609eda0bf3aa1cb32a96b594604 | 444 - .../shadow/abaaf90695610e34effe00775cd6f641 | 195 - .../shadow/acb11eb95add8cfd988d342e3de0d2e8 | 174 - .../shadow/af2d3669b4f915c4b09d4a8bb8dea1c9 | 795 -- .../shadow/b039f3a0fad6690bccc0969dbe561fcd | 18 - .../shadow/b18552684dcd0101a4c484af9d0f2615 | 39 - .../shadow/b64f8e080258d3fa416e98888a27cea5 | 33 - .../shadow/b7e0dffe6d3af66063c9752be07c9e75 | 30 - .../shadow/b818ce32cd61aa5d83fbf357d1184635 | 174 - .../shadow/bc2ad9133d134977d621104c59e9fd61 | 28 - .../shadow/bdd330a1af3dca522aae993ac38cf3c5 | 3 - .../shadow/bfd3f8ef41ef1f98968c106a423699b2 | 1 - .../shadow/c34a5d1f562bfd5f37c3de4632f25a47 | 7 - .../shadow/cbc7af3f90284b745f9cca4430668ab5 | 48 - .../shadow/cc91755cde6ab90a7f2aada55994f97b | 28 - .../shadow/ccdab27e57aa054e492f5b3d3850f6e5 | 55 - .../shadow/cdc42f08882d002bac276e9c1bdcac67 | 26 - .../shadow/d06ec8c63e9acac96c0817560b2dfabe | 55 - .../shadow/d431495cf623dd61f00bfa1aef2c6e0c | 333 - .../shadow/d778ad34ea1212ed7081b731d9a8dd80 | 10281 ---------------- .../shadow/dc103bcc7b8517ba408c3c19eca08b6e | 175 - .../shadow/ddd0681a0e90f0480910b3fb7719dde7 | 15 - .../shadow/e1726a184e69c885fe27c8669b2c885e | 773 -- .../shadow/e1ea49c66882f7882bfc53f7f896d31d | 7 - .../shadow/e2630975cd26f1f4330486f3d0a9055e | 576 - .../shadow/e275a3a559f2c49aff391d8cc3fe538d | 46 - .../shadow/e48aa03433d347bfaffcb9429f62a27c | 1 - .../shadow/e693185c0b5a32ed6979e22b10f1e433 | 83 - .../shadow/e6ca864b939a36765d43aa4ae3e8503e | 76 - .../shadow/ea5288a62fdc3f1ebfab27f709082842 | 43 - .../shadow/eceb4e0876fe71ea018f446d0d34eca1 | 34 - .../shadow/ede158f1f62eabab87526f2db25fad17 | 39 - .../shadow/ee3d3118cdab96fd9c2343d4742f2810 | 46 - .../shadow/ee62af99d5b417b7381e5299027cca6e | 28 - .../shadow/eef1f14577636af47a8ee7f55ba777bf | 209 - .../shadow/ef7b395faeaf7d9a60fd54f2dca409e5 | 350 - .../shadow/f0e5f885ff64458f62a2f0c202070139 | 20 - .../shadow/f3d17d035479bb837c846584a985fc9b | 33 - .../shadow/f46fc66fdb891a570f1a03add3c166cc | 34 - .../shadow/f6d27d5345b78d2d52c54cb2ada888f5 | 4 - .../shadow/f858621dbec7ad5f5a1f28be85acf0f0 | 31 - .../shadow/fe7e13bcdd4f10c3c8c55b3bb59e5ef8 | 576 - data/collaborative/shadow/index.db | 114 - .../text/060728b4cccf0e88d2d445947e0f6836 | 33 - .../text/0874412e2b238973158064bf29510f49 | 59 - .../text/098797bf7c4448ed6397b23257b8d0d1 | 102 - .../text/0b00081372c3f176d14f3626f2ff3ef5 | 69 - .../text/1bb5e516806eb514fb3779d8dff2bf13 | 773 -- .../text/264f67810f124a1136a3bca443af2651 | 1143 -- .../text/273e1de64502c06a2384fc8b66dfb4e4 | 70 - .../text/2a0da7cebddb7852e2ac34f7c0d5e0c7 | 1005 -- .../text/2af01a9b54a6e94e6a011cd84b4c5b48 | 48 - .../text/2b2340b37b43b24e5a2731ed5db41118 | 60 - .../text/2bcf46daf121a8f0ab61fb9c00ea4400 | 16 - .../text/303bfe190d5e04a7238bab12ce1bb129 | 1005 -- .../text/30e59348afad09731d1c4f8d66702f40 | 59 - .../text/329491055243ffcf41c2843c688c031d | 773 -- .../text/32e633ae3f9718c741560af1352f1a1a | 53 - .../text/37409041d6aae3c32d019a5f9481fe1a | 773 -- .../text/3833e87699ffe1cafb5dc3109d9b3dfb | 68 - .../text/3a7ac99607660738569ae0966a913bc8 | 30 - .../text/3a9233a747bb36b5549eb6d8455652d7 | 209 - .../text/3b05b09289a3db2ae8cf68f284bcfc46 | 7 - .../text/3d963d1e35c7582fb4cb19caad66130a | 350 - .../text/49234e7b9a6d49c284c2c075b71344f3 | 26 - .../text/532d917f0ec46400caa40e28a6576439 | 577 - .../text/54b750daba066a7ec6a3343604f86406 | 58 - .../text/550f42cee32ce845fd817cf600cddda0 | 12 - .../text/56cab2396298ed03d332f30384d3a133 | 192 - .../text/5b8f5fad3ae9914ed4b0fdd3c500d2e9 | 134 - .../text/5b945bc2935cd53d7f96e69b2a25dbae | 175 - .../text/6022c4dda0ee39cea577b5c430ca8eba | 1 - .../text/60cb37fe1c12580053ad40ecbfbee3e7 | 18 - .../text/6365716b69bf2058393d3c95cbf9e57a | 367 - .../text/6877732a642738ecdc29b7abb6306b16 | 444 - .../text/68b53024d1449751d6fe0678e5d19a8b | 7 - .../text/6ebbbc6206dc1a61c67475fee5a974ec | 69 - .../text/6fade3ab5ef16da4f4f55b5d4a13f71f | 174 - .../text/6ffeaa9f6d5362fa2f15fbf5a6146312 | 1 - .../text/729bd3977e9ec2c1b4869d62605d11a5 | 71 - .../text/74f9d1f373b31e36b320c5a6af2e87ea | 34 - .../text/76154443d29325fc407486ccf552c592 | 1 - .../text/76fba3c99c6a58e95b52ddf307b83ff9 | 27 - .../text/7741a9336615cea0064a11037be451c8 | 55 - .../text/7857144494313767d095f7fa224b75eb | 401 - .../text/8e024f4aac60a8331a03d54b83e75bf7 | 576 - .../text/91f54b2685411e1ea2b454be94a4b7f8 | 174 - .../text/973f750ac61e200c9a6566c6f4f0ada4 | 66 - .../text/9cf1e9203224be47c3ba9e5308987882 | 39 - .../text/a64c3a506cee116b66128f9fabd92174 | 1 - .../text/a9a0fb5543ed2953ba292d5f62bf6ae8 | 174 - .../text/afeec27bbb5ab15bae2cb560b3e7406d | 20 - .../text/b31c91140e129d845f56a9d887d718af | 3 - .../text/b4590e9cec70e9718018bc7905fc6c2d | 195 - .../text/b997313979c4592942656b494256e685 | 795 -- .../text/b9a2a6807be3cb2888a882de9a456ca8 | 236 - .../text/ba67cc584113e97440efff098f28393e | 55 - .../text/bbd5c30b8ceb2e0742e6264c1788b583 | 85 - .../text/c402a1cde9f402454c2313535a396934 | 333 - .../text/c41e653729c1a8ef77976647bbfbee70 | 7 - .../text/c611c854fd24594f69862df70e8afd48 | 55 - .../text/cddb2ae31e8ac7f5d87e69efa5924a02 | 43 - .../text/cf1d4b27a3b2b1bba71f454cc7fb5d91 | 3 - .../text/cfc98c3ef6b134046f878c0d1e586623 | 10281 ---------------- .../text/d2041fd4034fe73449cbed068d0d8296 | 76 - .../text/d416f4cb7eedbaa2b52088c3068022c1 | 28 - .../text/d52716adc5491c84a0bf68e831a266c3 | 31 - .../text/e19726eb67fd3c5787bb3825331076e4 | 33 - .../text/e31facd25dccf8a50c81c459c325e9a4 | 48 - .../text/ec501c81f6d7f8903809691ef846031d | 55 - .../text/ed6f50c067d7bad7bd358192b93543ec | 7 - .../text/edc2b5d20ee07a2ade83bca0dfc9bbc9 | 460 - .../text/edf0d6f9fc6fa8c4daafd04034251817 | 1 - .../text/ee0d4983f0759afbe9820ad34d7beec0 | 83 - .../text/f25962a7f5669c4f77a4a01d78918b40 | 1 - .../text/f61810c51eccf9e35faaf5cb43d1dfa9 | 4 - .../text/f81051379428c130bec3e26a0ce94231 | 190 - .../text/fd2c1c229ac53e0c86175bf5e58efac5 | 33 - data/collaborative/text/index.db | 75 - data/config/Macro.php | 3 - data/config/settings.FrankSmith22.php | 3 - data/config/settings.TrevorBeresford.php | 3 - data/config/settings.ithollie.php | 3 - data/config/settings.sabbakilam.php | 3 - data/config/settings.xevidos.php | 3 - favicon.ico | Bin 1150 -> 1641 bytes plugins/Codiad-Auto-Save/README.md | 3 + .../Codiad-Auto-Save/init.js | 33 +- .../Codiad-Auto-Save/plugin.json | 3 +- plugins/Codiad-Auto-Save/screen.css | 1 + plugins/Codiad-AutoUpdate-master/README.md | 31 + .../class.autoupdate.php | 331 + .../Codiad-AutoUpdate-master/controller.php | 70 + plugins/Codiad-AutoUpdate-master/dialog.php | 108 + plugins/Codiad-AutoUpdate-master/init.js | 91 + plugins/Codiad-AutoUpdate-master/plugin.json | 6 + plugins/Codiad-AutoUpdate-master/screen.png | Bin 0 -> 30742 bytes .../default.commands.json | 724 +- plugins/Codiad-DragDrop-master/README.md | 13 + plugins/Codiad-DragDrop-master/controller.php | 64 + plugins/Codiad-DragDrop-master/dialog.php | 20 + plugins/Codiad-DragDrop-master/init.js | 320 + plugins/Codiad-DragDrop-master/plugin.json | 10 + plugins/Codiad-DragDrop-master/screen.css | 33 + plugins/Codiad-DragDrop-master/template.html | 8 + 306 files changed, 1217 insertions(+), 52584 deletions(-) delete mode 100755 data/cache/Codiad-Archives-master.current delete mode 100755 data/cache/Codiad-AutoPrefixer-master.current delete mode 100755 data/cache/Codiad-CodeGit-master.current delete mode 100755 data/cache/Codiad-CodeSettings-master.current delete mode 100755 data/cache/Codiad-Collaborative-master.current delete mode 100755 data/cache/Codiad-ColorPicker-master.current delete mode 100755 data/cache/Codiad-DragDrop-master.current delete mode 100755 data/cache/Codiad-Duplicate-master.current delete mode 100755 data/cache/Codiad-Macro-master.current delete mode 100755 data/cache/Codiad-Permissions-master.current delete mode 100755 data/cache/Codiad-Terminal-master.current delete mode 100755 data/cache/Codiad-Together-master.current delete mode 100755 data/cache/auto_save.current delete mode 100755 data/cache/market.current delete mode 100755 data/cache/market.last delete mode 100755 data/collaborative/color/0fc47e267342f898f0694de8c66fe02a delete mode 100755 data/collaborative/color/9325ce6c6b09562de60b7db96a7fb8fa delete mode 100755 data/collaborative/color/d66c63e2c42ddc53c20116c7f4dd67d2 delete mode 100755 data/collaborative/color/index.db delete mode 100755 data/collaborative/heartbeat/521a72d0c807e2f9d68b250337d72b6f delete mode 100755 data/collaborative/heartbeat/index.db delete mode 100755 data/collaborative/registered/00f67b79a2f9c0defb5cb9e35a1eedc9 delete mode 100755 data/collaborative/registered/0231def7a6a1608f8242d5dfeee17fec delete mode 100755 data/collaborative/registered/0502dab6244f6cf47a408682bde2da19 delete mode 100755 data/collaborative/registered/06b4bf234c856dfc262ab9a104e7515d delete mode 100755 data/collaborative/registered/10cd3ff020218b98a70ae382ac763cba delete mode 100755 data/collaborative/registered/142ce5a5e09022f6b27c33c5bab75df2 delete mode 100755 data/collaborative/registered/19d575f3f3ce8f2aa9001aa4833228a1 delete mode 100755 data/collaborative/registered/1e7e459cde205d91c481b9015511414b delete mode 100755 data/collaborative/registered/23843b6cae13d579283d820ae8604f11 delete mode 100755 data/collaborative/registered/2d9e916777b9f877e8c43fdc5820f3ed delete mode 100755 data/collaborative/registered/357768ee57f499a81982c891d2e8212d delete mode 100755 data/collaborative/registered/39d5e786f59a5b05c3d7e4296ea42a76 delete mode 100755 data/collaborative/registered/3bad7b063c15d3531895bc5ad94efae5 delete mode 100755 data/collaborative/registered/3c0811e1791db35b940af5330f4ea307 delete mode 100755 data/collaborative/registered/3cee2d164d3de51fe4c83d4954105eb5 delete mode 100755 data/collaborative/registered/3fa8e3235f78fded26b0a95b3550a30c delete mode 100755 data/collaborative/registered/40f6a41afa74ace596bc5735f4133b27 delete mode 100755 data/collaborative/registered/42b6da74b138c81b431dd486e605d7a1 delete mode 100755 data/collaborative/registered/45f16dcf5deda7c1cfb3ba414bbf37a0 delete mode 100755 data/collaborative/registered/46e202c38d2c8a4216b81c0007276f38 delete mode 100755 data/collaborative/registered/48f9526f719a68de0bfb94ccd4284528 delete mode 100755 data/collaborative/registered/58b9c53d2f43d2a924386e0fc7f1a364 delete mode 100755 data/collaborative/registered/5a6ea387fe176a5ee685311d1368bdbf delete mode 100755 data/collaborative/registered/5e6656bf1b6fd77c4f86ab277cc0988b delete mode 100755 data/collaborative/registered/6117d79a736608652f0e2b84f18c2ee6 delete mode 100755 data/collaborative/registered/64054ac5cf0355c0c7a54a47a753e918 delete mode 100755 data/collaborative/registered/6cddbc005f97f76483eaf7397644de3b delete mode 100755 data/collaborative/registered/72670089ea1a80f64d41b30ab5abb317 delete mode 100755 data/collaborative/registered/77df941f7befd27ec8acf4166d618539 delete mode 100755 data/collaborative/registered/83e043f141603a9150e0718bc09bdac0 delete mode 100755 data/collaborative/registered/869e192baaf4f39d39c181279dffa05f delete mode 100755 data/collaborative/registered/8de74798a6eade7a47588beedfd958f4 delete mode 100755 data/collaborative/registered/97e1bfaa42d9fd93e5a8996f400585bd delete mode 100755 data/collaborative/registered/9cbc99f31b556308807390b4655cabf9 delete mode 100755 data/collaborative/registered/a07ab47d2665186a3e41f4f730ec7683 delete mode 100755 data/collaborative/registered/a25fdf5bb2a3722799c1dd377f337c6a delete mode 100755 data/collaborative/registered/a2962a947d6d5fcbc65facb728e37051 delete mode 100755 data/collaborative/registered/a2c548e3c41867b8373761249047ecb0 delete mode 100755 data/collaborative/registered/a65fec1802fb6a7362b302cfc0d3dacc delete mode 100755 data/collaborative/registered/ad20d395c6cbf9716cdccffe8776952e delete mode 100755 data/collaborative/registered/c411bfdc2e7d453914f61c6ac1113793 delete mode 100755 data/collaborative/registered/c8a4d866e1e889520d0e31839e0854e3 delete mode 100755 data/collaborative/registered/d63bfda1e19a710e4869b47822cbabf1 delete mode 100755 data/collaborative/registered/dcbd2e14b07c72b85ad7b5cd989cfd09 delete mode 100755 data/collaborative/registered/df0d7fda7f488203b2a32d3f9f6f8822 delete mode 100755 data/collaborative/registered/e1d97e7fc378fc2d6bae15b009dfe6b2 delete mode 100755 data/collaborative/registered/e2693b5a21a0545b9c1d44f2647703d0 delete mode 100755 data/collaborative/registered/e811c035b4fd6345836647c699408f91 delete mode 100755 data/collaborative/registered/eaacf5898c2cc7e26f68fe871e166773 delete mode 100755 data/collaborative/registered/ec2c158db3453f8ce0e25d234ead42b7 delete mode 100755 data/collaborative/registered/f3895333c762ec423739ab7db5496006 delete mode 100755 data/collaborative/registered/fbf7364839635641f96c195cbdcb7669 delete mode 100755 data/collaborative/registered/feb6db58347bafc0959a719eb8787268 delete mode 100755 data/collaborative/registered/index.db delete mode 100755 data/collaborative/selection/22f1d2494993531e6b1a016a8d8b6438 delete mode 100755 data/collaborative/selection/2741708a0ee997fc889e4770f0a3b8ea delete mode 100755 data/collaborative/selection/51640228b7c95ec21668deae8e14fd37 delete mode 100755 data/collaborative/selection/6e2f31eef830626055498ba7ba41f3dc delete mode 100755 data/collaborative/selection/8ca94770f4850fd864af830a177c90aa delete mode 100755 data/collaborative/selection/92e0d8216f938e9f6450634e2ac0d0da delete mode 100755 data/collaborative/selection/a0debe38b2118dc397cfe4898ab46b9e delete mode 100755 data/collaborative/selection/cc91755cde6ab90a7f2aada55994f97b delete mode 100755 data/collaborative/selection/ddd0681a0e90f0480910b3fb7719dde7 delete mode 100755 data/collaborative/selection/e6ca864b939a36765d43aa4ae3e8503e delete mode 100755 data/collaborative/selection/eceb4e0876fe71ea018f446d0d34eca1 delete mode 100755 data/collaborative/selection/f46fc66fdb891a570f1a03add3c166cc delete mode 100755 data/collaborative/selection/index.db delete mode 100755 data/collaborative/shadow/0231def7a6a1608f8242d5dfeee17fec delete mode 100755 data/collaborative/shadow/045f3b992ba538f82bbed4df39459fa9 delete mode 100755 data/collaborative/shadow/07a6a7a936469108b7eb1d5595405b41 delete mode 100755 data/collaborative/shadow/08791dea727327b5a0481e2a8fb350ff delete mode 100755 data/collaborative/shadow/09f6bedc033ef7c069a54c82fa8c7e62 delete mode 100755 data/collaborative/shadow/0b1d76a6acf247da79040a128cc3a528 delete mode 100755 data/collaborative/shadow/0bde8ce947815fedb4f056ef7111cc47 delete mode 100755 data/collaborative/shadow/0c7b6f96afab6e8fda974eea5a93e5c0 delete mode 100755 data/collaborative/shadow/1972a2c94075705efcb5226d1ac9889b delete mode 100755 data/collaborative/shadow/1dbc3b6b9a38f3065d2276656017f3f9 delete mode 100755 data/collaborative/shadow/1fad7d7bf81e5524143caee6f21cdfcf delete mode 100755 data/collaborative/shadow/1fe1266a755f7810fe2c73344d75770e delete mode 100755 data/collaborative/shadow/22f1d2494993531e6b1a016a8d8b6438 delete mode 100755 data/collaborative/shadow/23295112670db74d060930018ea19538 delete mode 100755 data/collaborative/shadow/2497b873b6c596aa0da54c628cb5fbd5 delete mode 100755 data/collaborative/shadow/2741708a0ee997fc889e4770f0a3b8ea delete mode 100755 data/collaborative/shadow/29a1edb2a360ce477af0bf0ecb5a2447 delete mode 100755 data/collaborative/shadow/2e951e1c04a09a48fa2ccc2c730cc7fd delete mode 100755 data/collaborative/shadow/3403458d3f9421a02e422cfe62741852 delete mode 100755 data/collaborative/shadow/37663faf229dd1ba5c77f60047934098 delete mode 100755 data/collaborative/shadow/3acf50a01e367e57cdfb32a08ac50fd0 delete mode 100755 data/collaborative/shadow/3ba13a3d4c97cda98f8675c7bccd82fe delete mode 100755 data/collaborative/shadow/3cd97ad18d409c51b5578b0b34c80ce6 delete mode 100755 data/collaborative/shadow/3e7c9f851da2aad425970b0be26f77ac delete mode 100755 data/collaborative/shadow/41118f97725e869c87455be694a53fe5 delete mode 100755 data/collaborative/shadow/41bbb319169d502d14088dd0ef762533 delete mode 100755 data/collaborative/shadow/45c06d935cb54cb6c59260028d5bb91c delete mode 100755 data/collaborative/shadow/49f589063ce4ea454204ce70b134a893 delete mode 100755 data/collaborative/shadow/4b5e696279610e8b11147b869777b685 delete mode 100755 data/collaborative/shadow/4e259f0bb87191d1f975f535dae106ea delete mode 100755 data/collaborative/shadow/51108580d8b1830f9d7e48021d6bde46 delete mode 100755 data/collaborative/shadow/51640228b7c95ec21668deae8e14fd37 delete mode 100755 data/collaborative/shadow/52e4730d2a0be9abffbc2bdea2204b5e delete mode 100755 data/collaborative/shadow/5456a19d342557d417efd28aced31c16 delete mode 100755 data/collaborative/shadow/57e91e0d3a50e23bca8a00a5e7539758 delete mode 100755 data/collaborative/shadow/5b9b38f2e267013b0042f802a120442b delete mode 100755 data/collaborative/shadow/5bb4642abdf3f7aa35eafebcba91df17 delete mode 100755 data/collaborative/shadow/5e7826f99928dc790d9cba5022cc30b4 delete mode 100755 data/collaborative/shadow/62da00833cc673ea3506e8c74cc03010 delete mode 100755 data/collaborative/shadow/64029b02e9eba9c858cf99ac5488be14 delete mode 100755 data/collaborative/shadow/65dd434e2ad28232ea285fab94ddfb75 delete mode 100755 data/collaborative/shadow/6a4b62d9024b66e2e6b0601593581d96 delete mode 100755 data/collaborative/shadow/6c9195df1db60f35f1cdb2d9ee97e4bf delete mode 100755 data/collaborative/shadow/6e2f31eef830626055498ba7ba41f3dc delete mode 100755 data/collaborative/shadow/6f1528298858cf4548f52302b9b3df09 delete mode 100755 data/collaborative/shadow/74153bbd75415243bee04ba5be3e0975 delete mode 100755 data/collaborative/shadow/74dea1994cc8087e93aa43126d0609fb delete mode 100755 data/collaborative/shadow/76a80f9d3d1f00f202f5b6a01af0fe82 delete mode 100755 data/collaborative/shadow/76e43d7b712f43510dae0cbf50e40bc9 delete mode 100755 data/collaborative/shadow/7c998484eb7cf6925bb4c8c12d9da2fc delete mode 100755 data/collaborative/shadow/7ed2ef8c2f8f09385af754d69279db57 delete mode 100755 data/collaborative/shadow/7f444cf225792632b9816fd7c212e785 delete mode 100755 data/collaborative/shadow/7f86659d402c096aeedb08e84283f596 delete mode 100755 data/collaborative/shadow/7fa8be2ce86bf557e18b4d8ffe01ab67 delete mode 100755 data/collaborative/shadow/7ff97b3475c197f26cad514f22ceb86b delete mode 100755 data/collaborative/shadow/81996f949129f48e0128cdb7b3cb7716 delete mode 100755 data/collaborative/shadow/870b887e9a5909882cbcebb4ba14b794 delete mode 100755 data/collaborative/shadow/8ca94770f4850fd864af830a177c90aa delete mode 100755 data/collaborative/shadow/92e0d8216f938e9f6450634e2ac0d0da delete mode 100755 data/collaborative/shadow/9412cdcf8b955c57d704e4994234d890 delete mode 100755 data/collaborative/shadow/941568d6e728e0f58bf59a686509defa delete mode 100755 data/collaborative/shadow/97d4726a27b0dc089ff2a1ebd49794c6 delete mode 100755 data/collaborative/shadow/9efb45e0fb52aae6da0f0aafa65a2485 delete mode 100755 data/collaborative/shadow/a0debe38b2118dc397cfe4898ab46b9e delete mode 100755 data/collaborative/shadow/a2a72e21333cf981f4a2281f1504cea3 delete mode 100755 data/collaborative/shadow/a6c8c908850fdd2fba740ab39de66cd2 delete mode 100755 data/collaborative/shadow/a7591bf8af26986d68f36815a5ea5273 delete mode 100755 data/collaborative/shadow/a7f6228ec1c43e9c52f5e91d07d4b453 delete mode 100755 data/collaborative/shadow/a8419f9f1457039c7fbc9740927be4e0 delete mode 100755 data/collaborative/shadow/a86d8153e2f67aeb9590093a5c30a149 delete mode 100755 data/collaborative/shadow/a8774609eda0bf3aa1cb32a96b594604 delete mode 100755 data/collaborative/shadow/abaaf90695610e34effe00775cd6f641 delete mode 100755 data/collaborative/shadow/acb11eb95add8cfd988d342e3de0d2e8 delete mode 100755 data/collaborative/shadow/af2d3669b4f915c4b09d4a8bb8dea1c9 delete mode 100755 data/collaborative/shadow/b039f3a0fad6690bccc0969dbe561fcd delete mode 100755 data/collaborative/shadow/b18552684dcd0101a4c484af9d0f2615 delete mode 100755 data/collaborative/shadow/b64f8e080258d3fa416e98888a27cea5 delete mode 100755 data/collaborative/shadow/b7e0dffe6d3af66063c9752be07c9e75 delete mode 100755 data/collaborative/shadow/b818ce32cd61aa5d83fbf357d1184635 delete mode 100755 data/collaborative/shadow/bc2ad9133d134977d621104c59e9fd61 delete mode 100755 data/collaborative/shadow/bdd330a1af3dca522aae993ac38cf3c5 delete mode 100755 data/collaborative/shadow/bfd3f8ef41ef1f98968c106a423699b2 delete mode 100755 data/collaborative/shadow/c34a5d1f562bfd5f37c3de4632f25a47 delete mode 100755 data/collaborative/shadow/cbc7af3f90284b745f9cca4430668ab5 delete mode 100755 data/collaborative/shadow/cc91755cde6ab90a7f2aada55994f97b delete mode 100755 data/collaborative/shadow/ccdab27e57aa054e492f5b3d3850f6e5 delete mode 100755 data/collaborative/shadow/cdc42f08882d002bac276e9c1bdcac67 delete mode 100755 data/collaborative/shadow/d06ec8c63e9acac96c0817560b2dfabe delete mode 100755 data/collaborative/shadow/d431495cf623dd61f00bfa1aef2c6e0c delete mode 100755 data/collaborative/shadow/d778ad34ea1212ed7081b731d9a8dd80 delete mode 100755 data/collaborative/shadow/dc103bcc7b8517ba408c3c19eca08b6e delete mode 100755 data/collaborative/shadow/ddd0681a0e90f0480910b3fb7719dde7 delete mode 100755 data/collaborative/shadow/e1726a184e69c885fe27c8669b2c885e delete mode 100755 data/collaborative/shadow/e1ea49c66882f7882bfc53f7f896d31d delete mode 100755 data/collaborative/shadow/e2630975cd26f1f4330486f3d0a9055e delete mode 100755 data/collaborative/shadow/e275a3a559f2c49aff391d8cc3fe538d delete mode 100755 data/collaborative/shadow/e48aa03433d347bfaffcb9429f62a27c delete mode 100755 data/collaborative/shadow/e693185c0b5a32ed6979e22b10f1e433 delete mode 100755 data/collaborative/shadow/e6ca864b939a36765d43aa4ae3e8503e delete mode 100755 data/collaborative/shadow/ea5288a62fdc3f1ebfab27f709082842 delete mode 100755 data/collaborative/shadow/eceb4e0876fe71ea018f446d0d34eca1 delete mode 100755 data/collaborative/shadow/ede158f1f62eabab87526f2db25fad17 delete mode 100755 data/collaborative/shadow/ee3d3118cdab96fd9c2343d4742f2810 delete mode 100755 data/collaborative/shadow/ee62af99d5b417b7381e5299027cca6e delete mode 100755 data/collaborative/shadow/eef1f14577636af47a8ee7f55ba777bf delete mode 100755 data/collaborative/shadow/ef7b395faeaf7d9a60fd54f2dca409e5 delete mode 100755 data/collaborative/shadow/f0e5f885ff64458f62a2f0c202070139 delete mode 100755 data/collaborative/shadow/f3d17d035479bb837c846584a985fc9b delete mode 100755 data/collaborative/shadow/f46fc66fdb891a570f1a03add3c166cc delete mode 100755 data/collaborative/shadow/f6d27d5345b78d2d52c54cb2ada888f5 delete mode 100755 data/collaborative/shadow/f858621dbec7ad5f5a1f28be85acf0f0 delete mode 100755 data/collaborative/shadow/fe7e13bcdd4f10c3c8c55b3bb59e5ef8 delete mode 100755 data/collaborative/shadow/index.db delete mode 100755 data/collaborative/text/060728b4cccf0e88d2d445947e0f6836 delete mode 100755 data/collaborative/text/0874412e2b238973158064bf29510f49 delete mode 100755 data/collaborative/text/098797bf7c4448ed6397b23257b8d0d1 delete mode 100755 data/collaborative/text/0b00081372c3f176d14f3626f2ff3ef5 delete mode 100755 data/collaborative/text/1bb5e516806eb514fb3779d8dff2bf13 delete mode 100755 data/collaborative/text/264f67810f124a1136a3bca443af2651 delete mode 100755 data/collaborative/text/273e1de64502c06a2384fc8b66dfb4e4 delete mode 100755 data/collaborative/text/2a0da7cebddb7852e2ac34f7c0d5e0c7 delete mode 100755 data/collaborative/text/2af01a9b54a6e94e6a011cd84b4c5b48 delete mode 100755 data/collaborative/text/2b2340b37b43b24e5a2731ed5db41118 delete mode 100755 data/collaborative/text/2bcf46daf121a8f0ab61fb9c00ea4400 delete mode 100755 data/collaborative/text/303bfe190d5e04a7238bab12ce1bb129 delete mode 100755 data/collaborative/text/30e59348afad09731d1c4f8d66702f40 delete mode 100755 data/collaborative/text/329491055243ffcf41c2843c688c031d delete mode 100755 data/collaborative/text/32e633ae3f9718c741560af1352f1a1a delete mode 100755 data/collaborative/text/37409041d6aae3c32d019a5f9481fe1a delete mode 100755 data/collaborative/text/3833e87699ffe1cafb5dc3109d9b3dfb delete mode 100755 data/collaborative/text/3a7ac99607660738569ae0966a913bc8 delete mode 100755 data/collaborative/text/3a9233a747bb36b5549eb6d8455652d7 delete mode 100755 data/collaborative/text/3b05b09289a3db2ae8cf68f284bcfc46 delete mode 100755 data/collaborative/text/3d963d1e35c7582fb4cb19caad66130a delete mode 100755 data/collaborative/text/49234e7b9a6d49c284c2c075b71344f3 delete mode 100755 data/collaborative/text/532d917f0ec46400caa40e28a6576439 delete mode 100755 data/collaborative/text/54b750daba066a7ec6a3343604f86406 delete mode 100755 data/collaborative/text/550f42cee32ce845fd817cf600cddda0 delete mode 100755 data/collaborative/text/56cab2396298ed03d332f30384d3a133 delete mode 100755 data/collaborative/text/5b8f5fad3ae9914ed4b0fdd3c500d2e9 delete mode 100755 data/collaborative/text/5b945bc2935cd53d7f96e69b2a25dbae delete mode 100755 data/collaborative/text/6022c4dda0ee39cea577b5c430ca8eba delete mode 100755 data/collaborative/text/60cb37fe1c12580053ad40ecbfbee3e7 delete mode 100755 data/collaborative/text/6365716b69bf2058393d3c95cbf9e57a delete mode 100755 data/collaborative/text/6877732a642738ecdc29b7abb6306b16 delete mode 100755 data/collaborative/text/68b53024d1449751d6fe0678e5d19a8b delete mode 100755 data/collaborative/text/6ebbbc6206dc1a61c67475fee5a974ec delete mode 100755 data/collaborative/text/6fade3ab5ef16da4f4f55b5d4a13f71f delete mode 100755 data/collaborative/text/6ffeaa9f6d5362fa2f15fbf5a6146312 delete mode 100755 data/collaborative/text/729bd3977e9ec2c1b4869d62605d11a5 delete mode 100755 data/collaborative/text/74f9d1f373b31e36b320c5a6af2e87ea delete mode 100755 data/collaborative/text/76154443d29325fc407486ccf552c592 delete mode 100755 data/collaborative/text/76fba3c99c6a58e95b52ddf307b83ff9 delete mode 100755 data/collaborative/text/7741a9336615cea0064a11037be451c8 delete mode 100755 data/collaborative/text/7857144494313767d095f7fa224b75eb delete mode 100755 data/collaborative/text/8e024f4aac60a8331a03d54b83e75bf7 delete mode 100755 data/collaborative/text/91f54b2685411e1ea2b454be94a4b7f8 delete mode 100755 data/collaborative/text/973f750ac61e200c9a6566c6f4f0ada4 delete mode 100755 data/collaborative/text/9cf1e9203224be47c3ba9e5308987882 delete mode 100755 data/collaborative/text/a64c3a506cee116b66128f9fabd92174 delete mode 100755 data/collaborative/text/a9a0fb5543ed2953ba292d5f62bf6ae8 delete mode 100755 data/collaborative/text/afeec27bbb5ab15bae2cb560b3e7406d delete mode 100755 data/collaborative/text/b31c91140e129d845f56a9d887d718af delete mode 100755 data/collaborative/text/b4590e9cec70e9718018bc7905fc6c2d delete mode 100755 data/collaborative/text/b997313979c4592942656b494256e685 delete mode 100755 data/collaborative/text/b9a2a6807be3cb2888a882de9a456ca8 delete mode 100755 data/collaborative/text/ba67cc584113e97440efff098f28393e delete mode 100755 data/collaborative/text/bbd5c30b8ceb2e0742e6264c1788b583 delete mode 100755 data/collaborative/text/c402a1cde9f402454c2313535a396934 delete mode 100755 data/collaborative/text/c41e653729c1a8ef77976647bbfbee70 delete mode 100755 data/collaborative/text/c611c854fd24594f69862df70e8afd48 delete mode 100755 data/collaborative/text/cddb2ae31e8ac7f5d87e69efa5924a02 delete mode 100755 data/collaborative/text/cf1d4b27a3b2b1bba71f454cc7fb5d91 delete mode 100755 data/collaborative/text/cfc98c3ef6b134046f878c0d1e586623 delete mode 100755 data/collaborative/text/d2041fd4034fe73449cbed068d0d8296 delete mode 100755 data/collaborative/text/d416f4cb7eedbaa2b52088c3068022c1 delete mode 100755 data/collaborative/text/d52716adc5491c84a0bf68e831a266c3 delete mode 100755 data/collaborative/text/e19726eb67fd3c5787bb3825331076e4 delete mode 100755 data/collaborative/text/e31facd25dccf8a50c81c459c325e9a4 delete mode 100755 data/collaborative/text/ec501c81f6d7f8903809691ef846031d delete mode 100755 data/collaborative/text/ed6f50c067d7bad7bd358192b93543ec delete mode 100755 data/collaborative/text/edc2b5d20ee07a2ade83bca0dfc9bbc9 delete mode 100755 data/collaborative/text/edf0d6f9fc6fa8c4daafd04034251817 delete mode 100755 data/collaborative/text/ee0d4983f0759afbe9820ad34d7beec0 delete mode 100755 data/collaborative/text/f25962a7f5669c4f77a4a01d78918b40 delete mode 100755 data/collaborative/text/f61810c51eccf9e35faaf5cb43d1dfa9 delete mode 100755 data/collaborative/text/f81051379428c130bec3e26a0ce94231 delete mode 100755 data/collaborative/text/fd2c1c229ac53e0c86175bf5e58efac5 delete mode 100755 data/collaborative/text/index.db delete mode 100755 data/config/Macro.php delete mode 100755 data/config/settings.FrankSmith22.php delete mode 100755 data/config/settings.TrevorBeresford.php delete mode 100755 data/config/settings.ithollie.php delete mode 100755 data/config/settings.sabbakilam.php delete mode 100755 data/config/settings.xevidos.php create mode 100755 plugins/Codiad-Auto-Save/README.md rename data/collaborative/shadow/a43aba4776a318fab1ae3091a8dfd1e9 => plugins/Codiad-Auto-Save/init.js (66%) rename data/collaborative/shadow/26d17024aafb824e93365a9d8d404b90 => plugins/Codiad-Auto-Save/plugin.json (91%) create mode 100755 plugins/Codiad-Auto-Save/screen.css create mode 100755 plugins/Codiad-AutoUpdate-master/README.md create mode 100755 plugins/Codiad-AutoUpdate-master/class.autoupdate.php create mode 100755 plugins/Codiad-AutoUpdate-master/controller.php create mode 100755 plugins/Codiad-AutoUpdate-master/dialog.php create mode 100755 plugins/Codiad-AutoUpdate-master/init.js create mode 100755 plugins/Codiad-AutoUpdate-master/plugin.json create mode 100755 plugins/Codiad-AutoUpdate-master/screen.png create mode 100755 plugins/Codiad-DragDrop-master/README.md create mode 100755 plugins/Codiad-DragDrop-master/controller.php create mode 100755 plugins/Codiad-DragDrop-master/dialog.php create mode 100755 plugins/Codiad-DragDrop-master/init.js create mode 100755 plugins/Codiad-DragDrop-master/plugin.json create mode 100755 plugins/Codiad-DragDrop-master/screen.css create mode 100755 plugins/Codiad-DragDrop-master/template.html diff --git a/components/filemanager/class.filemanager.php b/components/filemanager/class.filemanager.php index d32d8f7..4ce10f4 100755 --- a/components/filemanager/class.filemanager.php +++ b/components/filemanager/class.filemanager.php @@ -610,7 +610,7 @@ class Filemanager extends Common $path = str_replace('\\', '/', $path); // allow only valid chars in paths$ - $path = preg_replace('/[^A-Za-z0-9\-\._\/]/', '', $path); + $path = preg_replace('/[^A-Za-z0-9\-\._\/\ ]/', '', $path); // maybe this is not needed anymore // prevent Poison Null Byte injections $path = str_replace(chr(0), '', $path); diff --git a/components/filemanager/dialog.php b/components/filemanager/dialog.php index 5628edb..ae6b4f7 100755 --- a/components/filemanager/dialog.php +++ b/components/filemanager/dialog.php @@ -71,6 +71,21 @@ switch($_GET['action']){ + +


+ +

+ + 521a72d0c807e2f9d68b250337d72b6f> diff --git a/data/collaborative/registered/00f67b79a2f9c0defb5cb9e35a1eedc9 b/data/collaborative/registered/00f67b79a2f9c0defb5cb9e35a1eedc9 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/00f67b79a2f9c0defb5cb9e35a1eedc9 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/0231def7a6a1608f8242d5dfeee17fec b/data/collaborative/registered/0231def7a6a1608f8242d5dfeee17fec deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/0231def7a6a1608f8242d5dfeee17fec +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/0502dab6244f6cf47a408682bde2da19 b/data/collaborative/registered/0502dab6244f6cf47a408682bde2da19 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/0502dab6244f6cf47a408682bde2da19 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/06b4bf234c856dfc262ab9a104e7515d b/data/collaborative/registered/06b4bf234c856dfc262ab9a104e7515d deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/06b4bf234c856dfc262ab9a104e7515d +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/10cd3ff020218b98a70ae382ac763cba b/data/collaborative/registered/10cd3ff020218b98a70ae382ac763cba deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/10cd3ff020218b98a70ae382ac763cba +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/142ce5a5e09022f6b27c33c5bab75df2 b/data/collaborative/registered/142ce5a5e09022f6b27c33c5bab75df2 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/142ce5a5e09022f6b27c33c5bab75df2 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/19d575f3f3ce8f2aa9001aa4833228a1 b/data/collaborative/registered/19d575f3f3ce8f2aa9001aa4833228a1 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/19d575f3f3ce8f2aa9001aa4833228a1 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/1e7e459cde205d91c481b9015511414b b/data/collaborative/registered/1e7e459cde205d91c481b9015511414b deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/1e7e459cde205d91c481b9015511414b +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/23843b6cae13d579283d820ae8604f11 b/data/collaborative/registered/23843b6cae13d579283d820ae8604f11 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/23843b6cae13d579283d820ae8604f11 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/2d9e916777b9f877e8c43fdc5820f3ed b/data/collaborative/registered/2d9e916777b9f877e8c43fdc5820f3ed deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/2d9e916777b9f877e8c43fdc5820f3ed +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/357768ee57f499a81982c891d2e8212d b/data/collaborative/registered/357768ee57f499a81982c891d2e8212d deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/357768ee57f499a81982c891d2e8212d +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/39d5e786f59a5b05c3d7e4296ea42a76 b/data/collaborative/registered/39d5e786f59a5b05c3d7e4296ea42a76 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/39d5e786f59a5b05c3d7e4296ea42a76 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/3bad7b063c15d3531895bc5ad94efae5 b/data/collaborative/registered/3bad7b063c15d3531895bc5ad94efae5 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/3bad7b063c15d3531895bc5ad94efae5 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/3c0811e1791db35b940af5330f4ea307 b/data/collaborative/registered/3c0811e1791db35b940af5330f4ea307 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/3c0811e1791db35b940af5330f4ea307 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/3cee2d164d3de51fe4c83d4954105eb5 b/data/collaborative/registered/3cee2d164d3de51fe4c83d4954105eb5 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/3cee2d164d3de51fe4c83d4954105eb5 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/3fa8e3235f78fded26b0a95b3550a30c b/data/collaborative/registered/3fa8e3235f78fded26b0a95b3550a30c deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/3fa8e3235f78fded26b0a95b3550a30c +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/40f6a41afa74ace596bc5735f4133b27 b/data/collaborative/registered/40f6a41afa74ace596bc5735f4133b27 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/40f6a41afa74ace596bc5735f4133b27 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/42b6da74b138c81b431dd486e605d7a1 b/data/collaborative/registered/42b6da74b138c81b431dd486e605d7a1 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/42b6da74b138c81b431dd486e605d7a1 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/45f16dcf5deda7c1cfb3ba414bbf37a0 b/data/collaborative/registered/45f16dcf5deda7c1cfb3ba414bbf37a0 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/45f16dcf5deda7c1cfb3ba414bbf37a0 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/46e202c38d2c8a4216b81c0007276f38 b/data/collaborative/registered/46e202c38d2c8a4216b81c0007276f38 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/46e202c38d2c8a4216b81c0007276f38 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/48f9526f719a68de0bfb94ccd4284528 b/data/collaborative/registered/48f9526f719a68de0bfb94ccd4284528 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/48f9526f719a68de0bfb94ccd4284528 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/58b9c53d2f43d2a924386e0fc7f1a364 b/data/collaborative/registered/58b9c53d2f43d2a924386e0fc7f1a364 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/58b9c53d2f43d2a924386e0fc7f1a364 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/5a6ea387fe176a5ee685311d1368bdbf b/data/collaborative/registered/5a6ea387fe176a5ee685311d1368bdbf deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/5a6ea387fe176a5ee685311d1368bdbf +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/5e6656bf1b6fd77c4f86ab277cc0988b b/data/collaborative/registered/5e6656bf1b6fd77c4f86ab277cc0988b deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/5e6656bf1b6fd77c4f86ab277cc0988b +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/6117d79a736608652f0e2b84f18c2ee6 b/data/collaborative/registered/6117d79a736608652f0e2b84f18c2ee6 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/6117d79a736608652f0e2b84f18c2ee6 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/64054ac5cf0355c0c7a54a47a753e918 b/data/collaborative/registered/64054ac5cf0355c0c7a54a47a753e918 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/64054ac5cf0355c0c7a54a47a753e918 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/6cddbc005f97f76483eaf7397644de3b b/data/collaborative/registered/6cddbc005f97f76483eaf7397644de3b deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/6cddbc005f97f76483eaf7397644de3b +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/72670089ea1a80f64d41b30ab5abb317 b/data/collaborative/registered/72670089ea1a80f64d41b30ab5abb317 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/72670089ea1a80f64d41b30ab5abb317 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/77df941f7befd27ec8acf4166d618539 b/data/collaborative/registered/77df941f7befd27ec8acf4166d618539 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/77df941f7befd27ec8acf4166d618539 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/83e043f141603a9150e0718bc09bdac0 b/data/collaborative/registered/83e043f141603a9150e0718bc09bdac0 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/83e043f141603a9150e0718bc09bdac0 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/869e192baaf4f39d39c181279dffa05f b/data/collaborative/registered/869e192baaf4f39d39c181279dffa05f deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/869e192baaf4f39d39c181279dffa05f +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/8de74798a6eade7a47588beedfd958f4 b/data/collaborative/registered/8de74798a6eade7a47588beedfd958f4 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/8de74798a6eade7a47588beedfd958f4 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/97e1bfaa42d9fd93e5a8996f400585bd b/data/collaborative/registered/97e1bfaa42d9fd93e5a8996f400585bd deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/97e1bfaa42d9fd93e5a8996f400585bd +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/9cbc99f31b556308807390b4655cabf9 b/data/collaborative/registered/9cbc99f31b556308807390b4655cabf9 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/9cbc99f31b556308807390b4655cabf9 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/a07ab47d2665186a3e41f4f730ec7683 b/data/collaborative/registered/a07ab47d2665186a3e41f4f730ec7683 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/a07ab47d2665186a3e41f4f730ec7683 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/a25fdf5bb2a3722799c1dd377f337c6a b/data/collaborative/registered/a25fdf5bb2a3722799c1dd377f337c6a deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/a25fdf5bb2a3722799c1dd377f337c6a +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/a2962a947d6d5fcbc65facb728e37051 b/data/collaborative/registered/a2962a947d6d5fcbc65facb728e37051 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/a2962a947d6d5fcbc65facb728e37051 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/a2c548e3c41867b8373761249047ecb0 b/data/collaborative/registered/a2c548e3c41867b8373761249047ecb0 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/a2c548e3c41867b8373761249047ecb0 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/a65fec1802fb6a7362b302cfc0d3dacc b/data/collaborative/registered/a65fec1802fb6a7362b302cfc0d3dacc deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/a65fec1802fb6a7362b302cfc0d3dacc +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/ad20d395c6cbf9716cdccffe8776952e b/data/collaborative/registered/ad20d395c6cbf9716cdccffe8776952e deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/ad20d395c6cbf9716cdccffe8776952e +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/c411bfdc2e7d453914f61c6ac1113793 b/data/collaborative/registered/c411bfdc2e7d453914f61c6ac1113793 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/c411bfdc2e7d453914f61c6ac1113793 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/c8a4d866e1e889520d0e31839e0854e3 b/data/collaborative/registered/c8a4d866e1e889520d0e31839e0854e3 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/c8a4d866e1e889520d0e31839e0854e3 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/d63bfda1e19a710e4869b47822cbabf1 b/data/collaborative/registered/d63bfda1e19a710e4869b47822cbabf1 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/d63bfda1e19a710e4869b47822cbabf1 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/dcbd2e14b07c72b85ad7b5cd989cfd09 b/data/collaborative/registered/dcbd2e14b07c72b85ad7b5cd989cfd09 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/dcbd2e14b07c72b85ad7b5cd989cfd09 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/df0d7fda7f488203b2a32d3f9f6f8822 b/data/collaborative/registered/df0d7fda7f488203b2a32d3f9f6f8822 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/df0d7fda7f488203b2a32d3f9f6f8822 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/e1d97e7fc378fc2d6bae15b009dfe6b2 b/data/collaborative/registered/e1d97e7fc378fc2d6bae15b009dfe6b2 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/e1d97e7fc378fc2d6bae15b009dfe6b2 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/e2693b5a21a0545b9c1d44f2647703d0 b/data/collaborative/registered/e2693b5a21a0545b9c1d44f2647703d0 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/e2693b5a21a0545b9c1d44f2647703d0 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/e811c035b4fd6345836647c699408f91 b/data/collaborative/registered/e811c035b4fd6345836647c699408f91 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/e811c035b4fd6345836647c699408f91 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/eaacf5898c2cc7e26f68fe871e166773 b/data/collaborative/registered/eaacf5898c2cc7e26f68fe871e166773 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/eaacf5898c2cc7e26f68fe871e166773 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/ec2c158db3453f8ce0e25d234ead42b7 b/data/collaborative/registered/ec2c158db3453f8ce0e25d234ead42b7 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/ec2c158db3453f8ce0e25d234ead42b7 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/f3895333c762ec423739ab7db5496006 b/data/collaborative/registered/f3895333c762ec423739ab7db5496006 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/f3895333c762ec423739ab7db5496006 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/fbf7364839635641f96c195cbdcb7669 b/data/collaborative/registered/fbf7364839635641f96c195cbdcb7669 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/fbf7364839635641f96c195cbdcb7669 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/feb6db58347bafc0959a719eb8787268 b/data/collaborative/registered/feb6db58347bafc0959a719eb8787268 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/registered/feb6db58347bafc0959a719eb8787268 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/registered/index.db b/data/collaborative/registered/index.db deleted file mode 100755 index d6f2d72..0000000 --- a/data/collaborative/registered/index.db +++ /dev/null @@ -1,53 +0,0 @@ -|filename:xevidos|user:%2Fvar%2Fwww%2Fhtml%2Findex.php|>d63bfda1e19a710e4869b47822cbabf1> -|filename:test|user:%2Fvar%2Fwww%2Fhtml%2Findex.php|>ec2c158db3453f8ce0e25d234ead42b7> -|filename:sabbakilam|user:%2Fvar%2Fwww%2Fhtml%2Fmusic%2FmethodsHELPER.js|>83e043f141603a9150e0718bc09bdac0> -|filename:xevidos|user:web2%2Findex.php|>c411bfdc2e7d453914f61c6ac1113793> -|filename:sabbakilam|user:web2%2Findex.html|>23843b6cae13d579283d820ae8604f11> -|filename:TrevorBeresford|user:web2%2Findex.php|>3c0811e1791db35b940af5330f4ea307> -|filename:xevidos|user:web2%2Findex.html|>dcbd2e14b07c72b85ad7b5cd989cfd09> -|filename:TrevorBeresford|user:web2%2Findex.html|>6117d79a736608652f0e2b84f18c2ee6> -|filename:xevidos|user:web2%2Fjs%2FInitialize.js|>e2693b5a21a0545b9c1d44f2647703d0> -|filename:TrevorBeresford|user:web2%2Fjs%2FInitialize.js|>fbf7364839635641f96c195cbdcb7669> -|filename:sabbakilam|user:web2%2Fjs%2FInitialize.js|>a25fdf5bb2a3722799c1dd377f337c6a> -|filename:xevidos|user:web2%2Fjs%2FQualify.js|>a65fec1802fb6a7362b302cfc0d3dacc> -|filename:xevidos|user:web2%2Fcss%2Fstyles.css|>06b4bf234c856dfc262ab9a104e7515d> -|filename:TrevorBeresford|user:web2%2Fjs%2FQualify.js|>0502dab6244f6cf47a408682bde2da19> -|filename:sabbakilam|user:web2%2FL.js|>357768ee57f499a81982c891d2e8212d> -|filename:xevidos|user:web2%2Fjs%2FUpdate.js|>3fa8e3235f78fded26b0a95b3550a30c> -|filename:sabbakilam|user:web2%2Fcss%2Fstyles.css|>f3895333c762ec423739ab7db5496006> -|filename:xevidos|user:mobile_programming%2Fcss%2Fstyles.css|>ad20d395c6cbf9716cdccffe8776952e> -|filename:xevidos|user:mobile_programming%2Findex.html|>df0d7fda7f488203b2a32d3f9f6f8822> -|filename:TrevorBeresford|user:mobile_programming%2Findex.html|>142ce5a5e09022f6b27c33c5bab75df2> -|filename:sabbakilam|user:mobile_programming%2Fcss%2Fstyles.css|>e1d97e7fc378fc2d6bae15b009dfe6b2> -|filename:ithollie|user:mobile_programming%2Fcss%2Fstyles.css|>3bad7b063c15d3531895bc5ad94efae5> -|filename:sabbakilam|user:mobile_programming%2Findex.html|>2d9e916777b9f877e8c43fdc5820f3ed> -|filename:xevidos|user:mobile_programming%2FL.js|>eaacf5898c2cc7e26f68fe871e166773> -|filename:xevidos|user:mobile_programming%2Fjs%2FInitialize.js|>00f67b79a2f9c0defb5cb9e35a1eedc9> -|filename:ithollie|user:mobile_programming%2Fjs%2FInitialize.js|>1e7e459cde205d91c481b9015511414b> -|filename:TrevorBeresford|user:mobile_programming%2Fjs%2FInitialize.js|>8de74798a6eade7a47588beedfd958f4> -|filename:sabbakilam|user:mobile_programming%2Fjs%2FInitialize.js|>77df941f7befd27ec8acf4166d618539> -|filename:FrankSmith22|user:mobile_programming%2Fjs%2FInitialize.js|>9cbc99f31b556308807390b4655cabf9> -|filename:TrevorBeresford|user:mobile_programming%2Fjs%2FQualify.js|>45f16dcf5deda7c1cfb3ba414bbf37a0> -|filename:xevidos|user:mobile_programming%2Fjs%2FQualify.js|>64054ac5cf0355c0c7a54a47a753e918> -|filename:sabbakilam|user:mobile_programming%2Fjs%2FUpdate.js|>42b6da74b138c81b431dd486e605d7a1> -|filename:xevidos|user:mobile_programming%2Fjs%2FUpdate.js|>a2962a947d6d5fcbc65facb728e37051> -|filename:FrankSmith22|user:mobile_programming%2Fjs%2FUpdate.js|>e811c035b4fd6345836647c699408f91> -|filename:sabbakilam|user:mobile_programming%2Fjs%2FQualify.js|>10cd3ff020218b98a70ae382ac763cba> -|filename:xevidos|user:dev%2Fteacher.php|>58b9c53d2f43d2a924386e0fc7f1a364> -|filename:xevidos|user:dev%2Fstudents%2Fpages.php|>feb6db58347bafc0959a719eb8787268> -|filename:xevidos|user:dev%2Fincludes%2Fheader.php|>869e192baaf4f39d39c181279dffa05f> -|filename:xevidos|user:html%2Fweb2%2Fcomponents%2Factive%2Fclass.active.php|>97e1bfaa42d9fd93e5a8996f400585bd> -|filename:xevidos|user:html%2Fmobile_programming%2Fcomponents%2Factive%2Fclass.active.php|>19d575f3f3ce8f2aa9001aa4833228a1> -|filename:xevidos|user:html%2Fweb2%2Fplugins%2Fauto_save%2Finit.js|>39d5e786f59a5b05c3d7e4296ea42a76> -|filename:xevidos|user:html%2Fcode%2Fplugins%2Fauto_save%2Finit.js|>a07ab47d2665186a3e41f4f730ec7683> -|filename:xevidos|user:html%2Fdev%2Findex.php|>a2c548e3c41867b8373761249047ecb0> -|filename:xevidos|user:html%2Fcode%2Fcomponents%2Ffilemanager%2Finit.js|>40f6a41afa74ace596bc5735f4133b27> -|filename:xevidos|user:html%2Fmobile_programming%2Fplugins%2FCodiad-CodeGit-master%2Finit.js|>48f9526f719a68de0bfb94ccd4284528> -|filename:xevidos|user:html%2Fmobile_programming%2Fcomponents%2Factive%2Finit.js|>46e202c38d2c8a4216b81c0007276f38> -|filename:xevidos|user:html%2Fmobile_programming%2Fcomponents%2Ffilemanager%2Finit.js|>c8a4d866e1e889520d0e31839e0854e3> -|filename:xevidos|user:html%2Findex.php|>6cddbc005f97f76483eaf7397644de3b> -|filename:xevidos|user:html%2Fcode%2Fconfig.php|>72670089ea1a80f64d41b30ab5abb317> -|filename:xevidos|user:html%2Fcode%2Fdata%2Fcollaborative%2Ftext%2Fec501c81f6d7f8903809691ef846031d|>3cee2d164d3de51fe4c83d4954105eb5> -|filename:xevidos|user:html%2Fcode%2Fdata%2Fversion.php|>5e6656bf1b6fd77c4f86ab277cc0988b> -|filename:xevidos|user:html%2Fcode%2Fcomponents%2Fupdate%2Fclass.update.php|>5a6ea387fe176a5ee685311d1368bdbf> -|filename:html%2Fcode%2Fcomponents%2Fupdate%2Fdialog.php|user:xevidos|>0231def7a6a1608f8242d5dfeee17fec> diff --git a/data/collaborative/selection/22f1d2494993531e6b1a016a8d8b6438 b/data/collaborative/selection/22f1d2494993531e6b1a016a8d8b6438 deleted file mode 100755 index 28f557c..0000000 --- a/data/collaborative/selection/22f1d2494993531e6b1a016a8d8b6438 +++ /dev/null @@ -1 +0,0 @@ -O:8:"stdClass":2:{s:5:"start";O:8:"stdClass":2:{s:3:"row";i:20;s:6:"column";i:3;}s:3:"end";O:8:"stdClass":2:{s:3:"row";i:20;s:6:"column";i:24;}} \ No newline at end of file diff --git a/data/collaborative/selection/2741708a0ee997fc889e4770f0a3b8ea b/data/collaborative/selection/2741708a0ee997fc889e4770f0a3b8ea deleted file mode 100755 index 7ff7770..0000000 --- a/data/collaborative/selection/2741708a0ee997fc889e4770f0a3b8ea +++ /dev/null @@ -1 +0,0 @@ -O:8:"stdClass":2:{s:5:"start";O:8:"stdClass":2:{s:3:"row";i:27;s:6:"column";i:0;}s:3:"end";O:8:"stdClass":2:{s:3:"row";i:27;s:6:"column";i:0;}} \ No newline at end of file diff --git a/data/collaborative/selection/51640228b7c95ec21668deae8e14fd37 b/data/collaborative/selection/51640228b7c95ec21668deae8e14fd37 deleted file mode 100755 index 7d395f8..0000000 --- a/data/collaborative/selection/51640228b7c95ec21668deae8e14fd37 +++ /dev/null @@ -1 +0,0 @@ -O:8:"stdClass":2:{s:5:"start";O:8:"stdClass":2:{s:3:"row";i:9;s:6:"column";i:20;}s:3:"end";O:8:"stdClass":2:{s:3:"row";i:9;s:6:"column";i:20;}} \ No newline at end of file diff --git a/data/collaborative/selection/6e2f31eef830626055498ba7ba41f3dc b/data/collaborative/selection/6e2f31eef830626055498ba7ba41f3dc deleted file mode 100755 index cce96b4..0000000 --- a/data/collaborative/selection/6e2f31eef830626055498ba7ba41f3dc +++ /dev/null @@ -1 +0,0 @@ -O:8:"stdClass":2:{s:5:"start";O:8:"stdClass":2:{s:3:"row";i:29;s:6:"column";i:29;}s:3:"end";O:8:"stdClass":2:{s:3:"row";i:29;s:6:"column";i:33;}} \ No newline at end of file diff --git a/data/collaborative/selection/8ca94770f4850fd864af830a177c90aa b/data/collaborative/selection/8ca94770f4850fd864af830a177c90aa deleted file mode 100755 index 37aaff6..0000000 --- a/data/collaborative/selection/8ca94770f4850fd864af830a177c90aa +++ /dev/null @@ -1 +0,0 @@ -O:8:"stdClass":2:{s:5:"start";O:8:"stdClass":2:{s:3:"row";i:5;s:6:"column";i:0;}s:3:"end";O:8:"stdClass":2:{s:3:"row";i:5;s:6:"column";i:0;}} \ No newline at end of file diff --git a/data/collaborative/selection/92e0d8216f938e9f6450634e2ac0d0da b/data/collaborative/selection/92e0d8216f938e9f6450634e2ac0d0da deleted file mode 100755 index 37aaff6..0000000 --- a/data/collaborative/selection/92e0d8216f938e9f6450634e2ac0d0da +++ /dev/null @@ -1 +0,0 @@ -O:8:"stdClass":2:{s:5:"start";O:8:"stdClass":2:{s:3:"row";i:5;s:6:"column";i:0;}s:3:"end";O:8:"stdClass":2:{s:3:"row";i:5;s:6:"column";i:0;}} \ No newline at end of file diff --git a/data/collaborative/selection/a0debe38b2118dc397cfe4898ab46b9e b/data/collaborative/selection/a0debe38b2118dc397cfe4898ab46b9e deleted file mode 100755 index 70dfa49..0000000 --- a/data/collaborative/selection/a0debe38b2118dc397cfe4898ab46b9e +++ /dev/null @@ -1 +0,0 @@ -O:8:"stdClass":2:{s:5:"start";O:8:"stdClass":2:{s:3:"row";i:16;s:6:"column";i:1;}s:3:"end";O:8:"stdClass":2:{s:3:"row";i:16;s:6:"column";i:1;}} \ No newline at end of file diff --git a/data/collaborative/selection/cc91755cde6ab90a7f2aada55994f97b b/data/collaborative/selection/cc91755cde6ab90a7f2aada55994f97b deleted file mode 100755 index 7ff7770..0000000 --- a/data/collaborative/selection/cc91755cde6ab90a7f2aada55994f97b +++ /dev/null @@ -1 +0,0 @@ -O:8:"stdClass":2:{s:5:"start";O:8:"stdClass":2:{s:3:"row";i:27;s:6:"column";i:0;}s:3:"end";O:8:"stdClass":2:{s:3:"row";i:27;s:6:"column";i:0;}} \ No newline at end of file diff --git a/data/collaborative/selection/ddd0681a0e90f0480910b3fb7719dde7 b/data/collaborative/selection/ddd0681a0e90f0480910b3fb7719dde7 deleted file mode 100755 index 91c4cfe..0000000 --- a/data/collaborative/selection/ddd0681a0e90f0480910b3fb7719dde7 +++ /dev/null @@ -1 +0,0 @@ -O:8:"stdClass":2:{s:5:"start";O:8:"stdClass":2:{s:3:"row";i:14;s:6:"column";i:1;}s:3:"end";O:8:"stdClass":2:{s:3:"row";i:14;s:6:"column";i:1;}} \ No newline at end of file diff --git a/data/collaborative/selection/e6ca864b939a36765d43aa4ae3e8503e b/data/collaborative/selection/e6ca864b939a36765d43aa4ae3e8503e deleted file mode 100755 index 0812478..0000000 --- a/data/collaborative/selection/e6ca864b939a36765d43aa4ae3e8503e +++ /dev/null @@ -1 +0,0 @@ -O:8:"stdClass":2:{s:5:"start";O:8:"stdClass":2:{s:3:"row";i:36;s:6:"column";i:11;}s:3:"end";O:8:"stdClass":2:{s:3:"row";i:36;s:6:"column";i:11;}} \ No newline at end of file diff --git a/data/collaborative/selection/eceb4e0876fe71ea018f446d0d34eca1 b/data/collaborative/selection/eceb4e0876fe71ea018f446d0d34eca1 deleted file mode 100755 index 8c4f4a4..0000000 --- a/data/collaborative/selection/eceb4e0876fe71ea018f446d0d34eca1 +++ /dev/null @@ -1 +0,0 @@ -O:8:"stdClass":2:{s:5:"start";O:8:"stdClass":2:{s:3:"row";i:7;s:6:"column";i:0;}s:3:"end";O:8:"stdClass":2:{s:3:"row";i:7;s:6:"column";i:0;}} \ No newline at end of file diff --git a/data/collaborative/selection/f46fc66fdb891a570f1a03add3c166cc b/data/collaborative/selection/f46fc66fdb891a570f1a03add3c166cc deleted file mode 100755 index 72f571c..0000000 --- a/data/collaborative/selection/f46fc66fdb891a570f1a03add3c166cc +++ /dev/null @@ -1 +0,0 @@ -O:8:"stdClass":2:{s:5:"start";O:8:"stdClass":2:{s:3:"row";i:19;s:6:"column";i:0;}s:3:"end";O:8:"stdClass":2:{s:3:"row";i:19;s:6:"column";i:0;}} \ No newline at end of file diff --git a/data/collaborative/selection/index.db b/data/collaborative/selection/index.db deleted file mode 100755 index cf13405..0000000 --- a/data/collaborative/selection/index.db +++ /dev/null @@ -1,12 +0,0 @@ -|filename:%2Fvar%2Fwww%2Fhtml%2Findex.php|user:test|>a0debe38b2118dc397cfe4898ab46b9e> -|filename:mobile_programming%2Findex.html|user:FrankSmith22|>51640228b7c95ec21668deae8e14fd37> -|filename:mobile_programming%2Fcss%2Fstyles.css|user:FrankSmith22|>f46fc66fdb891a570f1a03add3c166cc> -|filename:mobile_programming%2Fcss%2Fstyles.css|user:ithollie|>ddd0681a0e90f0480910b3fb7719dde7> -|filename:mobile_programming%2Findex.html|user:ithollie|>6e2f31eef830626055498ba7ba41f3dc> -|filename:mobile_programming%2Fjs%2FQualify.js|user:ithollie|>cc91755cde6ab90a7f2aada55994f97b> -|filename:mobile_programming%2Fjs%2FInitialize.js|user:FrankSmith22|>e6ca864b939a36765d43aa4ae3e8503e> -|filename:mobile_programming%2Fjs%2FInitialize.js|user:ithollie|>22f1d2494993531e6b1a016a8d8b6438> -|filename:mobile_programming%2Fjs%2FQualify.js|user:FrankSmith22|>2741708a0ee997fc889e4770f0a3b8ea> -|filename:mobile_programming%2Fjs%2FUpdate.js|user:FrankSmith22|>92e0d8216f938e9f6450634e2ac0d0da> -|filename:mobile_programming%2Fjs%2FUpdate.js|user:ithollie|>8ca94770f4850fd864af830a177c90aa> -|filename:mobile_programming%2Fcss%2Fstyles.css|user:TrevorBeresford|>eceb4e0876fe71ea018f446d0d34eca1> diff --git a/data/collaborative/shadow/0231def7a6a1608f8242d5dfeee17fec b/data/collaborative/shadow/0231def7a6a1608f8242d5dfeee17fec deleted file mode 100755 index a98c1ee..0000000 --- a/data/collaborative/shadow/0231def7a6a1608f8242d5dfeee17fec +++ /dev/null @@ -1,66 +0,0 @@ -s:3098:" - -
- - Check(), true); - ?> -
- - - -
- - -
- -
-
- -

- - . - - -

- -
'.get_i18n("Download Codiad").' '; - } - ?> - - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/045f3b992ba538f82bbed4df39459fa9 b/data/collaborative/shadow/045f3b992ba538f82bbed4df39459fa9 deleted file mode 100755 index 67b7b9a..0000000 --- a/data/collaborative/shadow/045f3b992ba538f82bbed4df39459fa9 +++ /dev/null @@ -1,1143 +0,0 @@ -s:55059:"/* - * Copyright (c) Codiad & Andr3as, distributed - * as-is and without warranty under the MIT License. - * See http://opensource.org/licenses/MIT for more information. - * This information must remain intact. - */ - -(function(global, $){ - - var codiad = global.codiad, - scripts = document.getElementsByTagName('script'), - path = scripts[scripts.length-1].src.split('?')[0], - curpath = path.split('/').slice(0, -1).join('/')+'/'; - - $(function() { - codiad.CodeGit.init(); - }); - - codiad.CodeGit = { - - path : curpath, - location: '', - line : 0, - files : [], - network_graph : {}, - - init: function() { - var _this = this; - $.getScript(this.path + "network_graph.js"); - $.getScript(this.path + "raphael.min.js"); - //Check if directories has git repo - amplify.subscribe('filemanager.onIndex', function(obj){ - setTimeout(function(){ - $.each(obj.files, function(i, item){ - if (_this.basename(item.name) == '.git') { - $('.directory[data-path="'+_this.dirname(item.name)+'"]').addClass('repo'); - } else if (item.type == 'directory') { - //Deeper inspect - $.getJSON(_this.path + 'controller.php?action=checkRepo&path=' + item.name, function(result){ - if (result.status) { - $('.directory[data-path="'+item.name+'"]').addClass('repo'); - } - }); - } - }); - - // Repo status - _this.showRepoStatus(); - - // clear an old poller - if (_this._poller) { - clearInterval(_this._poller); - delete _this._poller; - } - - - },0); - }); - //Handle context-menu - amplify.subscribe('context-menu.onShow', function(obj){ - var path = $(obj.e.target).attr('data-path'), - root = $('#project-root').attr('data-path'), - counter = 0; - if ($(obj.e.target).hasClass('directory')) { - $('#context-menu').append('
'); - if ($(obj.e.target).hasClass('repo')) { - $('#context-menu').append('Open CodeGit'); - $('#context-menu').append('Add Submodule'); - } else { - $('#context-menu').append('Git Init'); - $('#context-menu').append('Git Clone'); - - //Git Submodule - while (path != root) { - path = _this.dirname(path); - if ($('.directory[data-path="' + path + '"]').hasClass('repo')) { - $('#context-menu').append('Add Submodule'); - break; - } - if (counter >= 10) break; - counter++; - } - } - } else { - var file = path; - while (path != root) { - path = _this.dirname(path); - if ($('.directory[data-path="' + path + '"]').hasClass('repo')) { - $('#context-menu').append('
'); - $('#context-menu').append('Git Diff'); - $('#context-menu').append('Git Blame'); - $('#context-menu').append('Git History'); - //Git rename - $('#context-menu a[onclick="codiad.filemanager.renameNode($(\'#context-menu\').attr(\'data-path\'));"]') - .attr("onclick", "codiad.CodeGit.rename($(\'#context-menu\').attr(\'data-path\'))"); - //Init Submodules - if (_this.basename(file) == '.gitmodules') { - $('#context-menu').append('Init Submodule'); - } - break; - } - if (counter >= 10) break; - counter++; - } - } - }); - amplify.subscribe("context-menu.onHide", function(){ - $('.code_git').remove(); - }); - //repo status - $('#file-manager').before(''); - _this.addStatusIcon(); - // clicking on it brings up the commit box - $("#git-repo-stat-wrapper").click(function(){ - codiad.CodeGit.showDialog('overview', codiad.project.getCurrent()); - }); - //File stats - $('#current-file').after('
'); - amplify.subscribe('active.onFocus', function(path){ - _this.numstat(path); - _this.repostat(); - }); - amplify.subscribe('active.onSave', function(path){ - setTimeout(function(){ - _this.numstat(path); - _this.repostat(); - }, 50); - }); - amplify.subscribe('active.onClose', function(path){ - _this.repostat(); - $('#git-stat').html(""); - }); - amplify.subscribe('active.onRemoveAll', function(){ - _this.repostat(); - $('#git-stat').html(""); - }); - amplify.subscribe('settings.changed', function(){ - _this.showRepoStatus(); - }); - amplify.subscribe('settings.loaded', function(){ - _this.showRepoStatus(); - }); - //Live features - $('.git_area #check_all').live("click", function(e){ - if ($('.git_area #check_all').attr("checked") == "checked") { - $('.git_area input:checkbox').attr("checked", "checked"); - } else { - $('.git_area input:checkbox').removeAttr("checked"); - } - }); - $('.git_area input:checkbox:not(#check_all)').live("click", function(e){ - if ($(this).attr("checked") != "checked") { - //One gets unchecked, remove all_input checking - if ($('.git_area #check_all').attr("checked") == "checked") { - $('.git_area #check_all').removeAttr("checked"); - } - } else { - var all = true; - $('.git_area input:checkbox:not(#check_all)').each(function(i, item){ - all = all && ($(this).attr("checked") == "checked"); - }); - if (all) { - $('.git_area #check_all').attr("checked", "checked"); - } - } - }); - $('.commit_hash').live('click', function(){ - var commit; - if (typeof($(this).attr('data-hash')) != 'undefined') { - commit = $(this).attr('data-hash'); - } else { - commit = $(this).text(); - } - commit = commit.replace("commit", "").trim(); - codiad.CodeGit.showCommit(codiad.CodeGit.location, commit); - }); - //Button Click listener - $('.git_area .git_diff').live("click", function(e){ - e.preventDefault(); - var line = $(this).attr('data-line'); - var path = $('.git_area .git_list .file[data-line="'+line+'"]').text(); - _this.files = []; - _this.files.push(path); - _this.showDialog('diff', _this.location); - }); - $('.git_area .git_undo').live("click", function(e){ - e.preventDefault(); - var line = $(this).attr('data-line'); - var path = $('.git_area .git_list .file[data-line="'+line+'"]').text(); - _this.checkout(path, _this.location); - _this.showDialog('overview', _this.location); - }); - $('.git_diff_area .git_undo').live("click", function(e){ - e.preventDefault(); - _this.checkout(_this.files[0], _this.location); - _this.showDialog('overview', _this.location); - }); - }, - - //Check if directories has git repo - showRepoStatus: function () { - var _this = this; - if ($('#project-root').hasClass('repo') && _this.isEnabledRepoStatus()) { - // add a poller - _this._poller = setInterval(function(){ - _this.repostat(); - }, 10000); - _this.addStatusIcon(); - // only show stat-wrapper if not configured - if (_this.isEnabledWrapper()) { - $("#git-repo-stat-wrapper").show(); - } else { - $("#git-repo-stat-wrapper").hide(); - } - $("#git-repo-status-icon").show(); - _this.repostat(); - } else { - $("#git-repo-stat-wrapper").hide(); - $("#git-repo-status-icon").hide(); - } - }, - - - showSidebarDialog: function() { - if (!$('#project-root').hasClass('repo')) { - codiad.message.error('Project root has no repository. Use the context menu!'); - return; - } - codiad.CodeGit.showDialog('overview', $('#project-root').attr('data-path')); - }, - - showDialog: function(type, path) { - this.location = path || this.location; - codiad.modal.load(600, this.path + 'dialog.php?action=' + type); - }, - - showCommitDialog: function(path) { - var _this = this; - path = _this.getPath(path); - $.getJSON(this.path + 'controller.php?action=getSettings&path=' + path, function(data){ - if (data.status == "success") { - if (data.data.email === ""){ - codiad.message.notice("Please tell git who you are:"); - _this.showDialog('userConfig', _this.location); - } else { - var files = [], line = 0, file = ""; - $('.git_area .git_list input:checkbox[checked="checked"]').each(function(i, item){ - line = $(item).attr('data-line'); - file = $('.git_area .git_list .file[data-line="'+line+'"]').text(); - files.push(file); - }); - _this.files = files; - _this.showDialog('commit', _this.location); - } - } else { - codiad.message.error(data.message); - } - }); - }, - - gitInit: function(path) { - $.getJSON(this.path + 'controller.php?action=init&path=' + path, function(result){ - codiad.message[result.status](result.message); - if (result.status == 'success') { - $('.directory[data-path="'+path+'"]').addClass('hasRepo'); - codiad.filemanager.rescan(path); - } - }); - }, - - /** - * Clone repo or show dialog to clone repo - * - * @param {string} path - * @param {string} repo - * @param {boolean} init_submodules - */ - clone: function(path, repo, init_submodules) { - var _this = this; - init_submodules = init_submodules || "false"; - if (typeof(repo) == 'undefined') { - this.showDialog('clone', path); - } else { - codiad.modal.unload(); - $.getJSON(_this.path + 'controller.php?action=clone&path=' + path + '&repo=' + repo + '&init_submodules=' + init_submodules, function(result){ - if (result.status == 'login_required') { - codiad.message.error(result.message); - _this.showDialog('login', _this.location); - _this.login = function(){ - var username = $('.git_login_area #username').val(); - var password = $('.git_login_area #password').val(); - codiad.modal.unload(); - $.post(_this.path + 'controller.php?action=clone&path='+path+'&repo=' + repo + '&init_submodules=' + init_submodules, {username: username, password: password}, - function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - if (result.status == 'success') { - codiad.filemanager.rescan(path); - } - }); - }; - } else { - codiad.message[result.status](result.message); - } - if (result.status == 'success') { - codiad.filemanager.rescan(path); - } - }); - } - }, - - diff: function(path, repo) { - var _this = this; - repo = this.getPath(repo); - $.getJSON(this.path + 'controller.php?action=diff&repo=' + repo + '&path=' + path, function(result){ - if (result.status != 'success') { - codiad.message[result.status](result.message); - _this.showDialog('overview', repo); - return; - } - result.data = _this.renderDiff(result.data); - $('.git_diff').append(result.data.join("")); - }); - }, - - contextMenuDiff: function(path, repo) { - this.location = repo; - path = path.replace(repo + "/", ""); - this.files = []; - this.files.push(path); - this.showDialog('diff', repo); - }, - - commit: function(path, msg) { - var _this = this; - path = this.getPath(path); - var message = $('.git_commit_area #commit_msg').val(); - this.showDialog('overview', this.location); - $.post(this.path + 'controller.php?action=add&path=' + path, {files : JSON.stringify(_this.files)}, function(result){ - result = JSON.parse(result); - if (result.status == 'error') { - codiad.message.error(result.message); - return; - } - $.post(_this.path + 'controller.php?action=commit&path=' + path, {message: message}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - _this.status(path); - }); - }); - }, - - filesDiff: function() { - var _this = this; - $.each(this.files, function(i, item){ - _this.diff(item, _this.location); - }); - }, - - push: function() { - var _this = this; - var remote = $('.git_push_area #git_remotes').val(); - var branch = $('.git_push_area #git_branches').val(); - this.showDialog('overview', this.location); - $.getJSON(this.path + 'controller.php?action=push&path=' + this.location + '&remote=' + remote + '&branch=' + branch, function(result){ - if (result.status == 'login_required') { - codiad.message.error(result.message); - _this.showDialog('login', _this.location); - _this.login = function(){ - var username = $('.git_login_area #username').val(); - var password = $('.git_login_area #password').val(); - _this.showDialog('overview', _this.location); - $.post(_this.path + 'controller.php?action=push&path=' + _this.location + '&remote=' + remote + '&branch=' + branch, - {username: username, password: password}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - }); - }; - } else if (result.status == 'passphrase_required') { - codiad.message.error(result.message); - _this.showDialog('passphrase', _this.location); - _this.login = function() { - var passphrase = $('.git_login_area #passphrase').val(); - _this.showDialog('overview', _this.location); - $.post(_this.path + 'controller.php?action=push&path=' + _this.location + '&remote=' + remote + '&branch=' + branch, - {passphrase: passphrase}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - }); - }; - } else { - codiad.message[result.status](result.message); - } - }); - }, - - pull: function() { - var _this = this; - var remote = $('.git_push_area #git_remotes').val(); - var branch = $('.git_push_area #git_branches').val(); - this.showDialog('overview', this.location); - $.getJSON(this.path + 'controller.php?action=pull&path=' + this.location + '&remote=' + remote + '&branch=' + branch, function(result){ - if (result.status == 'login_required') { - codiad.message.error(result.message); - _this.showDialog('login', _this.location); - _this.login = function(){ - var username = $('.git_login_area #username').val(); - var password = $('.git_login_area #password').val(); - _this.showDialog('overview', _this.location); - $.post(_this.path + 'controller.php?action=pull&path=' + _this.location + '&remote=' + remote + '&branch=' + branch, - {username: username, password: password}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - }); - }; - } else if (result.status == 'passphrase_required') { - codiad.message.error(result.message); - _this.showDialog('passphrase', _this.location); - _this.login = function() { - var passphrase = $('.git_login_area #passphrase').val(); - _this.showDialog('overview', _this.location); - $.post(_this.path + 'controller.php?action=pull&path=' + _this.location + '&remote=' + remote + '&branch=' + branch, - {passphrase: passphrase}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - }); - }; - } else { - codiad.message[result.status](result.message); - } - }); - }, - - fetch: function() { - var _this = this; - var remote = $('.git_remote_area #git_remotes').val(); - this.showDialog('overview', this.location); - $.getJSON(this.path + 'controller.php?action=fetch&path=' + this.location + '&remote=' + remote, function(result){ - if (result.status == 'login_required') { - codiad.message.error(result.message); - _this.showDialog('login', _this.location); - _this.login = function(){ - var username = $('.git_login_area #username').val(); - var password = $('.git_login_area #password').val(); - _this.showDialog('overview', _this.location); - $.post(_this.path + 'controller.php?action=fetch&path=' + _this.location + '&remote=' + remote, - {username: username, password: password}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - }); - }; - } else if (result.status == 'passphrase_required') { - codiad.message.error(result.message); - _this.showDialog('passphrase', _this.location); - _this.login = function() { - var passphrase = $('.git_login_area #passphrase').val(); - _this.showDialog('overview', _this.location); - $.post(_this.path + 'controller.php?action=fetch&path=' + _this.location + '&remote=' + remote, - {passphrase: passphrase}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - }); - }; - } else { - codiad.message[result.status](result.message); - } - }); - }, - - checkout: function(path, repo) { - var result = confirm("Are you sure to undo the changes on: " + path); - if (result) { - $.getJSON(this.path + 'controller.php?action=checkout&repo=' + repo + '&path=' + path, function(result){ - codiad.message[result.status](result.message); - if (codiad.active.isOpen(repo + "/" + path)) { - codiad.message.notice("Reloading file after undoing changes"); - codiad.active.close(repo + "/" + path); - codiad.filemanager.openFile(repo + "/" + path); - } - }); - } - }, - - status: function(path) { - path = this.getPath(path); - this.files = []; - var _this = this; - $.getJSON(this.path + 'controller.php?action=status&path=' + path, function(result){ - if (result.status == 'error') { - codiad.message.error(result.message); - return; - } - //Reset list - $('.git_list tbody').html(''); - var added, deleted, modified, renamed, untracked; - added = result.data.added; - deleted = result.data.deleted; - modified = result.data.modified; - renamed = result.data.renamed; - untracked = result.data.untracked; - //Add entries - $.each(added, function(i, item){ - _this.addLine("Added", item); - }); - $.each(deleted, function(i, item){ - _this.addLine("Deleted", item); - }); - $.each(modified, function(i, item){ - _this.addLine("Modified", item); - }); - $.each(renamed, function(i, item) { - _this.addLine("Renamed", item); - }); - $.each(untracked, function(i, item) { - _this.addLine("Untracked", item); - }); - _this.setBranch(result.data.branch); - }); - }, - - log: function(repo, path) { - repo = this.getPath(repo); - var component = ""; - if (typeof(path) !== 'undefined') { - component = '&path=' + this.encode(path); - $('.git_log_area .path').text(path); - } else if (this.files.length !== 0) { - component = '&path=' + this.encode(this.files[0]); - $('.git_log_area .path').text(this.files[0]); - } - $.getJSON(this.path + 'controller.php?action=log&repo=' + this.encode(repo) + component, function(result){ - if (result.status == 'error') { - codiad.message.error(result.message); - return; - } - $.each(result.data, function(i, item){ - item = item.replace(new RegExp(" ", "g"), " "); - if (item.indexOf("commit") === 0) { - $('.git_log_area .git_log').append('
  • ' + item + '
  • '); - } else { - $('.git_log_area .git_log').append('
  • ' + item + '
  • '); - } - }); - }); - }, - - getRemotes: function(path) { - path = this.getPath(path); - $.getJSON(this.path + 'controller.php?action=getRemotes&path=' + path, function(result){ - if (result.status == 'error') { - codiad.message.error(result.message); - return; - } - $.each(result.data, function(i, item){ - $('#git_remotes').append(''); - }); - $.each(result.data, function(i, item){ - $('.git_remote_info').html(item); - return false; - }); - $('#git_remotes').live('change', function(){ - var value = $('#git_remotes').val(); - $('.git_remote_info').html(result.data[value]); - }); - }); - }, - - newRemote: function(path) { - var _this = this; - path = this.getPath(path); - var name = $('.git_new_remote_area #remote_name').val(); - var url = $('.git_new_remote_area #remote_url').val(); - $.getJSON(this.path + 'controller.php?action=newRemote&path=' + path + '&name=' + name + '&url=' + url, function(result){ - _this.showDialog('overview', _this.location); - codiad.message[result.status](result.message); - }); - }, - - removeRemote: function(path) { - var _this = this; - path = this.getPath(path); - var name = $('#git_remotes').val(); - var result = confirm("Are you sure to remove the remote: " + name); - if (result) { - $.getJSON(this.path + 'controller.php?action=removeRemote&path=' + path + '&name=' + name, function(result){ - codiad.message[result.status](result.message); - }); - } - this.showDialog('overview', this.location); - }, - - renameRemote: function(path) { - path = this.getPath(path); - var name = $('#git_remote').text(); - var newName = $('#git_new_name').val(); - $.getJSON(this.path + 'controller.php?action=renameRemote&path=' + path + '&name=' + name + '&newName=' + newName, function(result){ - codiad.message[result.status](result.message); - }); - this.showDialog('overview', this.location); - }, - - getRemoteBranches: function(path){ - path = this.getPath(path); - $.getJSON(this.path + 'controller.php?action=getRemoteBranches&path=' + path, function(result){ - if (result.status == 'error') { - codiad.message.error(result.message); - return; - } - $.each(result.data.branches, function(i, item){ - $('#git_remote_branches').append(''); - }); - $('#git_new_branch').val(result.data.current.substr(result.data.current.search('/') + 1)); - $('#git_remote_branches').val(result.data.current); - }); - }, - - checkoutRemote: function(path){ - path = this.getPath(path); - var remoteName = $('#git_remote_branches').val(); - var name = $('#git_new_branch').val(); - $.getJSON(this.path + 'controller.php?action=checkoutRemote&path=' + path + '&name=' + name + '&remoteName=' + remoteName, function(result){ - codiad.message[result.status](result.message); - }); - this.showDialog('remote', this.location); - }, - - getBranches: function(path) { - path = this.getPath(path); - $.getJSON(this.path + 'controller.php?action=getBranches&path=' + path, function(result){ - if (result.status == 'error') { - codiad.message.error(result.message); - return; - } - $.each(result.data.branches, function(i, item){ - $('#git_branches').append(''); - }); - $('#git_branches').val(result.data.current); - }); - }, - - newBranch: function(path) { - var _this = this; - path = this.getPath(path); - var name = $('.git_new_branch_area #branch_name').val(); - $.getJSON(this.path + 'controller.php?action=newBranch&path=' + path + '&name=' + name, function(result){ - _this.showDialog('branches', _this.location); - codiad.message[result.status](result.message); - }); - }, - - deleteBranch: function(path) { - path = this.getPath(path); - var name = $('#git_branches').val(); - var result = confirm("Are you sure to remove the branch: " + name); - if (result) { - $.getJSON(this.path + 'controller.php?action=deleteBranch&path=' + path + '&name=' + name, function(result){ - codiad.message[result.status](result.message); - }); - } - this.showDialog('branches', this.location); - }, - - checkoutBranch: function(path) { - path = this.getPath(path); - var name = $('#git_branches').val(); - $.getJSON(this.path + 'controller.php?action=checkoutBranch&path=' + path + '&name=' + name, function(result){ - codiad.message[result.status](result.message); - }); - this.showDialog('overview', this.location); - }, - - renameBranch: function(path) { - path = this.getPath(path); - var name = $('#git_branch').text(); - var newName = $('#git_new_name').val(); - $.getJSON(this.path + 'controller.php?action=renameBranch&path=' + path + '&name=' + name + '&newName=' + newName, function(result){ - codiad.message[result.status](result.message); - }); - this.showDialog('overview', this.location); - }, - - merge: function(path) { - var _this = this; - path = this.getPath(path); - var name = $('#git_branches').val(); - var result = confirm("Are you sure to merge " + name + " into the current branch?"); - if (result) { - $.getJSON(this.path + 'controller.php?action=merge&path=' + path + '&name=' + name, function(result){ - codiad.message[result.status](result.message); - _this.status(_this.location); - }); - } - this.showDialog('overview', this.location); - }, - - rename: function(fPath) { - var _this = this; - var path = _this.dirname(fPath); - var old_name = fPath.replace(path, "").substr(1); - if (old_name.length === 0 || old_name === fPath) { - //Codiad renaming - codiad.filemanager.renameNode(fPath); - return; - } - var shortName = codiad.filemanager.getShortName(fPath); - var type = codiad.filemanager.getType(fPath); - codiad.modal.load(250, codiad.filemanager.dialog, { action: 'rename', path: fPath, short_name: shortName, type: type}); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - var newName = $('#modal-content form input[name="object_name"]') - .val(); - // Build new path - var arr = fPath.split('/'); - var temp = []; - for (i = 0; i < arr.length - 1; i++) { - temp.push(arr[i]); - } - var newPath = temp.join('/') + '/' + newName; - codiad.modal.unload(); - $.getJSON(_this.path + "controller.php?action=rename&path="+path+"&old_name="+old_name+"&new_name="+newName, function(data) { - if (data.status != 'error') { - codiad.message.success(type.charAt(0) - .toUpperCase() + type.slice(1) + ' Renamed'); - var node = $('#file-manager a[data-path="' + fPath + '"]'); - // Change pathing and name for node - node.attr('data-path', newPath) - .html(newName); - if (type == 'file') { // Change icons for file - curExtClass = 'ext-' + codiad.filemanager.getExtension(fPath); - newExtClass = 'ext-' + codiad.filemanager.getExtension(newPath); - $('#file-manager a[data-path="' + newPath + '"]') - .removeClass(curExtClass) - .addClass(newExtClass); - } else { // Change pathing on any sub-files/directories - codiad.filemanager.repathSubs(path, newPath); - } - // Change any active files - codiad.active.rename(fPath, newPath); - } else { - codiad.message.error(data.message); - codiad.filemanager.renameNode(fPath); - } - }); - }); - }, - - submoduleDialog: function(repo, path) { - this.location = repo; - if (repo === path) { - path = ""; - } else { - path = path.replace(repo + "/", ""); - } - this.files = []; - this.files.push(path); - this.showDialog('submodule'); - }, - - submodule: function(repo, dir, submodule) { - var _this = this; - repo = repo || this.location; - path = dir; - if (this.files[0] != "") { - path = this.files[0] + "/" + dir; - } - _this.showDialog('overview', repo); - $.getJSON(this.path + 'controller.php?action=submodule&repo='+repo+'&path='+path+'&submodule='+submodule, function(result){ - if (result.status == 'login_required') { - codiad.message.error(result.message); - _this.showDialog('login', _this.location); - _this.login = function(){ - var username = $('.git_login_area #username').val(); - var password = $('.git_login_area #password').val(); - _this.showDialog('overview', _this.location); - $.post(_this.path + 'controller.php?action=submodule&repo='+repo+'&path='+path+'&submodule='+submodule, - {username: username, password: password}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - if (result.status == 'success') { - codiad.filemanager.rescan(repo); - } - }); - }; - } else if (result.status == 'passphrase_required') { - codiad.message.error(result.message); - _this.showDialog('passphrase', _this.location); - _this.login = function() { - var passphrase = $('.git_login_area #passphrase').val(); - _this.showDialog('overview', _this.location); - $.post(_this.path + 'controller.php?action=submodule&repo='+repo+'&path='+path+'&submodule='+submodule, - {passphrase: passphrase}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - if (result.status == 'success') { - codiad.filemanager.rescan(repo); - } - }); - }; - } else { - codiad.message[result.status](result.message); - if (result.status == 'success') { - codiad.filemanager.rescan(repo); - } - } - }); - }, - - initSubmodule: function(path) { - var _this = this; - path = path || this.location; - $.getJSON(this.path + 'controller.php?action=initSubmodule&path='+path, function(result){ - if (result.status == 'login_required') { - codiad.message.error(result.message); - _this.showDialog('login', _this.location); - _this.login = function(){ - var username = $('.git_login_area #username').val(); - var password = $('.git_login_area #password').val(); - _this.showDialog('overview', _this.location); - $.post(_this.path + 'controller.php?action=initSubmodule&path='+path, - {username: username, password: password}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - if (result.status == 'success') { - codiad.filemanager.rescan(path); - } - }); - }; - } else if (result.status == 'passphrase_required') { - codiad.message.error(result.message); - _this.showDialog('passphrase', _this.location); - _this.login = function() { - var passphrase = $('.git_login_area #passphrase').val(); - _this.showDialog('overview', _this.location); - $.post(_this.path + 'controller.php?action=initSubmodule&path='+path, - {passphrase: passphrase}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - if (result.status == 'success') { - codiad.filemanager.rescan(path); - } - }); - }; - } else { - codiad.message[result.status](result.message); - if (result.status == 'success') { - codiad.filemanager.rescan(path); - } - } - }) - }, - - numstat: function(path) { - if (typeof(path) == 'undefined') { - path = codiad.active.getPath(); - } - $.getJSON(this.path + 'controller.php?action=numstat&path='+path, function(json){ - var insert = ""; - if (json.status != "error") { - var data = json.data; - insert = ''+ data.branch + ' +' + data.insertions + ',-' + data.deletions; - } - $('#git-stat').html(insert); - }); - }, - - repostat: function() { - path = codiad.project.getCurrent(); - $.getJSON(this.path + 'controller.php?action=status&path='+path, function(json){ - var insert = "Unknown", cls = ""; - if (json.status != "error") { - var data = json.data; - if (data.added.length !== 0 || - data.deleted.length !== 0 || - data.modified.length !== 0 || - data.renamed.length !== 0) { - insert = "Uncommitted"; - cls = "invalid"; - } else if (data.untracked.length !== 0) { - insert = "Untracked"; - cls = "untracked"; - } else { - insert = "Committed"; - cls = "valid"; - } - } - $('#git-repo-stat').html(insert); - $('#git-repo-stat-wrapper').removeClass("git-repo-stat-valid git-repo-stat-invalid git-repo-stat-untracked") - .addClass("git-repo-stat-"+cls); - // show the icon - $("#git-repo-status-icon").removeClass("git-repo-icon-valid git-repo-icon-invalid git-repo-icon-untracked") - .addClass("git-repo-icon-"+cls); - }); - }, - - showCommit: function(path, commit) { - var _this = this; - path = this.getPath(path); - this.showDialog('showCommit', path); - $.getJSON(this.path + 'controller.php?action=showCommit&path=' + this.encode(path) + '&commit=' + commit, function(result){ - $('.git_show_commit_area .hash').text(commit); - if (result.status != "success") { - codiad.message.error(result.message); - _this.showDialog('overview', path); - } - result.data = _this.renderDiff(result.data); - $('.git_show_commit_area .content ul').append(result.data.join("")); - }); - }, - - blame: function(path, repo) { - var _this = this; - this.location = repo; - path = path.replace(repo + "/", ""); - this.showDialog('blame', repo); - $.getJSON(this.path + 'controller.php?action=blame&repo=' + this.encode(repo) + '&path=' + this.encode(path), function(result){ - if (result.status != "success") { - codiad.message.error(result.message); - _this.showDialog('overview', repo); - } - $('.git_blame_area table thead th').text(path); - //Split blame output per file line - var hashRegExp = /^[a-z0-9]{40}/; - var data = result.data, starts, startIndexes = [], segments = [], s, e, i; - starts = data.filter(function(line){ - return hashRegExp.test(line); - }); - for (i = 0; i < starts.length; i++) { - startIndexes.push(data.indexOf(starts[i])); - } - for (i = 0; i < starts.length; i++) { - s = startIndexes[i]; - e = (i < (starts.length - 1)) ? (startIndexes[i + 1]) : (data.length); - segments.push(data.slice(s, e)); - } - //Combine lines with the same commit - var hash = segments[0][0].match(hashRegExp)[0]; - var unique = [{segment: segments[0], hash: hash, lines: [segments[0][12]]}]; - for (i = 1; i < segments.length; i++) { - if (hash === segments[i][0].match(hashRegExp)[0]) { - //Same - unique[unique.length - 1].lines.push(segments[i][12]); - } else { - hash = segments[i][0].match(hashRegExp)[0]; - //Next - unique.push({segment: segments[i], hash: hash, lines: [segments[i][12]]}); - } - } - //Format output - var output = "", msg, date, name, line; - for (i = 0; i < unique.length; i++) { - msg = unique[i].segment[9].replace("summary ", ""); - date = unique[i].segment[7].replace("committer-time ", ""); - date = new Date(date * 1000); - date = (date.getMonth() + 1) + "/" + date.getDate() + "/" + date.getFullYear(); - name = unique[i].segment[5].replace("committer ", ""); - hash = unique[i].hash; - output += '' + msg + '
    ' + name + ': ' + date + ''; - output += '' + hash.substr(0, 8) + '
      '; - for (var j = 0; j < unique[i].lines.length; j++) { - line = unique[i].lines[j].replace(new RegExp('\t', 'g'), ' ') - .replace(new RegExp(' ', 'g'), " ") - .replace(new RegExp('\n', 'g'), "
      "); - output += '
    1. ' + line + '
    2. '; - } - output += '
    '; - } - $('.git_blame_area table tbody').html(output); - }); - }, - - history: function(path, repo) { - this.location = repo; - path = path.replace(repo + "/", ""); - this.files = []; - this.files.push(path); - this.showDialog('log', repo); - }, - - network: function(path) { - var _this = this; - path = this.getPath(path); - this.showDialog('network', path); - $.getJSON(this.path + 'controller.php?action=network&path=' + this.encode(path), function(result){ - _this.network_graph.setData(result.data); - _this.network_graph.generate(); - }); - }, - - login: function(){}, - - setSettings: function(path) { - var _this = this; - var settings = {}; - path = this.getPath(path); - $('.git_settings_area input:not(.no_setting)').each(function(i, el){ - settings[$(el).attr("id")] = $(el).val(); - }); - - $.post(this.path + 'controller.php?action=setSettings&path='+path, {settings: JSON.stringify(settings)}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - _this.showDialog('overview', _this.location); - }); - }, - - getSettings: function(path) { - path = this.getPath(path); - $.getJSON(this.path + 'controller.php?action=getSettings&path=' + path, function(result){ - if (result.status == 'error') { - codiad.message.error(result.message); - return; - } - var local = false; - $.each(result.data, function(i, item){ - if (/\//.test(i)) { - return; - } - $('.git_settings_area #' + i).val(item); - if (/^local_/.test(i)) { - local = true; - } - }); - if (!local) { - $('#box_local').click(); - } - }); - }, - - /** - * Get path - * - * @param {string} [path] - * @result {string} path - */ - getPath: function(path) { - if (typeof(path) == 'undefined') { - return this.location; - } else { - return path; - } - }, - - /** - * Get basename - * - * @param {string} [path] - * @result {string} basename - */ - basename: function(path) { - return path.replace(/\\/g,'/').replace( /.*\//, '' ); - }, - - /** - * Get dirname - * - * @param {string} [path] - * @result {string} dirname - */ - dirname: function(path) { - return path.replace(/\\/g,'/').replace(/\/[^\/]*$/, ''); - }, - - /** - * Encode Uri component - * - * @param {string} [string] - * @result {string} encoded string - */ - encode: function(string) { - return encodeURIComponent(string); - }, - - addLine: function(status, name) { - var line = this.line; - var element = ''+status+''+name+''; - $('.git_list tbody').append(element); - this.line++; - }, - - /** - * Render git diff output - * - * @param {Array} [array] - * @result {Array} Renderd output - */ - renderDiff: function(array) { - var output = [], element, item; - for (var i = 0; i < array.length; i++) { - item = array[i]; - element = item.replace(new RegExp('\t', 'g'), ' ') - .replace(new RegExp(' ', 'g'), " ") - .replace(new RegExp('\n', 'g'), "
    "); - if (item.indexOf('+++') === 0 || item.indexOf('---') === 0 || /^index [0-9a-z]{7}..[0-9a-z]{7}/.test(item) || /^new file mode [0-9]{6}/.test(item)) { - continue; - } else if (/^diff --git a\/.+ b\/.+/.test(item)) { - element = item.match(/^diff --git a\/.+ b\/(.+)/); - element = '
  • ' + element[1] + '
  • '; - } else if (/^@@ -[0-9,]+ \+[0-9,]+ @@/.test(item)) { - element = '
  • ' + element + '
  • '; - } else if (item.indexOf('+') === 0 && item.indexOf('+++') !== 0) { - element = '
  • ' + element + '
  • '; - } else if (item.indexOf('-') === 0 && item.indexOf('---') !== 0) { - element = '
  • ' + element + '
  • '; - } else { - element = '
  • ' + element + '
  • '; - } - output.push(element); - } - return output; - }, - - setBranch: function(branch) { - $('.git_area .branch').text(branch); - }, - - addStatusIcon: function () { - if ($("span#git-repo-status-icon").length < 1) { - $('#file-manager #project-root').before(''); - } - }, - - isEnabledRepoStatus: function () { - var setting = localStorage.getItem('codiad.plugin.codegit.disableRepoStatus'), ret = true; - if (setting === "true") { - ret = false; - } - return(ret); - }, - - isEnabledWrapper: function () { - var setting = localStorage.getItem('codiad.plugin.codegit.disableHeader'), ret = true; - if (setting === "true") { - ret = false; - } - return(ret); - }, - - suppressCommitDiff: function() { - return false || localStorage.getItem('codiad.plugin.codegit.suppressCommitDiff') == "true"; - } - }; -})(this, jQuery);"; \ No newline at end of file diff --git a/data/collaborative/shadow/07a6a7a936469108b7eb1d5595405b41 b/data/collaborative/shadow/07a6a7a936469108b7eb1d5595405b41 deleted file mode 100755 index b511283..0000000 --- a/data/collaborative/shadow/07a6a7a936469108b7eb1d5595405b41 +++ /dev/null @@ -1,577 +0,0 @@ -s:22352:"/** - Author: Abbas Abdulmalik - Created: ~ May, 2017 - Revised: June 9, 2018 - Original Filename: L.js - Purpose: a small (but growing) personal re-usable js library for a simple MVC architecture - Notes: Now qualifyFunction helper doesn't return true for empty arrays (no vacuous truth) - - Added UploadFiles: - uploadFiles takes a callback -- progressReporter-- as it FIRST argument (parameter) - to allow for an optional fourth parameter of an upload path for the server. - progressReporter will be passed three arguments when called: - 1.) the amount of bytes uploaded so far - 2.) the total size of the file in bytes - 3.) the index of the file in the "array" of files being uploaded - - Added sortByExtension that alphabetizes an array of strings 'in place' by filename extension - Added arrayStringMatch that matches a collection of string arrays to a search string. - later (6-9-2018) included an option for a "maximum array index" to eliminate - searching irrelevant fields at the end of the array, such as image name and primary key. - Added loopCall as a 'better' version of setInterval - Removed L.attributes. It's a reserved word: an object belonging to DOM elements - Now it uses L.attribs - Added L.loopCall.stop() so that user can easily stop L.loopCall - Added L.symDiff for comparing arrays to determine their symmetric difference = conjunctive union = - exclusive-or - Restored an updated version of uploadFiles that signals the final file has uploaded - Added secToMinSec - Added runQualifiedFunctions that mirrors runQualifiedMethods using different parameters, - namely: functionQualifiers, model, view, controller - Added attachNewElement(tagname, id, view). Create new element, gives it an id and - attaches it to object provided: - L.attachNewElement(`div`, `picHolder`, view) - Added createListMixer and scrammbleThis, which depends on createListMixer - Added sortArrayOfStringArrays, with option of using a "link token" of choice as the 3rd argument - Added an optional argument for arrayStringMatch for a maximum array index - to eliminate searching irrelevant fields at the end of the array, - such as image name and primary key -*/ - -var L = {} -L.styles = function(styleString){ - const colonPosition = styleString.indexOf(':') - const property = styleString.slice(0, colonPosition) - const value = styleString.slice(colonPosition + 1) - this.style[property] = value - - return this.styles -} - -L.attribs = function(attributeString){ - const assignmentPosition = attributeString.indexOf('=') - const attribute = attributeString.slice(0, assignmentPosition) - const value = attributeString.slice(assignmentPosition + 1) - this.setAttribute(attribute, value) - - return this.attribs -} - -L.attachAllElementsById = function(here){ - let allElements = document.getElementsByTagName('*') - let array = [] - array.forEach.call(allElements, function(element) { - if(element.id){ - here[element.id] = element - element.styles = L.styles.bind(element) // attach L's styles() method here - element.attribs = L.attribs.bind(element) // attach L's attribs() method here - } - }) -} -///////////////| START of L.attachNewElement |///////////// -/** - L.attachNewElement(string tagname, string id, object view) ... - ... creates a new element of type "tagname" given as the first argument, - and gives it the id "id" given as the second argument. - The third argument is the view object where this new reference will be attached. - The element can then be referenced as view.id. -*/ -L.attachNewElement = function(tagname, id, view){ - if(arguments.length !== 3){ - console.log(`Error: requires 3 arguments: tagname, id, view`) - return - } - try{ - if(typeof tagname === `string`){ - var newElement = document.createElement(tagname) - } - else{ - console.log(`Error: tagname needs to be a string`) - return - } - if(typeof id === `string`){ - newElement.id = id - } - else{ - console.log(`Error: id needs to be a string`) - return - } - if(view.toString() === `[object Object]`){ - view[newElement.id] = newElement - newElement.styles = L.styles.bind(newElement) // attach L's styles() method here - newElement.attribs = L.attribs.bind(newElement) // attach L's attribs() method here - return newElement - } - else{ - console.log(`Error: view needs to be an object`) - return - } - } - catch(e){ - console.log(`Error in L.attachNewElement: ${e}`) - return - } -} -///////////////| END of L.attachNewElement |///////////// - -L.noPinchZoom = function(){ - window.ontouchstart = function(eventObject){ - if(eventObject.touches && eventObject.touches.length > 1){ - eventObject.preventDefault(); - } - } -} - -L.runQualifiedMethods = function(functionQualifiers, object, runNextUpdate){ - Object - .keys(functionQualifiers) - .filter(qualifyFunction) - .forEach(runFunction) - if(typeof runNextUpdate === 'function'){runNextUpdate()} - - //-----| helpers |-----// - function qualifyFunction(functionName){ - const isQualified = functionQualifiers[functionName].every( qualifier => qualifier) && - !!functionQualifiers[functionName].length - return isQualified - } - function runFunction(functionName){ - if(typeof object[functionName] === 'function'){ - object[functionName]() - } - - /** - If the prefix of this function's name is 'set' (for updating the MODEL), - and there is a similarly named function with a prefix of 'show' (for updating the VIEW), - then run the 'show' version as well. - */ - let prefix = functionName.slice(0,3) - let newFunctionName = 'show' + functionName.slice(3) - - if(prefix === 'set' && typeof object[newFunctionName] === 'function'){ - object[newFunctionName]() - } - } -} - -L.runQualifiedFunctions = function(functionQualifiers, model, view, controller){ - Object - .keys(functionQualifiers) - .filter(qualifyFunction) - .forEach(runFunction) - //-----| helpers |-----// - function qualifyFunction(functionName){ - const isQualified = functionQualifiers[functionName].every( qualifier => qualifier) && - !!functionQualifiers[functionName].length - return isQualified - } - function runFunction(functionName){ - if(typeof controller[functionName] === 'function'){ - controller[functionName](model) - } - /** - If the prefix of this function's name is 'set' (for updating the MODEL), - and there is a similarly named function with a prefix of 'show' (for updating the VIEW), - then run the 'show' version as well. - */ - let prefix = functionName.slice(0,3) - let newFunctionName = 'show' + functionName.slice(3) - if(prefix === 'set' && typeof controller[newFunctionName] === 'function'){ - controller[newFunctionName](view) - } - } -} -/** - Use a php script that reads contents of file from $_POST['contents'] that was convert by client - as DataURL, and expects filename and uploadPath from: $_POST['filename'] and $_POST['uploadPath'] - with trailing slash (/) provided by client (though script could check for this). -*/ -L.uploadFiles = function(progressReporter, fileElement, phpScriptName, uploadPath='../uploads/'){ - let doneCounter = 0 - let fileCount = fileElement.files.length - const array = [] // make a real array to borrow it's forEach method - array.forEach.call(fileElement.files, (file, index) => { - const postman = new XMLHttpRequest() // make a file deliverer for each file - const uploadObject = postman.upload // This object keeps track of upload progress - const envelope = new FormData() // make a holder for the file's name and content - envelope.stuff = envelope.append // give 'append' the nickname 'stuff' - const reader = new FileReader() // make a file reader (the raw file element is useless) - - reader.readAsDataURL(file) // process the file's contents - reader.onload = function(){ // when done ... - const contents = reader.result // collect the result, and ... - envelope.stuff('contents', contents) // place it in the envelope along with ... - envelope.stuff('filename', file.name) // its filename ... - envelope.stuff('uploadPath', uploadPath) // and its upload path on the server - - postman.open(`POST`, phpScriptName)// open up a POST to the server's php script - postman.send(envelope) // send the file - - //check when file loads and when there is an error - postman.onload = eventObject => { - postman.status !== 200 ? showMessage() : checkLastFileDone() - //-----| helper |------// - function showMessage(){ - const message = `Trouble with file: ${postman.status}` - console.log(message) - alert(message) - } - function checkLastFileDone(){ - doneCounter++ - if(typeof progressReporter === 'function'){ - if(doneCounter === fileCount){ - progressReporter(1, 1, index) - } - } - } - } - - postman.onerror = eventObject => { - const message = `Trouble connecting to server` - console.log(message) - alert(message) - } - - //invoke the callback for each upload progress report - uploadObject.onprogress = function(progressObject){ - if(typeof progressReporter === 'function'){ - progressReporter(progressObject.loaded, progressObject.total, index) - } - } - } - }) -} - -//---------------------------------------------------------// -/** - Given an array of strings (array), sorts the array 'in place' by filename EXTENSION, - and returns a copy of the array as well. Since it mutates the array, it is decidedly not - functionistic (but it functions). -*/ -L.sortByExtension = function (array) { - const type = {}.toString.call(array, null); - if (type !== '[object Array]') { - return array; - } - if (array.length === 0 || array.some(member => typeof member !== 'string')) { - return array; - } - //-------------------------------------// - let extension = ``; - let nudeWord = ``; - array.forEach((m, i, a) => { - if (m.lastIndexOf(`.`) !== -1) { - //get the extension - extension = m.slice(m.lastIndexOf(`.`) + 1); - nudeWord = m.slice(0, m.lastIndexOf(`.`)); - a[i] = `${extension}.${nudeWord}`; - } - }); - - array.sort(); - - array.forEach((m, i, a) => { - if (m.indexOf(`.`) !== -1){ - //get prefix (formerly the extension) - extension = m.slice(0, m.indexOf(`.`)) - nudeWord = m.slice(m.indexOf(`.`) + 1) - a[i] = `${nudeWord}.${extension}` - } - }); - - const newArray = [] - array.forEach( m => newArray.push(m)) - - return newArray; -} - -/** -From an array of string arrays, return a possibly smaller array -of only those string arrays whose member strings contain the given subString -regardless of case. - 1. For arrayOfStringArrays, use the filter method (a function property of an array) - that expects a function argument that operates on each array member - 2. Let's call the function argument 'match' - 3. 'match' should test each member array for a match of the substring as follows: - a.) join the members strings together into a bigString that is lowerCased - b.) lowerCase the subString - c.) use indexOf to match substring to the bigString - d.) return true for a match, otherwise return false - 4. the filter creates a new array after doing this. - 5. final step: return the new array that the filter produced -*/ -L.arrayStringMatch = function(subString, arrayOfStringArrays, maxIndex){ - //============================================================// - return arrayOfStringArrays.filter(match) - //-------| Helper function 'match' |---------// - function match(memberArray){ - //on 6-9-2018, added option of maximum index to eliminate searching through irrelevant fields - let bigString = '' - if(maxIndex && typeof maxIndex === "number" && maxIndex > 0){ - bigString = memberArray - .filter((m,i) => i <= maxIndex) - .join(` `) - .toLowerCase() - } - else{ - bigString = memberArray.join(` `).toLowerCase() - } - const substringToMatch = subString.toLowerCase() - return bigString.indexOf(substringToMatch) !== -1 - } -} -//-------------------------------------------------// - -/** - L.loopCall can be used to replace setInterval, which has been somewhat discredited. - See this blog post: - https://dev.to/akanksha_9560/why-not-to-use-setinterval--2na9 - - L.loopCall uses setTimeout recursively, which is a technique - reportedly more reliabale than setInterval. - - L.loopCall repeatedly calls (invokes) the callback function provided as its first argument. - The first call is immediate, but subsequent calls are delayed by the milliseconds - provided as the second argument. All additional arguments are optional - to be used by the callback if required. - - If needed, you can delay the initial call as well, - by having loopCall invoked by setTimeout using the same delay: - - setTimeout(L.loopCall, delay, callback, delay, arg1, arg2 ...) - - or the more readable, but more risky ... - - setTimeout("L.loopCall(callback, delay, arg1, arg2 ...)", delay) - //Doug Crockford would not be pleased - - To stop the loop, the callback function can test some external state condition, - (or test its own arguments, if they are passed by reference): - - if(externalStateCondition){ - L.loopCall.stop() - } -*/ -L.loopCall = function (callback, delay, ...args){ - L.loopCall.stopLoop = setTimeout(L.loopCall, delay, callback, delay, ...args) - callback(...args) -} - -L.loopCall.stop = () => { - clearTimeout(L.loopCall.stopLoop) -} - -/** - Returns an array that is the "mathematical or logical" symmetric difference among or between - any number of arrays provided as arguments (usually two). If the order of members is ignored - (as is done for mathematical sets), the result acts as the the exclusive-or (XOR), also know as - the disjunctive union. For the trivial cases of comparing one or two arrays, the result is - not surprising: for one array, the result is itself: L.symDiff(A, []) => A ⊕ [] = A. - For two arrays, the result is an array that has only members which are not shared in common: - L.symDiff(A, B) => A ⊕ B . - When comparing more than two arrays, the result may ne surprising. The proper result can be verified - by comparing only two at a time: L.symDiff(A, B, C) => A ⊕ B ⊕ C = (A ⊕ B) ⊕ C -*/ -L.symDiff = function symDiff(arrayA, arrayB){ // dummy paramters NOT referenced in body of the function - var partialSymDiff = [], - argsArray = arguments - ; - //============THE CRUX================= - return findSymDiff(partialSymDiff,0); - //============UNDER THE HOOD=========== - function findSymDiff(partialSymDiff,index){ - if (argsArray[index] === undefined){ - return partialSymDiff; - } - else{ - partialSymDiff = sd(partialSymDiff, argsArray[index] ); - return findSymDiff( partialSymDiff, index + 1 ); - } - } - //===================================== - function sd(arrayI, arrayJ){ - var diff = [], - blackList = [], - i = 0, - j = 0, - maxI = arrayI.length, - maxJ = arrayJ.length - ; - //------------------------------------------------- - //1.) Combine the arrays into a third array. - //2.) Find the matched elements and place them into a blacklist array. - //3.) Pull blacklisted elements from the combined array. - //4.) return the "reduced" combined array. - //--------------------------------------------------- - // 1.) Combine the arrays into a third array. - diff = arrayI.concat(arrayJ); - //--------------------------------------------------- - // 2.) Find the matched elements and place them into a blacklist array. - for ( i=0; i < maxI; i++ ){ - for( j=0; j< maxJ; j++ ){ - if(arrayI[i] === arrayJ[j]){ - blackList.push(arrayI[i] ); - } - } - } - //---------------------------------------------------- - // 3.) Pull blacklisted elements from the combined array. - diff = diff.filter( (element) => blackList.indexOf(element) === -1 ) - //---------------------------------------------------- - // 4.) return the "reduced" combined array. - return killDupes(diff); - } - //======================================================== - function killDupes(array){ - var kept = []; // Record of the "keepers" - return array.filter(function(element){ - if ( kept.indexOf(element) === -1 ){ //if not already retained ... - kept.push(element); // Record it as retained now, and... - return true; // allow this element to be kept (true) - } - else{ - return false; // otherwise, don't keep it (already kept) - } - }); - } -}; - -/** - * Pass in a numerical seconds: it returns a string in the format - * mm : ss, like ... - * 35 : 37 in minutes and seconds -*/ -L.secToMinSec = (seconds) =>{ - var min = Math.floor(seconds / 60); - var sec = Math.floor(seconds % 60); - if(isNaN(min)){min = 0} - if(isNaN(sec)){sec = 0} - var zeroMin = ((min < 10) ? ("0" + min) : ("" + min)); - var zeroSec = ((sec < 10) ? ("0" + sec) : ("" + sec)); - var minSec = zeroMin + ":" + zeroSec; - return minSec; -}; -//====| END of secToMinSec |====// - -///////////////////| START of CreateListMixer |////////////////////// -/** - * CreateListMixer: a factory that creates and returns a function that - * returns a random item from the collection (array or object) provided. - * Notes: Example-> var list = ["a", "short", "list"];//three (3) items to test - * var getRandomItem = CreateListMixer(); - * getRandomItem(list);//returns first of randomized list - * getRandomItem();//returns next item - * getRandomItem();//returns next item (last of three) - * getRandomItem();//new first item from re-randomized list - * - * // a new list; - * var list2 = { record1: "string", record2: "anotherString", ...}; - * getRandomItem(list2);//returns first of new randomized list2 - * getRandomItem();//etc. - * It returns a property name for objects or an array member for arrays; - * It returns 'false' if argument of function is not an object - * or an array (fails typeof arg === 'object') - * -*/ -L.CreateListMixer = function(){ - var list=[], - randList= [], - listLength= 0, - itemReturned= null, - itemReturnedIndex= -1 - ; - return function(){ - if(arguments[0]){ - if(typeof arguments[0] === 'object'){ - list = arguments[0]; - if({}.toString.call(arguments[0]) === '[object Object]'){ - list = Object.keys(list); - } - randList = randomize(list); - listLength = list.length; - } - else{ - return false; - } - } - //----| no args activity: return next random item |---- - if(itemReturnedIndex >= listLength-1){ - do{ - randList = randomize(list); - itemReturnedIndex = -1; - } - while(randList[itemReturnedIndex +1] === itemReturned); - } - itemReturnedIndex++; - itemReturned = randList[itemReturnedIndex]; - return itemReturned; - //-----helpers----- - function randomize(x){ - var mixedIndexes = []; - var randomList = []; - randomizeIndexes(); - return randomList; - //----sub helper---- - function randomizeIndexes(){ - // random numbers for mixedIndexes - while(mixedIndexes.length !== x.length){ - var match = false; - var possibleIndex = (x.length)*Math.random(); - possibleIndex = Math.floor(possibleIndex); - mixedIndexes.forEach(function(m){ - if(m === possibleIndex){ - match = true; - } - }); - if(!match){ - mixedIndexes.push(possibleIndex); - } - } - for(var i = 0; i < x.length; i++){ - var newIndex = mixedIndexes[i]; - randomList.push(list[newIndex]); - } - } - } - };//===| END returned function |====== -}//===| END enclosing factory function====== -///////////////////| END of CreateListMixer |////////////////////// - -///////////////////| START of scrammbleThis |////////////////////// -/** - scrammbleThis: (depends on createListMixer, above) - It returns an array of randomly arranged items of the collection provided. - The argument must be an array, an object, or a string. - If the argument is an object, a random array of its property names is returned. - If the argument is a string, a random array of its characters is returned. - If the argument is an array, a random array of its members is returned. -*/ -L.scrammbleThis = function(collection){ - if ( !(typeof collection === 'object' || typeof collection === 'string') ){return collection} - var mix = L.CreateListMixer(); - var list = (Object.prototype.toString.call(collection) === '[object Array]') - ? collection - : (typeof collection === 'string') - ? collection.split('') - : (typeof collection === 'object') - ? Object.keys(collection) - : null - return list.map((m,i,a)=> (i === 0) ? mix(a) : mix()) -} -///////////////////| END of scrammbleThis |////////////////////// - -/** - Given an array of string arrays, this function returns an alphabetized version -*/ -L.sortArrayOfStringArrays = function(arrayOfStringArrays, linkToken='```'){ - //use a unique token (default = triple back-ticks ```) to join the strings of each array of strings - const arrayOfStrings = arrayOfStringArrays.map(stringArray => stringArray.join(linkToken)) - - //case-insensitive sort this array of strings, mutating it in place: - //https://stackoverflow.com/questions/8996963/how-to-perform-case-insensitive-sorting-in-javascript - arrayOfStrings.sort( (a,b) => a.toLowerCase().localeCompare(b.toLowerCase()) ) - - //return a new array of string arrays after splitting the strings on the unique token - return arrayOfStrings.map( string => string.split(linkToken)) -} -"; \ No newline at end of file diff --git a/data/collaborative/shadow/08791dea727327b5a0481e2a8fb350ff b/data/collaborative/shadow/08791dea727327b5a0481e2a8fb350ff deleted file mode 100755 index c974307..0000000 --- a/data/collaborative/shadow/08791dea727327b5a0481e2a8fb350ff +++ /dev/null @@ -1,55 +0,0 @@ -s:1656:" $(window).height() - $('#context-menu').height()) { - top -= $('#context-menu').height(); - } - if (top < 10) { - top = 10; - } - var max = $(window).height() - top - 10; - - $('#context-menu') - .css({ - 'top': top + 'px', - 'left': e.pageX + 'px', - 'max-height': max + 'px' - }) - .fadeIn(200) - .attr('data-path', path) - .attr('data-type', type) - .attr('data-name', name); - // Show faded 'paste' if nothing in clipboard - if (this.clipboard === '') { - $('#context-menu a[content="Paste"]') - .addClass('disabled'); - } else { - $('#context-menu a[data-action="paste"]') - .removeClass('disabled'); - } - // Hide menu - $('#file-manager, #editor-region') - .on('mouseover', function() { - _this.contextMenuHide(); - }); - /* Notify listeners. */ - amplify.publish('context-menu.onShow', {e: e, path: path, type: type}); - // Hide on click - $('#context-menu a') - .click(function() { - _this.contextMenuHide(); - }); - }, - - contextMenuHide: function() { - $('#context-menu') - .fadeOut(200); - $('#file-manager a') - .removeClass('context-menu-active'); - /* Notify listeners. */ - amplify.publish('context-menu.onHide'); - }, - - ////////////////////////////////////////////////////////////////// - // Return the node name (sans path) - ////////////////////////////////////////////////////////////////// - - getShortName: function(path) { - return path.split('/') - .pop(); - }, - - ////////////////////////////////////////////////////////////////// - // Return extension - ////////////////////////////////////////////////////////////////// - - getExtension: function(path) { - return path.split('.') - .pop(); - }, - - ////////////////////////////////////////////////////////////////// - // Return type - ////////////////////////////////////////////////////////////////// - - getType: function(path) { - return $('#file-manager a[data-path="' + path + '"]') - .attr('data-type'); - }, - - ////////////////////////////////////////////////////////////////// - // Create node in file tree - ////////////////////////////////////////////////////////////////// - - createObject: function(parent, path, type) { - // NODE FORMAT:
  • {short_name}
  • - var parentNode = $('#file-manager a[data-path="' + parent + '"]'); - if (!$('#file-manager a[data-path="' + path + '"]') - .length) { // Doesn't already exist - if (parentNode.hasClass('open') && parentNode.hasClass('directory')) { // Only append node if parent is open (and a directory) - var shortName = this.getShortName(path); - if (type == 'directory') { - var appendage = '
  • ' + shortName + '
  • '; - } else { - var appendage = '
  • ' + shortName + '
  • '; - } - if (parentNode.siblings('ul') - .length) { // UL exists, other children to play with - parentNode.siblings('ul') - .append(appendage); - } else { - $('') - .insertAfter(parentNode); - } - } else { - parentNode.parent().children('span').removeClass('none'); - parentNode.parent().children('span').addClass('plus'); - } - } - }, - - ////////////////////////////////////////////////////////////////// - // Loop out all files and folders in directory path - ////////////////////////////////////////////////////////////////// - - indexFiles: [], - - index: function(path, rescan) { - var _this = this; - if (rescan === undefined) { - rescan = false; - } - node = $('#file-manager a[data-path="' + path + '"]'); - if (node.hasClass('open') && !rescan) { - node.parent('li') - .children('ul') - .slideUp(300, function() { - $(this) - .remove(); - node.removeClass('open'); - }); - } else { - node.addClass('loading'); - $.get(this.controller + '?action=index&path=' + encodeURIComponent(path), function(data) { - node.addClass('open'); - var objectsResponse = codiad.jsend.parse(data); - if (objectsResponse != 'error') { - /* Notify listener */ - _this.indexFiles = objectsResponse.index; - amplify.publish("filemanager.onIndex", {path: path, files: _this.indexFiles}); - var files = _this.indexFiles; - if (files.length > 0) { - if (node.parent().children('span').hasClass('plus')) { - node.parent().children('span').removeClass('plus').addClass('minus'); - } - var display = 'display:none;'; - if (rescan) { - display = ''; - } - var appendage = ''; - if (rescan) { - node.parent('li') - .children('ul') - .remove(); - } - $(appendage) - .insertAfter(node); - if (!rescan) { - node.siblings('ul') - .slideDown(300); - } - } - } - node.removeClass('loading'); - if (rescan && _this.rescanChildren.length > _this.rescanCounter) { - _this.rescan(_this.rescanChildren[_this.rescanCounter++]); - } else { - _this.rescanChildren = []; - _this.rescanCounter = 0; - } - }); - } - }, - - rescanChildren: [], - - rescanCounter: 0, - - rescan: function(path) { - var _this = this; - if (this.rescanCounter === 0) { - // Create array of open directories - node = $('#file-manager a[data-path="' + path + '"]'); - node.parent() - .find('a.open') - .each(function() { - _this.rescanChildren.push($(this) - .attr('data-path')); - }); - } - - this.index(path, true); - }, - - ////////////////////////////////////////////////////////////////// - // Open File - ////////////////////////////////////////////////////////////////// - - openFile: function(path, focus) { - if (focus === undefined) { - focus = true; - } - var node = $('#file-manager a[data-path="' + path + '"]'); - var ext = this.getExtension(path); - if ($.inArray(ext.toLowerCase(), this.noOpen) < 0) { - node.addClass('loading'); - $.get(this.controller + '?action=open&path=' + encodeURIComponent(path), function(data) { - var openResponse = codiad.jsend.parse(data); - if (openResponse != 'error') { - node.removeClass('loading'); - codiad.active.open(path, openResponse.content, openResponse.mtime, false, focus); - } - }); - } else { - if(!codiad.project.isAbsPath(path)) { - if ($.inArray(ext.toLowerCase(), this.noBrowser) < 0) { - this.download(path); - } else { - this.openInModal(path); - } - } else { - codiad.message.error(i18n('Unable to open file in Browser')); - } - } - }, - - ////////////////////////////////////////////////////////////////// - // Open in browser - ////////////////////////////////////////////////////////////////// - - openInBrowser: function(path) { - $.ajax({ - url: this.controller + '?action=open_in_browser&path=' + encodeURIComponent(path), - success: function(data) { - var openIBResponse = codiad.jsend.parse(data); - if (openIBResponse != 'error') { - window.open(openIBResponse.url, '_newtab'); - } - }, - async: false - }); - }, - openInModal: function(path) { - codiad.modal.load(250, this.dialog, { - action: 'preview', - path: path - }); - }, - saveModifications: function(path, data, callbacks, save=true){ - callbacks = callbacks || {}; - var _this = this, action, data; - var notifySaveErr = function() { - codiad.message.error(i18n('File could not be saved')); - if (typeof callbacks.error === 'function') { - var context = callbacks.context || _this; - callbacks.error.apply(context, [data]); - } - } - $.post(this.controller + '?action=modify&path=' + encodeURIComponent(path), data, function(resp){ - resp = $.parseJSON(resp); - if (resp.status == 'success') { - if ( save === true ) { - codiad.message.success(i18n('File saved')); - } - if (typeof callbacks.success === 'function'){ - var context = callbacks.context || _this; - callbacks.success.call(context, resp.data.mtime); - } - } else { - if (resp.message == 'Client is out of sync'){ - var reload = confirm( - "Server has a more updated copy of the file. Would "+ - "you like to refresh the contents ? Pressing no will "+ - "cause your changes to override the server's copy upon "+ - "next save." - ); - if (reload) { - codiad.active.close(path); - codiad.active.removeDraft(path); - _this.openFile(path); - } else { - var session = codiad.editor.getActive().getSession(); - session.serverMTime = null; - session.untainted = null; - } - } else codiad.message.error(i18n('File could not be saved')); - if (typeof callbacks.error === 'function') { - var context = callbacks.context || _this; - callbacks.error.apply(context, [resp.data]); - } - } - }).error(notifySaveErr); - }, - ////////////////////////////////////////////////////////////////// - // Save file - ////////////////////////////////////////////////////////////////// - - saveFile: function(path, content, callbacks, save=true) { - this.saveModifications(path, {content: content}, callbacks, save); - }, - - savePatch: function(path, patch, mtime, callbacks) { - if (patch.length > 0) - this.saveModifications(path, {patch: patch, mtime: mtime}, callbacks); - else if (typeof callbacks.success === 'function'){ - var context = callbacks.context || this; - callbacks.success.call(context, mtime); - } - }, - - ////////////////////////////////////////////////////////////////// - // Create Object - ////////////////////////////////////////////////////////////////// - - createNode: function(path, type) { - codiad.modal.load(250, this.dialog, { - action: 'create', - type: type, - path: path - }); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - var shortName = $('#modal-content form input[name="object_name"]') - .val(); - var path = $('#modal-content form input[name="path"]') - .val(); - var type = $('#modal-content form input[name="type"]') - .val(); - var createPath = path + '/' + shortName; - $.get(codiad.filemanager.controller + '?action=create&path=' + encodeURIComponent(createPath) + '&type=' + type, function(data) { - var createResponse = codiad.jsend.parse(data); - if (createResponse != 'error') { - codiad.message.success(type.charAt(0) - .toUpperCase() + type.slice(1) + ' Created'); - codiad.modal.unload(); - // Add new element to filemanager screen - codiad.filemanager.createObject(path, createPath, type); - if(type == 'file') { - codiad.filemanager.openFile(createPath, true); - } - /* Notify listeners. */ - amplify.publish('filemanager.onCreate', {createPath: createPath, path: path, shortName: shortName, type: type}); - } - }); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Copy to Clipboard - ////////////////////////////////////////////////////////////////// - - copyNode: function(path) { - this.clipboard = path; - codiad.message.success(i18n('Copied to Clipboard')); - }, - - ////////////////////////////////////////////////////////////////// - // Paste - ////////////////////////////////////////////////////////////////// - - pasteNode: function(path) { - var _this = this; - if (this.clipboard == '') { - codiad.message.error(i18n('Nothing in Your Clipboard')); - } else if (path == this.clipboard) { - codiad.message.error(i18n('Cannot Paste Directory Into Itself')); - } else { - var shortName = _this.getShortName(_this.clipboard); - if ($('#file-manager a[data-path="' + path + '/' + shortName + '"]') - .length) { // Confirm overwrite? - codiad.modal.load(400, this.dialog, { - action: 'overwrite', - path: path + '/' + shortName - }); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - var duplicate = false; - if($('#modal-content form select[name="or_action"]').val()==1){ - duplicate=true; console.log('Dup!'); - } - _this.processPasteNode(path,duplicate); - }); - } else { // No conflicts; proceed... - _this.processPasteNode(path,false); - } - } - }, - - processPasteNode: function(path,duplicate) { - var _this = this; - var shortName = this.getShortName(this.clipboard); - var type = this.getType(this.clipboard); - if(duplicate){ - shortName = "copy_of_"+shortName; - } - $.get(this.controller + '?action=duplicate&path=' + - encodeURIComponent(this.clipboard) + '&destination=' + - encodeURIComponent(path + '/' + shortName), function(data) { - var pasteResponse = codiad.jsend.parse(data); - if (pasteResponse != 'error') { - _this.createObject(path, path + '/' + shortName, type); - codiad.modal.unload(); - /* Notify listeners. */ - amplify.publish('filemanager.onPaste', {path: path, shortName: shortName, duplicate: duplicate}); - } - }); - }, - - ////////////////////////////////////////////////////////////////// - // Rename - ////////////////////////////////////////////////////////////////// - - renameNode: function(path) { - var shortName = this.getShortName(path); - var type = this.getType(path); - var _this = this; - codiad.modal.load(250, this.dialog, { action: 'rename', path: path, short_name: shortName, type: type}); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - var newName = $('#modal-content form input[name="object_name"]') - .val(); - // Build new path - var arr = path.split('/'); - var temp = new Array(); - for (i = 0; i < arr.length - 1; i++) { - temp.push(arr[i]) - } - var newPath = temp.join('/') + '/' + newName; - $.get(_this.controller, { action: 'modify', path: path, new_name: newName} , function(data) { - var renameResponse = codiad.jsend.parse(data); - if (renameResponse != 'error') { - codiad.message.success(type.charAt(0) - .toUpperCase() + type.slice(1) + ' Renamed'); - var node = $('#file-manager a[data-path="' + path + '"]'); - // Change pathing and name for node - node.attr('data-path', newPath) - .html(newName); - if (type == 'file') { // Change icons for file - curExtClass = 'ext-' + _this.getExtension(path); - newExtClass = 'ext-' + _this.getExtension(newPath); - $('#file-manager a[data-path="' + newPath + '"]') - .removeClass(curExtClass) - .addClass(newExtClass); - } else { // Change pathing on any sub-files/directories - _this.repathSubs(path, newPath); - } - // Change any active files - codiad.active.rename(path, newPath); - codiad.modal.unload(); - } - }); - }); - }, - - repathSubs: function(oldPath, newPath) { - $('#file-manager a[data-path="' + newPath + '"]') - .siblings('ul') - .find('a') - .each(function() { - // Hit the children, hit 'em hard - var curPath = $(this) - .attr('data-path'); - var revisedPath = curPath.replace(oldPath, newPath); - $(this) - .attr('data-path', revisedPath); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Delete - ////////////////////////////////////////////////////////////////// - - deleteNode: function(path) { - var _this = this; - codiad.modal.load(400, this.dialog, { - action: 'delete', - path: path - }); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - $.get(_this.controller + '?action=delete&path=' + encodeURIComponent(path), function(data) { - var deleteResponse = codiad.jsend.parse(data); - if (deleteResponse != 'error') { - var node = $('#file-manager a[data-path="' + path + '"]'); - node.parent('li') - .remove(); - // Close any active files - $('#active-files a') - .each(function() { - var curPath = $(this) - .attr('data-path'); - if (curPath.indexOf(path) == 0) { - codiad.active.remove(curPath); - } - }); - } - codiad.modal.unload(); - }); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Search - ////////////////////////////////////////////////////////////////// - - search: function(path) { - codiad.modal.load(500, this.dialog,{ - action: 'search', - path: path - }); - codiad.modal.load_process.done( function() { - var lastSearched = JSON.parse(localStorage.getItem("lastSearched")); - if(lastSearched) { - $('#modal-content form input[name="search_string"]').val(lastSearched.searchText); - $('#modal-content form input[name="search_file_type"]').val(lastSearched.fileExtension); - $('#modal-content form select[name="search_type"]').val(lastSearched.searchType); - if(lastSearched.searchResults != '') { - $('#filemanager-search-results').slideDown().html(lastSearched.searchResults); - } - } - }); - codiad.modal.hideOverlay(); - var _this = this; - $('#modal-content form') - .live('submit', function(e) { - $('#filemanager-search-processing') - .show(); - e.preventDefault(); - searchString = $('#modal-content form input[name="search_string"]') - .val(); - fileExtensions=$('#modal-content form input[name="search_file_type"]') - .val(); - searchFileType=$.trim(fileExtensions); - if (searchFileType != '') { - //season the string to use in find command - searchFileType = "\\(" + searchFileType.replace(/\s+/g, "\\|") + "\\)"; - } - searchType = $('#modal-content form select[name="search_type"]') - .val(); - $.post(_this.controller + '?action=search&path=' + encodeURIComponent(path) + '&type=' + searchType, { - search_string: searchString, - search_file_type: searchFileType - }, function(data) { - searchResponse = codiad.jsend.parse(data); - var results = ''; - if (searchResponse != 'error') { - $.each(searchResponse.index, function(key, val) { - // Cleanup file format - if(val['file'].substr(-1) == '/') { - val['file'] = val['file'].substr(0, str.length - 1); - } - val['file'] = val['file'].replace('//','/'); - // Add result - results += '
    Line ' + val['line'] + ': ' + val['file'] + '
    '; - }); - $('#filemanager-search-results') - .slideDown() - .html(results); - } else { - $('#filemanager-search-results') - .slideUp(); - } - _this.saveSearchResults(searchString, searchType, fileExtensions, results); - $('#filemanager-search-processing') - .hide(); - }); - }); - }, - - ///////////////////////////////////////////////////////////////// - // saveSearchResults - ///////////////////////////////////////////////////////////////// - saveSearchResults: function(searchText, searchType, fileExtensions, searchResults) { - var lastSearched = { - searchText: searchText, - searchType: searchType, - fileExtension: fileExtensions, - searchResults: searchResults - }; - localStorage.setItem("lastSearched", JSON.stringify(lastSearched)); - }, - ////////////////////////////////////////////////////////////////// - // Upload - ////////////////////////////////////////////////////////////////// - - uploadToNode: function(path) { - codiad.modal.load(500, this.dialogUpload, {path: path}); - }, - - ////////////////////////////////////////////////////////////////// - // Download - ////////////////////////////////////////////////////////////////// - - download: function(path) { - var type = this.getType(path); - $('#download') - .attr('src', 'components/filemanager/download.php?path=' + encodeURIComponent(path) + '&type=' + type); - } - }; - -})(this, jQuery); -"; \ No newline at end of file diff --git a/data/collaborative/shadow/0b1d76a6acf247da79040a128cc3a528 b/data/collaborative/shadow/0b1d76a6acf247da79040a128cc3a528 deleted file mode 100755 index 8c932cc..0000000 --- a/data/collaborative/shadow/0b1d76a6acf247da79040a128cc3a528 +++ /dev/null @@ -1,26 +0,0 @@ -s:445:"/* - -Created: 2018-07-09 -Revised: N/A -Purpose: A template for vanilla js with one library. - -*/ -/*global L*/ -/*global m*/ -/*global v*/ -/*global c*/ - -c.designateFunction = function(eventObject) { - c.updateMetaEvents(eventObject) - let functionQualifiers = { - setToggleFirstButton: [m.source === v.firstButton, m.released], - /* - setXXY: [], - setXXZ: [], - setXYX: [], - setXYY: [], - */ - } - L.runQualifiedFunctions(functionQualifiers, m, v, c) -} -"; \ No newline at end of file diff --git a/data/collaborative/shadow/0bde8ce947815fedb4f056ef7111cc47 b/data/collaborative/shadow/0bde8ce947815fedb4f056ef7111cc47 deleted file mode 100755 index 97cae79..0000000 --- a/data/collaborative/shadow/0bde8ce947815fedb4f056ef7111cc47 +++ /dev/null @@ -1,73 +0,0 @@ -s:1458:"/* - -Created: 2018-07-10 -Modified: N/A -Purpose: To pollute the global scope then initialize our plugin. - -*/ -/* global L - * global m - * global v - * global c -*/ -const m = {} -const v = {} -const c = {} - -///////////////////////////// -c.initialize = function(eventObject) { - c.initializeModel(eventObject) - - L.attachAllElementsById(v) - - let eventTypes = [ - `change`, - `click`, - `dblclick`, - `input`, - `keydown`, - `keyup`, - `load`, - `mousedown`, - `mousemove`, - `mouseout`, - `mouseover`, - `mouseup`, - `offline`, - `online`, - `orientationchange`, - `resize`, - `touchend`, - `touchmove`, - `touchstart`, - ] - - //Clever way: for each member of the eventTypes array, have the window listen for the event - eventTypes.forEach((event)=>{window.addEventListener(event, c.designateFunction)}) - - /* - - let eventType; - for(eventType of eventTypes){ - window.addEventListener(eventType, c.designateFunction) - } - - */ - -} -///////////////////////////// -c.initializeModel = function(eventObject){ - m.eventObject = eventObject //the event object itself - m.source = eventObject.target //where the event took place - m.type = eventObject.type //what the event was - m.id = eventObject.target.id //the id of the element where the event occurred - - //Shortcuts to combine similar mobile and computer events - m.pressed = m.type === `mousedown` || m.type === `touchstart` - m.released = m.type === `mouseup` || m.type === `touchend` - - //et cetera .... - -} - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/0c7b6f96afab6e8fda974eea5a93e5c0 b/data/collaborative/shadow/0c7b6f96afab6e8fda974eea5a93e5c0 deleted file mode 100755 index b9a8658..0000000 --- a/data/collaborative/shadow/0c7b6f96afab6e8fda974eea5a93e5c0 +++ /dev/null @@ -1,30 +0,0 @@ -s:855:" -
    -

    This page will eventually be password protected with a better interface.

    -

    Pages

    - - -

    Info

    - - vncserver -UserPasswdVerifier UnixAuth -
    -"; \ No newline at end of file diff --git a/data/collaborative/shadow/1972a2c94075705efcb5226d1ac9889b b/data/collaborative/shadow/1972a2c94075705efcb5226d1ac9889b deleted file mode 100755 index 8c932cc..0000000 --- a/data/collaborative/shadow/1972a2c94075705efcb5226d1ac9889b +++ /dev/null @@ -1,26 +0,0 @@ -s:445:"/* - -Created: 2018-07-09 -Revised: N/A -Purpose: A template for vanilla js with one library. - -*/ -/*global L*/ -/*global m*/ -/*global v*/ -/*global c*/ - -c.designateFunction = function(eventObject) { - c.updateMetaEvents(eventObject) - let functionQualifiers = { - setToggleFirstButton: [m.source === v.firstButton, m.released], - /* - setXXY: [], - setXXZ: [], - setXYX: [], - setXYY: [], - */ - } - L.runQualifiedFunctions(functionQualifiers, m, v, c) -} -"; \ No newline at end of file diff --git a/data/collaborative/shadow/1dbc3b6b9a38f3065d2276656017f3f9 b/data/collaborative/shadow/1dbc3b6b9a38f3065d2276656017f3f9 deleted file mode 100755 index 7bfe1bc..0000000 --- a/data/collaborative/shadow/1dbc3b6b9a38f3065d2276656017f3f9 +++ /dev/null @@ -1,190 +0,0 @@ -s:4545:" - */ - -class mypit_students { - - const VERSION = '1.0.0'; - - - /** - * Unique identifier for your plugin. - * - * - * The variable name is used as the text domain when internationalizing strings - * of text. Its value should match the Text Domain file header in the main - * plugin file. - * - * @var string - */ - protected $plugin_slug = ''; - - /** - * Instance of this class. - */ - protected static $instance = null; - - /** - * Initialize the plugin by setting localization and loading public scripts and styles. - */ - private function __construct() { - - // Trigger initial - $this->init(); - } - - /** - * Return the plugin slug. - * - * @since 1.0.0 - * - * @return Plugin slug variable. - */ - public function get_plugin_slug() { - return $this->plugin_slug; - } - - /** - * Return an instance of this class. - * - * @since 1.0.0 - * - * @return object A single instance of this class. - */ - public static function get_instance() { - // If the single instance hasn't been set, set it now. - if ( null == self::$instance ) { - self::$instance = new self; - } - - return self::$instance; - } - - /** - * Fired for each blog when the plugin is activated. - * - * @since 1.0.0 - */ - private static function install() { - } - - /** - * Fired for each blog when the plugin is uninstalled. - * - * @since 1.0.0 - */ - private static function uninstall() { - } - - public function check_session() { - - session_start(); - $access = $_SESSION['access']; - $user_check = $_SESSION['username']; - $query = "SELECT `username` FROM `users` WHERE `username`=? AND `access`=?"; - $bind = "ss"; - $bind_vars = array( $user_check, $access ); - - $result = mypit::sql( $query, $bind, $bind_vars, "Error Checking User Session." ); - //$row = mysqli_fetch_array( $sql, MYSQLI_ASSOC ); - //$login_user = $row['username']; - - unset( $query ); - unset( $bind ); - unset( $bind_vars ); - - //echo $user_check; - - if( mysqli_num_rows( $result ) == 0 ) { - - session_destroy(); - header( "Location: ../access?redirect=students" ); - exit; - } - } - - public static function check_privilege_level( $level ) { - - $username = $_SESSION['username']; - $query = "SELECT `privilege_level` FROM `admin_users` WHERE `username`=?"; - $bind = "s"; - $bind_vars = array( $username ); - - $check = mypit::sql( $query, $bind, $bind_vars, "Error Checking User Level" )->fetch_assoc()["privilege_level"]; - - if ( $check == $level ) { - - return( TRUE ); - } else { - - return( FALSE ); - } - } - - /** - * Load the plugin text domain for translation. - * - * @since 1.0.0 - */ - public function init() { - - self::check_session(); - - //Passwords for files that will be required. - define( "U29tZSByYW5kb20gc3RyaW5nIHRoYXQgbm8gb25lIHdpbGwgZXZlciBndWVzcy4gIFRoaXMgd2lsbCBiZSB0aGUgcGFnZXMgZmlsZSBwYXNzd29yZC4gSWYgeW91IHdhbnQgdG8gZGVjb2RlIHRoaXMsIHRoZW4gZ29vZCBmb3IgeW91LiAgVGhpcyBpcyBmb3IgQWJiYXNzJyBhcHBsaWNhdGlvbi4gIEFueSBxdWVzdGlvbnMgYXNrIEFiYmFzcyBvciBlbWFpbCBtZSBhdCB4ZXZpZG9zQGdtYWlsLmNvbS4=", TRUE ); - - //Classes that may be required for pages. - require_once( "./pages.php" ); - - //Check to see if a page is set - if ( isset( $_GET["page"] ) ) { - - $page = $_GET["page"]; - } else { - - $page = "index"; - } - - //Switch through possible pages. - switch( $page ) { - - case( "index" ): - pages::index(); - break; - - case( "my-quizes" ): - pages::my_quizes(); - break; - - case( "take-a-quiz" ): - pages::take_a_quiz(); - break; - - default: - pages::index(); - break; - } - } -}"; \ No newline at end of file diff --git a/data/collaborative/shadow/1fad7d7bf81e5524143caee6f21cdfcf b/data/collaborative/shadow/1fad7d7bf81e5524143caee6f21cdfcf deleted file mode 100755 index 52151ba..0000000 --- a/data/collaborative/shadow/1fad7d7bf81e5524143caee6f21cdfcf +++ /dev/null @@ -1,367 +0,0 @@ -s:6560:"* { - box-sizing: border-box; -} -html{ - padding: 0; - margin: 0; - height: 100%; - width: 100%; - font-family: sans-serif; - background-color: black; - font-size: 30px; - user-select: none; - overflow: hidden; -} - -body{ - position: fixed; - padding: 0; - margin: 0; - height: 100%; - width: 100%; - text-shadow: 0 1px 0 white; - transition: all 0.25s ease; - overflow: hidden; -} - -#background{ - position: fixed; - margin: auto; - top: 0; - bottom: 0; - left: 0; - right: 0; - background-image: url(images/twostalks.gif); - background-size: cover; - background-repeat: no-repeat; - background-position: center; - background-color: black; - transition: all 0.125s ease; -} -#pictureHolder{ - background-color: transparent; -} - -#controlsHolder{ - background-color: transparent; - overflow: hidden; - z-index: 6; -} - -#btnNonStop{ - position: absolute; - border-radius: 50%; - height: calc(calc(2.75vh + 2.75vw) + 4px); - width: calc(calc(2.75vh + 2.75vw) + 4px); - margin: 5px;/*calc(1vh + 1vw);*/ - - background-image: url(images/nsb.png); - background-repeat: no-repeat; - background-size: calc(calc(2vh + 2vw) + 11px) calc(calc(2vh + 2vw) + 11px); - background-position: center ; - background-color: lightblue ; - - box-shadow: 5px 5px 20px black; - opacity: 0.55; - - transition: all 0.25s ease; -} - -#btnNonStop:active{ - box-shadow: inset 5px 5px 20px black; - opacity: 1; -} - - -#controlsBlocker{ - position: fixed; - margin: auto; - top: -25%; - bottom: -22%; - left: 0; - right: 0; - visibility: hidden; - z-index: 9; - /* for testing: - background-color: white; - opacity: 1; - */ -} - -#fileElement{ - border-radius: 0.5rem; - border: 1px solid gray; - box-shadow: 0.15rem 0.15rem 0.30rem #222; - width: 55%; - padding: 2px; - visibility: hidden; -} - -select{ - display: inline-block; - width: 88%; - height: 18%; - text-align: center; - font-family: sans-serif; - font-weight: bold; - font-size: 0.5rem; -} -option{ - display: inline-block; - text-align: center; - font-family: sans-serif; - font-weight: bold; -} - -audio{ - display: inline-block; - position: absolute; - bottom: 0; - left: 50%; - transform: translateX(-50%); - color: gray; - text-shadow: 0 1px 0 white; - width: 99.8%; - border-radius: 0.125rem; - opacity: 0.50; - background-color: transparent; - z-index: -1; -} - -.released{ - box-shadow: 2px 2px 4px black; - font-size:20px; - background: #f8f8f8; - color: #181818; - text-shadow: 0 1px 0 white; -} - -.pressed{ - box-shadow: inset 2px 2px 4px black; - font-size:19.9px; - background: #f2f2f2; - color: black; - text-shadow: 0 2px 0 white; -} - -footer{ - position: fixed; - width: 100%; - height: 0.85rem; - bottom: 0; - left: 50%; - transform: translateX(-50%); - background: lightgray; - overflow: hidden; - text-align: center; - z-index: 10; - visibility: hidden; -} - -#info{ - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - /*font-size: 0.5rem; */ - font-size: calc(1vw + 8.5px); - width: 100%; - font-family: sans-serif; - z-index: -1; -} -#logout{ - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - /*font-size: 0.5rem; */ - font-size: calc(1vw + 8.5px); - width: 100%; - font-family: sans-serif; - -} - -#footerGlass{ - position: fixed; - width: 100%; - height: 100%; - bottom: 0; - left: 50%; - transform: translateX(-50%); -} - -#progressBar{ - position: fixed; - top: 0; - left: 0; - width: 0; - height: 5px; - background-color: red; - border-bottom: 1px solid gray; - border-radius: 2.5px; - z-index: 10; -} - -.portraitTop{ - /* center at top */ - position: absolute; - top: 0; - left: 50%; - transform: translateX(-50%); - - width: 100%; - height: 50%; - text-align: center; - background: transparent; -} - -.portraitBottom{ - /* center at bottom */ - position: absolute; - bottom: 0; - left: 50%; - transform: translateX(-50%); - - width: 100%; - height: 50%; - text-align: center; - background: #eee; - z-index: 5; -} - -.landscapeLeft{ - /* center at left */ - position: absolute; - left: 0; - top: 50%; - transform: translateY(-50%); - - width: 50%; - height: 100%; - text-align: center; - background: transparent; -} - -.landscapeRight{ - /* center at right */ - position: absolute; - right: 0; - top: 50%; - transform: translateY(-50%); - - width: 50%; - height: 100%; - text-align: center; - background: #eee; -} - -.landscapeRightNoPicture{ - position: absolute; - left: 50%; - top: 50%; - transform: translate(-50%, -50%); - - width: 50%; - height: 100%; - text-align: center; - background: #eee; -} - -.passwordWall{ - position: fixed; - margin: auto; - top: 0; - bottom: 0; - left: 0; - right: 0; - background-image: linear-gradient(-20deg, lightblue, white, lightblue); - /* - visibility: visible; - opacity: 1; - */ - visibility: hidden; - opacity: 0; - transition: all 0.37s ease; - z-index: 12; - -} -#passwordHolder{ - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - text-align: center; - border-radius: 0.5rem; - padding: 1rem; - width: 75vw; - font-size: 0.75rem; - background-image: linear-gradient(-20deg, gray, transparent, gray); - box-shadow: 5px 5px 15px black; -} -#passwordInput{ - font-size: 0.70rem; - text-align: center; - width: 78%; -} - -#controlsAssembly{ - position: absolute; - width: 100%; - height: 75%; - padding: 0.25rem; - padding-bottom: 0; - top: 45%; - left: 50%; - transform: translate(-50%, -50%); - text-align: center; - border: 1px solid gray; - border-radius: 0.5rem; - background-color: #eee; - background-color: rgba(238, 238, 238, 0.4); -} - -#controls{ - position: absolute; - top: 50%; - left: 50%; - padding-bottom: 1.5rem; - transform: translate(-50%, -50%); - border: 1px solid gray; - width: 100%; - border-radius: 0.25rem; -} - -.btnWide{ - display: inline-block; - position: absolute; - text-align: center; - vertical-align: middle; - width: 55%; - left: 50%; - transform: translate(-50%, -50%); - box-shadow: 0.275rem 0.275rem 0.40rem gray; - border-radius: 1.5rem; - background-image: linear-gradient(-20deg, hsla(210, 75%, 60%, 0.5), #f5f5f5, hsla(210, 75%, 60%, 0.5)); - cursor: pointer; - outline: none; - height: 18%; - padding: 2px; - line-height: 0.80; -} -#btnPlay{ - width: 55%; - top: 40%; -} -#btnDelete{ - width: 55%; - bottom: -4%; - visibility: hidden; -} - -#documentSelector{ - display: inline-block; - padding: 2px; - box-shadow: 0.275rem 0.275rem 0.40rem #444; - border-radius: 1.5rem; - background-image: linear-gradient(-20deg, hsla(210, 75%, 60%, 0.5), #f5f5f5, hsla(210, 75%, 60%, 0.5)); -}"; \ No newline at end of file diff --git a/data/collaborative/shadow/1fe1266a755f7810fe2c73344d75770e b/data/collaborative/shadow/1fe1266a755f7810fe2c73344d75770e deleted file mode 100755 index 4541553..0000000 --- a/data/collaborative/shadow/1fe1266a755f7810fe2c73344d75770e +++ /dev/null @@ -1,28 +0,0 @@ -s:477:"/* - -Created: 2018-07-10 -Modified: N/A -Purpose: Why did we name this Qualify ... Designate is better - -*/ - -/*global L*/ -/*global m*/ -/*global v*/ -/*global c*/ - -c.designateFunction = function(eventObject){ - c.updateMetaEvents(eventObject) - let functionQualifiers = { - setToggleTestButton: [m.source === v.testButton, m.type === `click`], - /* - setXXY: [], - setXXZ: [], - setXYX: [], - setXYY: [], - */ - } - L.runQualifiedFunctions(functionQualifiers, m, v, c) -} -/////////////// -"; \ No newline at end of file diff --git a/data/collaborative/shadow/22f1d2494993531e6b1a016a8d8b6438 b/data/collaborative/shadow/22f1d2494993531e6b1a016a8d8b6438 deleted file mode 100755 index 2f53002..0000000 --- a/data/collaborative/shadow/22f1d2494993531e6b1a016a8d8b6438 +++ /dev/null @@ -1,76 +0,0 @@ -s:1545:"/* - -Created: 2018-07-10 -Modified: N/A -Purpose: To pollute the global scope then initialize our plugin. - -*/ -/* global L - * global m - * global v - * global c -*/ -const m = {} -const v = {} -const c = {} - -///////////////////////////// -c.initialize = function(eventObject) { - c.initializeModel(eventObject) - - L.attachAllElementsById(v) - - let eventTypes = [ - `change`, - `click`, - `dblclick`, - `input`, - `keydown`, - `keyup`, - `load`, - `mousedown`, - `mousemove`, - `mouseout`, - `mouseover`, - `mouseup`, - `offline`, - `online`, - `orientationchange`, - `resize`, - `touchend`, - `touchmove`, - `touchstart`, - ] - - //Clever way: for each member of the eventTypes array, have the window listen for the event - eventTypes.forEach((event)=>{window.addEventListener(event, c.designateFunction)}) - - /* - - let eventType; - for(eventType of eventTypes){ - window.addEventListener(eventType, c.designateFunction) - } - - */ - -} -///////////////////////////// -c.initializeModel = function(eventObject){ - //define meta events - m.eventObject = eventObject //the event object itself - m.source = eventObject.target //where the event took place - m.type = eventObject.type //what the event was - m.id = eventObject.target.id //the id of the element where the event occurred - - //Shortcuts to combine similar mobile and computer events - m.pressed = m.type === `mousedown` || m.type === `touchstart` - m.released = m.type === `mouseup` || m.type === `touchend` - - //et cetera .... - - //state variable particular to this app - m.testButtonIn = false -} - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/23295112670db74d060930018ea19538 b/data/collaborative/shadow/23295112670db74d060930018ea19538 deleted file mode 100755 index 589c9a6..0000000 --- a/data/collaborative/shadow/23295112670db74d060930018ea19538 +++ /dev/null @@ -1,7 +0,0 @@ -s:100:"/* - -Created: 2018-07-10 -Modified: N/A -Purpose: Extra functions but their Xtra cause we are cool. - -*/"; \ No newline at end of file diff --git a/data/collaborative/shadow/2497b873b6c596aa0da54c628cb5fbd5 b/data/collaborative/shadow/2497b873b6c596aa0da54c628cb5fbd5 deleted file mode 100755 index be40c4d..0000000 --- a/data/collaborative/shadow/2497b873b6c596aa0da54c628cb5fbd5 +++ /dev/null @@ -1,65 +0,0 @@ -s:1296:"/* - -Created: 2018-07-09 -Revised: N/A -Purpose: A template for vanilla js with one library. - -*/ -/*global L*/ -/*global m*/ -/*global v*/ -/*global c*/ -let m = {} -let v = {} -let c = {} - -c.initialize = function(eventObject){ - c.defineStateVariables(eventObject) - - //Use the library to attach all element id's to variables - L.attachAllElementsById(v) - - //collect the names of all the events of interest - let eventTypes = [ - `change`, - `input`, - `keydown`, - `keyup`, - `load`, - `mousedown`, - `mouseover`, - `mouseup`, - `offline`, - `online`, - `orientationchange`, - `resize`, - `touchend`, - `touchmove`, - `touchstart`, - ] - for (let eventType of eventTypes){ - window.addEventListener(eventType, c.designateFunction) - } - -} - -////////////////| function that defines the "state variables" or app state references |/////////// -c.defineStateVariables = function(eventObject){ - ///////| define meta events |///////// - m.eventObject = eventObject - m.source = eventObject.target - m.type = eventObject.type - m.id = eventObject.target.id - - - m.type === 'mousedown' || m.type === `touchstart` - ? m.pressed = true - : m.pressed = false - - m.type === `mouseup` || m.type === `touchend` - ? m.released = true - : m.released = false - - ///////| define state varibales |/////////// - m.buttonIn = false -}"; \ No newline at end of file diff --git a/data/collaborative/shadow/2741708a0ee997fc889e4770f0a3b8ea b/data/collaborative/shadow/2741708a0ee997fc889e4770f0a3b8ea deleted file mode 100755 index 4541553..0000000 --- a/data/collaborative/shadow/2741708a0ee997fc889e4770f0a3b8ea +++ /dev/null @@ -1,28 +0,0 @@ -s:477:"/* - -Created: 2018-07-10 -Modified: N/A -Purpose: Why did we name this Qualify ... Designate is better - -*/ - -/*global L*/ -/*global m*/ -/*global v*/ -/*global c*/ - -c.designateFunction = function(eventObject){ - c.updateMetaEvents(eventObject) - let functionQualifiers = { - setToggleTestButton: [m.source === v.testButton, m.type === `click`], - /* - setXXY: [], - setXXZ: [], - setXYX: [], - setXYY: [], - */ - } - L.runQualifiedFunctions(functionQualifiers, m, v, c) -} -/////////////// -"; \ No newline at end of file diff --git a/data/collaborative/shadow/29a1edb2a360ce477af0bf0ecb5a2447 b/data/collaborative/shadow/29a1edb2a360ce477af0bf0ecb5a2447 deleted file mode 100755 index 4cf9139..0000000 --- a/data/collaborative/shadow/29a1edb2a360ce477af0bf0ecb5a2447 +++ /dev/null @@ -1,18 +0,0 @@ -s:418:"{window.addEventListener(event, c.designateFunction)}) - - /* - - let eventType; - for(eventType of eventTypes){ - window.addEventListener(eventType, c.designateFunction) - } - - */ - -} -///////////////////////////// -c.initializeModel = function(eventObject){ - //define meta events - m.eventObject = eventObject //the event object itself - m.source = eventObject.target //where the event took place - m.type = eventObject.type //what the event was - m.id = eventObject.target.id //the id of the element where the event occurred - - //Shortcuts to combine similar mobile and computer events - m.pressed = m.type === `mousedown` || m.type === `touchstart` - m.released = m.type === `mouseup` || m.type === `touchend` - - //et cetera .... - - //state variable particular to this app - m.testButtonIn = false -} - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/3acf50a01e367e57cdfb32a08ac50fd0 b/data/collaborative/shadow/3acf50a01e367e57cdfb32a08ac50fd0 deleted file mode 100755 index c413c0e..0000000 --- a/data/collaborative/shadow/3acf50a01e367e57cdfb32a08ac50fd0 +++ /dev/null @@ -1,85 +0,0 @@ -s:2598:" - - - - -
    - - - - - - - - - - - -
    - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/3ba13a3d4c97cda98f8675c7bccd82fe b/data/collaborative/shadow/3ba13a3d4c97cda98f8675c7bccd82fe deleted file mode 100755 index 9d1d5e8..0000000 --- a/data/collaborative/shadow/3ba13a3d4c97cda98f8675c7bccd82fe +++ /dev/null @@ -1,27 +0,0 @@ -s:856:"/* - -Created: 2018-07-10 -Modified: N/A -Purpose: Update the MVC - -*/ -/////////////////////////// -c.setToggleTestButton = function(m){ - m.testButtonIn = ! m.testButtonIn -} -c.showToggleTestButton = function(v){ - m.testButtonIn - ? v.testButton.styles(`box-shadow: inset 5px 5px 8px #000000`) - : v.testButton.styles(`box-shadow: 5px 5px 8px #000000`) -} -///////////////////////// -c.updateMetaEvents = function(eventObject){ - m.eventObject = eventObject //the event object itself - m.source = eventObject.target //where the event took place - m.type = eventObject.type //what the event was - m.id = eventObject.target.id //the id of the element where the event occurred - - //Shortcuts to combine similar mobile and computer events - m.pressed = m.type === `mousedown` || m.type === `touchstart` - m.released = m.type === `mouseup` || m.type === `touchend` -}"; \ No newline at end of file diff --git a/data/collaborative/shadow/3cd97ad18d409c51b5578b0b34c80ce6 b/data/collaborative/shadow/3cd97ad18d409c51b5578b0b34c80ce6 deleted file mode 100755 index 31bae3d..0000000 --- a/data/collaborative/shadow/3cd97ad18d409c51b5578b0b34c80ce6 +++ /dev/null @@ -1,236 +0,0 @@ -s:6332:"/*global L*/ -/*global m*/ -/*global v*/ -/*global c*/ -//============================// -////////////////////////////////////////// -c.setResize = (m, callback, arg) => { - m.width = window.innerWidth - m.height = window.innerHeight - arg ? callback(arg) : null -} -c.showResize = ({controlsAssembly, controlsHolder, pictureHolder, player}) => { - m.busyResizing = true - const isPortrait = m.height >= m.width; - if(isPortrait){ - controlsHolder.attribs(`class=portraitBottom`) - pictureHolder.attribs(`class=portraitTop`) - controlsAssembly - .styles - (`height: 60%`) - (`top: 47%`) - const controlsSpecs = controlsHolder.getBoundingClientRect() - v.player.styles(`bottom: ${controlsSpecs.top/1.2}px`)(`top: auto`) - } - else{ - m.noPicture - ? controlsHolder.attribs(`class=landscapeRightNoPicture`) - : controlsHolder.attribs(`class=landscapeRight`) - - pictureHolder.attribs(`class=landscapeLeft`) - controlsAssembly - .styles - (`height: 55%`) - (`top: 20%;`) - const controlsSpecs = controlsHolder.getBoundingClientRect() - v.player.styles(`top: ${controlsSpecs.bottom/1.345}px`)(`bottom: auto`) - } - //password holder - isPortrait - ? v.passwordHolder.styles(`width: 100vw`) - : v.passwordHolder.styles(`width: ${m.MAX_WIDTH}px`) - - setTimeout(()=>{ - m.busyResizing = false - },200) - -} -/////////////////////////////////////// -c.showInfo = ({info}) => { - const msg = `${m.id}: ${m.type}, prior event: ${m.priorType[1]}` - //const msg = `${m.id}: ${m.type}, clicked?: ${m.clicked}` - - info.innerText = msg; -} -////////////////////////////////////////// -c.setPlay = (m, show, arg)=>{ - if(m.busyWithPictureOnly){return} - m.playing = true - arg ? show(arg) : null -} -c.showPlay = ({player})=>{ - if(m.busyWithPictureOnly){return} - c.playChosenSong() -} -////////////////////////////////////////// -c.setPictureOnly = (m, show, arg)=>{ - if(m.busyWithPictureOnly){return} - - m.showPictureOnly = !m.showPictureOnly - m.playing = true - - arg ? show(arg) : null -} -c.showPictureOnly =({background, pictureHolder, controlsBlocker})=>{ - if(m.busyWithPictureOnly){return} - m.busyWithPictureOnly = true - - clearInterval(m.pictureBusyId) - - v.controlsBlocker.styles(`visibility: visible`) - /* - if m.showPictureOnly, bring background to the front - */ - m.showPictureOnly - ? showPictureOnly() - : restorePictureState() - - ///////| helpers |////// - function showPictureOnly(){ - //bring background in front - background.styles(`z-index: 10`) - //show current pictureData (m.pictureData), if there is one - if(!m.noPicture){ - background - .styles - (`background-image: url(${m.pictureData})`) - (`background-size: contain`) - (`background-repeat: no-repeat`) - (`background-position: center`) - } - } - function restorePictureState(){ - //put background behind - background.styles(`z-index: 0`) - //restore default background picture - background - .styles - (`background-image: url(${m.defaultBackground})`) - //(`background-size: cover`) - (`background-repeat: no-repeat`) - (`background-position: center`) - setTimeout(()=>{ - background.styles(`background-size: cover`) - },200) - } - m.pictureBusyId = setTimeout(()=>{ - m.busyWithPictureOnly = false - controlsBlocker.styles(`visibility: hidden`) - }, 500) -} -////////////////////////////////////////// -c.setLogout = (m, show, arg)=>{ - m.loggedIn = false - if(arg && show && typeof show === 'function'){show(arg)} -} -c.showLogout = ({passwordWall, passwordInput})=>{ - if(!m.loggedIn){ - //put up password wall and clear input - passwordWall - .styles - (`visibility: visible`) - (`opacity: 1`) - passwordInput.value = `` - passwordInput.focus() - // lower access level - const killer = new XMLHttpRequest() - killer.open('GET', `php/logout.php`) - killer.send() - killer.onload = ()=>{ - if(killer.status === 200){ - killer.responseText === 'allow' - ? m.loggedIn = true - : m.loggedIn = false - } - else{ - const msg = `Trouble logging out.` - console.log(msg) - alert(msg) - m.loggedIn = false - } - } - killer.onerror = ()=>{ - const msg = `Trouble connecting to server.` - console.log(msg) - alert(msg) - m.loggedIn = false - } - } -} -////////////////////////////////////////// -c.setLogin = (m, show, arg)=>{ - const postman = new XMLHttpRequest() - const envelope = new FormData() - envelope.append(`userPassword`, v.passwordInput.value) - postman.open(`POST`, `php/login.php`) - postman.send(envelope) - //--------------------// - postman.onload = ()=>{ - if(postman.status === 200){ - postman.responseText === 'allow' - ? m.loggedIn = true - : m.loggedIn = false - } - else{ - const msg = `Trouble checking password.` - console.log(msg) - alert(msg) - m.loggedIn = false - } - } - postman.onerror = ()=>{ - const msg = `Trouble connecting to server.` - console.log(msg) - alert(msg) - m.loggedIn = false - } - //--------------------// - if(arg && show && typeof show === 'function'){show(arg)} -} -c.showLogin = ({passwordWall, passwordInput})=>{ - if(m.loggedIn){ - //bring down wall - passwordWall - .styles - (`visibility: hidden`) - (`opacity: 0`) - passwordInput.value = `` - //get music list from server - c.getFileList() - } -} -////////////////////////////////////////// -c.setToggleNonStop = (m)=>{ - m.nonStop = !m.nonStop -} -c.showToggleNonStop = (v)=>{ - m.nonStop - ?(()=>{ - v.btnNonStop - .styles - (`box-shadow: inset 3px 3px 15px black`) - (`opacity: 1`) - })() - :(()=>{ - v.btnNonStop - .styles - (`box-shadow: 3px 3px 15px black`) - (`opacity: 0.55`) - })() - - /* - If non-stop: - 1. player should be in autoplay - 2. end event should increment selected index (or set it to 0) - */ - m.nonStop - ? v.player.attribs(`autoplay=autoplay`) - : v.player.attribs(`autoplay=false`) -} - -////////////////////////////////////////// -////////////////////////////////////////// -////////////////////////////////////////// -////////////////////////////////////////// -////////////////////////////////////////// -//////////////////////////////////////////"; \ No newline at end of file diff --git a/data/collaborative/shadow/3e7c9f851da2aad425970b0be26f77ac b/data/collaborative/shadow/3e7c9f851da2aad425970b0be26f77ac deleted file mode 100755 index 8285b39..0000000 --- a/data/collaborative/shadow/3e7c9f851da2aad425970b0be26f77ac +++ /dev/null @@ -1,53 +0,0 @@ -s:2353:" - - -
    - ☰ Menu -
    - - - - - "; \ No newline at end of file diff --git a/data/collaborative/shadow/41118f97725e869c87455be694a53fe5 b/data/collaborative/shadow/41118f97725e869c87455be694a53fe5 deleted file mode 100755 index 1a0c317..0000000 --- a/data/collaborative/shadow/41118f97725e869c87455be694a53fe5 +++ /dev/null @@ -1,55 +0,0 @@ -s:1638:"s:1628:"
    ' + i18n("Contacting GitHub...") + '

    '); - }, - - ////////////////////////////////////////////////////////////////// - // Download Archive - ////////////////////////////////////////////////////////////////// - - download: function () { - var _this = this; - var archive = $('#modal-content form input[name="archive"]') - .val(); - $('#download') - .attr('src', archive); - $.get(_this.controller + '?action=clear'); - codiad.modal.unload(); - } - - }; - -})(this, jQuery);"; \ No newline at end of file diff --git a/data/collaborative/shadow/49f589063ce4ea454204ce70b134a893 b/data/collaborative/shadow/49f589063ce4ea454204ce70b134a893 deleted file mode 100755 index 23485aa..0000000 --- a/data/collaborative/shadow/49f589063ce4ea454204ce70b134a893 +++ /dev/null @@ -1,1005 +0,0 @@ -s:37536:"/* - * Copyright (c) Codiad & Kent Safranski (codiad.com), distributed - * as-is and without warranty under the MIT License. See - * [root]/license.txt for more. This information must remain intact. - */ - -(function(global, $) { - - var EditSession = ace.require('ace/edit_session') - .EditSession; - var UndoManager = ace.require('ace/undomanager') - .UndoManager; - - var codiad = global.codiad; - - $(function() { - codiad.active.init(); - }); - - ////////////////////////////////////////////////////////////////// - // - // Active Files Component for Codiad - // --------------------------------- - // Track and manage EditSession instaces of files being edited. - // - ////////////////////////////////////////////////////////////////// - - codiad.active = { - - controller: 'components/active/controller.php', - - // Path to EditSession instance mapping - sessions: {}, - - // History of opened files - history: [], - - ////////////////////////////////////////////////////////////////// - // - // Check if a file is open. - // - // Parameters: - // path - {String} - // - ////////////////////////////////////////////////////////////////// - - isOpen: function(path) { - return !!this.sessions[path]; - }, - - open: function(path, content, mtime, inBackground, focus) { - if (focus === undefined) { - focus = true; - } - - var _this = this; - - if (this.isOpen(path)) { - if(focus) this.focus(path); - return; - } - var ext = codiad.filemanager.getExtension(path); - var mode = codiad.editor.selectMode(ext); - - var fn = function() { - //var Mode = require('ace/mode/' + mode) - // .Mode; - - // TODO: Ask for user confirmation before recovering - // And maybe show a diff - var draft = _this.checkDraft(path); - if (draft) { - content = draft; - codiad.message.success(i18n('Recovered unsaved content for: ') + path); - } - - //var session = new EditSession(content, new Mode()); - var session = new EditSession(content); - session.setMode("ace/mode/" + mode); - session.setUndoManager(new UndoManager()); - - session.path = path; - session.serverMTime = mtime; - _this.sessions[path] = session; - session.untainted = content.slice(0); - if (!inBackground && focus) { - codiad.editor.setSession(session); - } - _this.add(path, session, focus); - /* Notify listeners. */ - amplify.publish('active.onOpen', path); - }; - - // Assuming the mode file has no dependencies - $.loadScript('components/editor/ace-editor/mode-' + mode + '.js', - fn); - }, - - init: function() { - - var _this = this; - - _this.initTabDropdownMenu(); - _this.updateTabDropdownVisibility(); - - // Focus from list. - $('#list-active-files a') - .live('click', function(e) { - e.stopPropagation(); - _this.focus($(this).parent('li').attr('data-path')); - }); - - // Focus on left button click from dropdown. - $('#dropdown-list-active-files a') - .live('click', function(e) { - if(e.which == 1) { - /* Do not stop propagation of the event, - * it will be catch by the dropdown menu - * and close it. */ - _this.focus($(this).parent('li').attr('data-path')); - } - }); - - // Focus on left button mousedown from tab. - $('#tab-list-active-files li.tab-item>a.label') - .live('mousedown', function(e) { - if(e.which == 1) { - e.stopPropagation(); - _this.focus($(this).parent('li').attr('data-path')); - } - }); - - // Remove from list. - $('#list-active-files a>span') - .live('click', function(e) { - e.stopPropagation(); - _this.remove($(this) - .parent('a') - .parent('li') - .attr('data-path')); - }); - - // Remove from dropdown. - $('#dropdown-list-active-files a>span') - .live('click', function(e) { - e.stopPropagation(); - /* Get the active editor before removing anything. Remove the - * tab, then put back the focus on the previously active - * editor if it was not removed. */ - var activePath = _this.getPath(); - var pathToRemove = $(this).parents('li').attr('data-path'); - _this.remove(pathToRemove); - if (activePath !== null && activePath !== pathToRemove) { - _this.focus(activePath); - } - _this.updateTabDropdownVisibility(); - }); - - // Remove from tab. - $('#tab-list-active-files a.close') - .live('click', function(e) { - e.stopPropagation(); - /* Get the active editor before removing anything. Remove the - * tab, then put back the focus on the previously active - * editor if it was not removed. */ - var activePath = _this.getPath(); - var pathToRemove = $(this).parent('li').attr('data-path'); - _this.remove(pathToRemove); - if (activePath !== null && activePath !== pathToRemove) { - _this.focus(activePath); - } - _this.updateTabDropdownVisibility(); - }); - - // Remove from middle button click on dropdown. - $('#dropdown-list-active-files li') - .live('mouseup', function(e) { - if (e.which == 2) { - e.stopPropagation(); - /* Get the active editor before removing anything. Remove the - * tab, then put back the focus on the previously active - * editor if it was not removed. */ - var activePath = _this.getPath(); - var pathToRemove = $(this).attr('data-path'); - _this.remove(pathToRemove); - if (activePath !== null && activePath !== pathToRemove) { - _this.focus(activePath); - } - _this.updateTabDropdownVisibility(); - } - }); - - // Remove from middle button click on tab. - $('.tab-item') - .live('mouseup', function(e) { - if (e.which == 2) { - e.stopPropagation(); - /* Get the active editor before removing anything. Remove the - * tab, then put back the focus on the previously active - * editor if it was not removed. */ - var activePath = _this.getPath(); - var pathToRemove = $(this).attr('data-path'); - _this.remove(pathToRemove); - if (activePath !== null && activePath !== pathToRemove) { - _this.focus(activePath); - } - _this.updateTabDropdownVisibility(); - } - }); - - // Make list sortable - $('#list-active-files') - .sortable({ - placeholder: 'active-sort-placeholder', - tolerance: 'intersect', - start: function(e, ui) { - ui.placeholder.height(ui.item.height()); - } - }); - - // Make dropdown sortable. - $('#dropdown-list-active-files') - .sortable({ - axis: 'y', - tolerance: 'pointer', - start: function(e, ui) { - ui.placeholder.height(ui.item.height()); - } - }); - - // Make tabs sortable. - $('#tab-list-active-files') - .sortable({ - items: '> li', - axis: 'x', - tolerance: 'pointer', - containment: 'parent', - start: function(e, ui) { - ui.placeholder.css('background', 'transparent'); - ui.helper.css('width', '200px'); - }, - stop: function(e, ui) { - // Reset css - ui.item.css('z-index', '') - ui.item.css('position', '') - } - }); - /* Woaw, so tricky! At initialization, the tab-list is empty, so - * it is not marked as float so it is not detected as an horizontal - * list by the sortable plugin. Workaround is to mark it as - * floating at initialization time. See bug report - * http://bugs.jqueryui.com/ticket/6702. */ - $('#tab-list-active-files').data('sortable').floating = true; - - // Open saved-state active files on load - $.get(_this.controller + '?action=list', function(data) { - var listResponse = codiad.jsend.parse(data); - if (listResponse !== null) { - $.each(listResponse, function(index, data) { - codiad.filemanager.openFile(data.path, data.focused); - }); - } - }); - - // Prompt if a user tries to close window without saving all filess - window.onbeforeunload = function(e) { - if ($('#list-active-files li.changed') - .length > 0) { - var e = e || window.event; - var errMsg = i18n('You have unsaved files.'); - - // For IE and Firefox prior to version 4 - if (e) { - e.returnValue = errMsg; - } - - // For rest - return errMsg; - } - }; - }, - - ////////////////////////////////////////////////////////////////// - // Drafts - ////////////////////////////////////////////////////////////////// - - checkDraft: function(path) { - var draft = localStorage.getItem(path); - if (draft !== null) { - return draft; - } else { - return false; - } - }, - - removeDraft: function(path) { - localStorage.removeItem(path); - }, - - ////////////////////////////////////////////////////////////////// - // Get active editor path - ////////////////////////////////////////////////////////////////// - - getPath: function() { - try { - return codiad.editor.getActive() - .getSession() - .path; - } catch (e) { - return null; - } - }, - - ////////////////////////////////////////////////////////////////// - // Check if opened by another user - ////////////////////////////////////////////////////////////////// - - check: function(path) { - $.get(this.controller + '?action=check&path=' + encodeURIComponent(path), - - function(data) { - var checkResponse = codiad.jsend.parse(data); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Add newly opened file to list - ////////////////////////////////////////////////////////////////// - - add: function(path, session, focus) { - if (focus === undefined) { - focus = true; - } - - var listThumb = this.createListThumb(path); - session.listThumb = listThumb; - $('#list-active-files').append(listThumb); - - /* If the tab list would overflow with the new tab. Move the - * first tab to dropdown, then add a new tab. */ - if (this.isTabListOverflowed(true)) { - var tab = $('#tab-list-active-files li:first-child'); - this.moveTabToDropdownMenu(tab); - } - - var tabThumb = this.createTabThumb(path); - $('#tab-list-active-files').append(tabThumb); - session.tabThumb = tabThumb; - - this.updateTabDropdownVisibility(); - - $.get(this.controller + '?action=add&path=' + encodeURIComponent(path)); - - if(focus) { - this.focus(path); - } - - // Mark draft as changed - if (this.checkDraft(path)) { - this.markChanged(path); - } - }, - - ////////////////////////////////////////////////////////////////// - // Focus on opened file - ////////////////////////////////////////////////////////////////// - - focus: function(path, moveToTabList) { - if (moveToTabList === undefined) { - moveToTabList = true; - } - - this.highlightEntry(path, moveToTabList); - - if(path != this.getPath()) { - codiad.editor.setSession(this.sessions[path]); - this.history.push(path); - $.get(this.controller, {'action':'focused', 'path':path}); - } - - /* Check for users registered on the file. */ - this.check(path); - - /* Notify listeners. */ - amplify.publish('active.onFocus', path); - }, - - highlightEntry: function(path, moveToTabList) { - if (moveToTabList === undefined) { - moveToTabList = true; - } - - $('#list-active-files li') - .removeClass('active'); - - $('#tab-list-active-files li') - .removeClass('active'); - - $('#dropdown-list-active-files li') - .removeClass('active'); - - var session = this.sessions[path]; - - if($('#dropdown-list-active-files').has(session.tabThumb).length > 0) { - if(moveToTabList) { - /* Get the menu item as a tab, and put the last tab in - * dropdown. */ - var menuItem = session.tabThumb; - this.moveDropdownMenuItemToTab(menuItem, true); - - var tab = $('#tab-list-active-files li:last-child'); - this.moveTabToDropdownMenu(tab); - } else { - /* Show the dropdown menu if needed */ - this.showTabDropdownMenu(); - } - } - else if(this.history.length > 0) { - var prevPath = this.history[this.history.length-1]; - var prevSession = this.sessions[prevPath]; - if($('#dropdown-list-active-files').has(prevSession.tabThumb).length > 0) { - /* Hide the dropdown menu if needed */ - this.hideTabDropdownMenu(); - } - } - - session.tabThumb.addClass('active'); - session.listThumb.addClass('active'); - }, - - ////////////////////////////////////////////////////////////////// - // Mark changed - ////////////////////////////////////////////////////////////////// - - markChanged: function(path) { - this.sessions[path].listThumb.addClass('changed'); - this.sessions[path].tabThumb.addClass('changed'); - }, - - ////////////////////////////////////////////////////////////////// - // Save active editor - ////////////////////////////////////////////////////////////////// - - save: function(path) { - /* Notify listeners. */ - amplify.publish('active.onSave', path); - - var _this = this; - if ((path && !this.isOpen(path)) || (!path && !codiad.editor.getActive())) { - codiad.message.error(i18n('No Open Files to save')); - return; - } - var session; - if (path) session = this.sessions[path]; - else session = codiad.editor.getActive() - .getSession(); - var content = session.getValue(); - var path = session.path; - var handleSuccess = function(mtime){ - var session = codiad.active.sessions[path]; - if(typeof session != 'undefined') { - session.untainted = newContent; - session.serverMTime = mtime; - if (session.listThumb) session.listThumb.removeClass('changed'); - if (session.tabThumb) session.tabThumb.removeClass('changed'); - } - _this.removeDraft(path); - } - // Replicate the current content so as to avoid - // discrepancies due to content changes during - // computation of diff - - var newContent = content.slice(0); - if (session.serverMTime && session.untainted){ - codiad.workerManager.addTask({ - taskType: 'diff', - id: path, - original: session.untainted, - changed: newContent - }, function(success, patch){ - if (success) { - codiad.filemanager.savePatch(path, patch, session.serverMTime, { - success: handleSuccess - }); - } else { - codiad.filemanager.saveFile(path, newContent, { - success: handleSuccess - }); - } - }, this); - } else { - codiad.filemanager.saveFile(path, newContent, { - success: handleSuccess - }); - } - }, - - ////////////////////////////////////////////////////////////////// - // Save all files - ////////////////////////////////////////////////////////////////// - - saveAll: function() { - var _this = this; - for(var session in _this.sessions) { - if (_this.sessions[session].listThumb.hasClass('changed')) { - codiad.active.save(session); - } - } - }, - - ////////////////////////////////////////////////////////////////// - // Remove file - ////////////////////////////////////////////////////////////////// - - remove: function(path) { - if (!this.isOpen(path)) return; - var session = this.sessions[path]; - var closeFile = true; - if (session.listThumb.hasClass('changed')) { - codiad.modal.load(450, 'components/active/dialog.php?action=confirm&path=' + encodeURIComponent(path)); - closeFile = false; - } - if (closeFile) { - this.close(path); - } - }, - - removeAll: function(discard) { - discard = discard || false; - /* Notify listeners. */ - amplify.publish('active.onRemoveAll'); - - var _this = this; - var changed = false; - - var opentabs = new Array(); - for(var session in _this.sessions) { - opentabs[session] = session; - if (_this.sessions[session].listThumb.hasClass('changed')) { - changed = true; - } - } - if(changed && !discard) { - codiad.modal.load(450, 'components/active/dialog.php?action=confirmAll'); - return; - } - - for(var tab in opentabs) { - var session = this.sessions[tab]; - - session.tabThumb.remove(); - _this.updateTabDropdownVisibility(); - - session.listThumb.remove(); - - /* Remove closed path from history */ - var history = []; - $.each(this.history, function(index) { - if(this != tab) history.push(this); - }) - this.history = history - - delete this.sessions[tab]; - this.removeDraft(tab); - } - codiad.editor.exterminate(); - $('#list-active-files').html(''); - $.get(this.controller + '?action=removeall'); - }, - - close: function(path) { - /* Notify listeners. */ - amplify.publish('active.onClose', path); - - var _this = this; - var session = this.sessions[path]; - - /* Animate only if the tabThumb if a tab, not a dropdown item. */ - if(session.tabThumb.hasClass('tab-item')) { - session.tabThumb.css({'z-index': 1}); - session.tabThumb.animate({ - top: $('#editor-top-bar').height() + 'px' - }, 300, function() { - session.tabThumb.remove(); - _this.updateTabDropdownVisibility(); - }); - } else { - session.tabThumb.remove(); - _this.updateTabDropdownVisibility(); - } - - session.listThumb.remove(); - - /* Remove closed path from history */ - var history = []; - $.each(this.history, function(index) { - if(this != path) history.push(this); - }) - this.history = history - - /* Select all the tab tumbs except the one which is to be removed. */ - var tabThumbs = $('#tab-list-active-files li[data-path!="' + path + '"]'); - - if (tabThumbs.length == 0) { - codiad.editor.exterminate(); - } else { - - var nextPath = ''; - if(this.history.length > 0) { - nextPath = this.history[this.history.length - 1]; - } else { - nextPath = $(tabThumbs[0]).attr('data-path'); - } - var nextSession = this.sessions[nextPath]; - codiad.editor.removeSession(session, nextSession); - - this.focus(nextPath); - } - delete this.sessions[path]; - $.get(this.controller + '?action=remove&path=' + encodeURIComponent(path)); - this.removeDraft(path); - }, - - ////////////////////////////////////////////////////////////////// - // Process rename - ////////////////////////////////////////////////////////////////// - - rename: function(oldPath, newPath) { - var switchSessions = function(oldPath, newPath) { - var tabThumb = this.sessions[oldPath].tabThumb; - tabThumb.attr('data-path', newPath); - var title = newPath; - if (codiad.project.isAbsPath(newPath)) { - title = newPath.substring(1); - } - tabThumb.find('.label') - .text(title); - this.sessions[newPath] = this.sessions[oldPath]; - this.sessions[newPath].path = newPath; - delete this.sessions[oldPath]; - //Rename history - for (var i = 0; i < this.history.length; i++) { - if (this.history[i] === oldPath) { - this.history[i] = newPath; - } - } - }; - if (this.sessions[oldPath]) { - // A file was renamed - switchSessions.apply(this, [oldPath, newPath]); - // pass new sessions instance to setactive - for (var k = 0; k < codiad.editor.instances.length; k++) { - if (codiad.editor.instances[k].getSession().path === newPath) { - codiad.editor.setActive(codiad.editor.instances[k]); - } - } - - var newSession = this.sessions[newPath]; - - // Change Editor Mode - var ext = codiad.filemanager.getExtension(newPath); - var mode = codiad.editor.selectMode(ext); - - // handle async mode change - var fn = function() { - codiad.editor.setModeDisplay(newSession); - newSession.removeListener('changeMode', fn); - } - - newSession.on("changeMode", fn); - newSession.setMode("ace/mode/" + mode); - } else { - // A folder was renamed - var newKey; - for (var key in this.sessions) { - newKey = key.replace(oldPath, newPath); - if (newKey !== key) { - switchSessions.apply(this, [key, newKey]); - } - } - } - $.get(this.controller + '?action=rename&old_path=' + encodeURIComponent(oldPath) + '&new_path=' + encodeURIComponent(newPath), function() { - /* Notify listeners. */ - amplify.publish('active.onRename', {"oldPath": oldPath, "newPath": newPath}); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Open in Browser - ////////////////////////////////////////////////////////////////// - - openInBrowser: function() { - var path = this.getPath(); - if (path) { - codiad.filemanager.openInBrowser(path); - } else { - codiad.message.error('No Open Files'); - } - }, - - ////////////////////////////////////////////////////////////////// - // Get Selected Text - ////////////////////////////////////////////////////////////////// - - getSelectedText: function() { - var path = this.getPath(); - var session = this.sessions[path]; - - if (path && this.isOpen(path)) { - return session.getTextRange( - codiad.editor.getActive() - .getSelectionRange()); - } else { - codiad.message.error(i18n('No Open Files or Selected Text')); - } - }, - - ////////////////////////////////////////////////////////////////// - // Insert Text - ////////////////////////////////////////////////////////////////// - - insertText: function(val) { - codiad.editor.getActive() - .insert(val); - }, - - ////////////////////////////////////////////////////////////////// - // Goto Line - ////////////////////////////////////////////////////////////////// - - gotoLine: function(line) { - codiad.editor.getActive() - .gotoLine(line, 0, true); - }, - - ////////////////////////////////////////////////////////////////// - // Move Up (Key Combo) - ////////////////////////////////////////////////////////////////// - - move: function(dir) { - - var num = $('#tab-list-active-files li').length; - if (num === 0) return; - - var newActive = null; - var active = null; - - if (dir == 'up') { - - // If active is in the tab list - active = $('#tab-list-active-files li.active'); - if(active.length > 0) { - // Previous or rotate to the end - newActive = active.prev('li'); - if (newActive.length === 0) { - newActive = $('#dropdown-list-active-files li:last-child') - if (newActive.length === 0) { - newActive = $('#tab-list-active-files li:last-child') - } - } - } - - // If active is in the dropdown list - active = $('#dropdown-list-active-files li.active'); - if(active.length > 0) { - // Previous - newActive = active.prev('li'); - if (newActive.length === 0) { - newActive = $('#tab-list-active-files li:last-child') - } - } - - } else { - - // If active is in the tab list - active = $('#tab-list-active-files li.active'); - if(active.length > 0) { - // Next or rotate to the beginning - newActive = active.next('li'); - if (newActive.length === 0) { - newActive = $('#dropdown-list-active-files li:first-child'); - if (newActive.length === 0) { - newActive = $('#tab-list-active-files li:first-child') - } - } - } - - // If active is in the dropdown list - active = $('#dropdown-list-active-files li.active'); - if(active.length > 0) { - // Next or rotate to the beginning - newActive = active.next('li'); - if (newActive.length === 0) { - newActive = $('#tab-list-active-files li:first-child') - } - } - - } - - if(newActive) this.focus(newActive.attr('data-path'), false); - }, - - ////////////////////////////////////////////////////////////////// - // Dropdown Menu - ////////////////////////////////////////////////////////////////// - - initTabDropdownMenu: function() { - var _this = this; - - var menu = $('#dropdown-list-active-files'); - var button = $('#tab-dropdown-button'); - var closebutton = $('#tab-close-button'); - - menu.appendTo($('body')); - - button.click(function(e) { - e.stopPropagation(); - _this.toggleTabDropdownMenu(); - }); - - closebutton.click(function(e) { - e.stopPropagation(); - _this.removeAll(); - }); - }, - - showTabDropdownMenu: function() { - var menu = $('#dropdown-list-active-files'); - if(!menu.is(':visible')) this.toggleTabDropdownMenu(); - }, - - hideTabDropdownMenu: function() { - var menu = $('#dropdown-list-active-files'); - if(menu.is(':visible')) this.toggleTabDropdownMenu(); - }, - - toggleTabDropdownMenu: function() { - var _this = this; - var menu = $('#dropdown-list-active-files'); - - menu.css({ - top: $("#editor-top-bar").height() + 'px', - right: '20px', - width: '200px' - }); - - menu.slideToggle('fast'); - - if(menu.is(':visible')) { - // handle click-out autoclosing - var fn = function() { - menu.hide(); - $(window).off('click', fn) - } - $(window).on('click', fn); - } - }, - - moveTabToDropdownMenu: function(tab, prepend) { - if (prepend === undefined) { - prepend = false; - } - - tab.remove(); - path = tab.attr('data-path'); - - var tabThumb = this.createMenuItemThumb(path); - if(prepend) $('#dropdown-list-active-files').prepend(tabThumb); - else $('#dropdown-list-active-files').append(tabThumb); - - if(tab.hasClass("changed")) { - tabThumb.addClass("changed"); - } - - if(tab.hasClass("active")) { - tabThumb.addClass("active"); - } - - this.sessions[path].tabThumb = tabThumb; - }, - - moveDropdownMenuItemToTab: function(menuItem, prepend) { - if (prepend === undefined) { - prepend = false; - } - - menuItem.remove(); - path = menuItem.attr('data-path'); - - var tabThumb = this.createTabThumb(path); - if(prepend) $('#tab-list-active-files').prepend(tabThumb); - else $('#tab-list-active-files').append(tabThumb); - - if(menuItem.hasClass("changed")) { - tabThumb.addClass("changed"); - } - - if(menuItem.hasClass("active")) { - tabThumb.addClass("active"); - } - - this.sessions[path].tabThumb = tabThumb; - }, - - isTabListOverflowed: function(includeFictiveTab) { - if (includeFictiveTab === undefined) { - includeFictiveTab = false; - } - - var tabs = $('#tab-list-active-files li'); - var count = tabs.length - if (includeFictiveTab) count += 1; - if (count <= 1) return false; - - var width = 0; - tabs.each(function(index) { - width += $(this).outerWidth(true); - }) - if (includeFictiveTab) { - width += $(tabs[tabs.length-1]).outerWidth(true); - } - - /* If we subtract the width of the left side bar, of the right side - * bar handle and of the tab dropdown handle to the window width, - * do we have enough room for the tab list? Its kind of complicated - * to handle all the offsets, so afterwards we add a fixed offset - * just t be sure. */ - var lsbarWidth = $(".sidebar-handle").width(); - if (codiad.sidebars.isLeftSidebarOpen) { - lsbarWidth = $("#sb-left").width(); - } - - var rsbarWidth = $(".sidebar-handle").width(); - if (codiad.sidebars.isRightSidebarOpen) { - rsbarWidth = $("#sb-right").width(); - } - - var tabListWidth = $("#tab-list-active-files").width(); - var dropdownWidth = $('#tab-dropdown').width(); - var closeWidth = $('#tab-close').width(); - var room = window.innerWidth - lsbarWidth - rsbarWidth - dropdownWidth - closeWidth - width - 30; - return (room < 0); - }, - - updateTabDropdownVisibility: function() { - while(this.isTabListOverflowed()) { - var tab = $('#tab-list-active-files li:last-child'); - if (tab.length == 1) this.moveTabToDropdownMenu(tab, true); - else break; - } - - while(!this.isTabListOverflowed(true)) { - var menuItem = $('#dropdown-list-active-files li:first-child'); - if (menuItem.length == 1) this.moveDropdownMenuItemToTab(menuItem); - else break; - } - - if ($('#dropdown-list-active-files li').length > 0) { - $('#tab-dropdown').show(); - } else { - $('#tab-dropdown').hide(); - // Be sure to hide the menu if it is opened. - $('#dropdown-list-active-files').hide(); - } - if ($('#tab-list-active-files li').length > 1) { - $('#tab-close').show(); - } else { - $('#tab-close').hide(); - } - }, - - ////////////////////////////////////////////////////////////////// - // Factory - ////////////////////////////////////////////////////////////////// - - splitDirectoryAndFileName: function(path) { - var index = path.lastIndexOf('/'); - return { - fileName: path.substring(index + 1), - directory: (path.indexOf('/') == 0)? path.substring(1, index + 1):path.substring(0, index + 1) - } - }, - - createListThumb: function(path) { - return $('
  • ' + path + '
  • '); - }, - - createTabThumb: function(path) { - split = this.splitDirectoryAndFileName(path); - return $('
  • ' - + split.directory + '' + split.fileName + '' - + 'x
  • '); - }, - - createMenuItemThumb: function(path) { - split = this.splitDirectoryAndFileName(path); - return $('
  • ' - + split.directory + '' + split.fileName + '' - + '
  • '); - }, - - }; - -})(this, jQuery); -"; \ No newline at end of file diff --git a/data/collaborative/shadow/4b5e696279610e8b11147b869777b685 b/data/collaborative/shadow/4b5e696279610e8b11147b869777b685 deleted file mode 100755 index 5527786..0000000 --- a/data/collaborative/shadow/4b5e696279610e8b11147b869777b685 +++ /dev/null @@ -1,16 +0,0 @@ -s:1065:"lastname, firstname, phone, email, group, photo -Abdulmalik, Abbas, 610-357-2710, aabdulmalik@pit.edu, group, photo -Smith, Frank, 610-331-8295, 17Smith7920@pit.edu, group, photo -Fletcher, Thomas, 484-842-1021, 17Fletch7785@pit.edu, group, photo -Thollie, Ibrahim, 619-532-2344, 17Tholli8829@pit.edu, group, photo -Philmore, Mitchell, 215-520-1775, 17Philmo6088@pit.edu, group, photo -Beresford, Trevor, 610-490-0365, 17Beresf7817@pit.edu, group, photo -Hunsinger, Eric, 610-883-7292, 18Hunsin7743@pit.edu, group, photo -Tarawali, Abdul Salam, 484-477-5760, 18Tarawa6787@pit.edu, group, photo -Kupa, Shpetim, 215-909-3598, 15Kupa8824@pit.edu, group, photo -Dilligard, Deon, 484-347-4019, 16Dillig7628@pit.edu, group, photo -Brown, Isaac, 717-353-3888, 17Brown9053@pit.edu, group, photo -Anderson, Courtney, 267-414-6146, 17Anders7872@pit.edu, group, photo -Cammauf, Carter, 717-341-4278, 18Cammau7716@pit.edu, group, photo -Itchon, Lester, 610-883-7341, 17Itchon7808@pit.edu, group, photo -Povey, Stephen, 484-326-7389, 17Povey6023@pit.edu, group, photo"; \ No newline at end of file diff --git a/data/collaborative/shadow/4e259f0bb87191d1f975f535dae106ea b/data/collaborative/shadow/4e259f0bb87191d1f975f535dae106ea deleted file mode 100755 index 64fb9fd..0000000 --- a/data/collaborative/shadow/4e259f0bb87191d1f975f535dae106ea +++ /dev/null @@ -1,59 +0,0 @@ -s:1168:"/* - * Place copyright or other info here... - */ - -(function(global, $){ - - // Define core - var codiad = global.codiad, - scripts= document.getElementsByTagName('script'), - path = scripts[scripts.length-1].src.split('?')[0], - curpath = path.split('/').slice(0, -1).join('/')+'/'; - - // Instantiates plugin - $(function() { - codiad.tela_auto_save.init(); - }); - - codiad.tela_auto_save = { - - // Allows relative `this.path` linkage - path: curpath, - - init: function() { - - // Start your plugin here... - let editor = document.getElementsByClassName( 'ace_content' )[0]; - let auto_save_trigger = setInterval( this.auto_save, 500 ); - }, - - /** - * - * This is where the core functionality goes, any call, references, - * script-loads, etc... - * - */ - - auto_save: function() { - - let tabs = document.getElementsByClassName( "tab-item" ); - tabs = Array.from( tabs ); - tabs.forEach( function( m, i, a ) { - - // M = Current entry - // I = Index as integer - // A = Entire array - - if ( m.classList.contains( "active" ) ) { - - m.classList.remove( "changed" ) - } - }); - - codiad.active.save; - } - - }; - -})(this, jQuery); -"; \ No newline at end of file diff --git a/data/collaborative/shadow/51108580d8b1830f9d7e48021d6bde46 b/data/collaborative/shadow/51108580d8b1830f9d7e48021d6bde46 deleted file mode 100755 index 73631c9..0000000 --- a/data/collaborative/shadow/51108580d8b1830f9d7e48021d6bde46 +++ /dev/null @@ -1,33 +0,0 @@ -s:699:" -
    - -

    Looking for a quiz? Select one of the teachers below to view their active quizzes.

    - - - -
    "; \ No newline at end of file diff --git a/data/collaborative/shadow/51640228b7c95ec21668deae8e14fd37 b/data/collaborative/shadow/51640228b7c95ec21668deae8e14fd37 deleted file mode 100755 index b7d7165..0000000 --- a/data/collaborative/shadow/51640228b7c95ec21668deae8e14fd37 +++ /dev/null @@ -1,33 +0,0 @@ -s:987:" - - - Mobile Programming Template - - - - - - - - - - - - -

    Header 1

    -

    Header 2

    -

    Header 3

    -

    Hello! Paragraph

    -
    - - - - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/52e4730d2a0be9abffbc2bdea2204b5e b/data/collaborative/shadow/52e4730d2a0be9abffbc2bdea2204b5e deleted file mode 100755 index b7d7165..0000000 --- a/data/collaborative/shadow/52e4730d2a0be9abffbc2bdea2204b5e +++ /dev/null @@ -1,33 +0,0 @@ -s:987:" - - - Mobile Programming Template - - - - - - - - - - - - -

    Header 1

    -

    Header 2

    -

    Header 3

    -

    Hello! Paragraph

    -
    - - - - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/5456a19d342557d417efd28aced31c16 b/data/collaborative/shadow/5456a19d342557d417efd28aced31c16 deleted file mode 100755 index f0fb224..0000000 --- a/data/collaborative/shadow/5456a19d342557d417efd28aced31c16 +++ /dev/null @@ -1,577 +0,0 @@ -s:22351:"/** - Author: Abbas Abdulmalik - Created: ~ May, 2017 - Revised: June 9, 2018 - Original Filename: L.js - Purpose: a small (but growing) personal re-usable js library for a simple MVC architecture - Notes: Now qualifyFunction helper doesn't return true for empty arrays (no vacuous truth) - - Added UploadFiles: - uploadFiles takes a callback -- progressReporter-- as it FIRST argument (parameter) - to allow for an optional fourth parameter of an upload path for the server. - progressReporter will be passed three arguments when called: - 1.) the amount of bytes uploaded so far - 2.) the total size of the file in bytes - 3.) the index of the file in the "array" of files being uploaded - - Added sortByExtension that alphabetizes an array of strings 'in place' by filename extension - Added arrayStringMatch that matches a collection of string arrays to a search string. - later (6-9-2018) included an option for a "maximum array index" to eliminate - searching irrelevant fields at the end of the array, such as image name and primary key. - Added loopCall as a 'better' version of setInterval - Removed L.attributes. It's a reserved word: an object belonging to DOM elements - Now it uses L.attribs - Added L.loopCall.stop() so that user can easily stop L.loopCall - Added L.symDiff for comparing arrays to determine their symmetric difference = conjunctive union = - exclusive-or - Restored an updated version of uploadFiles that signals the final file has uploaded - Added secToMinSec - Added runQualifiedFunctions that mirrors runQualifiedMethods using different parameters, - namely: functionQualifiers, model, view, controller - Added attachNewElement(tagname, id, view). Create new element, gives it an id and - attaches it to object provided: - L.attachNewElement(`div`, `picHolder`, view) - Added createListMixer and scrammbleThis, which depends on createListMixer - Added sortArrayOfStringArrays, with option of using a "link token" of choice as the 3rd argument - Added an optional argument for arrayStringMatch for a maximum array index - to eliminate searching irrelevant fields at the end of the array, - such as image name and primary key -*/ - -var L = {} -L.styles = function(styleString){ - const colonPosition = styleString.indexOf(':') - const property = styleString.slice(0, colonPosition) - const value = styleString.slice(colonPosition + 1) - this.style[property] = value - - return this.styles -} - -L.attribs = function(attributeString){ - const assignmentPosition = attributeString.indexOf('=') - const attribute = attributeString.slice(0, assignmentPosition) - const value = attributeString.slice(assignmentPosition + 1) - this.setAttribute(attribute, value) - - return this.attribs -} - -L.attachAllElementsById = function(here){ - let allElements = document.getElementsByTagName('*') - let array = [] - array.forEach.call(allElements, function(element) { - if(element.id){ - here[element.id] = element - element.styles = L.styles.bind(element) // attach L's styles() method here - element.attribs = L.attribs.bind(element) // attach L's attribs() method here - } - }) -} -///////////////| START of L.attachNewElement |///////////// -/** - L.attachNewElement(string tagname, string id, object view) ... - ... creates a new element of type "tagname" given as the first argument, - and gives it the id "id" given as the second argument. - The third argument is the view object where this new reference will be attached. - The element can then be referenced as view.id. -*/ -L.attachNewElement = function(tagname, id, view){ - if(arguments.length !== 3){ - console.log(`Error: requires 3 arguments: tagname, id, view`) - return - } - try{ - if(typeof tagname === `string`){ - var newElement = document.createElement(tagname) - } - else{ - console.log(`Error: tagname needs to be a string`) - return - } - if(typeof id === `string`){ - newElement.id = id - } - else{ - console.log(`Error: id needs to be a string`) - return - } - if(view.toString() === `[object Object]`){ - view[newElement.id] = newElement - newElement.styles = L.styles.bind(newElement) // attach L's styles() method here - newElement.attribs = L.attribs.bind(newElement) // attach L's attribs() method here - return newElement - } - else{ - console.log(`Error: view needs to be an object`) - return - } - } - catch(e){ - console.log(`Error in L.attachNewElement: ${e}`) - return - } -} -///////////////| END of L.attachNewElement |///////////// - -L.noPinchZoom = function(){ - window.ontouchstart = function(eventObject){ - if(eventObject.touches && eventObject.touches.length > 1){ - eventObject.preventDefault(); - } - } -} - -L.runQualifiedMethods = function(functionQualifiers, object, runNextUpdate){ - Object - .keys(functionQualifiers) - .filter(qualifyFunction) - .forEach(runFunction) - if(typeof runNextUpdate === 'function'){runNextUpdate()} - - //-----| helpers |-----// - function qualifyFunction(functionName){ - const isQualified = functionQualifiers[functionName].every( qualifier => qualifier) && - !!functionQualifiers[functionName].length - return isQualified - } - function runFunction(functionName){ - if(typeof object[functionName] === 'function'){ - object[functionName]() - } - - /** - If the prefix of this function's name is 'set' (for updating the MODEL), - and there is a similarly named function with a prefix of 'show' (for updating the VIEW), - then run the 'show' version as well. - */ - let prefix = functionName.slice(0,3) - let newFunctionName = 'show' + functionName.slice(3) - - if(prefix === 'set' && typeof object[newFunctionName] === 'function'){ - object[newFunctionName]() - } - } -} - -L.runQualifiedFunctions = function(functionQualifiers, model, view, controller){ - Object - .keys(functionQualifiers) - .filter(qualifyFunction) - .forEach(runFunction) - //-----| helpers |-----// - function qualifyFunction(functionName){ - const isQualified = functionQualifiers[functionName].every( qualifier => qualifier) && - !!functionQualifiers[functionName].length - return isQualified - } - function runFunction(functionName){ - if(typeof controller[functionName] === 'function'){ - controller[functionName](model) - } - /** - If the prefix of this function's name is 'set' (for updating the MODEL), - and there is a similarly named function with a prefix of 'show' (for updating the VIEW), - then run the 'show' version as well. - */ - let prefix = functionName.slice(0,3) - let newFunctionName = 'show' + functionName.slice(3) - if(prefix === 'set' && typeof controller[newFunctionName] === 'function'){ - controller[newFunctionName](view) - } - } -} -/** - Use a php script that reads contents of file from $_POST['contents'] that was convert by client - as DataURL, and expects filename and uploadPath from: $_POST['filename'] and $_POST['uploadPath'] - with trailing slash (/) provided by client (though script could check for this). -*/ -L.uploadFiles = function(progressReporter, fileElement, phpScriptName, uploadPath='../uploads/'){ - let doneCounter = 0 - let fileCount = fileElement.files.length - const array = [] // make a real array to borrow it's forEach method - array.forEach.call(fileElement.files, (file, index) => { - const postman = new XMLHttpRequest() // make a file deliverer for each file - const uploadObject = postman.upload // This object keeps track of upload progress - const envelope = new FormData() // make a holder for the file's name and content - envelope.stuff = envelope.append // give 'append' the nickname 'stuff' - const reader = new FileReader() // make a file reader (the raw file element is useless) - - reader.readAsDataURL(file) // process the file's contents - reader.onload = function(){ // when done ... - const contents = reader.result // collect the result, and ... - envelope.stuff('contents', contents) // place it in the envelope along with ... - envelope.stuff('filename', file.name) // its filename ... - envelope.stuff('uploadPath', uploadPath) // and its upload path on the server - - postman.open(`POST`, phpScriptName)// open up a POST to the server's php script - postman.send(envelope) // send the file - - //check when file loads and when there is an error - postman.onload = eventObject => { - postman.status !== 200 ? showMessage() : checkLastFileDone() - //-----| helper |------// - function showMessage(){ - const message = `Trouble with file: ${postman.status}` - console.log(message) - alert(message) - } - function checkLastFileDone(){ - doneCounter++ - if(typeof progressReporter === 'function'){ - if(doneCounter === fileCount){ - progressReporter(1, 1, index) - } - } - } - } - - postman.onerror = eventObject => { - const message = `Trouble connecting to server` - console.log(message) - alert(message) - } - - //invoke the callback for each upload progress report - uploadObject.onprogress = function(progressObject){ - if(typeof progressReporter === 'function'){ - progressReporter(progressObject.loaded, progressObject.total, index) - } - } - } - }) -} - -//---------------------------------------------------------// -/** - Given an array of strings (array), sorts the array 'in place' by filename EXTENSION, - and returns a copy of the array as well. Since it mutates the array, it is decidedly not - functionistic (but it functions). -*/ -L.sortByExtension = function (array) { - const type = {}.toString.call(array, null); - if (type !== '[object Array]') { - return array; - } - if (array.length === 0 || array.some(member => typeof member !== 'string')) { - return array; - } - //-------------------------------------// - let extension = ``; - let nudeWord = ``; - array.forEach((m, i, a) => { - if (m.lastIndexOf(`.`) !== -1) { - //get the extension - extension = m.slice(m.lastIndexOf(`.`) + 1); - nudeWord = m.slice(0, m.lastIndexOf(`.`)); - a[i] = `${extension}.${nudeWord}`; - } - }); - - array.sort(); - - array.forEach((m, i, a) => { - if (m.indexOf(`.`) !== -1){ - //get prefix (formerly the extension) - extension = m.slice(0, m.indexOf(`.`)) - nudeWord = m.slice(m.indexOf(`.`) + 1) - a[i] = `${nudeWord}.${extension}` - } - }); - - const newArray = [] - array.forEach( m => newArray.push(m)) - - return newArray; -} - -/** -From an array of string arrays, return a possibly smaller array -of only those string arrays whose member strings contain the given subString -regardless of case. - 1. For arrayOfStringArrays, use the filter method (a function property of an array) - that expects a function argument that operates on each array member - 2. Let's call the function argument 'match' - 3. 'match' should test each member array for a match of the substring as follows: - a.) join the members strings together into a bigString that is lowerCased - b.) lowerCase the subString - c.) use indexOf to match substring to the bigString - d.) return true for a match, otherwise return false - 4. the filter creates a new array after doing this. - 5. final step: return the new array that the filter produced -*/ -L.arrayStringMatch = function(subString, arrayOfStringArrays, maxIndex){ - //============================================================// - return arrayOfStringArrays.filter(match) - //-------| Helper function 'match' |---------// - function match(memberArray){ - //on 6-9-2018, added option of maximum index to eliminate searching through irrelevant fields - let bigString = '' - if(maxIndex && typeof maxIndex === "number" && maxIndex > 0){ - bigString = memberArray - .filter((m,i) => i <= maxIndex) - .join(` `) - .toLowerCase() - } - else{ - bigString = memberArray.join(` `).toLowerCase() - } - const substringToMatch = subString.toLowerCase() - return bigString.indexOf(substringToMatch) !== -1 - } -} -//-------------------------------------------------// - -/** - L.loopCall can be used to replace setInterval, which has been somewhat discredited. - See this blog post: - https://dev.to/akanksha_9560/why-not-to-use-setinterval--2na9 - - L.loopCall uses setTimeout recursively, which is a technique - reportedly more reliabale than setInterval. - - L.loopCall repeatedly calls (invokes) the callback function provided as its first argument. - The first call is immediate, but subsequent calls are delayed by the milliseconds - provided as the second argument. All additional arguments are optional - to be used by the callback if required. - - If needed, you can delay the initial call as well, - by having loopCall invoked by setTimeout using the same delay: - - setTimeout(L.loopCall, delay, callback, delay, arg1, arg2 ...) - - or the more readable, but more risky ... - - setTimeout("L.loopCall(callback, delay, arg1, arg2 ...)", delay) - //Doug Crockford would not be pleased - - To stop the loop, the callback function can test some external state condition, - (or test its own arguments, if they are passed by reference): - - if(externalStateCondition){ - L.loopCall.stop() - } -*/ -L.loopCall = function (callback, delay, ...args){ - L.loopCall.stopLoop = setTimeout(L.loopCall, delay, callback, delay, ...args) - callback(...args) -} - -L.loopCall.stop = () => { - clearTimeout(L.loopCall.stopLoop) -} - -/** - Returns an array that is the "mathematical or logical" symmetric difference among or between - any number of arrays provided as arguments (usually two). If the order of members is ignored - (as is done for mathematical sets), the result acts as the the exclusive-or (XOR), also know as - the disjunctive union. For the trivial cases of comparing one or two arrays, the result is - not surprising: for one array, the result is itself: L.symDiff(A, []) => A ⊕ [] = A. - For two arrays, the result is an array that has only members which are not shared in common: - L.symDiff(A, B) => A ⊕ B . - When comparing more than two arrays, the result may ne surprising. The proper result can be verified - by comparing only two at a time: L.symDiff(A, B, C) => A ⊕ B ⊕ C = (A ⊕ B) ⊕ C -*/ -L.symDiff = function symDiff(arrayA, arrayB){ // dummy paramters NOT referenced in body of the function - var partialSymDiff = [], - argsArray = arguments - ; - //============THE CRUX================= - return findSymDiff(partialSymDiff,0); - //============UNDER THE HOOD=========== - function findSymDiff(partialSymDiff,index){ - if (argsArray[index] === undefined){ - return partialSymDiff; - } - else{ - partialSymDiff = sd(partialSymDiff, argsArray[index] ); - return findSymDiff( partialSymDiff, index + 1 ); - } - } - //===================================== - function sd(arrayI, arrayJ){ - var diff = [], - blackList = [], - i = 0, - j = 0, - maxI = arrayI.length, - maxJ = arrayJ.length - ; - //------------------------------------------------- - //1.) Combine the arrays into a third array. - //2.) Find the matched elements and place them into a blacklist array. - //3.) Pull blacklisted elements from the combined array. - //4.) return the "reduced" combined array. - //--------------------------------------------------- - // 1.) Combine the arrays into a third array. - diff = arrayI.concat(arrayJ); - //--------------------------------------------------- - // 2.) Find the matched elements and place them into a blacklist array. - for ( i=0; i < maxI; i++ ){ - for( j=0; j< maxJ; j++ ){ - if(arrayI[i] === arrayJ[j]){ - blackList.push(arrayI[i] ); - } - } - } - //---------------------------------------------------- - // 3.) Pull blacklisted elements from the combined array. - diff = diff.filter( (element) => blackList.indexOf(element) === -1 ) - //---------------------------------------------------- - // 4.) return the "reduced" combined array. - return killDupes(diff); - } - //======================================================== - function killDupes(array){ - var kept = []; // Record of the "keepers" - return array.filter(function(element){ - if ( kept.indexOf(element) === -1 ){ //if not already retained ... - kept.push(element); // Record it as retained now, and... - return true; // allow this element to be kept (true) - } - else{ - return false; // otherwise, don't keep it (already kept) - } - }); - } -}; - -/** - * Pass in a numerical seconds: it returns a string in the format - * mm : ss, like ... - * 35 : 37 in minutes and seconds -*/ -L.secToMinSec = (seconds) =>{ - var min = Math.floor(seconds / 60); - var sec = Math.floor(seconds % 60); - if(isNaN(min)){min = 0} - if(isNaN(sec)){sec = 0} - var zeroMin = ((min < 10) ? ("0" + min) : ("" + min)); - var zeroSec = ((sec < 10) ? ("0" + sec) : ("" + sec)); - var minSec = zeroMin + ":" + zeroSec; - return minSec; -}; -//====| END of secToMinSec |====// - -///////////////////| START of CreateListMixer |////////////////////// -/** - * CreateListMixer: a factory that creates and returns a function that - * returns a random item from the collection (array or object) provided. - * Notes: Example-> var list = ["a", "short", "list"];//three (3) items to test - * var getRandomItem = CreateListMixer(); - * getRandomItem(list);//returns first of randomized list - * getRandomItem();//returns next item - * getRandomItem();//returns next item (last of three) - * getRandomItem();//new first item from re-randomized list - * - * // a new list; - * var list2 = { record1: "string", record2: "anotherString", ...}; - * getRandomItem(list2);//returns first of new randomized list2 - * getRandomItem();//etc. - * It returns a property name for objects or an array member for arrays; - * It returns 'false' if argument of function is not an object - * or an array (fails typeof arg === 'object') - * -*/ -L.CreateListMixer = function(){ - var list=[], - randList= [], - listLength= 0, - itemReturned= null, - itemReturnedIndex= -1 - ; - return function(){ - if(arguments[0]){ - if(typeof arguments[0] === 'object'){ - list = arguments[0]; - if({}.toString.call(arguments[0]) === '[object Object]'){ - list = Object.keys(list); - } - randList = randomize(list); - listLength = list.length; - } - else{ - return false; - } - } - //----| no args activity: return next random item |---- - if(itemReturnedIndex >= listLength-1){ - do{ - randList = randomize(list); - itemReturnedIndex = -1; - } - while(randList[itemReturnedIndex +1] === itemReturned); - } - itemReturnedIndex++; - itemReturned = randList[itemReturnedIndex]; - return itemReturned; - //-----helpers----- - function randomize(x){ - var mixedIndexes = []; - var randomList = []; - randomizeIndexes(); - return randomList; - //----sub helper---- - function randomizeIndexes(){ - // random numbers for mixedIndexes - while(mixedIndexes.length !== x.length){ - var match = false; - var possibleIndex = (x.length)*Math.random(); - possibleIndex = Math.floor(possibleIndex); - mixedIndexes.forEach(function(m){ - if(m === possibleIndex){ - match = true; - } - }); - if(!match){ - mixedIndexes.push(possibleIndex); - } - } - for(var i = 0; i < x.length; i++){ - var newIndex = mixedIndexes[i]; - randomList.push(list[newIndex]); - } - } - } - };//===| END returned function |====== -}//===| END enclosing factory function====== -///////////////////| END of CreateListMixer |////////////////////// - -///////////////////| START of scrammbleThis |////////////////////// -/** - scrammbleThis: (depends on createListMixer, above) - It returns an array of randomly arranged items of the collection provided. - The argument must be an array, an object, or a string. - If the argument is an object, a random array of its property names is returned. - If the argument is a string, a random array of its characters is returned. - If the argument is an array, a random array of its members is returned. -*/ -L.scrammbleThis = function(collection){ - if ( !(typeof collection === 'object' || typeof collection === 'string') ){return collection} - var mix = L.CreateListMixer(); - var list = (Object.prototype.toString.call(collection) === '[object Array]') - ? collection - : (typeof collection === 'string') - ? collection.split('') - : (typeof collection === 'object') - ? Object.keys(collection) - : null - return list.map((m,i,a)=> (i === 0) ? mix(a) : mix()) -} -///////////////////| END of scrammbleThis |////////////////////// - -/** - Given an array of string arrays, this function returns an alphabetized version -*/ -L.sortArrayOfStringArrays = function(arrayOfStringArrays, linkToken='```'){ - //use a unique token (default = triple back-ticks ```) to join the strings of each array of strings - const arrayOfStrings = arrayOfStringArrays.map(stringArray => stringArray.join(linkToken)) - - //case-insensitive sort this array of strings, mutating it in place: - //https://stackoverflow.com/questions/8996963/how-to-perform-case-insensitive-sorting-in-javascript - arrayOfStrings.sort( (a,b) => a.toLowerCase().localeCompare(b.toLowerCase()) ) - - //return a new array of string arrays after splitting the strings on the unique token - return arrayOfStrings.map( string => string.split(linkToken)) -} -"; \ No newline at end of file diff --git a/data/collaborative/shadow/57e91e0d3a50e23bca8a00a5e7539758 b/data/collaborative/shadow/57e91e0d3a50e23bca8a00a5e7539758 deleted file mode 100755 index c0e0d04..0000000 --- a/data/collaborative/shadow/57e91e0d3a50e23bca8a00a5e7539758 +++ /dev/null @@ -1,30 +0,0 @@ -s:798:" - - - Web 2 Template - - - - - - - - - - - - - - - - - - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/5b9b38f2e267013b0042f802a120442b b/data/collaborative/shadow/5b9b38f2e267013b0042f802a120442b deleted file mode 100755 index 0880947..0000000 --- a/data/collaborative/shadow/5b9b38f2e267013b0042f802a120442b +++ /dev/null @@ -1,68 +0,0 @@ -s:1281:"/* - -Created: 2018-07-09 -Revised: N/A -Purpose: A template for vanilla js with one library. - -*/ -/*global L*/ - - -let m = {}; -let v = {}; -let c = {}; - -c.initialize = function(eventObject){ - c.defineStateVariables(eventObject); - - //Use the library to attach all element id's to variables - L.attachAllElementsById(v); - - //collect the names of all the events of interest - let eventTypes = [ - `change`, - `input`, - `keydown`, - `keyup`, - `load`, - `mousedown`, - `mouseover`, - `mouseup`, - `offline`, - `online`, - `orientationchange`, - `resize`, - `touchend`, - `touchmove`, - `touchstart`, - ]; - - for (let eventType of eventTypes){ - window.addEventListener(eventType, c.designateFunction); - } - -}; - -////////////////| function that defines the "state variables" or app state references |/////////// -c.defineStateVariables = function(eventObject){ - ///////| define meta events |///////// - m.eventObject = eventObject; - m.source = eventObject.target; - m.type = eventObject.type; - m.id = eventObject.target.id; - - - m.type === 'mousedown' || m.type === `touchstart` - ? m.pressed = true - : m.pressed = false - ; - - m.type === `mouseup` || m.type === `touchend` - ? m.released = true - : m.released = false - ; - ///////| define state varibales |/////////// - m.buttonIn = false; -}; - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/5bb4642abdf3f7aa35eafebcba91df17 b/data/collaborative/shadow/5bb4642abdf3f7aa35eafebcba91df17 deleted file mode 100755 index 23485aa..0000000 --- a/data/collaborative/shadow/5bb4642abdf3f7aa35eafebcba91df17 +++ /dev/null @@ -1,1005 +0,0 @@ -s:37536:"/* - * Copyright (c) Codiad & Kent Safranski (codiad.com), distributed - * as-is and without warranty under the MIT License. See - * [root]/license.txt for more. This information must remain intact. - */ - -(function(global, $) { - - var EditSession = ace.require('ace/edit_session') - .EditSession; - var UndoManager = ace.require('ace/undomanager') - .UndoManager; - - var codiad = global.codiad; - - $(function() { - codiad.active.init(); - }); - - ////////////////////////////////////////////////////////////////// - // - // Active Files Component for Codiad - // --------------------------------- - // Track and manage EditSession instaces of files being edited. - // - ////////////////////////////////////////////////////////////////// - - codiad.active = { - - controller: 'components/active/controller.php', - - // Path to EditSession instance mapping - sessions: {}, - - // History of opened files - history: [], - - ////////////////////////////////////////////////////////////////// - // - // Check if a file is open. - // - // Parameters: - // path - {String} - // - ////////////////////////////////////////////////////////////////// - - isOpen: function(path) { - return !!this.sessions[path]; - }, - - open: function(path, content, mtime, inBackground, focus) { - if (focus === undefined) { - focus = true; - } - - var _this = this; - - if (this.isOpen(path)) { - if(focus) this.focus(path); - return; - } - var ext = codiad.filemanager.getExtension(path); - var mode = codiad.editor.selectMode(ext); - - var fn = function() { - //var Mode = require('ace/mode/' + mode) - // .Mode; - - // TODO: Ask for user confirmation before recovering - // And maybe show a diff - var draft = _this.checkDraft(path); - if (draft) { - content = draft; - codiad.message.success(i18n('Recovered unsaved content for: ') + path); - } - - //var session = new EditSession(content, new Mode()); - var session = new EditSession(content); - session.setMode("ace/mode/" + mode); - session.setUndoManager(new UndoManager()); - - session.path = path; - session.serverMTime = mtime; - _this.sessions[path] = session; - session.untainted = content.slice(0); - if (!inBackground && focus) { - codiad.editor.setSession(session); - } - _this.add(path, session, focus); - /* Notify listeners. */ - amplify.publish('active.onOpen', path); - }; - - // Assuming the mode file has no dependencies - $.loadScript('components/editor/ace-editor/mode-' + mode + '.js', - fn); - }, - - init: function() { - - var _this = this; - - _this.initTabDropdownMenu(); - _this.updateTabDropdownVisibility(); - - // Focus from list. - $('#list-active-files a') - .live('click', function(e) { - e.stopPropagation(); - _this.focus($(this).parent('li').attr('data-path')); - }); - - // Focus on left button click from dropdown. - $('#dropdown-list-active-files a') - .live('click', function(e) { - if(e.which == 1) { - /* Do not stop propagation of the event, - * it will be catch by the dropdown menu - * and close it. */ - _this.focus($(this).parent('li').attr('data-path')); - } - }); - - // Focus on left button mousedown from tab. - $('#tab-list-active-files li.tab-item>a.label') - .live('mousedown', function(e) { - if(e.which == 1) { - e.stopPropagation(); - _this.focus($(this).parent('li').attr('data-path')); - } - }); - - // Remove from list. - $('#list-active-files a>span') - .live('click', function(e) { - e.stopPropagation(); - _this.remove($(this) - .parent('a') - .parent('li') - .attr('data-path')); - }); - - // Remove from dropdown. - $('#dropdown-list-active-files a>span') - .live('click', function(e) { - e.stopPropagation(); - /* Get the active editor before removing anything. Remove the - * tab, then put back the focus on the previously active - * editor if it was not removed. */ - var activePath = _this.getPath(); - var pathToRemove = $(this).parents('li').attr('data-path'); - _this.remove(pathToRemove); - if (activePath !== null && activePath !== pathToRemove) { - _this.focus(activePath); - } - _this.updateTabDropdownVisibility(); - }); - - // Remove from tab. - $('#tab-list-active-files a.close') - .live('click', function(e) { - e.stopPropagation(); - /* Get the active editor before removing anything. Remove the - * tab, then put back the focus on the previously active - * editor if it was not removed. */ - var activePath = _this.getPath(); - var pathToRemove = $(this).parent('li').attr('data-path'); - _this.remove(pathToRemove); - if (activePath !== null && activePath !== pathToRemove) { - _this.focus(activePath); - } - _this.updateTabDropdownVisibility(); - }); - - // Remove from middle button click on dropdown. - $('#dropdown-list-active-files li') - .live('mouseup', function(e) { - if (e.which == 2) { - e.stopPropagation(); - /* Get the active editor before removing anything. Remove the - * tab, then put back the focus on the previously active - * editor if it was not removed. */ - var activePath = _this.getPath(); - var pathToRemove = $(this).attr('data-path'); - _this.remove(pathToRemove); - if (activePath !== null && activePath !== pathToRemove) { - _this.focus(activePath); - } - _this.updateTabDropdownVisibility(); - } - }); - - // Remove from middle button click on tab. - $('.tab-item') - .live('mouseup', function(e) { - if (e.which == 2) { - e.stopPropagation(); - /* Get the active editor before removing anything. Remove the - * tab, then put back the focus on the previously active - * editor if it was not removed. */ - var activePath = _this.getPath(); - var pathToRemove = $(this).attr('data-path'); - _this.remove(pathToRemove); - if (activePath !== null && activePath !== pathToRemove) { - _this.focus(activePath); - } - _this.updateTabDropdownVisibility(); - } - }); - - // Make list sortable - $('#list-active-files') - .sortable({ - placeholder: 'active-sort-placeholder', - tolerance: 'intersect', - start: function(e, ui) { - ui.placeholder.height(ui.item.height()); - } - }); - - // Make dropdown sortable. - $('#dropdown-list-active-files') - .sortable({ - axis: 'y', - tolerance: 'pointer', - start: function(e, ui) { - ui.placeholder.height(ui.item.height()); - } - }); - - // Make tabs sortable. - $('#tab-list-active-files') - .sortable({ - items: '> li', - axis: 'x', - tolerance: 'pointer', - containment: 'parent', - start: function(e, ui) { - ui.placeholder.css('background', 'transparent'); - ui.helper.css('width', '200px'); - }, - stop: function(e, ui) { - // Reset css - ui.item.css('z-index', '') - ui.item.css('position', '') - } - }); - /* Woaw, so tricky! At initialization, the tab-list is empty, so - * it is not marked as float so it is not detected as an horizontal - * list by the sortable plugin. Workaround is to mark it as - * floating at initialization time. See bug report - * http://bugs.jqueryui.com/ticket/6702. */ - $('#tab-list-active-files').data('sortable').floating = true; - - // Open saved-state active files on load - $.get(_this.controller + '?action=list', function(data) { - var listResponse = codiad.jsend.parse(data); - if (listResponse !== null) { - $.each(listResponse, function(index, data) { - codiad.filemanager.openFile(data.path, data.focused); - }); - } - }); - - // Prompt if a user tries to close window without saving all filess - window.onbeforeunload = function(e) { - if ($('#list-active-files li.changed') - .length > 0) { - var e = e || window.event; - var errMsg = i18n('You have unsaved files.'); - - // For IE and Firefox prior to version 4 - if (e) { - e.returnValue = errMsg; - } - - // For rest - return errMsg; - } - }; - }, - - ////////////////////////////////////////////////////////////////// - // Drafts - ////////////////////////////////////////////////////////////////// - - checkDraft: function(path) { - var draft = localStorage.getItem(path); - if (draft !== null) { - return draft; - } else { - return false; - } - }, - - removeDraft: function(path) { - localStorage.removeItem(path); - }, - - ////////////////////////////////////////////////////////////////// - // Get active editor path - ////////////////////////////////////////////////////////////////// - - getPath: function() { - try { - return codiad.editor.getActive() - .getSession() - .path; - } catch (e) { - return null; - } - }, - - ////////////////////////////////////////////////////////////////// - // Check if opened by another user - ////////////////////////////////////////////////////////////////// - - check: function(path) { - $.get(this.controller + '?action=check&path=' + encodeURIComponent(path), - - function(data) { - var checkResponse = codiad.jsend.parse(data); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Add newly opened file to list - ////////////////////////////////////////////////////////////////// - - add: function(path, session, focus) { - if (focus === undefined) { - focus = true; - } - - var listThumb = this.createListThumb(path); - session.listThumb = listThumb; - $('#list-active-files').append(listThumb); - - /* If the tab list would overflow with the new tab. Move the - * first tab to dropdown, then add a new tab. */ - if (this.isTabListOverflowed(true)) { - var tab = $('#tab-list-active-files li:first-child'); - this.moveTabToDropdownMenu(tab); - } - - var tabThumb = this.createTabThumb(path); - $('#tab-list-active-files').append(tabThumb); - session.tabThumb = tabThumb; - - this.updateTabDropdownVisibility(); - - $.get(this.controller + '?action=add&path=' + encodeURIComponent(path)); - - if(focus) { - this.focus(path); - } - - // Mark draft as changed - if (this.checkDraft(path)) { - this.markChanged(path); - } - }, - - ////////////////////////////////////////////////////////////////// - // Focus on opened file - ////////////////////////////////////////////////////////////////// - - focus: function(path, moveToTabList) { - if (moveToTabList === undefined) { - moveToTabList = true; - } - - this.highlightEntry(path, moveToTabList); - - if(path != this.getPath()) { - codiad.editor.setSession(this.sessions[path]); - this.history.push(path); - $.get(this.controller, {'action':'focused', 'path':path}); - } - - /* Check for users registered on the file. */ - this.check(path); - - /* Notify listeners. */ - amplify.publish('active.onFocus', path); - }, - - highlightEntry: function(path, moveToTabList) { - if (moveToTabList === undefined) { - moveToTabList = true; - } - - $('#list-active-files li') - .removeClass('active'); - - $('#tab-list-active-files li') - .removeClass('active'); - - $('#dropdown-list-active-files li') - .removeClass('active'); - - var session = this.sessions[path]; - - if($('#dropdown-list-active-files').has(session.tabThumb).length > 0) { - if(moveToTabList) { - /* Get the menu item as a tab, and put the last tab in - * dropdown. */ - var menuItem = session.tabThumb; - this.moveDropdownMenuItemToTab(menuItem, true); - - var tab = $('#tab-list-active-files li:last-child'); - this.moveTabToDropdownMenu(tab); - } else { - /* Show the dropdown menu if needed */ - this.showTabDropdownMenu(); - } - } - else if(this.history.length > 0) { - var prevPath = this.history[this.history.length-1]; - var prevSession = this.sessions[prevPath]; - if($('#dropdown-list-active-files').has(prevSession.tabThumb).length > 0) { - /* Hide the dropdown menu if needed */ - this.hideTabDropdownMenu(); - } - } - - session.tabThumb.addClass('active'); - session.listThumb.addClass('active'); - }, - - ////////////////////////////////////////////////////////////////// - // Mark changed - ////////////////////////////////////////////////////////////////// - - markChanged: function(path) { - this.sessions[path].listThumb.addClass('changed'); - this.sessions[path].tabThumb.addClass('changed'); - }, - - ////////////////////////////////////////////////////////////////// - // Save active editor - ////////////////////////////////////////////////////////////////// - - save: function(path) { - /* Notify listeners. */ - amplify.publish('active.onSave', path); - - var _this = this; - if ((path && !this.isOpen(path)) || (!path && !codiad.editor.getActive())) { - codiad.message.error(i18n('No Open Files to save')); - return; - } - var session; - if (path) session = this.sessions[path]; - else session = codiad.editor.getActive() - .getSession(); - var content = session.getValue(); - var path = session.path; - var handleSuccess = function(mtime){ - var session = codiad.active.sessions[path]; - if(typeof session != 'undefined') { - session.untainted = newContent; - session.serverMTime = mtime; - if (session.listThumb) session.listThumb.removeClass('changed'); - if (session.tabThumb) session.tabThumb.removeClass('changed'); - } - _this.removeDraft(path); - } - // Replicate the current content so as to avoid - // discrepancies due to content changes during - // computation of diff - - var newContent = content.slice(0); - if (session.serverMTime && session.untainted){ - codiad.workerManager.addTask({ - taskType: 'diff', - id: path, - original: session.untainted, - changed: newContent - }, function(success, patch){ - if (success) { - codiad.filemanager.savePatch(path, patch, session.serverMTime, { - success: handleSuccess - }); - } else { - codiad.filemanager.saveFile(path, newContent, { - success: handleSuccess - }); - } - }, this); - } else { - codiad.filemanager.saveFile(path, newContent, { - success: handleSuccess - }); - } - }, - - ////////////////////////////////////////////////////////////////// - // Save all files - ////////////////////////////////////////////////////////////////// - - saveAll: function() { - var _this = this; - for(var session in _this.sessions) { - if (_this.sessions[session].listThumb.hasClass('changed')) { - codiad.active.save(session); - } - } - }, - - ////////////////////////////////////////////////////////////////// - // Remove file - ////////////////////////////////////////////////////////////////// - - remove: function(path) { - if (!this.isOpen(path)) return; - var session = this.sessions[path]; - var closeFile = true; - if (session.listThumb.hasClass('changed')) { - codiad.modal.load(450, 'components/active/dialog.php?action=confirm&path=' + encodeURIComponent(path)); - closeFile = false; - } - if (closeFile) { - this.close(path); - } - }, - - removeAll: function(discard) { - discard = discard || false; - /* Notify listeners. */ - amplify.publish('active.onRemoveAll'); - - var _this = this; - var changed = false; - - var opentabs = new Array(); - for(var session in _this.sessions) { - opentabs[session] = session; - if (_this.sessions[session].listThumb.hasClass('changed')) { - changed = true; - } - } - if(changed && !discard) { - codiad.modal.load(450, 'components/active/dialog.php?action=confirmAll'); - return; - } - - for(var tab in opentabs) { - var session = this.sessions[tab]; - - session.tabThumb.remove(); - _this.updateTabDropdownVisibility(); - - session.listThumb.remove(); - - /* Remove closed path from history */ - var history = []; - $.each(this.history, function(index) { - if(this != tab) history.push(this); - }) - this.history = history - - delete this.sessions[tab]; - this.removeDraft(tab); - } - codiad.editor.exterminate(); - $('#list-active-files').html(''); - $.get(this.controller + '?action=removeall'); - }, - - close: function(path) { - /* Notify listeners. */ - amplify.publish('active.onClose', path); - - var _this = this; - var session = this.sessions[path]; - - /* Animate only if the tabThumb if a tab, not a dropdown item. */ - if(session.tabThumb.hasClass('tab-item')) { - session.tabThumb.css({'z-index': 1}); - session.tabThumb.animate({ - top: $('#editor-top-bar').height() + 'px' - }, 300, function() { - session.tabThumb.remove(); - _this.updateTabDropdownVisibility(); - }); - } else { - session.tabThumb.remove(); - _this.updateTabDropdownVisibility(); - } - - session.listThumb.remove(); - - /* Remove closed path from history */ - var history = []; - $.each(this.history, function(index) { - if(this != path) history.push(this); - }) - this.history = history - - /* Select all the tab tumbs except the one which is to be removed. */ - var tabThumbs = $('#tab-list-active-files li[data-path!="' + path + '"]'); - - if (tabThumbs.length == 0) { - codiad.editor.exterminate(); - } else { - - var nextPath = ''; - if(this.history.length > 0) { - nextPath = this.history[this.history.length - 1]; - } else { - nextPath = $(tabThumbs[0]).attr('data-path'); - } - var nextSession = this.sessions[nextPath]; - codiad.editor.removeSession(session, nextSession); - - this.focus(nextPath); - } - delete this.sessions[path]; - $.get(this.controller + '?action=remove&path=' + encodeURIComponent(path)); - this.removeDraft(path); - }, - - ////////////////////////////////////////////////////////////////// - // Process rename - ////////////////////////////////////////////////////////////////// - - rename: function(oldPath, newPath) { - var switchSessions = function(oldPath, newPath) { - var tabThumb = this.sessions[oldPath].tabThumb; - tabThumb.attr('data-path', newPath); - var title = newPath; - if (codiad.project.isAbsPath(newPath)) { - title = newPath.substring(1); - } - tabThumb.find('.label') - .text(title); - this.sessions[newPath] = this.sessions[oldPath]; - this.sessions[newPath].path = newPath; - delete this.sessions[oldPath]; - //Rename history - for (var i = 0; i < this.history.length; i++) { - if (this.history[i] === oldPath) { - this.history[i] = newPath; - } - } - }; - if (this.sessions[oldPath]) { - // A file was renamed - switchSessions.apply(this, [oldPath, newPath]); - // pass new sessions instance to setactive - for (var k = 0; k < codiad.editor.instances.length; k++) { - if (codiad.editor.instances[k].getSession().path === newPath) { - codiad.editor.setActive(codiad.editor.instances[k]); - } - } - - var newSession = this.sessions[newPath]; - - // Change Editor Mode - var ext = codiad.filemanager.getExtension(newPath); - var mode = codiad.editor.selectMode(ext); - - // handle async mode change - var fn = function() { - codiad.editor.setModeDisplay(newSession); - newSession.removeListener('changeMode', fn); - } - - newSession.on("changeMode", fn); - newSession.setMode("ace/mode/" + mode); - } else { - // A folder was renamed - var newKey; - for (var key in this.sessions) { - newKey = key.replace(oldPath, newPath); - if (newKey !== key) { - switchSessions.apply(this, [key, newKey]); - } - } - } - $.get(this.controller + '?action=rename&old_path=' + encodeURIComponent(oldPath) + '&new_path=' + encodeURIComponent(newPath), function() { - /* Notify listeners. */ - amplify.publish('active.onRename', {"oldPath": oldPath, "newPath": newPath}); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Open in Browser - ////////////////////////////////////////////////////////////////// - - openInBrowser: function() { - var path = this.getPath(); - if (path) { - codiad.filemanager.openInBrowser(path); - } else { - codiad.message.error('No Open Files'); - } - }, - - ////////////////////////////////////////////////////////////////// - // Get Selected Text - ////////////////////////////////////////////////////////////////// - - getSelectedText: function() { - var path = this.getPath(); - var session = this.sessions[path]; - - if (path && this.isOpen(path)) { - return session.getTextRange( - codiad.editor.getActive() - .getSelectionRange()); - } else { - codiad.message.error(i18n('No Open Files or Selected Text')); - } - }, - - ////////////////////////////////////////////////////////////////// - // Insert Text - ////////////////////////////////////////////////////////////////// - - insertText: function(val) { - codiad.editor.getActive() - .insert(val); - }, - - ////////////////////////////////////////////////////////////////// - // Goto Line - ////////////////////////////////////////////////////////////////// - - gotoLine: function(line) { - codiad.editor.getActive() - .gotoLine(line, 0, true); - }, - - ////////////////////////////////////////////////////////////////// - // Move Up (Key Combo) - ////////////////////////////////////////////////////////////////// - - move: function(dir) { - - var num = $('#tab-list-active-files li').length; - if (num === 0) return; - - var newActive = null; - var active = null; - - if (dir == 'up') { - - // If active is in the tab list - active = $('#tab-list-active-files li.active'); - if(active.length > 0) { - // Previous or rotate to the end - newActive = active.prev('li'); - if (newActive.length === 0) { - newActive = $('#dropdown-list-active-files li:last-child') - if (newActive.length === 0) { - newActive = $('#tab-list-active-files li:last-child') - } - } - } - - // If active is in the dropdown list - active = $('#dropdown-list-active-files li.active'); - if(active.length > 0) { - // Previous - newActive = active.prev('li'); - if (newActive.length === 0) { - newActive = $('#tab-list-active-files li:last-child') - } - } - - } else { - - // If active is in the tab list - active = $('#tab-list-active-files li.active'); - if(active.length > 0) { - // Next or rotate to the beginning - newActive = active.next('li'); - if (newActive.length === 0) { - newActive = $('#dropdown-list-active-files li:first-child'); - if (newActive.length === 0) { - newActive = $('#tab-list-active-files li:first-child') - } - } - } - - // If active is in the dropdown list - active = $('#dropdown-list-active-files li.active'); - if(active.length > 0) { - // Next or rotate to the beginning - newActive = active.next('li'); - if (newActive.length === 0) { - newActive = $('#tab-list-active-files li:first-child') - } - } - - } - - if(newActive) this.focus(newActive.attr('data-path'), false); - }, - - ////////////////////////////////////////////////////////////////// - // Dropdown Menu - ////////////////////////////////////////////////////////////////// - - initTabDropdownMenu: function() { - var _this = this; - - var menu = $('#dropdown-list-active-files'); - var button = $('#tab-dropdown-button'); - var closebutton = $('#tab-close-button'); - - menu.appendTo($('body')); - - button.click(function(e) { - e.stopPropagation(); - _this.toggleTabDropdownMenu(); - }); - - closebutton.click(function(e) { - e.stopPropagation(); - _this.removeAll(); - }); - }, - - showTabDropdownMenu: function() { - var menu = $('#dropdown-list-active-files'); - if(!menu.is(':visible')) this.toggleTabDropdownMenu(); - }, - - hideTabDropdownMenu: function() { - var menu = $('#dropdown-list-active-files'); - if(menu.is(':visible')) this.toggleTabDropdownMenu(); - }, - - toggleTabDropdownMenu: function() { - var _this = this; - var menu = $('#dropdown-list-active-files'); - - menu.css({ - top: $("#editor-top-bar").height() + 'px', - right: '20px', - width: '200px' - }); - - menu.slideToggle('fast'); - - if(menu.is(':visible')) { - // handle click-out autoclosing - var fn = function() { - menu.hide(); - $(window).off('click', fn) - } - $(window).on('click', fn); - } - }, - - moveTabToDropdownMenu: function(tab, prepend) { - if (prepend === undefined) { - prepend = false; - } - - tab.remove(); - path = tab.attr('data-path'); - - var tabThumb = this.createMenuItemThumb(path); - if(prepend) $('#dropdown-list-active-files').prepend(tabThumb); - else $('#dropdown-list-active-files').append(tabThumb); - - if(tab.hasClass("changed")) { - tabThumb.addClass("changed"); - } - - if(tab.hasClass("active")) { - tabThumb.addClass("active"); - } - - this.sessions[path].tabThumb = tabThumb; - }, - - moveDropdownMenuItemToTab: function(menuItem, prepend) { - if (prepend === undefined) { - prepend = false; - } - - menuItem.remove(); - path = menuItem.attr('data-path'); - - var tabThumb = this.createTabThumb(path); - if(prepend) $('#tab-list-active-files').prepend(tabThumb); - else $('#tab-list-active-files').append(tabThumb); - - if(menuItem.hasClass("changed")) { - tabThumb.addClass("changed"); - } - - if(menuItem.hasClass("active")) { - tabThumb.addClass("active"); - } - - this.sessions[path].tabThumb = tabThumb; - }, - - isTabListOverflowed: function(includeFictiveTab) { - if (includeFictiveTab === undefined) { - includeFictiveTab = false; - } - - var tabs = $('#tab-list-active-files li'); - var count = tabs.length - if (includeFictiveTab) count += 1; - if (count <= 1) return false; - - var width = 0; - tabs.each(function(index) { - width += $(this).outerWidth(true); - }) - if (includeFictiveTab) { - width += $(tabs[tabs.length-1]).outerWidth(true); - } - - /* If we subtract the width of the left side bar, of the right side - * bar handle and of the tab dropdown handle to the window width, - * do we have enough room for the tab list? Its kind of complicated - * to handle all the offsets, so afterwards we add a fixed offset - * just t be sure. */ - var lsbarWidth = $(".sidebar-handle").width(); - if (codiad.sidebars.isLeftSidebarOpen) { - lsbarWidth = $("#sb-left").width(); - } - - var rsbarWidth = $(".sidebar-handle").width(); - if (codiad.sidebars.isRightSidebarOpen) { - rsbarWidth = $("#sb-right").width(); - } - - var tabListWidth = $("#tab-list-active-files").width(); - var dropdownWidth = $('#tab-dropdown').width(); - var closeWidth = $('#tab-close').width(); - var room = window.innerWidth - lsbarWidth - rsbarWidth - dropdownWidth - closeWidth - width - 30; - return (room < 0); - }, - - updateTabDropdownVisibility: function() { - while(this.isTabListOverflowed()) { - var tab = $('#tab-list-active-files li:last-child'); - if (tab.length == 1) this.moveTabToDropdownMenu(tab, true); - else break; - } - - while(!this.isTabListOverflowed(true)) { - var menuItem = $('#dropdown-list-active-files li:first-child'); - if (menuItem.length == 1) this.moveDropdownMenuItemToTab(menuItem); - else break; - } - - if ($('#dropdown-list-active-files li').length > 0) { - $('#tab-dropdown').show(); - } else { - $('#tab-dropdown').hide(); - // Be sure to hide the menu if it is opened. - $('#dropdown-list-active-files').hide(); - } - if ($('#tab-list-active-files li').length > 1) { - $('#tab-close').show(); - } else { - $('#tab-close').hide(); - } - }, - - ////////////////////////////////////////////////////////////////// - // Factory - ////////////////////////////////////////////////////////////////// - - splitDirectoryAndFileName: function(path) { - var index = path.lastIndexOf('/'); - return { - fileName: path.substring(index + 1), - directory: (path.indexOf('/') == 0)? path.substring(1, index + 1):path.substring(0, index + 1) - } - }, - - createListThumb: function(path) { - return $('
  • ' + path + '
  • '); - }, - - createTabThumb: function(path) { - split = this.splitDirectoryAndFileName(path); - return $('
  • ' - + split.directory + '' + split.fileName + '' - + 'x
  • '); - }, - - createMenuItemThumb: function(path) { - split = this.splitDirectoryAndFileName(path); - return $('
  • ' - + split.directory + '' + split.fileName + '' - + '
  • '); - }, - - }; - -})(this, jQuery); -"; \ No newline at end of file diff --git a/data/collaborative/shadow/5e7826f99928dc790d9cba5022cc30b4 b/data/collaborative/shadow/5e7826f99928dc790d9cba5022cc30b4 deleted file mode 100755 index e054c52..0000000 --- a/data/collaborative/shadow/5e7826f99928dc790d9cba5022cc30b4 +++ /dev/null @@ -1,773 +0,0 @@ -s:34893:"/* - * Copyright (c) Codiad & Kent Safranski (codiad.com), distributed - * as-is and without warranty under the MIT License. See - * [root]/license.txt for more. This information must remain intact. - */ - -(function(global, $){ - - var codiad = global.codiad; - - $(window) - .load(function() { - codiad.filemanager.init(); - }); - - codiad.filemanager = { - - clipboard: '', - - noOpen: ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'exe', 'zip', 'tar', 'tar.gz'], - noBrowser: ['jpg', 'jpeg', 'png', 'gif', 'bmp'], - - controller: 'components/filemanager/controller.php', - dialog: 'components/filemanager/dialog.php', - dialogUpload: 'components/filemanager/dialog_upload.php', - - init: function() { - // Initialize node listener - this.nodeListener(); - // Load uploader - $.loadScript("components/filemanager/upload_scripts/jquery.ui.widget.js", true); - $.loadScript("components/filemanager/upload_scripts/jquery.iframe-transport.js", true); - $.loadScript("components/filemanager/upload_scripts/jquery.fileupload.js", true); - }, - - ////////////////////////////////////////////////////////////////// - // Listen for dbclick events on nodes - ////////////////////////////////////////////////////////////////// - - nodeListener: function() { - var _this = this; - - $('#file-manager').on('selectstart', false); - - $('#file-manager span') - .live('click', function() { // Open or Expand - if ($(this).parent().children("a").attr('data-type') == 'directory') { - _this.index($(this).parent().children("a") - .attr('data-path')); - } else { - _this.openFile($(this).parent().children("a") - .attr('data-path')); - } - if (!$(this).hasClass('none')) { - if ($(this).hasClass('plus')) { - $(this).removeClass('plus') - $(this).addClass('minus'); - } else { - $(this).removeClass('minus') - $(this).addClass('plus'); - } - } - }); - $('#file-manager a') - .live('dblclick', function() { // Open or Expand - if (!codiad.editor.settings.fileManagerTrigger) { - if ($(this) - .hasClass('directory')) { - _this.index($(this) - .attr('data-path')); - } else { - _this.openFile($(this) - .attr('data-path')); - } - if (!$(this).parent().children("span").hasClass('none')) { - if ($(this).parent().children("span").hasClass('plus')) { - $(this).parent().children("span").removeClass('plus') - $(this).parent().children("span").addClass('minus'); - } else { - $(this).parent().children("span").removeClass('minus') - $(this).parent().children("span").addClass('plus'); - } - } - } - }) - .live('click', function() { // Open or Expand - if (codiad.editor.settings.fileManagerTrigger) { - if ($(this) - .hasClass('directory')) { - _this.index($(this) - .attr('data-path')); - } else { - _this.openFile($(this) - .attr('data-path')); - } - if (!$(this).parent().children("span").hasClass('none')) { - if ($(this).parent().children("span").hasClass('plus')) { - $(this).parent().children("span").removeClass('plus') - $(this).parent().children("span").addClass('minus'); - } else { - $(this).parent().children("span").removeClass('minus') - $(this).parent().children("span").addClass('plus'); - } - } - } - }) - .live("contextmenu", function(e) { // Context Menu - e.preventDefault(); - _this.contextMenuShow(e, $(this) - .attr('data-path'), $(this) - .attr('data-type'), $(this) - .html()); - $(this) - .addClass('context-menu-active'); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Context Menu - ////////////////////////////////////////////////////////////////// - - contextMenuShow: function(e, path, type, name) { - var _this = this; - - // Selective options - switch (type) { - case 'directory': - $('#context-menu .directory-only, #context-menu .non-root') - .show(); - $('#context-menu .file-only, #context-menu .root-only') - .hide(); - break; - case 'file': - $('#context-menu .directory-only, #context-menu .root-only') - .hide(); - $('#context-menu .file-only,#context-menu .non-root') - .show(); - break; - case 'root': - $('#context-menu .directory-only, #context-menu .root-only') - .show(); - $('#context-menu .non-root, #context-menu .file-only') - .hide(); - break; - } - if(codiad.project.isAbsPath($('#file-manager a[data-type="root"]').attr('data-path'))) { - $('#context-menu .no-external').hide(); - } else { - $('#context-menu .no-external').show(); - } - // Show menu - var top = e.pageY; - if (top > $(window).height() - $('#context-menu').height()) { - top -= $('#context-menu').height(); - } - if (top < 10) { - top = 10; - } - var max = $(window).height() - top - 10; - - $('#context-menu') - .css({ - 'top': top + 'px', - 'left': e.pageX + 'px', - 'max-height': max + 'px' - }) - .fadeIn(200) - .attr('data-path', path) - .attr('data-type', type) - .attr('data-name', name); - // Show faded 'paste' if nothing in clipboard - if (this.clipboard === '') { - $('#context-menu a[content="Paste"]') - .addClass('disabled'); - } else { - $('#context-menu a[data-action="paste"]') - .removeClass('disabled'); - } - // Hide menu - $('#file-manager, #editor-region') - .on('mouseover', function() { - _this.contextMenuHide(); - }); - /* Notify listeners. */ - amplify.publish('context-menu.onShow', {e: e, path: path, type: type}); - // Hide on click - $('#context-menu a') - .click(function() { - _this.contextMenuHide(); - }); - }, - - contextMenuHide: function() { - $('#context-menu') - .fadeOut(200); - $('#file-manager a') - .removeClass('context-menu-active'); - /* Notify listeners. */ - amplify.publish('context-menu.onHide'); - }, - - ////////////////////////////////////////////////////////////////// - // Return the node name (sans path) - ////////////////////////////////////////////////////////////////// - - getShortName: function(path) { - return path.split('/') - .pop(); - }, - - ////////////////////////////////////////////////////////////////// - // Return extension - ////////////////////////////////////////////////////////////////// - - getExtension: function(path) { - return path.split('.') - .pop(); - }, - - ////////////////////////////////////////////////////////////////// - // Return type - ////////////////////////////////////////////////////////////////// - - getType: function(path) { - return $('#file-manager a[data-path="' + path + '"]') - .attr('data-type'); - }, - - ////////////////////////////////////////////////////////////////// - // Create node in file tree - ////////////////////////////////////////////////////////////////// - - createObject: function(parent, path, type) { - // NODE FORMAT:
  • {short_name}
  • - var parentNode = $('#file-manager a[data-path="' + parent + '"]'); - if (!$('#file-manager a[data-path="' + path + '"]') - .length) { // Doesn't already exist - if (parentNode.hasClass('open') && parentNode.hasClass('directory')) { // Only append node if parent is open (and a directory) - var shortName = this.getShortName(path); - if (type == 'directory') { - var appendage = '
  • ' + shortName + '
  • '; - } else { - var appendage = '
  • ' + shortName + '
  • '; - } - if (parentNode.siblings('ul') - .length) { // UL exists, other children to play with - parentNode.siblings('ul') - .append(appendage); - } else { - $('') - .insertAfter(parentNode); - } - } else { - parentNode.parent().children('span').removeClass('none'); - parentNode.parent().children('span').addClass('plus'); - } - } - }, - - ////////////////////////////////////////////////////////////////// - // Loop out all files and folders in directory path - ////////////////////////////////////////////////////////////////// - - indexFiles: [], - - index: function(path, rescan) { - var _this = this; - if (rescan === undefined) { - rescan = false; - } - node = $('#file-manager a[data-path="' + path + '"]'); - if (node.hasClass('open') && !rescan) { - node.parent('li') - .children('ul') - .slideUp(300, function() { - $(this) - .remove(); - node.removeClass('open'); - }); - } else { - node.addClass('loading'); - $.get(this.controller + '?action=index&path=' + encodeURIComponent(path), function(data) { - node.addClass('open'); - var objectsResponse = codiad.jsend.parse(data); - if (objectsResponse != 'error') { - /* Notify listener */ - _this.indexFiles = objectsResponse.index; - amplify.publish("filemanager.onIndex", {path: path, files: _this.indexFiles}); - var files = _this.indexFiles; - if (files.length > 0) { - if (node.parent().children('span').hasClass('plus')) { - node.parent().children('span').removeClass('plus').addClass('minus'); - } - var display = 'display:none;'; - if (rescan) { - display = ''; - } - var appendage = ''; - if (rescan) { - node.parent('li') - .children('ul') - .remove(); - } - $(appendage) - .insertAfter(node); - if (!rescan) { - node.siblings('ul') - .slideDown(300); - } - } - } - node.removeClass('loading'); - if (rescan && _this.rescanChildren.length > _this.rescanCounter) { - _this.rescan(_this.rescanChildren[_this.rescanCounter++]); - } else { - _this.rescanChildren = []; - _this.rescanCounter = 0; - } - }); - } - }, - - rescanChildren: [], - - rescanCounter: 0, - - rescan: function(path) { - var _this = this; - if (this.rescanCounter === 0) { - // Create array of open directories - node = $('#file-manager a[data-path="' + path + '"]'); - node.parent() - .find('a.open') - .each(function() { - _this.rescanChildren.push($(this) - .attr('data-path')); - }); - } - - this.index(path, true); - }, - - ////////////////////////////////////////////////////////////////// - // Open File - ////////////////////////////////////////////////////////////////// - - openFile: function(path, focus) { - if (focus === undefined) { - focus = true; - } - var node = $('#file-manager a[data-path="' + path + '"]'); - var ext = this.getExtension(path); - if ($.inArray(ext.toLowerCase(), this.noOpen) < 0) { - node.addClass('loading'); - $.get(this.controller + '?action=open&path=' + encodeURIComponent(path), function(data) { - var openResponse = codiad.jsend.parse(data); - if (openResponse != 'error') { - node.removeClass('loading'); - codiad.active.open(path, openResponse.content, openResponse.mtime, false, focus); - } - }); - } else { - if(!codiad.project.isAbsPath(path)) { - if ($.inArray(ext.toLowerCase(), this.noBrowser) < 0) { - this.download(path); - } else { - this.openInModal(path); - } - } else { - codiad.message.error(i18n('Unable to open file in Browser')); - } - } - }, - - ////////////////////////////////////////////////////////////////// - // Open in browser - ////////////////////////////////////////////////////////////////// - - openInBrowser: function(path) { - $.ajax({ - url: this.controller + '?action=open_in_browser&path=' + encodeURIComponent(path), - success: function(data) { - var openIBResponse = codiad.jsend.parse(data); - if (openIBResponse != 'error') { - window.open(openIBResponse.url, '_newtab'); - } - }, - async: false - }); - }, - openInModal: function(path) { - codiad.modal.load(250, this.dialog, { - action: 'preview', - path: path - }); - }, - saveModifications: function(path, data, callbacks, save=true){ - callbacks = callbacks || {}; - var _this = this, action, data; - var notifySaveErr = function() { - codiad.message.error(i18n('File could not be saved')); - if (typeof callbacks.error === 'function') { - var context = callbacks.context || _this; - callbacks.error.apply(context, [data]); - } - } - $.post(this.controller + '?action=modify&path=' + encodeURIComponent(path), data, function(resp){ - resp = $.parseJSON(resp); - if (resp.status == 'success') { - if ( save === true ) { - codiad.message.success(i18n('File saved')); - } - if (typeof callbacks.success === 'function'){ - var context = callbacks.context || _this; - callbacks.success.call(context, resp.data.mtime); - } - } else { - if (resp.message == 'Client is out of sync'){ - var reload = confirm( - "Server has a more updated copy of the file. Would "+ - "you like to refresh the contents ? Pressing no will "+ - "cause your changes to override the server's copy upon "+ - "next save." - ); - if (reload) { - codiad.active.close(path); - codiad.active.removeDraft(path); - _this.openFile(path); - } else { - var session = codiad.editor.getActive().getSession(); - session.serverMTime = null; - session.untainted = null; - } - } else codiad.message.error(i18n('File could not be saved')); - if (typeof callbacks.error === 'function') { - var context = callbacks.context || _this; - callbacks.error.apply(context, [resp.data]); - } - } - }).error(notifySaveErr); - }, - ////////////////////////////////////////////////////////////////// - // Save file - ////////////////////////////////////////////////////////////////// - - saveFile: function(path, content, callbacks, save=true) { - this.saveModifications(path, {content: content}, callbacks, save); - }, - - savePatch: function(path, patch, mtime, callbacks) { - if (patch.length > 0) - this.saveModifications(path, {patch: patch, mtime: mtime}, callbacks); - else if (typeof callbacks.success === 'function'){ - var context = callbacks.context || this; - callbacks.success.call(context, mtime); - } - }, - - ////////////////////////////////////////////////////////////////// - // Create Object - ////////////////////////////////////////////////////////////////// - - createNode: function(path, type) { - codiad.modal.load(250, this.dialog, { - action: 'create', - type: type, - path: path - }); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - var shortName = $('#modal-content form input[name="object_name"]') - .val(); - var path = $('#modal-content form input[name="path"]') - .val(); - var type = $('#modal-content form input[name="type"]') - .val(); - var createPath = path + '/' + shortName; - $.get(codiad.filemanager.controller + '?action=create&path=' + encodeURIComponent(createPath) + '&type=' + type, function(data) { - var createResponse = codiad.jsend.parse(data); - if (createResponse != 'error') { - codiad.message.success(type.charAt(0) - .toUpperCase() + type.slice(1) + ' Created'); - codiad.modal.unload(); - // Add new element to filemanager screen - codiad.filemanager.createObject(path, createPath, type); - if(type == 'file') { - codiad.filemanager.openFile(createPath, true); - } - /* Notify listeners. */ - amplify.publish('filemanager.onCreate', {createPath: createPath, path: path, shortName: shortName, type: type}); - } - }); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Copy to Clipboard - ////////////////////////////////////////////////////////////////// - - copyNode: function(path) { - this.clipboard = path; - codiad.message.success(i18n('Copied to Clipboard')); - }, - - ////////////////////////////////////////////////////////////////// - // Paste - ////////////////////////////////////////////////////////////////// - - pasteNode: function(path) { - var _this = this; - if (this.clipboard == '') { - codiad.message.error(i18n('Nothing in Your Clipboard')); - } else if (path == this.clipboard) { - codiad.message.error(i18n('Cannot Paste Directory Into Itself')); - } else { - var shortName = _this.getShortName(_this.clipboard); - if ($('#file-manager a[data-path="' + path + '/' + shortName + '"]') - .length) { // Confirm overwrite? - codiad.modal.load(400, this.dialog, { - action: 'overwrite', - path: path + '/' + shortName - }); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - var duplicate = false; - if($('#modal-content form select[name="or_action"]').val()==1){ - duplicate=true; console.log('Dup!'); - } - _this.processPasteNode(path,duplicate); - }); - } else { // No conflicts; proceed... - _this.processPasteNode(path,false); - } - } - }, - - processPasteNode: function(path,duplicate) { - var _this = this; - var shortName = this.getShortName(this.clipboard); - var type = this.getType(this.clipboard); - if(duplicate){ - shortName = "copy_of_"+shortName; - } - $.get(this.controller + '?action=duplicate&path=' + - encodeURIComponent(this.clipboard) + '&destination=' + - encodeURIComponent(path + '/' + shortName), function(data) { - var pasteResponse = codiad.jsend.parse(data); - if (pasteResponse != 'error') { - _this.createObject(path, path + '/' + shortName, type); - codiad.modal.unload(); - /* Notify listeners. */ - amplify.publish('filemanager.onPaste', {path: path, shortName: shortName, duplicate: duplicate}); - } - }); - }, - - ////////////////////////////////////////////////////////////////// - // Rename - ////////////////////////////////////////////////////////////////// - - renameNode: function(path) { - var shortName = this.getShortName(path); - var type = this.getType(path); - var _this = this; - codiad.modal.load(250, this.dialog, { action: 'rename', path: path, short_name: shortName, type: type}); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - var newName = $('#modal-content form input[name="object_name"]') - .val(); - // Build new path - var arr = path.split('/'); - var temp = new Array(); - for (i = 0; i < arr.length - 1; i++) { - temp.push(arr[i]) - } - var newPath = temp.join('/') + '/' + newName; - $.get(_this.controller, { action: 'modify', path: path, new_name: newName} , function(data) { - var renameResponse = codiad.jsend.parse(data); - if (renameResponse != 'error') { - codiad.message.success(type.charAt(0) - .toUpperCase() + type.slice(1) + ' Renamed'); - var node = $('#file-manager a[data-path="' + path + '"]'); - // Change pathing and name for node - node.attr('data-path', newPath) - .html(newName); - if (type == 'file') { // Change icons for file - curExtClass = 'ext-' + _this.getExtension(path); - newExtClass = 'ext-' + _this.getExtension(newPath); - $('#file-manager a[data-path="' + newPath + '"]') - .removeClass(curExtClass) - .addClass(newExtClass); - } else { // Change pathing on any sub-files/directories - _this.repathSubs(path, newPath); - } - // Change any active files - codiad.active.rename(path, newPath); - codiad.modal.unload(); - } - }); - }); - }, - - repathSubs: function(oldPath, newPath) { - $('#file-manager a[data-path="' + newPath + '"]') - .siblings('ul') - .find('a') - .each(function() { - // Hit the children, hit 'em hard - var curPath = $(this) - .attr('data-path'); - var revisedPath = curPath.replace(oldPath, newPath); - $(this) - .attr('data-path', revisedPath); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Delete - ////////////////////////////////////////////////////////////////// - - deleteNode: function(path) { - var _this = this; - codiad.modal.load(400, this.dialog, { - action: 'delete', - path: path - }); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - $.get(_this.controller + '?action=delete&path=' + encodeURIComponent(path), function(data) { - var deleteResponse = codiad.jsend.parse(data); - if (deleteResponse != 'error') { - var node = $('#file-manager a[data-path="' + path + '"]'); - node.parent('li') - .remove(); - // Close any active files - $('#active-files a') - .each(function() { - var curPath = $(this) - .attr('data-path'); - if (curPath.indexOf(path) == 0) { - codiad.active.remove(curPath); - } - }); - } - codiad.modal.unload(); - }); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Search - ////////////////////////////////////////////////////////////////// - - search: function(path) { - codiad.modal.load(500, this.dialog,{ - action: 'search', - path: path - }); - codiad.modal.load_process.done( function() { - var lastSearched = JSON.parse(localStorage.getItem("lastSearched")); - if(lastSearched) { - $('#modal-content form input[name="search_string"]').val(lastSearched.searchText); - $('#modal-content form input[name="search_file_type"]').val(lastSearched.fileExtension); - $('#modal-content form select[name="search_type"]').val(lastSearched.searchType); - if(lastSearched.searchResults != '') { - $('#filemanager-search-results').slideDown().html(lastSearched.searchResults); - } - } - }); - codiad.modal.hideOverlay(); - var _this = this; - $('#modal-content form') - .live('submit', function(e) { - $('#filemanager-search-processing') - .show(); - e.preventDefault(); - searchString = $('#modal-content form input[name="search_string"]') - .val(); - fileExtensions=$('#modal-content form input[name="search_file_type"]') - .val(); - searchFileType=$.trim(fileExtensions); - if (searchFileType != '') { - //season the string to use in find command - searchFileType = "\\(" + searchFileType.replace(/\s+/g, "\\|") + "\\)"; - } - searchType = $('#modal-content form select[name="search_type"]') - .val(); - $.post(_this.controller + '?action=search&path=' + encodeURIComponent(path) + '&type=' + searchType, { - search_string: searchString, - search_file_type: searchFileType - }, function(data) { - searchResponse = codiad.jsend.parse(data); - var results = ''; - if (searchResponse != 'error') { - $.each(searchResponse.index, function(key, val) { - // Cleanup file format - if(val['file'].substr(-1) == '/') { - val['file'] = val['file'].substr(0, str.length - 1); - } - val['file'] = val['file'].replace('//','/'); - // Add result - results += '
    Line ' + val['line'] + ': ' + val['file'] + '
    '; - }); - $('#filemanager-search-results') - .slideDown() - .html(results); - } else { - $('#filemanager-search-results') - .slideUp(); - } - _this.saveSearchResults(searchString, searchType, fileExtensions, results); - $('#filemanager-search-processing') - .hide(); - }); - }); - }, - - ///////////////////////////////////////////////////////////////// - // saveSearchResults - ///////////////////////////////////////////////////////////////// - saveSearchResults: function(searchText, searchType, fileExtensions, searchResults) { - var lastSearched = { - searchText: searchText, - searchType: searchType, - fileExtension: fileExtensions, - searchResults: searchResults - }; - localStorage.setItem("lastSearched", JSON.stringify(lastSearched)); - }, - ////////////////////////////////////////////////////////////////// - // Upload - ////////////////////////////////////////////////////////////////// - - uploadToNode: function(path) { - codiad.modal.load(500, this.dialogUpload, {path: path}); - }, - - ////////////////////////////////////////////////////////////////// - // Download - ////////////////////////////////////////////////////////////////// - - download: function(path) { - var type = this.getType(path); - $('#download') - .attr('src', 'components/filemanager/download.php?path=' + encodeURIComponent(path) + '&type=' + type); - } - }; - -})(this, jQuery); -"; \ No newline at end of file diff --git a/data/collaborative/shadow/62da00833cc673ea3506e8c74cc03010 b/data/collaborative/shadow/62da00833cc673ea3506e8c74cc03010 deleted file mode 100755 index be40c4d..0000000 --- a/data/collaborative/shadow/62da00833cc673ea3506e8c74cc03010 +++ /dev/null @@ -1,65 +0,0 @@ -s:1296:"/* - -Created: 2018-07-09 -Revised: N/A -Purpose: A template for vanilla js with one library. - -*/ -/*global L*/ -/*global m*/ -/*global v*/ -/*global c*/ -let m = {} -let v = {} -let c = {} - -c.initialize = function(eventObject){ - c.defineStateVariables(eventObject) - - //Use the library to attach all element id's to variables - L.attachAllElementsById(v) - - //collect the names of all the events of interest - let eventTypes = [ - `change`, - `input`, - `keydown`, - `keyup`, - `load`, - `mousedown`, - `mouseover`, - `mouseup`, - `offline`, - `online`, - `orientationchange`, - `resize`, - `touchend`, - `touchmove`, - `touchstart`, - ] - for (let eventType of eventTypes){ - window.addEventListener(eventType, c.designateFunction) - } - -} - -////////////////| function that defines the "state variables" or app state references |/////////// -c.defineStateVariables = function(eventObject){ - ///////| define meta events |///////// - m.eventObject = eventObject - m.source = eventObject.target - m.type = eventObject.type - m.id = eventObject.target.id - - - m.type === 'mousedown' || m.type === `touchstart` - ? m.pressed = true - : m.pressed = false - - m.type === `mouseup` || m.type === `touchend` - ? m.released = true - : m.released = false - - ///////| define state varibales |/////////// - m.buttonIn = false -}"; \ No newline at end of file diff --git a/data/collaborative/shadow/64029b02e9eba9c858cf99ac5488be14 b/data/collaborative/shadow/64029b02e9eba9c858cf99ac5488be14 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/shadow/64029b02e9eba9c858cf99ac5488be14 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/shadow/65dd434e2ad28232ea285fab94ddfb75 b/data/collaborative/shadow/65dd434e2ad28232ea285fab94ddfb75 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/shadow/65dd434e2ad28232ea285fab94ddfb75 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/shadow/6a4b62d9024b66e2e6b0601593581d96 b/data/collaborative/shadow/6a4b62d9024b66e2e6b0601593581d96 deleted file mode 100755 index 659594c..0000000 --- a/data/collaborative/shadow/6a4b62d9024b66e2e6b0601593581d96 +++ /dev/null @@ -1,576 +0,0 @@ -s:22926:"/** - Author: Abbas Abdulmalik - Created: ~ May, 2017 - Revised: June 9, 2018 - Original Filename: L.js - Purpose: a small (but growing) personal re-usable js library for a simple MVC architecture - Notes: Now qualifyFunction helper doesn't return true for empty arrays (no vacuous truth) - - Added UploadFiles: - uploadFiles takes a callback -- progressReporter-- as it FIRST argument (parameter) - to allow for an optional fourth parameter of an upload path for the server. - progressReporter will be passed three arguments when called: - 1.) the amount of bytes uploaded so far - 2.) the total size of the file in bytes - 3.) the index of the file in the "array" of files being uploaded - - Added sortByExtension that alphabetizes an array of strings 'in place' by filename extension - Added arrayStringMatch that matches a collection of string arrays to a search string. - later (6-9-2018) included an option for a "maximum array index" to eliminate - searching irrelevant fields at the end of the array, such as image name and primary key. - Added loopCall as a 'better' version of setInterval - Removed L.attributes. It's a reserved word: an object belonging to DOM elements - Now it uses L.attribs - Added L.loopCall.stop() so that user can easily stop L.loopCall - Added L.symDiff for comparing arrays to determine their symmetric difference = conjunctive union = - exclusive-or - Restored an updated version of uploadFiles that signals the final file has uploaded - Added secToMinSec - Added runQualifiedFunctions that mirrors runQualifiedMethods using different parameters, - namely: functionQualifiers, model, view, controller - Added attachNewElement(tagname, id, view). Create new element, gives it an id and - attaches it to object provided: - L.attachNewElement(`div`, `picHolder`, view) - Added createListMixer and scrammbleThis, which depends on createListMixer - Added sortArrayOfStringArrays, with option of using a "link token" of choice as the 3rd argument - Added an optional argument for arrayStringMatch for a maximum array index - to eliminate searching irrelevant fields at the end of the array, - such as image name and primary key -*/ - -var L = {} -L.styles = function(styleString){ - const colonPosition = styleString.indexOf(':') - const property = styleString.slice(0, colonPosition) - const value = styleString.slice(colonPosition + 1) - this.style[property] = value - - return this.styles -} - -L.attribs = function(attributeString){ - const assignmentPosition = attributeString.indexOf('=') - const attribute = attributeString.slice(0, assignmentPosition) - const value = attributeString.slice(assignmentPosition + 1) - this.setAttribute(attribute, value) - - return this.attribs -} - -L.attachAllElementsById = function(here){ - let allElements = document.getElementsByTagName('*') - let array = [] - array.forEach.call(allElements, function(element) { - if(element.id){ - here[element.id] = element - element.styles = L.styles.bind(element) // attach L's styles() method here - element.attribs = L.attribs.bind(element) // attach L's attribs() method here - } - }) -} -///////////////| START of L.attachNewElement |///////////// -/** - L.attachNewElement(string tagname, string id, object view) ... - ... creates a new element of type "tagname" given as the first argument, - and gives it the id "id" given as the second argument. - The third argument is the view object where this new reference will be attached. - The element can then be referenced as view.id. -*/ -L.attachNewElement = function(tagname, id, view){ - if(arguments.length !== 3){ - console.log(`Error: requires 3 arguments: tagname, id, view`) - return - } - try{ - if(typeof tagname === `string`){ - var newElement = document.createElement(tagname) - } - else{ - console.log(`Error: tagname needs to be a string`) - return - } - if(typeof id === `string`){ - newElement.id = id - } - else{ - console.log(`Error: id needs to be a string`) - return - } - if(view.toString() === `[object Object]`){ - view[newElement.id] = newElement - newElement.styles = L.styles.bind(newElement) // attach L's styles() method here - newElement.attribs = L.attribs.bind(newElement) // attach L's attribs() method here - return newElement - } - else{ - console.log(`Error: view needs to be an object`) - return - } - } - catch(e){ - console.log(`Error in L.attachNewElement: ${e}`) - return - } -} -///////////////| END of L.attachNewElement |///////////// - -L.noPinchZoom = function(){ - window.ontouchstart = function(eventObject){ - if(eventObject.touches && eventObject.touches.length > 1){ - eventObject.preventDefault(); - } - } -} - -L.runQualifiedMethods = function(functionQualifiers, object, runNextUpdate){ - Object - .keys(functionQualifiers) - .filter(qualifyFunction) - .forEach(runFunction) - if(typeof runNextUpdate === 'function'){runNextUpdate()} - - //-----| helpers |-----// - function qualifyFunction(functionName){ - const isQualified = functionQualifiers[functionName].every( qualifier => qualifier) && - !!functionQualifiers[functionName].length - return isQualified - } - function runFunction(functionName){ - if(typeof object[functionName] === 'function'){ - object[functionName]() - } - - /** - If the prefix of this function's name is 'set' (for updating the MODEL), - and there is a similarly named function with a prefix of 'show' (for updating the VIEW), - then run the 'show' version as well. - */ - let prefix = functionName.slice(0,3) - let newFunctionName = 'show' + functionName.slice(3) - - if(prefix === 'set' && typeof object[newFunctionName] === 'function'){ - object[newFunctionName]() - } - } -} - -L.runQualifiedFunctions = function(functionQualifiers, model, view, controller){ - Object - .keys(functionQualifiers) - .filter(qualifyFunction) - .forEach(runFunction) - //-----| helpers |-----// - function qualifyFunction(functionName){ - const isQualified = functionQualifiers[functionName].every( qualifier => qualifier) && - !!functionQualifiers[functionName].length - return isQualified - } - function runFunction(functionName){ - if(typeof controller[functionName] === 'function'){ - controller[functionName](model) - } - /** - If the prefix of this function's name is 'set' (for updating the MODEL), - and there is a similarly named function with a prefix of 'show' (for updating the VIEW), - then run the 'show' version as well. - */ - let prefix = functionName.slice(0,3) - let newFunctionName = 'show' + functionName.slice(3) - if(prefix === 'set' && typeof controller[newFunctionName] === 'function'){ - controller[newFunctionName](view) - } - } -} -/** - Use a php script that reads contents of file from $_POST['contents'] that was convert by client - as DataURL, and expects filename and uploadPath from: $_POST['filename'] and $_POST['uploadPath'] - with trailing slash (/) provided by client (though script could check for this). -*/ -L.uploadFiles = function(progressReporter, fileElement, phpScriptName, uploadPath='../uploads/'){ - let doneCounter = 0 - let fileCount = fileElement.files.length - const array = [] // make a real array to borrow it's forEach method - array.forEach.call(fileElement.files, (file, index) => { - const postman = new XMLHttpRequest() // make a file deliverer for each file - const uploadObject = postman.upload // This object keeps track of upload progress - const envelope = new FormData() // make a holder for the file's name and content - envelope.stuff = envelope.append // give 'append' the nickname 'stuff' - const reader = new FileReader() // make a file reader (the raw file element is useless) - - reader.readAsDataURL(file) // process the file's contents - reader.onload = function(){ // when done ... - const contents = reader.result // collect the result, and ... - envelope.stuff('contents', contents) // place it in the envelope along with ... - envelope.stuff('filename', file.name) // its filename ... - envelope.stuff('uploadPath', uploadPath) // and its upload path on the server - - postman.open(`POST`, phpScriptName)// open up a POST to the server's php script - postman.send(envelope) // send the file - - //check when file loads and when there is an error - postman.onload = eventObject => { - postman.status !== 200 ? showMessage() : checkLastFileDone() - //-----| helper |------// - function showMessage(){ - const message = `Trouble with file: ${postman.status}` - console.log(message) - alert(message) - } - function checkLastFileDone(){ - doneCounter++ - if(typeof progressReporter === 'function'){ - if(doneCounter === fileCount){ - progressReporter(1, 1, index) - } - } - } - } - - postman.onerror = eventObject => { - const message = `Trouble connecting to server` - console.log(message) - alert(message) - } - - //invoke the callback for each upload progress report - uploadObject.onprogress = function(progressObject){ - if(typeof progressReporter === 'function'){ - progressReporter(progressObject.loaded, progressObject.total, index) - } - } - } - }) -} - -//---------------------------------------------------------// -/** - Given an array of strings (array), sorts the array 'in place' by filename EXTENSION, - and returns a copy of the array as well. Since it mutates the array, it is decidedly not - functionistic (but it functions). -*/ -L.sortByExtension = function (array) { - const type = {}.toString.call(array, null); - if (type !== '[object Array]') { - return array; - } - if (array.length === 0 || array.some(member => typeof member !== 'string')) { - return array; - } - //-------------------------------------// - let extension = ``; - let nudeWord = ``; - array.forEach((m, i, a) => { - if (m.lastIndexOf(`.`) !== -1) { - //get the extension - extension = m.slice(m.lastIndexOf(`.`) + 1); - nudeWord = m.slice(0, m.lastIndexOf(`.`)); - a[i] = `${extension}.${nudeWord}`; - } - }); - - array.sort(); - - array.forEach((m, i, a) => { - if (m.indexOf(`.`) !== -1){ - //get prefix (formerly the extension) - extension = m.slice(0, m.indexOf(`.`)) - nudeWord = m.slice(m.indexOf(`.`) + 1) - a[i] = `${nudeWord}.${extension}` - } - }); - - const newArray = [] - array.forEach( m => newArray.push(m)) - - return newArray; -} - -/** -From an array of string arrays, return a possibly smaller array -of only those string arrays whose member strings contain the given subString -regardless of case. - 1. For arrayOfStringArrays, use the filter method (a function property of an array) - that expects a function argument that operates on each array member - 2. Let's call the function argument 'match' - 3. 'match' should test each member array for a match of the substring as follows: - a.) join the members strings together into a bigString that is lowerCased - b.) lowerCase the subString - c.) use indexOf to match substring to the bigString - d.) return true for a match, otherwise return false - 4. the filter creates a new array after doing this. - 5. final step: return the new array that the filter produced -*/ -L.arrayStringMatch = function(subString, arrayOfStringArrays, maxIndex){ - //============================================================// - return arrayOfStringArrays.filter(match) - //-------| Helper function 'match' |---------// - function match(memberArray){ - //on 6-9-2018, added option of maximum index to eliminate searching through irrelevant fields - let bigString = '' - if(maxIndex && typeof maxIndex === "number" && maxIndex > 0){ - bigString = memberArray - .filter((m,i) => i <= maxIndex) - .join(` `) - .toLowerCase() - } - else{ - bigString = memberArray.join(` `).toLowerCase() - } - const substringToMatch = subString.toLowerCase() - return bigString.indexOf(substringToMatch) !== -1 - } -} -//-------------------------------------------------// - -/** - L.loopCall can be used to replace setInterval, which has been somewhat discredited. - See this blog post: - https://dev.to/akanksha_9560/why-not-to-use-setinterval--2na9 - - L.loopCall uses setTimeout recursively, which is a technique - reportedly more reliabale than setInterval. - - L.loopCall repeatedly calls (invokes) the callback function provided as its first argument. - The first call is immediate, but subsequent calls are delayed by the milliseconds - provided as the second argument. All additional arguments are optional - to be used by the callback if required. - - If needed, you can delay the initial call as well, - by having loopCall invoked by setTimeout using the same delay: - - setTimeout(L.loopCall, delay, callback, delay, arg1, arg2 ...) - - or the more readable, but more risky ... - - setTimeout("L.loopCall(callback, delay, arg1, arg2 ...)", delay) - //Doug Crockford would not be pleased - - To stop the loop, the callback function can test some external state condition, - (or test its own arguments, if they are passed by reference): - - if(externalStateCondition){ - L.loopCall.stop() - } -*/ -L.loopCall = function (callback, delay, ...args){ - L.loopCall.stopLoop = setTimeout(L.loopCall, delay, callback, delay, ...args) - callback(...args) -} - -L.loopCall.stop = () => { - clearTimeout(L.loopCall.stopLoop) -} - -/** - Returns an array that is the "mathematical or logical" symmetric difference among or between - any number of arrays provided as arguments (usually two). If the order of members is ignored - (as is done for mathematical sets), the result acts as the the exclusive-or (XOR), also know as - the disjunctive union. For the trivial cases of comparing one or two arrays, the result is - not surprising: for one array, the result is itself: L.symDiff(A, []) => A ⊕ [] = A. - For two arrays, the result is an array that has only members which are not shared in common: - L.symDiff(A, B) => A ⊕ B . - When comparing more than two arrays, the result may ne surprising. The proper result can be verified - by comparing only two at a time: L.symDiff(A, B, C) => A ⊕ B ⊕ C = (A ⊕ B) ⊕ C -*/ -L.symDiff = function symDiff(arrayA, arrayB){ // dummy paramters NOT referenced in body of the function - var partialSymDiff = [], - argsArray = arguments - ; - //============THE CRUX================= - return findSymDiff(partialSymDiff,0); - //============UNDER THE HOOD=========== - function findSymDiff(partialSymDiff,index){ - if (argsArray[index] === undefined){ - return partialSymDiff; - } - else{ - partialSymDiff = sd(partialSymDiff, argsArray[index] ); - return findSymDiff( partialSymDiff, index + 1 ); - } - } - //===================================== - function sd(arrayI, arrayJ){ - var diff = [], - blackList = [], - i = 0, - j = 0, - maxI = arrayI.length, - maxJ = arrayJ.length - ; - //------------------------------------------------- - //1.) Combine the arrays into a third array. - //2.) Find the matched elements and place them into a blacklist array. - //3.) Pull blacklisted elements from the combined array. - //4.) return the "reduced" combined array. - //--------------------------------------------------- - // 1.) Combine the arrays into a third array. - diff = arrayI.concat(arrayJ); - //--------------------------------------------------- - // 2.) Find the matched elements and place them into a blacklist array. - for ( i=0; i < maxI; i++ ){ - for( j=0; j< maxJ; j++ ){ - if(arrayI[i] === arrayJ[j]){ - blackList.push(arrayI[i] ); - } - } - } - //---------------------------------------------------- - // 3.) Pull blacklisted elements from the combined array. - diff = diff.filter( (element) => blackList.indexOf(element) === -1 ) - //---------------------------------------------------- - // 4.) return the "reduced" combined array. - return killDupes(diff); - } - //======================================================== - function killDupes(array){ - var kept = []; // Record of the "keepers" - return array.filter(function(element){ - if ( kept.indexOf(element) === -1 ){ //if not already retained ... - kept.push(element); // Record it as retained now, and... - return true; // allow this element to be kept (true) - } - else{ - return false; // otherwise, don't keep it (already kept) - } - }); - } -}; - -/** - * Pass in a numerical seconds: it returns a string in the format - * mm : ss, like ... - * 35 : 37 in minutes and seconds -*/ -L.secToMinSec = (seconds) =>{ - var min = Math.floor(seconds / 60); - var sec = Math.floor(seconds % 60); - if(isNaN(min)){min = 0} - if(isNaN(sec)){sec = 0} - var zeroMin = ((min < 10) ? ("0" + min) : ("" + min)); - var zeroSec = ((sec < 10) ? ("0" + sec) : ("" + sec)); - var minSec = zeroMin + ":" + zeroSec; - return minSec; -}; -//====| END of secToMinSec |====// - -///////////////////| START of CreateListMixer |////////////////////// -/** - * CreateListMixer: a factory that creates and returns a function that - * returns a random item from the collection (array or object) provided. - * Notes: Example-> var list = ["a", "short", "list"];//three (3) items to test - * var getRandomItem = CreateListMixer(); - * getRandomItem(list);//returns first of randomized list - * getRandomItem();//returns next item - * getRandomItem();//returns next item (last of three) - * getRandomItem();//new first item from re-randomized list - * - * // a new list; - * var list2 = { record1: "string", record2: "anotherString", ...}; - * getRandomItem(list2);//returns first of new randomized list2 - * getRandomItem();//etc. - * It returns a property name for objects or an array member for arrays; - * It returns 'false' if argument of function is not an object - * or an array (fails typeof arg === 'object') - * -*/ -L.CreateListMixer = function(){ - var list=[], - randList= [], - listLength= 0, - itemReturned= null, - itemReturnedIndex= -1 - ; - return function(){ - if(arguments[0]){ - if(typeof arguments[0] === 'object'){ - list = arguments[0]; - if({}.toString.call(arguments[0]) === '[object Object]'){ - list = Object.keys(list); - } - randList = randomize(list); - listLength = list.length; - } - else{ - return false; - } - } - //----| no args activity: return next random item |---- - if(itemReturnedIndex >= listLength-1){ - do{ - randList = randomize(list); - itemReturnedIndex = -1; - } - while(randList[itemReturnedIndex +1] === itemReturned); - } - itemReturnedIndex++; - itemReturned = randList[itemReturnedIndex]; - return itemReturned; - //-----helpers----- - function randomize(x){ - var mixedIndexes = []; - var randomList = []; - randomizeIndexes(); - return randomList; - //----sub helper---- - function randomizeIndexes(){ - // random numbers for mixedIndexes - while(mixedIndexes.length !== x.length){ - var match = false; - var possibleIndex = (x.length)*Math.random(); - possibleIndex = Math.floor(possibleIndex); - mixedIndexes.forEach(function(m){ - if(m === possibleIndex){ - match = true; - } - }); - if(!match){ - mixedIndexes.push(possibleIndex); - } - } - for(var i = 0; i < x.length; i++){ - var newIndex = mixedIndexes[i]; - randomList.push(list[newIndex]); - } - } - } - };//===| END returned function |====== -}//===| END enclosing factory function====== -///////////////////| END of CreateListMixer |////////////////////// - -///////////////////| START of scrammbleThis |////////////////////// -/** - scrammbleThis: (depends on createListMixer, above) - It returns an array of randomly arranged items of the collection provided. - The argument must be an array, an object, or a string. - If the argument is an object, a random array of its property names is returned. - If the argument is a string, a random array of its characters is returned. - If the argument is an array, a random array of its members is returned. -*/ -L.scrammbleThis = function(collection){ - if ( !(typeof collection === 'object' || typeof collection === 'string') ){return collection} - var mix = L.CreateListMixer(); - var list = (Object.prototype.toString.call(collection) === '[object Array]') - ? collection - : (typeof collection === 'string') - ? collection.split('') - : (typeof collection === 'object') - ? Object.keys(collection) - : null - return list.map((m,i,a)=> (i === 0) ? mix(a) : mix()) -} -///////////////////| END of scrammbleThis |////////////////////// - -/** - Given an array of string arrays, this function returns an alphabetized version -*/ -L.sortArrayOfStringArrays = function(arrayOfStringArrays, linkToken='```'){ - //use a unique token (default = triple back-ticks ```) to join the strings of each array of strings - const arrayOfStrings = arrayOfStringArrays.map(stringArray => stringArray.join(linkToken)) - - //case-insensitive sort this array of strings, mutating it in place: - //https://stackoverflow.com/questions/8996963/how-to-perform-case-insensitive-sorting-in-javascript - arrayOfStrings.sort( (a,b) => a.toLowerCase().localeCompare(b.toLowerCase()) ) - - //return a new array of string arrays after splitting the strings on the unique token - return arrayOfStrings.map( string => string.split(linkToken)) -}"; \ No newline at end of file diff --git a/data/collaborative/shadow/6c9195df1db60f35f1cdb2d9ee97e4bf b/data/collaborative/shadow/6c9195df1db60f35f1cdb2d9ee97e4bf deleted file mode 100755 index 37fa790..0000000 --- a/data/collaborative/shadow/6c9195df1db60f35f1cdb2d9ee97e4bf +++ /dev/null @@ -1,34 +0,0 @@ -s:553:"* { - box-sizing: border-box; -} - -html{ - font-size: calc(calc(0.5vh + 0.5vw) + 12px); -} - -html, body { - height: 100%; - width: 100%; - padding: 0; - margin: 0; - overflow: hidden; -} - -.button { - - -webkit-transition-duration: 0.4s; /* Safari */ - outline: none; - background-color: #1f2059; /* PIT Blue */ - border: none; - border-radius: 5px; - box-shadow: 5px 5px 8px #000000; - color: white; - cursor: pointer; - display: inline-block; - font-size: 16px; - margin: 4px 2px; - padding: 15px 32px; - text-align: center; - text-decoration: none; - transition-duration: 0.4s; -}"; \ No newline at end of file diff --git a/data/collaborative/shadow/6e2f31eef830626055498ba7ba41f3dc b/data/collaborative/shadow/6e2f31eef830626055498ba7ba41f3dc deleted file mode 100755 index b7d7165..0000000 --- a/data/collaborative/shadow/6e2f31eef830626055498ba7ba41f3dc +++ /dev/null @@ -1,33 +0,0 @@ -s:987:" - - - Mobile Programming Template - - - - - - - - - - - - -

    Header 1

    -

    Header 2

    -

    Header 3

    -

    Hello! Paragraph

    -
    - - - - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/6f1528298858cf4548f52302b9b3df09 b/data/collaborative/shadow/6f1528298858cf4548f52302b9b3df09 deleted file mode 100755 index 002d7ea..0000000 --- a/data/collaborative/shadow/6f1528298858cf4548f52302b9b3df09 +++ /dev/null @@ -1,60 +0,0 @@ -s:2621:" - - - - - - - Abbas' Color Picker - - - - - - - - - - -
    -
    -
    -
    -
    -
    Initializing

    - - - - - -
    hue - - -
    saturation - - -
    lightness - - -
    alpha - - -
    -

    -
    mnemonic
    -
    - -
    - X: - Y:
    - angle:
    - radius: -
    - - - - - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/74153bbd75415243bee04ba5be3e0975 b/data/collaborative/shadow/74153bbd75415243bee04ba5be3e0975 deleted file mode 100755 index 659594c..0000000 --- a/data/collaborative/shadow/74153bbd75415243bee04ba5be3e0975 +++ /dev/null @@ -1,576 +0,0 @@ -s:22926:"/** - Author: Abbas Abdulmalik - Created: ~ May, 2017 - Revised: June 9, 2018 - Original Filename: L.js - Purpose: a small (but growing) personal re-usable js library for a simple MVC architecture - Notes: Now qualifyFunction helper doesn't return true for empty arrays (no vacuous truth) - - Added UploadFiles: - uploadFiles takes a callback -- progressReporter-- as it FIRST argument (parameter) - to allow for an optional fourth parameter of an upload path for the server. - progressReporter will be passed three arguments when called: - 1.) the amount of bytes uploaded so far - 2.) the total size of the file in bytes - 3.) the index of the file in the "array" of files being uploaded - - Added sortByExtension that alphabetizes an array of strings 'in place' by filename extension - Added arrayStringMatch that matches a collection of string arrays to a search string. - later (6-9-2018) included an option for a "maximum array index" to eliminate - searching irrelevant fields at the end of the array, such as image name and primary key. - Added loopCall as a 'better' version of setInterval - Removed L.attributes. It's a reserved word: an object belonging to DOM elements - Now it uses L.attribs - Added L.loopCall.stop() so that user can easily stop L.loopCall - Added L.symDiff for comparing arrays to determine their symmetric difference = conjunctive union = - exclusive-or - Restored an updated version of uploadFiles that signals the final file has uploaded - Added secToMinSec - Added runQualifiedFunctions that mirrors runQualifiedMethods using different parameters, - namely: functionQualifiers, model, view, controller - Added attachNewElement(tagname, id, view). Create new element, gives it an id and - attaches it to object provided: - L.attachNewElement(`div`, `picHolder`, view) - Added createListMixer and scrammbleThis, which depends on createListMixer - Added sortArrayOfStringArrays, with option of using a "link token" of choice as the 3rd argument - Added an optional argument for arrayStringMatch for a maximum array index - to eliminate searching irrelevant fields at the end of the array, - such as image name and primary key -*/ - -var L = {} -L.styles = function(styleString){ - const colonPosition = styleString.indexOf(':') - const property = styleString.slice(0, colonPosition) - const value = styleString.slice(colonPosition + 1) - this.style[property] = value - - return this.styles -} - -L.attribs = function(attributeString){ - const assignmentPosition = attributeString.indexOf('=') - const attribute = attributeString.slice(0, assignmentPosition) - const value = attributeString.slice(assignmentPosition + 1) - this.setAttribute(attribute, value) - - return this.attribs -} - -L.attachAllElementsById = function(here){ - let allElements = document.getElementsByTagName('*') - let array = [] - array.forEach.call(allElements, function(element) { - if(element.id){ - here[element.id] = element - element.styles = L.styles.bind(element) // attach L's styles() method here - element.attribs = L.attribs.bind(element) // attach L's attribs() method here - } - }) -} -///////////////| START of L.attachNewElement |///////////// -/** - L.attachNewElement(string tagname, string id, object view) ... - ... creates a new element of type "tagname" given as the first argument, - and gives it the id "id" given as the second argument. - The third argument is the view object where this new reference will be attached. - The element can then be referenced as view.id. -*/ -L.attachNewElement = function(tagname, id, view){ - if(arguments.length !== 3){ - console.log(`Error: requires 3 arguments: tagname, id, view`) - return - } - try{ - if(typeof tagname === `string`){ - var newElement = document.createElement(tagname) - } - else{ - console.log(`Error: tagname needs to be a string`) - return - } - if(typeof id === `string`){ - newElement.id = id - } - else{ - console.log(`Error: id needs to be a string`) - return - } - if(view.toString() === `[object Object]`){ - view[newElement.id] = newElement - newElement.styles = L.styles.bind(newElement) // attach L's styles() method here - newElement.attribs = L.attribs.bind(newElement) // attach L's attribs() method here - return newElement - } - else{ - console.log(`Error: view needs to be an object`) - return - } - } - catch(e){ - console.log(`Error in L.attachNewElement: ${e}`) - return - } -} -///////////////| END of L.attachNewElement |///////////// - -L.noPinchZoom = function(){ - window.ontouchstart = function(eventObject){ - if(eventObject.touches && eventObject.touches.length > 1){ - eventObject.preventDefault(); - } - } -} - -L.runQualifiedMethods = function(functionQualifiers, object, runNextUpdate){ - Object - .keys(functionQualifiers) - .filter(qualifyFunction) - .forEach(runFunction) - if(typeof runNextUpdate === 'function'){runNextUpdate()} - - //-----| helpers |-----// - function qualifyFunction(functionName){ - const isQualified = functionQualifiers[functionName].every( qualifier => qualifier) && - !!functionQualifiers[functionName].length - return isQualified - } - function runFunction(functionName){ - if(typeof object[functionName] === 'function'){ - object[functionName]() - } - - /** - If the prefix of this function's name is 'set' (for updating the MODEL), - and there is a similarly named function with a prefix of 'show' (for updating the VIEW), - then run the 'show' version as well. - */ - let prefix = functionName.slice(0,3) - let newFunctionName = 'show' + functionName.slice(3) - - if(prefix === 'set' && typeof object[newFunctionName] === 'function'){ - object[newFunctionName]() - } - } -} - -L.runQualifiedFunctions = function(functionQualifiers, model, view, controller){ - Object - .keys(functionQualifiers) - .filter(qualifyFunction) - .forEach(runFunction) - //-----| helpers |-----// - function qualifyFunction(functionName){ - const isQualified = functionQualifiers[functionName].every( qualifier => qualifier) && - !!functionQualifiers[functionName].length - return isQualified - } - function runFunction(functionName){ - if(typeof controller[functionName] === 'function'){ - controller[functionName](model) - } - /** - If the prefix of this function's name is 'set' (for updating the MODEL), - and there is a similarly named function with a prefix of 'show' (for updating the VIEW), - then run the 'show' version as well. - */ - let prefix = functionName.slice(0,3) - let newFunctionName = 'show' + functionName.slice(3) - if(prefix === 'set' && typeof controller[newFunctionName] === 'function'){ - controller[newFunctionName](view) - } - } -} -/** - Use a php script that reads contents of file from $_POST['contents'] that was convert by client - as DataURL, and expects filename and uploadPath from: $_POST['filename'] and $_POST['uploadPath'] - with trailing slash (/) provided by client (though script could check for this). -*/ -L.uploadFiles = function(progressReporter, fileElement, phpScriptName, uploadPath='../uploads/'){ - let doneCounter = 0 - let fileCount = fileElement.files.length - const array = [] // make a real array to borrow it's forEach method - array.forEach.call(fileElement.files, (file, index) => { - const postman = new XMLHttpRequest() // make a file deliverer for each file - const uploadObject = postman.upload // This object keeps track of upload progress - const envelope = new FormData() // make a holder for the file's name and content - envelope.stuff = envelope.append // give 'append' the nickname 'stuff' - const reader = new FileReader() // make a file reader (the raw file element is useless) - - reader.readAsDataURL(file) // process the file's contents - reader.onload = function(){ // when done ... - const contents = reader.result // collect the result, and ... - envelope.stuff('contents', contents) // place it in the envelope along with ... - envelope.stuff('filename', file.name) // its filename ... - envelope.stuff('uploadPath', uploadPath) // and its upload path on the server - - postman.open(`POST`, phpScriptName)// open up a POST to the server's php script - postman.send(envelope) // send the file - - //check when file loads and when there is an error - postman.onload = eventObject => { - postman.status !== 200 ? showMessage() : checkLastFileDone() - //-----| helper |------// - function showMessage(){ - const message = `Trouble with file: ${postman.status}` - console.log(message) - alert(message) - } - function checkLastFileDone(){ - doneCounter++ - if(typeof progressReporter === 'function'){ - if(doneCounter === fileCount){ - progressReporter(1, 1, index) - } - } - } - } - - postman.onerror = eventObject => { - const message = `Trouble connecting to server` - console.log(message) - alert(message) - } - - //invoke the callback for each upload progress report - uploadObject.onprogress = function(progressObject){ - if(typeof progressReporter === 'function'){ - progressReporter(progressObject.loaded, progressObject.total, index) - } - } - } - }) -} - -//---------------------------------------------------------// -/** - Given an array of strings (array), sorts the array 'in place' by filename EXTENSION, - and returns a copy of the array as well. Since it mutates the array, it is decidedly not - functionistic (but it functions). -*/ -L.sortByExtension = function (array) { - const type = {}.toString.call(array, null); - if (type !== '[object Array]') { - return array; - } - if (array.length === 0 || array.some(member => typeof member !== 'string')) { - return array; - } - //-------------------------------------// - let extension = ``; - let nudeWord = ``; - array.forEach((m, i, a) => { - if (m.lastIndexOf(`.`) !== -1) { - //get the extension - extension = m.slice(m.lastIndexOf(`.`) + 1); - nudeWord = m.slice(0, m.lastIndexOf(`.`)); - a[i] = `${extension}.${nudeWord}`; - } - }); - - array.sort(); - - array.forEach((m, i, a) => { - if (m.indexOf(`.`) !== -1){ - //get prefix (formerly the extension) - extension = m.slice(0, m.indexOf(`.`)) - nudeWord = m.slice(m.indexOf(`.`) + 1) - a[i] = `${nudeWord}.${extension}` - } - }); - - const newArray = [] - array.forEach( m => newArray.push(m)) - - return newArray; -} - -/** -From an array of string arrays, return a possibly smaller array -of only those string arrays whose member strings contain the given subString -regardless of case. - 1. For arrayOfStringArrays, use the filter method (a function property of an array) - that expects a function argument that operates on each array member - 2. Let's call the function argument 'match' - 3. 'match' should test each member array for a match of the substring as follows: - a.) join the members strings together into a bigString that is lowerCased - b.) lowerCase the subString - c.) use indexOf to match substring to the bigString - d.) return true for a match, otherwise return false - 4. the filter creates a new array after doing this. - 5. final step: return the new array that the filter produced -*/ -L.arrayStringMatch = function(subString, arrayOfStringArrays, maxIndex){ - //============================================================// - return arrayOfStringArrays.filter(match) - //-------| Helper function 'match' |---------// - function match(memberArray){ - //on 6-9-2018, added option of maximum index to eliminate searching through irrelevant fields - let bigString = '' - if(maxIndex && typeof maxIndex === "number" && maxIndex > 0){ - bigString = memberArray - .filter((m,i) => i <= maxIndex) - .join(` `) - .toLowerCase() - } - else{ - bigString = memberArray.join(` `).toLowerCase() - } - const substringToMatch = subString.toLowerCase() - return bigString.indexOf(substringToMatch) !== -1 - } -} -//-------------------------------------------------// - -/** - L.loopCall can be used to replace setInterval, which has been somewhat discredited. - See this blog post: - https://dev.to/akanksha_9560/why-not-to-use-setinterval--2na9 - - L.loopCall uses setTimeout recursively, which is a technique - reportedly more reliabale than setInterval. - - L.loopCall repeatedly calls (invokes) the callback function provided as its first argument. - The first call is immediate, but subsequent calls are delayed by the milliseconds - provided as the second argument. All additional arguments are optional - to be used by the callback if required. - - If needed, you can delay the initial call as well, - by having loopCall invoked by setTimeout using the same delay: - - setTimeout(L.loopCall, delay, callback, delay, arg1, arg2 ...) - - or the more readable, but more risky ... - - setTimeout("L.loopCall(callback, delay, arg1, arg2 ...)", delay) - //Doug Crockford would not be pleased - - To stop the loop, the callback function can test some external state condition, - (or test its own arguments, if they are passed by reference): - - if(externalStateCondition){ - L.loopCall.stop() - } -*/ -L.loopCall = function (callback, delay, ...args){ - L.loopCall.stopLoop = setTimeout(L.loopCall, delay, callback, delay, ...args) - callback(...args) -} - -L.loopCall.stop = () => { - clearTimeout(L.loopCall.stopLoop) -} - -/** - Returns an array that is the "mathematical or logical" symmetric difference among or between - any number of arrays provided as arguments (usually two). If the order of members is ignored - (as is done for mathematical sets), the result acts as the the exclusive-or (XOR), also know as - the disjunctive union. For the trivial cases of comparing one or two arrays, the result is - not surprising: for one array, the result is itself: L.symDiff(A, []) => A ⊕ [] = A. - For two arrays, the result is an array that has only members which are not shared in common: - L.symDiff(A, B) => A ⊕ B . - When comparing more than two arrays, the result may ne surprising. The proper result can be verified - by comparing only two at a time: L.symDiff(A, B, C) => A ⊕ B ⊕ C = (A ⊕ B) ⊕ C -*/ -L.symDiff = function symDiff(arrayA, arrayB){ // dummy paramters NOT referenced in body of the function - var partialSymDiff = [], - argsArray = arguments - ; - //============THE CRUX================= - return findSymDiff(partialSymDiff,0); - //============UNDER THE HOOD=========== - function findSymDiff(partialSymDiff,index){ - if (argsArray[index] === undefined){ - return partialSymDiff; - } - else{ - partialSymDiff = sd(partialSymDiff, argsArray[index] ); - return findSymDiff( partialSymDiff, index + 1 ); - } - } - //===================================== - function sd(arrayI, arrayJ){ - var diff = [], - blackList = [], - i = 0, - j = 0, - maxI = arrayI.length, - maxJ = arrayJ.length - ; - //------------------------------------------------- - //1.) Combine the arrays into a third array. - //2.) Find the matched elements and place them into a blacklist array. - //3.) Pull blacklisted elements from the combined array. - //4.) return the "reduced" combined array. - //--------------------------------------------------- - // 1.) Combine the arrays into a third array. - diff = arrayI.concat(arrayJ); - //--------------------------------------------------- - // 2.) Find the matched elements and place them into a blacklist array. - for ( i=0; i < maxI; i++ ){ - for( j=0; j< maxJ; j++ ){ - if(arrayI[i] === arrayJ[j]){ - blackList.push(arrayI[i] ); - } - } - } - //---------------------------------------------------- - // 3.) Pull blacklisted elements from the combined array. - diff = diff.filter( (element) => blackList.indexOf(element) === -1 ) - //---------------------------------------------------- - // 4.) return the "reduced" combined array. - return killDupes(diff); - } - //======================================================== - function killDupes(array){ - var kept = []; // Record of the "keepers" - return array.filter(function(element){ - if ( kept.indexOf(element) === -1 ){ //if not already retained ... - kept.push(element); // Record it as retained now, and... - return true; // allow this element to be kept (true) - } - else{ - return false; // otherwise, don't keep it (already kept) - } - }); - } -}; - -/** - * Pass in a numerical seconds: it returns a string in the format - * mm : ss, like ... - * 35 : 37 in minutes and seconds -*/ -L.secToMinSec = (seconds) =>{ - var min = Math.floor(seconds / 60); - var sec = Math.floor(seconds % 60); - if(isNaN(min)){min = 0} - if(isNaN(sec)){sec = 0} - var zeroMin = ((min < 10) ? ("0" + min) : ("" + min)); - var zeroSec = ((sec < 10) ? ("0" + sec) : ("" + sec)); - var minSec = zeroMin + ":" + zeroSec; - return minSec; -}; -//====| END of secToMinSec |====// - -///////////////////| START of CreateListMixer |////////////////////// -/** - * CreateListMixer: a factory that creates and returns a function that - * returns a random item from the collection (array or object) provided. - * Notes: Example-> var list = ["a", "short", "list"];//three (3) items to test - * var getRandomItem = CreateListMixer(); - * getRandomItem(list);//returns first of randomized list - * getRandomItem();//returns next item - * getRandomItem();//returns next item (last of three) - * getRandomItem();//new first item from re-randomized list - * - * // a new list; - * var list2 = { record1: "string", record2: "anotherString", ...}; - * getRandomItem(list2);//returns first of new randomized list2 - * getRandomItem();//etc. - * It returns a property name for objects or an array member for arrays; - * It returns 'false' if argument of function is not an object - * or an array (fails typeof arg === 'object') - * -*/ -L.CreateListMixer = function(){ - var list=[], - randList= [], - listLength= 0, - itemReturned= null, - itemReturnedIndex= -1 - ; - return function(){ - if(arguments[0]){ - if(typeof arguments[0] === 'object'){ - list = arguments[0]; - if({}.toString.call(arguments[0]) === '[object Object]'){ - list = Object.keys(list); - } - randList = randomize(list); - listLength = list.length; - } - else{ - return false; - } - } - //----| no args activity: return next random item |---- - if(itemReturnedIndex >= listLength-1){ - do{ - randList = randomize(list); - itemReturnedIndex = -1; - } - while(randList[itemReturnedIndex +1] === itemReturned); - } - itemReturnedIndex++; - itemReturned = randList[itemReturnedIndex]; - return itemReturned; - //-----helpers----- - function randomize(x){ - var mixedIndexes = []; - var randomList = []; - randomizeIndexes(); - return randomList; - //----sub helper---- - function randomizeIndexes(){ - // random numbers for mixedIndexes - while(mixedIndexes.length !== x.length){ - var match = false; - var possibleIndex = (x.length)*Math.random(); - possibleIndex = Math.floor(possibleIndex); - mixedIndexes.forEach(function(m){ - if(m === possibleIndex){ - match = true; - } - }); - if(!match){ - mixedIndexes.push(possibleIndex); - } - } - for(var i = 0; i < x.length; i++){ - var newIndex = mixedIndexes[i]; - randomList.push(list[newIndex]); - } - } - } - };//===| END returned function |====== -}//===| END enclosing factory function====== -///////////////////| END of CreateListMixer |////////////////////// - -///////////////////| START of scrammbleThis |////////////////////// -/** - scrammbleThis: (depends on createListMixer, above) - It returns an array of randomly arranged items of the collection provided. - The argument must be an array, an object, or a string. - If the argument is an object, a random array of its property names is returned. - If the argument is a string, a random array of its characters is returned. - If the argument is an array, a random array of its members is returned. -*/ -L.scrammbleThis = function(collection){ - if ( !(typeof collection === 'object' || typeof collection === 'string') ){return collection} - var mix = L.CreateListMixer(); - var list = (Object.prototype.toString.call(collection) === '[object Array]') - ? collection - : (typeof collection === 'string') - ? collection.split('') - : (typeof collection === 'object') - ? Object.keys(collection) - : null - return list.map((m,i,a)=> (i === 0) ? mix(a) : mix()) -} -///////////////////| END of scrammbleThis |////////////////////// - -/** - Given an array of string arrays, this function returns an alphabetized version -*/ -L.sortArrayOfStringArrays = function(arrayOfStringArrays, linkToken='```'){ - //use a unique token (default = triple back-ticks ```) to join the strings of each array of strings - const arrayOfStrings = arrayOfStringArrays.map(stringArray => stringArray.join(linkToken)) - - //case-insensitive sort this array of strings, mutating it in place: - //https://stackoverflow.com/questions/8996963/how-to-perform-case-insensitive-sorting-in-javascript - arrayOfStrings.sort( (a,b) => a.toLowerCase().localeCompare(b.toLowerCase()) ) - - //return a new array of string arrays after splitting the strings on the unique token - return arrayOfStrings.map( string => string.split(linkToken)) -}"; \ No newline at end of file diff --git a/data/collaborative/shadow/74dea1994cc8087e93aa43126d0609fb b/data/collaborative/shadow/74dea1994cc8087e93aa43126d0609fb deleted file mode 100755 index 9d1d5e8..0000000 --- a/data/collaborative/shadow/74dea1994cc8087e93aa43126d0609fb +++ /dev/null @@ -1,27 +0,0 @@ -s:856:"/* - -Created: 2018-07-10 -Modified: N/A -Purpose: Update the MVC - -*/ -/////////////////////////// -c.setToggleTestButton = function(m){ - m.testButtonIn = ! m.testButtonIn -} -c.showToggleTestButton = function(v){ - m.testButtonIn - ? v.testButton.styles(`box-shadow: inset 5px 5px 8px #000000`) - : v.testButton.styles(`box-shadow: 5px 5px 8px #000000`) -} -///////////////////////// -c.updateMetaEvents = function(eventObject){ - m.eventObject = eventObject //the event object itself - m.source = eventObject.target //where the event took place - m.type = eventObject.type //what the event was - m.id = eventObject.target.id //the id of the element where the event occurred - - //Shortcuts to combine similar mobile and computer events - m.pressed = m.type === `mousedown` || m.type === `touchstart` - m.released = m.type === `mouseup` || m.type === `touchend` -}"; \ No newline at end of file diff --git a/data/collaborative/shadow/76a80f9d3d1f00f202f5b6a01af0fe82 b/data/collaborative/shadow/76a80f9d3d1f00f202f5b6a01af0fe82 deleted file mode 100755 index eb5eab9..0000000 --- a/data/collaborative/shadow/76a80f9d3d1f00f202f5b6a01af0fe82 +++ /dev/null @@ -1,34 +0,0 @@ -s:553:"* { - box-sizing: border-box; -} - -html{ - font-size: calc(calc(0.5vh + 0.5vw) + 12px); -} - -html, body { - height: 100%; - width: 100%; - padding: 0; - margin: 0; - overflow: hidden; -} - -.button { - - -webkit-transition-duration: 0.4s; /* Safari */ - background-color: #1f2059; /* PIT Blue */ - border: none; - border-radius: 5px; - box-shadow: 5px 5px 8px #000000; - color: white; - cursor: pointer; - display: inline-block; - font-size: 16px; - margin: 4px 2px; - outline: none; - padding: 15px 32px; - text-align: center; - text-decoration: none; - transition-duration: 0.4s; -}"; \ No newline at end of file diff --git a/data/collaborative/shadow/76e43d7b712f43510dae0cbf50e40bc9 b/data/collaborative/shadow/76e43d7b712f43510dae0cbf50e40bc9 deleted file mode 100755 index 2f53002..0000000 --- a/data/collaborative/shadow/76e43d7b712f43510dae0cbf50e40bc9 +++ /dev/null @@ -1,76 +0,0 @@ -s:1545:"/* - -Created: 2018-07-10 -Modified: N/A -Purpose: To pollute the global scope then initialize our plugin. - -*/ -/* global L - * global m - * global v - * global c -*/ -const m = {} -const v = {} -const c = {} - -///////////////////////////// -c.initialize = function(eventObject) { - c.initializeModel(eventObject) - - L.attachAllElementsById(v) - - let eventTypes = [ - `change`, - `click`, - `dblclick`, - `input`, - `keydown`, - `keyup`, - `load`, - `mousedown`, - `mousemove`, - `mouseout`, - `mouseover`, - `mouseup`, - `offline`, - `online`, - `orientationchange`, - `resize`, - `touchend`, - `touchmove`, - `touchstart`, - ] - - //Clever way: for each member of the eventTypes array, have the window listen for the event - eventTypes.forEach((event)=>{window.addEventListener(event, c.designateFunction)}) - - /* - - let eventType; - for(eventType of eventTypes){ - window.addEventListener(eventType, c.designateFunction) - } - - */ - -} -///////////////////////////// -c.initializeModel = function(eventObject){ - //define meta events - m.eventObject = eventObject //the event object itself - m.source = eventObject.target //where the event took place - m.type = eventObject.type //what the event was - m.id = eventObject.target.id //the id of the element where the event occurred - - //Shortcuts to combine similar mobile and computer events - m.pressed = m.type === `mousedown` || m.type === `touchstart` - m.released = m.type === `mouseup` || m.type === `touchend` - - //et cetera .... - - //state variable particular to this app - m.testButtonIn = false -} - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/7c998484eb7cf6925bb4c8c12d9da2fc b/data/collaborative/shadow/7c998484eb7cf6925bb4c8c12d9da2fc deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/shadow/7c998484eb7cf6925bb4c8c12d9da2fc +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/shadow/7ed2ef8c2f8f09385af754d69279db57 b/data/collaborative/shadow/7ed2ef8c2f8f09385af754d69279db57 deleted file mode 100755 index ba74cf4..0000000 --- a/data/collaborative/shadow/7ed2ef8c2f8f09385af754d69279db57 +++ /dev/null @@ -1,401 +0,0 @@ -s:9748:" - */ - -class pages { - - /** - * Program Constants - */ - - const VERSION = '1.0.0'; - - /** - * Unique identifier for your plugin. - * - * - * The variable name is used as the text domain when internationalizing strings - * of text. Its value should match the Text Domain file header in the main - * plugin file. - * - * @var string - */ - protected $plugin_slug = ''; - - /** - * Instance of this class. - */ - protected static $instance = null; - - /** - * Initialize the plugin by setting localization and loading public scripts and styles. - */ - private function __construct() { - - // Trigger initial - $this->init(); - } - - /** - * Return the plugin slug. - * - * @since 1.0.0 - * - * @return Plugin slug variable. - */ - public function get_plugin_slug() { - return $this->plugin_slug; - } - - /** - * Return an instance of this class. - * - * @since 1.0.0 - * - * @return object A single instance of this class. - */ - public static function get_instance() { - // If the single instance hasn't been set, set it now. - if ( null == self::$instance ) { - self::$instance = new self; - } - - return self::$instance; - } - - /** - * Fired for each blog when the plugin is activated. - * - * @since 1.0.0 - */ - private static function install() {} - - /** - * Fired for each blog when the plugin is uninstalled. - * - * @since 1.0.0 - */ - private static function uninstall() {} - - /** - * Load the plugin text domain for translation. - * - * @since 1.0.0 - */ - public function init() {} - - /** - * Register and enqueue public-facing style sheet. - * - * @since 1.0.0 - */ - public static function enqueue_scripts() { - - ?> - - - " rel="stylesheet" /> - - - - - Student Panel - - - - - - - - - - -
    - -
    - -
    - - - - -
    -
    -
    - -
    - - - -

    Error, no quiz was specified

    - - -
    -

    -
    - - - -
    - "; - switch( $question["type"] ) { - - case( "multiple_choice" ): - - foreach( json_decode( $question["answer"] ) as $option ) { - - ?> -
    - - - -
    - -
    - - -
    - - - -
    -

    Welcome ,

    -

    Most recent quizzes:

    -
    - 0 ) { - - while( $row = mysqli_fetch_assoc( $result ) ) { - ?> - - "> -

    -
    - -

    No quizzes currently, you should create one!

    - - -
    -
    - -
    - quizzes here -
    - "; \ No newline at end of file diff --git a/data/collaborative/shadow/7f444cf225792632b9816fd7c212e785 b/data/collaborative/shadow/7f444cf225792632b9816fd7c212e785 deleted file mode 100755 index 45803b7..0000000 --- a/data/collaborative/shadow/7f444cf225792632b9816fd7c212e785 +++ /dev/null @@ -1,192 +0,0 @@ -s:7542:"remote = "http://update.codiad.com/?v={VER}&o={OS}&p={PHP}&w={WEB}&a={ACT}"; - $this->commits = "https://api.github.com/repos/Codiad/Codiad/commits"; - $this->archive = "https://github.com/Codiad/Codiad/archive/master.zip"; - } - - ////////////////////////////////////////////////////////////////// - // Set Initial Version - ////////////////////////////////////////////////////////////////// - - public function Init() - { - $version = array(); - if (!file_exists(DATA ."/version.php")) { - if (file_exists(BASE_PATH."/.git/HEAD")) { - $remote = $this->getRemoteVersion("install_git"); - $local = $this->getLocalVersion(); - $version[] = array("version"=>$local[0]['version'],"time"=>time(),"optout"=>"true","name"=>""); - saveJSON('version.php', $version); - } else { - $remote = $this->getRemoteVersion("install_man"); - $version[] = array("version"=>$remote[0]["commit"]["sha"],"time"=>time(),"optout"=>"true","name"=>""); - saveJSON('version.php', $version); - } - } else { - $local = $this->getLocalVersion(); - - if (file_exists(BASE_PATH."/.git/HEAD")) { - $current = getJSON('version.php'); - if ($local[0]['version'] != $current[0]['version']) { - $remote = $this->getRemoteVersion("update_git", $local[0]['version']); - $version[] = array("version"=>$local[0]['version'],"time"=>time(),"optout"=>"true","name"=>""); - saveJSON('version.php', $version); - } - } else { - if ($local[0]['version'] == '' && $local[0]['name'] == $_SESSION['user']) { - $remote = $this->getRemoteVersion("update_man", $local[0]['version']); - $version[] = array("version"=>$remote[0]["commit"]["sha"],"time"=>time(),"optout"=>"true","name"=>$_SESSION['user']); - saveJSON('version.php', $version); - } - } - - $local = $this->getLocalVersion(); - if (!isset($local[0]['optout'])) { - $remote = $this->getRemoteVersion("optout", $local[0]['version']); - $this->OptOut(); - } - } - } - - ////////////////////////////////////////////////////////////////// - // Clear Version - ////////////////////////////////////////////////////////////////// - - public function Clear() - { - $version[] = array("version"=>"","time"=>time(),"optout"=>"true","name"=>$_SESSION['user']); - saveJSON('version.php', $version); - } - - ////////////////////////////////////////////////////////////////// - // Clear Version - ////////////////////////////////////////////////////////////////// - - public function OptOut() - { - $current = getJSON('version.php'); - $version[] = array("version"=>$current[0]['version'],"time"=>$current[0]['time'],"optout"=>"true","name"=>$current[0]['name']); - saveJSON('version.php', $version); - } - - ////////////////////////////////////////////////////////////////// - // Check Version - ////////////////////////////////////////////////////////////////// - - public function Check() - { - $local = $this->getLocalVersion(); - $remote = $this->getRemoteVersion("check", $local[0]['version']); - - $nightly = true; - $archive = Common::getConstant('ARCHIVEURL', $this->archive); - $latest = ''; - - foreach ($remote as $tag) { - if ($latest == '') { - $latest = $tag["name"]; - $archive = $tag["zipball_url"]; - } - if ($local[0]['version'] == $tag["commit"]["sha"]) { - $local[0]['version'] = $tag["name"]; - $nightly = false; - break; - } - } - - $search = array("\r\n", "\n", "\r"); - $replace = array(" ", " ", " "); - - $message = ''; - $merge = ''; - $commits = json_decode(file_get_contents(Common::getConstant('COMMITURL', $this->commits)), true); - foreach ($commits as $commit) { - if ($local[0]['version'] != $commit["sha"]) { - if (strpos($commit["commit"]["message"], "Merge") === false) { - $message .= '- '.str_replace($search, $replace, $commit["commit"]["message"]).'
    '; - } else { - $merge .= '- '.str_replace($search, $replace, $commit["commit"]["message"]).'
    '; - } - } else { - break; - } - } - - if ($message == '') { - $message = $merge; - } - - return "[".formatJSEND("success", array("currentversion"=>$local[0]['version'],"remoteversion"=>$latest,"message"=>$message,"archive"=>$archive,"nightly"=>$nightly,"name"=>$local[0]['name']))."]"; - } - - ////////////////////////////////////////////////////////////////// - // Get Local Version - ////////////////////////////////////////////////////////////////// - - public function getLocalVersion() - { - if (file_exists(BASE_PATH."/.git/HEAD")) { - $tmp = file_get_contents(BASE_PATH."/.git/HEAD"); - if (strpos($tmp, "ref:") === false) { - $data[0]['version'] = trim($tmp); - } else { - $data[0]['version'] = trim(file_get_contents(BASE_PATH."/.git/".trim(str_replace('ref: ', '', $tmp)))); - } - $data[0]['name'] = ""; - if (file_exists(DATA ."/version.php")) { - $data[0]['optout'] = "true"; - } - } else { - $data = getJSON('version.php'); - } - return $data; - } - - ////////////////////////////////////////////////////////////////// - // Get Remote Version - ////////////////////////////////////////////////////////////////// - - public function getRemoteVersion($action, $localversion = "") - { - $remoteurl = Common::getConstant('UPDATEURL', $this->remote); - $remoteurl = str_replace("{OS}", PHP_OS, $remoteurl); - $remoteurl = str_replace("{PHP}", phpversion(), $remoteurl); - $remoteurl = str_replace("{VER}", $localversion, $remoteurl); - $remoteurl = str_replace("{WEB}", urlencode($_SERVER['SERVER_SOFTWARE']), $remoteurl); - $remoteurl = str_replace("{ACT}", $action, $remoteurl); - - return json_decode(file_get_contents($remoteurl), true); - } -} -"; \ No newline at end of file diff --git a/data/collaborative/shadow/7f86659d402c096aeedb08e84283f596 b/data/collaborative/shadow/7f86659d402c096aeedb08e84283f596 deleted file mode 100755 index e6ffed0..0000000 --- a/data/collaborative/shadow/7f86659d402c096aeedb08e84283f596 +++ /dev/null @@ -1,48 +0,0 @@ -s:1186:"/* - -Created: 2018-07-09 -Revised: N/A -Purpose: A template for vanilla js with one library. - -*/ -/*global L*/ -/*global m*/ -/*global v*/ -/*global c*/ - -////////////////////////////////////// -c.setToggleFirstButton = function(m){ - m.buttonIn = !m.buttonIn - //console.log(m.buttonIn) -} -c.showToggleFirstButton = function(v){ - m.buttonIn - ? v.firstButton.style.boxShadow = "inset 5px 5px 10px rgba(0,0,0,1)" - : v.firstButton.style.boxShadow = "5px 5px 10px rgba(0,0,0,1)" -} -////////////////////////////////////// -c.setXXY = function(m){} -c.showXXY = function(v){} -////////////////////////////////////// -////////////////////////////////////// -////////////////////////////////////// -////////////////////////////////////// -////////////////////////////////////// -////////////////////////////////////// - -c.updateMetaEvents = function(eventObject){ - ///////| define meta events |///////// - m.eventObject = eventObject - m.source = eventObject.target - m.type = eventObject.type - m.id = eventObject.target.id - - - m.type === 'mousedown' || m.type === `touchstart` - ? m.pressed = true - : m.pressed = false - - m.type === `mouseup` || m.type === `touchend` - ? m.released = true - : m.released = false -}"; \ No newline at end of file diff --git a/data/collaborative/shadow/7fa8be2ce86bf557e18b4d8ffe01ab67 b/data/collaborative/shadow/7fa8be2ce86bf557e18b4d8ffe01ab67 deleted file mode 100755 index 73b877c..0000000 --- a/data/collaborative/shadow/7fa8be2ce86bf557e18b4d8ffe01ab67 +++ /dev/null @@ -1,12 +0,0 @@ -s:235:" -# BEGIN WordPress - -RewriteEngine On -RewriteBase / -RewriteRule ^index\.php$ - [L] -RewriteCond %{REQUEST_FILENAME} !-f -RewriteCond %{REQUEST_FILENAME} !-d -RewriteRule . /index.php [L] - - -# END WordPress"; \ No newline at end of file diff --git a/data/collaborative/shadow/7ff97b3475c197f26cad514f22ceb86b b/data/collaborative/shadow/7ff97b3475c197f26cad514f22ceb86b deleted file mode 100755 index f0fb224..0000000 --- a/data/collaborative/shadow/7ff97b3475c197f26cad514f22ceb86b +++ /dev/null @@ -1,577 +0,0 @@ -s:22351:"/** - Author: Abbas Abdulmalik - Created: ~ May, 2017 - Revised: June 9, 2018 - Original Filename: L.js - Purpose: a small (but growing) personal re-usable js library for a simple MVC architecture - Notes: Now qualifyFunction helper doesn't return true for empty arrays (no vacuous truth) - - Added UploadFiles: - uploadFiles takes a callback -- progressReporter-- as it FIRST argument (parameter) - to allow for an optional fourth parameter of an upload path for the server. - progressReporter will be passed three arguments when called: - 1.) the amount of bytes uploaded so far - 2.) the total size of the file in bytes - 3.) the index of the file in the "array" of files being uploaded - - Added sortByExtension that alphabetizes an array of strings 'in place' by filename extension - Added arrayStringMatch that matches a collection of string arrays to a search string. - later (6-9-2018) included an option for a "maximum array index" to eliminate - searching irrelevant fields at the end of the array, such as image name and primary key. - Added loopCall as a 'better' version of setInterval - Removed L.attributes. It's a reserved word: an object belonging to DOM elements - Now it uses L.attribs - Added L.loopCall.stop() so that user can easily stop L.loopCall - Added L.symDiff for comparing arrays to determine their symmetric difference = conjunctive union = - exclusive-or - Restored an updated version of uploadFiles that signals the final file has uploaded - Added secToMinSec - Added runQualifiedFunctions that mirrors runQualifiedMethods using different parameters, - namely: functionQualifiers, model, view, controller - Added attachNewElement(tagname, id, view). Create new element, gives it an id and - attaches it to object provided: - L.attachNewElement(`div`, `picHolder`, view) - Added createListMixer and scrammbleThis, which depends on createListMixer - Added sortArrayOfStringArrays, with option of using a "link token" of choice as the 3rd argument - Added an optional argument for arrayStringMatch for a maximum array index - to eliminate searching irrelevant fields at the end of the array, - such as image name and primary key -*/ - -var L = {} -L.styles = function(styleString){ - const colonPosition = styleString.indexOf(':') - const property = styleString.slice(0, colonPosition) - const value = styleString.slice(colonPosition + 1) - this.style[property] = value - - return this.styles -} - -L.attribs = function(attributeString){ - const assignmentPosition = attributeString.indexOf('=') - const attribute = attributeString.slice(0, assignmentPosition) - const value = attributeString.slice(assignmentPosition + 1) - this.setAttribute(attribute, value) - - return this.attribs -} - -L.attachAllElementsById = function(here){ - let allElements = document.getElementsByTagName('*') - let array = [] - array.forEach.call(allElements, function(element) { - if(element.id){ - here[element.id] = element - element.styles = L.styles.bind(element) // attach L's styles() method here - element.attribs = L.attribs.bind(element) // attach L's attribs() method here - } - }) -} -///////////////| START of L.attachNewElement |///////////// -/** - L.attachNewElement(string tagname, string id, object view) ... - ... creates a new element of type "tagname" given as the first argument, - and gives it the id "id" given as the second argument. - The third argument is the view object where this new reference will be attached. - The element can then be referenced as view.id. -*/ -L.attachNewElement = function(tagname, id, view){ - if(arguments.length !== 3){ - console.log(`Error: requires 3 arguments: tagname, id, view`) - return - } - try{ - if(typeof tagname === `string`){ - var newElement = document.createElement(tagname) - } - else{ - console.log(`Error: tagname needs to be a string`) - return - } - if(typeof id === `string`){ - newElement.id = id - } - else{ - console.log(`Error: id needs to be a string`) - return - } - if(view.toString() === `[object Object]`){ - view[newElement.id] = newElement - newElement.styles = L.styles.bind(newElement) // attach L's styles() method here - newElement.attribs = L.attribs.bind(newElement) // attach L's attribs() method here - return newElement - } - else{ - console.log(`Error: view needs to be an object`) - return - } - } - catch(e){ - console.log(`Error in L.attachNewElement: ${e}`) - return - } -} -///////////////| END of L.attachNewElement |///////////// - -L.noPinchZoom = function(){ - window.ontouchstart = function(eventObject){ - if(eventObject.touches && eventObject.touches.length > 1){ - eventObject.preventDefault(); - } - } -} - -L.runQualifiedMethods = function(functionQualifiers, object, runNextUpdate){ - Object - .keys(functionQualifiers) - .filter(qualifyFunction) - .forEach(runFunction) - if(typeof runNextUpdate === 'function'){runNextUpdate()} - - //-----| helpers |-----// - function qualifyFunction(functionName){ - const isQualified = functionQualifiers[functionName].every( qualifier => qualifier) && - !!functionQualifiers[functionName].length - return isQualified - } - function runFunction(functionName){ - if(typeof object[functionName] === 'function'){ - object[functionName]() - } - - /** - If the prefix of this function's name is 'set' (for updating the MODEL), - and there is a similarly named function with a prefix of 'show' (for updating the VIEW), - then run the 'show' version as well. - */ - let prefix = functionName.slice(0,3) - let newFunctionName = 'show' + functionName.slice(3) - - if(prefix === 'set' && typeof object[newFunctionName] === 'function'){ - object[newFunctionName]() - } - } -} - -L.runQualifiedFunctions = function(functionQualifiers, model, view, controller){ - Object - .keys(functionQualifiers) - .filter(qualifyFunction) - .forEach(runFunction) - //-----| helpers |-----// - function qualifyFunction(functionName){ - const isQualified = functionQualifiers[functionName].every( qualifier => qualifier) && - !!functionQualifiers[functionName].length - return isQualified - } - function runFunction(functionName){ - if(typeof controller[functionName] === 'function'){ - controller[functionName](model) - } - /** - If the prefix of this function's name is 'set' (for updating the MODEL), - and there is a similarly named function with a prefix of 'show' (for updating the VIEW), - then run the 'show' version as well. - */ - let prefix = functionName.slice(0,3) - let newFunctionName = 'show' + functionName.slice(3) - if(prefix === 'set' && typeof controller[newFunctionName] === 'function'){ - controller[newFunctionName](view) - } - } -} -/** - Use a php script that reads contents of file from $_POST['contents'] that was convert by client - as DataURL, and expects filename and uploadPath from: $_POST['filename'] and $_POST['uploadPath'] - with trailing slash (/) provided by client (though script could check for this). -*/ -L.uploadFiles = function(progressReporter, fileElement, phpScriptName, uploadPath='../uploads/'){ - let doneCounter = 0 - let fileCount = fileElement.files.length - const array = [] // make a real array to borrow it's forEach method - array.forEach.call(fileElement.files, (file, index) => { - const postman = new XMLHttpRequest() // make a file deliverer for each file - const uploadObject = postman.upload // This object keeps track of upload progress - const envelope = new FormData() // make a holder for the file's name and content - envelope.stuff = envelope.append // give 'append' the nickname 'stuff' - const reader = new FileReader() // make a file reader (the raw file element is useless) - - reader.readAsDataURL(file) // process the file's contents - reader.onload = function(){ // when done ... - const contents = reader.result // collect the result, and ... - envelope.stuff('contents', contents) // place it in the envelope along with ... - envelope.stuff('filename', file.name) // its filename ... - envelope.stuff('uploadPath', uploadPath) // and its upload path on the server - - postman.open(`POST`, phpScriptName)// open up a POST to the server's php script - postman.send(envelope) // send the file - - //check when file loads and when there is an error - postman.onload = eventObject => { - postman.status !== 200 ? showMessage() : checkLastFileDone() - //-----| helper |------// - function showMessage(){ - const message = `Trouble with file: ${postman.status}` - console.log(message) - alert(message) - } - function checkLastFileDone(){ - doneCounter++ - if(typeof progressReporter === 'function'){ - if(doneCounter === fileCount){ - progressReporter(1, 1, index) - } - } - } - } - - postman.onerror = eventObject => { - const message = `Trouble connecting to server` - console.log(message) - alert(message) - } - - //invoke the callback for each upload progress report - uploadObject.onprogress = function(progressObject){ - if(typeof progressReporter === 'function'){ - progressReporter(progressObject.loaded, progressObject.total, index) - } - } - } - }) -} - -//---------------------------------------------------------// -/** - Given an array of strings (array), sorts the array 'in place' by filename EXTENSION, - and returns a copy of the array as well. Since it mutates the array, it is decidedly not - functionistic (but it functions). -*/ -L.sortByExtension = function (array) { - const type = {}.toString.call(array, null); - if (type !== '[object Array]') { - return array; - } - if (array.length === 0 || array.some(member => typeof member !== 'string')) { - return array; - } - //-------------------------------------// - let extension = ``; - let nudeWord = ``; - array.forEach((m, i, a) => { - if (m.lastIndexOf(`.`) !== -1) { - //get the extension - extension = m.slice(m.lastIndexOf(`.`) + 1); - nudeWord = m.slice(0, m.lastIndexOf(`.`)); - a[i] = `${extension}.${nudeWord}`; - } - }); - - array.sort(); - - array.forEach((m, i, a) => { - if (m.indexOf(`.`) !== -1){ - //get prefix (formerly the extension) - extension = m.slice(0, m.indexOf(`.`)) - nudeWord = m.slice(m.indexOf(`.`) + 1) - a[i] = `${nudeWord}.${extension}` - } - }); - - const newArray = [] - array.forEach( m => newArray.push(m)) - - return newArray; -} - -/** -From an array of string arrays, return a possibly smaller array -of only those string arrays whose member strings contain the given subString -regardless of case. - 1. For arrayOfStringArrays, use the filter method (a function property of an array) - that expects a function argument that operates on each array member - 2. Let's call the function argument 'match' - 3. 'match' should test each member array for a match of the substring as follows: - a.) join the members strings together into a bigString that is lowerCased - b.) lowerCase the subString - c.) use indexOf to match substring to the bigString - d.) return true for a match, otherwise return false - 4. the filter creates a new array after doing this. - 5. final step: return the new array that the filter produced -*/ -L.arrayStringMatch = function(subString, arrayOfStringArrays, maxIndex){ - //============================================================// - return arrayOfStringArrays.filter(match) - //-------| Helper function 'match' |---------// - function match(memberArray){ - //on 6-9-2018, added option of maximum index to eliminate searching through irrelevant fields - let bigString = '' - if(maxIndex && typeof maxIndex === "number" && maxIndex > 0){ - bigString = memberArray - .filter((m,i) => i <= maxIndex) - .join(` `) - .toLowerCase() - } - else{ - bigString = memberArray.join(` `).toLowerCase() - } - const substringToMatch = subString.toLowerCase() - return bigString.indexOf(substringToMatch) !== -1 - } -} -//-------------------------------------------------// - -/** - L.loopCall can be used to replace setInterval, which has been somewhat discredited. - See this blog post: - https://dev.to/akanksha_9560/why-not-to-use-setinterval--2na9 - - L.loopCall uses setTimeout recursively, which is a technique - reportedly more reliabale than setInterval. - - L.loopCall repeatedly calls (invokes) the callback function provided as its first argument. - The first call is immediate, but subsequent calls are delayed by the milliseconds - provided as the second argument. All additional arguments are optional - to be used by the callback if required. - - If needed, you can delay the initial call as well, - by having loopCall invoked by setTimeout using the same delay: - - setTimeout(L.loopCall, delay, callback, delay, arg1, arg2 ...) - - or the more readable, but more risky ... - - setTimeout("L.loopCall(callback, delay, arg1, arg2 ...)", delay) - //Doug Crockford would not be pleased - - To stop the loop, the callback function can test some external state condition, - (or test its own arguments, if they are passed by reference): - - if(externalStateCondition){ - L.loopCall.stop() - } -*/ -L.loopCall = function (callback, delay, ...args){ - L.loopCall.stopLoop = setTimeout(L.loopCall, delay, callback, delay, ...args) - callback(...args) -} - -L.loopCall.stop = () => { - clearTimeout(L.loopCall.stopLoop) -} - -/** - Returns an array that is the "mathematical or logical" symmetric difference among or between - any number of arrays provided as arguments (usually two). If the order of members is ignored - (as is done for mathematical sets), the result acts as the the exclusive-or (XOR), also know as - the disjunctive union. For the trivial cases of comparing one or two arrays, the result is - not surprising: for one array, the result is itself: L.symDiff(A, []) => A ⊕ [] = A. - For two arrays, the result is an array that has only members which are not shared in common: - L.symDiff(A, B) => A ⊕ B . - When comparing more than two arrays, the result may ne surprising. The proper result can be verified - by comparing only two at a time: L.symDiff(A, B, C) => A ⊕ B ⊕ C = (A ⊕ B) ⊕ C -*/ -L.symDiff = function symDiff(arrayA, arrayB){ // dummy paramters NOT referenced in body of the function - var partialSymDiff = [], - argsArray = arguments - ; - //============THE CRUX================= - return findSymDiff(partialSymDiff,0); - //============UNDER THE HOOD=========== - function findSymDiff(partialSymDiff,index){ - if (argsArray[index] === undefined){ - return partialSymDiff; - } - else{ - partialSymDiff = sd(partialSymDiff, argsArray[index] ); - return findSymDiff( partialSymDiff, index + 1 ); - } - } - //===================================== - function sd(arrayI, arrayJ){ - var diff = [], - blackList = [], - i = 0, - j = 0, - maxI = arrayI.length, - maxJ = arrayJ.length - ; - //------------------------------------------------- - //1.) Combine the arrays into a third array. - //2.) Find the matched elements and place them into a blacklist array. - //3.) Pull blacklisted elements from the combined array. - //4.) return the "reduced" combined array. - //--------------------------------------------------- - // 1.) Combine the arrays into a third array. - diff = arrayI.concat(arrayJ); - //--------------------------------------------------- - // 2.) Find the matched elements and place them into a blacklist array. - for ( i=0; i < maxI; i++ ){ - for( j=0; j< maxJ; j++ ){ - if(arrayI[i] === arrayJ[j]){ - blackList.push(arrayI[i] ); - } - } - } - //---------------------------------------------------- - // 3.) Pull blacklisted elements from the combined array. - diff = diff.filter( (element) => blackList.indexOf(element) === -1 ) - //---------------------------------------------------- - // 4.) return the "reduced" combined array. - return killDupes(diff); - } - //======================================================== - function killDupes(array){ - var kept = []; // Record of the "keepers" - return array.filter(function(element){ - if ( kept.indexOf(element) === -1 ){ //if not already retained ... - kept.push(element); // Record it as retained now, and... - return true; // allow this element to be kept (true) - } - else{ - return false; // otherwise, don't keep it (already kept) - } - }); - } -}; - -/** - * Pass in a numerical seconds: it returns a string in the format - * mm : ss, like ... - * 35 : 37 in minutes and seconds -*/ -L.secToMinSec = (seconds) =>{ - var min = Math.floor(seconds / 60); - var sec = Math.floor(seconds % 60); - if(isNaN(min)){min = 0} - if(isNaN(sec)){sec = 0} - var zeroMin = ((min < 10) ? ("0" + min) : ("" + min)); - var zeroSec = ((sec < 10) ? ("0" + sec) : ("" + sec)); - var minSec = zeroMin + ":" + zeroSec; - return minSec; -}; -//====| END of secToMinSec |====// - -///////////////////| START of CreateListMixer |////////////////////// -/** - * CreateListMixer: a factory that creates and returns a function that - * returns a random item from the collection (array or object) provided. - * Notes: Example-> var list = ["a", "short", "list"];//three (3) items to test - * var getRandomItem = CreateListMixer(); - * getRandomItem(list);//returns first of randomized list - * getRandomItem();//returns next item - * getRandomItem();//returns next item (last of three) - * getRandomItem();//new first item from re-randomized list - * - * // a new list; - * var list2 = { record1: "string", record2: "anotherString", ...}; - * getRandomItem(list2);//returns first of new randomized list2 - * getRandomItem();//etc. - * It returns a property name for objects or an array member for arrays; - * It returns 'false' if argument of function is not an object - * or an array (fails typeof arg === 'object') - * -*/ -L.CreateListMixer = function(){ - var list=[], - randList= [], - listLength= 0, - itemReturned= null, - itemReturnedIndex= -1 - ; - return function(){ - if(arguments[0]){ - if(typeof arguments[0] === 'object'){ - list = arguments[0]; - if({}.toString.call(arguments[0]) === '[object Object]'){ - list = Object.keys(list); - } - randList = randomize(list); - listLength = list.length; - } - else{ - return false; - } - } - //----| no args activity: return next random item |---- - if(itemReturnedIndex >= listLength-1){ - do{ - randList = randomize(list); - itemReturnedIndex = -1; - } - while(randList[itemReturnedIndex +1] === itemReturned); - } - itemReturnedIndex++; - itemReturned = randList[itemReturnedIndex]; - return itemReturned; - //-----helpers----- - function randomize(x){ - var mixedIndexes = []; - var randomList = []; - randomizeIndexes(); - return randomList; - //----sub helper---- - function randomizeIndexes(){ - // random numbers for mixedIndexes - while(mixedIndexes.length !== x.length){ - var match = false; - var possibleIndex = (x.length)*Math.random(); - possibleIndex = Math.floor(possibleIndex); - mixedIndexes.forEach(function(m){ - if(m === possibleIndex){ - match = true; - } - }); - if(!match){ - mixedIndexes.push(possibleIndex); - } - } - for(var i = 0; i < x.length; i++){ - var newIndex = mixedIndexes[i]; - randomList.push(list[newIndex]); - } - } - } - };//===| END returned function |====== -}//===| END enclosing factory function====== -///////////////////| END of CreateListMixer |////////////////////// - -///////////////////| START of scrammbleThis |////////////////////// -/** - scrammbleThis: (depends on createListMixer, above) - It returns an array of randomly arranged items of the collection provided. - The argument must be an array, an object, or a string. - If the argument is an object, a random array of its property names is returned. - If the argument is a string, a random array of its characters is returned. - If the argument is an array, a random array of its members is returned. -*/ -L.scrammbleThis = function(collection){ - if ( !(typeof collection === 'object' || typeof collection === 'string') ){return collection} - var mix = L.CreateListMixer(); - var list = (Object.prototype.toString.call(collection) === '[object Array]') - ? collection - : (typeof collection === 'string') - ? collection.split('') - : (typeof collection === 'object') - ? Object.keys(collection) - : null - return list.map((m,i,a)=> (i === 0) ? mix(a) : mix()) -} -///////////////////| END of scrammbleThis |////////////////////// - -/** - Given an array of string arrays, this function returns an alphabetized version -*/ -L.sortArrayOfStringArrays = function(arrayOfStringArrays, linkToken='```'){ - //use a unique token (default = triple back-ticks ```) to join the strings of each array of strings - const arrayOfStrings = arrayOfStringArrays.map(stringArray => stringArray.join(linkToken)) - - //case-insensitive sort this array of strings, mutating it in place: - //https://stackoverflow.com/questions/8996963/how-to-perform-case-insensitive-sorting-in-javascript - arrayOfStrings.sort( (a,b) => a.toLowerCase().localeCompare(b.toLowerCase()) ) - - //return a new array of string arrays after splitting the strings on the unique token - return arrayOfStrings.map( string => string.split(linkToken)) -} -"; \ No newline at end of file diff --git a/data/collaborative/shadow/81996f949129f48e0128cdb7b3cb7716 b/data/collaborative/shadow/81996f949129f48e0128cdb7b3cb7716 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/shadow/81996f949129f48e0128cdb7b3cb7716 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/shadow/870b887e9a5909882cbcebb4ba14b794 b/data/collaborative/shadow/870b887e9a5909882cbcebb4ba14b794 deleted file mode 100755 index 64fb9fd..0000000 --- a/data/collaborative/shadow/870b887e9a5909882cbcebb4ba14b794 +++ /dev/null @@ -1,59 +0,0 @@ -s:1168:"/* - * Place copyright or other info here... - */ - -(function(global, $){ - - // Define core - var codiad = global.codiad, - scripts= document.getElementsByTagName('script'), - path = scripts[scripts.length-1].src.split('?')[0], - curpath = path.split('/').slice(0, -1).join('/')+'/'; - - // Instantiates plugin - $(function() { - codiad.tela_auto_save.init(); - }); - - codiad.tela_auto_save = { - - // Allows relative `this.path` linkage - path: curpath, - - init: function() { - - // Start your plugin here... - let editor = document.getElementsByClassName( 'ace_content' )[0]; - let auto_save_trigger = setInterval( this.auto_save, 500 ); - }, - - /** - * - * This is where the core functionality goes, any call, references, - * script-loads, etc... - * - */ - - auto_save: function() { - - let tabs = document.getElementsByClassName( "tab-item" ); - tabs = Array.from( tabs ); - tabs.forEach( function( m, i, a ) { - - // M = Current entry - // I = Index as integer - // A = Entire array - - if ( m.classList.contains( "active" ) ) { - - m.classList.remove( "changed" ) - } - }); - - codiad.active.save; - } - - }; - -})(this, jQuery); -"; \ No newline at end of file diff --git a/data/collaborative/shadow/8ca94770f4850fd864af830a177c90aa b/data/collaborative/shadow/8ca94770f4850fd864af830a177c90aa deleted file mode 100755 index 9d1d5e8..0000000 --- a/data/collaborative/shadow/8ca94770f4850fd864af830a177c90aa +++ /dev/null @@ -1,27 +0,0 @@ -s:856:"/* - -Created: 2018-07-10 -Modified: N/A -Purpose: Update the MVC - -*/ -/////////////////////////// -c.setToggleTestButton = function(m){ - m.testButtonIn = ! m.testButtonIn -} -c.showToggleTestButton = function(v){ - m.testButtonIn - ? v.testButton.styles(`box-shadow: inset 5px 5px 8px #000000`) - : v.testButton.styles(`box-shadow: 5px 5px 8px #000000`) -} -///////////////////////// -c.updateMetaEvents = function(eventObject){ - m.eventObject = eventObject //the event object itself - m.source = eventObject.target //where the event took place - m.type = eventObject.type //what the event was - m.id = eventObject.target.id //the id of the element where the event occurred - - //Shortcuts to combine similar mobile and computer events - m.pressed = m.type === `mousedown` || m.type === `touchstart` - m.released = m.type === `mouseup` || m.type === `touchend` -}"; \ No newline at end of file diff --git a/data/collaborative/shadow/92e0d8216f938e9f6450634e2ac0d0da b/data/collaborative/shadow/92e0d8216f938e9f6450634e2ac0d0da deleted file mode 100755 index 9d1d5e8..0000000 --- a/data/collaborative/shadow/92e0d8216f938e9f6450634e2ac0d0da +++ /dev/null @@ -1,27 +0,0 @@ -s:856:"/* - -Created: 2018-07-10 -Modified: N/A -Purpose: Update the MVC - -*/ -/////////////////////////// -c.setToggleTestButton = function(m){ - m.testButtonIn = ! m.testButtonIn -} -c.showToggleTestButton = function(v){ - m.testButtonIn - ? v.testButton.styles(`box-shadow: inset 5px 5px 8px #000000`) - : v.testButton.styles(`box-shadow: 5px 5px 8px #000000`) -} -///////////////////////// -c.updateMetaEvents = function(eventObject){ - m.eventObject = eventObject //the event object itself - m.source = eventObject.target //where the event took place - m.type = eventObject.type //what the event was - m.id = eventObject.target.id //the id of the element where the event occurred - - //Shortcuts to combine similar mobile and computer events - m.pressed = m.type === `mousedown` || m.type === `touchstart` - m.released = m.type === `mouseup` || m.type === `touchend` -}"; \ No newline at end of file diff --git a/data/collaborative/shadow/9412cdcf8b955c57d704e4994234d890 b/data/collaborative/shadow/9412cdcf8b955c57d704e4994234d890 deleted file mode 100755 index add08a4..0000000 --- a/data/collaborative/shadow/9412cdcf8b955c57d704e4994234d890 +++ /dev/null @@ -1,102 +0,0 @@ -s:3012:"/*global L*/ -/*global m*/ -/*global v*/ -/*global c*/ - -/////////////////////////////////////////////// -c.updateModel = (eventObject) => { - c.setMetaEvents(eventObject, m); - const functionQualifiers = { - setResize: [m.resized], - uploadFiles: [m.source === v.fileElement, m.type === 'change'], - setPlay: [m.source === v.btnPlay, m.clicked], - playChosenSong: [m.source === v.documentSelector, m.type === 'change'], - respondToEnded: [m.source === v.player, m.type === 'ended'], - respondToPause: [m.source === v.player, m.type === 'pause'], - respondToPlay: [m.source === v.player, m.type === 'play'], - deleteFile: [m.source === v.btnDelete, m.clicked], - setPictureOnly: [m.source === v.pictureHolder || m.source === v.background, m.clicked], - setLogout: [m.source === v.footerGlass, m.clicked], - setLogin: [m.source === v.passwordInput, m.type === "keyup"], - setToggleNonStop: [m.source === v.btnNonStop, m.clicked], - } - L.runQualifiedFunctions(functionQualifiers, m, v, c) - //-----------------// - if(!m.resized){ - window.localStorage.setItem(`model`, JSON.stringify(m)); - } - c.updateView(v); -}; -//-----------------------------// -c.updateView = (v) => { - //c.showInfo(v) -}; -///////////////////////////////////////// -c.setMetaEvents = (eventObject, model) => { - let m = model;//model is "passed by reference" - m.id = eventObject.target.id; - m.source = eventObject.target - m.eventObject = eventObject; - //add current event object, discard oldest event object: - m.eventArray.unshift(m.eventObject); - m.eventArray.pop(); - - m.type = eventObject.type; - //add current, discard oldest: - m.priorType.unshift(m.type); - m.priorType.pop(); - - m.pressed = m.type === 'mousedown' || m.type === 'touchstart'; - //add current, discard oldest: - m.priorPressed.unshift(m.pressed); - m.priorPressed.pop(); - - m.released = m.type === 'mouseup' || m.type === 'touchend'; - //add current, discard oldest: - m.priorReleased.unshift(m.released); - m.priorReleased.pop(); - - m.moved = m.type === 'mousemove' || m.type === 'touchmove'; - //add current, discard oldest: - m.priorMoved.unshift(m.moved); - m.priorMoved.pop(); - - m.startTime = Date.now(); - m.elapsedTime = m.startTime - m.priorStartTime; - m.elapsedMinSec = L.secToMinSec(60 * m.elapsedTime); - m.priorStartTime = m.startTime; - - m.resized = ( - m.type === 'resize' || - m.type === 'load' || - m.type === 'DOMContentLoaded' || - m.type === 'orientationchange' - ); - /* - m.CLICK_TIME_MIN = 25 //in milliseconds - m.CLICK_TIME_MAX = 750 //milliseconds - */ - m.clicked = ( - m.released && - m.elapsedTime >= m.CLICK_TIME_MIN && - m.elapsedTime <= m.CLICK_TIME_MAX && - ( - m.priorType[1] === `touchstart` || - m.priorType[1] ==`mousedown`|| - m.priorType[1] === `touchmove` || - m.priorType[1] ==`mousemove` - ) - ); - /* - if(!m.moved){ - console.log(o) - } - */ -}; -//======================================// - - - - - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/941568d6e728e0f58bf59a686509defa b/data/collaborative/shadow/941568d6e728e0f58bf59a686509defa deleted file mode 100755 index 1809f82..0000000 --- a/data/collaborative/shadow/941568d6e728e0f58bf59a686509defa +++ /dev/null @@ -1,69 +0,0 @@ -s:1621:"/* - * Place copyright or other info here... - */ - -(function(global, $){ - - // Define core - var codiad = global.codiad, - scripts= document.getElementsByTagName('script'), - path = scripts[scripts.length-1].src.split('?')[0], - curpath = path.split('/').slice(0, -1).join('/')+'/'; - - // Instantiates plugin - $(function() { - codiad.tela_auto_save.init(); - }); - - codiad.tela_auto_save = { - - // Allows relative `this.path` linkage - path: curpath, - - init: function() { - - // Start your plugin here... - let editor = document.getElementsByClassName( 'ace_content' )[0]; - let auto_save_trigger = setInterval( this.auto_save, 500 ); - }, - - /** - * - * This is where the core functionality goes, any call, references, - * script-loads, etc... - * - */ - - auto_save: function() { - - let tabs = document.getElementsByClassName( "tab-item" ); - let path = codiad.active.getPath(); - let content = codiad.editor.getContent; - tabs = Array.from( tabs ); - tabs.forEach( function( m, i, a ) { - - // M = Current entry - // I = Index as integer - // A = Entire array - - if ( m.classList.contains( "active" ) ) { - - m.classList.remove( "changed" ) - } - }); - - codiad.active.save; - codiad.filemanager.saveFile(path, newContent, localStorage.removeItem(path)); - var session = codiad.active.sessions[path]; - if(typeof session != 'undefined') { - session.untainted = newContent; - session.serverMTime = mtime; - if (session.listThumb) session.listThumb.removeClass('changed'); - if (session.tabThumb) session.tabThumb.removeClass('changed'); - } - } - - }; - -})(this, jQuery); -"; \ No newline at end of file diff --git a/data/collaborative/shadow/97d4726a27b0dc089ff2a1ebd49794c6 b/data/collaborative/shadow/97d4726a27b0dc089ff2a1ebd49794c6 deleted file mode 100755 index 4541553..0000000 --- a/data/collaborative/shadow/97d4726a27b0dc089ff2a1ebd49794c6 +++ /dev/null @@ -1,28 +0,0 @@ -s:477:"/* - -Created: 2018-07-10 -Modified: N/A -Purpose: Why did we name this Qualify ... Designate is better - -*/ - -/*global L*/ -/*global m*/ -/*global v*/ -/*global c*/ - -c.designateFunction = function(eventObject){ - c.updateMetaEvents(eventObject) - let functionQualifiers = { - setToggleTestButton: [m.source === v.testButton, m.type === `click`], - /* - setXXY: [], - setXXZ: [], - setXYX: [], - setXYY: [], - */ - } - L.runQualifiedFunctions(functionQualifiers, m, v, c) -} -/////////////// -"; \ No newline at end of file diff --git a/data/collaborative/shadow/9efb45e0fb52aae6da0f0aafa65a2485 b/data/collaborative/shadow/9efb45e0fb52aae6da0f0aafa65a2485 deleted file mode 100755 index 2a1704a..0000000 --- a/data/collaborative/shadow/9efb45e0fb52aae6da0f0aafa65a2485 +++ /dev/null @@ -1,136 +0,0 @@ -s:2671:"//let prefixfree = require('prefixfree'); -let m = {}; -const v = {}; -const c = {}; -/*global L*/ - -//===================================// -c.initialize = (eventObject) => { - c.initializeModel() - m.musicFilesUrl = 'https://aaserver.abbas411.com/music/uploads/' - - if(window.localStorage.getItem(`model`)){ - //m = JSON.parse(window.localStorage.getItem(`model`)); - } - - c.getFileList() - - window.id = 'window'; - window.document.id = `document`; - L.attachAllElementsById(v); - - const eventTypes = [ - 'play', - 'pause', - 'ended', - 'mousedown', - 'touchstart', - 'mouseup', - 'touchend', - 'mousemove', - 'touchmove', - 'keypress', - 'keyup', - 'keydown', - 'input', - 'change', - 'resize', - 'orientationchange', - 'load', - 'DOMContentLoaded', - 'online', - 'offline', - ]; - - //Update the model in response to events - for (let eventType of eventTypes) { - window.addEventListener(eventType, c.updateModel, true); - } - - L.noPinchZoom(); - - //c.setLogout(m, c.showLogout, v) - - if(m.securityIsActive){ - L.loopCall(c.pollForPaswordWall, 100, v); - } - - c.setResize(m, c.showResize, v) - - c.queueInitialRandomSong() - -}; -//============================// - -c.initializeModel = function(){ - // meta events - m.eventArray = [{},{},{}]; - m.priorType = ["","","",]; - m.priorPressed = [false, false, false]; - m.priorReleased = [false, false, false]; - m.priorMoved = [false, false, false]; - - m.eventObject = {target:{id:"none"}, type: "none" }; - - m.source = m.eventObject.target; - m.id = m.eventObject.target.id; - - m.type = m.eventObject.type; - - m.pressed = m.type === 'mousedown' || m.type === 'touchstart'; - - m.released = m.type === 'mouseup' || m.type === 'touchend'; - - m.moved = m.type === 'mousemove' || m.type === 'touchmove'; - - m.priorStartTime; - m.startTime = Date.now(); - m.elapsedTime = m.startTime - m.priorStartTime; - m.priorStartTime = m.startTime; - - m.resized = true; - m.clicked = false; - - m.width = window.innerWidth - m.height = window.innerHeight - - // app states - m.securityIsActive = false - m.nonStop = true - - m.loggedIn = false - m.CLICK_TIME_MIN = 25; //in milliseconds - m.CLICK_TIME_MAX = 750; //milliseconds - m.MAX_WIDTH = 411;//pixels - - m.defaultBackground = 'images/twostalks.gif' - m.noPicture = true - m.pictureData = null - m.showPictureOnly = false - m.busyWithPictureOnly = false - m.pictureBusyId = 0 - - m.fractionArray = []; - m.averageUploadFraction = 0; - m.uploadPath = `../uploads/`; - //m.musicFilesUrl = 'http://abbas411.com/diymusic/uploads/' - m.musicFilesUrl = 'https://aaserver/abbas411.com/music/uploads/' - - - m.busyChangingSongs = false - m.busyResizing = false - m.playing = false - //============================// -} - - - - - - - - - - - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/a0debe38b2118dc397cfe4898ab46b9e b/data/collaborative/shadow/a0debe38b2118dc397cfe4898ab46b9e deleted file mode 100755 index 53b7f9e..0000000 --- a/data/collaborative/shadow/a0debe38b2118dc397cfe4898ab46b9e +++ /dev/null @@ -1,71 +0,0 @@ -s:1728:"open($destination, ZIPARCHIVE::CREATE)) { - return false; - } - - $source = str_replace('\\', '/', realpath($source)); - - if (is_dir($source) === true) - { - $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST); - - foreach ($files as $file) - { - $file = str_replace('\\', '/', $file); - - // Ignore "." and ".." folders - if( in_array(substr($file, strrpos($file, '/')+1), array('.', '..')) ) - continue; - - $file = realpath($file); - - if (is_dir($file) === true) - { - $zip->addEmptyDir(str_replace($source . '/', '', $file . '/')); - } - else if (is_file($file) === true) - { - $zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file)); - } - } - } - else if (is_file($source) === true) - { - $zip->addFromString(basename($source), file_get_contents($source)); - } - - return $zip->close(); -} -Zip('./web2/', './web2.zip'); - -?> - - - - - AA Server - - - -

    This page will eventually have styles and other options.

    -

    Utilities

    - - - Download This
    - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/a2a72e21333cf981f4a2281f1504cea3 b/data/collaborative/shadow/a2a72e21333cf981f4a2281f1504cea3 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/shadow/a2a72e21333cf981f4a2281f1504cea3 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/shadow/a6c8c908850fdd2fba740ab39de66cd2 b/data/collaborative/shadow/a6c8c908850fdd2fba740ab39de66cd2 deleted file mode 100755 index 19357ec..0000000 --- a/data/collaborative/shadow/a6c8c908850fdd2fba740ab39de66cd2 +++ /dev/null @@ -1,460 +0,0 @@ -s:14897:"//======================================| ORIGINAL |======================================= -/* - Author: Abbas Abdulmalik - Title: hsla color picker - Created: December 3, 2013 - Revised: May 20, 2016 - Purpose: A quick and easy way to choose colors for web apps - Notes: I know, I know: Polluting the global namespace; code not very declarative; - using my own old lame library functions; not enough comments; etc. - Try not to beat yourself up too much, because it still works :) -*/ -var dragFlag = true; -var radius = 50; -var saturation = ""; -var degrees = 0; -var mostRecentAngle; -var opacity = "0.95"; -var luminosity = 50; -var maximumRadius = 150; -var colorString = ""; -var complementString = ""; -var centerX = parseInt(window.innerWidth/2, 10); -var centerY = 204; -var x = -75 + centerX; -var y = 210; -var dx, dy; -var saturationSliderFlag = false; -var hueSliderFlag = false; -var lightnessSliderFlag = false; -var opacitySliderFlag = false; -var saturationNumFlag = false; -var hueNumFlag = false; -var lightnessNumFlag = false; -var opacityNumFlag = false; -var wheelInUse = false; - -//==========Event Handlers======================= -window.onload = function(){ - var yDirection = Math.floor( 2*Math.random() ) == 0 ? -1 : 1; - var yDistance = Math.floor(maximumRadius * Math.random()); - var y = centerY + yDirection*yDistance; - - //xDistance is now restricted by y and maximumRadius - //var xMaximum = sqrt(maximumRadius^2 - (y-centerY)^2). - - var xDirection = Math.floor( 2*Math.random() ) == 0 ? -1 : 1; - var xMaximum = Math.sqrt( maximumRadius*maximumRadius - (y - centerY)*(y - centerY) ); - var xDistance = Math.floor( xMaximum * Math.random() ); - var x = centerX + xDirection*xDistance; - - /*global id*/ - id('light').value = luminosity; - id('opacity').value = opacity; - showColor(x,y); - id('lightNum').value = luminosity; - id('opacityNum').value = opacity; - id('hueNum').value = degrees; - id('saturationNum').value= saturation; -}; - -window.onresize = function(){ - centerX = parseFloat(window.innerWidth/2, 10); -}; - -//click anywhere on the colored circle to choose the color and move the ball -/*global on*/ -on("mousedown",id('colorWheel'),function(e){ - x = e.clientX; - y = e.clientY; - showColor(x,y); -}); -//=============NEW DRAG AND NO DROP BELOW=================== -//https://stackoverflow.com/questions/17992543/how-do-i-drag-an-image-smoothly-around-the-screen-using-pure-javascript -var dragAllowed = false; -on("mousedown", id('ball'), allowDrag); -on("mousemove", id('content'), dragDiv); -on("mouseup", id('ball'), prohibitDrag); -on("mouseout", id('ball'), maybeProhibitDrag); -//=========================================== -function allowDrag(e){ - dragAllowed = true; -} -function dragDiv(e){ - if (dragAllowed){ - x = e.clientX; - y = e.clientY; - showColor(x,y); - } -} -//============================================ -function prohibitDrag(e){ - dragAllowed=false; -} -//============================================ -function maybeProhibitDrag(e){// makes it hard to drop the ball - //if dropped prematurely, see if we are 15 pixels away from the ball's coordinates - var leftBehind = Math.abs(x - e.clientX)> 15 && Math.abs(y - e.clientY) > 15; - //see if we're beyond the colored circle - var newRadius = Math.sqrt( (e.clientX - centerX)*(e.clientX - centerX) + (centerY - e.clientY)*(centerY - e.clientY) ); - // if mouse's cursor far enough away from the ball, go ahead and drop it - if(leftBehind || (newRadius > maximumRadius)){ - dragAllowed=false; - } -} -//=============NEW DRAG AND NO DROP ABOVE==================== -//============keyboard input numbers event handlers -id('hueNum').onchange = changeHue; -id('hueNum').oninput = changeHue; -function changeHue(){ - hueNumFlag = true; - if(!hueSliderFlag){ - var newValue = parseFloat(id('hueNum').value); - if ( newValue > 360 && newValue < 364 ){//361,2,3 - id('hue').value = newValue - 360; - id('hueNum').value = newValue; - } - if ( newValue < 0 && newValue > -4 ){//-1,-2,-3 - id('hue').value = newValue + 360; - id('hueNum').value = newValue; - } - fixNumberError('hueNum', 'hue',0 ,360); - id('hue').value = id('hueNum').value; - mostRecentAngle = id('hueNum').value; - newHue(); - } - hueNumFlag = false; -} -id('saturationNum').onchange = changeSaturation; -id('saturationNum').oninput = changeSaturation; -function changeSaturation(){ - saturationNumFlag = true; - if(!saturationSliderFlag){ - fixNumberError('saturationNum','saturation', 0, 100); - id('saturation').value = id('saturationNum').value; - hueSatCore(); - } - saturationNumFlag = false; -}; -id('lightNum').onchange = changeLight; -id('lightNum').oninput = changeLight; -function changeLight(){ - lightnessNumFlag = true; - if(!lightnessSliderFlag){ - fixNumberError('lightNum', 'light',0 ,100); - id('light').value = id('lightNum').value; - coreColorSetter(); - } - lightnessNumFlag = false; -}; -id('opacityNum').onchange = changeOpacity; -id('opacityNum').oninput = changeOpacity; -function changeOpacity(){ - opacityNumFlag = true; - if(!opacitySliderFlag){ - fixNumberError('opacityNum', 'opacity', 0, 1.00); - id('opacity').value = id('opacityNum').value; - coreColorSetter(); - id('opacityNum').value = parseFloat(opacity).toFixed(2); - } - opacityNumFlag = false; -}; -//==========mouse scroll wheel=============== -//window.addEventListener("DOMMouseScroll",...;//Firefox -/*global attachEventHandler*/ -attachEventHandler(window, "mousewheel", mouseWheelHandler); -function mouseWheelHandler(e){ - if(!wheelInUse){ - id('hueNum').value = parseInt(id('hueNum').value, 10) + wheelDelta(e); - changeHue(); - return false; - } -} -function wheelDelta(e){ - e = window.event || e; //old IE possible - var delta = Math.max(-1, Math.min(1,(e.wheelDelta || -e.detail))); - return delta; -} -//helper -/*global isNumber*/ -function fixNumberError(elemID1, elemID2 ,min, max){ - if(id(elemID1).value < min || id(elemID1).value > max || !isNumber(id(elemID1).value)){ - id(elemID1).value = id(elemID2).value; - } -} -//========Slider event handlers============================ -id('saturation').oninput = function(){ - slideSaturation(); -}; -id('saturation').onchange = function(){ - slideSaturation(); -}; -id('hue').oninput = function(){ - newHue(); -}; -id('hue').onchange = function(){ - newHue(); -}; -// helper=== -function newHue(){ - hueSliderFlag = true; - var currentAngle = id('hue').value ; - var rad = degreesToRadians(mostRecentAngle); - var x = (parseFloat(id('saturation').value) * maximumRadius * Math.cos(rad) / 100 + centerX); - var y = (centerY - parseFloat(id('saturation').value) * maximumRadius * Math.sin(rad) / 100); - - var dx = x - centerX; - var dy = centerY - y; - var radius = Math.round(Math.sqrt(dy*dy + dx*dx)); - if (radius <= maximumRadius){ - moveBall(x,y); - } - showColor(x,y); - mostRecentAngle = currentAngle; - if(!hueNumFlag){ - id('hueNum').value = currentAngle; - } - hueSliderFlag = false; -} -//====helper -function slideSaturation(){ - saturationSliderFlag = true; - if(!saturationNumFlag){ - id('saturationNum').value = id('saturation').value; - } - hueSatCore(); - saturationSliderFlag = false; -} - -// helper -function hueSatCore(){ - var currentAngle = mostRecentAngle; - var rad = degreesToRadians(mostRecentAngle); - var x = (parseFloat(id('saturation').value) * maximumRadius * Math.cos(rad) / 100 + centerX); - var y = (centerY - parseFloat(id('saturation').value) * maximumRadius * Math.sin(rad) / 100); - - var dx = x - centerX; - var dy = centerY - y; - var radius = Math.round(Math.sqrt(dy*dy + dx*dx)); - if (radius <= maximumRadius){ - moveBall(x,y); - } - showColor(x,y); - mostRecentAngle = currentAngle; -} -//=============== -id('light').oninput = function(){ - lightnessSliderFlag = true; - coreColorSetter(); - if(!lightnessNumFlag){ - id('lightNum').value = luminosity; - } - lightnessSliderFlag = false; -}; -id('light').onchange = function(){ - lightnessSliderFlag = true; - coreColorSetter(); - if(!lightnessNumFlag){ - id('lightNum').value = luminosity; - } - lightnessSliderFlag = false; -}; -id('opacity').oninput = function(){ - opacitySliderFlag = true; - coreColorSetter(); - if(!opacityNumFlag){ - id('opacityNum').value = opacity; - } - opacitySliderFlag = false; -}; -id('opacity').onchange = function(){ - opacitySliderFlag = true; - coreColorSetter(); - if(!opacityNumFlag){ - id('opacityNum').value = opacity; - } - opacitySliderFlag = false; -}; -id('hsla').ondblclick = function(){ - //copyToClipboard(id('hsla').innerHTML); - var compDegrees; - if( degrees > 180){ - compDegrees = degrees - 180; - }else{ - compDegrees = degrees + 180; - } - copyToClipboard(" "+colorString + ", complementary hue: "+ compDegrees +" "); -}; -function copyToClipboard(text) { - prompt("Copy to Clipboard\nFor PC: Ctrl+C, Enter\nFor Mac: Cmd-C, Enter", text); -} -//========mouse wheel event handlers for labels, sliders and numbers (controls)====== -var aryControls = [id('satSpan'), id('lightSpan'), id('opacitySpan'), id("saturation"),id("light"), id("opacity"), - id("saturationNum"),id("lightNum"), id("opacityNum")]; - -var aryWheelHandlers = [ satWheelHandler, lightWheelHandler, opacityWheelHandler,satWheelHandler, lightWheelHandler, opacityWheelHandler, - satWheelHandler, lightWheelHandler, opacityWheelHandler]; -/*global forTwinArrays*/ -forTwinArrays(aryControls, aryWheelHandlers, function(aSlider, aHandler){ - on("mousewheel", aSlider, aHandler); -}); -/*global forAll*/ -forAll(aryControls, function(aSlider){ - on("mouseout", aSlider, function(){ - wheelInUse = false; - }); -}); -function satWheelHandler(e){ - wheelInUse = true; - var delta = wheelDelta(e); - var newSaturation = parseFloat(id('saturationNum').value) + delta; - id('saturationNum').value = newSaturation; - id('saturation').value = newSaturation; - fixNumberError('saturationNum', 'saturation', 0, 100); - slideSaturation(); -} -function lightWheelHandler(e){ - wheelInUse = true; - var delta = wheelDelta(e); - var newLightness = parseFloat(id('lightNum').value) + delta; - id('lightNum').value = newLightness; - id('light').value = newLightness; - fixNumberError('lightNum', 'light', 0, 100); - coreColorSetter(); -} -function opacityWheelHandler(e){ - wheelInUse = true; - var delta = wheelDelta(e); - delta *= 0.01; - var newOpacity = (parseFloat(id('opacityNum').value) + delta).toFixed(2); - id('opacityNum').value = newOpacity; - id('opacity').value = newOpacity; - fixNumberError('opacityNum', 'opacity', 0, 1.00); - coreColorSetter(); -} -//=============helper functions======= -function radiansToDegrees(rad){ - return 180*rad/Math.PI; -} -function degreesToRadians(degrees){ - return Math.PI*degrees/180; -} -//==================================================== -function showColor(x,y){ - - dx = x - centerX; - dy = centerY - y; - var rad = Math.atan(dy/dx); - degrees = Math.round(radiansToDegrees(rad)); - radius = Math.round(Math.sqrt(dy*dy + dx*dx)); - if (radius <= maximumRadius){ - id('radius').value = radius; - id('x').value = parseFloat(dx).toFixed(2); - id('y').value = parseFloat(dy).toFixed(2); - if ( (dx < 0) && (dy <= 0) ){// - - - degrees += 180; - }else if ( (dx >= 0) && (dy < 0) ){// + - - degrees += 360; - }else if ( (dx < 0) && (dy > 0) ){// - + - degrees += 180; - } - if (!isNumber(degrees)){ - degrees = 0; - } - id('angle').value = degrees; - moveBall(x,y); - setColors(); - } -} -//============================ -function moveBall(x,y){ - id('ball').style.marginTop = "" + (y - centerY + 3 ) +"px"; //3 or 4 px minor adjustment added for centering pointer - id('ball').style.marginLeft = "" + (x - centerX) +"px"; -} -//=============================== -function setColors(){ - mostRecentAngle = degrees; - if(saturationSliderFlag){ - saturation = id('saturation').value; - } - else{ - saturation = "" + Math.round((radius*100/maximumRadius)); - } - luminosity = Math.round(parseFloat(id('light').value)); - coreColorSetter(); -} -function coreColorSetter(){ - luminosity = id('light').value; - opacity = parseFloat(id('opacity').value); - opacity = opacity.toFixed(2); - var compAngle; - //=================== - if(mostRecentAngle > 180){ - compAngle = parseInt(mostRecentAngle - 180, 10); - } - else{ - compAngle = parseInt(mostRecentAngle + 180, 10); - } - //================= - colorString = "hsla(" + mostRecentAngle + ", " + saturation + "%, " +luminosity + "%, "+ opacity + ")"; - complementString = "hsla(" + compAngle + ", " + saturation + "%," +luminosity + "%, "+ opacity + ")"; - id('bod').style.background = colorString; - id('hsla').innerHTML = colorString; - id('hsla').style.backgroundColor = complementString; - - if(!hueSliderFlag){ - id('hue').value = mostRecentAngle; - } - if(!saturationSliderFlag){ - id('saturation').value = saturation; - } - if(!hueNumFlag){ - id('hueNum').value = mostRecentAngle; - } - if(!saturationNumFlag){ - id('saturationNum').value = saturation; - } -} - -//================= mnemonic ====================== - -var mword = document.getElementById("mnemonicWord"); -var mpic = document.getElementById("mnemonicPicture"); - -(function(){ - - var pictureVisible = false; - - mword.onclick = togglePicture; - mword.onmouseout = hide; - mpic.onclick = hide; - - //----| Internal Helpers |---- - function togglePicture(e){ - if(pictureVisible){ - hide(e); - } - else{ - showPicture(e); - pictureVisible = true; - } - } - function hide(e){ - hidePicture(e); - pictureVisible = false; - } -})(); - -//----| Helpers |---- -function hidePicture(e){ - mpic.style.opacity = 0; - mpic.style.zIndex = -5; -} -function showPicture(e){ - mpic.style.opacity = 1; - mpic.style.zIndex = 5; -} - - - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/a7591bf8af26986d68f36815a5ea5273 b/data/collaborative/shadow/a7591bf8af26986d68f36815a5ea5273 deleted file mode 100755 index b7d7165..0000000 --- a/data/collaborative/shadow/a7591bf8af26986d68f36815a5ea5273 +++ /dev/null @@ -1,33 +0,0 @@ -s:987:" - - - Mobile Programming Template - - - - - - - - - - - - -

    Header 1

    -

    Header 2

    -

    Header 3

    -

    Hello! Paragraph

    -
    - - - - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/a7f6228ec1c43e9c52f5e91d07d4b453 b/data/collaborative/shadow/a7f6228ec1c43e9c52f5e91d07d4b453 deleted file mode 100755 index 2a20dc3..0000000 --- a/data/collaborative/shadow/a7f6228ec1c43e9c52f5e91d07d4b453 +++ /dev/null @@ -1,3 +0,0 @@ -s:7:"hello - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/a8419f9f1457039c7fbc9740927be4e0 b/data/collaborative/shadow/a8419f9f1457039c7fbc9740927be4e0 deleted file mode 100755 index 0120813..0000000 --- a/data/collaborative/shadow/a8419f9f1457039c7fbc9740927be4e0 +++ /dev/null @@ -1,174 +0,0 @@ -s:6166:"actives = getJSON('active.php'); - } - - ////////////////////////////////////////////////////////////////// - // List User's Active Files - ////////////////////////////////////////////////////////////////// - - public function ListActive() - { - $active_list = array(); - $tainted = false; - $root = WORKSPACE; - if ($this->actives) { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']==$this->username) { - if ($this->isAbsPath($data['path'])) { - $root = ""; - } else { - $root = $root.'/'; - } - if (file_exists($root.$data['path'])) { - $focused = isset($data['focused']) ? $data['focused'] : false; - $active_list[] = array('path'=>$data['path'], 'focused'=>$focused); - } else { - unset($this->actives[$active]); - $tainted = true; - } - } - } - } - if ($tainted) { - saveJSON('active.php', $this->actives); - } - echo formatJSEND("success", $active_list); - } - - ////////////////////////////////////////////////////////////////// - // Check File - ////////////////////////////////////////////////////////////////// - - public function Check() - { - $cur_users = array(); - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']!=$this->username && $data['path']==$this->path) { - $cur_users[] = $data['username']; - } - } - if (count($cur_users)!=0) { - //echo formatJSEND("error", "Warning: File ".substr($this->path, strrpos($this->path, "/")+1)." Currently Opened By: " . implode(", ", $cur_users)); - } else { - echo formatJSEND("success"); - } - } - - ////////////////////////////////////////////////////////////////// - // Add File - ////////////////////////////////////////////////////////////////// - - public function Add() - { - $process_add = true; - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']==$this->username && $data['path']==$this->path) { - $process_add = false; - } - } - if ($process_add) { - $this->actives[] = array("username"=>$this->username,"path"=>$this->path); - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - } - - ////////////////////////////////////////////////////////////////// - // Rename File - ////////////////////////////////////////////////////////////////// - - public function Rename() - { - $revised_actives = array(); - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username'])) { - $revised_actives[] = array("username"=>$data['username'],"path"=>str_replace($this->path, $this->new_path, $data['path'])); - } - } - saveJSON('active.php', $revised_actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Remove File - ////////////////////////////////////////////////////////////////// - - public function Remove() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username'] && $this->path==$data['path']) { - unset($this->actives[$active]); - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Remove All Files - ////////////////////////////////////////////////////////////////// - - public function RemoveAll() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username']) { - unset($this->actives[$active]); - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Mark File As Focused - // All other files will be marked as non-focused. - ////////////////////////////////////////////////////////////////// - - public function MarkFileAsFocused() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username']) { - $this->actives[$active]['focused']=false; - if ($this->path==$data['path']) { - $this->actives[$active]['focused']=true; - } - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } -} -"; \ No newline at end of file diff --git a/data/collaborative/shadow/a86d8153e2f67aeb9590093a5c30a149 b/data/collaborative/shadow/a86d8153e2f67aeb9590093a5c30a149 deleted file mode 100755 index 903a3c5..0000000 --- a/data/collaborative/shadow/a86d8153e2f67aeb9590093a5c30a149 +++ /dev/null @@ -1,70 +0,0 @@ -s:1864:"/* - * Copyright (c) Codiad & Kent Safranski (codiad.com), distributed - * as-is and without warranty under the MIT License. See - * [root]/license.txt for more. This information must remain intact. - */ - -(function(global, $){ - - var codiad = global.codiad, - scripts= document.getElementsByTagName('script'), - path = scripts[scripts.length-1].src.split('?')[0], - curpath = path.split('/').slice(0, -1).join('/')+'/'; - - - $(function() { - codiad.colorPicker.init(); - }); - - codiad.colorPicker = { - - path: curpath, - - init: function() { - - $.loadScript(this.path+"color_parser.js"); - $.loadScript(this.path+"jquery.colorpicker.js"); - - }, - - open: function() { - - codiad.modal.load(400, this.path+'dialog.php'); - - }, - - insert: function(type) { - var color = ''; - if (type == 'rgb') { - color = $('.colorpicker_rgb_r input') - .val() + ',' + $('.colorpicker_rgb_g input') - .val() + ',' + $('.colorpicker_rgb_b input') - .val(); - if (returnRGBWrapper === false) { - insert = (color); - } else { - insert = ('rgb(' + color + ')'); - } - } else { - color = $('.colorpicker_hex input') - .val(); - if (sellength == 3 || sellength == 6) { - if (seltest) { - insert = color; - } else { - insert = '#' + color; - } - } else { - insert = '#' + color; - } - } - - codiad.active.insertText(insert); - codiad.modal.unload(); - - } - - }; - -})(this, jQuery); -"; \ No newline at end of file diff --git a/data/collaborative/shadow/a8774609eda0bf3aa1cb32a96b594604 b/data/collaborative/shadow/a8774609eda0bf3aa1cb32a96b594604 deleted file mode 100755 index 213f5eb..0000000 --- a/data/collaborative/shadow/a8774609eda0bf3aa1cb32a96b594604 +++ /dev/null @@ -1,444 +0,0 @@ -s:16229:"/* - * Copyright (c) Codiad & Andr3as, distributed - * as-is and without warranty under the MIT License. - * See http://opensource.org/licenses/MIT for more information. - * This information must remain intact. - */ - -(function(global, $){ - - var codiad = global.codiad, - scripts = document.getElementsByTagName('script'), - path = scripts[scripts.length-1].src.split('?')[0], - curpath = path.split('/').slice(0, -1).join('/')+'/'; - - $(function() { - codiad.CodeSettings.init(); - }); - - codiad.CodeSettings = { - - path: curpath, - file: "", - open: false, - redo: false, - settings: null, - template: "", - commands: null, - entries: 0, - - init: function() { - var _this = this; - this.$pSave = this.saveExpert.bind(this); - this.$cSave = codiad.active.save.bind(this); - //Load keymap - this.load(); - //Load template - $.get(this.path+"template.html", function(html){ - _this.template = html; - }); - $.getScript(this.path+"beautify.js"); - //Load default commands - $.getJSON(this.path+"default.commands.json", function(json){ - _this.commands = json; - }); - //Set keymap - amplify.subscribe("active.onOpen", function(path){ - //Overwrite save commands - var manager = codiad.editor.getActive().commands; - manager.addCommand({ - name: 'Save', - bindKey: "Ctrl-S", - exec: function () { - codiad.active.save(); - } - }); - _this.setKeys(); - if (_this.open && path === _this.file && _this.redo) { - _this.addCommands(); - } - if (codiad.editor.getActive() !== null) { - _this.commands = codiad.editor.getActive().commands.byName; - } - //Save current existing commands - setTimeout(function(){ - $.post(_this.path+"controller.php?action=saveCommands", {commands: JSON.stringify(_this.commands)}, function(data){ - var json = JSON.parse(data); - if (json.status == "error") { - codiad.message.error(json.message); - } - }); - }, 10); - }); - amplify.subscribe("active.onFocus", function(path){ - if (_this.open) { - if (path === _this.file) { - _this.addCommands(); - } else { - _this.restoreCommands(); - } - } - }); - amplify.subscribe("active.onClose", function(path){ - if (_this.file === path) { - _this.open = false; - } - }); - - amplify.subscribe('settings.dialog.save', function(){ - if ($('#hotkey_div').length > 0) { - _this.saveDialog(); - } - }); - //Live feature - $('.command_name').live("change", function(){ - var line = $(this).attr('data-line'); - var name = $(this).val(); - var com = _this.commands[name].bindKey; - if (typeof(com.win) != 'undefined') { - $('.command_win[data-line="'+line+'"]').val(com.win); - } else { - if (!$.isPlainObject(com) && !$.isArray(com)) { - $('.command_win[data-line="'+line+'"]').val(com); - } - } - if (typeof(com.win) != 'undefined') { - $('.command_mac[data-line="'+line+'"]').val(com.mac); - } else { - if (!$.isPlainObject(com) && !$.isArray(com)) { - $('.command_mac[data-line="'+line+'"]').val(com); - } - } - - }); - $('.command_win').live("change", function(){ - _this.onCommandChange(this); - }); - $('.command_mac').live("change", function(){ - _this.onCommandChange(this); - }); - }, - - ////////////////////////////////////////////////////////// - // - // Show dialog - // - ////////////////////////////////////////////////////////// - showDialog: function() { - codiad.settings.show(this.path.replace(location.toString(), "") + '/dialog.php'); - }, - - ////////////////////////////////////////////////////////// - // - // Load current settings - // - ////////////////////////////////////////////////////////// - load: function() { - var _this = this; - $.getJSON(this.path+"controller.php?action=load", function(json){ - _this.settings = json || {}; - _this.settings.keys = json.keys || {}; - }); - }, - - ////////////////////////////////////////////////////////// - // - // Set keybindings of settings - // - ////////////////////////////////////////////////////////// - setKeys: function() { - var _this = this; - setTimeout(function(){ - if (codiad.editor.getActive() !== null) { - var manager = codiad.editor.getActive().commands; - //var command; - for (var i = 0; i < _this.settings.keys.length; i++) { - var element = _this.settings.keys[i]; - if (typeof(manager.byName[element.name]) != 'undefined') { - manager.addCommand({ - name: element.name, - bindKey: element.bindKey, - exec: manager.byName[element.name].exec - }); - } - } - } - }, 50); - }, - - ////////////////////////////////////////////////////////// - // - // Open file for expert settings - // - ////////////////////////////////////////////////////////// - edit: function() { - var _this = this; - //Open file and load currrent settings - $.getJSON(this.path+"controller.php?action=open", function(json){ - if (json.status !== "error") { - var opt = { - "indent_size": codiad.editor.settings.tabSize, - "indent_char": " ", - "indent_with_tabs": !codiad.editor.settings.softTabs - }; - _this.content = json.content; - json.content = js_beautify(json.content, opt); - _this.file = json.name; - _this.open = true; - codiad.modal.unload(); - codiad.active.open(json.name, json.content, json.mtime, false, true); - } else { - codiad.message.error(json.message); - } - }); - }, - - ////////////////////////////////////////////////////////// - // - // Save expert settings - // - ////////////////////////////////////////////////////////// - saveExpert: function() { - var _this = this; - var content = codiad.editor.getContent(); - try { - this.settings = JSON.parse(content); - } catch (e) { - codiad.message.error("Error: "+e); - return false; - } - this.save(); - return true; - }, - - ////////////////////////////////////////////////////////// - // - // Save dialog settings - // - ////////////////////////////////////////////////////////// - saveDialog: function() { - var buf = []; - var line; - $('.command_line').each(function(i, item){ - var obj = {"name": "","bindKey": {"win": "","mac": ""}}; - line = $(item).attr("data-line"); - obj.name = $('.command_name[data-line="'+line+'"]').val(); - obj.bindKey.win = $('.command_win[data-line="'+line+'"]').val(); - obj.bindKey.mac = $('.command_mac[data-line="'+line+'"]').val(); - buf.push(obj); - }); - if ($.isArray(this.settings)) { - this.settings = {}; - } - this.settings.keys = buf; - this.save(); - }, - - ////////////////////////////////////////////////////////// - // - // Save current user settings - // - ////////////////////////////////////////////////////////// - save: function() { - var _this = this; - var content = this.settings; - content = JSON.stringify(content); - $.post(this.path+"controller.php?action=save", {"content": content}, function(data){ - var json = JSON.parse(data); - if (json.status !== "error") { - $('li[data-path="'+_this.file+'"]').removeClass('changed'); - _this.load(); - _this.setKeys(); - codiad.message.success(json.message); - } else { - codiad.message.error(json.message); - } - }); - }, - - ////////////////////////////////////////////////////////// - // - // Change save command for expert settings - // - ////////////////////////////////////////////////////////// - addCommands: function() { - if (codiad.editor.getActive() === null) { - return false; - } - var manager = codiad.editor.getActive().commands; - try { - manager.commands.Save.exec = this.$pSave; - this.redo = false; - } catch (e) { - this.redo = true; - } - }, - - ////////////////////////////////////////////////////////// - // - // Restore save command after expert settings - // - ////////////////////////////////////////////////////////// - restoreCommands: function() { - if (codiad.editor.getActive() === null) { - return false; - } - var manager = codiad.editor.getActive().commands; - try { - manager.commands.Save.exec = this.$cSave; - } catch(e) {} - }, - - ////////////////////////////////////////////////////////// - // - // Display commands in dialog - // - ////////////////////////////////////////////////////////// - show: function() { - var _this = this; - $.each(this.settings.keys, function(i, item){ - _this.addEntry(item.name, item.bindKey.win, item.bindKey.mac); - }); - $('#hotkey_div').css('max-height', function(){ - return 0.6*window.innerHeight + "px"; - }); - }, - - ////////////////////////////////////////////////////////// - // - // Add new command - // - // Parameter - // - // name - {String} - Name of command - // win - {String} - Command for win - // mac - {String} - Command for mac - // - ////////////////////////////////////////////////////////// - addEntry: function(name, win, mac) { - var coms = this.getCommands(); - if (coms === false) { - return false; - } - var template = this.template; - var option = ""; - for (var i = 0; i < coms.length; i++) { - if (coms[i].name == name) { - option += ""; - } else { - option += ""; - } - } - template = template.replace("__options__", option); - template = template.replace("__win__", win); - template = template.replace("__mac__", mac); - template = template.replace(new RegExp("__line__", "g"), this.entries++); - $('#hotkey_list').append(template); - this.setDelete(); - }, - - ////////////////////////////////////////////////////////// - // - // Add new empty command - // - ////////////////////////////////////////////////////////// - add: function() { - this.addEntry("","",""); - $('.command_name:last').trigger('change'); - }, - - ////////////////////////////////////////////////////////// - // - // Activate delete button - // - ////////////////////////////////////////////////////////// - setDelete: function(){ - $('.command_remove').click(function(){ - var line = $(this).attr("data-line"); - $('.command_line[data-line="'+line+'"]').remove(); - return false; - }); - }, - - ////////////////////////////////////////////////////////// - // - // Get current commands or a fallback - // - ////////////////////////////////////////////////////////// - getCommands: function() { - var commands; - if (codiad.editor.getActive() === null) { - if (this.commands === null) { - codiad.message.error("Open file to display all commands!"); - return false; - } else { - commands = this.commands; - } - } else { - commands = codiad.editor.getActive().commands.byName; - } - - var buf = []; - $.each(commands, function(i, item){ - buf.push(item); - }); - buf.sort(function(a,b){ - var newBuf = [a.name,b.name]; - if (a === b) { - return 0; - } - newBuf.sort(); - if (newBuf[0] === a.name) { - return -1; - } else { - return 1; - } - }); - return buf; - }, - - ////////////////////////////////////////////////////////// - // - // Display help command - // - ////////////////////////////////////////////////////////// - help: function() { - codiad.modal.load(400, this.path+"dialog.php?action=help"); - }, - - ////////////////////////////////////////////////////////// - // - // Check if command is already used - // - // Parameter - // - // field - {jQuery objcet} - Field to check - // - ////////////////////////////////////////////////////////// - onCommandChange: function(field) { - var type = 'win'; - if ($(field).hasClass('.command_mac')) { - type = 'mac'; - } - var value = $(field).val(); - if (this.commands === null) { - return false; - } - var com; - $.each(this.commands, function(i, item){ - if (typeof(item.bindKey) == 'undefined') { - return; - } - if (typeof(item.bindKey[type]) == 'undefined') { - com = item.bindKey; - } else { - com = item.bindKey[type]; - } - if (value === com) { - codiad.message.notice("Command already used!"); - return false; - } - }); - } - }; -})(this, jQuery);"; \ No newline at end of file diff --git a/data/collaborative/shadow/abaaf90695610e34effe00775cd6f641 b/data/collaborative/shadow/abaaf90695610e34effe00775cd6f641 deleted file mode 100755 index b61100b..0000000 --- a/data/collaborative/shadow/abaaf90695610e34effe00775cd6f641 +++ /dev/null @@ -1,195 +0,0 @@ -s:5841:""; - saveFile($file, $data); -} - -function encryptPassword($p) -{ - return sha1(md5($p)); -} - -function cleanUsername($username) -{ - return preg_replace('#[^A-Za-z0-9'.preg_quote('-_@. ').']#', '', $username); -} - -function isAbsPath($path) -{ - return $path[0] === '/'; -} - -function cleanPath($path) -{ - - // prevent Poison Null Byte injections - $path = str_replace(chr(0), '', $path); - - // prevent go out of the workspace - while (strpos($path, '../') !== false) { - $path = str_replace('../', '', $path); - } - - return $path; -} - -////////////////////////////////////////////////////////////////////// -// Verify no overwrites -////////////////////////////////////////////////////////////////////// - -if (!file_exists($users) && !file_exists($projects) && !file_exists($active)) { - ////////////////////////////////////////////////////////////////// - // Get POST responses - ////////////////////////////////////////////////////////////////// - - $username = cleanUsername($_POST['username']); - $password = encryptPassword($_POST['password']); - $project_name = $_POST['project_name']; - if (isset($_POST['project_path'])) { - $project_path = $_POST['project_path']; - } else { - $project_path = $project_name; - } - $timezone = $_POST['timezone']; - - ////////////////////////////////////////////////////////////////// - // Create Projects files - ////////////////////////////////////////////////////////////////// - - $project_path = cleanPath($project_path); - - if (!isAbsPath($project_path)) { - $project_path = str_replace(" ", "_", preg_replace('/[^\w-\.]/', '', $project_path)); - mkdir($workspace . "/" . $project_path); - } else { - $project_path = cleanPath($project_path); - if (substr($project_path, -1) == '/') { - $project_path = substr($project_path, 0, strlen($project_path)-1); - } - if (!file_exists($project_path)) { - if (!mkdir($project_path.'/', 0755, true)) { - die("Unable to create Absolute Path"); - } - } else { - if (!is_writable($project_path) || !is_readable($project_path)) { - die("No Read/Write Permission"); - } - } - } - $project_data = array("name"=>$project_name,"path"=>$project_path); - - saveJSON($projects, array($project_data)); - - ////////////////////////////////////////////////////////////////// - // Create Users file - ////////////////////////////////////////////////////////////////// - - $user_data = array("username"=>$username,"password"=>$password,"project"=>$project_path); - - saveJSON($users, array($user_data)); - - ////////////////////////////////////////////////////////////////// - // Create Active file - ////////////////////////////////////////////////////////////////// - - saveJSON($active, array('')); - - ////////////////////////////////////////////////////////////////// - // Create Config - ////////////////////////////////////////////////////////////////// - - - $config_data = 'actives = getJSON('active.php'); - } - - ////////////////////////////////////////////////////////////////// - // List User's Active Files - ////////////////////////////////////////////////////////////////// - - public function ListActive() - { - $active_list = array(); - $tainted = false; - $root = WORKSPACE; - if ($this->actives) { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']==$this->username) { - if ($this->isAbsPath($data['path'])) { - $root = ""; - } else { - $root = $root.'/'; - } - if (file_exists($root.$data['path'])) { - $focused = isset($data['focused']) ? $data['focused'] : false; - $active_list[] = array('path'=>$data['path'], 'focused'=>$focused); - } else { - unset($this->actives[$active]); - $tainted = true; - } - } - } - } - if ($tainted) { - saveJSON('active.php', $this->actives); - } - echo formatJSEND("success", $active_list); - } - - ////////////////////////////////////////////////////////////////// - // Check File - ////////////////////////////////////////////////////////////////// - - public function Check() - { - $cur_users = array(); - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']!=$this->username && $data['path']==$this->path) { - $cur_users[] = $data['username']; - } - } - if (count($cur_users)!=0) { - //echo formatJSEND("error", "Warning: File ".substr($this->path, strrpos($this->path, "/")+1)." Currently Opened By: " . implode(", ", $cur_users)); - } else { - echo formatJSEND("success"); - } - } - - ////////////////////////////////////////////////////////////////// - // Add File - ////////////////////////////////////////////////////////////////// - - public function Add() - { - $process_add = true; - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']==$this->username && $data['path']==$this->path) { - $process_add = false; - } - } - if ($process_add) { - $this->actives[] = array("username"=>$this->username,"path"=>$this->path); - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - } - - ////////////////////////////////////////////////////////////////// - // Rename File - ////////////////////////////////////////////////////////////////// - - public function Rename() - { - $revised_actives = array(); - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username'])) { - $revised_actives[] = array("username"=>$data['username'],"path"=>str_replace($this->path, $this->new_path, $data['path'])); - } - } - saveJSON('active.php', $revised_actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Remove File - ////////////////////////////////////////////////////////////////// - - public function Remove() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username'] && $this->path==$data['path']) { - unset($this->actives[$active]); - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Remove All Files - ////////////////////////////////////////////////////////////////// - - public function RemoveAll() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username']) { - unset($this->actives[$active]); - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Mark File As Focused - // All other files will be marked as non-focused. - ////////////////////////////////////////////////////////////////// - - public function MarkFileAsFocused() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username']) { - $this->actives[$active]['focused']=false; - if ($this->path==$data['path']) { - $this->actives[$active]['focused']=true; - } - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } -} -"; \ No newline at end of file diff --git a/data/collaborative/shadow/af2d3669b4f915c4b09d4a8bb8dea1c9 b/data/collaborative/shadow/af2d3669b4f915c4b09d4a8bb8dea1c9 deleted file mode 100755 index d4b12fa..0000000 --- a/data/collaborative/shadow/af2d3669b4f915c4b09d4a8bb8dea1c9 +++ /dev/null @@ -1,795 +0,0 @@ -s:26248:"/*global L*/ -/*global m*/ -/*global v*/ -/*global c*/ -//////////////////////////// -c.setClearSearch = (m)=>{ - v.txtSearch.value = '' //clear the search text - c.setSearchResult(m) -} -c.showClearSearch = (v)=>{ - c.showSearchResult(v) -} -//////////////////////////// -c.setSearchResult = function(m){ - if(m.nowEditing){return} // !m.nowEditing is now set as a function qualifier - m.handlingSearch = true - m.searchIsEmpty = v.txtSearch.value === '' - if(m.currentContactsArray[m.selectedIndex]){ - m.priorName = m.currentContactsArray[m.selectedIndex][0]+m.currentContactsArray[m.selectedIndex][1] - } - m.sameContact = false - - //get result of search and place in - //m.currentCurrentContactsArray - const subString = v.txtSearch.value.trim(); - const list = m.arrayOfContactArrays - //restrict search to only fields 0 -> 4: This eliminates searching image name and primary key - m.currentContactsArray = L.arrayStringMatch(subString, list, 4) - if(m.currentContactsArray[0]){ - m.currentTopSearchName = m.currentContactsArray[0][0]+m.currentContactsArray[0][1] - } - m.sameContact = m.currentTopSearchName === m.priorName -} -c.showSearchResult = function(v){ - if(m.nowEditing){return} - console.log(m.currentContactsArray) - c.fillSelector(m.currentContactsArray) - c.setContactDisplay(m) - c.showContactDisplay(v) - c.showMailPhoneTouched(v) - if(m.searchIsEmpty){ - Array.from(document.querySelectorAll('.endcap')).forEach(endcap => endcap.styles('visibility: hidden')('opacity: 0')) - } - else{ - Array.from(document.querySelectorAll('.endcap')).forEach(endcap => endcap.styles('visibility: visible')('opacity: 0.55')) - v.matchCount.innerText = m.currentContactsArray.length - v.matchIndex.innerText = m.selectedIndex + 1 || 0 - } -} - -/////////////////////////// -c.setPulseNextButton = (m)=>{ - m.nextButtonIsPressed = true - m.currentDirection = `next` -} -c.showPulseNextButton = ({btnNext})=>{ - if(m.nextButtonIsPressed){ - btnNext.attribs('class=pressed button') - selectNextContact() - c.showMailPhoneTouched(v) - v.matchIndex.innerText = m.selectedIndex + 1 || 0 - } - ///////| helper |/////// - function selectNextContact(){ - if(notTooFarAhead()){ - moveForward() - } - else{ - selectFirstContact() - } - ///////| 2nd level helpers |////// - function notTooFarAhead(){ - let notTooFar = false - let indexTooFar = v.contactSelector.length - let currentIndex = v.contactSelector.selectedIndex - //set to true if next index < size of current Array - notTooFar = (currentIndex + 1) < indexTooFar - // otherwise its false that it's notTooFar ahead - return notTooFar - } - function moveForward(){ - //increment selected index of current array - ++v.contactSelector.selectedIndex - c.setContactDisplay(m) - c.showContactDisplay(v) - } - function selectFirstContact(){ - //set selected index of current array to 0 - v.contactSelector.selectedIndex = 0 - c.setContactDisplay(m) - c.showContactDisplay(v) - } - } - setTimeout(()=>{ - btnNext.attribs('class=released button') - m.buttonIsPressed = false - },100) -} -/////////////////////////////////// -c.setPulseBackButton = (m)=>{ - m.backButtonIsPressed = true - m.currentDirection = `back` -} -c.showPulseBackButton = ({btnBack})=>{ - if(m.backButtonIsPressed){ - btnBack.attribs('class=pressed button') - selectPriorContact() - c.showMailPhoneTouched(v) - v.matchIndex.innerText = m.selectedIndex + 1 || 0 - } - ///////| helper |///////// - function selectPriorContact(){ - if(notTooFarBack()){ - moveBack() - } - else{ - selectLastContact() - } - } - ///////| 2nd level helpers |////// - function notTooFarBack(){ - let notTooFar = false - let currentIndex = v.contactSelector.selectedIndex - //set to true if next index >= 0 - notTooFar = (currentIndex - 1) >= 0 - // otherwise its false that it's notTooFar ahead - return notTooFar - } - function moveBack(){ - //increment selected index of current array - v.contactSelector.selectedIndex -= 1 - c.setContactDisplay(m) - c.showContactDisplay(v) - } - function selectLastContact(){ - //set selected index of current array to 0 - v.contactSelector.selectedIndex = v.contactSelector.length - 1 - c.setContactDisplay(m) - c.showContactDisplay(v) - } - setTimeout(()=>{ - btnBack.attribs('class=released button') - m.buttonIsPressed = false - },100) -} -/////////////////////////////////// -c.setFooterActive = (m)=>{ - m.footerActive = !m.footerActive -} -c.showFooterActive = ({app, footerGlass})=>{ - m.footerActive - ? footerGlass.styles(`background: linear-gradient(-20deg, transparent, pink, transparent, pink, transparent)`) - : footerGlass.styles(`background: transparent`) -} -/////////////////////////////// -c.setIconClicked = (m)=>{ - m.source === v.phoneIcon - ? m.action = 'calling' - : m.source === v.mailIcon - ? m.action = 'mailing' - : m.action = 'none' -} -c.showIconClicked = ({contactSelector})=>{ - let i = contactSelector.selectedIndex - let contact = m.currentContactsArray[i] - m.action === 'mailing' - ? sendMail() - : m.action === 'calling' - ? makeCall() - : null - ////////| helpers |/////// - function sendMail(){ - window.location.href = `mailto:${contact[1]} ${contact[0]} <${contact[3]}>` - m.action = 'none' - } - function makeCall(){ - window.location.href = `tel:${contact[2]}` - m.action = 'none' - } - -} -////////////////////////////// -c.setClearIconText = (m)=>{} -c.showClearIconText = (v)=>{ - Array.from(m.source.querySelectorAll('span')).forEach(span =>{span.innerText = ``}) -} -////////////////////////////// -c.setAddNewContact = (m)=>{ - //gather new user data into an array of strings - //suggetion: inputs are: v.newLast, v.newFirst, v.newPhone, v.newEmail - // const newContact = [v.newLast.value, v.newFirst.value, ...] - // m.arrayOfContactsArray.push(newContact) - // c.saveContactsToServer(m.arrayOfContactsArray) -} -c.showAddNewContact = (v)=>{} -///////////////////////////// -c.setContactDisplay = (m)=>{ - m.selectedIndex = v.contactSelector.selectedIndex - m.priorSelectedPrimaryKey = m.selectedPrimaryKey - if(m.currentContactsArray[m.selectedIndex]){ - m.selectedPrimaryKey = m.currentContactsArray[m.selectedIndex][6] - } -} -c.showContactDisplay = ({nameHolder, faceHolder, actionHolder})=>{ - nameHolder.innerHTML = '' - faceHolder.innerHTML = '' - actionHolder.innerHTML = '' - if(m.currentContactsArray[m.selectedIndex]){ - const lastName = m.currentContactsArray[m.selectedIndex][0] - const firstName = m.currentContactsArray[m.selectedIndex][1] - nameHolder.innerText = `${firstName} ${lastName}` - } - c.showMailPhoneTouched(v) - //switch pictures only if its a different contact - if(m.selectedPrimaryKey !== m.priorSelectedPrimaryKey){ - c.movePicture(7); - } - //if in search, show current contact index - v.matchCount.innerText = m.currentContactsArray.length - v.matchIndex.innerText = m.selectedIndex + 1 || 0 -} -//////////////////////////////////// -c.setResize = (m)=>{ - m.height = window.innerHeight - m.width = window.innerWidth -} -c.showResize = ({contactBox, faceHolder, nameHolder, actionHolder, app})=>{ - - const boxes = Array.from(document.querySelectorAll(`.box`)) - ;(m.width <= m.MAX_WIDTH) - ? boxes.forEach( box => box.styles(`width: 93%`) ) - : boxes.forEach( box => box.styles(`width: ${m.MAX_WIDTH}px`) ) - - const isLandscape = (m.width >= m.height) - const isPortrait = (m.width < m.height) - if(isLandscape){ - faceHolder.styles(`width: 5rem`)(`height: 5rem`) - nameHolder.styles(`margin-top: 1%`) - actionHolder.styles(`top: 35%`) - v.controlsAssembly.styles(`width: 85%`) - } - else if(isPortrait){ - faceHolder.styles(`width: 7rem`)(`height: 7rem`) - nameHolder.styles(`margin-top: 5%`) - actionHolder.styles(`top: 40%`) - v.controlsAssembly.styles(`width: 98.5%`) - } - - m.width >= 600 - ? app.styles(`width: 600px`) - : app.styles(`width: 100%`) -} -///////////////////////////////////// - -c.setMailPhoneTouched = (m) => { - /* - m.action = 'none' //either 'calling', 'mailing' or 'none' - */ - ;(m.source === v.phoneIcon && m.action !== `calling`) - ? m.action = `calling` - :(m.source === v.mailIcon && m.action !== `mailing`) - ? m.action = `mailing` - : null//m.action = `none` -} -c.showMailPhoneTouched = ({actionHolder}) => { - const index = m.selectedIndex - const phoneIndex = 2 - const mailIndex = 3 - if(m.currentContactsArray[index]){ - ;(m.action === `calling`) - ? actionHolder.innerText = m.currentContactsArray[index][phoneIndex] - :(m.action === `mailing`) - ? actionHolder.innerText = m.currentContactsArray[index][mailIndex] - : actionHolder.innerText = `` - } -} -///////////////////////////////////// -c.setMailOrCall =(m)=>{ - -} -c.showMailOrCall = ({actionHolder})=>{ - ;(m.action === `calling`) - ? makeTheCall() - :(m.action === `mailing`) - ? sendTheMail() - : null - ///| helpers |/// - function makeTheCall(){ - window.location.href = `tel:${actionHolder.innerText}` - } - ///// - function sendTheMail(){ - const index = m.selectedIndex - const lastname = m.currentContactsArray[index][0] - const firstname = m.currentContactsArray[index][1] - window.location.href = `mailto: ${firstname} ${lastname}<${actionHolder.innerText}>` - } - -} -//////////////| aliases function |/////////////// -c.setMailOrCall2 = c.setMailOrCall -c.showMailOrCall2 = c.showMailOrCall -///////////////////////////////////// -c.setClearAction = ()=>{ - m.action = `none` -} -c.showClearAction = ({actionHolder})=>{ - ; (m.action === `none`) - ? actionHolder.innerText = `` - : null -} -///////////////////////////////////// -/////////////////////////////// -c.setCheckSwipe = (m)=>{} -c.showCheckSwipe = (v)=>{ - const percent = Math.round(100 * (m.historyX[1] - m.historyX[0]) / m.width) - percent > 5 - ? showNext() - : percent < -5 - ? showPrior() - : null - /////| helpers |////// - function showNext(){ - c.setPulseNextButton(m) - c.showPulseNextButton(v) - } - function showPrior(){ - c.setPulseBackButton(m) - c.showPulseBackButton(v) - } -} -/////////////////////////////// -c.setEdit = (m)=>{ - m.nowEditing = true; -} -c.showEdit = (v)=>{ - /* - m.nowEditing - ? ((m,v)=>{ - c.setClearSearch(m); - c.showClearSearch(v); - })(m,v) - : null - */ - m.nowEditing - ? v.editBox.styles(`visibility: visible`)(`opacity: 0.95`) - : v.editBox.styles(`visibility: hidden`)(`opacity: 0`) - - m.nowEditing - ? v.editBtn.styles(`box-shadow: inset 2px 2px 10px black`) - : v.editBtn.styles(`box-shadow: 2px 2px 10px black`) - - m.source === v.faceHolder - ? v.editBox.styles(`background-image: url(images/${m.currentContactsArray[m.selectedIndex][5]})`) - : v.editBox.styles(`background-image: linear-gradient(-20deg, hsl(210, 33%, 30%), hsl(210, 33%, 50%), hsl(210, 33%, 30%))`) - const currentContact = m.currentContactsArray[m.selectedIndex] - const max = currentContact.length; - - v.lastname.attribs(`placeholder=${currentContact[0]}`) - v.firstname.attribs(`placeholder=${currentContact[1]}`) - v.phone.attribs(`placeholder=${currentContact[2]}`) - v.email.attribs(`placeholder=${currentContact[3]}`) - if(currentContact[4] !== null && currentContact[4] !== 'null'){ - v.group.attribs(`placeholder=${currentContact[4]}`) - } - else{ - v.group.attribs(`placeholder=""`) - } - - -} -/////////////////////////////// -c.setStopEdit = (m)=>{ - m.nowEditing = false; -} -c.showStopEdit = ({editBox, btnCancelEdit, photoChooserAssembly})=>{ - photoChooserAssembly.styles(`background-image: url(images/${m.defaultPhoto})`) - - m.nowEditing - ? v.editBtn.styles(`box-shadow: inset 2px 2px 10px black`) - : v.editBtn.styles(`box-shadow: 2px 2px 10px black`) - - m.nowEditing - ? editBox.styles(`visibility: visible`)(`opacity: 0.95`) - : editBox.styles(`visibility: hidden`)(`opacity: 0`) - //////| helper |////// - // more to be done - m.source === v.btnCancelEdit - ? clearChanges()//photoChooserAssembly.styles(`background-image: url(${m.defaultPhoto})`) - : m.source === v.btnSaveEdit - ? saveEdit() : null - //////| helpers |////// - function clearChanges(){ - v.lastname.value = '' - v.firstname.value = '' - v.phone.value = '' - v.email.value = '' - v.group.value = '' - if(v.photoChooser.files && v.photoChooser.files[0]){ - v.photoChooser = "" - } - photoChooserAssembly.styles(`background-image: url(images/${m.noPhotoFilename})`) - } - function saveEdit(){ //On June 10, 2018, I did a large edit on saveEdit(), and some associated functions - - const index = m.selectedIndex - //save my edits to current contact - if(v.lastname.value !== ""){ - m.currentContactsArray[index][0] = v.lastname.value.trim() - } - if(v.firstname.value !== ""){ - m.currentContactsArray[index][1] = v.firstname.value.trim() - } - if(v.phone.value !== ""){ - m.currentContactsArray[index][2] = v.phone.value.trim() - } - if(v.email.value !== ""){ - m.currentContactsArray[index][3] = v.email.value.trim() - } - if(v.group.value !== "" && v.group.value !== null){ - m.currentContactsArray[index][4] = v.group.value.trim() - } - if(v.photoChooser.files && v.photoChooser.files[0]){ - m.currentContactsArray[index][5] = v.photoChooser.files[0].name.trim() - savePhotoToServer() - ///////| helper function |////// - function savePhotoToServer(){ - const file = v.photoChooser.files[0] - const filename = file.name - const postman = new XMLHttpRequest() - const envelope = new FormData() - const reader = new FileReader() - reader.readAsDataURL(file) - ////////////////////////////////////// - reader.onload = () => { - envelope.append(`filename`, filename) - envelope.append(`contents`, reader.result) - postman.open(`POST`, `savePhoto.php`) - postman.send(envelope) - ////////////////////////////////////// - postman.onload = ()=>{ - if(postman.status !== 200){alert("Trouble saving photo: " + filename)} - } - postman.onerror = ()=>{ - console.log("Trouble connecting to server.") - } - } - } - } - - //get the primary key and save changes locally and to the server - const primaryKey = m.currentContactsArray[index][6] - c.saveChangedContact(primaryKey, m.currentContactsArray[index]) - c.saveContactsToServer(m.arrayOfContactArrays) - - // now clear out the edit fields for the next edit session - v.lastname.value = '' - v.firstname.value = '' - v.phone.value = '' - v.email.value = '' - v.group.value = '' - m.selectedPhoto = '' - if(v.photoChooser.files && v.photoChooser.files[0]){ - v.photoChooser = "" - } - - //now update current contact array based on primary keys of current contacts array - const newCurrentContactsArray = m.arrayOfContactArrays.filter(memberBigList =>{ - return m.currentContactsArray.some(memberLittleList =>{ - return memberBigList[6] === memberLittleList[6] - }) - }) - - //now alphabetize it - m.currentContactsArray = L.sortArrayOfStringArrays(newCurrentContactsArray) - - //determine a more accurate selected index from primary key of current contact - const newSelectedIndex = m.currentContactsArray.reduce((newIndex, m, i)=>{ - //if the member's primary key is the current one, use its index - m[6] === primaryKey - ? newIndex = i - : newIndex - return newIndex - }, 0) - - //fill, change primary key and show image (now included in fillSelector) - c.fillSelector( m.currentContactsArray, newSelectedIndex ) - - //MAYBE renew the search, but not sure when, so saving it for last - c.newSearch() - } -} -//////////| alias for setStopEdit |//////// -c.setEditButtonOut = (m)=>{} -c.showEditButtonOut = (v)=>{ - c.setStopEdit(m) - c.showStopEdit(v) -} -/////////////////////////////// -c.setKeyDirection = (m)=>{ - //if(m.nowEditing){return} - const keycode = m.eventObject.which - m.correctKey = true - keycode === 39 - ? m.currentDirection = `next` - : keycode === 37 - ? m.currentDirection = `back` - : m.correctKey = false -} -c.showKeyDirection = (v)=>{ - if(m.nowEditing || !m.correctKey){return} - m.currentDirection === `next` - ? showNext() - : m.currentDirection === `back` - ? showPrior() - : null - /////| helpers |////// - function showNext(){ - c.setPulseNextButton(m) - c.showPulseNextButton(v) - } - function showPrior(){ - c.setPulseBackButton(m) - c.showPulseBackButton(v) - } -} -/////////////////////////////// -c.setChosenPhoto = (m)=>{ - if(v.photoChooser.files && v.photoChooser.files[0].name){ - m.selectedPhoto = v.photoChooser.files[0].name - }else{ - m.selectedPhoto = '' - } -} -c.showChosenPhoto = ({photoChooser, photoChooserAssembly})=>{ - if ( !(photoChooser.files && photoChooser.files[0]) ){ - return - } - const file = photoChooser.files && photoChooser.files[0] - m.currentChosenPhoto = file - const filename = file.name - const reader = new FileReader() - reader.readAsDataURL(file) - reader.onload = ()=>{ - photoChooserAssembly.styles(`background-image: url(${reader.result})`) - delete photoChooser.files[0] - } -} -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// -c.setNewChosenPhoto = (m)=>{ - if(v.newPhotoChooser.files && v.newPhotoChooser.files[0].name){ - m.newSelectedPhoto = v.newPhotoChooser.files[0].name - }else{ - m.newSelectedPhoto = '' - } -} -c.showNewChosenPhoto = ({newPhotoChooser, newContactPhotoAssembly})=>{ - if ( !(newPhotoChooser.files && newPhotoChooser.files[0]) ){ - return - } - const file = newPhotoChooser.files && newPhotoChooser.files[0] - m.currentChosenPhoto = file - const filename = file.name - const reader = new FileReader() - reader.readAsDataURL(file) - reader.onload = ()=>{ - newContactPhotoAssembly.styles(`background-image: url(${reader.result})`) - delete newPhotoChooser.files[0] - } -} -/////////////////////////////// -c.setDeleteContact = (m) => { - m.selectedPrimaryKey = m.currentContactsArray[m.selectedIndex][6] - m.nowEditing - ? m.shroudVisible = false - : m.shroudVisible = true -} -c.showDeleteContact = (v) => { - m.shroudVisible - ? v.shroud.styles(`visibility: visible`)(`opacity: 1`) - : v.shroud.styles(`visibility: hidden`)(`opacity: 0`) - - const firstname = m.currentContactsArray[m.selectedIndex][1] - const lastname = m.currentContactsArray[m.selectedIndex][0] - v.shroudMessage.innerHTML = `Are you sure you want to delete
    ${firstname} ${lastname}?` -} -/////////////////////////////// -c.setShroudHidden = (m) => { - m.shroudVisible = false -} -c.showShroudHidden = (v) => { - m.shroudVisible - ? v.shroud.styles(`visibility: visible`)(`opacity: 1`) - : v.shroud.styles(`visibility: hidden`)(`opacity: 0`) -} -/////////////////////////////// -c.setKillContact = (m) => { - m.backup = m.arrayOfContactArrays; - - const imageName = m.arrayOfContactArrays.reduce((imageName, member)=>{ - member[6] === m.selectedPrimaryKey - ? imageName = member[5] - : null - return imageName - },"") - - if ( `DefaultImage.png` !== imageName && `contacts2.png` !== imageName ){ - c.deleteImageFromServer(imageName) - } - - m.arrayOfContactArrays = m.arrayOfContactArrays.filter(member => member[6] !== m.selectedPrimaryKey) - m.currentContactsArray = m.currentContactsArray.filter(member => member[6] !== m.selectedPrimaryKey) - c.saveContactsToServer(m.arrayOfContactArrays) - /* - Because we eliminated a contact, the current selected index is pointing - to the next contact, or to nothing. If pointing to nothing, make it point to - the first contact. - */ - const maxIndex = m.currentContactsArray.length - 1 - if(m.selectedIndex > maxIndex){ - m.selectedIndex = 0 - } -} -c.showKillContact = (v) => { - for(let x of m.currentContactsArray){ - console.log(x[0]) - } - //////// - c.fillSelector(m.currentContactsArray, m.selectedIndex ) -} -/////////////////////////////// -c.setAddContact = (m) => { - m.buildingNewContact = true; -} -c.showAddContact = (v) => { - m.buildingNewContact - ? v.addBox.styles(`visibility: visible`)(`opacity: 0.95`) - : v.addBox.styles(`visibility: hidden`)(`opacity: 0`) - - m.buildingNewContact - ? v.addContactBtn.styles(`box-shadow: inset 2px 2px 10px black`) - : v.addContactBtn.styles(`box-shadow: 2px 2px 10px black`) - - m.buildingNewContact - ? ((m,v)=>{ - c.setClearSearch(m); - c.showClearSearch(v); - })(m,v) - : null -} -/////////////////////////////// -c.setStopAdd = (m)=>{ - m.buildingNewContact = false; -} -c.showStopAdd = (v)=>{ - m.buildingNewContact - ? v.addBox.styles(`visibility: visible`)(`opacity: 0.95`) - : v.addBox.styles(`visibility: hidden`)(`opacity: 0`) - - m.buildingNewContact - ? v.addContactBtn.styles(`box-shadow: inset 2px 2px 10px black`) - : v.addContactBtn.styles(`box-shadow: 2px 2px 10px black`) - - m.source === v.saveAddBtn - ? saveNew() - : m.source === v.cancelAddBtn - ? clearAddChanges() - : null - //////| helpers |////// - function saveNew(){ - //only save values if a full name was provided, else return - if(!v.newLastname.value || !v.newFirstname.value ){ - alert(`You must provide a full name`) - return - } - //create new contact array: - const newContact = [] - //save fields in the proper order - newContact.push(v.newLastname.value.trim()) //firstname - newContact.push(v.newFirstname.value.trim()) //lastname - newContact.push(v.newPhone.value.trim()) //phone - newContact.push(v.newEmail.value.trim()) //email - newContact.push(v.newGroup.value.trim()) //group - v.newPhotoChooser.files && v.newPhotoChooser.files[0] //photo - ? handleImage() - : newContact[5] = m.noPhotoFilename - newContact[6] = Date.now() //primary key - ///////| helper handle image |////// - function handleImage(){ - newContact[5] = v.newPhotoChooser.files[0].name - //...and save image to server, then clear out chosen file and new info fields - c.saveFileToServerPath(clearAddChanges, v.newPhotoChooser.files[0], `images/`) - } - - //save new contact to master list (in memory) - m.arrayOfContactArrays.push(newContact) - //now alphabetize it - m.arrayOfContactArrays = L.sortArrayOfStringArrays(m.arrayOfContactArrays) - //now save new master list to the server - c.saveContactsToServer(m.arrayOfContactArrays) - - //do the search again,which now includes the new contact - c.newSearch() - - //clear fields - setTimeout(clearAddChanges,100) - } - //----------------------------// - function clearAddChanges(){ - v.newLastname.value = '' - v.newFirstname.value = '' - v.newPhone.value = '' - v.newEmail.value = '' - v.newGroup.value = '' - delete v.newPhotoChooser.files[0] - v.newContactPhotoAssembly.styles(`background-image: url(images/${m.defaultPhoto})`) - } -} -/////////////////////////////////// -c.setAddButtonOut = (m)=>{ - c.setStopAdd(m) -} -c.showAddButtonOut = (v)=>{ - c.showStopAdd(v) -} -/////////////////////////////// -c.setToggleMenu = (m)=>{ - m.menuIsOpen = !m.menuIsOpen -} -c.showToggleMenu = (v)=>{ - if(m.menuIsOpen){ - v.searchAssembly.styles(`visibility: hidden`)(`opacity: 0`) - v.txtSearch.styles(`visibility: hidden`)(`opacity: 0`) - - //hide the endcaps of the search assembly to avoid some issues: 1) accidently clearing the search - //2) blocking the edit button - Array.from(document.querySelectorAll('.endcap')).forEach(endcap => endcap.styles('visibility: hidden')('opacity: 0')) - - v.controlsAssembly - .styles - ( `background-image: linear-gradient( white, #aaa)` )//(`border: 1px solid magenta`) - (`box-shadow: 1px 1px 10px`) - v.burgerTop.styles(`transform: rotateZ(35deg)`) - v.burgerMiddle.styles(`transform: rotateY(90deg)`) - v.burgerBottom.styles(`transform: rotateZ(-35deg)`) - v.menuButtonsAssembly - .styles - (`visibility: visible`) - (`opacity: 1`) - - for ( let burgerLine of Array.from(document.querySelectorAll(`.burgerLines`)) ){ - burgerLine.styles(`background-color: red`) - } - } - else if(!m.menuIsOpen){ - v.searchAssembly.styles(`visibility: visible`)(`opacity: 1`) - v.txtSearch.styles(`visibility: visible`)(`opacity: 1`) - if(!m.searchIsEmpty){ - Array.from(document.querySelectorAll('.endcap')).forEach(endcap => endcap.styles('visibility: visible')('opacity: 0.55')); - } - v.controlsAssembly - .styles - (`background-image: none`) - (`box-shadow: 0 0 0`) - v.burgerTop.styles(`transform: rotateZ(0deg)`) - v.burgerMiddle.styles(`transform: rotateY(0deg)`) - v.burgerBottom.styles(`transform: rotateZ(0deg)`) - - v.menuButtonsAssembly.styles(`visibility: hidden`)(`opacity: 0`) - - //restore search assembly's end caps - // Array.from(document.querySelectorAll('.endcap')).forEach(endcap => endcap.styles('visibility: visible')('opacity: 0.55')) - - for ( let burgerLine of Array.from(document.querySelectorAll(`.burgerLines`)) ){ - burgerLine.styles(`background-color: black`) - } - } -} -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/b039f3a0fad6690bccc0969dbe561fcd b/data/collaborative/shadow/b039f3a0fad6690bccc0969dbe561fcd deleted file mode 100755 index 4cf9139..0000000 --- a/data/collaborative/shadow/b039f3a0fad6690bccc0969dbe561fcd +++ /dev/null @@ -1,18 +0,0 @@ -s:418:" -
    - -

    Looking for a quiz? Select one of the teachers below to view their active quizzes.

    - - - -
    "; \ No newline at end of file diff --git a/data/collaborative/shadow/b7e0dffe6d3af66063c9752be07c9e75 b/data/collaborative/shadow/b7e0dffe6d3af66063c9752be07c9e75 deleted file mode 100755 index c0e0d04..0000000 --- a/data/collaborative/shadow/b7e0dffe6d3af66063c9752be07c9e75 +++ /dev/null @@ -1,30 +0,0 @@ -s:798:" - - - Web 2 Template - - - - - - - - - - - - - - - - - - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/b818ce32cd61aa5d83fbf357d1184635 b/data/collaborative/shadow/b818ce32cd61aa5d83fbf357d1184635 deleted file mode 100755 index 85c6268..0000000 --- a/data/collaborative/shadow/b818ce32cd61aa5d83fbf357d1184635 +++ /dev/null @@ -1,174 +0,0 @@ -s:6176:"s:6166:"actives = getJSON('active.php'); - } - - ////////////////////////////////////////////////////////////////// - // List User's Active Files - ////////////////////////////////////////////////////////////////// - - public function ListActive() - { - $active_list = array(); - $tainted = false; - $root = WORKSPACE; - if ($this->actives) { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']==$this->username) { - if ($this->isAbsPath($data['path'])) { - $root = ""; - } else { - $root = $root.'/'; - } - if (file_exists($root.$data['path'])) { - $focused = isset($data['focused']) ? $data['focused'] : false; - $active_list[] = array('path'=>$data['path'], 'focused'=>$focused); - } else { - unset($this->actives[$active]); - $tainted = true; - } - } - } - } - if ($tainted) { - saveJSON('active.php', $this->actives); - } - echo formatJSEND("success", $active_list); - } - - ////////////////////////////////////////////////////////////////// - // Check File - ////////////////////////////////////////////////////////////////// - - public function Check() - { - $cur_users = array(); - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']!=$this->username && $data['path']==$this->path) { - $cur_users[] = $data['username']; - } - } - if (count($cur_users)!=0) { - //echo formatJSEND("error", "Warning: File ".substr($this->path, strrpos($this->path, "/")+1)." Currently Opened By: " . implode(", ", $cur_users)); - } else { - echo formatJSEND("success"); - } - } - - ////////////////////////////////////////////////////////////////// - // Add File - ////////////////////////////////////////////////////////////////// - - public function Add() - { - $process_add = true; - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']==$this->username && $data['path']==$this->path) { - $process_add = false; - } - } - if ($process_add) { - $this->actives[] = array("username"=>$this->username,"path"=>$this->path); - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - } - - ////////////////////////////////////////////////////////////////// - // Rename File - ////////////////////////////////////////////////////////////////// - - public function Rename() - { - $revised_actives = array(); - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username'])) { - $revised_actives[] = array("username"=>$data['username'],"path"=>str_replace($this->path, $this->new_path, $data['path'])); - } - } - saveJSON('active.php', $revised_actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Remove File - ////////////////////////////////////////////////////////////////// - - public function Remove() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username'] && $this->path==$data['path']) { - unset($this->actives[$active]); - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Remove All Files - ////////////////////////////////////////////////////////////////// - - public function RemoveAll() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username']) { - unset($this->actives[$active]); - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Mark File As Focused - // All other files will be marked as non-focused. - ////////////////////////////////////////////////////////////////// - - public function MarkFileAsFocused() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username']) { - $this->actives[$active]['focused']=false; - if ($this->path==$data['path']) { - $this->actives[$active]['focused']=true; - } - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } -} -";"; \ No newline at end of file diff --git a/data/collaborative/shadow/bc2ad9133d134977d621104c59e9fd61 b/data/collaborative/shadow/bc2ad9133d134977d621104c59e9fd61 deleted file mode 100755 index 4541553..0000000 --- a/data/collaborative/shadow/bc2ad9133d134977d621104c59e9fd61 +++ /dev/null @@ -1,28 +0,0 @@ -s:477:"/* - -Created: 2018-07-10 -Modified: N/A -Purpose: Why did we name this Qualify ... Designate is better - -*/ - -/*global L*/ -/*global m*/ -/*global v*/ -/*global c*/ - -c.designateFunction = function(eventObject){ - c.updateMetaEvents(eventObject) - let functionQualifiers = { - setToggleTestButton: [m.source === v.testButton, m.type === `click`], - /* - setXXY: [], - setXXZ: [], - setXYX: [], - setXYY: [], - */ - } - L.runQualifiedFunctions(functionQualifiers, m, v, c) -} -/////////////// -"; \ No newline at end of file diff --git a/data/collaborative/shadow/bdd330a1af3dca522aae993ac38cf3c5 b/data/collaborative/shadow/bdd330a1af3dca522aae993ac38cf3c5 deleted file mode 100755 index 2a92b64..0000000 --- a/data/collaborative/shadow/bdd330a1af3dca522aae993ac38cf3c5 +++ /dev/null @@ -1,3 +0,0 @@ -s:79:""; \ No newline at end of file diff --git a/data/collaborative/shadow/bfd3f8ef41ef1f98968c106a423699b2 b/data/collaborative/shadow/bfd3f8ef41ef1f98968c106a423699b2 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/shadow/bfd3f8ef41ef1f98968c106a423699b2 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/shadow/c34a5d1f562bfd5f37c3de4632f25a47 b/data/collaborative/shadow/c34a5d1f562bfd5f37c3de4632f25a47 deleted file mode 100755 index 589c9a6..0000000 --- a/data/collaborative/shadow/c34a5d1f562bfd5f37c3de4632f25a47 +++ /dev/null @@ -1,7 +0,0 @@ -s:100:"/* - -Created: 2018-07-10 -Modified: N/A -Purpose: Extra functions but their Xtra cause we are cool. - -*/"; \ No newline at end of file diff --git a/data/collaborative/shadow/cbc7af3f90284b745f9cca4430668ab5 b/data/collaborative/shadow/cbc7af3f90284b745f9cca4430668ab5 deleted file mode 100755 index e913fc2..0000000 --- a/data/collaborative/shadow/cbc7af3f90284b745f9cca4430668ab5 +++ /dev/null @@ -1,48 +0,0 @@ -s:1265:"Init(); -} - - ////////////////////////////////////////////////////////////////// - // Clear Version - ////////////////////////////////////////////////////////////////// - -if ($_GET['action']=='clear') { - if (checkAccess()) { - $update->Clear(); - } -} - - ////////////////////////////////////////////////////////////////// - // OptOut - ////////////////////////////////////////////////////////////////// - -if ($_GET['action']=='optout') { - if (checkAccess()) { - $update->OptOut(); - } -} -"; \ No newline at end of file diff --git a/data/collaborative/shadow/cc91755cde6ab90a7f2aada55994f97b b/data/collaborative/shadow/cc91755cde6ab90a7f2aada55994f97b deleted file mode 100755 index 4541553..0000000 --- a/data/collaborative/shadow/cc91755cde6ab90a7f2aada55994f97b +++ /dev/null @@ -1,28 +0,0 @@ -s:477:"/* - -Created: 2018-07-10 -Modified: N/A -Purpose: Why did we name this Qualify ... Designate is better - -*/ - -/*global L*/ -/*global m*/ -/*global v*/ -/*global c*/ - -c.designateFunction = function(eventObject){ - c.updateMetaEvents(eventObject) - let functionQualifiers = { - setToggleTestButton: [m.source === v.testButton, m.type === `click`], - /* - setXXY: [], - setXXZ: [], - setXYX: [], - setXYY: [], - */ - } - L.runQualifiedFunctions(functionQualifiers, m, v, c) -} -/////////////// -"; \ No newline at end of file diff --git a/data/collaborative/shadow/ccdab27e57aa054e492f5b3d3850f6e5 b/data/collaborative/shadow/ccdab27e57aa054e492f5b3d3850f6e5 deleted file mode 100755 index 8401ef3..0000000 --- a/data/collaborative/shadow/ccdab27e57aa054e492f5b3d3850f6e5 +++ /dev/null @@ -1,55 +0,0 @@ -s:1628:"{ - const option = document.createElement('option') - option.innerText = filename - v.documentSelector.appendChild(option) - }) - } - - v.documentSelector.selectedIndex = filenameArray.indexOf(currentFilename) - v.documentSelector.selectedIndex === -1 ? v.documentSelector.selectedIndex = 0 : null - -} - -//=====================================================================// -c.uploadFiles =(eventObject)=>{ - if( !(v.fileElement.files && v.fileElement.files[0]) ){return} - if(m.busyWithPictureOnly){return} - - let allFilesMp3 = Array.from(v.fileElement.files).every( file=> getExtention(file) === `mp3` ) - if(!allFilesMp3){ - alert(`Only .mp3 files allowed.`) - return - } - //----| helper |------// - function getExtention(file){ - let name = file.name - let maxIndex = name.length -1 - let extLength = maxIndex - name.lastIndexOf(`.`) - return name.slice(-extLength) - } - L.uploadFiles(c.showUploadProgress, v.fileElement, "php/uploadFile.php") -} -//===========================================// -c.showUploadProgress = (loaded, total, index)=>{ - const numberOfFiles = v.fileElement.files.length - if(numberOfFiles === 0){return} - const pct = Math.round(100 * m.averageUploadFraction) - m.fractionArray[index] = loaded/total - m.averageUploadFraction = m.fractionArray.reduce(function(sum, value){ - return sum + value/numberOfFiles - }, 0) - - v.progressBar.styles(`width: ${pct}%`) - - console.log(`loaded: ${(100 * m.averageUploadFraction).toFixed(0)}`) - if( (loaded === 1 && total === 1) || pct === 100 ){// && index === (numberOfFiles-1) - c.getFileList() - setTimeout(()=>{ - c.clearUploadData() - v.progressBar.styles(`width: 0`) - }, 1000) - } -} -//=============================================// -c.playChosenSong = () => { - if(m.busyWithPictureOnly){return} - c.setResize(m, c.showResize, v) //not sure if invoking here is overkill - const base = m.musicFilesUrl - const index = v.documentSelector.selectedIndex - const src = `${base}${v.documentSelector.options[index].innerText}` - v.player.pause() - setTimeout(()=>{//this delay improves performance - v.player.src = src - v.player.styles(`visibility: visible`) - v.player.play() - m.playing = true - },25) - - v.background - .styles - (`background-image: url(${m.defaultBackground})`) - (`background-size: cover`) - - //attempt to show image - var jsmediatags = window.jsmediatags ; - if(!jsmediatags){ - m.noPicture = true - console.log("Can't find the 'jsmediatags' object."); - console.log("Try https://github.com/aadsm/jsmediatags/tree/master/dist/jsmediatags.min.js"); - console.log("... or https://cdnjs.cloudflare.com/ajax/libs/jsmediatags/3.9.0/jsmediatags.js") - c.setResize(m, c.showResize, v) - return; - } - // url from local host - const url = `${base}${v.documentSelector.options[index].innerText}` - jsmediatags.read(url, { - onSuccess: (tag) => { - console.log(tag); - let tags = tag.tags; - //========================// - var image = tags.picture; - if (image) { - m.noPicture = false - const base64String = image.data.reduce((string, datum) => string += String.fromCharCode(datum), ''); - m.pictureData = "data:" + image.format + ";base64," + window.btoa(base64String); - v.pictureHolder - .styles - (`background-image: url(${m.pictureData})`) - (`background-size: contain`) - (`background-repeat: no-repeat`) - (`background-position: center`) - (`background-size: contain`) - (`background-color: black`) - v.controlsHolder - .styles - (`background-color: black`) - v.controlsAssembly - .styles - (`background-color: #eee`) - c.setResize(m, c.showResize, v) - } - else{//no image - m.noPicture = true - console.log("No image found :(") - v.pictureHolder - .styles - (`background-image: url()`) - (`background-color: transparent`) - v.controlsHolder - .styles - (`background-color: transparent`) - v.controlsAssembly - .styles - (`background-color: rgba(238, 238, 238, 0.4)`) - c.setResize(m, c.showResize, v) - } - //=========================// - //=====| show picture |====// - //=========================// - //////////////////////////// - c.showPicture(1000)//argument is delay-time in milliseconds - /////////////////////////// - }, - onError: (error) => { - console.log(error); - return; - } - }); - -} -//==========================================================// -c.clearUploadData = ()=>{ - m.fractionArray = []; - m.averageUploadFraction = 0; -} -//================================================// -c.respondToEnded = ()=>{ - m.nonStop - ? pointToNextSong() - : m.playing = false - //---| helper |---// - function pointToNextSong(){ - v.documentSelector.selectedIndex + 1 < v.documentSelector.options.length - ? v.documentSelector.selectedIndex = v.documentSelector.selectedIndex + 1 - : v.documentSelector.selectedIndex = 0 - setTimeout(c.playChosenSong, 20) - } - c.showPicture(1000) - -} -//========================================// -c.respondToPause = ()=>{ - if(m.busyWithPictureOnly){return} - m.playing = false -} -//============================================// -c.respondToPlay = ()=> { - if(m.busyWithPictureOnly){return} - m.playing = true -} -//============================================// -c.deleteFile = ()=>{ - if(m.busyWithPictureOnly){return} - - const index = v.documentSelector.selectedIndex - const filename = v.documentSelector.options[index].innerText - - const msg = `OK to DELETE ${filename}?\n( Otherwise, CANCEL )` - const okToDelete = confirm(msg) - if(okToDelete){ - const killer = new XMLHttpRequest() - const envelope = new FormData() - envelope.append(`filename`, filename) - killer.open(`POST`, `php/deleteFile.php`) - killer.send(envelope) - //--------------------------// - killer.onload = ()=>{ - if(killer.status !== 200){ - console.log("Trouble deleting the file.") - } - else{ - c.getFileList() - } - } - killer.onerror = ()=>{ - console.log("Trouble Connecting to server.") - } - } -} -//========================================// -c.getAccessLevel = ()=>{ - const reporter = new XMLHttpRequest() - reporter.open(`GET`, `php/getAccessLevel.php`) - reporter.send() - //----------------// - reporter.onload = ()=>{ - if(reporter.status === 200){ - reporter.responseText === 'allow' - ? m.loggedIn = true - : m.loggedIn = false - console.log(reporter.responseText) - if(!m.loggedIn){ - c.setLogout(m, c.showLogout, v) - } - } - } - reporter.onerror = ()=>{ - const msg = `Trouble connecting to server.` - console.log(msg) - } -} -//--------------------------------------// - -c.pollForPaswordWall = ()=>{ - const reporter = new XMLHttpRequest() - reporter.open(`GET`, `php/getAccessLevel.php`) - reporter.send() - //----------------// - reporter.onload = ()=>{ - if(reporter.status === 200){ - reporter.responseText === 'allow' - ? m.loggedIn = true - : m.loggedIn = false - //console.log(reporter.responseText) - if(!m.loggedIn){ - //put up password wall - passwordWall - .styles - (`visibility: visible`) - (`opacity: 1`) - } - } - else{ - const msg = `Trouble with password.` - console.log(msg) - } - } - reporter.onerror = ()=>{ - const msg = `Trouble connecting to server.` - console.log(msg) - } - -} -//////////////////////////////////////// -c.queueInitialRandomSong = ()=>{ - c.showToggleNonStop(v) - setTimeout(()=>{ - m.selectedIndex = Math.floor( v.documentSelector.options.length * Math.random() ) - v.documentSelector.selectedIndex = m.selectedIndex - v.player.src =`${m.musicFilesUrl}${v.documentSelector.options[m.selectedIndex].innerText}` - c.playChosenSong() - }, 320) - setTimeout(()=>{v.player.pause()},475) -} -//////////////////////////////////////// -c.showPicture = function(delay=2000){ - setTimeout(()=>{ - m.showPictureOnly - ? showPictureOnly() - : restorePictureState() - ////| helpers |//// - function showPictureOnly(){ - //bring background in front - v.background.styles(`z-index: 10`) - //show current pictureData (m.pictureData), if there is one - if(!m.noPicture){ - v.background - .styles - (`background-image: url(${m.pictureData})`) - (`background-size: contain`) - (`background-repeat: no-repeat`) - (`background-position: center`) - } - } - function restorePictureState(){ - //put background behind - v.background.styles(`z-index: 0`) - //restore default background picture - v.background - .styles - (`background-image: url(${m.defaultBackground})`) - (`background-repeat: no-repeat`) - (`background-position: center`) - setTimeout(()=>{ - v.background.styles(`background-size: cover`) - },300) - } - }, delay) -} -//////////////////////////////////////////////"; \ No newline at end of file diff --git a/data/collaborative/shadow/d778ad34ea1212ed7081b731d9a8dd80 b/data/collaborative/shadow/d778ad34ea1212ed7081b731d9a8dd80 deleted file mode 100755 index 7061009..0000000 --- a/data/collaborative/shadow/d778ad34ea1212ed7081b731d9a8dd80 +++ /dev/null @@ -1,10281 +0,0 @@ -s:441251:"(function() { -/** - * almond 0.2.5 Copyright (c) 2011-2012, The Dojo Foundation All Rights Reserved. - * Available via the MIT or new BSD license. - * see: http://github.com/jrburke/almond for details - */ -//Going sloppy to avoid 'use strict' string cost, but strict practices should -//be followed. -/*jslint sloppy: true */ -/*global setTimeout: false */ - -var requirejs, require, define; -(function (undef) { - var main, req, makeMap, handlers, - defined = {}, - waiting = {}, - config = {}, - defining = {}, - hasOwn = Object.prototype.hasOwnProperty, - aps = [].slice; - - function hasProp(obj, prop) { - return hasOwn.call(obj, prop); - } - - /** - * Given a relative module name, like ./something, normalize it to - * a real name that can be mapped to a path. - * @param {String} name the relative name - * @param {String} baseName a real name that the name arg is relative - * to. - * @returns {String} normalized name - */ - function normalize(name, baseName) { - var nameParts, nameSegment, mapValue, foundMap, - foundI, foundStarMap, starI, i, j, part, - baseParts = baseName && baseName.split("/"), - map = config.map, - starMap = (map && map['*']) || {}; - - //Adjust any relative paths. - if (name && name.charAt(0) === ".") { - //If have a base name, try to normalize against it, - //otherwise, assume it is a top-level require that will - //be relative to baseUrl in the end. - if (baseName) { - //Convert baseName to array, and lop off the last part, - //so that . matches that "directory" and not name of the baseName's - //module. For instance, baseName of "one/two/three", maps to - //"one/two/three.js", but we want the directory, "one/two" for - //this normalization. - baseParts = baseParts.slice(0, baseParts.length - 1); - - name = baseParts.concat(name.split("/")); - - //start trimDots - for (i = 0; i < name.length; i += 1) { - part = name[i]; - if (part === ".") { - name.splice(i, 1); - i -= 1; - } else if (part === "..") { - if (i === 1 && (name[2] === '..' || name[0] === '..')) { - //End of the line. Keep at least one non-dot - //path segment at the front so it can be mapped - //correctly to disk. Otherwise, there is likely - //no path mapping for a path starting with '..'. - //This can still fail, but catches the most reasonable - //uses of .. - break; - } else if (i > 0) { - name.splice(i - 1, 2); - i -= 2; - } - } - } - //end trimDots - - name = name.join("/"); - } else if (name.indexOf('./') === 0) { - // No baseName, so this is ID is resolved relative - // to baseUrl, pull off the leading dot. - name = name.substring(2); - } - } - - //Apply map config if available. - if ((baseParts || starMap) && map) { - nameParts = name.split('/'); - - for (i = nameParts.length; i > 0; i -= 1) { - nameSegment = nameParts.slice(0, i).join("/"); - - if (baseParts) { - //Find the longest baseName segment match in the config. - //So, do joins on the biggest to smallest lengths of baseParts. - for (j = baseParts.length; j > 0; j -= 1) { - mapValue = map[baseParts.slice(0, j).join('/')]; - - //baseName segment has config, find if it has one for - //this name. - if (mapValue) { - mapValue = mapValue[nameSegment]; - if (mapValue) { - //Match, update name to the new value. - foundMap = mapValue; - foundI = i; - break; - } - } - } - } - - if (foundMap) { - break; - } - - //Check for a star map match, but just hold on to it, - //if there is a shorter segment match later in a matching - //config, then favor over this star map. - if (!foundStarMap && starMap && starMap[nameSegment]) { - foundStarMap = starMap[nameSegment]; - starI = i; - } - } - - if (!foundMap && foundStarMap) { - foundMap = foundStarMap; - foundI = starI; - } - - if (foundMap) { - nameParts.splice(0, foundI, foundMap); - name = nameParts.join('/'); - } - } - - return name; - } - - function makeRequire(relName, forceSync) { - return function () { - //A version of a require function that passes a moduleName - //value for items that may need to - //look up paths relative to the moduleName - return req.apply(undef, aps.call(arguments, 0).concat([relName, forceSync])); - }; - } - - function makeNormalize(relName) { - return function (name) { - return normalize(name, relName); - }; - } - - function makeLoad(depName) { - return function (value) { - defined[depName] = value; - }; - } - - function callDep(name) { - if (hasProp(waiting, name)) { - var args = waiting[name]; - delete waiting[name]; - defining[name] = true; - main.apply(undef, args); - } - - if (!hasProp(defined, name) && !hasProp(defining, name)) { - throw new Error('No ' + name); - } - return defined[name]; - } - - //Turns a plugin!resource to [plugin, resource] - //with the plugin being undefined if the name - //did not have a plugin prefix. - function splitPrefix(name) { - var prefix, - index = name ? name.indexOf('!') : -1; - if (index > -1) { - prefix = name.substring(0, index); - name = name.substring(index + 1, name.length); - } - return [prefix, name]; - } - - /** - * Makes a name map, normalizing the name, and using a plugin - * for normalization if necessary. Grabs a ref to plugin - * too, as an optimization. - */ - makeMap = function (name, relName) { - var plugin, - parts = splitPrefix(name), - prefix = parts[0]; - - name = parts[1]; - - if (prefix) { - prefix = normalize(prefix, relName); - plugin = callDep(prefix); - } - - //Normalize according - if (prefix) { - if (plugin && plugin.normalize) { - name = plugin.normalize(name, makeNormalize(relName)); - } else { - name = normalize(name, relName); - } - } else { - name = normalize(name, relName); - parts = splitPrefix(name); - prefix = parts[0]; - name = parts[1]; - if (prefix) { - plugin = callDep(prefix); - } - } - - //Using ridiculous property names for space reasons - return { - f: prefix ? prefix + '!' + name : name, //fullName - n: name, - pr: prefix, - p: plugin - }; - }; - - function makeConfig(name) { - return function () { - return (config && config.config && config.config[name]) || {}; - }; - } - - handlers = { - require: function (name) { - return makeRequire(name); - }, - exports: function (name) { - var e = defined[name]; - if (typeof e !== 'undefined') { - return e; - } else { - return (defined[name] = {}); - } - }, - module: function (name) { - return { - id: name, - uri: '', - exports: defined[name], - config: makeConfig(name) - }; - } - }; - - main = function (name, deps, callback, relName) { - var cjsModule, depName, ret, map, i, - args = [], - usingExports; - - //Use name if no relName - relName = relName || name; - - //Call the callback to define the module, if necessary. - if (typeof callback === 'function') { - - //Pull out the defined dependencies and pass the ordered - //values to the callback. - //Default to [require, exports, module] if no deps - deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps; - for (i = 0; i < deps.length; i += 1) { - map = makeMap(deps[i], relName); - depName = map.f; - - //Fast path CommonJS standard dependencies. - if (depName === "require") { - args[i] = handlers.require(name); - } else if (depName === "exports") { - //CommonJS module spec 1.1 - args[i] = handlers.exports(name); - usingExports = true; - } else if (depName === "module") { - //CommonJS module spec 1.1 - cjsModule = args[i] = handlers.module(name); - } else if (hasProp(defined, depName) || - hasProp(waiting, depName) || - hasProp(defining, depName)) { - args[i] = callDep(depName); - } else if (map.p) { - map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {}); - args[i] = defined[depName]; - } else { - throw new Error(name + ' missing ' + depName); - } - } - - ret = callback.apply(defined[name], args); - - if (name) { - //If setting exports via "module" is in play, - //favor that over return value and exports. After that, - //favor a non-undefined return value over exports use. - if (cjsModule && cjsModule.exports !== undef && - cjsModule.exports !== defined[name]) { - defined[name] = cjsModule.exports; - } else if (ret !== undef || !usingExports) { - //Use the return value from the function. - defined[name] = ret; - } - } - } else if (name) { - //May just be an object definition for the module. Only - //worry about defining if have a module name. - defined[name] = callback; - } - }; - - requirejs = require = req = function (deps, callback, relName, forceSync, alt) { - if (typeof deps === "string") { - if (handlers[deps]) { - //callback in this case is really relName - return handlers[deps](callback); - } - //Just return the module wanted. In this scenario, the - //deps arg is the module name, and second arg (if passed) - //is just the relName. - //Normalize module name, if it contains . or .. - return callDep(makeMap(deps, callback).f); - } else if (!deps.splice) { - //deps is a config object, not an array. - config = deps; - if (callback.splice) { - //callback is an array, which means it is a dependency list. - //Adjust args if there are dependencies - deps = callback; - callback = relName; - relName = null; - } else { - deps = undef; - } - } - - //Support require(['a']) - callback = callback || function () {}; - - //If relName is a function, it is an errback handler, - //so remove it. - if (typeof relName === 'function') { - relName = forceSync; - forceSync = alt; - } - - //Simulate async callback; - if (forceSync) { - main(undef, deps, callback, relName); - } else { - //Using a non-zero value because of concern for what old browsers - //do, and latest browsers "upgrade" to 4 if lower value is used: - //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout: - //If want a value immediately, use require('id') instead -- something - //that works in almond on the global level, but not guaranteed and - //unlikely to work in other AMD implementations. - setTimeout(function () { - main(undef, deps, callback, relName); - }, 4); - } - - return req; - }; - - /** - * Just drops the config on the floor, but returns req in case - * the config return value is used. - */ - req.config = function (cfg) { - config = cfg; - if (config.deps) { - req(config.deps, config.callback); - } - return req; - }; - - define = function (name, deps, callback) { - - //This module may not have dependencies - if (!deps.splice) { - //deps is not an array, so probably means - //an object literal or factory function for - //the value. Adjust args. - callback = deps; - deps = []; - } - - if (!hasProp(defined, name) && !hasProp(waiting, name)) { - waiting[name] = [name, deps, callback]; - } - }; - - define.amd = { - jQuery: true - }; -}()); - -define("libs/almond", function(){}); - -/*! jQuery v1.8.3 jquery.com | jquery.org/license */ -(function (){ -(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write(""),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t
    a",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="
    t
    ",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="
    ",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;ti.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="
    ",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="

    ",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t0)for(i=r;i=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*\s*$/g,Nt={option:[1,""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X
    ","
    "]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1>");try{for(;r1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]===""&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("
    ").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window); -jQuery.noConflict(true); -})(); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('jqueryPlugins',["jquery"], function ($) { - // This isn't really a "module" since it just patches jQuery itself - - // FIX ME Animations TO DO - // walkthrough animations go here - // animate participant cursor and box popping in when they enter the session - // animate participant cursor and box popping out when they leave the session - // animate the participant cursor -> rotate down when they're down the page - $.fn.rotateCursorDown = function () { - $('svg').animate({borderSpacing: -150, opacity: 1}, { - step: function(now, fx) { - if (fx.prop == "borderSpacing") { - $(this).css('-webkit-transform', 'rotate('+now+'deg)') - .css('-moz-transform', 'rotate('+now+'deg)') - .css('-ms-transform', 'rotate('+now+'deg)') - .css('-o-transform', 'rotate('+now+'deg)') - .css('transform', 'rotate('+now+'deg)'); - } else { - $(this).css(fx.prop, now); - } - }, - duration: 500 - }, 'linear').promise().then(function () { - this.css('-webkit-transform', ''); - this.css('-moz-transform', ''); - this.css('-ms-transform', ''); - this.css('-o-transform', ''); - this.css('transform', ''); - this.css("opacity", ""); - }); - }; - - // animate the participant cursor -> rotate up when they're on the same frame as the user - $.fn.rotateCursorDown = function () { - $('.togetherjs-cursor svg').animate({borderSpacing: 0, opacity: 1}, { - step: function(now, fx) { - if (fx.prop == "borderSpacing") { - $(this).css('-webkit-transform', 'rotate('+now+'deg)') - .css('-moz-transform', 'rotate('+now+'deg)') - .css('-ms-transform', 'rotate('+now+'deg)') - .css('-o-transform', 'rotate('+now+'deg)') - .css('transform', 'rotate('+now+'deg)'); - } else { - $(this).css(fx.prop, now); - } - }, - duration: 500 - }, 'linear').promise().then(function () { - this.css('-webkit-transform', ''); - this.css('-moz-transform', ''); - this.css('-ms-transform', ''); - this.css('-o-transform', ''); - this.css('transform', ''); - this.css("opacity", ""); - }); - }; - - // Move notification when another notification slides in // - - - /* Pop in window from dock button: */ - $.fn.popinWindow = function () { - - //mobile popout window with no animation - if($.browser.mobile) { - - //starting position - this.css({ - left: "0px", - opacity: 1, - "zIndex": 8888 - }); - - //starting position for arrow - $('#togetherjs-window-pointer-right').css({ - left: "+=74px", - opacity: 1, - "zIndex": 8888 - }); - - //animate arrow out - $('#togetherjs-window-pointer-right').animate({ - opacity: 1, - left: "-=78px" - }, { - duration:60, easing:"linear" - }); - $('#togetherjs-window-pointer-right').queue(); - - //bounce arrow back - $('#togetherjs-window-pointer-right').animate({ - left:'+=4px' - }, { - duration:60, easing:"linear" - }); - - //animate window out - this.animate({ - opacity: 1, - left: "0px" - }, { - duration:60, easing:"linear" - }); - this.queue(); - - //bounce window back - this.animate({ - left:'0px' - }, { - duration:60, easing:"linear" - }); - } - - else { - - //starting position - this.css({ - left: "+=74px", - opacity: 1, - "zIndex": 8888 - }); - - //starting position for arrow - $('#togetherjs-window-pointer-right').css({ - left: "+=74px", - opacity: 1, - "zIndex": 8888 - }); - - //animate arrow out - $('#togetherjs-window-pointer-right').animate({ - opacity: 1, - left: "-=78px" - }, { - duration:60, easing:"linear" - }); - $('#togetherjs-window-pointer-right').queue(); - - //bounce arrow back - $('#togetherjs-window-pointer-right').animate({ - left:'+=4px' - }, { - duration:60, easing:"linear" - }); - - //animate window out - this.animate({ - opacity: 1, - left: "-=78px" - }, { - duration:60, easing:"linear" - }); - this.queue(); - - //bounce window back - this.animate({ - left:'+=4px' - }, { - duration:60, easing:"linear" - }); - - } - - }; - - /* Slide in notification window: */ - $.fn.slideIn = function () { - this.css({ - //top: "240px", - left: "+=74px", - opacity: 0, - "zIndex": 8888 - }); - return this.animate({ - "left": "-=74px", - opacity: 1, - "zIndex": 9999 - }, "fast"); - }; - - /* Used to fade away notification windows + flip the bottom of them out: */ - $.fn.fadeOut = function () { - this.animate({borderSpacing: -90, opacity: 0.5}, { - step: function(now, fx) { - if (fx.prop == "borderSpacing") { - $(this).css('-webkit-transform', 'perspective( 600px ) rotateX('+now+'deg)') - .css('-moz-transform', 'perspective( 600px ) rotateX('+now+'deg)') - .css('-ms-transform', 'perspective( 600px ) rotateX('+now+'deg)') - .css('-o-transform', 'perspective( 600px ) rotateX('+now+'deg)') - .css('transform', 'perspective( 600px ) rotateX('+now+'deg)'); - } else { - $(this).css(fx.prop, now); - } - }, - duration: 500 - }, 'linear').promise().then(function () { - this.css('-webkit-transform', ''); - this.css('-moz-transform', ''); - this.css('-ms-transform', ''); - this.css('-o-transform', ''); - this.css('transform', ''); - this.css("opacity", ""); - }); - return this; - }; - - /* used when user goes down to participant cursor location on screen */ - $.fn.easeTo = function (y) { - return this.animate({ - scrollTop: y - }, { - duration: 400, - easing: "swing" - }); - }; - - // avatar animate in - $.fn.animateDockEntry = function () { - var height = this.height(); - var width = this.width(); - var backgroundSize = height + 4; - var margin = parseInt(this.css("marginLeft"), 10); - - // set starting position CSS for avatar - this.css({ - marginLeft: margin + width/2, - height: 0, - width: 0, - backgroundSize: "0 0" - }); - - var self = this; - - //then animate avatar to the actual dimensions, and reset the values - this.animate({ - marginLeft: margin, - height: height, - width: width, - backgroundSize: backgroundSize - }, { - duration: 600 - }).promise().then(function () { - self.css({ - marginLeft: "", - height: "", - width: "", - backgroundSize: "" - }); - }); - return this; - }; - - // avatar animate out, reverse of above - $.fn.animateDockExit = function () { - - // get the current avatar dimenensions - var height = this.height(); - var width = this.width(); - var backgroundSize = height + 4; - var margin = parseInt(this.css("marginLeft"), 10); - - //then animate avatar to shrink to nothing, and reset the values again - // FIXME this needs to animate from the CENTER - this.animate({ - marginLeft: margin + width/2, - height: 0, - width: 0, - backgroundSize: "0 0", - opacity: 0 - }, 600 ); - - return this; - - }; - - $.fn.animateCursorEntry = function () { - // Make the cursor bubble pop in - }; - - // keyboard typing animation - $.fn.animateKeyboard = function () { - var one = this.find(".togetherjs-typing-ellipse-one"); - var two = this.find(".togetherjs-typing-ellipse-two"); - var three = this.find(".togetherjs-typing-ellipse-three"); - var count = -1; - var run = (function () { - count = (count+1) % 4; - if (count === 0) { - one.css("opacity", 0.5); - two.css("opacity", 0.5); - three.css("opacity", 0.5); - } else if (count == 1) { - one.css("opacity", 1); - } else if (count == 2) { - two.css("opacity", 1); - } else { // count==3 - three.css("opacity", 1); - } - }).bind(this); - run(); - var interval = setInterval(run, 300); - this.data("animateKeyboard", interval); - }; - - $.fn.stopKeyboardAnimation = function () { - clearTimeout(this.data("animateKeyboard")); - this.data("animateKeyboard", null); - }; - - // FIXME: not sure if this is legit, but at least the modern mobile devices we - // care about should have this defined: - if (! $.browser) { - $.browser = {}; - } - $.browser.mobile = window.orientation !== undefined; - if (navigator.userAgent.search(/mobile/i) != -1) { - // FIXME: At least on the Firefox OS simulator I need this - $.browser.mobile = true; - } - - if ($.browser.mobile && window.matchMedia && ! window.matchMedia("screen and (max-screen-width: 480px)").matches) { - // FIXME: for Firefox OS simulator really: - document.body.className += " togetherjs-mobile-browser"; - } - -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('util',["jquery", "jqueryPlugins"], function ($) { - var util = {}; - - util.Deferred = $.Deferred; - TogetherJS.$ = $; - - /* A simple class pattern, use like: - - var Foo = util.Class({ - constructor: function (a, b) { - init the class - }, - otherMethod: ... - }); - - You can also give a superclass as the optional first argument. - - Instantiation does not require "new" - - */ - util.Class = function (superClass, prototype) { - var a; - if (prototype === undefined) { - prototype = superClass; - } else { - if (superClass.prototype) { - superClass = superClass.prototype; - } - var newPrototype = Object.create(superClass); - for (a in prototype) { - if (prototype.hasOwnProperty(a)) { - newPrototype[a] = prototype[a]; - } - } - prototype = newPrototype; - } - var ClassObject = function () { - var obj = Object.create(prototype); - obj.constructor.apply(obj, arguments); - obj.constructor = ClassObject; - return obj; - }; - ClassObject.prototype = prototype; - if (prototype.constructor.name) { - ClassObject.className = prototype.constructor.name; - ClassObject.toString = function () { - return '[Class ' + this.className + ']'; - }; - } - if (prototype.classMethods) { - for (a in prototype.classMethods) { - if (prototype.classMethods.hasOwnProperty(a)) { - ClassObject[a] = prototype.classMethods[a]; - } - } - } - return ClassObject; - }; - - /* Extends obj with other, or copies obj if no other is given. */ - util.extend = TogetherJS._extend; - - util.forEachAttr = function (obj, callback, context) { - context = context || obj; - for (var a in obj) { - if (obj.hasOwnProperty(a)) { - callback.call(context, obj[a], a); - } - } - }; - - /* Trim whitespace from a string */ - util.trim = function trim(s) { - return s.replace(/^\s+/, "").replace(/\s+$/, ""); - }; - - /* Convert a string into something safe to use as an HTML class name */ - util.safeClassName = function safeClassName(name) { - return name.replace(/[^a-zA-Z0-9_\-]/g, "_") || "class"; - }; - - util.AssertionError = function (message) { - if (! this instanceof util.AssertionError) { - return new util.AssertionError(message); - } - this.message = message; - this.name = "AssertionError"; - }; - util.AssertionError.prototype = Error.prototype; - - util.assert = function (cond) { - if (! cond) { - var args = ["Assertion error:"].concat(Array.prototype.slice.call(arguments, 1)); - console.error.apply(console, args); - if (console.trace) { - console.trace(); - } - throw new util.AssertionError(args.join(" ")); - } - }; - - /* Generates a random ID */ - util.generateId = function (length) { - length = length || 10; - var letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV0123456789'; - var s = ''; - for (var i=0; i this.backoffDetection) { - this._backoff = 0; - } else { - this._backoff++; - } - var time = Math.min(this._backoff * this.backoffTime, this.maxBackoffTime); - setTimeout((function () { - this._setupConnection(); - }).bind(this), time); - } - }).bind(this); - this.socket.onmessage = (function (event) { - this._incoming(event.data); - }).bind(this); - this.socket.onerror = (function (event) { - console.error('WebSocket error:', event.data); - }).bind(this); - } - -}); - - -/* Sends TO a window or iframe */ -channels.PostMessageChannel = util.Class(AbstractChannel, { - _pingPollPeriod: 100, // milliseconds - _pingPollIncrease: 100, // +100 milliseconds for each failure - _pingMax: 2000, // up to a max of 2000 milliseconds - - constructor: function (win, expectedOrigin) { - this.expectedOrigin = expectedOrigin; - this._pingReceived = false; - this._receiveMessage = this._receiveMessage.bind(this); - if (win) { - this.bindWindow(win, true); - } - this._pingFailures = 0; - this.baseConstructor(); - }, - - toString: function () { - var s = '[PostMessageChannel'; - if (this.window) { - s += ' to window ' + this.window; - } else { - s += ' not bound to a window'; - } - if (this.window && ! this._pingReceived) { - s += ' still establishing'; - } - return s + ']'; - }, - - bindWindow: function (win, noSetup) { - if (this.window) { - this.close(); - // Though we deinitialized everything, we aren't exactly closed: - this.closed = false; - } - if (win && win.contentWindow) { - win = win.contentWindow; - } - this.window = win; - // FIXME: The distinction between this.window and window seems unimportant - // in the case of postMessage - var w = this.window; - // In a Content context we add the listener to the local window - // object, but in the addon context we add the listener to some - // other window, like the one we were given: - if (typeof window != "undefined") { - w = window; - } - w.addEventListener("message", this._receiveMessage, false); - if (! noSetup) { - this._setupConnection(); - } - }, - - _send: function (data) { - this.window.postMessage(data, this.expectedOrigin || "*"); - }, - - _ready: function () { - return this.window && this._pingReceived; - }, - - _setupConnection: function () { - if (this.closed || this._pingReceived || (! this.window)) { - return; - } - this._pingFailures++; - this._send("hello"); - // We'll keep sending ping messages until we get a reply - var time = this._pingPollPeriod + (this._pingPollIncrease * this._pingFailures); - time = time > this._pingPollMax ? this._pingPollMax : time; - this._pingTimeout = setTimeout(this._setupConnection.bind(this), time); - }, - - _receiveMessage: function (event) { - if (event.source !== this.window) { - return; - } - if (this.expectedOrigin && event.origin != this.expectedOrigin) { - console.info("Expected message from", this.expectedOrigin, - "but got message from", event.origin); - return; - } - if (! this.expectedOrigin) { - this.expectedOrigin = event.origin; - } - if (event.data == "hello") { - this._pingReceived = true; - if (this._pingTimeout) { - clearTimeout(this._pingTimeout); - this._pingTimeout = null; - } - this._flush(); - return; - } - this._incoming(event.data); - }, - - close: function () { - this.closed = true; - this._pingReceived = false; - if (this._pingTimeout) { - clearTimeout(this._pingTimeout); - } - window.removeEventListener("message", this._receiveMessage, false); - if (this.onclose) { - this.onclose(); - } - this.emit("close"); - } - -}); - - -/* Handles message FROM an exterior window/parent */ -channels.PostMessageIncomingChannel = util.Class(AbstractChannel, { - - constructor: function (expectedOrigin) { - this.source = null; - this.expectedOrigin = expectedOrigin; - this._receiveMessage = this._receiveMessage.bind(this); - window.addEventListener("message", this._receiveMessage, false); - this.baseConstructor(); - }, - - toString: function () { - var s = '[PostMessageIncomingChannel'; - if (this.source) { - s += ' bound to source ' + s; - } else { - s += ' awaiting source'; - } - return s + ']'; - }, - - _send: function (data) { - this.source.postMessage(data, this.expectedOrigin); - }, - - _ready: function () { - return !!this.source; - }, - - _setupConnection: function () { - }, - - _receiveMessage: function (event) { - if (this.expectedOrigin && this.expectedOrigin != "*" && - event.origin != this.expectedOrigin) { - // FIXME: Maybe not worth mentioning? - console.info("Expected message from", this.expectedOrigin, - "but got message from", event.origin); - return; - } - if (! this.expectedOrigin) { - this.expectedOrigin = event.origin; - } - if (! this.source) { - this.source = event.source; - } - if (event.data == "hello") { - // Just a ping - this.source.postMessage("hello", this.expectedOrigin); - return; - } - this._incoming(event.data); - }, - - close: function () { - this.closed = true; - window.removeEventListener("message", this._receiveMessage, false); - if (this._pingTimeout) { - clearTimeout(this._pingTimeout); - } - if (this.onclose) { - this.onclose(); - } - this.emit("close"); - } - -}); - -channels.Router = util.Class(util.mixinEvents({ - - constructor: function (channel) { - this._channelMessage = this._channelMessage.bind(this); - this._channelClosed = this._channelClosed.bind(this); - this._routes = Object.create(null); - if (channel) { - this.bindChannel(channel); - } - }, - - bindChannel: function (channel) { - if (this.channel) { - this.channel.removeListener("message", this._channelMessage); - this.channel.removeListener("close", this._channelClosed); - } - this.channel = channel; - this.channel.on("message", this._channelMessage.bind(this)); - this.channel.on("close", this._channelClosed.bind(this)); - }, - - _channelMessage: function (msg) { - if (msg.type == "route") { - var id = msg.routeId; - var route = this._routes[id]; - if (! route) { - console.warn("No route with the id", id); - return; - } - if (msg.close) { - this._closeRoute(route.id); - } else { - if (route.onmessage) { - route.onmessage(msg.message); - } - route.emit("message", msg.message); - } - } - }, - - _channelClosed: function () { - for (var id in this._routes) { - this._closeRoute(id); - } - }, - - _closeRoute: function (id) { - var route = this._routes[id]; - if (route.onclose) { - route.onclose(); - } - route.emit("close"); - delete this._routes[id]; - }, - - makeRoute: function (id) { - id = id || util.generateId(); - var route = Route(this, id); - this._routes[id] = route; - return route; - } -})); - -var Route = util.Class(util.mixinEvents({ - constructor: function (router, id) { - this.router = router; - this.id = id; - }, - - send: function (msg) { - this.router.channel.send({ - type: "route", - routeId: this.id, - message: msg - }); - }, - - close: function () { - if (this.router._routes[this.id] !== this) { - // This route instance has been overwritten, so ignore - return; - } - delete this.router._routes[this.id]; - } - -})); - -return channels; - -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('storage',["util"], function (util) { - var assert = util.assert; - var Deferred = util.Deferred; - var DEFAULT_SETTINGS = { - name: "", - defaultName: "", - avatar: null, - stickyShare: null, - color: null, - seenIntroDialog: false, - seenWalkthrough: false, - dontShowRtcInfo: false - }; - - var DEBUG_STORAGE = false; - - var Storage = util.Class({ - constructor: function (name, storage, prefix) { - this.name = name; - this.storage = storage; - this.prefix = prefix; - }, - - get: function (key, defaultValue) { - var self = this; - return Deferred(function (def) { - // Strictly this isn't necessary, but eventually I want to move to something more - // async for the storage, and this simulates that much better. - setTimeout(util.resolver(def, function () { - key = self.prefix + key; - var value = self.storage.getItem(key); - if (! value) { - value = defaultValue; - if (DEBUG_STORAGE) { - console.debug("Get storage", key, "defaults to", value); - } - } else { - value = JSON.parse(value); - if (DEBUG_STORAGE) { - console.debug("Get storage", key, "=", value); - } - } - return value; - })); - }); - }, - - set: function (key, value) { - var self = this; - if (value !== undefined) { - value = JSON.stringify(value); - } - return Deferred(function (def) { - key = self.prefix + key; - if (value === undefined) { - self.storage.removeItem(key); - if (DEBUG_STORAGE) { - console.debug("Delete storage", key); - } - } else { - self.storage.setItem(key, value); - if (DEBUG_STORAGE) { - console.debug("Set storage", key, value); - } - } - setTimeout(def.resolve); - }); - }, - - clear: function () { - var self = this; - var promises = []; - return Deferred((function (def) { - this.keys().then(function (keys) { - keys.forEach(function (key) { - // FIXME: technically we're ignoring the promise returned by all - // these sets: - promises.push(self.set(key, undefined)); - }); - util.resolveMany(promises).then(function () { - def.resolve(); - }); - }); - }).bind(this)); - }, - - keys: function (prefix, excludePrefix) { - // Returns a list of keys, potentially with the given prefix - var self = this; - return Deferred(function (def) { - setTimeout(util.resolver(def, function () { - prefix = prefix || ""; - var result = []; - for (var i = 0; i < self.storage.length; i++) { - var key = self.storage.key(i); - if (key.indexOf(self.prefix + prefix) === 0) { - var shortKey = key.substr(self.prefix.length); - if (excludePrefix) { - shortKey = shortKey.substr(prefix.length); - } - result.push(shortKey); - } - } - return result; - })); - }); - }, - - toString: function () { - return '[storage for ' + this.name + ']'; - } - - }); - - var namePrefix = TogetherJS.config.get("storagePrefix"); - TogetherJS.config.close("storagePrefix"); - - var storage = Storage('localStorage', localStorage, namePrefix + "."); - - storage.settings = util.mixinEvents({ - defaults: DEFAULT_SETTINGS, - - get: function (name) { - assert(storage.settings.defaults.hasOwnProperty(name), "Unknown setting:", name); - return storage.get("settings." + name, storage.settings.defaults[name]); - }, - - set: function (name, value) { - assert(storage.settings.defaults.hasOwnProperty(name), "Unknown setting:", name); - return storage.set("settings." + name, value); - } - - }); - - storage.tab = Storage('sessionStorage', sessionStorage, namePrefix + "-session."); - - return storage; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('session',["require", "util", "channels", "jquery", "storage"], function (require, util, channels, $, storage) { - - var DEBUG = true; - - // This is the amount of time in which a hello-back must be received after a hello - // for us to respect a URL change: - var HELLO_BACK_CUTOFF = 1500; - - var session = util.mixinEvents(util.Module("session")); - var assert = util.assert; - - // We will load this module later (there's a circular import): - var peers; - - // This is the hub we connect to: - session.shareId = null; - // This is the ID that identifies this client: - session.clientId = null; - session.router = channels.Router(); - // Indicates if TogetherJS has just started (not continuing from a saved session): - session.firstRun = false; - - // This is the key we use for localStorage: - var localStoragePrefix = "togetherjs."; - // This is the channel to the hub: - var channel = null; - - // Setting, essentially global: - session.AVATAR_SIZE = 90; - - var MAX_SESSION_AGE = 30*24*60*60*1000; // 30 days - - /**************************************** - * URLs - */ - var includeHashInUrl = TogetherJS.config.get("includeHashInUrl"); - TogetherJS.config.close("includeHashInUrl"); - var currentUrl = (location.href + "").replace(/\#.*$/, ""); - if (includeHashInUrl) { - currentUrl = location.href; - } - - session.hubUrl = function (id) { - id = id || session.shareId; - assert(id, "URL cannot be resolved before TogetherJS.shareId has been initialized"); - TogetherJS.config.close("hubBase"); - var hubBase = TogetherJS.config.get("hubBase"); - return hubBase.replace(/\/*$/, "") + "/hub/" + id; - }; - - session.shareUrl = function () { - assert(session.shareId, "Attempted to access shareUrl() before shareId is set"); - var hash = location.hash; - var m = /\?[^#]*/.exec(location.href); - var query = ""; - if (m) { - query = m[0]; - } - hash = hash.replace(/&?togetherjs-[a-zA-Z0-9]+/, ""); - hash = hash || "#"; - return location.protocol + "//" + location.host + location.pathname + query + - hash + "&togetherjs=" + session.shareId; - }; - - session.recordUrl = function () { - assert(session.shareId); - var url = TogetherJS.baseUrl.replace(/\/*$/, "") + "/togetherjs/recorder.html"; - url += "#&togetherjs=" + session.shareId + "&hubBase=" + TogetherJS.config.get("hubBase"); - return url; - }; - - /* location.href without the hash */ - session.currentUrl = function () { - if (includeHashInUrl) { - return location.href; - } else { - return location.href.replace(/#.*/, ""); - } - }; - - /**************************************** - * Message handling/dispatching - */ - - session.hub = util.mixinEvents({}); - - var IGNORE_MESSAGES = TogetherJS.config.get("ignoreMessages"); - if (IGNORE_MESSAGES === true) { - DEBUG = false; - IGNORE_MESSAGES = []; - } - // These are messages sent by clients who aren't "part" of the TogetherJS session: - var MESSAGES_WITHOUT_CLIENTID = ["who", "invite", "init-connection"]; - - // We ignore incoming messages from the channel until this is true: - var readyForMessages = false; - - function openChannel() { - assert(! channel, "Attempt to re-open channel"); - console.info("Connecting to", session.hubUrl(), location.href); - var c = channels.WebSocketChannel(session.hubUrl()); - c.onmessage = function (msg) { - if (! readyForMessages) { - if (DEBUG) { - console.info("In (but ignored for being early):", msg); - } - return; - } - if (DEBUG && IGNORE_MESSAGES.indexOf(msg.type) == -1) { - console.info("In:", msg); - } - if (! peers) { - // We're getting messages before everything is fully initialized - console.warn("Message received before all modules loaded (ignoring):", msg); - return; - } - if ((! msg.clientId) && MESSAGES_WITHOUT_CLIENTID.indexOf(msg.type) == -1) { - console.warn("Got message without clientId, where clientId is required", msg); - return; - } - if (msg.clientId) { - msg.peer = peers.getPeer(msg.clientId, msg); - } - if (msg.type == "hello" || msg.type == "hello-back" || msg.type == "peer-update") { - // We do this here to make sure this is run before any other - // hello handlers: - msg.peer.updateFromHello(msg); - } - if (msg.peer) { - msg.sameUrl = msg.peer.url == currentUrl; - if (!msg.peer.isSelf) { - msg.peer.updateMessageDate(msg); - } - } - session.hub.emit(msg.type, msg); - TogetherJS._onmessage(msg); - }; - channel = c; - session.router.bindChannel(channel); - } - - session.send = function (msg) { - if (DEBUG && IGNORE_MESSAGES.indexOf(msg.type) == -1) { - console.info("Send:", msg); - } - msg.clientId = session.clientId; - channel.send(msg); - }; - - session.appSend = function (msg) { - var type = msg.type; - if (type.search(/^togetherjs\./) === 0) { - type = type.substr("togetherjs.".length); - } else if (type.search(/^app\./) === -1) { - type = "app." + type; - } - msg.type = type; - session.send(msg); - }; - - /**************************************** - * Standard message responses - */ - - /* Always say hello back, and keep track of peers: */ - session.hub.on("hello hello-back", function (msg) { - if (msg.type == "hello") { - sendHello(true); - } - if (session.isClient && (! msg.isClient) && - session.firstRun && session.timeHelloSent && - Date.now() - session.timeHelloSent < HELLO_BACK_CUTOFF) { - processFirstHello(msg); - } - }); - - session.hub.on("who", function (msg) { - sendHello(true); - }); - - function processFirstHello(msg) { - if (! msg.sameUrl) { - var url = msg.url; - if (msg.urlHash) { - url += msg.urlHash; - } - require("ui").showUrlChangeMessage(msg.peer, url); - location.href = url; - } - } - - session.timeHelloSent = null; - - function sendHello(helloBack) { - var msg = session.makeHelloMessage(helloBack); - if (! helloBack) { - session.timeHelloSent = Date.now(); - peers.Self.url = msg.url; - } - session.send(msg); - } - - session.makeHelloMessage = function (helloBack) { - var msg = { - name: peers.Self.name || peers.Self.defaultName, - avatar: peers.Self.avatar, - color: peers.Self.color, - url: session.currentUrl(), - urlHash: location.hash, - // FIXME: titles update, we should track those changes: - title: document.title, - rtcSupported: session.RTCSupported, - isClient: session.isClient - }; - if (helloBack) { - msg.type = "hello-back"; - } else { - msg.type = "hello"; - msg.clientVersion = TogetherJS.version; - } - if (! TogetherJS.startup.continued) { - msg.starting = true; - } - // This is a chance for other modules to effect the hello message: - session.emit("prepare-hello", msg); - return msg; - }; - /**************************************** - * Lifecycle (start and end) - */ - - // These are Javascript files that implement features, and so must - // be injected at runtime because they aren't pulled in naturally - // via define(). - // ui must be the first item: - var features = ["peers", "ui", "chat", "webrtc", "cursor", "startup", "videos", "forms", "visibilityApi", "youtubeVideos"]; - - function getRoomName(prefix, maxSize) { - var findRoom = TogetherJS.config.get("hubBase").replace(/\/*$/, "") + "/findroom"; - return $.ajax({ - url: findRoom, - dataType: "json", - data: {prefix: prefix, max: maxSize} - }).then(function (resp) { - return resp.name; - }); - } - - function initIdentityId() { - return util.Deferred(function (def) { - if (session.identityId) { - def.resolve(); - return; - } - storage.get("identityId").then(function (identityId) { - if (! identityId) { - identityId = util.generateId(); - storage.set("identityId", identityId); - } - session.identityId = identityId; - // We don't actually have to wait for the set to succede, so - // long as session.identityId is set - def.resolve(); - }); - }); - } - - initIdentityId.done = initIdentityId(); - - function initShareId() { - return util.Deferred(function (def) { - var hash = location.hash; - var shareId = session.shareId; - var isClient = true; - var set = true; - var sessionId; - session.firstRun = ! TogetherJS.startup.continued; - if (! shareId) { - if (TogetherJS.startup._joinShareId) { - // Like, below, this *also* means we got the shareId from the hash - // (in togetherjs.js): - shareId = TogetherJS.startup._joinShareId; - } - } - if (! shareId) { - // FIXME: I'm not sure if this will ever happen, because togetherjs.js should - // handle it - var m = /&?togetherjs=([^&]*)/.exec(hash); - if (m) { - isClient = ! m[1]; - shareId = m[2]; - var newHash = hash.substr(0, m.index) + hash.substr(m.index + m[0].length); - location.hash = newHash; - } - } - return storage.tab.get("status").then(function (saved) { - var findRoom = TogetherJS.config.get("findRoom"); - TogetherJS.config.close("findRoom"); - if (findRoom && saved && findRoom != saved.shareId) { - console.info("Ignoring findRoom in lieu of continued session"); - } else if (findRoom && TogetherJS.startup._joinShareId) { - console.info("Ignoring findRoom in lieu of explicit invite to session"); - } - if (findRoom && typeof findRoom == "string" && (! saved) && (! TogetherJS.startup._joinShareId)) { - isClient = true; - shareId = findRoom; - sessionId = util.generateId(); - } else if (findRoom && (! saved) && (! TogetherJS.startup._joinShareId)) { - assert(findRoom.prefix && typeof findRoom.prefix == "string", "Bad findRoom.prefix", findRoom); - assert(findRoom.max && typeof findRoom.max == "number" && findRoom.max > 0, - "Bad findRoom.max", findRoom); - sessionId = util.generateId(); - if (findRoom.prefix.search(/[^a-zA-Z0-9]/) != -1) { - console.warn("Bad value for findRoom.prefix:", JSON.stringify(findRoom.prefix)); - } - getRoomName(findRoom.prefix, findRoom.max).then(function (shareId) { - // FIXME: duplicates code below: - session.clientId = session.identityId + "." + sessionId; - storage.tab.set("status", {reason: "joined", shareId: shareId, running: true, date: Date.now(), sessionId: sessionId}); - session.isClient = true; - session.shareId = shareId; - session.emit("shareId"); - def.resolve(session.shareId); - }); - return; - } else if (TogetherJS.startup._launch) { - if (saved) { - isClient = saved.reason == "joined"; - if (! shareId) { - shareId = saved.shareId; - } - sessionId = saved.sessionId; - } else { - isClient = TogetherJS.startup.reason == "joined"; - assert(! sessionId); - sessionId = util.generateId(); - } - if (! shareId) { - shareId = util.generateId(); - } - } else if (saved) { - isClient = saved.reason == "joined"; - TogetherJS.startup.reason = saved.reason; - TogetherJS.startup.continued = true; - shareId = saved.shareId; - sessionId = saved.sessionId; - // The only case when we don't need to set the storage status again is when - // we're already set to be running - set = ! saved.running; - } else { - throw new util.AssertionError("No saved status, and no startup._launch request; why did TogetherJS start?"); - } - assert(session.identityId); - session.clientId = session.identityId + "." + sessionId; - if (set) { - storage.tab.set("status", {reason: TogetherJS.startup.reason, shareId: shareId, running: true, date: Date.now(), sessionId: sessionId}); - } - session.isClient = isClient; - session.shareId = shareId; - session.emit("shareId"); - def.resolve(session.shareId); - }); - }); - } - - function initStartTarget() { - var id; - if (TogetherJS.startup.button) { - id = TogetherJS.startup.button.id; - if (id) { - storage.set("startTarget", id); - } - return; - } - storage.get("startTarget").then(function (id) { - var el = document.getElementById(id); - if (el) { - TogetherJS.startup.button = el; - } - }); - } - session.start = function () { - initStartTarget(); - initIdentityId().then(function () { - initShareId().then(function () { - readyForMessages = false; - openChannel(); - require(["ui"], function (ui) { - TogetherJS.running = true; - ui.prepareUI(); - require(features, function () { - $(function () { - peers = require("peers"); - var startup = require("startup"); - session.emit("start"); - session.once("ui-ready", function () { - readyForMessages = true; - startup.start(); - }); - ui.activateUI(); - TogetherJS.config.close("enableAnalytics"); - if (TogetherJS.config.get("enableAnalytics")) { - require(["analytics"], function (analytics) { - analytics.activate(); - }); - } - peers._SelfLoaded.then(function () { - sendHello(false); - }); - TogetherJS.emit("ready"); - }); - }); - }); - }); - }); - }; - - session.close = function (reason) { - TogetherJS.running = false; - var msg = {type: "bye"}; - if (reason) { - msg.reason = reason; - } - session.send(msg); - session.emit("close"); - var name = window.name; - storage.tab.get("status").then(function (saved) { - if (! saved) { - console.warn("No session information saved in", "status." + name); - } else { - saved.running = false; - saved.date = Date.now(); - storage.tab.set("status", saved); - } - channel.close(); - channel = null; - session.shareId = null; - session.emit("shareId"); - TogetherJS.emit("close"); - TogetherJS._teardown(); - }); - }; - - session.on("start", function () { - $(window).on("resize", resizeEvent); - if (includeHashInUrl) { - $(window).on("hashchange", hashchangeEvent); - } - }); - - session.on("close", function () { - $(window).off("resize", resizeEvent); - if (includeHashInUrl) { - $(window).off("hashchange", hashchangeEvent); - } - }); - - function hashchangeEvent() { - // needed because when message arives from peer this variable will be checked to - // decide weather to show actions or not - sendHello(false); - } - - function resizeEvent() { - session.emit("resize"); - } - - if (TogetherJS.startup._launch) { - setTimeout(session.start); - } - - util.testExpose({ - getChannel: function () { - return channel; - } - }); - - return session; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('templates',["util"], function (util) { - function clean(t) { - // Removes <% /* ... */ %> comments: - t = t.replace(/[<][%]\s*\/\*[\S\s\r\n]*\*\/\s*[%][>]/, ""); - t = util.trim(t); - t = t.replace(/http:\/\/localhost:8080/g, TogetherJS.baseUrl); - return t; - } - return { - "interface": clean("<% /*\n This is basically all the markup and interface for TogetherJS.\n Note all links should be like http://localhost:8080/togetherjs/*\n these links are rewritten with the location where TogetherJS was deployed.\n\n This file is inlined into togetherjs/templates.js\n*/ %>\n
    \n\n \n
    \n
    \n \n \"drag\"\n \n \n \"drag\"\n \n
    \n
    \n
    \n \n
    \n \n \n \n \n
    \n
    \n
    \n\n \n
    \n
    Update avatar
    \n
    \n
    \n
    \n \n \n \n
    \n
    \n
    \n \n or\n \n
    \n
    \n\n \n
    \n
    Invite a friend
    \n
    \n
    \n

    Copy and paste this link over IM or email:

    \n \n
    \n
    \n

    Copy and paste this link over IM or email:

    \n \n \n
    \n
    \n
    \n\n \n
    \n
    Participants
    \n
    \n
    \n \n
    \n
    \n\n \n
    \n
    \n\n
    \n

    Role:\n \n

    \n\n

    Currently at:\n \n

    \n\n

    Status:\n \n

    \n\n

    Follow this participant:\n \n \n

    \n\n
    \n\n
    \n \n \n \n
    \n is on the same page as you.\n
    \n
    \n
    \n\n \n
    \n
    Chat
    \n
    \n
    \n \n & You\n
    \n
    \n No one else is here.\n
    \n
    \n\n
    \n\n \n
    \n
    \n
    HH:MM AM/PM
    \n
    \n
    \n
    \n\n \n
    \n
    \n
    \n
    left the session.
    \n
    \n
    \n
    declined to join the session.
    \n
    \n
    \n
    \n\n \n
    \n
    \n
    joined the session.
    \n
    \n
    \n\n \n
    \n \n
    \n\n \n \n\n \n
    \n
    \n
    \n
    \n \n is on the same page as you.\n
    \n
    \n \n has gone to: \n
    \n \n \n
    \n\n \n\n
    \n
    \n
    \n
    \n
    \n\n
    \n \n
    \n
    \n \n
    \n
    \n\n \n
    \n\n
    Audio Chat
    \n
    \n

    \n Activate your browser microphone near your URL bar above.\n

    \n

    \n Talking on your microphone through your web browser is an experimental feature.\n

    \n

    \n Read more about Audio Chat here.\n

    \n
    \n\n
    \n \n \n
    \n
    \n\n \n
    \n
    Audio Chat
    \n\n
    \n

    Audio chat requires you to use a \n newer browser\n !

    \n

    \n Live audio chat requires a newer (or different) browser than you're using.\n

    \n

    \n See\n \n this page\n \n for more information and a list of supported browsers.\n

    \n
    \n\n
    \n
    \n \n
    \n
    \n
    \n\n \n
    \n \"\"\n \"[close]\"\n
    \n
    \n
    \n\n \n
    \n
    \n \n \n \n
    \n
    \n
    \"\" Update your name
    \n
    \"\" Change avatar
    \n
    Pick profile color
    \n
    \n
    Help
    \n
    Feedback
    \n
    \n
    \n
    \n
    Refresh users
    \n
    Invite anyone
    \n
    \n
    \n
    \"\" End TogetherJS
    \n
    \n\n \n
    \n
    \n \n \n
    \n
    \n\n \n
    \n
    Settings and Profile
    \n
    \n
    \n \n \n
    \n
    \n
    \"\" Update your name
    \n
    \"\" Change avatar
    \n
    Pick profile color
    \n
    \n
    Help
    \n
    Feedback
    \n
    \n
    \"\" End TogetherJS
    \n
    \n
    \n \n
    \n
    \n\n \n
    \n
    Update Name
    \n
    \n
    \n \n
    \n
    \n
    \n \n
    \n
    \n\n
    \n
    \n
    \n
    \n
    \n
    \n
    \n\n \n \n \n \n\n \n
    \n
    Join TogetherJS session?
    \n
    \n

    Your friend has asked you to join their TogetherJS browser session to collaborate in real-time!

    \n\n

    Would you like to join their session?

    \n
    \n\n
    \n \n \n
    \n
    \n\n \n
    \n
    Sorry
    \n\n
    \n

    \n We're sorry, TogetherJS doesn't work with this browser. Please\n upgrade\n to a supported browser to try TogetherJS.\n

    \n\n

    \n We need your help fixing TogetherJS on Internet Explorer! Here are a list of IE GitHub issues we need fixed that you can work on.\n Internet Explorer is\n currently not supported. If you do want to try out TogetherJS, we'd suggest using Firefox or Chrome.\n

    \n
    \n\n
    \n \n
    \n\n
    \n\n \n
    \n
    Unsupported Browser
    \n\n
    \n

    \n We need your help fixing TogetherJS on Internet Explorer! Here are a list of IE GitHub issues we need fixed that you can work on.\n Internet Explorer is not supported\n at this time. While we may add support later, adding support is\n not currently on our roadmap. If you do want to try out TogetherJS, we'd suggest using Firefox or Chrome.\n

    \n\n

    You can continue to try to use TogetherJS, but you are likely to hit\n lots of bugs. So be warned.

    \n\n
    \n\n
    \n \n \n
    \n\n
    \n\n
    \n
    End session?
    \n
    \n

    \n Are you sure you'd like to end your TogetherJS session?\n

    \n
    \n
    \n \n or\n \n
    \n
    \n\n
    \n
    Feedback
    \n \n \n
    \n\n
    \n \n
    \n
    Following to new URL...
    \n
    \n
    \n Following\n \n to \n
    \n
    \n\n \n
    \n
    \n
    \n \n has invited anyone\n you\n to \n
    \n
    \n\n
    \n\n \n
    \n
    \n\n \n
    \n\n \n
    \n\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n\n \n \n
    \n\n \n
    \n
    \n
    \n\n \n
    \n
    \n
    \n
    \n"), - help: clean("<% /*\n This is used to show the help when you type /help. Used in\n TogetherJS.localChatMessage().\n\n*/ %>\n/help : this message\n/test : run an automated/randomized test (or stop one that is in progress)\n /test start N : run N times (instead of default 100)\n /test show : show what kind of actions the random test would take (or stop showing)\n /test describe : describe the possible actions (instead of showing them)\n/clear : clear the chat area\n/record : open up a recorder for the session\n/playback URL : play back a session that was recorded (it's up to you to figure out how to host it)\n /playback local:NAME : play a locally saved log\n/savelogs NAME : save the currently recorded logs under NAME (recorder must be open)\n/baseurl : set a local baseUrl to load TogetherJS from, for debugging a development version of TogetherJS.\n/config : override some TogetherJS configuration parameters\n /config VAR VALUE : set TogetherJS.config(\"VAR\", VALUE). VALUE must be a legal Javascript/JSON literal.\n /config clear : remove all overridden configuration\n"), - walkthrough: clean("\n
    \n
    You're using TogetherJS!
    \n\n
    \n
    \n\n
    \n

    \n\t

    TogetherJS is a service for your website that makes it easy to collaborate in real-time on: [site name]

    \n
    \n\n
    \n
    \n
    \n
    \n
    \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n

    Set up your avatar, name and user color above. If you'd like to update it later, you can click your Profile button.

    \n
    \n
    \n

    \n

    Change your avatar, name and user color using the Profile button.

    \n
    \n
    \n\n
    \n

    \n

    \n

    You can invite more friends to the session by sending the invite link in the TogetherJS dock.

    \n

    \n \n Copy and paste this link into IM or email to invite friends.\n \n \n

    \n

    Send the above link to a friend so they can join your session! You can find this invite link on the TogetherJS dock as well.

    \n
    \n\n
    \n

    \n

    Friends who join your TogetherJS session will appear here. You can click their avatars to see more.

    \n
    \n\n
    \n

    \n

    When your friends join you in your TogetherJS session, you can chat with them here!

    \n
    \n\n
    \n

    \n

    If your browser supports it, click the microphone icon to begin a audio chat. Learn more about this experimental feature here.

    \n
    \n\n
    \n

    \n

    Alright, you're ready to use TogetherJS. Now start collaborating on [site name]!

    \n
    \n\n
    \n \n \n
    \n
    \n
    \n\n
    \n \n
    \n\n
    \n") - }; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('peers',["util", "session", "storage", "require"], function (util, session, storage, require) { - var peers = util.Module("peers"); - var assert = util.assert; - var CHECK_ACTIVITY_INTERVAL = 10*1000; // Every 10 seconds see if someone has gone idle - var IDLE_TIME = 3*60*1000; // Idle time is 3 minutes - var TAB_IDLE_TIME = 2*60*1000; // When you tab away, after two minutes you'll say you are idle - var BYE_TIME = 10*60*1000; // After 10 minutes of inactivity the person is considered to be "gone" - - var ui; - require(["ui"], function (uiModule) { - ui = uiModule; - }); - - var DEFAULT_NICKNAMES = [ - "Friendly Fox", - "Brilliant Beaver", - "Observant Owl", - "Gregarious Giraffe", - "Wild Wolf", - "Silent Seal", - "Wacky Whale", - "Curious Cat", - "Intelligent Iguana" - ]; - - var Peer = util.Class({ - - isSelf: false, - - constructor: function (id, attrs) { - attrs = attrs || {}; - assert(id); - assert(! Peer.peers[id]); - this.id = id; - this.identityId = attrs.identityId || null; - this.status = attrs.status || "live"; - this.idle = attrs.status || "active"; - this.name = attrs.name || null; - this.avatar = attrs.avatar || null; - this.color = attrs.color || "#00FF00"; - this.view = ui.PeerView(this); - this.lastMessageDate = 0; - this.following = attrs.following || false; - Peer.peers[id] = this; - var joined = attrs.joined || false; - if (attrs.fromHelloMessage) { - this.updateFromHello(attrs.fromHelloMessage); - if (attrs.fromHelloMessage.type == "hello") { - joined = true; - } - } - peers.emit("new-peer", this); - if (joined) { - this.view.notifyJoined(); - } - this.view.update(); - }, - - repr: function () { - return "Peer(" + JSON.stringify(this.id) + ")"; - }, - - serialize: function () { - return { - id: this.id, - status: this.status, - idle: this.idle, - url: this.url, - hash: this.hash, - title: this.title, - identityId: this.identityId, - rtcSupported: this.rtcSupported, - name: this.name, - avatar: this.avatar, - color: this.color, - following: this.following - }; - }, - - destroy: function () { - this.view.destroy(); - delete Peer.peers[this.id]; - }, - - updateMessageDate: function (msg) { - if (this.idle == "inactive") { - this.update({idle: "active"}); - } - if (this.status == "bye") { - this.unbye(); - } - this.lastMessageDate = Date.now(); - }, - - updateFromHello: function (msg) { - var urlUpdated = false; - var activeRTC = false; - var identityUpdated = false; - if (msg.url && msg.url != this.url) { - this.url = msg.url; - this.hash = null; - this.title = null; - urlUpdated = true; - } - if (msg.hash != this.hash) { - this.hash = msg.urlHash; - urlUpdated = true; - } - if (msg.title != this.title) { - this.title = msg.title; - urlUpdated = true; - } - if (msg.rtcSupported !== undefined) { - this.rtcSupported = msg.rtcSupported; - } - if (msg.identityId !== undefined) { - this.identityId = msg.identityId; - } - if (msg.name && msg.name != this.name) { - this.name = msg.name; - identityUpdated = true; - } - if (msg.avatar && msg.avatar != this.avatar) { - util.assertValidUrl(msg.avatar); - this.avatar = msg.avatar; - identityUpdated = true; - } - if (msg.color && msg.color != this.color) { - this.color = msg.color; - identityUpdated = true; - } - if (msg.isClient !== undefined) { - this.isCreator = ! msg.isClient; - } - if (this.status != "live") { - this.status = "live"; - peers.emit("status-updated", this); - } - if (this.idle != "active") { - this.idle = "active"; - peers.emit("idle-updated", this); - } - if (msg.rtcSupported) { - peers.emit("rtc-supported", this); - } - if (urlUpdated) { - peers.emit("url-updated", this); - } - if (identityUpdated) { - peers.emit("identity-updated", this); - } - // FIXME: I can't decide if this is the only time we need to emit - // this message (and not .update() or other methods) - if (this.following) { - session.emit("follow-peer", this); - } - }, - - update: function (attrs) { - // FIXME: should probably test that only a couple attributes are settable - // particularly status and idle - if (attrs.idle) { - this.idle = attrs.idle; - } - if (attrs.status) { - this.status = attrs.status; - } - this.view.update(); - }, - - className: function (prefix) { - prefix = prefix || ""; - return prefix + util.safeClassName(this.id); - }, - - bye: function () { - if (this.status != "bye") { - this.status = "bye"; - peers.emit("status-updated", this); - } - this.view.update(); - }, - - unbye: function () { - if (this.status == "bye") { - this.status = "live"; - peers.emit("status-updated", this); - } - this.view.update(); - }, - - nudge: function () { - session.send({ - type: "url-change-nudge", - url: location.href, - to: this.id - }); - }, - - follow: function () { - if (this.following) { - return; - } - peers.getAllPeers().forEach(function (p) { - if (p.following) { - p.unfollow(); - } - }); - this.following = true; - // We have to make sure we remember this, even if we change URLs: - storeSerialization(); - this.view.update(); - session.emit("follow-peer", this); - }, - - unfollow: function () { - this.following = false; - storeSerialization(); - this.view.update(); - } - - }); - - // FIXME: I can't decide where this should actually go, seems weird - // that it is emitted and handled in the same module - session.on("follow-peer", function (peer) { - if (peer.url != session.currentUrl()) { - var url = peer.url; - if (peer.urlHash) { - url += peer.urlHash; - } - location.href = url; - } - }); - - Peer.peers = {}; - - Peer.deserialize = function (obj) { - obj.fromStorage = true; - var peer = Peer(obj.id, obj); - }; - - peers.Self = undefined; - - session.on("start", function () { - if (peers.Self) { - return; - } - /* Same interface as Peer, represents oneself (local user): */ - peers.Self = util.mixinEvents({ - isSelf: true, - id: session.clientId, - identityId: session.identityId, - status: "live", - idle: "active", - name: null, - avatar: null, - color: null, - defaultName: null, - loaded: false, - isCreator: ! session.isClient, - - update: function (attrs) { - var updatePeers = false; - var updateIdle = false; - var updateMsg = {type: "peer-update"}; - if (typeof attrs.name == "string" && attrs.name != this.name) { - this.name = attrs.name; - updateMsg.name = this.name; - if (! attrs.fromLoad) { - storage.settings.set("name", this.name); - updatePeers = true; - } - } - if (attrs.avatar && attrs.avatar != this.avatar) { - util.assertValidUrl(attrs.avatar); - this.avatar = attrs.avatar; - updateMsg.avatar = this.avatar; - if (! attrs.fromLoad) { - storage.settings.set("avatar", this.avatar); - updatePeers = true; - } - } - if (attrs.color && attrs.color != this.color) { - this.color = attrs.color; - updateMsg.color = this.color; - if (! attrs.fromLoad) { - storage.settings.set("color", this.color); - updatePeers = true; - } - } - if (attrs.defaultName && attrs.defaultName != this.defaultName) { - this.defaultName = attrs.defaultName; - if (! attrs.fromLoad) { - storage.settings.set("defaultName", this.defaultName); - updatePeers = true; - } - } - if (attrs.status && attrs.status != this.status) { - this.status = attrs.status; - peers.emit("status-updated", this); - } - if (attrs.idle && attrs.idle != this.idle) { - this.idle = attrs.idle; - updateIdle = true; - peers.emit("idle-updated", this); - } - this.view.update(); - if (updatePeers && ! attrs.fromLoad) { - session.emit("self-updated"); - session.send(updateMsg); - } - if (updateIdle && ! attrs.fromLoad) { - session.send({ - type: "idle-status", - idle: this.idle - }); - } - }, - - className: function (prefix) { - prefix = prefix || ""; - return prefix + "self"; - }, - - _loadFromSettings: function () { - return util.resolveMany( - storage.settings.get("name"), - storage.settings.get("avatar"), - storage.settings.get("defaultName"), - storage.settings.get("color")).then((function (name, avatar, defaultName, color) { - if (! defaultName) { - defaultName = util.pickRandom(DEFAULT_NICKNAMES); - storage.settings.set("defaultName", defaultName); - } - if (! color) { - color = Math.floor(Math.random() * 0xffffff).toString(16); - while (color.length < 6) { - color = "0" + color; - } - color = "#" + color; - storage.settings.set("color", color); - } - if (! avatar) { - avatar = TogetherJS.baseUrl + "/togetherjs/images/default-avatar.png"; - } - this.update({ - name: name, - avatar: avatar, - defaultName: defaultName, - color: color, - fromLoad: true - }); - peers._SelfLoaded.resolve(); - }).bind(this)); // FIXME: ignoring error - }, - - _loadFromApp: function () { - // FIXME: I wonder if these should be optionally functions? - // We could test typeof==function to distinguish between a getter and a concrete value - var getUserName = TogetherJS.config.get("getUserName"); - var getUserColor = TogetherJS.config.get("getUserColor"); - var getUserAvatar = TogetherJS.config.get("getUserAvatar"); - var name, color, avatar; - if (getUserName) { - if (typeof getUserName == "string") { - name = getUserName; - } else { - name = getUserName(); - } - if (name && typeof name != "string") { - // FIXME: test for HTML safe? Not that we require it, but - // <>'s are probably a sign something is wrong. - console.warn("Error in getUserName(): should return a string (got", name, ")"); - name = null; - } - } - if (getUserColor) { - if (typeof getUserColor == "string") { - color = getUserColor; - } else { - color = getUserColor(); - } - if (color && typeof color != "string") { - // FIXME: would be nice to test for color-ness here. - console.warn("Error in getUserColor(): should return a string (got", color, ")"); - color = null; - } - } - if (getUserAvatar) { - if (typeof getUserAvatar == "string") { - avatar = getUserAvatar; - } else { - avatar = getUserAvatar(); - } - if (avatar && typeof avatar != "string") { - console.warn("Error in getUserAvatar(): should return a string (got", avatar, ")"); - avatar = null; - } - } - if (name || color || avatar) { - this.update({ - name: name, - color: color, - avatar: avatar - }); - } - } - }); - - peers.Self.view = ui.PeerView(peers.Self); - storage.tab.get("peerCache").then(deserialize); - peers.Self._loadFromSettings().then(function() { - peers.Self._loadFromApp(); - peers.Self.view.update(); - session.emit("self-updated"); - }); - }); - - session.on("refresh-user-data", function () { - if (peers.Self) { - peers.Self._loadFromApp(); - } - }); - - TogetherJS.config.track( - "getUserName", - TogetherJS.config.track( - "getUserColor", - TogetherJS.config.track( - "getUserAvatar", - function () { - if (peers.Self) { - peers.Self._loadFromApp(); - } - } - ) - ) - ); - - peers._SelfLoaded = util.Deferred(); - - function serialize() { - var peers = []; - util.forEachAttr(Peer.peers, function (peer) { - peers.push(peer.serialize()); - }); - return { - peers: peers - }; - } - - function deserialize(obj) { - if (! obj) { - return; - } - obj.peers.forEach(function (peer) { - Peer.deserialize(peer); - }); - } - - peers.getPeer = function getPeer(id, message) { - assert(id); - var peer = Peer.peers[id]; - if (id === session.clientId) { - return peers.Self; - } - if (message && ! peer) { - peer = Peer(id, {fromHelloMessage: message}); - return peer; - } - assert(peer, "No peer with id:", id); - if (message && - (message.type == "hello" || message.type == "hello-back" || - message.type == "peer-update")) { - peer.updateFromHello(message); - peer.view.update(); - } - return Peer.peers[id]; - }; - - peers.getAllPeers = function (liveOnly) { - var result = []; - util.forEachAttr(Peer.peers, function (peer) { - if (liveOnly && peer.status != "live") { - return; - } - result.push(peer); - }); - return result; - }; - - function checkActivity() { - var ps = peers.getAllPeers(); - var now = Date.now(); - ps.forEach(function (p) { - if (p.idle == "active" && now - p.lastMessageDate > IDLE_TIME) { - p.update({idle: "inactive"}); - } - if (p.status != "bye" && now - p.lastMessageDate > BYE_TIME) { - p.bye(); - } - }); - } - - session.hub.on("bye", function (msg) { - var peer = peers.getPeer(msg.clientId); - peer.bye(); - }); - - var checkActivityTask = null; - - session.on("start", function () { - if (checkActivityTask) { - console.warn("Old peers checkActivityTask left over?"); - clearTimeout(checkActivityTask); - } - checkActivityTask = setInterval(checkActivity, CHECK_ACTIVITY_INTERVAL); - }); - - session.on("close", function () { - util.forEachAttr(Peer.peers, function (peer) { - peer.destroy(); - }); - storage.tab.set("peerCache", undefined); - clearTimeout(checkActivityTask); - checkActivityTask = null; - }); - - var tabIdleTimeout = null; - - session.on("visibility-change", function (hidden) { - if (hidden) { - if (tabIdleTimeout) { - clearTimeout(tabIdleTimeout); - } - tabIdleTimeout = setTimeout(function () { - peers.Self.update({idle: "inactive"}); - }, TAB_IDLE_TIME); - } else { - if (tabIdleTimeout) { - clearTimeout(tabIdleTimeout); - } - if (peers.Self.idle == "inactive") { - peers.Self.update({idle: "active"}); - } - } - }); - - session.hub.on("idle-status", function (msg) { - msg.peer.update({idle: msg.idle}); - }); - - // Pings are a straight alive check, and contain no more information: - session.hub.on("ping", function () { - session.send({type: "ping-back"}); - }); - - window.addEventListener("pagehide", function () { - // FIXME: not certain if this should be tab local or not: - storeSerialization(); - }, false); - - function storeSerialization() { - storage.tab.set("peerCache", serialize()); - } - - util.mixinEvents(peers); - - util.testExpose({ - setIdleTime: function (time) { - IDLE_TIME = time; - CHECK_ACTIVITY_INTERVAL = time / 2; - if (TogetherJS.running) { - clearTimeout(checkActivityTask); - checkActivityTask = setInterval(checkActivity, CHECK_ACTIVITY_INTERVAL); - } - } - }); - - util.testExpose({ - setByeTime: function (time) { - BYE_TIME = time; - CHECK_ACTIVITY_INTERVAL = Math.min(CHECK_ACTIVITY_INTERVAL, time / 2); - if (TogetherJS.running) { - clearTimeout(checkActivityTask); - checkActivityTask = setInterval(checkActivity, CHECK_ACTIVITY_INTERVAL); - } - } - }); - - return peers; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ -define('windowing',["jquery", "util", "peers", "session"], function ($, util, peers, session) { - var assert = util.assert; - var windowing = util.Module("windowing"); - var $window = $(window); - // This is also in togetherjs.less, under .togetherjs-animated - var ANIMATION_DURATION = 1000; - - /* Displays one window. A window must already exist. This hides other windows, and - positions the window according to its data-bound-to attributes */ - windowing.show = function (element, options) { - element = $(element); - options = options || {}; - options.bind = options.bind || element.attr("data-bind-to"); - var notification = element.hasClass("togetherjs-notification"); - var modal = element.hasClass("togetherjs-modal"); - if (options.bind) { - options.bind = $(options.bind); - } - windowing.hide(); - element.stop(); - element.show(); - // In addition to being hidden, the window can be faded out, which we want to undo: - element.css({opacity: "1"}); - if (options.bind) { - assert(! modal, "Binding does not currently work with modals"); - bind(element, options.bind); - } - if (notification) { - element.slideIn(); - } else if (! modal) { - element.popinWindow(); - } - if (modal) { - getModalBackground().show(); - modalEscape.bind(); - } - onClose = options.onClose || null; - session.emit("display-window", element.attr("id"), element); - }; - - var onClose = null; - - /* Moves a window to be attached to data-bind-to, e.g., the button - that opened the window. Or you can provide an element that it should bind to. */ - function bind(win, bound) { - if ($.browser.mobile) { - return; - } - win = $(win); - assert(bound.length, "Cannot find binding:", bound.selector, "from:", win.selector); - // FIXME: hardcoding - var ifacePos = "right"; - //var ifacePos = panelPosition(); - var boundPos = bound.offset(); - boundPos.height = bound.height(); - boundPos.width = bound.width(); - var windowHeight = $window.height(); - boundPos.top -= $window.scrollTop(); - boundPos.left -= $window.scrollLeft(); - // FIXME: I appear to have to add the padding to the width to get a "true" - // width. But it's still not entirely consistent. - var height = win.height() + 5; - var width = win.width() + 20; - var left, top; - if (ifacePos == "right") { - left = boundPos.left - 11 - width; - top = boundPos.top + (boundPos.height / 2) - (height / 2); - } else if (ifacePos == "left") { - left = boundPos.left + boundPos.width + 15; - top = boundPos.top + (boundPos.height / 2) - (height / 2); - } else if (ifacePos == "bottom") { - left = (boundPos.left + boundPos.width / 2) - (width / 2); - top = boundPos.top - 10 - height; - } - top = Math.min(windowHeight - 10 - height, Math.max(10, top)); - win.css({ - top: top + "px", - left: left + "px" - }); - if (win.hasClass("togetherjs-window")) { - $("#togetherjs-window-pointer-right, #togetherjs-window-pointer-left").hide(); - var pointer = $("#togetherjs-window-pointer-" + ifacePos); - pointer.show(); - if (ifacePos == "right") { - pointer.css({ - top: boundPos.top + Math.floor(boundPos.height / 2) + "px", - left: left + win.width() + 9 + "px" - }); - } else if (ifacePos == "left") { - pointer.css({ - top: boundPos.top + Math.floor(boundPos.height / 2) + "px", - left: (left - 5) + "px" - }); - } else { - console.warn("don't know how to deal with position:", ifacePos); - } - } - win.data("boundTo", bound.selector || "#" + bound.attr("id")); - bound.addClass("togetherjs-active"); - } - - session.on("resize", function () { - var win = $(".togetherjs-modal:visible, .togetherjs-window:visible"); - if (! win.length) { - return; - } - var boundTo = win.data("boundTo"); - if (! boundTo) { - return; - } - boundTo = $(boundTo); - bind(win, boundTo); - }); - - windowing.hide = function (els) { - // FIXME: also hide modals? - els = els || ".togetherjs-window, .togetherjs-modal, .togetherjs-notification"; - els = $(els); - els = els.filter(":visible"); - els.filter(":not(.togetherjs-notification)").hide(); - getModalBackground().hide(); - var windows = []; - els.each(function (index, element) { - element = $(element); - windows.push(element); - var bound = element.data("boundTo"); - if (! bound) { - return; - } - bound = $(bound); - bound.addClass("togetherjs-animated").addClass("togetherjs-color-pulse"); - setTimeout(function () { - bound.removeClass("togetherjs-color-pulse").removeClass("togetherjs-animated"); - }, ANIMATION_DURATION+10); - element.data("boundTo", null); - bound.removeClass("togetherjs-active"); - if (element.hasClass("togetherjs-notification")) { - element.fadeOut().promise().then(function () { - this.hide(); - }); - } - }); - $("#togetherjs-window-pointer-right, #togetherjs-window-pointer-left").hide(); - if (onClose) { - onClose(); - onClose = null; - } - if (windows.length) { - session.emit("hide-window", windows); - } - }; - - windowing.showNotification = function (element, options) { - element = $(element); - options = options || {}; - assert(false); - }; - - windowing.toggle = function (el) { - el = $(el); - if (el.is(":visible")) { - windowing.hide(el); - } else { - windowing.show(el); - } - }; - - function bindEvents(el) { - el.find(".togetherjs-close, .togetherjs-dismiss").click(function (event) { - var w = $(event.target).closest(".togetherjs-window, .togetherjs-modal, .togetherjs-notification"); - windowing.hide(w); - event.stopPropagation(); - return false; - }); - } - - function getModalBackground() { - if (getModalBackground.element) { - return getModalBackground.element; - } - var background = $("#togetherjs-modal-background"); - assert(background.length); - getModalBackground.element = background; - background.click(function () { - windowing.hide(); - }); - return background; - } - - var modalEscape = { - bind: function () { - $(document).keydown(modalEscape.onKeydown); - }, - unbind: function () { - $(document).unbind("keydown", modalEscape.onKeydown); - }, - onKeydown: function (event) { - if (event.which == 27) { - windowing.hide(); - } - } - }; - - session.on("close", function () { - modalEscape.unbind(); - }); - - session.on("new-element", function (el) { - bindEvents(el); - }); - - return windowing; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ -define('templating',["jquery", "util", "peers", "windowing", "session"], function ($, util, peers, windowing, session) { - var assert = util.assert; - var templating = util.Module("templating"); - - templating.clone = function (templateId) { - templateId = "#togetherjs-template-" + templateId; - var template = $(templateId); - assert(template.length, "No template found with id:", templateId); - template = template.clone(); - template.attr("id", null); - // FIXME: if called directly, doesn't emit new-element event: - return template; - }; - - templating.sub = function (templateId, variables) { - var template = templating.clone(templateId); - variables = variables || {}; - util.forEachAttr(variables, function (value, attr) { - // FIXME: do the substitution... somehow? - var subs = template.find(".togetherjs-sub-" + attr).removeClass("togetherjs-sub-" + attr); - if (subs.length) { - if (typeof value == "string") { - subs.text(value); - } else if (value instanceof $) { - subs.append(value); - } else { - assert(false, "Unknown variable value type:", attr, "=", value); - } - } - var ifs = template.find(".togetherjs-if-" + attr).removeClass("togetherjs-sub-" + attr); - if (! value) { - ifs.hide(); - } - ifs = template.find(".togetherjs-ifnot-" + attr).removeClass("togetherjs-ifnot-" + attr); - if (value) { - ifs.hide(); - } - var attrName = "data-togetherjs-subattr-" + attr; - var attrs = template.find("[" + attrName + "]"); - attrs.each(function (index, element) { - assert(typeof value == "string"); - element = $(element); - var subAttribute = element.attr(attrName); - element.attr(attrName, null); - element.attr(subAttribute, value); - }); - }); - if (variables.peer) { - variables.peer.view.setElement(template); - } - if (variables.date) { - var date = variables.date; - if (typeof date == "number") { - date = new Date(date); - } - var ampm = "AM"; - var hour = date.getHours(); - if (hour > 12) { - hour -= 12; - ampm = "PM"; - } - var minute = date.getMinutes(); - var t = hour + ":"; - if (minute < 10) { - t += "0"; - } - t += minute; - template.find(".togetherjs-time").text(t); - template.find(".togetherjs-ampm").text(ampm); - } - - // FIXME: silly this is on session: - session.emit("new-element", template); - return template; - }; - - return templating; -}); - -define('linkify',[], function () { - // FIXME: this could be moved to a different module, it's pretty stand-alone - /* Finds any links in the text of an element (or its children) and turns them - into anchors (with target=_blank) */ - function linkify(el) { - if (el.jquery) { - el = el[0]; - } - el.normalize(); - function linkifyNode(node) { - var _len = node.childNodes.length; - for (var i=0; i<_len; i++) { - if (node.childNodes[i].nodeType == document.ELEMENT_NODE) { - linkifyNode(node.childNodes[i]); - } - } - var texts = []; - for (i=0; i<_len; i++) { - if (node.childNodes[i].nodeType == document.TEXT_NODE) { - texts.push(node.childNodes[i]); - } - } - texts.forEach(function (item) { - if (item.nodeType == document.ELEMENT_NODE) { - linkifyNode(item); - } else if (item.nodeType == document.TEXT_NODE) { - while (true) { - var text = item.nodeValue; - var regex = /\bhttps?:\/\/[a-z0-9\.\-_](:\d+)?[^ \n\t<>()\[\]]*/i; - var match = regex.exec(text); - if (! match) { - break; - } - var leadingNode = document.createTextNode(text.substr(0, match.index)); - node.replaceChild(leadingNode, item); - var anchor = document.createElement("a"); - anchor.setAttribute("target", "_blank"); - anchor.href = match[0]; - anchor.appendChild(document.createTextNode(match[0])); - node.insertBefore(anchor, leadingNode.nextSibling); - var trailing = document.createTextNode(text.substr(match.index + match[0].length)); - node.insertBefore(trailing, anchor.nextSibling); - item = trailing; - } - } - }); - } - linkifyNode(el); - return el; - } - - return linkify; -}); - -// TinyColor v0.9.13 -// https://github.com/bgrins/TinyColor -// 2012-11-28, Brian Grinstead, MIT License - -(function(root) { - -var trimLeft = /^[\s,#]+/, - trimRight = /\s+$/, - tinyCounter = 0, - math = Math, - mathRound = math.round, - mathMin = math.min, - mathMax = math.max, - mathRandom = math.random; - -function tinycolor (color, opts) { - - color = (color) ? color : ''; - - // If input is already a tinycolor, return itself - if (typeof color == "object" && color.hasOwnProperty("_tc_id")) { - return color; - } - - var rgb = inputToRGB(color); - var r = rgb.r, - g = rgb.g, - b = rgb.b, - a = rgb.a, - roundA = mathRound(100*a) / 100, - format = rgb.format; - - // Don't let the range of [0,255] come back in [0,1]. - // Potentially lose a little bit of precision here, but will fix issues where - // .5 gets interpreted as half of the total, instead of half of 1 - // If it was supposed to be 128, this was already taken care of by `inputToRgb` - if (r < 1) { r = mathRound(r); } - if (g < 1) { g = mathRound(g); } - if (b < 1) { b = mathRound(b); } - - return { - ok: rgb.ok, - format: format, - _tc_id: tinyCounter++, - alpha: a, - toHsv: function() { - var hsv = rgbToHsv(r, g, b); - return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: a }; - }, - toHsvString: function() { - var hsv = rgbToHsv(r, g, b); - var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100); - return (a == 1) ? - "hsv(" + h + ", " + s + "%, " + v + "%)" : - "hsva(" + h + ", " + s + "%, " + v + "%, "+ roundA + ")"; - }, - toHsl: function() { - var hsl = rgbToHsl(r, g, b); - return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: a }; - }, - toHslString: function() { - var hsl = rgbToHsl(r, g, b); - var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100); - return (a == 1) ? - "hsl(" + h + ", " + s + "%, " + l + "%)" : - "hsla(" + h + ", " + s + "%, " + l + "%, "+ roundA + ")"; - }, - toHex: function() { - return rgbToHex(r, g, b); - }, - toHexString: function() { - return '#' + rgbToHex(r, g, b); - }, - toRgb: function() { - return { r: mathRound(r), g: mathRound(g), b: mathRound(b), a: a }; - }, - toRgbString: function() { - return (a == 1) ? - "rgb(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ")" : - "rgba(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ", " + roundA + ")"; - }, - toPercentageRgb: function() { - return { r: mathRound(bound01(r, 255) * 100) + "%", g: mathRound(bound01(g, 255) * 100) + "%", b: mathRound(bound01(b, 255) * 100) + "%", a: a }; - }, - toPercentageRgbString: function() { - return (a == 1) ? - "rgb(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%)" : - "rgba(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%, " + roundA + ")"; - }, - toName: function() { - return hexNames[rgbToHex(r, g, b)] || false; - }, - toFilter: function() { - var hex = rgbToHex(r, g, b); - var secondHex = hex; - var alphaHex = Math.round(parseFloat(a) * 255).toString(16); - var secondAlphaHex = alphaHex; - var gradientType = opts && opts.gradientType ? "GradientType = 1, " : ""; - - if (secondColor) { - var s = tinycolor(secondColor); - secondHex = s.toHex(); - secondAlphaHex = Math.round(parseFloat(s.alpha) * 255).toString(16); - } - - return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr=#" + pad2(alphaHex) + hex + ",endColorstr=#" + pad2(secondAlphaHex) + secondHex + ")"; - }, - toString: function(format) { - format = format || this.format; - var formattedString = false; - if (format === "rgb") { - formattedString = this.toRgbString(); - } - if (format === "prgb") { - formattedString = this.toPercentageRgbString(); - } - if (format === "hex") { - formattedString = this.toHexString(); - } - if (format === "name") { - formattedString = this.toName(); - } - if (format === "hsl") { - formattedString = this.toHslString(); - } - if (format === "hsv") { - formattedString = this.toHsvString(); - } - - return formattedString || this.toHexString(); - } - }; -} - -// If input is an object, force 1 into "1.0" to handle ratios properly -// String input requires "1.0" as input, so 1 will be treated as 1 -tinycolor.fromRatio = function(color) { - if (typeof color == "object") { - var newColor = {}; - for (var i in color) { - newColor[i] = convertToPercentage(color[i]); - } - color = newColor; - } - - return tinycolor(color); -}; - -// Given a string or object, convert that input to RGB -// Possible string inputs: -// -// "red" -// "#f00" or "f00" -// "#ff0000" or "ff0000" -// "rgb 255 0 0" or "rgb (255, 0, 0)" -// "rgb 1.0 0 0" or "rgb (1, 0, 0)" -// "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1" -// "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1" -// "hsl(0, 100%, 50%)" or "hsl 0 100% 50%" -// "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1" -// "hsv(0, 100%, 100%)" or "hsv 0 100% 100%" -// -function inputToRGB(color) { - - var rgb = { r: 255, g: 255, b: 255 }; - var a = 1; - var ok = false; - var format = false; - - if (typeof color == "string") { - color = stringInputToObject(color); - } - - if (typeof color == "object") { - if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) { - rgb = rgbToRgb(color.r, color.g, color.b); - ok = true; - format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb"; - } - else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) { - color.s = convertToPercentage(color.s); - color.v = convertToPercentage(color.v); - rgb = hsvToRgb(color.h, color.s, color.v); - ok = true; - format = "hsv"; - } - else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) { - color.s = convertToPercentage(color.s); - color.l = convertToPercentage(color.l); - rgb = hslToRgb(color.h, color.s, color.l); - ok = true; - format = "hsl"; - } - - if (color.hasOwnProperty("a")) { - a = color.a; - } - } - - a = parseFloat(a); - - // Handle invalid alpha characters by setting to 1 - if (isNaN(a) || a < 0 || a > 1) { - a = 1; - } - - return { - ok: ok, - format: color.format || format, - r: mathMin(255, mathMax(rgb.r, 0)), - g: mathMin(255, mathMax(rgb.g, 0)), - b: mathMin(255, mathMax(rgb.b, 0)), - a: a - }; -} - - - -// Conversion Functions -// -------------------- - -// `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from: -// - -// `rgbToRgb` -// Handle bounds / percentage checking to conform to CSS color spec -// -// *Assumes:* r, g, b in [0, 255] or [0, 1] -// *Returns:* { r, g, b } in [0, 255] -function rgbToRgb(r, g, b){ - return { - r: bound01(r, 255) * 255, - g: bound01(g, 255) * 255, - b: bound01(b, 255) * 255 - }; -} - -// `rgbToHsl` -// Converts an RGB color value to HSL. -// *Assumes:* r, g, and b are contained in [0, 255] or [0, 1] -// *Returns:* { h, s, l } in [0,1] -function rgbToHsl(r, g, b) { - - r = bound01(r, 255); - g = bound01(g, 255); - b = bound01(b, 255); - - var max = mathMax(r, g, b), min = mathMin(r, g, b); - var h, s, l = (max + min) / 2; - - if(max == min) { - h = s = 0; // achromatic - } - else { - var d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - switch(max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - - h /= 6; - } - - return { h: h, s: s, l: l }; -} - -// `hslToRgb` -// Converts an HSL color value to RGB. -// *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100] -// *Returns:* { r, g, b } in the set [0, 255] -function hslToRgb(h, s, l) { - var r, g, b; - - h = bound01(h, 360); - s = bound01(s, 100); - l = bound01(l, 100); - - function hue2rgb(p, q, t) { - if(t < 0) t += 1; - if(t > 1) t -= 1; - if(t < 1/6) return p + (q - p) * 6 * t; - if(t < 1/2) return q; - if(t < 2/3) return p + (q - p) * (2/3 - t) * 6; - return p; - } - - if(s === 0) { - r = g = b = l; // achromatic - } - else { - var q = l < 0.5 ? l * (1 + s) : l + s - l * s; - var p = 2 * l - q; - r = hue2rgb(p, q, h + 1/3); - g = hue2rgb(p, q, h); - b = hue2rgb(p, q, h - 1/3); - } - - return { r: r * 255, g: g * 255, b: b * 255 }; -} - -// `rgbToHsv` -// Converts an RGB color value to HSV -// *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1] -// *Returns:* { h, s, v } in [0,1] -function rgbToHsv(r, g, b) { - - r = bound01(r, 255); - g = bound01(g, 255); - b = bound01(b, 255); - - var max = mathMax(r, g, b), min = mathMin(r, g, b); - var h, s, v = max; - - var d = max - min; - s = max === 0 ? 0 : d / max; - - if(max == min) { - h = 0; // achromatic - } - else { - switch(max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - h /= 6; - } - return { h: h, s: s, v: v }; -} - -// `hsvToRgb` -// Converts an HSV color value to RGB. -// *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100] -// *Returns:* { r, g, b } in the set [0, 255] - function hsvToRgb(h, s, v) { - - h = bound01(h, 360) * 6; - s = bound01(s, 100); - v = bound01(v, 100); - - var i = math.floor(h), - f = h - i, - p = v * (1 - s), - q = v * (1 - f * s), - t = v * (1 - (1 - f) * s), - mod = i % 6, - r = [v, q, p, p, t, v][mod], - g = [t, v, v, q, p, p][mod], - b = [p, p, t, v, v, q][mod]; - - return { r: r * 255, g: g * 255, b: b * 255 }; -} - -// `rgbToHex` -// Converts an RGB color to hex -// Assumes r, g, and b are contained in the set [0, 255] -// Returns a 3 or 6 character hex -function rgbToHex(r, g, b) { - var hex = [ - pad2(mathRound(r).toString(16)), - pad2(mathRound(g).toString(16)), - pad2(mathRound(b).toString(16)) - ]; - - // Return a 3 character hex if possible - if (hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) { - return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0); - } - - return hex.join(""); -} - -// `equals` -// Can be called with any tinycolor input -tinycolor.equals = function (color1, color2) { - if (!color1 || !color2) { return false; } - return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString(); -}; -tinycolor.random = function() { - return tinycolor.fromRatio({ - r: mathRandom(), - g: mathRandom(), - b: mathRandom() - }); -}; - - -// Modification Functions -// ---------------------- -// Thanks to less.js for some of the basics here -// - - -tinycolor.desaturate = function (color, amount) { - var hsl = tinycolor(color).toHsl(); - hsl.s -= ((amount || 10) / 100); - hsl.s = clamp01(hsl.s); - return tinycolor(hsl); -}; -tinycolor.saturate = function (color, amount) { - var hsl = tinycolor(color).toHsl(); - hsl.s += ((amount || 10) / 100); - hsl.s = clamp01(hsl.s); - return tinycolor(hsl); -}; -tinycolor.greyscale = function(color) { - return tinycolor.desaturate(color, 100); -}; -tinycolor.lighten = function(color, amount) { - var hsl = tinycolor(color).toHsl(); - hsl.l += ((amount || 10) / 100); - hsl.l = clamp01(hsl.l); - return tinycolor(hsl); -}; -tinycolor.darken = function (color, amount) { - var hsl = tinycolor(color).toHsl(); - hsl.l -= ((amount || 10) / 100); - hsl.l = clamp01(hsl.l); - return tinycolor(hsl); -}; -tinycolor.complement = function(color) { - var hsl = tinycolor(color).toHsl(); - hsl.h = (hsl.h + 180) % 360; - return tinycolor(hsl); -}; - - -// Combination Functions -// --------------------- -// Thanks to jQuery xColor for some of the ideas behind these -// - -tinycolor.triad = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l }) - ]; -}; -tinycolor.tetrad = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l }) - ]; -}; -tinycolor.splitcomplement = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}), - tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l}) - ]; -}; -tinycolor.analogous = function(color, results, slices) { - results = results || 6; - slices = slices || 30; - - var hsl = tinycolor(color).toHsl(); - var part = 360 / slices; - var ret = [tinycolor(color)]; - - for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) { - hsl.h = (hsl.h + part) % 360; - ret.push(tinycolor(hsl)); - } - return ret; -}; -tinycolor.monochromatic = function(color, results) { - results = results || 6; - var hsv = tinycolor(color).toHsv(); - var h = hsv.h, s = hsv.s, v = hsv.v; - var ret = []; - var modification = 1 / results; - - while (results--) { - ret.push(tinycolor({ h: h, s: s, v: v})); - v = (v + modification) % 1; - } - - return ret; -}; -// Readability based on W3C recommendations: http://www.w3.org/TR/AERT#color-contrast -// Returns object with two properties: -// .brightness: the difference in brightness between the two colors -// .color: the difference in color/hue between the two colors -// An "acceptable" color is considered to have a brightness difference of 125 and a -// color difference of 500 -tinycolor.readability = function(color1, color2) { - var a = tinycolor(color1).toRgb(), b = tinycolor(color2).toRgb(); - var brightnessA = (a.r * 299 + a.g * 587 + a.b * 114) / 1000; - var brightnessB = (b.r * 299 + b.g * 587 + b.b * 114) / 1000; - var colorDiff = ( - Math.max(a.r, b.r) - Math.min(a.r, b.r) + - Math.max(a.g, b.g) - Math.min(a.g, b.g) + - Math.max(a.b, b.b) - Math.min(a.b, b.b)); - return { - brightness: Math.abs(brightnessA - brightnessB), - color: colorDiff - }; -}; -// True if using color1 over color2 (or vice versa) is "readable" -// Based on: http://www.w3.org/TR/AERT#color-contrast -// Example: -// tinycolor.readable("#000", "#111") => false -tinycolor.readable = function(color1, color2) { - var readability = tinycolor.readability(color1, color2); - return readability.brightness > 125 && readability.color > 500; -}; -// Given a base color and a list of possible foreground or background -// colors for that base, returns the most readable color. -// Example: -// tinycolor.mostReadable("#123", ["#fff", "#000"]) => "#000" -tinycolor.mostReadable = function(baseColor, colorList) { - var bestColor; - var bestScore = 0; - var bestIsReadable = false; - for (var i=0; i < colorList.length; i++) { - var readability = tinycolor.readability(baseColor, colorList[i]); - var readable = readability.brightness > 125 && readability.color > 500; - // We normalize both around the "acceptable" breaking point, - // but rank brightness constrast higher than hue. Why? I'm - // not sure, seems reasonable. - var score = 3 * (readability.brightness / 125) + (readability.color / 500); - if ((readable && ! bestIsReadable) || - (readable && bestIsReadable && score > bestScore) || - ((! readable) && (! bestIsReadable) && score > bestScore)) { - bestIsReadable = readable; - bestScore = score; - bestColor = colorList[i]; - } - } - return bestColor; -}; - - -// Big List of Colors -// --------- -// -var names = tinycolor.names = { - aliceblue: "f0f8ff", - antiquewhite: "faebd7", - aqua: "0ff", - aquamarine: "7fffd4", - azure: "f0ffff", - beige: "f5f5dc", - bisque: "ffe4c4", - black: "000", - blanchedalmond: "ffebcd", - blue: "00f", - blueviolet: "8a2be2", - brown: "a52a2a", - burlywood: "deb887", - burntsienna: "ea7e5d", - cadetblue: "5f9ea0", - chartreuse: "7fff00", - chocolate: "d2691e", - coral: "ff7f50", - cornflowerblue: "6495ed", - cornsilk: "fff8dc", - crimson: "dc143c", - cyan: "0ff", - darkblue: "00008b", - darkcyan: "008b8b", - darkgoldenrod: "b8860b", - darkgray: "a9a9a9", - darkgreen: "006400", - darkgrey: "a9a9a9", - darkkhaki: "bdb76b", - darkmagenta: "8b008b", - darkolivegreen: "556b2f", - darkorange: "ff8c00", - darkorchid: "9932cc", - darkred: "8b0000", - darksalmon: "e9967a", - darkseagreen: "8fbc8f", - darkslateblue: "483d8b", - darkslategray: "2f4f4f", - darkslategrey: "2f4f4f", - darkturquoise: "00ced1", - darkviolet: "9400d3", - deeppink: "ff1493", - deepskyblue: "00bfff", - dimgray: "696969", - dimgrey: "696969", - dodgerblue: "1e90ff", - firebrick: "b22222", - floralwhite: "fffaf0", - forestgreen: "228b22", - fuchsia: "f0f", - gainsboro: "dcdcdc", - ghostwhite: "f8f8ff", - gold: "ffd700", - goldenrod: "daa520", - gray: "808080", - green: "008000", - greenyellow: "adff2f", - grey: "808080", - honeydew: "f0fff0", - hotpink: "ff69b4", - indianred: "cd5c5c", - indigo: "4b0082", - ivory: "fffff0", - khaki: "f0e68c", - lavender: "e6e6fa", - lavenderblush: "fff0f5", - lawngreen: "7cfc00", - lemonchiffon: "fffacd", - lightblue: "add8e6", - lightcoral: "f08080", - lightcyan: "e0ffff", - lightgoldenrodyellow: "fafad2", - lightgray: "d3d3d3", - lightgreen: "90ee90", - lightgrey: "d3d3d3", - lightpink: "ffb6c1", - lightsalmon: "ffa07a", - lightseagreen: "20b2aa", - lightskyblue: "87cefa", - lightslategray: "789", - lightslategrey: "789", - lightsteelblue: "b0c4de", - lightyellow: "ffffe0", - lime: "0f0", - limegreen: "32cd32", - linen: "faf0e6", - magenta: "f0f", - maroon: "800000", - mediumaquamarine: "66cdaa", - mediumblue: "0000cd", - mediumorchid: "ba55d3", - mediumpurple: "9370db", - mediumseagreen: "3cb371", - mediumslateblue: "7b68ee", - mediumspringgreen: "00fa9a", - mediumturquoise: "48d1cc", - mediumvioletred: "c71585", - midnightblue: "191970", - mintcream: "f5fffa", - mistyrose: "ffe4e1", - moccasin: "ffe4b5", - navajowhite: "ffdead", - navy: "000080", - oldlace: "fdf5e6", - olive: "808000", - olivedrab: "6b8e23", - orange: "ffa500", - orangered: "ff4500", - orchid: "da70d6", - palegoldenrod: "eee8aa", - palegreen: "98fb98", - paleturquoise: "afeeee", - palevioletred: "db7093", - papayawhip: "ffefd5", - peachpuff: "ffdab9", - peru: "cd853f", - pink: "ffc0cb", - plum: "dda0dd", - powderblue: "b0e0e6", - purple: "800080", - red: "f00", - rosybrown: "bc8f8f", - royalblue: "4169e1", - saddlebrown: "8b4513", - salmon: "fa8072", - sandybrown: "f4a460", - seagreen: "2e8b57", - seashell: "fff5ee", - sienna: "a0522d", - silver: "c0c0c0", - skyblue: "87ceeb", - slateblue: "6a5acd", - slategray: "708090", - slategrey: "708090", - snow: "fffafa", - springgreen: "00ff7f", - steelblue: "4682b4", - tan: "d2b48c", - teal: "008080", - thistle: "d8bfd8", - tomato: "ff6347", - turquoise: "40e0d0", - violet: "ee82ee", - wheat: "f5deb3", - white: "fff", - whitesmoke: "f5f5f5", - yellow: "ff0", - yellowgreen: "9acd32" -}; - -// Make it easy to access colors via `hexNames[hex]` -var hexNames = tinycolor.hexNames = flip(names); - - -// Utilities -// --------- - -// `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }` -function flip(o) { - var flipped = { }; - for (var i in o) { - if (o.hasOwnProperty(i)) { - flipped[o[i]] = i; - } - } - return flipped; -} - -// Take input from [0, n] and return it as [0, 1] -function bound01(n, max) { - if (isOnePointZero(n)) { n = "100%"; } - - var processPercent = isPercentage(n); - n = mathMin(max, mathMax(0, parseFloat(n))); - - // Automatically convert percentage into number - if (processPercent) { - n = parseInt(n * max, 10) / 100; - } - - // Handle floating point rounding errors - if ((math.abs(n - max) < 0.000001)) { - return 1; - } - - // Convert into [0, 1] range if it isn't already - return (n % max) / parseFloat(max); -} - -// Force a number between 0 and 1 -function clamp01(val) { - return mathMin(1, mathMax(0, val)); -} - -// Parse an integer into hex -function parseHex(val) { - return parseInt(val, 16); -} - -// Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1 -// -function isOnePointZero(n) { - return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1; -} - -// Check to see if string passed in is a percentage -function isPercentage(n) { - return typeof n === "string" && n.indexOf('%') != -1; -} - -// Force a hex value to have 2 characters -function pad2(c) { - return c.length == 1 ? '0' + c : '' + c; -} - -// Replace a decimal with it's percentage value -function convertToPercentage(n) { - if (n <= 1) { - n = (n * 100) + "%"; - } - - return n; -} - -var matchers = (function() { - - // - var CSS_INTEGER = "[-\\+]?\\d+%?"; - - // - var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?"; - - // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome. - var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")"; - - // Actual matching. - // Parentheses and commas are optional, but not required. - // Whitespace can take the place of commas or opening paren - var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; - var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; - - return { - rgb: new RegExp("rgb" + PERMISSIVE_MATCH3), - rgba: new RegExp("rgba" + PERMISSIVE_MATCH4), - hsl: new RegExp("hsl" + PERMISSIVE_MATCH3), - hsla: new RegExp("hsla" + PERMISSIVE_MATCH4), - hsv: new RegExp("hsv" + PERMISSIVE_MATCH3), - hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, - hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/ - }; -})(); - -// `stringInputToObject` -// Permissive string parsing. Take in a number of formats, and output an object -// based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}` -function stringInputToObject(color) { - - color = color.replace(trimLeft,'').replace(trimRight, '').toLowerCase(); - var named = false; - if (names[color]) { - color = names[color]; - named = true; - } - else if (color == 'transparent') { - return { r: 0, g: 0, b: 0, a: 0 }; - } - - // Try to match string input using regular expressions. - // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360] - // Just return an object and let the conversion functions handle that. - // This way the result will be the same whether the tinycolor is initialized with string or object. - var match; - if ((match = matchers.rgb.exec(color))) { - return { r: match[1], g: match[2], b: match[3] }; - } - if ((match = matchers.rgba.exec(color))) { - return { r: match[1], g: match[2], b: match[3], a: match[4] }; - } - if ((match = matchers.hsl.exec(color))) { - return { h: match[1], s: match[2], l: match[3] }; - } - if ((match = matchers.hsla.exec(color))) { - return { h: match[1], s: match[2], l: match[3], a: match[4] }; - } - if ((match = matchers.hsv.exec(color))) { - return { h: match[1], s: match[2], v: match[3] }; - } - if ((match = matchers.hex6.exec(color))) { - return { - r: parseHex(match[1]), - g: parseHex(match[2]), - b: parseHex(match[3]), - format: named ? "name" : "hex" - }; - } - if ((match = matchers.hex3.exec(color))) { - return { - r: parseHex(match[1] + '' + match[1]), - g: parseHex(match[2] + '' + match[2]), - b: parseHex(match[3] + '' + match[3]), - format: named ? "name" : "hex" - }; - } - - return false; -} - -// Node: Export function -if (typeof module !== "undefined" && module.exports) { - module.exports = tinycolor; -} -// AMD/requirejs: Define the module -else if (typeof define !== "undefined") { - define('tinycolor',[],function () {return tinycolor;}); -} -// Browser: Expose to window -else { - root.tinycolor = tinycolor; -} - -})(this); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('elementFinder',["util", "jquery"], function (util, $) { - var elementFinder = util.Module("elementFinder"); - var assert = util.assert; - - elementFinder.ignoreElement = function ignoreElement(el) { - if (el instanceof $) { - el = el[0]; - } - while (el) { - if ($(el).hasClass("togetherjs")) { - return true; - } - el = el.parentNode; - } - return false; - }; - - elementFinder.elementLocation = function elementLocation(el) { - assert(el !== null, "Got null element"); - if (el instanceof $) { - // a jQuery element - el = el[0]; - } - if (el[0] && el.attr && el[0].nodeType == 1) { - // Or a jQuery element not made by us - el = el[0]; - } - if (el.id) { - return "#" + el.id; - } - if (el.tagName == "BODY") { - return "body"; - } - if (el.tagName == "HEAD") { - return "head"; - } - if (el === document) { - return "document"; - } - var parent = el.parentNode; - if ((! parent) || parent == el) { - console.warn("elementLocation(", el, ") has null parent"); - throw new Error("No locatable parent found"); - } - var parentLocation = elementLocation(parent); - var children = parent.childNodes; - var _len = children.length; - var index = 0; - for (var i=0; i<_len; i++) { - if (children[i] == el) { - break; - } - if (children[i].nodeType == document.ELEMENT_NODE) { - if (children[i].className.indexOf("togetherjs") != -1) { - // Don't count our UI - continue; - } - // Don't count text or comments - index++; - } - } - return parentLocation + ":nth-child(" + (index+1) + ")"; - }; - - elementFinder.CannotFind = util.Class({ - constructor: function CannotFind(location, reason, context) { - this.prefix = ""; - this.location = location; - this.reason = reason; - this.context = context; - }, - toString: function () { - var loc; - try { - loc = elementFinder.elementLocation(this.context); - } catch (e) { - loc = this.context; - } - return ( - "[CannotFind " + this.prefix + - "(" + this.location + "): " + - this.reason + " in " + - loc + "]"); - } - }); - - elementFinder.findElement = function findElement(loc, container) { - // FIXME: should this all just be done with document.querySelector()? - // But no! We can't ignore togetherjs elements with querySelector. - // But maybe! We *could* make togetherjs elements less obtrusive? - container = container || document; - var el, rest; - if (loc === "body") { - return document.body; - } else if (loc === "head") { - return document.head; - } else if (loc === "document") { - return document; - } else if (loc.indexOf("body") === 0) { - el = document.body; - try { - return findElement(loc.substr(("body").length), el); - } catch (e) { - if (e instanceof elementFinder.CannotFind) { - e.prefix = "body" + e.prefix; - } - throw e; - } - } else if (loc.indexOf("head") === 0) { - el = document.head; - try { - return findElement(loc.substr(("head").length), el); - } catch (e) { - if (e instanceof elementFinder.CannotFind) { - e.prefix = "head" + e.prefix; - } - throw e; - } - } else if (loc.indexOf("#") === 0) { - var id; - loc = loc.substr(1); - if (loc.indexOf(":") === -1) { - id = loc; - rest = ""; - } else { - id = loc.substr(0, loc.indexOf(":")); - rest = loc.substr(loc.indexOf(":")); - } - el = document.getElementById(id); - if (! el) { - throw elementFinder.CannotFind("#" + id, "No element by that id", container); - } - if (rest) { - try { - return findElement(rest, el); - } catch (e) { - if (e instanceof elementFinder.CannotFind) { - e.prefix = "#" + id + e.prefix; - } - throw e; - } - } else { - return el; - } - } else if (loc.indexOf(":nth-child(") === 0) { - loc = loc.substr((":nth-child(").length); - if (loc.indexOf(")") == -1) { - throw "Invalid location, missing ): " + loc; - } - var num = loc.substr(0, loc.indexOf(")")); - num = parseInt(num, 10); - var count = num; - loc = loc.substr(loc.indexOf(")") + 1); - var children = container.childNodes; - el = null; - for (var i=0; i height) { - return false; - } - last = el; - }); - if ((! children.length) || (! last)) { - // There are no children, or only inapplicable children - return { - location: elementFinder.elementLocation(start[0]), - offset: height - start.offset().top, - absoluteTop: height, - documentHeight: $(document).height() - }; - } - return search(last, height); - } - return search($(document.body), height); - }; - - elementFinder.pixelForPosition = function (position) { - /* Inverse of elementFinder.elementByPixel */ - if (position.location == "body") { - return position.offset; - } - var el; - try { - el = elementFinder.findElement(position.location); - } catch (e) { - if (e instanceof elementFinder.CannotFind && position.absoluteTop) { - // We don't trust absoluteTop to be quite right locally, so we adjust - // for the total document height differences: - var percent = position.absoluteTop / position.documentHeight; - return $(document).height() * percent; - } - throw e; - } - var top = $(el).offset().top; - // FIXME: maybe here we should test for sanity, like if an element is - // hidden. We can use position.absoluteTop to get a sense of where the - // element roughly should be. If the sanity check failed we'd use - // absoluteTop - return top + position.offset; - }; - - return elementFinder; - -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Loading this module will cause, when TogetherJS is active, the - session object to emit visibility-change with a `hidden` argument - whenever the visibility changes, on browsers where we can detect - it. - */ - -define('visibilityApi',["util", "session"], function (util, session) { - var visibilityApi = util.Module("visibilityApi"); - var hidden; - var visibilityChange; - if (document.hidden !== undefined) { // Opera 12.10 and Firefox 18 and later support - hidden = "hidden"; - visibilityChange = "visibilitychange"; - } else if (document.mozHidden !== undefined) { - hidden = "mozHidden"; - visibilityChange = "mozvisibilitychange"; - } else if (document.msHidden !== undefined) { - hidden = "msHidden"; - visibilityChange = "msvisibilitychange"; - } else if (document.webkitHidden !== undefined) { - hidden = "webkitHidden"; - visibilityChange = "webkitvisibilitychange"; - } - - session.on("start", function () { - document.addEventListener(visibilityChange, change, false); - }); - - session.on("close", function () { - document.removeEventListener(visibilityChange, change, false); - }); - - function change() { - session.emit("visibility-change", document[hidden]); - } - - visibilityApi.hidden = function () { - return document[hidden]; - }; - - return visibilityApi; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('ui',["require", "jquery", "util", "session", "templates", "templating", "linkify", "peers", "windowing", "tinycolor", "elementFinder", "visibilityApi"], function (require, $, util, session, templates, templating, linkify, peers, windowing, tinycolor, elementFinder, visibilityApi) { - var ui = util.Module('ui'); - var assert = util.assert; - var AssertionError = util.AssertionError; - var chat; - var $window = $(window); - // This is also in togetherjs.less, as @button-height: - var BUTTON_HEIGHT = 60 + 1; // 60 is button height, 1 is border - // chat TextArea - var TEXTAREA_LINE_HEIGHT = 20; // in pixels - var TEXTAREA_MAX_LINES = 5; - // This is also in togetherjs.less, under .togetherjs-animated - var ANIMATION_DURATION = 1000; - // Time the new user window sticks around until it fades away: - var NEW_USER_FADE_TIMEOUT = 5000; - // This is set when an animation will keep the UI from being ready - // (until this time): - var finishedAt = null; - // Time in milliseconds for the dock to animate out: - var DOCK_ANIMATION_TIME = 300; - // If two chat messages come from the same person in this time - // (milliseconds) then they are collapsed into one message: - var COLLAPSE_MESSAGE_LIMIT = 5000; - - var COLORS = [ - "#8A2BE2", "#7FFF00", "#DC143C", "#00FFFF", "#8FBC8F", "#FF8C00", "#FF00FF", - "#FFD700", "#F08080", "#90EE90", "#FF6347"]; - - // This would be a circular import, but we just need the chat module sometime - // after everything is loaded, and this is sure to complete by that time: - require(["chat"], function (c) { - chat = c; - }); - - /* Displays some toggleable element; toggleable elements have a - data-toggles attribute that indicates what other elements should - be hidden when this element is shown. */ - ui.displayToggle = function (el) { - el = $(el); - assert(el.length, "No element", arguments[0]); - var other = $(el.attr("data-toggles")); - assert(other.length, "Cannot toggle", el[0], "selector", other.selector); - other.hide(); - el.show(); - }; - - function panelPosition() { - var iface = $("#togetherjs-dock"); - if (iface.hasClass("togetherjs-dock-right")) { - return "right"; - } else if (iface.hasClass("togetherjs-dock-left")) { - return "left"; - } else if (iface.hasClass("togetherjs-dock-bottom")) { - return "bottom"; - } else { - throw new AssertionError("#togetherjs-dock doesn't have positioning class"); - } - } - - ui.container = null; - - // This is used for some signalling when ui.prepareUI and/or - // ui.activateUI is called before the DOM is fully loaded: - var deferringPrepareUI = null; - - function deferForContainer(func) { - /* Defers any calls to func() until after ui.container is set - Function cannot have a return value (as sometimes the call will - become async). Use like: - - method: deferForContainer(function (args) {...}) - */ - return function () { - if (ui.container) { - func.apply(this, arguments); - } - var self = this; - var args = Array.prototype.slice.call(arguments); - session.once("ui-ready", function () { - func.apply(self, args); - }); - }; - } - - // This is called before activateUI; it doesn't bind anything, but does display - // the dock - // FIXME: because this module has lots of requirements we can't do - // this before those requirements are loaded. Maybe worth splitting - // this out? OTOH, in production we should have all the files - // combined so there's not much problem loading those modules. - ui.prepareUI = function () { - if (! (document.readyState == "complete" || document.readyState == "interactive")) { - // Too soon! Wait a sec... - deferringPrepareUI = "deferring"; - document.addEventListener("DOMContentLoaded", function () { - var d = deferringPrepareUI; - deferringPrepareUI = null; - ui.prepareUI(); - // This happens when ui.activateUI is called before the document has been - // loaded: - if (d == "activate") { - ui.activateUI(); - } - }); - return; - } - var container = ui.container = $(templates["interface"]); - assert(container.length); - $("body").append(container); - fixupAvatars(container); - if (session.firstRun && TogetherJS.startTarget) { - // Time at which the UI will be fully ready: - // (We have to do this because the offset won't be quite right - // until the animation finishes - attempts to calculate the - // offset without taking into account CSS transforms have so far - // failed.) - var timeoutSeconds = DOCK_ANIMATION_TIME / 1000; - finishedAt = Date.now() + DOCK_ANIMATION_TIME + 50; - setTimeout(function () { - finishedAt = Date.now() + DOCK_ANIMATION_TIME + 40; - var iface = container.find("#togetherjs-dock"); - var start = iface.offset(); - var pos = $(TogetherJS.startTarget).offset(); - pos.top = Math.floor(pos.top - start.top); - pos.left = Math.floor(pos.left - start.left); - var translate = "translate(" + pos.left + "px, " + pos.top + "px)"; - iface.css({ - MozTransform: translate, - WebkitTransform: translate, - transform: translate, - opacity: "0.0" - }); - setTimeout(function () { - // We keep recalculating because the setTimeout times aren't always so accurate: - finishedAt = Date.now() + DOCK_ANIMATION_TIME + 20; - var transition = "transform " + timeoutSeconds + "s ease-out, "; - transition += "opacity " + timeoutSeconds + "s ease-out"; - iface.css({ - opacity: "1.0", - MozTransition: "-moz-" + transition, - MozTransform: "translate(0, 0)", - WebkitTransition: "-webkit-" + transition, - WebkitTransform: "translate(0, 0)", - transition: transition, - transform: "translate(0, 0)" - }); - setTimeout(function () { - finishedAt = null; - iface.attr("style", ""); - }, 510); - }, 5); - }, 5); - } - if (TogetherJS.startTarget) { - var el = $(TogetherJS.startTarget); - var text = el.text().toLowerCase().replace(/\s+/g, " "); - text = text.replace(/^\s*/, "").replace(/\s*$/, ""); - if (text == "start togetherjs") { - el.attr("data-end-togetherjs-html", "End TogetherJS"); - } - if (el.attr("data-end-togetherjs-html")) { - el.attr("data-start-togetherjs-html", el.html()); - el.html(el.attr("data-end-togetherjs-html")); - } - el.addClass("togetherjs-started"); - } - ui.container.find(".togetherjs-window > header, .togetherjs-modal > header").each(function () { - $(this).append($('')); - }); - - TogetherJS.config.track("disableWebRTC", function (hide, previous) { - if (hide && ! previous) { - ui.container.find("#togetherjs-audio-button").hide(); - adjustDockSize(-1); - } else if ((! hide) && previous) { - ui.container.find("#togetherjs-audio-button").show(); - adjustDockSize(1); - } - }); - - }; - - // After prepareUI, this actually makes the interface live. We have - // to do this later because we call prepareUI when many components - // aren't initialized, so we don't even want the user to be able to - // interact with the interface. But activateUI is called once - // everything is loaded and ready for interaction. - ui.activateUI = function () { - if (deferringPrepareUI) { - console.warn("ui.activateUI called before document is ready; waiting..."); - deferringPrepareUI = "activate"; - return; - } - if (! ui.container) { - ui.prepareUI(); - } - var container = ui.container; - - //create the overlay - if($.browser.mobile) { - // $("body").append( "\x3cdiv class='overlay' style='position: absolute; top: 0; left: 0; background-color: rgba(0,0,0,0); width: 120%; height: 100%; z-index: 1000; margin: -10px'>\x3c/div>" ); - } - - // The share link: - ui.prepareShareLink(container); - container.find("input.togetherjs-share-link").on("keydown", function (event) { - if (event.which == 27) { - windowing.hide("#togetherjs-share"); - return false; - } - return undefined; - }); - session.on("shareId", updateShareLink); - - // The chat input element: - var input = container.find("#togetherjs-chat-input"); - input.bind("keydown", function (event) { - if (event.which == 13 && !event.shiftKey) { // Enter without Shift pressed - submitChat(); - return false; - } - if (event.which == 27) { // Escape - windowing.hide("#togetherjs-chat"); - return false; - } - }); - - function submitChat() { - var val = input.val(); - if ($.trim(val)) { - input.val(""); - // triggering the event manually to avoid the addition of newline character to the textarea: - input.trigger("input").trigger("propertychange"); - chat.submit(val); - } - } - // auto-resize textarea: - input.on("input propertychange", function () { - var $this = $(this); - var actualHeight = $this.height(); - // reset the height of textarea to remove trailing empty space (used for shrinking): - $this.height(TEXTAREA_LINE_HEIGHT); - this.scrollTop = 0; - // scroll to bottom: - this.scrollTop = 9999; - var newHeight = this.scrollTop + $this.height(); - var maxHeight = TEXTAREA_MAX_LINES * TEXTAREA_LINE_HEIGHT; - if (newHeight > maxHeight) { - newHeight = maxHeight; - this.style.overflowY = "scroll"; - } else { - this.style.overflowY = "hidden"; - } - this.style.height = newHeight + "px"; - var diff = newHeight - actualHeight; - $("#togetherjs-chat-input-box").height($("#togetherjs-chat-input-box").height() + diff); - $("#togetherjs-chat-messages").height($("#togetherjs-chat-messages").height() - diff); - return false; - }); - - util.testExpose({submitChat: submitChat}); - - // Moving the window: - // FIXME: this should probably be stickier, and not just move the window around - // so abruptly - var anchor = container.find("#togetherjs-dock-anchor"); - assert(anchor.length); - // FIXME: This is in place to temporarily disable dock dragging: - anchor = container.find("#togetherjs-dock-anchor-disabled"); - anchor.mousedown(function (event) { - var iface = $("#togetherjs-dock"); - // FIXME: switch to .offset() and pageX/Y - var startPos = panelPosition(); - function selectoff() { - return false; - } - function mousemove(event2) { - var fromRight = $window.width() + window.pageXOffset - event2.pageX; - var fromLeft = event2.pageX - window.pageXOffset; - var fromBottom = $window.height() + window.pageYOffset - event2.pageY; - // FIXME: this is to temporarily disable the bottom view: - fromBottom = 10000; - - var pos; - if (fromLeft < fromRight && fromLeft < fromBottom) { - pos = "left"; - } else if (fromRight < fromLeft && fromRight < fromBottom) { - pos = "right"; - } else { - pos = "bottom"; - } - iface.removeClass("togetherjs-dock-left"); - iface.removeClass("togetherjs-dock-right"); - iface.removeClass("togetherjs-dock-bottom"); - iface.addClass("togetherjs-dock-" + pos); - if (startPos && pos != startPos) { - windowing.hide(); - startPos = null; - } - } - $(document).bind("mousemove", mousemove); - // If you don't turn selection off it will still select text, and show a - // text selection cursor: - $(document).bind("selectstart", selectoff); - // FIXME: it seems like sometimes we lose the mouseup event, and it's as though - // the mouse is stuck down: - $(document).one("mouseup", function () { - $(document).unbind("mousemove", mousemove); - $(document).unbind("selectstart", selectoff); - }); - return false; - }); - - function openDock() { - $('.togetherjs-window').animate({ - opacity: 1 - }); - $('#togetherjs-dock-participants').animate({ - opacity: 1 - }); - $('#togetherjs-dock #togetherjs-buttons').animate({ - opacity: 1 - }); - - //for iphone - if($(window).width() < 480) { - $('.togetherjs-dock-right').animate({ - width: "204px" - }, { - duration:60, easing:"linear" - }); - } - - //for ipad - else { - $('.togetherjs-dock-right').animate({ - width: "27%" - }, { - duration:60, easing:"linear" - }); - } - - - // add bg overlay - // $("body").append( "\x3cdiv class='overlay' style='position: absolute; top: 0; left: -2px; background-color: rgba(0,0,0,0.5); width: 200%; height: 400%; z-index: 1000; margin: 0px;'>\x3c/div>" ); - - //disable vertical scrolling - // $("body").css({ - // "position": "fixed", - // top: 0, - // left: 0 - // }); - - //replace the anchor icon - var src = "/togetherjs/images/togetherjs-logo-close.png"; - $("#togetherjs-dock-anchor #togetherjs-dock-anchor-horizontal img").attr("src", src); - } - - function closeDock() { - //enable vertical scrolling - $("body").css({ - "position": "", - top: "", - left: "" - }); - - //replace the anchor icon - var src = "/togetherjs/images/togetherjs-logo-open.png"; - $("#togetherjs-dock-anchor #togetherjs-dock-anchor-horizontal img").attr("src", src); - - $('.togetherjs-window').animate({ - opacity: 0 - }); - $('#togetherjs-dock-participants').animate({ - opacity: 0 - }); - $('#togetherjs-dock #togetherjs-buttons').animate({ - opacity: 0 - }); - $('.togetherjs-dock-right').animate({ - width: "40px" - }, { - duration:60, easing:"linear" - }); - - // remove bg overlay - //$(".overlay").remove(); - } - - // Setting the anchor button + dock mobile actions - if($.browser.mobile) { - - // toggle the audio button - $("#togetherjs-audio-button").click(function () { - windowing.toggle("#togetherjs-rtc-not-supported"); - }); - - // toggle the profile button - $("#togetherjs-profile-button").click(function () { - windowing.toggle("#togetherjs-menu-window"); - }); - - // $("body").append( "\x3cdiv class='overlay' style='position: absolute; top: 0; left: -2px; background-color: rgba(0,0,0,0.5); width: 200%; height: 400%; z-index: 1000; margin: 0px'>\x3c/div>" ); - - //disable vertical scrolling - // $("body").css({ - // "position": "fixed", - // top: 0, - // left: 0 - // }); - - //replace the anchor icon - var src = "/togetherjs/images/togetherjs-logo-close.png"; - $("#togetherjs-dock-anchor #togetherjs-dock-anchor-horizontal img").attr("src", src); - - $("#togetherjs-dock-anchor").toggle(function() { - closeDock(); - },function(){ - openDock(); - }); - } - - $("#togetherjs-share-button").click(function () { - windowing.toggle("#togetherjs-share"); - }); - - $("#togetherjs-profile-button").click(function (event) { - if ($.browser.mobile) { - windowing.show("#togetherjs-menu-window"); - return false; - } - toggleMenu(); - event.stopPropagation(); - return false; - }); - - $("#togetherjs-menu-feedback, #togetherjs-menu-feedback-button").click(function(){ - windowing.hide(); - hideMenu(); - windowing.show("#togetherjs-feedback-form"); - }); - - $("#togetherjs-menu-help, #togetherjs-menu-help-button").click(function () { - windowing.hide(); - hideMenu(); - require(["walkthrough"], function (walkthrough) { - windowing.hide(); - walkthrough.start(false); - }); - }); - - $("#togetherjs-menu-update-name").click(function () { - var input = $("#togetherjs-menu .togetherjs-self-name"); - input.css({ - width: $("#togetherjs-menu").width() - 32 + "px" - }); - ui.displayToggle("#togetherjs-menu .togetherjs-self-name"); - $("#togetherjs-menu .togetherjs-self-name").focus(); - }); - - $("#togetherjs-menu-update-name-button").click(function () { - windowing.show("#togetherjs-edit-name-window"); - $("#togetherjs-edit-name-window input").focus(); - }); - - $("#togetherjs-menu .togetherjs-self-name").bind("keyup change", function (event) { - console.log("alrighty", event); - if (event.which == 13) { - ui.displayToggle("#togetherjs-self-name-display"); - return; - } - var val = $("#togetherjs-menu .togetherjs-self-name").val(); - console.log("values!!", val); - if (val) { - peers.Self.update({name: val}); - } - }); - - $("#togetherjs-menu-update-avatar, #togetherjs-menu-update-avatar-button").click(function () { - hideMenu(); - windowing.show("#togetherjs-avatar-edit"); - }); - - $("#togetherjs-menu-end, #togetherjs-menu-end-button").click(function () { - hideMenu(); - windowing.show("#togetherjs-confirm-end"); - }); - - $("#togetherjs-end-session").click(function () { - session.close(); - //$(".overlay").remove(); - - }); - - $("#togetherjs-menu-update-color").click(function () { - var picker = $("#togetherjs-pick-color"); - if (picker.is(":visible")) { - picker.hide(); - return; - } - picker.show(); - bindPicker(); - picker.find(".togetherjs-swatch-active").removeClass("togetherjs-swatch-active"); - picker.find(".togetherjs-swatch[data-color=\"" + peers.Self.color + "\"]").addClass("togetherjs-swatch-active"); - }); - - $("#togetherjs-pick-color").click(".togetherjs-swatch", function (event) { - var swatch = $(event.target); - var color = swatch.attr("data-color"); - peers.Self.update({ - color: color - }); - event.stopPropagation(); - return false; - }); - - $("#togetherjs-pick-color").click(function (event) { - $("#togetherjs-pick-color").hide(); - event.stopPropagation(); - return false; - }); - - COLORS.forEach(function (color) { - var el = templating.sub("swatch"); - el.attr("data-color", color); - var darkened = tinycolor.darken(color); - el.css({ - backgroundColor: color, - borderColor: darkened - }); - $("#togetherjs-pick-color").append(el); - }); - - $("#togetherjs-chat-button").click(function () { - windowing.toggle("#togetherjs-chat"); - }); - - session.on("display-window", function (id, element) { - if (id == "togetherjs-chat") { - if (! $.browser.mobile) { - $("#togetherjs-chat-input").focus(); - } - } else if (id == "togetherjs-share") { - var link = element.find("input.togetherjs-share-link"); - if (link.is(":visible")) { - link.focus().select(); - } - } - }); - - container.find("#togetherjs-chat-notifier").click(function (event) { - if ($(event.target).is("a") || container.is(".togetherjs-close")) { - return; - } - windowing.show("#togetherjs-chat"); - }); - - // FIXME: Don't think this makes sense - $(".togetherjs header.togetherjs-title").each(function (index, item) { - var button = $(''); - button.click(function (event) { - var window = button.closest(".togetherjs-window"); - windowing.hide(window); - }); - $(item).append(button); - }); - - $("#togetherjs-avatar-done").click(function () { - ui.displayToggle("#togetherjs-no-avatar-edit"); - }); - - $("#togetherjs-self-color").css({backgroundColor: peers.Self.color}); - - var avatar = peers.Self.avatar; - if (avatar) { - $("#togetherjs-self-avatar").attr("src", avatar); - } - - var starterButton = $("#togetherjs-starter button"); - starterButton.click(function () { - windowing.show("#togetherjs-about"); - }).addClass("togetherjs-running"); - if (starterButton.text() == "Start TogetherJS") { - starterButton.attr("data-start-text", starterButton.text()); - starterButton.text("End TogetherJS Session"); - } - - ui.activateAvatarEdit(container, { - onSave: function () { - windowing.hide("#togetherjs-avatar-edit"); - } - }); - - TogetherJS.config.track("inviteFromRoom", function (inviter, previous) { - if (inviter) { - container.find("#togetherjs-invite").show(); - } else { - container.find("#togetherjs-invite").hide(); - } - }); - - container.find("#togetherjs-menu-refresh-invite").click(refreshInvite); - container.find("#togetherjs-menu-invite-anyone").click(function () { - invite(null); - }); - - // The following lines should be at the end of this function - // (new code goes above) - session.emit("new-element", ui.container); - - if (finishedAt && finishedAt > Date.now()) { - setTimeout(function () { - finishedAt = null; - session.emit("ui-ready", ui); - }, finishedAt - Date.now()); - } else { - session.emit("ui-ready", ui); - } - - }; // End ui.activateUI() - - ui.activateAvatarEdit = function (container, options) { - options = options || {}; - var pendingImage = null; - - container.find(".togetherjs-avatar-save").prop("disabled", true); - - container.find(".togetherjs-avatar-save").click(function () { - if (pendingImage) { - peers.Self.update({avatar: pendingImage}); - container.find(".togetherjs-avatar-save").prop("disabled", true); - if (options.onSave) { - options.onSave(); - } - } - }); - - container.find(".togetherjs-upload-avatar").on("change", function () { - util.readFileImage(this).then(function (url) { - sizeDownImage(url).then(function (smallUrl) { - pendingImage = smallUrl; - container.find(".togetherjs-avatar-preview").css({ - backgroundImage: 'url(' + pendingImage + ')' - }); - container.find(".togetherjs-avatar-save").prop("disabled", false); - if (options.onPending) { - options.onPending(); - } - }); - }); - }); - - }; - - function sizeDownImage(imageUrl) { - return util.Deferred(function (def) { - var $canvas = $(""); - $canvas[0].height = session.AVATAR_SIZE; - $canvas[0].width = session.AVATAR_SIZE; - var context = $canvas[0].getContext("2d"); - var img = new Image(); - img.src = imageUrl; - // Sometimes the DOM updates immediately to call - // naturalWidth/etc, and sometimes it doesn't; using setTimeout - // gives it a chance to catch up - setTimeout(function () { - var width = img.naturalWidth || img.width; - var height = img.naturalHeight || img.height; - width = width * (session.AVATAR_SIZE / height); - height = session.AVATAR_SIZE; - context.drawImage(img, 0, 0, width, height); - def.resolve($canvas[0].toDataURL("image/png")); - }); - }); - } - - function fixupAvatars(container) { - /* All
    elements need an element inside, - so we add that element here */ - container.find(".togetherjs-person").each(function () { - var $this = $(this); - var inner = $this.find(".togetherjs-person-avatar-swatch"); - if (! inner.length) { - $this.append('
    '); - } - }); - } - - ui.prepareShareLink = function (container) { - container.find("input.togetherjs-share-link").click(function () { - $(this).select(); - }).change(function () { - updateShareLink(); - }); - container.find("a.togetherjs-share-link").click(function () { - // FIXME: this is currently opening up Bluetooth, not sharing a link - if (false && window.MozActivity) { - var activity = new MozActivity({ - name: "share", - data: { - type: "url", - url: $(this).attr("href") - } - }); - } - // FIXME: should show some help if you actually try to follow the link - // like this, instead of simply suppressing it - return false; - }); - updateShareLink(); - }; - - // Menu - - function showMenu(event) { - var el = $("#togetherjs-menu"); - assert(el.length); - el.show(); - bindMenu(); - $(document).bind("click", maybeHideMenu); - } - - function bindMenu() { - var el = $("#togetherjs-menu:visible"); - if (el.length) { - var bound = $("#togetherjs-profile-button"); - var boundOffset = bound.offset(); - el.css({ - top: boundOffset.top + bound.height() - $window.scrollTop() + "px", - left: (boundOffset.left + bound.width() - 10 - el.width() - $window.scrollLeft()) + "px" - }); - } - } - - function bindPicker() { - var picker = $("#togetherjs-pick-color:visible"); - if (picker.length) { - var menu = $("#togetherjs-menu-update-color"); - var menuOffset = menu.offset(); - picker.css({ - top: menuOffset.top + menu.height(), - left: menuOffset.left - }); - } - } - - session.on("resize", function () { - bindMenu(); - bindPicker(); - }); - - function toggleMenu() { - if ($("#togetherjs-menu").is(":visible")) { - hideMenu(); - } else { - showMenu(); - } - } - - function hideMenu() { - var el = $("#togetherjs-menu"); - el.hide(); - $(document).unbind("click", maybeHideMenu); - ui.displayToggle("#togetherjs-self-name-display"); - $("#togetherjs-pick-color").hide(); - } - - function maybeHideMenu(event) { - var t = event.target; - while (t) { - if (t.id == "togetherjs-menu") { - // Click inside the menu, ignore this - return; - } - t = t.parentNode; - } - hideMenu(); - } - - function adjustDockSize(buttons) { - /* Add or remove spots from the dock; positive number to - add button(s), negative number to remove button(s) - */ - assert(typeof buttons == "number"); - assert(buttons && Math.floor(buttons) == buttons); - var iface = $("#togetherjs-dock"); - var newHeight = iface.height() + (BUTTON_HEIGHT * buttons); - assert(newHeight >= BUTTON_HEIGHT * 3, "Height went too low (", newHeight, - "), should never be less than 3 buttons high (", BUTTON_HEIGHT * 3, ")"); - iface.css({ - height: newHeight + "px" - }); - } - - // Misc - - function updateShareLink() { - var input = $("input.togetherjs-share-link"); - var link = $("a.togetherjs-share-link"); - var display = $("#togetherjs-session-id"); - if (! session.shareId) { - input.val(""); - link.attr("href", "#"); - display.text("(none)"); - } else { - input.val(session.shareUrl()); - link.attr("href", session.shareUrl()); - display.text(session.shareId); - } - } - - session.on("close", function () { - - if($.browser.mobile) { - // remove bg overlay - //$(".overlay").remove(); - - //after hitting End, reset window draggin - $("body").css({ - "position": "", - top: "", - left: "" - }); - - } - - if (ui.container) { - ui.container.remove(); - ui.container = null; - } - // Clear out any other spurious elements: - $(".togetherjs").remove(); - var starterButton = $("#togetherjs-starter button"); - starterButton.removeClass("togetherjs-running"); - if (starterButton.attr("data-start-text")) { - starterButton.text(starterButton.attr("data-start-text")); - starterButton.attr("data-start-text", ""); - } - if (TogetherJS.startTarget) { - var el = $(TogetherJS.startTarget); - if (el.attr("data-start-togetherjs-html")) { - el.html(el.attr("data-start-togetherjs-html")); - } - el.removeClass("togetherjs-started"); - } - }); - - ui.chat = { - text: function (attrs) { - assert(typeof attrs.text == "string"); - assert(attrs.peer); - assert(attrs.messageId); - var date = attrs.date || Date.now(); - var lastEl = ui.container.find("#togetherjs-chat .togetherjs-chat-message"); - if (lastEl.length) { - lastEl = $(lastEl[lastEl.length-1]); - } - var lastDate = null; - if (lastEl) { - lastDate = parseInt(lastEl.attr("data-date"), 10); - } - if (lastEl && lastEl.attr("data-person") == attrs.peer.id && - lastDate && date < lastDate + COLLAPSE_MESSAGE_LIMIT) { - lastEl.attr("data-date", date); - var content = lastEl.find(".togetherjs-chat-content"); - assert(content.length); - attrs.text = content.text() + "\n" + attrs.text; - attrs.messageId = lastEl.attr("data-message-id"); - lastEl.remove(); - } - var el = templating.sub("chat-message", { - peer: attrs.peer, - content: attrs.text, - date: date - }); - linkify(el.find(".togetherjs-chat-content")); - el.attr("data-person", attrs.peer.id) - .attr("data-date", date) - .attr("data-message-id", attrs.messageId); - ui.chat.add(el, attrs.messageId, attrs.notify); - }, - - joinedSession: function (attrs) { - assert(attrs.peer); - var date = attrs.date || Date.now(); - var el = templating.sub("chat-joined", { - peer: attrs.peer, - date: date - }); - // FIXME: should bind the notification to the dock location - ui.chat.add(el, attrs.peer.className("join-message-"), 4000); - }, - - leftSession: function (attrs) { - assert(attrs.peer); - var date = attrs.date || Date.now(); - var el = templating.sub("chat-left", { - peer: attrs.peer, - date: date, - declinedJoin: attrs.declinedJoin - }); - // FIXME: should bind the notification to the dock location - ui.chat.add(el, attrs.peer.className("join-message-"), 4000); - }, - - system: function (attrs) { - assert(! attrs.peer); - assert(typeof attrs.text == "string"); - var date = attrs.date || Date.now(); - var el = templating.sub("chat-system", { - content: attrs.text, - date: date - }); - ui.chat.add(el, undefined, true); - }, - - clear: deferForContainer(function () { - var container = ui.container.find("#togetherjs-chat-messages"); - container.empty(); - }), - - urlChange: function (attrs) { - assert(attrs.peer); - assert(typeof attrs.url == "string"); - assert(typeof attrs.sameUrl == "boolean"); - var messageId = attrs.peer.className("url-change-"); - // FIXME: duplicating functionality in .add(): - var realId = "togetherjs-chat-" + messageId; - var date = attrs.date || Date.now(); - var title; - // FIXME: strip off common domain from msg.url? E.g., if I'm on - // http://example.com/foobar, and someone goes to http://example.com/baz then - // show only /baz - // FIXME: truncate long titles - if (attrs.title) { - title = attrs.title + " (" + attrs.url + ")"; - } else { - title = attrs.url; - } - var el = templating.sub("url-change", { - peer: attrs.peer, - date: date, - href: attrs.url, - title: title, - sameUrl: attrs.sameUrl - }); - el.find(".togetherjs-nudge").click(function () { - attrs.peer.nudge(); - return false; - }); - el.find(".togetherjs-follow").click(function () { - var url = attrs.peer.url; - if (attrs.peer.urlHash) { - url += attrs.peer.urlHash; - } - location.href = url; - }); - var notify = ! attrs.sameUrl; - if (attrs.sameUrl && ! $("#" + realId).length) { - // Don't bother showing a same-url notification, if no previous notification - // had been shown - return; - } - ui.chat.add(el, messageId, notify); - }, - - invite: function (attrs) { - assert(attrs.peer); - assert(typeof attrs.url == "string"); - var messageId = attrs.peer.className("invite-"); - var date = attrs.date || Date.now(); - var hrefTitle = attrs.url.replace(/\#?&togetherjs=.*/, "").replace(/^\w+:\/\//, ""); - var el = templating.sub("invite", { - peer: attrs.peer, - date: date, - href: attrs.url, - hrefTitle: hrefTitle, - forEveryone: attrs.forEveryone - }); - if (attrs.forEveryone) { - el.find("a").click(function () { - // FIXME: hacky way to do this: - chat.submit("Followed link to " + attrs.url); - }); - } - ui.chat.add(el, messageId, true); - }, - - hideTimeout: null, - - add: deferForContainer(function (el, id, notify) { - if (id) { - el.attr("id", "togetherjs-chat-" + util.safeClassName(id)); - } - var container = ui.container.find("#togetherjs-chat-messages"); - assert(container.length); - var popup = ui.container.find("#togetherjs-chat-notifier"); - container.append(el); - ui.chat.scroll(); - var doNotify = !! notify; - var section = popup.find("#togetherjs-chat-notifier-message"); - if (notify && visibilityApi.hidden()) { - ui.container.find("#togetherjs-notification")[0].play(); - } - if (id && section.data("message-id") == id) { - doNotify = true; - } - if (container.is(":visible")) { - doNotify = false; - } - if (doNotify) { - section.empty(); - section.append(el.clone(true, true)); - if (section.data("message-id") != id) { - section.data("message-id", id || ""); - windowing.show(popup); - } else if (! popup.is(":visible")) { - windowing.show(popup); - } - if (typeof notify == "number") { - // This is the amount of time we're supposed to notify - if (this.hideTimeout) { - clearTimeout(this.hideTimeout); - this.hideTimeout = null; - } - this.hideTimeout = setTimeout((function () { - windowing.hide(popup); - this.hideTimeout = null; - }).bind(this), notify); - } - } - }), - - scroll: deferForContainer(function () { - var container = ui.container.find("#togetherjs-chat-messages")[0]; - container.scrollTop = container.scrollHeight; - }) - - }; - - session.on("display-window", function (id, win) { - if (id == "togetherjs-chat") { - ui.chat.scroll(); - windowing.hide("#togetherjs-chat-notifier"); - } - }); - - /* This class is bound to peers.Peer instances as peer.view. - The .update() method is regularly called by peer objects when info changes. */ - ui.PeerView = util.Class({ - - constructor: function (peer) { - assert(peer.isSelf !== undefined, "PeerView instantiated with non-Peer object"); - this.peer = peer; - this.dockClick = this.dockClick.bind(this); - }, - - /* Takes an element and sets any person-related attributes on the element - Different from updates, which use the class names we set here: */ - setElement: function (el) { - var count = 0; - var classes = ["togetherjs-person", "togetherjs-person-status", - "togetherjs-person-name", "togetherjs-person-name-abbrev", - "togetherjs-person-bgcolor", "togetherjs-person-swatch", - "togetherjs-person-status", "togetherjs-person-role", - "togetherjs-person-url", "togetherjs-person-url-title", - "togetherjs-person-bordercolor"]; - classes.forEach(function (cls) { - var els = el.find("." + cls); - els.addClass(this.peer.className(cls + "-")); - count += els.length; - }, this); - if (! count) { - console.warn("setElement(", el, ") doesn't contain any person items"); - } - this.updateDisplay(el); - }, - - updateDisplay: deferForContainer(function (container) { - container = container || ui.container; - var abbrev = this.peer.name; - if (this.peer.isSelf) { - abbrev = "me"; - } - container.find("." + this.peer.className("togetherjs-person-name-")).text(this.peer.name || ""); - container.find("." + this.peer.className("togetherjs-person-name-abbrev-")).text(abbrev); - var avatarEl = container.find("." + this.peer.className("togetherjs-person-")); - if (this.peer.avatar) { - util.assertValidUrl(this.peer.avatar); - avatarEl.css({ - backgroundImage: "url(" + this.peer.avatar + ")" - }); - } - if (this.peer.idle == "inactive") { - avatarEl.addClass("togetherjs-person-inactive"); - } else { - avatarEl.removeClass("togetherjs-person-inactive"); - } - avatarEl.attr("title", this.peer.name); - if (this.peer.color) { - avatarEl.css({ - borderColor: this.peer.color - }); - avatarEl.find(".togetherjs-person-avatar-swatch").css({ - borderTopColor: this.peer.color, - borderRightColor: this.peer.color - }); - } - if (this.peer.color) { - var colors = container.find("." + this.peer.className("togetherjs-person-bgcolor-")); - colors.css({ - backgroundColor: this.peer.color - }); - colors = container.find("." + this.peer.className("togetherjs-person-bordercolor-")); - colors.css({ - borderColor: this.peer.color - }); - } - container.find("." + this.peer.className("togetherjs-person-role-")) - .text(this.peer.isCreator ? "Creator" : "Participant"); - var urlName = this.peer.title || ""; - if (this.peer.title) { - urlName += " ("; - } - urlName += util.truncateCommonDomain(this.peer.url, location.href); - if (this.peer.title) { - urlName += ")"; - } - container.find("." + this.peer.className("togetherjs-person-url-title-")) - .text(urlName); - var url = this.peer.url; - if (this.peer.urlHash) { - url += this.peer.urlHash; - } - container.find("." + this.peer.className("togetherjs-person-url-")) - .attr("href", url); - // FIXME: should have richer status: - container.find("." + this.peer.className("togetherjs-person-status-")) - .text(this.peer.idle == "active" ? "Active" : "Inactive"); - if (this.peer.isSelf) { - // FIXME: these could also have consistent/reliable class names: - var selfName = $(".togetherjs-self-name"); - selfName.each((function (index, el) { - el = $(el); - if (el.val() != this.peer.name) { - el.val(this.peer.name); - } - }).bind(this)); - $("#togetherjs-menu-avatar").attr("src", this.peer.avatar); - if (! this.peer.name) { - $("#togetherjs-menu .togetherjs-person-name-self").text(this.peer.defaultName); - } - } - if (this.peer.url != session.currentUrl()) { - container.find("." + this.peer.className("togetherjs-person-")) - .addClass("togetherjs-person-other-url"); - } else { - container.find("." + this.peer.className("togetherjs-person-")) - .removeClass("togetherjs-person-other-url"); - } - if (this.peer.following) { - if (this.followCheckbox) { - this.followCheckbox.prop("checked", true); - } - } else { - if (this.followCheckbox) { - this.followCheckbox.prop("checked", false); - } - } - // FIXME: add some style based on following? - updateChatParticipantList(); - this.updateFollow(); - }),UPDATEURL - - update: function () { - if (! this.peer.isSelf) { - if (this.peer.status == "live") { - this.dock(); - } else { - this.undock(); - } - } - this.updateDisplay(); - this.updateUrlDisplay(); - }, - - updateUrlDisplay: function (force) { - var url = this.peer.url; - if ((! url) || (url == this._lastUpdateUrlDisplay && ! force)) { - return; - } - this._lastUpdateUrlDisplay = url; - var sameUrl = url == session.currentUrl(); - ui.chat.urlChange({ - peer: this.peer, - url: this.peer.url, - title: this.peer.title, - sameUrl: sameUrl - }); - }, - - urlNudge: function () { - // FIXME: do something more distinct here - this.updateUrlDisplay(true); - }, - - notifyJoined: function () { - ui.chat.joinedSession({ - peer: this.peer - }); - }, - - // when there are too many participants in the dock, consolidate the participants to one avatar, and on mouseOver, the dock expands down to reveal the rest of the participants - // if there are X users in the session - // then hide the users in the dock - // and shrink the size of the dock - // and if you rollover the dock, it expands and reveals the rest of the participants in the dock - - //if users hit X then show the participant button with the consol - - dock: deferForContainer(function () { - - var numberOfUsers = peers.getAllPeers().length; - - // collapse the Dock if too many users - function CollapsedDock() { - // decrease/reset dock height - $("#togetherjs-dock").css("height", 260); - //replace participant button - $("#togetherjs-dock-participants").replaceWith(""); - // new full participant window created on toggle - $("#togetherjs-participantlist-button").click(function () { - windowing.toggle("#togetherjs-participantlist"); - }); - } - - // FIXME: turned off for now - if( numberOfUsers >= 5 && false) { - CollapsedDock(); - } else { - // reset - - } - - - if (this.dockElement) { - return; - } - this.dockElement = templating.sub("dock-person", { - peer: this.peer - }); - this.dockElement.attr("id", this.peer.className("togetherjs-dock-element-")); - ui.container.find("#togetherjs-dock-participants").append(this.dockElement); - this.dockElement.find(".togetherjs-person").animateDockEntry(); - adjustDockSize(1); - this.detailElement = templating.sub("participant-window", { - peer: this.peer - }); - var followId = this.peer.className("togetherjs-person-status-follow-"); - this.detailElement.find('[for="togetherjs-person-status-follow"]').attr("for", followId); - this.detailElement.find('#togetherjs-person-status-follow').attr("id", followId); - this.detailElement.find(".togetherjs-follow").click(function () { - location.href = $(this).attr("href"); - }); - this.detailElement.find(".togetherjs-nudge").click((function () { - this.peer.nudge(); - }).bind(this)); - this.followCheckbox = this.detailElement.find("#" + followId); - this.followCheckbox.change(function () { - if (! this.checked) { - this.peer.unfollow(); - } - // Following doesn't happen until the window is closed - // FIXME: should we tell the user this? - }); - this.maybeHideDetailWindow = this.maybeHideDetailWindow.bind(this); - session.on("hide-window", this.maybeHideDetailWindow); - ui.container.append(this.detailElement); - this.dockElement.click((function () { - if (this.detailElement.is(":visible")) { - windowing.hide(this.detailElement); - } else { - windowing.show(this.detailElement, {bind: this.dockElement}); - this.scrollTo(); - this.cursor().element.animate({ - opacity:0.3 - }).animate({ - opacity:1 - }).animate({ - opacity:0.3 - }).animate({ - opacity:1 - }); - } - }).bind(this)); - this.updateFollow(); - }), - - undock: function () { - if (! this.dockElement) { - return; - } - this.dockElement.animateDockExit().promise().then((function () { - this.dockElement.remove(); - this.dockElement = null; - this.detailElement.remove(); - this.detailElement = null; - adjustDockSize(-1); - }).bind(this)); - }, - - scrollTo: function () { - if (this.peer.url != session.currentUrl()) { - return; - } - var pos = this.peer.scrollPosition; - if (! pos) { - console.warn("Peer has no scroll position:", this.peer); - return; - } - pos = elementFinder.pixelForPosition(pos); - $("html, body").easeTo(pos); - }, - - updateFollow: function () { - if (! this.peer.url) { - return; - } - if (! this.detailElement) { - return; - } - var same = this.detailElement.find(".togetherjs-same-url"); - var different = this.detailElement.find(".togetherjs-different-url"); - if (this.peer.url == session.currentUrl()) { - same.show(); - different.hide(); - } else { - same.hide(); - different.show(); - } - }, - - maybeHideDetailWindow: function (windows) { - if (this.detailElement && windows[0] && windows[0][0] === this.detailElement[0]) { - if (this.followCheckbox[0].checked) { - this.peer.follow(); - } else { - this.peer.unfollow(); - } - } - }, - - dockClick: function () { - // FIXME: scroll to person - }, - - cursor: function () { - return require("cursor").getClient(this.peer.id); - }, - - destroy: function () { - // FIXME: should I get rid of the dockElement? - session.off("hide-window", this.maybeHideDetailWindow); - } - }); - - function updateChatParticipantList() { - var live = peers.getAllPeers(true); - if (live.length) { - ui.displayToggle("#togetherjs-chat-participants"); - $("#togetherjs-chat-participant-list").text( - live.map(function (p) {return p.name;}).join(", ")); - } else { - ui.displayToggle("#togetherjs-chat-no-participants"); - } - } - - function inviteHubUrl() { - var base = TogetherJS.config.get("inviteFromRoom"); - assert(base); - return util.makeUrlAbsolute(base, session.hubUrl()); - } - - var inRefresh = false; - - function refreshInvite() { - if (inRefresh) { - return; - } - inRefresh = true; - require(["who"], function (who) { - var def = who.getList(inviteHubUrl()); - function addUser(user, before) { - var item = templating.sub("invite-user-item", {peer: user}); - item.attr("data-clientid", user.id); - if (before) { - item.insertBefore(before); - } else { - $("#togetherjs-invite-users").append(item); - } - item.click(function() { - invite(user.clientId); - }); - } - function refresh(users, finished) { - var sorted = []; - for (var id in users) { - if (users.hasOwnProperty(id)) { - sorted.push(users[id]); - } - } - sorted.sort(function (a, b) { - return a.name < b.name ? -1 : 1; - }); - var pos = 0; - ui.container.find("#togetherjs-invite-users .togetherjs-menu-item").each(function () { - var $this = $(this); - if (finished && ! users[$this.attr("data-clientid")]) { - $this.remove(); - return; - } - if (pos >= sorted.length) { - return; - } - while (pos < sorted.length && $this.attr("data-clientid") !== sorted[pos].id) { - addUser(sorted[pos], $this); - pos++; - } - while (pos < sorted.length && $this.attr("data-clientid") == sorted[pos].id) { - pos++; - } - }); - for (var i=pos; i= this.logs.length) { - this.unload(); - return; - } - if (this.pos !== 0) { - // First we need to play the hello - var toReplay = []; - var foundHello = false; - for (var i=this.pos-1; i>=0; i--) { - var item = this.logs[i]; - if (ALWAYS_REPLAY[item.type]) { - toReplay.push(item); - } - if (item.type == "hello" || item.type == "hello-back") { - this.playItem(item); - foundHello = true; - break; - } - } - if (! foundHello) { - console.warn("No hello message found before position", this.pos); - } - toReplay.reverse(); - for (i=0; i= this.logs.length) { - this.unload(); - return; - } - var item = this.logs[this.pos]; - this.playItem(item); - this.pos++; - if (this.pos >= this.logs.length) { - this.unload(); - return; - } - var next = this.logs[this.pos]; - var pause = next.date - item.date; - this.playTimer = setTimeout(this.playOne.bind(this), pause); - if (this.fromStorage) { - this.savePos(); - } - }, - - playItem: function (item) { - if (item.type == "hello") { - // We may need to pause here - if (item.url != (location.href+"").replace(/\#.*/, "")) { - this.pause(); - } - } - try { - session._getChannel().onmessage(item); - } catch (e) { - console.warn("Could not play back message:", item, "error:", e); - } - }, - - save: function () { - this.fromStorage = true; - storage.set("playback.logs", this.logs); - this.savePos(); - }, - - savePos: function () { - storage.set("playback.pos", this.pos); - }, - - unload: function () { - if (this.fromStorage) { - storage.set("playback.logs", undefined); - storage.set("playback.pos", undefined); - } - // FIXME: should do a bye message here - } - - }); - - playback.getRunningLogs = function () { - return storage.get("playback.logs").then(function (value) { - if (! value) { - return null; - } - var logs = Logs(value, true); - return storage.get("playback.pos").then(function (pos) { - pos = pos || 0; - logs.pos = pos; - return logs; - }); - }); - }; - - return playback; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ -/*jshint evil:true */ -define('chat',["require", "jquery", "util", "session", "ui", "templates", "playback", "storage", "peers", "windowing"], function (require, $, util, session, ui, templates, playback, storage, peers, windowing) { - var chat = util.Module("chat"); - var assert = util.assert; - var Walkabout; - - session.hub.on("chat", function (msg) { - ui.chat.text({ - text: msg.text, - peer: msg.peer, - // FIXME: a little unsure of trusting this (maybe I should prefix it?) - messageId: msg.messageId, - notify: true - }); - saveChatMessage({ - text: msg.text, - date: Date.now(), - peerId: msg.peer.id, - messageId: msg.messageId - }); - }); - - // FIXME: this doesn't really belong in this module: - session.hub.on("bye", function (msg) { - ui.chat.leftSession({ - peer: msg.peer, - declinedJoin: msg.reason == "declined-join" - }); - }); - - chat.submit = function (message) { - var parts = message.split(/ /); - if (parts[0].charAt(0) == "/") { - var name = parts[0].substr(1).toLowerCase(); - var method = commands["command_" + name]; - if (method) { - method.apply(null, parts.slice(1)); - return; - } - } - var messageId = session.clientId + "-" + Date.now(); - session.send({ - type: "chat", - text: message, - messageId: messageId - }); - ui.chat.text({ - text: message, - peer: peers.Self, - messageId: messageId, - notify: false - }); - saveChatMessage({ - text: message, - date: Date.now(), - peerId: peers.Self.id, - messageId: messageId - }); - }; - - var commands = { - command_help: function () { - var msg = util.trim(templates.help); - ui.chat.system({ - text: msg - }); - }, - - command_test: function (args) { - if (! Walkabout) { - require(["walkabout"], (function (WalkaboutModule) { - Walkabout = WalkaboutModule; - this.command_test(args); - }).bind(this)); - return; - } - args = util.trim(args || "").split(/\s+/g); - if (args[0] === "" || ! args.length) { - if (this._testCancel) { - args = ["cancel"]; - } else { - args = ["start"]; - } - } - if (args[0] == "cancel") { - ui.chat.system({ - text: "Aborting test" - }); - this._testCancel(); - this._testCancel = null; - return; - } - if (args[0] == "start") { - var times = parseInt(args[1], 10); - if (isNaN(times) || ! times) { - times = 100; - } - ui.chat.system({ - text: "Testing with walkabout.js" - }); - var tmpl = $(templates.walkabout); - var container = ui.container.find(".togetherjs-test-container"); - container.empty(); - container.append(tmpl); - container.show(); - var statusContainer = container.find(".togetherjs-status"); - statusContainer.text("starting..."); - this._testCancel = Walkabout.runManyActions({ - ondone: function () { - statusContainer.text("done"); - statusContainer.one("click", function () { - container.hide(); - }); - this._testCancel = null; - }, - onstatus: function (status) { - var note = "actions: " + status.actions.length + " running: " + - (status.times - status.remaining) + " / " + status.times; - statusContainer.text(note); - } - }); - return; - } - if (args[0] == "show") { - if (this._testShow.length) { - this._testShow.forEach(function (item) { - if (item) { - item.remove(); - } - }, this); - this._testShow = []; - } else { - var actions = Walkabout.findActions(); - actions.forEach(function (action) { - this._testShow.push(action.show()); - }, this); - } - return; - } - if (args[0] == "describe") { - Walkabout.findActions().forEach(function (action) { - ui.chat.system({ - text: action.description() - }); - }, this); - return; - } - ui.chat.system({ - text: "Did not understand: " + args.join(" ") - }); - }, - - _testCancel: null, - _testShow: [], - - command_clear: function () { - ui.chat.clear(); - }, - - command_exec: function () { - var expr = Array.prototype.slice.call(arguments).join(" "); - var result; - // We use this to force global eval (not in this scope): - var e = eval; - try { - result = e(expr); - } catch (error) { - ui.chat.system({ - text: "Error: " + error - }); - } - if (result !== undefined) { - ui.chat.system({ - text: "" + result - }); - } - }, - - command_record: function () { - ui.chat.system({ - text: "When you see the robot appear, the recording will have started" - }); - window.open( - session.recordUrl(), "_blank", - "left,width=" + ($(window).width() / 2)); - }, - - playing: null, - - command_playback: function (url) { - if (this.playing) { - this.playing.cancel(); - this.playing.unload(); - this.playing = null; - ui.chat.system({ - text: "playback cancelled" - }); - return; - } - if (! url) { - ui.chat.system({ - text: "Nothing is playing" - }); - return; - } - var logLoader = playback.getLogs(url); - logLoader.then( - (function (logs) { - if (! logs) { - ui.chat.system({ - text: "No logs found." - }); - return; - } - logs.save(); - this.playing = logs; - logs.play(); - }).bind(this), - function (error) { - ui.chat.system({ - text: "Error fetching " + url + ":\n" + JSON.stringify(error, null, " ") - }); - }); - windowing.hide("#togetherjs-chat"); - }, - - command_savelogs: function (name) { - session.send({ - type: "get-logs", - forClient: session.clientId, - saveAs: name - }); - function save(msg) { - if (msg.request.forClient == session.clientId && msg.request.saveAs == name) { - storage.set("recording." + name, msg.logs).then(function () { - session.hub.off("logs", save); - ui.chat.system({ - text: "Saved as local:" + name - }); - }); - } - } - session.hub.on("logs", save); - }, - - command_baseurl: function (url) { - if (! url) { - storage.get("baseUrlOverride").then(function (b) { - if (b) { - ui.chat.system({ - text: "Set to: " + b.baseUrl - }); - } else { - ui.chat.system({ - text: "No baseUrl override set" - }); - } - }); - return; - } - url = url.replace(/\/*$/, ""); - ui.chat.system({ - text: "If this goes wrong, do this in the console to reset:\n localStorage.setItem('togetherjs.baseUrlOverride', null)" - }); - storage.set("baseUrlOverride", { - baseUrl: url, - expiresAt: Date.now() + (1000 * 60 * 60 * 24) - }).then(function () { - ui.chat.system({ - text: "baseUrl overridden (to " + url + "), will last for one day." - }); - }); - }, - - command_config: function (variable, value) { - if (! (variable || value)) { - storage.get("configOverride").then(function (c) { - if (c) { - util.forEachAttr(c, function (value, attr) { - if (attr == "expiresAt") { - return; - } - ui.chat.system({ - text: " " + attr + " = " + JSON.stringify(value) - }); - }); - ui.chat.system({ - text: "Config expires at " + (new Date(c.expiresAt)) - }); - } else { - ui.chat.system({ - text: "No config override" - }); - } - }); - return; - } - if (variable == "clear") { - storage.set("configOverride", undefined); - ui.chat.system({ - text: "Clearing all overridden configuration" - }); - return; - } - console.log("config", [variable, value]); - if (! (variable && value)) { - ui.chat.system({ - text: "Error: must provide /config VAR VALUE" - }); - return; - } - try { - value = JSON.parse(value); - } catch (e) { - ui.chat.system({ - text: "Error: value (" + value + ") could not be parsed: " + e - }); - return; - } - if (! TogetherJS._defaultConfiguration.hasOwnProperty(variable)) { - ui.chat.system({ - text: "Warning: variable " + variable + " is unknown" - }); - } - storage.get("configOverride").then(function (c) { - c = c || {}; - c[variable] = value; - c.expiresAt = Date.now() + (1000 * 60 * 60 * 24); - storage.set("configOverride", c).then(function () { - ui.chat.system({ - text: "Variable " + variable + " = " + JSON.stringify(value) + "\nValue will be set for one day." - }); - }); - }); - } - - }; - - // this section deal with saving/restoring chat history as long as session is alive - var chatStorageKey = "chatlog"; - var maxLogMessages = 100; - - function saveChatMessage(obj) { - assert(obj.peerId); - assert(obj.messageId); - assert(obj.date); - assert(typeof obj.text == "string"); - - loadChatLog().then(function (log) { - for (var i = log.length - 1; i >= 0; i--) { - if (log[i].messageId === obj.messageId) { - return; - } - } - log.push(obj); - if (log.length > maxLogMessages) { - log.splice(0, log.length - maxLogMessages); - } - storage.tab.set(chatStorageKey, log); - }); - } - - function loadChatLog() { - return storage.tab.get(chatStorageKey, []); - } - - session.once("ui-ready", function () { - loadChatLog().then(function (log) { - if (! log) { - return; - } - for (var i = 0; i < log.length; i++) { - // peers should already be loaded from sessionStorage by the peers module - // maybe i should use a try catch block here - var currentPeer = peers.getPeer(log[i].peerId); - ui.chat.text({ - text: log[i].text, - date: log[i].date, - peer: currentPeer, - messageId: log[i].messageId - }); - } - }); - }); - //delete chat log - session.on("close", function(){ - storage.tab.set(chatStorageKey, undefined); - }); - - return chat; - -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ -define('console',["util"], function (util) { - - var console = window.console || {log: function () {}}; - - var Console = util.Class({ - constructor: function () { - this.messages = []; - this.level = this.levels.log; - }, - - messageLimit: 100, - - levels: { - debug: 1, - // FIXME: I'm considering *not* wrapping console.log, and strictly keeping - // it as a debugging tool; also line numbers would be preserved - log: 2, - info: 3, - notify: 4, - warn: 5, - error: 6, - fatal: 7 - }, - - // Gets set below: - maxLevel: 0, - - consoleLevels: [ - [], - console.debug || [], - console.log || [], - console.info || [], - console.notify || [], - console.warn || [], - console.error || [], - console.fatal || [] - ], - - levelNames: {}, - - setLevel: function (l) { - var number; - if (typeof l == "string") { - number = this.levels[l]; - if (number === undefined) { - throw new Error("Tried to set Console level to unknown level string: " + l); - } - l = number; - } - if (typeof l == "function") { - number = this.consoleLevels.indexOf(l); - if (number == -1) { - throw new Error("Tried to set Console level based on unknown console function: " + l); - } - l = number; - } - if (typeof l == "number") { - if (l < 0) { - throw new Error("Console level must be 0 or larger: " + l); - } else if (l > this.maxLevel) { - throw new Error("Console level must be " + this.maxLevel + " or smaller: " + l); - } - } - this.level = l; - }, - - write: function (level) { - try { - this.messages.push([ - Date.now(), - level, - this._stringify(Array.prototype.slice.call(arguments, 1)) - ]); - } catch (e) { - console.warn("Error stringifying argument:", e); - } - if (level != "suppress" && this.level <= level) { - var method = console[this.levelNames[level]]; - if (! method) { - method = console.log; - } - method.apply(console, Array.prototype.slice.call(arguments, 1)); - } - }, - - suppressedWrite: function () { - this.write.apply(this, ["suppress"].concat(Array.prototype.slice.call(arguments))); - }, - - trace: function (level) { - level = level || 'log'; - if (console.trace) { - level = "suppressedWrite"; - } - try { - throw new Error(); - } catch (e) { - // FIXME: trim this frame - var stack = e.stack; - stack = stack.replace(/^[^\n]*\n/, ""); - this[level](stack); - } - if (console.trace) { - console.trace(); - } - }, - - _browserInfo: function () { - // FIXME: add TogetherJS version and - return [ - "TogetherJS base URL: " + TogetherJS.baseUrl, - "User Agent: " + navigator.userAgent, - "Page loaded: " + this._formatDate(TogetherJS.pageLoaded), - "Age: " + this._formatMinutes(Date.now() - TogetherJS.pageLoaded) + " minutes", - // FIXME: make this right: - //"Window: height: " + window.screen.height + " width: " + window.screen.width - "URL: " + location.href, - "------+------+----------------------------------------------" - ]; - }, - - _stringify: function (args) { - var s = ""; - for (var i=0; i 10) { - // Over 10 minutes, just ignore the seconds - return m; - } - var seconds = Math.floor(remaining / 1000) + ""; - m += ":"; - seconds = lpad(seconds, 2, "0"); - m += seconds; - if (m == "0:00") { - m += ((remaining / 1000).toFixed(3) + "").substr(1); - } - return m; - }, - - _formatLevel: function (l) { - if (l === "suppress") { - return ""; - } - return this.levelNames[l]; - }, - - toString: function () { - try { - var lines = this._browserInfo(); - this.messages.forEach(function (m) { - lines.push(lpad(this._formatTime(m[0]), 6) + " " + rpad(this._formatLevel(m[1]), 6) + " " + lpadLines(m[2], 14)); - }, this); - return lines.join("\n"); - } catch (e) { - // toString errors can otherwise be swallowed: - console.warn("Error running console.toString():", e); - throw e; - } - }, - - submit: function (options) { - // FIXME: friendpaste is broken for this - // (and other pastebin sites aren't really Browser-accessible) - return util.Deferred(function (def) { - options = options || {}; - var site = options.site || TogetherJS.config.get("pasteSite") || "https://www.friendpaste.com/"; - var req = new XMLHttpRequest(); - req.open("POST", site); - req.setRequestHeader("Content-Type", "application/json"); - req.send(JSON.stringify({ - "title": options.title || "TogetherJS log file", - "snippet": this.toString(), - "language": "text" - })); - req.onreadystatechange = function () { - if (req.readyState === 4) { - var data = JSON.parse(req.responseText); - } - }; - }); - } - - }); - - function rpad(s, len, pad) { - s = s + ""; - pad = pad || " "; - while (s.length < len) { - s += pad; - } - return s; - } - - function lpad(s, len, pad) { - s = s + ""; - pad = pad || " "; - while (s.length < len) { - s = pad + s; - } - return s; - } - - function lpadLines(s, len, pad) { - var i; - s = s + ""; - if (s.indexOf("\n") == -1) { - return s; - } - pad = pad || " "; - var fullPad = ""; - for (i=0; i wTop + height - CURSOR_HEIGHT) { - top = height - CURSOR_HEIGHT - 5; - this.setClass("togetherjs-scrolled-below"); - } else { - this.setClass("togetherjs-scrolled-normal"); - } - this.element.css({ - top: top, - left: left - }); - }, - - refresh: function () { - if (this.lastTop !== null) { - this.setPosition(this.lastTop, this.lastLeft); - } - }, - - setKeydown: function () { - if (this.keydownTimeout) { - clearTimeout(this.keydownTimeout); - } else { - this.element.find(".togetherjs-cursor-typing").show().animateKeyboard(); - } - this.keydownTimeout = setTimeout(this.clearKeydown, this.KEYDOWN_WAIT_TIME); - }, - - clearKeydown: function () { - this.keydownTimeout = null; - this.element.find(".togetherjs-cursor-typing").hide().stopKeyboardAnimation(); - }, - - _destroy: function () { - this.element.remove(); - this.element = null; - } - }); - - Cursor._cursors = {}; - - cursor.getClient = Cursor.getClient = function (clientId) { - var c = Cursor._cursors[clientId]; - if (! c) { - c = Cursor._cursors[clientId] = Cursor(clientId); - } - return c; - }; - - Cursor.forEach = function (callback, context) { - context = context || null; - for (var a in Cursor._cursors) { - if (Cursor._cursors.hasOwnProperty(a)) { - callback.call(context, Cursor._cursors[a], a); - } - } - }; - - Cursor.destroy = function (clientId) { - Cursor._cursors[clientId]._destroy(); - delete Cursor._cursors[clientId]; - }; - - peers.on("new-peer identity-updated status-updated", function (peer) { - var c = Cursor.getClient(peer.id); - c.updatePeer(peer); - }); - - var lastTime = 0; - var MIN_TIME = 100; - var lastPosX = -1; - var lastPosY = -1; - var lastMessage = null; - function mousemove(event) { - var now = Date.now(); - if (now - lastTime < MIN_TIME) { - return; - } - lastTime = now; - var pageX = event.pageX; - var pageY = event.pageY; - if (Math.abs(lastPosX - pageX) < 3 && Math.abs(lastPosY - pageY) < 3) { - // Not a substantial enough change - return; - } - lastPosX = pageX; - lastPosY = pageY; - var target = event.target; - var parent = $(target).closest(".togetherjs-window, .togetherjs-popup, #togetherjs-dock"); - if (parent.length) { - target = parent[0]; - } else if (elementFinder.ignoreElement(target)) { - target = null; - } - if ((! target) || target == document.documentElement || target == document.body) { - lastMessage = { - type: "cursor-update", - top: pageY, - left: pageX - }; - //session.send(lastMessage); - return; - } - target = $(target); - var offset = target.offset(); - if (! offset) { - // FIXME: this really is walkabout.js's problem to fire events on the - // document instead of a specific element - console.warn("Could not get offset of element:", target[0]); - return; - } - var offsetX = pageX - offset.left; - var offsetY = pageY - offset.top; - lastMessage = { - type: "cursor-update", - element: elementFinder.elementLocation(target), - offsetX: Math.floor(offsetX), - offsetY: Math.floor(offsetY) - }; - //session.send(lastMessage); - } - - function makeCursor(color) { - var canvas = $(""); - canvas.attr("height", CURSOR_HEIGHT); - canvas.attr("width", CURSOR_WIDTH); - var context = canvas[0].getContext('2d'); - context.fillStyle = color; - context.moveTo(0, 0); - context.beginPath(); - context.lineTo(0, CURSOR_HEIGHT/1.2); - context.lineTo(Math.sin(CURSOR_ANGLE/2) * CURSOR_HEIGHT / 1.5, - Math.cos(CURSOR_ANGLE/2) * CURSOR_HEIGHT / 1.5); - context.lineTo(Math.sin(CURSOR_ANGLE) * CURSOR_HEIGHT / 1.2, - Math.cos(CURSOR_ANGLE) * CURSOR_HEIGHT / 1.2); - context.lineTo(0, 0); - context.shadowColor = 'rgba(0,0,0,0.3)'; - context.shadowBlur = 2; - context.shadowOffsetX = 1; - context.shadowOffsetY = 2; - context.strokeStyle = "#ffffff"; - context.stroke(); - context.fill(); - return canvas[0].toDataURL("image/png"); - } - - var scrollTimeout = null; - var scrollTimeoutSet = 0; - var SCROLL_DELAY_TIMEOUT = 75; - var SCROLL_DELAY_LIMIT = 300; - - function scroll() { - var now = Date.now(); - if (scrollTimeout) { - if (now - scrollTimeoutSet < SCROLL_DELAY_LIMIT) { - clearTimeout(scrollTimeout); - } else { - // Just let it progress anyway - return; - } - } - scrollTimeout = setTimeout(_scrollRefresh, SCROLL_DELAY_TIMEOUT); - if (! scrollTimeoutSet) { - scrollTimeoutSet = now; - } - } - - var lastScrollMessage = null; - function _scrollRefresh() { - scrollTimeout = null; - scrollTimeoutSet = 0; - Cursor.forEach(function (c) { - c.refresh(); - }); - lastScrollMessage = { - type: "scroll-update", - position: elementFinder.elementByPixel($(window).scrollTop()) - }; - session.send(lastScrollMessage); - } - - // FIXME: do the same thing for cursor position? And give up on the - // ad hoc update-on-hello? - session.on("prepare-hello", function (helloMessage) { - if (lastScrollMessage) { - helloMessage.scrollPosition = lastScrollMessage.position; - } - }); - - session.hub.on("scroll-update", function (msg) { - msg.peer.scrollPosition = msg.position; - if (msg.peer.following) { - msg.peer.view.scrollTo(); - } - }); - - // In case there are multiple peers, we track that we've accepted one of their - // hello-based scroll updates, just so we don't bounce around (we don't intelligently - // choose which one to use, just the first that comes in) - var acceptedScrollUpdate = false; - session.hub.on("hello-back hello", function (msg) { - if (msg.type == "hello") { - // Once a hello comes in, a bunch of hello-backs not intended for us will also - // come in, and we should ignore them - acceptedScrollUpdate = true; - } - if (! msg.scrollPosition) { - return; - } - msg.peer.scrollPosition = msg.scrollPosition; - if ((! acceptedScrollUpdate) && - msg.sameUrl && - Date.now() - session.timeHelloSent < SCROLL_UPDATE_CUTOFF) { - acceptedScrollUpdate = true; - msg.peer.view.scrollTo(); - } - }); - - session.on("ui-ready", function () { - $(document).mousemove(mousemove); - document.addEventListener("click", documentClick, true); - document.addEventListener("keydown", documentKeydown, true); - $(window).scroll(scroll); - scroll(); - }); - - session.on("close", function () { - Cursor.forEach(function (c, clientId) { - Cursor.destroy(clientId); - }); - $(document).unbind("mousemove", mousemove); - document.removeEventListener("click", documentClick, true); - document.removeEventListener("keydown", documentKeydown, true); - $(window).unbind("scroll", scroll); - }); - - session.hub.on("hello", function (msg) { - // Immediately get our cursor onto this new person's screen: - if (lastMessage) { - session.send(lastMessage); - } - if (lastScrollMessage) { - session.send(lastScrollMessage); - } - }); - - function documentClick(event) { - if (event.togetherjsInternal) { - // This is an artificial internal event - return; - } - // FIXME: this might just be my imagination, but somehow I just - // really don't want to do anything at this stage of the event - // handling (since I'm catching every click), and I'll just do - // something real soon: - setTimeout(function () { - if (! TogetherJS.running) { - // This can end up running right after TogetherJS has been closed, often - // because TogetherJS was closed with a click... - return; - } - var element = event.target; - if (element == document.documentElement) { - // For some reason clicking on gives the element here - element = document.body; - } - if (elementFinder.ignoreElement(element)) { - return; - } - //Prevent click events on video objects to avoid conflicts with - //togetherjs's own video events - if (element.nodeName.toLowerCase() === 'video'){ - return; - } - - var dontShowClicks = TogetherJS.config.get("dontShowClicks"); - var cloneClicks = TogetherJS.config.get("cloneClicks"); - // If you dont want to clone the click for this element - // and you dont want to show the click for this element or you dont want to show any clicks - // then return to avoid sending a useless click - if ((! util.matchElement(element, cloneClicks)) && util.matchElement(element, dontShowClicks)) { - return; - } - var location = elementFinder.elementLocation(element); - var offset = $(element).offset(); - var offsetX = event.pageX - offset.left; - var offsetY = event.pageY - offset.top; - /*session.send({ - type: "cursor-click", - element: location, - offsetX: offsetX, - offsetY: offsetY - });*/ - if (util.matchElement(element, dontShowClicks)) { - return; - } - //displayClick({top: event.pageY, left: event.pageX}, peers.Self.color); - }); - } - - session.hub.on("app.codiad", function (data) { - codiad.together.handle(data); - }); - - var CLICK_TRANSITION_TIME = 3000; - - session.hub.on("cursor-click", function (pos) { - // When the click is calculated isn't always the same as how the - // last cursor update was calculated, so we force the cursor to - // the last location during a click: - if (! pos.sameUrl) { - // FIXME: if we *could have* done a local click, but we follow along - // later, we'll be in different states if that click was important. - // Mostly click cloning just won't work. - return; - } - Cursor.getClient(pos.clientId).updatePosition(pos); - var target = $(elementFinder.findElement(pos.element)); - var offset = target.offset(); - var top = offset.top + pos.offsetY; - var left = offset.left + pos.offsetX; - var cloneClicks = TogetherJS.config.get("cloneClicks"); - if (util.matchElement(target, cloneClicks)) { - eventMaker.performClick(target); - } - var dontShowClicks = TogetherJS.config.get("dontShowClicks"); - if (util.matchElement(target, dontShowClicks)) { - return; - } - displayClick({top: top, left: left}, pos.peer.color); - }); - - function displayClick(pos, color) { - // FIXME: should we hide the local click if no one else is going to see it? - // That means tracking who might be able to see our screen. - var element = templating.clone("click"); - $(document.body).append(element); - element.css({ - top: pos.top, - left: pos.left, - borderColor: color - }); - setTimeout(function () { - element.addClass("togetherjs-clicking"); - }, 100); - setTimeout(function () { - element.remove(); - }, CLICK_TRANSITION_TIME); - } - - var lastKeydown = 0; - var MIN_KEYDOWN_TIME = 500; - - function documentKeydown(event) { - setTimeout(function () { - var now = Date.now(); - if (now - lastKeydown < MIN_KEYDOWN_TIME) { - return; - } - lastKeydown = now; - // FIXME: is event.target interesting here? That is, *what* the - // user is typing into, not just that the user is typing? Also - // I'm assuming we don't care if the user it typing into a - // togetherjs-related field, since chat activity is as interesting - // as any other activity. - session.send({type: "keydown"}); - }); - } - - session.hub.on("keydown", function (msg) { - // FIXME: when the cursor is hidden there's nothing to show with setKeydown(). - var cursor = Cursor.getClient(msg.clientId); - cursor.setKeydown(); - }); - - util.testExpose({Cursor: Cursor}); - - return cursor; - -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('ot',["util"], function (util) { - - var ot = util.Module("ot"); - var assert = util.assert; - - var StringSet = util.Class({ - /* Set that only supports string items */ - constructor: function () { - this._items = {}; - this._count = 0; - }, - contains: function (k) { - assert(typeof k == "string"); - return this._items.hasOwnProperty(k); - }, - add: function (k) { - assert(typeof k == "string"); - if (this.contains(k)) { - return; - } - this._items[k] = null; - this._count++; - }, - remove: function (k) { - assert(typeof k == "string"); - if (! this.contains(k)) { - return; - } - delete this._items[k]; - this._count++; - }, - isEmpty: function () { - return ! this._count; - } - }); - - var Queue = util.Class({ - - constructor: function (size) { - this._q = []; - this._size = size; - this._deleted = 0; - }, - - _trim: function () { - if (this._size) { - if (this._q.length > this._size) { - this._q.splice(0, this._q.length - this._size); - this._deleted += this._q.length - this._size; - } - } - }, - - push: function (item) { - this._q.push(item); - this._trim(); - }, - - last: function () { - return this._q[this._q.length-1]; - }, - - walkBack: function (callback, context) { - var result = true; - for (var i=this._q.length-1; i >= 0; i--) { - var item = this._q[i]; - result = callback.call(context, item, i + this._deleted); - if (result === false) { - return result; - } else if (! result) { - result = true; - } - } - return result; - }, - - walkForward: function (index, callback, context) { - var result = true; - for (var i=index; i this.version || - (otherChange.version == this.version && otherChange.clientId > this.clientId); - }, - - knowsAboutAll: function (versions) { - for (var clientId in versions) { - if (! versions.hasOwnProperty(clientId)) { - continue; - } - if (! versions[clientId]) { - continue; - } - if ((! this.known[clientId]) || this.known[clientId] < versions[clientId]) { - return false; - } - } - return true; - }, - - knowsAboutChange: function (change) { - return change.clientId == this.clientId || - (this.known[change.clientId] && this.known[change.clientId] >= change.version); - }, - - knowsAboutVersion: function (version, clientId) { - if ((! version) || clientId == this.clientId) { - return true; - } - return this.known[clientId] && this.known[clientId] >= version; - }, - - maybeMissingChanges: function (mostRecentVersion, clientId) { - if (! mostRecentVersion) { - // No actual changes for clientId exist - return false; - } - if (! this.known[clientId]) { - // We don't even know about clientId, so we are definitely missing something - return true; - } - if (this.known[clientId] >= mostRecentVersion) { - // We know about all versions through mostRecentVersion - return false; - } - if ((clientId > this.clientId && this.known[clientId] >= this.version-1) || - (clientId < this.clientId && this.known[clientId] == this.version)) { - // We know about all versions from clientId that could exist before this - // version - return false; - } - // We may or may not be missing something - return true; - } - }); - - /* SimpleHistory synchronizes peers by relying on the server to serialize - * the order of all updates. Each client maintains a queue of patches - * which have not yet been 'committed' (by being echoed back from the - * server). The client is responsible for transposing its own queue - * if 'earlier' patches are heard from the server. - * - * Let's say that A's edit "1" and B's edit "2" occur and get put in - * their respective SimpleHistory queues. The server happens to - * handle 1 first, then 2, so those are the order that all peers - * (both A and B) see the messages. - * - * A sees 1, and has 1 on its queue, so everything's fine. It - * updates the 'committed' text to match its current text and drops - * the patch from its queue. It then sees 2, but the basis number - * for 2 no longer matches the committed basis, so it throws it - * away. - * - * B sees 1, and has 2 on its queue. It does the OT transpose thing, - * updating the committed text to include 1 and the 'current' text - * to include 1+2. It updates its queue with the newly transposed - * version of 2 (call it 2prime) and updates 2prime's basis - * number. It them resends 2prime to the server. It then receives 2 - * (the original) but the basis number no longer matches the - * committed basis, so it throws it away. - * - * Now the server sees 2prime and rebroadcasts it to both A and B. - * - * A is seeing it for the first time, and the basis number matches, - * so it applies it to the current and committed text. - * - * B sees that 2prime matches what's on the start of its queue, - * shifts it off, and updates the committed text to match the - * current text. - * - * Note that no one tries to keep an entire history of changes, - * which is the main difference with ot.History. Everyone applies - * the same patches in the same order. - */ - ot.SimpleHistory = util.Class({ - - constructor: function(clientId, initState, initBasis) { - this.clientId = clientId; - this.committed = initState; - this.current = initState; - this.basis = initBasis; - this.queue = []; - this.deltaId = 1; - this.selection = null; - }, - - // Use a fake change to represent the selection. - // (This is the only bit that hard codes ot.TextReplace as the delta - // representation; override this in a subclass (or don't set the - // selection) if you are using a different delta representation. - setSelection: function(selection) { - if (selection) { - this.selection = ot.TextReplace(selection[0], - selection[1] - selection[0], '@'); - } else { - this.selection = null; - } - }, - - // Decode the fake change to reconstruct the updated selection. - getSelection: function() { - if (! this.selection) { - return null; - } - return [this.selection.start, this.selection.start + this.selection.del]; - }, - - // Add this delta to this client's queue. - add: function(delta) { - var change = { - id: this.clientId + '.' + (this.deltaId++), - delta: delta - }; - if (! this.queue.length) { - change.basis = this.basis; - } - this.queue.push(change); - this.current = delta.apply(this.current); - return !!change.basis; - }, - - // Apply a delta received from the server. - // Return true iff the current text changed as a result. - commit: function(change) { - - // ignore it if the basis doesn't match (this patch doesn't apply) - // if so, this delta is out of order; we expect the original client - // to retransmit an updated delta. - if (change.basis !== this.basis) { - return false; // 'current' text did not change - } - - // is this the first thing on the queue? - if (this.queue.length && this.queue[0].id === change.id) { - assert(change.basis === this.queue[0].basis); - // good, apply this to commit state & remove it from queue - this.committed = this.queue.shift().delta.apply(this.committed); - this.basis++; - if (this.queue.length) { - this.queue[0].basis = this.basis; - } - return false; // 'current' text did not change - } - - // Transpose all bits on the queue to put this patch first. - var inserted = change.delta; - this.queue = this.queue.map(function(qchange) { - var tt = qchange.delta.transpose(inserted); - inserted = tt[1]; - return { - id: qchange.id, - delta: tt[0] - }; - }); - if (this.selection) { - // update the selection! - this.selection = this.selection.transpose(inserted)[0]; - } - this.committed = change.delta.apply(this.committed); - this.basis++; - if (this.queue.length) { - this.queue[0].basis = this.basis; - } - // Update current by replaying queued changes starting from 'committed' - this.current = this.committed; - this.queue.forEach(function(qchange) { - this.current = qchange.delta.apply(this.current); - }.bind(this)); - return true; // The 'current' text changed. - }, - - // Return the next change to transmit to the server, or null if there - // isn't one. - getNextToSend: function() { - var qchange = this.queue[0]; - if (! qchange) { - /* nothing to send */ - return null; - } - if (qchange.sent) { - /* already sent */ - return null; - } - assert(qchange.basis); - qchange.sent = true; - return qchange; - } - }); - - ot.History = util.Class({ - - constructor: function (clientId, initState) { - this._history = Queue(); - this._history.push({ - clientId: "init", state: initState - }); - this.clientId = clientId; - this.known = {}; - this.mostRecentLocalChange = null; - }, - - add: function (change) { - // Simplest cast, it is our change: - if (change.clientId == this.clientId) { - this._history.push(change); - this.mostRecentLocalChange = change.version; - return change.delta; - } - assert((! this.known[change.clientId]) || this.known[change.clientId] < change.version, - "Got a change", change, "that appears older (or same as) a known change", this.known[change.clientId]); - // Second simplest case, we get a change that we can add to our - // history without modification: - var last = this._history.last(); - if ((last.clientId == "init" || last.isBefore(change)) && - change.knowsAboutAll(this.known) && - change.knowsAboutVersion(this.mostRecentLocalChange, this.clientId)) { - this._history.push(change); - this.known[change.clientId] = change.version; - return change.delta; - } - // We must do work! - - this.logHistory("//"); - - // First we check if we need to modify this change because we - // know about changes that it should know about (changes that - // preceed it that are in our local history). - var clientsToCheck = StringSet(); - for (var clientId in this.known) { - if (! this.known.hasOwnProperty(clientId)) { - continue; - } - if (change.maybeMissingChanges(this.known[clientId], clientId)) { - clientsToCheck.add(clientId); - } - } - if (change.maybeMissingChanges(this.mostRecentLocalChange, this.clientId)) { - clientsToCheck.add(this.clientId); - } - if (! clientsToCheck.isEmpty()) { - var indexToCheckFrom = null; - this._history.walkBack(function (c, index) { - indexToCheckFrom = index; - if (c.clientId == "init") { - return false; - } - if (clientsToCheck.contains(c.clientId) && - ! change.maybeMissingChanges(c.version, c.clientId)) { - clientsToCheck.remove(c.clientId); - if (clientsToCheck.isEmpty()) { - return false; - } - } - return true; - }, this); - this._history.walkForward(indexToCheckFrom, function (c, index) { - if (c.clientId == "init") { - return true; - } - if (change.isBefore(c)) { - return false; - } - if (! change.knowsAboutChange(c)) { - var presentDelta = this.promoteDelta(c.delta, index, change); - if (! presentDelta.equals(c.delta)) { - //console.log("->rebase delta rewrite", presentDelta+""); - } - this.logChange("->rebase", change, function () { - var result = change.delta.transpose(presentDelta); - change.delta = result[0]; - change.known[c.clientId] = c.version; - }, "with:", c); - } - return true; - }, this); - } - - // Next we insert the change into its proper location - var indexToInsert = null; - this._history.walkBack(function (c, index) { - if (c.clientId == "init" || c.isBefore(change)) { - indexToInsert = index+1; - return false; - } - return true; - }, this); - assert(indexToInsert); - this._history.insert(indexToInsert, change); - - // Now we fix up any forward changes - var fixupDelta = change.delta; - this._history.walkForward(indexToInsert+1, function (c, index) { - if (! c.knowsAboutChange(change)) { - var origChange = c.clone(); - this.logChange("^^fix", c, function () { - var fixupResult = c.delta.transpose(fixupDelta); - console.log(" ^^real"); - var result = c.delta.transpose(fixupDelta); - c.delta = result[0]; - c.known[change.clientId] = change.version; - fixupDelta = fixupResult[1]; - }, "clone:", change.delta+""); - console.log("(trans)", fixupDelta+""); - assert(c.knowsAboutChange(change)); - } - }, this); - - // Finally we return the transformed delta that represents - // changes that should be made to the state: - - this.logHistory("!!"); - return fixupDelta; - }, - - promoteDelta: function (delta, deltaIndex, untilChange) { - this._history.walkForward(deltaIndex+1, function (c, index) { - if (untilChange.isBefore(c)) { - return false; - } - // FIXME: not sure if this clientId check here is right. Maybe - // if untilChange.knowsAbout(c)? - if (untilChange.knowsAboutChange(c)) { - var result = c.delta.transpose(delta); - delta = result[1]; - } - return true; - }); - return delta; - }, - - logHistory: function (prefix) { - prefix = prefix || ""; - var postfix = Array.prototype.slice.call(arguments, 1); - console.log.apply(console, [prefix + "history", this.clientId, ":"].concat(postfix)); - console.log(prefix + " state:", JSON.stringify(this.getStateSafe())); - var hstate; - this._history.walkForward(0, function (c, index) { - if (! index) { - assert(c.clientId == "init"); - console.log(prefix + " init:", JSON.stringify(c.state)); - hstate = c.state; - } else { - try { - hstate = c.delta.apply(hstate); - } catch (e) { - hstate = "Error: " + e; - } - console.log(prefix + " ", index, c+"", JSON.stringify(hstate)); - } - }); - }, - - logChange: function (prefix, change, callback) { - prefix = prefix || "before"; - var postfix = Array.prototype.slice.call(arguments, 3); - console.log.apply( - console, - [prefix, this.clientId, ":", change+""].concat(postfix).concat([JSON.stringify(this.getStateSafe(true))])); - try { - callback(); - } finally { - console.log(prefix + " after:", change+"", JSON.stringify(this.getStateSafe())); - } - }, - - addDelta: function (delta) { - var version = this._createVersion(); - var change = Change(version, this.clientId, delta, util.extend(this.knownVersions)); - this.add(change); - return change; - }, - - _createVersion: function () { - var max = 1; - for (var id in this.knownVersions) { - max = Math.max(max, this.knownVersions[id]); - } - max = Math.max(max, this.mostRecentLocalChange); - return max+1; - }, - - fault: function (change) { - throw new Error('Fault'); - }, - - getState: function () { - var state; - this._history.walkForward(0, function (c) { - if (c.clientId == "init") { - // Initialization, has the state - state = c.state; - } else { - state = c.delta.apply(state); - } - }, this); - return state; - }, - - getStateSafe: function () { - try { - return this.getState(); - } catch (e) { - return 'Error: ' + e; - } - } - - }); - - ot.TextReplace = util.Class({ - - constructor: function (start, del, text) { - assert(typeof start == "number" && typeof del == "number" && typeof text == "string", start, del, text); - assert(start >=0 && del >= 0, start, del); - this.start = start; - this.del = del; - this.text = text; - }, - - toString: function () { - if (this.empty()) { - return '[no-op]'; - } - if (! this.del) { - return '[insert ' + JSON.stringify(this.text) + ' @' + this.start + ']'; - } else if (! this.text) { - return '[delete ' + this.del + ' chars @' + this.start + ']'; - } else { - return '[replace ' + this.del + ' chars with ' + JSON.stringify(this.text) + ' @' + this.start + ']'; - } - }, - - equals: function (other) { - return other.constructor === this.constructor && - other.del === this.del && - other.start === this.start && - other.text === this.text; - }, - - clone: function (start, del, text) { - if (start === undefined) { - start = this.start; - } - if (del === undefined) { - del = this.del; - } - if (text === undefined) { - text = this.text; - } - return ot.TextReplace(start, del, text); - }, - - empty: function () { - return (! this.del) && (! this.text); - }, - - apply: function (text) { - if (this.empty()) { - return text; - } - if (this.start > text.length) { - console.trace(); - throw new util.AssertionError("Start after end of text (" + JSON.stringify(text) + "/" + text.length + "): " + this); - } - if (this.start + this.del > text.length) { - throw new util.AssertionError("Start+del after end of text (" + JSON.stringify(text) + "/" + text.length + "): " + this); - } - return text.substr(0, this.start) + this.text + text.substr(this.start+this.del); - }, - - transpose: function (delta) { - /* Transform this delta as though the other delta had come before it. - Returns a [new_version_of_this, transformed_delta], where transformed_delta - satisfies: - - result1 = new_version_of_this.apply(delta.apply(text)); - result2 = transformed_delta.apply(this.apply(text)); - assert(result1 == result2); - - Does not modify this object. - */ - var overlap; - assert(delta instanceof ot.TextReplace, "Transposing with non-TextReplace:", delta); - if (this.empty()) { - //console.log(" =this is empty"); - return [this.clone(), delta.clone()]; - } - if (delta.empty()) { - //console.log(" =other is empty"); - return [this.clone(), delta.clone()]; - } - if (delta.before(this)) { - //console.log(" =this after other"); - return [this.clone(this.start + delta.text.length - delta.del), - delta.clone()]; - } else if (this.before(delta)) { - //console.log(" =this before other"); - return [this.clone(), delta.clone(delta.start + this.text.length - this.del)]; - } else if (delta.sameRange(this)) { - //console.log(" =same range"); - return [this.clone(this.start+delta.text.length, 0), - delta.clone(undefined, 0)]; - } else if (delta.contains(this)) { - //console.log(" =other contains this"); - return [this.clone(delta.start+delta.text.length, 0, this.text), - delta.clone(undefined, delta.del - this.del + this.text.length, delta.text + this.text)]; - } else if (this.contains(delta)) { - //console.log(" =this contains other"); - return [this.clone(undefined, this.del - delta.del + delta.text.length, delta.text + this.text), - delta.clone(this.start, 0, delta.text)]; - } else if (this.overlapsStart(delta)) { - //console.log(" =this overlaps start of other"); - overlap = this.start + this.del - delta.start; - return [this.clone(undefined, this.del - overlap), - delta.clone(this.start + this.text.length, delta.del - overlap)]; - } else { - //console.log(" =this overlaps end of other"); - assert(delta.overlapsStart(this), delta+"", "does not overlap start of", this+"", delta.before(this)); - overlap = delta.start + delta.del - this.start; - return [this.clone(delta.start + delta.text.length, this.del - overlap), - delta.clone(undefined, delta.del - overlap)]; - } - throw 'Should not happen'; - }, - - before: function (other) { - return this.start + this.del <= other.start; - }, - - contains: function (other) { - return other.start >= this.start && other.start + other.del < this.start + this.del; - }, - - sameRange: function (other) { - return other.start == this.start && other.del == this.del; - }, - - overlapsStart: function (other) { - return this.start < other.start && this.start + this.del > other.start; - }, - - classMethods: { - - /* Make a new ot.TextReplace that converts oldValue to newValue. */ - fromChange: function(oldValue, newValue) { - assert(typeof oldValue == "string"); - assert(typeof newValue == "string"); - var commonStart = 0; - while (commonStart < newValue.length && - newValue.charAt(commonStart) == oldValue.charAt(commonStart)) { - commonStart++; - } - var commonEnd = 0; - while (commonEnd < (newValue.length - commonStart) && - commonEnd < (oldValue.length - commonStart) && - newValue.charAt(newValue.length - commonEnd - 1) == - oldValue.charAt(oldValue.length - commonEnd - 1)) { - commonEnd++; - } - var removed = oldValue.substr(commonStart, oldValue.length - commonStart - commonEnd); - var inserted = newValue.substr(commonStart, newValue.length - commonStart - commonEnd); - if (! (removed.length || inserted)) { - return null; - } - return this(commonStart, removed.length, inserted); - }, - - random: function (source, generator) { - var text, start, len; - var ops = ["ins", "del", "repl"]; - if (! source.length) { - ops = ["ins"]; - } - switch (generator.pick(ops)) { - case "ins": - if (! generator.number(2)) { - text = generator.string(1); - } else { - text = generator.string(generator.number(3)+1); - } - if (! generator.number(4)) { - start = 0; - } else if (! generator.number(3)) { - start = source.length-1; - } else { - start = generator.number(source.length); - } - return this(start, 0, text); - - case "del": - if (! generator.number(20)) { - return this(0, source.length, ""); - } - start = generator.number(source.length-1); - if (! generator.number(2)) { - len = 1; - } else { - len = generator.number(5)+1; - } - len = Math.min(len, source.length - start); - return this(start, len, ""); - - case "repl": - start = generator.number(source.length-1); - len = generator.number(5); - len = Math.min(len, source.length - start); - text = generator.string(generator.number(2)+1); - return this(start, len, text); - } - throw 'Unreachable'; - } - } - }); - - return ot; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('forms',["jquery", "util", "session", "elementFinder", "eventMaker", "templating", "ot"], function ($, util, session, elementFinder, eventMaker, templating, ot) { - var forms = util.Module("forms"); - var assert = util.assert; - - // This is how much larger the focus element is than the element it surrounds - // (this is padding on each side) - var FOCUS_BUFFER = 5; - - var inRemoteUpdate = false; - - function suppressSync(element) { - var ignoreForms = TogetherJS.config.get("ignoreForms"); - if (ignoreForms === true) { - return true; - } - else { - return $(element).is(ignoreForms.join(",")); - } - } - - function maybeChange(event) { - // Called when we get an event that may or may not indicate a real change - // (like keyup in a textarea) - var tag = event.target.tagName; - if (tag == "TEXTAREA" || tag == "INPUT") { - change(event); - } - } - - function change(event) { - sendData({ - element: event.target, - value: getValue(event.target) - }); - } - - function sendData(attrs) { - var el = $(attrs.element); - assert(el); - var tracker = attrs.tracker; - var value = attrs.value; - if (inRemoteUpdate) { - return; - } - if (elementFinder.ignoreElement(el) || - (elementTracked(el) && !tracker) || - suppressSync(el)) { - return; - } - var location = elementFinder.elementLocation(el); - var msg = { - type: "form-update", - element: location - }; - if (isText(el) || tracker) { - var history = el.data("togetherjsHistory"); - if (history) { - if (history.current == value) { - return; - } - var delta = ot.TextReplace.fromChange(history.current, value); - assert(delta); - history.add(delta); - maybeSendUpdate(msg.element, history, tracker); - return; - } else { - msg.value = value; - msg.basis = 1; - el.data("togetherjsHistory", ot.SimpleHistory(session.clientId, value, 1)); - } - } else { - msg.value = value; - } - session.send(msg); - } - - function isCheckable(el) { - el = $(el); - var type = (el.prop("type") || "text").toLowerCase(); - if (el.prop("tagName") == "INPUT" && ["radio", "checkbox"].indexOf(type) != -1) { - return true; - } - return false; - } - - var editTrackers = {}; - var liveTrackers = []; - - TogetherJS.addTracker = function (TrackerClass, skipSetInit) { - assert(typeof TrackerClass === "function", "You must pass in a class"); - assert(typeof TrackerClass.prototype.trackerName === "string", - "Needs a .prototype.trackerName string"); - // Test for required instance methods. - "destroy update init makeInit tracked".split(/ /).forEach(function(m) { - assert(typeof TrackerClass.prototype[m] === "function", - "Missing required tracker method: "+m); - }); - // Test for required class methods. - "scan tracked".split(/ /).forEach(function(m) { - assert(typeof TrackerClass[m] === "function", - "Missing required tracker class method: "+m); - }); - editTrackers[TrackerClass.prototype.trackerName] = TrackerClass; - if (!skipSetInit) { - setInit(); - } - }; - - var AceEditor = util.Class({ - - trackerName: "AceEditor", - - constructor: function (el) { - this.element = $(el)[0]; - assert($(this.element).hasClass("ace_editor")); - this._change = this._change.bind(this); - this._editor().document.on("change", this._change); - }, - - tracked: function (el) { - return this.element === $(el)[0]; - }, - - destroy: function (el) { - this._editor().document.removeListener("change", this._change); - }, - - update: function (msg) { - this._editor().document.setValue(msg.value); - }, - - init: function (update, msg) { - this.update(update); - }, - - makeInit: function () { - return { - element: this.element, - tracker: this.trackerName, - value: this._editor().document.getValue() - }; - }, - - _editor: function () { - return this.element.env; - }, - - _change: function (e) { - // FIXME: I should have an internal .send() function that automatically - // asserts !inRemoteUpdate, among other things - if (inRemoteUpdate) { - return; - } - sendData({ - tracker: this.trackerName, - element: this.element, - value: this.getContent() - }); - }, - - getContent: function() { - return this._editor().document.getValue(); - } - }); - - AceEditor.scan = function () { - return $(".ace_editor"); - }; - - AceEditor.tracked = function (el) { - return !! $(el).closest(".ace_editor").length; - }; - - TogetherJS.addTracker(AceEditor, true /* skip setInit */); - - var CodeMirrorEditor = util.Class({ - trackerName: "CodeMirrorEditor", - - constructor: function (el) { - this.element = $(el)[0]; - assert(this.element.CodeMirror); - this._change = this._change.bind(this); - this._editor().on("change", this._change); - }, - - tracked: function (el) { - return this.element === $(el)[0]; - }, - - destroy: function (el) { - this._editor().off("change", this._change); - }, - - update: function (msg) { - this._editor().setValue(msg.value); - }, - - init: function (msg) { - if (msg.value) { - this.update(msg); - } - }, - - makeInit: function () { - return { - element: this.element, - tracker: this.trackerName, - value: this._editor().getValue() - }; - }, - - _change: function (editor, change) { - if (inRemoteUpdate) { - return; - } - sendData({ - tracker: this.trackerName, - element: this.element, - value: this.getContent() - }); - }, - - _editor: function () { - return this.element.CodeMirror; - }, - - getContent: function() { - return this._editor().getValue(); - } - }); - - CodeMirrorEditor.scan = function () { - var result = []; - var els = document.body.getElementsByTagName("*"); - var _len = els.length; - for (var i=0; i<_len; i++) { - var el = els[i]; - if (el.CodeMirror) { - result.push(el); - } - } - return $(result); - }; - - CodeMirrorEditor.tracked = function (el) { - el = $(el)[0]; - while (el) { - if (el.CodeMirror) { - return true; - } - el = el.parentNode; - } - return false; - }; - - TogetherJS.addTracker(CodeMirrorEditor, true /* skip setInit */); - - - var CKEditor = util.Class({ - trackerName: "CKEditor", - - constructor: function (el) { - this.element = $(el)[0]; - assert(CKEDITOR); - assert(CKEDITOR.dom.element.get(this.element)); - this._change = this._change.bind(this); - // FIXME: change event is available since CKEditor 4.2 - this._editor().on("change", this._change); - }, - tracked: function (el) { - return this.element === $(el)[0]; - }, - destroy: function (el) { - this._editor().removeListener("change", this._change); - }, - - update: function (msg) { - //FIXME: use setHtml instead of setData to avoid frame reloading overhead - this._editor().editable().setHtml(msg.value); - }, - - init: function (update, msg) { - this.update(update); - }, - - makeInit: function () { - return { - element: this.element, - tracker: this.trackerName, - value: this.getContent() - }; - }, - - _change: function (e) { - if (inRemoteUpdate) { - return; - } - sendData({ - tracker: this.trackerName, - element: this.element, - value: this.getContent() - }); - }, - - _editor: function () { - return CKEDITOR.dom.element.get(this.element).getEditor(); - }, - - getContent: function () { - return this._editor().getData(); - } - }); - - CKEditor.scan = function () { - var result = []; - if (typeof CKEDITOR == "undefined") { - return; - } - var editorInstance; - for (var instanceIdentifier in CKEDITOR.instances) { - editorInstance = document.getElementById(instanceIdentifier) || document.getElementsByName(instanceIdentifier)[0]; - if (editorInstance) { - result.push(editorInstance); - } - } - return $(result); - }; - - CKEditor.tracked = function (el) { - if (typeof CKEDITOR == "undefined") { - return false; - } - el = $(el)[0]; - return !! (CKEDITOR.dom.element.get(el) && CKEDITOR.dom.element.get(el).getEditor()); - }; - - TogetherJS.addTracker(CKEditor, true /* skip setInit */); - - - function buildTrackers() { - assert(! liveTrackers.length); - util.forEachAttr(editTrackers, function (TrackerClass) { - var els = TrackerClass.scan(); - if (els) { - $.each(els, function () { - var tracker = new TrackerClass(this); - $(this).data("togetherjsHistory", ot.SimpleHistory(session.clientId, tracker.getContent(), 1)); - liveTrackers.push(tracker); - }); - } - }); - } - - function destroyTrackers() { - liveTrackers.forEach(function (tracker) { - tracker.destroy(); - }); - liveTrackers = []; - } - - function elementTracked(el) { - var result = false; - util.forEachAttr(editTrackers, function (TrackerClass) { - if (TrackerClass.tracked(el)) { - result = true; - } - }); - return result; - } - - function getTracker(el, name) { - el = $(el)[0]; - for (var i=0; i= STEPS.length) { - session.emit("startup-ready"); - return; - } - currentStep = STEPS[index]; - handlers[currentStep](startup.start); - }; - - var handlers = { - - browserBroken: function (next) { - if (window.WebSocket) { - next(); - return; - } - windowing.show("#togetherjs-browser-broken", { - onClose: function () { - session.close(); - } - }); - if ($.browser.msie) { - $("#togetherjs-browser-broken-is-ie").show(); - } - }, - - browserUnsupported: function (next) { - if (! $.browser.msie) { - next(); - return; - } - var cancel = true; - windowing.show("#togetherjs-browser-unsupported", { - onClose: function () { - if (cancel) { - session.close(); - } else { - next(); - } - } - }); - $("#togetherjs-browser-unsupported-anyway").click(function () { - cancel = false; - }); - }, - - sessionIntro: function (next) { - if ((! session.isClient) || ! session.firstRun) { - next(); - return; - } - TogetherJS.config.close("suppressJoinConfirmation"); - if (TogetherJS.config.get("suppressJoinConfirmation")) { - next(); - return; - } - var cancelled = false; - windowing.show("#togetherjs-intro", { - onClose: function () { - if (! cancelled) { - next(); - } - } - }); - $("#togetherjs-intro .togetherjs-modal-dont-join").click(function () { - cancelled = true; - windowing.hide(); - session.close("declined-join"); - }); - }, - - walkthrough: function (next) { - storage.settings.get("seenIntroDialog").then(function (seenIntroDialog) { - if (seenIntroDialog) { - next(); - return; - } - require(["walkthrough"], function (walkthrough) { - walkthrough.start(true, function () { - storage.settings.set("seenIntroDialog", true); - next(); - }); - }); - }); - }, - - share: function (next) { - TogetherJS.config.close("suppressInvite"); - if (session.isClient || (! session.firstRun) || - TogetherJS.config.get("suppressInvite")) { - next(); - return; - } - require(["windowing"], function (windowing) { - windowing.show("#togetherjs-share"); - // FIXME: no way to detect when the window is closed - // If there was a next() step then it would not work - }); - } - - }; - - return startup; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('videos',["jquery", "util", "session", "elementFinder"], -function ($, util, session, elementFinder) { - - var listeners = []; - - var TIME_UPDATE = 'timeupdate'; - var MIRRORED_EVENTS = ['play', 'pause']; - - var TOO_FAR_APART = 3000; - - session.on("reinitialize", function () { - unsetListeners(); - setupListeners(); - }); - - session.on("ui-ready", setupListeners); - - function setupListeners() { - var videos = $('video'); - setupMirroredEvents(videos); - setupTimeSync(videos); - } - - function setupMirroredEvents(videos) { - var currentListener; - MIRRORED_EVENTS.forEach(function (eventName) { - currentListener = makeEventSender(eventName); - videos.on(eventName, currentListener); - listeners.push({ - name: eventName, - listener: currentListener - }); - }); - } - - function makeEventSender(eventName) { - return function (event, options) { - var element = event.target; - options || (options = {}); - if (!options.silent) { - session.send({ - type: ('video-'+eventName), - location: elementFinder.elementLocation(element), - position: element.currentTime - }); - } - }; - } - - function setupTimeSync(videos) { - videos.each(function(i, video) { - var onTimeUpdate = makeTimeUpdater(); - $(video).on(TIME_UPDATE, onTimeUpdate); - listeners.push({ - name: TIME_UPDATE, - listener: onTimeUpdate - }); - }); - } - - function makeTimeUpdater() { - var last = 0; - return function (event) { - var currentTime = event.target.currentTime; - if(areTooFarApart(currentTime, last)){ - makeEventSender(TIME_UPDATE)(event); - } - last = currentTime; - }; - } - - function areTooFarApart(currentTime, lastTime) { - var secDiff = Math.abs(currentTime - lastTime); - var milliDiff = secDiff * 1000; - return milliDiff > TOO_FAR_APART; - } - - session.on("close", unsetListeners); - - function unsetListeners() { - var videos = $('video'); - listeners.forEach(function (event) { - videos.off(event.name, event.listener); - }); - listeners = []; - } - - - session.hub.on('video-timeupdate', function (msg) { - var element = $findElement(msg.location); - var oldTime = element.prop('currentTime'); - var newTime = msg.position; - - //to help throttle uneccesary position changes - if(areTooFarApart(oldTime, newTime)){ - setTime(element, msg.position); - } - }); - - MIRRORED_EVENTS.forEach( function (eventName) { - session.hub.on("video-"+eventName, function (msg) { - var element = $findElement(msg.location); - - setTime(element, msg.position); - - element.trigger(eventName, {silent: true}); - }); - }); - - //Currently does not discriminate between visible and invisible videos - function $findElement(location) { - return $(elementFinder.findElement(location)); - } - - function setTime(video, time) { - video.prop('currentTime', time); - } - -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('walkthrough',["util", "ui", "jquery", "windowing", "templates", "templating", "session", "peers"], function (util, ui, $, windowing, templates, templating, session, peers) { - var assert = util.assert; - var walkthrough = util.Module("walkthrough"); - var onHideAll = null; - var container = null; - - var slides = null; - - walkthrough.start = function (firstTime, doneCallback) { - if (! container) { - container = $(templates.walkthrough); - container.hide(); - ui.container.append(container); - slides = container.find(".togetherjs-walkthrough-slide"); - slides.hide(); - var progress = $("#togetherjs-walkthrough-progress"); - slides.each(function (index) { - var bullet = templating.sub("walkthrough-slide-progress"); - progress.append(bullet); - bullet.click(function () { - show(index); - }); - }); - container.find("#togetherjs-walkthrough-previous").click(previous); - container.find("#togetherjs-walkthrough-next").click(next); - ui.prepareShareLink(container); - container.find(".togetherjs-self-name").bind("keyup", function (event) { - var val = $(event.target).val(); - peers.Self.update({name: val}); - }); - container.find(".togetherjs-swatch").click(function () { - var picker = $("#togetherjs-pick-color"); - if (picker.is(":visible")) { - picker.hide(); - return; - } - picker.show(); - picker.find(".togetherjs-swatch-active").removeClass("togetherjs-swatch-active"); - picker.find(".togetherjs-swatch[data-color=\"" + peers.Self.color + "\"]").addClass("togetherjs-swatch-active"); - var location = container.find(".togetherjs-swatch").offset(); - picker.css({ - top: location.top, - // The -7 comes out of thin air, but puts it in the right place: - left: location.left-7 - }); - }); - if (session.isClient) { - container.find(".togetherjs-if-creator").remove(); - container.find(".togetherjs-ifnot-creator").show(); - } else { - container.find(".togetherjs-if-creator").show(); - container.find(".togetherjs-ifnot-creator").remove(); - } - TogetherJS.config.track("siteName", function (value) { - value = value || document.title; - container.find(".togetherjs-site-name").text(value); - }); - ui.activateAvatarEdit(container, { - onSave: function () { - container.find("#togetherjs-avatar-when-saved").show(); - container.find("#togetherjs-avatar-when-unsaved").hide(); - }, - onPending: function () { - container.find("#togetherjs-avatar-when-saved").hide(); - container.find("#togetherjs-avatar-when-unsaved").show(); - } - }); - // This triggers substititions in the walkthrough: - peers.Self.update({}); - session.emit("new-element", container); - } - assert(typeof firstTime == "boolean", "You must provide a firstTime boolean parameter"); - if (firstTime) { - container.find(".togetherjs-walkthrough-firsttime").show(); - container.find(".togetherjs-walkthrough-not-firsttime").hide(); - } else { - container.find(".togetherjs-walkthrough-firsttime").hide(); - container.find(".togetherjs-walkthrough-not-firsttime").show(); - } - onHideAll = doneCallback; - show(0); - windowing.show(container); - }; - - function show(index) { - slides.hide(); - $(slides[index]).show(); - var bullets = container.find("#togetherjs-walkthrough-progress .togetherjs-walkthrough-slide-progress"); - bullets.removeClass("togetherjs-active"); - $(bullets[index]).addClass("togetherjs-active"); - var $next = $("#togetherjs-walkthrough-next").removeClass("togetherjs-disabled"); - var $previous = $("#togetherjs-walkthrough-previous").removeClass("togetherjs-disabled"); - if (index == slides.length - 1) { - $next.addClass("togetherjs-disabled"); - } else if (index === 0) { - $previous.addClass("togetherjs-disabled"); - } - } - - function previous() { - var index = getIndex(); - index--; - if (index < 0) { - index = 0; - } - show(index); - } - - function next() { - var index = getIndex(); - index++; - if (index >= slides.length) { - index = slides.length-1; - } - show(index); - } - - function getIndex() { - var active = slides.filter(":visible"); - if (! active.length) { - return 0; - } - for (var i=0; i"); - $canvas[0].height = session.AVATAR_SIZE; - $canvas[0].width = session.AVATAR_SIZE; - var context = $canvas[0].getContext("2d"); - context.arc(session.AVATAR_SIZE/2, session.AVATAR_SIZE/2, session.AVATAR_SIZE/2, 0, Math.PI*2); - context.closePath(); - context.clip(); - context.drawImage($video[0], (session.AVATAR_SIZE - width) / 2, 0, width, height); - savePicture($canvas[0].toDataURL("image/png")); - } - - $upload.on("change", function () { - var reader = new FileReader(); - reader.onload = function () { - // FIXME: I don't actually know it's JPEG, but it's probably a - // good enough guess: - var url = "data:image/jpeg;base64," + util.blobToBase64(this.result); - convertImage(url, function (result) { - savePicture(result); - }); - }; - reader.onerror = function () { - console.error("Error reading file:", this.error); - }; - reader.readAsArrayBuffer(this.files[0]); - }); - - function convertImage(imageUrl, callback) { - var $canvas = $(""); - $canvas[0].height = session.AVATAR_SIZE; - $canvas[0].width = session.AVATAR_SIZE; - var context = $canvas[0].getContext("2d"); - var img = new Image(); - img.src = imageUrl; - // Sometimes the DOM updates immediately to call - // naturalWidth/etc, and sometimes it doesn't; using setTimeout - // gives it a chance to catch up - setTimeout(function () { - var width = img.naturalWidth || img.width; - var height = img.naturalHeight || img.height; - width = width * (session.AVATAR_SIZE / height); - height = session.AVATAR_SIZE; - context.drawImage(img, 0, 0, width, height); - callback($canvas[0].toDataURL("image/png")); - }); - } - - }); - - /**************************************** - * RTC support - */ - - function audioButton(selector) { - ui.displayToggle(selector); - if (selector == "#togetherjs-audio-incoming") { - $("#togetherjs-audio-button").addClass("togetherjs-animated").addClass("togetherjs-color-alert"); - } else { - $("#togetherjs-audio-button").removeClass("togetherjs-animated").removeClass("togetherjs-color-alert"); - } - } - - session.on("ui-ready", function () { - $("#togetherjs-audio-button").click(function () { - if ($("#togetherjs-rtc-info").is(":visible")) { - windowing.hide(); - return; - } - if (session.RTCSupported) { - enableAudio(); - } else { - windowing.show("#togetherjs-rtc-not-supported"); - } - }); - - if (! session.RTCSupported) { - audioButton("#togetherjs-audio-unavailable"); - return; - } - audioButton("#togetherjs-audio-ready"); - - var audioStream = null; - var accepted = false; - var connected = false; - var $audio = $("#togetherjs-audio-element"); - var offerSent = null; - var offerReceived = null; - var offerDescription = false; - var answerSent = null; - var answerReceived = null; - var answerDescription = false; - var _connection = null; - var iceCandidate = null; - - function enableAudio() { - accepted = true; - storage.settings.get("dontShowRtcInfo").then(function (dontShow) { - if (! dontShow) { - windowing.show("#togetherjs-rtc-info"); - } - }); - if (! audioStream) { - startStreaming(connect); - return; - } - if (! connected) { - connect(); - } - toggleMute(); - } - - ui.container.find("#togetherjs-rtc-info .togetherjs-dont-show-again").change(function () { - storage.settings.set("dontShowRtcInfo", this.checked); - }); - - function error() { - console.warn.apply(console, arguments); - var s = ""; - for (var i=0; i= expected) { - close(); - } else { - def.notify(users); - } - } - } - console.log("users", users); - }; - channel.send({ - type: "who", - "server-echo": true, - clientId: null - }); - var timeout = setTimeout(function () { - close(); - }, MAX_RESPONSE_TIME); - function close() { - if (timeout) { - clearTimeout(timeout); - } - if (lateResponseTimeout) { - clearTimeout(lateResponseTimeout); - } - channel.close(); - def.resolve(users); - } - }); - }; - - who.invite = function (hubUrl, clientId) { - return util.Deferred(function (def) { - var channel = channels.WebSocketChannel(hubUrl); - var id = util.generateId(); - channel.onmessage = function (msg) { - if (msg.type == "invite" && msg.inviteId == id) { - channel.close(); - def.resolve(); - } - }; - var userInfo = session.makeHelloMessage(false); - delete userInfo.type; - userInfo.clientId = session.clientId; - channel.send({ - type: "invite", - inviteId: id, - url: session.shareUrl(), - userInfo: userInfo, - forClientId: clientId, - clientId: null, - "server-echo": true - }); - }); - }; - - who.ExternalPeer = util.Class({ - isSelf: false, - isExternal: true, - constructor: function (id, attrs) { - attrs = attrs || {}; - assert(id); - this.id = id; - this.identityId = attrs.identityId || null; - this.status = attrs.status || "live"; - this.idle = attrs.status || "active"; - this.name = attrs.name || null; - this.avatar = attrs.avatar || null; - this.color = attrs.color || "#00FF00"; - this.lastMessageDate = 0; - this.view = ui.PeerView(this); - }, - - className: function (prefix) { - prefix = prefix || ""; - return prefix + util.safeClassName(this.id); - } - - }); - - return who; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http:// mozilla.org/MPL/2.0/. */ - -define('youtubeVideos',["jquery", "util", "session", "elementFinder"], -function ($, util, session, elementFinder) { - - // constant var to indicate whether two players are too far apart in sync - var TOO_FAR_APART = 3000; - // embedded youtube iframes - var youTubeIframes = []; - // youtube API load delay - var API_LOADING_DELAY = 2000; - - session.on("reinitialize", function () { - if (TogetherJS.config.get("youtube")) { - prepareYouTube(); - } - }); - - session.on("close", function () { - $(youTubeIframes).each(function (i, iframe) { - // detach players from iframes - $(iframe).removeData("togetherjs-player"); - $(iframe).removeData("dontPublish"); - $(iframe).removeData("currentVideoId"); - // disable iframeAPI - $(iframe).removeAttr("enablejsapi"); - // remove unique youtube iframe indicators - var id = $(iframe).attr("id") || ""; - if (id.indexOf("youtube-player") === 0) { - // An id we added - $(iframe).removeAttr("id"); - } - youTubeIframes = []; - }); - }); - - TogetherJS.config.track("youtube", function (track, previous) { - if (track && ! previous) { - prepareYouTube(); - // You can enable youtube dynamically, but can't turn it off: - TogetherJS.config.close("youtube"); - } - }); - - function prepareYouTube() { - // setup iframes first - setupYouTubeIframes(); - - // this function should be global so it can be called when API is loaded - window.onYouTubeIframeAPIReady = function() { - // YouTube API is ready - $(youTubeIframes).each(function (i, iframe) { - var player = new YT.Player(iframe.id, { // get the reference to the already existing iframe - events: { - 'onReady': insertPlayer, - 'onStateChange': publishPlayerStateChange - } - }); - }); - }; - - if (window.YT === undefined) { - // load necessary API - // it calls onYouTubeIframeAPIReady automatically when the API finishes loading - var tag = document.createElement('script'); - tag.src = "https://www.youtube.com/iframe_api"; - var firstScriptTag = document.getElementsByTagName('script')[0]; - firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); - } else { - // manually invoke APIReady function when the API was already loaded by user - onYouTubeIframeAPIReady(); - } - - // give each youtube iframe a unique id and set its enablejsapi param to true - function setupYouTubeIframes() { - var iframes = $('iframe'); - iframes.each(function (i, iframe) { - // if the iframe's unique id is already set, skip it - // FIXME: what if the user manually sets an iframe's id (i.e. "#my-youtube")? - // maybe we should set iframes everytime togetherjs is reinitialized? - if (($(iframe).attr("src") || "").indexOf("youtube") != -1 && !$(iframe).attr("id")) { - $(iframe).attr("id", "youtube-player"+i); - $(iframe).attr("enablejsapi", 1); - youTubeIframes[i] = iframe; - } - }); - } // iframes are ready - - function insertPlayer(event) { - // only when it is READY, attach a player to its iframe - var currentPlayer = event.target; - var currentIframe = currentPlayer.a; - // check if a player is already attached in case of being reinitialized - if (!$(currentIframe).data("togetherjs-player")) { - $(currentIframe).data("togetherjs-player", currentPlayer); - // initialize its dontPublish flag as well - $(currentIframe).data("dontPublish", false); - // store its current video's id - var currentVideoId = getVideoIdFromUrl(currentPlayer.getVideoUrl()); - $(currentIframe).data("currentVideoId", currentVideoId); - } - } - } // end of prepareYouTube - - function publishPlayerStateChange(event) { - var target = event.target; - var currentIframe = target.a; - // FIXME: player object retrieved from event.target has an incomplete set of essential functions - // this is most likely due to a recently-introduced problem with current YouTube API as others have been reporting the same issue (12/18/`13) - //var currentPlayer = target; - //var currentTime = currentPlayer.getCurrentTime(); - var currentPlayer = $(currentIframe).data("togetherjs-player"); - var currentTime = target.k.currentTime; - var iframeLocation = elementFinder.elementLocation(currentIframe); - - if ($(currentPlayer).data("seek")) { - $(currentPlayer).removeData("seek"); - return; - } - - // do not publish if playerState was changed by other users - if ($(currentIframe).data("dontPublish")) { - // make it false again so it can start publishing events of its own state changes - $(currentIframe).data("dontPublish", false); - return; - } - - // notify other people that I changed the player state - if (event.data == YT.PlayerState.PLAYING) { - - var currentVideoId = isDifferentVideoLoaded(currentIframe); - if (currentVideoId) { - // notify that I just loaded another video - publishDifferentVideoLoaded(iframeLocation, currentVideoId); - // update current video id - $(currentIframe).data("currentVideoId", currentVideoId); - } else { - session.send({ - type: "playerStateChange", - element: iframeLocation, - playerState: 1, - playerTime: currentTime - }); - } - } else if (event.data == YT.PlayerState.PAUSED) { - session.send({ - type: "playerStateChange", - element: iframeLocation, - playerState: 2, - playerTime: currentTime - }); - } else { - // do nothing when the state is buffering, cued, or ended - return; - } - } - - function publishDifferentVideoLoaded(iframeLocation, videoId) { - session.send({ - type: "differentVideoLoaded", - videoId: videoId, - element: iframeLocation - }); - } - - session.hub.on('playerStateChange', function (msg) { - var iframe = elementFinder.findElement(msg.element); - var player = $(iframe).data("togetherjs-player"); - var currentTime = player.getCurrentTime(); - var currentState = player.getPlayerState(); - - if (currentState != msg.playerState) { - $(iframe).data("dontPublish", true); - } - - if (msg.playerState == 1) { - player.playVideo(); - // seekTo() updates the video's time and plays it if it was already playing - // and pauses it if it was already paused - if (areTooFarApart(currentTime, msg.playerTime)) { - player.seekTo(msg.playerTime, true); - } - } else if (msg.playerState == 2) { - // When YouTube videos are advanced while playing, - // Chrome: pause -> pause -> play (onStateChange is called even when it is from pause to pause) - // FireFox: buffering -> play -> buffering -> play - // We must prevent advanced videos from going out of sync - player.pauseVideo(); - if (areTooFarApart(currentTime, msg.playerTime)) { - // "seek" flag will help supress publishing unwanted state changes - $(player).data("seek", true); - player.seekTo(msg.playerTime, true); - } - } - }); - - // if a late user joins a channel, synchronize his videos - session.hub.on('hello', function () { - // wait a couple seconds to make sure the late user has finished loading API - setTimeout(synchronizeVideosOfLateGuest, API_LOADING_DELAY); - }); - - session.hub.on('synchronizeVideosOfLateGuest', function (msg) { - var iframe = elementFinder.findElement(msg.element); - var player = $(iframe).data("togetherjs-player"); - // check if another video had been loaded to an existing iframe before I joined - var currentVideoId = $(iframe).data("currentVideoId"); - if (msg.videoId != currentVideoId) { - $(iframe).data("currentVideoId", msg.videoId); - player.loadVideoById(msg.videoId, msg.playerTime, 'default'); - } else { - // if the video is only cued, I do not have to do anything to sync - if (msg.playerState != 5) { - player.seekTo(msg.playerTime, true); - } - } - }); - - session.hub.on('differentVideoLoaded', function (msg) { - // load a new video if the host has loaded one - var iframe = elementFinder.findElement(msg.element); - var player = $(iframe).data("togetherjs-player"); - player.loadVideoById(msg.videoId, 0, 'default'); - $(iframe).data("currentVideoId", msg.videoId); - - }); - - function synchronizeVideosOfLateGuest() { - youTubeIframes.forEach(function (iframe) { - var currentPlayer = $(iframe).data("togetherjs-player"); - var currentVideoId = getVideoIdFromUrl(currentPlayer.getVideoUrl()); - var currentState = currentPlayer.getPlayerState(); - var currentTime = currentPlayer.getCurrentTime(); - var iframeLocation = elementFinder.elementLocation(iframe); - session.send({ - type: "synchronizeVideosOfLateGuest", - element: iframeLocation, - videoId: currentVideoId, - playerState: currentState, //this might be necessary later - playerTime: currentTime - }); - }); - } - - function isDifferentVideoLoaded(iframe) { - var lastVideoId = $(iframe).data("currentVideoId"); - var currentPlayer = $(iframe).data("togetherjs-player"); - var currentVideoId = getVideoIdFromUrl(currentPlayer.getVideoUrl()); - - // since url forms of iframe src and player's video url are different, - // I have to compare the video ids - if (currentVideoId != lastVideoId) { - return currentVideoId; - } else { - return false; - } - } - - // parses videoId from the url returned by getVideoUrl function - function getVideoIdFromUrl(videoUrl) { - var videoId = videoUrl.split('v=')[1]; - //Chrome and Firefox have different positions for parameters - var ampersandIndex = videoId.indexOf('&'); - if (ampersandIndex != -1) { - videoId = videoId.substring(0, ampersandIndex); - } - return videoId; - } - - function areTooFarApart(myTime, theirTime) { - var secDiff = Math.abs(myTime - theirTime); - var milliDiff = secDiff * 1000; - return milliDiff > TOO_FAR_APART; - } -}); -TogetherJS.require = TogetherJS._requireObject = require; -TogetherJS._loaded = true; -require(["session"]); -}());"; \ No newline at end of file diff --git a/data/collaborative/shadow/dc103bcc7b8517ba408c3c19eca08b6e b/data/collaborative/shadow/dc103bcc7b8517ba408c3c19eca08b6e deleted file mode 100755 index 034a040..0000000 --- a/data/collaborative/shadow/dc103bcc7b8517ba408c3c19eca08b6e +++ /dev/null @@ -1,175 +0,0 @@ -s:6176:"actives = getJSON('active.php'); - } - - ////////////////////////////////////////////////////////////////// - // List User's Active Files - ////////////////////////////////////////////////////////////////// - - public function ListActive() - { - $active_list = array(); - $tainted = false; - $root = WORKSPACE; - if ($this->actives) { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']==$this->username) { - if ($this->isAbsPath($data['path'])) { - $root = ""; - } else { - $root = $root.'/'; - } - if (file_exists($root.$data['path'])) { - $focused = isset($data['focused']) ? $data['focused'] : false; - $active_list[] = array('path'=>$data['path'], 'focused'=>$focused); - } else { - unset($this->actives[$active]); - $tainted = true; - } - } - } - } - if ($tainted) { - saveJSON('active.php', $this->actives); - } - echo formatJSEND("success", $active_list); - } - - ////////////////////////////////////////////////////////////////// - // Check File - ////////////////////////////////////////////////////////////////// - - public function Check() - { - $cur_users = array(); - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']!=$this->username && $data['path']==$this->path) { - $cur_users[] = $data['username']; - } - } - if (count($cur_users)!=0) { - - //echo formatJSEND("error", "Warning: File ".substr($this->path, strrpos($this->path, "/")+1)." Currently Opened By: " . implode(", ", $cur_users)); - } else { - echo formatJSEND("success"); - } - } - - ////////////////////////////////////////////////////////////////// - // Add File - ////////////////////////////////////////////////////////////////// - - public function Add() - { - $process_add = true; - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']==$this->username && $data['path']==$this->path) { - $process_add = false; - } - } - if ($process_add) { - $this->actives[] = array("username"=>$this->username,"path"=>$this->path); - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - } - - ////////////////////////////////////////////////////////////////// - // Rename File - ////////////////////////////////////////////////////////////////// - - public function Rename() - { - $revised_actives = array(); - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username'])) { - $revised_actives[] = array("username"=>$data['username'],"path"=>str_replace($this->path, $this->new_path, $data['path'])); - } - } - saveJSON('active.php', $revised_actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Remove File - ////////////////////////////////////////////////////////////////// - - public function Remove() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username'] && $this->path==$data['path']) { - unset($this->actives[$active]); - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Remove All Files - ////////////////////////////////////////////////////////////////// - - public function RemoveAll() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username']) { - unset($this->actives[$active]); - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Mark File As Focused - // All other files will be marked as non-focused. - ////////////////////////////////////////////////////////////////// - - public function MarkFileAsFocused() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username']) { - $this->actives[$active]['focused']=false; - if ($this->path==$data['path']) { - $this->actives[$active]['focused']=true; - } - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } -} -"; \ No newline at end of file diff --git a/data/collaborative/shadow/ddd0681a0e90f0480910b3fb7719dde7 b/data/collaborative/shadow/ddd0681a0e90f0480910b3fb7719dde7 deleted file mode 100755 index c34e0d2..0000000 --- a/data/collaborative/shadow/ddd0681a0e90f0480910b3fb7719dde7 +++ /dev/null @@ -1,15 +0,0 @@ -s:174:"* { - box-sizing: border-box; -} - -html{ - font-size: calc(calc(0.5vh + 0.5vw) + 12px); -} - -html, body { - height: 100%; - width: 100%; - padding: 0; - margin: 0; - overflow: hidden; -}"; \ No newline at end of file diff --git a/data/collaborative/shadow/e1726a184e69c885fe27c8669b2c885e b/data/collaborative/shadow/e1726a184e69c885fe27c8669b2c885e deleted file mode 100755 index e054c52..0000000 --- a/data/collaborative/shadow/e1726a184e69c885fe27c8669b2c885e +++ /dev/null @@ -1,773 +0,0 @@ -s:34893:"/* - * Copyright (c) Codiad & Kent Safranski (codiad.com), distributed - * as-is and without warranty under the MIT License. See - * [root]/license.txt for more. This information must remain intact. - */ - -(function(global, $){ - - var codiad = global.codiad; - - $(window) - .load(function() { - codiad.filemanager.init(); - }); - - codiad.filemanager = { - - clipboard: '', - - noOpen: ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'exe', 'zip', 'tar', 'tar.gz'], - noBrowser: ['jpg', 'jpeg', 'png', 'gif', 'bmp'], - - controller: 'components/filemanager/controller.php', - dialog: 'components/filemanager/dialog.php', - dialogUpload: 'components/filemanager/dialog_upload.php', - - init: function() { - // Initialize node listener - this.nodeListener(); - // Load uploader - $.loadScript("components/filemanager/upload_scripts/jquery.ui.widget.js", true); - $.loadScript("components/filemanager/upload_scripts/jquery.iframe-transport.js", true); - $.loadScript("components/filemanager/upload_scripts/jquery.fileupload.js", true); - }, - - ////////////////////////////////////////////////////////////////// - // Listen for dbclick events on nodes - ////////////////////////////////////////////////////////////////// - - nodeListener: function() { - var _this = this; - - $('#file-manager').on('selectstart', false); - - $('#file-manager span') - .live('click', function() { // Open or Expand - if ($(this).parent().children("a").attr('data-type') == 'directory') { - _this.index($(this).parent().children("a") - .attr('data-path')); - } else { - _this.openFile($(this).parent().children("a") - .attr('data-path')); - } - if (!$(this).hasClass('none')) { - if ($(this).hasClass('plus')) { - $(this).removeClass('plus') - $(this).addClass('minus'); - } else { - $(this).removeClass('minus') - $(this).addClass('plus'); - } - } - }); - $('#file-manager a') - .live('dblclick', function() { // Open or Expand - if (!codiad.editor.settings.fileManagerTrigger) { - if ($(this) - .hasClass('directory')) { - _this.index($(this) - .attr('data-path')); - } else { - _this.openFile($(this) - .attr('data-path')); - } - if (!$(this).parent().children("span").hasClass('none')) { - if ($(this).parent().children("span").hasClass('plus')) { - $(this).parent().children("span").removeClass('plus') - $(this).parent().children("span").addClass('minus'); - } else { - $(this).parent().children("span").removeClass('minus') - $(this).parent().children("span").addClass('plus'); - } - } - } - }) - .live('click', function() { // Open or Expand - if (codiad.editor.settings.fileManagerTrigger) { - if ($(this) - .hasClass('directory')) { - _this.index($(this) - .attr('data-path')); - } else { - _this.openFile($(this) - .attr('data-path')); - } - if (!$(this).parent().children("span").hasClass('none')) { - if ($(this).parent().children("span").hasClass('plus')) { - $(this).parent().children("span").removeClass('plus') - $(this).parent().children("span").addClass('minus'); - } else { - $(this).parent().children("span").removeClass('minus') - $(this).parent().children("span").addClass('plus'); - } - } - } - }) - .live("contextmenu", function(e) { // Context Menu - e.preventDefault(); - _this.contextMenuShow(e, $(this) - .attr('data-path'), $(this) - .attr('data-type'), $(this) - .html()); - $(this) - .addClass('context-menu-active'); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Context Menu - ////////////////////////////////////////////////////////////////// - - contextMenuShow: function(e, path, type, name) { - var _this = this; - - // Selective options - switch (type) { - case 'directory': - $('#context-menu .directory-only, #context-menu .non-root') - .show(); - $('#context-menu .file-only, #context-menu .root-only') - .hide(); - break; - case 'file': - $('#context-menu .directory-only, #context-menu .root-only') - .hide(); - $('#context-menu .file-only,#context-menu .non-root') - .show(); - break; - case 'root': - $('#context-menu .directory-only, #context-menu .root-only') - .show(); - $('#context-menu .non-root, #context-menu .file-only') - .hide(); - break; - } - if(codiad.project.isAbsPath($('#file-manager a[data-type="root"]').attr('data-path'))) { - $('#context-menu .no-external').hide(); - } else { - $('#context-menu .no-external').show(); - } - // Show menu - var top = e.pageY; - if (top > $(window).height() - $('#context-menu').height()) { - top -= $('#context-menu').height(); - } - if (top < 10) { - top = 10; - } - var max = $(window).height() - top - 10; - - $('#context-menu') - .css({ - 'top': top + 'px', - 'left': e.pageX + 'px', - 'max-height': max + 'px' - }) - .fadeIn(200) - .attr('data-path', path) - .attr('data-type', type) - .attr('data-name', name); - // Show faded 'paste' if nothing in clipboard - if (this.clipboard === '') { - $('#context-menu a[content="Paste"]') - .addClass('disabled'); - } else { - $('#context-menu a[data-action="paste"]') - .removeClass('disabled'); - } - // Hide menu - $('#file-manager, #editor-region') - .on('mouseover', function() { - _this.contextMenuHide(); - }); - /* Notify listeners. */ - amplify.publish('context-menu.onShow', {e: e, path: path, type: type}); - // Hide on click - $('#context-menu a') - .click(function() { - _this.contextMenuHide(); - }); - }, - - contextMenuHide: function() { - $('#context-menu') - .fadeOut(200); - $('#file-manager a') - .removeClass('context-menu-active'); - /* Notify listeners. */ - amplify.publish('context-menu.onHide'); - }, - - ////////////////////////////////////////////////////////////////// - // Return the node name (sans path) - ////////////////////////////////////////////////////////////////// - - getShortName: function(path) { - return path.split('/') - .pop(); - }, - - ////////////////////////////////////////////////////////////////// - // Return extension - ////////////////////////////////////////////////////////////////// - - getExtension: function(path) { - return path.split('.') - .pop(); - }, - - ////////////////////////////////////////////////////////////////// - // Return type - ////////////////////////////////////////////////////////////////// - - getType: function(path) { - return $('#file-manager a[data-path="' + path + '"]') - .attr('data-type'); - }, - - ////////////////////////////////////////////////////////////////// - // Create node in file tree - ////////////////////////////////////////////////////////////////// - - createObject: function(parent, path, type) { - // NODE FORMAT:
  • {short_name}
  • - var parentNode = $('#file-manager a[data-path="' + parent + '"]'); - if (!$('#file-manager a[data-path="' + path + '"]') - .length) { // Doesn't already exist - if (parentNode.hasClass('open') && parentNode.hasClass('directory')) { // Only append node if parent is open (and a directory) - var shortName = this.getShortName(path); - if (type == 'directory') { - var appendage = '
  • ' + shortName + '
  • '; - } else { - var appendage = '
  • ' + shortName + '
  • '; - } - if (parentNode.siblings('ul') - .length) { // UL exists, other children to play with - parentNode.siblings('ul') - .append(appendage); - } else { - $('
      ' + appendage + '
    ') - .insertAfter(parentNode); - } - } else { - parentNode.parent().children('span').removeClass('none'); - parentNode.parent().children('span').addClass('plus'); - } - } - }, - - ////////////////////////////////////////////////////////////////// - // Loop out all files and folders in directory path - ////////////////////////////////////////////////////////////////// - - indexFiles: [], - - index: function(path, rescan) { - var _this = this; - if (rescan === undefined) { - rescan = false; - } - node = $('#file-manager a[data-path="' + path + '"]'); - if (node.hasClass('open') && !rescan) { - node.parent('li') - .children('ul') - .slideUp(300, function() { - $(this) - .remove(); - node.removeClass('open'); - }); - } else { - node.addClass('loading'); - $.get(this.controller + '?action=index&path=' + encodeURIComponent(path), function(data) { - node.addClass('open'); - var objectsResponse = codiad.jsend.parse(data); - if (objectsResponse != 'error') { - /* Notify listener */ - _this.indexFiles = objectsResponse.index; - amplify.publish("filemanager.onIndex", {path: path, files: _this.indexFiles}); - var files = _this.indexFiles; - if (files.length > 0) { - if (node.parent().children('span').hasClass('plus')) { - node.parent().children('span').removeClass('plus').addClass('minus'); - } - var display = 'display:none;'; - if (rescan) { - display = ''; - } - var appendage = '
      '; - $.each(files, function(index) { - var ext = ''; - var name = files[index].name.replace(path, ''); - var nodeClass = 'none'; - name = name.split('/') - .join(' '); - if (files[index].type == 'file') { - var ext = ' ext-' + name.split('.') - .pop(); - } - if(files[index].type == 'directory' && files[index].size > 0) { - nodeClass = 'plus'; - } - appendage += '
    • ' + name + '
    • '; - }); - appendage += '
    '; - if (rescan) { - node.parent('li') - .children('ul') - .remove(); - } - $(appendage) - .insertAfter(node); - if (!rescan) { - node.siblings('ul') - .slideDown(300); - } - } - } - node.removeClass('loading'); - if (rescan && _this.rescanChildren.length > _this.rescanCounter) { - _this.rescan(_this.rescanChildren[_this.rescanCounter++]); - } else { - _this.rescanChildren = []; - _this.rescanCounter = 0; - } - }); - } - }, - - rescanChildren: [], - - rescanCounter: 0, - - rescan: function(path) { - var _this = this; - if (this.rescanCounter === 0) { - // Create array of open directories - node = $('#file-manager a[data-path="' + path + '"]'); - node.parent() - .find('a.open') - .each(function() { - _this.rescanChildren.push($(this) - .attr('data-path')); - }); - } - - this.index(path, true); - }, - - ////////////////////////////////////////////////////////////////// - // Open File - ////////////////////////////////////////////////////////////////// - - openFile: function(path, focus) { - if (focus === undefined) { - focus = true; - } - var node = $('#file-manager a[data-path="' + path + '"]'); - var ext = this.getExtension(path); - if ($.inArray(ext.toLowerCase(), this.noOpen) < 0) { - node.addClass('loading'); - $.get(this.controller + '?action=open&path=' + encodeURIComponent(path), function(data) { - var openResponse = codiad.jsend.parse(data); - if (openResponse != 'error') { - node.removeClass('loading'); - codiad.active.open(path, openResponse.content, openResponse.mtime, false, focus); - } - }); - } else { - if(!codiad.project.isAbsPath(path)) { - if ($.inArray(ext.toLowerCase(), this.noBrowser) < 0) { - this.download(path); - } else { - this.openInModal(path); - } - } else { - codiad.message.error(i18n('Unable to open file in Browser')); - } - } - }, - - ////////////////////////////////////////////////////////////////// - // Open in browser - ////////////////////////////////////////////////////////////////// - - openInBrowser: function(path) { - $.ajax({ - url: this.controller + '?action=open_in_browser&path=' + encodeURIComponent(path), - success: function(data) { - var openIBResponse = codiad.jsend.parse(data); - if (openIBResponse != 'error') { - window.open(openIBResponse.url, '_newtab'); - } - }, - async: false - }); - }, - openInModal: function(path) { - codiad.modal.load(250, this.dialog, { - action: 'preview', - path: path - }); - }, - saveModifications: function(path, data, callbacks, save=true){ - callbacks = callbacks || {}; - var _this = this, action, data; - var notifySaveErr = function() { - codiad.message.error(i18n('File could not be saved')); - if (typeof callbacks.error === 'function') { - var context = callbacks.context || _this; - callbacks.error.apply(context, [data]); - } - } - $.post(this.controller + '?action=modify&path=' + encodeURIComponent(path), data, function(resp){ - resp = $.parseJSON(resp); - if (resp.status == 'success') { - if ( save === true ) { - codiad.message.success(i18n('File saved')); - } - if (typeof callbacks.success === 'function'){ - var context = callbacks.context || _this; - callbacks.success.call(context, resp.data.mtime); - } - } else { - if (resp.message == 'Client is out of sync'){ - var reload = confirm( - "Server has a more updated copy of the file. Would "+ - "you like to refresh the contents ? Pressing no will "+ - "cause your changes to override the server's copy upon "+ - "next save." - ); - if (reload) { - codiad.active.close(path); - codiad.active.removeDraft(path); - _this.openFile(path); - } else { - var session = codiad.editor.getActive().getSession(); - session.serverMTime = null; - session.untainted = null; - } - } else codiad.message.error(i18n('File could not be saved')); - if (typeof callbacks.error === 'function') { - var context = callbacks.context || _this; - callbacks.error.apply(context, [resp.data]); - } - } - }).error(notifySaveErr); - }, - ////////////////////////////////////////////////////////////////// - // Save file - ////////////////////////////////////////////////////////////////// - - saveFile: function(path, content, callbacks, save=true) { - this.saveModifications(path, {content: content}, callbacks, save); - }, - - savePatch: function(path, patch, mtime, callbacks) { - if (patch.length > 0) - this.saveModifications(path, {patch: patch, mtime: mtime}, callbacks); - else if (typeof callbacks.success === 'function'){ - var context = callbacks.context || this; - callbacks.success.call(context, mtime); - } - }, - - ////////////////////////////////////////////////////////////////// - // Create Object - ////////////////////////////////////////////////////////////////// - - createNode: function(path, type) { - codiad.modal.load(250, this.dialog, { - action: 'create', - type: type, - path: path - }); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - var shortName = $('#modal-content form input[name="object_name"]') - .val(); - var path = $('#modal-content form input[name="path"]') - .val(); - var type = $('#modal-content form input[name="type"]') - .val(); - var createPath = path + '/' + shortName; - $.get(codiad.filemanager.controller + '?action=create&path=' + encodeURIComponent(createPath) + '&type=' + type, function(data) { - var createResponse = codiad.jsend.parse(data); - if (createResponse != 'error') { - codiad.message.success(type.charAt(0) - .toUpperCase() + type.slice(1) + ' Created'); - codiad.modal.unload(); - // Add new element to filemanager screen - codiad.filemanager.createObject(path, createPath, type); - if(type == 'file') { - codiad.filemanager.openFile(createPath, true); - } - /* Notify listeners. */ - amplify.publish('filemanager.onCreate', {createPath: createPath, path: path, shortName: shortName, type: type}); - } - }); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Copy to Clipboard - ////////////////////////////////////////////////////////////////// - - copyNode: function(path) { - this.clipboard = path; - codiad.message.success(i18n('Copied to Clipboard')); - }, - - ////////////////////////////////////////////////////////////////// - // Paste - ////////////////////////////////////////////////////////////////// - - pasteNode: function(path) { - var _this = this; - if (this.clipboard == '') { - codiad.message.error(i18n('Nothing in Your Clipboard')); - } else if (path == this.clipboard) { - codiad.message.error(i18n('Cannot Paste Directory Into Itself')); - } else { - var shortName = _this.getShortName(_this.clipboard); - if ($('#file-manager a[data-path="' + path + '/' + shortName + '"]') - .length) { // Confirm overwrite? - codiad.modal.load(400, this.dialog, { - action: 'overwrite', - path: path + '/' + shortName - }); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - var duplicate = false; - if($('#modal-content form select[name="or_action"]').val()==1){ - duplicate=true; console.log('Dup!'); - } - _this.processPasteNode(path,duplicate); - }); - } else { // No conflicts; proceed... - _this.processPasteNode(path,false); - } - } - }, - - processPasteNode: function(path,duplicate) { - var _this = this; - var shortName = this.getShortName(this.clipboard); - var type = this.getType(this.clipboard); - if(duplicate){ - shortName = "copy_of_"+shortName; - } - $.get(this.controller + '?action=duplicate&path=' + - encodeURIComponent(this.clipboard) + '&destination=' + - encodeURIComponent(path + '/' + shortName), function(data) { - var pasteResponse = codiad.jsend.parse(data); - if (pasteResponse != 'error') { - _this.createObject(path, path + '/' + shortName, type); - codiad.modal.unload(); - /* Notify listeners. */ - amplify.publish('filemanager.onPaste', {path: path, shortName: shortName, duplicate: duplicate}); - } - }); - }, - - ////////////////////////////////////////////////////////////////// - // Rename - ////////////////////////////////////////////////////////////////// - - renameNode: function(path) { - var shortName = this.getShortName(path); - var type = this.getType(path); - var _this = this; - codiad.modal.load(250, this.dialog, { action: 'rename', path: path, short_name: shortName, type: type}); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - var newName = $('#modal-content form input[name="object_name"]') - .val(); - // Build new path - var arr = path.split('/'); - var temp = new Array(); - for (i = 0; i < arr.length - 1; i++) { - temp.push(arr[i]) - } - var newPath = temp.join('/') + '/' + newName; - $.get(_this.controller, { action: 'modify', path: path, new_name: newName} , function(data) { - var renameResponse = codiad.jsend.parse(data); - if (renameResponse != 'error') { - codiad.message.success(type.charAt(0) - .toUpperCase() + type.slice(1) + ' Renamed'); - var node = $('#file-manager a[data-path="' + path + '"]'); - // Change pathing and name for node - node.attr('data-path', newPath) - .html(newName); - if (type == 'file') { // Change icons for file - curExtClass = 'ext-' + _this.getExtension(path); - newExtClass = 'ext-' + _this.getExtension(newPath); - $('#file-manager a[data-path="' + newPath + '"]') - .removeClass(curExtClass) - .addClass(newExtClass); - } else { // Change pathing on any sub-files/directories - _this.repathSubs(path, newPath); - } - // Change any active files - codiad.active.rename(path, newPath); - codiad.modal.unload(); - } - }); - }); - }, - - repathSubs: function(oldPath, newPath) { - $('#file-manager a[data-path="' + newPath + '"]') - .siblings('ul') - .find('a') - .each(function() { - // Hit the children, hit 'em hard - var curPath = $(this) - .attr('data-path'); - var revisedPath = curPath.replace(oldPath, newPath); - $(this) - .attr('data-path', revisedPath); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Delete - ////////////////////////////////////////////////////////////////// - - deleteNode: function(path) { - var _this = this; - codiad.modal.load(400, this.dialog, { - action: 'delete', - path: path - }); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - $.get(_this.controller + '?action=delete&path=' + encodeURIComponent(path), function(data) { - var deleteResponse = codiad.jsend.parse(data); - if (deleteResponse != 'error') { - var node = $('#file-manager a[data-path="' + path + '"]'); - node.parent('li') - .remove(); - // Close any active files - $('#active-files a') - .each(function() { - var curPath = $(this) - .attr('data-path'); - if (curPath.indexOf(path) == 0) { - codiad.active.remove(curPath); - } - }); - } - codiad.modal.unload(); - }); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Search - ////////////////////////////////////////////////////////////////// - - search: function(path) { - codiad.modal.load(500, this.dialog,{ - action: 'search', - path: path - }); - codiad.modal.load_process.done( function() { - var lastSearched = JSON.parse(localStorage.getItem("lastSearched")); - if(lastSearched) { - $('#modal-content form input[name="search_string"]').val(lastSearched.searchText); - $('#modal-content form input[name="search_file_type"]').val(lastSearched.fileExtension); - $('#modal-content form select[name="search_type"]').val(lastSearched.searchType); - if(lastSearched.searchResults != '') { - $('#filemanager-search-results').slideDown().html(lastSearched.searchResults); - } - } - }); - codiad.modal.hideOverlay(); - var _this = this; - $('#modal-content form') - .live('submit', function(e) { - $('#filemanager-search-processing') - .show(); - e.preventDefault(); - searchString = $('#modal-content form input[name="search_string"]') - .val(); - fileExtensions=$('#modal-content form input[name="search_file_type"]') - .val(); - searchFileType=$.trim(fileExtensions); - if (searchFileType != '') { - //season the string to use in find command - searchFileType = "\\(" + searchFileType.replace(/\s+/g, "\\|") + "\\)"; - } - searchType = $('#modal-content form select[name="search_type"]') - .val(); - $.post(_this.controller + '?action=search&path=' + encodeURIComponent(path) + '&type=' + searchType, { - search_string: searchString, - search_file_type: searchFileType - }, function(data) { - searchResponse = codiad.jsend.parse(data); - var results = ''; - if (searchResponse != 'error') { - $.each(searchResponse.index, function(key, val) { - // Cleanup file format - if(val['file'].substr(-1) == '/') { - val['file'] = val['file'].substr(0, str.length - 1); - } - val['file'] = val['file'].replace('//','/'); - // Add result - results += ''; - }); - $('#filemanager-search-results') - .slideDown() - .html(results); - } else { - $('#filemanager-search-results') - .slideUp(); - } - _this.saveSearchResults(searchString, searchType, fileExtensions, results); - $('#filemanager-search-processing') - .hide(); - }); - }); - }, - - ///////////////////////////////////////////////////////////////// - // saveSearchResults - ///////////////////////////////////////////////////////////////// - saveSearchResults: function(searchText, searchType, fileExtensions, searchResults) { - var lastSearched = { - searchText: searchText, - searchType: searchType, - fileExtension: fileExtensions, - searchResults: searchResults - }; - localStorage.setItem("lastSearched", JSON.stringify(lastSearched)); - }, - ////////////////////////////////////////////////////////////////// - // Upload - ////////////////////////////////////////////////////////////////// - - uploadToNode: function(path) { - codiad.modal.load(500, this.dialogUpload, {path: path}); - }, - - ////////////////////////////////////////////////////////////////// - // Download - ////////////////////////////////////////////////////////////////// - - download: function(path) { - var type = this.getType(path); - $('#download') - .attr('src', 'components/filemanager/download.php?path=' + encodeURIComponent(path) + '&type=' + type); - } - }; - -})(this, jQuery); -"; \ No newline at end of file diff --git a/data/collaborative/shadow/e1ea49c66882f7882bfc53f7f896d31d b/data/collaborative/shadow/e1ea49c66882f7882bfc53f7f896d31d deleted file mode 100755 index 2bfe8b7..0000000 --- a/data/collaborative/shadow/e1ea49c66882f7882bfc53f7f896d31d +++ /dev/null @@ -1,7 +0,0 @@ -s:126:"[{ - "author": "Isaac Brown", - "version": "1.0.0", - "name": "Tela Auto Save", - "url": "https://telaaedifex.com" -}] -"; \ No newline at end of file diff --git a/data/collaborative/shadow/e2630975cd26f1f4330486f3d0a9055e b/data/collaborative/shadow/e2630975cd26f1f4330486f3d0a9055e deleted file mode 100755 index 659594c..0000000 --- a/data/collaborative/shadow/e2630975cd26f1f4330486f3d0a9055e +++ /dev/null @@ -1,576 +0,0 @@ -s:22926:"/** - Author: Abbas Abdulmalik - Created: ~ May, 2017 - Revised: June 9, 2018 - Original Filename: L.js - Purpose: a small (but growing) personal re-usable js library for a simple MVC architecture - Notes: Now qualifyFunction helper doesn't return true for empty arrays (no vacuous truth) - - Added UploadFiles: - uploadFiles takes a callback -- progressReporter-- as it FIRST argument (parameter) - to allow for an optional fourth parameter of an upload path for the server. - progressReporter will be passed three arguments when called: - 1.) the amount of bytes uploaded so far - 2.) the total size of the file in bytes - 3.) the index of the file in the "array" of files being uploaded - - Added sortByExtension that alphabetizes an array of strings 'in place' by filename extension - Added arrayStringMatch that matches a collection of string arrays to a search string. - later (6-9-2018) included an option for a "maximum array index" to eliminate - searching irrelevant fields at the end of the array, such as image name and primary key. - Added loopCall as a 'better' version of setInterval - Removed L.attributes. It's a reserved word: an object belonging to DOM elements - Now it uses L.attribs - Added L.loopCall.stop() so that user can easily stop L.loopCall - Added L.symDiff for comparing arrays to determine their symmetric difference = conjunctive union = - exclusive-or - Restored an updated version of uploadFiles that signals the final file has uploaded - Added secToMinSec - Added runQualifiedFunctions that mirrors runQualifiedMethods using different parameters, - namely: functionQualifiers, model, view, controller - Added attachNewElement(tagname, id, view). Create new element, gives it an id and - attaches it to object provided: - L.attachNewElement(`div`, `picHolder`, view) - Added createListMixer and scrammbleThis, which depends on createListMixer - Added sortArrayOfStringArrays, with option of using a "link token" of choice as the 3rd argument - Added an optional argument for arrayStringMatch for a maximum array index - to eliminate searching irrelevant fields at the end of the array, - such as image name and primary key -*/ - -var L = {} -L.styles = function(styleString){ - const colonPosition = styleString.indexOf(':') - const property = styleString.slice(0, colonPosition) - const value = styleString.slice(colonPosition + 1) - this.style[property] = value - - return this.styles -} - -L.attribs = function(attributeString){ - const assignmentPosition = attributeString.indexOf('=') - const attribute = attributeString.slice(0, assignmentPosition) - const value = attributeString.slice(assignmentPosition + 1) - this.setAttribute(attribute, value) - - return this.attribs -} - -L.attachAllElementsById = function(here){ - let allElements = document.getElementsByTagName('*') - let array = [] - array.forEach.call(allElements, function(element) { - if(element.id){ - here[element.id] = element - element.styles = L.styles.bind(element) // attach L's styles() method here - element.attribs = L.attribs.bind(element) // attach L's attribs() method here - } - }) -} -///////////////| START of L.attachNewElement |///////////// -/** - L.attachNewElement(string tagname, string id, object view) ... - ... creates a new element of type "tagname" given as the first argument, - and gives it the id "id" given as the second argument. - The third argument is the view object where this new reference will be attached. - The element can then be referenced as view.id. -*/ -L.attachNewElement = function(tagname, id, view){ - if(arguments.length !== 3){ - console.log(`Error: requires 3 arguments: tagname, id, view`) - return - } - try{ - if(typeof tagname === `string`){ - var newElement = document.createElement(tagname) - } - else{ - console.log(`Error: tagname needs to be a string`) - return - } - if(typeof id === `string`){ - newElement.id = id - } - else{ - console.log(`Error: id needs to be a string`) - return - } - if(view.toString() === `[object Object]`){ - view[newElement.id] = newElement - newElement.styles = L.styles.bind(newElement) // attach L's styles() method here - newElement.attribs = L.attribs.bind(newElement) // attach L's attribs() method here - return newElement - } - else{ - console.log(`Error: view needs to be an object`) - return - } - } - catch(e){ - console.log(`Error in L.attachNewElement: ${e}`) - return - } -} -///////////////| END of L.attachNewElement |///////////// - -L.noPinchZoom = function(){ - window.ontouchstart = function(eventObject){ - if(eventObject.touches && eventObject.touches.length > 1){ - eventObject.preventDefault(); - } - } -} - -L.runQualifiedMethods = function(functionQualifiers, object, runNextUpdate){ - Object - .keys(functionQualifiers) - .filter(qualifyFunction) - .forEach(runFunction) - if(typeof runNextUpdate === 'function'){runNextUpdate()} - - //-----| helpers |-----// - function qualifyFunction(functionName){ - const isQualified = functionQualifiers[functionName].every( qualifier => qualifier) && - !!functionQualifiers[functionName].length - return isQualified - } - function runFunction(functionName){ - if(typeof object[functionName] === 'function'){ - object[functionName]() - } - - /** - If the prefix of this function's name is 'set' (for updating the MODEL), - and there is a similarly named function with a prefix of 'show' (for updating the VIEW), - then run the 'show' version as well. - */ - let prefix = functionName.slice(0,3) - let newFunctionName = 'show' + functionName.slice(3) - - if(prefix === 'set' && typeof object[newFunctionName] === 'function'){ - object[newFunctionName]() - } - } -} - -L.runQualifiedFunctions = function(functionQualifiers, model, view, controller){ - Object - .keys(functionQualifiers) - .filter(qualifyFunction) - .forEach(runFunction) - //-----| helpers |-----// - function qualifyFunction(functionName){ - const isQualified = functionQualifiers[functionName].every( qualifier => qualifier) && - !!functionQualifiers[functionName].length - return isQualified - } - function runFunction(functionName){ - if(typeof controller[functionName] === 'function'){ - controller[functionName](model) - } - /** - If the prefix of this function's name is 'set' (for updating the MODEL), - and there is a similarly named function with a prefix of 'show' (for updating the VIEW), - then run the 'show' version as well. - */ - let prefix = functionName.slice(0,3) - let newFunctionName = 'show' + functionName.slice(3) - if(prefix === 'set' && typeof controller[newFunctionName] === 'function'){ - controller[newFunctionName](view) - } - } -} -/** - Use a php script that reads contents of file from $_POST['contents'] that was convert by client - as DataURL, and expects filename and uploadPath from: $_POST['filename'] and $_POST['uploadPath'] - with trailing slash (/) provided by client (though script could check for this). -*/ -L.uploadFiles = function(progressReporter, fileElement, phpScriptName, uploadPath='../uploads/'){ - let doneCounter = 0 - let fileCount = fileElement.files.length - const array = [] // make a real array to borrow it's forEach method - array.forEach.call(fileElement.files, (file, index) => { - const postman = new XMLHttpRequest() // make a file deliverer for each file - const uploadObject = postman.upload // This object keeps track of upload progress - const envelope = new FormData() // make a holder for the file's name and content - envelope.stuff = envelope.append // give 'append' the nickname 'stuff' - const reader = new FileReader() // make a file reader (the raw file element is useless) - - reader.readAsDataURL(file) // process the file's contents - reader.onload = function(){ // when done ... - const contents = reader.result // collect the result, and ... - envelope.stuff('contents', contents) // place it in the envelope along with ... - envelope.stuff('filename', file.name) // its filename ... - envelope.stuff('uploadPath', uploadPath) // and its upload path on the server - - postman.open(`POST`, phpScriptName)// open up a POST to the server's php script - postman.send(envelope) // send the file - - //check when file loads and when there is an error - postman.onload = eventObject => { - postman.status !== 200 ? showMessage() : checkLastFileDone() - //-----| helper |------// - function showMessage(){ - const message = `Trouble with file: ${postman.status}` - console.log(message) - alert(message) - } - function checkLastFileDone(){ - doneCounter++ - if(typeof progressReporter === 'function'){ - if(doneCounter === fileCount){ - progressReporter(1, 1, index) - } - } - } - } - - postman.onerror = eventObject => { - const message = `Trouble connecting to server` - console.log(message) - alert(message) - } - - //invoke the callback for each upload progress report - uploadObject.onprogress = function(progressObject){ - if(typeof progressReporter === 'function'){ - progressReporter(progressObject.loaded, progressObject.total, index) - } - } - } - }) -} - -//---------------------------------------------------------// -/** - Given an array of strings (array), sorts the array 'in place' by filename EXTENSION, - and returns a copy of the array as well. Since it mutates the array, it is decidedly not - functionistic (but it functions). -*/ -L.sortByExtension = function (array) { - const type = {}.toString.call(array, null); - if (type !== '[object Array]') { - return array; - } - if (array.length === 0 || array.some(member => typeof member !== 'string')) { - return array; - } - //-------------------------------------// - let extension = ``; - let nudeWord = ``; - array.forEach((m, i, a) => { - if (m.lastIndexOf(`.`) !== -1) { - //get the extension - extension = m.slice(m.lastIndexOf(`.`) + 1); - nudeWord = m.slice(0, m.lastIndexOf(`.`)); - a[i] = `${extension}.${nudeWord}`; - } - }); - - array.sort(); - - array.forEach((m, i, a) => { - if (m.indexOf(`.`) !== -1){ - //get prefix (formerly the extension) - extension = m.slice(0, m.indexOf(`.`)) - nudeWord = m.slice(m.indexOf(`.`) + 1) - a[i] = `${nudeWord}.${extension}` - } - }); - - const newArray = [] - array.forEach( m => newArray.push(m)) - - return newArray; -} - -/** -From an array of string arrays, return a possibly smaller array -of only those string arrays whose member strings contain the given subString -regardless of case. - 1. For arrayOfStringArrays, use the filter method (a function property of an array) - that expects a function argument that operates on each array member - 2. Let's call the function argument 'match' - 3. 'match' should test each member array for a match of the substring as follows: - a.) join the members strings together into a bigString that is lowerCased - b.) lowerCase the subString - c.) use indexOf to match substring to the bigString - d.) return true for a match, otherwise return false - 4. the filter creates a new array after doing this. - 5. final step: return the new array that the filter produced -*/ -L.arrayStringMatch = function(subString, arrayOfStringArrays, maxIndex){ - //============================================================// - return arrayOfStringArrays.filter(match) - //-------| Helper function 'match' |---------// - function match(memberArray){ - //on 6-9-2018, added option of maximum index to eliminate searching through irrelevant fields - let bigString = '' - if(maxIndex && typeof maxIndex === "number" && maxIndex > 0){ - bigString = memberArray - .filter((m,i) => i <= maxIndex) - .join(` `) - .toLowerCase() - } - else{ - bigString = memberArray.join(` `).toLowerCase() - } - const substringToMatch = subString.toLowerCase() - return bigString.indexOf(substringToMatch) !== -1 - } -} -//-------------------------------------------------// - -/** - L.loopCall can be used to replace setInterval, which has been somewhat discredited. - See this blog post: - https://dev.to/akanksha_9560/why-not-to-use-setinterval--2na9 - - L.loopCall uses setTimeout recursively, which is a technique - reportedly more reliabale than setInterval. - - L.loopCall repeatedly calls (invokes) the callback function provided as its first argument. - The first call is immediate, but subsequent calls are delayed by the milliseconds - provided as the second argument. All additional arguments are optional - to be used by the callback if required. - - If needed, you can delay the initial call as well, - by having loopCall invoked by setTimeout using the same delay: - - setTimeout(L.loopCall, delay, callback, delay, arg1, arg2 ...) - - or the more readable, but more risky ... - - setTimeout("L.loopCall(callback, delay, arg1, arg2 ...)", delay) - //Doug Crockford would not be pleased - - To stop the loop, the callback function can test some external state condition, - (or test its own arguments, if they are passed by reference): - - if(externalStateCondition){ - L.loopCall.stop() - } -*/ -L.loopCall = function (callback, delay, ...args){ - L.loopCall.stopLoop = setTimeout(L.loopCall, delay, callback, delay, ...args) - callback(...args) -} - -L.loopCall.stop = () => { - clearTimeout(L.loopCall.stopLoop) -} - -/** - Returns an array that is the "mathematical or logical" symmetric difference among or between - any number of arrays provided as arguments (usually two). If the order of members is ignored - (as is done for mathematical sets), the result acts as the the exclusive-or (XOR), also know as - the disjunctive union. For the trivial cases of comparing one or two arrays, the result is - not surprising: for one array, the result is itself: L.symDiff(A, []) => A ⊕ [] = A. - For two arrays, the result is an array that has only members which are not shared in common: - L.symDiff(A, B) => A ⊕ B . - When comparing more than two arrays, the result may ne surprising. The proper result can be verified - by comparing only two at a time: L.symDiff(A, B, C) => A ⊕ B ⊕ C = (A ⊕ B) ⊕ C -*/ -L.symDiff = function symDiff(arrayA, arrayB){ // dummy paramters NOT referenced in body of the function - var partialSymDiff = [], - argsArray = arguments - ; - //============THE CRUX================= - return findSymDiff(partialSymDiff,0); - //============UNDER THE HOOD=========== - function findSymDiff(partialSymDiff,index){ - if (argsArray[index] === undefined){ - return partialSymDiff; - } - else{ - partialSymDiff = sd(partialSymDiff, argsArray[index] ); - return findSymDiff( partialSymDiff, index + 1 ); - } - } - //===================================== - function sd(arrayI, arrayJ){ - var diff = [], - blackList = [], - i = 0, - j = 0, - maxI = arrayI.length, - maxJ = arrayJ.length - ; - //------------------------------------------------- - //1.) Combine the arrays into a third array. - //2.) Find the matched elements and place them into a blacklist array. - //3.) Pull blacklisted elements from the combined array. - //4.) return the "reduced" combined array. - //--------------------------------------------------- - // 1.) Combine the arrays into a third array. - diff = arrayI.concat(arrayJ); - //--------------------------------------------------- - // 2.) Find the matched elements and place them into a blacklist array. - for ( i=0; i < maxI; i++ ){ - for( j=0; j< maxJ; j++ ){ - if(arrayI[i] === arrayJ[j]){ - blackList.push(arrayI[i] ); - } - } - } - //---------------------------------------------------- - // 3.) Pull blacklisted elements from the combined array. - diff = diff.filter( (element) => blackList.indexOf(element) === -1 ) - //---------------------------------------------------- - // 4.) return the "reduced" combined array. - return killDupes(diff); - } - //======================================================== - function killDupes(array){ - var kept = []; // Record of the "keepers" - return array.filter(function(element){ - if ( kept.indexOf(element) === -1 ){ //if not already retained ... - kept.push(element); // Record it as retained now, and... - return true; // allow this element to be kept (true) - } - else{ - return false; // otherwise, don't keep it (already kept) - } - }); - } -}; - -/** - * Pass in a numerical seconds: it returns a string in the format - * mm : ss, like ... - * 35 : 37 in minutes and seconds -*/ -L.secToMinSec = (seconds) =>{ - var min = Math.floor(seconds / 60); - var sec = Math.floor(seconds % 60); - if(isNaN(min)){min = 0} - if(isNaN(sec)){sec = 0} - var zeroMin = ((min < 10) ? ("0" + min) : ("" + min)); - var zeroSec = ((sec < 10) ? ("0" + sec) : ("" + sec)); - var minSec = zeroMin + ":" + zeroSec; - return minSec; -}; -//====| END of secToMinSec |====// - -///////////////////| START of CreateListMixer |////////////////////// -/** - * CreateListMixer: a factory that creates and returns a function that - * returns a random item from the collection (array or object) provided. - * Notes: Example-> var list = ["a", "short", "list"];//three (3) items to test - * var getRandomItem = CreateListMixer(); - * getRandomItem(list);//returns first of randomized list - * getRandomItem();//returns next item - * getRandomItem();//returns next item (last of three) - * getRandomItem();//new first item from re-randomized list - * - * // a new list; - * var list2 = { record1: "string", record2: "anotherString", ...}; - * getRandomItem(list2);//returns first of new randomized list2 - * getRandomItem();//etc. - * It returns a property name for objects or an array member for arrays; - * It returns 'false' if argument of function is not an object - * or an array (fails typeof arg === 'object') - * -*/ -L.CreateListMixer = function(){ - var list=[], - randList= [], - listLength= 0, - itemReturned= null, - itemReturnedIndex= -1 - ; - return function(){ - if(arguments[0]){ - if(typeof arguments[0] === 'object'){ - list = arguments[0]; - if({}.toString.call(arguments[0]) === '[object Object]'){ - list = Object.keys(list); - } - randList = randomize(list); - listLength = list.length; - } - else{ - return false; - } - } - //----| no args activity: return next random item |---- - if(itemReturnedIndex >= listLength-1){ - do{ - randList = randomize(list); - itemReturnedIndex = -1; - } - while(randList[itemReturnedIndex +1] === itemReturned); - } - itemReturnedIndex++; - itemReturned = randList[itemReturnedIndex]; - return itemReturned; - //-----helpers----- - function randomize(x){ - var mixedIndexes = []; - var randomList = []; - randomizeIndexes(); - return randomList; - //----sub helper---- - function randomizeIndexes(){ - // random numbers for mixedIndexes - while(mixedIndexes.length !== x.length){ - var match = false; - var possibleIndex = (x.length)*Math.random(); - possibleIndex = Math.floor(possibleIndex); - mixedIndexes.forEach(function(m){ - if(m === possibleIndex){ - match = true; - } - }); - if(!match){ - mixedIndexes.push(possibleIndex); - } - } - for(var i = 0; i < x.length; i++){ - var newIndex = mixedIndexes[i]; - randomList.push(list[newIndex]); - } - } - } - };//===| END returned function |====== -}//===| END enclosing factory function====== -///////////////////| END of CreateListMixer |////////////////////// - -///////////////////| START of scrammbleThis |////////////////////// -/** - scrammbleThis: (depends on createListMixer, above) - It returns an array of randomly arranged items of the collection provided. - The argument must be an array, an object, or a string. - If the argument is an object, a random array of its property names is returned. - If the argument is a string, a random array of its characters is returned. - If the argument is an array, a random array of its members is returned. -*/ -L.scrammbleThis = function(collection){ - if ( !(typeof collection === 'object' || typeof collection === 'string') ){return collection} - var mix = L.CreateListMixer(); - var list = (Object.prototype.toString.call(collection) === '[object Array]') - ? collection - : (typeof collection === 'string') - ? collection.split('') - : (typeof collection === 'object') - ? Object.keys(collection) - : null - return list.map((m,i,a)=> (i === 0) ? mix(a) : mix()) -} -///////////////////| END of scrammbleThis |////////////////////// - -/** - Given an array of string arrays, this function returns an alphabetized version -*/ -L.sortArrayOfStringArrays = function(arrayOfStringArrays, linkToken='```'){ - //use a unique token (default = triple back-ticks ```) to join the strings of each array of strings - const arrayOfStrings = arrayOfStringArrays.map(stringArray => stringArray.join(linkToken)) - - //case-insensitive sort this array of strings, mutating it in place: - //https://stackoverflow.com/questions/8996963/how-to-perform-case-insensitive-sorting-in-javascript - arrayOfStrings.sort( (a,b) => a.toLowerCase().localeCompare(b.toLowerCase()) ) - - //return a new array of string arrays after splitting the strings on the unique token - return arrayOfStrings.map( string => string.split(linkToken)) -}"; \ No newline at end of file diff --git a/data/collaborative/shadow/e275a3a559f2c49aff391d8cc3fe538d b/data/collaborative/shadow/e275a3a559f2c49aff391d8cc3fe538d deleted file mode 100755 index a7a68ea..0000000 --- a/data/collaborative/shadow/e275a3a559f2c49aff391d8cc3fe538d +++ /dev/null @@ -1,46 +0,0 @@ -s:1135:"/* - -Created: 2018-07-09 -Revised: N/A -Purpose: A template for vanilla js with one library. - -*/ -/*global L*/ -/*global m*/ -/*global v*/ -/*global c*/ - -////////////////////////////////////// -c.setToggleFirstButton = function(m){ - m.buttonIn = !m.buttonIn - //console.log(m.buttonIn) -} -c.showToggleFirstButton = function(v){ - m.buttonIn - ? v.firstButton.style.boxShadow = "inset 5px 5px 10px rgba(0,0,0,1)" - : v.firstButton.style.boxShadow = "5px 5px 10px rgba(0,0,0,1)" -} -////////////////////////////////////// -////////////////////////////////////// -////////////////////////////////////// -////////////////////////////////////// -////////////////////////////////////// -////////////////////////////////////// -////////////////////////////////////// - -c.updateMetaEvents = function(eventObject){ - ///////| define meta events |///////// - m.eventObject = eventObject - m.source = eventObject.target - m.type = eventObject.type - m.id = eventObject.target.id - - - m.type === 'mousedown' || m.type === `touchstart` - ? m.pressed = true - : m.pressed = false - - m.type === `mouseup` || m.type === `touchend` - ? m.released = true - : m.released = false -}"; \ No newline at end of file diff --git a/data/collaborative/shadow/e48aa03433d347bfaffcb9429f62a27c b/data/collaborative/shadow/e48aa03433d347bfaffcb9429f62a27c deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/shadow/e48aa03433d347bfaffcb9429f62a27c +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/shadow/e693185c0b5a32ed6979e22b10f1e433 b/data/collaborative/shadow/e693185c0b5a32ed6979e22b10f1e433 deleted file mode 100755 index 8c20d5d..0000000 --- a/data/collaborative/shadow/e693185c0b5a32ed6979e22b10f1e433 +++ /dev/null @@ -1,83 +0,0 @@ -s:2415:" - - - - - - - - - 50's Music - - - - - - - - - - - - - -
    -
    -
    - -
    - -
    - -
    - - -
    - -
    - -
    - -
    - -
    -
    - -
    - -
    - -
    - Logout - -
    -
    - -
    -
    - Password
    - -
    -
    - - - - - - - - - - - - - - - - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/e6ca864b939a36765d43aa4ae3e8503e b/data/collaborative/shadow/e6ca864b939a36765d43aa4ae3e8503e deleted file mode 100755 index 2f53002..0000000 --- a/data/collaborative/shadow/e6ca864b939a36765d43aa4ae3e8503e +++ /dev/null @@ -1,76 +0,0 @@ -s:1545:"/* - -Created: 2018-07-10 -Modified: N/A -Purpose: To pollute the global scope then initialize our plugin. - -*/ -/* global L - * global m - * global v - * global c -*/ -const m = {} -const v = {} -const c = {} - -///////////////////////////// -c.initialize = function(eventObject) { - c.initializeModel(eventObject) - - L.attachAllElementsById(v) - - let eventTypes = [ - `change`, - `click`, - `dblclick`, - `input`, - `keydown`, - `keyup`, - `load`, - `mousedown`, - `mousemove`, - `mouseout`, - `mouseover`, - `mouseup`, - `offline`, - `online`, - `orientationchange`, - `resize`, - `touchend`, - `touchmove`, - `touchstart`, - ] - - //Clever way: for each member of the eventTypes array, have the window listen for the event - eventTypes.forEach((event)=>{window.addEventListener(event, c.designateFunction)}) - - /* - - let eventType; - for(eventType of eventTypes){ - window.addEventListener(eventType, c.designateFunction) - } - - */ - -} -///////////////////////////// -c.initializeModel = function(eventObject){ - //define meta events - m.eventObject = eventObject //the event object itself - m.source = eventObject.target //where the event took place - m.type = eventObject.type //what the event was - m.id = eventObject.target.id //the id of the element where the event occurred - - //Shortcuts to combine similar mobile and computer events - m.pressed = m.type === `mousedown` || m.type === `touchstart` - m.released = m.type === `mouseup` || m.type === `touchend` - - //et cetera .... - - //state variable particular to this app - m.testButtonIn = false -} - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/ea5288a62fdc3f1ebfab27f709082842 b/data/collaborative/shadow/ea5288a62fdc3f1ebfab27f709082842 deleted file mode 100755 index 216f622..0000000 --- a/data/collaborative/shadow/ea5288a62fdc3f1ebfab27f709082842 +++ /dev/null @@ -1,43 +0,0 @@ -s:919:" -
    - ";echo var_dump( $quizzes );?> - -

    This teacher currently has no quizzes active.

    - -
  • ">
  • - -
    -"; \ No newline at end of file diff --git a/data/collaborative/shadow/eceb4e0876fe71ea018f446d0d34eca1 b/data/collaborative/shadow/eceb4e0876fe71ea018f446d0d34eca1 deleted file mode 100755 index eb5eab9..0000000 --- a/data/collaborative/shadow/eceb4e0876fe71ea018f446d0d34eca1 +++ /dev/null @@ -1,34 +0,0 @@ -s:553:"* { - box-sizing: border-box; -} - -html{ - font-size: calc(calc(0.5vh + 0.5vw) + 12px); -} - -html, body { - height: 100%; - width: 100%; - padding: 0; - margin: 0; - overflow: hidden; -} - -.button { - - -webkit-transition-duration: 0.4s; /* Safari */ - background-color: #1f2059; /* PIT Blue */ - border: none; - border-radius: 5px; - box-shadow: 5px 5px 8px #000000; - color: white; - cursor: pointer; - display: inline-block; - font-size: 16px; - margin: 4px 2px; - outline: none; - padding: 15px 32px; - text-align: center; - text-decoration: none; - transition-duration: 0.4s; -}"; \ No newline at end of file diff --git a/data/collaborative/shadow/ede158f1f62eabab87526f2db25fad17 b/data/collaborative/shadow/ede158f1f62eabab87526f2db25fad17 deleted file mode 100755 index 0df5794..0000000 --- a/data/collaborative/shadow/ede158f1f62eabab87526f2db25fad17 +++ /dev/null @@ -1,39 +0,0 @@ -s:675:"html, body { - height: 100%; - margin: 0px; -} - -body { - background-color: #dfdfdf; - width: 100%; -} - -.button { - -webkit-transition-duration: 0.4s; /* Safari */ - background-color: lightblue;/*#1f2059; PIT Blue */ - border: none; - border-radius: 5px; - box-shadow: 5px 5px 10px rgba(0,0,0,1); - color: white; - cursor: pointer; - display: inline-block; - font-size: 16px; - margin: 4px 2px; - padding: 15px 32px; - text-align: center; - text-decoration: none; - transition-duration: 0.4s; -} - - -#firstButton{ - display: inline-block; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - color: black; - outline: none; - font-weight: bold; - text-shadow: 0 1px 0 white; -}"; \ No newline at end of file diff --git a/data/collaborative/shadow/ee3d3118cdab96fd9c2343d4742f2810 b/data/collaborative/shadow/ee3d3118cdab96fd9c2343d4742f2810 deleted file mode 100755 index 980354f..0000000 --- a/data/collaborative/shadow/ee3d3118cdab96fd9c2343d4742f2810 +++ /dev/null @@ -1,46 +0,0 @@ -s:1129:"/* - -Created: 2018-07-09 -Revised: N/A -Purpose: A template for vanilla js with one library. - -*/ -/*global L*/ -/*global m*/ -/*global v*/ -/*global c*/ - -////////////////////////////////////// -c.setToggleFirstButton = function(m){ - m.buttonIn = !m.buttonIn -} -c.showToggleFirstButton = function(v){ - alert(m.buttonIn) - m.buttonIn - ? v.firstButton.style.boxShadow = "inset 5px 5px 10px rgba(0,0,0,1);" - : v.firstButton.style.boxShadow = "5px 5px 10px rgba(0,0,0,1);" -} -////////////////////////////////////// -////////////////////////////////////// -////////////////////////////////////// -////////////////////////////////////// -////////////////////////////////////// -////////////////////////////////////// -////////////////////////////////////// - -c.updateMetaEvents = function(eventObject){ - ///////| define meta events |///////// - m.eventObject = eventObject - m.source = eventObject.target - m.type = eventObject.type - m.id = eventObject.target.id - - - m.type === 'mousedown' || m.type === `touchstart` - ? m.pressed = true - : m.pressed = false - - m.type === `mouseup` || m.type === `touchend` - ? m.released = true - : m.released = false -}"; \ No newline at end of file diff --git a/data/collaborative/shadow/ee62af99d5b417b7381e5299027cca6e b/data/collaborative/shadow/ee62af99d5b417b7381e5299027cca6e deleted file mode 100755 index 6a1cd94..0000000 --- a/data/collaborative/shadow/ee62af99d5b417b7381e5299027cca6e +++ /dev/null @@ -1,28 +0,0 @@ -s:427:"html, body { - - margin: 0px; -} - -body { - - width: 100%; -} - -.button { - - -webkit-transition-duration: 0.4s; /* Safari */ - background-color: #1f2059; /* PIT Blue */ - border: none; - border-radius: 5px; - box-shadow: 5px 5px 10px rgba(0,0,0,1); - color: white; - cursor: pointer; - display: inline-block; - font-size: 16px; - margin: 4px 2px; - padding: 15px 32px; - text-align: center; - text-decoration: none; - transition-duration: 0.4s; -} -"; \ No newline at end of file diff --git a/data/collaborative/shadow/eef1f14577636af47a8ee7f55ba777bf b/data/collaborative/shadow/eef1f14577636af47a8ee7f55ba777bf deleted file mode 100755 index e126e14..0000000 --- a/data/collaborative/shadow/eef1f14577636af47a8ee7f55ba777bf +++ /dev/null @@ -1,209 +0,0 @@ -s:4684:" - */ - -class mypit { - - const VERSION = '1.0.0'; - - - /** - * Unique identifier for your plugin. - * - * - * The variable name is used as the text domain when internationalizing strings - * of text. Its value should match the Text Domain file header in the main - * plugin file. - * - * @var string - */ - protected $plugin_slug = ''; - - /** - * Instance of this class. - */ - protected static $instance = null; - - /** - * Initialize the plugin by setting localization and loading public scripts and styles. - */ - private function __construct() { - - // Trigger initial - $this->init(); - } - - /** - * Return the plugin slug. - * - * @since 1.0.0 - * - * @return Plugin slug variable. - */ - public function get_plugin_slug() { - return $this->plugin_slug; - } - - /** - * Return an instance of this class. - * - * @since 1.0.0 - * - * @return object A single instance of this class. - */ - public static function get_instance() { - // If the single instance hasn't been set, set it now. - if ( null == self::$instance ) { - self::$instance = new self; - } - - return self::$instance; - } - - /** - * Fired for each blog when the plugin is activated. - * - * @since 1.0.0 - */ - private static function install() {} - - /** - * Fired for each blog when the plugin is uninstalled. - * - * @since 1.0.0 - */ - private static function uninstall() {} - - /** - * Load the plugin text domain for translation. - * - * @since 1.0.0 - */ - public function init() {} - - /** - * Register and enqueue public-facing style sheet. - * - * @since 1.0.0 - */ - public function enqueue_scripts() {} - - /** - * Register and enqueue public-facing style sheet. - * - * @since 1.0.0 - */ - public function enqueue_styles() {} - - /** - * Connect to specified MYSQL database with preset login details. - * - * @since 1.0.0 - */ - public static function sql_connect( $database = "" ) { - - switch( $database ) { - - default : - - $database = "main"; - $host = "localhost"; - $password = base64_decode( "UCF0QWRtIW4=" ); - $username = "main"; - break; - } - - $connection = mysqli_connect( $host, $username, $password, $database ); - return( $connection ); - } - - /** - * Execute an sql query with binded variables - * - * This allows you to use POST or GET values without - * having to worry about people hacking your query. - * - * @since 1.0.0 - */ - public static function sql( $sql, $bind, $bind_vars, $error, $last_id = FALSE ) { - - $connection = self::sql_connect(); - - $result = mysqli_prepare( $connection, $sql ) or die( "

    " . $error . ":
    Query:" . $sql . "
    " . mysqli_error( $connection ) . "

    " ); - - //call_user_func_array(array($result, "bind_param"), array_merge(array($bind), $bind_vars)); - $result->bind_param( $bind, ...$bind_vars ); - $result->execute(); - - if ( $last_id === FALSE ) { - - $return = $result->get_result(); - } else { - - $return = mysqli_insert_id( $connection ); - } - $result->close(); - - return( $return ); - } - - - /** - * Execute a basic sql query - * - * This allows should only be used for statements without user input. - * - * @since 1.0.0 - */ - public static function sql_internal( $sql, $error ) { - - $connection = self::sql_connect(); - $result = mysqli_query( $connection, $sql ) or die( "

    " . $error . ":
    Query:" . $sql . "
    " . mysqli_error( $connection ) . "

    " ); - return( $result ); - } - - - /** - * Connect to a microsoft sql database with preset login details. - * - * @since 1.0.0 - */ - public static function ms_sql_connect( $database ) { - - - $server = ""; - $connection_info = array(); - - $connection_info["Database"] = $database; - $connection_info["UID"] = ""; - $connection_info["PWD"] = ""; - - $connection = sqlsrv_connect( $server , $connection_info ); - - if( $connection === false ) { - - echo "

    Error connecting to database.



    "; - die( print_r( sqlsrv_errors(), true ) ); - } - - return( $connection ); - } -}"; \ No newline at end of file diff --git a/data/collaborative/shadow/ef7b395faeaf7d9a60fd54f2dca409e5 b/data/collaborative/shadow/ef7b395faeaf7d9a60fd54f2dca409e5 deleted file mode 100755 index b1567e6..0000000 --- a/data/collaborative/shadow/ef7b395faeaf7d9a60fd54f2dca409e5 +++ /dev/null @@ -1,350 +0,0 @@ -s:5688:"/* CSS Document */ - -html {} -body { - - margin: 0; - padding: 0; -} - -.content { - - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; - padding: 0 10px 0 10px; -} - -/*================================================== -* Start Header -*==================================================*/ -.main_menu_container { - - background-color: #1f2059; - /*display: block;*/ - position: relative; - text-align: center; - top: 0; - width: 100%; - transition: all 0.5s; -} - -.main_menu_container_sticky { - - transition: all 0.5s; - position: fixed; - top: 0; - z-index: 10; -} - -.main_menu { - - align-items: center; - display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */ - display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */ - display: -ms-flexbox; /* TWEENER - IE 10 */ - display: -webkit-flex; /* NEW - Chrome */ - display: flex; /* NEW, Spec - Opera 12.1, Firefox 20+ */ - justify-content: center; - margin: 0; - padding: 0; - text-align: center; - transition: all 0.5s; - width: 100%; -} - -.main_menu_drop_down { - - list-style: none; -} - -.main_menu_drop_down_item { - - list-style: none; -} - -.mobile_menu_open { - - display: none; -} - -.mobile_menu_close { - - display: none; -} - -.main_menu_item { - - display: inline-block; - list-style: none; - - -webkit-transition: background-color .5s; - transition: background-color .5s; -} - -.main_menu_item:hover { - - background-color: #CCCCCC; - - -webkit-transition: background-color .5s; - transition: background-color .5s; -} - -.menu_item_selected { - - background-color: #FFFFFF; - - -webkit-transition: background-color .5s; - transition: background-color .5s; -} - -.menu_item_selected:hover { - - background-color: #FFFFFF; -} - -.main_menu_link { - - -webkit-transition: all 500ms; - border-radius: 0px; - color: #FFFFF0; - display: block; - font-family: 'IM Fell English SC', serif; - font-size: 16px; - font-weight: 600; - letter-spacing: 1px; - line-height: 22px; - padding: 20px 10px; - text-decoration: none; - text-transform: uppercase; - transition: all 500ms; - white-space: nowrap; -} - -.main_menu_link_selected { - - color: #777777; -} - -.main_menu_container_sticky + .content { - - -} - -.main_menu_logo_link { - - display: none; -} - -.logo { - - max-width: 0; - overflow: hidden; - transition: all 0.5s; -} - - -.main_menu_container_sticky li.logo { - - max-width:500px; -} - -.main_menu_container_sticky .main_menu_logo_link { - - display: visible; -} - -/*================================================== -* Start Mobile Menu -*==================================================*/ - -.mobile_menu_open { - - display: none; -} - -.mobile_menu_close { - - display: none; -} - -/* If screen is less than x */ -@media only - screen and (max-device-width : 736px), - screen and (max-width: 736px) - /*and (-webkit-min-device-pixel-ratio : 3) This isnt needed*/ -{ - - html, body { - - max-width: 100%; - overflow-x: hidden; - } - /* - .body { - - -webkit-transform: rotate(180deg); - -moz-transform: rotate(180deg); - -ms-transform: rotate(180deg); - -o-transform: rotate(180deg); - transform: rotate(180deg); - } - - .body > section { - display: block; - -webkit-transform: rotate(-180deg); - -moz-transform: rotate(-180deg); - -ms-transform: rotate(-180deg); - -o-transform: rotate(-180deg); - transform: rotate(-180deg); - }*/ - - p { - - font-size: 1em; - margin: 1em 0; - } - - table { - - width: 100% !important; - } - - tr { - - width: 100% !important; - } - - td { - - display: block; - width: 100% !important; - } - - th { - - display: block; - width: 100% !important; - } - - table.keep_layout td { - - display: table-cell; - width: initial !important; - } - - .header_table_column { - - text-align: center; - } - - .mobile_menu_open { - - background-color: #ededed; - display: block; - text-align: center; - width: 100%; - } - - .mobile_menu_open_button { - - font-size: 25px; - text-decoration: none; - } - - .mobile_menu_close { - - display: block; - text-align: right; - } - - .mobile_menu_close_button { - - color: #FFF; - font-size: 50px; - padding-right: 5%; - text-align: right; - text-decoration: none; - - } - - .main_menu { - - background-color: #111; - display: block; - height: 100%; - left: 0; - margin-top: 0; - overflow-x: hidden; - position: fixed; - top: 0; - transition: 0.5s; - width: 0; - z-index: 11; - - } - - .main_menu_drop_down { - - list-style: none; - } - - .main_menu_drop_down_item { - - list-style: none; - } - - .main_menu_item { - - display: block; - list-style: none; - width: 100%; - - -webkit-transition: background-color .5s; - transition: background-color .5s; - } - - .main_menu_item:hover { - - background-color: #CCCCCC; - - -webkit-transition: background-color .5s; - transition: background-color .5s; - } - - .menu_item_selected { - - background-color: #FFFFFF; - display: block; - list-style: none; - width: 100%; - - -webkit-transition: background-color .5s; - transition: background-color .5s; - } - - .menu_item_selected:hover { - - background-color: #FFFFFF; - } - - .main_menu_link { - - -webkit-transition: all 500ms; - border-radius: 0px; - color: #777777; - display: block; - font-family: 'IM Fell English SC', serif; - font-size: 16px; - font-weight: 600; - letter-spacing: 1px; - line-height: 22px; - padding: 20px 10px; - text-decoration: none; - text-transform: uppercase; - transition: all 500ms; - white-space: nowrap; - width: 100%; - } -} -"; \ No newline at end of file diff --git a/data/collaborative/shadow/f0e5f885ff64458f62a2f0c202070139 b/data/collaborative/shadow/f0e5f885ff64458f62a2f0c202070139 deleted file mode 100755 index 6562584..0000000 --- a/data/collaborative/shadow/f0e5f885ff64458f62a2f0c202070139 +++ /dev/null @@ -1,20 +0,0 @@ -s:441:""; \ No newline at end of file diff --git a/data/collaborative/shadow/f3d17d035479bb837c846584a985fc9b b/data/collaborative/shadow/f3d17d035479bb837c846584a985fc9b deleted file mode 100755 index b7d7165..0000000 --- a/data/collaborative/shadow/f3d17d035479bb837c846584a985fc9b +++ /dev/null @@ -1,33 +0,0 @@ -s:987:" - - - Mobile Programming Template - - - - - - - - - - - - -

    Header 1

    -

    Header 2

    -

    Header 3

    -

    Hello! Paragraph

    -
    - - - - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/f46fc66fdb891a570f1a03add3c166cc b/data/collaborative/shadow/f46fc66fdb891a570f1a03add3c166cc deleted file mode 100755 index eb5eab9..0000000 --- a/data/collaborative/shadow/f46fc66fdb891a570f1a03add3c166cc +++ /dev/null @@ -1,34 +0,0 @@ -s:553:"* { - box-sizing: border-box; -} - -html{ - font-size: calc(calc(0.5vh + 0.5vw) + 12px); -} - -html, body { - height: 100%; - width: 100%; - padding: 0; - margin: 0; - overflow: hidden; -} - -.button { - - -webkit-transition-duration: 0.4s; /* Safari */ - background-color: #1f2059; /* PIT Blue */ - border: none; - border-radius: 5px; - box-shadow: 5px 5px 8px #000000; - color: white; - cursor: pointer; - display: inline-block; - font-size: 16px; - margin: 4px 2px; - outline: none; - padding: 15px 32px; - text-align: center; - text-decoration: none; - transition-duration: 0.4s; -}"; \ No newline at end of file diff --git a/data/collaborative/shadow/f6d27d5345b78d2d52c54cb2ada888f5 b/data/collaborative/shadow/f6d27d5345b78d2d52c54cb2ada888f5 deleted file mode 100755 index b549139..0000000 --- a/data/collaborative/shadow/f6d27d5345b78d2d52c54cb2ada888f5 +++ /dev/null @@ -1,4 +0,0 @@ -s:20:""; \ No newline at end of file diff --git a/data/collaborative/shadow/f858621dbec7ad5f5a1f28be85acf0f0 b/data/collaborative/shadow/f858621dbec7ad5f5a1f28be85acf0f0 deleted file mode 100755 index 6a48e81..0000000 --- a/data/collaborative/shadow/f858621dbec7ad5f5a1f28be85acf0f0 +++ /dev/null @@ -1,31 +0,0 @@ -s:857:" - - - Web 2 Template - - - - - - - - - - - - - - - - - - - -"; \ No newline at end of file diff --git a/data/collaborative/shadow/fe7e13bcdd4f10c3c8c55b3bb59e5ef8 b/data/collaborative/shadow/fe7e13bcdd4f10c3c8c55b3bb59e5ef8 deleted file mode 100755 index 659594c..0000000 --- a/data/collaborative/shadow/fe7e13bcdd4f10c3c8c55b3bb59e5ef8 +++ /dev/null @@ -1,576 +0,0 @@ -s:22926:"/** - Author: Abbas Abdulmalik - Created: ~ May, 2017 - Revised: June 9, 2018 - Original Filename: L.js - Purpose: a small (but growing) personal re-usable js library for a simple MVC architecture - Notes: Now qualifyFunction helper doesn't return true for empty arrays (no vacuous truth) - - Added UploadFiles: - uploadFiles takes a callback -- progressReporter-- as it FIRST argument (parameter) - to allow for an optional fourth parameter of an upload path for the server. - progressReporter will be passed three arguments when called: - 1.) the amount of bytes uploaded so far - 2.) the total size of the file in bytes - 3.) the index of the file in the "array" of files being uploaded - - Added sortByExtension that alphabetizes an array of strings 'in place' by filename extension - Added arrayStringMatch that matches a collection of string arrays to a search string. - later (6-9-2018) included an option for a "maximum array index" to eliminate - searching irrelevant fields at the end of the array, such as image name and primary key. - Added loopCall as a 'better' version of setInterval - Removed L.attributes. It's a reserved word: an object belonging to DOM elements - Now it uses L.attribs - Added L.loopCall.stop() so that user can easily stop L.loopCall - Added L.symDiff for comparing arrays to determine their symmetric difference = conjunctive union = - exclusive-or - Restored an updated version of uploadFiles that signals the final file has uploaded - Added secToMinSec - Added runQualifiedFunctions that mirrors runQualifiedMethods using different parameters, - namely: functionQualifiers, model, view, controller - Added attachNewElement(tagname, id, view). Create new element, gives it an id and - attaches it to object provided: - L.attachNewElement(`div`, `picHolder`, view) - Added createListMixer and scrammbleThis, which depends on createListMixer - Added sortArrayOfStringArrays, with option of using a "link token" of choice as the 3rd argument - Added an optional argument for arrayStringMatch for a maximum array index - to eliminate searching irrelevant fields at the end of the array, - such as image name and primary key -*/ - -var L = {} -L.styles = function(styleString){ - const colonPosition = styleString.indexOf(':') - const property = styleString.slice(0, colonPosition) - const value = styleString.slice(colonPosition + 1) - this.style[property] = value - - return this.styles -} - -L.attribs = function(attributeString){ - const assignmentPosition = attributeString.indexOf('=') - const attribute = attributeString.slice(0, assignmentPosition) - const value = attributeString.slice(assignmentPosition + 1) - this.setAttribute(attribute, value) - - return this.attribs -} - -L.attachAllElementsById = function(here){ - let allElements = document.getElementsByTagName('*') - let array = [] - array.forEach.call(allElements, function(element) { - if(element.id){ - here[element.id] = element - element.styles = L.styles.bind(element) // attach L's styles() method here - element.attribs = L.attribs.bind(element) // attach L's attribs() method here - } - }) -} -///////////////| START of L.attachNewElement |///////////// -/** - L.attachNewElement(string tagname, string id, object view) ... - ... creates a new element of type "tagname" given as the first argument, - and gives it the id "id" given as the second argument. - The third argument is the view object where this new reference will be attached. - The element can then be referenced as view.id. -*/ -L.attachNewElement = function(tagname, id, view){ - if(arguments.length !== 3){ - console.log(`Error: requires 3 arguments: tagname, id, view`) - return - } - try{ - if(typeof tagname === `string`){ - var newElement = document.createElement(tagname) - } - else{ - console.log(`Error: tagname needs to be a string`) - return - } - if(typeof id === `string`){ - newElement.id = id - } - else{ - console.log(`Error: id needs to be a string`) - return - } - if(view.toString() === `[object Object]`){ - view[newElement.id] = newElement - newElement.styles = L.styles.bind(newElement) // attach L's styles() method here - newElement.attribs = L.attribs.bind(newElement) // attach L's attribs() method here - return newElement - } - else{ - console.log(`Error: view needs to be an object`) - return - } - } - catch(e){ - console.log(`Error in L.attachNewElement: ${e}`) - return - } -} -///////////////| END of L.attachNewElement |///////////// - -L.noPinchZoom = function(){ - window.ontouchstart = function(eventObject){ - if(eventObject.touches && eventObject.touches.length > 1){ - eventObject.preventDefault(); - } - } -} - -L.runQualifiedMethods = function(functionQualifiers, object, runNextUpdate){ - Object - .keys(functionQualifiers) - .filter(qualifyFunction) - .forEach(runFunction) - if(typeof runNextUpdate === 'function'){runNextUpdate()} - - //-----| helpers |-----// - function qualifyFunction(functionName){ - const isQualified = functionQualifiers[functionName].every( qualifier => qualifier) && - !!functionQualifiers[functionName].length - return isQualified - } - function runFunction(functionName){ - if(typeof object[functionName] === 'function'){ - object[functionName]() - } - - /** - If the prefix of this function's name is 'set' (for updating the MODEL), - and there is a similarly named function with a prefix of 'show' (for updating the VIEW), - then run the 'show' version as well. - */ - let prefix = functionName.slice(0,3) - let newFunctionName = 'show' + functionName.slice(3) - - if(prefix === 'set' && typeof object[newFunctionName] === 'function'){ - object[newFunctionName]() - } - } -} - -L.runQualifiedFunctions = function(functionQualifiers, model, view, controller){ - Object - .keys(functionQualifiers) - .filter(qualifyFunction) - .forEach(runFunction) - //-----| helpers |-----// - function qualifyFunction(functionName){ - const isQualified = functionQualifiers[functionName].every( qualifier => qualifier) && - !!functionQualifiers[functionName].length - return isQualified - } - function runFunction(functionName){ - if(typeof controller[functionName] === 'function'){ - controller[functionName](model) - } - /** - If the prefix of this function's name is 'set' (for updating the MODEL), - and there is a similarly named function with a prefix of 'show' (for updating the VIEW), - then run the 'show' version as well. - */ - let prefix = functionName.slice(0,3) - let newFunctionName = 'show' + functionName.slice(3) - if(prefix === 'set' && typeof controller[newFunctionName] === 'function'){ - controller[newFunctionName](view) - } - } -} -/** - Use a php script that reads contents of file from $_POST['contents'] that was convert by client - as DataURL, and expects filename and uploadPath from: $_POST['filename'] and $_POST['uploadPath'] - with trailing slash (/) provided by client (though script could check for this). -*/ -L.uploadFiles = function(progressReporter, fileElement, phpScriptName, uploadPath='../uploads/'){ - let doneCounter = 0 - let fileCount = fileElement.files.length - const array = [] // make a real array to borrow it's forEach method - array.forEach.call(fileElement.files, (file, index) => { - const postman = new XMLHttpRequest() // make a file deliverer for each file - const uploadObject = postman.upload // This object keeps track of upload progress - const envelope = new FormData() // make a holder for the file's name and content - envelope.stuff = envelope.append // give 'append' the nickname 'stuff' - const reader = new FileReader() // make a file reader (the raw file element is useless) - - reader.readAsDataURL(file) // process the file's contents - reader.onload = function(){ // when done ... - const contents = reader.result // collect the result, and ... - envelope.stuff('contents', contents) // place it in the envelope along with ... - envelope.stuff('filename', file.name) // its filename ... - envelope.stuff('uploadPath', uploadPath) // and its upload path on the server - - postman.open(`POST`, phpScriptName)// open up a POST to the server's php script - postman.send(envelope) // send the file - - //check when file loads and when there is an error - postman.onload = eventObject => { - postman.status !== 200 ? showMessage() : checkLastFileDone() - //-----| helper |------// - function showMessage(){ - const message = `Trouble with file: ${postman.status}` - console.log(message) - alert(message) - } - function checkLastFileDone(){ - doneCounter++ - if(typeof progressReporter === 'function'){ - if(doneCounter === fileCount){ - progressReporter(1, 1, index) - } - } - } - } - - postman.onerror = eventObject => { - const message = `Trouble connecting to server` - console.log(message) - alert(message) - } - - //invoke the callback for each upload progress report - uploadObject.onprogress = function(progressObject){ - if(typeof progressReporter === 'function'){ - progressReporter(progressObject.loaded, progressObject.total, index) - } - } - } - }) -} - -//---------------------------------------------------------// -/** - Given an array of strings (array), sorts the array 'in place' by filename EXTENSION, - and returns a copy of the array as well. Since it mutates the array, it is decidedly not - functionistic (but it functions). -*/ -L.sortByExtension = function (array) { - const type = {}.toString.call(array, null); - if (type !== '[object Array]') { - return array; - } - if (array.length === 0 || array.some(member => typeof member !== 'string')) { - return array; - } - //-------------------------------------// - let extension = ``; - let nudeWord = ``; - array.forEach((m, i, a) => { - if (m.lastIndexOf(`.`) !== -1) { - //get the extension - extension = m.slice(m.lastIndexOf(`.`) + 1); - nudeWord = m.slice(0, m.lastIndexOf(`.`)); - a[i] = `${extension}.${nudeWord}`; - } - }); - - array.sort(); - - array.forEach((m, i, a) => { - if (m.indexOf(`.`) !== -1){ - //get prefix (formerly the extension) - extension = m.slice(0, m.indexOf(`.`)) - nudeWord = m.slice(m.indexOf(`.`) + 1) - a[i] = `${nudeWord}.${extension}` - } - }); - - const newArray = [] - array.forEach( m => newArray.push(m)) - - return newArray; -} - -/** -From an array of string arrays, return a possibly smaller array -of only those string arrays whose member strings contain the given subString -regardless of case. - 1. For arrayOfStringArrays, use the filter method (a function property of an array) - that expects a function argument that operates on each array member - 2. Let's call the function argument 'match' - 3. 'match' should test each member array for a match of the substring as follows: - a.) join the members strings together into a bigString that is lowerCased - b.) lowerCase the subString - c.) use indexOf to match substring to the bigString - d.) return true for a match, otherwise return false - 4. the filter creates a new array after doing this. - 5. final step: return the new array that the filter produced -*/ -L.arrayStringMatch = function(subString, arrayOfStringArrays, maxIndex){ - //============================================================// - return arrayOfStringArrays.filter(match) - //-------| Helper function 'match' |---------// - function match(memberArray){ - //on 6-9-2018, added option of maximum index to eliminate searching through irrelevant fields - let bigString = '' - if(maxIndex && typeof maxIndex === "number" && maxIndex > 0){ - bigString = memberArray - .filter((m,i) => i <= maxIndex) - .join(` `) - .toLowerCase() - } - else{ - bigString = memberArray.join(` `).toLowerCase() - } - const substringToMatch = subString.toLowerCase() - return bigString.indexOf(substringToMatch) !== -1 - } -} -//-------------------------------------------------// - -/** - L.loopCall can be used to replace setInterval, which has been somewhat discredited. - See this blog post: - https://dev.to/akanksha_9560/why-not-to-use-setinterval--2na9 - - L.loopCall uses setTimeout recursively, which is a technique - reportedly more reliabale than setInterval. - - L.loopCall repeatedly calls (invokes) the callback function provided as its first argument. - The first call is immediate, but subsequent calls are delayed by the milliseconds - provided as the second argument. All additional arguments are optional - to be used by the callback if required. - - If needed, you can delay the initial call as well, - by having loopCall invoked by setTimeout using the same delay: - - setTimeout(L.loopCall, delay, callback, delay, arg1, arg2 ...) - - or the more readable, but more risky ... - - setTimeout("L.loopCall(callback, delay, arg1, arg2 ...)", delay) - //Doug Crockford would not be pleased - - To stop the loop, the callback function can test some external state condition, - (or test its own arguments, if they are passed by reference): - - if(externalStateCondition){ - L.loopCall.stop() - } -*/ -L.loopCall = function (callback, delay, ...args){ - L.loopCall.stopLoop = setTimeout(L.loopCall, delay, callback, delay, ...args) - callback(...args) -} - -L.loopCall.stop = () => { - clearTimeout(L.loopCall.stopLoop) -} - -/** - Returns an array that is the "mathematical or logical" symmetric difference among or between - any number of arrays provided as arguments (usually two). If the order of members is ignored - (as is done for mathematical sets), the result acts as the the exclusive-or (XOR), also know as - the disjunctive union. For the trivial cases of comparing one or two arrays, the result is - not surprising: for one array, the result is itself: L.symDiff(A, []) => A ⊕ [] = A. - For two arrays, the result is an array that has only members which are not shared in common: - L.symDiff(A, B) => A ⊕ B . - When comparing more than two arrays, the result may ne surprising. The proper result can be verified - by comparing only two at a time: L.symDiff(A, B, C) => A ⊕ B ⊕ C = (A ⊕ B) ⊕ C -*/ -L.symDiff = function symDiff(arrayA, arrayB){ // dummy paramters NOT referenced in body of the function - var partialSymDiff = [], - argsArray = arguments - ; - //============THE CRUX================= - return findSymDiff(partialSymDiff,0); - //============UNDER THE HOOD=========== - function findSymDiff(partialSymDiff,index){ - if (argsArray[index] === undefined){ - return partialSymDiff; - } - else{ - partialSymDiff = sd(partialSymDiff, argsArray[index] ); - return findSymDiff( partialSymDiff, index + 1 ); - } - } - //===================================== - function sd(arrayI, arrayJ){ - var diff = [], - blackList = [], - i = 0, - j = 0, - maxI = arrayI.length, - maxJ = arrayJ.length - ; - //------------------------------------------------- - //1.) Combine the arrays into a third array. - //2.) Find the matched elements and place them into a blacklist array. - //3.) Pull blacklisted elements from the combined array. - //4.) return the "reduced" combined array. - //--------------------------------------------------- - // 1.) Combine the arrays into a third array. - diff = arrayI.concat(arrayJ); - //--------------------------------------------------- - // 2.) Find the matched elements and place them into a blacklist array. - for ( i=0; i < maxI; i++ ){ - for( j=0; j< maxJ; j++ ){ - if(arrayI[i] === arrayJ[j]){ - blackList.push(arrayI[i] ); - } - } - } - //---------------------------------------------------- - // 3.) Pull blacklisted elements from the combined array. - diff = diff.filter( (element) => blackList.indexOf(element) === -1 ) - //---------------------------------------------------- - // 4.) return the "reduced" combined array. - return killDupes(diff); - } - //======================================================== - function killDupes(array){ - var kept = []; // Record of the "keepers" - return array.filter(function(element){ - if ( kept.indexOf(element) === -1 ){ //if not already retained ... - kept.push(element); // Record it as retained now, and... - return true; // allow this element to be kept (true) - } - else{ - return false; // otherwise, don't keep it (already kept) - } - }); - } -}; - -/** - * Pass in a numerical seconds: it returns a string in the format - * mm : ss, like ... - * 35 : 37 in minutes and seconds -*/ -L.secToMinSec = (seconds) =>{ - var min = Math.floor(seconds / 60); - var sec = Math.floor(seconds % 60); - if(isNaN(min)){min = 0} - if(isNaN(sec)){sec = 0} - var zeroMin = ((min < 10) ? ("0" + min) : ("" + min)); - var zeroSec = ((sec < 10) ? ("0" + sec) : ("" + sec)); - var minSec = zeroMin + ":" + zeroSec; - return minSec; -}; -//====| END of secToMinSec |====// - -///////////////////| START of CreateListMixer |////////////////////// -/** - * CreateListMixer: a factory that creates and returns a function that - * returns a random item from the collection (array or object) provided. - * Notes: Example-> var list = ["a", "short", "list"];//three (3) items to test - * var getRandomItem = CreateListMixer(); - * getRandomItem(list);//returns first of randomized list - * getRandomItem();//returns next item - * getRandomItem();//returns next item (last of three) - * getRandomItem();//new first item from re-randomized list - * - * // a new list; - * var list2 = { record1: "string", record2: "anotherString", ...}; - * getRandomItem(list2);//returns first of new randomized list2 - * getRandomItem();//etc. - * It returns a property name for objects or an array member for arrays; - * It returns 'false' if argument of function is not an object - * or an array (fails typeof arg === 'object') - * -*/ -L.CreateListMixer = function(){ - var list=[], - randList= [], - listLength= 0, - itemReturned= null, - itemReturnedIndex= -1 - ; - return function(){ - if(arguments[0]){ - if(typeof arguments[0] === 'object'){ - list = arguments[0]; - if({}.toString.call(arguments[0]) === '[object Object]'){ - list = Object.keys(list); - } - randList = randomize(list); - listLength = list.length; - } - else{ - return false; - } - } - //----| no args activity: return next random item |---- - if(itemReturnedIndex >= listLength-1){ - do{ - randList = randomize(list); - itemReturnedIndex = -1; - } - while(randList[itemReturnedIndex +1] === itemReturned); - } - itemReturnedIndex++; - itemReturned = randList[itemReturnedIndex]; - return itemReturned; - //-----helpers----- - function randomize(x){ - var mixedIndexes = []; - var randomList = []; - randomizeIndexes(); - return randomList; - //----sub helper---- - function randomizeIndexes(){ - // random numbers for mixedIndexes - while(mixedIndexes.length !== x.length){ - var match = false; - var possibleIndex = (x.length)*Math.random(); - possibleIndex = Math.floor(possibleIndex); - mixedIndexes.forEach(function(m){ - if(m === possibleIndex){ - match = true; - } - }); - if(!match){ - mixedIndexes.push(possibleIndex); - } - } - for(var i = 0; i < x.length; i++){ - var newIndex = mixedIndexes[i]; - randomList.push(list[newIndex]); - } - } - } - };//===| END returned function |====== -}//===| END enclosing factory function====== -///////////////////| END of CreateListMixer |////////////////////// - -///////////////////| START of scrammbleThis |////////////////////// -/** - scrammbleThis: (depends on createListMixer, above) - It returns an array of randomly arranged items of the collection provided. - The argument must be an array, an object, or a string. - If the argument is an object, a random array of its property names is returned. - If the argument is a string, a random array of its characters is returned. - If the argument is an array, a random array of its members is returned. -*/ -L.scrammbleThis = function(collection){ - if ( !(typeof collection === 'object' || typeof collection === 'string') ){return collection} - var mix = L.CreateListMixer(); - var list = (Object.prototype.toString.call(collection) === '[object Array]') - ? collection - : (typeof collection === 'string') - ? collection.split('') - : (typeof collection === 'object') - ? Object.keys(collection) - : null - return list.map((m,i,a)=> (i === 0) ? mix(a) : mix()) -} -///////////////////| END of scrammbleThis |////////////////////// - -/** - Given an array of string arrays, this function returns an alphabetized version -*/ -L.sortArrayOfStringArrays = function(arrayOfStringArrays, linkToken='```'){ - //use a unique token (default = triple back-ticks ```) to join the strings of each array of strings - const arrayOfStrings = arrayOfStringArrays.map(stringArray => stringArray.join(linkToken)) - - //case-insensitive sort this array of strings, mutating it in place: - //https://stackoverflow.com/questions/8996963/how-to-perform-case-insensitive-sorting-in-javascript - arrayOfStrings.sort( (a,b) => a.toLowerCase().localeCompare(b.toLowerCase()) ) - - //return a new array of string arrays after splitting the strings on the unique token - return arrayOfStrings.map( string => string.split(linkToken)) -}"; \ No newline at end of file diff --git a/data/collaborative/shadow/index.db b/data/collaborative/shadow/index.db deleted file mode 100755 index 6f8d5a7..0000000 --- a/data/collaborative/shadow/index.db +++ /dev/null @@ -1,114 +0,0 @@ -|filename:%2Fvar%2Fwww%2Fhtml%2Findex.php|user:xevidos|>b039f3a0fad6690bccc0969dbe561fcd> -|filename:%2Fvar%2Fwww%2Fhtml%2Findex.php|user:test|>a0debe38b2118dc397cfe4898ab46b9e> -|filename:%2Fvar%2Fwww%2Fhtml%2Ftest.php|user:test|>7c998484eb7cf6925bb4c8c12d9da2fc> -|filename:%2Fvar%2Fwww%2Fhtml%2Fcontacts%2Fcontacts.csv|user:sabbakilam|>4b5e696279610e8b11147b869777b685> -|filename:%2Fvar%2Fwww%2Fhtml%2Fdev%2Fquizzes.php|user:xevidos|>51108580d8b1830f9d7e48021d6bde46> -|filename:%2Fvar%2Fwww%2Fhtml%2Fcontacts%2FmethodsREACT.js|user:sabbakilam|>af2d3669b4f915c4b09d4a8bb8dea1c9> -|filename:%2Fvar%2Fwww%2Fhtml%2Fcolor_wheel%2Findex.html|user:sabbakilam|>6f1528298858cf4548f52302b9b3df09> -|filename:%2Fvar%2Fwww%2Fhtml%2Fcolor_wheel%2Fjs%2Fscript.js|user:sabbakilam|>a6c8c908850fdd2fba740ab39de66cd2> -|filename:%2Fvar%2Fwww%2Fhtml%2Fmusic%2Findex.html|user:sabbakilam|>e693185c0b5a32ed6979e22b10f1e433> -|filename:%2Fvar%2Fwww%2Fhtml%2Fmusic%2Fstyles.css|user:sabbakilam|>1fad7d7bf81e5524143caee6f21cdfcf> -|filename:%2Fvar%2Fwww%2Fhtml%2Fmusic%2Fphp%2Flogin.php|user:sabbakilam|>f0e5f885ff64458f62a2f0c202070139> -|filename:%2Fvar%2Fwww%2Fhtml%2Fmusic%2FmethodsUPDATE.js|user:sabbakilam|>9412cdcf8b955c57d704e4994234d890> -|filename:%2Fvar%2Fwww%2Fhtml%2Fmusic%2FMVC.js|user:sabbakilam|>9efb45e0fb52aae6da0f0aafa65a2485> -|filename:%2Fvar%2Fwww%2Fhtml%2Fmusic%2FmethodsREACT.js|user:sabbakilam|>3cd97ad18d409c51b5578b0b34c80ce6> -|filename:%2Fvar%2Fwww%2Fhtml%2Fmusic%2FmethodsHELPER.js|user:sabbakilam|>d431495cf623dd61f00bfa1aef2c6e0c> -|filename:web2%2Findex.php|user:xevidos|>3403458d3f9421a02e422cfe62741852> -|filename:web2%2Findex.php|user:TrevorBeresford|>a7f6228ec1c43e9c52f5e91d07d4b453> -|filename:web2%2Findex.html|user:sabbakilam|>57e91e0d3a50e23bca8a00a5e7539758> -|filename:web2%2Findex.html|user:xevidos|>b7e0dffe6d3af66063c9752be07c9e75> -|filename:web2%2Fjs%2FfunctionsINITIALIZE.js|user:sabbakilam|>65dd434e2ad28232ea285fab94ddfb75> -|filename:web2%2Fjs%2FfunctionsINITIALIZE.js|user:xevidos|>e48aa03433d347bfaffcb9429f62a27c> -|filename:web2%2Fjs%2FInitialize.js|user:sabbakilam|>5b9b38f2e267013b0042f802a120442b> -|filename:web2%2Fjs%2FInitialize.js|user:xevidos|>2497b873b6c596aa0da54c628cb5fbd5> -|filename:web2%2Fjs%2FQualify.js|user:sabbakilam|>0b1d76a6acf247da79040a128cc3a528> -|filename:web2%2Fjs%2FUpdate.js|user:sabbakilam|>7f86659d402c096aeedb08e84283f596> -|filename:web2%2Fjs%2FXtra.js|user:sabbakilam|>a2a72e21333cf981f4a2281f1504cea3> -|filename:web2%2Fcss%2Fstyles|user:xevidos|>bfd3f8ef41ef1f98968c106a423699b2> -|filename:web2%2Findex.html|user:TrevorBeresford|>f858621dbec7ad5f5a1f28be85acf0f0> -|filename:web2%2Fcss%2Fstyles.css|user:xevidos|>ee62af99d5b417b7381e5299027cca6e> -|filename:web2%2Fjs%2FL.js|user:sabbakilam|>81996f949129f48e0128cdb7b3cb7716> -|filename:web2%2FL.js|user:sabbakilam|>7ff97b3475c197f26cad514f22ceb86b> -|filename:web2%2FL.js|user:xevidos|>07a6a7a936469108b7eb1d5595405b41> -|filename:web2%2FL.js|user:TrevorBeresford|>5456a19d342557d417efd28aced31c16> -|filename:web2%2Fjs%2FInitialize.js|user:TrevorBeresford|>62da00833cc673ea3506e8c74cc03010> -|filename:web2%2Fjs%2FQualify.js|user:xevidos|>1972a2c94075705efcb5226d1ac9889b> -|filename:web2%2Fjs%2FQualify.js|user:TrevorBeresford|>cdc42f08882d002bac276e9c1bdcac67> -|filename:web2%2Fjs%2FUpdate.js|user:xevidos|>e275a3a559f2c49aff391d8cc3fe538d> -|filename:web2%2Fjs%2FUpdate.js|user:TrevorBeresford|>ee3d3118cdab96fd9c2343d4742f2810> -|filename:web2%2Fcss%2Fstyles.css|user:TrevorBeresford|>ede158f1f62eabab87526f2db25fad17> -|filename:web2%2Fcss%2Fstyles.css|user:sabbakilam|>b18552684dcd0101a4c484af9d0f2615> -|filename:mobile_programming%2Findex.hml|user:xevidos|>64029b02e9eba9c858cf99ac5488be14> -|filename:mobile_programming%2Fcss%2Fstyles.css|user:xevidos|>76a80f9d3d1f00f202f5b6a01af0fe82> -|filename:mobile_programming%2Findex.html|user:xevidos|>f3d17d035479bb837c846584a985fc9b> -|filename:mobile_programming%2Findex.html|user:FrankSmith22|>51640228b7c95ec21668deae8e14fd37> -|filename:mobile_programming%2Fcss%2Fstyles.css|user:sabbakilam|>6c9195df1db60f35f1cdb2d9ee97e4bf> -|filename:mobile_programming%2Findex.html|user:TrevorBeresford|>a7591bf8af26986d68f36815a5ea5273> -|filename:mobile_programming%2Fcss%2Fstyles.css|user:FrankSmith22|>f46fc66fdb891a570f1a03add3c166cc> -|filename:mobile_programming%2Fcss%2Fstyles.css|user:ithollie|>ddd0681a0e90f0480910b3fb7719dde7> -|filename:mobile_programming%2Findex.html|user:ithollie|>6e2f31eef830626055498ba7ba41f3dc> -|filename:mobile_programming%2Fcss%2Fstyles.css|user:TrevorBeresford|>eceb4e0876fe71ea018f446d0d34eca1> -|filename:mobile_programming%2Findex.html|user:sabbakilam|>52e4730d2a0be9abffbc2bdea2204b5e> -|filename:mobile_programming%2FL.js|user:xevidos|>e2630975cd26f1f4330486f3d0a9055e> -|filename:mobile_programming%2FL.js|user:FrankSmith22|>6a4b62d9024b66e2e6b0601593581d96> -|filename:mobile_programming%2FL.js|user:sabbakilam|>fe7e13bcdd4f10c3c8c55b3bb59e5ef8> -|filename:mobile_programming%2Fjs%2FUpdate.js|user:xevidos|>74dea1994cc8087e93aa43126d0609fb> -|filename:mobile_programming%2Fjs%2FInitialize.js|user:FrankSmith22|>e6ca864b939a36765d43aa4ae3e8503e> -|filename:mobile_programming%2Fjs%2FQualify.js|user:ithollie|>cc91755cde6ab90a7f2aada55994f97b> -|filename:mobile_programming%2Fjs%2FXtra.js|user:TrevorBeresford|>c34a5d1f562bfd5f37c3de4632f25a47> -|filename:mobile_programming%2Fjs%2FInitialize.js|user:xevidos|>37663faf229dd1ba5c77f60047934098> -|filename:mobile_programming%2Fjs%2FInitialize.js|user:sabbakilam|>76e43d7b712f43510dae0cbf50e40bc9> -|filename:mobile_programming%2Fjs%2FQualify.js|user:xevidos|>bc2ad9133d134977d621104c59e9fd61> -|filename:mobile_programming%2Fjs%2FXtra.js|user:xevidos|>23295112670db74d060930018ea19538> -|filename:mobile_programming%2Fjs%2FInitialize.js|user:TrevorBeresford|>0bde8ce947815fedb4f056ef7111cc47> -|filename:mobile_programming%2Fjs%2FInitialize.js|user:ithollie|>22f1d2494993531e6b1a016a8d8b6438> -|filename:mobile_programming%2FL.js|user:TrevorBeresford|>74153bbd75415243bee04ba5be3e0975> -|filename:mobile_programming%2Fjs%2FQualify.js|user:FrankSmith22|>2741708a0ee997fc889e4770f0a3b8ea> -|filename:mobile_programming%2Fjs%2FQualify.js|user:sabbakilam|>97d4726a27b0dc089ff2a1ebd49794c6> -|filename:mobile_programming%2Fjs%2FQualify.js|user:TrevorBeresford|>1fe1266a755f7810fe2c73344d75770e> -|filename:mobile_programming%2Fjs%2FUpdate.js|user:sabbakilam|>41bbb319169d502d14088dd0ef762533> -|filename:mobile_programming%2Fjs%2FUpdate.js|user:FrankSmith22|>92e0d8216f938e9f6450634e2ac0d0da> -|filename:mobile_programming%2Fjs%2FUpdate.js|user:TrevorBeresford|>3ba13a3d4c97cda98f8675c7bccd82fe> -|filename:mobile_programming%2Fjs%2FUpdate.js|user:ithollie|>8ca94770f4850fd864af830a177c90aa> -|filename:html%2Fcode%2Fconfig.php|user:xevidos|>ccdab27e57aa054e492f5b3d3850f6e5> -|filename:html%2Fweb2%2Fconfig.php|user:xevidos|>d06ec8c63e9acac96c0817560b2dfabe> -|filename:html%2Fmobile_programming%2Fconfig.php|user:xevidos|>08791dea727327b5a0481e2a8fb350ff> -|filename:dev%2F.htaccess|user:xevidos|>2e951e1c04a09a48fa2ccc2c730cc7fd> -|filename:dev%2Fquizzes.php|user:xevidos|>b64f8e080258d3fa416e98888a27cea5> -|filename:dev%2Fteacher.php|user:xevidos|>ea5288a62fdc3f1ebfab27f709082842> -|filename:dev%2Fstudents%2Fpages.php|user:xevidos|>7ed2ef8c2f8f09385af754d69279db57> -|filename:dev%2Fstudents%2Fstudents.php|user:xevidos|>1dbc3b6b9a38f3065d2276656017f3f9> -|filename:dev%2Fpublic%2Fpublic.php|user:xevidos|>eef1f14577636af47a8ee7f55ba777bf> -|filename:dev%2Fincludes%2Fheader.php|user:xevidos|>3e7c9f851da2aad425970b0be26f77ac> -|filename:dev%2Fassets%2Fcss%2Fstyles.css|user:xevidos|>ef7b395faeaf7d9a60fd54f2dca409e5> -|filename:html%2Fweb2%2Fcomponents%2Factive%2Fclass.active.php|user:xevidos|>dc103bcc7b8517ba408c3c19eca08b6e> -|filename:html%2Fmobile_programming%2Fcomponents%2Factive%2Fclass.active.php|user:xevidos|>acb11eb95add8cfd988d342e3de0d2e8> -|filename:html%2Fcode%2Fdata%2Fcollaborative%2Ftext%2Fa9a0fb5543ed2953ba292d5f62bf6ae8|user:xevidos|>b818ce32cd61aa5d83fbf357d1184635> -|filename:html%2Fcode%2Fcomponents%2Factive%2Fclass.active.php|user:xevidos|>a8419f9f1457039c7fbc9740927be4e0> -|filename:html%2Finfo.php|user:xevidos|>f6d27d5345b78d2d52c54cb2ada888f5> -|filename:html%2Fweb2%2Fplugins%2Fauto_save%2Finit.js|user:xevidos|>a43aba4776a318fab1ae3091a8dfd1e9> -|filename:html%2Fdev%2Findex.php|user:xevidos|>0c7b6f96afab6e8fda974eea5a93e5c0> -|filename:html%2Fcode%2Fplugins%2Fauto_save%2Finit.js|user:xevidos|>870b887e9a5909882cbcebb4ba14b794> -|filename:html%2Fcode%2Fplugins%2Fauto_save%2Fplugin.json|user:xevidos|>e1ea49c66882f7882bfc53f7f896d31d> -|filename:html%2Fmobile_programming%2Fplugins%2Fauto_save%2Finit.js|user:xevidos|>4e259f0bb87191d1f975f535dae106ea> -|filename:html%2Fcode%2Fcomponents%2Ffilemanager%2Finit.js|user:xevidos|>5e7826f99928dc790d9cba5022cc30b4> -|filename:html%2Fcode%2Fcomponents%2Factive%2Finit.js|user:xevidos|>49f589063ce4ea454204ce70b134a893> -|filename:html%2Fmobile_programming%2Fplugins%2FCodiad-CodeGit-master%2Finit.js|user:xevidos|>045f3b992ba538f82bbed4df39459fa9> -|filename:html%2Fmobile_programming%2Fcomponents%2Ffilemanager%2Finit.js|user:xevidos|>09f6bedc033ef7c069a54c82fa8c7e62> -|filename:html%2Fmobile_programming%2Fcomponents%2Factive%2Fdialog.php|user:xevidos|>3acf50a01e367e57cdfb32a08ac50fd0> -|filename:html%2Fmobile_programming%2Fcomponents%2Factive%2Finit.js|user:xevidos|>5bb4642abdf3f7aa35eafebcba91df17> -|filename:html%2Fweb2%2Fplugins%2Fauto_save%2Fplugin.json|user:xevidos|>26d17024aafb824e93365a9d8d404b90> -|filename:html%2Ftest.txt|user:xevidos|>941568d6e728e0f58bf59a686509defa> -|filename:html%2Fweb2%2Fcomponents%2Ffilemanager%2Finit.js|user:xevidos|>e1726a184e69c885fe27c8669b2c885e> -|filename:html%2Findex.php|user:xevidos|>29a1edb2a360ce477af0bf0ecb5a2447> -|filename:html%2F.htaccess|user:xevidos|>7fa8be2ce86bf557e18b4d8ffe01ab67> -|filename:html%2Fcode%2Fplugins%2FCodiad-CodeSettings-master%2Finit.js|user:xevidos|>a8774609eda0bf3aa1cb32a96b594604> -|filename:html%2Fcode%2Fplugins%2FCodiad-ColorPicker-master%2Finit.js|user:xevidos|>a86d8153e2f67aeb9590093a5c30a149> -|filename:html%2Fcode%2Fdata%2Fcollaborative%2Ftext%2Fec501c81f6d7f8903809691ef846031d|user:xevidos|>41118f97725e869c87455be694a53fe5> -|filename:html%2Fcode%2Fplugins%2FCodiad-Together-master%2Ftogetherjs%2FtogetherjsPackage.js|user:xevidos|>d778ad34ea1212ed7081b731d9a8dd80> -|filename:html%2Fcode%2Fcomponents%2Fupdate%2Fclass.update.php|user:xevidos|>7f444cf225792632b9816fd7c212e785> -|filename:html%2Fcode%2Fdata%2Fversion.php|user:xevidos|>bdd330a1af3dca522aae993ac38cf3c5> -|filename:html%2Fcode%2Fcomponents%2Finstall%2Fprocess.php|user:xevidos|>abaaf90695610e34effe00775cd6f641> -|filename:html%2Fcode%2Fcomponents%2Fupdate%2Finit.js|user:xevidos|>45c06d935cb54cb6c59260028d5bb91c> -|filename:html%2Fcode%2Fcomponents%2Fupdate%2Fcontroller.php|user:xevidos|>cbc7af3f90284b745f9cca4430668ab5> -|filename:html%2Fcode%2Fcomponents%2Fupdate%2Fdialog.php|user:xevidos|>0231def7a6a1608f8242d5dfeee17fec> diff --git a/data/collaborative/text/060728b4cccf0e88d2d445947e0f6836 b/data/collaborative/text/060728b4cccf0e88d2d445947e0f6836 deleted file mode 100755 index 73631c9..0000000 --- a/data/collaborative/text/060728b4cccf0e88d2d445947e0f6836 +++ /dev/null @@ -1,33 +0,0 @@ -s:699:" -
    - -

    Looking for a quiz? Select one of the teachers below to view their active quizzes.

    - -
      - $value ) { - - echo "
    • $value
    • "; - } - ?> -
    - -
    "; \ No newline at end of file diff --git a/data/collaborative/text/0874412e2b238973158064bf29510f49 b/data/collaborative/text/0874412e2b238973158064bf29510f49 deleted file mode 100755 index c042890..0000000 --- a/data/collaborative/text/0874412e2b238973158064bf29510f49 +++ /dev/null @@ -1,59 +0,0 @@ -s:1170:"/* - * Place copyright or other info here... - */ - -(function(global, $){ - - // Define core - var codiad = global.codiad, - scripts= document.getElementsByTagName('script'), - path = scripts[scripts.length-1].src.split('?')[0], - curpath = path.split('/').slice(0, -1).join('/')+'/'; - - // Instantiates plugin - $(function() { - codiad.tela_auto_save.init(); - }); - - codiad.tela_auto_save = { - - // Allows relative `this.path` linkage - path: curpath, - - init: function() { - - // Start your plugin here... - //let editor = document.getElementsByClassName( 'ace_content' )[0]; - let auto_save_trigger = setInterval( this.auto_save, 500 ); - }, - - /** - * - * This is where the core functionality goes, any call, references, - * script-loads, etc... - * - */ - - auto_save: function() { - - let tabs = document.getElementsByClassName( "tab-item" ); - tabs = Array.from( tabs ); - tabs.forEach( function( m, i, a ) { - - // M = Current entry - // I = Index as integer - // A = Entire array - - if ( m.classList.contains( "active" ) ) { - - m.classList.remove( "changed" ) - } - }); - - codiad.active.save; - } - - }; - -})(this, jQuery); -"; \ No newline at end of file diff --git a/data/collaborative/text/098797bf7c4448ed6397b23257b8d0d1 b/data/collaborative/text/098797bf7c4448ed6397b23257b8d0d1 deleted file mode 100755 index add08a4..0000000 --- a/data/collaborative/text/098797bf7c4448ed6397b23257b8d0d1 +++ /dev/null @@ -1,102 +0,0 @@ -s:3012:"/*global L*/ -/*global m*/ -/*global v*/ -/*global c*/ - -/////////////////////////////////////////////// -c.updateModel = (eventObject) => { - c.setMetaEvents(eventObject, m); - const functionQualifiers = { - setResize: [m.resized], - uploadFiles: [m.source === v.fileElement, m.type === 'change'], - setPlay: [m.source === v.btnPlay, m.clicked], - playChosenSong: [m.source === v.documentSelector, m.type === 'change'], - respondToEnded: [m.source === v.player, m.type === 'ended'], - respondToPause: [m.source === v.player, m.type === 'pause'], - respondToPlay: [m.source === v.player, m.type === 'play'], - deleteFile: [m.source === v.btnDelete, m.clicked], - setPictureOnly: [m.source === v.pictureHolder || m.source === v.background, m.clicked], - setLogout: [m.source === v.footerGlass, m.clicked], - setLogin: [m.source === v.passwordInput, m.type === "keyup"], - setToggleNonStop: [m.source === v.btnNonStop, m.clicked], - } - L.runQualifiedFunctions(functionQualifiers, m, v, c) - //-----------------// - if(!m.resized){ - window.localStorage.setItem(`model`, JSON.stringify(m)); - } - c.updateView(v); -}; -//-----------------------------// -c.updateView = (v) => { - //c.showInfo(v) -}; -///////////////////////////////////////// -c.setMetaEvents = (eventObject, model) => { - let m = model;//model is "passed by reference" - m.id = eventObject.target.id; - m.source = eventObject.target - m.eventObject = eventObject; - //add current event object, discard oldest event object: - m.eventArray.unshift(m.eventObject); - m.eventArray.pop(); - - m.type = eventObject.type; - //add current, discard oldest: - m.priorType.unshift(m.type); - m.priorType.pop(); - - m.pressed = m.type === 'mousedown' || m.type === 'touchstart'; - //add current, discard oldest: - m.priorPressed.unshift(m.pressed); - m.priorPressed.pop(); - - m.released = m.type === 'mouseup' || m.type === 'touchend'; - //add current, discard oldest: - m.priorReleased.unshift(m.released); - m.priorReleased.pop(); - - m.moved = m.type === 'mousemove' || m.type === 'touchmove'; - //add current, discard oldest: - m.priorMoved.unshift(m.moved); - m.priorMoved.pop(); - - m.startTime = Date.now(); - m.elapsedTime = m.startTime - m.priorStartTime; - m.elapsedMinSec = L.secToMinSec(60 * m.elapsedTime); - m.priorStartTime = m.startTime; - - m.resized = ( - m.type === 'resize' || - m.type === 'load' || - m.type === 'DOMContentLoaded' || - m.type === 'orientationchange' - ); - /* - m.CLICK_TIME_MIN = 25 //in milliseconds - m.CLICK_TIME_MAX = 750 //milliseconds - */ - m.clicked = ( - m.released && - m.elapsedTime >= m.CLICK_TIME_MIN && - m.elapsedTime <= m.CLICK_TIME_MAX && - ( - m.priorType[1] === `touchstart` || - m.priorType[1] ==`mousedown`|| - m.priorType[1] === `touchmove` || - m.priorType[1] ==`mousemove` - ) - ); - /* - if(!m.moved){ - console.log(o) - } - */ -}; -//======================================// - - - - - -"; \ No newline at end of file diff --git a/data/collaborative/text/0b00081372c3f176d14f3626f2ff3ef5 b/data/collaborative/text/0b00081372c3f176d14f3626f2ff3ef5 deleted file mode 100755 index 1809f82..0000000 --- a/data/collaborative/text/0b00081372c3f176d14f3626f2ff3ef5 +++ /dev/null @@ -1,69 +0,0 @@ -s:1621:"/* - * Place copyright or other info here... - */ - -(function(global, $){ - - // Define core - var codiad = global.codiad, - scripts= document.getElementsByTagName('script'), - path = scripts[scripts.length-1].src.split('?')[0], - curpath = path.split('/').slice(0, -1).join('/')+'/'; - - // Instantiates plugin - $(function() { - codiad.tela_auto_save.init(); - }); - - codiad.tela_auto_save = { - - // Allows relative `this.path` linkage - path: curpath, - - init: function() { - - // Start your plugin here... - let editor = document.getElementsByClassName( 'ace_content' )[0]; - let auto_save_trigger = setInterval( this.auto_save, 500 ); - }, - - /** - * - * This is where the core functionality goes, any call, references, - * script-loads, etc... - * - */ - - auto_save: function() { - - let tabs = document.getElementsByClassName( "tab-item" ); - let path = codiad.active.getPath(); - let content = codiad.editor.getContent; - tabs = Array.from( tabs ); - tabs.forEach( function( m, i, a ) { - - // M = Current entry - // I = Index as integer - // A = Entire array - - if ( m.classList.contains( "active" ) ) { - - m.classList.remove( "changed" ) - } - }); - - codiad.active.save; - codiad.filemanager.saveFile(path, newContent, localStorage.removeItem(path)); - var session = codiad.active.sessions[path]; - if(typeof session != 'undefined') { - session.untainted = newContent; - session.serverMTime = mtime; - if (session.listThumb) session.listThumb.removeClass('changed'); - if (session.tabThumb) session.tabThumb.removeClass('changed'); - } - } - - }; - -})(this, jQuery); -"; \ No newline at end of file diff --git a/data/collaborative/text/1bb5e516806eb514fb3779d8dff2bf13 b/data/collaborative/text/1bb5e516806eb514fb3779d8dff2bf13 deleted file mode 100755 index e054c52..0000000 --- a/data/collaborative/text/1bb5e516806eb514fb3779d8dff2bf13 +++ /dev/null @@ -1,773 +0,0 @@ -s:34893:"/* - * Copyright (c) Codiad & Kent Safranski (codiad.com), distributed - * as-is and without warranty under the MIT License. See - * [root]/license.txt for more. This information must remain intact. - */ - -(function(global, $){ - - var codiad = global.codiad; - - $(window) - .load(function() { - codiad.filemanager.init(); - }); - - codiad.filemanager = { - - clipboard: '', - - noOpen: ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'exe', 'zip', 'tar', 'tar.gz'], - noBrowser: ['jpg', 'jpeg', 'png', 'gif', 'bmp'], - - controller: 'components/filemanager/controller.php', - dialog: 'components/filemanager/dialog.php', - dialogUpload: 'components/filemanager/dialog_upload.php', - - init: function() { - // Initialize node listener - this.nodeListener(); - // Load uploader - $.loadScript("components/filemanager/upload_scripts/jquery.ui.widget.js", true); - $.loadScript("components/filemanager/upload_scripts/jquery.iframe-transport.js", true); - $.loadScript("components/filemanager/upload_scripts/jquery.fileupload.js", true); - }, - - ////////////////////////////////////////////////////////////////// - // Listen for dbclick events on nodes - ////////////////////////////////////////////////////////////////// - - nodeListener: function() { - var _this = this; - - $('#file-manager').on('selectstart', false); - - $('#file-manager span') - .live('click', function() { // Open or Expand - if ($(this).parent().children("a").attr('data-type') == 'directory') { - _this.index($(this).parent().children("a") - .attr('data-path')); - } else { - _this.openFile($(this).parent().children("a") - .attr('data-path')); - } - if (!$(this).hasClass('none')) { - if ($(this).hasClass('plus')) { - $(this).removeClass('plus') - $(this).addClass('minus'); - } else { - $(this).removeClass('minus') - $(this).addClass('plus'); - } - } - }); - $('#file-manager a') - .live('dblclick', function() { // Open or Expand - if (!codiad.editor.settings.fileManagerTrigger) { - if ($(this) - .hasClass('directory')) { - _this.index($(this) - .attr('data-path')); - } else { - _this.openFile($(this) - .attr('data-path')); - } - if (!$(this).parent().children("span").hasClass('none')) { - if ($(this).parent().children("span").hasClass('plus')) { - $(this).parent().children("span").removeClass('plus') - $(this).parent().children("span").addClass('minus'); - } else { - $(this).parent().children("span").removeClass('minus') - $(this).parent().children("span").addClass('plus'); - } - } - } - }) - .live('click', function() { // Open or Expand - if (codiad.editor.settings.fileManagerTrigger) { - if ($(this) - .hasClass('directory')) { - _this.index($(this) - .attr('data-path')); - } else { - _this.openFile($(this) - .attr('data-path')); - } - if (!$(this).parent().children("span").hasClass('none')) { - if ($(this).parent().children("span").hasClass('plus')) { - $(this).parent().children("span").removeClass('plus') - $(this).parent().children("span").addClass('minus'); - } else { - $(this).parent().children("span").removeClass('minus') - $(this).parent().children("span").addClass('plus'); - } - } - } - }) - .live("contextmenu", function(e) { // Context Menu - e.preventDefault(); - _this.contextMenuShow(e, $(this) - .attr('data-path'), $(this) - .attr('data-type'), $(this) - .html()); - $(this) - .addClass('context-menu-active'); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Context Menu - ////////////////////////////////////////////////////////////////// - - contextMenuShow: function(e, path, type, name) { - var _this = this; - - // Selective options - switch (type) { - case 'directory': - $('#context-menu .directory-only, #context-menu .non-root') - .show(); - $('#context-menu .file-only, #context-menu .root-only') - .hide(); - break; - case 'file': - $('#context-menu .directory-only, #context-menu .root-only') - .hide(); - $('#context-menu .file-only,#context-menu .non-root') - .show(); - break; - case 'root': - $('#context-menu .directory-only, #context-menu .root-only') - .show(); - $('#context-menu .non-root, #context-menu .file-only') - .hide(); - break; - } - if(codiad.project.isAbsPath($('#file-manager a[data-type="root"]').attr('data-path'))) { - $('#context-menu .no-external').hide(); - } else { - $('#context-menu .no-external').show(); - } - // Show menu - var top = e.pageY; - if (top > $(window).height() - $('#context-menu').height()) { - top -= $('#context-menu').height(); - } - if (top < 10) { - top = 10; - } - var max = $(window).height() - top - 10; - - $('#context-menu') - .css({ - 'top': top + 'px', - 'left': e.pageX + 'px', - 'max-height': max + 'px' - }) - .fadeIn(200) - .attr('data-path', path) - .attr('data-type', type) - .attr('data-name', name); - // Show faded 'paste' if nothing in clipboard - if (this.clipboard === '') { - $('#context-menu a[content="Paste"]') - .addClass('disabled'); - } else { - $('#context-menu a[data-action="paste"]') - .removeClass('disabled'); - } - // Hide menu - $('#file-manager, #editor-region') - .on('mouseover', function() { - _this.contextMenuHide(); - }); - /* Notify listeners. */ - amplify.publish('context-menu.onShow', {e: e, path: path, type: type}); - // Hide on click - $('#context-menu a') - .click(function() { - _this.contextMenuHide(); - }); - }, - - contextMenuHide: function() { - $('#context-menu') - .fadeOut(200); - $('#file-manager a') - .removeClass('context-menu-active'); - /* Notify listeners. */ - amplify.publish('context-menu.onHide'); - }, - - ////////////////////////////////////////////////////////////////// - // Return the node name (sans path) - ////////////////////////////////////////////////////////////////// - - getShortName: function(path) { - return path.split('/') - .pop(); - }, - - ////////////////////////////////////////////////////////////////// - // Return extension - ////////////////////////////////////////////////////////////////// - - getExtension: function(path) { - return path.split('.') - .pop(); - }, - - ////////////////////////////////////////////////////////////////// - // Return type - ////////////////////////////////////////////////////////////////// - - getType: function(path) { - return $('#file-manager a[data-path="' + path + '"]') - .attr('data-type'); - }, - - ////////////////////////////////////////////////////////////////// - // Create node in file tree - ////////////////////////////////////////////////////////////////// - - createObject: function(parent, path, type) { - // NODE FORMAT:
  • {short_name}
  • - var parentNode = $('#file-manager a[data-path="' + parent + '"]'); - if (!$('#file-manager a[data-path="' + path + '"]') - .length) { // Doesn't already exist - if (parentNode.hasClass('open') && parentNode.hasClass('directory')) { // Only append node if parent is open (and a directory) - var shortName = this.getShortName(path); - if (type == 'directory') { - var appendage = '
  • ' + shortName + '
  • '; - } else { - var appendage = '
  • ' + shortName + '
  • '; - } - if (parentNode.siblings('ul') - .length) { // UL exists, other children to play with - parentNode.siblings('ul') - .append(appendage); - } else { - $('
      ' + appendage + '
    ') - .insertAfter(parentNode); - } - } else { - parentNode.parent().children('span').removeClass('none'); - parentNode.parent().children('span').addClass('plus'); - } - } - }, - - ////////////////////////////////////////////////////////////////// - // Loop out all files and folders in directory path - ////////////////////////////////////////////////////////////////// - - indexFiles: [], - - index: function(path, rescan) { - var _this = this; - if (rescan === undefined) { - rescan = false; - } - node = $('#file-manager a[data-path="' + path + '"]'); - if (node.hasClass('open') && !rescan) { - node.parent('li') - .children('ul') - .slideUp(300, function() { - $(this) - .remove(); - node.removeClass('open'); - }); - } else { - node.addClass('loading'); - $.get(this.controller + '?action=index&path=' + encodeURIComponent(path), function(data) { - node.addClass('open'); - var objectsResponse = codiad.jsend.parse(data); - if (objectsResponse != 'error') { - /* Notify listener */ - _this.indexFiles = objectsResponse.index; - amplify.publish("filemanager.onIndex", {path: path, files: _this.indexFiles}); - var files = _this.indexFiles; - if (files.length > 0) { - if (node.parent().children('span').hasClass('plus')) { - node.parent().children('span').removeClass('plus').addClass('minus'); - } - var display = 'display:none;'; - if (rescan) { - display = ''; - } - var appendage = '
      '; - $.each(files, function(index) { - var ext = ''; - var name = files[index].name.replace(path, ''); - var nodeClass = 'none'; - name = name.split('/') - .join(' '); - if (files[index].type == 'file') { - var ext = ' ext-' + name.split('.') - .pop(); - } - if(files[index].type == 'directory' && files[index].size > 0) { - nodeClass = 'plus'; - } - appendage += '
    • ' + name + '
    • '; - }); - appendage += '
    '; - if (rescan) { - node.parent('li') - .children('ul') - .remove(); - } - $(appendage) - .insertAfter(node); - if (!rescan) { - node.siblings('ul') - .slideDown(300); - } - } - } - node.removeClass('loading'); - if (rescan && _this.rescanChildren.length > _this.rescanCounter) { - _this.rescan(_this.rescanChildren[_this.rescanCounter++]); - } else { - _this.rescanChildren = []; - _this.rescanCounter = 0; - } - }); - } - }, - - rescanChildren: [], - - rescanCounter: 0, - - rescan: function(path) { - var _this = this; - if (this.rescanCounter === 0) { - // Create array of open directories - node = $('#file-manager a[data-path="' + path + '"]'); - node.parent() - .find('a.open') - .each(function() { - _this.rescanChildren.push($(this) - .attr('data-path')); - }); - } - - this.index(path, true); - }, - - ////////////////////////////////////////////////////////////////// - // Open File - ////////////////////////////////////////////////////////////////// - - openFile: function(path, focus) { - if (focus === undefined) { - focus = true; - } - var node = $('#file-manager a[data-path="' + path + '"]'); - var ext = this.getExtension(path); - if ($.inArray(ext.toLowerCase(), this.noOpen) < 0) { - node.addClass('loading'); - $.get(this.controller + '?action=open&path=' + encodeURIComponent(path), function(data) { - var openResponse = codiad.jsend.parse(data); - if (openResponse != 'error') { - node.removeClass('loading'); - codiad.active.open(path, openResponse.content, openResponse.mtime, false, focus); - } - }); - } else { - if(!codiad.project.isAbsPath(path)) { - if ($.inArray(ext.toLowerCase(), this.noBrowser) < 0) { - this.download(path); - } else { - this.openInModal(path); - } - } else { - codiad.message.error(i18n('Unable to open file in Browser')); - } - } - }, - - ////////////////////////////////////////////////////////////////// - // Open in browser - ////////////////////////////////////////////////////////////////// - - openInBrowser: function(path) { - $.ajax({ - url: this.controller + '?action=open_in_browser&path=' + encodeURIComponent(path), - success: function(data) { - var openIBResponse = codiad.jsend.parse(data); - if (openIBResponse != 'error') { - window.open(openIBResponse.url, '_newtab'); - } - }, - async: false - }); - }, - openInModal: function(path) { - codiad.modal.load(250, this.dialog, { - action: 'preview', - path: path - }); - }, - saveModifications: function(path, data, callbacks, save=true){ - callbacks = callbacks || {}; - var _this = this, action, data; - var notifySaveErr = function() { - codiad.message.error(i18n('File could not be saved')); - if (typeof callbacks.error === 'function') { - var context = callbacks.context || _this; - callbacks.error.apply(context, [data]); - } - } - $.post(this.controller + '?action=modify&path=' + encodeURIComponent(path), data, function(resp){ - resp = $.parseJSON(resp); - if (resp.status == 'success') { - if ( save === true ) { - codiad.message.success(i18n('File saved')); - } - if (typeof callbacks.success === 'function'){ - var context = callbacks.context || _this; - callbacks.success.call(context, resp.data.mtime); - } - } else { - if (resp.message == 'Client is out of sync'){ - var reload = confirm( - "Server has a more updated copy of the file. Would "+ - "you like to refresh the contents ? Pressing no will "+ - "cause your changes to override the server's copy upon "+ - "next save." - ); - if (reload) { - codiad.active.close(path); - codiad.active.removeDraft(path); - _this.openFile(path); - } else { - var session = codiad.editor.getActive().getSession(); - session.serverMTime = null; - session.untainted = null; - } - } else codiad.message.error(i18n('File could not be saved')); - if (typeof callbacks.error === 'function') { - var context = callbacks.context || _this; - callbacks.error.apply(context, [resp.data]); - } - } - }).error(notifySaveErr); - }, - ////////////////////////////////////////////////////////////////// - // Save file - ////////////////////////////////////////////////////////////////// - - saveFile: function(path, content, callbacks, save=true) { - this.saveModifications(path, {content: content}, callbacks, save); - }, - - savePatch: function(path, patch, mtime, callbacks) { - if (patch.length > 0) - this.saveModifications(path, {patch: patch, mtime: mtime}, callbacks); - else if (typeof callbacks.success === 'function'){ - var context = callbacks.context || this; - callbacks.success.call(context, mtime); - } - }, - - ////////////////////////////////////////////////////////////////// - // Create Object - ////////////////////////////////////////////////////////////////// - - createNode: function(path, type) { - codiad.modal.load(250, this.dialog, { - action: 'create', - type: type, - path: path - }); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - var shortName = $('#modal-content form input[name="object_name"]') - .val(); - var path = $('#modal-content form input[name="path"]') - .val(); - var type = $('#modal-content form input[name="type"]') - .val(); - var createPath = path + '/' + shortName; - $.get(codiad.filemanager.controller + '?action=create&path=' + encodeURIComponent(createPath) + '&type=' + type, function(data) { - var createResponse = codiad.jsend.parse(data); - if (createResponse != 'error') { - codiad.message.success(type.charAt(0) - .toUpperCase() + type.slice(1) + ' Created'); - codiad.modal.unload(); - // Add new element to filemanager screen - codiad.filemanager.createObject(path, createPath, type); - if(type == 'file') { - codiad.filemanager.openFile(createPath, true); - } - /* Notify listeners. */ - amplify.publish('filemanager.onCreate', {createPath: createPath, path: path, shortName: shortName, type: type}); - } - }); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Copy to Clipboard - ////////////////////////////////////////////////////////////////// - - copyNode: function(path) { - this.clipboard = path; - codiad.message.success(i18n('Copied to Clipboard')); - }, - - ////////////////////////////////////////////////////////////////// - // Paste - ////////////////////////////////////////////////////////////////// - - pasteNode: function(path) { - var _this = this; - if (this.clipboard == '') { - codiad.message.error(i18n('Nothing in Your Clipboard')); - } else if (path == this.clipboard) { - codiad.message.error(i18n('Cannot Paste Directory Into Itself')); - } else { - var shortName = _this.getShortName(_this.clipboard); - if ($('#file-manager a[data-path="' + path + '/' + shortName + '"]') - .length) { // Confirm overwrite? - codiad.modal.load(400, this.dialog, { - action: 'overwrite', - path: path + '/' + shortName - }); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - var duplicate = false; - if($('#modal-content form select[name="or_action"]').val()==1){ - duplicate=true; console.log('Dup!'); - } - _this.processPasteNode(path,duplicate); - }); - } else { // No conflicts; proceed... - _this.processPasteNode(path,false); - } - } - }, - - processPasteNode: function(path,duplicate) { - var _this = this; - var shortName = this.getShortName(this.clipboard); - var type = this.getType(this.clipboard); - if(duplicate){ - shortName = "copy_of_"+shortName; - } - $.get(this.controller + '?action=duplicate&path=' + - encodeURIComponent(this.clipboard) + '&destination=' + - encodeURIComponent(path + '/' + shortName), function(data) { - var pasteResponse = codiad.jsend.parse(data); - if (pasteResponse != 'error') { - _this.createObject(path, path + '/' + shortName, type); - codiad.modal.unload(); - /* Notify listeners. */ - amplify.publish('filemanager.onPaste', {path: path, shortName: shortName, duplicate: duplicate}); - } - }); - }, - - ////////////////////////////////////////////////////////////////// - // Rename - ////////////////////////////////////////////////////////////////// - - renameNode: function(path) { - var shortName = this.getShortName(path); - var type = this.getType(path); - var _this = this; - codiad.modal.load(250, this.dialog, { action: 'rename', path: path, short_name: shortName, type: type}); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - var newName = $('#modal-content form input[name="object_name"]') - .val(); - // Build new path - var arr = path.split('/'); - var temp = new Array(); - for (i = 0; i < arr.length - 1; i++) { - temp.push(arr[i]) - } - var newPath = temp.join('/') + '/' + newName; - $.get(_this.controller, { action: 'modify', path: path, new_name: newName} , function(data) { - var renameResponse = codiad.jsend.parse(data); - if (renameResponse != 'error') { - codiad.message.success(type.charAt(0) - .toUpperCase() + type.slice(1) + ' Renamed'); - var node = $('#file-manager a[data-path="' + path + '"]'); - // Change pathing and name for node - node.attr('data-path', newPath) - .html(newName); - if (type == 'file') { // Change icons for file - curExtClass = 'ext-' + _this.getExtension(path); - newExtClass = 'ext-' + _this.getExtension(newPath); - $('#file-manager a[data-path="' + newPath + '"]') - .removeClass(curExtClass) - .addClass(newExtClass); - } else { // Change pathing on any sub-files/directories - _this.repathSubs(path, newPath); - } - // Change any active files - codiad.active.rename(path, newPath); - codiad.modal.unload(); - } - }); - }); - }, - - repathSubs: function(oldPath, newPath) { - $('#file-manager a[data-path="' + newPath + '"]') - .siblings('ul') - .find('a') - .each(function() { - // Hit the children, hit 'em hard - var curPath = $(this) - .attr('data-path'); - var revisedPath = curPath.replace(oldPath, newPath); - $(this) - .attr('data-path', revisedPath); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Delete - ////////////////////////////////////////////////////////////////// - - deleteNode: function(path) { - var _this = this; - codiad.modal.load(400, this.dialog, { - action: 'delete', - path: path - }); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - $.get(_this.controller + '?action=delete&path=' + encodeURIComponent(path), function(data) { - var deleteResponse = codiad.jsend.parse(data); - if (deleteResponse != 'error') { - var node = $('#file-manager a[data-path="' + path + '"]'); - node.parent('li') - .remove(); - // Close any active files - $('#active-files a') - .each(function() { - var curPath = $(this) - .attr('data-path'); - if (curPath.indexOf(path) == 0) { - codiad.active.remove(curPath); - } - }); - } - codiad.modal.unload(); - }); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Search - ////////////////////////////////////////////////////////////////// - - search: function(path) { - codiad.modal.load(500, this.dialog,{ - action: 'search', - path: path - }); - codiad.modal.load_process.done( function() { - var lastSearched = JSON.parse(localStorage.getItem("lastSearched")); - if(lastSearched) { - $('#modal-content form input[name="search_string"]').val(lastSearched.searchText); - $('#modal-content form input[name="search_file_type"]').val(lastSearched.fileExtension); - $('#modal-content form select[name="search_type"]').val(lastSearched.searchType); - if(lastSearched.searchResults != '') { - $('#filemanager-search-results').slideDown().html(lastSearched.searchResults); - } - } - }); - codiad.modal.hideOverlay(); - var _this = this; - $('#modal-content form') - .live('submit', function(e) { - $('#filemanager-search-processing') - .show(); - e.preventDefault(); - searchString = $('#modal-content form input[name="search_string"]') - .val(); - fileExtensions=$('#modal-content form input[name="search_file_type"]') - .val(); - searchFileType=$.trim(fileExtensions); - if (searchFileType != '') { - //season the string to use in find command - searchFileType = "\\(" + searchFileType.replace(/\s+/g, "\\|") + "\\)"; - } - searchType = $('#modal-content form select[name="search_type"]') - .val(); - $.post(_this.controller + '?action=search&path=' + encodeURIComponent(path) + '&type=' + searchType, { - search_string: searchString, - search_file_type: searchFileType - }, function(data) { - searchResponse = codiad.jsend.parse(data); - var results = ''; - if (searchResponse != 'error') { - $.each(searchResponse.index, function(key, val) { - // Cleanup file format - if(val['file'].substr(-1) == '/') { - val['file'] = val['file'].substr(0, str.length - 1); - } - val['file'] = val['file'].replace('//','/'); - // Add result - results += ''; - }); - $('#filemanager-search-results') - .slideDown() - .html(results); - } else { - $('#filemanager-search-results') - .slideUp(); - } - _this.saveSearchResults(searchString, searchType, fileExtensions, results); - $('#filemanager-search-processing') - .hide(); - }); - }); - }, - - ///////////////////////////////////////////////////////////////// - // saveSearchResults - ///////////////////////////////////////////////////////////////// - saveSearchResults: function(searchText, searchType, fileExtensions, searchResults) { - var lastSearched = { - searchText: searchText, - searchType: searchType, - fileExtension: fileExtensions, - searchResults: searchResults - }; - localStorage.setItem("lastSearched", JSON.stringify(lastSearched)); - }, - ////////////////////////////////////////////////////////////////// - // Upload - ////////////////////////////////////////////////////////////////// - - uploadToNode: function(path) { - codiad.modal.load(500, this.dialogUpload, {path: path}); - }, - - ////////////////////////////////////////////////////////////////// - // Download - ////////////////////////////////////////////////////////////////// - - download: function(path) { - var type = this.getType(path); - $('#download') - .attr('src', 'components/filemanager/download.php?path=' + encodeURIComponent(path) + '&type=' + type); - } - }; - -})(this, jQuery); -"; \ No newline at end of file diff --git a/data/collaborative/text/264f67810f124a1136a3bca443af2651 b/data/collaborative/text/264f67810f124a1136a3bca443af2651 deleted file mode 100755 index 67b7b9a..0000000 --- a/data/collaborative/text/264f67810f124a1136a3bca443af2651 +++ /dev/null @@ -1,1143 +0,0 @@ -s:55059:"/* - * Copyright (c) Codiad & Andr3as, distributed - * as-is and without warranty under the MIT License. - * See http://opensource.org/licenses/MIT for more information. - * This information must remain intact. - */ - -(function(global, $){ - - var codiad = global.codiad, - scripts = document.getElementsByTagName('script'), - path = scripts[scripts.length-1].src.split('?')[0], - curpath = path.split('/').slice(0, -1).join('/')+'/'; - - $(function() { - codiad.CodeGit.init(); - }); - - codiad.CodeGit = { - - path : curpath, - location: '', - line : 0, - files : [], - network_graph : {}, - - init: function() { - var _this = this; - $.getScript(this.path + "network_graph.js"); - $.getScript(this.path + "raphael.min.js"); - //Check if directories has git repo - amplify.subscribe('filemanager.onIndex', function(obj){ - setTimeout(function(){ - $.each(obj.files, function(i, item){ - if (_this.basename(item.name) == '.git') { - $('.directory[data-path="'+_this.dirname(item.name)+'"]').addClass('repo'); - } else if (item.type == 'directory') { - //Deeper inspect - $.getJSON(_this.path + 'controller.php?action=checkRepo&path=' + item.name, function(result){ - if (result.status) { - $('.directory[data-path="'+item.name+'"]').addClass('repo'); - } - }); - } - }); - - // Repo status - _this.showRepoStatus(); - - // clear an old poller - if (_this._poller) { - clearInterval(_this._poller); - delete _this._poller; - } - - - },0); - }); - //Handle context-menu - amplify.subscribe('context-menu.onShow', function(obj){ - var path = $(obj.e.target).attr('data-path'), - root = $('#project-root').attr('data-path'), - counter = 0; - if ($(obj.e.target).hasClass('directory')) { - $('#context-menu').append('
    '); - if ($(obj.e.target).hasClass('repo')) { - $('#context-menu').append('Open CodeGit'); - $('#context-menu').append('Add Submodule'); - } else { - $('#context-menu').append('Git Init'); - $('#context-menu').append('Git Clone'); - - //Git Submodule - while (path != root) { - path = _this.dirname(path); - if ($('.directory[data-path="' + path + '"]').hasClass('repo')) { - $('#context-menu').append('Add Submodule'); - break; - } - if (counter >= 10) break; - counter++; - } - } - } else { - var file = path; - while (path != root) { - path = _this.dirname(path); - if ($('.directory[data-path="' + path + '"]').hasClass('repo')) { - $('#context-menu').append('
    '); - $('#context-menu').append('Git Diff'); - $('#context-menu').append('Git Blame'); - $('#context-menu').append('Git History'); - //Git rename - $('#context-menu a[onclick="codiad.filemanager.renameNode($(\'#context-menu\').attr(\'data-path\'));"]') - .attr("onclick", "codiad.CodeGit.rename($(\'#context-menu\').attr(\'data-path\'))"); - //Init Submodules - if (_this.basename(file) == '.gitmodules') { - $('#context-menu').append('Init Submodule'); - } - break; - } - if (counter >= 10) break; - counter++; - } - } - }); - amplify.subscribe("context-menu.onHide", function(){ - $('.code_git').remove(); - }); - //repo status - $('#file-manager').before(''); - _this.addStatusIcon(); - // clicking on it brings up the commit box - $("#git-repo-stat-wrapper").click(function(){ - codiad.CodeGit.showDialog('overview', codiad.project.getCurrent()); - }); - //File stats - $('#current-file').after('
    '); - amplify.subscribe('active.onFocus', function(path){ - _this.numstat(path); - _this.repostat(); - }); - amplify.subscribe('active.onSave', function(path){ - setTimeout(function(){ - _this.numstat(path); - _this.repostat(); - }, 50); - }); - amplify.subscribe('active.onClose', function(path){ - _this.repostat(); - $('#git-stat').html(""); - }); - amplify.subscribe('active.onRemoveAll', function(){ - _this.repostat(); - $('#git-stat').html(""); - }); - amplify.subscribe('settings.changed', function(){ - _this.showRepoStatus(); - }); - amplify.subscribe('settings.loaded', function(){ - _this.showRepoStatus(); - }); - //Live features - $('.git_area #check_all').live("click", function(e){ - if ($('.git_area #check_all').attr("checked") == "checked") { - $('.git_area input:checkbox').attr("checked", "checked"); - } else { - $('.git_area input:checkbox').removeAttr("checked"); - } - }); - $('.git_area input:checkbox:not(#check_all)').live("click", function(e){ - if ($(this).attr("checked") != "checked") { - //One gets unchecked, remove all_input checking - if ($('.git_area #check_all').attr("checked") == "checked") { - $('.git_area #check_all').removeAttr("checked"); - } - } else { - var all = true; - $('.git_area input:checkbox:not(#check_all)').each(function(i, item){ - all = all && ($(this).attr("checked") == "checked"); - }); - if (all) { - $('.git_area #check_all').attr("checked", "checked"); - } - } - }); - $('.commit_hash').live('click', function(){ - var commit; - if (typeof($(this).attr('data-hash')) != 'undefined') { - commit = $(this).attr('data-hash'); - } else { - commit = $(this).text(); - } - commit = commit.replace("commit", "").trim(); - codiad.CodeGit.showCommit(codiad.CodeGit.location, commit); - }); - //Button Click listener - $('.git_area .git_diff').live("click", function(e){ - e.preventDefault(); - var line = $(this).attr('data-line'); - var path = $('.git_area .git_list .file[data-line="'+line+'"]').text(); - _this.files = []; - _this.files.push(path); - _this.showDialog('diff', _this.location); - }); - $('.git_area .git_undo').live("click", function(e){ - e.preventDefault(); - var line = $(this).attr('data-line'); - var path = $('.git_area .git_list .file[data-line="'+line+'"]').text(); - _this.checkout(path, _this.location); - _this.showDialog('overview', _this.location); - }); - $('.git_diff_area .git_undo').live("click", function(e){ - e.preventDefault(); - _this.checkout(_this.files[0], _this.location); - _this.showDialog('overview', _this.location); - }); - }, - - //Check if directories has git repo - showRepoStatus: function () { - var _this = this; - if ($('#project-root').hasClass('repo') && _this.isEnabledRepoStatus()) { - // add a poller - _this._poller = setInterval(function(){ - _this.repostat(); - }, 10000); - _this.addStatusIcon(); - // only show stat-wrapper if not configured - if (_this.isEnabledWrapper()) { - $("#git-repo-stat-wrapper").show(); - } else { - $("#git-repo-stat-wrapper").hide(); - } - $("#git-repo-status-icon").show(); - _this.repostat(); - } else { - $("#git-repo-stat-wrapper").hide(); - $("#git-repo-status-icon").hide(); - } - }, - - - showSidebarDialog: function() { - if (!$('#project-root').hasClass('repo')) { - codiad.message.error('Project root has no repository. Use the context menu!'); - return; - } - codiad.CodeGit.showDialog('overview', $('#project-root').attr('data-path')); - }, - - showDialog: function(type, path) { - this.location = path || this.location; - codiad.modal.load(600, this.path + 'dialog.php?action=' + type); - }, - - showCommitDialog: function(path) { - var _this = this; - path = _this.getPath(path); - $.getJSON(this.path + 'controller.php?action=getSettings&path=' + path, function(data){ - if (data.status == "success") { - if (data.data.email === ""){ - codiad.message.notice("Please tell git who you are:"); - _this.showDialog('userConfig', _this.location); - } else { - var files = [], line = 0, file = ""; - $('.git_area .git_list input:checkbox[checked="checked"]').each(function(i, item){ - line = $(item).attr('data-line'); - file = $('.git_area .git_list .file[data-line="'+line+'"]').text(); - files.push(file); - }); - _this.files = files; - _this.showDialog('commit', _this.location); - } - } else { - codiad.message.error(data.message); - } - }); - }, - - gitInit: function(path) { - $.getJSON(this.path + 'controller.php?action=init&path=' + path, function(result){ - codiad.message[result.status](result.message); - if (result.status == 'success') { - $('.directory[data-path="'+path+'"]').addClass('hasRepo'); - codiad.filemanager.rescan(path); - } - }); - }, - - /** - * Clone repo or show dialog to clone repo - * - * @param {string} path - * @param {string} repo - * @param {boolean} init_submodules - */ - clone: function(path, repo, init_submodules) { - var _this = this; - init_submodules = init_submodules || "false"; - if (typeof(repo) == 'undefined') { - this.showDialog('clone', path); - } else { - codiad.modal.unload(); - $.getJSON(_this.path + 'controller.php?action=clone&path=' + path + '&repo=' + repo + '&init_submodules=' + init_submodules, function(result){ - if (result.status == 'login_required') { - codiad.message.error(result.message); - _this.showDialog('login', _this.location); - _this.login = function(){ - var username = $('.git_login_area #username').val(); - var password = $('.git_login_area #password').val(); - codiad.modal.unload(); - $.post(_this.path + 'controller.php?action=clone&path='+path+'&repo=' + repo + '&init_submodules=' + init_submodules, {username: username, password: password}, - function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - if (result.status == 'success') { - codiad.filemanager.rescan(path); - } - }); - }; - } else { - codiad.message[result.status](result.message); - } - if (result.status == 'success') { - codiad.filemanager.rescan(path); - } - }); - } - }, - - diff: function(path, repo) { - var _this = this; - repo = this.getPath(repo); - $.getJSON(this.path + 'controller.php?action=diff&repo=' + repo + '&path=' + path, function(result){ - if (result.status != 'success') { - codiad.message[result.status](result.message); - _this.showDialog('overview', repo); - return; - } - result.data = _this.renderDiff(result.data); - $('.git_diff').append(result.data.join("")); - }); - }, - - contextMenuDiff: function(path, repo) { - this.location = repo; - path = path.replace(repo + "/", ""); - this.files = []; - this.files.push(path); - this.showDialog('diff', repo); - }, - - commit: function(path, msg) { - var _this = this; - path = this.getPath(path); - var message = $('.git_commit_area #commit_msg').val(); - this.showDialog('overview', this.location); - $.post(this.path + 'controller.php?action=add&path=' + path, {files : JSON.stringify(_this.files)}, function(result){ - result = JSON.parse(result); - if (result.status == 'error') { - codiad.message.error(result.message); - return; - } - $.post(_this.path + 'controller.php?action=commit&path=' + path, {message: message}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - _this.status(path); - }); - }); - }, - - filesDiff: function() { - var _this = this; - $.each(this.files, function(i, item){ - _this.diff(item, _this.location); - }); - }, - - push: function() { - var _this = this; - var remote = $('.git_push_area #git_remotes').val(); - var branch = $('.git_push_area #git_branches').val(); - this.showDialog('overview', this.location); - $.getJSON(this.path + 'controller.php?action=push&path=' + this.location + '&remote=' + remote + '&branch=' + branch, function(result){ - if (result.status == 'login_required') { - codiad.message.error(result.message); - _this.showDialog('login', _this.location); - _this.login = function(){ - var username = $('.git_login_area #username').val(); - var password = $('.git_login_area #password').val(); - _this.showDialog('overview', _this.location); - $.post(_this.path + 'controller.php?action=push&path=' + _this.location + '&remote=' + remote + '&branch=' + branch, - {username: username, password: password}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - }); - }; - } else if (result.status == 'passphrase_required') { - codiad.message.error(result.message); - _this.showDialog('passphrase', _this.location); - _this.login = function() { - var passphrase = $('.git_login_area #passphrase').val(); - _this.showDialog('overview', _this.location); - $.post(_this.path + 'controller.php?action=push&path=' + _this.location + '&remote=' + remote + '&branch=' + branch, - {passphrase: passphrase}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - }); - }; - } else { - codiad.message[result.status](result.message); - } - }); - }, - - pull: function() { - var _this = this; - var remote = $('.git_push_area #git_remotes').val(); - var branch = $('.git_push_area #git_branches').val(); - this.showDialog('overview', this.location); - $.getJSON(this.path + 'controller.php?action=pull&path=' + this.location + '&remote=' + remote + '&branch=' + branch, function(result){ - if (result.status == 'login_required') { - codiad.message.error(result.message); - _this.showDialog('login', _this.location); - _this.login = function(){ - var username = $('.git_login_area #username').val(); - var password = $('.git_login_area #password').val(); - _this.showDialog('overview', _this.location); - $.post(_this.path + 'controller.php?action=pull&path=' + _this.location + '&remote=' + remote + '&branch=' + branch, - {username: username, password: password}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - }); - }; - } else if (result.status == 'passphrase_required') { - codiad.message.error(result.message); - _this.showDialog('passphrase', _this.location); - _this.login = function() { - var passphrase = $('.git_login_area #passphrase').val(); - _this.showDialog('overview', _this.location); - $.post(_this.path + 'controller.php?action=pull&path=' + _this.location + '&remote=' + remote + '&branch=' + branch, - {passphrase: passphrase}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - }); - }; - } else { - codiad.message[result.status](result.message); - } - }); - }, - - fetch: function() { - var _this = this; - var remote = $('.git_remote_area #git_remotes').val(); - this.showDialog('overview', this.location); - $.getJSON(this.path + 'controller.php?action=fetch&path=' + this.location + '&remote=' + remote, function(result){ - if (result.status == 'login_required') { - codiad.message.error(result.message); - _this.showDialog('login', _this.location); - _this.login = function(){ - var username = $('.git_login_area #username').val(); - var password = $('.git_login_area #password').val(); - _this.showDialog('overview', _this.location); - $.post(_this.path + 'controller.php?action=fetch&path=' + _this.location + '&remote=' + remote, - {username: username, password: password}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - }); - }; - } else if (result.status == 'passphrase_required') { - codiad.message.error(result.message); - _this.showDialog('passphrase', _this.location); - _this.login = function() { - var passphrase = $('.git_login_area #passphrase').val(); - _this.showDialog('overview', _this.location); - $.post(_this.path + 'controller.php?action=fetch&path=' + _this.location + '&remote=' + remote, - {passphrase: passphrase}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - }); - }; - } else { - codiad.message[result.status](result.message); - } - }); - }, - - checkout: function(path, repo) { - var result = confirm("Are you sure to undo the changes on: " + path); - if (result) { - $.getJSON(this.path + 'controller.php?action=checkout&repo=' + repo + '&path=' + path, function(result){ - codiad.message[result.status](result.message); - if (codiad.active.isOpen(repo + "/" + path)) { - codiad.message.notice("Reloading file after undoing changes"); - codiad.active.close(repo + "/" + path); - codiad.filemanager.openFile(repo + "/" + path); - } - }); - } - }, - - status: function(path) { - path = this.getPath(path); - this.files = []; - var _this = this; - $.getJSON(this.path + 'controller.php?action=status&path=' + path, function(result){ - if (result.status == 'error') { - codiad.message.error(result.message); - return; - } - //Reset list - $('.git_list tbody').html(''); - var added, deleted, modified, renamed, untracked; - added = result.data.added; - deleted = result.data.deleted; - modified = result.data.modified; - renamed = result.data.renamed; - untracked = result.data.untracked; - //Add entries - $.each(added, function(i, item){ - _this.addLine("Added", item); - }); - $.each(deleted, function(i, item){ - _this.addLine("Deleted", item); - }); - $.each(modified, function(i, item){ - _this.addLine("Modified", item); - }); - $.each(renamed, function(i, item) { - _this.addLine("Renamed", item); - }); - $.each(untracked, function(i, item) { - _this.addLine("Untracked", item); - }); - _this.setBranch(result.data.branch); - }); - }, - - log: function(repo, path) { - repo = this.getPath(repo); - var component = ""; - if (typeof(path) !== 'undefined') { - component = '&path=' + this.encode(path); - $('.git_log_area .path').text(path); - } else if (this.files.length !== 0) { - component = '&path=' + this.encode(this.files[0]); - $('.git_log_area .path').text(this.files[0]); - } - $.getJSON(this.path + 'controller.php?action=log&repo=' + this.encode(repo) + component, function(result){ - if (result.status == 'error') { - codiad.message.error(result.message); - return; - } - $.each(result.data, function(i, item){ - item = item.replace(new RegExp(" ", "g"), " "); - if (item.indexOf("commit") === 0) { - $('.git_log_area .git_log').append('
  • ' + item + '
  • '); - } else { - $('.git_log_area .git_log').append('
  • ' + item + '
  • '); - } - }); - }); - }, - - getRemotes: function(path) { - path = this.getPath(path); - $.getJSON(this.path + 'controller.php?action=getRemotes&path=' + path, function(result){ - if (result.status == 'error') { - codiad.message.error(result.message); - return; - } - $.each(result.data, function(i, item){ - $('#git_remotes').append(''); - }); - $.each(result.data, function(i, item){ - $('.git_remote_info').html(item); - return false; - }); - $('#git_remotes').live('change', function(){ - var value = $('#git_remotes').val(); - $('.git_remote_info').html(result.data[value]); - }); - }); - }, - - newRemote: function(path) { - var _this = this; - path = this.getPath(path); - var name = $('.git_new_remote_area #remote_name').val(); - var url = $('.git_new_remote_area #remote_url').val(); - $.getJSON(this.path + 'controller.php?action=newRemote&path=' + path + '&name=' + name + '&url=' + url, function(result){ - _this.showDialog('overview', _this.location); - codiad.message[result.status](result.message); - }); - }, - - removeRemote: function(path) { - var _this = this; - path = this.getPath(path); - var name = $('#git_remotes').val(); - var result = confirm("Are you sure to remove the remote: " + name); - if (result) { - $.getJSON(this.path + 'controller.php?action=removeRemote&path=' + path + '&name=' + name, function(result){ - codiad.message[result.status](result.message); - }); - } - this.showDialog('overview', this.location); - }, - - renameRemote: function(path) { - path = this.getPath(path); - var name = $('#git_remote').text(); - var newName = $('#git_new_name').val(); - $.getJSON(this.path + 'controller.php?action=renameRemote&path=' + path + '&name=' + name + '&newName=' + newName, function(result){ - codiad.message[result.status](result.message); - }); - this.showDialog('overview', this.location); - }, - - getRemoteBranches: function(path){ - path = this.getPath(path); - $.getJSON(this.path + 'controller.php?action=getRemoteBranches&path=' + path, function(result){ - if (result.status == 'error') { - codiad.message.error(result.message); - return; - } - $.each(result.data.branches, function(i, item){ - $('#git_remote_branches').append(''); - }); - $('#git_new_branch').val(result.data.current.substr(result.data.current.search('/') + 1)); - $('#git_remote_branches').val(result.data.current); - }); - }, - - checkoutRemote: function(path){ - path = this.getPath(path); - var remoteName = $('#git_remote_branches').val(); - var name = $('#git_new_branch').val(); - $.getJSON(this.path + 'controller.php?action=checkoutRemote&path=' + path + '&name=' + name + '&remoteName=' + remoteName, function(result){ - codiad.message[result.status](result.message); - }); - this.showDialog('remote', this.location); - }, - - getBranches: function(path) { - path = this.getPath(path); - $.getJSON(this.path + 'controller.php?action=getBranches&path=' + path, function(result){ - if (result.status == 'error') { - codiad.message.error(result.message); - return; - } - $.each(result.data.branches, function(i, item){ - $('#git_branches').append(''); - }); - $('#git_branches').val(result.data.current); - }); - }, - - newBranch: function(path) { - var _this = this; - path = this.getPath(path); - var name = $('.git_new_branch_area #branch_name').val(); - $.getJSON(this.path + 'controller.php?action=newBranch&path=' + path + '&name=' + name, function(result){ - _this.showDialog('branches', _this.location); - codiad.message[result.status](result.message); - }); - }, - - deleteBranch: function(path) { - path = this.getPath(path); - var name = $('#git_branches').val(); - var result = confirm("Are you sure to remove the branch: " + name); - if (result) { - $.getJSON(this.path + 'controller.php?action=deleteBranch&path=' + path + '&name=' + name, function(result){ - codiad.message[result.status](result.message); - }); - } - this.showDialog('branches', this.location); - }, - - checkoutBranch: function(path) { - path = this.getPath(path); - var name = $('#git_branches').val(); - $.getJSON(this.path + 'controller.php?action=checkoutBranch&path=' + path + '&name=' + name, function(result){ - codiad.message[result.status](result.message); - }); - this.showDialog('overview', this.location); - }, - - renameBranch: function(path) { - path = this.getPath(path); - var name = $('#git_branch').text(); - var newName = $('#git_new_name').val(); - $.getJSON(this.path + 'controller.php?action=renameBranch&path=' + path + '&name=' + name + '&newName=' + newName, function(result){ - codiad.message[result.status](result.message); - }); - this.showDialog('overview', this.location); - }, - - merge: function(path) { - var _this = this; - path = this.getPath(path); - var name = $('#git_branches').val(); - var result = confirm("Are you sure to merge " + name + " into the current branch?"); - if (result) { - $.getJSON(this.path + 'controller.php?action=merge&path=' + path + '&name=' + name, function(result){ - codiad.message[result.status](result.message); - _this.status(_this.location); - }); - } - this.showDialog('overview', this.location); - }, - - rename: function(fPath) { - var _this = this; - var path = _this.dirname(fPath); - var old_name = fPath.replace(path, "").substr(1); - if (old_name.length === 0 || old_name === fPath) { - //Codiad renaming - codiad.filemanager.renameNode(fPath); - return; - } - var shortName = codiad.filemanager.getShortName(fPath); - var type = codiad.filemanager.getType(fPath); - codiad.modal.load(250, codiad.filemanager.dialog, { action: 'rename', path: fPath, short_name: shortName, type: type}); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - var newName = $('#modal-content form input[name="object_name"]') - .val(); - // Build new path - var arr = fPath.split('/'); - var temp = []; - for (i = 0; i < arr.length - 1; i++) { - temp.push(arr[i]); - } - var newPath = temp.join('/') + '/' + newName; - codiad.modal.unload(); - $.getJSON(_this.path + "controller.php?action=rename&path="+path+"&old_name="+old_name+"&new_name="+newName, function(data) { - if (data.status != 'error') { - codiad.message.success(type.charAt(0) - .toUpperCase() + type.slice(1) + ' Renamed'); - var node = $('#file-manager a[data-path="' + fPath + '"]'); - // Change pathing and name for node - node.attr('data-path', newPath) - .html(newName); - if (type == 'file') { // Change icons for file - curExtClass = 'ext-' + codiad.filemanager.getExtension(fPath); - newExtClass = 'ext-' + codiad.filemanager.getExtension(newPath); - $('#file-manager a[data-path="' + newPath + '"]') - .removeClass(curExtClass) - .addClass(newExtClass); - } else { // Change pathing on any sub-files/directories - codiad.filemanager.repathSubs(path, newPath); - } - // Change any active files - codiad.active.rename(fPath, newPath); - } else { - codiad.message.error(data.message); - codiad.filemanager.renameNode(fPath); - } - }); - }); - }, - - submoduleDialog: function(repo, path) { - this.location = repo; - if (repo === path) { - path = ""; - } else { - path = path.replace(repo + "/", ""); - } - this.files = []; - this.files.push(path); - this.showDialog('submodule'); - }, - - submodule: function(repo, dir, submodule) { - var _this = this; - repo = repo || this.location; - path = dir; - if (this.files[0] != "") { - path = this.files[0] + "/" + dir; - } - _this.showDialog('overview', repo); - $.getJSON(this.path + 'controller.php?action=submodule&repo='+repo+'&path='+path+'&submodule='+submodule, function(result){ - if (result.status == 'login_required') { - codiad.message.error(result.message); - _this.showDialog('login', _this.location); - _this.login = function(){ - var username = $('.git_login_area #username').val(); - var password = $('.git_login_area #password').val(); - _this.showDialog('overview', _this.location); - $.post(_this.path + 'controller.php?action=submodule&repo='+repo+'&path='+path+'&submodule='+submodule, - {username: username, password: password}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - if (result.status == 'success') { - codiad.filemanager.rescan(repo); - } - }); - }; - } else if (result.status == 'passphrase_required') { - codiad.message.error(result.message); - _this.showDialog('passphrase', _this.location); - _this.login = function() { - var passphrase = $('.git_login_area #passphrase').val(); - _this.showDialog('overview', _this.location); - $.post(_this.path + 'controller.php?action=submodule&repo='+repo+'&path='+path+'&submodule='+submodule, - {passphrase: passphrase}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - if (result.status == 'success') { - codiad.filemanager.rescan(repo); - } - }); - }; - } else { - codiad.message[result.status](result.message); - if (result.status == 'success') { - codiad.filemanager.rescan(repo); - } - } - }); - }, - - initSubmodule: function(path) { - var _this = this; - path = path || this.location; - $.getJSON(this.path + 'controller.php?action=initSubmodule&path='+path, function(result){ - if (result.status == 'login_required') { - codiad.message.error(result.message); - _this.showDialog('login', _this.location); - _this.login = function(){ - var username = $('.git_login_area #username').val(); - var password = $('.git_login_area #password').val(); - _this.showDialog('overview', _this.location); - $.post(_this.path + 'controller.php?action=initSubmodule&path='+path, - {username: username, password: password}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - if (result.status == 'success') { - codiad.filemanager.rescan(path); - } - }); - }; - } else if (result.status == 'passphrase_required') { - codiad.message.error(result.message); - _this.showDialog('passphrase', _this.location); - _this.login = function() { - var passphrase = $('.git_login_area #passphrase').val(); - _this.showDialog('overview', _this.location); - $.post(_this.path + 'controller.php?action=initSubmodule&path='+path, - {passphrase: passphrase}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - if (result.status == 'success') { - codiad.filemanager.rescan(path); - } - }); - }; - } else { - codiad.message[result.status](result.message); - if (result.status == 'success') { - codiad.filemanager.rescan(path); - } - } - }) - }, - - numstat: function(path) { - if (typeof(path) == 'undefined') { - path = codiad.active.getPath(); - } - $.getJSON(this.path + 'controller.php?action=numstat&path='+path, function(json){ - var insert = ""; - if (json.status != "error") { - var data = json.data; - insert = ''+ data.branch + ' +' + data.insertions + ',-' + data.deletions; - } - $('#git-stat').html(insert); - }); - }, - - repostat: function() { - path = codiad.project.getCurrent(); - $.getJSON(this.path + 'controller.php?action=status&path='+path, function(json){ - var insert = "Unknown", cls = ""; - if (json.status != "error") { - var data = json.data; - if (data.added.length !== 0 || - data.deleted.length !== 0 || - data.modified.length !== 0 || - data.renamed.length !== 0) { - insert = "Uncommitted"; - cls = "invalid"; - } else if (data.untracked.length !== 0) { - insert = "Untracked"; - cls = "untracked"; - } else { - insert = "Committed"; - cls = "valid"; - } - } - $('#git-repo-stat').html(insert); - $('#git-repo-stat-wrapper').removeClass("git-repo-stat-valid git-repo-stat-invalid git-repo-stat-untracked") - .addClass("git-repo-stat-"+cls); - // show the icon - $("#git-repo-status-icon").removeClass("git-repo-icon-valid git-repo-icon-invalid git-repo-icon-untracked") - .addClass("git-repo-icon-"+cls); - }); - }, - - showCommit: function(path, commit) { - var _this = this; - path = this.getPath(path); - this.showDialog('showCommit', path); - $.getJSON(this.path + 'controller.php?action=showCommit&path=' + this.encode(path) + '&commit=' + commit, function(result){ - $('.git_show_commit_area .hash').text(commit); - if (result.status != "success") { - codiad.message.error(result.message); - _this.showDialog('overview', path); - } - result.data = _this.renderDiff(result.data); - $('.git_show_commit_area .content ul').append(result.data.join("")); - }); - }, - - blame: function(path, repo) { - var _this = this; - this.location = repo; - path = path.replace(repo + "/", ""); - this.showDialog('blame', repo); - $.getJSON(this.path + 'controller.php?action=blame&repo=' + this.encode(repo) + '&path=' + this.encode(path), function(result){ - if (result.status != "success") { - codiad.message.error(result.message); - _this.showDialog('overview', repo); - } - $('.git_blame_area table thead th').text(path); - //Split blame output per file line - var hashRegExp = /^[a-z0-9]{40}/; - var data = result.data, starts, startIndexes = [], segments = [], s, e, i; - starts = data.filter(function(line){ - return hashRegExp.test(line); - }); - for (i = 0; i < starts.length; i++) { - startIndexes.push(data.indexOf(starts[i])); - } - for (i = 0; i < starts.length; i++) { - s = startIndexes[i]; - e = (i < (starts.length - 1)) ? (startIndexes[i + 1]) : (data.length); - segments.push(data.slice(s, e)); - } - //Combine lines with the same commit - var hash = segments[0][0].match(hashRegExp)[0]; - var unique = [{segment: segments[0], hash: hash, lines: [segments[0][12]]}]; - for (i = 1; i < segments.length; i++) { - if (hash === segments[i][0].match(hashRegExp)[0]) { - //Same - unique[unique.length - 1].lines.push(segments[i][12]); - } else { - hash = segments[i][0].match(hashRegExp)[0]; - //Next - unique.push({segment: segments[i], hash: hash, lines: [segments[i][12]]}); - } - } - //Format output - var output = "", msg, date, name, line; - for (i = 0; i < unique.length; i++) { - msg = unique[i].segment[9].replace("summary ", ""); - date = unique[i].segment[7].replace("committer-time ", ""); - date = new Date(date * 1000); - date = (date.getMonth() + 1) + "/" + date.getDate() + "/" + date.getFullYear(); - name = unique[i].segment[5].replace("committer ", ""); - hash = unique[i].hash; - output += '
    '; - output += ''; - } - $('.git_blame_area table tbody').html(output); - }); - }, - - history: function(path, repo) { - this.location = repo; - path = path.replace(repo + "/", ""); - this.files = []; - this.files.push(path); - this.showDialog('log', repo); - }, - - network: function(path) { - var _this = this; - path = this.getPath(path); - this.showDialog('network', path); - $.getJSON(this.path + 'controller.php?action=network&path=' + this.encode(path), function(result){ - _this.network_graph.setData(result.data); - _this.network_graph.generate(); - }); - }, - - login: function(){}, - - setSettings: function(path) { - var _this = this; - var settings = {}; - path = this.getPath(path); - $('.git_settings_area input:not(.no_setting)').each(function(i, el){ - settings[$(el).attr("id")] = $(el).val(); - }); - - $.post(this.path + 'controller.php?action=setSettings&path='+path, {settings: JSON.stringify(settings)}, function(result){ - result = JSON.parse(result); - codiad.message[result.status](result.message); - _this.showDialog('overview', _this.location); - }); - }, - - getSettings: function(path) { - path = this.getPath(path); - $.getJSON(this.path + 'controller.php?action=getSettings&path=' + path, function(result){ - if (result.status == 'error') { - codiad.message.error(result.message); - return; - } - var local = false; - $.each(result.data, function(i, item){ - if (/\//.test(i)) { - return; - } - $('.git_settings_area #' + i).val(item); - if (/^local_/.test(i)) { - local = true; - } - }); - if (!local) { - $('#box_local').click(); - } - }); - }, - - /** - * Get path - * - * @param {string} [path] - * @result {string} path - */ - getPath: function(path) { - if (typeof(path) == 'undefined') { - return this.location; - } else { - return path; - } - }, - - /** - * Get basename - * - * @param {string} [path] - * @result {string} basename - */ - basename: function(path) { - return path.replace(/\\/g,'/').replace( /.*\//, '' ); - }, - - /** - * Get dirname - * - * @param {string} [path] - * @result {string} dirname - */ - dirname: function(path) { - return path.replace(/\\/g,'/').replace(/\/[^\/]*$/, ''); - }, - - /** - * Encode Uri component - * - * @param {string} [string] - * @result {string} encoded string - */ - encode: function(string) { - return encodeURIComponent(string); - }, - - addLine: function(status, name) { - var line = this.line; - var element = ''; - $('.git_list tbody').append(element); - this.line++; - }, - - /** - * Render git diff output - * - * @param {Array} [array] - * @result {Array} Renderd output - */ - renderDiff: function(array) { - var output = [], element, item; - for (var i = 0; i < array.length; i++) { - item = array[i]; - element = item.replace(new RegExp('\t', 'g'), ' ') - .replace(new RegExp(' ', 'g'), " ") - .replace(new RegExp('\n', 'g'), "
    "); - if (item.indexOf('+++') === 0 || item.indexOf('---') === 0 || /^index [0-9a-z]{7}..[0-9a-z]{7}/.test(item) || /^new file mode [0-9]{6}/.test(item)) { - continue; - } else if (/^diff --git a\/.+ b\/.+/.test(item)) { - element = item.match(/^diff --git a\/.+ b\/(.+)/); - element = '
  • ' + element[1] + '
  • '; - } else if (/^@@ -[0-9,]+ \+[0-9,]+ @@/.test(item)) { - element = '
  • ' + element + '
  • '; - } else if (item.indexOf('+') === 0 && item.indexOf('+++') !== 0) { - element = '
  • ' + element + '
  • '; - } else if (item.indexOf('-') === 0 && item.indexOf('---') !== 0) { - element = '
  • ' + element + '
  • '; - } else { - element = '
  • ' + element + '
  • '; - } - output.push(element); - } - return output; - }, - - setBranch: function(branch) { - $('.git_area .branch').text(branch); - }, - - addStatusIcon: function () { - if ($("span#git-repo-status-icon").length < 1) { - $('#file-manager #project-root').before(''); - } - }, - - isEnabledRepoStatus: function () { - var setting = localStorage.getItem('codiad.plugin.codegit.disableRepoStatus'), ret = true; - if (setting === "true") { - ret = false; - } - return(ret); - }, - - isEnabledWrapper: function () { - var setting = localStorage.getItem('codiad.plugin.codegit.disableHeader'), ret = true; - if (setting === "true") { - ret = false; - } - return(ret); - }, - - suppressCommitDiff: function() { - return false || localStorage.getItem('codiad.plugin.codegit.suppressCommitDiff') == "true"; - } - }; -})(this, jQuery);"; \ No newline at end of file diff --git a/data/collaborative/text/273e1de64502c06a2384fc8b66dfb4e4 b/data/collaborative/text/273e1de64502c06a2384fc8b66dfb4e4 deleted file mode 100755 index 903a3c5..0000000 --- a/data/collaborative/text/273e1de64502c06a2384fc8b66dfb4e4 +++ /dev/null @@ -1,70 +0,0 @@ -s:1864:"/* - * Copyright (c) Codiad & Kent Safranski (codiad.com), distributed - * as-is and without warranty under the MIT License. See - * [root]/license.txt for more. This information must remain intact. - */ - -(function(global, $){ - - var codiad = global.codiad, - scripts= document.getElementsByTagName('script'), - path = scripts[scripts.length-1].src.split('?')[0], - curpath = path.split('/').slice(0, -1).join('/')+'/'; - - - $(function() { - codiad.colorPicker.init(); - }); - - codiad.colorPicker = { - - path: curpath, - - init: function() { - - $.loadScript(this.path+"color_parser.js"); - $.loadScript(this.path+"jquery.colorpicker.js"); - - }, - - open: function() { - - codiad.modal.load(400, this.path+'dialog.php'); - - }, - - insert: function(type) { - var color = ''; - if (type == 'rgb') { - color = $('.colorpicker_rgb_r input') - .val() + ',' + $('.colorpicker_rgb_g input') - .val() + ',' + $('.colorpicker_rgb_b input') - .val(); - if (returnRGBWrapper === false) { - insert = (color); - } else { - insert = ('rgb(' + color + ')'); - } - } else { - color = $('.colorpicker_hex input') - .val(); - if (sellength == 3 || sellength == 6) { - if (seltest) { - insert = color; - } else { - insert = '#' + color; - } - } else { - insert = '#' + color; - } - } - - codiad.active.insertText(insert); - codiad.modal.unload(); - - } - - }; - -})(this, jQuery); -"; \ No newline at end of file diff --git a/data/collaborative/text/2a0da7cebddb7852e2ac34f7c0d5e0c7 b/data/collaborative/text/2a0da7cebddb7852e2ac34f7c0d5e0c7 deleted file mode 100755 index 23485aa..0000000 --- a/data/collaborative/text/2a0da7cebddb7852e2ac34f7c0d5e0c7 +++ /dev/null @@ -1,1005 +0,0 @@ -s:37536:"/* - * Copyright (c) Codiad & Kent Safranski (codiad.com), distributed - * as-is and without warranty under the MIT License. See - * [root]/license.txt for more. This information must remain intact. - */ - -(function(global, $) { - - var EditSession = ace.require('ace/edit_session') - .EditSession; - var UndoManager = ace.require('ace/undomanager') - .UndoManager; - - var codiad = global.codiad; - - $(function() { - codiad.active.init(); - }); - - ////////////////////////////////////////////////////////////////// - // - // Active Files Component for Codiad - // --------------------------------- - // Track and manage EditSession instaces of files being edited. - // - ////////////////////////////////////////////////////////////////// - - codiad.active = { - - controller: 'components/active/controller.php', - - // Path to EditSession instance mapping - sessions: {}, - - // History of opened files - history: [], - - ////////////////////////////////////////////////////////////////// - // - // Check if a file is open. - // - // Parameters: - // path - {String} - // - ////////////////////////////////////////////////////////////////// - - isOpen: function(path) { - return !!this.sessions[path]; - }, - - open: function(path, content, mtime, inBackground, focus) { - if (focus === undefined) { - focus = true; - } - - var _this = this; - - if (this.isOpen(path)) { - if(focus) this.focus(path); - return; - } - var ext = codiad.filemanager.getExtension(path); - var mode = codiad.editor.selectMode(ext); - - var fn = function() { - //var Mode = require('ace/mode/' + mode) - // .Mode; - - // TODO: Ask for user confirmation before recovering - // And maybe show a diff - var draft = _this.checkDraft(path); - if (draft) { - content = draft; - codiad.message.success(i18n('Recovered unsaved content for: ') + path); - } - - //var session = new EditSession(content, new Mode()); - var session = new EditSession(content); - session.setMode("ace/mode/" + mode); - session.setUndoManager(new UndoManager()); - - session.path = path; - session.serverMTime = mtime; - _this.sessions[path] = session; - session.untainted = content.slice(0); - if (!inBackground && focus) { - codiad.editor.setSession(session); - } - _this.add(path, session, focus); - /* Notify listeners. */ - amplify.publish('active.onOpen', path); - }; - - // Assuming the mode file has no dependencies - $.loadScript('components/editor/ace-editor/mode-' + mode + '.js', - fn); - }, - - init: function() { - - var _this = this; - - _this.initTabDropdownMenu(); - _this.updateTabDropdownVisibility(); - - // Focus from list. - $('#list-active-files a') - .live('click', function(e) { - e.stopPropagation(); - _this.focus($(this).parent('li').attr('data-path')); - }); - - // Focus on left button click from dropdown. - $('#dropdown-list-active-files a') - .live('click', function(e) { - if(e.which == 1) { - /* Do not stop propagation of the event, - * it will be catch by the dropdown menu - * and close it. */ - _this.focus($(this).parent('li').attr('data-path')); - } - }); - - // Focus on left button mousedown from tab. - $('#tab-list-active-files li.tab-item>a.label') - .live('mousedown', function(e) { - if(e.which == 1) { - e.stopPropagation(); - _this.focus($(this).parent('li').attr('data-path')); - } - }); - - // Remove from list. - $('#list-active-files a>span') - .live('click', function(e) { - e.stopPropagation(); - _this.remove($(this) - .parent('a') - .parent('li') - .attr('data-path')); - }); - - // Remove from dropdown. - $('#dropdown-list-active-files a>span') - .live('click', function(e) { - e.stopPropagation(); - /* Get the active editor before removing anything. Remove the - * tab, then put back the focus on the previously active - * editor if it was not removed. */ - var activePath = _this.getPath(); - var pathToRemove = $(this).parents('li').attr('data-path'); - _this.remove(pathToRemove); - if (activePath !== null && activePath !== pathToRemove) { - _this.focus(activePath); - } - _this.updateTabDropdownVisibility(); - }); - - // Remove from tab. - $('#tab-list-active-files a.close') - .live('click', function(e) { - e.stopPropagation(); - /* Get the active editor before removing anything. Remove the - * tab, then put back the focus on the previously active - * editor if it was not removed. */ - var activePath = _this.getPath(); - var pathToRemove = $(this).parent('li').attr('data-path'); - _this.remove(pathToRemove); - if (activePath !== null && activePath !== pathToRemove) { - _this.focus(activePath); - } - _this.updateTabDropdownVisibility(); - }); - - // Remove from middle button click on dropdown. - $('#dropdown-list-active-files li') - .live('mouseup', function(e) { - if (e.which == 2) { - e.stopPropagation(); - /* Get the active editor before removing anything. Remove the - * tab, then put back the focus on the previously active - * editor if it was not removed. */ - var activePath = _this.getPath(); - var pathToRemove = $(this).attr('data-path'); - _this.remove(pathToRemove); - if (activePath !== null && activePath !== pathToRemove) { - _this.focus(activePath); - } - _this.updateTabDropdownVisibility(); - } - }); - - // Remove from middle button click on tab. - $('.tab-item') - .live('mouseup', function(e) { - if (e.which == 2) { - e.stopPropagation(); - /* Get the active editor before removing anything. Remove the - * tab, then put back the focus on the previously active - * editor if it was not removed. */ - var activePath = _this.getPath(); - var pathToRemove = $(this).attr('data-path'); - _this.remove(pathToRemove); - if (activePath !== null && activePath !== pathToRemove) { - _this.focus(activePath); - } - _this.updateTabDropdownVisibility(); - } - }); - - // Make list sortable - $('#list-active-files') - .sortable({ - placeholder: 'active-sort-placeholder', - tolerance: 'intersect', - start: function(e, ui) { - ui.placeholder.height(ui.item.height()); - } - }); - - // Make dropdown sortable. - $('#dropdown-list-active-files') - .sortable({ - axis: 'y', - tolerance: 'pointer', - start: function(e, ui) { - ui.placeholder.height(ui.item.height()); - } - }); - - // Make tabs sortable. - $('#tab-list-active-files') - .sortable({ - items: '> li', - axis: 'x', - tolerance: 'pointer', - containment: 'parent', - start: function(e, ui) { - ui.placeholder.css('background', 'transparent'); - ui.helper.css('width', '200px'); - }, - stop: function(e, ui) { - // Reset css - ui.item.css('z-index', '') - ui.item.css('position', '') - } - }); - /* Woaw, so tricky! At initialization, the tab-list is empty, so - * it is not marked as float so it is not detected as an horizontal - * list by the sortable plugin. Workaround is to mark it as - * floating at initialization time. See bug report - * http://bugs.jqueryui.com/ticket/6702. */ - $('#tab-list-active-files').data('sortable').floating = true; - - // Open saved-state active files on load - $.get(_this.controller + '?action=list', function(data) { - var listResponse = codiad.jsend.parse(data); - if (listResponse !== null) { - $.each(listResponse, function(index, data) { - codiad.filemanager.openFile(data.path, data.focused); - }); - } - }); - - // Prompt if a user tries to close window without saving all filess - window.onbeforeunload = function(e) { - if ($('#list-active-files li.changed') - .length > 0) { - var e = e || window.event; - var errMsg = i18n('You have unsaved files.'); - - // For IE and Firefox prior to version 4 - if (e) { - e.returnValue = errMsg; - } - - // For rest - return errMsg; - } - }; - }, - - ////////////////////////////////////////////////////////////////// - // Drafts - ////////////////////////////////////////////////////////////////// - - checkDraft: function(path) { - var draft = localStorage.getItem(path); - if (draft !== null) { - return draft; - } else { - return false; - } - }, - - removeDraft: function(path) { - localStorage.removeItem(path); - }, - - ////////////////////////////////////////////////////////////////// - // Get active editor path - ////////////////////////////////////////////////////////////////// - - getPath: function() { - try { - return codiad.editor.getActive() - .getSession() - .path; - } catch (e) { - return null; - } - }, - - ////////////////////////////////////////////////////////////////// - // Check if opened by another user - ////////////////////////////////////////////////////////////////// - - check: function(path) { - $.get(this.controller + '?action=check&path=' + encodeURIComponent(path), - - function(data) { - var checkResponse = codiad.jsend.parse(data); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Add newly opened file to list - ////////////////////////////////////////////////////////////////// - - add: function(path, session, focus) { - if (focus === undefined) { - focus = true; - } - - var listThumb = this.createListThumb(path); - session.listThumb = listThumb; - $('#list-active-files').append(listThumb); - - /* If the tab list would overflow with the new tab. Move the - * first tab to dropdown, then add a new tab. */ - if (this.isTabListOverflowed(true)) { - var tab = $('#tab-list-active-files li:first-child'); - this.moveTabToDropdownMenu(tab); - } - - var tabThumb = this.createTabThumb(path); - $('#tab-list-active-files').append(tabThumb); - session.tabThumb = tabThumb; - - this.updateTabDropdownVisibility(); - - $.get(this.controller + '?action=add&path=' + encodeURIComponent(path)); - - if(focus) { - this.focus(path); - } - - // Mark draft as changed - if (this.checkDraft(path)) { - this.markChanged(path); - } - }, - - ////////////////////////////////////////////////////////////////// - // Focus on opened file - ////////////////////////////////////////////////////////////////// - - focus: function(path, moveToTabList) { - if (moveToTabList === undefined) { - moveToTabList = true; - } - - this.highlightEntry(path, moveToTabList); - - if(path != this.getPath()) { - codiad.editor.setSession(this.sessions[path]); - this.history.push(path); - $.get(this.controller, {'action':'focused', 'path':path}); - } - - /* Check for users registered on the file. */ - this.check(path); - - /* Notify listeners. */ - amplify.publish('active.onFocus', path); - }, - - highlightEntry: function(path, moveToTabList) { - if (moveToTabList === undefined) { - moveToTabList = true; - } - - $('#list-active-files li') - .removeClass('active'); - - $('#tab-list-active-files li') - .removeClass('active'); - - $('#dropdown-list-active-files li') - .removeClass('active'); - - var session = this.sessions[path]; - - if($('#dropdown-list-active-files').has(session.tabThumb).length > 0) { - if(moveToTabList) { - /* Get the menu item as a tab, and put the last tab in - * dropdown. */ - var menuItem = session.tabThumb; - this.moveDropdownMenuItemToTab(menuItem, true); - - var tab = $('#tab-list-active-files li:last-child'); - this.moveTabToDropdownMenu(tab); - } else { - /* Show the dropdown menu if needed */ - this.showTabDropdownMenu(); - } - } - else if(this.history.length > 0) { - var prevPath = this.history[this.history.length-1]; - var prevSession = this.sessions[prevPath]; - if($('#dropdown-list-active-files').has(prevSession.tabThumb).length > 0) { - /* Hide the dropdown menu if needed */ - this.hideTabDropdownMenu(); - } - } - - session.tabThumb.addClass('active'); - session.listThumb.addClass('active'); - }, - - ////////////////////////////////////////////////////////////////// - // Mark changed - ////////////////////////////////////////////////////////////////// - - markChanged: function(path) { - this.sessions[path].listThumb.addClass('changed'); - this.sessions[path].tabThumb.addClass('changed'); - }, - - ////////////////////////////////////////////////////////////////// - // Save active editor - ////////////////////////////////////////////////////////////////// - - save: function(path) { - /* Notify listeners. */ - amplify.publish('active.onSave', path); - - var _this = this; - if ((path && !this.isOpen(path)) || (!path && !codiad.editor.getActive())) { - codiad.message.error(i18n('No Open Files to save')); - return; - } - var session; - if (path) session = this.sessions[path]; - else session = codiad.editor.getActive() - .getSession(); - var content = session.getValue(); - var path = session.path; - var handleSuccess = function(mtime){ - var session = codiad.active.sessions[path]; - if(typeof session != 'undefined') { - session.untainted = newContent; - session.serverMTime = mtime; - if (session.listThumb) session.listThumb.removeClass('changed'); - if (session.tabThumb) session.tabThumb.removeClass('changed'); - } - _this.removeDraft(path); - } - // Replicate the current content so as to avoid - // discrepancies due to content changes during - // computation of diff - - var newContent = content.slice(0); - if (session.serverMTime && session.untainted){ - codiad.workerManager.addTask({ - taskType: 'diff', - id: path, - original: session.untainted, - changed: newContent - }, function(success, patch){ - if (success) { - codiad.filemanager.savePatch(path, patch, session.serverMTime, { - success: handleSuccess - }); - } else { - codiad.filemanager.saveFile(path, newContent, { - success: handleSuccess - }); - } - }, this); - } else { - codiad.filemanager.saveFile(path, newContent, { - success: handleSuccess - }); - } - }, - - ////////////////////////////////////////////////////////////////// - // Save all files - ////////////////////////////////////////////////////////////////// - - saveAll: function() { - var _this = this; - for(var session in _this.sessions) { - if (_this.sessions[session].listThumb.hasClass('changed')) { - codiad.active.save(session); - } - } - }, - - ////////////////////////////////////////////////////////////////// - // Remove file - ////////////////////////////////////////////////////////////////// - - remove: function(path) { - if (!this.isOpen(path)) return; - var session = this.sessions[path]; - var closeFile = true; - if (session.listThumb.hasClass('changed')) { - codiad.modal.load(450, 'components/active/dialog.php?action=confirm&path=' + encodeURIComponent(path)); - closeFile = false; - } - if (closeFile) { - this.close(path); - } - }, - - removeAll: function(discard) { - discard = discard || false; - /* Notify listeners. */ - amplify.publish('active.onRemoveAll'); - - var _this = this; - var changed = false; - - var opentabs = new Array(); - for(var session in _this.sessions) { - opentabs[session] = session; - if (_this.sessions[session].listThumb.hasClass('changed')) { - changed = true; - } - } - if(changed && !discard) { - codiad.modal.load(450, 'components/active/dialog.php?action=confirmAll'); - return; - } - - for(var tab in opentabs) { - var session = this.sessions[tab]; - - session.tabThumb.remove(); - _this.updateTabDropdownVisibility(); - - session.listThumb.remove(); - - /* Remove closed path from history */ - var history = []; - $.each(this.history, function(index) { - if(this != tab) history.push(this); - }) - this.history = history - - delete this.sessions[tab]; - this.removeDraft(tab); - } - codiad.editor.exterminate(); - $('#list-active-files').html(''); - $.get(this.controller + '?action=removeall'); - }, - - close: function(path) { - /* Notify listeners. */ - amplify.publish('active.onClose', path); - - var _this = this; - var session = this.sessions[path]; - - /* Animate only if the tabThumb if a tab, not a dropdown item. */ - if(session.tabThumb.hasClass('tab-item')) { - session.tabThumb.css({'z-index': 1}); - session.tabThumb.animate({ - top: $('#editor-top-bar').height() + 'px' - }, 300, function() { - session.tabThumb.remove(); - _this.updateTabDropdownVisibility(); - }); - } else { - session.tabThumb.remove(); - _this.updateTabDropdownVisibility(); - } - - session.listThumb.remove(); - - /* Remove closed path from history */ - var history = []; - $.each(this.history, function(index) { - if(this != path) history.push(this); - }) - this.history = history - - /* Select all the tab tumbs except the one which is to be removed. */ - var tabThumbs = $('#tab-list-active-files li[data-path!="' + path + '"]'); - - if (tabThumbs.length == 0) { - codiad.editor.exterminate(); - } else { - - var nextPath = ''; - if(this.history.length > 0) { - nextPath = this.history[this.history.length - 1]; - } else { - nextPath = $(tabThumbs[0]).attr('data-path'); - } - var nextSession = this.sessions[nextPath]; - codiad.editor.removeSession(session, nextSession); - - this.focus(nextPath); - } - delete this.sessions[path]; - $.get(this.controller + '?action=remove&path=' + encodeURIComponent(path)); - this.removeDraft(path); - }, - - ////////////////////////////////////////////////////////////////// - // Process rename - ////////////////////////////////////////////////////////////////// - - rename: function(oldPath, newPath) { - var switchSessions = function(oldPath, newPath) { - var tabThumb = this.sessions[oldPath].tabThumb; - tabThumb.attr('data-path', newPath); - var title = newPath; - if (codiad.project.isAbsPath(newPath)) { - title = newPath.substring(1); - } - tabThumb.find('.label') - .text(title); - this.sessions[newPath] = this.sessions[oldPath]; - this.sessions[newPath].path = newPath; - delete this.sessions[oldPath]; - //Rename history - for (var i = 0; i < this.history.length; i++) { - if (this.history[i] === oldPath) { - this.history[i] = newPath; - } - } - }; - if (this.sessions[oldPath]) { - // A file was renamed - switchSessions.apply(this, [oldPath, newPath]); - // pass new sessions instance to setactive - for (var k = 0; k < codiad.editor.instances.length; k++) { - if (codiad.editor.instances[k].getSession().path === newPath) { - codiad.editor.setActive(codiad.editor.instances[k]); - } - } - - var newSession = this.sessions[newPath]; - - // Change Editor Mode - var ext = codiad.filemanager.getExtension(newPath); - var mode = codiad.editor.selectMode(ext); - - // handle async mode change - var fn = function() { - codiad.editor.setModeDisplay(newSession); - newSession.removeListener('changeMode', fn); - } - - newSession.on("changeMode", fn); - newSession.setMode("ace/mode/" + mode); - } else { - // A folder was renamed - var newKey; - for (var key in this.sessions) { - newKey = key.replace(oldPath, newPath); - if (newKey !== key) { - switchSessions.apply(this, [key, newKey]); - } - } - } - $.get(this.controller + '?action=rename&old_path=' + encodeURIComponent(oldPath) + '&new_path=' + encodeURIComponent(newPath), function() { - /* Notify listeners. */ - amplify.publish('active.onRename', {"oldPath": oldPath, "newPath": newPath}); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Open in Browser - ////////////////////////////////////////////////////////////////// - - openInBrowser: function() { - var path = this.getPath(); - if (path) { - codiad.filemanager.openInBrowser(path); - } else { - codiad.message.error('No Open Files'); - } - }, - - ////////////////////////////////////////////////////////////////// - // Get Selected Text - ////////////////////////////////////////////////////////////////// - - getSelectedText: function() { - var path = this.getPath(); - var session = this.sessions[path]; - - if (path && this.isOpen(path)) { - return session.getTextRange( - codiad.editor.getActive() - .getSelectionRange()); - } else { - codiad.message.error(i18n('No Open Files or Selected Text')); - } - }, - - ////////////////////////////////////////////////////////////////// - // Insert Text - ////////////////////////////////////////////////////////////////// - - insertText: function(val) { - codiad.editor.getActive() - .insert(val); - }, - - ////////////////////////////////////////////////////////////////// - // Goto Line - ////////////////////////////////////////////////////////////////// - - gotoLine: function(line) { - codiad.editor.getActive() - .gotoLine(line, 0, true); - }, - - ////////////////////////////////////////////////////////////////// - // Move Up (Key Combo) - ////////////////////////////////////////////////////////////////// - - move: function(dir) { - - var num = $('#tab-list-active-files li').length; - if (num === 0) return; - - var newActive = null; - var active = null; - - if (dir == 'up') { - - // If active is in the tab list - active = $('#tab-list-active-files li.active'); - if(active.length > 0) { - // Previous or rotate to the end - newActive = active.prev('li'); - if (newActive.length === 0) { - newActive = $('#dropdown-list-active-files li:last-child') - if (newActive.length === 0) { - newActive = $('#tab-list-active-files li:last-child') - } - } - } - - // If active is in the dropdown list - active = $('#dropdown-list-active-files li.active'); - if(active.length > 0) { - // Previous - newActive = active.prev('li'); - if (newActive.length === 0) { - newActive = $('#tab-list-active-files li:last-child') - } - } - - } else { - - // If active is in the tab list - active = $('#tab-list-active-files li.active'); - if(active.length > 0) { - // Next or rotate to the beginning - newActive = active.next('li'); - if (newActive.length === 0) { - newActive = $('#dropdown-list-active-files li:first-child'); - if (newActive.length === 0) { - newActive = $('#tab-list-active-files li:first-child') - } - } - } - - // If active is in the dropdown list - active = $('#dropdown-list-active-files li.active'); - if(active.length > 0) { - // Next or rotate to the beginning - newActive = active.next('li'); - if (newActive.length === 0) { - newActive = $('#tab-list-active-files li:first-child') - } - } - - } - - if(newActive) this.focus(newActive.attr('data-path'), false); - }, - - ////////////////////////////////////////////////////////////////// - // Dropdown Menu - ////////////////////////////////////////////////////////////////// - - initTabDropdownMenu: function() { - var _this = this; - - var menu = $('#dropdown-list-active-files'); - var button = $('#tab-dropdown-button'); - var closebutton = $('#tab-close-button'); - - menu.appendTo($('body')); - - button.click(function(e) { - e.stopPropagation(); - _this.toggleTabDropdownMenu(); - }); - - closebutton.click(function(e) { - e.stopPropagation(); - _this.removeAll(); - }); - }, - - showTabDropdownMenu: function() { - var menu = $('#dropdown-list-active-files'); - if(!menu.is(':visible')) this.toggleTabDropdownMenu(); - }, - - hideTabDropdownMenu: function() { - var menu = $('#dropdown-list-active-files'); - if(menu.is(':visible')) this.toggleTabDropdownMenu(); - }, - - toggleTabDropdownMenu: function() { - var _this = this; - var menu = $('#dropdown-list-active-files'); - - menu.css({ - top: $("#editor-top-bar").height() + 'px', - right: '20px', - width: '200px' - }); - - menu.slideToggle('fast'); - - if(menu.is(':visible')) { - // handle click-out autoclosing - var fn = function() { - menu.hide(); - $(window).off('click', fn) - } - $(window).on('click', fn); - } - }, - - moveTabToDropdownMenu: function(tab, prepend) { - if (prepend === undefined) { - prepend = false; - } - - tab.remove(); - path = tab.attr('data-path'); - - var tabThumb = this.createMenuItemThumb(path); - if(prepend) $('#dropdown-list-active-files').prepend(tabThumb); - else $('#dropdown-list-active-files').append(tabThumb); - - if(tab.hasClass("changed")) { - tabThumb.addClass("changed"); - } - - if(tab.hasClass("active")) { - tabThumb.addClass("active"); - } - - this.sessions[path].tabThumb = tabThumb; - }, - - moveDropdownMenuItemToTab: function(menuItem, prepend) { - if (prepend === undefined) { - prepend = false; - } - - menuItem.remove(); - path = menuItem.attr('data-path'); - - var tabThumb = this.createTabThumb(path); - if(prepend) $('#tab-list-active-files').prepend(tabThumb); - else $('#tab-list-active-files').append(tabThumb); - - if(menuItem.hasClass("changed")) { - tabThumb.addClass("changed"); - } - - if(menuItem.hasClass("active")) { - tabThumb.addClass("active"); - } - - this.sessions[path].tabThumb = tabThumb; - }, - - isTabListOverflowed: function(includeFictiveTab) { - if (includeFictiveTab === undefined) { - includeFictiveTab = false; - } - - var tabs = $('#tab-list-active-files li'); - var count = tabs.length - if (includeFictiveTab) count += 1; - if (count <= 1) return false; - - var width = 0; - tabs.each(function(index) { - width += $(this).outerWidth(true); - }) - if (includeFictiveTab) { - width += $(tabs[tabs.length-1]).outerWidth(true); - } - - /* If we subtract the width of the left side bar, of the right side - * bar handle and of the tab dropdown handle to the window width, - * do we have enough room for the tab list? Its kind of complicated - * to handle all the offsets, so afterwards we add a fixed offset - * just t be sure. */ - var lsbarWidth = $(".sidebar-handle").width(); - if (codiad.sidebars.isLeftSidebarOpen) { - lsbarWidth = $("#sb-left").width(); - } - - var rsbarWidth = $(".sidebar-handle").width(); - if (codiad.sidebars.isRightSidebarOpen) { - rsbarWidth = $("#sb-right").width(); - } - - var tabListWidth = $("#tab-list-active-files").width(); - var dropdownWidth = $('#tab-dropdown').width(); - var closeWidth = $('#tab-close').width(); - var room = window.innerWidth - lsbarWidth - rsbarWidth - dropdownWidth - closeWidth - width - 30; - return (room < 0); - }, - - updateTabDropdownVisibility: function() { - while(this.isTabListOverflowed()) { - var tab = $('#tab-list-active-files li:last-child'); - if (tab.length == 1) this.moveTabToDropdownMenu(tab, true); - else break; - } - - while(!this.isTabListOverflowed(true)) { - var menuItem = $('#dropdown-list-active-files li:first-child'); - if (menuItem.length == 1) this.moveDropdownMenuItemToTab(menuItem); - else break; - } - - if ($('#dropdown-list-active-files li').length > 0) { - $('#tab-dropdown').show(); - } else { - $('#tab-dropdown').hide(); - // Be sure to hide the menu if it is opened. - $('#dropdown-list-active-files').hide(); - } - if ($('#tab-list-active-files li').length > 1) { - $('#tab-close').show(); - } else { - $('#tab-close').hide(); - } - }, - - ////////////////////////////////////////////////////////////////// - // Factory - ////////////////////////////////////////////////////////////////// - - splitDirectoryAndFileName: function(path) { - var index = path.lastIndexOf('/'); - return { - fileName: path.substring(index + 1), - directory: (path.indexOf('/') == 0)? path.substring(1, index + 1):path.substring(0, index + 1) - } - }, - - createListThumb: function(path) { - return $('
  • ' + path + '
  • '); - }, - - createTabThumb: function(path) { - split = this.splitDirectoryAndFileName(path); - return $('
  • ' - + split.directory + '' + split.fileName + '' - + 'x
  • '); - }, - - createMenuItemThumb: function(path) { - split = this.splitDirectoryAndFileName(path); - return $('
  • ' - + split.directory + '' + split.fileName + '' - + '
  • '); - }, - - }; - -})(this, jQuery); -"; \ No newline at end of file diff --git a/data/collaborative/text/2af01a9b54a6e94e6a011cd84b4c5b48 b/data/collaborative/text/2af01a9b54a6e94e6a011cd84b4c5b48 deleted file mode 100755 index e913fc2..0000000 --- a/data/collaborative/text/2af01a9b54a6e94e6a011cd84b4c5b48 +++ /dev/null @@ -1,48 +0,0 @@ -s:1265:"Init(); -} - - ////////////////////////////////////////////////////////////////// - // Clear Version - ////////////////////////////////////////////////////////////////// - -if ($_GET['action']=='clear') { - if (checkAccess()) { - $update->Clear(); - } -} - - ////////////////////////////////////////////////////////////////// - // OptOut - ////////////////////////////////////////////////////////////////// - -if ($_GET['action']=='optout') { - if (checkAccess()) { - $update->OptOut(); - } -} -"; \ No newline at end of file diff --git a/data/collaborative/text/2b2340b37b43b24e5a2731ed5db41118 b/data/collaborative/text/2b2340b37b43b24e5a2731ed5db41118 deleted file mode 100755 index 002d7ea..0000000 --- a/data/collaborative/text/2b2340b37b43b24e5a2731ed5db41118 +++ /dev/null @@ -1,60 +0,0 @@ -s:2621:" - - - - - - - Abbas' Color Picker - - - - - - - - - - -
    -
    -
    -
    -
    -
    Initializing

    -
    ' + msg + '
    ' + name + ': ' + date + '
    ' + hash.substr(0, 8) + '
      '; - for (var j = 0; j < unique[i].lines.length; j++) { - line = unique[i].lines[j].replace(new RegExp('\t', 'g'), ' ') - .replace(new RegExp(' ', 'g'), " ") - .replace(new RegExp('\n', 'g'), "
      "); - output += '
    1. ' + line + '
    2. '; - } - output += '
    '+status+''+name+'
    - - - - -
    hue - - -
    saturation - - -
    lightness - - -
    alpha - - -
    -

    -
    mnemonic
    -
    - -
    - X: - Y:
    - angle:
    - radius: -
    - - - - - -"; \ No newline at end of file diff --git a/data/collaborative/text/2bcf46daf121a8f0ab61fb9c00ea4400 b/data/collaborative/text/2bcf46daf121a8f0ab61fb9c00ea4400 deleted file mode 100755 index 5527786..0000000 --- a/data/collaborative/text/2bcf46daf121a8f0ab61fb9c00ea4400 +++ /dev/null @@ -1,16 +0,0 @@ -s:1065:"lastname, firstname, phone, email, group, photo -Abdulmalik, Abbas, 610-357-2710, aabdulmalik@pit.edu, group, photo -Smith, Frank, 610-331-8295, 17Smith7920@pit.edu, group, photo -Fletcher, Thomas, 484-842-1021, 17Fletch7785@pit.edu, group, photo -Thollie, Ibrahim, 619-532-2344, 17Tholli8829@pit.edu, group, photo -Philmore, Mitchell, 215-520-1775, 17Philmo6088@pit.edu, group, photo -Beresford, Trevor, 610-490-0365, 17Beresf7817@pit.edu, group, photo -Hunsinger, Eric, 610-883-7292, 18Hunsin7743@pit.edu, group, photo -Tarawali, Abdul Salam, 484-477-5760, 18Tarawa6787@pit.edu, group, photo -Kupa, Shpetim, 215-909-3598, 15Kupa8824@pit.edu, group, photo -Dilligard, Deon, 484-347-4019, 16Dillig7628@pit.edu, group, photo -Brown, Isaac, 717-353-3888, 17Brown9053@pit.edu, group, photo -Anderson, Courtney, 267-414-6146, 17Anders7872@pit.edu, group, photo -Cammauf, Carter, 717-341-4278, 18Cammau7716@pit.edu, group, photo -Itchon, Lester, 610-883-7341, 17Itchon7808@pit.edu, group, photo -Povey, Stephen, 484-326-7389, 17Povey6023@pit.edu, group, photo"; \ No newline at end of file diff --git a/data/collaborative/text/303bfe190d5e04a7238bab12ce1bb129 b/data/collaborative/text/303bfe190d5e04a7238bab12ce1bb129 deleted file mode 100755 index 23485aa..0000000 --- a/data/collaborative/text/303bfe190d5e04a7238bab12ce1bb129 +++ /dev/null @@ -1,1005 +0,0 @@ -s:37536:"/* - * Copyright (c) Codiad & Kent Safranski (codiad.com), distributed - * as-is and without warranty under the MIT License. See - * [root]/license.txt for more. This information must remain intact. - */ - -(function(global, $) { - - var EditSession = ace.require('ace/edit_session') - .EditSession; - var UndoManager = ace.require('ace/undomanager') - .UndoManager; - - var codiad = global.codiad; - - $(function() { - codiad.active.init(); - }); - - ////////////////////////////////////////////////////////////////// - // - // Active Files Component for Codiad - // --------------------------------- - // Track and manage EditSession instaces of files being edited. - // - ////////////////////////////////////////////////////////////////// - - codiad.active = { - - controller: 'components/active/controller.php', - - // Path to EditSession instance mapping - sessions: {}, - - // History of opened files - history: [], - - ////////////////////////////////////////////////////////////////// - // - // Check if a file is open. - // - // Parameters: - // path - {String} - // - ////////////////////////////////////////////////////////////////// - - isOpen: function(path) { - return !!this.sessions[path]; - }, - - open: function(path, content, mtime, inBackground, focus) { - if (focus === undefined) { - focus = true; - } - - var _this = this; - - if (this.isOpen(path)) { - if(focus) this.focus(path); - return; - } - var ext = codiad.filemanager.getExtension(path); - var mode = codiad.editor.selectMode(ext); - - var fn = function() { - //var Mode = require('ace/mode/' + mode) - // .Mode; - - // TODO: Ask for user confirmation before recovering - // And maybe show a diff - var draft = _this.checkDraft(path); - if (draft) { - content = draft; - codiad.message.success(i18n('Recovered unsaved content for: ') + path); - } - - //var session = new EditSession(content, new Mode()); - var session = new EditSession(content); - session.setMode("ace/mode/" + mode); - session.setUndoManager(new UndoManager()); - - session.path = path; - session.serverMTime = mtime; - _this.sessions[path] = session; - session.untainted = content.slice(0); - if (!inBackground && focus) { - codiad.editor.setSession(session); - } - _this.add(path, session, focus); - /* Notify listeners. */ - amplify.publish('active.onOpen', path); - }; - - // Assuming the mode file has no dependencies - $.loadScript('components/editor/ace-editor/mode-' + mode + '.js', - fn); - }, - - init: function() { - - var _this = this; - - _this.initTabDropdownMenu(); - _this.updateTabDropdownVisibility(); - - // Focus from list. - $('#list-active-files a') - .live('click', function(e) { - e.stopPropagation(); - _this.focus($(this).parent('li').attr('data-path')); - }); - - // Focus on left button click from dropdown. - $('#dropdown-list-active-files a') - .live('click', function(e) { - if(e.which == 1) { - /* Do not stop propagation of the event, - * it will be catch by the dropdown menu - * and close it. */ - _this.focus($(this).parent('li').attr('data-path')); - } - }); - - // Focus on left button mousedown from tab. - $('#tab-list-active-files li.tab-item>a.label') - .live('mousedown', function(e) { - if(e.which == 1) { - e.stopPropagation(); - _this.focus($(this).parent('li').attr('data-path')); - } - }); - - // Remove from list. - $('#list-active-files a>span') - .live('click', function(e) { - e.stopPropagation(); - _this.remove($(this) - .parent('a') - .parent('li') - .attr('data-path')); - }); - - // Remove from dropdown. - $('#dropdown-list-active-files a>span') - .live('click', function(e) { - e.stopPropagation(); - /* Get the active editor before removing anything. Remove the - * tab, then put back the focus on the previously active - * editor if it was not removed. */ - var activePath = _this.getPath(); - var pathToRemove = $(this).parents('li').attr('data-path'); - _this.remove(pathToRemove); - if (activePath !== null && activePath !== pathToRemove) { - _this.focus(activePath); - } - _this.updateTabDropdownVisibility(); - }); - - // Remove from tab. - $('#tab-list-active-files a.close') - .live('click', function(e) { - e.stopPropagation(); - /* Get the active editor before removing anything. Remove the - * tab, then put back the focus on the previously active - * editor if it was not removed. */ - var activePath = _this.getPath(); - var pathToRemove = $(this).parent('li').attr('data-path'); - _this.remove(pathToRemove); - if (activePath !== null && activePath !== pathToRemove) { - _this.focus(activePath); - } - _this.updateTabDropdownVisibility(); - }); - - // Remove from middle button click on dropdown. - $('#dropdown-list-active-files li') - .live('mouseup', function(e) { - if (e.which == 2) { - e.stopPropagation(); - /* Get the active editor before removing anything. Remove the - * tab, then put back the focus on the previously active - * editor if it was not removed. */ - var activePath = _this.getPath(); - var pathToRemove = $(this).attr('data-path'); - _this.remove(pathToRemove); - if (activePath !== null && activePath !== pathToRemove) { - _this.focus(activePath); - } - _this.updateTabDropdownVisibility(); - } - }); - - // Remove from middle button click on tab. - $('.tab-item') - .live('mouseup', function(e) { - if (e.which == 2) { - e.stopPropagation(); - /* Get the active editor before removing anything. Remove the - * tab, then put back the focus on the previously active - * editor if it was not removed. */ - var activePath = _this.getPath(); - var pathToRemove = $(this).attr('data-path'); - _this.remove(pathToRemove); - if (activePath !== null && activePath !== pathToRemove) { - _this.focus(activePath); - } - _this.updateTabDropdownVisibility(); - } - }); - - // Make list sortable - $('#list-active-files') - .sortable({ - placeholder: 'active-sort-placeholder', - tolerance: 'intersect', - start: function(e, ui) { - ui.placeholder.height(ui.item.height()); - } - }); - - // Make dropdown sortable. - $('#dropdown-list-active-files') - .sortable({ - axis: 'y', - tolerance: 'pointer', - start: function(e, ui) { - ui.placeholder.height(ui.item.height()); - } - }); - - // Make tabs sortable. - $('#tab-list-active-files') - .sortable({ - items: '> li', - axis: 'x', - tolerance: 'pointer', - containment: 'parent', - start: function(e, ui) { - ui.placeholder.css('background', 'transparent'); - ui.helper.css('width', '200px'); - }, - stop: function(e, ui) { - // Reset css - ui.item.css('z-index', '') - ui.item.css('position', '') - } - }); - /* Woaw, so tricky! At initialization, the tab-list is empty, so - * it is not marked as float so it is not detected as an horizontal - * list by the sortable plugin. Workaround is to mark it as - * floating at initialization time. See bug report - * http://bugs.jqueryui.com/ticket/6702. */ - $('#tab-list-active-files').data('sortable').floating = true; - - // Open saved-state active files on load - $.get(_this.controller + '?action=list', function(data) { - var listResponse = codiad.jsend.parse(data); - if (listResponse !== null) { - $.each(listResponse, function(index, data) { - codiad.filemanager.openFile(data.path, data.focused); - }); - } - }); - - // Prompt if a user tries to close window without saving all filess - window.onbeforeunload = function(e) { - if ($('#list-active-files li.changed') - .length > 0) { - var e = e || window.event; - var errMsg = i18n('You have unsaved files.'); - - // For IE and Firefox prior to version 4 - if (e) { - e.returnValue = errMsg; - } - - // For rest - return errMsg; - } - }; - }, - - ////////////////////////////////////////////////////////////////// - // Drafts - ////////////////////////////////////////////////////////////////// - - checkDraft: function(path) { - var draft = localStorage.getItem(path); - if (draft !== null) { - return draft; - } else { - return false; - } - }, - - removeDraft: function(path) { - localStorage.removeItem(path); - }, - - ////////////////////////////////////////////////////////////////// - // Get active editor path - ////////////////////////////////////////////////////////////////// - - getPath: function() { - try { - return codiad.editor.getActive() - .getSession() - .path; - } catch (e) { - return null; - } - }, - - ////////////////////////////////////////////////////////////////// - // Check if opened by another user - ////////////////////////////////////////////////////////////////// - - check: function(path) { - $.get(this.controller + '?action=check&path=' + encodeURIComponent(path), - - function(data) { - var checkResponse = codiad.jsend.parse(data); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Add newly opened file to list - ////////////////////////////////////////////////////////////////// - - add: function(path, session, focus) { - if (focus === undefined) { - focus = true; - } - - var listThumb = this.createListThumb(path); - session.listThumb = listThumb; - $('#list-active-files').append(listThumb); - - /* If the tab list would overflow with the new tab. Move the - * first tab to dropdown, then add a new tab. */ - if (this.isTabListOverflowed(true)) { - var tab = $('#tab-list-active-files li:first-child'); - this.moveTabToDropdownMenu(tab); - } - - var tabThumb = this.createTabThumb(path); - $('#tab-list-active-files').append(tabThumb); - session.tabThumb = tabThumb; - - this.updateTabDropdownVisibility(); - - $.get(this.controller + '?action=add&path=' + encodeURIComponent(path)); - - if(focus) { - this.focus(path); - } - - // Mark draft as changed - if (this.checkDraft(path)) { - this.markChanged(path); - } - }, - - ////////////////////////////////////////////////////////////////// - // Focus on opened file - ////////////////////////////////////////////////////////////////// - - focus: function(path, moveToTabList) { - if (moveToTabList === undefined) { - moveToTabList = true; - } - - this.highlightEntry(path, moveToTabList); - - if(path != this.getPath()) { - codiad.editor.setSession(this.sessions[path]); - this.history.push(path); - $.get(this.controller, {'action':'focused', 'path':path}); - } - - /* Check for users registered on the file. */ - this.check(path); - - /* Notify listeners. */ - amplify.publish('active.onFocus', path); - }, - - highlightEntry: function(path, moveToTabList) { - if (moveToTabList === undefined) { - moveToTabList = true; - } - - $('#list-active-files li') - .removeClass('active'); - - $('#tab-list-active-files li') - .removeClass('active'); - - $('#dropdown-list-active-files li') - .removeClass('active'); - - var session = this.sessions[path]; - - if($('#dropdown-list-active-files').has(session.tabThumb).length > 0) { - if(moveToTabList) { - /* Get the menu item as a tab, and put the last tab in - * dropdown. */ - var menuItem = session.tabThumb; - this.moveDropdownMenuItemToTab(menuItem, true); - - var tab = $('#tab-list-active-files li:last-child'); - this.moveTabToDropdownMenu(tab); - } else { - /* Show the dropdown menu if needed */ - this.showTabDropdownMenu(); - } - } - else if(this.history.length > 0) { - var prevPath = this.history[this.history.length-1]; - var prevSession = this.sessions[prevPath]; - if($('#dropdown-list-active-files').has(prevSession.tabThumb).length > 0) { - /* Hide the dropdown menu if needed */ - this.hideTabDropdownMenu(); - } - } - - session.tabThumb.addClass('active'); - session.listThumb.addClass('active'); - }, - - ////////////////////////////////////////////////////////////////// - // Mark changed - ////////////////////////////////////////////////////////////////// - - markChanged: function(path) { - this.sessions[path].listThumb.addClass('changed'); - this.sessions[path].tabThumb.addClass('changed'); - }, - - ////////////////////////////////////////////////////////////////// - // Save active editor - ////////////////////////////////////////////////////////////////// - - save: function(path) { - /* Notify listeners. */ - amplify.publish('active.onSave', path); - - var _this = this; - if ((path && !this.isOpen(path)) || (!path && !codiad.editor.getActive())) { - codiad.message.error(i18n('No Open Files to save')); - return; - } - var session; - if (path) session = this.sessions[path]; - else session = codiad.editor.getActive() - .getSession(); - var content = session.getValue(); - var path = session.path; - var handleSuccess = function(mtime){ - var session = codiad.active.sessions[path]; - if(typeof session != 'undefined') { - session.untainted = newContent; - session.serverMTime = mtime; - if (session.listThumb) session.listThumb.removeClass('changed'); - if (session.tabThumb) session.tabThumb.removeClass('changed'); - } - _this.removeDraft(path); - } - // Replicate the current content so as to avoid - // discrepancies due to content changes during - // computation of diff - - var newContent = content.slice(0); - if (session.serverMTime && session.untainted){ - codiad.workerManager.addTask({ - taskType: 'diff', - id: path, - original: session.untainted, - changed: newContent - }, function(success, patch){ - if (success) { - codiad.filemanager.savePatch(path, patch, session.serverMTime, { - success: handleSuccess - }); - } else { - codiad.filemanager.saveFile(path, newContent, { - success: handleSuccess - }); - } - }, this); - } else { - codiad.filemanager.saveFile(path, newContent, { - success: handleSuccess - }); - } - }, - - ////////////////////////////////////////////////////////////////// - // Save all files - ////////////////////////////////////////////////////////////////// - - saveAll: function() { - var _this = this; - for(var session in _this.sessions) { - if (_this.sessions[session].listThumb.hasClass('changed')) { - codiad.active.save(session); - } - } - }, - - ////////////////////////////////////////////////////////////////// - // Remove file - ////////////////////////////////////////////////////////////////// - - remove: function(path) { - if (!this.isOpen(path)) return; - var session = this.sessions[path]; - var closeFile = true; - if (session.listThumb.hasClass('changed')) { - codiad.modal.load(450, 'components/active/dialog.php?action=confirm&path=' + encodeURIComponent(path)); - closeFile = false; - } - if (closeFile) { - this.close(path); - } - }, - - removeAll: function(discard) { - discard = discard || false; - /* Notify listeners. */ - amplify.publish('active.onRemoveAll'); - - var _this = this; - var changed = false; - - var opentabs = new Array(); - for(var session in _this.sessions) { - opentabs[session] = session; - if (_this.sessions[session].listThumb.hasClass('changed')) { - changed = true; - } - } - if(changed && !discard) { - codiad.modal.load(450, 'components/active/dialog.php?action=confirmAll'); - return; - } - - for(var tab in opentabs) { - var session = this.sessions[tab]; - - session.tabThumb.remove(); - _this.updateTabDropdownVisibility(); - - session.listThumb.remove(); - - /* Remove closed path from history */ - var history = []; - $.each(this.history, function(index) { - if(this != tab) history.push(this); - }) - this.history = history - - delete this.sessions[tab]; - this.removeDraft(tab); - } - codiad.editor.exterminate(); - $('#list-active-files').html(''); - $.get(this.controller + '?action=removeall'); - }, - - close: function(path) { - /* Notify listeners. */ - amplify.publish('active.onClose', path); - - var _this = this; - var session = this.sessions[path]; - - /* Animate only if the tabThumb if a tab, not a dropdown item. */ - if(session.tabThumb.hasClass('tab-item')) { - session.tabThumb.css({'z-index': 1}); - session.tabThumb.animate({ - top: $('#editor-top-bar').height() + 'px' - }, 300, function() { - session.tabThumb.remove(); - _this.updateTabDropdownVisibility(); - }); - } else { - session.tabThumb.remove(); - _this.updateTabDropdownVisibility(); - } - - session.listThumb.remove(); - - /* Remove closed path from history */ - var history = []; - $.each(this.history, function(index) { - if(this != path) history.push(this); - }) - this.history = history - - /* Select all the tab tumbs except the one which is to be removed. */ - var tabThumbs = $('#tab-list-active-files li[data-path!="' + path + '"]'); - - if (tabThumbs.length == 0) { - codiad.editor.exterminate(); - } else { - - var nextPath = ''; - if(this.history.length > 0) { - nextPath = this.history[this.history.length - 1]; - } else { - nextPath = $(tabThumbs[0]).attr('data-path'); - } - var nextSession = this.sessions[nextPath]; - codiad.editor.removeSession(session, nextSession); - - this.focus(nextPath); - } - delete this.sessions[path]; - $.get(this.controller + '?action=remove&path=' + encodeURIComponent(path)); - this.removeDraft(path); - }, - - ////////////////////////////////////////////////////////////////// - // Process rename - ////////////////////////////////////////////////////////////////// - - rename: function(oldPath, newPath) { - var switchSessions = function(oldPath, newPath) { - var tabThumb = this.sessions[oldPath].tabThumb; - tabThumb.attr('data-path', newPath); - var title = newPath; - if (codiad.project.isAbsPath(newPath)) { - title = newPath.substring(1); - } - tabThumb.find('.label') - .text(title); - this.sessions[newPath] = this.sessions[oldPath]; - this.sessions[newPath].path = newPath; - delete this.sessions[oldPath]; - //Rename history - for (var i = 0; i < this.history.length; i++) { - if (this.history[i] === oldPath) { - this.history[i] = newPath; - } - } - }; - if (this.sessions[oldPath]) { - // A file was renamed - switchSessions.apply(this, [oldPath, newPath]); - // pass new sessions instance to setactive - for (var k = 0; k < codiad.editor.instances.length; k++) { - if (codiad.editor.instances[k].getSession().path === newPath) { - codiad.editor.setActive(codiad.editor.instances[k]); - } - } - - var newSession = this.sessions[newPath]; - - // Change Editor Mode - var ext = codiad.filemanager.getExtension(newPath); - var mode = codiad.editor.selectMode(ext); - - // handle async mode change - var fn = function() { - codiad.editor.setModeDisplay(newSession); - newSession.removeListener('changeMode', fn); - } - - newSession.on("changeMode", fn); - newSession.setMode("ace/mode/" + mode); - } else { - // A folder was renamed - var newKey; - for (var key in this.sessions) { - newKey = key.replace(oldPath, newPath); - if (newKey !== key) { - switchSessions.apply(this, [key, newKey]); - } - } - } - $.get(this.controller + '?action=rename&old_path=' + encodeURIComponent(oldPath) + '&new_path=' + encodeURIComponent(newPath), function() { - /* Notify listeners. */ - amplify.publish('active.onRename', {"oldPath": oldPath, "newPath": newPath}); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Open in Browser - ////////////////////////////////////////////////////////////////// - - openInBrowser: function() { - var path = this.getPath(); - if (path) { - codiad.filemanager.openInBrowser(path); - } else { - codiad.message.error('No Open Files'); - } - }, - - ////////////////////////////////////////////////////////////////// - // Get Selected Text - ////////////////////////////////////////////////////////////////// - - getSelectedText: function() { - var path = this.getPath(); - var session = this.sessions[path]; - - if (path && this.isOpen(path)) { - return session.getTextRange( - codiad.editor.getActive() - .getSelectionRange()); - } else { - codiad.message.error(i18n('No Open Files or Selected Text')); - } - }, - - ////////////////////////////////////////////////////////////////// - // Insert Text - ////////////////////////////////////////////////////////////////// - - insertText: function(val) { - codiad.editor.getActive() - .insert(val); - }, - - ////////////////////////////////////////////////////////////////// - // Goto Line - ////////////////////////////////////////////////////////////////// - - gotoLine: function(line) { - codiad.editor.getActive() - .gotoLine(line, 0, true); - }, - - ////////////////////////////////////////////////////////////////// - // Move Up (Key Combo) - ////////////////////////////////////////////////////////////////// - - move: function(dir) { - - var num = $('#tab-list-active-files li').length; - if (num === 0) return; - - var newActive = null; - var active = null; - - if (dir == 'up') { - - // If active is in the tab list - active = $('#tab-list-active-files li.active'); - if(active.length > 0) { - // Previous or rotate to the end - newActive = active.prev('li'); - if (newActive.length === 0) { - newActive = $('#dropdown-list-active-files li:last-child') - if (newActive.length === 0) { - newActive = $('#tab-list-active-files li:last-child') - } - } - } - - // If active is in the dropdown list - active = $('#dropdown-list-active-files li.active'); - if(active.length > 0) { - // Previous - newActive = active.prev('li'); - if (newActive.length === 0) { - newActive = $('#tab-list-active-files li:last-child') - } - } - - } else { - - // If active is in the tab list - active = $('#tab-list-active-files li.active'); - if(active.length > 0) { - // Next or rotate to the beginning - newActive = active.next('li'); - if (newActive.length === 0) { - newActive = $('#dropdown-list-active-files li:first-child'); - if (newActive.length === 0) { - newActive = $('#tab-list-active-files li:first-child') - } - } - } - - // If active is in the dropdown list - active = $('#dropdown-list-active-files li.active'); - if(active.length > 0) { - // Next or rotate to the beginning - newActive = active.next('li'); - if (newActive.length === 0) { - newActive = $('#tab-list-active-files li:first-child') - } - } - - } - - if(newActive) this.focus(newActive.attr('data-path'), false); - }, - - ////////////////////////////////////////////////////////////////// - // Dropdown Menu - ////////////////////////////////////////////////////////////////// - - initTabDropdownMenu: function() { - var _this = this; - - var menu = $('#dropdown-list-active-files'); - var button = $('#tab-dropdown-button'); - var closebutton = $('#tab-close-button'); - - menu.appendTo($('body')); - - button.click(function(e) { - e.stopPropagation(); - _this.toggleTabDropdownMenu(); - }); - - closebutton.click(function(e) { - e.stopPropagation(); - _this.removeAll(); - }); - }, - - showTabDropdownMenu: function() { - var menu = $('#dropdown-list-active-files'); - if(!menu.is(':visible')) this.toggleTabDropdownMenu(); - }, - - hideTabDropdownMenu: function() { - var menu = $('#dropdown-list-active-files'); - if(menu.is(':visible')) this.toggleTabDropdownMenu(); - }, - - toggleTabDropdownMenu: function() { - var _this = this; - var menu = $('#dropdown-list-active-files'); - - menu.css({ - top: $("#editor-top-bar").height() + 'px', - right: '20px', - width: '200px' - }); - - menu.slideToggle('fast'); - - if(menu.is(':visible')) { - // handle click-out autoclosing - var fn = function() { - menu.hide(); - $(window).off('click', fn) - } - $(window).on('click', fn); - } - }, - - moveTabToDropdownMenu: function(tab, prepend) { - if (prepend === undefined) { - prepend = false; - } - - tab.remove(); - path = tab.attr('data-path'); - - var tabThumb = this.createMenuItemThumb(path); - if(prepend) $('#dropdown-list-active-files').prepend(tabThumb); - else $('#dropdown-list-active-files').append(tabThumb); - - if(tab.hasClass("changed")) { - tabThumb.addClass("changed"); - } - - if(tab.hasClass("active")) { - tabThumb.addClass("active"); - } - - this.sessions[path].tabThumb = tabThumb; - }, - - moveDropdownMenuItemToTab: function(menuItem, prepend) { - if (prepend === undefined) { - prepend = false; - } - - menuItem.remove(); - path = menuItem.attr('data-path'); - - var tabThumb = this.createTabThumb(path); - if(prepend) $('#tab-list-active-files').prepend(tabThumb); - else $('#tab-list-active-files').append(tabThumb); - - if(menuItem.hasClass("changed")) { - tabThumb.addClass("changed"); - } - - if(menuItem.hasClass("active")) { - tabThumb.addClass("active"); - } - - this.sessions[path].tabThumb = tabThumb; - }, - - isTabListOverflowed: function(includeFictiveTab) { - if (includeFictiveTab === undefined) { - includeFictiveTab = false; - } - - var tabs = $('#tab-list-active-files li'); - var count = tabs.length - if (includeFictiveTab) count += 1; - if (count <= 1) return false; - - var width = 0; - tabs.each(function(index) { - width += $(this).outerWidth(true); - }) - if (includeFictiveTab) { - width += $(tabs[tabs.length-1]).outerWidth(true); - } - - /* If we subtract the width of the left side bar, of the right side - * bar handle and of the tab dropdown handle to the window width, - * do we have enough room for the tab list? Its kind of complicated - * to handle all the offsets, so afterwards we add a fixed offset - * just t be sure. */ - var lsbarWidth = $(".sidebar-handle").width(); - if (codiad.sidebars.isLeftSidebarOpen) { - lsbarWidth = $("#sb-left").width(); - } - - var rsbarWidth = $(".sidebar-handle").width(); - if (codiad.sidebars.isRightSidebarOpen) { - rsbarWidth = $("#sb-right").width(); - } - - var tabListWidth = $("#tab-list-active-files").width(); - var dropdownWidth = $('#tab-dropdown').width(); - var closeWidth = $('#tab-close').width(); - var room = window.innerWidth - lsbarWidth - rsbarWidth - dropdownWidth - closeWidth - width - 30; - return (room < 0); - }, - - updateTabDropdownVisibility: function() { - while(this.isTabListOverflowed()) { - var tab = $('#tab-list-active-files li:last-child'); - if (tab.length == 1) this.moveTabToDropdownMenu(tab, true); - else break; - } - - while(!this.isTabListOverflowed(true)) { - var menuItem = $('#dropdown-list-active-files li:first-child'); - if (menuItem.length == 1) this.moveDropdownMenuItemToTab(menuItem); - else break; - } - - if ($('#dropdown-list-active-files li').length > 0) { - $('#tab-dropdown').show(); - } else { - $('#tab-dropdown').hide(); - // Be sure to hide the menu if it is opened. - $('#dropdown-list-active-files').hide(); - } - if ($('#tab-list-active-files li').length > 1) { - $('#tab-close').show(); - } else { - $('#tab-close').hide(); - } - }, - - ////////////////////////////////////////////////////////////////// - // Factory - ////////////////////////////////////////////////////////////////// - - splitDirectoryAndFileName: function(path) { - var index = path.lastIndexOf('/'); - return { - fileName: path.substring(index + 1), - directory: (path.indexOf('/') == 0)? path.substring(1, index + 1):path.substring(0, index + 1) - } - }, - - createListThumb: function(path) { - return $('
  • ' + path + '
  • '); - }, - - createTabThumb: function(path) { - split = this.splitDirectoryAndFileName(path); - return $('
  • ' - + split.directory + '' + split.fileName + '' - + 'x
  • '); - }, - - createMenuItemThumb: function(path) { - split = this.splitDirectoryAndFileName(path); - return $('
  • ' - + split.directory + '' + split.fileName + '' - + '
  • '); - }, - - }; - -})(this, jQuery); -"; \ No newline at end of file diff --git a/data/collaborative/text/30e59348afad09731d1c4f8d66702f40 b/data/collaborative/text/30e59348afad09731d1c4f8d66702f40 deleted file mode 100755 index 64fb9fd..0000000 --- a/data/collaborative/text/30e59348afad09731d1c4f8d66702f40 +++ /dev/null @@ -1,59 +0,0 @@ -s:1168:"/* - * Place copyright or other info here... - */ - -(function(global, $){ - - // Define core - var codiad = global.codiad, - scripts= document.getElementsByTagName('script'), - path = scripts[scripts.length-1].src.split('?')[0], - curpath = path.split('/').slice(0, -1).join('/')+'/'; - - // Instantiates plugin - $(function() { - codiad.tela_auto_save.init(); - }); - - codiad.tela_auto_save = { - - // Allows relative `this.path` linkage - path: curpath, - - init: function() { - - // Start your plugin here... - let editor = document.getElementsByClassName( 'ace_content' )[0]; - let auto_save_trigger = setInterval( this.auto_save, 500 ); - }, - - /** - * - * This is where the core functionality goes, any call, references, - * script-loads, etc... - * - */ - - auto_save: function() { - - let tabs = document.getElementsByClassName( "tab-item" ); - tabs = Array.from( tabs ); - tabs.forEach( function( m, i, a ) { - - // M = Current entry - // I = Index as integer - // A = Entire array - - if ( m.classList.contains( "active" ) ) { - - m.classList.remove( "changed" ) - } - }); - - codiad.active.save; - } - - }; - -})(this, jQuery); -"; \ No newline at end of file diff --git a/data/collaborative/text/329491055243ffcf41c2843c688c031d b/data/collaborative/text/329491055243ffcf41c2843c688c031d deleted file mode 100755 index e054c52..0000000 --- a/data/collaborative/text/329491055243ffcf41c2843c688c031d +++ /dev/null @@ -1,773 +0,0 @@ -s:34893:"/* - * Copyright (c) Codiad & Kent Safranski (codiad.com), distributed - * as-is and without warranty under the MIT License. See - * [root]/license.txt for more. This information must remain intact. - */ - -(function(global, $){ - - var codiad = global.codiad; - - $(window) - .load(function() { - codiad.filemanager.init(); - }); - - codiad.filemanager = { - - clipboard: '', - - noOpen: ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'exe', 'zip', 'tar', 'tar.gz'], - noBrowser: ['jpg', 'jpeg', 'png', 'gif', 'bmp'], - - controller: 'components/filemanager/controller.php', - dialog: 'components/filemanager/dialog.php', - dialogUpload: 'components/filemanager/dialog_upload.php', - - init: function() { - // Initialize node listener - this.nodeListener(); - // Load uploader - $.loadScript("components/filemanager/upload_scripts/jquery.ui.widget.js", true); - $.loadScript("components/filemanager/upload_scripts/jquery.iframe-transport.js", true); - $.loadScript("components/filemanager/upload_scripts/jquery.fileupload.js", true); - }, - - ////////////////////////////////////////////////////////////////// - // Listen for dbclick events on nodes - ////////////////////////////////////////////////////////////////// - - nodeListener: function() { - var _this = this; - - $('#file-manager').on('selectstart', false); - - $('#file-manager span') - .live('click', function() { // Open or Expand - if ($(this).parent().children("a").attr('data-type') == 'directory') { - _this.index($(this).parent().children("a") - .attr('data-path')); - } else { - _this.openFile($(this).parent().children("a") - .attr('data-path')); - } - if (!$(this).hasClass('none')) { - if ($(this).hasClass('plus')) { - $(this).removeClass('plus') - $(this).addClass('minus'); - } else { - $(this).removeClass('minus') - $(this).addClass('plus'); - } - } - }); - $('#file-manager a') - .live('dblclick', function() { // Open or Expand - if (!codiad.editor.settings.fileManagerTrigger) { - if ($(this) - .hasClass('directory')) { - _this.index($(this) - .attr('data-path')); - } else { - _this.openFile($(this) - .attr('data-path')); - } - if (!$(this).parent().children("span").hasClass('none')) { - if ($(this).parent().children("span").hasClass('plus')) { - $(this).parent().children("span").removeClass('plus') - $(this).parent().children("span").addClass('minus'); - } else { - $(this).parent().children("span").removeClass('minus') - $(this).parent().children("span").addClass('plus'); - } - } - } - }) - .live('click', function() { // Open or Expand - if (codiad.editor.settings.fileManagerTrigger) { - if ($(this) - .hasClass('directory')) { - _this.index($(this) - .attr('data-path')); - } else { - _this.openFile($(this) - .attr('data-path')); - } - if (!$(this).parent().children("span").hasClass('none')) { - if ($(this).parent().children("span").hasClass('plus')) { - $(this).parent().children("span").removeClass('plus') - $(this).parent().children("span").addClass('minus'); - } else { - $(this).parent().children("span").removeClass('minus') - $(this).parent().children("span").addClass('plus'); - } - } - } - }) - .live("contextmenu", function(e) { // Context Menu - e.preventDefault(); - _this.contextMenuShow(e, $(this) - .attr('data-path'), $(this) - .attr('data-type'), $(this) - .html()); - $(this) - .addClass('context-menu-active'); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Context Menu - ////////////////////////////////////////////////////////////////// - - contextMenuShow: function(e, path, type, name) { - var _this = this; - - // Selective options - switch (type) { - case 'directory': - $('#context-menu .directory-only, #context-menu .non-root') - .show(); - $('#context-menu .file-only, #context-menu .root-only') - .hide(); - break; - case 'file': - $('#context-menu .directory-only, #context-menu .root-only') - .hide(); - $('#context-menu .file-only,#context-menu .non-root') - .show(); - break; - case 'root': - $('#context-menu .directory-only, #context-menu .root-only') - .show(); - $('#context-menu .non-root, #context-menu .file-only') - .hide(); - break; - } - if(codiad.project.isAbsPath($('#file-manager a[data-type="root"]').attr('data-path'))) { - $('#context-menu .no-external').hide(); - } else { - $('#context-menu .no-external').show(); - } - // Show menu - var top = e.pageY; - if (top > $(window).height() - $('#context-menu').height()) { - top -= $('#context-menu').height(); - } - if (top < 10) { - top = 10; - } - var max = $(window).height() - top - 10; - - $('#context-menu') - .css({ - 'top': top + 'px', - 'left': e.pageX + 'px', - 'max-height': max + 'px' - }) - .fadeIn(200) - .attr('data-path', path) - .attr('data-type', type) - .attr('data-name', name); - // Show faded 'paste' if nothing in clipboard - if (this.clipboard === '') { - $('#context-menu a[content="Paste"]') - .addClass('disabled'); - } else { - $('#context-menu a[data-action="paste"]') - .removeClass('disabled'); - } - // Hide menu - $('#file-manager, #editor-region') - .on('mouseover', function() { - _this.contextMenuHide(); - }); - /* Notify listeners. */ - amplify.publish('context-menu.onShow', {e: e, path: path, type: type}); - // Hide on click - $('#context-menu a') - .click(function() { - _this.contextMenuHide(); - }); - }, - - contextMenuHide: function() { - $('#context-menu') - .fadeOut(200); - $('#file-manager a') - .removeClass('context-menu-active'); - /* Notify listeners. */ - amplify.publish('context-menu.onHide'); - }, - - ////////////////////////////////////////////////////////////////// - // Return the node name (sans path) - ////////////////////////////////////////////////////////////////// - - getShortName: function(path) { - return path.split('/') - .pop(); - }, - - ////////////////////////////////////////////////////////////////// - // Return extension - ////////////////////////////////////////////////////////////////// - - getExtension: function(path) { - return path.split('.') - .pop(); - }, - - ////////////////////////////////////////////////////////////////// - // Return type - ////////////////////////////////////////////////////////////////// - - getType: function(path) { - return $('#file-manager a[data-path="' + path + '"]') - .attr('data-type'); - }, - - ////////////////////////////////////////////////////////////////// - // Create node in file tree - ////////////////////////////////////////////////////////////////// - - createObject: function(parent, path, type) { - // NODE FORMAT:
  • {short_name}
  • - var parentNode = $('#file-manager a[data-path="' + parent + '"]'); - if (!$('#file-manager a[data-path="' + path + '"]') - .length) { // Doesn't already exist - if (parentNode.hasClass('open') && parentNode.hasClass('directory')) { // Only append node if parent is open (and a directory) - var shortName = this.getShortName(path); - if (type == 'directory') { - var appendage = '
  • ' + shortName + '
  • '; - } else { - var appendage = '
  • ' + shortName + '
  • '; - } - if (parentNode.siblings('ul') - .length) { // UL exists, other children to play with - parentNode.siblings('ul') - .append(appendage); - } else { - $('
      ' + appendage + '
    ') - .insertAfter(parentNode); - } - } else { - parentNode.parent().children('span').removeClass('none'); - parentNode.parent().children('span').addClass('plus'); - } - } - }, - - ////////////////////////////////////////////////////////////////// - // Loop out all files and folders in directory path - ////////////////////////////////////////////////////////////////// - - indexFiles: [], - - index: function(path, rescan) { - var _this = this; - if (rescan === undefined) { - rescan = false; - } - node = $('#file-manager a[data-path="' + path + '"]'); - if (node.hasClass('open') && !rescan) { - node.parent('li') - .children('ul') - .slideUp(300, function() { - $(this) - .remove(); - node.removeClass('open'); - }); - } else { - node.addClass('loading'); - $.get(this.controller + '?action=index&path=' + encodeURIComponent(path), function(data) { - node.addClass('open'); - var objectsResponse = codiad.jsend.parse(data); - if (objectsResponse != 'error') { - /* Notify listener */ - _this.indexFiles = objectsResponse.index; - amplify.publish("filemanager.onIndex", {path: path, files: _this.indexFiles}); - var files = _this.indexFiles; - if (files.length > 0) { - if (node.parent().children('span').hasClass('plus')) { - node.parent().children('span').removeClass('plus').addClass('minus'); - } - var display = 'display:none;'; - if (rescan) { - display = ''; - } - var appendage = '
      '; - $.each(files, function(index) { - var ext = ''; - var name = files[index].name.replace(path, ''); - var nodeClass = 'none'; - name = name.split('/') - .join(' '); - if (files[index].type == 'file') { - var ext = ' ext-' + name.split('.') - .pop(); - } - if(files[index].type == 'directory' && files[index].size > 0) { - nodeClass = 'plus'; - } - appendage += '
    • ' + name + '
    • '; - }); - appendage += '
    '; - if (rescan) { - node.parent('li') - .children('ul') - .remove(); - } - $(appendage) - .insertAfter(node); - if (!rescan) { - node.siblings('ul') - .slideDown(300); - } - } - } - node.removeClass('loading'); - if (rescan && _this.rescanChildren.length > _this.rescanCounter) { - _this.rescan(_this.rescanChildren[_this.rescanCounter++]); - } else { - _this.rescanChildren = []; - _this.rescanCounter = 0; - } - }); - } - }, - - rescanChildren: [], - - rescanCounter: 0, - - rescan: function(path) { - var _this = this; - if (this.rescanCounter === 0) { - // Create array of open directories - node = $('#file-manager a[data-path="' + path + '"]'); - node.parent() - .find('a.open') - .each(function() { - _this.rescanChildren.push($(this) - .attr('data-path')); - }); - } - - this.index(path, true); - }, - - ////////////////////////////////////////////////////////////////// - // Open File - ////////////////////////////////////////////////////////////////// - - openFile: function(path, focus) { - if (focus === undefined) { - focus = true; - } - var node = $('#file-manager a[data-path="' + path + '"]'); - var ext = this.getExtension(path); - if ($.inArray(ext.toLowerCase(), this.noOpen) < 0) { - node.addClass('loading'); - $.get(this.controller + '?action=open&path=' + encodeURIComponent(path), function(data) { - var openResponse = codiad.jsend.parse(data); - if (openResponse != 'error') { - node.removeClass('loading'); - codiad.active.open(path, openResponse.content, openResponse.mtime, false, focus); - } - }); - } else { - if(!codiad.project.isAbsPath(path)) { - if ($.inArray(ext.toLowerCase(), this.noBrowser) < 0) { - this.download(path); - } else { - this.openInModal(path); - } - } else { - codiad.message.error(i18n('Unable to open file in Browser')); - } - } - }, - - ////////////////////////////////////////////////////////////////// - // Open in browser - ////////////////////////////////////////////////////////////////// - - openInBrowser: function(path) { - $.ajax({ - url: this.controller + '?action=open_in_browser&path=' + encodeURIComponent(path), - success: function(data) { - var openIBResponse = codiad.jsend.parse(data); - if (openIBResponse != 'error') { - window.open(openIBResponse.url, '_newtab'); - } - }, - async: false - }); - }, - openInModal: function(path) { - codiad.modal.load(250, this.dialog, { - action: 'preview', - path: path - }); - }, - saveModifications: function(path, data, callbacks, save=true){ - callbacks = callbacks || {}; - var _this = this, action, data; - var notifySaveErr = function() { - codiad.message.error(i18n('File could not be saved')); - if (typeof callbacks.error === 'function') { - var context = callbacks.context || _this; - callbacks.error.apply(context, [data]); - } - } - $.post(this.controller + '?action=modify&path=' + encodeURIComponent(path), data, function(resp){ - resp = $.parseJSON(resp); - if (resp.status == 'success') { - if ( save === true ) { - codiad.message.success(i18n('File saved')); - } - if (typeof callbacks.success === 'function'){ - var context = callbacks.context || _this; - callbacks.success.call(context, resp.data.mtime); - } - } else { - if (resp.message == 'Client is out of sync'){ - var reload = confirm( - "Server has a more updated copy of the file. Would "+ - "you like to refresh the contents ? Pressing no will "+ - "cause your changes to override the server's copy upon "+ - "next save." - ); - if (reload) { - codiad.active.close(path); - codiad.active.removeDraft(path); - _this.openFile(path); - } else { - var session = codiad.editor.getActive().getSession(); - session.serverMTime = null; - session.untainted = null; - } - } else codiad.message.error(i18n('File could not be saved')); - if (typeof callbacks.error === 'function') { - var context = callbacks.context || _this; - callbacks.error.apply(context, [resp.data]); - } - } - }).error(notifySaveErr); - }, - ////////////////////////////////////////////////////////////////// - // Save file - ////////////////////////////////////////////////////////////////// - - saveFile: function(path, content, callbacks, save=true) { - this.saveModifications(path, {content: content}, callbacks, save); - }, - - savePatch: function(path, patch, mtime, callbacks) { - if (patch.length > 0) - this.saveModifications(path, {patch: patch, mtime: mtime}, callbacks); - else if (typeof callbacks.success === 'function'){ - var context = callbacks.context || this; - callbacks.success.call(context, mtime); - } - }, - - ////////////////////////////////////////////////////////////////// - // Create Object - ////////////////////////////////////////////////////////////////// - - createNode: function(path, type) { - codiad.modal.load(250, this.dialog, { - action: 'create', - type: type, - path: path - }); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - var shortName = $('#modal-content form input[name="object_name"]') - .val(); - var path = $('#modal-content form input[name="path"]') - .val(); - var type = $('#modal-content form input[name="type"]') - .val(); - var createPath = path + '/' + shortName; - $.get(codiad.filemanager.controller + '?action=create&path=' + encodeURIComponent(createPath) + '&type=' + type, function(data) { - var createResponse = codiad.jsend.parse(data); - if (createResponse != 'error') { - codiad.message.success(type.charAt(0) - .toUpperCase() + type.slice(1) + ' Created'); - codiad.modal.unload(); - // Add new element to filemanager screen - codiad.filemanager.createObject(path, createPath, type); - if(type == 'file') { - codiad.filemanager.openFile(createPath, true); - } - /* Notify listeners. */ - amplify.publish('filemanager.onCreate', {createPath: createPath, path: path, shortName: shortName, type: type}); - } - }); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Copy to Clipboard - ////////////////////////////////////////////////////////////////// - - copyNode: function(path) { - this.clipboard = path; - codiad.message.success(i18n('Copied to Clipboard')); - }, - - ////////////////////////////////////////////////////////////////// - // Paste - ////////////////////////////////////////////////////////////////// - - pasteNode: function(path) { - var _this = this; - if (this.clipboard == '') { - codiad.message.error(i18n('Nothing in Your Clipboard')); - } else if (path == this.clipboard) { - codiad.message.error(i18n('Cannot Paste Directory Into Itself')); - } else { - var shortName = _this.getShortName(_this.clipboard); - if ($('#file-manager a[data-path="' + path + '/' + shortName + '"]') - .length) { // Confirm overwrite? - codiad.modal.load(400, this.dialog, { - action: 'overwrite', - path: path + '/' + shortName - }); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - var duplicate = false; - if($('#modal-content form select[name="or_action"]').val()==1){ - duplicate=true; console.log('Dup!'); - } - _this.processPasteNode(path,duplicate); - }); - } else { // No conflicts; proceed... - _this.processPasteNode(path,false); - } - } - }, - - processPasteNode: function(path,duplicate) { - var _this = this; - var shortName = this.getShortName(this.clipboard); - var type = this.getType(this.clipboard); - if(duplicate){ - shortName = "copy_of_"+shortName; - } - $.get(this.controller + '?action=duplicate&path=' + - encodeURIComponent(this.clipboard) + '&destination=' + - encodeURIComponent(path + '/' + shortName), function(data) { - var pasteResponse = codiad.jsend.parse(data); - if (pasteResponse != 'error') { - _this.createObject(path, path + '/' + shortName, type); - codiad.modal.unload(); - /* Notify listeners. */ - amplify.publish('filemanager.onPaste', {path: path, shortName: shortName, duplicate: duplicate}); - } - }); - }, - - ////////////////////////////////////////////////////////////////// - // Rename - ////////////////////////////////////////////////////////////////// - - renameNode: function(path) { - var shortName = this.getShortName(path); - var type = this.getType(path); - var _this = this; - codiad.modal.load(250, this.dialog, { action: 'rename', path: path, short_name: shortName, type: type}); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - var newName = $('#modal-content form input[name="object_name"]') - .val(); - // Build new path - var arr = path.split('/'); - var temp = new Array(); - for (i = 0; i < arr.length - 1; i++) { - temp.push(arr[i]) - } - var newPath = temp.join('/') + '/' + newName; - $.get(_this.controller, { action: 'modify', path: path, new_name: newName} , function(data) { - var renameResponse = codiad.jsend.parse(data); - if (renameResponse != 'error') { - codiad.message.success(type.charAt(0) - .toUpperCase() + type.slice(1) + ' Renamed'); - var node = $('#file-manager a[data-path="' + path + '"]'); - // Change pathing and name for node - node.attr('data-path', newPath) - .html(newName); - if (type == 'file') { // Change icons for file - curExtClass = 'ext-' + _this.getExtension(path); - newExtClass = 'ext-' + _this.getExtension(newPath); - $('#file-manager a[data-path="' + newPath + '"]') - .removeClass(curExtClass) - .addClass(newExtClass); - } else { // Change pathing on any sub-files/directories - _this.repathSubs(path, newPath); - } - // Change any active files - codiad.active.rename(path, newPath); - codiad.modal.unload(); - } - }); - }); - }, - - repathSubs: function(oldPath, newPath) { - $('#file-manager a[data-path="' + newPath + '"]') - .siblings('ul') - .find('a') - .each(function() { - // Hit the children, hit 'em hard - var curPath = $(this) - .attr('data-path'); - var revisedPath = curPath.replace(oldPath, newPath); - $(this) - .attr('data-path', revisedPath); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Delete - ////////////////////////////////////////////////////////////////// - - deleteNode: function(path) { - var _this = this; - codiad.modal.load(400, this.dialog, { - action: 'delete', - path: path - }); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - $.get(_this.controller + '?action=delete&path=' + encodeURIComponent(path), function(data) { - var deleteResponse = codiad.jsend.parse(data); - if (deleteResponse != 'error') { - var node = $('#file-manager a[data-path="' + path + '"]'); - node.parent('li') - .remove(); - // Close any active files - $('#active-files a') - .each(function() { - var curPath = $(this) - .attr('data-path'); - if (curPath.indexOf(path) == 0) { - codiad.active.remove(curPath); - } - }); - } - codiad.modal.unload(); - }); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Search - ////////////////////////////////////////////////////////////////// - - search: function(path) { - codiad.modal.load(500, this.dialog,{ - action: 'search', - path: path - }); - codiad.modal.load_process.done( function() { - var lastSearched = JSON.parse(localStorage.getItem("lastSearched")); - if(lastSearched) { - $('#modal-content form input[name="search_string"]').val(lastSearched.searchText); - $('#modal-content form input[name="search_file_type"]').val(lastSearched.fileExtension); - $('#modal-content form select[name="search_type"]').val(lastSearched.searchType); - if(lastSearched.searchResults != '') { - $('#filemanager-search-results').slideDown().html(lastSearched.searchResults); - } - } - }); - codiad.modal.hideOverlay(); - var _this = this; - $('#modal-content form') - .live('submit', function(e) { - $('#filemanager-search-processing') - .show(); - e.preventDefault(); - searchString = $('#modal-content form input[name="search_string"]') - .val(); - fileExtensions=$('#modal-content form input[name="search_file_type"]') - .val(); - searchFileType=$.trim(fileExtensions); - if (searchFileType != '') { - //season the string to use in find command - searchFileType = "\\(" + searchFileType.replace(/\s+/g, "\\|") + "\\)"; - } - searchType = $('#modal-content form select[name="search_type"]') - .val(); - $.post(_this.controller + '?action=search&path=' + encodeURIComponent(path) + '&type=' + searchType, { - search_string: searchString, - search_file_type: searchFileType - }, function(data) { - searchResponse = codiad.jsend.parse(data); - var results = ''; - if (searchResponse != 'error') { - $.each(searchResponse.index, function(key, val) { - // Cleanup file format - if(val['file'].substr(-1) == '/') { - val['file'] = val['file'].substr(0, str.length - 1); - } - val['file'] = val['file'].replace('//','/'); - // Add result - results += ''; - }); - $('#filemanager-search-results') - .slideDown() - .html(results); - } else { - $('#filemanager-search-results') - .slideUp(); - } - _this.saveSearchResults(searchString, searchType, fileExtensions, results); - $('#filemanager-search-processing') - .hide(); - }); - }); - }, - - ///////////////////////////////////////////////////////////////// - // saveSearchResults - ///////////////////////////////////////////////////////////////// - saveSearchResults: function(searchText, searchType, fileExtensions, searchResults) { - var lastSearched = { - searchText: searchText, - searchType: searchType, - fileExtension: fileExtensions, - searchResults: searchResults - }; - localStorage.setItem("lastSearched", JSON.stringify(lastSearched)); - }, - ////////////////////////////////////////////////////////////////// - // Upload - ////////////////////////////////////////////////////////////////// - - uploadToNode: function(path) { - codiad.modal.load(500, this.dialogUpload, {path: path}); - }, - - ////////////////////////////////////////////////////////////////// - // Download - ////////////////////////////////////////////////////////////////// - - download: function(path) { - var type = this.getType(path); - $('#download') - .attr('src', 'components/filemanager/download.php?path=' + encodeURIComponent(path) + '&type=' + type); - } - }; - -})(this, jQuery); -"; \ No newline at end of file diff --git a/data/collaborative/text/32e633ae3f9718c741560af1352f1a1a b/data/collaborative/text/32e633ae3f9718c741560af1352f1a1a deleted file mode 100755 index 8285b39..0000000 --- a/data/collaborative/text/32e633ae3f9718c741560af1352f1a1a +++ /dev/null @@ -1,53 +0,0 @@ -s:2353:" - - -
    - ☰ Menu -
    - - - - - "; \ No newline at end of file diff --git a/data/collaborative/text/37409041d6aae3c32d019a5f9481fe1a b/data/collaborative/text/37409041d6aae3c32d019a5f9481fe1a deleted file mode 100755 index e054c52..0000000 --- a/data/collaborative/text/37409041d6aae3c32d019a5f9481fe1a +++ /dev/null @@ -1,773 +0,0 @@ -s:34893:"/* - * Copyright (c) Codiad & Kent Safranski (codiad.com), distributed - * as-is and without warranty under the MIT License. See - * [root]/license.txt for more. This information must remain intact. - */ - -(function(global, $){ - - var codiad = global.codiad; - - $(window) - .load(function() { - codiad.filemanager.init(); - }); - - codiad.filemanager = { - - clipboard: '', - - noOpen: ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'exe', 'zip', 'tar', 'tar.gz'], - noBrowser: ['jpg', 'jpeg', 'png', 'gif', 'bmp'], - - controller: 'components/filemanager/controller.php', - dialog: 'components/filemanager/dialog.php', - dialogUpload: 'components/filemanager/dialog_upload.php', - - init: function() { - // Initialize node listener - this.nodeListener(); - // Load uploader - $.loadScript("components/filemanager/upload_scripts/jquery.ui.widget.js", true); - $.loadScript("components/filemanager/upload_scripts/jquery.iframe-transport.js", true); - $.loadScript("components/filemanager/upload_scripts/jquery.fileupload.js", true); - }, - - ////////////////////////////////////////////////////////////////// - // Listen for dbclick events on nodes - ////////////////////////////////////////////////////////////////// - - nodeListener: function() { - var _this = this; - - $('#file-manager').on('selectstart', false); - - $('#file-manager span') - .live('click', function() { // Open or Expand - if ($(this).parent().children("a").attr('data-type') == 'directory') { - _this.index($(this).parent().children("a") - .attr('data-path')); - } else { - _this.openFile($(this).parent().children("a") - .attr('data-path')); - } - if (!$(this).hasClass('none')) { - if ($(this).hasClass('plus')) { - $(this).removeClass('plus') - $(this).addClass('minus'); - } else { - $(this).removeClass('minus') - $(this).addClass('plus'); - } - } - }); - $('#file-manager a') - .live('dblclick', function() { // Open or Expand - if (!codiad.editor.settings.fileManagerTrigger) { - if ($(this) - .hasClass('directory')) { - _this.index($(this) - .attr('data-path')); - } else { - _this.openFile($(this) - .attr('data-path')); - } - if (!$(this).parent().children("span").hasClass('none')) { - if ($(this).parent().children("span").hasClass('plus')) { - $(this).parent().children("span").removeClass('plus') - $(this).parent().children("span").addClass('minus'); - } else { - $(this).parent().children("span").removeClass('minus') - $(this).parent().children("span").addClass('plus'); - } - } - } - }) - .live('click', function() { // Open or Expand - if (codiad.editor.settings.fileManagerTrigger) { - if ($(this) - .hasClass('directory')) { - _this.index($(this) - .attr('data-path')); - } else { - _this.openFile($(this) - .attr('data-path')); - } - if (!$(this).parent().children("span").hasClass('none')) { - if ($(this).parent().children("span").hasClass('plus')) { - $(this).parent().children("span").removeClass('plus') - $(this).parent().children("span").addClass('minus'); - } else { - $(this).parent().children("span").removeClass('minus') - $(this).parent().children("span").addClass('plus'); - } - } - } - }) - .live("contextmenu", function(e) { // Context Menu - e.preventDefault(); - _this.contextMenuShow(e, $(this) - .attr('data-path'), $(this) - .attr('data-type'), $(this) - .html()); - $(this) - .addClass('context-menu-active'); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Context Menu - ////////////////////////////////////////////////////////////////// - - contextMenuShow: function(e, path, type, name) { - var _this = this; - - // Selective options - switch (type) { - case 'directory': - $('#context-menu .directory-only, #context-menu .non-root') - .show(); - $('#context-menu .file-only, #context-menu .root-only') - .hide(); - break; - case 'file': - $('#context-menu .directory-only, #context-menu .root-only') - .hide(); - $('#context-menu .file-only,#context-menu .non-root') - .show(); - break; - case 'root': - $('#context-menu .directory-only, #context-menu .root-only') - .show(); - $('#context-menu .non-root, #context-menu .file-only') - .hide(); - break; - } - if(codiad.project.isAbsPath($('#file-manager a[data-type="root"]').attr('data-path'))) { - $('#context-menu .no-external').hide(); - } else { - $('#context-menu .no-external').show(); - } - // Show menu - var top = e.pageY; - if (top > $(window).height() - $('#context-menu').height()) { - top -= $('#context-menu').height(); - } - if (top < 10) { - top = 10; - } - var max = $(window).height() - top - 10; - - $('#context-menu') - .css({ - 'top': top + 'px', - 'left': e.pageX + 'px', - 'max-height': max + 'px' - }) - .fadeIn(200) - .attr('data-path', path) - .attr('data-type', type) - .attr('data-name', name); - // Show faded 'paste' if nothing in clipboard - if (this.clipboard === '') { - $('#context-menu a[content="Paste"]') - .addClass('disabled'); - } else { - $('#context-menu a[data-action="paste"]') - .removeClass('disabled'); - } - // Hide menu - $('#file-manager, #editor-region') - .on('mouseover', function() { - _this.contextMenuHide(); - }); - /* Notify listeners. */ - amplify.publish('context-menu.onShow', {e: e, path: path, type: type}); - // Hide on click - $('#context-menu a') - .click(function() { - _this.contextMenuHide(); - }); - }, - - contextMenuHide: function() { - $('#context-menu') - .fadeOut(200); - $('#file-manager a') - .removeClass('context-menu-active'); - /* Notify listeners. */ - amplify.publish('context-menu.onHide'); - }, - - ////////////////////////////////////////////////////////////////// - // Return the node name (sans path) - ////////////////////////////////////////////////////////////////// - - getShortName: function(path) { - return path.split('/') - .pop(); - }, - - ////////////////////////////////////////////////////////////////// - // Return extension - ////////////////////////////////////////////////////////////////// - - getExtension: function(path) { - return path.split('.') - .pop(); - }, - - ////////////////////////////////////////////////////////////////// - // Return type - ////////////////////////////////////////////////////////////////// - - getType: function(path) { - return $('#file-manager a[data-path="' + path + '"]') - .attr('data-type'); - }, - - ////////////////////////////////////////////////////////////////// - // Create node in file tree - ////////////////////////////////////////////////////////////////// - - createObject: function(parent, path, type) { - // NODE FORMAT:
  • {short_name}
  • - var parentNode = $('#file-manager a[data-path="' + parent + '"]'); - if (!$('#file-manager a[data-path="' + path + '"]') - .length) { // Doesn't already exist - if (parentNode.hasClass('open') && parentNode.hasClass('directory')) { // Only append node if parent is open (and a directory) - var shortName = this.getShortName(path); - if (type == 'directory') { - var appendage = '
  • ' + shortName + '
  • '; - } else { - var appendage = '
  • ' + shortName + '
  • '; - } - if (parentNode.siblings('ul') - .length) { // UL exists, other children to play with - parentNode.siblings('ul') - .append(appendage); - } else { - $('
      ' + appendage + '
    ') - .insertAfter(parentNode); - } - } else { - parentNode.parent().children('span').removeClass('none'); - parentNode.parent().children('span').addClass('plus'); - } - } - }, - - ////////////////////////////////////////////////////////////////// - // Loop out all files and folders in directory path - ////////////////////////////////////////////////////////////////// - - indexFiles: [], - - index: function(path, rescan) { - var _this = this; - if (rescan === undefined) { - rescan = false; - } - node = $('#file-manager a[data-path="' + path + '"]'); - if (node.hasClass('open') && !rescan) { - node.parent('li') - .children('ul') - .slideUp(300, function() { - $(this) - .remove(); - node.removeClass('open'); - }); - } else { - node.addClass('loading'); - $.get(this.controller + '?action=index&path=' + encodeURIComponent(path), function(data) { - node.addClass('open'); - var objectsResponse = codiad.jsend.parse(data); - if (objectsResponse != 'error') { - /* Notify listener */ - _this.indexFiles = objectsResponse.index; - amplify.publish("filemanager.onIndex", {path: path, files: _this.indexFiles}); - var files = _this.indexFiles; - if (files.length > 0) { - if (node.parent().children('span').hasClass('plus')) { - node.parent().children('span').removeClass('plus').addClass('minus'); - } - var display = 'display:none;'; - if (rescan) { - display = ''; - } - var appendage = '
      '; - $.each(files, function(index) { - var ext = ''; - var name = files[index].name.replace(path, ''); - var nodeClass = 'none'; - name = name.split('/') - .join(' '); - if (files[index].type == 'file') { - var ext = ' ext-' + name.split('.') - .pop(); - } - if(files[index].type == 'directory' && files[index].size > 0) { - nodeClass = 'plus'; - } - appendage += '
    • ' + name + '
    • '; - }); - appendage += '
    '; - if (rescan) { - node.parent('li') - .children('ul') - .remove(); - } - $(appendage) - .insertAfter(node); - if (!rescan) { - node.siblings('ul') - .slideDown(300); - } - } - } - node.removeClass('loading'); - if (rescan && _this.rescanChildren.length > _this.rescanCounter) { - _this.rescan(_this.rescanChildren[_this.rescanCounter++]); - } else { - _this.rescanChildren = []; - _this.rescanCounter = 0; - } - }); - } - }, - - rescanChildren: [], - - rescanCounter: 0, - - rescan: function(path) { - var _this = this; - if (this.rescanCounter === 0) { - // Create array of open directories - node = $('#file-manager a[data-path="' + path + '"]'); - node.parent() - .find('a.open') - .each(function() { - _this.rescanChildren.push($(this) - .attr('data-path')); - }); - } - - this.index(path, true); - }, - - ////////////////////////////////////////////////////////////////// - // Open File - ////////////////////////////////////////////////////////////////// - - openFile: function(path, focus) { - if (focus === undefined) { - focus = true; - } - var node = $('#file-manager a[data-path="' + path + '"]'); - var ext = this.getExtension(path); - if ($.inArray(ext.toLowerCase(), this.noOpen) < 0) { - node.addClass('loading'); - $.get(this.controller + '?action=open&path=' + encodeURIComponent(path), function(data) { - var openResponse = codiad.jsend.parse(data); - if (openResponse != 'error') { - node.removeClass('loading'); - codiad.active.open(path, openResponse.content, openResponse.mtime, false, focus); - } - }); - } else { - if(!codiad.project.isAbsPath(path)) { - if ($.inArray(ext.toLowerCase(), this.noBrowser) < 0) { - this.download(path); - } else { - this.openInModal(path); - } - } else { - codiad.message.error(i18n('Unable to open file in Browser')); - } - } - }, - - ////////////////////////////////////////////////////////////////// - // Open in browser - ////////////////////////////////////////////////////////////////// - - openInBrowser: function(path) { - $.ajax({ - url: this.controller + '?action=open_in_browser&path=' + encodeURIComponent(path), - success: function(data) { - var openIBResponse = codiad.jsend.parse(data); - if (openIBResponse != 'error') { - window.open(openIBResponse.url, '_newtab'); - } - }, - async: false - }); - }, - openInModal: function(path) { - codiad.modal.load(250, this.dialog, { - action: 'preview', - path: path - }); - }, - saveModifications: function(path, data, callbacks, save=true){ - callbacks = callbacks || {}; - var _this = this, action, data; - var notifySaveErr = function() { - codiad.message.error(i18n('File could not be saved')); - if (typeof callbacks.error === 'function') { - var context = callbacks.context || _this; - callbacks.error.apply(context, [data]); - } - } - $.post(this.controller + '?action=modify&path=' + encodeURIComponent(path), data, function(resp){ - resp = $.parseJSON(resp); - if (resp.status == 'success') { - if ( save === true ) { - codiad.message.success(i18n('File saved')); - } - if (typeof callbacks.success === 'function'){ - var context = callbacks.context || _this; - callbacks.success.call(context, resp.data.mtime); - } - } else { - if (resp.message == 'Client is out of sync'){ - var reload = confirm( - "Server has a more updated copy of the file. Would "+ - "you like to refresh the contents ? Pressing no will "+ - "cause your changes to override the server's copy upon "+ - "next save." - ); - if (reload) { - codiad.active.close(path); - codiad.active.removeDraft(path); - _this.openFile(path); - } else { - var session = codiad.editor.getActive().getSession(); - session.serverMTime = null; - session.untainted = null; - } - } else codiad.message.error(i18n('File could not be saved')); - if (typeof callbacks.error === 'function') { - var context = callbacks.context || _this; - callbacks.error.apply(context, [resp.data]); - } - } - }).error(notifySaveErr); - }, - ////////////////////////////////////////////////////////////////// - // Save file - ////////////////////////////////////////////////////////////////// - - saveFile: function(path, content, callbacks, save=true) { - this.saveModifications(path, {content: content}, callbacks, save); - }, - - savePatch: function(path, patch, mtime, callbacks) { - if (patch.length > 0) - this.saveModifications(path, {patch: patch, mtime: mtime}, callbacks); - else if (typeof callbacks.success === 'function'){ - var context = callbacks.context || this; - callbacks.success.call(context, mtime); - } - }, - - ////////////////////////////////////////////////////////////////// - // Create Object - ////////////////////////////////////////////////////////////////// - - createNode: function(path, type) { - codiad.modal.load(250, this.dialog, { - action: 'create', - type: type, - path: path - }); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - var shortName = $('#modal-content form input[name="object_name"]') - .val(); - var path = $('#modal-content form input[name="path"]') - .val(); - var type = $('#modal-content form input[name="type"]') - .val(); - var createPath = path + '/' + shortName; - $.get(codiad.filemanager.controller + '?action=create&path=' + encodeURIComponent(createPath) + '&type=' + type, function(data) { - var createResponse = codiad.jsend.parse(data); - if (createResponse != 'error') { - codiad.message.success(type.charAt(0) - .toUpperCase() + type.slice(1) + ' Created'); - codiad.modal.unload(); - // Add new element to filemanager screen - codiad.filemanager.createObject(path, createPath, type); - if(type == 'file') { - codiad.filemanager.openFile(createPath, true); - } - /* Notify listeners. */ - amplify.publish('filemanager.onCreate', {createPath: createPath, path: path, shortName: shortName, type: type}); - } - }); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Copy to Clipboard - ////////////////////////////////////////////////////////////////// - - copyNode: function(path) { - this.clipboard = path; - codiad.message.success(i18n('Copied to Clipboard')); - }, - - ////////////////////////////////////////////////////////////////// - // Paste - ////////////////////////////////////////////////////////////////// - - pasteNode: function(path) { - var _this = this; - if (this.clipboard == '') { - codiad.message.error(i18n('Nothing in Your Clipboard')); - } else if (path == this.clipboard) { - codiad.message.error(i18n('Cannot Paste Directory Into Itself')); - } else { - var shortName = _this.getShortName(_this.clipboard); - if ($('#file-manager a[data-path="' + path + '/' + shortName + '"]') - .length) { // Confirm overwrite? - codiad.modal.load(400, this.dialog, { - action: 'overwrite', - path: path + '/' + shortName - }); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - var duplicate = false; - if($('#modal-content form select[name="or_action"]').val()==1){ - duplicate=true; console.log('Dup!'); - } - _this.processPasteNode(path,duplicate); - }); - } else { // No conflicts; proceed... - _this.processPasteNode(path,false); - } - } - }, - - processPasteNode: function(path,duplicate) { - var _this = this; - var shortName = this.getShortName(this.clipboard); - var type = this.getType(this.clipboard); - if(duplicate){ - shortName = "copy_of_"+shortName; - } - $.get(this.controller + '?action=duplicate&path=' + - encodeURIComponent(this.clipboard) + '&destination=' + - encodeURIComponent(path + '/' + shortName), function(data) { - var pasteResponse = codiad.jsend.parse(data); - if (pasteResponse != 'error') { - _this.createObject(path, path + '/' + shortName, type); - codiad.modal.unload(); - /* Notify listeners. */ - amplify.publish('filemanager.onPaste', {path: path, shortName: shortName, duplicate: duplicate}); - } - }); - }, - - ////////////////////////////////////////////////////////////////// - // Rename - ////////////////////////////////////////////////////////////////// - - renameNode: function(path) { - var shortName = this.getShortName(path); - var type = this.getType(path); - var _this = this; - codiad.modal.load(250, this.dialog, { action: 'rename', path: path, short_name: shortName, type: type}); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - var newName = $('#modal-content form input[name="object_name"]') - .val(); - // Build new path - var arr = path.split('/'); - var temp = new Array(); - for (i = 0; i < arr.length - 1; i++) { - temp.push(arr[i]) - } - var newPath = temp.join('/') + '/' + newName; - $.get(_this.controller, { action: 'modify', path: path, new_name: newName} , function(data) { - var renameResponse = codiad.jsend.parse(data); - if (renameResponse != 'error') { - codiad.message.success(type.charAt(0) - .toUpperCase() + type.slice(1) + ' Renamed'); - var node = $('#file-manager a[data-path="' + path + '"]'); - // Change pathing and name for node - node.attr('data-path', newPath) - .html(newName); - if (type == 'file') { // Change icons for file - curExtClass = 'ext-' + _this.getExtension(path); - newExtClass = 'ext-' + _this.getExtension(newPath); - $('#file-manager a[data-path="' + newPath + '"]') - .removeClass(curExtClass) - .addClass(newExtClass); - } else { // Change pathing on any sub-files/directories - _this.repathSubs(path, newPath); - } - // Change any active files - codiad.active.rename(path, newPath); - codiad.modal.unload(); - } - }); - }); - }, - - repathSubs: function(oldPath, newPath) { - $('#file-manager a[data-path="' + newPath + '"]') - .siblings('ul') - .find('a') - .each(function() { - // Hit the children, hit 'em hard - var curPath = $(this) - .attr('data-path'); - var revisedPath = curPath.replace(oldPath, newPath); - $(this) - .attr('data-path', revisedPath); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Delete - ////////////////////////////////////////////////////////////////// - - deleteNode: function(path) { - var _this = this; - codiad.modal.load(400, this.dialog, { - action: 'delete', - path: path - }); - $('#modal-content form') - .live('submit', function(e) { - e.preventDefault(); - $.get(_this.controller + '?action=delete&path=' + encodeURIComponent(path), function(data) { - var deleteResponse = codiad.jsend.parse(data); - if (deleteResponse != 'error') { - var node = $('#file-manager a[data-path="' + path + '"]'); - node.parent('li') - .remove(); - // Close any active files - $('#active-files a') - .each(function() { - var curPath = $(this) - .attr('data-path'); - if (curPath.indexOf(path) == 0) { - codiad.active.remove(curPath); - } - }); - } - codiad.modal.unload(); - }); - }); - }, - - ////////////////////////////////////////////////////////////////// - // Search - ////////////////////////////////////////////////////////////////// - - search: function(path) { - codiad.modal.load(500, this.dialog,{ - action: 'search', - path: path - }); - codiad.modal.load_process.done( function() { - var lastSearched = JSON.parse(localStorage.getItem("lastSearched")); - if(lastSearched) { - $('#modal-content form input[name="search_string"]').val(lastSearched.searchText); - $('#modal-content form input[name="search_file_type"]').val(lastSearched.fileExtension); - $('#modal-content form select[name="search_type"]').val(lastSearched.searchType); - if(lastSearched.searchResults != '') { - $('#filemanager-search-results').slideDown().html(lastSearched.searchResults); - } - } - }); - codiad.modal.hideOverlay(); - var _this = this; - $('#modal-content form') - .live('submit', function(e) { - $('#filemanager-search-processing') - .show(); - e.preventDefault(); - searchString = $('#modal-content form input[name="search_string"]') - .val(); - fileExtensions=$('#modal-content form input[name="search_file_type"]') - .val(); - searchFileType=$.trim(fileExtensions); - if (searchFileType != '') { - //season the string to use in find command - searchFileType = "\\(" + searchFileType.replace(/\s+/g, "\\|") + "\\)"; - } - searchType = $('#modal-content form select[name="search_type"]') - .val(); - $.post(_this.controller + '?action=search&path=' + encodeURIComponent(path) + '&type=' + searchType, { - search_string: searchString, - search_file_type: searchFileType - }, function(data) { - searchResponse = codiad.jsend.parse(data); - var results = ''; - if (searchResponse != 'error') { - $.each(searchResponse.index, function(key, val) { - // Cleanup file format - if(val['file'].substr(-1) == '/') { - val['file'] = val['file'].substr(0, str.length - 1); - } - val['file'] = val['file'].replace('//','/'); - // Add result - results += ''; - }); - $('#filemanager-search-results') - .slideDown() - .html(results); - } else { - $('#filemanager-search-results') - .slideUp(); - } - _this.saveSearchResults(searchString, searchType, fileExtensions, results); - $('#filemanager-search-processing') - .hide(); - }); - }); - }, - - ///////////////////////////////////////////////////////////////// - // saveSearchResults - ///////////////////////////////////////////////////////////////// - saveSearchResults: function(searchText, searchType, fileExtensions, searchResults) { - var lastSearched = { - searchText: searchText, - searchType: searchType, - fileExtension: fileExtensions, - searchResults: searchResults - }; - localStorage.setItem("lastSearched", JSON.stringify(lastSearched)); - }, - ////////////////////////////////////////////////////////////////// - // Upload - ////////////////////////////////////////////////////////////////// - - uploadToNode: function(path) { - codiad.modal.load(500, this.dialogUpload, {path: path}); - }, - - ////////////////////////////////////////////////////////////////// - // Download - ////////////////////////////////////////////////////////////////// - - download: function(path) { - var type = this.getType(path); - $('#download') - .attr('src', 'components/filemanager/download.php?path=' + encodeURIComponent(path) + '&type=' + type); - } - }; - -})(this, jQuery); -"; \ No newline at end of file diff --git a/data/collaborative/text/3833e87699ffe1cafb5dc3109d9b3dfb b/data/collaborative/text/3833e87699ffe1cafb5dc3109d9b3dfb deleted file mode 100755 index 0880947..0000000 --- a/data/collaborative/text/3833e87699ffe1cafb5dc3109d9b3dfb +++ /dev/null @@ -1,68 +0,0 @@ -s:1281:"/* - -Created: 2018-07-09 -Revised: N/A -Purpose: A template for vanilla js with one library. - -*/ -/*global L*/ - - -let m = {}; -let v = {}; -let c = {}; - -c.initialize = function(eventObject){ - c.defineStateVariables(eventObject); - - //Use the library to attach all element id's to variables - L.attachAllElementsById(v); - - //collect the names of all the events of interest - let eventTypes = [ - `change`, - `input`, - `keydown`, - `keyup`, - `load`, - `mousedown`, - `mouseover`, - `mouseup`, - `offline`, - `online`, - `orientationchange`, - `resize`, - `touchend`, - `touchmove`, - `touchstart`, - ]; - - for (let eventType of eventTypes){ - window.addEventListener(eventType, c.designateFunction); - } - -}; - -////////////////| function that defines the "state variables" or app state references |/////////// -c.defineStateVariables = function(eventObject){ - ///////| define meta events |///////// - m.eventObject = eventObject; - m.source = eventObject.target; - m.type = eventObject.type; - m.id = eventObject.target.id; - - - m.type === 'mousedown' || m.type === `touchstart` - ? m.pressed = true - : m.pressed = false - ; - - m.type === `mouseup` || m.type === `touchend` - ? m.released = true - : m.released = false - ; - ///////| define state varibales |/////////// - m.buttonIn = false; -}; - -"; \ No newline at end of file diff --git a/data/collaborative/text/3a7ac99607660738569ae0966a913bc8 b/data/collaborative/text/3a7ac99607660738569ae0966a913bc8 deleted file mode 100755 index b9a8658..0000000 --- a/data/collaborative/text/3a7ac99607660738569ae0966a913bc8 +++ /dev/null @@ -1,30 +0,0 @@ -s:855:" -
    -

    This page will eventually be password protected with a better interface.

    -

    Pages

    - - -

    Info

    - - vncserver -UserPasswdVerifier UnixAuth -
    -"; \ No newline at end of file diff --git a/data/collaborative/text/3a9233a747bb36b5549eb6d8455652d7 b/data/collaborative/text/3a9233a747bb36b5549eb6d8455652d7 deleted file mode 100755 index e126e14..0000000 --- a/data/collaborative/text/3a9233a747bb36b5549eb6d8455652d7 +++ /dev/null @@ -1,209 +0,0 @@ -s:4684:" - */ - -class mypit { - - const VERSION = '1.0.0'; - - - /** - * Unique identifier for your plugin. - * - * - * The variable name is used as the text domain when internationalizing strings - * of text. Its value should match the Text Domain file header in the main - * plugin file. - * - * @var string - */ - protected $plugin_slug = ''; - - /** - * Instance of this class. - */ - protected static $instance = null; - - /** - * Initialize the plugin by setting localization and loading public scripts and styles. - */ - private function __construct() { - - // Trigger initial - $this->init(); - } - - /** - * Return the plugin slug. - * - * @since 1.0.0 - * - * @return Plugin slug variable. - */ - public function get_plugin_slug() { - return $this->plugin_slug; - } - - /** - * Return an instance of this class. - * - * @since 1.0.0 - * - * @return object A single instance of this class. - */ - public static function get_instance() { - // If the single instance hasn't been set, set it now. - if ( null == self::$instance ) { - self::$instance = new self; - } - - return self::$instance; - } - - /** - * Fired for each blog when the plugin is activated. - * - * @since 1.0.0 - */ - private static function install() {} - - /** - * Fired for each blog when the plugin is uninstalled. - * - * @since 1.0.0 - */ - private static function uninstall() {} - - /** - * Load the plugin text domain for translation. - * - * @since 1.0.0 - */ - public function init() {} - - /** - * Register and enqueue public-facing style sheet. - * - * @since 1.0.0 - */ - public function enqueue_scripts() {} - - /** - * Register and enqueue public-facing style sheet. - * - * @since 1.0.0 - */ - public function enqueue_styles() {} - - /** - * Connect to specified MYSQL database with preset login details. - * - * @since 1.0.0 - */ - public static function sql_connect( $database = "" ) { - - switch( $database ) { - - default : - - $database = "main"; - $host = "localhost"; - $password = base64_decode( "UCF0QWRtIW4=" ); - $username = "main"; - break; - } - - $connection = mysqli_connect( $host, $username, $password, $database ); - return( $connection ); - } - - /** - * Execute an sql query with binded variables - * - * This allows you to use POST or GET values without - * having to worry about people hacking your query. - * - * @since 1.0.0 - */ - public static function sql( $sql, $bind, $bind_vars, $error, $last_id = FALSE ) { - - $connection = self::sql_connect(); - - $result = mysqli_prepare( $connection, $sql ) or die( "

    " . $error . ":
    Query:" . $sql . "
    " . mysqli_error( $connection ) . "

    " ); - - //call_user_func_array(array($result, "bind_param"), array_merge(array($bind), $bind_vars)); - $result->bind_param( $bind, ...$bind_vars ); - $result->execute(); - - if ( $last_id === FALSE ) { - - $return = $result->get_result(); - } else { - - $return = mysqli_insert_id( $connection ); - } - $result->close(); - - return( $return ); - } - - - /** - * Execute a basic sql query - * - * This allows should only be used for statements without user input. - * - * @since 1.0.0 - */ - public static function sql_internal( $sql, $error ) { - - $connection = self::sql_connect(); - $result = mysqli_query( $connection, $sql ) or die( "

    " . $error . ":
    Query:" . $sql . "
    " . mysqli_error( $connection ) . "

    " ); - return( $result ); - } - - - /** - * Connect to a microsoft sql database with preset login details. - * - * @since 1.0.0 - */ - public static function ms_sql_connect( $database ) { - - - $server = ""; - $connection_info = array(); - - $connection_info["Database"] = $database; - $connection_info["UID"] = ""; - $connection_info["PWD"] = ""; - - $connection = sqlsrv_connect( $server , $connection_info ); - - if( $connection === false ) { - - echo "

    Error connecting to database.



    "; - die( print_r( sqlsrv_errors(), true ) ); - } - - return( $connection ); - } -}"; \ No newline at end of file diff --git a/data/collaborative/text/3b05b09289a3db2ae8cf68f284bcfc46 b/data/collaborative/text/3b05b09289a3db2ae8cf68f284bcfc46 deleted file mode 100755 index 2bfe8b7..0000000 --- a/data/collaborative/text/3b05b09289a3db2ae8cf68f284bcfc46 +++ /dev/null @@ -1,7 +0,0 @@ -s:126:"[{ - "author": "Isaac Brown", - "version": "1.0.0", - "name": "Tela Auto Save", - "url": "https://telaaedifex.com" -}] -"; \ No newline at end of file diff --git a/data/collaborative/text/3d963d1e35c7582fb4cb19caad66130a b/data/collaborative/text/3d963d1e35c7582fb4cb19caad66130a deleted file mode 100755 index b1567e6..0000000 --- a/data/collaborative/text/3d963d1e35c7582fb4cb19caad66130a +++ /dev/null @@ -1,350 +0,0 @@ -s:5688:"/* CSS Document */ - -html {} -body { - - margin: 0; - padding: 0; -} - -.content { - - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; - padding: 0 10px 0 10px; -} - -/*================================================== -* Start Header -*==================================================*/ -.main_menu_container { - - background-color: #1f2059; - /*display: block;*/ - position: relative; - text-align: center; - top: 0; - width: 100%; - transition: all 0.5s; -} - -.main_menu_container_sticky { - - transition: all 0.5s; - position: fixed; - top: 0; - z-index: 10; -} - -.main_menu { - - align-items: center; - display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */ - display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */ - display: -ms-flexbox; /* TWEENER - IE 10 */ - display: -webkit-flex; /* NEW - Chrome */ - display: flex; /* NEW, Spec - Opera 12.1, Firefox 20+ */ - justify-content: center; - margin: 0; - padding: 0; - text-align: center; - transition: all 0.5s; - width: 100%; -} - -.main_menu_drop_down { - - list-style: none; -} - -.main_menu_drop_down_item { - - list-style: none; -} - -.mobile_menu_open { - - display: none; -} - -.mobile_menu_close { - - display: none; -} - -.main_menu_item { - - display: inline-block; - list-style: none; - - -webkit-transition: background-color .5s; - transition: background-color .5s; -} - -.main_menu_item:hover { - - background-color: #CCCCCC; - - -webkit-transition: background-color .5s; - transition: background-color .5s; -} - -.menu_item_selected { - - background-color: #FFFFFF; - - -webkit-transition: background-color .5s; - transition: background-color .5s; -} - -.menu_item_selected:hover { - - background-color: #FFFFFF; -} - -.main_menu_link { - - -webkit-transition: all 500ms; - border-radius: 0px; - color: #FFFFF0; - display: block; - font-family: 'IM Fell English SC', serif; - font-size: 16px; - font-weight: 600; - letter-spacing: 1px; - line-height: 22px; - padding: 20px 10px; - text-decoration: none; - text-transform: uppercase; - transition: all 500ms; - white-space: nowrap; -} - -.main_menu_link_selected { - - color: #777777; -} - -.main_menu_container_sticky + .content { - - -} - -.main_menu_logo_link { - - display: none; -} - -.logo { - - max-width: 0; - overflow: hidden; - transition: all 0.5s; -} - - -.main_menu_container_sticky li.logo { - - max-width:500px; -} - -.main_menu_container_sticky .main_menu_logo_link { - - display: visible; -} - -/*================================================== -* Start Mobile Menu -*==================================================*/ - -.mobile_menu_open { - - display: none; -} - -.mobile_menu_close { - - display: none; -} - -/* If screen is less than x */ -@media only - screen and (max-device-width : 736px), - screen and (max-width: 736px) - /*and (-webkit-min-device-pixel-ratio : 3) This isnt needed*/ -{ - - html, body { - - max-width: 100%; - overflow-x: hidden; - } - /* - .body { - - -webkit-transform: rotate(180deg); - -moz-transform: rotate(180deg); - -ms-transform: rotate(180deg); - -o-transform: rotate(180deg); - transform: rotate(180deg); - } - - .body > section { - display: block; - -webkit-transform: rotate(-180deg); - -moz-transform: rotate(-180deg); - -ms-transform: rotate(-180deg); - -o-transform: rotate(-180deg); - transform: rotate(-180deg); - }*/ - - p { - - font-size: 1em; - margin: 1em 0; - } - - table { - - width: 100% !important; - } - - tr { - - width: 100% !important; - } - - td { - - display: block; - width: 100% !important; - } - - th { - - display: block; - width: 100% !important; - } - - table.keep_layout td { - - display: table-cell; - width: initial !important; - } - - .header_table_column { - - text-align: center; - } - - .mobile_menu_open { - - background-color: #ededed; - display: block; - text-align: center; - width: 100%; - } - - .mobile_menu_open_button { - - font-size: 25px; - text-decoration: none; - } - - .mobile_menu_close { - - display: block; - text-align: right; - } - - .mobile_menu_close_button { - - color: #FFF; - font-size: 50px; - padding-right: 5%; - text-align: right; - text-decoration: none; - - } - - .main_menu { - - background-color: #111; - display: block; - height: 100%; - left: 0; - margin-top: 0; - overflow-x: hidden; - position: fixed; - top: 0; - transition: 0.5s; - width: 0; - z-index: 11; - - } - - .main_menu_drop_down { - - list-style: none; - } - - .main_menu_drop_down_item { - - list-style: none; - } - - .main_menu_item { - - display: block; - list-style: none; - width: 100%; - - -webkit-transition: background-color .5s; - transition: background-color .5s; - } - - .main_menu_item:hover { - - background-color: #CCCCCC; - - -webkit-transition: background-color .5s; - transition: background-color .5s; - } - - .menu_item_selected { - - background-color: #FFFFFF; - display: block; - list-style: none; - width: 100%; - - -webkit-transition: background-color .5s; - transition: background-color .5s; - } - - .menu_item_selected:hover { - - background-color: #FFFFFF; - } - - .main_menu_link { - - -webkit-transition: all 500ms; - border-radius: 0px; - color: #777777; - display: block; - font-family: 'IM Fell English SC', serif; - font-size: 16px; - font-weight: 600; - letter-spacing: 1px; - line-height: 22px; - padding: 20px 10px; - text-decoration: none; - text-transform: uppercase; - transition: all 500ms; - white-space: nowrap; - width: 100%; - } -} -"; \ No newline at end of file diff --git a/data/collaborative/text/49234e7b9a6d49c284c2c075b71344f3 b/data/collaborative/text/49234e7b9a6d49c284c2c075b71344f3 deleted file mode 100755 index 8c932cc..0000000 --- a/data/collaborative/text/49234e7b9a6d49c284c2c075b71344f3 +++ /dev/null @@ -1,26 +0,0 @@ -s:445:"/* - -Created: 2018-07-09 -Revised: N/A -Purpose: A template for vanilla js with one library. - -*/ -/*global L*/ -/*global m*/ -/*global v*/ -/*global c*/ - -c.designateFunction = function(eventObject) { - c.updateMetaEvents(eventObject) - let functionQualifiers = { - setToggleFirstButton: [m.source === v.firstButton, m.released], - /* - setXXY: [], - setXXZ: [], - setXYX: [], - setXYY: [], - */ - } - L.runQualifiedFunctions(functionQualifiers, m, v, c) -} -"; \ No newline at end of file diff --git a/data/collaborative/text/532d917f0ec46400caa40e28a6576439 b/data/collaborative/text/532d917f0ec46400caa40e28a6576439 deleted file mode 100755 index f0fb224..0000000 --- a/data/collaborative/text/532d917f0ec46400caa40e28a6576439 +++ /dev/null @@ -1,577 +0,0 @@ -s:22351:"/** - Author: Abbas Abdulmalik - Created: ~ May, 2017 - Revised: June 9, 2018 - Original Filename: L.js - Purpose: a small (but growing) personal re-usable js library for a simple MVC architecture - Notes: Now qualifyFunction helper doesn't return true for empty arrays (no vacuous truth) - - Added UploadFiles: - uploadFiles takes a callback -- progressReporter-- as it FIRST argument (parameter) - to allow for an optional fourth parameter of an upload path for the server. - progressReporter will be passed three arguments when called: - 1.) the amount of bytes uploaded so far - 2.) the total size of the file in bytes - 3.) the index of the file in the "array" of files being uploaded - - Added sortByExtension that alphabetizes an array of strings 'in place' by filename extension - Added arrayStringMatch that matches a collection of string arrays to a search string. - later (6-9-2018) included an option for a "maximum array index" to eliminate - searching irrelevant fields at the end of the array, such as image name and primary key. - Added loopCall as a 'better' version of setInterval - Removed L.attributes. It's a reserved word: an object belonging to DOM elements - Now it uses L.attribs - Added L.loopCall.stop() so that user can easily stop L.loopCall - Added L.symDiff for comparing arrays to determine their symmetric difference = conjunctive union = - exclusive-or - Restored an updated version of uploadFiles that signals the final file has uploaded - Added secToMinSec - Added runQualifiedFunctions that mirrors runQualifiedMethods using different parameters, - namely: functionQualifiers, model, view, controller - Added attachNewElement(tagname, id, view). Create new element, gives it an id and - attaches it to object provided: - L.attachNewElement(`div`, `picHolder`, view) - Added createListMixer and scrammbleThis, which depends on createListMixer - Added sortArrayOfStringArrays, with option of using a "link token" of choice as the 3rd argument - Added an optional argument for arrayStringMatch for a maximum array index - to eliminate searching irrelevant fields at the end of the array, - such as image name and primary key -*/ - -var L = {} -L.styles = function(styleString){ - const colonPosition = styleString.indexOf(':') - const property = styleString.slice(0, colonPosition) - const value = styleString.slice(colonPosition + 1) - this.style[property] = value - - return this.styles -} - -L.attribs = function(attributeString){ - const assignmentPosition = attributeString.indexOf('=') - const attribute = attributeString.slice(0, assignmentPosition) - const value = attributeString.slice(assignmentPosition + 1) - this.setAttribute(attribute, value) - - return this.attribs -} - -L.attachAllElementsById = function(here){ - let allElements = document.getElementsByTagName('*') - let array = [] - array.forEach.call(allElements, function(element) { - if(element.id){ - here[element.id] = element - element.styles = L.styles.bind(element) // attach L's styles() method here - element.attribs = L.attribs.bind(element) // attach L's attribs() method here - } - }) -} -///////////////| START of L.attachNewElement |///////////// -/** - L.attachNewElement(string tagname, string id, object view) ... - ... creates a new element of type "tagname" given as the first argument, - and gives it the id "id" given as the second argument. - The third argument is the view object where this new reference will be attached. - The element can then be referenced as view.id. -*/ -L.attachNewElement = function(tagname, id, view){ - if(arguments.length !== 3){ - console.log(`Error: requires 3 arguments: tagname, id, view`) - return - } - try{ - if(typeof tagname === `string`){ - var newElement = document.createElement(tagname) - } - else{ - console.log(`Error: tagname needs to be a string`) - return - } - if(typeof id === `string`){ - newElement.id = id - } - else{ - console.log(`Error: id needs to be a string`) - return - } - if(view.toString() === `[object Object]`){ - view[newElement.id] = newElement - newElement.styles = L.styles.bind(newElement) // attach L's styles() method here - newElement.attribs = L.attribs.bind(newElement) // attach L's attribs() method here - return newElement - } - else{ - console.log(`Error: view needs to be an object`) - return - } - } - catch(e){ - console.log(`Error in L.attachNewElement: ${e}`) - return - } -} -///////////////| END of L.attachNewElement |///////////// - -L.noPinchZoom = function(){ - window.ontouchstart = function(eventObject){ - if(eventObject.touches && eventObject.touches.length > 1){ - eventObject.preventDefault(); - } - } -} - -L.runQualifiedMethods = function(functionQualifiers, object, runNextUpdate){ - Object - .keys(functionQualifiers) - .filter(qualifyFunction) - .forEach(runFunction) - if(typeof runNextUpdate === 'function'){runNextUpdate()} - - //-----| helpers |-----// - function qualifyFunction(functionName){ - const isQualified = functionQualifiers[functionName].every( qualifier => qualifier) && - !!functionQualifiers[functionName].length - return isQualified - } - function runFunction(functionName){ - if(typeof object[functionName] === 'function'){ - object[functionName]() - } - - /** - If the prefix of this function's name is 'set' (for updating the MODEL), - and there is a similarly named function with a prefix of 'show' (for updating the VIEW), - then run the 'show' version as well. - */ - let prefix = functionName.slice(0,3) - let newFunctionName = 'show' + functionName.slice(3) - - if(prefix === 'set' && typeof object[newFunctionName] === 'function'){ - object[newFunctionName]() - } - } -} - -L.runQualifiedFunctions = function(functionQualifiers, model, view, controller){ - Object - .keys(functionQualifiers) - .filter(qualifyFunction) - .forEach(runFunction) - //-----| helpers |-----// - function qualifyFunction(functionName){ - const isQualified = functionQualifiers[functionName].every( qualifier => qualifier) && - !!functionQualifiers[functionName].length - return isQualified - } - function runFunction(functionName){ - if(typeof controller[functionName] === 'function'){ - controller[functionName](model) - } - /** - If the prefix of this function's name is 'set' (for updating the MODEL), - and there is a similarly named function with a prefix of 'show' (for updating the VIEW), - then run the 'show' version as well. - */ - let prefix = functionName.slice(0,3) - let newFunctionName = 'show' + functionName.slice(3) - if(prefix === 'set' && typeof controller[newFunctionName] === 'function'){ - controller[newFunctionName](view) - } - } -} -/** - Use a php script that reads contents of file from $_POST['contents'] that was convert by client - as DataURL, and expects filename and uploadPath from: $_POST['filename'] and $_POST['uploadPath'] - with trailing slash (/) provided by client (though script could check for this). -*/ -L.uploadFiles = function(progressReporter, fileElement, phpScriptName, uploadPath='../uploads/'){ - let doneCounter = 0 - let fileCount = fileElement.files.length - const array = [] // make a real array to borrow it's forEach method - array.forEach.call(fileElement.files, (file, index) => { - const postman = new XMLHttpRequest() // make a file deliverer for each file - const uploadObject = postman.upload // This object keeps track of upload progress - const envelope = new FormData() // make a holder for the file's name and content - envelope.stuff = envelope.append // give 'append' the nickname 'stuff' - const reader = new FileReader() // make a file reader (the raw file element is useless) - - reader.readAsDataURL(file) // process the file's contents - reader.onload = function(){ // when done ... - const contents = reader.result // collect the result, and ... - envelope.stuff('contents', contents) // place it in the envelope along with ... - envelope.stuff('filename', file.name) // its filename ... - envelope.stuff('uploadPath', uploadPath) // and its upload path on the server - - postman.open(`POST`, phpScriptName)// open up a POST to the server's php script - postman.send(envelope) // send the file - - //check when file loads and when there is an error - postman.onload = eventObject => { - postman.status !== 200 ? showMessage() : checkLastFileDone() - //-----| helper |------// - function showMessage(){ - const message = `Trouble with file: ${postman.status}` - console.log(message) - alert(message) - } - function checkLastFileDone(){ - doneCounter++ - if(typeof progressReporter === 'function'){ - if(doneCounter === fileCount){ - progressReporter(1, 1, index) - } - } - } - } - - postman.onerror = eventObject => { - const message = `Trouble connecting to server` - console.log(message) - alert(message) - } - - //invoke the callback for each upload progress report - uploadObject.onprogress = function(progressObject){ - if(typeof progressReporter === 'function'){ - progressReporter(progressObject.loaded, progressObject.total, index) - } - } - } - }) -} - -//---------------------------------------------------------// -/** - Given an array of strings (array), sorts the array 'in place' by filename EXTENSION, - and returns a copy of the array as well. Since it mutates the array, it is decidedly not - functionistic (but it functions). -*/ -L.sortByExtension = function (array) { - const type = {}.toString.call(array, null); - if (type !== '[object Array]') { - return array; - } - if (array.length === 0 || array.some(member => typeof member !== 'string')) { - return array; - } - //-------------------------------------// - let extension = ``; - let nudeWord = ``; - array.forEach((m, i, a) => { - if (m.lastIndexOf(`.`) !== -1) { - //get the extension - extension = m.slice(m.lastIndexOf(`.`) + 1); - nudeWord = m.slice(0, m.lastIndexOf(`.`)); - a[i] = `${extension}.${nudeWord}`; - } - }); - - array.sort(); - - array.forEach((m, i, a) => { - if (m.indexOf(`.`) !== -1){ - //get prefix (formerly the extension) - extension = m.slice(0, m.indexOf(`.`)) - nudeWord = m.slice(m.indexOf(`.`) + 1) - a[i] = `${nudeWord}.${extension}` - } - }); - - const newArray = [] - array.forEach( m => newArray.push(m)) - - return newArray; -} - -/** -From an array of string arrays, return a possibly smaller array -of only those string arrays whose member strings contain the given subString -regardless of case. - 1. For arrayOfStringArrays, use the filter method (a function property of an array) - that expects a function argument that operates on each array member - 2. Let's call the function argument 'match' - 3. 'match' should test each member array for a match of the substring as follows: - a.) join the members strings together into a bigString that is lowerCased - b.) lowerCase the subString - c.) use indexOf to match substring to the bigString - d.) return true for a match, otherwise return false - 4. the filter creates a new array after doing this. - 5. final step: return the new array that the filter produced -*/ -L.arrayStringMatch = function(subString, arrayOfStringArrays, maxIndex){ - //============================================================// - return arrayOfStringArrays.filter(match) - //-------| Helper function 'match' |---------// - function match(memberArray){ - //on 6-9-2018, added option of maximum index to eliminate searching through irrelevant fields - let bigString = '' - if(maxIndex && typeof maxIndex === "number" && maxIndex > 0){ - bigString = memberArray - .filter((m,i) => i <= maxIndex) - .join(` `) - .toLowerCase() - } - else{ - bigString = memberArray.join(` `).toLowerCase() - } - const substringToMatch = subString.toLowerCase() - return bigString.indexOf(substringToMatch) !== -1 - } -} -//-------------------------------------------------// - -/** - L.loopCall can be used to replace setInterval, which has been somewhat discredited. - See this blog post: - https://dev.to/akanksha_9560/why-not-to-use-setinterval--2na9 - - L.loopCall uses setTimeout recursively, which is a technique - reportedly more reliabale than setInterval. - - L.loopCall repeatedly calls (invokes) the callback function provided as its first argument. - The first call is immediate, but subsequent calls are delayed by the milliseconds - provided as the second argument. All additional arguments are optional - to be used by the callback if required. - - If needed, you can delay the initial call as well, - by having loopCall invoked by setTimeout using the same delay: - - setTimeout(L.loopCall, delay, callback, delay, arg1, arg2 ...) - - or the more readable, but more risky ... - - setTimeout("L.loopCall(callback, delay, arg1, arg2 ...)", delay) - //Doug Crockford would not be pleased - - To stop the loop, the callback function can test some external state condition, - (or test its own arguments, if they are passed by reference): - - if(externalStateCondition){ - L.loopCall.stop() - } -*/ -L.loopCall = function (callback, delay, ...args){ - L.loopCall.stopLoop = setTimeout(L.loopCall, delay, callback, delay, ...args) - callback(...args) -} - -L.loopCall.stop = () => { - clearTimeout(L.loopCall.stopLoop) -} - -/** - Returns an array that is the "mathematical or logical" symmetric difference among or between - any number of arrays provided as arguments (usually two). If the order of members is ignored - (as is done for mathematical sets), the result acts as the the exclusive-or (XOR), also know as - the disjunctive union. For the trivial cases of comparing one or two arrays, the result is - not surprising: for one array, the result is itself: L.symDiff(A, []) => A ⊕ [] = A. - For two arrays, the result is an array that has only members which are not shared in common: - L.symDiff(A, B) => A ⊕ B . - When comparing more than two arrays, the result may ne surprising. The proper result can be verified - by comparing only two at a time: L.symDiff(A, B, C) => A ⊕ B ⊕ C = (A ⊕ B) ⊕ C -*/ -L.symDiff = function symDiff(arrayA, arrayB){ // dummy paramters NOT referenced in body of the function - var partialSymDiff = [], - argsArray = arguments - ; - //============THE CRUX================= - return findSymDiff(partialSymDiff,0); - //============UNDER THE HOOD=========== - function findSymDiff(partialSymDiff,index){ - if (argsArray[index] === undefined){ - return partialSymDiff; - } - else{ - partialSymDiff = sd(partialSymDiff, argsArray[index] ); - return findSymDiff( partialSymDiff, index + 1 ); - } - } - //===================================== - function sd(arrayI, arrayJ){ - var diff = [], - blackList = [], - i = 0, - j = 0, - maxI = arrayI.length, - maxJ = arrayJ.length - ; - //------------------------------------------------- - //1.) Combine the arrays into a third array. - //2.) Find the matched elements and place them into a blacklist array. - //3.) Pull blacklisted elements from the combined array. - //4.) return the "reduced" combined array. - //--------------------------------------------------- - // 1.) Combine the arrays into a third array. - diff = arrayI.concat(arrayJ); - //--------------------------------------------------- - // 2.) Find the matched elements and place them into a blacklist array. - for ( i=0; i < maxI; i++ ){ - for( j=0; j< maxJ; j++ ){ - if(arrayI[i] === arrayJ[j]){ - blackList.push(arrayI[i] ); - } - } - } - //---------------------------------------------------- - // 3.) Pull blacklisted elements from the combined array. - diff = diff.filter( (element) => blackList.indexOf(element) === -1 ) - //---------------------------------------------------- - // 4.) return the "reduced" combined array. - return killDupes(diff); - } - //======================================================== - function killDupes(array){ - var kept = []; // Record of the "keepers" - return array.filter(function(element){ - if ( kept.indexOf(element) === -1 ){ //if not already retained ... - kept.push(element); // Record it as retained now, and... - return true; // allow this element to be kept (true) - } - else{ - return false; // otherwise, don't keep it (already kept) - } - }); - } -}; - -/** - * Pass in a numerical seconds: it returns a string in the format - * mm : ss, like ... - * 35 : 37 in minutes and seconds -*/ -L.secToMinSec = (seconds) =>{ - var min = Math.floor(seconds / 60); - var sec = Math.floor(seconds % 60); - if(isNaN(min)){min = 0} - if(isNaN(sec)){sec = 0} - var zeroMin = ((min < 10) ? ("0" + min) : ("" + min)); - var zeroSec = ((sec < 10) ? ("0" + sec) : ("" + sec)); - var minSec = zeroMin + ":" + zeroSec; - return minSec; -}; -//====| END of secToMinSec |====// - -///////////////////| START of CreateListMixer |////////////////////// -/** - * CreateListMixer: a factory that creates and returns a function that - * returns a random item from the collection (array or object) provided. - * Notes: Example-> var list = ["a", "short", "list"];//three (3) items to test - * var getRandomItem = CreateListMixer(); - * getRandomItem(list);//returns first of randomized list - * getRandomItem();//returns next item - * getRandomItem();//returns next item (last of three) - * getRandomItem();//new first item from re-randomized list - * - * // a new list; - * var list2 = { record1: "string", record2: "anotherString", ...}; - * getRandomItem(list2);//returns first of new randomized list2 - * getRandomItem();//etc. - * It returns a property name for objects or an array member for arrays; - * It returns 'false' if argument of function is not an object - * or an array (fails typeof arg === 'object') - * -*/ -L.CreateListMixer = function(){ - var list=[], - randList= [], - listLength= 0, - itemReturned= null, - itemReturnedIndex= -1 - ; - return function(){ - if(arguments[0]){ - if(typeof arguments[0] === 'object'){ - list = arguments[0]; - if({}.toString.call(arguments[0]) === '[object Object]'){ - list = Object.keys(list); - } - randList = randomize(list); - listLength = list.length; - } - else{ - return false; - } - } - //----| no args activity: return next random item |---- - if(itemReturnedIndex >= listLength-1){ - do{ - randList = randomize(list); - itemReturnedIndex = -1; - } - while(randList[itemReturnedIndex +1] === itemReturned); - } - itemReturnedIndex++; - itemReturned = randList[itemReturnedIndex]; - return itemReturned; - //-----helpers----- - function randomize(x){ - var mixedIndexes = []; - var randomList = []; - randomizeIndexes(); - return randomList; - //----sub helper---- - function randomizeIndexes(){ - // random numbers for mixedIndexes - while(mixedIndexes.length !== x.length){ - var match = false; - var possibleIndex = (x.length)*Math.random(); - possibleIndex = Math.floor(possibleIndex); - mixedIndexes.forEach(function(m){ - if(m === possibleIndex){ - match = true; - } - }); - if(!match){ - mixedIndexes.push(possibleIndex); - } - } - for(var i = 0; i < x.length; i++){ - var newIndex = mixedIndexes[i]; - randomList.push(list[newIndex]); - } - } - } - };//===| END returned function |====== -}//===| END enclosing factory function====== -///////////////////| END of CreateListMixer |////////////////////// - -///////////////////| START of scrammbleThis |////////////////////// -/** - scrammbleThis: (depends on createListMixer, above) - It returns an array of randomly arranged items of the collection provided. - The argument must be an array, an object, or a string. - If the argument is an object, a random array of its property names is returned. - If the argument is a string, a random array of its characters is returned. - If the argument is an array, a random array of its members is returned. -*/ -L.scrammbleThis = function(collection){ - if ( !(typeof collection === 'object' || typeof collection === 'string') ){return collection} - var mix = L.CreateListMixer(); - var list = (Object.prototype.toString.call(collection) === '[object Array]') - ? collection - : (typeof collection === 'string') - ? collection.split('') - : (typeof collection === 'object') - ? Object.keys(collection) - : null - return list.map((m,i,a)=> (i === 0) ? mix(a) : mix()) -} -///////////////////| END of scrammbleThis |////////////////////// - -/** - Given an array of string arrays, this function returns an alphabetized version -*/ -L.sortArrayOfStringArrays = function(arrayOfStringArrays, linkToken='```'){ - //use a unique token (default = triple back-ticks ```) to join the strings of each array of strings - const arrayOfStrings = arrayOfStringArrays.map(stringArray => stringArray.join(linkToken)) - - //case-insensitive sort this array of strings, mutating it in place: - //https://stackoverflow.com/questions/8996963/how-to-perform-case-insensitive-sorting-in-javascript - arrayOfStrings.sort( (a,b) => a.toLowerCase().localeCompare(b.toLowerCase()) ) - - //return a new array of string arrays after splitting the strings on the unique token - return arrayOfStrings.map( string => string.split(linkToken)) -} -"; \ No newline at end of file diff --git a/data/collaborative/text/54b750daba066a7ec6a3343604f86406 b/data/collaborative/text/54b750daba066a7ec6a3343604f86406 deleted file mode 100755 index 0c3ab42..0000000 --- a/data/collaborative/text/54b750daba066a7ec6a3343604f86406 +++ /dev/null @@ -1,58 +0,0 @@ -s:1901:"/* - * Copyright (c) Codiad & daeks (codiad.com), distributed - * as-is and without warranty under the MIT License. See - * [root]/license.txt for more. This information must remain intact. - */ - - (function (global, $) { - - var codiad = global.codiad; - - $(window) - .load(function() { - codiad.update.init(); - }); - - codiad.update = { - - controller: 'components/update/controller.php', - dialog: 'components/update/dialog.php', - - ////////////////////////////////////////////////////////////////// - // Initilization - ////////////////////////////////////////////////////////////////// - - init: function () { - var _this = this; - $.get(_this.controller + '?action=init'); - }, - - ////////////////////////////////////////////////////////////////// - // Update Check - ////////////////////////////////////////////////////////////////// - - check: function () { - var _this = this; - $('#modal-content form') - .die('submit'); // Prevent form bubbling - codiad.modal.load(500, this.dialog + '?action=check'); - $('#modal-content').html('
    ' + i18n("Contacting GitHub...") + '

    '); - }, - - ////////////////////////////////////////////////////////////////// - // Download Archive - ////////////////////////////////////////////////////////////////// - - download: function () { - var _this = this; - var archive = $('#modal-content form input[name="archive"]') - .val(); - $('#download') - .attr('src', archive); - $.get(_this.controller + '?action=clear'); - codiad.modal.unload(); - } - - }; - -})(this, jQuery);"; \ No newline at end of file diff --git a/data/collaborative/text/550f42cee32ce845fd817cf600cddda0 b/data/collaborative/text/550f42cee32ce845fd817cf600cddda0 deleted file mode 100755 index 73b877c..0000000 --- a/data/collaborative/text/550f42cee32ce845fd817cf600cddda0 +++ /dev/null @@ -1,12 +0,0 @@ -s:235:" -# BEGIN WordPress - -RewriteEngine On -RewriteBase / -RewriteRule ^index\.php$ - [L] -RewriteCond %{REQUEST_FILENAME} !-f -RewriteCond %{REQUEST_FILENAME} !-d -RewriteRule . /index.php [L] - - -# END WordPress"; \ No newline at end of file diff --git a/data/collaborative/text/56cab2396298ed03d332f30384d3a133 b/data/collaborative/text/56cab2396298ed03d332f30384d3a133 deleted file mode 100755 index 45803b7..0000000 --- a/data/collaborative/text/56cab2396298ed03d332f30384d3a133 +++ /dev/null @@ -1,192 +0,0 @@ -s:7542:"remote = "http://update.codiad.com/?v={VER}&o={OS}&p={PHP}&w={WEB}&a={ACT}"; - $this->commits = "https://api.github.com/repos/Codiad/Codiad/commits"; - $this->archive = "https://github.com/Codiad/Codiad/archive/master.zip"; - } - - ////////////////////////////////////////////////////////////////// - // Set Initial Version - ////////////////////////////////////////////////////////////////// - - public function Init() - { - $version = array(); - if (!file_exists(DATA ."/version.php")) { - if (file_exists(BASE_PATH."/.git/HEAD")) { - $remote = $this->getRemoteVersion("install_git"); - $local = $this->getLocalVersion(); - $version[] = array("version"=>$local[0]['version'],"time"=>time(),"optout"=>"true","name"=>""); - saveJSON('version.php', $version); - } else { - $remote = $this->getRemoteVersion("install_man"); - $version[] = array("version"=>$remote[0]["commit"]["sha"],"time"=>time(),"optout"=>"true","name"=>""); - saveJSON('version.php', $version); - } - } else { - $local = $this->getLocalVersion(); - - if (file_exists(BASE_PATH."/.git/HEAD")) { - $current = getJSON('version.php'); - if ($local[0]['version'] != $current[0]['version']) { - $remote = $this->getRemoteVersion("update_git", $local[0]['version']); - $version[] = array("version"=>$local[0]['version'],"time"=>time(),"optout"=>"true","name"=>""); - saveJSON('version.php', $version); - } - } else { - if ($local[0]['version'] == '' && $local[0]['name'] == $_SESSION['user']) { - $remote = $this->getRemoteVersion("update_man", $local[0]['version']); - $version[] = array("version"=>$remote[0]["commit"]["sha"],"time"=>time(),"optout"=>"true","name"=>$_SESSION['user']); - saveJSON('version.php', $version); - } - } - - $local = $this->getLocalVersion(); - if (!isset($local[0]['optout'])) { - $remote = $this->getRemoteVersion("optout", $local[0]['version']); - $this->OptOut(); - } - } - } - - ////////////////////////////////////////////////////////////////// - // Clear Version - ////////////////////////////////////////////////////////////////// - - public function Clear() - { - $version[] = array("version"=>"","time"=>time(),"optout"=>"true","name"=>$_SESSION['user']); - saveJSON('version.php', $version); - } - - ////////////////////////////////////////////////////////////////// - // Clear Version - ////////////////////////////////////////////////////////////////// - - public function OptOut() - { - $current = getJSON('version.php'); - $version[] = array("version"=>$current[0]['version'],"time"=>$current[0]['time'],"optout"=>"true","name"=>$current[0]['name']); - saveJSON('version.php', $version); - } - - ////////////////////////////////////////////////////////////////// - // Check Version - ////////////////////////////////////////////////////////////////// - - public function Check() - { - $local = $this->getLocalVersion(); - $remote = $this->getRemoteVersion("check", $local[0]['version']); - - $nightly = true; - $archive = Common::getConstant('ARCHIVEURL', $this->archive); - $latest = ''; - - foreach ($remote as $tag) { - if ($latest == '') { - $latest = $tag["name"]; - $archive = $tag["zipball_url"]; - } - if ($local[0]['version'] == $tag["commit"]["sha"]) { - $local[0]['version'] = $tag["name"]; - $nightly = false; - break; - } - } - - $search = array("\r\n", "\n", "\r"); - $replace = array(" ", " ", " "); - - $message = ''; - $merge = ''; - $commits = json_decode(file_get_contents(Common::getConstant('COMMITURL', $this->commits)), true); - foreach ($commits as $commit) { - if ($local[0]['version'] != $commit["sha"]) { - if (strpos($commit["commit"]["message"], "Merge") === false) { - $message .= '- '.str_replace($search, $replace, $commit["commit"]["message"]).'
    '; - } else { - $merge .= '- '.str_replace($search, $replace, $commit["commit"]["message"]).'
    '; - } - } else { - break; - } - } - - if ($message == '') { - $message = $merge; - } - - return "[".formatJSEND("success", array("currentversion"=>$local[0]['version'],"remoteversion"=>$latest,"message"=>$message,"archive"=>$archive,"nightly"=>$nightly,"name"=>$local[0]['name']))."]"; - } - - ////////////////////////////////////////////////////////////////// - // Get Local Version - ////////////////////////////////////////////////////////////////// - - public function getLocalVersion() - { - if (file_exists(BASE_PATH."/.git/HEAD")) { - $tmp = file_get_contents(BASE_PATH."/.git/HEAD"); - if (strpos($tmp, "ref:") === false) { - $data[0]['version'] = trim($tmp); - } else { - $data[0]['version'] = trim(file_get_contents(BASE_PATH."/.git/".trim(str_replace('ref: ', '', $tmp)))); - } - $data[0]['name'] = ""; - if (file_exists(DATA ."/version.php")) { - $data[0]['optout'] = "true"; - } - } else { - $data = getJSON('version.php'); - } - return $data; - } - - ////////////////////////////////////////////////////////////////// - // Get Remote Version - ////////////////////////////////////////////////////////////////// - - public function getRemoteVersion($action, $localversion = "") - { - $remoteurl = Common::getConstant('UPDATEURL', $this->remote); - $remoteurl = str_replace("{OS}", PHP_OS, $remoteurl); - $remoteurl = str_replace("{PHP}", phpversion(), $remoteurl); - $remoteurl = str_replace("{VER}", $localversion, $remoteurl); - $remoteurl = str_replace("{WEB}", urlencode($_SERVER['SERVER_SOFTWARE']), $remoteurl); - $remoteurl = str_replace("{ACT}", $action, $remoteurl); - - return json_decode(file_get_contents($remoteurl), true); - } -} -"; \ No newline at end of file diff --git a/data/collaborative/text/5b8f5fad3ae9914ed4b0fdd3c500d2e9 b/data/collaborative/text/5b8f5fad3ae9914ed4b0fdd3c500d2e9 deleted file mode 100755 index 1010883..0000000 --- a/data/collaborative/text/5b8f5fad3ae9914ed4b0fdd3c500d2e9 +++ /dev/null @@ -1,134 +0,0 @@ -s:2634:"//let prefixfree = require('prefixfree'); -let m = {}; -const v = {}; -const c = {}; -/*global L*/ - -//===================================// -c.initialize = (eventObject) => { - c.initializeModel() - m.musicFilesUrl = 'https://aaserver.abbas411.com/music/uploads/' - - if(window.localStorage.getItem(`model`)){ - //m = JSON.parse(window.localStorage.getItem(`model`)); - } - - c.getFileList() - - window.id = 'window'; - window.document.id = `document`; - L.attachAllElementsById(v); - - const eventTypes = [ - 'play', - 'pause', - 'ended', - 'mousedown', - 'touchstart', - 'mouseup', - 'touchend', - 'mousemove', - 'touchmove', - 'keypress', - 'keyup', - 'keydown', - 'input', - 'change', - 'resize', - 'orientationchange', - 'load', - 'DOMContentLoaded', - 'online', - 'offline', - ]; - - //Update the model in response to events - for (let eventType of eventTypes) { - window.addEventListener(eventType, c.updateModel, true); - } - - L.noPinchZoom(); - - //c.setLogout(m, c.showLogout, v) - - if(m.securityIsActive){ - L.loopCall(c.pollForPaswordWall, 100, v); - } - - c.setResize(m, c.showResize, v) - -}; -//============================// - -c.initializeModel = function(){ - // meta events - m.eventArray = [{},{},{}]; - m.priorType = ["","","",]; - m.priorPressed = [false, false, false]; - m.priorReleased = [false, false, false]; - m.priorMoved = [false, false, false]; - - m.eventObject = {target:{id:"none"}, type: "none" }; - - m.source = m.eventObject.target; - m.id = m.eventObject.target.id; - - m.type = m.eventObject.type; - - m.pressed = m.type === 'mousedown' || m.type === 'touchstart'; - - m.released = m.type === 'mouseup' || m.type === 'touchend'; - - m.moved = m.type === 'mousemove' || m.type === 'touchmove'; - - m.priorStartTime; - m.startTime = Date.now(); - m.elapsedTime = m.startTime - m.priorStartTime; - m.priorStartTime = m.startTime; - - m.resized = true; - m.clicked = false; - - m.width = window.innerWidth - m.height = window.innerHeight - - // app states - m.securityIsActive = false - m.nonStop = false - - m.loggedIn = false - m.CLICK_TIME_MIN = 25; //in milliseconds - m.CLICK_TIME_MAX = 750; //milliseconds - m.MAX_WIDTH = 411;//pixels - - m.defaultBackground = 'images/twostalks.gif' - m.noPicture = true - m.pictureData = null - m.showPictureOnly = false - m.busyWithPictureOnly = false - m.pictureBusyId = 0 - - m.fractionArray = []; - m.averageUploadFraction = 0; - m.uploadPath = `../uploads/`; - //m.musicFilesUrl = 'http://abbas411.com/diymusic/uploads/' - m.musicFilesUrl = 'https://aaserver/abbas411.com/music/uploads/' - - - m.busyChangingSongs = false - m.busyResizing = false - m.playing = false - //============================// -} - - - - - - - - - - - -"; \ No newline at end of file diff --git a/data/collaborative/text/5b945bc2935cd53d7f96e69b2a25dbae b/data/collaborative/text/5b945bc2935cd53d7f96e69b2a25dbae deleted file mode 100755 index 034a040..0000000 --- a/data/collaborative/text/5b945bc2935cd53d7f96e69b2a25dbae +++ /dev/null @@ -1,175 +0,0 @@ -s:6176:"actives = getJSON('active.php'); - } - - ////////////////////////////////////////////////////////////////// - // List User's Active Files - ////////////////////////////////////////////////////////////////// - - public function ListActive() - { - $active_list = array(); - $tainted = false; - $root = WORKSPACE; - if ($this->actives) { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']==$this->username) { - if ($this->isAbsPath($data['path'])) { - $root = ""; - } else { - $root = $root.'/'; - } - if (file_exists($root.$data['path'])) { - $focused = isset($data['focused']) ? $data['focused'] : false; - $active_list[] = array('path'=>$data['path'], 'focused'=>$focused); - } else { - unset($this->actives[$active]); - $tainted = true; - } - } - } - } - if ($tainted) { - saveJSON('active.php', $this->actives); - } - echo formatJSEND("success", $active_list); - } - - ////////////////////////////////////////////////////////////////// - // Check File - ////////////////////////////////////////////////////////////////// - - public function Check() - { - $cur_users = array(); - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']!=$this->username && $data['path']==$this->path) { - $cur_users[] = $data['username']; - } - } - if (count($cur_users)!=0) { - - //echo formatJSEND("error", "Warning: File ".substr($this->path, strrpos($this->path, "/")+1)." Currently Opened By: " . implode(", ", $cur_users)); - } else { - echo formatJSEND("success"); - } - } - - ////////////////////////////////////////////////////////////////// - // Add File - ////////////////////////////////////////////////////////////////// - - public function Add() - { - $process_add = true; - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']==$this->username && $data['path']==$this->path) { - $process_add = false; - } - } - if ($process_add) { - $this->actives[] = array("username"=>$this->username,"path"=>$this->path); - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - } - - ////////////////////////////////////////////////////////////////// - // Rename File - ////////////////////////////////////////////////////////////////// - - public function Rename() - { - $revised_actives = array(); - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username'])) { - $revised_actives[] = array("username"=>$data['username'],"path"=>str_replace($this->path, $this->new_path, $data['path'])); - } - } - saveJSON('active.php', $revised_actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Remove File - ////////////////////////////////////////////////////////////////// - - public function Remove() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username'] && $this->path==$data['path']) { - unset($this->actives[$active]); - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Remove All Files - ////////////////////////////////////////////////////////////////// - - public function RemoveAll() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username']) { - unset($this->actives[$active]); - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Mark File As Focused - // All other files will be marked as non-focused. - ////////////////////////////////////////////////////////////////// - - public function MarkFileAsFocused() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username']) { - $this->actives[$active]['focused']=false; - if ($this->path==$data['path']) { - $this->actives[$active]['focused']=true; - } - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } -} -"; \ No newline at end of file diff --git a/data/collaborative/text/6022c4dda0ee39cea577b5c430ca8eba b/data/collaborative/text/6022c4dda0ee39cea577b5c430ca8eba deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/text/6022c4dda0ee39cea577b5c430ca8eba +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/text/60cb37fe1c12580053ad40ecbfbee3e7 b/data/collaborative/text/60cb37fe1c12580053ad40ecbfbee3e7 deleted file mode 100755 index 4cf9139..0000000 --- a/data/collaborative/text/60cb37fe1c12580053ad40ecbfbee3e7 +++ /dev/null @@ -1,18 +0,0 @@ -s:418:" 0) { - _this.saveDialog(); - } - }); - //Live feature - $('.command_name').live("change", function(){ - var line = $(this).attr('data-line'); - var name = $(this).val(); - var com = _this.commands[name].bindKey; - if (typeof(com.win) != 'undefined') { - $('.command_win[data-line="'+line+'"]').val(com.win); - } else { - if (!$.isPlainObject(com) && !$.isArray(com)) { - $('.command_win[data-line="'+line+'"]').val(com); - } - } - if (typeof(com.win) != 'undefined') { - $('.command_mac[data-line="'+line+'"]').val(com.mac); - } else { - if (!$.isPlainObject(com) && !$.isArray(com)) { - $('.command_mac[data-line="'+line+'"]').val(com); - } - } - - }); - $('.command_win').live("change", function(){ - _this.onCommandChange(this); - }); - $('.command_mac').live("change", function(){ - _this.onCommandChange(this); - }); - }, - - ////////////////////////////////////////////////////////// - // - // Show dialog - // - ////////////////////////////////////////////////////////// - showDialog: function() { - codiad.settings.show(this.path.replace(location.toString(), "") + '/dialog.php'); - }, - - ////////////////////////////////////////////////////////// - // - // Load current settings - // - ////////////////////////////////////////////////////////// - load: function() { - var _this = this; - $.getJSON(this.path+"controller.php?action=load", function(json){ - _this.settings = json || {}; - _this.settings.keys = json.keys || {}; - }); - }, - - ////////////////////////////////////////////////////////// - // - // Set keybindings of settings - // - ////////////////////////////////////////////////////////// - setKeys: function() { - var _this = this; - setTimeout(function(){ - if (codiad.editor.getActive() !== null) { - var manager = codiad.editor.getActive().commands; - //var command; - for (var i = 0; i < _this.settings.keys.length; i++) { - var element = _this.settings.keys[i]; - if (typeof(manager.byName[element.name]) != 'undefined') { - manager.addCommand({ - name: element.name, - bindKey: element.bindKey, - exec: manager.byName[element.name].exec - }); - } - } - } - }, 50); - }, - - ////////////////////////////////////////////////////////// - // - // Open file for expert settings - // - ////////////////////////////////////////////////////////// - edit: function() { - var _this = this; - //Open file and load currrent settings - $.getJSON(this.path+"controller.php?action=open", function(json){ - if (json.status !== "error") { - var opt = { - "indent_size": codiad.editor.settings.tabSize, - "indent_char": " ", - "indent_with_tabs": !codiad.editor.settings.softTabs - }; - _this.content = json.content; - json.content = js_beautify(json.content, opt); - _this.file = json.name; - _this.open = true; - codiad.modal.unload(); - codiad.active.open(json.name, json.content, json.mtime, false, true); - } else { - codiad.message.error(json.message); - } - }); - }, - - ////////////////////////////////////////////////////////// - // - // Save expert settings - // - ////////////////////////////////////////////////////////// - saveExpert: function() { - var _this = this; - var content = codiad.editor.getContent(); - try { - this.settings = JSON.parse(content); - } catch (e) { - codiad.message.error("Error: "+e); - return false; - } - this.save(); - return true; - }, - - ////////////////////////////////////////////////////////// - // - // Save dialog settings - // - ////////////////////////////////////////////////////////// - saveDialog: function() { - var buf = []; - var line; - $('.command_line').each(function(i, item){ - var obj = {"name": "","bindKey": {"win": "","mac": ""}}; - line = $(item).attr("data-line"); - obj.name = $('.command_name[data-line="'+line+'"]').val(); - obj.bindKey.win = $('.command_win[data-line="'+line+'"]').val(); - obj.bindKey.mac = $('.command_mac[data-line="'+line+'"]').val(); - buf.push(obj); - }); - if ($.isArray(this.settings)) { - this.settings = {}; - } - this.settings.keys = buf; - this.save(); - }, - - ////////////////////////////////////////////////////////// - // - // Save current user settings - // - ////////////////////////////////////////////////////////// - save: function() { - var _this = this; - var content = this.settings; - content = JSON.stringify(content); - $.post(this.path+"controller.php?action=save", {"content": content}, function(data){ - var json = JSON.parse(data); - if (json.status !== "error") { - $('li[data-path="'+_this.file+'"]').removeClass('changed'); - _this.load(); - _this.setKeys(); - codiad.message.success(json.message); - } else { - codiad.message.error(json.message); - } - }); - }, - - ////////////////////////////////////////////////////////// - // - // Change save command for expert settings - // - ////////////////////////////////////////////////////////// - addCommands: function() { - if (codiad.editor.getActive() === null) { - return false; - } - var manager = codiad.editor.getActive().commands; - try { - manager.commands.Save.exec = this.$pSave; - this.redo = false; - } catch (e) { - this.redo = true; - } - }, - - ////////////////////////////////////////////////////////// - // - // Restore save command after expert settings - // - ////////////////////////////////////////////////////////// - restoreCommands: function() { - if (codiad.editor.getActive() === null) { - return false; - } - var manager = codiad.editor.getActive().commands; - try { - manager.commands.Save.exec = this.$cSave; - } catch(e) {} - }, - - ////////////////////////////////////////////////////////// - // - // Display commands in dialog - // - ////////////////////////////////////////////////////////// - show: function() { - var _this = this; - $.each(this.settings.keys, function(i, item){ - _this.addEntry(item.name, item.bindKey.win, item.bindKey.mac); - }); - $('#hotkey_div').css('max-height', function(){ - return 0.6*window.innerHeight + "px"; - }); - }, - - ////////////////////////////////////////////////////////// - // - // Add new command - // - // Parameter - // - // name - {String} - Name of command - // win - {String} - Command for win - // mac - {String} - Command for mac - // - ////////////////////////////////////////////////////////// - addEntry: function(name, win, mac) { - var coms = this.getCommands(); - if (coms === false) { - return false; - } - var template = this.template; - var option = ""; - for (var i = 0; i < coms.length; i++) { - if (coms[i].name == name) { - option += ""; - } else { - option += ""; - } - } - template = template.replace("__options__", option); - template = template.replace("__win__", win); - template = template.replace("__mac__", mac); - template = template.replace(new RegExp("__line__", "g"), this.entries++); - $('#hotkey_list').append(template); - this.setDelete(); - }, - - ////////////////////////////////////////////////////////// - // - // Add new empty command - // - ////////////////////////////////////////////////////////// - add: function() { - this.addEntry("","",""); - $('.command_name:last').trigger('change'); - }, - - ////////////////////////////////////////////////////////// - // - // Activate delete button - // - ////////////////////////////////////////////////////////// - setDelete: function(){ - $('.command_remove').click(function(){ - var line = $(this).attr("data-line"); - $('.command_line[data-line="'+line+'"]').remove(); - return false; - }); - }, - - ////////////////////////////////////////////////////////// - // - // Get current commands or a fallback - // - ////////////////////////////////////////////////////////// - getCommands: function() { - var commands; - if (codiad.editor.getActive() === null) { - if (this.commands === null) { - codiad.message.error("Open file to display all commands!"); - return false; - } else { - commands = this.commands; - } - } else { - commands = codiad.editor.getActive().commands.byName; - } - - var buf = []; - $.each(commands, function(i, item){ - buf.push(item); - }); - buf.sort(function(a,b){ - var newBuf = [a.name,b.name]; - if (a === b) { - return 0; - } - newBuf.sort(); - if (newBuf[0] === a.name) { - return -1; - } else { - return 1; - } - }); - return buf; - }, - - ////////////////////////////////////////////////////////// - // - // Display help command - // - ////////////////////////////////////////////////////////// - help: function() { - codiad.modal.load(400, this.path+"dialog.php?action=help"); - }, - - ////////////////////////////////////////////////////////// - // - // Check if command is already used - // - // Parameter - // - // field - {jQuery objcet} - Field to check - // - ////////////////////////////////////////////////////////// - onCommandChange: function(field) { - var type = 'win'; - if ($(field).hasClass('.command_mac')) { - type = 'mac'; - } - var value = $(field).val(); - if (this.commands === null) { - return false; - } - var com; - $.each(this.commands, function(i, item){ - if (typeof(item.bindKey) == 'undefined') { - return; - } - if (typeof(item.bindKey[type]) == 'undefined') { - com = item.bindKey; - } else { - com = item.bindKey[type]; - } - if (value === com) { - codiad.message.notice("Command already used!"); - return false; - } - }); - } - }; -})(this, jQuery);"; \ No newline at end of file diff --git a/data/collaborative/text/68b53024d1449751d6fe0678e5d19a8b b/data/collaborative/text/68b53024d1449751d6fe0678e5d19a8b deleted file mode 100755 index 42efa9c..0000000 --- a/data/collaborative/text/68b53024d1449751d6fe0678e5d19a8b +++ /dev/null @@ -1,7 +0,0 @@ -s:187:"RewriteEngine On -RewriteCond %{REQUEST_FILENAME} !-d -RewriteCond %{REQUEST_FILENAME} !-f -RewriteRule ^([^\.]+)$ $1.php [NC,L] - - -RewriteRule ^teacher-([^/]*).php$ ./teacher?teacher=$1 [L] "; \ No newline at end of file diff --git a/data/collaborative/text/6ebbbc6206dc1a61c67475fee5a974ec b/data/collaborative/text/6ebbbc6206dc1a61c67475fee5a974ec deleted file mode 100755 index 1809f82..0000000 --- a/data/collaborative/text/6ebbbc6206dc1a61c67475fee5a974ec +++ /dev/null @@ -1,69 +0,0 @@ -s:1621:"/* - * Place copyright or other info here... - */ - -(function(global, $){ - - // Define core - var codiad = global.codiad, - scripts= document.getElementsByTagName('script'), - path = scripts[scripts.length-1].src.split('?')[0], - curpath = path.split('/').slice(0, -1).join('/')+'/'; - - // Instantiates plugin - $(function() { - codiad.tela_auto_save.init(); - }); - - codiad.tela_auto_save = { - - // Allows relative `this.path` linkage - path: curpath, - - init: function() { - - // Start your plugin here... - let editor = document.getElementsByClassName( 'ace_content' )[0]; - let auto_save_trigger = setInterval( this.auto_save, 500 ); - }, - - /** - * - * This is where the core functionality goes, any call, references, - * script-loads, etc... - * - */ - - auto_save: function() { - - let tabs = document.getElementsByClassName( "tab-item" ); - let path = codiad.active.getPath(); - let content = codiad.editor.getContent; - tabs = Array.from( tabs ); - tabs.forEach( function( m, i, a ) { - - // M = Current entry - // I = Index as integer - // A = Entire array - - if ( m.classList.contains( "active" ) ) { - - m.classList.remove( "changed" ) - } - }); - - codiad.active.save; - codiad.filemanager.saveFile(path, newContent, localStorage.removeItem(path)); - var session = codiad.active.sessions[path]; - if(typeof session != 'undefined') { - session.untainted = newContent; - session.serverMTime = mtime; - if (session.listThumb) session.listThumb.removeClass('changed'); - if (session.tabThumb) session.tabThumb.removeClass('changed'); - } - } - - }; - -})(this, jQuery); -"; \ No newline at end of file diff --git a/data/collaborative/text/6fade3ab5ef16da4f4f55b5d4a13f71f b/data/collaborative/text/6fade3ab5ef16da4f4f55b5d4a13f71f deleted file mode 100755 index 85c6268..0000000 --- a/data/collaborative/text/6fade3ab5ef16da4f4f55b5d4a13f71f +++ /dev/null @@ -1,174 +0,0 @@ -s:6176:"s:6166:"actives = getJSON('active.php'); - } - - ////////////////////////////////////////////////////////////////// - // List User's Active Files - ////////////////////////////////////////////////////////////////// - - public function ListActive() - { - $active_list = array(); - $tainted = false; - $root = WORKSPACE; - if ($this->actives) { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']==$this->username) { - if ($this->isAbsPath($data['path'])) { - $root = ""; - } else { - $root = $root.'/'; - } - if (file_exists($root.$data['path'])) { - $focused = isset($data['focused']) ? $data['focused'] : false; - $active_list[] = array('path'=>$data['path'], 'focused'=>$focused); - } else { - unset($this->actives[$active]); - $tainted = true; - } - } - } - } - if ($tainted) { - saveJSON('active.php', $this->actives); - } - echo formatJSEND("success", $active_list); - } - - ////////////////////////////////////////////////////////////////// - // Check File - ////////////////////////////////////////////////////////////////// - - public function Check() - { - $cur_users = array(); - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']!=$this->username && $data['path']==$this->path) { - $cur_users[] = $data['username']; - } - } - if (count($cur_users)!=0) { - //echo formatJSEND("error", "Warning: File ".substr($this->path, strrpos($this->path, "/")+1)." Currently Opened By: " . implode(", ", $cur_users)); - } else { - echo formatJSEND("success"); - } - } - - ////////////////////////////////////////////////////////////////// - // Add File - ////////////////////////////////////////////////////////////////// - - public function Add() - { - $process_add = true; - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']==$this->username && $data['path']==$this->path) { - $process_add = false; - } - } - if ($process_add) { - $this->actives[] = array("username"=>$this->username,"path"=>$this->path); - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - } - - ////////////////////////////////////////////////////////////////// - // Rename File - ////////////////////////////////////////////////////////////////// - - public function Rename() - { - $revised_actives = array(); - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username'])) { - $revised_actives[] = array("username"=>$data['username'],"path"=>str_replace($this->path, $this->new_path, $data['path'])); - } - } - saveJSON('active.php', $revised_actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Remove File - ////////////////////////////////////////////////////////////////// - - public function Remove() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username'] && $this->path==$data['path']) { - unset($this->actives[$active]); - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Remove All Files - ////////////////////////////////////////////////////////////////// - - public function RemoveAll() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username']) { - unset($this->actives[$active]); - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Mark File As Focused - // All other files will be marked as non-focused. - ////////////////////////////////////////////////////////////////// - - public function MarkFileAsFocused() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username']) { - $this->actives[$active]['focused']=false; - if ($this->path==$data['path']) { - $this->actives[$active]['focused']=true; - } - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } -} -";"; \ No newline at end of file diff --git a/data/collaborative/text/6ffeaa9f6d5362fa2f15fbf5a6146312 b/data/collaborative/text/6ffeaa9f6d5362fa2f15fbf5a6146312 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/text/6ffeaa9f6d5362fa2f15fbf5a6146312 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/text/729bd3977e9ec2c1b4869d62605d11a5 b/data/collaborative/text/729bd3977e9ec2c1b4869d62605d11a5 deleted file mode 100755 index 53b7f9e..0000000 --- a/data/collaborative/text/729bd3977e9ec2c1b4869d62605d11a5 +++ /dev/null @@ -1,71 +0,0 @@ -s:1728:"open($destination, ZIPARCHIVE::CREATE)) { - return false; - } - - $source = str_replace('\\', '/', realpath($source)); - - if (is_dir($source) === true) - { - $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST); - - foreach ($files as $file) - { - $file = str_replace('\\', '/', $file); - - // Ignore "." and ".." folders - if( in_array(substr($file, strrpos($file, '/')+1), array('.', '..')) ) - continue; - - $file = realpath($file); - - if (is_dir($file) === true) - { - $zip->addEmptyDir(str_replace($source . '/', '', $file . '/')); - } - else if (is_file($file) === true) - { - $zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file)); - } - } - } - else if (is_file($source) === true) - { - $zip->addFromString(basename($source), file_get_contents($source)); - } - - return $zip->close(); -} -Zip('./web2/', './web2.zip'); - -?> - - - - - AA Server - - - -

    This page will eventually have styles and other options.

    -

    Utilities

    - - - Download This
    - -"; \ No newline at end of file diff --git a/data/collaborative/text/74f9d1f373b31e36b320c5a6af2e87ea b/data/collaborative/text/74f9d1f373b31e36b320c5a6af2e87ea deleted file mode 100755 index eb5eab9..0000000 --- a/data/collaborative/text/74f9d1f373b31e36b320c5a6af2e87ea +++ /dev/null @@ -1,34 +0,0 @@ -s:553:"* { - box-sizing: border-box; -} - -html{ - font-size: calc(calc(0.5vh + 0.5vw) + 12px); -} - -html, body { - height: 100%; - width: 100%; - padding: 0; - margin: 0; - overflow: hidden; -} - -.button { - - -webkit-transition-duration: 0.4s; /* Safari */ - background-color: #1f2059; /* PIT Blue */ - border: none; - border-radius: 5px; - box-shadow: 5px 5px 8px #000000; - color: white; - cursor: pointer; - display: inline-block; - font-size: 16px; - margin: 4px 2px; - outline: none; - padding: 15px 32px; - text-align: center; - text-decoration: none; - transition-duration: 0.4s; -}"; \ No newline at end of file diff --git a/data/collaborative/text/76154443d29325fc407486ccf552c592 b/data/collaborative/text/76154443d29325fc407486ccf552c592 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/text/76154443d29325fc407486ccf552c592 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/text/76fba3c99c6a58e95b52ddf307b83ff9 b/data/collaborative/text/76fba3c99c6a58e95b52ddf307b83ff9 deleted file mode 100755 index 9d1d5e8..0000000 --- a/data/collaborative/text/76fba3c99c6a58e95b52ddf307b83ff9 +++ /dev/null @@ -1,27 +0,0 @@ -s:856:"/* - -Created: 2018-07-10 -Modified: N/A -Purpose: Update the MVC - -*/ -/////////////////////////// -c.setToggleTestButton = function(m){ - m.testButtonIn = ! m.testButtonIn -} -c.showToggleTestButton = function(v){ - m.testButtonIn - ? v.testButton.styles(`box-shadow: inset 5px 5px 8px #000000`) - : v.testButton.styles(`box-shadow: 5px 5px 8px #000000`) -} -///////////////////////// -c.updateMetaEvents = function(eventObject){ - m.eventObject = eventObject //the event object itself - m.source = eventObject.target //where the event took place - m.type = eventObject.type //what the event was - m.id = eventObject.target.id //the id of the element where the event occurred - - //Shortcuts to combine similar mobile and computer events - m.pressed = m.type === `mousedown` || m.type === `touchstart` - m.released = m.type === `mouseup` || m.type === `touchend` -}"; \ No newline at end of file diff --git a/data/collaborative/text/7741a9336615cea0064a11037be451c8 b/data/collaborative/text/7741a9336615cea0064a11037be451c8 deleted file mode 100755 index c974307..0000000 --- a/data/collaborative/text/7741a9336615cea0064a11037be451c8 +++ /dev/null @@ -1,55 +0,0 @@ -s:1656:" - */ - -class pages { - - /** - * Program Constants - */ - - const VERSION = '1.0.0'; - - /** - * Unique identifier for your plugin. - * - * - * The variable name is used as the text domain when internationalizing strings - * of text. Its value should match the Text Domain file header in the main - * plugin file. - * - * @var string - */ - protected $plugin_slug = ''; - - /** - * Instance of this class. - */ - protected static $instance = null; - - /** - * Initialize the plugin by setting localization and loading public scripts and styles. - */ - private function __construct() { - - // Trigger initial - $this->init(); - } - - /** - * Return the plugin slug. - * - * @since 1.0.0 - * - * @return Plugin slug variable. - */ - public function get_plugin_slug() { - return $this->plugin_slug; - } - - /** - * Return an instance of this class. - * - * @since 1.0.0 - * - * @return object A single instance of this class. - */ - public static function get_instance() { - // If the single instance hasn't been set, set it now. - if ( null == self::$instance ) { - self::$instance = new self; - } - - return self::$instance; - } - - /** - * Fired for each blog when the plugin is activated. - * - * @since 1.0.0 - */ - private static function install() {} - - /** - * Fired for each blog when the plugin is uninstalled. - * - * @since 1.0.0 - */ - private static function uninstall() {} - - /** - * Load the plugin text domain for translation. - * - * @since 1.0.0 - */ - public function init() {} - - /** - * Register and enqueue public-facing style sheet. - * - * @since 1.0.0 - */ - public static function enqueue_scripts() { - - ?> - - - " rel="stylesheet" /> - - - - - Student Panel - - - - - - - - - - -
    - -
    - -
    - - - - -
    -
    -
    - -
    - - - -

    Error, no quiz was specified

    - - -
    -

    -
    - - - -
    - "; - switch( $question["type"] ) { - - case( "multiple_choice" ): - - foreach( json_decode( $question["answer"] ) as $option ) { - - ?> -
    - - - -
    - -
    - - -
    - - - -
    -

    Welcome ,

    -

    Most recent quizzes:

    -
    - 0 ) { - - while( $row = mysqli_fetch_assoc( $result ) ) { - ?> - - "> -

    -
    - -

    No quizzes currently, you should create one!

    - - -
    -
    - -
    - quizzes here -
    - "; \ No newline at end of file diff --git a/data/collaborative/text/8e024f4aac60a8331a03d54b83e75bf7 b/data/collaborative/text/8e024f4aac60a8331a03d54b83e75bf7 deleted file mode 100755 index 659594c..0000000 --- a/data/collaborative/text/8e024f4aac60a8331a03d54b83e75bf7 +++ /dev/null @@ -1,576 +0,0 @@ -s:22926:"/** - Author: Abbas Abdulmalik - Created: ~ May, 2017 - Revised: June 9, 2018 - Original Filename: L.js - Purpose: a small (but growing) personal re-usable js library for a simple MVC architecture - Notes: Now qualifyFunction helper doesn't return true for empty arrays (no vacuous truth) - - Added UploadFiles: - uploadFiles takes a callback -- progressReporter-- as it FIRST argument (parameter) - to allow for an optional fourth parameter of an upload path for the server. - progressReporter will be passed three arguments when called: - 1.) the amount of bytes uploaded so far - 2.) the total size of the file in bytes - 3.) the index of the file in the "array" of files being uploaded - - Added sortByExtension that alphabetizes an array of strings 'in place' by filename extension - Added arrayStringMatch that matches a collection of string arrays to a search string. - later (6-9-2018) included an option for a "maximum array index" to eliminate - searching irrelevant fields at the end of the array, such as image name and primary key. - Added loopCall as a 'better' version of setInterval - Removed L.attributes. It's a reserved word: an object belonging to DOM elements - Now it uses L.attribs - Added L.loopCall.stop() so that user can easily stop L.loopCall - Added L.symDiff for comparing arrays to determine their symmetric difference = conjunctive union = - exclusive-or - Restored an updated version of uploadFiles that signals the final file has uploaded - Added secToMinSec - Added runQualifiedFunctions that mirrors runQualifiedMethods using different parameters, - namely: functionQualifiers, model, view, controller - Added attachNewElement(tagname, id, view). Create new element, gives it an id and - attaches it to object provided: - L.attachNewElement(`div`, `picHolder`, view) - Added createListMixer and scrammbleThis, which depends on createListMixer - Added sortArrayOfStringArrays, with option of using a "link token" of choice as the 3rd argument - Added an optional argument for arrayStringMatch for a maximum array index - to eliminate searching irrelevant fields at the end of the array, - such as image name and primary key -*/ - -var L = {} -L.styles = function(styleString){ - const colonPosition = styleString.indexOf(':') - const property = styleString.slice(0, colonPosition) - const value = styleString.slice(colonPosition + 1) - this.style[property] = value - - return this.styles -} - -L.attribs = function(attributeString){ - const assignmentPosition = attributeString.indexOf('=') - const attribute = attributeString.slice(0, assignmentPosition) - const value = attributeString.slice(assignmentPosition + 1) - this.setAttribute(attribute, value) - - return this.attribs -} - -L.attachAllElementsById = function(here){ - let allElements = document.getElementsByTagName('*') - let array = [] - array.forEach.call(allElements, function(element) { - if(element.id){ - here[element.id] = element - element.styles = L.styles.bind(element) // attach L's styles() method here - element.attribs = L.attribs.bind(element) // attach L's attribs() method here - } - }) -} -///////////////| START of L.attachNewElement |///////////// -/** - L.attachNewElement(string tagname, string id, object view) ... - ... creates a new element of type "tagname" given as the first argument, - and gives it the id "id" given as the second argument. - The third argument is the view object where this new reference will be attached. - The element can then be referenced as view.id. -*/ -L.attachNewElement = function(tagname, id, view){ - if(arguments.length !== 3){ - console.log(`Error: requires 3 arguments: tagname, id, view`) - return - } - try{ - if(typeof tagname === `string`){ - var newElement = document.createElement(tagname) - } - else{ - console.log(`Error: tagname needs to be a string`) - return - } - if(typeof id === `string`){ - newElement.id = id - } - else{ - console.log(`Error: id needs to be a string`) - return - } - if(view.toString() === `[object Object]`){ - view[newElement.id] = newElement - newElement.styles = L.styles.bind(newElement) // attach L's styles() method here - newElement.attribs = L.attribs.bind(newElement) // attach L's attribs() method here - return newElement - } - else{ - console.log(`Error: view needs to be an object`) - return - } - } - catch(e){ - console.log(`Error in L.attachNewElement: ${e}`) - return - } -} -///////////////| END of L.attachNewElement |///////////// - -L.noPinchZoom = function(){ - window.ontouchstart = function(eventObject){ - if(eventObject.touches && eventObject.touches.length > 1){ - eventObject.preventDefault(); - } - } -} - -L.runQualifiedMethods = function(functionQualifiers, object, runNextUpdate){ - Object - .keys(functionQualifiers) - .filter(qualifyFunction) - .forEach(runFunction) - if(typeof runNextUpdate === 'function'){runNextUpdate()} - - //-----| helpers |-----// - function qualifyFunction(functionName){ - const isQualified = functionQualifiers[functionName].every( qualifier => qualifier) && - !!functionQualifiers[functionName].length - return isQualified - } - function runFunction(functionName){ - if(typeof object[functionName] === 'function'){ - object[functionName]() - } - - /** - If the prefix of this function's name is 'set' (for updating the MODEL), - and there is a similarly named function with a prefix of 'show' (for updating the VIEW), - then run the 'show' version as well. - */ - let prefix = functionName.slice(0,3) - let newFunctionName = 'show' + functionName.slice(3) - - if(prefix === 'set' && typeof object[newFunctionName] === 'function'){ - object[newFunctionName]() - } - } -} - -L.runQualifiedFunctions = function(functionQualifiers, model, view, controller){ - Object - .keys(functionQualifiers) - .filter(qualifyFunction) - .forEach(runFunction) - //-----| helpers |-----// - function qualifyFunction(functionName){ - const isQualified = functionQualifiers[functionName].every( qualifier => qualifier) && - !!functionQualifiers[functionName].length - return isQualified - } - function runFunction(functionName){ - if(typeof controller[functionName] === 'function'){ - controller[functionName](model) - } - /** - If the prefix of this function's name is 'set' (for updating the MODEL), - and there is a similarly named function with a prefix of 'show' (for updating the VIEW), - then run the 'show' version as well. - */ - let prefix = functionName.slice(0,3) - let newFunctionName = 'show' + functionName.slice(3) - if(prefix === 'set' && typeof controller[newFunctionName] === 'function'){ - controller[newFunctionName](view) - } - } -} -/** - Use a php script that reads contents of file from $_POST['contents'] that was convert by client - as DataURL, and expects filename and uploadPath from: $_POST['filename'] and $_POST['uploadPath'] - with trailing slash (/) provided by client (though script could check for this). -*/ -L.uploadFiles = function(progressReporter, fileElement, phpScriptName, uploadPath='../uploads/'){ - let doneCounter = 0 - let fileCount = fileElement.files.length - const array = [] // make a real array to borrow it's forEach method - array.forEach.call(fileElement.files, (file, index) => { - const postman = new XMLHttpRequest() // make a file deliverer for each file - const uploadObject = postman.upload // This object keeps track of upload progress - const envelope = new FormData() // make a holder for the file's name and content - envelope.stuff = envelope.append // give 'append' the nickname 'stuff' - const reader = new FileReader() // make a file reader (the raw file element is useless) - - reader.readAsDataURL(file) // process the file's contents - reader.onload = function(){ // when done ... - const contents = reader.result // collect the result, and ... - envelope.stuff('contents', contents) // place it in the envelope along with ... - envelope.stuff('filename', file.name) // its filename ... - envelope.stuff('uploadPath', uploadPath) // and its upload path on the server - - postman.open(`POST`, phpScriptName)// open up a POST to the server's php script - postman.send(envelope) // send the file - - //check when file loads and when there is an error - postman.onload = eventObject => { - postman.status !== 200 ? showMessage() : checkLastFileDone() - //-----| helper |------// - function showMessage(){ - const message = `Trouble with file: ${postman.status}` - console.log(message) - alert(message) - } - function checkLastFileDone(){ - doneCounter++ - if(typeof progressReporter === 'function'){ - if(doneCounter === fileCount){ - progressReporter(1, 1, index) - } - } - } - } - - postman.onerror = eventObject => { - const message = `Trouble connecting to server` - console.log(message) - alert(message) - } - - //invoke the callback for each upload progress report - uploadObject.onprogress = function(progressObject){ - if(typeof progressReporter === 'function'){ - progressReporter(progressObject.loaded, progressObject.total, index) - } - } - } - }) -} - -//---------------------------------------------------------// -/** - Given an array of strings (array), sorts the array 'in place' by filename EXTENSION, - and returns a copy of the array as well. Since it mutates the array, it is decidedly not - functionistic (but it functions). -*/ -L.sortByExtension = function (array) { - const type = {}.toString.call(array, null); - if (type !== '[object Array]') { - return array; - } - if (array.length === 0 || array.some(member => typeof member !== 'string')) { - return array; - } - //-------------------------------------// - let extension = ``; - let nudeWord = ``; - array.forEach((m, i, a) => { - if (m.lastIndexOf(`.`) !== -1) { - //get the extension - extension = m.slice(m.lastIndexOf(`.`) + 1); - nudeWord = m.slice(0, m.lastIndexOf(`.`)); - a[i] = `${extension}.${nudeWord}`; - } - }); - - array.sort(); - - array.forEach((m, i, a) => { - if (m.indexOf(`.`) !== -1){ - //get prefix (formerly the extension) - extension = m.slice(0, m.indexOf(`.`)) - nudeWord = m.slice(m.indexOf(`.`) + 1) - a[i] = `${nudeWord}.${extension}` - } - }); - - const newArray = [] - array.forEach( m => newArray.push(m)) - - return newArray; -} - -/** -From an array of string arrays, return a possibly smaller array -of only those string arrays whose member strings contain the given subString -regardless of case. - 1. For arrayOfStringArrays, use the filter method (a function property of an array) - that expects a function argument that operates on each array member - 2. Let's call the function argument 'match' - 3. 'match' should test each member array for a match of the substring as follows: - a.) join the members strings together into a bigString that is lowerCased - b.) lowerCase the subString - c.) use indexOf to match substring to the bigString - d.) return true for a match, otherwise return false - 4. the filter creates a new array after doing this. - 5. final step: return the new array that the filter produced -*/ -L.arrayStringMatch = function(subString, arrayOfStringArrays, maxIndex){ - //============================================================// - return arrayOfStringArrays.filter(match) - //-------| Helper function 'match' |---------// - function match(memberArray){ - //on 6-9-2018, added option of maximum index to eliminate searching through irrelevant fields - let bigString = '' - if(maxIndex && typeof maxIndex === "number" && maxIndex > 0){ - bigString = memberArray - .filter((m,i) => i <= maxIndex) - .join(` `) - .toLowerCase() - } - else{ - bigString = memberArray.join(` `).toLowerCase() - } - const substringToMatch = subString.toLowerCase() - return bigString.indexOf(substringToMatch) !== -1 - } -} -//-------------------------------------------------// - -/** - L.loopCall can be used to replace setInterval, which has been somewhat discredited. - See this blog post: - https://dev.to/akanksha_9560/why-not-to-use-setinterval--2na9 - - L.loopCall uses setTimeout recursively, which is a technique - reportedly more reliabale than setInterval. - - L.loopCall repeatedly calls (invokes) the callback function provided as its first argument. - The first call is immediate, but subsequent calls are delayed by the milliseconds - provided as the second argument. All additional arguments are optional - to be used by the callback if required. - - If needed, you can delay the initial call as well, - by having loopCall invoked by setTimeout using the same delay: - - setTimeout(L.loopCall, delay, callback, delay, arg1, arg2 ...) - - or the more readable, but more risky ... - - setTimeout("L.loopCall(callback, delay, arg1, arg2 ...)", delay) - //Doug Crockford would not be pleased - - To stop the loop, the callback function can test some external state condition, - (or test its own arguments, if they are passed by reference): - - if(externalStateCondition){ - L.loopCall.stop() - } -*/ -L.loopCall = function (callback, delay, ...args){ - L.loopCall.stopLoop = setTimeout(L.loopCall, delay, callback, delay, ...args) - callback(...args) -} - -L.loopCall.stop = () => { - clearTimeout(L.loopCall.stopLoop) -} - -/** - Returns an array that is the "mathematical or logical" symmetric difference among or between - any number of arrays provided as arguments (usually two). If the order of members is ignored - (as is done for mathematical sets), the result acts as the the exclusive-or (XOR), also know as - the disjunctive union. For the trivial cases of comparing one or two arrays, the result is - not surprising: for one array, the result is itself: L.symDiff(A, []) => A ⊕ [] = A. - For two arrays, the result is an array that has only members which are not shared in common: - L.symDiff(A, B) => A ⊕ B . - When comparing more than two arrays, the result may ne surprising. The proper result can be verified - by comparing only two at a time: L.symDiff(A, B, C) => A ⊕ B ⊕ C = (A ⊕ B) ⊕ C -*/ -L.symDiff = function symDiff(arrayA, arrayB){ // dummy paramters NOT referenced in body of the function - var partialSymDiff = [], - argsArray = arguments - ; - //============THE CRUX================= - return findSymDiff(partialSymDiff,0); - //============UNDER THE HOOD=========== - function findSymDiff(partialSymDiff,index){ - if (argsArray[index] === undefined){ - return partialSymDiff; - } - else{ - partialSymDiff = sd(partialSymDiff, argsArray[index] ); - return findSymDiff( partialSymDiff, index + 1 ); - } - } - //===================================== - function sd(arrayI, arrayJ){ - var diff = [], - blackList = [], - i = 0, - j = 0, - maxI = arrayI.length, - maxJ = arrayJ.length - ; - //------------------------------------------------- - //1.) Combine the arrays into a third array. - //2.) Find the matched elements and place them into a blacklist array. - //3.) Pull blacklisted elements from the combined array. - //4.) return the "reduced" combined array. - //--------------------------------------------------- - // 1.) Combine the arrays into a third array. - diff = arrayI.concat(arrayJ); - //--------------------------------------------------- - // 2.) Find the matched elements and place them into a blacklist array. - for ( i=0; i < maxI; i++ ){ - for( j=0; j< maxJ; j++ ){ - if(arrayI[i] === arrayJ[j]){ - blackList.push(arrayI[i] ); - } - } - } - //---------------------------------------------------- - // 3.) Pull blacklisted elements from the combined array. - diff = diff.filter( (element) => blackList.indexOf(element) === -1 ) - //---------------------------------------------------- - // 4.) return the "reduced" combined array. - return killDupes(diff); - } - //======================================================== - function killDupes(array){ - var kept = []; // Record of the "keepers" - return array.filter(function(element){ - if ( kept.indexOf(element) === -1 ){ //if not already retained ... - kept.push(element); // Record it as retained now, and... - return true; // allow this element to be kept (true) - } - else{ - return false; // otherwise, don't keep it (already kept) - } - }); - } -}; - -/** - * Pass in a numerical seconds: it returns a string in the format - * mm : ss, like ... - * 35 : 37 in minutes and seconds -*/ -L.secToMinSec = (seconds) =>{ - var min = Math.floor(seconds / 60); - var sec = Math.floor(seconds % 60); - if(isNaN(min)){min = 0} - if(isNaN(sec)){sec = 0} - var zeroMin = ((min < 10) ? ("0" + min) : ("" + min)); - var zeroSec = ((sec < 10) ? ("0" + sec) : ("" + sec)); - var minSec = zeroMin + ":" + zeroSec; - return minSec; -}; -//====| END of secToMinSec |====// - -///////////////////| START of CreateListMixer |////////////////////// -/** - * CreateListMixer: a factory that creates and returns a function that - * returns a random item from the collection (array or object) provided. - * Notes: Example-> var list = ["a", "short", "list"];//three (3) items to test - * var getRandomItem = CreateListMixer(); - * getRandomItem(list);//returns first of randomized list - * getRandomItem();//returns next item - * getRandomItem();//returns next item (last of three) - * getRandomItem();//new first item from re-randomized list - * - * // a new list; - * var list2 = { record1: "string", record2: "anotherString", ...}; - * getRandomItem(list2);//returns first of new randomized list2 - * getRandomItem();//etc. - * It returns a property name for objects or an array member for arrays; - * It returns 'false' if argument of function is not an object - * or an array (fails typeof arg === 'object') - * -*/ -L.CreateListMixer = function(){ - var list=[], - randList= [], - listLength= 0, - itemReturned= null, - itemReturnedIndex= -1 - ; - return function(){ - if(arguments[0]){ - if(typeof arguments[0] === 'object'){ - list = arguments[0]; - if({}.toString.call(arguments[0]) === '[object Object]'){ - list = Object.keys(list); - } - randList = randomize(list); - listLength = list.length; - } - else{ - return false; - } - } - //----| no args activity: return next random item |---- - if(itemReturnedIndex >= listLength-1){ - do{ - randList = randomize(list); - itemReturnedIndex = -1; - } - while(randList[itemReturnedIndex +1] === itemReturned); - } - itemReturnedIndex++; - itemReturned = randList[itemReturnedIndex]; - return itemReturned; - //-----helpers----- - function randomize(x){ - var mixedIndexes = []; - var randomList = []; - randomizeIndexes(); - return randomList; - //----sub helper---- - function randomizeIndexes(){ - // random numbers for mixedIndexes - while(mixedIndexes.length !== x.length){ - var match = false; - var possibleIndex = (x.length)*Math.random(); - possibleIndex = Math.floor(possibleIndex); - mixedIndexes.forEach(function(m){ - if(m === possibleIndex){ - match = true; - } - }); - if(!match){ - mixedIndexes.push(possibleIndex); - } - } - for(var i = 0; i < x.length; i++){ - var newIndex = mixedIndexes[i]; - randomList.push(list[newIndex]); - } - } - } - };//===| END returned function |====== -}//===| END enclosing factory function====== -///////////////////| END of CreateListMixer |////////////////////// - -///////////////////| START of scrammbleThis |////////////////////// -/** - scrammbleThis: (depends on createListMixer, above) - It returns an array of randomly arranged items of the collection provided. - The argument must be an array, an object, or a string. - If the argument is an object, a random array of its property names is returned. - If the argument is a string, a random array of its characters is returned. - If the argument is an array, a random array of its members is returned. -*/ -L.scrammbleThis = function(collection){ - if ( !(typeof collection === 'object' || typeof collection === 'string') ){return collection} - var mix = L.CreateListMixer(); - var list = (Object.prototype.toString.call(collection) === '[object Array]') - ? collection - : (typeof collection === 'string') - ? collection.split('') - : (typeof collection === 'object') - ? Object.keys(collection) - : null - return list.map((m,i,a)=> (i === 0) ? mix(a) : mix()) -} -///////////////////| END of scrammbleThis |////////////////////// - -/** - Given an array of string arrays, this function returns an alphabetized version -*/ -L.sortArrayOfStringArrays = function(arrayOfStringArrays, linkToken='```'){ - //use a unique token (default = triple back-ticks ```) to join the strings of each array of strings - const arrayOfStrings = arrayOfStringArrays.map(stringArray => stringArray.join(linkToken)) - - //case-insensitive sort this array of strings, mutating it in place: - //https://stackoverflow.com/questions/8996963/how-to-perform-case-insensitive-sorting-in-javascript - arrayOfStrings.sort( (a,b) => a.toLowerCase().localeCompare(b.toLowerCase()) ) - - //return a new array of string arrays after splitting the strings on the unique token - return arrayOfStrings.map( string => string.split(linkToken)) -}"; \ No newline at end of file diff --git a/data/collaborative/text/91f54b2685411e1ea2b454be94a4b7f8 b/data/collaborative/text/91f54b2685411e1ea2b454be94a4b7f8 deleted file mode 100755 index 0120813..0000000 --- a/data/collaborative/text/91f54b2685411e1ea2b454be94a4b7f8 +++ /dev/null @@ -1,174 +0,0 @@ -s:6166:"actives = getJSON('active.php'); - } - - ////////////////////////////////////////////////////////////////// - // List User's Active Files - ////////////////////////////////////////////////////////////////// - - public function ListActive() - { - $active_list = array(); - $tainted = false; - $root = WORKSPACE; - if ($this->actives) { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']==$this->username) { - if ($this->isAbsPath($data['path'])) { - $root = ""; - } else { - $root = $root.'/'; - } - if (file_exists($root.$data['path'])) { - $focused = isset($data['focused']) ? $data['focused'] : false; - $active_list[] = array('path'=>$data['path'], 'focused'=>$focused); - } else { - unset($this->actives[$active]); - $tainted = true; - } - } - } - } - if ($tainted) { - saveJSON('active.php', $this->actives); - } - echo formatJSEND("success", $active_list); - } - - ////////////////////////////////////////////////////////////////// - // Check File - ////////////////////////////////////////////////////////////////// - - public function Check() - { - $cur_users = array(); - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']!=$this->username && $data['path']==$this->path) { - $cur_users[] = $data['username']; - } - } - if (count($cur_users)!=0) { - //echo formatJSEND("error", "Warning: File ".substr($this->path, strrpos($this->path, "/")+1)." Currently Opened By: " . implode(", ", $cur_users)); - } else { - echo formatJSEND("success"); - } - } - - ////////////////////////////////////////////////////////////////// - // Add File - ////////////////////////////////////////////////////////////////// - - public function Add() - { - $process_add = true; - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']==$this->username && $data['path']==$this->path) { - $process_add = false; - } - } - if ($process_add) { - $this->actives[] = array("username"=>$this->username,"path"=>$this->path); - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - } - - ////////////////////////////////////////////////////////////////// - // Rename File - ////////////////////////////////////////////////////////////////// - - public function Rename() - { - $revised_actives = array(); - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username'])) { - $revised_actives[] = array("username"=>$data['username'],"path"=>str_replace($this->path, $this->new_path, $data['path'])); - } - } - saveJSON('active.php', $revised_actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Remove File - ////////////////////////////////////////////////////////////////// - - public function Remove() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username'] && $this->path==$data['path']) { - unset($this->actives[$active]); - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Remove All Files - ////////////////////////////////////////////////////////////////// - - public function RemoveAll() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username']) { - unset($this->actives[$active]); - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Mark File As Focused - // All other files will be marked as non-focused. - ////////////////////////////////////////////////////////////////// - - public function MarkFileAsFocused() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username']) { - $this->actives[$active]['focused']=false; - if ($this->path==$data['path']) { - $this->actives[$active]['focused']=true; - } - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } -} -"; \ No newline at end of file diff --git a/data/collaborative/text/973f750ac61e200c9a6566c6f4f0ada4 b/data/collaborative/text/973f750ac61e200c9a6566c6f4f0ada4 deleted file mode 100755 index a98c1ee..0000000 --- a/data/collaborative/text/973f750ac61e200c9a6566c6f4f0ada4 +++ /dev/null @@ -1,66 +0,0 @@ -s:3098:" - -
    - - Check(), true); - ?> -
    - - - -
    - - -
    - -
    -
    - -

    - - . - - -

    - -
    '.get_i18n("Download Codiad").' '; - } - ?> - - -"; \ No newline at end of file diff --git a/data/collaborative/text/9cf1e9203224be47c3ba9e5308987882 b/data/collaborative/text/9cf1e9203224be47c3ba9e5308987882 deleted file mode 100755 index 0df5794..0000000 --- a/data/collaborative/text/9cf1e9203224be47c3ba9e5308987882 +++ /dev/null @@ -1,39 +0,0 @@ -s:675:"html, body { - height: 100%; - margin: 0px; -} - -body { - background-color: #dfdfdf; - width: 100%; -} - -.button { - -webkit-transition-duration: 0.4s; /* Safari */ - background-color: lightblue;/*#1f2059; PIT Blue */ - border: none; - border-radius: 5px; - box-shadow: 5px 5px 10px rgba(0,0,0,1); - color: white; - cursor: pointer; - display: inline-block; - font-size: 16px; - margin: 4px 2px; - padding: 15px 32px; - text-align: center; - text-decoration: none; - transition-duration: 0.4s; -} - - -#firstButton{ - display: inline-block; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - color: black; - outline: none; - font-weight: bold; - text-shadow: 0 1px 0 white; -}"; \ No newline at end of file diff --git a/data/collaborative/text/a64c3a506cee116b66128f9fabd92174 b/data/collaborative/text/a64c3a506cee116b66128f9fabd92174 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/text/a64c3a506cee116b66128f9fabd92174 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/text/a9a0fb5543ed2953ba292d5f62bf6ae8 b/data/collaborative/text/a9a0fb5543ed2953ba292d5f62bf6ae8 deleted file mode 100755 index 0120813..0000000 --- a/data/collaborative/text/a9a0fb5543ed2953ba292d5f62bf6ae8 +++ /dev/null @@ -1,174 +0,0 @@ -s:6166:"actives = getJSON('active.php'); - } - - ////////////////////////////////////////////////////////////////// - // List User's Active Files - ////////////////////////////////////////////////////////////////// - - public function ListActive() - { - $active_list = array(); - $tainted = false; - $root = WORKSPACE; - if ($this->actives) { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']==$this->username) { - if ($this->isAbsPath($data['path'])) { - $root = ""; - } else { - $root = $root.'/'; - } - if (file_exists($root.$data['path'])) { - $focused = isset($data['focused']) ? $data['focused'] : false; - $active_list[] = array('path'=>$data['path'], 'focused'=>$focused); - } else { - unset($this->actives[$active]); - $tainted = true; - } - } - } - } - if ($tainted) { - saveJSON('active.php', $this->actives); - } - echo formatJSEND("success", $active_list); - } - - ////////////////////////////////////////////////////////////////// - // Check File - ////////////////////////////////////////////////////////////////// - - public function Check() - { - $cur_users = array(); - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']!=$this->username && $data['path']==$this->path) { - $cur_users[] = $data['username']; - } - } - if (count($cur_users)!=0) { - //echo formatJSEND("error", "Warning: File ".substr($this->path, strrpos($this->path, "/")+1)." Currently Opened By: " . implode(", ", $cur_users)); - } else { - echo formatJSEND("success"); - } - } - - ////////////////////////////////////////////////////////////////// - // Add File - ////////////////////////////////////////////////////////////////// - - public function Add() - { - $process_add = true; - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $data['username']==$this->username && $data['path']==$this->path) { - $process_add = false; - } - } - if ($process_add) { - $this->actives[] = array("username"=>$this->username,"path"=>$this->path); - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - } - - ////////////////////////////////////////////////////////////////// - // Rename File - ////////////////////////////////////////////////////////////////// - - public function Rename() - { - $revised_actives = array(); - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username'])) { - $revised_actives[] = array("username"=>$data['username'],"path"=>str_replace($this->path, $this->new_path, $data['path'])); - } - } - saveJSON('active.php', $revised_actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Remove File - ////////////////////////////////////////////////////////////////// - - public function Remove() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username'] && $this->path==$data['path']) { - unset($this->actives[$active]); - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Remove All Files - ////////////////////////////////////////////////////////////////// - - public function RemoveAll() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username']) { - unset($this->actives[$active]); - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } - - ////////////////////////////////////////////////////////////////// - // Mark File As Focused - // All other files will be marked as non-focused. - ////////////////////////////////////////////////////////////////// - - public function MarkFileAsFocused() - { - foreach ($this->actives as $active => $data) { - if (is_array($data) && isset($data['username']) && $this->username==$data['username']) { - $this->actives[$active]['focused']=false; - if ($this->path==$data['path']) { - $this->actives[$active]['focused']=true; - } - } - } - saveJSON('active.php', $this->actives); - echo formatJSEND("success"); - } -} -"; \ No newline at end of file diff --git a/data/collaborative/text/afeec27bbb5ab15bae2cb560b3e7406d b/data/collaborative/text/afeec27bbb5ab15bae2cb560b3e7406d deleted file mode 100755 index 6562584..0000000 --- a/data/collaborative/text/afeec27bbb5ab15bae2cb560b3e7406d +++ /dev/null @@ -1,20 +0,0 @@ -s:441:""; \ No newline at end of file diff --git a/data/collaborative/text/b31c91140e129d845f56a9d887d718af b/data/collaborative/text/b31c91140e129d845f56a9d887d718af deleted file mode 100755 index 2a20dc3..0000000 --- a/data/collaborative/text/b31c91140e129d845f56a9d887d718af +++ /dev/null @@ -1,3 +0,0 @@ -s:7:"hello - -"; \ No newline at end of file diff --git a/data/collaborative/text/b4590e9cec70e9718018bc7905fc6c2d b/data/collaborative/text/b4590e9cec70e9718018bc7905fc6c2d deleted file mode 100755 index b61100b..0000000 --- a/data/collaborative/text/b4590e9cec70e9718018bc7905fc6c2d +++ /dev/null @@ -1,195 +0,0 @@ -s:5841:""; - saveFile($file, $data); -} - -function encryptPassword($p) -{ - return sha1(md5($p)); -} - -function cleanUsername($username) -{ - return preg_replace('#[^A-Za-z0-9'.preg_quote('-_@. ').']#', '', $username); -} - -function isAbsPath($path) -{ - return $path[0] === '/'; -} - -function cleanPath($path) -{ - - // prevent Poison Null Byte injections - $path = str_replace(chr(0), '', $path); - - // prevent go out of the workspace - while (strpos($path, '../') !== false) { - $path = str_replace('../', '', $path); - } - - return $path; -} - -////////////////////////////////////////////////////////////////////// -// Verify no overwrites -////////////////////////////////////////////////////////////////////// - -if (!file_exists($users) && !file_exists($projects) && !file_exists($active)) { - ////////////////////////////////////////////////////////////////// - // Get POST responses - ////////////////////////////////////////////////////////////////// - - $username = cleanUsername($_POST['username']); - $password = encryptPassword($_POST['password']); - $project_name = $_POST['project_name']; - if (isset($_POST['project_path'])) { - $project_path = $_POST['project_path']; - } else { - $project_path = $project_name; - } - $timezone = $_POST['timezone']; - - ////////////////////////////////////////////////////////////////// - // Create Projects files - ////////////////////////////////////////////////////////////////// - - $project_path = cleanPath($project_path); - - if (!isAbsPath($project_path)) { - $project_path = str_replace(" ", "_", preg_replace('/[^\w-\.]/', '', $project_path)); - mkdir($workspace . "/" . $project_path); - } else { - $project_path = cleanPath($project_path); - if (substr($project_path, -1) == '/') { - $project_path = substr($project_path, 0, strlen($project_path)-1); - } - if (!file_exists($project_path)) { - if (!mkdir($project_path.'/', 0755, true)) { - die("Unable to create Absolute Path"); - } - } else { - if (!is_writable($project_path) || !is_readable($project_path)) { - die("No Read/Write Permission"); - } - } - } - $project_data = array("name"=>$project_name,"path"=>$project_path); - - saveJSON($projects, array($project_data)); - - ////////////////////////////////////////////////////////////////// - // Create Users file - ////////////////////////////////////////////////////////////////// - - $user_data = array("username"=>$username,"password"=>$password,"project"=>$project_path); - - saveJSON($users, array($user_data)); - - ////////////////////////////////////////////////////////////////// - // Create Active file - ////////////////////////////////////////////////////////////////// - - saveJSON($active, array('')); - - ////////////////////////////////////////////////////////////////// - // Create Config - ////////////////////////////////////////////////////////////////// - - - $config_data = '{ - v.txtSearch.value = '' //clear the search text - c.setSearchResult(m) -} -c.showClearSearch = (v)=>{ - c.showSearchResult(v) -} -//////////////////////////// -c.setSearchResult = function(m){ - if(m.nowEditing){return} // !m.nowEditing is now set as a function qualifier - m.handlingSearch = true - m.searchIsEmpty = v.txtSearch.value === '' - if(m.currentContactsArray[m.selectedIndex]){ - m.priorName = m.currentContactsArray[m.selectedIndex][0]+m.currentContactsArray[m.selectedIndex][1] - } - m.sameContact = false - - //get result of search and place in - //m.currentCurrentContactsArray - const subString = v.txtSearch.value.trim(); - const list = m.arrayOfContactArrays - //restrict search to only fields 0 -> 4: This eliminates searching image name and primary key - m.currentContactsArray = L.arrayStringMatch(subString, list, 4) - if(m.currentContactsArray[0]){ - m.currentTopSearchName = m.currentContactsArray[0][0]+m.currentContactsArray[0][1] - } - m.sameContact = m.currentTopSearchName === m.priorName -} -c.showSearchResult = function(v){ - if(m.nowEditing){return} - console.log(m.currentContactsArray) - c.fillSelector(m.currentContactsArray) - c.setContactDisplay(m) - c.showContactDisplay(v) - c.showMailPhoneTouched(v) - if(m.searchIsEmpty){ - Array.from(document.querySelectorAll('.endcap')).forEach(endcap => endcap.styles('visibility: hidden')('opacity: 0')) - } - else{ - Array.from(document.querySelectorAll('.endcap')).forEach(endcap => endcap.styles('visibility: visible')('opacity: 0.55')) - v.matchCount.innerText = m.currentContactsArray.length - v.matchIndex.innerText = m.selectedIndex + 1 || 0 - } -} - -/////////////////////////// -c.setPulseNextButton = (m)=>{ - m.nextButtonIsPressed = true - m.currentDirection = `next` -} -c.showPulseNextButton = ({btnNext})=>{ - if(m.nextButtonIsPressed){ - btnNext.attribs('class=pressed button') - selectNextContact() - c.showMailPhoneTouched(v) - v.matchIndex.innerText = m.selectedIndex + 1 || 0 - } - ///////| helper |/////// - function selectNextContact(){ - if(notTooFarAhead()){ - moveForward() - } - else{ - selectFirstContact() - } - ///////| 2nd level helpers |////// - function notTooFarAhead(){ - let notTooFar = false - let indexTooFar = v.contactSelector.length - let currentIndex = v.contactSelector.selectedIndex - //set to true if next index < size of current Array - notTooFar = (currentIndex + 1) < indexTooFar - // otherwise its false that it's notTooFar ahead - return notTooFar - } - function moveForward(){ - //increment selected index of current array - ++v.contactSelector.selectedIndex - c.setContactDisplay(m) - c.showContactDisplay(v) - } - function selectFirstContact(){ - //set selected index of current array to 0 - v.contactSelector.selectedIndex = 0 - c.setContactDisplay(m) - c.showContactDisplay(v) - } - } - setTimeout(()=>{ - btnNext.attribs('class=released button') - m.buttonIsPressed = false - },100) -} -/////////////////////////////////// -c.setPulseBackButton = (m)=>{ - m.backButtonIsPressed = true - m.currentDirection = `back` -} -c.showPulseBackButton = ({btnBack})=>{ - if(m.backButtonIsPressed){ - btnBack.attribs('class=pressed button') - selectPriorContact() - c.showMailPhoneTouched(v) - v.matchIndex.innerText = m.selectedIndex + 1 || 0 - } - ///////| helper |///////// - function selectPriorContact(){ - if(notTooFarBack()){ - moveBack() - } - else{ - selectLastContact() - } - } - ///////| 2nd level helpers |////// - function notTooFarBack(){ - let notTooFar = false - let currentIndex = v.contactSelector.selectedIndex - //set to true if next index >= 0 - notTooFar = (currentIndex - 1) >= 0 - // otherwise its false that it's notTooFar ahead - return notTooFar - } - function moveBack(){ - //increment selected index of current array - v.contactSelector.selectedIndex -= 1 - c.setContactDisplay(m) - c.showContactDisplay(v) - } - function selectLastContact(){ - //set selected index of current array to 0 - v.contactSelector.selectedIndex = v.contactSelector.length - 1 - c.setContactDisplay(m) - c.showContactDisplay(v) - } - setTimeout(()=>{ - btnBack.attribs('class=released button') - m.buttonIsPressed = false - },100) -} -/////////////////////////////////// -c.setFooterActive = (m)=>{ - m.footerActive = !m.footerActive -} -c.showFooterActive = ({app, footerGlass})=>{ - m.footerActive - ? footerGlass.styles(`background: linear-gradient(-20deg, transparent, pink, transparent, pink, transparent)`) - : footerGlass.styles(`background: transparent`) -} -/////////////////////////////// -c.setIconClicked = (m)=>{ - m.source === v.phoneIcon - ? m.action = 'calling' - : m.source === v.mailIcon - ? m.action = 'mailing' - : m.action = 'none' -} -c.showIconClicked = ({contactSelector})=>{ - let i = contactSelector.selectedIndex - let contact = m.currentContactsArray[i] - m.action === 'mailing' - ? sendMail() - : m.action === 'calling' - ? makeCall() - : null - ////////| helpers |/////// - function sendMail(){ - window.location.href = `mailto:${contact[1]} ${contact[0]} <${contact[3]}>` - m.action = 'none' - } - function makeCall(){ - window.location.href = `tel:${contact[2]}` - m.action = 'none' - } - -} -////////////////////////////// -c.setClearIconText = (m)=>{} -c.showClearIconText = (v)=>{ - Array.from(m.source.querySelectorAll('span')).forEach(span =>{span.innerText = ``}) -} -////////////////////////////// -c.setAddNewContact = (m)=>{ - //gather new user data into an array of strings - //suggetion: inputs are: v.newLast, v.newFirst, v.newPhone, v.newEmail - // const newContact = [v.newLast.value, v.newFirst.value, ...] - // m.arrayOfContactsArray.push(newContact) - // c.saveContactsToServer(m.arrayOfContactsArray) -} -c.showAddNewContact = (v)=>{} -///////////////////////////// -c.setContactDisplay = (m)=>{ - m.selectedIndex = v.contactSelector.selectedIndex - m.priorSelectedPrimaryKey = m.selectedPrimaryKey - if(m.currentContactsArray[m.selectedIndex]){ - m.selectedPrimaryKey = m.currentContactsArray[m.selectedIndex][6] - } -} -c.showContactDisplay = ({nameHolder, faceHolder, actionHolder})=>{ - nameHolder.innerHTML = '' - faceHolder.innerHTML = '' - actionHolder.innerHTML = '' - if(m.currentContactsArray[m.selectedIndex]){ - const lastName = m.currentContactsArray[m.selectedIndex][0] - const firstName = m.currentContactsArray[m.selectedIndex][1] - nameHolder.innerText = `${firstName} ${lastName}` - } - c.showMailPhoneTouched(v) - //switch pictures only if its a different contact - if(m.selectedPrimaryKey !== m.priorSelectedPrimaryKey){ - c.movePicture(7); - } - //if in search, show current contact index - v.matchCount.innerText = m.currentContactsArray.length - v.matchIndex.innerText = m.selectedIndex + 1 || 0 -} -//////////////////////////////////// -c.setResize = (m)=>{ - m.height = window.innerHeight - m.width = window.innerWidth -} -c.showResize = ({contactBox, faceHolder, nameHolder, actionHolder, app})=>{ - - const boxes = Array.from(document.querySelectorAll(`.box`)) - ;(m.width <= m.MAX_WIDTH) - ? boxes.forEach( box => box.styles(`width: 93%`) ) - : boxes.forEach( box => box.styles(`width: ${m.MAX_WIDTH}px`) ) - - const isLandscape = (m.width >= m.height) - const isPortrait = (m.width < m.height) - if(isLandscape){ - faceHolder.styles(`width: 5rem`)(`height: 5rem`) - nameHolder.styles(`margin-top: 1%`) - actionHolder.styles(`top: 35%`) - v.controlsAssembly.styles(`width: 85%`) - } - else if(isPortrait){ - faceHolder.styles(`width: 7rem`)(`height: 7rem`) - nameHolder.styles(`margin-top: 5%`) - actionHolder.styles(`top: 40%`) - v.controlsAssembly.styles(`width: 98.5%`) - } - - m.width >= 600 - ? app.styles(`width: 600px`) - : app.styles(`width: 100%`) -} -///////////////////////////////////// - -c.setMailPhoneTouched = (m) => { - /* - m.action = 'none' //either 'calling', 'mailing' or 'none' - */ - ;(m.source === v.phoneIcon && m.action !== `calling`) - ? m.action = `calling` - :(m.source === v.mailIcon && m.action !== `mailing`) - ? m.action = `mailing` - : null//m.action = `none` -} -c.showMailPhoneTouched = ({actionHolder}) => { - const index = m.selectedIndex - const phoneIndex = 2 - const mailIndex = 3 - if(m.currentContactsArray[index]){ - ;(m.action === `calling`) - ? actionHolder.innerText = m.currentContactsArray[index][phoneIndex] - :(m.action === `mailing`) - ? actionHolder.innerText = m.currentContactsArray[index][mailIndex] - : actionHolder.innerText = `` - } -} -///////////////////////////////////// -c.setMailOrCall =(m)=>{ - -} -c.showMailOrCall = ({actionHolder})=>{ - ;(m.action === `calling`) - ? makeTheCall() - :(m.action === `mailing`) - ? sendTheMail() - : null - ///| helpers |/// - function makeTheCall(){ - window.location.href = `tel:${actionHolder.innerText}` - } - ///// - function sendTheMail(){ - const index = m.selectedIndex - const lastname = m.currentContactsArray[index][0] - const firstname = m.currentContactsArray[index][1] - window.location.href = `mailto: ${firstname} ${lastname}<${actionHolder.innerText}>` - } - -} -//////////////| aliases function |/////////////// -c.setMailOrCall2 = c.setMailOrCall -c.showMailOrCall2 = c.showMailOrCall -///////////////////////////////////// -c.setClearAction = ()=>{ - m.action = `none` -} -c.showClearAction = ({actionHolder})=>{ - ; (m.action === `none`) - ? actionHolder.innerText = `` - : null -} -///////////////////////////////////// -/////////////////////////////// -c.setCheckSwipe = (m)=>{} -c.showCheckSwipe = (v)=>{ - const percent = Math.round(100 * (m.historyX[1] - m.historyX[0]) / m.width) - percent > 5 - ? showNext() - : percent < -5 - ? showPrior() - : null - /////| helpers |////// - function showNext(){ - c.setPulseNextButton(m) - c.showPulseNextButton(v) - } - function showPrior(){ - c.setPulseBackButton(m) - c.showPulseBackButton(v) - } -} -/////////////////////////////// -c.setEdit = (m)=>{ - m.nowEditing = true; -} -c.showEdit = (v)=>{ - /* - m.nowEditing - ? ((m,v)=>{ - c.setClearSearch(m); - c.showClearSearch(v); - })(m,v) - : null - */ - m.nowEditing - ? v.editBox.styles(`visibility: visible`)(`opacity: 0.95`) - : v.editBox.styles(`visibility: hidden`)(`opacity: 0`) - - m.nowEditing - ? v.editBtn.styles(`box-shadow: inset 2px 2px 10px black`) - : v.editBtn.styles(`box-shadow: 2px 2px 10px black`) - - m.source === v.faceHolder - ? v.editBox.styles(`background-image: url(images/${m.currentContactsArray[m.selectedIndex][5]})`) - : v.editBox.styles(`background-image: linear-gradient(-20deg, hsl(210, 33%, 30%), hsl(210, 33%, 50%), hsl(210, 33%, 30%))`) - const currentContact = m.currentContactsArray[m.selectedIndex] - const max = currentContact.length; - - v.lastname.attribs(`placeholder=${currentContact[0]}`) - v.firstname.attribs(`placeholder=${currentContact[1]}`) - v.phone.attribs(`placeholder=${currentContact[2]}`) - v.email.attribs(`placeholder=${currentContact[3]}`) - if(currentContact[4] !== null && currentContact[4] !== 'null'){ - v.group.attribs(`placeholder=${currentContact[4]}`) - } - else{ - v.group.attribs(`placeholder=""`) - } - - -} -/////////////////////////////// -c.setStopEdit = (m)=>{ - m.nowEditing = false; -} -c.showStopEdit = ({editBox, btnCancelEdit, photoChooserAssembly})=>{ - photoChooserAssembly.styles(`background-image: url(images/${m.defaultPhoto})`) - - m.nowEditing - ? v.editBtn.styles(`box-shadow: inset 2px 2px 10px black`) - : v.editBtn.styles(`box-shadow: 2px 2px 10px black`) - - m.nowEditing - ? editBox.styles(`visibility: visible`)(`opacity: 0.95`) - : editBox.styles(`visibility: hidden`)(`opacity: 0`) - //////| helper |////// - // more to be done - m.source === v.btnCancelEdit - ? clearChanges()//photoChooserAssembly.styles(`background-image: url(${m.defaultPhoto})`) - : m.source === v.btnSaveEdit - ? saveEdit() : null - //////| helpers |////// - function clearChanges(){ - v.lastname.value = '' - v.firstname.value = '' - v.phone.value = '' - v.email.value = '' - v.group.value = '' - if(v.photoChooser.files && v.photoChooser.files[0]){ - v.photoChooser = "" - } - photoChooserAssembly.styles(`background-image: url(images/${m.noPhotoFilename})`) - } - function saveEdit(){ //On June 10, 2018, I did a large edit on saveEdit(), and some associated functions - - const index = m.selectedIndex - //save my edits to current contact - if(v.lastname.value !== ""){ - m.currentContactsArray[index][0] = v.lastname.value.trim() - } - if(v.firstname.value !== ""){ - m.currentContactsArray[index][1] = v.firstname.value.trim() - } - if(v.phone.value !== ""){ - m.currentContactsArray[index][2] = v.phone.value.trim() - } - if(v.email.value !== ""){ - m.currentContactsArray[index][3] = v.email.value.trim() - } - if(v.group.value !== "" && v.group.value !== null){ - m.currentContactsArray[index][4] = v.group.value.trim() - } - if(v.photoChooser.files && v.photoChooser.files[0]){ - m.currentContactsArray[index][5] = v.photoChooser.files[0].name.trim() - savePhotoToServer() - ///////| helper function |////// - function savePhotoToServer(){ - const file = v.photoChooser.files[0] - const filename = file.name - const postman = new XMLHttpRequest() - const envelope = new FormData() - const reader = new FileReader() - reader.readAsDataURL(file) - ////////////////////////////////////// - reader.onload = () => { - envelope.append(`filename`, filename) - envelope.append(`contents`, reader.result) - postman.open(`POST`, `savePhoto.php`) - postman.send(envelope) - ////////////////////////////////////// - postman.onload = ()=>{ - if(postman.status !== 200){alert("Trouble saving photo: " + filename)} - } - postman.onerror = ()=>{ - console.log("Trouble connecting to server.") - } - } - } - } - - //get the primary key and save changes locally and to the server - const primaryKey = m.currentContactsArray[index][6] - c.saveChangedContact(primaryKey, m.currentContactsArray[index]) - c.saveContactsToServer(m.arrayOfContactArrays) - - // now clear out the edit fields for the next edit session - v.lastname.value = '' - v.firstname.value = '' - v.phone.value = '' - v.email.value = '' - v.group.value = '' - m.selectedPhoto = '' - if(v.photoChooser.files && v.photoChooser.files[0]){ - v.photoChooser = "" - } - - //now update current contact array based on primary keys of current contacts array - const newCurrentContactsArray = m.arrayOfContactArrays.filter(memberBigList =>{ - return m.currentContactsArray.some(memberLittleList =>{ - return memberBigList[6] === memberLittleList[6] - }) - }) - - //now alphabetize it - m.currentContactsArray = L.sortArrayOfStringArrays(newCurrentContactsArray) - - //determine a more accurate selected index from primary key of current contact - const newSelectedIndex = m.currentContactsArray.reduce((newIndex, m, i)=>{ - //if the member's primary key is the current one, use its index - m[6] === primaryKey - ? newIndex = i - : newIndex - return newIndex - }, 0) - - //fill, change primary key and show image (now included in fillSelector) - c.fillSelector( m.currentContactsArray, newSelectedIndex ) - - //MAYBE renew the search, but not sure when, so saving it for last - c.newSearch() - } -} -//////////| alias for setStopEdit |//////// -c.setEditButtonOut = (m)=>{} -c.showEditButtonOut = (v)=>{ - c.setStopEdit(m) - c.showStopEdit(v) -} -/////////////////////////////// -c.setKeyDirection = (m)=>{ - //if(m.nowEditing){return} - const keycode = m.eventObject.which - m.correctKey = true - keycode === 39 - ? m.currentDirection = `next` - : keycode === 37 - ? m.currentDirection = `back` - : m.correctKey = false -} -c.showKeyDirection = (v)=>{ - if(m.nowEditing || !m.correctKey){return} - m.currentDirection === `next` - ? showNext() - : m.currentDirection === `back` - ? showPrior() - : null - /////| helpers |////// - function showNext(){ - c.setPulseNextButton(m) - c.showPulseNextButton(v) - } - function showPrior(){ - c.setPulseBackButton(m) - c.showPulseBackButton(v) - } -} -/////////////////////////////// -c.setChosenPhoto = (m)=>{ - if(v.photoChooser.files && v.photoChooser.files[0].name){ - m.selectedPhoto = v.photoChooser.files[0].name - }else{ - m.selectedPhoto = '' - } -} -c.showChosenPhoto = ({photoChooser, photoChooserAssembly})=>{ - if ( !(photoChooser.files && photoChooser.files[0]) ){ - return - } - const file = photoChooser.files && photoChooser.files[0] - m.currentChosenPhoto = file - const filename = file.name - const reader = new FileReader() - reader.readAsDataURL(file) - reader.onload = ()=>{ - photoChooserAssembly.styles(`background-image: url(${reader.result})`) - delete photoChooser.files[0] - } -} -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// -c.setNewChosenPhoto = (m)=>{ - if(v.newPhotoChooser.files && v.newPhotoChooser.files[0].name){ - m.newSelectedPhoto = v.newPhotoChooser.files[0].name - }else{ - m.newSelectedPhoto = '' - } -} -c.showNewChosenPhoto = ({newPhotoChooser, newContactPhotoAssembly})=>{ - if ( !(newPhotoChooser.files && newPhotoChooser.files[0]) ){ - return - } - const file = newPhotoChooser.files && newPhotoChooser.files[0] - m.currentChosenPhoto = file - const filename = file.name - const reader = new FileReader() - reader.readAsDataURL(file) - reader.onload = ()=>{ - newContactPhotoAssembly.styles(`background-image: url(${reader.result})`) - delete newPhotoChooser.files[0] - } -} -/////////////////////////////// -c.setDeleteContact = (m) => { - m.selectedPrimaryKey = m.currentContactsArray[m.selectedIndex][6] - m.nowEditing - ? m.shroudVisible = false - : m.shroudVisible = true -} -c.showDeleteContact = (v) => { - m.shroudVisible - ? v.shroud.styles(`visibility: visible`)(`opacity: 1`) - : v.shroud.styles(`visibility: hidden`)(`opacity: 0`) - - const firstname = m.currentContactsArray[m.selectedIndex][1] - const lastname = m.currentContactsArray[m.selectedIndex][0] - v.shroudMessage.innerHTML = `Are you sure you want to delete
    ${firstname} ${lastname}?` -} -/////////////////////////////// -c.setShroudHidden = (m) => { - m.shroudVisible = false -} -c.showShroudHidden = (v) => { - m.shroudVisible - ? v.shroud.styles(`visibility: visible`)(`opacity: 1`) - : v.shroud.styles(`visibility: hidden`)(`opacity: 0`) -} -/////////////////////////////// -c.setKillContact = (m) => { - m.backup = m.arrayOfContactArrays; - - const imageName = m.arrayOfContactArrays.reduce((imageName, member)=>{ - member[6] === m.selectedPrimaryKey - ? imageName = member[5] - : null - return imageName - },"") - - if ( `DefaultImage.png` !== imageName && `contacts2.png` !== imageName ){ - c.deleteImageFromServer(imageName) - } - - m.arrayOfContactArrays = m.arrayOfContactArrays.filter(member => member[6] !== m.selectedPrimaryKey) - m.currentContactsArray = m.currentContactsArray.filter(member => member[6] !== m.selectedPrimaryKey) - c.saveContactsToServer(m.arrayOfContactArrays) - /* - Because we eliminated a contact, the current selected index is pointing - to the next contact, or to nothing. If pointing to nothing, make it point to - the first contact. - */ - const maxIndex = m.currentContactsArray.length - 1 - if(m.selectedIndex > maxIndex){ - m.selectedIndex = 0 - } -} -c.showKillContact = (v) => { - for(let x of m.currentContactsArray){ - console.log(x[0]) - } - //////// - c.fillSelector(m.currentContactsArray, m.selectedIndex ) -} -/////////////////////////////// -c.setAddContact = (m) => { - m.buildingNewContact = true; -} -c.showAddContact = (v) => { - m.buildingNewContact - ? v.addBox.styles(`visibility: visible`)(`opacity: 0.95`) - : v.addBox.styles(`visibility: hidden`)(`opacity: 0`) - - m.buildingNewContact - ? v.addContactBtn.styles(`box-shadow: inset 2px 2px 10px black`) - : v.addContactBtn.styles(`box-shadow: 2px 2px 10px black`) - - m.buildingNewContact - ? ((m,v)=>{ - c.setClearSearch(m); - c.showClearSearch(v); - })(m,v) - : null -} -/////////////////////////////// -c.setStopAdd = (m)=>{ - m.buildingNewContact = false; -} -c.showStopAdd = (v)=>{ - m.buildingNewContact - ? v.addBox.styles(`visibility: visible`)(`opacity: 0.95`) - : v.addBox.styles(`visibility: hidden`)(`opacity: 0`) - - m.buildingNewContact - ? v.addContactBtn.styles(`box-shadow: inset 2px 2px 10px black`) - : v.addContactBtn.styles(`box-shadow: 2px 2px 10px black`) - - m.source === v.saveAddBtn - ? saveNew() - : m.source === v.cancelAddBtn - ? clearAddChanges() - : null - //////| helpers |////// - function saveNew(){ - //only save values if a full name was provided, else return - if(!v.newLastname.value || !v.newFirstname.value ){ - alert(`You must provide a full name`) - return - } - //create new contact array: - const newContact = [] - //save fields in the proper order - newContact.push(v.newLastname.value.trim()) //firstname - newContact.push(v.newFirstname.value.trim()) //lastname - newContact.push(v.newPhone.value.trim()) //phone - newContact.push(v.newEmail.value.trim()) //email - newContact.push(v.newGroup.value.trim()) //group - v.newPhotoChooser.files && v.newPhotoChooser.files[0] //photo - ? handleImage() - : newContact[5] = m.noPhotoFilename - newContact[6] = Date.now() //primary key - ///////| helper handle image |////// - function handleImage(){ - newContact[5] = v.newPhotoChooser.files[0].name - //...and save image to server, then clear out chosen file and new info fields - c.saveFileToServerPath(clearAddChanges, v.newPhotoChooser.files[0], `images/`) - } - - //save new contact to master list (in memory) - m.arrayOfContactArrays.push(newContact) - //now alphabetize it - m.arrayOfContactArrays = L.sortArrayOfStringArrays(m.arrayOfContactArrays) - //now save new master list to the server - c.saveContactsToServer(m.arrayOfContactArrays) - - //do the search again,which now includes the new contact - c.newSearch() - - //clear fields - setTimeout(clearAddChanges,100) - } - //----------------------------// - function clearAddChanges(){ - v.newLastname.value = '' - v.newFirstname.value = '' - v.newPhone.value = '' - v.newEmail.value = '' - v.newGroup.value = '' - delete v.newPhotoChooser.files[0] - v.newContactPhotoAssembly.styles(`background-image: url(images/${m.defaultPhoto})`) - } -} -/////////////////////////////////// -c.setAddButtonOut = (m)=>{ - c.setStopAdd(m) -} -c.showAddButtonOut = (v)=>{ - c.showStopAdd(v) -} -/////////////////////////////// -c.setToggleMenu = (m)=>{ - m.menuIsOpen = !m.menuIsOpen -} -c.showToggleMenu = (v)=>{ - if(m.menuIsOpen){ - v.searchAssembly.styles(`visibility: hidden`)(`opacity: 0`) - v.txtSearch.styles(`visibility: hidden`)(`opacity: 0`) - - //hide the endcaps of the search assembly to avoid some issues: 1) accidently clearing the search - //2) blocking the edit button - Array.from(document.querySelectorAll('.endcap')).forEach(endcap => endcap.styles('visibility: hidden')('opacity: 0')) - - v.controlsAssembly - .styles - ( `background-image: linear-gradient( white, #aaa)` )//(`border: 1px solid magenta`) - (`box-shadow: 1px 1px 10px`) - v.burgerTop.styles(`transform: rotateZ(35deg)`) - v.burgerMiddle.styles(`transform: rotateY(90deg)`) - v.burgerBottom.styles(`transform: rotateZ(-35deg)`) - v.menuButtonsAssembly - .styles - (`visibility: visible`) - (`opacity: 1`) - - for ( let burgerLine of Array.from(document.querySelectorAll(`.burgerLines`)) ){ - burgerLine.styles(`background-color: red`) - } - } - else if(!m.menuIsOpen){ - v.searchAssembly.styles(`visibility: visible`)(`opacity: 1`) - v.txtSearch.styles(`visibility: visible`)(`opacity: 1`) - if(!m.searchIsEmpty){ - Array.from(document.querySelectorAll('.endcap')).forEach(endcap => endcap.styles('visibility: visible')('opacity: 0.55')); - } - v.controlsAssembly - .styles - (`background-image: none`) - (`box-shadow: 0 0 0`) - v.burgerTop.styles(`transform: rotateZ(0deg)`) - v.burgerMiddle.styles(`transform: rotateY(0deg)`) - v.burgerBottom.styles(`transform: rotateZ(0deg)`) - - v.menuButtonsAssembly.styles(`visibility: hidden`)(`opacity: 0`) - - //restore search assembly's end caps - // Array.from(document.querySelectorAll('.endcap')).forEach(endcap => endcap.styles('visibility: visible')('opacity: 0.55')) - - for ( let burgerLine of Array.from(document.querySelectorAll(`.burgerLines`)) ){ - burgerLine.styles(`background-color: black`) - } - } -} -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// -/////////////////////////////// - -"; \ No newline at end of file diff --git a/data/collaborative/text/b9a2a6807be3cb2888a882de9a456ca8 b/data/collaborative/text/b9a2a6807be3cb2888a882de9a456ca8 deleted file mode 100755 index 31bae3d..0000000 --- a/data/collaborative/text/b9a2a6807be3cb2888a882de9a456ca8 +++ /dev/null @@ -1,236 +0,0 @@ -s:6332:"/*global L*/ -/*global m*/ -/*global v*/ -/*global c*/ -//============================// -////////////////////////////////////////// -c.setResize = (m, callback, arg) => { - m.width = window.innerWidth - m.height = window.innerHeight - arg ? callback(arg) : null -} -c.showResize = ({controlsAssembly, controlsHolder, pictureHolder, player}) => { - m.busyResizing = true - const isPortrait = m.height >= m.width; - if(isPortrait){ - controlsHolder.attribs(`class=portraitBottom`) - pictureHolder.attribs(`class=portraitTop`) - controlsAssembly - .styles - (`height: 60%`) - (`top: 47%`) - const controlsSpecs = controlsHolder.getBoundingClientRect() - v.player.styles(`bottom: ${controlsSpecs.top/1.2}px`)(`top: auto`) - } - else{ - m.noPicture - ? controlsHolder.attribs(`class=landscapeRightNoPicture`) - : controlsHolder.attribs(`class=landscapeRight`) - - pictureHolder.attribs(`class=landscapeLeft`) - controlsAssembly - .styles - (`height: 55%`) - (`top: 20%;`) - const controlsSpecs = controlsHolder.getBoundingClientRect() - v.player.styles(`top: ${controlsSpecs.bottom/1.345}px`)(`bottom: auto`) - } - //password holder - isPortrait - ? v.passwordHolder.styles(`width: 100vw`) - : v.passwordHolder.styles(`width: ${m.MAX_WIDTH}px`) - - setTimeout(()=>{ - m.busyResizing = false - },200) - -} -/////////////////////////////////////// -c.showInfo = ({info}) => { - const msg = `${m.id}: ${m.type}, prior event: ${m.priorType[1]}` - //const msg = `${m.id}: ${m.type}, clicked?: ${m.clicked}` - - info.innerText = msg; -} -////////////////////////////////////////// -c.setPlay = (m, show, arg)=>{ - if(m.busyWithPictureOnly){return} - m.playing = true - arg ? show(arg) : null -} -c.showPlay = ({player})=>{ - if(m.busyWithPictureOnly){return} - c.playChosenSong() -} -////////////////////////////////////////// -c.setPictureOnly = (m, show, arg)=>{ - if(m.busyWithPictureOnly){return} - - m.showPictureOnly = !m.showPictureOnly - m.playing = true - - arg ? show(arg) : null -} -c.showPictureOnly =({background, pictureHolder, controlsBlocker})=>{ - if(m.busyWithPictureOnly){return} - m.busyWithPictureOnly = true - - clearInterval(m.pictureBusyId) - - v.controlsBlocker.styles(`visibility: visible`) - /* - if m.showPictureOnly, bring background to the front - */ - m.showPictureOnly - ? showPictureOnly() - : restorePictureState() - - ///////| helpers |////// - function showPictureOnly(){ - //bring background in front - background.styles(`z-index: 10`) - //show current pictureData (m.pictureData), if there is one - if(!m.noPicture){ - background - .styles - (`background-image: url(${m.pictureData})`) - (`background-size: contain`) - (`background-repeat: no-repeat`) - (`background-position: center`) - } - } - function restorePictureState(){ - //put background behind - background.styles(`z-index: 0`) - //restore default background picture - background - .styles - (`background-image: url(${m.defaultBackground})`) - //(`background-size: cover`) - (`background-repeat: no-repeat`) - (`background-position: center`) - setTimeout(()=>{ - background.styles(`background-size: cover`) - },200) - } - m.pictureBusyId = setTimeout(()=>{ - m.busyWithPictureOnly = false - controlsBlocker.styles(`visibility: hidden`) - }, 500) -} -////////////////////////////////////////// -c.setLogout = (m, show, arg)=>{ - m.loggedIn = false - if(arg && show && typeof show === 'function'){show(arg)} -} -c.showLogout = ({passwordWall, passwordInput})=>{ - if(!m.loggedIn){ - //put up password wall and clear input - passwordWall - .styles - (`visibility: visible`) - (`opacity: 1`) - passwordInput.value = `` - passwordInput.focus() - // lower access level - const killer = new XMLHttpRequest() - killer.open('GET', `php/logout.php`) - killer.send() - killer.onload = ()=>{ - if(killer.status === 200){ - killer.responseText === 'allow' - ? m.loggedIn = true - : m.loggedIn = false - } - else{ - const msg = `Trouble logging out.` - console.log(msg) - alert(msg) - m.loggedIn = false - } - } - killer.onerror = ()=>{ - const msg = `Trouble connecting to server.` - console.log(msg) - alert(msg) - m.loggedIn = false - } - } -} -////////////////////////////////////////// -c.setLogin = (m, show, arg)=>{ - const postman = new XMLHttpRequest() - const envelope = new FormData() - envelope.append(`userPassword`, v.passwordInput.value) - postman.open(`POST`, `php/login.php`) - postman.send(envelope) - //--------------------// - postman.onload = ()=>{ - if(postman.status === 200){ - postman.responseText === 'allow' - ? m.loggedIn = true - : m.loggedIn = false - } - else{ - const msg = `Trouble checking password.` - console.log(msg) - alert(msg) - m.loggedIn = false - } - } - postman.onerror = ()=>{ - const msg = `Trouble connecting to server.` - console.log(msg) - alert(msg) - m.loggedIn = false - } - //--------------------// - if(arg && show && typeof show === 'function'){show(arg)} -} -c.showLogin = ({passwordWall, passwordInput})=>{ - if(m.loggedIn){ - //bring down wall - passwordWall - .styles - (`visibility: hidden`) - (`opacity: 0`) - passwordInput.value = `` - //get music list from server - c.getFileList() - } -} -////////////////////////////////////////// -c.setToggleNonStop = (m)=>{ - m.nonStop = !m.nonStop -} -c.showToggleNonStop = (v)=>{ - m.nonStop - ?(()=>{ - v.btnNonStop - .styles - (`box-shadow: inset 3px 3px 15px black`) - (`opacity: 1`) - })() - :(()=>{ - v.btnNonStop - .styles - (`box-shadow: 3px 3px 15px black`) - (`opacity: 0.55`) - })() - - /* - If non-stop: - 1. player should be in autoplay - 2. end event should increment selected index (or set it to 0) - */ - m.nonStop - ? v.player.attribs(`autoplay=autoplay`) - : v.player.attribs(`autoplay=false`) -} - -////////////////////////////////////////// -////////////////////////////////////////// -////////////////////////////////////////// -////////////////////////////////////////// -////////////////////////////////////////// -//////////////////////////////////////////"; \ No newline at end of file diff --git a/data/collaborative/text/ba67cc584113e97440efff098f28393e b/data/collaborative/text/ba67cc584113e97440efff098f28393e deleted file mode 100755 index 8401ef3..0000000 --- a/data/collaborative/text/ba67cc584113e97440efff098f28393e +++ /dev/null @@ -1,55 +0,0 @@ -s:1628:" - - - - -
    - - - - - - - - - - - -
    - -"; \ No newline at end of file diff --git a/data/collaborative/text/c402a1cde9f402454c2313535a396934 b/data/collaborative/text/c402a1cde9f402454c2313535a396934 deleted file mode 100755 index 2af380b..0000000 --- a/data/collaborative/text/c402a1cde9f402454c2313535a396934 +++ /dev/null @@ -1,333 +0,0 @@ -s:10581:"/*global L*/ -/*global m*/ -/*global v*/ -/*global c*/ - -//=========================================================================// -c.getFileList = function (){ - const getter = new XMLHttpRequest() - getter.open('POST', 'php/getFileList.php') - getter.send() - getter.onload = function(){ - if(getter.status === 200){ - c.fillDocumentSelector(getter.responseText) - console.log(getter.responseText) - } - else{ - console.log('Trouble getting file list.') - } - } -} -//======================================================================// -c.fillDocumentSelector = function (filesString){ - const currentFilename = v.documentSelector.options[v.documentSelector.selectedIndex] && v.documentSelector.options[v.documentSelector.selectedIndex].innerText - v.documentSelector.innerHTML = '' - const filenameArray = filesString.split('\n') - filenameArray.pop() // get rid of the blank last entry - - if(filenameArray.length === 0){ - const option = document.createElement('option') - option.innerText = "(No Music Files)" - v.documentSelector.appendChild(option) - v.player.styles(`visibility: hidden`) - } - else{ - filenameArray.forEach( filename =>{ - const option = document.createElement('option') - option.innerText = filename - v.documentSelector.appendChild(option) - }) - } - - v.documentSelector.selectedIndex = filenameArray.indexOf(currentFilename) - v.documentSelector.selectedIndex === -1 ? v.documentSelector.selectedIndex = 0 : null - -} - -//=====================================================================// -c.uploadFiles =(eventObject)=>{ - if( !(v.fileElement.files && v.fileElement.files[0]) ){return} - if(m.busyWithPictureOnly){return} - - let allFilesMp3 = Array.from(v.fileElement.files).every( file=> getExtention(file) === `mp3` ) - if(!allFilesMp3){ - alert(`Only .mp3 files allowed.`) - return - } - //----| helper |------// - function getExtention(file){ - let name = file.name - let maxIndex = name.length -1 - let extLength = maxIndex - name.lastIndexOf(`.`) - return name.slice(-extLength) - } - L.uploadFiles(c.showUploadProgress, v.fileElement, "php/uploadFile.php") -} -//===========================================// -c.showUploadProgress = (loaded, total, index)=>{ - const numberOfFiles = v.fileElement.files.length - if(numberOfFiles === 0){return} - const pct = Math.round(100 * m.averageUploadFraction) - m.fractionArray[index] = loaded/total - m.averageUploadFraction = m.fractionArray.reduce(function(sum, value){ - return sum + value/numberOfFiles - }, 0) - - v.progressBar.styles(`width: ${pct}%`) - - console.log(`loaded: ${(100 * m.averageUploadFraction).toFixed(0)}`) - if( (loaded === 1 && total === 1) || pct === 100 ){// && index === (numberOfFiles-1) - c.getFileList() - setTimeout(()=>{ - c.clearUploadData() - v.progressBar.styles(`width: 0`) - }, 1000) - } -} -//=============================================// -c.playChosenSong = () => { - if(m.busyWithPictureOnly){return} - c.setResize(m, c.showResize, v) //not sure if invoking here is overkill - const base = m.musicFilesUrl - const index = v.documentSelector.selectedIndex - const src = `${base}${v.documentSelector.options[index].innerText}` - v.player.pause() - setTimeout(()=>{//this delay improves performance - v.player.src = src - v.player.styles(`visibility: visible`) - v.player.play() - m.playing = true - },25) - - v.background - .styles - (`background-image: url(${m.defaultBackground})`) - (`background-size: cover`) - - //attempt to show image - var jsmediatags = window.jsmediatags ; - if(!jsmediatags){ - m.noPicture = true - console.log("Can't find the 'jsmediatags' object."); - console.log("Try https://github.com/aadsm/jsmediatags/tree/master/dist/jsmediatags.min.js"); - console.log("... or https://cdnjs.cloudflare.com/ajax/libs/jsmediatags/3.9.0/jsmediatags.js") - c.setResize(m, c.showResize, v) - return; - } - // url from local host - const url = `${base}${v.documentSelector.options[index].innerText}` - jsmediatags.read(url, { - onSuccess: (tag) => { - console.log(tag); - let tags = tag.tags; - //========================// - var image = tags.picture; - if (image) { - m.noPicture = false - const base64String = image.data.reduce((string, datum) => string += String.fromCharCode(datum), ''); - m.pictureData = "data:" + image.format + ";base64," + window.btoa(base64String); - v.pictureHolder - .styles - (`background-image: url(${m.pictureData})`) - (`background-size: contain`) - (`background-repeat: no-repeat`) - (`background-position: center`) - (`background-size: contain`) - (`background-color: black`) - v.controlsHolder - .styles - (`background-color: black`) - v.controlsAssembly - .styles - (`background-color: #eee`) - c.setResize(m, c.showResize, v) - } - else{//no image - m.noPicture = true - console.log("No image found :(") - v.pictureHolder - .styles - (`background-image: url()`) - (`background-color: transparent`) - v.controlsHolder - .styles - (`background-color: transparent`) - v.controlsAssembly - .styles - (`background-color: rgba(238, 238, 238, 0.4)`) - c.setResize(m, c.showResize, v) - } - //=========================// - //=====| show picture |====// - //=========================// - //////////////////////////// - c.showPicture(1000)//argument is delay-time in milliseconds - /////////////////////////// - }, - onError: (error) => { - console.log(error); - return; - } - }); - -} -//==========================================================// -c.clearUploadData = ()=>{ - m.fractionArray = []; - m.averageUploadFraction = 0; -} -//================================================// -c.respondToEnded = ()=>{ - m.nonStop - ? pointToNextSong() - : m.playing = false - //---| helper |---// - function pointToNextSong(){ - v.documentSelector.selectedIndex + 1 < v.documentSelector.options.length - ? v.documentSelector.selectedIndex = v.documentSelector.selectedIndex + 1 - : v.documentSelector.selectedIndex = 0 - setTimeout(c.playChosenSong, 20) - } - c.showPicture(1000) - -} -//========================================// -c.respondToPause = ()=>{ - if(m.busyWithPictureOnly){return} - m.playing = false -} -//============================================// -c.respondToPlay = ()=> { - if(m.busyWithPictureOnly){return} - m.playing = true -} -//============================================// -c.deleteFile = ()=>{ - if(m.busyWithPictureOnly){return} - - const index = v.documentSelector.selectedIndex - const filename = v.documentSelector.options[index].innerText - - const msg = `OK to DELETE ${filename}?\n( Otherwise, CANCEL )` - const okToDelete = confirm(msg) - if(okToDelete){ - const killer = new XMLHttpRequest() - const envelope = new FormData() - envelope.append(`filename`, filename) - killer.open(`POST`, `php/deleteFile.php`) - killer.send(envelope) - //--------------------------// - killer.onload = ()=>{ - if(killer.status !== 200){ - console.log("Trouble deleting the file.") - } - else{ - c.getFileList() - } - } - killer.onerror = ()=>{ - console.log("Trouble Connecting to server.") - } - } -} -//========================================// -c.getAccessLevel = ()=>{ - const reporter = new XMLHttpRequest() - reporter.open(`GET`, `php/getAccessLevel.php`) - reporter.send() - //----------------// - reporter.onload = ()=>{ - if(reporter.status === 200){ - reporter.responseText === 'allow' - ? m.loggedIn = true - : m.loggedIn = false - console.log(reporter.responseText) - if(!m.loggedIn){ - c.setLogout(m, c.showLogout, v) - } - } - } - reporter.onerror = ()=>{ - const msg = `Trouble connecting to server.` - console.log(msg) - } -} -//--------------------------------------// - -c.pollForPaswordWall = ()=>{ - const reporter = new XMLHttpRequest() - reporter.open(`GET`, `php/getAccessLevel.php`) - reporter.send() - //----------------// - reporter.onload = ()=>{ - if(reporter.status === 200){ - reporter.responseText === 'allow' - ? m.loggedIn = true - : m.loggedIn = false - //console.log(reporter.responseText) - if(!m.loggedIn){ - //put up password wall - passwordWall - .styles - (`visibility: visible`) - (`opacity: 1`) - } - } - else{ - const msg = `Trouble with password.` - console.log(msg) - } - } - reporter.onerror = ()=>{ - const msg = `Trouble connecting to server.` - console.log(msg) - } - -} -//////////////////////////////////////// -c.queueInitialRandomSong = ()=>{ - c.showToggleNonStop(v) - setTimeout(()=>{ - m.selectedIndex = Math.floor( v.documentSelector.options.length * Math.random() ) - v.documentSelector.selectedIndex = m.selectedIndex - v.player.src =`${m.musicFilesUrl}${v.documentSelector.options[m.selectedIndex].innerText}` - c.playChosenSong() - }, 320) - setTimeout(()=>{v.player.pause()},475) -} -//////////////////////////////////////// -c.showPicture = function(delay=2000){ - setTimeout(()=>{ - m.showPictureOnly - ? showPictureOnly() - : restorePictureState() - ////| helpers |//// - function showPictureOnly(){ - //bring background in front - v.background.styles(`z-index: 10`) - //show current pictureData (m.pictureData), if there is one - if(!m.noPicture){ - v.background - .styles - (`background-image: url(${m.pictureData})`) - (`background-size: contain`) - (`background-repeat: no-repeat`) - (`background-position: center`) - } - } - function restorePictureState(){ - //put background behind - v.background.styles(`z-index: 0`) - //restore default background picture - v.background - .styles - (`background-image: url(${m.defaultBackground})`) - (`background-repeat: no-repeat`) - (`background-position: center`) - setTimeout(()=>{ - v.background.styles(`background-size: cover`) - },300) - } - }, delay) -} -//////////////////////////////////////////////"; \ No newline at end of file diff --git a/data/collaborative/text/c41e653729c1a8ef77976647bbfbee70 b/data/collaborative/text/c41e653729c1a8ef77976647bbfbee70 deleted file mode 100755 index 2bfe8b7..0000000 --- a/data/collaborative/text/c41e653729c1a8ef77976647bbfbee70 +++ /dev/null @@ -1,7 +0,0 @@ -s:126:"[{ - "author": "Isaac Brown", - "version": "1.0.0", - "name": "Tela Auto Save", - "url": "https://telaaedifex.com" -}] -"; \ No newline at end of file diff --git a/data/collaborative/text/c611c854fd24594f69862df70e8afd48 b/data/collaborative/text/c611c854fd24594f69862df70e8afd48 deleted file mode 100755 index 1a0c317..0000000 --- a/data/collaborative/text/c611c854fd24594f69862df70e8afd48 +++ /dev/null @@ -1,55 +0,0 @@ -s:1638:"s:1628:" -
    - ";echo var_dump( $quizzes );?> - -

    This teacher currently has no quizzes active.

    - -
  • ">
  • - -
    -"; \ No newline at end of file diff --git a/data/collaborative/text/cf1d4b27a3b2b1bba71f454cc7fb5d91 b/data/collaborative/text/cf1d4b27a3b2b1bba71f454cc7fb5d91 deleted file mode 100755 index 2a92b64..0000000 --- a/data/collaborative/text/cf1d4b27a3b2b1bba71f454cc7fb5d91 +++ /dev/null @@ -1,3 +0,0 @@ -s:79:""; \ No newline at end of file diff --git a/data/collaborative/text/cfc98c3ef6b134046f878c0d1e586623 b/data/collaborative/text/cfc98c3ef6b134046f878c0d1e586623 deleted file mode 100755 index 7061009..0000000 --- a/data/collaborative/text/cfc98c3ef6b134046f878c0d1e586623 +++ /dev/null @@ -1,10281 +0,0 @@ -s:441251:"(function() { -/** - * almond 0.2.5 Copyright (c) 2011-2012, The Dojo Foundation All Rights Reserved. - * Available via the MIT or new BSD license. - * see: http://github.com/jrburke/almond for details - */ -//Going sloppy to avoid 'use strict' string cost, but strict practices should -//be followed. -/*jslint sloppy: true */ -/*global setTimeout: false */ - -var requirejs, require, define; -(function (undef) { - var main, req, makeMap, handlers, - defined = {}, - waiting = {}, - config = {}, - defining = {}, - hasOwn = Object.prototype.hasOwnProperty, - aps = [].slice; - - function hasProp(obj, prop) { - return hasOwn.call(obj, prop); - } - - /** - * Given a relative module name, like ./something, normalize it to - * a real name that can be mapped to a path. - * @param {String} name the relative name - * @param {String} baseName a real name that the name arg is relative - * to. - * @returns {String} normalized name - */ - function normalize(name, baseName) { - var nameParts, nameSegment, mapValue, foundMap, - foundI, foundStarMap, starI, i, j, part, - baseParts = baseName && baseName.split("/"), - map = config.map, - starMap = (map && map['*']) || {}; - - //Adjust any relative paths. - if (name && name.charAt(0) === ".") { - //If have a base name, try to normalize against it, - //otherwise, assume it is a top-level require that will - //be relative to baseUrl in the end. - if (baseName) { - //Convert baseName to array, and lop off the last part, - //so that . matches that "directory" and not name of the baseName's - //module. For instance, baseName of "one/two/three", maps to - //"one/two/three.js", but we want the directory, "one/two" for - //this normalization. - baseParts = baseParts.slice(0, baseParts.length - 1); - - name = baseParts.concat(name.split("/")); - - //start trimDots - for (i = 0; i < name.length; i += 1) { - part = name[i]; - if (part === ".") { - name.splice(i, 1); - i -= 1; - } else if (part === "..") { - if (i === 1 && (name[2] === '..' || name[0] === '..')) { - //End of the line. Keep at least one non-dot - //path segment at the front so it can be mapped - //correctly to disk. Otherwise, there is likely - //no path mapping for a path starting with '..'. - //This can still fail, but catches the most reasonable - //uses of .. - break; - } else if (i > 0) { - name.splice(i - 1, 2); - i -= 2; - } - } - } - //end trimDots - - name = name.join("/"); - } else if (name.indexOf('./') === 0) { - // No baseName, so this is ID is resolved relative - // to baseUrl, pull off the leading dot. - name = name.substring(2); - } - } - - //Apply map config if available. - if ((baseParts || starMap) && map) { - nameParts = name.split('/'); - - for (i = nameParts.length; i > 0; i -= 1) { - nameSegment = nameParts.slice(0, i).join("/"); - - if (baseParts) { - //Find the longest baseName segment match in the config. - //So, do joins on the biggest to smallest lengths of baseParts. - for (j = baseParts.length; j > 0; j -= 1) { - mapValue = map[baseParts.slice(0, j).join('/')]; - - //baseName segment has config, find if it has one for - //this name. - if (mapValue) { - mapValue = mapValue[nameSegment]; - if (mapValue) { - //Match, update name to the new value. - foundMap = mapValue; - foundI = i; - break; - } - } - } - } - - if (foundMap) { - break; - } - - //Check for a star map match, but just hold on to it, - //if there is a shorter segment match later in a matching - //config, then favor over this star map. - if (!foundStarMap && starMap && starMap[nameSegment]) { - foundStarMap = starMap[nameSegment]; - starI = i; - } - } - - if (!foundMap && foundStarMap) { - foundMap = foundStarMap; - foundI = starI; - } - - if (foundMap) { - nameParts.splice(0, foundI, foundMap); - name = nameParts.join('/'); - } - } - - return name; - } - - function makeRequire(relName, forceSync) { - return function () { - //A version of a require function that passes a moduleName - //value for items that may need to - //look up paths relative to the moduleName - return req.apply(undef, aps.call(arguments, 0).concat([relName, forceSync])); - }; - } - - function makeNormalize(relName) { - return function (name) { - return normalize(name, relName); - }; - } - - function makeLoad(depName) { - return function (value) { - defined[depName] = value; - }; - } - - function callDep(name) { - if (hasProp(waiting, name)) { - var args = waiting[name]; - delete waiting[name]; - defining[name] = true; - main.apply(undef, args); - } - - if (!hasProp(defined, name) && !hasProp(defining, name)) { - throw new Error('No ' + name); - } - return defined[name]; - } - - //Turns a plugin!resource to [plugin, resource] - //with the plugin being undefined if the name - //did not have a plugin prefix. - function splitPrefix(name) { - var prefix, - index = name ? name.indexOf('!') : -1; - if (index > -1) { - prefix = name.substring(0, index); - name = name.substring(index + 1, name.length); - } - return [prefix, name]; - } - - /** - * Makes a name map, normalizing the name, and using a plugin - * for normalization if necessary. Grabs a ref to plugin - * too, as an optimization. - */ - makeMap = function (name, relName) { - var plugin, - parts = splitPrefix(name), - prefix = parts[0]; - - name = parts[1]; - - if (prefix) { - prefix = normalize(prefix, relName); - plugin = callDep(prefix); - } - - //Normalize according - if (prefix) { - if (plugin && plugin.normalize) { - name = plugin.normalize(name, makeNormalize(relName)); - } else { - name = normalize(name, relName); - } - } else { - name = normalize(name, relName); - parts = splitPrefix(name); - prefix = parts[0]; - name = parts[1]; - if (prefix) { - plugin = callDep(prefix); - } - } - - //Using ridiculous property names for space reasons - return { - f: prefix ? prefix + '!' + name : name, //fullName - n: name, - pr: prefix, - p: plugin - }; - }; - - function makeConfig(name) { - return function () { - return (config && config.config && config.config[name]) || {}; - }; - } - - handlers = { - require: function (name) { - return makeRequire(name); - }, - exports: function (name) { - var e = defined[name]; - if (typeof e !== 'undefined') { - return e; - } else { - return (defined[name] = {}); - } - }, - module: function (name) { - return { - id: name, - uri: '', - exports: defined[name], - config: makeConfig(name) - }; - } - }; - - main = function (name, deps, callback, relName) { - var cjsModule, depName, ret, map, i, - args = [], - usingExports; - - //Use name if no relName - relName = relName || name; - - //Call the callback to define the module, if necessary. - if (typeof callback === 'function') { - - //Pull out the defined dependencies and pass the ordered - //values to the callback. - //Default to [require, exports, module] if no deps - deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps; - for (i = 0; i < deps.length; i += 1) { - map = makeMap(deps[i], relName); - depName = map.f; - - //Fast path CommonJS standard dependencies. - if (depName === "require") { - args[i] = handlers.require(name); - } else if (depName === "exports") { - //CommonJS module spec 1.1 - args[i] = handlers.exports(name); - usingExports = true; - } else if (depName === "module") { - //CommonJS module spec 1.1 - cjsModule = args[i] = handlers.module(name); - } else if (hasProp(defined, depName) || - hasProp(waiting, depName) || - hasProp(defining, depName)) { - args[i] = callDep(depName); - } else if (map.p) { - map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {}); - args[i] = defined[depName]; - } else { - throw new Error(name + ' missing ' + depName); - } - } - - ret = callback.apply(defined[name], args); - - if (name) { - //If setting exports via "module" is in play, - //favor that over return value and exports. After that, - //favor a non-undefined return value over exports use. - if (cjsModule && cjsModule.exports !== undef && - cjsModule.exports !== defined[name]) { - defined[name] = cjsModule.exports; - } else if (ret !== undef || !usingExports) { - //Use the return value from the function. - defined[name] = ret; - } - } - } else if (name) { - //May just be an object definition for the module. Only - //worry about defining if have a module name. - defined[name] = callback; - } - }; - - requirejs = require = req = function (deps, callback, relName, forceSync, alt) { - if (typeof deps === "string") { - if (handlers[deps]) { - //callback in this case is really relName - return handlers[deps](callback); - } - //Just return the module wanted. In this scenario, the - //deps arg is the module name, and second arg (if passed) - //is just the relName. - //Normalize module name, if it contains . or .. - return callDep(makeMap(deps, callback).f); - } else if (!deps.splice) { - //deps is a config object, not an array. - config = deps; - if (callback.splice) { - //callback is an array, which means it is a dependency list. - //Adjust args if there are dependencies - deps = callback; - callback = relName; - relName = null; - } else { - deps = undef; - } - } - - //Support require(['a']) - callback = callback || function () {}; - - //If relName is a function, it is an errback handler, - //so remove it. - if (typeof relName === 'function') { - relName = forceSync; - forceSync = alt; - } - - //Simulate async callback; - if (forceSync) { - main(undef, deps, callback, relName); - } else { - //Using a non-zero value because of concern for what old browsers - //do, and latest browsers "upgrade" to 4 if lower value is used: - //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout: - //If want a value immediately, use require('id') instead -- something - //that works in almond on the global level, but not guaranteed and - //unlikely to work in other AMD implementations. - setTimeout(function () { - main(undef, deps, callback, relName); - }, 4); - } - - return req; - }; - - /** - * Just drops the config on the floor, but returns req in case - * the config return value is used. - */ - req.config = function (cfg) { - config = cfg; - if (config.deps) { - req(config.deps, config.callback); - } - return req; - }; - - define = function (name, deps, callback) { - - //This module may not have dependencies - if (!deps.splice) { - //deps is not an array, so probably means - //an object literal or factory function for - //the value. Adjust args. - callback = deps; - deps = []; - } - - if (!hasProp(defined, name) && !hasProp(waiting, name)) { - waiting[name] = [name, deps, callback]; - } - }; - - define.amd = { - jQuery: true - }; -}()); - -define("libs/almond", function(){}); - -/*! jQuery v1.8.3 jquery.com | jquery.org/license */ -(function (){ -(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write(""),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t
    a",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="
    t
    ",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="
    ",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;ti.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="
    ",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="

    ",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t0)for(i=r;i=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*\s*$/g,Nt={option:[1,""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X
    ","
    "]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1>");try{for(;r1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]===""&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("
    ").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window); -jQuery.noConflict(true); -})(); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('jqueryPlugins',["jquery"], function ($) { - // This isn't really a "module" since it just patches jQuery itself - - // FIX ME Animations TO DO - // walkthrough animations go here - // animate participant cursor and box popping in when they enter the session - // animate participant cursor and box popping out when they leave the session - // animate the participant cursor -> rotate down when they're down the page - $.fn.rotateCursorDown = function () { - $('svg').animate({borderSpacing: -150, opacity: 1}, { - step: function(now, fx) { - if (fx.prop == "borderSpacing") { - $(this).css('-webkit-transform', 'rotate('+now+'deg)') - .css('-moz-transform', 'rotate('+now+'deg)') - .css('-ms-transform', 'rotate('+now+'deg)') - .css('-o-transform', 'rotate('+now+'deg)') - .css('transform', 'rotate('+now+'deg)'); - } else { - $(this).css(fx.prop, now); - } - }, - duration: 500 - }, 'linear').promise().then(function () { - this.css('-webkit-transform', ''); - this.css('-moz-transform', ''); - this.css('-ms-transform', ''); - this.css('-o-transform', ''); - this.css('transform', ''); - this.css("opacity", ""); - }); - }; - - // animate the participant cursor -> rotate up when they're on the same frame as the user - $.fn.rotateCursorDown = function () { - $('.togetherjs-cursor svg').animate({borderSpacing: 0, opacity: 1}, { - step: function(now, fx) { - if (fx.prop == "borderSpacing") { - $(this).css('-webkit-transform', 'rotate('+now+'deg)') - .css('-moz-transform', 'rotate('+now+'deg)') - .css('-ms-transform', 'rotate('+now+'deg)') - .css('-o-transform', 'rotate('+now+'deg)') - .css('transform', 'rotate('+now+'deg)'); - } else { - $(this).css(fx.prop, now); - } - }, - duration: 500 - }, 'linear').promise().then(function () { - this.css('-webkit-transform', ''); - this.css('-moz-transform', ''); - this.css('-ms-transform', ''); - this.css('-o-transform', ''); - this.css('transform', ''); - this.css("opacity", ""); - }); - }; - - // Move notification when another notification slides in // - - - /* Pop in window from dock button: */ - $.fn.popinWindow = function () { - - //mobile popout window with no animation - if($.browser.mobile) { - - //starting position - this.css({ - left: "0px", - opacity: 1, - "zIndex": 8888 - }); - - //starting position for arrow - $('#togetherjs-window-pointer-right').css({ - left: "+=74px", - opacity: 1, - "zIndex": 8888 - }); - - //animate arrow out - $('#togetherjs-window-pointer-right').animate({ - opacity: 1, - left: "-=78px" - }, { - duration:60, easing:"linear" - }); - $('#togetherjs-window-pointer-right').queue(); - - //bounce arrow back - $('#togetherjs-window-pointer-right').animate({ - left:'+=4px' - }, { - duration:60, easing:"linear" - }); - - //animate window out - this.animate({ - opacity: 1, - left: "0px" - }, { - duration:60, easing:"linear" - }); - this.queue(); - - //bounce window back - this.animate({ - left:'0px' - }, { - duration:60, easing:"linear" - }); - } - - else { - - //starting position - this.css({ - left: "+=74px", - opacity: 1, - "zIndex": 8888 - }); - - //starting position for arrow - $('#togetherjs-window-pointer-right').css({ - left: "+=74px", - opacity: 1, - "zIndex": 8888 - }); - - //animate arrow out - $('#togetherjs-window-pointer-right').animate({ - opacity: 1, - left: "-=78px" - }, { - duration:60, easing:"linear" - }); - $('#togetherjs-window-pointer-right').queue(); - - //bounce arrow back - $('#togetherjs-window-pointer-right').animate({ - left:'+=4px' - }, { - duration:60, easing:"linear" - }); - - //animate window out - this.animate({ - opacity: 1, - left: "-=78px" - }, { - duration:60, easing:"linear" - }); - this.queue(); - - //bounce window back - this.animate({ - left:'+=4px' - }, { - duration:60, easing:"linear" - }); - - } - - }; - - /* Slide in notification window: */ - $.fn.slideIn = function () { - this.css({ - //top: "240px", - left: "+=74px", - opacity: 0, - "zIndex": 8888 - }); - return this.animate({ - "left": "-=74px", - opacity: 1, - "zIndex": 9999 - }, "fast"); - }; - - /* Used to fade away notification windows + flip the bottom of them out: */ - $.fn.fadeOut = function () { - this.animate({borderSpacing: -90, opacity: 0.5}, { - step: function(now, fx) { - if (fx.prop == "borderSpacing") { - $(this).css('-webkit-transform', 'perspective( 600px ) rotateX('+now+'deg)') - .css('-moz-transform', 'perspective( 600px ) rotateX('+now+'deg)') - .css('-ms-transform', 'perspective( 600px ) rotateX('+now+'deg)') - .css('-o-transform', 'perspective( 600px ) rotateX('+now+'deg)') - .css('transform', 'perspective( 600px ) rotateX('+now+'deg)'); - } else { - $(this).css(fx.prop, now); - } - }, - duration: 500 - }, 'linear').promise().then(function () { - this.css('-webkit-transform', ''); - this.css('-moz-transform', ''); - this.css('-ms-transform', ''); - this.css('-o-transform', ''); - this.css('transform', ''); - this.css("opacity", ""); - }); - return this; - }; - - /* used when user goes down to participant cursor location on screen */ - $.fn.easeTo = function (y) { - return this.animate({ - scrollTop: y - }, { - duration: 400, - easing: "swing" - }); - }; - - // avatar animate in - $.fn.animateDockEntry = function () { - var height = this.height(); - var width = this.width(); - var backgroundSize = height + 4; - var margin = parseInt(this.css("marginLeft"), 10); - - // set starting position CSS for avatar - this.css({ - marginLeft: margin + width/2, - height: 0, - width: 0, - backgroundSize: "0 0" - }); - - var self = this; - - //then animate avatar to the actual dimensions, and reset the values - this.animate({ - marginLeft: margin, - height: height, - width: width, - backgroundSize: backgroundSize - }, { - duration: 600 - }).promise().then(function () { - self.css({ - marginLeft: "", - height: "", - width: "", - backgroundSize: "" - }); - }); - return this; - }; - - // avatar animate out, reverse of above - $.fn.animateDockExit = function () { - - // get the current avatar dimenensions - var height = this.height(); - var width = this.width(); - var backgroundSize = height + 4; - var margin = parseInt(this.css("marginLeft"), 10); - - //then animate avatar to shrink to nothing, and reset the values again - // FIXME this needs to animate from the CENTER - this.animate({ - marginLeft: margin + width/2, - height: 0, - width: 0, - backgroundSize: "0 0", - opacity: 0 - }, 600 ); - - return this; - - }; - - $.fn.animateCursorEntry = function () { - // Make the cursor bubble pop in - }; - - // keyboard typing animation - $.fn.animateKeyboard = function () { - var one = this.find(".togetherjs-typing-ellipse-one"); - var two = this.find(".togetherjs-typing-ellipse-two"); - var three = this.find(".togetherjs-typing-ellipse-three"); - var count = -1; - var run = (function () { - count = (count+1) % 4; - if (count === 0) { - one.css("opacity", 0.5); - two.css("opacity", 0.5); - three.css("opacity", 0.5); - } else if (count == 1) { - one.css("opacity", 1); - } else if (count == 2) { - two.css("opacity", 1); - } else { // count==3 - three.css("opacity", 1); - } - }).bind(this); - run(); - var interval = setInterval(run, 300); - this.data("animateKeyboard", interval); - }; - - $.fn.stopKeyboardAnimation = function () { - clearTimeout(this.data("animateKeyboard")); - this.data("animateKeyboard", null); - }; - - // FIXME: not sure if this is legit, but at least the modern mobile devices we - // care about should have this defined: - if (! $.browser) { - $.browser = {}; - } - $.browser.mobile = window.orientation !== undefined; - if (navigator.userAgent.search(/mobile/i) != -1) { - // FIXME: At least on the Firefox OS simulator I need this - $.browser.mobile = true; - } - - if ($.browser.mobile && window.matchMedia && ! window.matchMedia("screen and (max-screen-width: 480px)").matches) { - // FIXME: for Firefox OS simulator really: - document.body.className += " togetherjs-mobile-browser"; - } - -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('util',["jquery", "jqueryPlugins"], function ($) { - var util = {}; - - util.Deferred = $.Deferred; - TogetherJS.$ = $; - - /* A simple class pattern, use like: - - var Foo = util.Class({ - constructor: function (a, b) { - init the class - }, - otherMethod: ... - }); - - You can also give a superclass as the optional first argument. - - Instantiation does not require "new" - - */ - util.Class = function (superClass, prototype) { - var a; - if (prototype === undefined) { - prototype = superClass; - } else { - if (superClass.prototype) { - superClass = superClass.prototype; - } - var newPrototype = Object.create(superClass); - for (a in prototype) { - if (prototype.hasOwnProperty(a)) { - newPrototype[a] = prototype[a]; - } - } - prototype = newPrototype; - } - var ClassObject = function () { - var obj = Object.create(prototype); - obj.constructor.apply(obj, arguments); - obj.constructor = ClassObject; - return obj; - }; - ClassObject.prototype = prototype; - if (prototype.constructor.name) { - ClassObject.className = prototype.constructor.name; - ClassObject.toString = function () { - return '[Class ' + this.className + ']'; - }; - } - if (prototype.classMethods) { - for (a in prototype.classMethods) { - if (prototype.classMethods.hasOwnProperty(a)) { - ClassObject[a] = prototype.classMethods[a]; - } - } - } - return ClassObject; - }; - - /* Extends obj with other, or copies obj if no other is given. */ - util.extend = TogetherJS._extend; - - util.forEachAttr = function (obj, callback, context) { - context = context || obj; - for (var a in obj) { - if (obj.hasOwnProperty(a)) { - callback.call(context, obj[a], a); - } - } - }; - - /* Trim whitespace from a string */ - util.trim = function trim(s) { - return s.replace(/^\s+/, "").replace(/\s+$/, ""); - }; - - /* Convert a string into something safe to use as an HTML class name */ - util.safeClassName = function safeClassName(name) { - return name.replace(/[^a-zA-Z0-9_\-]/g, "_") || "class"; - }; - - util.AssertionError = function (message) { - if (! this instanceof util.AssertionError) { - return new util.AssertionError(message); - } - this.message = message; - this.name = "AssertionError"; - }; - util.AssertionError.prototype = Error.prototype; - - util.assert = function (cond) { - if (! cond) { - var args = ["Assertion error:"].concat(Array.prototype.slice.call(arguments, 1)); - console.error.apply(console, args); - if (console.trace) { - console.trace(); - } - throw new util.AssertionError(args.join(" ")); - } - }; - - /* Generates a random ID */ - util.generateId = function (length) { - length = length || 10; - var letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV0123456789'; - var s = ''; - for (var i=0; i this.backoffDetection) { - this._backoff = 0; - } else { - this._backoff++; - } - var time = Math.min(this._backoff * this.backoffTime, this.maxBackoffTime); - setTimeout((function () { - this._setupConnection(); - }).bind(this), time); - } - }).bind(this); - this.socket.onmessage = (function (event) { - this._incoming(event.data); - }).bind(this); - this.socket.onerror = (function (event) { - console.error('WebSocket error:', event.data); - }).bind(this); - } - -}); - - -/* Sends TO a window or iframe */ -channels.PostMessageChannel = util.Class(AbstractChannel, { - _pingPollPeriod: 100, // milliseconds - _pingPollIncrease: 100, // +100 milliseconds for each failure - _pingMax: 2000, // up to a max of 2000 milliseconds - - constructor: function (win, expectedOrigin) { - this.expectedOrigin = expectedOrigin; - this._pingReceived = false; - this._receiveMessage = this._receiveMessage.bind(this); - if (win) { - this.bindWindow(win, true); - } - this._pingFailures = 0; - this.baseConstructor(); - }, - - toString: function () { - var s = '[PostMessageChannel'; - if (this.window) { - s += ' to window ' + this.window; - } else { - s += ' not bound to a window'; - } - if (this.window && ! this._pingReceived) { - s += ' still establishing'; - } - return s + ']'; - }, - - bindWindow: function (win, noSetup) { - if (this.window) { - this.close(); - // Though we deinitialized everything, we aren't exactly closed: - this.closed = false; - } - if (win && win.contentWindow) { - win = win.contentWindow; - } - this.window = win; - // FIXME: The distinction between this.window and window seems unimportant - // in the case of postMessage - var w = this.window; - // In a Content context we add the listener to the local window - // object, but in the addon context we add the listener to some - // other window, like the one we were given: - if (typeof window != "undefined") { - w = window; - } - w.addEventListener("message", this._receiveMessage, false); - if (! noSetup) { - this._setupConnection(); - } - }, - - _send: function (data) { - this.window.postMessage(data, this.expectedOrigin || "*"); - }, - - _ready: function () { - return this.window && this._pingReceived; - }, - - _setupConnection: function () { - if (this.closed || this._pingReceived || (! this.window)) { - return; - } - this._pingFailures++; - this._send("hello"); - // We'll keep sending ping messages until we get a reply - var time = this._pingPollPeriod + (this._pingPollIncrease * this._pingFailures); - time = time > this._pingPollMax ? this._pingPollMax : time; - this._pingTimeout = setTimeout(this._setupConnection.bind(this), time); - }, - - _receiveMessage: function (event) { - if (event.source !== this.window) { - return; - } - if (this.expectedOrigin && event.origin != this.expectedOrigin) { - console.info("Expected message from", this.expectedOrigin, - "but got message from", event.origin); - return; - } - if (! this.expectedOrigin) { - this.expectedOrigin = event.origin; - } - if (event.data == "hello") { - this._pingReceived = true; - if (this._pingTimeout) { - clearTimeout(this._pingTimeout); - this._pingTimeout = null; - } - this._flush(); - return; - } - this._incoming(event.data); - }, - - close: function () { - this.closed = true; - this._pingReceived = false; - if (this._pingTimeout) { - clearTimeout(this._pingTimeout); - } - window.removeEventListener("message", this._receiveMessage, false); - if (this.onclose) { - this.onclose(); - } - this.emit("close"); - } - -}); - - -/* Handles message FROM an exterior window/parent */ -channels.PostMessageIncomingChannel = util.Class(AbstractChannel, { - - constructor: function (expectedOrigin) { - this.source = null; - this.expectedOrigin = expectedOrigin; - this._receiveMessage = this._receiveMessage.bind(this); - window.addEventListener("message", this._receiveMessage, false); - this.baseConstructor(); - }, - - toString: function () { - var s = '[PostMessageIncomingChannel'; - if (this.source) { - s += ' bound to source ' + s; - } else { - s += ' awaiting source'; - } - return s + ']'; - }, - - _send: function (data) { - this.source.postMessage(data, this.expectedOrigin); - }, - - _ready: function () { - return !!this.source; - }, - - _setupConnection: function () { - }, - - _receiveMessage: function (event) { - if (this.expectedOrigin && this.expectedOrigin != "*" && - event.origin != this.expectedOrigin) { - // FIXME: Maybe not worth mentioning? - console.info("Expected message from", this.expectedOrigin, - "but got message from", event.origin); - return; - } - if (! this.expectedOrigin) { - this.expectedOrigin = event.origin; - } - if (! this.source) { - this.source = event.source; - } - if (event.data == "hello") { - // Just a ping - this.source.postMessage("hello", this.expectedOrigin); - return; - } - this._incoming(event.data); - }, - - close: function () { - this.closed = true; - window.removeEventListener("message", this._receiveMessage, false); - if (this._pingTimeout) { - clearTimeout(this._pingTimeout); - } - if (this.onclose) { - this.onclose(); - } - this.emit("close"); - } - -}); - -channels.Router = util.Class(util.mixinEvents({ - - constructor: function (channel) { - this._channelMessage = this._channelMessage.bind(this); - this._channelClosed = this._channelClosed.bind(this); - this._routes = Object.create(null); - if (channel) { - this.bindChannel(channel); - } - }, - - bindChannel: function (channel) { - if (this.channel) { - this.channel.removeListener("message", this._channelMessage); - this.channel.removeListener("close", this._channelClosed); - } - this.channel = channel; - this.channel.on("message", this._channelMessage.bind(this)); - this.channel.on("close", this._channelClosed.bind(this)); - }, - - _channelMessage: function (msg) { - if (msg.type == "route") { - var id = msg.routeId; - var route = this._routes[id]; - if (! route) { - console.warn("No route with the id", id); - return; - } - if (msg.close) { - this._closeRoute(route.id); - } else { - if (route.onmessage) { - route.onmessage(msg.message); - } - route.emit("message", msg.message); - } - } - }, - - _channelClosed: function () { - for (var id in this._routes) { - this._closeRoute(id); - } - }, - - _closeRoute: function (id) { - var route = this._routes[id]; - if (route.onclose) { - route.onclose(); - } - route.emit("close"); - delete this._routes[id]; - }, - - makeRoute: function (id) { - id = id || util.generateId(); - var route = Route(this, id); - this._routes[id] = route; - return route; - } -})); - -var Route = util.Class(util.mixinEvents({ - constructor: function (router, id) { - this.router = router; - this.id = id; - }, - - send: function (msg) { - this.router.channel.send({ - type: "route", - routeId: this.id, - message: msg - }); - }, - - close: function () { - if (this.router._routes[this.id] !== this) { - // This route instance has been overwritten, so ignore - return; - } - delete this.router._routes[this.id]; - } - -})); - -return channels; - -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('storage',["util"], function (util) { - var assert = util.assert; - var Deferred = util.Deferred; - var DEFAULT_SETTINGS = { - name: "", - defaultName: "", - avatar: null, - stickyShare: null, - color: null, - seenIntroDialog: false, - seenWalkthrough: false, - dontShowRtcInfo: false - }; - - var DEBUG_STORAGE = false; - - var Storage = util.Class({ - constructor: function (name, storage, prefix) { - this.name = name; - this.storage = storage; - this.prefix = prefix; - }, - - get: function (key, defaultValue) { - var self = this; - return Deferred(function (def) { - // Strictly this isn't necessary, but eventually I want to move to something more - // async for the storage, and this simulates that much better. - setTimeout(util.resolver(def, function () { - key = self.prefix + key; - var value = self.storage.getItem(key); - if (! value) { - value = defaultValue; - if (DEBUG_STORAGE) { - console.debug("Get storage", key, "defaults to", value); - } - } else { - value = JSON.parse(value); - if (DEBUG_STORAGE) { - console.debug("Get storage", key, "=", value); - } - } - return value; - })); - }); - }, - - set: function (key, value) { - var self = this; - if (value !== undefined) { - value = JSON.stringify(value); - } - return Deferred(function (def) { - key = self.prefix + key; - if (value === undefined) { - self.storage.removeItem(key); - if (DEBUG_STORAGE) { - console.debug("Delete storage", key); - } - } else { - self.storage.setItem(key, value); - if (DEBUG_STORAGE) { - console.debug("Set storage", key, value); - } - } - setTimeout(def.resolve); - }); - }, - - clear: function () { - var self = this; - var promises = []; - return Deferred((function (def) { - this.keys().then(function (keys) { - keys.forEach(function (key) { - // FIXME: technically we're ignoring the promise returned by all - // these sets: - promises.push(self.set(key, undefined)); - }); - util.resolveMany(promises).then(function () { - def.resolve(); - }); - }); - }).bind(this)); - }, - - keys: function (prefix, excludePrefix) { - // Returns a list of keys, potentially with the given prefix - var self = this; - return Deferred(function (def) { - setTimeout(util.resolver(def, function () { - prefix = prefix || ""; - var result = []; - for (var i = 0; i < self.storage.length; i++) { - var key = self.storage.key(i); - if (key.indexOf(self.prefix + prefix) === 0) { - var shortKey = key.substr(self.prefix.length); - if (excludePrefix) { - shortKey = shortKey.substr(prefix.length); - } - result.push(shortKey); - } - } - return result; - })); - }); - }, - - toString: function () { - return '[storage for ' + this.name + ']'; - } - - }); - - var namePrefix = TogetherJS.config.get("storagePrefix"); - TogetherJS.config.close("storagePrefix"); - - var storage = Storage('localStorage', localStorage, namePrefix + "."); - - storage.settings = util.mixinEvents({ - defaults: DEFAULT_SETTINGS, - - get: function (name) { - assert(storage.settings.defaults.hasOwnProperty(name), "Unknown setting:", name); - return storage.get("settings." + name, storage.settings.defaults[name]); - }, - - set: function (name, value) { - assert(storage.settings.defaults.hasOwnProperty(name), "Unknown setting:", name); - return storage.set("settings." + name, value); - } - - }); - - storage.tab = Storage('sessionStorage', sessionStorage, namePrefix + "-session."); - - return storage; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('session',["require", "util", "channels", "jquery", "storage"], function (require, util, channels, $, storage) { - - var DEBUG = true; - - // This is the amount of time in which a hello-back must be received after a hello - // for us to respect a URL change: - var HELLO_BACK_CUTOFF = 1500; - - var session = util.mixinEvents(util.Module("session")); - var assert = util.assert; - - // We will load this module later (there's a circular import): - var peers; - - // This is the hub we connect to: - session.shareId = null; - // This is the ID that identifies this client: - session.clientId = null; - session.router = channels.Router(); - // Indicates if TogetherJS has just started (not continuing from a saved session): - session.firstRun = false; - - // This is the key we use for localStorage: - var localStoragePrefix = "togetherjs."; - // This is the channel to the hub: - var channel = null; - - // Setting, essentially global: - session.AVATAR_SIZE = 90; - - var MAX_SESSION_AGE = 30*24*60*60*1000; // 30 days - - /**************************************** - * URLs - */ - var includeHashInUrl = TogetherJS.config.get("includeHashInUrl"); - TogetherJS.config.close("includeHashInUrl"); - var currentUrl = (location.href + "").replace(/\#.*$/, ""); - if (includeHashInUrl) { - currentUrl = location.href; - } - - session.hubUrl = function (id) { - id = id || session.shareId; - assert(id, "URL cannot be resolved before TogetherJS.shareId has been initialized"); - TogetherJS.config.close("hubBase"); - var hubBase = TogetherJS.config.get("hubBase"); - return hubBase.replace(/\/*$/, "") + "/hub/" + id; - }; - - session.shareUrl = function () { - assert(session.shareId, "Attempted to access shareUrl() before shareId is set"); - var hash = location.hash; - var m = /\?[^#]*/.exec(location.href); - var query = ""; - if (m) { - query = m[0]; - } - hash = hash.replace(/&?togetherjs-[a-zA-Z0-9]+/, ""); - hash = hash || "#"; - return location.protocol + "//" + location.host + location.pathname + query + - hash + "&togetherjs=" + session.shareId; - }; - - session.recordUrl = function () { - assert(session.shareId); - var url = TogetherJS.baseUrl.replace(/\/*$/, "") + "/togetherjs/recorder.html"; - url += "#&togetherjs=" + session.shareId + "&hubBase=" + TogetherJS.config.get("hubBase"); - return url; - }; - - /* location.href without the hash */ - session.currentUrl = function () { - if (includeHashInUrl) { - return location.href; - } else { - return location.href.replace(/#.*/, ""); - } - }; - - /**************************************** - * Message handling/dispatching - */ - - session.hub = util.mixinEvents({}); - - var IGNORE_MESSAGES = TogetherJS.config.get("ignoreMessages"); - if (IGNORE_MESSAGES === true) { - DEBUG = false; - IGNORE_MESSAGES = []; - } - // These are messages sent by clients who aren't "part" of the TogetherJS session: - var MESSAGES_WITHOUT_CLIENTID = ["who", "invite", "init-connection"]; - - // We ignore incoming messages from the channel until this is true: - var readyForMessages = false; - - function openChannel() { - assert(! channel, "Attempt to re-open channel"); - console.info("Connecting to", session.hubUrl(), location.href); - var c = channels.WebSocketChannel(session.hubUrl()); - c.onmessage = function (msg) { - if (! readyForMessages) { - if (DEBUG) { - console.info("In (but ignored for being early):", msg); - } - return; - } - if (DEBUG && IGNORE_MESSAGES.indexOf(msg.type) == -1) { - console.info("In:", msg); - } - if (! peers) { - // We're getting messages before everything is fully initialized - console.warn("Message received before all modules loaded (ignoring):", msg); - return; - } - if ((! msg.clientId) && MESSAGES_WITHOUT_CLIENTID.indexOf(msg.type) == -1) { - console.warn("Got message without clientId, where clientId is required", msg); - return; - } - if (msg.clientId) { - msg.peer = peers.getPeer(msg.clientId, msg); - } - if (msg.type == "hello" || msg.type == "hello-back" || msg.type == "peer-update") { - // We do this here to make sure this is run before any other - // hello handlers: - msg.peer.updateFromHello(msg); - } - if (msg.peer) { - msg.sameUrl = msg.peer.url == currentUrl; - if (!msg.peer.isSelf) { - msg.peer.updateMessageDate(msg); - } - } - session.hub.emit(msg.type, msg); - TogetherJS._onmessage(msg); - }; - channel = c; - session.router.bindChannel(channel); - } - - session.send = function (msg) { - if (DEBUG && IGNORE_MESSAGES.indexOf(msg.type) == -1) { - console.info("Send:", msg); - } - msg.clientId = session.clientId; - channel.send(msg); - }; - - session.appSend = function (msg) { - var type = msg.type; - if (type.search(/^togetherjs\./) === 0) { - type = type.substr("togetherjs.".length); - } else if (type.search(/^app\./) === -1) { - type = "app." + type; - } - msg.type = type; - session.send(msg); - }; - - /**************************************** - * Standard message responses - */ - - /* Always say hello back, and keep track of peers: */ - session.hub.on("hello hello-back", function (msg) { - if (msg.type == "hello") { - sendHello(true); - } - if (session.isClient && (! msg.isClient) && - session.firstRun && session.timeHelloSent && - Date.now() - session.timeHelloSent < HELLO_BACK_CUTOFF) { - processFirstHello(msg); - } - }); - - session.hub.on("who", function (msg) { - sendHello(true); - }); - - function processFirstHello(msg) { - if (! msg.sameUrl) { - var url = msg.url; - if (msg.urlHash) { - url += msg.urlHash; - } - require("ui").showUrlChangeMessage(msg.peer, url); - location.href = url; - } - } - - session.timeHelloSent = null; - - function sendHello(helloBack) { - var msg = session.makeHelloMessage(helloBack); - if (! helloBack) { - session.timeHelloSent = Date.now(); - peers.Self.url = msg.url; - } - session.send(msg); - } - - session.makeHelloMessage = function (helloBack) { - var msg = { - name: peers.Self.name || peers.Self.defaultName, - avatar: peers.Self.avatar, - color: peers.Self.color, - url: session.currentUrl(), - urlHash: location.hash, - // FIXME: titles update, we should track those changes: - title: document.title, - rtcSupported: session.RTCSupported, - isClient: session.isClient - }; - if (helloBack) { - msg.type = "hello-back"; - } else { - msg.type = "hello"; - msg.clientVersion = TogetherJS.version; - } - if (! TogetherJS.startup.continued) { - msg.starting = true; - } - // This is a chance for other modules to effect the hello message: - session.emit("prepare-hello", msg); - return msg; - }; - /**************************************** - * Lifecycle (start and end) - */ - - // These are Javascript files that implement features, and so must - // be injected at runtime because they aren't pulled in naturally - // via define(). - // ui must be the first item: - var features = ["peers", "ui", "chat", "webrtc", "cursor", "startup", "videos", "forms", "visibilityApi", "youtubeVideos"]; - - function getRoomName(prefix, maxSize) { - var findRoom = TogetherJS.config.get("hubBase").replace(/\/*$/, "") + "/findroom"; - return $.ajax({ - url: findRoom, - dataType: "json", - data: {prefix: prefix, max: maxSize} - }).then(function (resp) { - return resp.name; - }); - } - - function initIdentityId() { - return util.Deferred(function (def) { - if (session.identityId) { - def.resolve(); - return; - } - storage.get("identityId").then(function (identityId) { - if (! identityId) { - identityId = util.generateId(); - storage.set("identityId", identityId); - } - session.identityId = identityId; - // We don't actually have to wait for the set to succede, so - // long as session.identityId is set - def.resolve(); - }); - }); - } - - initIdentityId.done = initIdentityId(); - - function initShareId() { - return util.Deferred(function (def) { - var hash = location.hash; - var shareId = session.shareId; - var isClient = true; - var set = true; - var sessionId; - session.firstRun = ! TogetherJS.startup.continued; - if (! shareId) { - if (TogetherJS.startup._joinShareId) { - // Like, below, this *also* means we got the shareId from the hash - // (in togetherjs.js): - shareId = TogetherJS.startup._joinShareId; - } - } - if (! shareId) { - // FIXME: I'm not sure if this will ever happen, because togetherjs.js should - // handle it - var m = /&?togetherjs=([^&]*)/.exec(hash); - if (m) { - isClient = ! m[1]; - shareId = m[2]; - var newHash = hash.substr(0, m.index) + hash.substr(m.index + m[0].length); - location.hash = newHash; - } - } - return storage.tab.get("status").then(function (saved) { - var findRoom = TogetherJS.config.get("findRoom"); - TogetherJS.config.close("findRoom"); - if (findRoom && saved && findRoom != saved.shareId) { - console.info("Ignoring findRoom in lieu of continued session"); - } else if (findRoom && TogetherJS.startup._joinShareId) { - console.info("Ignoring findRoom in lieu of explicit invite to session"); - } - if (findRoom && typeof findRoom == "string" && (! saved) && (! TogetherJS.startup._joinShareId)) { - isClient = true; - shareId = findRoom; - sessionId = util.generateId(); - } else if (findRoom && (! saved) && (! TogetherJS.startup._joinShareId)) { - assert(findRoom.prefix && typeof findRoom.prefix == "string", "Bad findRoom.prefix", findRoom); - assert(findRoom.max && typeof findRoom.max == "number" && findRoom.max > 0, - "Bad findRoom.max", findRoom); - sessionId = util.generateId(); - if (findRoom.prefix.search(/[^a-zA-Z0-9]/) != -1) { - console.warn("Bad value for findRoom.prefix:", JSON.stringify(findRoom.prefix)); - } - getRoomName(findRoom.prefix, findRoom.max).then(function (shareId) { - // FIXME: duplicates code below: - session.clientId = session.identityId + "." + sessionId; - storage.tab.set("status", {reason: "joined", shareId: shareId, running: true, date: Date.now(), sessionId: sessionId}); - session.isClient = true; - session.shareId = shareId; - session.emit("shareId"); - def.resolve(session.shareId); - }); - return; - } else if (TogetherJS.startup._launch) { - if (saved) { - isClient = saved.reason == "joined"; - if (! shareId) { - shareId = saved.shareId; - } - sessionId = saved.sessionId; - } else { - isClient = TogetherJS.startup.reason == "joined"; - assert(! sessionId); - sessionId = util.generateId(); - } - if (! shareId) { - shareId = util.generateId(); - } - } else if (saved) { - isClient = saved.reason == "joined"; - TogetherJS.startup.reason = saved.reason; - TogetherJS.startup.continued = true; - shareId = saved.shareId; - sessionId = saved.sessionId; - // The only case when we don't need to set the storage status again is when - // we're already set to be running - set = ! saved.running; - } else { - throw new util.AssertionError("No saved status, and no startup._launch request; why did TogetherJS start?"); - } - assert(session.identityId); - session.clientId = session.identityId + "." + sessionId; - if (set) { - storage.tab.set("status", {reason: TogetherJS.startup.reason, shareId: shareId, running: true, date: Date.now(), sessionId: sessionId}); - } - session.isClient = isClient; - session.shareId = shareId; - session.emit("shareId"); - def.resolve(session.shareId); - }); - }); - } - - function initStartTarget() { - var id; - if (TogetherJS.startup.button) { - id = TogetherJS.startup.button.id; - if (id) { - storage.set("startTarget", id); - } - return; - } - storage.get("startTarget").then(function (id) { - var el = document.getElementById(id); - if (el) { - TogetherJS.startup.button = el; - } - }); - } - session.start = function () { - initStartTarget(); - initIdentityId().then(function () { - initShareId().then(function () { - readyForMessages = false; - openChannel(); - require(["ui"], function (ui) { - TogetherJS.running = true; - ui.prepareUI(); - require(features, function () { - $(function () { - peers = require("peers"); - var startup = require("startup"); - session.emit("start"); - session.once("ui-ready", function () { - readyForMessages = true; - startup.start(); - }); - ui.activateUI(); - TogetherJS.config.close("enableAnalytics"); - if (TogetherJS.config.get("enableAnalytics")) { - require(["analytics"], function (analytics) { - analytics.activate(); - }); - } - peers._SelfLoaded.then(function () { - sendHello(false); - }); - TogetherJS.emit("ready"); - }); - }); - }); - }); - }); - }; - - session.close = function (reason) { - TogetherJS.running = false; - var msg = {type: "bye"}; - if (reason) { - msg.reason = reason; - } - session.send(msg); - session.emit("close"); - var name = window.name; - storage.tab.get("status").then(function (saved) { - if (! saved) { - console.warn("No session information saved in", "status." + name); - } else { - saved.running = false; - saved.date = Date.now(); - storage.tab.set("status", saved); - } - channel.close(); - channel = null; - session.shareId = null; - session.emit("shareId"); - TogetherJS.emit("close"); - TogetherJS._teardown(); - }); - }; - - session.on("start", function () { - $(window).on("resize", resizeEvent); - if (includeHashInUrl) { - $(window).on("hashchange", hashchangeEvent); - } - }); - - session.on("close", function () { - $(window).off("resize", resizeEvent); - if (includeHashInUrl) { - $(window).off("hashchange", hashchangeEvent); - } - }); - - function hashchangeEvent() { - // needed because when message arives from peer this variable will be checked to - // decide weather to show actions or not - sendHello(false); - } - - function resizeEvent() { - session.emit("resize"); - } - - if (TogetherJS.startup._launch) { - setTimeout(session.start); - } - - util.testExpose({ - getChannel: function () { - return channel; - } - }); - - return session; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('templates',["util"], function (util) { - function clean(t) { - // Removes <% /* ... */ %> comments: - t = t.replace(/[<][%]\s*\/\*[\S\s\r\n]*\*\/\s*[%][>]/, ""); - t = util.trim(t); - t = t.replace(/http:\/\/localhost:8080/g, TogetherJS.baseUrl); - return t; - } - return { - "interface": clean("<% /*\n This is basically all the markup and interface for TogetherJS.\n Note all links should be like http://localhost:8080/togetherjs/*\n these links are rewritten with the location where TogetherJS was deployed.\n\n This file is inlined into togetherjs/templates.js\n*/ %>\n
    \n\n \n
    \n
    \n \n \"drag\"\n \n \n \"drag\"\n \n
    \n
    \n
    \n \n
    \n \n \n \n \n
    \n
    \n
    \n\n \n
    \n
    Update avatar
    \n
    \n
    \n
    \n \n \n \n
    \n
    \n
    \n \n or\n \n
    \n
    \n\n \n
    \n
    Invite a friend
    \n
    \n
    \n

    Copy and paste this link over IM or email:

    \n \n
    \n
    \n

    Copy and paste this link over IM or email:

    \n \n \n
    \n
    \n
    \n\n \n
    \n
    Participants
    \n
    \n
    \n \n
    \n
    \n\n \n
    \n
    \n\n
    \n

    Role:\n \n

    \n\n

    Currently at:\n \n

    \n\n

    Status:\n \n

    \n\n

    Follow this participant:\n \n \n

    \n\n
    \n\n
    \n \n \n \n
    \n is on the same page as you.\n
    \n
    \n
    \n\n \n
    \n
    Chat
    \n
    \n
    \n \n & You\n
    \n
    \n No one else is here.\n
    \n
    \n\n
    \n\n \n
    \n
    \n
    HH:MM AM/PM
    \n
    \n
    \n
    \n\n \n
    \n
    \n
    \n
    left the session.
    \n
    \n
    \n
    declined to join the session.
    \n
    \n
    \n
    \n\n \n
    \n
    \n
    joined the session.
    \n
    \n
    \n\n \n
    \n \n
    \n\n \n \n\n \n
    \n
    \n
    \n
    \n \n is on the same page as you.\n
    \n
    \n \n has gone to: \n
    \n \n \n
    \n\n \n\n
    \n
    \n
    \n
    \n
    \n\n
    \n \n
    \n
    \n \n
    \n
    \n\n \n
    \n\n
    Audio Chat
    \n
    \n

    \n Activate your browser microphone near your URL bar above.\n

    \n

    \n Talking on your microphone through your web browser is an experimental feature.\n

    \n

    \n Read more about Audio Chat here.\n

    \n
    \n\n
    \n \n \n
    \n
    \n\n \n
    \n
    Audio Chat
    \n\n
    \n

    Audio chat requires you to use a \n newer browser\n !

    \n

    \n Live audio chat requires a newer (or different) browser than you're using.\n

    \n

    \n See\n \n this page\n \n for more information and a list of supported browsers.\n

    \n
    \n\n
    \n
    \n \n
    \n
    \n
    \n\n \n
    \n \"\"\n \"[close]\"\n
    \n
    \n
    \n\n \n
    \n
    \n \n \n \n
    \n
    \n
    \"\" Update your name
    \n
    \"\" Change avatar
    \n
    Pick profile color
    \n
    \n
    Help
    \n
    Feedback
    \n
    \n
    \n
    \n
    Refresh users
    \n
    Invite anyone
    \n
    \n
    \n
    \"\" End TogetherJS
    \n
    \n\n \n
    \n
    \n \n \n
    \n
    \n\n \n
    \n
    Settings and Profile
    \n
    \n
    \n \n \n
    \n
    \n
    \"\" Update your name
    \n
    \"\" Change avatar
    \n
    Pick profile color
    \n
    \n
    Help
    \n
    Feedback
    \n
    \n
    \"\" End TogetherJS
    \n
    \n
    \n \n
    \n
    \n\n \n
    \n
    Update Name
    \n
    \n
    \n \n
    \n
    \n
    \n \n
    \n
    \n\n
    \n
    \n
    \n
    \n
    \n
    \n
    \n\n \n \n \n \n\n \n
    \n
    Join TogetherJS session?
    \n
    \n

    Your friend has asked you to join their TogetherJS browser session to collaborate in real-time!

    \n\n

    Would you like to join their session?

    \n
    \n\n
    \n \n \n
    \n
    \n\n \n
    \n
    Sorry
    \n\n
    \n

    \n We're sorry, TogetherJS doesn't work with this browser. Please\n upgrade\n to a supported browser to try TogetherJS.\n

    \n\n

    \n We need your help fixing TogetherJS on Internet Explorer! Here are a list of IE GitHub issues we need fixed that you can work on.\n Internet Explorer is\n currently not supported. If you do want to try out TogetherJS, we'd suggest using Firefox or Chrome.\n

    \n
    \n\n
    \n \n
    \n\n
    \n\n \n
    \n
    Unsupported Browser
    \n\n
    \n

    \n We need your help fixing TogetherJS on Internet Explorer! Here are a list of IE GitHub issues we need fixed that you can work on.\n Internet Explorer is not supported\n at this time. While we may add support later, adding support is\n not currently on our roadmap. If you do want to try out TogetherJS, we'd suggest using Firefox or Chrome.\n

    \n\n

    You can continue to try to use TogetherJS, but you are likely to hit\n lots of bugs. So be warned.

    \n\n
    \n\n
    \n \n \n
    \n\n
    \n\n
    \n
    End session?
    \n
    \n

    \n Are you sure you'd like to end your TogetherJS session?\n

    \n
    \n
    \n \n or\n \n
    \n
    \n\n
    \n
    Feedback
    \n \n \n
    \n\n
    \n \n
    \n
    Following to new URL...
    \n
    \n
    \n Following\n \n to \n
    \n
    \n\n \n
    \n
    \n
    \n \n has invited anyone\n you\n to \n
    \n
    \n\n
    \n\n \n
    \n
    \n\n \n
    \n\n \n
    \n\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n\n \n \n
    \n\n \n
    \n
    \n
    \n\n \n
    \n
    \n
    \n
    \n"), - help: clean("<% /*\n This is used to show the help when you type /help. Used in\n TogetherJS.localChatMessage().\n\n*/ %>\n/help : this message\n/test : run an automated/randomized test (or stop one that is in progress)\n /test start N : run N times (instead of default 100)\n /test show : show what kind of actions the random test would take (or stop showing)\n /test describe : describe the possible actions (instead of showing them)\n/clear : clear the chat area\n/record : open up a recorder for the session\n/playback URL : play back a session that was recorded (it's up to you to figure out how to host it)\n /playback local:NAME : play a locally saved log\n/savelogs NAME : save the currently recorded logs under NAME (recorder must be open)\n/baseurl : set a local baseUrl to load TogetherJS from, for debugging a development version of TogetherJS.\n/config : override some TogetherJS configuration parameters\n /config VAR VALUE : set TogetherJS.config(\"VAR\", VALUE). VALUE must be a legal Javascript/JSON literal.\n /config clear : remove all overridden configuration\n"), - walkthrough: clean("\n
    \n
    You're using TogetherJS!
    \n\n
    \n
    \n\n
    \n

    \n\t

    TogetherJS is a service for your website that makes it easy to collaborate in real-time on: [site name]

    \n
    \n\n
    \n
    \n
    \n
    \n
    \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n

    Set up your avatar, name and user color above. If you'd like to update it later, you can click your Profile button.

    \n
    \n
    \n

    \n

    Change your avatar, name and user color using the Profile button.

    \n
    \n
    \n\n
    \n

    \n

    \n

    You can invite more friends to the session by sending the invite link in the TogetherJS dock.

    \n

    \n \n Copy and paste this link into IM or email to invite friends.\n \n \n

    \n

    Send the above link to a friend so they can join your session! You can find this invite link on the TogetherJS dock as well.

    \n
    \n\n
    \n

    \n

    Friends who join your TogetherJS session will appear here. You can click their avatars to see more.

    \n
    \n\n
    \n

    \n

    When your friends join you in your TogetherJS session, you can chat with them here!

    \n
    \n\n
    \n

    \n

    If your browser supports it, click the microphone icon to begin a audio chat. Learn more about this experimental feature here.

    \n
    \n\n
    \n

    \n

    Alright, you're ready to use TogetherJS. Now start collaborating on [site name]!

    \n
    \n\n
    \n \n \n
    \n
    \n
    \n\n
    \n \n
    \n\n
    \n") - }; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('peers',["util", "session", "storage", "require"], function (util, session, storage, require) { - var peers = util.Module("peers"); - var assert = util.assert; - var CHECK_ACTIVITY_INTERVAL = 10*1000; // Every 10 seconds see if someone has gone idle - var IDLE_TIME = 3*60*1000; // Idle time is 3 minutes - var TAB_IDLE_TIME = 2*60*1000; // When you tab away, after two minutes you'll say you are idle - var BYE_TIME = 10*60*1000; // After 10 minutes of inactivity the person is considered to be "gone" - - var ui; - require(["ui"], function (uiModule) { - ui = uiModule; - }); - - var DEFAULT_NICKNAMES = [ - "Friendly Fox", - "Brilliant Beaver", - "Observant Owl", - "Gregarious Giraffe", - "Wild Wolf", - "Silent Seal", - "Wacky Whale", - "Curious Cat", - "Intelligent Iguana" - ]; - - var Peer = util.Class({ - - isSelf: false, - - constructor: function (id, attrs) { - attrs = attrs || {}; - assert(id); - assert(! Peer.peers[id]); - this.id = id; - this.identityId = attrs.identityId || null; - this.status = attrs.status || "live"; - this.idle = attrs.status || "active"; - this.name = attrs.name || null; - this.avatar = attrs.avatar || null; - this.color = attrs.color || "#00FF00"; - this.view = ui.PeerView(this); - this.lastMessageDate = 0; - this.following = attrs.following || false; - Peer.peers[id] = this; - var joined = attrs.joined || false; - if (attrs.fromHelloMessage) { - this.updateFromHello(attrs.fromHelloMessage); - if (attrs.fromHelloMessage.type == "hello") { - joined = true; - } - } - peers.emit("new-peer", this); - if (joined) { - this.view.notifyJoined(); - } - this.view.update(); - }, - - repr: function () { - return "Peer(" + JSON.stringify(this.id) + ")"; - }, - - serialize: function () { - return { - id: this.id, - status: this.status, - idle: this.idle, - url: this.url, - hash: this.hash, - title: this.title, - identityId: this.identityId, - rtcSupported: this.rtcSupported, - name: this.name, - avatar: this.avatar, - color: this.color, - following: this.following - }; - }, - - destroy: function () { - this.view.destroy(); - delete Peer.peers[this.id]; - }, - - updateMessageDate: function (msg) { - if (this.idle == "inactive") { - this.update({idle: "active"}); - } - if (this.status == "bye") { - this.unbye(); - } - this.lastMessageDate = Date.now(); - }, - - updateFromHello: function (msg) { - var urlUpdated = false; - var activeRTC = false; - var identityUpdated = false; - if (msg.url && msg.url != this.url) { - this.url = msg.url; - this.hash = null; - this.title = null; - urlUpdated = true; - } - if (msg.hash != this.hash) { - this.hash = msg.urlHash; - urlUpdated = true; - } - if (msg.title != this.title) { - this.title = msg.title; - urlUpdated = true; - } - if (msg.rtcSupported !== undefined) { - this.rtcSupported = msg.rtcSupported; - } - if (msg.identityId !== undefined) { - this.identityId = msg.identityId; - } - if (msg.name && msg.name != this.name) { - this.name = msg.name; - identityUpdated = true; - } - if (msg.avatar && msg.avatar != this.avatar) { - util.assertValidUrl(msg.avatar); - this.avatar = msg.avatar; - identityUpdated = true; - } - if (msg.color && msg.color != this.color) { - this.color = msg.color; - identityUpdated = true; - } - if (msg.isClient !== undefined) { - this.isCreator = ! msg.isClient; - } - if (this.status != "live") { - this.status = "live"; - peers.emit("status-updated", this); - } - if (this.idle != "active") { - this.idle = "active"; - peers.emit("idle-updated", this); - } - if (msg.rtcSupported) { - peers.emit("rtc-supported", this); - } - if (urlUpdated) { - peers.emit("url-updated", this); - } - if (identityUpdated) { - peers.emit("identity-updated", this); - } - // FIXME: I can't decide if this is the only time we need to emit - // this message (and not .update() or other methods) - if (this.following) { - session.emit("follow-peer", this); - } - }, - - update: function (attrs) { - // FIXME: should probably test that only a couple attributes are settable - // particularly status and idle - if (attrs.idle) { - this.idle = attrs.idle; - } - if (attrs.status) { - this.status = attrs.status; - } - this.view.update(); - }, - - className: function (prefix) { - prefix = prefix || ""; - return prefix + util.safeClassName(this.id); - }, - - bye: function () { - if (this.status != "bye") { - this.status = "bye"; - peers.emit("status-updated", this); - } - this.view.update(); - }, - - unbye: function () { - if (this.status == "bye") { - this.status = "live"; - peers.emit("status-updated", this); - } - this.view.update(); - }, - - nudge: function () { - session.send({ - type: "url-change-nudge", - url: location.href, - to: this.id - }); - }, - - follow: function () { - if (this.following) { - return; - } - peers.getAllPeers().forEach(function (p) { - if (p.following) { - p.unfollow(); - } - }); - this.following = true; - // We have to make sure we remember this, even if we change URLs: - storeSerialization(); - this.view.update(); - session.emit("follow-peer", this); - }, - - unfollow: function () { - this.following = false; - storeSerialization(); - this.view.update(); - } - - }); - - // FIXME: I can't decide where this should actually go, seems weird - // that it is emitted and handled in the same module - session.on("follow-peer", function (peer) { - if (peer.url != session.currentUrl()) { - var url = peer.url; - if (peer.urlHash) { - url += peer.urlHash; - } - location.href = url; - } - }); - - Peer.peers = {}; - - Peer.deserialize = function (obj) { - obj.fromStorage = true; - var peer = Peer(obj.id, obj); - }; - - peers.Self = undefined; - - session.on("start", function () { - if (peers.Self) { - return; - } - /* Same interface as Peer, represents oneself (local user): */ - peers.Self = util.mixinEvents({ - isSelf: true, - id: session.clientId, - identityId: session.identityId, - status: "live", - idle: "active", - name: null, - avatar: null, - color: null, - defaultName: null, - loaded: false, - isCreator: ! session.isClient, - - update: function (attrs) { - var updatePeers = false; - var updateIdle = false; - var updateMsg = {type: "peer-update"}; - if (typeof attrs.name == "string" && attrs.name != this.name) { - this.name = attrs.name; - updateMsg.name = this.name; - if (! attrs.fromLoad) { - storage.settings.set("name", this.name); - updatePeers = true; - } - } - if (attrs.avatar && attrs.avatar != this.avatar) { - util.assertValidUrl(attrs.avatar); - this.avatar = attrs.avatar; - updateMsg.avatar = this.avatar; - if (! attrs.fromLoad) { - storage.settings.set("avatar", this.avatar); - updatePeers = true; - } - } - if (attrs.color && attrs.color != this.color) { - this.color = attrs.color; - updateMsg.color = this.color; - if (! attrs.fromLoad) { - storage.settings.set("color", this.color); - updatePeers = true; - } - } - if (attrs.defaultName && attrs.defaultName != this.defaultName) { - this.defaultName = attrs.defaultName; - if (! attrs.fromLoad) { - storage.settings.set("defaultName", this.defaultName); - updatePeers = true; - } - } - if (attrs.status && attrs.status != this.status) { - this.status = attrs.status; - peers.emit("status-updated", this); - } - if (attrs.idle && attrs.idle != this.idle) { - this.idle = attrs.idle; - updateIdle = true; - peers.emit("idle-updated", this); - } - this.view.update(); - if (updatePeers && ! attrs.fromLoad) { - session.emit("self-updated"); - session.send(updateMsg); - } - if (updateIdle && ! attrs.fromLoad) { - session.send({ - type: "idle-status", - idle: this.idle - }); - } - }, - - className: function (prefix) { - prefix = prefix || ""; - return prefix + "self"; - }, - - _loadFromSettings: function () { - return util.resolveMany( - storage.settings.get("name"), - storage.settings.get("avatar"), - storage.settings.get("defaultName"), - storage.settings.get("color")).then((function (name, avatar, defaultName, color) { - if (! defaultName) { - defaultName = util.pickRandom(DEFAULT_NICKNAMES); - storage.settings.set("defaultName", defaultName); - } - if (! color) { - color = Math.floor(Math.random() * 0xffffff).toString(16); - while (color.length < 6) { - color = "0" + color; - } - color = "#" + color; - storage.settings.set("color", color); - } - if (! avatar) { - avatar = TogetherJS.baseUrl + "/togetherjs/images/default-avatar.png"; - } - this.update({ - name: name, - avatar: avatar, - defaultName: defaultName, - color: color, - fromLoad: true - }); - peers._SelfLoaded.resolve(); - }).bind(this)); // FIXME: ignoring error - }, - - _loadFromApp: function () { - // FIXME: I wonder if these should be optionally functions? - // We could test typeof==function to distinguish between a getter and a concrete value - var getUserName = TogetherJS.config.get("getUserName"); - var getUserColor = TogetherJS.config.get("getUserColor"); - var getUserAvatar = TogetherJS.config.get("getUserAvatar"); - var name, color, avatar; - if (getUserName) { - if (typeof getUserName == "string") { - name = getUserName; - } else { - name = getUserName(); - } - if (name && typeof name != "string") { - // FIXME: test for HTML safe? Not that we require it, but - // <>'s are probably a sign something is wrong. - console.warn("Error in getUserName(): should return a string (got", name, ")"); - name = null; - } - } - if (getUserColor) { - if (typeof getUserColor == "string") { - color = getUserColor; - } else { - color = getUserColor(); - } - if (color && typeof color != "string") { - // FIXME: would be nice to test for color-ness here. - console.warn("Error in getUserColor(): should return a string (got", color, ")"); - color = null; - } - } - if (getUserAvatar) { - if (typeof getUserAvatar == "string") { - avatar = getUserAvatar; - } else { - avatar = getUserAvatar(); - } - if (avatar && typeof avatar != "string") { - console.warn("Error in getUserAvatar(): should return a string (got", avatar, ")"); - avatar = null; - } - } - if (name || color || avatar) { - this.update({ - name: name, - color: color, - avatar: avatar - }); - } - } - }); - - peers.Self.view = ui.PeerView(peers.Self); - storage.tab.get("peerCache").then(deserialize); - peers.Self._loadFromSettings().then(function() { - peers.Self._loadFromApp(); - peers.Self.view.update(); - session.emit("self-updated"); - }); - }); - - session.on("refresh-user-data", function () { - if (peers.Self) { - peers.Self._loadFromApp(); - } - }); - - TogetherJS.config.track( - "getUserName", - TogetherJS.config.track( - "getUserColor", - TogetherJS.config.track( - "getUserAvatar", - function () { - if (peers.Self) { - peers.Self._loadFromApp(); - } - } - ) - ) - ); - - peers._SelfLoaded = util.Deferred(); - - function serialize() { - var peers = []; - util.forEachAttr(Peer.peers, function (peer) { - peers.push(peer.serialize()); - }); - return { - peers: peers - }; - } - - function deserialize(obj) { - if (! obj) { - return; - } - obj.peers.forEach(function (peer) { - Peer.deserialize(peer); - }); - } - - peers.getPeer = function getPeer(id, message) { - assert(id); - var peer = Peer.peers[id]; - if (id === session.clientId) { - return peers.Self; - } - if (message && ! peer) { - peer = Peer(id, {fromHelloMessage: message}); - return peer; - } - assert(peer, "No peer with id:", id); - if (message && - (message.type == "hello" || message.type == "hello-back" || - message.type == "peer-update")) { - peer.updateFromHello(message); - peer.view.update(); - } - return Peer.peers[id]; - }; - - peers.getAllPeers = function (liveOnly) { - var result = []; - util.forEachAttr(Peer.peers, function (peer) { - if (liveOnly && peer.status != "live") { - return; - } - result.push(peer); - }); - return result; - }; - - function checkActivity() { - var ps = peers.getAllPeers(); - var now = Date.now(); - ps.forEach(function (p) { - if (p.idle == "active" && now - p.lastMessageDate > IDLE_TIME) { - p.update({idle: "inactive"}); - } - if (p.status != "bye" && now - p.lastMessageDate > BYE_TIME) { - p.bye(); - } - }); - } - - session.hub.on("bye", function (msg) { - var peer = peers.getPeer(msg.clientId); - peer.bye(); - }); - - var checkActivityTask = null; - - session.on("start", function () { - if (checkActivityTask) { - console.warn("Old peers checkActivityTask left over?"); - clearTimeout(checkActivityTask); - } - checkActivityTask = setInterval(checkActivity, CHECK_ACTIVITY_INTERVAL); - }); - - session.on("close", function () { - util.forEachAttr(Peer.peers, function (peer) { - peer.destroy(); - }); - storage.tab.set("peerCache", undefined); - clearTimeout(checkActivityTask); - checkActivityTask = null; - }); - - var tabIdleTimeout = null; - - session.on("visibility-change", function (hidden) { - if (hidden) { - if (tabIdleTimeout) { - clearTimeout(tabIdleTimeout); - } - tabIdleTimeout = setTimeout(function () { - peers.Self.update({idle: "inactive"}); - }, TAB_IDLE_TIME); - } else { - if (tabIdleTimeout) { - clearTimeout(tabIdleTimeout); - } - if (peers.Self.idle == "inactive") { - peers.Self.update({idle: "active"}); - } - } - }); - - session.hub.on("idle-status", function (msg) { - msg.peer.update({idle: msg.idle}); - }); - - // Pings are a straight alive check, and contain no more information: - session.hub.on("ping", function () { - session.send({type: "ping-back"}); - }); - - window.addEventListener("pagehide", function () { - // FIXME: not certain if this should be tab local or not: - storeSerialization(); - }, false); - - function storeSerialization() { - storage.tab.set("peerCache", serialize()); - } - - util.mixinEvents(peers); - - util.testExpose({ - setIdleTime: function (time) { - IDLE_TIME = time; - CHECK_ACTIVITY_INTERVAL = time / 2; - if (TogetherJS.running) { - clearTimeout(checkActivityTask); - checkActivityTask = setInterval(checkActivity, CHECK_ACTIVITY_INTERVAL); - } - } - }); - - util.testExpose({ - setByeTime: function (time) { - BYE_TIME = time; - CHECK_ACTIVITY_INTERVAL = Math.min(CHECK_ACTIVITY_INTERVAL, time / 2); - if (TogetherJS.running) { - clearTimeout(checkActivityTask); - checkActivityTask = setInterval(checkActivity, CHECK_ACTIVITY_INTERVAL); - } - } - }); - - return peers; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ -define('windowing',["jquery", "util", "peers", "session"], function ($, util, peers, session) { - var assert = util.assert; - var windowing = util.Module("windowing"); - var $window = $(window); - // This is also in togetherjs.less, under .togetherjs-animated - var ANIMATION_DURATION = 1000; - - /* Displays one window. A window must already exist. This hides other windows, and - positions the window according to its data-bound-to attributes */ - windowing.show = function (element, options) { - element = $(element); - options = options || {}; - options.bind = options.bind || element.attr("data-bind-to"); - var notification = element.hasClass("togetherjs-notification"); - var modal = element.hasClass("togetherjs-modal"); - if (options.bind) { - options.bind = $(options.bind); - } - windowing.hide(); - element.stop(); - element.show(); - // In addition to being hidden, the window can be faded out, which we want to undo: - element.css({opacity: "1"}); - if (options.bind) { - assert(! modal, "Binding does not currently work with modals"); - bind(element, options.bind); - } - if (notification) { - element.slideIn(); - } else if (! modal) { - element.popinWindow(); - } - if (modal) { - getModalBackground().show(); - modalEscape.bind(); - } - onClose = options.onClose || null; - session.emit("display-window", element.attr("id"), element); - }; - - var onClose = null; - - /* Moves a window to be attached to data-bind-to, e.g., the button - that opened the window. Or you can provide an element that it should bind to. */ - function bind(win, bound) { - if ($.browser.mobile) { - return; - } - win = $(win); - assert(bound.length, "Cannot find binding:", bound.selector, "from:", win.selector); - // FIXME: hardcoding - var ifacePos = "right"; - //var ifacePos = panelPosition(); - var boundPos = bound.offset(); - boundPos.height = bound.height(); - boundPos.width = bound.width(); - var windowHeight = $window.height(); - boundPos.top -= $window.scrollTop(); - boundPos.left -= $window.scrollLeft(); - // FIXME: I appear to have to add the padding to the width to get a "true" - // width. But it's still not entirely consistent. - var height = win.height() + 5; - var width = win.width() + 20; - var left, top; - if (ifacePos == "right") { - left = boundPos.left - 11 - width; - top = boundPos.top + (boundPos.height / 2) - (height / 2); - } else if (ifacePos == "left") { - left = boundPos.left + boundPos.width + 15; - top = boundPos.top + (boundPos.height / 2) - (height / 2); - } else if (ifacePos == "bottom") { - left = (boundPos.left + boundPos.width / 2) - (width / 2); - top = boundPos.top - 10 - height; - } - top = Math.min(windowHeight - 10 - height, Math.max(10, top)); - win.css({ - top: top + "px", - left: left + "px" - }); - if (win.hasClass("togetherjs-window")) { - $("#togetherjs-window-pointer-right, #togetherjs-window-pointer-left").hide(); - var pointer = $("#togetherjs-window-pointer-" + ifacePos); - pointer.show(); - if (ifacePos == "right") { - pointer.css({ - top: boundPos.top + Math.floor(boundPos.height / 2) + "px", - left: left + win.width() + 9 + "px" - }); - } else if (ifacePos == "left") { - pointer.css({ - top: boundPos.top + Math.floor(boundPos.height / 2) + "px", - left: (left - 5) + "px" - }); - } else { - console.warn("don't know how to deal with position:", ifacePos); - } - } - win.data("boundTo", bound.selector || "#" + bound.attr("id")); - bound.addClass("togetherjs-active"); - } - - session.on("resize", function () { - var win = $(".togetherjs-modal:visible, .togetherjs-window:visible"); - if (! win.length) { - return; - } - var boundTo = win.data("boundTo"); - if (! boundTo) { - return; - } - boundTo = $(boundTo); - bind(win, boundTo); - }); - - windowing.hide = function (els) { - // FIXME: also hide modals? - els = els || ".togetherjs-window, .togetherjs-modal, .togetherjs-notification"; - els = $(els); - els = els.filter(":visible"); - els.filter(":not(.togetherjs-notification)").hide(); - getModalBackground().hide(); - var windows = []; - els.each(function (index, element) { - element = $(element); - windows.push(element); - var bound = element.data("boundTo"); - if (! bound) { - return; - } - bound = $(bound); - bound.addClass("togetherjs-animated").addClass("togetherjs-color-pulse"); - setTimeout(function () { - bound.removeClass("togetherjs-color-pulse").removeClass("togetherjs-animated"); - }, ANIMATION_DURATION+10); - element.data("boundTo", null); - bound.removeClass("togetherjs-active"); - if (element.hasClass("togetherjs-notification")) { - element.fadeOut().promise().then(function () { - this.hide(); - }); - } - }); - $("#togetherjs-window-pointer-right, #togetherjs-window-pointer-left").hide(); - if (onClose) { - onClose(); - onClose = null; - } - if (windows.length) { - session.emit("hide-window", windows); - } - }; - - windowing.showNotification = function (element, options) { - element = $(element); - options = options || {}; - assert(false); - }; - - windowing.toggle = function (el) { - el = $(el); - if (el.is(":visible")) { - windowing.hide(el); - } else { - windowing.show(el); - } - }; - - function bindEvents(el) { - el.find(".togetherjs-close, .togetherjs-dismiss").click(function (event) { - var w = $(event.target).closest(".togetherjs-window, .togetherjs-modal, .togetherjs-notification"); - windowing.hide(w); - event.stopPropagation(); - return false; - }); - } - - function getModalBackground() { - if (getModalBackground.element) { - return getModalBackground.element; - } - var background = $("#togetherjs-modal-background"); - assert(background.length); - getModalBackground.element = background; - background.click(function () { - windowing.hide(); - }); - return background; - } - - var modalEscape = { - bind: function () { - $(document).keydown(modalEscape.onKeydown); - }, - unbind: function () { - $(document).unbind("keydown", modalEscape.onKeydown); - }, - onKeydown: function (event) { - if (event.which == 27) { - windowing.hide(); - } - } - }; - - session.on("close", function () { - modalEscape.unbind(); - }); - - session.on("new-element", function (el) { - bindEvents(el); - }); - - return windowing; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ -define('templating',["jquery", "util", "peers", "windowing", "session"], function ($, util, peers, windowing, session) { - var assert = util.assert; - var templating = util.Module("templating"); - - templating.clone = function (templateId) { - templateId = "#togetherjs-template-" + templateId; - var template = $(templateId); - assert(template.length, "No template found with id:", templateId); - template = template.clone(); - template.attr("id", null); - // FIXME: if called directly, doesn't emit new-element event: - return template; - }; - - templating.sub = function (templateId, variables) { - var template = templating.clone(templateId); - variables = variables || {}; - util.forEachAttr(variables, function (value, attr) { - // FIXME: do the substitution... somehow? - var subs = template.find(".togetherjs-sub-" + attr).removeClass("togetherjs-sub-" + attr); - if (subs.length) { - if (typeof value == "string") { - subs.text(value); - } else if (value instanceof $) { - subs.append(value); - } else { - assert(false, "Unknown variable value type:", attr, "=", value); - } - } - var ifs = template.find(".togetherjs-if-" + attr).removeClass("togetherjs-sub-" + attr); - if (! value) { - ifs.hide(); - } - ifs = template.find(".togetherjs-ifnot-" + attr).removeClass("togetherjs-ifnot-" + attr); - if (value) { - ifs.hide(); - } - var attrName = "data-togetherjs-subattr-" + attr; - var attrs = template.find("[" + attrName + "]"); - attrs.each(function (index, element) { - assert(typeof value == "string"); - element = $(element); - var subAttribute = element.attr(attrName); - element.attr(attrName, null); - element.attr(subAttribute, value); - }); - }); - if (variables.peer) { - variables.peer.view.setElement(template); - } - if (variables.date) { - var date = variables.date; - if (typeof date == "number") { - date = new Date(date); - } - var ampm = "AM"; - var hour = date.getHours(); - if (hour > 12) { - hour -= 12; - ampm = "PM"; - } - var minute = date.getMinutes(); - var t = hour + ":"; - if (minute < 10) { - t += "0"; - } - t += minute; - template.find(".togetherjs-time").text(t); - template.find(".togetherjs-ampm").text(ampm); - } - - // FIXME: silly this is on session: - session.emit("new-element", template); - return template; - }; - - return templating; -}); - -define('linkify',[], function () { - // FIXME: this could be moved to a different module, it's pretty stand-alone - /* Finds any links in the text of an element (or its children) and turns them - into anchors (with target=_blank) */ - function linkify(el) { - if (el.jquery) { - el = el[0]; - } - el.normalize(); - function linkifyNode(node) { - var _len = node.childNodes.length; - for (var i=0; i<_len; i++) { - if (node.childNodes[i].nodeType == document.ELEMENT_NODE) { - linkifyNode(node.childNodes[i]); - } - } - var texts = []; - for (i=0; i<_len; i++) { - if (node.childNodes[i].nodeType == document.TEXT_NODE) { - texts.push(node.childNodes[i]); - } - } - texts.forEach(function (item) { - if (item.nodeType == document.ELEMENT_NODE) { - linkifyNode(item); - } else if (item.nodeType == document.TEXT_NODE) { - while (true) { - var text = item.nodeValue; - var regex = /\bhttps?:\/\/[a-z0-9\.\-_](:\d+)?[^ \n\t<>()\[\]]*/i; - var match = regex.exec(text); - if (! match) { - break; - } - var leadingNode = document.createTextNode(text.substr(0, match.index)); - node.replaceChild(leadingNode, item); - var anchor = document.createElement("a"); - anchor.setAttribute("target", "_blank"); - anchor.href = match[0]; - anchor.appendChild(document.createTextNode(match[0])); - node.insertBefore(anchor, leadingNode.nextSibling); - var trailing = document.createTextNode(text.substr(match.index + match[0].length)); - node.insertBefore(trailing, anchor.nextSibling); - item = trailing; - } - } - }); - } - linkifyNode(el); - return el; - } - - return linkify; -}); - -// TinyColor v0.9.13 -// https://github.com/bgrins/TinyColor -// 2012-11-28, Brian Grinstead, MIT License - -(function(root) { - -var trimLeft = /^[\s,#]+/, - trimRight = /\s+$/, - tinyCounter = 0, - math = Math, - mathRound = math.round, - mathMin = math.min, - mathMax = math.max, - mathRandom = math.random; - -function tinycolor (color, opts) { - - color = (color) ? color : ''; - - // If input is already a tinycolor, return itself - if (typeof color == "object" && color.hasOwnProperty("_tc_id")) { - return color; - } - - var rgb = inputToRGB(color); - var r = rgb.r, - g = rgb.g, - b = rgb.b, - a = rgb.a, - roundA = mathRound(100*a) / 100, - format = rgb.format; - - // Don't let the range of [0,255] come back in [0,1]. - // Potentially lose a little bit of precision here, but will fix issues where - // .5 gets interpreted as half of the total, instead of half of 1 - // If it was supposed to be 128, this was already taken care of by `inputToRgb` - if (r < 1) { r = mathRound(r); } - if (g < 1) { g = mathRound(g); } - if (b < 1) { b = mathRound(b); } - - return { - ok: rgb.ok, - format: format, - _tc_id: tinyCounter++, - alpha: a, - toHsv: function() { - var hsv = rgbToHsv(r, g, b); - return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: a }; - }, - toHsvString: function() { - var hsv = rgbToHsv(r, g, b); - var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100); - return (a == 1) ? - "hsv(" + h + ", " + s + "%, " + v + "%)" : - "hsva(" + h + ", " + s + "%, " + v + "%, "+ roundA + ")"; - }, - toHsl: function() { - var hsl = rgbToHsl(r, g, b); - return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: a }; - }, - toHslString: function() { - var hsl = rgbToHsl(r, g, b); - var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100); - return (a == 1) ? - "hsl(" + h + ", " + s + "%, " + l + "%)" : - "hsla(" + h + ", " + s + "%, " + l + "%, "+ roundA + ")"; - }, - toHex: function() { - return rgbToHex(r, g, b); - }, - toHexString: function() { - return '#' + rgbToHex(r, g, b); - }, - toRgb: function() { - return { r: mathRound(r), g: mathRound(g), b: mathRound(b), a: a }; - }, - toRgbString: function() { - return (a == 1) ? - "rgb(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ")" : - "rgba(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ", " + roundA + ")"; - }, - toPercentageRgb: function() { - return { r: mathRound(bound01(r, 255) * 100) + "%", g: mathRound(bound01(g, 255) * 100) + "%", b: mathRound(bound01(b, 255) * 100) + "%", a: a }; - }, - toPercentageRgbString: function() { - return (a == 1) ? - "rgb(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%)" : - "rgba(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%, " + roundA + ")"; - }, - toName: function() { - return hexNames[rgbToHex(r, g, b)] || false; - }, - toFilter: function() { - var hex = rgbToHex(r, g, b); - var secondHex = hex; - var alphaHex = Math.round(parseFloat(a) * 255).toString(16); - var secondAlphaHex = alphaHex; - var gradientType = opts && opts.gradientType ? "GradientType = 1, " : ""; - - if (secondColor) { - var s = tinycolor(secondColor); - secondHex = s.toHex(); - secondAlphaHex = Math.round(parseFloat(s.alpha) * 255).toString(16); - } - - return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr=#" + pad2(alphaHex) + hex + ",endColorstr=#" + pad2(secondAlphaHex) + secondHex + ")"; - }, - toString: function(format) { - format = format || this.format; - var formattedString = false; - if (format === "rgb") { - formattedString = this.toRgbString(); - } - if (format === "prgb") { - formattedString = this.toPercentageRgbString(); - } - if (format === "hex") { - formattedString = this.toHexString(); - } - if (format === "name") { - formattedString = this.toName(); - } - if (format === "hsl") { - formattedString = this.toHslString(); - } - if (format === "hsv") { - formattedString = this.toHsvString(); - } - - return formattedString || this.toHexString(); - } - }; -} - -// If input is an object, force 1 into "1.0" to handle ratios properly -// String input requires "1.0" as input, so 1 will be treated as 1 -tinycolor.fromRatio = function(color) { - if (typeof color == "object") { - var newColor = {}; - for (var i in color) { - newColor[i] = convertToPercentage(color[i]); - } - color = newColor; - } - - return tinycolor(color); -}; - -// Given a string or object, convert that input to RGB -// Possible string inputs: -// -// "red" -// "#f00" or "f00" -// "#ff0000" or "ff0000" -// "rgb 255 0 0" or "rgb (255, 0, 0)" -// "rgb 1.0 0 0" or "rgb (1, 0, 0)" -// "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1" -// "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1" -// "hsl(0, 100%, 50%)" or "hsl 0 100% 50%" -// "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1" -// "hsv(0, 100%, 100%)" or "hsv 0 100% 100%" -// -function inputToRGB(color) { - - var rgb = { r: 255, g: 255, b: 255 }; - var a = 1; - var ok = false; - var format = false; - - if (typeof color == "string") { - color = stringInputToObject(color); - } - - if (typeof color == "object") { - if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) { - rgb = rgbToRgb(color.r, color.g, color.b); - ok = true; - format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb"; - } - else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) { - color.s = convertToPercentage(color.s); - color.v = convertToPercentage(color.v); - rgb = hsvToRgb(color.h, color.s, color.v); - ok = true; - format = "hsv"; - } - else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) { - color.s = convertToPercentage(color.s); - color.l = convertToPercentage(color.l); - rgb = hslToRgb(color.h, color.s, color.l); - ok = true; - format = "hsl"; - } - - if (color.hasOwnProperty("a")) { - a = color.a; - } - } - - a = parseFloat(a); - - // Handle invalid alpha characters by setting to 1 - if (isNaN(a) || a < 0 || a > 1) { - a = 1; - } - - return { - ok: ok, - format: color.format || format, - r: mathMin(255, mathMax(rgb.r, 0)), - g: mathMin(255, mathMax(rgb.g, 0)), - b: mathMin(255, mathMax(rgb.b, 0)), - a: a - }; -} - - - -// Conversion Functions -// -------------------- - -// `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from: -// - -// `rgbToRgb` -// Handle bounds / percentage checking to conform to CSS color spec -// -// *Assumes:* r, g, b in [0, 255] or [0, 1] -// *Returns:* { r, g, b } in [0, 255] -function rgbToRgb(r, g, b){ - return { - r: bound01(r, 255) * 255, - g: bound01(g, 255) * 255, - b: bound01(b, 255) * 255 - }; -} - -// `rgbToHsl` -// Converts an RGB color value to HSL. -// *Assumes:* r, g, and b are contained in [0, 255] or [0, 1] -// *Returns:* { h, s, l } in [0,1] -function rgbToHsl(r, g, b) { - - r = bound01(r, 255); - g = bound01(g, 255); - b = bound01(b, 255); - - var max = mathMax(r, g, b), min = mathMin(r, g, b); - var h, s, l = (max + min) / 2; - - if(max == min) { - h = s = 0; // achromatic - } - else { - var d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - switch(max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - - h /= 6; - } - - return { h: h, s: s, l: l }; -} - -// `hslToRgb` -// Converts an HSL color value to RGB. -// *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100] -// *Returns:* { r, g, b } in the set [0, 255] -function hslToRgb(h, s, l) { - var r, g, b; - - h = bound01(h, 360); - s = bound01(s, 100); - l = bound01(l, 100); - - function hue2rgb(p, q, t) { - if(t < 0) t += 1; - if(t > 1) t -= 1; - if(t < 1/6) return p + (q - p) * 6 * t; - if(t < 1/2) return q; - if(t < 2/3) return p + (q - p) * (2/3 - t) * 6; - return p; - } - - if(s === 0) { - r = g = b = l; // achromatic - } - else { - var q = l < 0.5 ? l * (1 + s) : l + s - l * s; - var p = 2 * l - q; - r = hue2rgb(p, q, h + 1/3); - g = hue2rgb(p, q, h); - b = hue2rgb(p, q, h - 1/3); - } - - return { r: r * 255, g: g * 255, b: b * 255 }; -} - -// `rgbToHsv` -// Converts an RGB color value to HSV -// *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1] -// *Returns:* { h, s, v } in [0,1] -function rgbToHsv(r, g, b) { - - r = bound01(r, 255); - g = bound01(g, 255); - b = bound01(b, 255); - - var max = mathMax(r, g, b), min = mathMin(r, g, b); - var h, s, v = max; - - var d = max - min; - s = max === 0 ? 0 : d / max; - - if(max == min) { - h = 0; // achromatic - } - else { - switch(max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - h /= 6; - } - return { h: h, s: s, v: v }; -} - -// `hsvToRgb` -// Converts an HSV color value to RGB. -// *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100] -// *Returns:* { r, g, b } in the set [0, 255] - function hsvToRgb(h, s, v) { - - h = bound01(h, 360) * 6; - s = bound01(s, 100); - v = bound01(v, 100); - - var i = math.floor(h), - f = h - i, - p = v * (1 - s), - q = v * (1 - f * s), - t = v * (1 - (1 - f) * s), - mod = i % 6, - r = [v, q, p, p, t, v][mod], - g = [t, v, v, q, p, p][mod], - b = [p, p, t, v, v, q][mod]; - - return { r: r * 255, g: g * 255, b: b * 255 }; -} - -// `rgbToHex` -// Converts an RGB color to hex -// Assumes r, g, and b are contained in the set [0, 255] -// Returns a 3 or 6 character hex -function rgbToHex(r, g, b) { - var hex = [ - pad2(mathRound(r).toString(16)), - pad2(mathRound(g).toString(16)), - pad2(mathRound(b).toString(16)) - ]; - - // Return a 3 character hex if possible - if (hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) { - return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0); - } - - return hex.join(""); -} - -// `equals` -// Can be called with any tinycolor input -tinycolor.equals = function (color1, color2) { - if (!color1 || !color2) { return false; } - return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString(); -}; -tinycolor.random = function() { - return tinycolor.fromRatio({ - r: mathRandom(), - g: mathRandom(), - b: mathRandom() - }); -}; - - -// Modification Functions -// ---------------------- -// Thanks to less.js for some of the basics here -// - - -tinycolor.desaturate = function (color, amount) { - var hsl = tinycolor(color).toHsl(); - hsl.s -= ((amount || 10) / 100); - hsl.s = clamp01(hsl.s); - return tinycolor(hsl); -}; -tinycolor.saturate = function (color, amount) { - var hsl = tinycolor(color).toHsl(); - hsl.s += ((amount || 10) / 100); - hsl.s = clamp01(hsl.s); - return tinycolor(hsl); -}; -tinycolor.greyscale = function(color) { - return tinycolor.desaturate(color, 100); -}; -tinycolor.lighten = function(color, amount) { - var hsl = tinycolor(color).toHsl(); - hsl.l += ((amount || 10) / 100); - hsl.l = clamp01(hsl.l); - return tinycolor(hsl); -}; -tinycolor.darken = function (color, amount) { - var hsl = tinycolor(color).toHsl(); - hsl.l -= ((amount || 10) / 100); - hsl.l = clamp01(hsl.l); - return tinycolor(hsl); -}; -tinycolor.complement = function(color) { - var hsl = tinycolor(color).toHsl(); - hsl.h = (hsl.h + 180) % 360; - return tinycolor(hsl); -}; - - -// Combination Functions -// --------------------- -// Thanks to jQuery xColor for some of the ideas behind these -// - -tinycolor.triad = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l }) - ]; -}; -tinycolor.tetrad = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l }) - ]; -}; -tinycolor.splitcomplement = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}), - tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l}) - ]; -}; -tinycolor.analogous = function(color, results, slices) { - results = results || 6; - slices = slices || 30; - - var hsl = tinycolor(color).toHsl(); - var part = 360 / slices; - var ret = [tinycolor(color)]; - - for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) { - hsl.h = (hsl.h + part) % 360; - ret.push(tinycolor(hsl)); - } - return ret; -}; -tinycolor.monochromatic = function(color, results) { - results = results || 6; - var hsv = tinycolor(color).toHsv(); - var h = hsv.h, s = hsv.s, v = hsv.v; - var ret = []; - var modification = 1 / results; - - while (results--) { - ret.push(tinycolor({ h: h, s: s, v: v})); - v = (v + modification) % 1; - } - - return ret; -}; -// Readability based on W3C recommendations: http://www.w3.org/TR/AERT#color-contrast -// Returns object with two properties: -// .brightness: the difference in brightness between the two colors -// .color: the difference in color/hue between the two colors -// An "acceptable" color is considered to have a brightness difference of 125 and a -// color difference of 500 -tinycolor.readability = function(color1, color2) { - var a = tinycolor(color1).toRgb(), b = tinycolor(color2).toRgb(); - var brightnessA = (a.r * 299 + a.g * 587 + a.b * 114) / 1000; - var brightnessB = (b.r * 299 + b.g * 587 + b.b * 114) / 1000; - var colorDiff = ( - Math.max(a.r, b.r) - Math.min(a.r, b.r) + - Math.max(a.g, b.g) - Math.min(a.g, b.g) + - Math.max(a.b, b.b) - Math.min(a.b, b.b)); - return { - brightness: Math.abs(brightnessA - brightnessB), - color: colorDiff - }; -}; -// True if using color1 over color2 (or vice versa) is "readable" -// Based on: http://www.w3.org/TR/AERT#color-contrast -// Example: -// tinycolor.readable("#000", "#111") => false -tinycolor.readable = function(color1, color2) { - var readability = tinycolor.readability(color1, color2); - return readability.brightness > 125 && readability.color > 500; -}; -// Given a base color and a list of possible foreground or background -// colors for that base, returns the most readable color. -// Example: -// tinycolor.mostReadable("#123", ["#fff", "#000"]) => "#000" -tinycolor.mostReadable = function(baseColor, colorList) { - var bestColor; - var bestScore = 0; - var bestIsReadable = false; - for (var i=0; i < colorList.length; i++) { - var readability = tinycolor.readability(baseColor, colorList[i]); - var readable = readability.brightness > 125 && readability.color > 500; - // We normalize both around the "acceptable" breaking point, - // but rank brightness constrast higher than hue. Why? I'm - // not sure, seems reasonable. - var score = 3 * (readability.brightness / 125) + (readability.color / 500); - if ((readable && ! bestIsReadable) || - (readable && bestIsReadable && score > bestScore) || - ((! readable) && (! bestIsReadable) && score > bestScore)) { - bestIsReadable = readable; - bestScore = score; - bestColor = colorList[i]; - } - } - return bestColor; -}; - - -// Big List of Colors -// --------- -// -var names = tinycolor.names = { - aliceblue: "f0f8ff", - antiquewhite: "faebd7", - aqua: "0ff", - aquamarine: "7fffd4", - azure: "f0ffff", - beige: "f5f5dc", - bisque: "ffe4c4", - black: "000", - blanchedalmond: "ffebcd", - blue: "00f", - blueviolet: "8a2be2", - brown: "a52a2a", - burlywood: "deb887", - burntsienna: "ea7e5d", - cadetblue: "5f9ea0", - chartreuse: "7fff00", - chocolate: "d2691e", - coral: "ff7f50", - cornflowerblue: "6495ed", - cornsilk: "fff8dc", - crimson: "dc143c", - cyan: "0ff", - darkblue: "00008b", - darkcyan: "008b8b", - darkgoldenrod: "b8860b", - darkgray: "a9a9a9", - darkgreen: "006400", - darkgrey: "a9a9a9", - darkkhaki: "bdb76b", - darkmagenta: "8b008b", - darkolivegreen: "556b2f", - darkorange: "ff8c00", - darkorchid: "9932cc", - darkred: "8b0000", - darksalmon: "e9967a", - darkseagreen: "8fbc8f", - darkslateblue: "483d8b", - darkslategray: "2f4f4f", - darkslategrey: "2f4f4f", - darkturquoise: "00ced1", - darkviolet: "9400d3", - deeppink: "ff1493", - deepskyblue: "00bfff", - dimgray: "696969", - dimgrey: "696969", - dodgerblue: "1e90ff", - firebrick: "b22222", - floralwhite: "fffaf0", - forestgreen: "228b22", - fuchsia: "f0f", - gainsboro: "dcdcdc", - ghostwhite: "f8f8ff", - gold: "ffd700", - goldenrod: "daa520", - gray: "808080", - green: "008000", - greenyellow: "adff2f", - grey: "808080", - honeydew: "f0fff0", - hotpink: "ff69b4", - indianred: "cd5c5c", - indigo: "4b0082", - ivory: "fffff0", - khaki: "f0e68c", - lavender: "e6e6fa", - lavenderblush: "fff0f5", - lawngreen: "7cfc00", - lemonchiffon: "fffacd", - lightblue: "add8e6", - lightcoral: "f08080", - lightcyan: "e0ffff", - lightgoldenrodyellow: "fafad2", - lightgray: "d3d3d3", - lightgreen: "90ee90", - lightgrey: "d3d3d3", - lightpink: "ffb6c1", - lightsalmon: "ffa07a", - lightseagreen: "20b2aa", - lightskyblue: "87cefa", - lightslategray: "789", - lightslategrey: "789", - lightsteelblue: "b0c4de", - lightyellow: "ffffe0", - lime: "0f0", - limegreen: "32cd32", - linen: "faf0e6", - magenta: "f0f", - maroon: "800000", - mediumaquamarine: "66cdaa", - mediumblue: "0000cd", - mediumorchid: "ba55d3", - mediumpurple: "9370db", - mediumseagreen: "3cb371", - mediumslateblue: "7b68ee", - mediumspringgreen: "00fa9a", - mediumturquoise: "48d1cc", - mediumvioletred: "c71585", - midnightblue: "191970", - mintcream: "f5fffa", - mistyrose: "ffe4e1", - moccasin: "ffe4b5", - navajowhite: "ffdead", - navy: "000080", - oldlace: "fdf5e6", - olive: "808000", - olivedrab: "6b8e23", - orange: "ffa500", - orangered: "ff4500", - orchid: "da70d6", - palegoldenrod: "eee8aa", - palegreen: "98fb98", - paleturquoise: "afeeee", - palevioletred: "db7093", - papayawhip: "ffefd5", - peachpuff: "ffdab9", - peru: "cd853f", - pink: "ffc0cb", - plum: "dda0dd", - powderblue: "b0e0e6", - purple: "800080", - red: "f00", - rosybrown: "bc8f8f", - royalblue: "4169e1", - saddlebrown: "8b4513", - salmon: "fa8072", - sandybrown: "f4a460", - seagreen: "2e8b57", - seashell: "fff5ee", - sienna: "a0522d", - silver: "c0c0c0", - skyblue: "87ceeb", - slateblue: "6a5acd", - slategray: "708090", - slategrey: "708090", - snow: "fffafa", - springgreen: "00ff7f", - steelblue: "4682b4", - tan: "d2b48c", - teal: "008080", - thistle: "d8bfd8", - tomato: "ff6347", - turquoise: "40e0d0", - violet: "ee82ee", - wheat: "f5deb3", - white: "fff", - whitesmoke: "f5f5f5", - yellow: "ff0", - yellowgreen: "9acd32" -}; - -// Make it easy to access colors via `hexNames[hex]` -var hexNames = tinycolor.hexNames = flip(names); - - -// Utilities -// --------- - -// `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }` -function flip(o) { - var flipped = { }; - for (var i in o) { - if (o.hasOwnProperty(i)) { - flipped[o[i]] = i; - } - } - return flipped; -} - -// Take input from [0, n] and return it as [0, 1] -function bound01(n, max) { - if (isOnePointZero(n)) { n = "100%"; } - - var processPercent = isPercentage(n); - n = mathMin(max, mathMax(0, parseFloat(n))); - - // Automatically convert percentage into number - if (processPercent) { - n = parseInt(n * max, 10) / 100; - } - - // Handle floating point rounding errors - if ((math.abs(n - max) < 0.000001)) { - return 1; - } - - // Convert into [0, 1] range if it isn't already - return (n % max) / parseFloat(max); -} - -// Force a number between 0 and 1 -function clamp01(val) { - return mathMin(1, mathMax(0, val)); -} - -// Parse an integer into hex -function parseHex(val) { - return parseInt(val, 16); -} - -// Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1 -// -function isOnePointZero(n) { - return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1; -} - -// Check to see if string passed in is a percentage -function isPercentage(n) { - return typeof n === "string" && n.indexOf('%') != -1; -} - -// Force a hex value to have 2 characters -function pad2(c) { - return c.length == 1 ? '0' + c : '' + c; -} - -// Replace a decimal with it's percentage value -function convertToPercentage(n) { - if (n <= 1) { - n = (n * 100) + "%"; - } - - return n; -} - -var matchers = (function() { - - // - var CSS_INTEGER = "[-\\+]?\\d+%?"; - - // - var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?"; - - // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome. - var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")"; - - // Actual matching. - // Parentheses and commas are optional, but not required. - // Whitespace can take the place of commas or opening paren - var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; - var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; - - return { - rgb: new RegExp("rgb" + PERMISSIVE_MATCH3), - rgba: new RegExp("rgba" + PERMISSIVE_MATCH4), - hsl: new RegExp("hsl" + PERMISSIVE_MATCH3), - hsla: new RegExp("hsla" + PERMISSIVE_MATCH4), - hsv: new RegExp("hsv" + PERMISSIVE_MATCH3), - hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, - hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/ - }; -})(); - -// `stringInputToObject` -// Permissive string parsing. Take in a number of formats, and output an object -// based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}` -function stringInputToObject(color) { - - color = color.replace(trimLeft,'').replace(trimRight, '').toLowerCase(); - var named = false; - if (names[color]) { - color = names[color]; - named = true; - } - else if (color == 'transparent') { - return { r: 0, g: 0, b: 0, a: 0 }; - } - - // Try to match string input using regular expressions. - // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360] - // Just return an object and let the conversion functions handle that. - // This way the result will be the same whether the tinycolor is initialized with string or object. - var match; - if ((match = matchers.rgb.exec(color))) { - return { r: match[1], g: match[2], b: match[3] }; - } - if ((match = matchers.rgba.exec(color))) { - return { r: match[1], g: match[2], b: match[3], a: match[4] }; - } - if ((match = matchers.hsl.exec(color))) { - return { h: match[1], s: match[2], l: match[3] }; - } - if ((match = matchers.hsla.exec(color))) { - return { h: match[1], s: match[2], l: match[3], a: match[4] }; - } - if ((match = matchers.hsv.exec(color))) { - return { h: match[1], s: match[2], v: match[3] }; - } - if ((match = matchers.hex6.exec(color))) { - return { - r: parseHex(match[1]), - g: parseHex(match[2]), - b: parseHex(match[3]), - format: named ? "name" : "hex" - }; - } - if ((match = matchers.hex3.exec(color))) { - return { - r: parseHex(match[1] + '' + match[1]), - g: parseHex(match[2] + '' + match[2]), - b: parseHex(match[3] + '' + match[3]), - format: named ? "name" : "hex" - }; - } - - return false; -} - -// Node: Export function -if (typeof module !== "undefined" && module.exports) { - module.exports = tinycolor; -} -// AMD/requirejs: Define the module -else if (typeof define !== "undefined") { - define('tinycolor',[],function () {return tinycolor;}); -} -// Browser: Expose to window -else { - root.tinycolor = tinycolor; -} - -})(this); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('elementFinder',["util", "jquery"], function (util, $) { - var elementFinder = util.Module("elementFinder"); - var assert = util.assert; - - elementFinder.ignoreElement = function ignoreElement(el) { - if (el instanceof $) { - el = el[0]; - } - while (el) { - if ($(el).hasClass("togetherjs")) { - return true; - } - el = el.parentNode; - } - return false; - }; - - elementFinder.elementLocation = function elementLocation(el) { - assert(el !== null, "Got null element"); - if (el instanceof $) { - // a jQuery element - el = el[0]; - } - if (el[0] && el.attr && el[0].nodeType == 1) { - // Or a jQuery element not made by us - el = el[0]; - } - if (el.id) { - return "#" + el.id; - } - if (el.tagName == "BODY") { - return "body"; - } - if (el.tagName == "HEAD") { - return "head"; - } - if (el === document) { - return "document"; - } - var parent = el.parentNode; - if ((! parent) || parent == el) { - console.warn("elementLocation(", el, ") has null parent"); - throw new Error("No locatable parent found"); - } - var parentLocation = elementLocation(parent); - var children = parent.childNodes; - var _len = children.length; - var index = 0; - for (var i=0; i<_len; i++) { - if (children[i] == el) { - break; - } - if (children[i].nodeType == document.ELEMENT_NODE) { - if (children[i].className.indexOf("togetherjs") != -1) { - // Don't count our UI - continue; - } - // Don't count text or comments - index++; - } - } - return parentLocation + ":nth-child(" + (index+1) + ")"; - }; - - elementFinder.CannotFind = util.Class({ - constructor: function CannotFind(location, reason, context) { - this.prefix = ""; - this.location = location; - this.reason = reason; - this.context = context; - }, - toString: function () { - var loc; - try { - loc = elementFinder.elementLocation(this.context); - } catch (e) { - loc = this.context; - } - return ( - "[CannotFind " + this.prefix + - "(" + this.location + "): " + - this.reason + " in " + - loc + "]"); - } - }); - - elementFinder.findElement = function findElement(loc, container) { - // FIXME: should this all just be done with document.querySelector()? - // But no! We can't ignore togetherjs elements with querySelector. - // But maybe! We *could* make togetherjs elements less obtrusive? - container = container || document; - var el, rest; - if (loc === "body") { - return document.body; - } else if (loc === "head") { - return document.head; - } else if (loc === "document") { - return document; - } else if (loc.indexOf("body") === 0) { - el = document.body; - try { - return findElement(loc.substr(("body").length), el); - } catch (e) { - if (e instanceof elementFinder.CannotFind) { - e.prefix = "body" + e.prefix; - } - throw e; - } - } else if (loc.indexOf("head") === 0) { - el = document.head; - try { - return findElement(loc.substr(("head").length), el); - } catch (e) { - if (e instanceof elementFinder.CannotFind) { - e.prefix = "head" + e.prefix; - } - throw e; - } - } else if (loc.indexOf("#") === 0) { - var id; - loc = loc.substr(1); - if (loc.indexOf(":") === -1) { - id = loc; - rest = ""; - } else { - id = loc.substr(0, loc.indexOf(":")); - rest = loc.substr(loc.indexOf(":")); - } - el = document.getElementById(id); - if (! el) { - throw elementFinder.CannotFind("#" + id, "No element by that id", container); - } - if (rest) { - try { - return findElement(rest, el); - } catch (e) { - if (e instanceof elementFinder.CannotFind) { - e.prefix = "#" + id + e.prefix; - } - throw e; - } - } else { - return el; - } - } else if (loc.indexOf(":nth-child(") === 0) { - loc = loc.substr((":nth-child(").length); - if (loc.indexOf(")") == -1) { - throw "Invalid location, missing ): " + loc; - } - var num = loc.substr(0, loc.indexOf(")")); - num = parseInt(num, 10); - var count = num; - loc = loc.substr(loc.indexOf(")") + 1); - var children = container.childNodes; - el = null; - for (var i=0; i height) { - return false; - } - last = el; - }); - if ((! children.length) || (! last)) { - // There are no children, or only inapplicable children - return { - location: elementFinder.elementLocation(start[0]), - offset: height - start.offset().top, - absoluteTop: height, - documentHeight: $(document).height() - }; - } - return search(last, height); - } - return search($(document.body), height); - }; - - elementFinder.pixelForPosition = function (position) { - /* Inverse of elementFinder.elementByPixel */ - if (position.location == "body") { - return position.offset; - } - var el; - try { - el = elementFinder.findElement(position.location); - } catch (e) { - if (e instanceof elementFinder.CannotFind && position.absoluteTop) { - // We don't trust absoluteTop to be quite right locally, so we adjust - // for the total document height differences: - var percent = position.absoluteTop / position.documentHeight; - return $(document).height() * percent; - } - throw e; - } - var top = $(el).offset().top; - // FIXME: maybe here we should test for sanity, like if an element is - // hidden. We can use position.absoluteTop to get a sense of where the - // element roughly should be. If the sanity check failed we'd use - // absoluteTop - return top + position.offset; - }; - - return elementFinder; - -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Loading this module will cause, when TogetherJS is active, the - session object to emit visibility-change with a `hidden` argument - whenever the visibility changes, on browsers where we can detect - it. - */ - -define('visibilityApi',["util", "session"], function (util, session) { - var visibilityApi = util.Module("visibilityApi"); - var hidden; - var visibilityChange; - if (document.hidden !== undefined) { // Opera 12.10 and Firefox 18 and later support - hidden = "hidden"; - visibilityChange = "visibilitychange"; - } else if (document.mozHidden !== undefined) { - hidden = "mozHidden"; - visibilityChange = "mozvisibilitychange"; - } else if (document.msHidden !== undefined) { - hidden = "msHidden"; - visibilityChange = "msvisibilitychange"; - } else if (document.webkitHidden !== undefined) { - hidden = "webkitHidden"; - visibilityChange = "webkitvisibilitychange"; - } - - session.on("start", function () { - document.addEventListener(visibilityChange, change, false); - }); - - session.on("close", function () { - document.removeEventListener(visibilityChange, change, false); - }); - - function change() { - session.emit("visibility-change", document[hidden]); - } - - visibilityApi.hidden = function () { - return document[hidden]; - }; - - return visibilityApi; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('ui',["require", "jquery", "util", "session", "templates", "templating", "linkify", "peers", "windowing", "tinycolor", "elementFinder", "visibilityApi"], function (require, $, util, session, templates, templating, linkify, peers, windowing, tinycolor, elementFinder, visibilityApi) { - var ui = util.Module('ui'); - var assert = util.assert; - var AssertionError = util.AssertionError; - var chat; - var $window = $(window); - // This is also in togetherjs.less, as @button-height: - var BUTTON_HEIGHT = 60 + 1; // 60 is button height, 1 is border - // chat TextArea - var TEXTAREA_LINE_HEIGHT = 20; // in pixels - var TEXTAREA_MAX_LINES = 5; - // This is also in togetherjs.less, under .togetherjs-animated - var ANIMATION_DURATION = 1000; - // Time the new user window sticks around until it fades away: - var NEW_USER_FADE_TIMEOUT = 5000; - // This is set when an animation will keep the UI from being ready - // (until this time): - var finishedAt = null; - // Time in milliseconds for the dock to animate out: - var DOCK_ANIMATION_TIME = 300; - // If two chat messages come from the same person in this time - // (milliseconds) then they are collapsed into one message: - var COLLAPSE_MESSAGE_LIMIT = 5000; - - var COLORS = [ - "#8A2BE2", "#7FFF00", "#DC143C", "#00FFFF", "#8FBC8F", "#FF8C00", "#FF00FF", - "#FFD700", "#F08080", "#90EE90", "#FF6347"]; - - // This would be a circular import, but we just need the chat module sometime - // after everything is loaded, and this is sure to complete by that time: - require(["chat"], function (c) { - chat = c; - }); - - /* Displays some toggleable element; toggleable elements have a - data-toggles attribute that indicates what other elements should - be hidden when this element is shown. */ - ui.displayToggle = function (el) { - el = $(el); - assert(el.length, "No element", arguments[0]); - var other = $(el.attr("data-toggles")); - assert(other.length, "Cannot toggle", el[0], "selector", other.selector); - other.hide(); - el.show(); - }; - - function panelPosition() { - var iface = $("#togetherjs-dock"); - if (iface.hasClass("togetherjs-dock-right")) { - return "right"; - } else if (iface.hasClass("togetherjs-dock-left")) { - return "left"; - } else if (iface.hasClass("togetherjs-dock-bottom")) { - return "bottom"; - } else { - throw new AssertionError("#togetherjs-dock doesn't have positioning class"); - } - } - - ui.container = null; - - // This is used for some signalling when ui.prepareUI and/or - // ui.activateUI is called before the DOM is fully loaded: - var deferringPrepareUI = null; - - function deferForContainer(func) { - /* Defers any calls to func() until after ui.container is set - Function cannot have a return value (as sometimes the call will - become async). Use like: - - method: deferForContainer(function (args) {...}) - */ - return function () { - if (ui.container) { - func.apply(this, arguments); - } - var self = this; - var args = Array.prototype.slice.call(arguments); - session.once("ui-ready", function () { - func.apply(self, args); - }); - }; - } - - // This is called before activateUI; it doesn't bind anything, but does display - // the dock - // FIXME: because this module has lots of requirements we can't do - // this before those requirements are loaded. Maybe worth splitting - // this out? OTOH, in production we should have all the files - // combined so there's not much problem loading those modules. - ui.prepareUI = function () { - if (! (document.readyState == "complete" || document.readyState == "interactive")) { - // Too soon! Wait a sec... - deferringPrepareUI = "deferring"; - document.addEventListener("DOMContentLoaded", function () { - var d = deferringPrepareUI; - deferringPrepareUI = null; - ui.prepareUI(); - // This happens when ui.activateUI is called before the document has been - // loaded: - if (d == "activate") { - ui.activateUI(); - } - }); - return; - } - var container = ui.container = $(templates["interface"]); - assert(container.length); - $("body").append(container); - fixupAvatars(container); - if (session.firstRun && TogetherJS.startTarget) { - // Time at which the UI will be fully ready: - // (We have to do this because the offset won't be quite right - // until the animation finishes - attempts to calculate the - // offset without taking into account CSS transforms have so far - // failed.) - var timeoutSeconds = DOCK_ANIMATION_TIME / 1000; - finishedAt = Date.now() + DOCK_ANIMATION_TIME + 50; - setTimeout(function () { - finishedAt = Date.now() + DOCK_ANIMATION_TIME + 40; - var iface = container.find("#togetherjs-dock"); - var start = iface.offset(); - var pos = $(TogetherJS.startTarget).offset(); - pos.top = Math.floor(pos.top - start.top); - pos.left = Math.floor(pos.left - start.left); - var translate = "translate(" + pos.left + "px, " + pos.top + "px)"; - iface.css({ - MozTransform: translate, - WebkitTransform: translate, - transform: translate, - opacity: "0.0" - }); - setTimeout(function () { - // We keep recalculating because the setTimeout times aren't always so accurate: - finishedAt = Date.now() + DOCK_ANIMATION_TIME + 20; - var transition = "transform " + timeoutSeconds + "s ease-out, "; - transition += "opacity " + timeoutSeconds + "s ease-out"; - iface.css({ - opacity: "1.0", - MozTransition: "-moz-" + transition, - MozTransform: "translate(0, 0)", - WebkitTransition: "-webkit-" + transition, - WebkitTransform: "translate(0, 0)", - transition: transition, - transform: "translate(0, 0)" - }); - setTimeout(function () { - finishedAt = null; - iface.attr("style", ""); - }, 510); - }, 5); - }, 5); - } - if (TogetherJS.startTarget) { - var el = $(TogetherJS.startTarget); - var text = el.text().toLowerCase().replace(/\s+/g, " "); - text = text.replace(/^\s*/, "").replace(/\s*$/, ""); - if (text == "start togetherjs") { - el.attr("data-end-togetherjs-html", "End TogetherJS"); - } - if (el.attr("data-end-togetherjs-html")) { - el.attr("data-start-togetherjs-html", el.html()); - el.html(el.attr("data-end-togetherjs-html")); - } - el.addClass("togetherjs-started"); - } - ui.container.find(".togetherjs-window > header, .togetherjs-modal > header").each(function () { - $(this).append($('')); - }); - - TogetherJS.config.track("disableWebRTC", function (hide, previous) { - if (hide && ! previous) { - ui.container.find("#togetherjs-audio-button").hide(); - adjustDockSize(-1); - } else if ((! hide) && previous) { - ui.container.find("#togetherjs-audio-button").show(); - adjustDockSize(1); - } - }); - - }; - - // After prepareUI, this actually makes the interface live. We have - // to do this later because we call prepareUI when many components - // aren't initialized, so we don't even want the user to be able to - // interact with the interface. But activateUI is called once - // everything is loaded and ready for interaction. - ui.activateUI = function () { - if (deferringPrepareUI) { - console.warn("ui.activateUI called before document is ready; waiting..."); - deferringPrepareUI = "activate"; - return; - } - if (! ui.container) { - ui.prepareUI(); - } - var container = ui.container; - - //create the overlay - if($.browser.mobile) { - // $("body").append( "\x3cdiv class='overlay' style='position: absolute; top: 0; left: 0; background-color: rgba(0,0,0,0); width: 120%; height: 100%; z-index: 1000; margin: -10px'>\x3c/div>" ); - } - - // The share link: - ui.prepareShareLink(container); - container.find("input.togetherjs-share-link").on("keydown", function (event) { - if (event.which == 27) { - windowing.hide("#togetherjs-share"); - return false; - } - return undefined; - }); - session.on("shareId", updateShareLink); - - // The chat input element: - var input = container.find("#togetherjs-chat-input"); - input.bind("keydown", function (event) { - if (event.which == 13 && !event.shiftKey) { // Enter without Shift pressed - submitChat(); - return false; - } - if (event.which == 27) { // Escape - windowing.hide("#togetherjs-chat"); - return false; - } - }); - - function submitChat() { - var val = input.val(); - if ($.trim(val)) { - input.val(""); - // triggering the event manually to avoid the addition of newline character to the textarea: - input.trigger("input").trigger("propertychange"); - chat.submit(val); - } - } - // auto-resize textarea: - input.on("input propertychange", function () { - var $this = $(this); - var actualHeight = $this.height(); - // reset the height of textarea to remove trailing empty space (used for shrinking): - $this.height(TEXTAREA_LINE_HEIGHT); - this.scrollTop = 0; - // scroll to bottom: - this.scrollTop = 9999; - var newHeight = this.scrollTop + $this.height(); - var maxHeight = TEXTAREA_MAX_LINES * TEXTAREA_LINE_HEIGHT; - if (newHeight > maxHeight) { - newHeight = maxHeight; - this.style.overflowY = "scroll"; - } else { - this.style.overflowY = "hidden"; - } - this.style.height = newHeight + "px"; - var diff = newHeight - actualHeight; - $("#togetherjs-chat-input-box").height($("#togetherjs-chat-input-box").height() + diff); - $("#togetherjs-chat-messages").height($("#togetherjs-chat-messages").height() - diff); - return false; - }); - - util.testExpose({submitChat: submitChat}); - - // Moving the window: - // FIXME: this should probably be stickier, and not just move the window around - // so abruptly - var anchor = container.find("#togetherjs-dock-anchor"); - assert(anchor.length); - // FIXME: This is in place to temporarily disable dock dragging: - anchor = container.find("#togetherjs-dock-anchor-disabled"); - anchor.mousedown(function (event) { - var iface = $("#togetherjs-dock"); - // FIXME: switch to .offset() and pageX/Y - var startPos = panelPosition(); - function selectoff() { - return false; - } - function mousemove(event2) { - var fromRight = $window.width() + window.pageXOffset - event2.pageX; - var fromLeft = event2.pageX - window.pageXOffset; - var fromBottom = $window.height() + window.pageYOffset - event2.pageY; - // FIXME: this is to temporarily disable the bottom view: - fromBottom = 10000; - - var pos; - if (fromLeft < fromRight && fromLeft < fromBottom) { - pos = "left"; - } else if (fromRight < fromLeft && fromRight < fromBottom) { - pos = "right"; - } else { - pos = "bottom"; - } - iface.removeClass("togetherjs-dock-left"); - iface.removeClass("togetherjs-dock-right"); - iface.removeClass("togetherjs-dock-bottom"); - iface.addClass("togetherjs-dock-" + pos); - if (startPos && pos != startPos) { - windowing.hide(); - startPos = null; - } - } - $(document).bind("mousemove", mousemove); - // If you don't turn selection off it will still select text, and show a - // text selection cursor: - $(document).bind("selectstart", selectoff); - // FIXME: it seems like sometimes we lose the mouseup event, and it's as though - // the mouse is stuck down: - $(document).one("mouseup", function () { - $(document).unbind("mousemove", mousemove); - $(document).unbind("selectstart", selectoff); - }); - return false; - }); - - function openDock() { - $('.togetherjs-window').animate({ - opacity: 1 - }); - $('#togetherjs-dock-participants').animate({ - opacity: 1 - }); - $('#togetherjs-dock #togetherjs-buttons').animate({ - opacity: 1 - }); - - //for iphone - if($(window).width() < 480) { - $('.togetherjs-dock-right').animate({ - width: "204px" - }, { - duration:60, easing:"linear" - }); - } - - //for ipad - else { - $('.togetherjs-dock-right').animate({ - width: "27%" - }, { - duration:60, easing:"linear" - }); - } - - - // add bg overlay - // $("body").append( "\x3cdiv class='overlay' style='position: absolute; top: 0; left: -2px; background-color: rgba(0,0,0,0.5); width: 200%; height: 400%; z-index: 1000; margin: 0px;'>\x3c/div>" ); - - //disable vertical scrolling - // $("body").css({ - // "position": "fixed", - // top: 0, - // left: 0 - // }); - - //replace the anchor icon - var src = "/togetherjs/images/togetherjs-logo-close.png"; - $("#togetherjs-dock-anchor #togetherjs-dock-anchor-horizontal img").attr("src", src); - } - - function closeDock() { - //enable vertical scrolling - $("body").css({ - "position": "", - top: "", - left: "" - }); - - //replace the anchor icon - var src = "/togetherjs/images/togetherjs-logo-open.png"; - $("#togetherjs-dock-anchor #togetherjs-dock-anchor-horizontal img").attr("src", src); - - $('.togetherjs-window').animate({ - opacity: 0 - }); - $('#togetherjs-dock-participants').animate({ - opacity: 0 - }); - $('#togetherjs-dock #togetherjs-buttons').animate({ - opacity: 0 - }); - $('.togetherjs-dock-right').animate({ - width: "40px" - }, { - duration:60, easing:"linear" - }); - - // remove bg overlay - //$(".overlay").remove(); - } - - // Setting the anchor button + dock mobile actions - if($.browser.mobile) { - - // toggle the audio button - $("#togetherjs-audio-button").click(function () { - windowing.toggle("#togetherjs-rtc-not-supported"); - }); - - // toggle the profile button - $("#togetherjs-profile-button").click(function () { - windowing.toggle("#togetherjs-menu-window"); - }); - - // $("body").append( "\x3cdiv class='overlay' style='position: absolute; top: 0; left: -2px; background-color: rgba(0,0,0,0.5); width: 200%; height: 400%; z-index: 1000; margin: 0px'>\x3c/div>" ); - - //disable vertical scrolling - // $("body").css({ - // "position": "fixed", - // top: 0, - // left: 0 - // }); - - //replace the anchor icon - var src = "/togetherjs/images/togetherjs-logo-close.png"; - $("#togetherjs-dock-anchor #togetherjs-dock-anchor-horizontal img").attr("src", src); - - $("#togetherjs-dock-anchor").toggle(function() { - closeDock(); - },function(){ - openDock(); - }); - } - - $("#togetherjs-share-button").click(function () { - windowing.toggle("#togetherjs-share"); - }); - - $("#togetherjs-profile-button").click(function (event) { - if ($.browser.mobile) { - windowing.show("#togetherjs-menu-window"); - return false; - } - toggleMenu(); - event.stopPropagation(); - return false; - }); - - $("#togetherjs-menu-feedback, #togetherjs-menu-feedback-button").click(function(){ - windowing.hide(); - hideMenu(); - windowing.show("#togetherjs-feedback-form"); - }); - - $("#togetherjs-menu-help, #togetherjs-menu-help-button").click(function () { - windowing.hide(); - hideMenu(); - require(["walkthrough"], function (walkthrough) { - windowing.hide(); - walkthrough.start(false); - }); - }); - - $("#togetherjs-menu-update-name").click(function () { - var input = $("#togetherjs-menu .togetherjs-self-name"); - input.css({ - width: $("#togetherjs-menu").width() - 32 + "px" - }); - ui.displayToggle("#togetherjs-menu .togetherjs-self-name"); - $("#togetherjs-menu .togetherjs-self-name").focus(); - }); - - $("#togetherjs-menu-update-name-button").click(function () { - windowing.show("#togetherjs-edit-name-window"); - $("#togetherjs-edit-name-window input").focus(); - }); - - $("#togetherjs-menu .togetherjs-self-name").bind("keyup change", function (event) { - console.log("alrighty", event); - if (event.which == 13) { - ui.displayToggle("#togetherjs-self-name-display"); - return; - } - var val = $("#togetherjs-menu .togetherjs-self-name").val(); - console.log("values!!", val); - if (val) { - peers.Self.update({name: val}); - } - }); - - $("#togetherjs-menu-update-avatar, #togetherjs-menu-update-avatar-button").click(function () { - hideMenu(); - windowing.show("#togetherjs-avatar-edit"); - }); - - $("#togetherjs-menu-end, #togetherjs-menu-end-button").click(function () { - hideMenu(); - windowing.show("#togetherjs-confirm-end"); - }); - - $("#togetherjs-end-session").click(function () { - session.close(); - //$(".overlay").remove(); - - }); - - $("#togetherjs-menu-update-color").click(function () { - var picker = $("#togetherjs-pick-color"); - if (picker.is(":visible")) { - picker.hide(); - return; - } - picker.show(); - bindPicker(); - picker.find(".togetherjs-swatch-active").removeClass("togetherjs-swatch-active"); - picker.find(".togetherjs-swatch[data-color=\"" + peers.Self.color + "\"]").addClass("togetherjs-swatch-active"); - }); - - $("#togetherjs-pick-color").click(".togetherjs-swatch", function (event) { - var swatch = $(event.target); - var color = swatch.attr("data-color"); - peers.Self.update({ - color: color - }); - event.stopPropagation(); - return false; - }); - - $("#togetherjs-pick-color").click(function (event) { - $("#togetherjs-pick-color").hide(); - event.stopPropagation(); - return false; - }); - - COLORS.forEach(function (color) { - var el = templating.sub("swatch"); - el.attr("data-color", color); - var darkened = tinycolor.darken(color); - el.css({ - backgroundColor: color, - borderColor: darkened - }); - $("#togetherjs-pick-color").append(el); - }); - - $("#togetherjs-chat-button").click(function () { - windowing.toggle("#togetherjs-chat"); - }); - - session.on("display-window", function (id, element) { - if (id == "togetherjs-chat") { - if (! $.browser.mobile) { - $("#togetherjs-chat-input").focus(); - } - } else if (id == "togetherjs-share") { - var link = element.find("input.togetherjs-share-link"); - if (link.is(":visible")) { - link.focus().select(); - } - } - }); - - container.find("#togetherjs-chat-notifier").click(function (event) { - if ($(event.target).is("a") || container.is(".togetherjs-close")) { - return; - } - windowing.show("#togetherjs-chat"); - }); - - // FIXME: Don't think this makes sense - $(".togetherjs header.togetherjs-title").each(function (index, item) { - var button = $(''); - button.click(function (event) { - var window = button.closest(".togetherjs-window"); - windowing.hide(window); - }); - $(item).append(button); - }); - - $("#togetherjs-avatar-done").click(function () { - ui.displayToggle("#togetherjs-no-avatar-edit"); - }); - - $("#togetherjs-self-color").css({backgroundColor: peers.Self.color}); - - var avatar = peers.Self.avatar; - if (avatar) { - $("#togetherjs-self-avatar").attr("src", avatar); - } - - var starterButton = $("#togetherjs-starter button"); - starterButton.click(function () { - windowing.show("#togetherjs-about"); - }).addClass("togetherjs-running"); - if (starterButton.text() == "Start TogetherJS") { - starterButton.attr("data-start-text", starterButton.text()); - starterButton.text("End TogetherJS Session"); - } - - ui.activateAvatarEdit(container, { - onSave: function () { - windowing.hide("#togetherjs-avatar-edit"); - } - }); - - TogetherJS.config.track("inviteFromRoom", function (inviter, previous) { - if (inviter) { - container.find("#togetherjs-invite").show(); - } else { - container.find("#togetherjs-invite").hide(); - } - }); - - container.find("#togetherjs-menu-refresh-invite").click(refreshInvite); - container.find("#togetherjs-menu-invite-anyone").click(function () { - invite(null); - }); - - // The following lines should be at the end of this function - // (new code goes above) - session.emit("new-element", ui.container); - - if (finishedAt && finishedAt > Date.now()) { - setTimeout(function () { - finishedAt = null; - session.emit("ui-ready", ui); - }, finishedAt - Date.now()); - } else { - session.emit("ui-ready", ui); - } - - }; // End ui.activateUI() - - ui.activateAvatarEdit = function (container, options) { - options = options || {}; - var pendingImage = null; - - container.find(".togetherjs-avatar-save").prop("disabled", true); - - container.find(".togetherjs-avatar-save").click(function () { - if (pendingImage) { - peers.Self.update({avatar: pendingImage}); - container.find(".togetherjs-avatar-save").prop("disabled", true); - if (options.onSave) { - options.onSave(); - } - } - }); - - container.find(".togetherjs-upload-avatar").on("change", function () { - util.readFileImage(this).then(function (url) { - sizeDownImage(url).then(function (smallUrl) { - pendingImage = smallUrl; - container.find(".togetherjs-avatar-preview").css({ - backgroundImage: 'url(' + pendingImage + ')' - }); - container.find(".togetherjs-avatar-save").prop("disabled", false); - if (options.onPending) { - options.onPending(); - } - }); - }); - }); - - }; - - function sizeDownImage(imageUrl) { - return util.Deferred(function (def) { - var $canvas = $(""); - $canvas[0].height = session.AVATAR_SIZE; - $canvas[0].width = session.AVATAR_SIZE; - var context = $canvas[0].getContext("2d"); - var img = new Image(); - img.src = imageUrl; - // Sometimes the DOM updates immediately to call - // naturalWidth/etc, and sometimes it doesn't; using setTimeout - // gives it a chance to catch up - setTimeout(function () { - var width = img.naturalWidth || img.width; - var height = img.naturalHeight || img.height; - width = width * (session.AVATAR_SIZE / height); - height = session.AVATAR_SIZE; - context.drawImage(img, 0, 0, width, height); - def.resolve($canvas[0].toDataURL("image/png")); - }); - }); - } - - function fixupAvatars(container) { - /* All
    elements need an element inside, - so we add that element here */ - container.find(".togetherjs-person").each(function () { - var $this = $(this); - var inner = $this.find(".togetherjs-person-avatar-swatch"); - if (! inner.length) { - $this.append('
    '); - } - }); - } - - ui.prepareShareLink = function (container) { - container.find("input.togetherjs-share-link").click(function () { - $(this).select(); - }).change(function () { - updateShareLink(); - }); - container.find("a.togetherjs-share-link").click(function () { - // FIXME: this is currently opening up Bluetooth, not sharing a link - if (false && window.MozActivity) { - var activity = new MozActivity({ - name: "share", - data: { - type: "url", - url: $(this).attr("href") - } - }); - } - // FIXME: should show some help if you actually try to follow the link - // like this, instead of simply suppressing it - return false; - }); - updateShareLink(); - }; - - // Menu - - function showMenu(event) { - var el = $("#togetherjs-menu"); - assert(el.length); - el.show(); - bindMenu(); - $(document).bind("click", maybeHideMenu); - } - - function bindMenu() { - var el = $("#togetherjs-menu:visible"); - if (el.length) { - var bound = $("#togetherjs-profile-button"); - var boundOffset = bound.offset(); - el.css({ - top: boundOffset.top + bound.height() - $window.scrollTop() + "px", - left: (boundOffset.left + bound.width() - 10 - el.width() - $window.scrollLeft()) + "px" - }); - } - } - - function bindPicker() { - var picker = $("#togetherjs-pick-color:visible"); - if (picker.length) { - var menu = $("#togetherjs-menu-update-color"); - var menuOffset = menu.offset(); - picker.css({ - top: menuOffset.top + menu.height(), - left: menuOffset.left - }); - } - } - - session.on("resize", function () { - bindMenu(); - bindPicker(); - }); - - function toggleMenu() { - if ($("#togetherjs-menu").is(":visible")) { - hideMenu(); - } else { - showMenu(); - } - } - - function hideMenu() { - var el = $("#togetherjs-menu"); - el.hide(); - $(document).unbind("click", maybeHideMenu); - ui.displayToggle("#togetherjs-self-name-display"); - $("#togetherjs-pick-color").hide(); - } - - function maybeHideMenu(event) { - var t = event.target; - while (t) { - if (t.id == "togetherjs-menu") { - // Click inside the menu, ignore this - return; - } - t = t.parentNode; - } - hideMenu(); - } - - function adjustDockSize(buttons) { - /* Add or remove spots from the dock; positive number to - add button(s), negative number to remove button(s) - */ - assert(typeof buttons == "number"); - assert(buttons && Math.floor(buttons) == buttons); - var iface = $("#togetherjs-dock"); - var newHeight = iface.height() + (BUTTON_HEIGHT * buttons); - assert(newHeight >= BUTTON_HEIGHT * 3, "Height went too low (", newHeight, - "), should never be less than 3 buttons high (", BUTTON_HEIGHT * 3, ")"); - iface.css({ - height: newHeight + "px" - }); - } - - // Misc - - function updateShareLink() { - var input = $("input.togetherjs-share-link"); - var link = $("a.togetherjs-share-link"); - var display = $("#togetherjs-session-id"); - if (! session.shareId) { - input.val(""); - link.attr("href", "#"); - display.text("(none)"); - } else { - input.val(session.shareUrl()); - link.attr("href", session.shareUrl()); - display.text(session.shareId); - } - } - - session.on("close", function () { - - if($.browser.mobile) { - // remove bg overlay - //$(".overlay").remove(); - - //after hitting End, reset window draggin - $("body").css({ - "position": "", - top: "", - left: "" - }); - - } - - if (ui.container) { - ui.container.remove(); - ui.container = null; - } - // Clear out any other spurious elements: - $(".togetherjs").remove(); - var starterButton = $("#togetherjs-starter button"); - starterButton.removeClass("togetherjs-running"); - if (starterButton.attr("data-start-text")) { - starterButton.text(starterButton.attr("data-start-text")); - starterButton.attr("data-start-text", ""); - } - if (TogetherJS.startTarget) { - var el = $(TogetherJS.startTarget); - if (el.attr("data-start-togetherjs-html")) { - el.html(el.attr("data-start-togetherjs-html")); - } - el.removeClass("togetherjs-started"); - } - }); - - ui.chat = { - text: function (attrs) { - assert(typeof attrs.text == "string"); - assert(attrs.peer); - assert(attrs.messageId); - var date = attrs.date || Date.now(); - var lastEl = ui.container.find("#togetherjs-chat .togetherjs-chat-message"); - if (lastEl.length) { - lastEl = $(lastEl[lastEl.length-1]); - } - var lastDate = null; - if (lastEl) { - lastDate = parseInt(lastEl.attr("data-date"), 10); - } - if (lastEl && lastEl.attr("data-person") == attrs.peer.id && - lastDate && date < lastDate + COLLAPSE_MESSAGE_LIMIT) { - lastEl.attr("data-date", date); - var content = lastEl.find(".togetherjs-chat-content"); - assert(content.length); - attrs.text = content.text() + "\n" + attrs.text; - attrs.messageId = lastEl.attr("data-message-id"); - lastEl.remove(); - } - var el = templating.sub("chat-message", { - peer: attrs.peer, - content: attrs.text, - date: date - }); - linkify(el.find(".togetherjs-chat-content")); - el.attr("data-person", attrs.peer.id) - .attr("data-date", date) - .attr("data-message-id", attrs.messageId); - ui.chat.add(el, attrs.messageId, attrs.notify); - }, - - joinedSession: function (attrs) { - assert(attrs.peer); - var date = attrs.date || Date.now(); - var el = templating.sub("chat-joined", { - peer: attrs.peer, - date: date - }); - // FIXME: should bind the notification to the dock location - ui.chat.add(el, attrs.peer.className("join-message-"), 4000); - }, - - leftSession: function (attrs) { - assert(attrs.peer); - var date = attrs.date || Date.now(); - var el = templating.sub("chat-left", { - peer: attrs.peer, - date: date, - declinedJoin: attrs.declinedJoin - }); - // FIXME: should bind the notification to the dock location - ui.chat.add(el, attrs.peer.className("join-message-"), 4000); - }, - - system: function (attrs) { - assert(! attrs.peer); - assert(typeof attrs.text == "string"); - var date = attrs.date || Date.now(); - var el = templating.sub("chat-system", { - content: attrs.text, - date: date - }); - ui.chat.add(el, undefined, true); - }, - - clear: deferForContainer(function () { - var container = ui.container.find("#togetherjs-chat-messages"); - container.empty(); - }), - - urlChange: function (attrs) { - assert(attrs.peer); - assert(typeof attrs.url == "string"); - assert(typeof attrs.sameUrl == "boolean"); - var messageId = attrs.peer.className("url-change-"); - // FIXME: duplicating functionality in .add(): - var realId = "togetherjs-chat-" + messageId; - var date = attrs.date || Date.now(); - var title; - // FIXME: strip off common domain from msg.url? E.g., if I'm on - // http://example.com/foobar, and someone goes to http://example.com/baz then - // show only /baz - // FIXME: truncate long titles - if (attrs.title) { - title = attrs.title + " (" + attrs.url + ")"; - } else { - title = attrs.url; - } - var el = templating.sub("url-change", { - peer: attrs.peer, - date: date, - href: attrs.url, - title: title, - sameUrl: attrs.sameUrl - }); - el.find(".togetherjs-nudge").click(function () { - attrs.peer.nudge(); - return false; - }); - el.find(".togetherjs-follow").click(function () { - var url = attrs.peer.url; - if (attrs.peer.urlHash) { - url += attrs.peer.urlHash; - } - location.href = url; - }); - var notify = ! attrs.sameUrl; - if (attrs.sameUrl && ! $("#" + realId).length) { - // Don't bother showing a same-url notification, if no previous notification - // had been shown - return; - } - ui.chat.add(el, messageId, notify); - }, - - invite: function (attrs) { - assert(attrs.peer); - assert(typeof attrs.url == "string"); - var messageId = attrs.peer.className("invite-"); - var date = attrs.date || Date.now(); - var hrefTitle = attrs.url.replace(/\#?&togetherjs=.*/, "").replace(/^\w+:\/\//, ""); - var el = templating.sub("invite", { - peer: attrs.peer, - date: date, - href: attrs.url, - hrefTitle: hrefTitle, - forEveryone: attrs.forEveryone - }); - if (attrs.forEveryone) { - el.find("a").click(function () { - // FIXME: hacky way to do this: - chat.submit("Followed link to " + attrs.url); - }); - } - ui.chat.add(el, messageId, true); - }, - - hideTimeout: null, - - add: deferForContainer(function (el, id, notify) { - if (id) { - el.attr("id", "togetherjs-chat-" + util.safeClassName(id)); - } - var container = ui.container.find("#togetherjs-chat-messages"); - assert(container.length); - var popup = ui.container.find("#togetherjs-chat-notifier"); - container.append(el); - ui.chat.scroll(); - var doNotify = !! notify; - var section = popup.find("#togetherjs-chat-notifier-message"); - if (notify && visibilityApi.hidden()) { - ui.container.find("#togetherjs-notification")[0].play(); - } - if (id && section.data("message-id") == id) { - doNotify = true; - } - if (container.is(":visible")) { - doNotify = false; - } - if (doNotify) { - section.empty(); - section.append(el.clone(true, true)); - if (section.data("message-id") != id) { - section.data("message-id", id || ""); - windowing.show(popup); - } else if (! popup.is(":visible")) { - windowing.show(popup); - } - if (typeof notify == "number") { - // This is the amount of time we're supposed to notify - if (this.hideTimeout) { - clearTimeout(this.hideTimeout); - this.hideTimeout = null; - } - this.hideTimeout = setTimeout((function () { - windowing.hide(popup); - this.hideTimeout = null; - }).bind(this), notify); - } - } - }), - - scroll: deferForContainer(function () { - var container = ui.container.find("#togetherjs-chat-messages")[0]; - container.scrollTop = container.scrollHeight; - }) - - }; - - session.on("display-window", function (id, win) { - if (id == "togetherjs-chat") { - ui.chat.scroll(); - windowing.hide("#togetherjs-chat-notifier"); - } - }); - - /* This class is bound to peers.Peer instances as peer.view. - The .update() method is regularly called by peer objects when info changes. */ - ui.PeerView = util.Class({ - - constructor: function (peer) { - assert(peer.isSelf !== undefined, "PeerView instantiated with non-Peer object"); - this.peer = peer; - this.dockClick = this.dockClick.bind(this); - }, - - /* Takes an element and sets any person-related attributes on the element - Different from updates, which use the class names we set here: */ - setElement: function (el) { - var count = 0; - var classes = ["togetherjs-person", "togetherjs-person-status", - "togetherjs-person-name", "togetherjs-person-name-abbrev", - "togetherjs-person-bgcolor", "togetherjs-person-swatch", - "togetherjs-person-status", "togetherjs-person-role", - "togetherjs-person-url", "togetherjs-person-url-title", - "togetherjs-person-bordercolor"]; - classes.forEach(function (cls) { - var els = el.find("." + cls); - els.addClass(this.peer.className(cls + "-")); - count += els.length; - }, this); - if (! count) { - console.warn("setElement(", el, ") doesn't contain any person items"); - } - this.updateDisplay(el); - }, - - updateDisplay: deferForContainer(function (container) { - container = container || ui.container; - var abbrev = this.peer.name; - if (this.peer.isSelf) { - abbrev = "me"; - } - container.find("." + this.peer.className("togetherjs-person-name-")).text(this.peer.name || ""); - container.find("." + this.peer.className("togetherjs-person-name-abbrev-")).text(abbrev); - var avatarEl = container.find("." + this.peer.className("togetherjs-person-")); - if (this.peer.avatar) { - util.assertValidUrl(this.peer.avatar); - avatarEl.css({ - backgroundImage: "url(" + this.peer.avatar + ")" - }); - } - if (this.peer.idle == "inactive") { - avatarEl.addClass("togetherjs-person-inactive"); - } else { - avatarEl.removeClass("togetherjs-person-inactive"); - } - avatarEl.attr("title", this.peer.name); - if (this.peer.color) { - avatarEl.css({ - borderColor: this.peer.color - }); - avatarEl.find(".togetherjs-person-avatar-swatch").css({ - borderTopColor: this.peer.color, - borderRightColor: this.peer.color - }); - } - if (this.peer.color) { - var colors = container.find("." + this.peer.className("togetherjs-person-bgcolor-")); - colors.css({ - backgroundColor: this.peer.color - }); - colors = container.find("." + this.peer.className("togetherjs-person-bordercolor-")); - colors.css({ - borderColor: this.peer.color - }); - } - container.find("." + this.peer.className("togetherjs-person-role-")) - .text(this.peer.isCreator ? "Creator" : "Participant"); - var urlName = this.peer.title || ""; - if (this.peer.title) { - urlName += " ("; - } - urlName += util.truncateCommonDomain(this.peer.url, location.href); - if (this.peer.title) { - urlName += ")"; - } - container.find("." + this.peer.className("togetherjs-person-url-title-")) - .text(urlName); - var url = this.peer.url; - if (this.peer.urlHash) { - url += this.peer.urlHash; - } - container.find("." + this.peer.className("togetherjs-person-url-")) - .attr("href", url); - // FIXME: should have richer status: - container.find("." + this.peer.className("togetherjs-person-status-")) - .text(this.peer.idle == "active" ? "Active" : "Inactive"); - if (this.peer.isSelf) { - // FIXME: these could also have consistent/reliable class names: - var selfName = $(".togetherjs-self-name"); - selfName.each((function (index, el) { - el = $(el); - if (el.val() != this.peer.name) { - el.val(this.peer.name); - } - }).bind(this)); - $("#togetherjs-menu-avatar").attr("src", this.peer.avatar); - if (! this.peer.name) { - $("#togetherjs-menu .togetherjs-person-name-self").text(this.peer.defaultName); - } - } - if (this.peer.url != session.currentUrl()) { - container.find("." + this.peer.className("togetherjs-person-")) - .addClass("togetherjs-person-other-url"); - } else { - container.find("." + this.peer.className("togetherjs-person-")) - .removeClass("togetherjs-person-other-url"); - } - if (this.peer.following) { - if (this.followCheckbox) { - this.followCheckbox.prop("checked", true); - } - } else { - if (this.followCheckbox) { - this.followCheckbox.prop("checked", false); - } - } - // FIXME: add some style based on following? - updateChatParticipantList(); - this.updateFollow(); - }),UPDATEURL - - update: function () { - if (! this.peer.isSelf) { - if (this.peer.status == "live") { - this.dock(); - } else { - this.undock(); - } - } - this.updateDisplay(); - this.updateUrlDisplay(); - }, - - updateUrlDisplay: function (force) { - var url = this.peer.url; - if ((! url) || (url == this._lastUpdateUrlDisplay && ! force)) { - return; - } - this._lastUpdateUrlDisplay = url; - var sameUrl = url == session.currentUrl(); - ui.chat.urlChange({ - peer: this.peer, - url: this.peer.url, - title: this.peer.title, - sameUrl: sameUrl - }); - }, - - urlNudge: function () { - // FIXME: do something more distinct here - this.updateUrlDisplay(true); - }, - - notifyJoined: function () { - ui.chat.joinedSession({ - peer: this.peer - }); - }, - - // when there are too many participants in the dock, consolidate the participants to one avatar, and on mouseOver, the dock expands down to reveal the rest of the participants - // if there are X users in the session - // then hide the users in the dock - // and shrink the size of the dock - // and if you rollover the dock, it expands and reveals the rest of the participants in the dock - - //if users hit X then show the participant button with the consol - - dock: deferForContainer(function () { - - var numberOfUsers = peers.getAllPeers().length; - - // collapse the Dock if too many users - function CollapsedDock() { - // decrease/reset dock height - $("#togetherjs-dock").css("height", 260); - //replace participant button - $("#togetherjs-dock-participants").replaceWith(""); - // new full participant window created on toggle - $("#togetherjs-participantlist-button").click(function () { - windowing.toggle("#togetherjs-participantlist"); - }); - } - - // FIXME: turned off for now - if( numberOfUsers >= 5 && false) { - CollapsedDock(); - } else { - // reset - - } - - - if (this.dockElement) { - return; - } - this.dockElement = templating.sub("dock-person", { - peer: this.peer - }); - this.dockElement.attr("id", this.peer.className("togetherjs-dock-element-")); - ui.container.find("#togetherjs-dock-participants").append(this.dockElement); - this.dockElement.find(".togetherjs-person").animateDockEntry(); - adjustDockSize(1); - this.detailElement = templating.sub("participant-window", { - peer: this.peer - }); - var followId = this.peer.className("togetherjs-person-status-follow-"); - this.detailElement.find('[for="togetherjs-person-status-follow"]').attr("for", followId); - this.detailElement.find('#togetherjs-person-status-follow').attr("id", followId); - this.detailElement.find(".togetherjs-follow").click(function () { - location.href = $(this).attr("href"); - }); - this.detailElement.find(".togetherjs-nudge").click((function () { - this.peer.nudge(); - }).bind(this)); - this.followCheckbox = this.detailElement.find("#" + followId); - this.followCheckbox.change(function () { - if (! this.checked) { - this.peer.unfollow(); - } - // Following doesn't happen until the window is closed - // FIXME: should we tell the user this? - }); - this.maybeHideDetailWindow = this.maybeHideDetailWindow.bind(this); - session.on("hide-window", this.maybeHideDetailWindow); - ui.container.append(this.detailElement); - this.dockElement.click((function () { - if (this.detailElement.is(":visible")) { - windowing.hide(this.detailElement); - } else { - windowing.show(this.detailElement, {bind: this.dockElement}); - this.scrollTo(); - this.cursor().element.animate({ - opacity:0.3 - }).animate({ - opacity:1 - }).animate({ - opacity:0.3 - }).animate({ - opacity:1 - }); - } - }).bind(this)); - this.updateFollow(); - }), - - undock: function () { - if (! this.dockElement) { - return; - } - this.dockElement.animateDockExit().promise().then((function () { - this.dockElement.remove(); - this.dockElement = null; - this.detailElement.remove(); - this.detailElement = null; - adjustDockSize(-1); - }).bind(this)); - }, - - scrollTo: function () { - if (this.peer.url != session.currentUrl()) { - return; - } - var pos = this.peer.scrollPosition; - if (! pos) { - console.warn("Peer has no scroll position:", this.peer); - return; - } - pos = elementFinder.pixelForPosition(pos); - $("html, body").easeTo(pos); - }, - - updateFollow: function () { - if (! this.peer.url) { - return; - } - if (! this.detailElement) { - return; - } - var same = this.detailElement.find(".togetherjs-same-url"); - var different = this.detailElement.find(".togetherjs-different-url"); - if (this.peer.url == session.currentUrl()) { - same.show(); - different.hide(); - } else { - same.hide(); - different.show(); - } - }, - - maybeHideDetailWindow: function (windows) { - if (this.detailElement && windows[0] && windows[0][0] === this.detailElement[0]) { - if (this.followCheckbox[0].checked) { - this.peer.follow(); - } else { - this.peer.unfollow(); - } - } - }, - - dockClick: function () { - // FIXME: scroll to person - }, - - cursor: function () { - return require("cursor").getClient(this.peer.id); - }, - - destroy: function () { - // FIXME: should I get rid of the dockElement? - session.off("hide-window", this.maybeHideDetailWindow); - } - }); - - function updateChatParticipantList() { - var live = peers.getAllPeers(true); - if (live.length) { - ui.displayToggle("#togetherjs-chat-participants"); - $("#togetherjs-chat-participant-list").text( - live.map(function (p) {return p.name;}).join(", ")); - } else { - ui.displayToggle("#togetherjs-chat-no-participants"); - } - } - - function inviteHubUrl() { - var base = TogetherJS.config.get("inviteFromRoom"); - assert(base); - return util.makeUrlAbsolute(base, session.hubUrl()); - } - - var inRefresh = false; - - function refreshInvite() { - if (inRefresh) { - return; - } - inRefresh = true; - require(["who"], function (who) { - var def = who.getList(inviteHubUrl()); - function addUser(user, before) { - var item = templating.sub("invite-user-item", {peer: user}); - item.attr("data-clientid", user.id); - if (before) { - item.insertBefore(before); - } else { - $("#togetherjs-invite-users").append(item); - } - item.click(function() { - invite(user.clientId); - }); - } - function refresh(users, finished) { - var sorted = []; - for (var id in users) { - if (users.hasOwnProperty(id)) { - sorted.push(users[id]); - } - } - sorted.sort(function (a, b) { - return a.name < b.name ? -1 : 1; - }); - var pos = 0; - ui.container.find("#togetherjs-invite-users .togetherjs-menu-item").each(function () { - var $this = $(this); - if (finished && ! users[$this.attr("data-clientid")]) { - $this.remove(); - return; - } - if (pos >= sorted.length) { - return; - } - while (pos < sorted.length && $this.attr("data-clientid") !== sorted[pos].id) { - addUser(sorted[pos], $this); - pos++; - } - while (pos < sorted.length && $this.attr("data-clientid") == sorted[pos].id) { - pos++; - } - }); - for (var i=pos; i= this.logs.length) { - this.unload(); - return; - } - if (this.pos !== 0) { - // First we need to play the hello - var toReplay = []; - var foundHello = false; - for (var i=this.pos-1; i>=0; i--) { - var item = this.logs[i]; - if (ALWAYS_REPLAY[item.type]) { - toReplay.push(item); - } - if (item.type == "hello" || item.type == "hello-back") { - this.playItem(item); - foundHello = true; - break; - } - } - if (! foundHello) { - console.warn("No hello message found before position", this.pos); - } - toReplay.reverse(); - for (i=0; i= this.logs.length) { - this.unload(); - return; - } - var item = this.logs[this.pos]; - this.playItem(item); - this.pos++; - if (this.pos >= this.logs.length) { - this.unload(); - return; - } - var next = this.logs[this.pos]; - var pause = next.date - item.date; - this.playTimer = setTimeout(this.playOne.bind(this), pause); - if (this.fromStorage) { - this.savePos(); - } - }, - - playItem: function (item) { - if (item.type == "hello") { - // We may need to pause here - if (item.url != (location.href+"").replace(/\#.*/, "")) { - this.pause(); - } - } - try { - session._getChannel().onmessage(item); - } catch (e) { - console.warn("Could not play back message:", item, "error:", e); - } - }, - - save: function () { - this.fromStorage = true; - storage.set("playback.logs", this.logs); - this.savePos(); - }, - - savePos: function () { - storage.set("playback.pos", this.pos); - }, - - unload: function () { - if (this.fromStorage) { - storage.set("playback.logs", undefined); - storage.set("playback.pos", undefined); - } - // FIXME: should do a bye message here - } - - }); - - playback.getRunningLogs = function () { - return storage.get("playback.logs").then(function (value) { - if (! value) { - return null; - } - var logs = Logs(value, true); - return storage.get("playback.pos").then(function (pos) { - pos = pos || 0; - logs.pos = pos; - return logs; - }); - }); - }; - - return playback; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ -/*jshint evil:true */ -define('chat',["require", "jquery", "util", "session", "ui", "templates", "playback", "storage", "peers", "windowing"], function (require, $, util, session, ui, templates, playback, storage, peers, windowing) { - var chat = util.Module("chat"); - var assert = util.assert; - var Walkabout; - - session.hub.on("chat", function (msg) { - ui.chat.text({ - text: msg.text, - peer: msg.peer, - // FIXME: a little unsure of trusting this (maybe I should prefix it?) - messageId: msg.messageId, - notify: true - }); - saveChatMessage({ - text: msg.text, - date: Date.now(), - peerId: msg.peer.id, - messageId: msg.messageId - }); - }); - - // FIXME: this doesn't really belong in this module: - session.hub.on("bye", function (msg) { - ui.chat.leftSession({ - peer: msg.peer, - declinedJoin: msg.reason == "declined-join" - }); - }); - - chat.submit = function (message) { - var parts = message.split(/ /); - if (parts[0].charAt(0) == "/") { - var name = parts[0].substr(1).toLowerCase(); - var method = commands["command_" + name]; - if (method) { - method.apply(null, parts.slice(1)); - return; - } - } - var messageId = session.clientId + "-" + Date.now(); - session.send({ - type: "chat", - text: message, - messageId: messageId - }); - ui.chat.text({ - text: message, - peer: peers.Self, - messageId: messageId, - notify: false - }); - saveChatMessage({ - text: message, - date: Date.now(), - peerId: peers.Self.id, - messageId: messageId - }); - }; - - var commands = { - command_help: function () { - var msg = util.trim(templates.help); - ui.chat.system({ - text: msg - }); - }, - - command_test: function (args) { - if (! Walkabout) { - require(["walkabout"], (function (WalkaboutModule) { - Walkabout = WalkaboutModule; - this.command_test(args); - }).bind(this)); - return; - } - args = util.trim(args || "").split(/\s+/g); - if (args[0] === "" || ! args.length) { - if (this._testCancel) { - args = ["cancel"]; - } else { - args = ["start"]; - } - } - if (args[0] == "cancel") { - ui.chat.system({ - text: "Aborting test" - }); - this._testCancel(); - this._testCancel = null; - return; - } - if (args[0] == "start") { - var times = parseInt(args[1], 10); - if (isNaN(times) || ! times) { - times = 100; - } - ui.chat.system({ - text: "Testing with walkabout.js" - }); - var tmpl = $(templates.walkabout); - var container = ui.container.find(".togetherjs-test-container"); - container.empty(); - container.append(tmpl); - container.show(); - var statusContainer = container.find(".togetherjs-status"); - statusContainer.text("starting..."); - this._testCancel = Walkabout.runManyActions({ - ondone: function () { - statusContainer.text("done"); - statusContainer.one("click", function () { - container.hide(); - }); - this._testCancel = null; - }, - onstatus: function (status) { - var note = "actions: " + status.actions.length + " running: " + - (status.times - status.remaining) + " / " + status.times; - statusContainer.text(note); - } - }); - return; - } - if (args[0] == "show") { - if (this._testShow.length) { - this._testShow.forEach(function (item) { - if (item) { - item.remove(); - } - }, this); - this._testShow = []; - } else { - var actions = Walkabout.findActions(); - actions.forEach(function (action) { - this._testShow.push(action.show()); - }, this); - } - return; - } - if (args[0] == "describe") { - Walkabout.findActions().forEach(function (action) { - ui.chat.system({ - text: action.description() - }); - }, this); - return; - } - ui.chat.system({ - text: "Did not understand: " + args.join(" ") - }); - }, - - _testCancel: null, - _testShow: [], - - command_clear: function () { - ui.chat.clear(); - }, - - command_exec: function () { - var expr = Array.prototype.slice.call(arguments).join(" "); - var result; - // We use this to force global eval (not in this scope): - var e = eval; - try { - result = e(expr); - } catch (error) { - ui.chat.system({ - text: "Error: " + error - }); - } - if (result !== undefined) { - ui.chat.system({ - text: "" + result - }); - } - }, - - command_record: function () { - ui.chat.system({ - text: "When you see the robot appear, the recording will have started" - }); - window.open( - session.recordUrl(), "_blank", - "left,width=" + ($(window).width() / 2)); - }, - - playing: null, - - command_playback: function (url) { - if (this.playing) { - this.playing.cancel(); - this.playing.unload(); - this.playing = null; - ui.chat.system({ - text: "playback cancelled" - }); - return; - } - if (! url) { - ui.chat.system({ - text: "Nothing is playing" - }); - return; - } - var logLoader = playback.getLogs(url); - logLoader.then( - (function (logs) { - if (! logs) { - ui.chat.system({ - text: "No logs found." - }); - return; - } - logs.save(); - this.playing = logs; - logs.play(); - }).bind(this), - function (error) { - ui.chat.system({ - text: "Error fetching " + url + ":\n" + JSON.stringify(error, null, " ") - }); - }); - windowing.hide("#togetherjs-chat"); - }, - - command_savelogs: function (name) { - session.send({ - type: "get-logs", - forClient: session.clientId, - saveAs: name - }); - function save(msg) { - if (msg.request.forClient == session.clientId && msg.request.saveAs == name) { - storage.set("recording." + name, msg.logs).then(function () { - session.hub.off("logs", save); - ui.chat.system({ - text: "Saved as local:" + name - }); - }); - } - } - session.hub.on("logs", save); - }, - - command_baseurl: function (url) { - if (! url) { - storage.get("baseUrlOverride").then(function (b) { - if (b) { - ui.chat.system({ - text: "Set to: " + b.baseUrl - }); - } else { - ui.chat.system({ - text: "No baseUrl override set" - }); - } - }); - return; - } - url = url.replace(/\/*$/, ""); - ui.chat.system({ - text: "If this goes wrong, do this in the console to reset:\n localStorage.setItem('togetherjs.baseUrlOverride', null)" - }); - storage.set("baseUrlOverride", { - baseUrl: url, - expiresAt: Date.now() + (1000 * 60 * 60 * 24) - }).then(function () { - ui.chat.system({ - text: "baseUrl overridden (to " + url + "), will last for one day." - }); - }); - }, - - command_config: function (variable, value) { - if (! (variable || value)) { - storage.get("configOverride").then(function (c) { - if (c) { - util.forEachAttr(c, function (value, attr) { - if (attr == "expiresAt") { - return; - } - ui.chat.system({ - text: " " + attr + " = " + JSON.stringify(value) - }); - }); - ui.chat.system({ - text: "Config expires at " + (new Date(c.expiresAt)) - }); - } else { - ui.chat.system({ - text: "No config override" - }); - } - }); - return; - } - if (variable == "clear") { - storage.set("configOverride", undefined); - ui.chat.system({ - text: "Clearing all overridden configuration" - }); - return; - } - console.log("config", [variable, value]); - if (! (variable && value)) { - ui.chat.system({ - text: "Error: must provide /config VAR VALUE" - }); - return; - } - try { - value = JSON.parse(value); - } catch (e) { - ui.chat.system({ - text: "Error: value (" + value + ") could not be parsed: " + e - }); - return; - } - if (! TogetherJS._defaultConfiguration.hasOwnProperty(variable)) { - ui.chat.system({ - text: "Warning: variable " + variable + " is unknown" - }); - } - storage.get("configOverride").then(function (c) { - c = c || {}; - c[variable] = value; - c.expiresAt = Date.now() + (1000 * 60 * 60 * 24); - storage.set("configOverride", c).then(function () { - ui.chat.system({ - text: "Variable " + variable + " = " + JSON.stringify(value) + "\nValue will be set for one day." - }); - }); - }); - } - - }; - - // this section deal with saving/restoring chat history as long as session is alive - var chatStorageKey = "chatlog"; - var maxLogMessages = 100; - - function saveChatMessage(obj) { - assert(obj.peerId); - assert(obj.messageId); - assert(obj.date); - assert(typeof obj.text == "string"); - - loadChatLog().then(function (log) { - for (var i = log.length - 1; i >= 0; i--) { - if (log[i].messageId === obj.messageId) { - return; - } - } - log.push(obj); - if (log.length > maxLogMessages) { - log.splice(0, log.length - maxLogMessages); - } - storage.tab.set(chatStorageKey, log); - }); - } - - function loadChatLog() { - return storage.tab.get(chatStorageKey, []); - } - - session.once("ui-ready", function () { - loadChatLog().then(function (log) { - if (! log) { - return; - } - for (var i = 0; i < log.length; i++) { - // peers should already be loaded from sessionStorage by the peers module - // maybe i should use a try catch block here - var currentPeer = peers.getPeer(log[i].peerId); - ui.chat.text({ - text: log[i].text, - date: log[i].date, - peer: currentPeer, - messageId: log[i].messageId - }); - } - }); - }); - //delete chat log - session.on("close", function(){ - storage.tab.set(chatStorageKey, undefined); - }); - - return chat; - -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ -define('console',["util"], function (util) { - - var console = window.console || {log: function () {}}; - - var Console = util.Class({ - constructor: function () { - this.messages = []; - this.level = this.levels.log; - }, - - messageLimit: 100, - - levels: { - debug: 1, - // FIXME: I'm considering *not* wrapping console.log, and strictly keeping - // it as a debugging tool; also line numbers would be preserved - log: 2, - info: 3, - notify: 4, - warn: 5, - error: 6, - fatal: 7 - }, - - // Gets set below: - maxLevel: 0, - - consoleLevels: [ - [], - console.debug || [], - console.log || [], - console.info || [], - console.notify || [], - console.warn || [], - console.error || [], - console.fatal || [] - ], - - levelNames: {}, - - setLevel: function (l) { - var number; - if (typeof l == "string") { - number = this.levels[l]; - if (number === undefined) { - throw new Error("Tried to set Console level to unknown level string: " + l); - } - l = number; - } - if (typeof l == "function") { - number = this.consoleLevels.indexOf(l); - if (number == -1) { - throw new Error("Tried to set Console level based on unknown console function: " + l); - } - l = number; - } - if (typeof l == "number") { - if (l < 0) { - throw new Error("Console level must be 0 or larger: " + l); - } else if (l > this.maxLevel) { - throw new Error("Console level must be " + this.maxLevel + " or smaller: " + l); - } - } - this.level = l; - }, - - write: function (level) { - try { - this.messages.push([ - Date.now(), - level, - this._stringify(Array.prototype.slice.call(arguments, 1)) - ]); - } catch (e) { - console.warn("Error stringifying argument:", e); - } - if (level != "suppress" && this.level <= level) { - var method = console[this.levelNames[level]]; - if (! method) { - method = console.log; - } - method.apply(console, Array.prototype.slice.call(arguments, 1)); - } - }, - - suppressedWrite: function () { - this.write.apply(this, ["suppress"].concat(Array.prototype.slice.call(arguments))); - }, - - trace: function (level) { - level = level || 'log'; - if (console.trace) { - level = "suppressedWrite"; - } - try { - throw new Error(); - } catch (e) { - // FIXME: trim this frame - var stack = e.stack; - stack = stack.replace(/^[^\n]*\n/, ""); - this[level](stack); - } - if (console.trace) { - console.trace(); - } - }, - - _browserInfo: function () { - // FIXME: add TogetherJS version and - return [ - "TogetherJS base URL: " + TogetherJS.baseUrl, - "User Agent: " + navigator.userAgent, - "Page loaded: " + this._formatDate(TogetherJS.pageLoaded), - "Age: " + this._formatMinutes(Date.now() - TogetherJS.pageLoaded) + " minutes", - // FIXME: make this right: - //"Window: height: " + window.screen.height + " width: " + window.screen.width - "URL: " + location.href, - "------+------+----------------------------------------------" - ]; - }, - - _stringify: function (args) { - var s = ""; - for (var i=0; i 10) { - // Over 10 minutes, just ignore the seconds - return m; - } - var seconds = Math.floor(remaining / 1000) + ""; - m += ":"; - seconds = lpad(seconds, 2, "0"); - m += seconds; - if (m == "0:00") { - m += ((remaining / 1000).toFixed(3) + "").substr(1); - } - return m; - }, - - _formatLevel: function (l) { - if (l === "suppress") { - return ""; - } - return this.levelNames[l]; - }, - - toString: function () { - try { - var lines = this._browserInfo(); - this.messages.forEach(function (m) { - lines.push(lpad(this._formatTime(m[0]), 6) + " " + rpad(this._formatLevel(m[1]), 6) + " " + lpadLines(m[2], 14)); - }, this); - return lines.join("\n"); - } catch (e) { - // toString errors can otherwise be swallowed: - console.warn("Error running console.toString():", e); - throw e; - } - }, - - submit: function (options) { - // FIXME: friendpaste is broken for this - // (and other pastebin sites aren't really Browser-accessible) - return util.Deferred(function (def) { - options = options || {}; - var site = options.site || TogetherJS.config.get("pasteSite") || "https://www.friendpaste.com/"; - var req = new XMLHttpRequest(); - req.open("POST", site); - req.setRequestHeader("Content-Type", "application/json"); - req.send(JSON.stringify({ - "title": options.title || "TogetherJS log file", - "snippet": this.toString(), - "language": "text" - })); - req.onreadystatechange = function () { - if (req.readyState === 4) { - var data = JSON.parse(req.responseText); - } - }; - }); - } - - }); - - function rpad(s, len, pad) { - s = s + ""; - pad = pad || " "; - while (s.length < len) { - s += pad; - } - return s; - } - - function lpad(s, len, pad) { - s = s + ""; - pad = pad || " "; - while (s.length < len) { - s = pad + s; - } - return s; - } - - function lpadLines(s, len, pad) { - var i; - s = s + ""; - if (s.indexOf("\n") == -1) { - return s; - } - pad = pad || " "; - var fullPad = ""; - for (i=0; i wTop + height - CURSOR_HEIGHT) { - top = height - CURSOR_HEIGHT - 5; - this.setClass("togetherjs-scrolled-below"); - } else { - this.setClass("togetherjs-scrolled-normal"); - } - this.element.css({ - top: top, - left: left - }); - }, - - refresh: function () { - if (this.lastTop !== null) { - this.setPosition(this.lastTop, this.lastLeft); - } - }, - - setKeydown: function () { - if (this.keydownTimeout) { - clearTimeout(this.keydownTimeout); - } else { - this.element.find(".togetherjs-cursor-typing").show().animateKeyboard(); - } - this.keydownTimeout = setTimeout(this.clearKeydown, this.KEYDOWN_WAIT_TIME); - }, - - clearKeydown: function () { - this.keydownTimeout = null; - this.element.find(".togetherjs-cursor-typing").hide().stopKeyboardAnimation(); - }, - - _destroy: function () { - this.element.remove(); - this.element = null; - } - }); - - Cursor._cursors = {}; - - cursor.getClient = Cursor.getClient = function (clientId) { - var c = Cursor._cursors[clientId]; - if (! c) { - c = Cursor._cursors[clientId] = Cursor(clientId); - } - return c; - }; - - Cursor.forEach = function (callback, context) { - context = context || null; - for (var a in Cursor._cursors) { - if (Cursor._cursors.hasOwnProperty(a)) { - callback.call(context, Cursor._cursors[a], a); - } - } - }; - - Cursor.destroy = function (clientId) { - Cursor._cursors[clientId]._destroy(); - delete Cursor._cursors[clientId]; - }; - - peers.on("new-peer identity-updated status-updated", function (peer) { - var c = Cursor.getClient(peer.id); - c.updatePeer(peer); - }); - - var lastTime = 0; - var MIN_TIME = 100; - var lastPosX = -1; - var lastPosY = -1; - var lastMessage = null; - function mousemove(event) { - var now = Date.now(); - if (now - lastTime < MIN_TIME) { - return; - } - lastTime = now; - var pageX = event.pageX; - var pageY = event.pageY; - if (Math.abs(lastPosX - pageX) < 3 && Math.abs(lastPosY - pageY) < 3) { - // Not a substantial enough change - return; - } - lastPosX = pageX; - lastPosY = pageY; - var target = event.target; - var parent = $(target).closest(".togetherjs-window, .togetherjs-popup, #togetherjs-dock"); - if (parent.length) { - target = parent[0]; - } else if (elementFinder.ignoreElement(target)) { - target = null; - } - if ((! target) || target == document.documentElement || target == document.body) { - lastMessage = { - type: "cursor-update", - top: pageY, - left: pageX - }; - //session.send(lastMessage); - return; - } - target = $(target); - var offset = target.offset(); - if (! offset) { - // FIXME: this really is walkabout.js's problem to fire events on the - // document instead of a specific element - console.warn("Could not get offset of element:", target[0]); - return; - } - var offsetX = pageX - offset.left; - var offsetY = pageY - offset.top; - lastMessage = { - type: "cursor-update", - element: elementFinder.elementLocation(target), - offsetX: Math.floor(offsetX), - offsetY: Math.floor(offsetY) - }; - //session.send(lastMessage); - } - - function makeCursor(color) { - var canvas = $(""); - canvas.attr("height", CURSOR_HEIGHT); - canvas.attr("width", CURSOR_WIDTH); - var context = canvas[0].getContext('2d'); - context.fillStyle = color; - context.moveTo(0, 0); - context.beginPath(); - context.lineTo(0, CURSOR_HEIGHT/1.2); - context.lineTo(Math.sin(CURSOR_ANGLE/2) * CURSOR_HEIGHT / 1.5, - Math.cos(CURSOR_ANGLE/2) * CURSOR_HEIGHT / 1.5); - context.lineTo(Math.sin(CURSOR_ANGLE) * CURSOR_HEIGHT / 1.2, - Math.cos(CURSOR_ANGLE) * CURSOR_HEIGHT / 1.2); - context.lineTo(0, 0); - context.shadowColor = 'rgba(0,0,0,0.3)'; - context.shadowBlur = 2; - context.shadowOffsetX = 1; - context.shadowOffsetY = 2; - context.strokeStyle = "#ffffff"; - context.stroke(); - context.fill(); - return canvas[0].toDataURL("image/png"); - } - - var scrollTimeout = null; - var scrollTimeoutSet = 0; - var SCROLL_DELAY_TIMEOUT = 75; - var SCROLL_DELAY_LIMIT = 300; - - function scroll() { - var now = Date.now(); - if (scrollTimeout) { - if (now - scrollTimeoutSet < SCROLL_DELAY_LIMIT) { - clearTimeout(scrollTimeout); - } else { - // Just let it progress anyway - return; - } - } - scrollTimeout = setTimeout(_scrollRefresh, SCROLL_DELAY_TIMEOUT); - if (! scrollTimeoutSet) { - scrollTimeoutSet = now; - } - } - - var lastScrollMessage = null; - function _scrollRefresh() { - scrollTimeout = null; - scrollTimeoutSet = 0; - Cursor.forEach(function (c) { - c.refresh(); - }); - lastScrollMessage = { - type: "scroll-update", - position: elementFinder.elementByPixel($(window).scrollTop()) - }; - session.send(lastScrollMessage); - } - - // FIXME: do the same thing for cursor position? And give up on the - // ad hoc update-on-hello? - session.on("prepare-hello", function (helloMessage) { - if (lastScrollMessage) { - helloMessage.scrollPosition = lastScrollMessage.position; - } - }); - - session.hub.on("scroll-update", function (msg) { - msg.peer.scrollPosition = msg.position; - if (msg.peer.following) { - msg.peer.view.scrollTo(); - } - }); - - // In case there are multiple peers, we track that we've accepted one of their - // hello-based scroll updates, just so we don't bounce around (we don't intelligently - // choose which one to use, just the first that comes in) - var acceptedScrollUpdate = false; - session.hub.on("hello-back hello", function (msg) { - if (msg.type == "hello") { - // Once a hello comes in, a bunch of hello-backs not intended for us will also - // come in, and we should ignore them - acceptedScrollUpdate = true; - } - if (! msg.scrollPosition) { - return; - } - msg.peer.scrollPosition = msg.scrollPosition; - if ((! acceptedScrollUpdate) && - msg.sameUrl && - Date.now() - session.timeHelloSent < SCROLL_UPDATE_CUTOFF) { - acceptedScrollUpdate = true; - msg.peer.view.scrollTo(); - } - }); - - session.on("ui-ready", function () { - $(document).mousemove(mousemove); - document.addEventListener("click", documentClick, true); - document.addEventListener("keydown", documentKeydown, true); - $(window).scroll(scroll); - scroll(); - }); - - session.on("close", function () { - Cursor.forEach(function (c, clientId) { - Cursor.destroy(clientId); - }); - $(document).unbind("mousemove", mousemove); - document.removeEventListener("click", documentClick, true); - document.removeEventListener("keydown", documentKeydown, true); - $(window).unbind("scroll", scroll); - }); - - session.hub.on("hello", function (msg) { - // Immediately get our cursor onto this new person's screen: - if (lastMessage) { - session.send(lastMessage); - } - if (lastScrollMessage) { - session.send(lastScrollMessage); - } - }); - - function documentClick(event) { - if (event.togetherjsInternal) { - // This is an artificial internal event - return; - } - // FIXME: this might just be my imagination, but somehow I just - // really don't want to do anything at this stage of the event - // handling (since I'm catching every click), and I'll just do - // something real soon: - setTimeout(function () { - if (! TogetherJS.running) { - // This can end up running right after TogetherJS has been closed, often - // because TogetherJS was closed with a click... - return; - } - var element = event.target; - if (element == document.documentElement) { - // For some reason clicking on gives the element here - element = document.body; - } - if (elementFinder.ignoreElement(element)) { - return; - } - //Prevent click events on video objects to avoid conflicts with - //togetherjs's own video events - if (element.nodeName.toLowerCase() === 'video'){ - return; - } - - var dontShowClicks = TogetherJS.config.get("dontShowClicks"); - var cloneClicks = TogetherJS.config.get("cloneClicks"); - // If you dont want to clone the click for this element - // and you dont want to show the click for this element or you dont want to show any clicks - // then return to avoid sending a useless click - if ((! util.matchElement(element, cloneClicks)) && util.matchElement(element, dontShowClicks)) { - return; - } - var location = elementFinder.elementLocation(element); - var offset = $(element).offset(); - var offsetX = event.pageX - offset.left; - var offsetY = event.pageY - offset.top; - /*session.send({ - type: "cursor-click", - element: location, - offsetX: offsetX, - offsetY: offsetY - });*/ - if (util.matchElement(element, dontShowClicks)) { - return; - } - //displayClick({top: event.pageY, left: event.pageX}, peers.Self.color); - }); - } - - session.hub.on("app.codiad", function (data) { - codiad.together.handle(data); - }); - - var CLICK_TRANSITION_TIME = 3000; - - session.hub.on("cursor-click", function (pos) { - // When the click is calculated isn't always the same as how the - // last cursor update was calculated, so we force the cursor to - // the last location during a click: - if (! pos.sameUrl) { - // FIXME: if we *could have* done a local click, but we follow along - // later, we'll be in different states if that click was important. - // Mostly click cloning just won't work. - return; - } - Cursor.getClient(pos.clientId).updatePosition(pos); - var target = $(elementFinder.findElement(pos.element)); - var offset = target.offset(); - var top = offset.top + pos.offsetY; - var left = offset.left + pos.offsetX; - var cloneClicks = TogetherJS.config.get("cloneClicks"); - if (util.matchElement(target, cloneClicks)) { - eventMaker.performClick(target); - } - var dontShowClicks = TogetherJS.config.get("dontShowClicks"); - if (util.matchElement(target, dontShowClicks)) { - return; - } - displayClick({top: top, left: left}, pos.peer.color); - }); - - function displayClick(pos, color) { - // FIXME: should we hide the local click if no one else is going to see it? - // That means tracking who might be able to see our screen. - var element = templating.clone("click"); - $(document.body).append(element); - element.css({ - top: pos.top, - left: pos.left, - borderColor: color - }); - setTimeout(function () { - element.addClass("togetherjs-clicking"); - }, 100); - setTimeout(function () { - element.remove(); - }, CLICK_TRANSITION_TIME); - } - - var lastKeydown = 0; - var MIN_KEYDOWN_TIME = 500; - - function documentKeydown(event) { - setTimeout(function () { - var now = Date.now(); - if (now - lastKeydown < MIN_KEYDOWN_TIME) { - return; - } - lastKeydown = now; - // FIXME: is event.target interesting here? That is, *what* the - // user is typing into, not just that the user is typing? Also - // I'm assuming we don't care if the user it typing into a - // togetherjs-related field, since chat activity is as interesting - // as any other activity. - session.send({type: "keydown"}); - }); - } - - session.hub.on("keydown", function (msg) { - // FIXME: when the cursor is hidden there's nothing to show with setKeydown(). - var cursor = Cursor.getClient(msg.clientId); - cursor.setKeydown(); - }); - - util.testExpose({Cursor: Cursor}); - - return cursor; - -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('ot',["util"], function (util) { - - var ot = util.Module("ot"); - var assert = util.assert; - - var StringSet = util.Class({ - /* Set that only supports string items */ - constructor: function () { - this._items = {}; - this._count = 0; - }, - contains: function (k) { - assert(typeof k == "string"); - return this._items.hasOwnProperty(k); - }, - add: function (k) { - assert(typeof k == "string"); - if (this.contains(k)) { - return; - } - this._items[k] = null; - this._count++; - }, - remove: function (k) { - assert(typeof k == "string"); - if (! this.contains(k)) { - return; - } - delete this._items[k]; - this._count++; - }, - isEmpty: function () { - return ! this._count; - } - }); - - var Queue = util.Class({ - - constructor: function (size) { - this._q = []; - this._size = size; - this._deleted = 0; - }, - - _trim: function () { - if (this._size) { - if (this._q.length > this._size) { - this._q.splice(0, this._q.length - this._size); - this._deleted += this._q.length - this._size; - } - } - }, - - push: function (item) { - this._q.push(item); - this._trim(); - }, - - last: function () { - return this._q[this._q.length-1]; - }, - - walkBack: function (callback, context) { - var result = true; - for (var i=this._q.length-1; i >= 0; i--) { - var item = this._q[i]; - result = callback.call(context, item, i + this._deleted); - if (result === false) { - return result; - } else if (! result) { - result = true; - } - } - return result; - }, - - walkForward: function (index, callback, context) { - var result = true; - for (var i=index; i this.version || - (otherChange.version == this.version && otherChange.clientId > this.clientId); - }, - - knowsAboutAll: function (versions) { - for (var clientId in versions) { - if (! versions.hasOwnProperty(clientId)) { - continue; - } - if (! versions[clientId]) { - continue; - } - if ((! this.known[clientId]) || this.known[clientId] < versions[clientId]) { - return false; - } - } - return true; - }, - - knowsAboutChange: function (change) { - return change.clientId == this.clientId || - (this.known[change.clientId] && this.known[change.clientId] >= change.version); - }, - - knowsAboutVersion: function (version, clientId) { - if ((! version) || clientId == this.clientId) { - return true; - } - return this.known[clientId] && this.known[clientId] >= version; - }, - - maybeMissingChanges: function (mostRecentVersion, clientId) { - if (! mostRecentVersion) { - // No actual changes for clientId exist - return false; - } - if (! this.known[clientId]) { - // We don't even know about clientId, so we are definitely missing something - return true; - } - if (this.known[clientId] >= mostRecentVersion) { - // We know about all versions through mostRecentVersion - return false; - } - if ((clientId > this.clientId && this.known[clientId] >= this.version-1) || - (clientId < this.clientId && this.known[clientId] == this.version)) { - // We know about all versions from clientId that could exist before this - // version - return false; - } - // We may or may not be missing something - return true; - } - }); - - /* SimpleHistory synchronizes peers by relying on the server to serialize - * the order of all updates. Each client maintains a queue of patches - * which have not yet been 'committed' (by being echoed back from the - * server). The client is responsible for transposing its own queue - * if 'earlier' patches are heard from the server. - * - * Let's say that A's edit "1" and B's edit "2" occur and get put in - * their respective SimpleHistory queues. The server happens to - * handle 1 first, then 2, so those are the order that all peers - * (both A and B) see the messages. - * - * A sees 1, and has 1 on its queue, so everything's fine. It - * updates the 'committed' text to match its current text and drops - * the patch from its queue. It then sees 2, but the basis number - * for 2 no longer matches the committed basis, so it throws it - * away. - * - * B sees 1, and has 2 on its queue. It does the OT transpose thing, - * updating the committed text to include 1 and the 'current' text - * to include 1+2. It updates its queue with the newly transposed - * version of 2 (call it 2prime) and updates 2prime's basis - * number. It them resends 2prime to the server. It then receives 2 - * (the original) but the basis number no longer matches the - * committed basis, so it throws it away. - * - * Now the server sees 2prime and rebroadcasts it to both A and B. - * - * A is seeing it for the first time, and the basis number matches, - * so it applies it to the current and committed text. - * - * B sees that 2prime matches what's on the start of its queue, - * shifts it off, and updates the committed text to match the - * current text. - * - * Note that no one tries to keep an entire history of changes, - * which is the main difference with ot.History. Everyone applies - * the same patches in the same order. - */ - ot.SimpleHistory = util.Class({ - - constructor: function(clientId, initState, initBasis) { - this.clientId = clientId; - this.committed = initState; - this.current = initState; - this.basis = initBasis; - this.queue = []; - this.deltaId = 1; - this.selection = null; - }, - - // Use a fake change to represent the selection. - // (This is the only bit that hard codes ot.TextReplace as the delta - // representation; override this in a subclass (or don't set the - // selection) if you are using a different delta representation. - setSelection: function(selection) { - if (selection) { - this.selection = ot.TextReplace(selection[0], - selection[1] - selection[0], '@'); - } else { - this.selection = null; - } - }, - - // Decode the fake change to reconstruct the updated selection. - getSelection: function() { - if (! this.selection) { - return null; - } - return [this.selection.start, this.selection.start + this.selection.del]; - }, - - // Add this delta to this client's queue. - add: function(delta) { - var change = { - id: this.clientId + '.' + (this.deltaId++), - delta: delta - }; - if (! this.queue.length) { - change.basis = this.basis; - } - this.queue.push(change); - this.current = delta.apply(this.current); - return !!change.basis; - }, - - // Apply a delta received from the server. - // Return true iff the current text changed as a result. - commit: function(change) { - - // ignore it if the basis doesn't match (this patch doesn't apply) - // if so, this delta is out of order; we expect the original client - // to retransmit an updated delta. - if (change.basis !== this.basis) { - return false; // 'current' text did not change - } - - // is this the first thing on the queue? - if (this.queue.length && this.queue[0].id === change.id) { - assert(change.basis === this.queue[0].basis); - // good, apply this to commit state & remove it from queue - this.committed = this.queue.shift().delta.apply(this.committed); - this.basis++; - if (this.queue.length) { - this.queue[0].basis = this.basis; - } - return false; // 'current' text did not change - } - - // Transpose all bits on the queue to put this patch first. - var inserted = change.delta; - this.queue = this.queue.map(function(qchange) { - var tt = qchange.delta.transpose(inserted); - inserted = tt[1]; - return { - id: qchange.id, - delta: tt[0] - }; - }); - if (this.selection) { - // update the selection! - this.selection = this.selection.transpose(inserted)[0]; - } - this.committed = change.delta.apply(this.committed); - this.basis++; - if (this.queue.length) { - this.queue[0].basis = this.basis; - } - // Update current by replaying queued changes starting from 'committed' - this.current = this.committed; - this.queue.forEach(function(qchange) { - this.current = qchange.delta.apply(this.current); - }.bind(this)); - return true; // The 'current' text changed. - }, - - // Return the next change to transmit to the server, or null if there - // isn't one. - getNextToSend: function() { - var qchange = this.queue[0]; - if (! qchange) { - /* nothing to send */ - return null; - } - if (qchange.sent) { - /* already sent */ - return null; - } - assert(qchange.basis); - qchange.sent = true; - return qchange; - } - }); - - ot.History = util.Class({ - - constructor: function (clientId, initState) { - this._history = Queue(); - this._history.push({ - clientId: "init", state: initState - }); - this.clientId = clientId; - this.known = {}; - this.mostRecentLocalChange = null; - }, - - add: function (change) { - // Simplest cast, it is our change: - if (change.clientId == this.clientId) { - this._history.push(change); - this.mostRecentLocalChange = change.version; - return change.delta; - } - assert((! this.known[change.clientId]) || this.known[change.clientId] < change.version, - "Got a change", change, "that appears older (or same as) a known change", this.known[change.clientId]); - // Second simplest case, we get a change that we can add to our - // history without modification: - var last = this._history.last(); - if ((last.clientId == "init" || last.isBefore(change)) && - change.knowsAboutAll(this.known) && - change.knowsAboutVersion(this.mostRecentLocalChange, this.clientId)) { - this._history.push(change); - this.known[change.clientId] = change.version; - return change.delta; - } - // We must do work! - - this.logHistory("//"); - - // First we check if we need to modify this change because we - // know about changes that it should know about (changes that - // preceed it that are in our local history). - var clientsToCheck = StringSet(); - for (var clientId in this.known) { - if (! this.known.hasOwnProperty(clientId)) { - continue; - } - if (change.maybeMissingChanges(this.known[clientId], clientId)) { - clientsToCheck.add(clientId); - } - } - if (change.maybeMissingChanges(this.mostRecentLocalChange, this.clientId)) { - clientsToCheck.add(this.clientId); - } - if (! clientsToCheck.isEmpty()) { - var indexToCheckFrom = null; - this._history.walkBack(function (c, index) { - indexToCheckFrom = index; - if (c.clientId == "init") { - return false; - } - if (clientsToCheck.contains(c.clientId) && - ! change.maybeMissingChanges(c.version, c.clientId)) { - clientsToCheck.remove(c.clientId); - if (clientsToCheck.isEmpty()) { - return false; - } - } - return true; - }, this); - this._history.walkForward(indexToCheckFrom, function (c, index) { - if (c.clientId == "init") { - return true; - } - if (change.isBefore(c)) { - return false; - } - if (! change.knowsAboutChange(c)) { - var presentDelta = this.promoteDelta(c.delta, index, change); - if (! presentDelta.equals(c.delta)) { - //console.log("->rebase delta rewrite", presentDelta+""); - } - this.logChange("->rebase", change, function () { - var result = change.delta.transpose(presentDelta); - change.delta = result[0]; - change.known[c.clientId] = c.version; - }, "with:", c); - } - return true; - }, this); - } - - // Next we insert the change into its proper location - var indexToInsert = null; - this._history.walkBack(function (c, index) { - if (c.clientId == "init" || c.isBefore(change)) { - indexToInsert = index+1; - return false; - } - return true; - }, this); - assert(indexToInsert); - this._history.insert(indexToInsert, change); - - // Now we fix up any forward changes - var fixupDelta = change.delta; - this._history.walkForward(indexToInsert+1, function (c, index) { - if (! c.knowsAboutChange(change)) { - var origChange = c.clone(); - this.logChange("^^fix", c, function () { - var fixupResult = c.delta.transpose(fixupDelta); - console.log(" ^^real"); - var result = c.delta.transpose(fixupDelta); - c.delta = result[0]; - c.known[change.clientId] = change.version; - fixupDelta = fixupResult[1]; - }, "clone:", change.delta+""); - console.log("(trans)", fixupDelta+""); - assert(c.knowsAboutChange(change)); - } - }, this); - - // Finally we return the transformed delta that represents - // changes that should be made to the state: - - this.logHistory("!!"); - return fixupDelta; - }, - - promoteDelta: function (delta, deltaIndex, untilChange) { - this._history.walkForward(deltaIndex+1, function (c, index) { - if (untilChange.isBefore(c)) { - return false; - } - // FIXME: not sure if this clientId check here is right. Maybe - // if untilChange.knowsAbout(c)? - if (untilChange.knowsAboutChange(c)) { - var result = c.delta.transpose(delta); - delta = result[1]; - } - return true; - }); - return delta; - }, - - logHistory: function (prefix) { - prefix = prefix || ""; - var postfix = Array.prototype.slice.call(arguments, 1); - console.log.apply(console, [prefix + "history", this.clientId, ":"].concat(postfix)); - console.log(prefix + " state:", JSON.stringify(this.getStateSafe())); - var hstate; - this._history.walkForward(0, function (c, index) { - if (! index) { - assert(c.clientId == "init"); - console.log(prefix + " init:", JSON.stringify(c.state)); - hstate = c.state; - } else { - try { - hstate = c.delta.apply(hstate); - } catch (e) { - hstate = "Error: " + e; - } - console.log(prefix + " ", index, c+"", JSON.stringify(hstate)); - } - }); - }, - - logChange: function (prefix, change, callback) { - prefix = prefix || "before"; - var postfix = Array.prototype.slice.call(arguments, 3); - console.log.apply( - console, - [prefix, this.clientId, ":", change+""].concat(postfix).concat([JSON.stringify(this.getStateSafe(true))])); - try { - callback(); - } finally { - console.log(prefix + " after:", change+"", JSON.stringify(this.getStateSafe())); - } - }, - - addDelta: function (delta) { - var version = this._createVersion(); - var change = Change(version, this.clientId, delta, util.extend(this.knownVersions)); - this.add(change); - return change; - }, - - _createVersion: function () { - var max = 1; - for (var id in this.knownVersions) { - max = Math.max(max, this.knownVersions[id]); - } - max = Math.max(max, this.mostRecentLocalChange); - return max+1; - }, - - fault: function (change) { - throw new Error('Fault'); - }, - - getState: function () { - var state; - this._history.walkForward(0, function (c) { - if (c.clientId == "init") { - // Initialization, has the state - state = c.state; - } else { - state = c.delta.apply(state); - } - }, this); - return state; - }, - - getStateSafe: function () { - try { - return this.getState(); - } catch (e) { - return 'Error: ' + e; - } - } - - }); - - ot.TextReplace = util.Class({ - - constructor: function (start, del, text) { - assert(typeof start == "number" && typeof del == "number" && typeof text == "string", start, del, text); - assert(start >=0 && del >= 0, start, del); - this.start = start; - this.del = del; - this.text = text; - }, - - toString: function () { - if (this.empty()) { - return '[no-op]'; - } - if (! this.del) { - return '[insert ' + JSON.stringify(this.text) + ' @' + this.start + ']'; - } else if (! this.text) { - return '[delete ' + this.del + ' chars @' + this.start + ']'; - } else { - return '[replace ' + this.del + ' chars with ' + JSON.stringify(this.text) + ' @' + this.start + ']'; - } - }, - - equals: function (other) { - return other.constructor === this.constructor && - other.del === this.del && - other.start === this.start && - other.text === this.text; - }, - - clone: function (start, del, text) { - if (start === undefined) { - start = this.start; - } - if (del === undefined) { - del = this.del; - } - if (text === undefined) { - text = this.text; - } - return ot.TextReplace(start, del, text); - }, - - empty: function () { - return (! this.del) && (! this.text); - }, - - apply: function (text) { - if (this.empty()) { - return text; - } - if (this.start > text.length) { - console.trace(); - throw new util.AssertionError("Start after end of text (" + JSON.stringify(text) + "/" + text.length + "): " + this); - } - if (this.start + this.del > text.length) { - throw new util.AssertionError("Start+del after end of text (" + JSON.stringify(text) + "/" + text.length + "): " + this); - } - return text.substr(0, this.start) + this.text + text.substr(this.start+this.del); - }, - - transpose: function (delta) { - /* Transform this delta as though the other delta had come before it. - Returns a [new_version_of_this, transformed_delta], where transformed_delta - satisfies: - - result1 = new_version_of_this.apply(delta.apply(text)); - result2 = transformed_delta.apply(this.apply(text)); - assert(result1 == result2); - - Does not modify this object. - */ - var overlap; - assert(delta instanceof ot.TextReplace, "Transposing with non-TextReplace:", delta); - if (this.empty()) { - //console.log(" =this is empty"); - return [this.clone(), delta.clone()]; - } - if (delta.empty()) { - //console.log(" =other is empty"); - return [this.clone(), delta.clone()]; - } - if (delta.before(this)) { - //console.log(" =this after other"); - return [this.clone(this.start + delta.text.length - delta.del), - delta.clone()]; - } else if (this.before(delta)) { - //console.log(" =this before other"); - return [this.clone(), delta.clone(delta.start + this.text.length - this.del)]; - } else if (delta.sameRange(this)) { - //console.log(" =same range"); - return [this.clone(this.start+delta.text.length, 0), - delta.clone(undefined, 0)]; - } else if (delta.contains(this)) { - //console.log(" =other contains this"); - return [this.clone(delta.start+delta.text.length, 0, this.text), - delta.clone(undefined, delta.del - this.del + this.text.length, delta.text + this.text)]; - } else if (this.contains(delta)) { - //console.log(" =this contains other"); - return [this.clone(undefined, this.del - delta.del + delta.text.length, delta.text + this.text), - delta.clone(this.start, 0, delta.text)]; - } else if (this.overlapsStart(delta)) { - //console.log(" =this overlaps start of other"); - overlap = this.start + this.del - delta.start; - return [this.clone(undefined, this.del - overlap), - delta.clone(this.start + this.text.length, delta.del - overlap)]; - } else { - //console.log(" =this overlaps end of other"); - assert(delta.overlapsStart(this), delta+"", "does not overlap start of", this+"", delta.before(this)); - overlap = delta.start + delta.del - this.start; - return [this.clone(delta.start + delta.text.length, this.del - overlap), - delta.clone(undefined, delta.del - overlap)]; - } - throw 'Should not happen'; - }, - - before: function (other) { - return this.start + this.del <= other.start; - }, - - contains: function (other) { - return other.start >= this.start && other.start + other.del < this.start + this.del; - }, - - sameRange: function (other) { - return other.start == this.start && other.del == this.del; - }, - - overlapsStart: function (other) { - return this.start < other.start && this.start + this.del > other.start; - }, - - classMethods: { - - /* Make a new ot.TextReplace that converts oldValue to newValue. */ - fromChange: function(oldValue, newValue) { - assert(typeof oldValue == "string"); - assert(typeof newValue == "string"); - var commonStart = 0; - while (commonStart < newValue.length && - newValue.charAt(commonStart) == oldValue.charAt(commonStart)) { - commonStart++; - } - var commonEnd = 0; - while (commonEnd < (newValue.length - commonStart) && - commonEnd < (oldValue.length - commonStart) && - newValue.charAt(newValue.length - commonEnd - 1) == - oldValue.charAt(oldValue.length - commonEnd - 1)) { - commonEnd++; - } - var removed = oldValue.substr(commonStart, oldValue.length - commonStart - commonEnd); - var inserted = newValue.substr(commonStart, newValue.length - commonStart - commonEnd); - if (! (removed.length || inserted)) { - return null; - } - return this(commonStart, removed.length, inserted); - }, - - random: function (source, generator) { - var text, start, len; - var ops = ["ins", "del", "repl"]; - if (! source.length) { - ops = ["ins"]; - } - switch (generator.pick(ops)) { - case "ins": - if (! generator.number(2)) { - text = generator.string(1); - } else { - text = generator.string(generator.number(3)+1); - } - if (! generator.number(4)) { - start = 0; - } else if (! generator.number(3)) { - start = source.length-1; - } else { - start = generator.number(source.length); - } - return this(start, 0, text); - - case "del": - if (! generator.number(20)) { - return this(0, source.length, ""); - } - start = generator.number(source.length-1); - if (! generator.number(2)) { - len = 1; - } else { - len = generator.number(5)+1; - } - len = Math.min(len, source.length - start); - return this(start, len, ""); - - case "repl": - start = generator.number(source.length-1); - len = generator.number(5); - len = Math.min(len, source.length - start); - text = generator.string(generator.number(2)+1); - return this(start, len, text); - } - throw 'Unreachable'; - } - } - }); - - return ot; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('forms',["jquery", "util", "session", "elementFinder", "eventMaker", "templating", "ot"], function ($, util, session, elementFinder, eventMaker, templating, ot) { - var forms = util.Module("forms"); - var assert = util.assert; - - // This is how much larger the focus element is than the element it surrounds - // (this is padding on each side) - var FOCUS_BUFFER = 5; - - var inRemoteUpdate = false; - - function suppressSync(element) { - var ignoreForms = TogetherJS.config.get("ignoreForms"); - if (ignoreForms === true) { - return true; - } - else { - return $(element).is(ignoreForms.join(",")); - } - } - - function maybeChange(event) { - // Called when we get an event that may or may not indicate a real change - // (like keyup in a textarea) - var tag = event.target.tagName; - if (tag == "TEXTAREA" || tag == "INPUT") { - change(event); - } - } - - function change(event) { - sendData({ - element: event.target, - value: getValue(event.target) - }); - } - - function sendData(attrs) { - var el = $(attrs.element); - assert(el); - var tracker = attrs.tracker; - var value = attrs.value; - if (inRemoteUpdate) { - return; - } - if (elementFinder.ignoreElement(el) || - (elementTracked(el) && !tracker) || - suppressSync(el)) { - return; - } - var location = elementFinder.elementLocation(el); - var msg = { - type: "form-update", - element: location - }; - if (isText(el) || tracker) { - var history = el.data("togetherjsHistory"); - if (history) { - if (history.current == value) { - return; - } - var delta = ot.TextReplace.fromChange(history.current, value); - assert(delta); - history.add(delta); - maybeSendUpdate(msg.element, history, tracker); - return; - } else { - msg.value = value; - msg.basis = 1; - el.data("togetherjsHistory", ot.SimpleHistory(session.clientId, value, 1)); - } - } else { - msg.value = value; - } - session.send(msg); - } - - function isCheckable(el) { - el = $(el); - var type = (el.prop("type") || "text").toLowerCase(); - if (el.prop("tagName") == "INPUT" && ["radio", "checkbox"].indexOf(type) != -1) { - return true; - } - return false; - } - - var editTrackers = {}; - var liveTrackers = []; - - TogetherJS.addTracker = function (TrackerClass, skipSetInit) { - assert(typeof TrackerClass === "function", "You must pass in a class"); - assert(typeof TrackerClass.prototype.trackerName === "string", - "Needs a .prototype.trackerName string"); - // Test for required instance methods. - "destroy update init makeInit tracked".split(/ /).forEach(function(m) { - assert(typeof TrackerClass.prototype[m] === "function", - "Missing required tracker method: "+m); - }); - // Test for required class methods. - "scan tracked".split(/ /).forEach(function(m) { - assert(typeof TrackerClass[m] === "function", - "Missing required tracker class method: "+m); - }); - editTrackers[TrackerClass.prototype.trackerName] = TrackerClass; - if (!skipSetInit) { - setInit(); - } - }; - - var AceEditor = util.Class({ - - trackerName: "AceEditor", - - constructor: function (el) { - this.element = $(el)[0]; - assert($(this.element).hasClass("ace_editor")); - this._change = this._change.bind(this); - this._editor().document.on("change", this._change); - }, - - tracked: function (el) { - return this.element === $(el)[0]; - }, - - destroy: function (el) { - this._editor().document.removeListener("change", this._change); - }, - - update: function (msg) { - this._editor().document.setValue(msg.value); - }, - - init: function (update, msg) { - this.update(update); - }, - - makeInit: function () { - return { - element: this.element, - tracker: this.trackerName, - value: this._editor().document.getValue() - }; - }, - - _editor: function () { - return this.element.env; - }, - - _change: function (e) { - // FIXME: I should have an internal .send() function that automatically - // asserts !inRemoteUpdate, among other things - if (inRemoteUpdate) { - return; - } - sendData({ - tracker: this.trackerName, - element: this.element, - value: this.getContent() - }); - }, - - getContent: function() { - return this._editor().document.getValue(); - } - }); - - AceEditor.scan = function () { - return $(".ace_editor"); - }; - - AceEditor.tracked = function (el) { - return !! $(el).closest(".ace_editor").length; - }; - - TogetherJS.addTracker(AceEditor, true /* skip setInit */); - - var CodeMirrorEditor = util.Class({ - trackerName: "CodeMirrorEditor", - - constructor: function (el) { - this.element = $(el)[0]; - assert(this.element.CodeMirror); - this._change = this._change.bind(this); - this._editor().on("change", this._change); - }, - - tracked: function (el) { - return this.element === $(el)[0]; - }, - - destroy: function (el) { - this._editor().off("change", this._change); - }, - - update: function (msg) { - this._editor().setValue(msg.value); - }, - - init: function (msg) { - if (msg.value) { - this.update(msg); - } - }, - - makeInit: function () { - return { - element: this.element, - tracker: this.trackerName, - value: this._editor().getValue() - }; - }, - - _change: function (editor, change) { - if (inRemoteUpdate) { - return; - } - sendData({ - tracker: this.trackerName, - element: this.element, - value: this.getContent() - }); - }, - - _editor: function () { - return this.element.CodeMirror; - }, - - getContent: function() { - return this._editor().getValue(); - } - }); - - CodeMirrorEditor.scan = function () { - var result = []; - var els = document.body.getElementsByTagName("*"); - var _len = els.length; - for (var i=0; i<_len; i++) { - var el = els[i]; - if (el.CodeMirror) { - result.push(el); - } - } - return $(result); - }; - - CodeMirrorEditor.tracked = function (el) { - el = $(el)[0]; - while (el) { - if (el.CodeMirror) { - return true; - } - el = el.parentNode; - } - return false; - }; - - TogetherJS.addTracker(CodeMirrorEditor, true /* skip setInit */); - - - var CKEditor = util.Class({ - trackerName: "CKEditor", - - constructor: function (el) { - this.element = $(el)[0]; - assert(CKEDITOR); - assert(CKEDITOR.dom.element.get(this.element)); - this._change = this._change.bind(this); - // FIXME: change event is available since CKEditor 4.2 - this._editor().on("change", this._change); - }, - tracked: function (el) { - return this.element === $(el)[0]; - }, - destroy: function (el) { - this._editor().removeListener("change", this._change); - }, - - update: function (msg) { - //FIXME: use setHtml instead of setData to avoid frame reloading overhead - this._editor().editable().setHtml(msg.value); - }, - - init: function (update, msg) { - this.update(update); - }, - - makeInit: function () { - return { - element: this.element, - tracker: this.trackerName, - value: this.getContent() - }; - }, - - _change: function (e) { - if (inRemoteUpdate) { - return; - } - sendData({ - tracker: this.trackerName, - element: this.element, - value: this.getContent() - }); - }, - - _editor: function () { - return CKEDITOR.dom.element.get(this.element).getEditor(); - }, - - getContent: function () { - return this._editor().getData(); - } - }); - - CKEditor.scan = function () { - var result = []; - if (typeof CKEDITOR == "undefined") { - return; - } - var editorInstance; - for (var instanceIdentifier in CKEDITOR.instances) { - editorInstance = document.getElementById(instanceIdentifier) || document.getElementsByName(instanceIdentifier)[0]; - if (editorInstance) { - result.push(editorInstance); - } - } - return $(result); - }; - - CKEditor.tracked = function (el) { - if (typeof CKEDITOR == "undefined") { - return false; - } - el = $(el)[0]; - return !! (CKEDITOR.dom.element.get(el) && CKEDITOR.dom.element.get(el).getEditor()); - }; - - TogetherJS.addTracker(CKEditor, true /* skip setInit */); - - - function buildTrackers() { - assert(! liveTrackers.length); - util.forEachAttr(editTrackers, function (TrackerClass) { - var els = TrackerClass.scan(); - if (els) { - $.each(els, function () { - var tracker = new TrackerClass(this); - $(this).data("togetherjsHistory", ot.SimpleHistory(session.clientId, tracker.getContent(), 1)); - liveTrackers.push(tracker); - }); - } - }); - } - - function destroyTrackers() { - liveTrackers.forEach(function (tracker) { - tracker.destroy(); - }); - liveTrackers = []; - } - - function elementTracked(el) { - var result = false; - util.forEachAttr(editTrackers, function (TrackerClass) { - if (TrackerClass.tracked(el)) { - result = true; - } - }); - return result; - } - - function getTracker(el, name) { - el = $(el)[0]; - for (var i=0; i= STEPS.length) { - session.emit("startup-ready"); - return; - } - currentStep = STEPS[index]; - handlers[currentStep](startup.start); - }; - - var handlers = { - - browserBroken: function (next) { - if (window.WebSocket) { - next(); - return; - } - windowing.show("#togetherjs-browser-broken", { - onClose: function () { - session.close(); - } - }); - if ($.browser.msie) { - $("#togetherjs-browser-broken-is-ie").show(); - } - }, - - browserUnsupported: function (next) { - if (! $.browser.msie) { - next(); - return; - } - var cancel = true; - windowing.show("#togetherjs-browser-unsupported", { - onClose: function () { - if (cancel) { - session.close(); - } else { - next(); - } - } - }); - $("#togetherjs-browser-unsupported-anyway").click(function () { - cancel = false; - }); - }, - - sessionIntro: function (next) { - if ((! session.isClient) || ! session.firstRun) { - next(); - return; - } - TogetherJS.config.close("suppressJoinConfirmation"); - if (TogetherJS.config.get("suppressJoinConfirmation")) { - next(); - return; - } - var cancelled = false; - windowing.show("#togetherjs-intro", { - onClose: function () { - if (! cancelled) { - next(); - } - } - }); - $("#togetherjs-intro .togetherjs-modal-dont-join").click(function () { - cancelled = true; - windowing.hide(); - session.close("declined-join"); - }); - }, - - walkthrough: function (next) { - storage.settings.get("seenIntroDialog").then(function (seenIntroDialog) { - if (seenIntroDialog) { - next(); - return; - } - require(["walkthrough"], function (walkthrough) { - walkthrough.start(true, function () { - storage.settings.set("seenIntroDialog", true); - next(); - }); - }); - }); - }, - - share: function (next) { - TogetherJS.config.close("suppressInvite"); - if (session.isClient || (! session.firstRun) || - TogetherJS.config.get("suppressInvite")) { - next(); - return; - } - require(["windowing"], function (windowing) { - windowing.show("#togetherjs-share"); - // FIXME: no way to detect when the window is closed - // If there was a next() step then it would not work - }); - } - - }; - - return startup; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('videos',["jquery", "util", "session", "elementFinder"], -function ($, util, session, elementFinder) { - - var listeners = []; - - var TIME_UPDATE = 'timeupdate'; - var MIRRORED_EVENTS = ['play', 'pause']; - - var TOO_FAR_APART = 3000; - - session.on("reinitialize", function () { - unsetListeners(); - setupListeners(); - }); - - session.on("ui-ready", setupListeners); - - function setupListeners() { - var videos = $('video'); - setupMirroredEvents(videos); - setupTimeSync(videos); - } - - function setupMirroredEvents(videos) { - var currentListener; - MIRRORED_EVENTS.forEach(function (eventName) { - currentListener = makeEventSender(eventName); - videos.on(eventName, currentListener); - listeners.push({ - name: eventName, - listener: currentListener - }); - }); - } - - function makeEventSender(eventName) { - return function (event, options) { - var element = event.target; - options || (options = {}); - if (!options.silent) { - session.send({ - type: ('video-'+eventName), - location: elementFinder.elementLocation(element), - position: element.currentTime - }); - } - }; - } - - function setupTimeSync(videos) { - videos.each(function(i, video) { - var onTimeUpdate = makeTimeUpdater(); - $(video).on(TIME_UPDATE, onTimeUpdate); - listeners.push({ - name: TIME_UPDATE, - listener: onTimeUpdate - }); - }); - } - - function makeTimeUpdater() { - var last = 0; - return function (event) { - var currentTime = event.target.currentTime; - if(areTooFarApart(currentTime, last)){ - makeEventSender(TIME_UPDATE)(event); - } - last = currentTime; - }; - } - - function areTooFarApart(currentTime, lastTime) { - var secDiff = Math.abs(currentTime - lastTime); - var milliDiff = secDiff * 1000; - return milliDiff > TOO_FAR_APART; - } - - session.on("close", unsetListeners); - - function unsetListeners() { - var videos = $('video'); - listeners.forEach(function (event) { - videos.off(event.name, event.listener); - }); - listeners = []; - } - - - session.hub.on('video-timeupdate', function (msg) { - var element = $findElement(msg.location); - var oldTime = element.prop('currentTime'); - var newTime = msg.position; - - //to help throttle uneccesary position changes - if(areTooFarApart(oldTime, newTime)){ - setTime(element, msg.position); - } - }); - - MIRRORED_EVENTS.forEach( function (eventName) { - session.hub.on("video-"+eventName, function (msg) { - var element = $findElement(msg.location); - - setTime(element, msg.position); - - element.trigger(eventName, {silent: true}); - }); - }); - - //Currently does not discriminate between visible and invisible videos - function $findElement(location) { - return $(elementFinder.findElement(location)); - } - - function setTime(video, time) { - video.prop('currentTime', time); - } - -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -define('walkthrough',["util", "ui", "jquery", "windowing", "templates", "templating", "session", "peers"], function (util, ui, $, windowing, templates, templating, session, peers) { - var assert = util.assert; - var walkthrough = util.Module("walkthrough"); - var onHideAll = null; - var container = null; - - var slides = null; - - walkthrough.start = function (firstTime, doneCallback) { - if (! container) { - container = $(templates.walkthrough); - container.hide(); - ui.container.append(container); - slides = container.find(".togetherjs-walkthrough-slide"); - slides.hide(); - var progress = $("#togetherjs-walkthrough-progress"); - slides.each(function (index) { - var bullet = templating.sub("walkthrough-slide-progress"); - progress.append(bullet); - bullet.click(function () { - show(index); - }); - }); - container.find("#togetherjs-walkthrough-previous").click(previous); - container.find("#togetherjs-walkthrough-next").click(next); - ui.prepareShareLink(container); - container.find(".togetherjs-self-name").bind("keyup", function (event) { - var val = $(event.target).val(); - peers.Self.update({name: val}); - }); - container.find(".togetherjs-swatch").click(function () { - var picker = $("#togetherjs-pick-color"); - if (picker.is(":visible")) { - picker.hide(); - return; - } - picker.show(); - picker.find(".togetherjs-swatch-active").removeClass("togetherjs-swatch-active"); - picker.find(".togetherjs-swatch[data-color=\"" + peers.Self.color + "\"]").addClass("togetherjs-swatch-active"); - var location = container.find(".togetherjs-swatch").offset(); - picker.css({ - top: location.top, - // The -7 comes out of thin air, but puts it in the right place: - left: location.left-7 - }); - }); - if (session.isClient) { - container.find(".togetherjs-if-creator").remove(); - container.find(".togetherjs-ifnot-creator").show(); - } else { - container.find(".togetherjs-if-creator").show(); - container.find(".togetherjs-ifnot-creator").remove(); - } - TogetherJS.config.track("siteName", function (value) { - value = value || document.title; - container.find(".togetherjs-site-name").text(value); - }); - ui.activateAvatarEdit(container, { - onSave: function () { - container.find("#togetherjs-avatar-when-saved").show(); - container.find("#togetherjs-avatar-when-unsaved").hide(); - }, - onPending: function () { - container.find("#togetherjs-avatar-when-saved").hide(); - container.find("#togetherjs-avatar-when-unsaved").show(); - } - }); - // This triggers substititions in the walkthrough: - peers.Self.update({}); - session.emit("new-element", container); - } - assert(typeof firstTime == "boolean", "You must provide a firstTime boolean parameter"); - if (firstTime) { - container.find(".togetherjs-walkthrough-firsttime").show(); - container.find(".togetherjs-walkthrough-not-firsttime").hide(); - } else { - container.find(".togetherjs-walkthrough-firsttime").hide(); - container.find(".togetherjs-walkthrough-not-firsttime").show(); - } - onHideAll = doneCallback; - show(0); - windowing.show(container); - }; - - function show(index) { - slides.hide(); - $(slides[index]).show(); - var bullets = container.find("#togetherjs-walkthrough-progress .togetherjs-walkthrough-slide-progress"); - bullets.removeClass("togetherjs-active"); - $(bullets[index]).addClass("togetherjs-active"); - var $next = $("#togetherjs-walkthrough-next").removeClass("togetherjs-disabled"); - var $previous = $("#togetherjs-walkthrough-previous").removeClass("togetherjs-disabled"); - if (index == slides.length - 1) { - $next.addClass("togetherjs-disabled"); - } else if (index === 0) { - $previous.addClass("togetherjs-disabled"); - } - } - - function previous() { - var index = getIndex(); - index--; - if (index < 0) { - index = 0; - } - show(index); - } - - function next() { - var index = getIndex(); - index++; - if (index >= slides.length) { - index = slides.length-1; - } - show(index); - } - - function getIndex() { - var active = slides.filter(":visible"); - if (! active.length) { - return 0; - } - for (var i=0; i"); - $canvas[0].height = session.AVATAR_SIZE; - $canvas[0].width = session.AVATAR_SIZE; - var context = $canvas[0].getContext("2d"); - context.arc(session.AVATAR_SIZE/2, session.AVATAR_SIZE/2, session.AVATAR_SIZE/2, 0, Math.PI*2); - context.closePath(); - context.clip(); - context.drawImage($video[0], (session.AVATAR_SIZE - width) / 2, 0, width, height); - savePicture($canvas[0].toDataURL("image/png")); - } - - $upload.on("change", function () { - var reader = new FileReader(); - reader.onload = function () { - // FIXME: I don't actually know it's JPEG, but it's probably a - // good enough guess: - var url = "data:image/jpeg;base64," + util.blobToBase64(this.result); - convertImage(url, function (result) { - savePicture(result); - }); - }; - reader.onerror = function () { - console.error("Error reading file:", this.error); - }; - reader.readAsArrayBuffer(this.files[0]); - }); - - function convertImage(imageUrl, callback) { - var $canvas = $(""); - $canvas[0].height = session.AVATAR_SIZE; - $canvas[0].width = session.AVATAR_SIZE; - var context = $canvas[0].getContext("2d"); - var img = new Image(); - img.src = imageUrl; - // Sometimes the DOM updates immediately to call - // naturalWidth/etc, and sometimes it doesn't; using setTimeout - // gives it a chance to catch up - setTimeout(function () { - var width = img.naturalWidth || img.width; - var height = img.naturalHeight || img.height; - width = width * (session.AVATAR_SIZE / height); - height = session.AVATAR_SIZE; - context.drawImage(img, 0, 0, width, height); - callback($canvas[0].toDataURL("image/png")); - }); - } - - }); - - /**************************************** - * RTC support - */ - - function audioButton(selector) { - ui.displayToggle(selector); - if (selector == "#togetherjs-audio-incoming") { - $("#togetherjs-audio-button").addClass("togetherjs-animated").addClass("togetherjs-color-alert"); - } else { - $("#togetherjs-audio-button").removeClass("togetherjs-animated").removeClass("togetherjs-color-alert"); - } - } - - session.on("ui-ready", function () { - $("#togetherjs-audio-button").click(function () { - if ($("#togetherjs-rtc-info").is(":visible")) { - windowing.hide(); - return; - } - if (session.RTCSupported) { - enableAudio(); - } else { - windowing.show("#togetherjs-rtc-not-supported"); - } - }); - - if (! session.RTCSupported) { - audioButton("#togetherjs-audio-unavailable"); - return; - } - audioButton("#togetherjs-audio-ready"); - - var audioStream = null; - var accepted = false; - var connected = false; - var $audio = $("#togetherjs-audio-element"); - var offerSent = null; - var offerReceived = null; - var offerDescription = false; - var answerSent = null; - var answerReceived = null; - var answerDescription = false; - var _connection = null; - var iceCandidate = null; - - function enableAudio() { - accepted = true; - storage.settings.get("dontShowRtcInfo").then(function (dontShow) { - if (! dontShow) { - windowing.show("#togetherjs-rtc-info"); - } - }); - if (! audioStream) { - startStreaming(connect); - return; - } - if (! connected) { - connect(); - } - toggleMute(); - } - - ui.container.find("#togetherjs-rtc-info .togetherjs-dont-show-again").change(function () { - storage.settings.set("dontShowRtcInfo", this.checked); - }); - - function error() { - console.warn.apply(console, arguments); - var s = ""; - for (var i=0; i= expected) { - close(); - } else { - def.notify(users); - } - } - } - console.log("users", users); - }; - channel.send({ - type: "who", - "server-echo": true, - clientId: null - }); - var timeout = setTimeout(function () { - close(); - }, MAX_RESPONSE_TIME); - function close() { - if (timeout) { - clearTimeout(timeout); - } - if (lateResponseTimeout) { - clearTimeout(lateResponseTimeout); - } - channel.close(); - def.resolve(users); - } - }); - }; - - who.invite = function (hubUrl, clientId) { - return util.Deferred(function (def) { - var channel = channels.WebSocketChannel(hubUrl); - var id = util.generateId(); - channel.onmessage = function (msg) { - if (msg.type == "invite" && msg.inviteId == id) { - channel.close(); - def.resolve(); - } - }; - var userInfo = session.makeHelloMessage(false); - delete userInfo.type; - userInfo.clientId = session.clientId; - channel.send({ - type: "invite", - inviteId: id, - url: session.shareUrl(), - userInfo: userInfo, - forClientId: clientId, - clientId: null, - "server-echo": true - }); - }); - }; - - who.ExternalPeer = util.Class({ - isSelf: false, - isExternal: true, - constructor: function (id, attrs) { - attrs = attrs || {}; - assert(id); - this.id = id; - this.identityId = attrs.identityId || null; - this.status = attrs.status || "live"; - this.idle = attrs.status || "active"; - this.name = attrs.name || null; - this.avatar = attrs.avatar || null; - this.color = attrs.color || "#00FF00"; - this.lastMessageDate = 0; - this.view = ui.PeerView(this); - }, - - className: function (prefix) { - prefix = prefix || ""; - return prefix + util.safeClassName(this.id); - } - - }); - - return who; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http:// mozilla.org/MPL/2.0/. */ - -define('youtubeVideos',["jquery", "util", "session", "elementFinder"], -function ($, util, session, elementFinder) { - - // constant var to indicate whether two players are too far apart in sync - var TOO_FAR_APART = 3000; - // embedded youtube iframes - var youTubeIframes = []; - // youtube API load delay - var API_LOADING_DELAY = 2000; - - session.on("reinitialize", function () { - if (TogetherJS.config.get("youtube")) { - prepareYouTube(); - } - }); - - session.on("close", function () { - $(youTubeIframes).each(function (i, iframe) { - // detach players from iframes - $(iframe).removeData("togetherjs-player"); - $(iframe).removeData("dontPublish"); - $(iframe).removeData("currentVideoId"); - // disable iframeAPI - $(iframe).removeAttr("enablejsapi"); - // remove unique youtube iframe indicators - var id = $(iframe).attr("id") || ""; - if (id.indexOf("youtube-player") === 0) { - // An id we added - $(iframe).removeAttr("id"); - } - youTubeIframes = []; - }); - }); - - TogetherJS.config.track("youtube", function (track, previous) { - if (track && ! previous) { - prepareYouTube(); - // You can enable youtube dynamically, but can't turn it off: - TogetherJS.config.close("youtube"); - } - }); - - function prepareYouTube() { - // setup iframes first - setupYouTubeIframes(); - - // this function should be global so it can be called when API is loaded - window.onYouTubeIframeAPIReady = function() { - // YouTube API is ready - $(youTubeIframes).each(function (i, iframe) { - var player = new YT.Player(iframe.id, { // get the reference to the already existing iframe - events: { - 'onReady': insertPlayer, - 'onStateChange': publishPlayerStateChange - } - }); - }); - }; - - if (window.YT === undefined) { - // load necessary API - // it calls onYouTubeIframeAPIReady automatically when the API finishes loading - var tag = document.createElement('script'); - tag.src = "https://www.youtube.com/iframe_api"; - var firstScriptTag = document.getElementsByTagName('script')[0]; - firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); - } else { - // manually invoke APIReady function when the API was already loaded by user - onYouTubeIframeAPIReady(); - } - - // give each youtube iframe a unique id and set its enablejsapi param to true - function setupYouTubeIframes() { - var iframes = $('iframe'); - iframes.each(function (i, iframe) { - // if the iframe's unique id is already set, skip it - // FIXME: what if the user manually sets an iframe's id (i.e. "#my-youtube")? - // maybe we should set iframes everytime togetherjs is reinitialized? - if (($(iframe).attr("src") || "").indexOf("youtube") != -1 && !$(iframe).attr("id")) { - $(iframe).attr("id", "youtube-player"+i); - $(iframe).attr("enablejsapi", 1); - youTubeIframes[i] = iframe; - } - }); - } // iframes are ready - - function insertPlayer(event) { - // only when it is READY, attach a player to its iframe - var currentPlayer = event.target; - var currentIframe = currentPlayer.a; - // check if a player is already attached in case of being reinitialized - if (!$(currentIframe).data("togetherjs-player")) { - $(currentIframe).data("togetherjs-player", currentPlayer); - // initialize its dontPublish flag as well - $(currentIframe).data("dontPublish", false); - // store its current video's id - var currentVideoId = getVideoIdFromUrl(currentPlayer.getVideoUrl()); - $(currentIframe).data("currentVideoId", currentVideoId); - } - } - } // end of prepareYouTube - - function publishPlayerStateChange(event) { - var target = event.target; - var currentIframe = target.a; - // FIXME: player object retrieved from event.target has an incomplete set of essential functions - // this is most likely due to a recently-introduced problem with current YouTube API as others have been reporting the same issue (12/18/`13) - //var currentPlayer = target; - //var currentTime = currentPlayer.getCurrentTime(); - var currentPlayer = $(currentIframe).data("togetherjs-player"); - var currentTime = target.k.currentTime; - var iframeLocation = elementFinder.elementLocation(currentIframe); - - if ($(currentPlayer).data("seek")) { - $(currentPlayer).removeData("seek"); - return; - } - - // do not publish if playerState was changed by other users - if ($(currentIframe).data("dontPublish")) { - // make it false again so it can start publishing events of its own state changes - $(currentIframe).data("dontPublish", false); - return; - } - - // notify other people that I changed the player state - if (event.data == YT.PlayerState.PLAYING) { - - var currentVideoId = isDifferentVideoLoaded(currentIframe); - if (currentVideoId) { - // notify that I just loaded another video - publishDifferentVideoLoaded(iframeLocation, currentVideoId); - // update current video id - $(currentIframe).data("currentVideoId", currentVideoId); - } else { - session.send({ - type: "playerStateChange", - element: iframeLocation, - playerState: 1, - playerTime: currentTime - }); - } - } else if (event.data == YT.PlayerState.PAUSED) { - session.send({ - type: "playerStateChange", - element: iframeLocation, - playerState: 2, - playerTime: currentTime - }); - } else { - // do nothing when the state is buffering, cued, or ended - return; - } - } - - function publishDifferentVideoLoaded(iframeLocation, videoId) { - session.send({ - type: "differentVideoLoaded", - videoId: videoId, - element: iframeLocation - }); - } - - session.hub.on('playerStateChange', function (msg) { - var iframe = elementFinder.findElement(msg.element); - var player = $(iframe).data("togetherjs-player"); - var currentTime = player.getCurrentTime(); - var currentState = player.getPlayerState(); - - if (currentState != msg.playerState) { - $(iframe).data("dontPublish", true); - } - - if (msg.playerState == 1) { - player.playVideo(); - // seekTo() updates the video's time and plays it if it was already playing - // and pauses it if it was already paused - if (areTooFarApart(currentTime, msg.playerTime)) { - player.seekTo(msg.playerTime, true); - } - } else if (msg.playerState == 2) { - // When YouTube videos are advanced while playing, - // Chrome: pause -> pause -> play (onStateChange is called even when it is from pause to pause) - // FireFox: buffering -> play -> buffering -> play - // We must prevent advanced videos from going out of sync - player.pauseVideo(); - if (areTooFarApart(currentTime, msg.playerTime)) { - // "seek" flag will help supress publishing unwanted state changes - $(player).data("seek", true); - player.seekTo(msg.playerTime, true); - } - } - }); - - // if a late user joins a channel, synchronize his videos - session.hub.on('hello', function () { - // wait a couple seconds to make sure the late user has finished loading API - setTimeout(synchronizeVideosOfLateGuest, API_LOADING_DELAY); - }); - - session.hub.on('synchronizeVideosOfLateGuest', function (msg) { - var iframe = elementFinder.findElement(msg.element); - var player = $(iframe).data("togetherjs-player"); - // check if another video had been loaded to an existing iframe before I joined - var currentVideoId = $(iframe).data("currentVideoId"); - if (msg.videoId != currentVideoId) { - $(iframe).data("currentVideoId", msg.videoId); - player.loadVideoById(msg.videoId, msg.playerTime, 'default'); - } else { - // if the video is only cued, I do not have to do anything to sync - if (msg.playerState != 5) { - player.seekTo(msg.playerTime, true); - } - } - }); - - session.hub.on('differentVideoLoaded', function (msg) { - // load a new video if the host has loaded one - var iframe = elementFinder.findElement(msg.element); - var player = $(iframe).data("togetherjs-player"); - player.loadVideoById(msg.videoId, 0, 'default'); - $(iframe).data("currentVideoId", msg.videoId); - - }); - - function synchronizeVideosOfLateGuest() { - youTubeIframes.forEach(function (iframe) { - var currentPlayer = $(iframe).data("togetherjs-player"); - var currentVideoId = getVideoIdFromUrl(currentPlayer.getVideoUrl()); - var currentState = currentPlayer.getPlayerState(); - var currentTime = currentPlayer.getCurrentTime(); - var iframeLocation = elementFinder.elementLocation(iframe); - session.send({ - type: "synchronizeVideosOfLateGuest", - element: iframeLocation, - videoId: currentVideoId, - playerState: currentState, //this might be necessary later - playerTime: currentTime - }); - }); - } - - function isDifferentVideoLoaded(iframe) { - var lastVideoId = $(iframe).data("currentVideoId"); - var currentPlayer = $(iframe).data("togetherjs-player"); - var currentVideoId = getVideoIdFromUrl(currentPlayer.getVideoUrl()); - - // since url forms of iframe src and player's video url are different, - // I have to compare the video ids - if (currentVideoId != lastVideoId) { - return currentVideoId; - } else { - return false; - } - } - - // parses videoId from the url returned by getVideoUrl function - function getVideoIdFromUrl(videoUrl) { - var videoId = videoUrl.split('v=')[1]; - //Chrome and Firefox have different positions for parameters - var ampersandIndex = videoId.indexOf('&'); - if (ampersandIndex != -1) { - videoId = videoId.substring(0, ampersandIndex); - } - return videoId; - } - - function areTooFarApart(myTime, theirTime) { - var secDiff = Math.abs(myTime - theirTime); - var milliDiff = secDiff * 1000; - return milliDiff > TOO_FAR_APART; - } -}); -TogetherJS.require = TogetherJS._requireObject = require; -TogetherJS._loaded = true; -require(["session"]); -}());"; \ No newline at end of file diff --git a/data/collaborative/text/d2041fd4034fe73449cbed068d0d8296 b/data/collaborative/text/d2041fd4034fe73449cbed068d0d8296 deleted file mode 100755 index 2f53002..0000000 --- a/data/collaborative/text/d2041fd4034fe73449cbed068d0d8296 +++ /dev/null @@ -1,76 +0,0 @@ -s:1545:"/* - -Created: 2018-07-10 -Modified: N/A -Purpose: To pollute the global scope then initialize our plugin. - -*/ -/* global L - * global m - * global v - * global c -*/ -const m = {} -const v = {} -const c = {} - -///////////////////////////// -c.initialize = function(eventObject) { - c.initializeModel(eventObject) - - L.attachAllElementsById(v) - - let eventTypes = [ - `change`, - `click`, - `dblclick`, - `input`, - `keydown`, - `keyup`, - `load`, - `mousedown`, - `mousemove`, - `mouseout`, - `mouseover`, - `mouseup`, - `offline`, - `online`, - `orientationchange`, - `resize`, - `touchend`, - `touchmove`, - `touchstart`, - ] - - //Clever way: for each member of the eventTypes array, have the window listen for the event - eventTypes.forEach((event)=>{window.addEventListener(event, c.designateFunction)}) - - /* - - let eventType; - for(eventType of eventTypes){ - window.addEventListener(eventType, c.designateFunction) - } - - */ - -} -///////////////////////////// -c.initializeModel = function(eventObject){ - //define meta events - m.eventObject = eventObject //the event object itself - m.source = eventObject.target //where the event took place - m.type = eventObject.type //what the event was - m.id = eventObject.target.id //the id of the element where the event occurred - - //Shortcuts to combine similar mobile and computer events - m.pressed = m.type === `mousedown` || m.type === `touchstart` - m.released = m.type === `mouseup` || m.type === `touchend` - - //et cetera .... - - //state variable particular to this app - m.testButtonIn = false -} - -"; \ No newline at end of file diff --git a/data/collaborative/text/d416f4cb7eedbaa2b52088c3068022c1 b/data/collaborative/text/d416f4cb7eedbaa2b52088c3068022c1 deleted file mode 100755 index 4541553..0000000 --- a/data/collaborative/text/d416f4cb7eedbaa2b52088c3068022c1 +++ /dev/null @@ -1,28 +0,0 @@ -s:477:"/* - -Created: 2018-07-10 -Modified: N/A -Purpose: Why did we name this Qualify ... Designate is better - -*/ - -/*global L*/ -/*global m*/ -/*global v*/ -/*global c*/ - -c.designateFunction = function(eventObject){ - c.updateMetaEvents(eventObject) - let functionQualifiers = { - setToggleTestButton: [m.source === v.testButton, m.type === `click`], - /* - setXXY: [], - setXXZ: [], - setXYX: [], - setXYY: [], - */ - } - L.runQualifiedFunctions(functionQualifiers, m, v, c) -} -/////////////// -"; \ No newline at end of file diff --git a/data/collaborative/text/d52716adc5491c84a0bf68e831a266c3 b/data/collaborative/text/d52716adc5491c84a0bf68e831a266c3 deleted file mode 100755 index 6a48e81..0000000 --- a/data/collaborative/text/d52716adc5491c84a0bf68e831a266c3 +++ /dev/null @@ -1,31 +0,0 @@ -s:857:" - - - Web 2 Template - - - - - - - - - - - - - - - - - - - -"; \ No newline at end of file diff --git a/data/collaborative/text/e19726eb67fd3c5787bb3825331076e4 b/data/collaborative/text/e19726eb67fd3c5787bb3825331076e4 deleted file mode 100755 index b7d7165..0000000 --- a/data/collaborative/text/e19726eb67fd3c5787bb3825331076e4 +++ /dev/null @@ -1,33 +0,0 @@ -s:987:" - - - Mobile Programming Template - - - - - - - - - - - - -

    Header 1

    -

    Header 2

    -

    Header 3

    -

    Hello! Paragraph

    -
    - - - - -"; \ No newline at end of file diff --git a/data/collaborative/text/e31facd25dccf8a50c81c459c325e9a4 b/data/collaborative/text/e31facd25dccf8a50c81c459c325e9a4 deleted file mode 100755 index e6ffed0..0000000 --- a/data/collaborative/text/e31facd25dccf8a50c81c459c325e9a4 +++ /dev/null @@ -1,48 +0,0 @@ -s:1186:"/* - -Created: 2018-07-09 -Revised: N/A -Purpose: A template for vanilla js with one library. - -*/ -/*global L*/ -/*global m*/ -/*global v*/ -/*global c*/ - -////////////////////////////////////// -c.setToggleFirstButton = function(m){ - m.buttonIn = !m.buttonIn - //console.log(m.buttonIn) -} -c.showToggleFirstButton = function(v){ - m.buttonIn - ? v.firstButton.style.boxShadow = "inset 5px 5px 10px rgba(0,0,0,1)" - : v.firstButton.style.boxShadow = "5px 5px 10px rgba(0,0,0,1)" -} -////////////////////////////////////// -c.setXXY = function(m){} -c.showXXY = function(v){} -////////////////////////////////////// -////////////////////////////////////// -////////////////////////////////////// -////////////////////////////////////// -////////////////////////////////////// -////////////////////////////////////// - -c.updateMetaEvents = function(eventObject){ - ///////| define meta events |///////// - m.eventObject = eventObject - m.source = eventObject.target - m.type = eventObject.type - m.id = eventObject.target.id - - - m.type === 'mousedown' || m.type === `touchstart` - ? m.pressed = true - : m.pressed = false - - m.type === `mouseup` || m.type === `touchend` - ? m.released = true - : m.released = false -}"; \ No newline at end of file diff --git a/data/collaborative/text/ec501c81f6d7f8903809691ef846031d b/data/collaborative/text/ec501c81f6d7f8903809691ef846031d deleted file mode 100755 index 88ce35e..0000000 --- a/data/collaborative/text/ec501c81f6d7f8903809691ef846031d +++ /dev/null @@ -1,55 +0,0 @@ -s:1628:" 15 && Math.abs(y - e.clientY) > 15; - //see if we're beyond the colored circle - var newRadius = Math.sqrt( (e.clientX - centerX)*(e.clientX - centerX) + (centerY - e.clientY)*(centerY - e.clientY) ); - // if mouse's cursor far enough away from the ball, go ahead and drop it - if(leftBehind || (newRadius > maximumRadius)){ - dragAllowed=false; - } -} -//=============NEW DRAG AND NO DROP ABOVE==================== -//============keyboard input numbers event handlers -id('hueNum').onchange = changeHue; -id('hueNum').oninput = changeHue; -function changeHue(){ - hueNumFlag = true; - if(!hueSliderFlag){ - var newValue = parseFloat(id('hueNum').value); - if ( newValue > 360 && newValue < 364 ){//361,2,3 - id('hue').value = newValue - 360; - id('hueNum').value = newValue; - } - if ( newValue < 0 && newValue > -4 ){//-1,-2,-3 - id('hue').value = newValue + 360; - id('hueNum').value = newValue; - } - fixNumberError('hueNum', 'hue',0 ,360); - id('hue').value = id('hueNum').value; - mostRecentAngle = id('hueNum').value; - newHue(); - } - hueNumFlag = false; -} -id('saturationNum').onchange = changeSaturation; -id('saturationNum').oninput = changeSaturation; -function changeSaturation(){ - saturationNumFlag = true; - if(!saturationSliderFlag){ - fixNumberError('saturationNum','saturation', 0, 100); - id('saturation').value = id('saturationNum').value; - hueSatCore(); - } - saturationNumFlag = false; -} -id('lightNum').onchange = changeLight; -id('lightNum').oninput = changeLight; -function changeLight(){ - lightnessNumFlag = true; - if(!lightnessSliderFlag){ - fixNumberError('lightNum', 'light',0 ,100); - id('light').value = id('lightNum').value; - coreColorSetter(); - } - lightnessNumFlag = false; -}; -id('opacityNum').onchange = changeOpacity; -id('opacityNum').oninput = changeOpacity; -function changeOpacity(){ - opacityNumFlag = true; - if(!opacitySliderFlag){ - fixNumberError('opacityNum', 'opacity', 0, 1.00); - id('opacity').value = id('opacityNum').value; - coreColorSetter(); - id('opacityNum').value = parseFloat(opacity).toFixed(2); - } - opacityNumFlag = false; -}; -//==========mouse scroll wheel=============== -//window.addEventListener("DOMMouseScroll",...;//Firefox -/*global attachEventHandler*/ -attachEventHandler(window, "mousewheel", mouseWheelHandler); -function mouseWheelHandler(e){ - if(!wheelInUse){ - id('hueNum').value = parseInt(id('hueNum').value, 10) + wheelDelta(e); - changeHue(); - return false; - } -} -function wheelDelta(e){ - e = window.event || e; //old IE possible - var delta = Math.max(-1, Math.min(1,(e.wheelDelta || -e.detail))); - return delta; -} -//helper -/*global isNumber*/ -function fixNumberError(elemID1, elemID2 ,min, max){ - if(id(elemID1).value < min || id(elemID1).value > max || !isNumber(id(elemID1).value)){ - id(elemID1).value = id(elemID2).value; - } -} -//========Slider event handlers============================ -id('saturation').oninput = function(){ - slideSaturation(); -}; -id('saturation').onchange = function(){ - slideSaturation(); -}; -id('hue').oninput = function(){ - newHue(); -}; -id('hue').onchange = function(){ - newHue(); -}; -// helper=== -function newHue(){ - hueSliderFlag = true; - var currentAngle = id('hue').value ; - var rad = degreesToRadians(mostRecentAngle); - var x = (parseFloat(id('saturation').value) * maximumRadius * Math.cos(rad) / 100 + centerX); - var y = (centerY - parseFloat(id('saturation').value) * maximumRadius * Math.sin(rad) / 100); - - var dx = x - centerX; - var dy = centerY - y; - var radius = Math.round(Math.sqrt(dy*dy + dx*dx)); - if (radius <= maximumRadius){ - moveBall(x,y); - } - showColor(x,y); - mostRecentAngle = currentAngle; - if(!hueNumFlag){ - id('hueNum').value = currentAngle; - } - hueSliderFlag = false; -} -//====helper -function slideSaturation(){ - saturationSliderFlag = true; - if(!saturationNumFlag){ - id('saturationNum').value = id('saturation').value; - } - hueSatCore(); - saturationSliderFlag = false; -} - -// helper -function hueSatCore(){ - var currentAngle = mostRecentAngle; - var rad = degreesToRadians(mostRecentAngle); - var x = (parseFloat(id('saturation').value) * maximumRadius * Math.cos(rad) / 100 + centerX); - var y = (centerY - parseFloat(id('saturation').value) * maximumRadius * Math.sin(rad) / 100); - - var dx = x - centerX; - var dy = centerY - y; - var radius = Math.round(Math.sqrt(dy*dy + dx*dx)); - if (radius <= maximumRadius){ - moveBall(x,y); - } - showColor(x,y); - mostRecentAngle = currentAngle; -} -//=============== -id('light').oninput = function(){ - lightnessSliderFlag = true; - coreColorSetter(); - if(!lightnessNumFlag){ - id('lightNum').value = luminosity; - } - lightnessSliderFlag = false; -}; -id('light').onchange = function(){ - lightnessSliderFlag = true; - coreColorSetter(); - if(!lightnessNumFlag){ - id('lightNum').value = luminosity; - } - lightnessSliderFlag = false; -}; -id('opacity').oninput = function(){ - opacitySliderFlag = true; - coreColorSetter(); - if(!opacityNumFlag){ - id('opacityNum').value = opacity; - } - opacitySliderFlag = false; -}; -id('opacity').onchange = function(){ - opacitySliderFlag = true; - coreColorSetter(); - if(!opacityNumFlag){ - id('opacityNum').value = opacity; - } - opacitySliderFlag = false; -}; -id('hsla').ondblclick = function(){ - //copyToClipboard(id('hsla').innerHTML); - var compDegrees; - if( degrees > 180){ - compDegrees = degrees - 180; - }else{ - compDegrees = degrees + 180; - } - copyToClipboard(" "+colorString + ", complementary hue: "+ compDegrees +" "); -}; -function copyToClipboard(text) { - prompt("Copy to Clipboard\nFor PC: Ctrl+C, Enter\nFor Mac: Cmd-C, Enter", text); -} -//========mouse wheel event handlers for labels, sliders and numbers (controls)====== -var aryControls = [id('satSpan'), id('lightSpan'), id('opacitySpan'), id("saturation"),id("light"), id("opacity"), - id("saturationNum"),id("lightNum"), id("opacityNum")]; - -var aryWheelHandlers = [ satWheelHandler, lightWheelHandler, opacityWheelHandler,satWheelHandler, lightWheelHandler, opacityWheelHandler, - satWheelHandler, lightWheelHandler, opacityWheelHandler]; -/*global forTwinArrays*/ -forTwinArrays(aryControls, aryWheelHandlers, function(aSlider, aHandler){ - on("mousewheel", aSlider, aHandler); -}); -/*global forAll*/ -forAll(aryControls, function(aSlider){ - on("mouseout", aSlider, function(){ - wheelInUse = false; - }); -}); -function satWheelHandler(e){ - wheelInUse = true; - var delta = wheelDelta(e); - var newSaturation = parseFloat(id('saturationNum').value) + delta; - id('saturationNum').value = newSaturation; - id('saturation').value = newSaturation; - fixNumberError('saturationNum', 'saturation', 0, 100); - slideSaturation(); -} -function lightWheelHandler(e){ - wheelInUse = true; - var delta = wheelDelta(e); - var newLightness = parseFloat(id('lightNum').value) + delta; - id('lightNum').value = newLightness; - id('light').value = newLightness; - fixNumberError('lightNum', 'light', 0, 100); - coreColorSetter(); -} -function opacityWheelHandler(e){ - wheelInUse = true; - var delta = wheelDelta(e); - delta *= 0.01; - var newOpacity = (parseFloat(id('opacityNum').value) + delta).toFixed(2); - id('opacityNum').value = newOpacity; - id('opacity').value = newOpacity; - fixNumberError('opacityNum', 'opacity', 0, 1.00); - coreColorSetter(); -} -//=============helper functions======= -function radiansToDegrees(rad){ - return 180*rad/Math.PI; -} -function degreesToRadians(degrees){ - return Math.PI*degrees/180; -} -//==================================================== -function showColor(x,y){ - - dx = x - centerX; - dy = centerY - y; - var rad = Math.atan(dy/dx); - degrees = Math.round(radiansToDegrees(rad)); - radius = Math.round(Math.sqrt(dy*dy + dx*dx)); - if (radius <= maximumRadius){ - id('radius').value = radius; - id('x').value = parseFloat(dx).toFixed(2); - id('y').value = parseFloat(dy).toFixed(2); - if ( (dx < 0) && (dy <= 0) ){// - - - degrees += 180; - }else if ( (dx >= 0) && (dy < 0) ){// + - - degrees += 360; - }else if ( (dx < 0) && (dy > 0) ){// - + - degrees += 180; - } - if (!isNumber(degrees)){ - degrees = 0; - } - id('angle').value = degrees; - moveBall(x,y); - setColors(); - } -} -//============================ -function moveBall(x,y){ - id('ball').style.marginTop = "" + (y - centerY + 3 ) +"px"; //3 or 4 px minor adjustment added for centering pointer - id('ball').style.marginLeft = "" + (x - centerX) +"px"; -} -//=============================== -function setColors(){ - mostRecentAngle = degrees; - if(saturationSliderFlag){ - saturation = id('saturation').value; - } - else{ - saturation = "" + Math.round((radius*100/maximumRadius)); - } - luminosity = Math.round(parseFloat(id('light').value)); - coreColorSetter(); -} -function coreColorSetter(){ - luminosity = id('light').value; - opacity = parseFloat(id('opacity').value); - opacity = opacity.toFixed(2); - var compAngle; - //=================== - if(mostRecentAngle > 180){ - compAngle = parseInt(mostRecentAngle - 180, 10); - } - else{ - compAngle = parseInt(mostRecentAngle + 180, 10); - } - //================= - colorString = "hsla(" + mostRecentAngle + ", " + saturation + "%, " +luminosity + "%, "+ opacity + ")"; - complementString = "hsla(" + compAngle + ", " + saturation + "%," +luminosity + "%, "+ opacity + ")"; - id('bod').style.background = colorString; - id('hsla').innerHTML = colorString; - id('hsla').style.backgroundColor = complementString; - - if(!hueSliderFlag){ - id('hue').value = mostRecentAngle; - } - if(!saturationSliderFlag){ - id('saturation').value = saturation; - } - if(!hueNumFlag){ - id('hueNum').value = mostRecentAngle; - } - if(!saturationNumFlag){ - id('saturationNum').value = saturation; - } -} - -//================= mnemonic ====================== - -var mword = document.getElementById("mnemonicWord"); -var mpic = document.getElementById("mnemonicPicture"); - -(function(){ - - var pictureVisible = false; - - mword.onclick = togglePicture; - mword.onmouseout = hide; - mpic.onclick = hide; - - //----| Internal Helpers |---- - function togglePicture(e){ - if(pictureVisible){ - hide(e); - } - else{ - showPicture(e); - pictureVisible = true; - } - } - function hide(e){ - hidePicture(e); - pictureVisible = false; - } -})(); - -//----| Helpers |---- -function hidePicture(e){ - mpic.style.opacity = 0; - mpic.style.zIndex = -5; -} -function showPicture(e){ - mpic.style.opacity = 1; - mpic.style.zIndex = 5; -} - - - -"; \ No newline at end of file diff --git a/data/collaborative/text/edf0d6f9fc6fa8c4daafd04034251817 b/data/collaborative/text/edf0d6f9fc6fa8c4daafd04034251817 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/text/edf0d6f9fc6fa8c4daafd04034251817 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/text/ee0d4983f0759afbe9820ad34d7beec0 b/data/collaborative/text/ee0d4983f0759afbe9820ad34d7beec0 deleted file mode 100755 index 8c20d5d..0000000 --- a/data/collaborative/text/ee0d4983f0759afbe9820ad34d7beec0 +++ /dev/null @@ -1,83 +0,0 @@ -s:2415:" - - - - - - - - - 50's Music - - - - - - - - - - - - - -
    -
    -
    - -
    - -
    - -
    - - -
    - -
    - -
    - -
    - -
    -
    - -
    - -
    - -
    - Logout - -
    -
    - -
    -
    - Password
    - -
    -
    - - - - - - - - - - - - - - - - -"; \ No newline at end of file diff --git a/data/collaborative/text/f25962a7f5669c4f77a4a01d78918b40 b/data/collaborative/text/f25962a7f5669c4f77a4a01d78918b40 deleted file mode 100755 index 925bf38..0000000 --- a/data/collaborative/text/f25962a7f5669c4f77a4a01d78918b40 +++ /dev/null @@ -1 +0,0 @@ -s:0:""; \ No newline at end of file diff --git a/data/collaborative/text/f61810c51eccf9e35faaf5cb43d1dfa9 b/data/collaborative/text/f61810c51eccf9e35faaf5cb43d1dfa9 deleted file mode 100755 index b549139..0000000 --- a/data/collaborative/text/f61810c51eccf9e35faaf5cb43d1dfa9 +++ /dev/null @@ -1,4 +0,0 @@ -s:20:""; \ No newline at end of file diff --git a/data/collaborative/text/f81051379428c130bec3e26a0ce94231 b/data/collaborative/text/f81051379428c130bec3e26a0ce94231 deleted file mode 100755 index 7bfe1bc..0000000 --- a/data/collaborative/text/f81051379428c130bec3e26a0ce94231 +++ /dev/null @@ -1,190 +0,0 @@ -s:4545:" - */ - -class mypit_students { - - const VERSION = '1.0.0'; - - - /** - * Unique identifier for your plugin. - * - * - * The variable name is used as the text domain when internationalizing strings - * of text. Its value should match the Text Domain file header in the main - * plugin file. - * - * @var string - */ - protected $plugin_slug = ''; - - /** - * Instance of this class. - */ - protected static $instance = null; - - /** - * Initialize the plugin by setting localization and loading public scripts and styles. - */ - private function __construct() { - - // Trigger initial - $this->init(); - } - - /** - * Return the plugin slug. - * - * @since 1.0.0 - * - * @return Plugin slug variable. - */ - public function get_plugin_slug() { - return $this->plugin_slug; - } - - /** - * Return an instance of this class. - * - * @since 1.0.0 - * - * @return object A single instance of this class. - */ - public static function get_instance() { - // If the single instance hasn't been set, set it now. - if ( null == self::$instance ) { - self::$instance = new self; - } - - return self::$instance; - } - - /** - * Fired for each blog when the plugin is activated. - * - * @since 1.0.0 - */ - private static function install() { - } - - /** - * Fired for each blog when the plugin is uninstalled. - * - * @since 1.0.0 - */ - private static function uninstall() { - } - - public function check_session() { - - session_start(); - $access = $_SESSION['access']; - $user_check = $_SESSION['username']; - $query = "SELECT `username` FROM `users` WHERE `username`=? AND `access`=?"; - $bind = "ss"; - $bind_vars = array( $user_check, $access ); - - $result = mypit::sql( $query, $bind, $bind_vars, "Error Checking User Session." ); - //$row = mysqli_fetch_array( $sql, MYSQLI_ASSOC ); - //$login_user = $row['username']; - - unset( $query ); - unset( $bind ); - unset( $bind_vars ); - - //echo $user_check; - - if( mysqli_num_rows( $result ) == 0 ) { - - session_destroy(); - header( "Location: ../access?redirect=students" ); - exit; - } - } - - public static function check_privilege_level( $level ) { - - $username = $_SESSION['username']; - $query = "SELECT `privilege_level` FROM `admin_users` WHERE `username`=?"; - $bind = "s"; - $bind_vars = array( $username ); - - $check = mypit::sql( $query, $bind, $bind_vars, "Error Checking User Level" )->fetch_assoc()["privilege_level"]; - - if ( $check == $level ) { - - return( TRUE ); - } else { - - return( FALSE ); - } - } - - /** - * Load the plugin text domain for translation. - * - * @since 1.0.0 - */ - public function init() { - - self::check_session(); - - //Passwords for files that will be required. - define( "U29tZSByYW5kb20gc3RyaW5nIHRoYXQgbm8gb25lIHdpbGwgZXZlciBndWVzcy4gIFRoaXMgd2lsbCBiZSB0aGUgcGFnZXMgZmlsZSBwYXNzd29yZC4gSWYgeW91IHdhbnQgdG8gZGVjb2RlIHRoaXMsIHRoZW4gZ29vZCBmb3IgeW91LiAgVGhpcyBpcyBmb3IgQWJiYXNzJyBhcHBsaWNhdGlvbi4gIEFueSBxdWVzdGlvbnMgYXNrIEFiYmFzcyBvciBlbWFpbCBtZSBhdCB4ZXZpZG9zQGdtYWlsLmNvbS4=", TRUE ); - - //Classes that may be required for pages. - require_once( "./pages.php" ); - - //Check to see if a page is set - if ( isset( $_GET["page"] ) ) { - - $page = $_GET["page"]; - } else { - - $page = "index"; - } - - //Switch through possible pages. - switch( $page ) { - - case( "index" ): - pages::index(); - break; - - case( "my-quizes" ): - pages::my_quizes(); - break; - - case( "take-a-quiz" ): - pages::take_a_quiz(); - break; - - default: - pages::index(); - break; - } - } -}"; \ No newline at end of file diff --git a/data/collaborative/text/fd2c1c229ac53e0c86175bf5e58efac5 b/data/collaborative/text/fd2c1c229ac53e0c86175bf5e58efac5 deleted file mode 100755 index 73631c9..0000000 --- a/data/collaborative/text/fd2c1c229ac53e0c86175bf5e58efac5 +++ /dev/null @@ -1,33 +0,0 @@ -s:699:" -
    - -

    Looking for a quiz? Select one of the teachers below to view their active quizzes.

    - -
      - $value ) { - - echo "
    • $value
    • "; - } - ?> -
    - -
    "; \ No newline at end of file diff --git a/data/collaborative/text/index.db b/data/collaborative/text/index.db deleted file mode 100755 index c08e271..0000000 --- a/data/collaborative/text/index.db +++ /dev/null @@ -1,75 +0,0 @@ -|filename:%2Fvar%2Fwww%2Fhtml%2Findex.php|>729bd3977e9ec2c1b4869d62605d11a5> -|filename:%2Fvar%2Fwww%2Fhtml%2Ftest.php|>76154443d29325fc407486ccf552c592> -|filename:%2Fvar%2Fwww%2Fhtml%2Fcontacts%2Fcontacts.csv|>2bcf46daf121a8f0ab61fb9c00ea4400> -|filename:%2Fvar%2Fwww%2Fhtml%2Fdev%2Fquizzes.php|>fd2c1c229ac53e0c86175bf5e58efac5> -|filename:%2Fvar%2Fwww%2Fhtml%2Fcontacts%2FmethodsREACT.js|>b997313979c4592942656b494256e685> -|filename:%2Fvar%2Fwww%2Fhtml%2Fcolor_wheel%2Findex.html|>2b2340b37b43b24e5a2731ed5db41118> -|filename:%2Fvar%2Fwww%2Fhtml%2Fcolor_wheel%2Fjs%2Fscript.js|>edc2b5d20ee07a2ade83bca0dfc9bbc9> -|filename:%2Fvar%2Fwww%2Fhtml%2Fmusic%2Findex.html|>ee0d4983f0759afbe9820ad34d7beec0> -|filename:%2Fvar%2Fwww%2Fhtml%2Fmusic%2Fstyles.css|>6365716b69bf2058393d3c95cbf9e57a> -|filename:%2Fvar%2Fwww%2Fhtml%2Fmusic%2Fphp%2Flogin.php|>afeec27bbb5ab15bae2cb560b3e7406d> -|filename:%2Fvar%2Fwww%2Fhtml%2Fmusic%2FmethodsUPDATE.js|>098797bf7c4448ed6397b23257b8d0d1> -|filename:%2Fvar%2Fwww%2Fhtml%2Fmusic%2FMVC.js|>5b8f5fad3ae9914ed4b0fdd3c500d2e9> -|filename:%2Fvar%2Fwww%2Fhtml%2Fmusic%2FmethodsREACT.js|>b9a2a6807be3cb2888a882de9a456ca8> -|filename:%2Fvar%2Fwww%2Fhtml%2Fmusic%2FmethodsHELPER.js|>c402a1cde9f402454c2313535a396934> -|filename:web2%2Findex.php|>b31c91140e129d845f56a9d887d718af> -|filename:web2%2Findex.html|>d52716adc5491c84a0bf68e831a266c3> -|filename:web2%2Fjs%2FfunctionsINITIALIZE.js|>6ffeaa9f6d5362fa2f15fbf5a6146312> -|filename:web2%2Fjs%2FInitialize.js|>3833e87699ffe1cafb5dc3109d9b3dfb> -|filename:web2%2Fjs%2FQualify.js|>49234e7b9a6d49c284c2c075b71344f3> -|filename:web2%2Fjs%2FUpdate.js|>e31facd25dccf8a50c81c459c325e9a4> -|filename:web2%2Fjs%2FXtra.js|>a64c3a506cee116b66128f9fabd92174> -|filename:web2%2Fcss%2Fstyles|>6022c4dda0ee39cea577b5c430ca8eba> -|filename:web2%2Fcss%2Fstyles.css|>9cf1e9203224be47c3ba9e5308987882> -|filename:web2%2Fjs%2FL.js|>f25962a7f5669c4f77a4a01d78918b40> -|filename:web2%2FL.js|>532d917f0ec46400caa40e28a6576439> -|filename:mobile_programming%2Findex.hml|>edf0d6f9fc6fa8c4daafd04034251817> -|filename:mobile_programming%2Fcss%2Fstyles.css|>74f9d1f373b31e36b320c5a6af2e87ea> -|filename:mobile_programming%2Findex.html|>e19726eb67fd3c5787bb3825331076e4> -|filename:mobile_programming%2FL.js|>8e024f4aac60a8331a03d54b83e75bf7> -|filename:mobile_programming%2Fjs%2FUpdate.js|>76fba3c99c6a58e95b52ddf307b83ff9> -|filename:mobile_programming%2Fjs%2FInitialize.js|>d2041fd4034fe73449cbed068d0d8296> -|filename:mobile_programming%2Fjs%2FQualify.js|>d416f4cb7eedbaa2b52088c3068022c1> -|filename:mobile_programming%2Fjs%2FXtra.js|>ed6f50c067d7bad7bd358192b93543ec> -|filename:html%2Fcode%2Fconfig.php|>ba67cc584113e97440efff098f28393e> -|filename:html%2Fweb2%2Fconfig.php|>ec501c81f6d7f8903809691ef846031d> -|filename:html%2Fmobile_programming%2Fconfig.php|>7741a9336615cea0064a11037be451c8> -|filename:dev%2F.htaccess|>68b53024d1449751d6fe0678e5d19a8b> -|filename:dev%2Fquizzes.php|>060728b4cccf0e88d2d445947e0f6836> -|filename:dev%2Fteacher.php|>cddb2ae31e8ac7f5d87e69efa5924a02> -|filename:dev%2Fstudents%2Fpages.php|>7857144494313767d095f7fa224b75eb> -|filename:dev%2Fstudents%2Fstudents.php|>f81051379428c130bec3e26a0ce94231> -|filename:dev%2Fpublic%2Fpublic.php|>3a9233a747bb36b5549eb6d8455652d7> -|filename:dev%2Fincludes%2Fheader.php|>32e633ae3f9718c741560af1352f1a1a> -|filename:dev%2Fassets%2Fcss%2Fstyles.css|>3d963d1e35c7582fb4cb19caad66130a> -|filename:html%2Fweb2%2Fcomponents%2Factive%2Fclass.active.php|>5b945bc2935cd53d7f96e69b2a25dbae> -|filename:html%2Fmobile_programming%2Fcomponents%2Factive%2Fclass.active.php|>a9a0fb5543ed2953ba292d5f62bf6ae8> -|filename:html%2Fcode%2Fdata%2Fcollaborative%2Ftext%2Fa9a0fb5543ed2953ba292d5f62bf6ae8|>6fade3ab5ef16da4f4f55b5d4a13f71f> -|filename:html%2Fcode%2Fcomponents%2Factive%2Fclass.active.php|>91f54b2685411e1ea2b454be94a4b7f8> -|filename:html%2Finfo.php|>f61810c51eccf9e35faaf5cb43d1dfa9> -|filename:html%2Fweb2%2Fplugins%2Fauto_save%2Finit.js|>0b00081372c3f176d14f3626f2ff3ef5> -|filename:html%2Fdev%2Findex.php|>3a7ac99607660738569ae0966a913bc8> -|filename:html%2Fcode%2Fplugins%2Fauto_save%2Finit.js|>0874412e2b238973158064bf29510f49> -|filename:html%2Fcode%2Fplugins%2Fauto_save%2Fplugin.json|>3b05b09289a3db2ae8cf68f284bcfc46> -|filename:html%2Fmobile_programming%2Fplugins%2Fauto_save%2Finit.js|>30e59348afad09731d1c4f8d66702f40> -|filename:html%2Fcode%2Fcomponents%2Ffilemanager%2Finit.js|>1bb5e516806eb514fb3779d8dff2bf13> -|filename:html%2Fcode%2Fcomponents%2Factive%2Finit.js|>303bfe190d5e04a7238bab12ce1bb129> -|filename:html%2Fmobile_programming%2Fplugins%2FCodiad-CodeGit-master%2Finit.js|>264f67810f124a1136a3bca443af2651> -|filename:html%2Fmobile_programming%2Fcomponents%2Ffilemanager%2Finit.js|>37409041d6aae3c32d019a5f9481fe1a> -|filename:html%2Fmobile_programming%2Fcomponents%2Factive%2Fdialog.php|>bbd5c30b8ceb2e0742e6264c1788b583> -|filename:html%2Fmobile_programming%2Fcomponents%2Factive%2Finit.js|>2a0da7cebddb7852e2ac34f7c0d5e0c7> -|filename:html%2Fweb2%2Fplugins%2Fauto_save%2Fplugin.json|>c41e653729c1a8ef77976647bbfbee70> -|filename:html%2Ftest.txt|>6ebbbc6206dc1a61c67475fee5a974ec> -|filename:html%2Fweb2%2Fcomponents%2Ffilemanager%2Finit.js|>329491055243ffcf41c2843c688c031d> -|filename:html%2Findex.php|>60cb37fe1c12580053ad40ecbfbee3e7> -|filename:html%2F.htaccess|>550f42cee32ce845fd817cf600cddda0> -|filename:html%2Fcode%2Fplugins%2FCodiad-CodeSettings-master%2Finit.js|>6877732a642738ecdc29b7abb6306b16> -|filename:html%2Fcode%2Fplugins%2FCodiad-ColorPicker-master%2Finit.js|>273e1de64502c06a2384fc8b66dfb4e4> -|filename:html%2Fcode%2Fdata%2Fcollaborative%2Ftext%2Fec501c81f6d7f8903809691ef846031d|>c611c854fd24594f69862df70e8afd48> -|filename:html%2Fcode%2Fplugins%2FCodiad-Together-master%2Ftogetherjs%2FtogetherjsPackage.js|>cfc98c3ef6b134046f878c0d1e586623> -|filename:html%2Fcode%2Fcomponents%2Fupdate%2Fclass.update.php|>56cab2396298ed03d332f30384d3a133> -|filename:html%2Fcode%2Fdata%2Fversion.php|>cf1d4b27a3b2b1bba71f454cc7fb5d91> -|filename:html%2Fcode%2Fcomponents%2Finstall%2Fprocess.php|>b4590e9cec70e9718018bc7905fc6c2d> -|filename:html%2Fcode%2Fcomponents%2Fupdate%2Finit.js|>54b750daba066a7ec6a3343604f86406> -|filename:html%2Fcode%2Fcomponents%2Fupdate%2Fcontroller.php|>2af01a9b54a6e94e6a011cd84b4c5b48> -|filename:html%2Fcode%2Fcomponents%2Fupdate%2Fdialog.php|>973f750ac61e200c9a6566c6f4f0ada4> diff --git a/data/config/Macro.php b/data/config/Macro.php deleted file mode 100755 index 4e52643..0000000 --- a/data/config/Macro.php +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/data/config/settings.FrankSmith22.php b/data/config/settings.FrankSmith22.php deleted file mode 100755 index 4e52643..0000000 --- a/data/config/settings.FrankSmith22.php +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/data/config/settings.TrevorBeresford.php b/data/config/settings.TrevorBeresford.php deleted file mode 100755 index 4e52643..0000000 --- a/data/config/settings.TrevorBeresford.php +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/data/config/settings.ithollie.php b/data/config/settings.ithollie.php deleted file mode 100755 index 4e52643..0000000 --- a/data/config/settings.ithollie.php +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/data/config/settings.sabbakilam.php b/data/config/settings.sabbakilam.php deleted file mode 100755 index 4e52643..0000000 --- a/data/config/settings.sabbakilam.php +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/data/config/settings.xevidos.php b/data/config/settings.xevidos.php deleted file mode 100755 index 169e14a..0000000 --- a/data/config/settings.xevidos.php +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/favicon.ico b/favicon.ico index 80b1d454fa681ab91aab016755bd470dbb4320c1..4747e7c935b576064716cf512d689727d7c43c74 100755 GIT binary patch literal 1641 zcmchXziR?f49DL|2N&_C6Z}O52MgjLbZ~a@e{fL*uiYKQyQLkh)`k6c9?K(#AqQpGUB7j9L>xr;3+?I$kD|p)L0eP3cwuycWQ|GD&f1NgFCU!wMOd zq2KRQhNK+N^O7~YW)LQmiH?@tdcW3|rt4_CU=T*5k#@@*X0w_0;ao@$=7c+)4xR3d z(b0CvAPk2??M{1;K8?p?gkG=b;+(1*#DgXD_AONHBctZ8`>;eNEd_oME|<#)l}bg2 zZa2IriV&vLsa6;a2Gp_}M!SEV+yye~#MNq*-nTme!Z1V-*-uZa)zZ;YudY~iBaUN) zZnvxBYqc63an6ukF$m3OQ^&O1ZCblxl>0ph0(?rR`=2L~!ZmZ`UiZ+M(;b*FNwmLj VEpRINw(}QHdPv>c=5o8-{R56!=&1kz literal 1150 zcmbu8J!=9%5Qg_8g^hUC34Rg5;sRnJq_DQ}KiDXOm-H6mU8994T8gcOU}s_DPw=y_ z(#}3r{(-#NS+j$NByzaNd%N?_JTN!h3Sr2{G=+RWi?=5sEFpv~B`xV(e7OlBb3YdV z@rc&z^=rG`cBMR@a)~uf^HcVOU@!>Vwn69rluoA+3WZe7H+!b~*=&YrG44&R^9sFK5B|ZnukSwaPKgrP*w9yj(8zS@HRN9<5eOd+7Cgs8lK(>%R3~tJP2} z7AdcIn#p7`;re_0bUM|u=KeRE&7XWc9!DaP;QYP$xvq;wqrvs%av8(nkmKLxw_2?@ zpG+okI-TG+4v3|5Hk;-ARj=H?=Xod;3S5&)rO@eg(C_z=$z<5i<#HGd20A`lmi3|M h>USshcs#zy|HF}b_bG?iNAB*0m6wOU#^)l2^aYlZ%pd>& diff --git a/plugins/Codiad-Auto-Save/README.md b/plugins/Codiad-Auto-Save/README.md new file mode 100755 index 0000000..90af24c --- /dev/null +++ b/plugins/Codiad-Auto-Save/README.md @@ -0,0 +1,3 @@ +# Codiad Plugin +Tela Auto Save +Saves your current working file every 500ms. \ No newline at end of file diff --git a/data/collaborative/shadow/a43aba4776a318fab1ae3091a8dfd1e9 b/plugins/Codiad-Auto-Save/init.js similarity index 66% rename from data/collaborative/shadow/a43aba4776a318fab1ae3091a8dfd1e9 rename to plugins/Codiad-Auto-Save/init.js index 1809f82..97e5290 100755 --- a/data/collaborative/shadow/a43aba4776a318fab1ae3091a8dfd1e9 +++ b/plugins/Codiad-Auto-Save/init.js @@ -1,4 +1,4 @@ -s:1621:"/* +/* * Place copyright or other info here... */ @@ -23,7 +23,7 @@ s:1621:"/* init: function() { // Start your plugin here... - let editor = document.getElementsByClassName( 'ace_content' )[0]; + //let editor = document.getElementsByClassName( 'ace_content' )[0]; let auto_save_trigger = setInterval( this.auto_save, 500 ); }, @@ -36,34 +36,25 @@ s:1621:"/* auto_save: function() { + if ( codiad.active.getPath() === null ) { + + return; + } let tabs = document.getElementsByClassName( "tab-item" ); let path = codiad.active.getPath(); - let content = codiad.editor.getContent; - tabs = Array.from( tabs ); - tabs.forEach( function( m, i, a ) { - - // M = Current entry - // I = Index as integer - // A = Entire array - - if ( m.classList.contains( "active" ) ) { - - m.classList.remove( "changed" ) - } - }); + let content = codiad.editor.getContent(); codiad.active.save; - codiad.filemanager.saveFile(path, newContent, localStorage.removeItem(path)); + codiad.filemanager.saveFile(path, content, localStorage.removeItem(path), false); var session = codiad.active.sessions[path]; if(typeof session != 'undefined') { - session.untainted = newContent; - session.serverMTime = mtime; + session.untainted = content; + session.serverMTime = session.serverMTime; if (session.listThumb) session.listThumb.removeClass('changed'); if (session.tabThumb) session.tabThumb.removeClass('changed'); - } + } } }; -})(this, jQuery); -"; \ No newline at end of file +})(this, jQuery); \ No newline at end of file diff --git a/data/collaborative/shadow/26d17024aafb824e93365a9d8d404b90 b/plugins/Codiad-Auto-Save/plugin.json similarity index 91% rename from data/collaborative/shadow/26d17024aafb824e93365a9d8d404b90 rename to plugins/Codiad-Auto-Save/plugin.json index 2bfe8b7..ee7f717 100755 --- a/data/collaborative/shadow/26d17024aafb824e93365a9d8d404b90 +++ b/plugins/Codiad-Auto-Save/plugin.json @@ -1,7 +1,6 @@ -s:126:"[{ +[{ "author": "Isaac Brown", "version": "1.0.0", "name": "Tela Auto Save", "url": "https://telaaedifex.com" }] -"; \ No newline at end of file diff --git a/plugins/Codiad-Auto-Save/screen.css b/plugins/Codiad-Auto-Save/screen.css new file mode 100755 index 0000000..2be8c00 --- /dev/null +++ b/plugins/Codiad-Auto-Save/screen.css @@ -0,0 +1 @@ +/* Any needed CSS directives... */ \ No newline at end of file diff --git a/plugins/Codiad-AutoUpdate-master/README.md b/plugins/Codiad-AutoUpdate-master/README.md new file mode 100755 index 0000000..e00eaa0 --- /dev/null +++ b/plugins/Codiad-AutoUpdate-master/README.md @@ -0,0 +1,31 @@ +# WARNING + +It is tested on Ubuntu 12.04 and Windows 2008R2 with Apache 2.x but may mess up your system. +All files during the upgrade are stored at /backup if there is some failure. + +# Auto Update + +This plugin hooks into the current update check and provides the possibility to automatically update your system. + +# Requirements + +- Write Permission for webserver user for whole codiad directory +- Installed ZIP Extension for PHP +- Installed OPENSSL Extension for PHP +- Environment variable ```allow_url_fopen``` has been set to ```On``` + +# Installation + +- Download the zip file and extract it to your plugins folder +- Enable this plugin in the plugins manager in Codiad + +# Change Update URL + +- Define UPDATEURL in your config.php +- UPDATEURL needs syntax like https://api.github.com/repos/Codiad/Codiad/tags +- Update Channel is only available if update.codiad.com is used + +# WARNING + +It is tested on Ubuntu 12.04 and Windows 2008R2 with Apache 2.x but may mess up your system. +All files during the upgrade are stored at /backup if there is some failure. diff --git a/plugins/Codiad-AutoUpdate-master/class.autoupdate.php b/plugins/Codiad-AutoUpdate-master/class.autoupdate.php new file mode 100755 index 0000000..19a21f4 --- /dev/null +++ b/plugins/Codiad-AutoUpdate-master/class.autoupdate.php @@ -0,0 +1,331 @@ +remote = "https://codiad.telaaedifex.com/update/?v={VER}&o={OS}&p={PHP}&w={WEB}&a={ACT}"; + $this->commits = "https://gitlab.telaaedifex.com/xevidos/codiad/commits/master"; + $this->archive = "https://gitlab.telaaedifex.com/xevidos/codiad/-/archive/master/codiad-master.zip"; + $this->type = ""; + } + + ////////////////////////////////////////////////////////////////// + // Set Initial Version + ////////////////////////////////////////////////////////////////// + + public function Init() { + $version = array(); + if(!file_exists(DATA ."/version.php")) { + if(file_exists(BASE_PATH."/.git/HEAD")) { + $remote = $this->getRemoteVersion("install_git", $this->type); + $local = $this->getLocalVersion(); + $version[] = array("version"=>$local[0]['version'],"time"=>time(),"optout"=>"true","name"=>""); + saveJSON('version.php',$version); + } else { + $remote = $this->getRemoteVersion("install_man", $this->type); + $version[] = array("version"=>$remote[0]["commit"]["sha"],"time"=>time(),"optout"=>"true","name"=>""); + saveJSON('version.php',$version); + } + } else { + $local = $this->getLocalVersion(); + + if(file_exists(BASE_PATH."/.git/HEAD")) { + $current = getJSON('version.php'); + if($local[0]['version'] != $current[0]['version']) { + $remote = $this->getRemoteVersion("update_git", $this->type, $local[0]['version']); + $version[] = array("version"=>$local[0]['version'],"time"=>time(),"optout"=>"true","name"=>""); + saveJSON('version.php',$version); + } + } else { + if($local[0]['version'] == '' && $local[0]['name'] == $_SESSION['user']) { + $remote = $this->getRemoteVersion("update_man", $this->type, $local[0]['version']); + $version[] = array("version"=>$remote[0]["commit"]["sha"],"time"=>time(),"optout"=>"true","name"=>$_SESSION['user']); + saveJSON('version.php',$version); + } + } + + $local = $this->getLocalVersion(); + if(!isset($local[0]['optout'])) { + $remote = $this->getRemoteVersion("optout", $this->type, $local[0]['version']); + $this->OptOut(); + } + } + + if(!file_exists(DATA."/config/".get_called_class().".php")) { + mkdir(DATA."/config"); + $settings = array("type"=>"stable"); + saveJSON("/config/".get_called_class().".php",$settings); + } + } + + ////////////////////////////////////////////////////////////////// + // Clear Version + ////////////////////////////////////////////////////////////////// + + public function Clear() { + $version[] = array("version"=>"","time"=>time(),"optout"=>"true","name"=>$_SESSION['user']); + saveJSON('version.php',$version); + } + + ////////////////////////////////////////////////////////////////// + // Clear Version + ////////////////////////////////////////////////////////////////// + + public function OptOut() { + $current = getJSON('version.php'); + $version[] = array("version"=>$current[0]['version'],"time"=>$current[0]['time'],"optout"=>"true","name"=>$current[0]['name']); + saveJSON('version.php',$version); + } + + ////////////////////////////////////////////////////////////////// + // Check Version + ////////////////////////////////////////////////////////////////// + + public function Check() { + + if($this->type == 'undefined' || $this->type == '') { + $data = getJSON("/config/".get_called_class().".php"); + $this->type = $data['type']; + } + + $local = $this->getLocalVersion(); + $remote = $this->getRemoteVersion("check", $this->type, $local[0]['version']); + + $settings = array("type"=>$this->type); + saveJSON("/config/".get_called_class().".php",$settings); + + $nightly = true; + $archive = Common::getConstant('ARCHIVEURL', $this->archive); + $latestversion = ''; + $latestname = ''; + + if(file_exists(BASE_PATH."/.git/FETCH_HEAD")) { + $autoupdate = '-1'; + } else { + if(is_writeable(BASE_PATH) && is_writeable(COMPONENTS) && is_writeable(THEMES)) { + if(extension_loaded('zip') && extension_loaded('openssl') && ini_get('allow_url_fopen') == 1) { + $autoupdate = '1'; + } else { + $autoupdate = '-1'; + } + } else { + $autoupdate = '0'; + } + } + + $local[0]['tag'] = $local[0]['version']; + + foreach($remote as $tag) { + if($latestversion == '') { + if($tag['name'] != 'latest') { + $latestname = $tag["name"]; + } else { + $latestname = 'Latest Commit from Repository'; + } + $latestversion = $tag["commit"]["sha"]; + $archive = $tag["zipball_url"]; + } + if($local[0]['version'] == $tag["commit"]["sha"]) { + if($tag['name'] != 'latest') { + $local[0]['tag'] = $tag["name"]; + } + $nightly = false; + break; + } + } + + $search = array("\r\n", "\n", "\r"); + $replace = array(" ", " ", " "); + + $message = ''; + $merge = ''; + $commits = json_decode(file_get_contents(Common::getConstant('COMMITURL', $this->commits)),true); + foreach($commits as $commit) { + if($local[0]['version'] != $commit["sha"]) { + if(strpos($commit["commit"]["message"],"Merge") === false) { + $message .= '- '.str_replace($search,$replace,$commit["commit"]["message"]).'
    '; + } else { + $merge .= '- '.str_replace($search,$replace,$commit["commit"]["message"]).'
    '; + } + } else { + break; + } + } + + if($message == '') { + $message = $merge; + } + + return "[".formatJSEND("success",array("currentname"=>$local[0]['tag'], "currentversion"=>$local[0]['version'],"remoteversion"=>$latestversion,"remotename"=>$latestname,"message"=>$message,"archive"=>$archive,"nightly"=>$nightly,"autoupdate"=>$autoupdate,"name"=>$local[0]['name']))."]"; + } + + ////////////////////////////////////////////////////////////////// + // Get Local Version + ////////////////////////////////////////////////////////////////// + + public function getLocalVersion() { + if(file_exists(BASE_PATH."/.git/HEAD")) { + $tmp = file_get_contents(BASE_PATH."/.git/HEAD"); + if (strpos($tmp,"ref:") === false) { + $data[0]['version'] = trim($tmp); + } else { + $data[0]['version'] = trim(file_get_contents(BASE_PATH."/.git/".trim(str_replace('ref: ', '', $tmp)))); + } + $data[0]['name'] = ""; + } else { + $data = getJSON('version.php'); + } + return $data; + } + + ////////////////////////////////////////////////////////////////// + // Get Remote Version + ////////////////////////////////////////////////////////////////// + + public function getRemoteVersion($action, $type, $localversion = "") { + $remoteurl = Common::getConstant('UPDATEURL', $this->remote); + $remoteurl = str_replace("{OS}", PHP_OS, $remoteurl); + $remoteurl = str_replace("{PHP}", phpversion(), $remoteurl); + $remoteurl = str_replace("{VER}", $localversion, $remoteurl); + $remoteurl = str_replace("{WEB}", urlencode($_SERVER['SERVER_SOFTWARE']), $remoteurl); + $remoteurl = str_replace("{ACT}", $action, $remoteurl); + + if($type == 'latest') { + $remoteurl = $remoteurl.'&l'; + } + + return json_decode(file_get_contents($remoteurl),true); + } + + ////////////////////////////////////////////////////////////////// + // Download Version + ////////////////////////////////////////////////////////////////// + + public function Download() { + if(file_exists('../../'.$this->commit.'.zip')) { + unlink('../../'.$this->commit.'.zip'); + } + file_put_contents('../../'.$this->commit.'.zip', fopen(str_replace('master', $this->commit, $this->archive), 'r')); + + $data = 'commit.'"; + +function delTree($dir) { + $files = array_diff(scandir($dir), array(".","..")); + foreach ($files as $file) { + (is_dir("$dir/$file")) ? delTree("$dir/$file") : unlink("$dir/$file"); + } + return rmdir($dir); +} + +function cpy($source, $dest, $ign, $frc){ + if(is_dir($source)) { + $dir_handle=opendir($source); + while($file=readdir($dir_handle)){ + if(!in_array($file, array(".",".."))) { + if(!in_array($file, $ign) || in_array($file, $frc)){ + if(is_dir($source."/".$file)){ + if(!file_exists($dest."/".$file)) { @mkdir($dest."/".$file); } + cpy($source."/".$file, $dest."/".$file, $ign, $frc); + rmdir($source."/".$file); + } else { + copy($source."/".$file, $dest."/".$file); + unlink($source."/".$file); + } + } else { + if(array_key_exists($file, $frc)) { + if(is_dir($source."/".$file)){ + if(!file_exists($dest."/".$file)) { @mkdir($dest."/".$file); } + cpy($source."/".$file."/".$frc[$file], $dest."/".$file."/".$frc[$file], $ign, $frc); + } else { + copy($source."/".$file, $dest."/".$file); + unlink($source."/".$file); + } + } + } + } + } + closedir($dir_handle); + } else { + copy($source, $dest); + unlink($source); + } +} + +// Getting current codiad path +$path = rtrim(str_replace($commit.".php", "", $_SERVER["SCRIPT_FILENAME"]),"/"); +$ignore = array(".git", "config.json", "data", "workspace", "plugins", "themes", "backup", "config.php", $commit.".php",$commit.".zip", "Codiad-".$commit); +$force = array("themes" => "default", "themes" => "README.md"); + +$zip = new ZipArchive; +$res = $zip->open($path."/".$commit.".zip"); +// open downloaded archive +if ($res === TRUE) { + // extract archive + if($zip->extractTo($path) === true) { + // delete old files except some directories and files + if(!file_exists($path."/backup")) { mkdir($path."/backup"); } + cpy($path, $path."/backup", $ignore, $force); + + // move extracted files to path + cpy($path."/Codiad-".$commit, $path, array(), array()); + + // store current commit to version.json + $version = array(); + $version[] = array("version"=>$commit,"optout"=>"true","name"=>"'.$_SESSION['user'].'","time"=>"'.time().'"); + file_put_contents($path."/data/version.php", ""); + + // cleanup and restart codiad + @$zip->close(); + delTree($path."/backup"); + rmdir($path."/Codiad-".$commit); + unlink($path."/".$commit.".zip"); + unlink($path."/".$commit.".php"); + header("Location: ".str_replace($commit.".php","",$_SERVER["SCRIPT_NAME"])); + } else { + echo "Unable to extract ".$path."/".$commit.".zip to path ".$path; + } + $zip->close(); +} else { + echo "Unable to open ".$path."/".$commit.".zip"; +} + +?>'; + $write = fopen('../../'.$this->commit.'.php', 'w') or die("can't open file"); + fwrite($write, $data); + fclose($write); + + @session_unset(); @session_destroy(); session_start(); + echo formatJSEND("success",null); + } + +} diff --git a/plugins/Codiad-AutoUpdate-master/controller.php b/plugins/Codiad-AutoUpdate-master/controller.php new file mode 100755 index 0000000..050ff0d --- /dev/null +++ b/plugins/Codiad-AutoUpdate-master/controller.php @@ -0,0 +1,70 @@ +Init(); + } + + ////////////////////////////////////////////////////////////////// + // Clear Version + ////////////////////////////////////////////////////////////////// + + if($_GET['action']=='clear'){ + if(checkAccess()) { + $update->Clear(); + } + } + + ////////////////////////////////////////////////////////////////// + // Test Write Access + ////////////////////////////////////////////////////////////////// + + if($_GET['action']=='test'){ + if(checkAccess()) { + $update->Test(); + } + } + + ////////////////////////////////////////////////////////////////// + // Download Version + ////////////////////////////////////////////////////////////////// + + if($_GET['action']=='download'){ + if(checkAccess()) { + $update->commit = $_GET['remoteversion']; + $update->Download(); + } + } + + ////////////////////////////////////////////////////////////////// + // OptOut + ////////////////////////////////////////////////////////////////// + + if($_GET['action']=='optout'){ + if(checkAccess()) { + $update->OptOut(); + } + } + +?> diff --git a/plugins/Codiad-AutoUpdate-master/dialog.php b/plugins/Codiad-AutoUpdate-master/dialog.php new file mode 100755 index 0000000..f3af1f2 --- /dev/null +++ b/plugins/Codiad-AutoUpdate-master/dialog.php @@ -0,0 +1,108 @@ + + +
    + + type = $_GET['type']; + } + $vars = json_decode($update->Check(), true); + ?> +
    + + + + + remote == Common::getConstant('UPDATEURL', $update->remote)) { ?> +
    + + + + +
    +
    + +
    + + +
    + +
    +
    + +

    + + .
    + Force Update Codiad'; + } + } ?> + +
    Note: Your installation is a nightly build. Codiad might be unstable.
    + +
    Update Codiad  '; + } else { + if($vars[0]['data']['autoupdate'] == '-1') { + echo ' '; + } else { + echo '  '; + } + } + } + ?> + + + + + +
     
    +   + + diff --git a/plugins/Codiad-AutoUpdate-master/init.js b/plugins/Codiad-AutoUpdate-master/init.js new file mode 100755 index 0000000..6348595 --- /dev/null +++ b/plugins/Codiad-AutoUpdate-master/init.js @@ -0,0 +1,91 @@ +/* + * Copyright (c) Codiad & daeks, distributed + * as-is and without warranty under the MIT License. See + * [root]/license.txt for more. This information must remain intact. + */ + + (function (global, $) { + + var codiad = global.codiad, + scripts= document.getElementsByTagName('script'), + path = scripts[scripts.length-1].src.split('?')[0], + curpath = path.split('/').slice(0, -1).join('/')+'/'; + + $(window) + .load(function() { + codiad.autoupdate.init(); + }); + + codiad.autoupdate = { + + controller: curpath + 'controller.php', + dialog: curpath + 'dialog.php', + + ////////////////////////////////////////////////////////////////// + // Initilization + ////////////////////////////////////////////////////////////////// + + init: function () { + var _this = this; + $.get(_this.controller + '?action=init'); + $('#sb-right a[onclick="codiad.update.check();"]').attr("onclick", "codiad.autoupdate.check();"); + }, + + ////////////////////////////////////////////////////////////////// + // Update Check + ////////////////////////////////////////////////////////////////// + + check: function (type) { + var _this = this; + $('#modal-content form') + .die('submit'); // Prevent form bubbling + codiad.modal.load(500, this.dialog + '?action=check&type='+type); + $('#modal-content').html('
    Checking...

    '); + }, + + ////////////////////////////////////////////////////////////////// + // Update System + ////////////////////////////////////////////////////////////////// + + update: function () { + var _this = this; + var remoteversion = $('#modal-content form input[name="remoteversion"]') + .val(); + var remotename = $('#modal-content form input[name="remotename"]') + .val(); + codiad.modal.load(350, this.dialog + '?action=update&remoteversion=' + remoteversion + '&remotename=' + remotename); + $('#modal-content form') + .live('submit', function (e) { + e.preventDefault(); + var remoteversion = $('#modal-content form input[name="remoteversion"]') + .val(); + $('#modal-content').html('
    Downloading & Installing...

    '); + $.get(_this.controller + '?action=download&remoteversion=' + remoteversion, function(data) { + var response = codiad.jsend.parse(data); + codiad.modal.unload(); + if (response != 'error') { + window.open('./' + remoteversion + '.php','_self'); + } else { + codiad.message.error('Update failed'); + } + }); + }); + }, + + ////////////////////////////////////////////////////////////////// + // Download Archive + ////////////////////////////////////////////////////////////////// + + download: function () { + var _this = this; + var archive = $('#modal-content form input[name="archive"]') + .val(); + $('#download') + .attr('src', archive); + $.get(_this.controller + '?action=clear'); + codiad.modal.unload(); + } + + }; + +})(this, jQuery); \ No newline at end of file diff --git a/plugins/Codiad-AutoUpdate-master/plugin.json b/plugins/Codiad-AutoUpdate-master/plugin.json new file mode 100755 index 0000000..a547edc --- /dev/null +++ b/plugins/Codiad-AutoUpdate-master/plugin.json @@ -0,0 +1,6 @@ +[ { "author" : "daeks", + "version": "1.2", + "name" : "Codiad AutoUpdate", + "image" : "https://raw.github.com/daeks/Codiad-AutoUpdate/master/screen.png", + "url" : "https://github.com/daeks/Codiad-AutoUpdate" + } ] diff --git a/plugins/Codiad-AutoUpdate-master/screen.png b/plugins/Codiad-AutoUpdate-master/screen.png new file mode 100755 index 0000000000000000000000000000000000000000..5ba0d184585071f40d15d3695b3e404ba38a7ecf GIT binary patch literal 30742 zcmcG#WmH?y)-D`MfwovFZE-0ShayD^flw%}MT%Q-iaWun;nL#n1gCg$TAbiPiUxO0 z&=BB;o^#&sJ9nJ%j`xmn?~ja~tew4l&G|fYK0EZSiY(y+$_D@dfKXmeN*w^W!-M%e zzK4q`xjXPw6?4IIRhN|nln+sF-IiHNC`$kUmC^X<_c)l}_nqW)T>${1-?tyEC#(vA z0DxzSyp)8dm(kulz8iH{I`?(vDodSt@;AEQfjl}|KkkG+nvMy+H|apDVw!Beb{F`} z_MpYb#BtK<;DnNahj@i^CrjDa{rc>D4v=bRC&{BL+9%xme1<7Jo&GmY9=&Nyb(PKl zc?7TZ4^E07T)H=?cj5(&5aX9A6w1-9bmX>{jZKZkjgZT!iHUh>CMKrbJG__1@i0$J zcLB+7H8u0v6nR=*QTqI@>jR@Uu!7O4)>DDT^W|_u>?e0I!w1B0sbCST97IzKOGblG ztmz;>5t2?PfNKY#&IY3&Ogs%9Fa9+*z>_O@{eF zFZHk;b9uc26zM8oWwFssWmDGCY1GmDw?_c>O#7Nv zYSp{kUl)wVB$L!r(p3Pt5JNqfRDw*}cKmo=Ju0psiRTVErtU*65O;&I(gW|a{V8nv z92}_Q_(yV*=DDA~L8nahsNKDZ1-#FH2UK|Tc@oyO#jke45*gL<$&H~1%p77ga~UWQ z!uyHrXwUy7?%nHqCYU+{QPDeC5%=DGNGVNJORel)BoRr{0(3|{H1oJ8NT9CjRzdz< zWRIRv|_^?^0&3mM&1QIltwy)W8aQbjX!_T1FyL7QM&Tu zTZ2=C`rZJrG3}@a$R_%542-_mmIL~;K~S}!i))+Lc$-)&V|K0bMwAi+e}_2IQ2U!e zefZ_pvF4~|gdri`Skb?oF>(3ug<|*OjJKvWg#Uyi?UmPb z+4FIDN?KnfZf0pp9!Im2jmtBqW@ zsooGPTGw|`t{amh#F@K!erJZ6N8ogzCz;sHw0!i!nxPhEj_vw&0Uf}mZ#xIMEL}qf zeRTd}`RVY@O+D07>x-Fyo0J;Q6bImm>&DRNl>hm2_x+~m$-Ly#X;<_C4`HUrT5_9G zTt_<$eqs%|mo`2X>jpnzbXy*-Kxat~Tx2kLjMSw%W=Q49vZAH9MZhnBk!Ld}*Hj zTc``q^n;ZA@jN0dE%H4`rPDMne+|{| zHiMaLiM8i}OEmMnz4OQ4q_L03J!x}{igP#)K(_mUbQQ&37@z8OOgWiE(A=}|3M)fD zysIVRfUKb*KQ}m~y(sOCN-dM5(#rUE)4XTQJR84W{h%Dh?LCl{t?zBt(G#R?f$UtByPQ_LF?$t{CsDwqpClk+C10)K7HsSE{@u9n7z?%(WcRUDRC3>((>)| zN8cm{#t(dh_mlYL=~M?cNIl2!xtp`{AyfI^GT`X*gOjs8jjy(4z;35cqs5aKn}+fo zn9)=*Sz!&F+|0cW_o0Ibh}#xqx)F?61e}`bF?u8oh;li5^v>PyhwNM8?2`^tsxK~NKp%s!zXDlN$dnZbh9K7Y{RY≦oIQx zWv}~qKBQ<6X{jfelC)u|M#~kPqTgol2Dveu2y@&g&(9YMTYRrWY})Bm@8T5RzvsH% z8)$x(t!Ojhc#tbFx0+2(F)gVb;sDyE5Ov&sg9Te8$Pe#bz>=jf z4aRD|SbZKyL81F5z~h2b?8MMVO515vOV;} zGwQ79d$}5Q(~KO-&B+W!eR%dYf%Bt!ttZeyq69jJ6wd-MaN4*TU=FZ+%N)hs5 zEa@zsGimFbVuLQ<*5w3-k*`{gVmn2xl-E8e?KZbvl2OqPTqMVn=&7*xb8g4 ziGM?^P~1iWnKJTGR`J=T^AaIZBGiXEt2A$@N=r|gbjgqA6fqjMHp}2Ot3rQpbJN+8%^lFF^Jl%>bJY)!uji!6hd5@Iq%Sm_u!%fFZmHlasEiyq zjOw}7Xps_8KOG}%vXl6w8Xa~RYQ5hTQ08~4`5f8~PSY!eFs^r59H!7|Q*9J_AvAUU zb!CqD?l8X?47lF+bjvBtXq~NmgDZH?2;=+{t7zMu#6zQBJOVanet>wLTc_U)B^_yO zb6q|zTj=+DLo}w((y4Os`vj$lb+tuPNmX7DZ9gSm?Pw^6?5uY@+ssrJ&rkY;98Pg< zp!jnLA04GCbjdhBJf%ARffm#qHD(^87FfT)-pDfF!&#HU#@n2_F?g;@I>@!8g@2Il zGx~-)ZlC~vTcIc?=i^gOo!4YWUe65OMx`~?)lKgcg@qsF4H@NB5eEddW}j&vb-?tO z!|~vUX>?bbR7S`zH|44^rJHh$hR5j;YZEn6=>r9~UJT0U{Zfj{)2uOu^dFWti#0LJ@znJbDw5KZx8>9hpnO7zEu0hI! zsyA{TMC)$m;PSSG-OoGuKhKGVFO*Z<$o3v}KtUISQWVmSGI%CK%13d!{Fh6$ZjL1dQ6aaf2hJ9LWFuOK=+EC z`%3J5qBFm*S>wt$b3r+{A0!V4A4vTmP{9qq4n6{C>Fk6LmeMR1ECNpYvo>$m!*q-5hG#DJevgGI&;joirRlsKK zvmYn%DGaKnRTmEuJM-8kZ<$dFHlDAalMHa)z+;FRk@fgx<24wq8Y$-crp)4%@o9^! zd@ArB65)G@x>2UVwy4>4q|K_mMSAqIVFjw0phhs#vH@l~YOQ%ac(+yFARwS^j?D#% zPq#+(^JHb-6P`~DI)7c)dpPPNN((uI2N(nU$$s6%!(Url<0A(jw4AM;i_!$FA2fXV zwDAj$bjpaT*j)nAoR*k+kw^P1citCq-;N_Ff914T^Rpt1_xkbxF45+7!J&Cv&DZGt z=_#CI#c3u2>4aF7r=+HiI}o-X;z%6rqc0ZEuvPv zSHNi?KRp#Fc;omdH$EO~Pc&WPfiR&;cn{EHHwhi3O6pAMfLz&XD96RcH8(tR8p2kE zLJ#-q;es$>*L8vxQqGRjuSk(9$>P5{+!&qU|k=CDG(AR3x_S)kOvGOTmWe;^Xz?ln%8@5 zW_J3?3kvL4KNY#(#aP?>4p>TBs?UxHyddi}W-G(ZZ&n$-%~+r-&bD{!-42auEq7Tj zxa)Zi&(MkDNd9d%G-4){61ln+3H}*543Ueta0ZP#pSOIYQwcVf$rx|;CUj*F7BP&e z`Z+8UFgG6>$E&pEtXjzmxOZ=~#B^?dqECM5Cxg7eQrfBC>Y z8q6c~s(A=~Vb6W)ma_#Pem=gO0Bk@E7;Vr_@zSz)<1TK{Wji2{ z3BZ0RiSYpR+6Z@_|6J`~eE(47X9VTn+9}A%N8niPQnfB?3Ri}x)BX99Hl&u8RzVvw z0SYZ7X$P#{$2=1AfXKxE@Dtr;rn)C`P$*a=@E6;2jKz7la#@pyV!!*BQqj9H%K)k^ zh%qoeb8?%mr|0PmtRZ@z4z9F0Id*j^Vl({oicyJYXEVF}joW4n;zOG@T>?87S5M!R zn3Q4g3|np7Npr*M#=>dk>V$+I_--$EZf-7H+XIOV9G>P_&p(wefUyQyg26hayA*m9 zBJoqL=ny?Xp3m$-RtY?6Y`H7^WJ>IKcdkIngr^*MV(8XETJeyp*gff{MYAbnGk#zH zWSHW|4sNl2^GCiUhSx*FIIR8^l7Sj>$koG;bqYPo`qNUUda#d zYk5vHSf7gzkIDCBy{Dd=QLY$aD6X|yU(h?+Tf*{e*+ux3vP7`6wuq2gdvN_c!$^UZGPAS%NB|QnDz?hEzvo7_KH1X zs(oA{pJw##h${)!E7pV--}jn(CozEYJ(dQv^* zf%E*@&7s=PIquJ4c9pdwlyS&^awe+Cvh^hFMR_ij$B`$)TWdY33aJwf6}6}rpu|57 z_~GlVZ_avQYHHq>+dyhmrxQGZ`B7*;|328`g@C)*^Hz6{lBd6(-@!kM(vKnnJ$w25 zJWt4$WRz4?iMT&yeXRP-dgVn_tFrb@I;^>NanHUw&9oUf{@Rv=EBhvw*yoF-VT%?8 zE|33sdtP(%+(~|v_PqzokH;ph$p{m)U@i+QJ3&&~<6{KNAI`3gcPi{l?LD$*;YhcH_Yz1#(wKYd zUM!r(3Op+_!dg@TUq+9gsUGRHAUX*d_)Uk(SZelNYs|HlkB7^tGP1NSxw3~FWO$mk zrephUo`d|{5cEvTWNpVPV?ex<`Z3OwYN-I9od?z1U~hF1=+NW=;(EeK=)mT^ zyeR+j;de+h5$HX>Nb{Ias*#ZFI-iVuL}~Pn%f$G1Vg8*}U|fh#4b0wh(M+C{J|H3@ zLdPfo1Q|P=#ulxpLZNee}cT{AJmy3HvaRFr*;cs zo8WNpXysC^d&+py|HVgIsdrGztjGEB5c)f-RLoDO$vU%d`pQ{0vn;I278lo|nA}EQ z;dGP> z2a7Cf#p}AVs^KVF4{`b^61~1wQzfLR$jG1-j<^vaS>;W;c;~7 z7TBw^w5-4HW@V;So{8(8jlf4IjyaiLsHm%?J3&8>p`09jTz2|$hPSr*Og?Se`)GV2 zh>6pX^oHm_zCMfv4Q^aJ+#mGL*Z)i(ra2bd5l7VE;L-9z!3JpmMT_hn76kCcn7ifp z`^p)b{Vv$^fz6pRVNFYkf$&MTyOcc-%4PGZAY})zsIob{PH4^?_to4pEstG+v9}eH zGmR-TL>v$;PKa#{{qt{vp59O3T=u#CBuV5**A|vYxm11C{`ls;L}RIyWQZGh%|~dy zMm+i>SMRg^&ZeXsM`LBrB#1H5D2*b~n3zo4!xn+{ZQ!v6m&{0R^ksu*&T@5a?RtFu zhV|CGv%qNe*>e;$sb;8S-G+KPXT|g8$zBEzh90~8JX3tIb@W85>P z8)?9(Jaq&>glhyYpRwP4=9`r35wCXPpGFk)`(v>1o!9IU!NRR*1QaFo%kR8{uDgR8 z6YVrXzpDLl-ts`=9(K~an+CStZPfHnytYv?0%Pe8A3u8i{x`;Z$>C&5QkL*!N@Bcb z3=76HziySJyA3x661@J0ga03S(1z9Tiqz03SG1|c!Pf%s|&>Yr$_#$3;jPp2>*izHTeBd$D@O( zLa^1o*fp}h==ZUIjUc9BC4wW*6;#uJ^@k7N1A>EtZ7|4C6BE{MsiJAe+y>-9x&Gng z0rzPB2QB@#bM@bi?LT!fuJ?lE3KNI{JZ?O1a=tROYxDES%w0PxvRu+Gc@i$LWWX7T?O@%|6sN{QO`0OFUPKF(%*xp`fSIwO6jvTepS z-&PTOYBwsr{>d)E2THp==h?<8V6Jb3!=ry163=Gy%a$X+Dq+fB*bxHmeIka>@$-CX zb%L1kcTW|Ghf(IL_h82$eB$X$uF^_l_5^IfO802O<}5@NYip-zN;DS9rqgegnyEc) z2qB&QPPG%#SO*)+SL`YYa+oO_0NVJj8(U7<2QLC6VD4P5BQ8v@3W^km!d?ABNCq$T zVGru|z2c`MlN~SA`z?pVuOGxU+Zq;B({3K~m$iilelJk22l*8s^@1NL-S$|!espO} zq*2XKxQ<`VaO?dC{g!t(48S_tS4uU9{dw^odx#J0G`sm%=#HVdvXV7o7O3>ckIaIm zsoRBZkwWdu6CO!V1=*<#{TS<-jp1@ab5br(o{E=Y&z{&MI6z($=PJwVzv9|czl!}z z{G77L0KVyXzz&f~BrKnw!9)UrXOF?`;P(y}HSxnD;uTds%G%0nId89IS~&AYsQ*m}^8kjZ1lk#PXA9p4RSyg8pEI z2kd%5A_sw!0RNpJHlw1y&p}|Ds8RbW=1&Er-Y0sG`d15SX;l3AW_R!irsGA3WJQwqucZ{I z8YSg}jt{646E_-TfBUW~P8WG|VdGaug|;*_ivMshp0IB_JNSfSMC=yThTm6rmICDLi=PwPa%;wPNo8sjS1-r}noh5&r0u4q)y!HR)$LA8xnG6meyZ~)@ze7- zUm&9TR^|jMBX%a+>ETCO`BMk zQ9m#s3h%OSu51saaJB4J)tn;kb@QUQYpFb$On}kQSQT3w&$TlF`JVV6oX7kHc#CqKN>a>Qn&!l+C-MDM+_qx@v>r4o4p12Wf?l6S32vLyofV z+oQlLmp;1UKgk@nKRjmoyg$d6myN!Fswt0cG0u`Cli2C%+wYdD1$@_pj?Z%crpV-f ze`k>}O-J>qU_XuWn4>hcXL3;WAN6=4k=k<`s)bIqrgMLA0~bxCXqm~V;#GH0_V58i z<>)xlcABkmHFgR)CNfsvAxLX+mNt~?+-|;WEeaK7c7R%Pt|9amijIto9ClPb%+)!c zTEt}S6%rq)8VM2Vm1qjvR2IVzIt*QC=K{#OCCVGG>JUj<3iY7*0(>I}TfZ+Fw75LK z_fxIK@hXGQ^cmlR7#{V|Ols6Mt5wpz&sUB%Dp{-OU&3SD;Etm14Ex0qYyfUn2|--U zV)jG0%?i*1tx&6k=*16Io#ur2S6f6)y-Z9`Xfnayeo$DGMs13a=9XTvN)ThIh*#z7fgyj+{P+}#XVgFa>*Dk~2lf@{`u z)dR_R(F*K^EtFc-$hv*q_}&(D|>BGtJdQt73B?#D`vTs&%WTJYy+ zE{Gp1Q?1`>hVB^|FU4hIMNsuj;#uVKt*1BXut}|I>b0azHlj^9WkpcX>X+rC_m%DL zb*9A4#T{rf16bx*B<*S9%4oNVp6PI;&usr(>;E#x+dkKRROAbar^j}jzLP~=Ha%Pm zK{fG!S2gz9`vws*;H&<9!SqxvpPKZ9tH%|N$*?u`b>4W6KZv2{KH=^PyY5?c1a5jg z%h;3eeLu*ENe}-@0QKISEwwWdx3=L&H=d}s6 zc7oN))+B8u^y`gSvykkrjm`aO4h`x$3q@6&+*I!K^6>(O(H8VuSEA~n)So8v`^1PB z+VK4@_r?-CUG-Akc3^yl{cA+^n7;p>oR}>tF$lGWHd!}K&(+WFiZcd7CZy`(bE>B5 zXTVcG;xiQ@`-B)YrC64~jgR*lV#e z6geFH1SC>l{X*8wKR58`b>qpFaJqIw%Qi>ee+3LvM8Q>P2Fl3(w&d@TvbNZd8PHk) z`rWEZ8ry$IP0x+9ZT}|W|0l@tpJ>R%Ux#t|6joQqrdi^} z5KWy-(NCH2M)~fMwBb6oZean;N%TzAf1I?x&-tRwZ2xEKMMc5bFQb_@{Tl|-y7Gd2 z#l*4gGL%)I+g6bLisV%_BT2Jkaqe|pzDvvO!aJ47%YCxo$3%DX@c=P~*$+%sNixBo ztsRe8^Ba{>JjlWrea%O(LcH+Fn(dGBSmP5qRkIaaSX?;ztC$t z825ZQ1g@;dwJFm$wGpUu>%zzD{=(I8($U&V-s$aXCUD|_NjAK_8TysL(UsztM6`*8 z+`nq!*U?jk!jy>t^iats?RJJ`G&CP%L!{h=ih)NG+mEQ;2^$FN9}=~F>u;*Fh1Z6T zVgbI7a81I`CE9o&ADTO3KXw`m#@- zuEtB+^5TX>|mXCl1?yRmPEe3K-F&a}M{24mq<{51 zfGqq{FHZ0w+B+Uyx)NgYpf*CfKYGs1H|Q_&VH$X%-qtINAgQ8{&dC1ZY@1a{>yXVM z9hhp3qtvmVS}0LBN3mm{s}qh_1h@N+VK>}M_f0S%(mK!3!4kTY@rYBt;Rjpk=E5{2 zVtFH0<`}|w!-FvckXro|DW~t7LNSZH#w`9|XFIi`0+-=?L=R{(WyU7o)Wc-i_$J@@ zhnjrlo9Cqg(0`KjdBB!jCLnp>)HGM&E?rmXOx4mB_z+^pq?+2I(yNhMjaNYr|CN~q9 zDC`Js4gTr3dE)H$$3sV0z)bi{O}v(VN?QYV$+?3K)rtO?g4?pPZ++-?VK{A!pH|wK zb5(o};sF7~(kJ>t#Cb4$;;;2<9;L3oW!A1NCVsD!q`JKej~h%;B5Sk7))cA@{q|sS zd*foaal#Z@z-yu>%9)th4sv~vAB-@+kmje14|vH$6+MZ|Ds^54c>Tx14ER^xLqtpr ztFxaiEG(33eX#lX5ym7aJ^t@_)V~uj6_tJLTlop;oAQ0^*pt5zW_rV)-~N&+g8!F% z?tklt(OsU6p|Wf`(6s#Jep7~wtn7*7GyS3Y6IOQ*kb-AqL`b7JCYjcOh*y~}v3ZZN zeXq+`IRlr{XAPr0!qU@G-rx6|{67z+Q5000!i7X!n8$$BdeNLgeF9w2~4rgZ`|jawo}kV?Rf>snPn~D#eU} zkxI4IZ~<~yJoCl*Ma5QcG@PtMR(>B(wx=$aPF2NXb&AoED>wD#kkwwk`pfT%{V|1D zuM{;B9vA!p)gqg|FK+J#KcJEYUom~qyImK0?f>L9egkWPbbC1!apKDLTn6&Q@o^(@ zY#OU)zNj22Us{@$p#7UGd$&P5KL!s37+G7i{c8&$Ka1l;%}X+U>Fcnq{Y^UR9la98vzq;6fpBK!Ws5tQ#0`bAvND3()BR7K zed-+95yuV}4XB6s*10g>HTeZB*`=ll5&y|KD)U!YT*XW z0Io)*%%j#QQ^W&WsaqS&;u01L(-E&+Ek6&1VBZ8q%^tgz!4N|kp8F*){JwY$C+Fth zI92>9$;_@kaNQXeZj23<&B&hZavFl~zeyY`hA*(FUPahVo2lp<8L5yNqbV9YJc_%@ zA`DuEUHv7DuO^=5NYiC=Sq+`9Yd^``H;?J~g zb?ph1GqmO6#V+_pycy?D*;`g#+vuW-f4j<6bnT@rf$L#yj%`PzDZ;J=c3VriZvIC; zpk*PC9O*8NRTbyc-T9hrZH8VQxBR&+q>B6Yc#-AX!`Og;WZeFKo1-n5DMUnJIY8}u zp9|hF4CMcMS94+z=zwI}M;ED# zcjEs)#RvCC>g4l#PgIi`f}Kn7HgwnC$v8Yqo|sZ)v8H`jdhvSTAkE6Zp%k<5o(_B1 zX@)f)oMUr&oKb83jR5%FWh_%!WAR?S9nZ7xR-uvP>>bdcE`Q* zxovOr!K-T<3?^B9J&B#o*^|Ry`(ruJdQ7tcJAsQpqgI22(X^)zIN^A`$+o?> zm#=N?7r%hshZHIi09o!lBr+k#6Ys9MK}`asERd@zXS*p6Qr=)6dkjAoj_@2{(sq-`7)hFEc0YI9!AE8pyr2*;JqVP}m z%vd0{aFep#Q~QcUGlM&+HtMd&YRfg0Z+ond5q3N#gUhG4NLkQb-|>4RF1-}2PdVQG zwU#W7l#n{h_{NpwR*kiup!5VTav;118_QfE0WMDSpLM+OnZbiUl=yAem{lH!iK1Em z`iSGU^o49pn#}OIDw*?0ho7+}yz=Avz_fDkCZC@F%@o(#BA-V?oU@x7*A+C=SZ4fE zbY9TUTb)Be-Tz6@wn{=p3aHNTW}wym*&r#rb)Ip7sv}_0_+X&ATtn$!9X?b;d0y`t z7uD~=#?i;o=2j!$zL8u|wqB!NpUHs_2|-;hIDQwiur;={A~xz%GVx>WGWTRBbZ)K@I z$pUSqNYMb>VX>sina@N6lRfJ(a-f(-4)4u2o3+bkEzo}c)qI7qbTvle)`s57le%cT zem?JaTAHRMzO&w2@~^pedDI>kZ=bI^+>$OLQ&Dixe9q8v_!}QF;Roe9Ci8S@d+29Q z_W#o|c&jPFT~q%^>~x?H(T-QUTH9HwurltJ=Nmq=??P<@!RH-t6#4ulZ*(gH0kvE( z`r``O9dBH}zS1*lYT6pfW-bODJ-*7M^4QX_jo|bDFhuQr{)dIr0=?bK$nSH?*Vt03 zge!CUl$={)JL*%ZzPQhQG4v$F{Nks-)-X6_|L6L_+B*g65c_L%{;|`6X|*q2n|CrO z*xbl{@Is!63lnX&>qGfr4&xm<-$ShQSI!?*kQ1ECz3HB-&7an;nVZc-{n0;tjrH`{ zJ^Mu$D$ROUJzrW5WMR_Jsw$3ihzulD8|Ok93JLN`@r3(n7yN=I)5({@VI*)sVhx>u&x5cV6My;@Ubp}tgFgK7< z2}k|{i@B~xBnv^%lyD04_C7{Lr^rqh&;#Ch`nbDe0&(;zEudWd#V|&p`9&t;(fdmqdJIy# z7yJ>UJFCGx<7im?h`*XY>Kl683`SBP6k^U1VCn6lkCVgurG%&ZBmL=bFSv~fKVMVc z-uS|N@Am2c%Q1Q-4E06KPZ_vIUYM_c!Xw5oU_m}UNlZQ-ljp!R7b_pjJo<&qNG?7; z-tDN14E7NRe?S`yZlDJ7^XEmU3kwJcAPyQ_H#UnP8Q+Ob6Dly;!Dxqt=42^)M%fUV zT!bUD^WpE8D`4`VM;Uhs0f2|Jx9U%BZpW6Br!Cj09Teo>QWFjMCJ~Dk{c&uTfKQ7U z{RX|kQ*I->?gtJknIPrc+}AbR%Wi?drNyp$m_Oo3U~((3y)?D8cMh7}-QBki_&T@( z`@C6Q*jqQtIMDA@K1w`_r43_7@%llK&wo|KD{P{}DSY zEdmOXJ@#g0FK6^lhCTc{t|HvMF_k&J48l%&sy8*F!h5B`*S6%}Eh2^~{@I7>pq7=D zwZQ-b#QUgNX63QA!SCyaHICBx*Fn~WK6nBSn*FeG1$(LwMN&89wvH^t6RV=%A5T`~@>x2B#4LI%58Qzac#*0RR&E@8a^-rQ8493alpQGO=FIiE0MG1aKO#wcYnn#mr&;?xvA5yIY2EOe{sKc$ zdLu+1m>h!`{!aV9um{kVWPu7uK!p3Hir=Z}YpNccB1eS?K+)!&8w`Q<2= z$E{DUz@T@HE;u8dm-G8Znf$cg+&W0&<%AR}j$dHz_xn2Eno`D>>qqQuFDA=tzJ`GJ zccXOf5KJxkuWA3h9X0(M1Z&_Dh%q$xvXf(T3(p5%4tsBth#GVrPMiBGldp0$(l{9? z=E6yv9adl&_ExC2r=+m9;UmM58S1ULM8CMy5$LLnF?vauRUEU^-hOd?P$a**8yq(o zR-mO!>CQQ12nSz@QBcL0}|b69C{ww!UWukkx$ z>7$Imr6A*r{71!xjxFrPt?VkHx?Y55Y`1k2J<()YD3}y%Sz)Eh(TOOms`_lYM>u0c zpwFUB`%Ft$K3>L3vu)|)sG7j97Sb}M!IpjEcElWsDyh3AfA>%HS z+%10NyCP!Xf;sjpxrcX>3bcx&buy>T+DJLY*K}K&>~y4r1p5)@#}ukID^}XI8cH{} zS}{c&Or*>~SM6Yxo2~vx+p*TMO}f>CDqwF~8gY7NF8b6Yq;YWe!iNW<8sRuJyrza@ zNgH7k{FPNpT{7O+=h`FZiHiZIR7Ay7Y>$BUbAC+gi5gZNn8Ur(G)>MAr|czdtO-^5 zB<6^Irozx>>A9-0AGxVty?ShF+F5~bho44l%6wS0=?XxE4){4AMR|^4IhGB>>U%mt zJ`iEhaD|WDT`WslZ>iTY))d<%Gg;{ieCu2v@pz~pcrhecYgG-9dsZapz4z#ii`4$+Wnq{jq~f4d z!~5ZTs0c|Mt7@LZ0@Iz3J&(A^{hnx6#0{d}N=e)`T1T6TC1@o^94fRG#TPH{O={7o zWt@6F>Dw0^6nL!m@g?|yJg%=u#)8-5AS2K;O7l_QJOUdKc%L!)4*9;uw^!b(&7~04 zs&e+6%sXt^a`C>g-y>&b2&$%{w^nsb9pG|RA?_1*>oZO=LNfv=$5xJW(+u`H3Wn2Z8#i5&E zhplX{va!bJ{1xh`rjYNaowjel?ihpoSyjS)xz^+LMAuA_M266khUO%Qin1*CL+048 zshQBk;pRUgXw$<-_@?spM+Xqbo65;*z$d{}J;w*qZi(quf6 zYEOhm|A@?pr~#)M3%L8|tad(g^d3ZZ+NZ}f04nxi;F706!bwMxNAtEwERycvWNKIknOKInC=+j(xqdAfbeE_56OLk` z$Gc^+1q0ITXHZxc^1k?GQMxG#^26GG)&iXN8g%44xxY)+8~%a)OGh0yBnRKv&T{?pK8E903v-mnP)Dqgq}kZiE0| zrV)N|Wie_sye>8yCo9S}i`*&fx=!w?oPS{KCl%;{kAAkjAEjYm#v66soT~=H?{)l{ zw@{VIR{tl_u48QlYn#K`5cduzXqzXD8R~BLE~gX{Y;CP~Kc0Y4tu*g5`^D)sqVKM# z=wjLRo&`*oR)AiIj_Dzq_fE!z(DrDBzq{}AnhXyShfXvCvi=EnP{5v(KEt=}7AY%H zxD&OiExvx(DPmTzp-u!;Tp*~kY3a8j(4c$vtY?}8;ysiKM=c#)9&rUkIi;72OtRA9 zEPDvq^_(!izP6Ydm;I(^*1USsQ+6F`VV`Hkskq~v2ikvLS;pIapD%!0hE}J4$MLmI zSwNkLsr*GOdZ)+UyZYLUx44vl^1c2QxD5V41!{l!n>yHP@obp$gu}n$jj5lt+l=5g zCv-U1H)vaSAQ#n6d_uh7#InFoq55eZkFeWkpm^#e1n2uJm%S2&IWA8#Gi-O__z=3! zM?A8il%3pSLOrP+p|sladNKRP3I&_~r{W+etZ+WVK8_Z&z1RykVAG#ed*c%^W%5C1 zR4&rjoZUl(0lDlWY^xhZGfz@{|525!ka{k8TdID|G2%#Z{^wD2NwH(Fu+k9AA{*Z@ zdPm&h0ClpFDBhs)j8~k=&(-Xi7w!9t31VWhHHz&88{Fo!3~KSk?(m&n>-Rik^?2My zYb)+aJ8=h(TC$6WsUZalt6U?frR&T4RsO4ze(%y&hcoCvdhaUyD5Toa+LO$a66I7Y zeaL~5>pd=37hMFZ%-TLSzFZkP`_y8??l7e-leer5E3f5xYbVAS|Euwpm$Kuy_(5tU zf@vzV2PLLOaen0*lRfF^V?Z6Z-C>Se1|F9f%orOsD{P0Xg%Uix^G#KG z;WY=te4lu0>w{wLF)dG(uR2YSoWtTxAr{#CyarN`ccyr6o1T4ZjVM>dz=>2_)|}F2 zhFp|Q#XxA-rm~-@o2}pHMmi04iQV%7kqf>-QM#xeOK%H)p9)AAw(<*Va5g7*Anm zd(`2SzV^Lpc|8PWIn7bSDJYTajlwb4p-uVtC*R!s4~a}%*s@#8 zWZ&md-+4)jdBRvf61=2a4k_eTcLdHXYZ2xTVLJ`Csa~Ou1~WBKdWH~>#|P@-xGSuj zUAf%G6vYABLH^M%YPdcD!&xL$Wg3UKVcXTz!2BBDOQ+t^q@z#A~y<=Q8m< zEGf-XaL~Os_qZ1b*azn3*)jsnr9~b=-i)J`Kulr+d~|7^xi1YDhrAQ`{vb?riBdFy zSXFswj=7zwLNXvzG#0{2Rh(D!HEN*5pTLD0G_}h!@Wy2t$0$PvOBA}179iZr{RefV z^X2S77QxkagG%Ltzymb7xC5pnz7cM5i&u9r1whyGJH6Hg+a0f}Hei$YCqP#tF|Q=| zVIrS!Q`#T|UKiw()f?dPucgf&2>hximq-Q`9{Jn}=`vax5QIWH$s7~C_^mkW?NK*k); z#3R_S9D;bUqZ8cMNxU$eOTu0*k1M)Wk%0|z&@1G3Wz*14YY4Q6&9>qYn0hNUEezG* zp^n(f>^8WzQ$0w$QR2zCTN3b?#A1x}z1d!W$Eegubu};tr+wNe0K>hQz>nLVGJ`uu z?U&)A=Mh97QdaC2^LuvmSv0CWa8a{yMmr|BW zGuJq2#o+RUfd3Yda7r&dq9lzUV?tz>WOMQCgFgHNQqp4}<>lvyTC@bj6WTU>+8Epe`!`wF+FudNj z3i=b49?Togr_Hr$&s8*alY8kiqcnjpFB9khS+AFD#sMqJcX{leL^By$bYVp_GjLXm zV_`ObU`Y(1I~4rs_mg;pg22gm`eap(=U7*~Gyni5{y*bgNr}*H?wxdp+NJ5{++sKy z`9wT@y0=>U%Dm~iifi`*v+E_BBN~h1XC_Gn3JxD{MNl4GSOM_(c5JN1A{Rbl5TkSt zrL&bD=6|1nN0uaXx+R`DiE*wj!AkSq<7b}}rp6uKIm!oE%dNJm;%dyC<#5hB7ncd}Z5asG1DLI^ioVmv zFLs@>2IYZuXgyWTvW6W|vy|p3;PtH;a@H?SymBDy!8`V6l!iCc07Gamm@pt@ zuW#T3oMf+-!2Dqc(47}f_-?$Oaf0SYFvc*2)$8j&)|(8a&kftXlv`lC1qhgw zO%4^1^~FcJ+PB(U>JcS^FnEv8esscwK{cJLU``lLewN6Q9nExOB8Q+Las!)IsjG&b0E=PQ^6 zo$at)zz&_aoi8Bf3s9WF?*jT+6;TKkDE{96;dlB8W%# zcNy87%dg5$r~j+BGmnQV{{Q_*C>51GTTuxilx-}@9>$*Ch-8iIyAhS0WG7UXvCF<2 zWjFQ_iHvP9gfNyFX67D!zmMO&zwhrpzW3h8VUToVyt% zIXSH}jw%8p!v%up7MX7PJypeDtiHP$b&wPn_rWLXoYhr~+mA6dBlcM4q~|lJ&rQ3( zM{ciIEtgk1h5H8xsgum7W^z=81`-SmL7+GMz%A9Lqde|x{1|@GW;2R8;q-!sTvl5( z+VOENRYA%)C9vyAt?((ubUd2ob)pEL3!4YG^>~v^SChybddLyQUdWZM?|;s?RD4oD zgxnGls*MkqCMHc7EA9_e8;7ewTZ3ZNZmpq^lO^xfAD>2q*Gj;>G|R{1j{D%p4_5B; zRASslp$iA+9xcs{FW&(YYA0kW{u>ZEbt7*>_~!nC4RbTi+9xscZAKs81T5Comj>28 zx#54U)0eQbk_0n&EfA~MIHD0PWO2pTX3OpU#3%S`rzvxt=?UZR;t1ZzRIcc$it52q z02x9Hio@xVx7hfOkj@7=c>C1&>Pg37(}CQzFIjh>>?(`ODJfAGO=K2- z%3$^Hs-E(X3GhsbcON$9tC)}`ThMN8xv8CYqtU8E;S813=vZxX4pyjSD{T?B>pCdfDa$5yX0h zRoQ&J)QYV9r9MraNN)Wuym8C#snEu?BDvdPk=YbyLIDQJ=;%Z5KAM~!k-vV@sEH2mJs$uY+zqCr~(oOTo7+78G~%%2kW zq**Ji3|mie6r$gEuJ{yLy_W*_^NGxEC-wXK83-D&H4IFl(#q*?T@iwXplBGKb!r=x z6T0_(!_X%fRJHSRplkQ&nedAWLM?XL=V(*-9!qXtrRcSdV&+jCQdo6_pZn(IcLs5C zVJwc5vGSKS9aOKFN)6ZrpT9|9V%M1eA`?#I+X3@s*RSdig8p0vxS~AfX+Jx{1DC%9 z+EZXo&{Z)IS1HQ+xnwl)(?T)vNHo~tc_eG63zJhh-})D2wZC`fPpT4y8JUhaleJSd ziH>%aQ9tR2DLsGrrNu~C+t0J8ao+f?lu61@z}>}t3gnvr+E}bDU0}NaCYs;}p$^z6 zgJ(vUR0uN5$0Y=T=)?SLR_>Sc5g2)u1Lk{qOg*3W-zYmePnlE36H25UP5+E2C=AIs zzI;mw5b-+~slG=|{WcT;Dn(U8Q`7frkxm=SNZu|1!Q$~Xt#wI@FJ59P$?^3Rg}!+! zmMdvj9gDLQ?{asHFG zZ%7BZF);QsFeC$d#`b>@-)PqaZnnE;?fy|t%j(V0ad>XS5%O`q#5N9R@+N>m7U%^W zExs#>s*$ruG+o)gH>*>RGIqP2hP&@}W9=ln&@L5gP-YGSu_`pu@;l>J*Zxp4cE_JW zKp*pfCeK?{sPDOTonK?B#2@5P4}q=rOl6DZW2^jGUKFj1!`)as4YpIhbs8&oLCo2< zyq$?RO(D4(d^`8oeDKyPfds3))p=zA0cnwYqEW{1Rf5jx(-G7Rz=(;i5i<5ik-`P_ zX=#Z%eYtIm6lO{~Ge5P=S@kikmZRq`K(3hn=z^lB_G>_1>T&Zg%i`J98_X<>KG&^0 zcTs3V`JJv&C2Tis6K6j8;7<8%Azb?A)AW$Nw0-Q@Vkb7Q8>myoKFyzD-CKBd@>0cn z)spGPq1r9JKb+4Gi{YPp1oS^4u7Hnh-Ae!~go66wx*P#bp2>(?g#yl4NmNORe8l{) zY6k3HP>D`Uo=8KFRQ7Y=sre^KjY7+&_j&LpZ9ApwoJ!pe7jXgh6O|wYe|TmTa-%M3 zPvf1alPRB07OUM7XJdJyt&3QSyaMC<+{vQam1prGB?&r;c-d?~6Ye<80;4#y_L)u` zyM`X5D5nSxa!UE$F24_P$8|@Y$%S0;*Vr&rJFilLYj}GkN{s7~dT|RH*L&yDP6q}V zLf~kr9h1i^JHri}NqagfCGbYz>|UhuqAkvFN~SC8DFy52)y*qQ>Z^@kK}@bMeSeJl z$=pg6dHh;eg@?FeRL7XMTJzz-wuckup4sR3t67^khHRJY+&kIpC!0sKe03GluoT;K zp@8nXC=iP*!YB8>H5;$syY_jDvz2m%vu-S{`)D{I<6caiv(TkfWT24EM9w3@cejF% z?RthvF({#;Egj1fRMTH`ZC_s;R(ZYE>DBvd` zr~5}U?!HC_! zORIL(ZcujZ4ku(rRC~yohfn$EL2q-*mrrzi06o;ypSF63<1;5)@FQElqZG8Wlt|Kf zvlncb{k52XZe9l7`RN+L{Wluj;~p%M7Y@yp*<|c8aZORUudFno7H1Q%dHhd^?k;}P z#Y<}_o4a2tE*(5mP7?CJx0j=i8g!#=m<8(FuO2P1L{~|pE1R|Q&tL7;86-a}72M#Z zxr=R)-2(JqnTCb(7cZ1g1Hw0w$vOPj7SikM_`@Y5g~8I3kiEm9T%tQ29rD)$7~^lf z%Y#)U@mdna!-a3zel>uujn&ax$s2r2eWkTbH>ZX7i1XDhbqm0a<%22fdNl_*zx4oJ zXLqiAy%5D2FQ33^W8du zlQL%UdM(mHfTCP2J~{B?`mU~iiz2Lu7j|2WYi$T@{UF%1n-0D<&bRLSrut&i`cxk2 zEaK#Nr<5D9dpv}02$?F~sFZ;1GZxvC{D@c3{rf81!uW|F7PBR`mjDPMfFPvEMm%PHb5XiI{U z_OgwM)TM~g=u^GAL@zBj2;)KI-Z(vM@TnSI5V2S{FqSvkD$t}8%CZ%nIFWf-p%C$O z@tl9#gX=|=(FQv27WOu7U2pVt#oyz{5rMhTi(I>cvfCy+g3D$9_+07hO((fr;eTN5$})f^9oGQdZo#n5AjjZZ|0u0`t zt9%ysD-a+&eMei!>-z)TL5)2yPFx>%%?b5{BQZ6BXK0@uL~Gvey(m-$x{X{m5*uLR zH|6!Y4iFgAV{_0l?W6+eB>-O@JqGW72b(@GhMtGo@qk}O^E$Na-x@9E488ajIImB` zm`@u-{=E775-JMJ4FkXaSFtbDVllA)4@NGixOzi-W0w-`%ZJ`O2VyW*q`DVWT(iT$ zhD7?v-GK^c4qdA8mo6dEu40OUmc$cb5t=>X2CyycasRTN@%j&fltK+cQ4GV zLE*Ji!lH#tG@L7cM9ck#YD*+?P-^Fk{C&;ZLps|W5E>C+BlxGwlZdFkcFWYt`ysps zUOo25Iiv$r)Xog;Onb>k08K=V1=;IiOvUKvy3b?88@ zZ4+)z+;bC*9Z3~zJnr~&MrN`xo}jGUl;dM2ai7EPTEk}@*)tE}v$w70arfJZ*`{2bIvDv*4f{?@p}u6CRbN$OYwlmp>-v`)VsrG zb5nVrsTMMVuqTT8Umz$``F$6yfp7QvlEMmtlx&n#f+yCVkOyA!zF3+(QI#`Wu|+CO zRW`d2&zdUueIPWZ+pEddmCLBctxqPdx{)Dct)+1STn3XyxjVmh#w;)G=kMHkC0Y)X zv0^?zR}6SJju7~^^M3)=tzfJj>q*0q#gu|=+vN>|Q(3dg;^ewf21|J?Q}wJ($X^sD z*e6E5j)0vqc*~W|A0^6`tQ+Yw1orD>50WeD!pb%ubKbz?ydW;rx-56W!k^=zvxt49 z_B(Xt%&zE0uif#YIc)Gr1pf;K$_a(lrzu6->gA$VyC*chq&m`#hTEgT)&h>*?ZGQ= zRWbf&S$?Upf_Dkc*Nn$j@@1>)eq4M*<%3 z8Am)C%7ukG;eRgOO64w_dU<>$(jwKyw8#voc-{)FOQzfgM*HU+>U#ZFZ^;X8(5xn; z<*vT1^LR5J#5wOE0pw8Ug?~+^Rh7ds=IcmRKwr$KyPcdo>C=~6RXV(h;`N+1t0H0_ zQ#9o@qkH4}(3O)icUPdL!Q1y?2sFZ&xYOK?7o#jq^%fJVq7a`Fo!XatNRorI#G>i9 z1LJmgYI~A~FtS~~2h1K1{C19s@eNfjXkxuc`@ZDlrhO>EKBX?o-(kE2HRDM%-2S()d{%HNJqtK1-1%cTV>r|4|2a{hD{OD2Oe4@p2zD=tdfPU<0o+I6rCTkbQAYfAlYUsOfr_p^jGj8;p9;>E!6gRl;}J zSrH34jigvL4FE`7Z@T$@oX{T(oi$WZ4p0sKrlz^rR#5q-{fd}`ya#*gPSPayAee25 zkapf`BX`*2A!Qx{f)5L1)>mJVE!+mM|Mu zhOolZHLa2cl0og2P22gK+$15DF#zl~v{8aF-85X}jS%6mGIY zf(E+Jx!+ukUWRsL^!`>m=SZDsYhxaf%zHf!{SuHf8I2QK2aQMf4K9rO=Z&cS5EQ7( zes%3*U!EAR<(yPhp8be-V?l&XDl>D0w?v2*jA76Z7u+9veIs|SS;n#k>2JaLZ?qS7{8izM)pmzyz94FxMa4IwijFL&xaf@_Epwjj7f3V z9q{Yzo7C#+v`(f%U%>h4$B8Q(e)lE@m*$Oo5DUV6!Tny~2yyP=e zZmoPNzmO&sve%Xfl21Z5a&Lz9><`fC#WTQ@OB}RZ_E^?S&kQSA6Ws-=zc-kfL-VUD z5w=-#mo>^h&)RD^KBeD19yF&&OE^C0R_m$H-P+&QHYec=0Zh6}EnhWM?K`>@SB#QY znoD%Z4v7m9ueME^jxu&0zf_%9H4N=t{TSzCYUTKXv-oOu(T6>_Pc`kg92z7pXOG1t z`#L{!o{8NpquoT~CD9SW(oHGQ{q=VnP%Q|6e&U_yu*VOW0!0)c@=YX$&UExkpvIE1 zC_$nnFLA4?nVVI5OZa9A7b_K3Zvpk4u3PHDdNT`11mPtkS@L_IA&9tV-cCZIorxR8 z3o_b4_OT4D43)hnzFoz0cUY$Ub>b{W{HNKn-KFVw2tdc#cYG;QvSS;)eOQ{be;NDI z;vjy*t>eVg!*v5TzX`Wve`n$|D73k(pWj=>;7W@~Ts}Gfs$n~<_u$r;qj_#mF{!7P zIMFnLAk6HTh2RhFsR2ytdPFU#Fq~&29GEp=Z>21U`_UR>9y%=>=?*ZNf}WoC;8=%M zakRlbx-Py0w9-&TVBRwHZc>^$d$z%qR?xGv|8&~=SG4<|YlEa4LA=*PLezS=wGF-; zweue92e8^mJOxkDUCvnK05Haw}XR(MgXTVSrxe>6$hO!nh)c5TGKKHpUU)DyjX zlGP|z#*{|6njW9hmow$*LJf^RjhF7%%+i{DnT-!9%4#kiXl=R8-Cg-vK6>IB_AG*_ z-d)h%Hl!ygRyMN}Xe(K^uh5Lb4YAwtH`Gh)In7ET^G-srG$q`}QU~ll({Fo!&P1(; z|4Ni#LHgcB(t|#ZE~xsLev^z|=MuOAmRx!oyI7Z(P$E&JHY*qPbn&}!-3|AF>&=PR zx_x_;4r1Nkhp}9x2$OeFgBp$3hzd9}=yd%WE0CQPVU#kDPjm3A9$SV<%H6?Q?WP~Hv1-%_Pf6@ z0LyDi0iL9Dd_34XWK};}8%Virn8D@QJxdtV)2>g)nQ(fylV@YDnxP$F;#=yC8f^ge zj-2*JXj2zsYVt*L-d!KLNt{YNK@kM3oW=vQ^><#=rdXKC=EK)A`PL zn?Z3Yvsr`ESxW-^V|7E&gK4Xf(~+gW$SJZb(S0%HF$3vx_c5+PRj4~ELj*N6!wF6(IYn|-}^jfv;m!twH zX#Wpat;X*`p!YKp=>6RGiyT%AC8Zu4rVBkhRVoW4ko;8T-|r+DS18A3c;;RzP*A)4 zFa4kHrhYeG;)(hC3ekTd@Oba{`<0Kkk`{%skU%@!xBQPeszV8-34gO?urNHnB=bge zcdfe+r=Ad}ViMThEJr|)6;JKDocczZRfUs$T7chbpITU zF+iDQngUYDRneh%ovM(#OD2U(%G5R~DTZu+u&vV;?QEvNsiL}z284bKkgdg)vu|jC zU9dix7s$Um7Jsr2$*-mqWW0J83h-zq!@nLj&uIP^nu)c|LLlZ(Hcggq6WR-4>$_Hy zm5&63g$t=JFpvJ8u5mma5NnwB2FURG_BLD+9b`a0HO%W-9Lx|WfZc*H?ziJ+jMO<= z2Xhq^?7v=E^4|#(XGij};9opp_%xKJb=si+&hdYrE&NME;QymPEVQ=N5+tuM6IR5C zw&V7He3^nhQ4Nk56@nTRJKc&q}cwH>Q^hw0%JO(^N$ z{Ntp_bk&K4xv@jyX~<5MCmT9|WJ>4}#7cgM-!WM!d1OX%Jn!62@g7q~^?U{6+~by4 z5a@d7hFu%HHBsamnHKyubx`&(;urA)NhMX5EKVRDY@)_7yT`c1)Z2*E zZec91)|z6>t$`f-tf+&%f8`y;9sQaR5eW!8$I+fC1i=# z$*QSf?Wgk7{Z^T&SKhM*UZZ{H`qS@`>+3LvusFEBawDN`rq zd&y{%amK;wqXOH?JjoOpNX|$%lq6A}@x8dRh1y*1@#E>>DQR1-e&m$sX8!&-B&%?@ zj~55y_GL#pPm5RL%{ICN{i%l#ogOj+Gg)1dO{OINyT<*QZy{s(N7fRPY$)3g1OkS4m8LA} zo}8#tcO_uuU$BxtPM%!iXBULW&D0qlz}41{TR)||>X*a{xWC@#;I?ZbTIY~CIm^tI zG!a3fZ5na4ue*94vrQ>*&xMgqQg(~{S+*-J=Uew66_l<26r%_3B7ZF2$s~4ked@(`)do^H2&*mWj(#rqhB5ee7UPw?afi#yE9o+k#~P@F(F!8rX_SB=nSQj>ZG*XWxX`L>nzD*TGu`KF3beHX%CpOD@e@^OrsIU4J$u*J%>Up6qIWo;%rC;;Wi3spkP2>tvzhmgbI;zp zpgem-l@)@N@5VO^k9h6nR$B}z6-*jr&WK1#|B7!c%bmW%5*jlLRTT=0s8>iCtIO3J zo|SREkB>BhZA53Oe~*7_D?7EGmT(=ss5Ku)pSHScrkUuxYG0FKB7$HgC(HLunG|XV z`s4oy9-8d_7HG?xu+GU-QnMd_?_BY@w1j!Im{)`vJdSY4>HE%qZN5euTj3eNglqdeSe7C#|1m6*A`nsXH#PBj(Hsr&_{_PfNn>&lmDv!tIg_QNwK zs)7b>ZUdgU8Z@Uj!fDiP8ZHOT(kfWGrHMqx*)>tmh1gkVCB52=9B2-48mz6UvZQ_~ z>bSey?+f)DdSGZ#)-6UuAMGHQC!C)U(II$9~< zWh{njOj#Z~5^!*N?F%vAOE1;#7zaIn!*PJsv3%S)QfqK5-f7t8bgTRwnhhO;>$=h{ zi)gO=;>1wE~k(;#a!{x8SxQggdF*31?Q<$NgLm7 z)>+@TK0Z02xaN~RS=_#4Sg}0ak|R67r@$VTZ0oo$tDFEiv0R`YSxaJ!O- z_d&FOV8N218fWc@{;JLUq&CA^-HDNT@!Gw^Neiceq5v$D*R)MA3FthNfhTuMY)e`Z z>976DS%>AX6z=;SzA9^8jcx01hMhT z|C~7XUyx_T3pyjYL1NVZXiJGV2Z;-3|D9s%IrHy3Re+9b`^{~Atc04=OAcRV99Ugh?;U47vG6i>NKM;<;plz@?fi0q-?QuaY_ zb=a-{`4KaD?)hN)C)k-g7HfZVzyFGWfnz zZfrQO-_c^>{V=YZkE}jMmf{f<;-rMlDk+e(W94!CEz91&(Z_SDgl`{=vFNS9lvW=@r(ckHZtjxlx|SQIR_A)H^IK0do2a{Ve6 zmLUU17wk4`VoyF#ttoWL9TypQWqhH!NMP@;MHV4+NC@ryHE3OH#%p(hA6ySn2ASq={1C8u758!^zNp?;Svra4^a*SSubjRb5pH? zw#1stT<$ymLap})HraVdTU$PcS<;&MTG?rr2@Y>WcrB{vu_W*n!hGe0$}_d|K6Cj8 zG;F@zYfj<%@F?uj)t?6His^7RNb6&iyf5F2nfgR|1vL&g;_b&GIr9`Yc~z_aGNP-V zIEC$|h%GbG>>Rmav~zTfE$(K+m!P$P>9X1J-84g9AJ7PKMFHF9xQC5_;r-tq)}8ce zdyUA!RAS(*5b{nQdUQcLw;+p*&0Rj?mf7J@$rFhwexEH{3={Neg+sDGpIQ|pN~X3_ zU}j(m@m#6wJ*$wQ$ae4THl87EoINH2E2$8ozntTr_7rgTH{{8s7LAMM(>b_{`Y1bq zgNQ(PXa^Nz7heB3?`}G~zO~QqiCwp|vHNI@MZ^y=f}{AowqDoEQWNGrE9x1qauP*E zlO2YuOC7()Iue?3v_nTHFKql_N)uV>O7@jjZa!OkE0|O)Ce)ihSaBUfeTU0V+r@cy zl3p~p7MPOsUPNUJ!T8^Dxx(dWMg{`3>{=*5bF@663%njp&KWSy;H~I>8zn&n9McG`Fvd(*{A{nb~BXt5tzxorbp`oEJ;#*y|v6U$6XbG#49 zR;(ZUBAhhta>|I}UY)bHnLr8Jj3opqPjtIq%alnOZXHn^l`SFaDi;b)75L}ouS=`g zOs9_WuLj?~jd3h7)%jY_4w^6j z0;!G9$xGU9*W8Xys|p8;zI+d%bLf@a6BJnf;)|BkSWVuX`ty=|lhg~#58Ni&uj79- zbSF+-y6NNgs7h;f&~#H>d+;Gw!KF2|KfT@v~w?$4^Z=?m)j2X5$S$xma;E&C(Lb35hC&95pN-mUrT|@BLpdgLQ-t# z6T&94p{5KUrVgtSKa9af;GPnSaHk?vdFoa(ASWWy(bmfAwutx% zPIx#F{M}lG^h?YiiObK&L*DAi@Qu4m>q_E<8ni@c$~3VT^nJfJPytUDJ(j_uz$M(o z@9CdkKF(YM{b3FRt>_b^+`Qwr3+(B1-m~W{GE|Ox2F>p-B%lh`nU!Pr$W~ceNw+VJ zy8ZN{IegmuLGognrLd$$Z#Ts4AqShb%*n+~qY?au+7l69&SW)hx05Z6#bWG{v)SlP ziN~qT?s9DnIsUIm1{|iGa)hhI#TIt#q&Yc*E?cfNE{~P1>2)gEUwTZF{Ag26Q<-$+ z5Cb+PrH7m>-D&f3a^gt{oLRfKs+YWQzU^Y}(UA*qU*J>uyK%cz+?e5$`GlLLE4w55 zn|G@i#(cG0y?eol?^U>&kbgkLV+4ZNM|IC(J*wENyV@T&%%BtLwu(|?N$K0s$4GAf z$Eh*6jZglbV8uf7GbHbOcOp8n7N#|p2GJY)e9OaRbdwt7cj0T??`Q|bUo6<_qiqLh zZw)R&;p9~gap{VTcXvQ@DfX)Wen-9r-@c$xMPBov&)8NkS-lOuGG;GX21lw=t6aXH zRYB@!b$iJtJ4EN^taEqEEqv9j7N+LZ1j^9iAak*q^ zWlv^Ux^TLD)=K2UFPkGz8~N^-b!_u@Bi!&3;v+1O;27|PW2{@g=+gsVSU7X*Va{)d zlEo1NmY@&qW^&48!X8xL*q8+{XHg7T3U_K=2xKp+02X8-le`E=EbB$fI*8A`xs3jd zj$AU{RKc6^mE%-OO6@?pApgbU>%4KHzrl0=!Zcsw8=R}nFo-ZYUZGVLF5en25$xFB z8m6qAZg|*jSK;0JO2b`)UweCld0)wJ4_}G;=19pX?VFq<+d(muJ67ji6WLXrCF`%7 zg&uSw^hMaC{ObeiraZAPi&tA?kfq|y9AAVB5W-Z&Ej70;V0S;+TOyn1TYcrG=&iU@ zEiF}P4#`<%F%`ztU9`TG51p7w7VkJY6d#c)L{++W-zxp;;*hRwDxz zPKznj;cKrB&8m$PeB$@hf3Ytsq1i7JunFl%Sk#4)*Av0a1=%Ki*xn8^J6#FFg0F5FcIwfF0(FSXwXZ zNa;3+tkfb7VgrY=HYEP>v^!akNA`5i4h)=3 z(m>KSoB!5bL&Uf32a9UWv&YWu~EWC|RgGB^+f4pdQbSuQg zpBp#?ZZ{5T6i3IOo;MdduTp6720L%s845_y%F?-U#LA1wa=KkV5^?(?CB)SORv{sC z<7DPXW_d98KcLyM9swtEOZTM}PNrgHF2O&ghO=Rw9Xz$Nv+l``4o~f`gp8;3XVb05 zA?<1}d$dbcT1cMg03O z>|7B;NF{u*7tYFt{@OW|m7`x8IhiVk#NIz@L)(W>wbs;~UcbP9rgdOI#5NsePYJir zA8{<2q4u6zzt>O;>M(UU!z!{mER@e~W>#c}dSJ+WJrbyeLSG6-g5DPAS0+`IMg6Ov%0u9X$E~X$mVVb;xHgyDs@KT}88Qe>aAzpp(zjBDt^oHe#s0UeIDR zb^Ghes&2ft{nrlB`ro;#{$IAx`Ok|58CVz^DxaK627Sh=tu|eE9ZvTwRCnR}KP&ow zsluxnfSD9vNdg1#4)ajDsO_m`q@hJ@&tHogoz>y&JRm8~P>gkXb-IKP&1omnaxSl0 ze0sS^nZv0Vf-2O`s|? "success", "content" => $content); + echo json_encode($result); + } else { + echo '{"status":"error","message":"Missing Parameter"}'; + } + break; + + default: + echo '{"status":"error","message":"No Type"}'; + break; + } + + + function getWorkspacePath($path) { + if (strpos($path, "/") === 0) { + //Unix absolute path + return $path; + } + if (strpos($path, ":/") !== false) { + //Windows absolute path + return $path; + } + if (strpos($path, ":\\") !== false) { + //Windows absolute path + return $path; + } + return WORKSPACE . "/" . $path; + } +?> \ No newline at end of file diff --git a/plugins/Codiad-DragDrop-master/dialog.php b/plugins/Codiad-DragDrop-master/dialog.php new file mode 100755 index 0000000..ce6a897 --- /dev/null +++ b/plugins/Codiad-DragDrop-master/dialog.php @@ -0,0 +1,20 @@ + +
    + +
    + + + + + +
    + Enable drag'n'drop to insert or append file content in active file + + +
    +
    \ No newline at end of file diff --git a/plugins/Codiad-DragDrop-master/init.js b/plugins/Codiad-DragDrop-master/init.js new file mode 100755 index 0000000..9185e01 --- /dev/null +++ b/plugins/Codiad-DragDrop-master/init.js @@ -0,0 +1,320 @@ +/* + * Copyright (c) Codiad & Andr3as, distributed + * as-is and without warranty under the MIT License. + * See http://opensource.org/licenses/MIT for more information. + * This information must remain intact. + */ + +(function(global, $){ + + var codiad = global.codiad, + scripts = document.getElementsByTagName('script'), + path = scripts[scripts.length-1].src.split('?')[0], + curpath = path.split('/').slice(0, -1).join('/')+'/', + instance = null; + + $(function() { + codiad.Drag.init(); + }); + + codiad.Drag = { + + path: curpath, + files: [], + template: "", + + init: function() { + var _this = this; + instance = this; + var fn = function(){ + //Drag + $('#file-manager a:not(#project-root)').draggable({ + opacity: 0.85, + revert: true, + start: _this.start, + stop: _this.stop, + zIndex: 100 + }); + //Drop + $('.directory').droppable({ + accept : "#file-manager a:not(#project-root)", + drop : _this.drop, + over : _this.over, + out : _this.out + }); + }; + amplify.subscribe('filemanager.onIndex', function(obj){ + setTimeout(fn, 250); + setTimeout(function(){ + //Reopen closed files + $.each(instance.files, function(i, item){ + codiad.filemanager.openFile(item, false); + }); + instance.files = []; + }, 250); + }); + amplify.subscribe('filemanager.onCreate', function(obj){ + setTimeout(fn, 250); + }); + amplify.subscribe('filemanager.onPaste', function(obj){ + setTimeout(fn, 250); + }); + amplify.subscribe('filemanager.onUpload', function(obj){ + setTimeout(fn, 250); + }); + //File drop + var apply = function() { + $('#file-manager').append(_this.template); + $('#drag_append').droppable({ + accept : "#file-manager a.file", + drop : _this.appendDrop, + over : _this.over, + out : _this.out + }); + $('#drag_insert').droppable({ + accept : "#file-manager a.file", + drop : _this.insertDrop, + over : _this.over, + out : _this.out + }); + }; + $.get(this.path + 'template.html', function(html){ + _this.template = html; + apply(); + }); + amplify.subscribe('filemanager.onIndex', function(obj){ + if (obj.path == $('#project-root').attr('data-path')) { + setTimeout(function(){ + apply(); + }, 100); + } + }); + }, + + ////////////////////////////////////////////////////////// + // + // Start dragging + // + ////////////////////////////////////////////////////////// + start: function() { + if (codiad.editor.getActive() !== null && instance.__editEnabled()) { + $('#dragdrop').show(); + } + }, + + ////////////////////////////////////////////////////////// + // + // Stop dragging + // + ////////////////////////////////////////////////////////// + stop: function() { + $('#dragdrop').hide(); + $('#dragdrop .drop_over').removeClass('drop_over'); + }, + + ////////////////////////////////////////////////////////// + // + // Drop item + // + // Parameters: + // + // event - {Event} - Check for more details + // ui - {Object} - http://api.jqueryui.com/droppable/ + // + ////////////////////////////////////////////////////////// + drop: function(event, ui) { + var dest = $(this).attr('data-path'); + var source = $(ui.draggable).attr('data-path'); + var target = dest + instance.getName(source); + //Close file(s) if open and save it/them for reopening + if (instance.isDir(ui.draggable)) { + $.each(codiad.active.sessions, function(i, item){ + if (instance.startsWith(i,source)) { + codiad.active.save(i); + codiad.active.close(i); + instance.files.push(i.replace(source, target)); + } + }); + } else { + if (codiad.active.isOpen(source)) { + codiad.active.save(source); + codiad.active.close(source); + instance.files.push(target); + } + } + instance.move(source, dest, ui.draggable); + instance.out(); + }, + + ////////////////////////////////////////////////////////// + // + // Item over + // + // Parameters: + // + // event - {Event} - Check for more details + // ui - {Object} - http://api.jqueryui.com/droppable/ + // + ////////////////////////////////////////////////////////// + over: function(event, ui) { + $(this).addClass('drop_over'); + }, + + ////////////////////////////////////////////////////////// + // + // Item out + // + // Parameters: + // + // event - {Event} - Check for more details + // ui - {Object} - http://api.jqueryui.com/droppable/ + // + ////////////////////////////////////////////////////////// + out: function(event, ui) { + $(this).removeClass('drop_over'); + }, + + ////////////////////////////////////////////////////////// + // + // Move item + // + // Parameters: + // + // source - {String} - Dropping item path + // dest - {String} - Dropping zone path + // element - {jQuery} - Dropped item + // + ////////////////////////////////////////////////////////// + move: function(source, dest, element) { + $.getJSON(this.path+"controller.php?action=move&source="+source+"&dest="+dest, function(json){ + codiad.message[json.status](json.message); + if (json.status == "success") { + element.context.parentElement.remove(); + codiad.filemanager.rescan(codiad.project.getCurrent()); + } + }); + }, + + ////////////////////////////////////////////////////////// + // + // Is file or directory + // + // Parameters: + // + // element - {jQuery} - Item + // + ////////////////////////////////////////////////////////// + isDir: function(element) { + if ($(element).hasClass('directory')) { + return true; + } else { + return false; + } + }, + + ////////////////////////////////////////////////////////// + // + // Get name + // + // Parameters: + // + // path - {String} - File path + // + ////////////////////////////////////////////////////////// + getName: function(path) { + return path.substring(path.lastIndexOf("/")); + }, + + ////////////////////////////////////////////////////////// + // + // Starts string with something + // + // Parameters: + // + // string - {String} - String to search in + // needle - {String} - Needle to search for + // + ////////////////////////////////////////////////////////// + startsWith: function(string, needle) { + if (string.indexOf(needle) === 0) { + return true; + } else { + return false; + } + }, + + ////////////////////////////////////////////////////////// + // + // Drop item to append it to current file + // + // Parameters: + // + // event - {Event} - Check for more details + // ui - {Object} - http://api.jqueryui.com/droppable/ + // + ////////////////////////////////////////////////////////// + appendDrop: function(event, ui) { + var path = $(ui.draggable).attr('data-path'); + instance.__edit(path, "append"); + }, + + ////////////////////////////////////////////////////////// + // + // Drop item to insert it + // + // Parameters: + // + // event - {Event} - Check for more details + // ui - {Object} - http://api.jqueryui.com/droppable/ + // + ////////////////////////////////////////////////////////// + insertDrop: function(event, ui) { + var path = $(ui.draggable).attr('data-path'); + instance.__edit(path, "insert"); + }, + + ////////////////////////////////////////////////////////// + // + // Load content of dropped file and insert it + // + // Parameters: + // + // path - {String} - Path of dropped file + // type - {String} - Type of action: insert or append content + // + ////////////////////////////////////////////////////////// + __edit: function(path, type) { + $.getJSON(instance.path + 'controller.php?action=getContent&path=' + path, function(result){ + if (result.status == "success") { + var active = codiad.editor.getActive(); + if (active === null) { + codiad.message.error("No Open Files"); + return false; + } + if (type == "append") { + active.navigateFileEnd(); + } + active.insert(result.content); + codiad.message.success("Content " + type + "ed"); + } else { + codiad.message.error(result.message); + } + }); + }, + + ////////////////////////////////////////////////////////// + // + // Wheater dragging to insert file content is enabled or not + // + ////////////////////////////////////////////////////////// + __editEnabled: function() { + var setting = localStorage.getItem('codiad.plugin.drag.insert'); + if (setting === null) { + return false; + } else if (setting === "true") { + return true; + } + return false; + } + }; +})(this, jQuery); \ No newline at end of file diff --git a/plugins/Codiad-DragDrop-master/plugin.json b/plugins/Codiad-DragDrop-master/plugin.json new file mode 100755 index 0000000..0fe087b --- /dev/null +++ b/plugins/Codiad-DragDrop-master/plugin.json @@ -0,0 +1,10 @@ +[{ "author" : "Andr3as", + "version": "0.3.0", + "name" : "DragDrop", + "url" : "https://github.com/Andr3as/Codiad-DragDrop", + "config": [{ + "file": "dialog.php", + "icon": "icon-magnet", + "title": "DragDrop" + }] +}] \ No newline at end of file diff --git a/plugins/Codiad-DragDrop-master/screen.css b/plugins/Codiad-DragDrop-master/screen.css new file mode 100755 index 0000000..4e1c651 --- /dev/null +++ b/plugins/Codiad-DragDrop-master/screen.css @@ -0,0 +1,33 @@ +#dragdrop { + box-shadow: 0 0 5px 5px #111; + display: none; + float: left; + margin-top: 10px; + margin-bottom: 20px; + width: 100%; +} + +#dragdrop div { + background-color: rgb(40,40,40); + background-color: rgba(40,40,40,0.25); + float: left; + width: 50%; +} + +#dragdrop #drag_append { + border-right: 2px solid black; +} + +#dragdrop label { + margin: 10px; + padding: 0; + text-align: center; +} + +.ui-draggable-dragging { + min-width: 0 !important; +} + +.drop_over { + background-color: #333333 !important; +} \ No newline at end of file diff --git a/plugins/Codiad-DragDrop-master/template.html b/plugins/Codiad-DragDrop-master/template.html new file mode 100755 index 0000000..661e751 --- /dev/null +++ b/plugins/Codiad-DragDrop-master/template.html @@ -0,0 +1,8 @@ +
    +
    + +
    +
    + +
    +
    \ No newline at end of file