active_scaffold_sortable 3.6.1 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +267 -0
- data/app/views/active_scaffold_overrides/_form_association.html.erb +1 -1
- data/frontends/default/active_scaffold_overrides/_list.html.erb +1 -1
- data/lib/active_scaffold/config/sortable.rb +5 -5
- data/lib/active_scaffold_sortable/version.rb +2 -2
- data/lib/active_scaffold_sortable.rb +1 -0
- data/test/attribute_params_test.rb +69 -0
- data/test/auto_models_controller_test.rb +51 -42
- data/test/config_test.rb +44 -37
- data/test/controllers/ancestry_models_controller.rb +8 -0
- data/test/controllers/auto_models_controller.rb +2 -0
- data/test/controllers/models_controller.rb +2 -0
- data/test/controllers/nested_set_models_controller.rb +5 -0
- data/test/controllers/sortable_models_controller.rb +2 -0
- data/test/dummy/app/assets/config/manifest.js +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/-0/-01A5W7YK9kU3BAS800iZYKE1Jjr-mMTZS7fQ87Rx9Y.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/-2/-2oLK5aS0W7YRh6DWw7gleUOPUgPQHe3WA-XlTeeQ6I.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/-3/-3JSgLkvqrbXhc6cV7vAvXuo40s6t9QfDEvko0kGqHY.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/-5/-5b8vqL4AFE9S1wXk_ZysEvjY3K9KSkap5rhGfqbAns.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/-D/-DnuHI88d2RugNRU74FFqmOIb9ctTsdUQh0DlMENCyo.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/-x/-xveB5ZfM-eQ6NKFAdea3lFoN1vnudJ5LvZSRuzKQ_A.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/0B/0BKtmzv1AlH_D8ePKCo6cK758902Yb9LuqMKD1YYRCI.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/0R/0RBP8nKamBasZw5QxqMbxS-0qm_HmB-IrbHuLY5EkAE.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/0o/0oBXAn_gNl9ci2FebzcrXp5muYP0gkwyuICM_2XgZSM.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/1G/1GbJS0MAW1RcmPPFOzvRIWmCWnuRzHFpzYtbrSf9kn0.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/1e/1epYXgb89BkEMcjSsF8ZneNxpnJd7CwQYPoeukBAUPk.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/24/24C1vwwkvwnqO43YwbPnrtooBEgS2hzFxyGb5UIQ_z8.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/2F/2FFeltlt3UB92gSStDW3dCExS323nvlf8jnLx0AQT7U.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/2T/2TEBf82sw5GOia5tXBuC6_qcelFGyl_BiMd5t2mRo3I.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/2X/2XvO4DdiQnv9iimEOceo5KSLzXyIpsH9zJPy0-G-mWw.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/2e/2ejWr7IoRaAvGd2C8f9UZYwIeAFYcrQo97m9SM5XvG0.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/2s/2sGAQ3lUIHy362ttHb99ML7tixBpnZ0gAE_1gjC5QNc.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/38/38pY3RTKFmdKPW92BesHrVZZ5hOgBN2ZOMpg8Pfeq8o.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/3V/3VQHyC_HOI6vTzyOFRqKgqBaibU0LvqY-vHrz2VsLe4.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/4T/4TPtaEh2eMInSYN2oh7Pc5iDR4qR41inNfWu2Z3-4d4.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/4Y/4Yd3Q4u1iCSnYLn28-EcjXomhSB9VJvBrsDuT5feMgE.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/4c/4cYrHjoGTnsvI5Bxiol1DP1Cl17-8kMS0cA9d8QVvl4.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/4c/4cx0kSMnteO1fMuTu1ldK4SK3T4qBMmFqHpYBEJIl1M.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/5F/5FPfSxfXAzfMqbv9MYp_oPqDqCp5Ti42XqV96raVNmY.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/5R/5RmcFexTZX4RML0m9HNAEogOkz6kAUnL1XAycQBQF68.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/5d/5d7byxXxH0tYfzrL1xmvvOK3IWGWYmbIGYVFfFaE9dY.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/5g/5g89-0a4fx7-hBM92_O2WNgdJMrUC5NJEbpBvAleVWU.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/63/633hFkOuEJb_oUSK8cX03s1n2fLSTEb5NdC4cDIwpwA.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/6j/6jKoXrSpfNRDsyNX4Zt6bH298l8LflVJ8bYAKsaHzzE.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/6v/6v3hLMm6-Nd9GuMM_2saYxwsHtPGQIbkupZG2vvqa-c.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/7P/7PY1-QqnAkLe9n-nRR-vrU2Fzd5MdehED9jP8erf8eo.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/7a/7a8xYHOtPE4wTHEMmm6noe1konW7gY0PUSm0IBNTMtI.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/7d/7d4afpWdI5JNwQ5cItnECrWVgm4tCn8n0JvJTD4T3qs.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/8A/8Awct50GB7qO_BjbGb7z6tLppN4-Zkvgw2MOYqw6YZM.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/8G/8GByrSoo2FlXP9v-YtRr3mXAlELF8VORWoHShm6nDdA.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/8c/8c1AnZluzIU5mA6hxvyQIdoKGWB_gGzUtUbmAL-EMi4.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/8v/8vSTgcVfo7zRgOO9tDN887A2SISF1N6LaLE0SwEienU.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/9V/9VuN8VYKTVYvAFQ8Og_aBqpRpiGxuy0Et3roDr_okqk.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/BG/BGKeBGsHVMizN9unVFE6OuxZYBGKG1t6r-cH4MYW3LQ.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/BQ/BQStLknXZiiwpMoPe6YrBxnBD-1wDEEN8k1mYrJ3Uxw.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/BW/BWochnvJlhWYZdwSmq6mz-jEixAT70nDd-v2kKu9vqw.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/C-/C-7R1F-IclQa7n3Hd4qJnLbBAU5Pcu7LxaVCrdCpGm0.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/CK/CKhIMyvEb6CDyLEFjVWINYFKmLJ4PP4loyBb9TSRuMY.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/CP/CPRlIspialBD_8QWdu_BfuiA-0NiaCIAIjENtD1GTVM.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/CV/CV9H0CtTQ90oOjk85ymAap-0weDW8crx2mv9iWwADxs.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Cs/CsQ51viK_aIp-m7ZlSFOnb4sFWpBNWaZblmvpPZAPZM.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/D6/D6Qu6xXoQxwWWu9I8MH06EV_ZCDIdkd1C30t_qGVDNI.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/DN/DNjqY8NAzkt9P2e6Y6nhm_lDGdHAmeYStAwysDr_XI8.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Dv/DvsUO7WNA9YxClJwRzWSEzvC1WbUiIqoELa81jklXnU.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Fa/Fams27IUjgGgDYh4ZebQLOL2ZVlyXeObh0zGm7L7itY.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Fd/FdwcZofVKxaRa1PHEqgrVNOb_NfhW7AkOaQr8Jpd8F8.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Fi/Fix6os7onITNYUoeQXZIZ9ipaPXY8qveVp544iQ2pu0.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Fo/Foxj9g0CYVowTIQC5l3ont29y6kzyjq1tCto_XmD1Y8.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Gm/Gmx2uSucvix2U85bFcJwdUiK4W0_l0ktmUpZYH0kuh8.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/H5/H5jANW5FBiru_dQ2zHyOLCXrUutOhHWVccsPOlHjPlw.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/I8/I8Di5A_iVdMQnWl8i0jR1EDPY-zGKXRsX6FrHOUKY_k.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/IG/IGLiMvn8Ia3obsUVYlf5H2Pc4hMVBXoHVrCh_BbHeos.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/IU/IU3Vj0C_4HJivemzxbufqxLy3uOizcW6mjksAApYonI.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/IV/IVzbuuk4Y8uceJaYEi3eHzZ3L3-X9_RyiKuV2mjuq14.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Im/ImYjTVLdbIdhT9HmAR5592TGiS6do4CU5aTM57NDtF8.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Jo/Joc7W-HUxa_SCuMY1ji3Tb_anGXmH8dXBLEIl7y3qQY.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Kp/Kp1mrZLRWB7EWOtPVpLqGWKv-kIAAM_cHpkoYEASq0k.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Kp/KpOG7KGgj5QGIvXgdmmMNmNLcDzUNj0-HRArprvTc2M.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Kr/KrnWYZN30K4B7kS4tYoFPc2uvUXN4wq4R-zg1s8Pte8.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/LB/LBAH0XPkrk6feDLGh6rjc-oRVjDHWf09jT2s1OF0DGk.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/LK/LKdhU8uwD92K_SdC7Tg_nnk32QEeIHGK5PnSSsQB1GU.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/LX/LXRQyuA2BiXpXNe-2PIOPP_gfu2J9r8ECfinQWs5Pn4.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Lt/LtK_Npm-kOHPrwrpfOkzvivUSMv9C35TO8kccAJFAoE.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/M-/M-zp45dW9TWoC7zAUn3L2BwKG2a6gagSXpG8nSyMg8g.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Mv/MvW2Dl5BoobN-SWNyCaxMP47Ihyd8e8UCEcYVeDkEr4.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Mw/MwZE2PNpy_0-Qa3_iv7j25MuGl-1OZUO2XkDoomSyQc.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/NP/NPs6FRY1WbljwZoGarj2bqozBfutuaWBe3nVfrQ2A-k.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/O7/O7ygnT4NqWCR5SU1qTty3j0909VVtEN7SqVI3exJ1Fs.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Oj/OjnYwM2pcnX18Fnj3AKBYJslH-_oI-eJFr1jKF_bec0.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Om/OmD88cOkZnce7jiIW_uKN5UzecfSk7LPBHUWdr9nuaY.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/P1/P1RCU1-eTX730fxykGCghfCTNXe74fdWitwW7p0lux0.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/P5/P5ifL2bLkG9zc7oNXwYKCzsAZLzKY_bHqBAQf64TnFo.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/PB/PBNeP5ORDO5a3Tn1n5hEA4OS0JTbGgGuyupEljHYK-Q.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/PJ/PJDpkmr3C8KVM9BqbaUPLH4L5f0xWtRDo3wc4vuvtTw.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Pa/Paylg2dvY4FEVeol8QRGXmnlmSxW9iAhrhu8WUIH_2E.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Pc/Pcgbo3Rysr6BlArqxHR4qLirVHsynsi_FRV-fndn8Hg.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Q1/Q1opUEyDInXXYe5UDccDz438AyblZ0oiavmzG2BDFJc.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Q7/Q7La6t5hz_qGvKi59nbxxnhObRb0nHwdofHEDbNLYGI.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Qh/Qhnmild8NLF6AJmiUOCxEq6l4V9WDM46gt3iKNUpfGE.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Ra/Ra8PGm0CtdBdRARR5KsiT2Iv-P3wZNe55vCNqu4qdM8.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Rx/RxmsaxLeIQ5xwIZ14vz5ehoc_6TjP5Rpa3CRny4tWG8.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/SA/SA8b2a-PX1nDgzdCcJaBTW8Y2qQfBeKvrsNd2FHV9kk.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/SO/SOAX-5LQ2QKMVKgYM3-vLvqxZEFV7aXqi6T0nHK8JdE.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/SS/SSg5bDqJBLv8UDn6NjSt-28FTDnXrmr4lm3-qD-gzlg.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Sb/Sb2EeQPQyWe0nb2aId-BRi76gdNMbx-_b7oDXu_--3I.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Sh/ShqS7p9Dz8B0KnsOEeur1lGGb96LoW2Tufapu6vRYQQ.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Sn/SngbFvFTz9jtho3VfcDRkhi5KvV5mNXHtZ3faRj0mq0.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/TJ/TJXSOh8D6dsgfhXh7KlzynHOrYwXy9yi0YKdvZlwS2M.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/TR/TRWPFjvokQ5AmFcLYZk5OlgmDulZ1HeMWnwASg_0tDA.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/UZ/UZkjDOYpoE1pwHlkI402W8lj58qyM9pbBo0Jmqwnh_M.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Ut/UtUl8dEEP8OUFS138GTWLf8TE8FhJYK5c1vaXAmRM_E.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/VR/VRDKUY6-sXjrwpqcbxGHgP9_ONi3gwEVncUA1uzJPV8.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Wl/WlFfd39WfPdb8ecb3P-6msbwc6U1rpZ67MkPGvuwwPI.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Wl/WlNGLojqnKVWTZGT6xG9pS4_52XBnkQaDrxPeLOjfG0.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Wo/Wo7IjVQE59FU0N57DfY8aS_EhOHYTevXt2w-A6GG1OE.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Wp/Wp_HHYHjzz0iw5PQ3uWhju_JwBeuUmjrFE-w9P7TiJI.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Wt/WtsclIiibz_nWtYI4bN1ogz2DouCxLxRhZ4To_veN6c.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/X6/X6rI-YDY0BKCdMA_eQAK3u_bZOrZxe7wtn_t4wjcyGM.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Y2/Y2GMeqGBGgWrYZmI2sZO62LNEPoBGJ1bF9nRF5tHo30.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/YL/YLRMkD5PzC_acvA63jrF8Q_ImDPecqclwDlUHfU6tFk.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/YQ/YQfKqw0LUSliN1R029iBJ-Q5rvPflUcQMcBaQUy9tHI.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/YY/YYt9duEQUzPtfzFEbyThgE8axhVDyynnMHRsJ7ivmfU.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Yb/Yb6WF-FKlg7AX5I1fBtUVFJwGZ9lZng-WBXOWcNKBFI.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Yb/YbSqwPYrjO2_pDN9Gar6NmrSu9uPMQVK6bOg9t6rLQE.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/ZD/ZDax1kp2GkGUgRyO0nM0Rrg_AqtpocNI69dbDijDz-o.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/Z_/Z_J_urKomTrgc54gT_yMF77dy5dvTc4o8tP9xBT0Ei4.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/_9/_96XOgK4uLAgBpmlNxMhvpSKR0RACQPa7b8Zs7JvFhM.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/_e/_eGqFuynzxHdBcyQcb39R3gIpkw8pJHIpIb2d3y4Wgw.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/_k/_khcJKAEuVGqYQyMhPgrorWWBci3uioHdU_rRWHor5U.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/aW/aWhzKkJzJA3zSzcyHgvAH6gY0wtH9AvCwrPfGn0yinQ.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/bf/bfvmq2y8rZqB0uY7rAOUlBowZqo6ufc_5nfG1LYwzBA.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/bw/bwhovo7do9KWTEDh74VaX0SkTZ9rVlapdjDGGsOkYoA.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/dA/dAk68mPJqLTk4teOIIYt_aLVM14EOuIxA9fCCeBrKFE.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/df/df1Eyp3Nlhb2MpTqIOUTNLPF3zLZm8glepkhoAgalaU.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/eH/eHywcNwiONssCBDpivCVg95qXNqh3DG7IW-Gn09y_WI.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/eW/eWSTSytTG9nrCXUXlFyNTT2SnQNavB-7ZHbQJdzRW78.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/ea/eaG88T0kV6x-aQgXngib2_5TkPRHcQUsNeRwyBFvTxw.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/fR/fROdNnXbOkrkCX0VjA67bx-85BNOcWA-pr9oNeTX-6U.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/fZ/fZszKxkZvRa-5uIuGwojHFzFDfTBdaghYq0YuSDd0fg.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/h2/h2jllO4xPhzz7DDl4giyfC-M-KE2kBHbFjbKneUaH0s.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/hG/hGOgAdR_N4noGNRRx25KqnZDGCE4OtVHqBvMAxHqVCI.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/iA/iA5sBAvo4LBx2bolG45IV3j3VAir_HgEFaYJSU1CsuI.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/kA/kAE78w1XBkLkUmFIMRQaeSzbVb4I5djjXPgd9rVMQak.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/kS/kS3sp7MRq8LQbBTY9WRRMfWcKyqYZG0V9KSs9JlIDPI.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/ka/ka1yaE-uG5A54kvAVKscIBd4DGwDGOnLpCk6EV4NeK8.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/kj/kjHBBL52Qb2LGmXskl7pye9EKuqYX23L_DKk5H-jTCY.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/kt/ktYvvoV5OLXgOJ-0uUmNrJzScE6jrUD1r0VeS7rToRI.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/kw/kwcepSV0CIKivTUVXF3xfeIHW4sLfQta700qqhtx-PA.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/lk/lkd5ZZsrE9KoB6uUBMiHYDIf7nUofIZ0zUzTQhw3q5M.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/m5/m5zl3ZQ9497Ws3dcM25-9xPXK7EHZhM8lN_sGgEkDao.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/nN/nNeCvN6msedBHaJP2LDnQQcMItRJFjRBEoNrxJIJsqA.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/nj/njx8yCFK0rUv9-EODcBOR1dqntXG_qErD4GKmlLVP5U.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/o7/o7uGfsn8XAZCoxgv-xvAx64lNhXKqHROrnQ0eM67ShI.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/oi/oiR9kx7NN7FtqW4tuxAqKuMbTzntnD4h4vtvnEzHJJs.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/om/om6KTDfdJHGdhoscNLPYOkzi9bALNxlUp7Ax_uVS3LY.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/op/opp4OeslOryoI1PDbzk_OMlXuQGqNjp5R-BoWFPinqk.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/ox/oxrsONd2_TIlLWaYwbrbwvAoFIr4XYacRKStijLPMhs.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/pC/pCI6lsX8vSY57jAP9xHgpaaxzxIv1qwGBtNzxfbtWL0.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/pD/pDRTkMgfNorje-QH5KBHWyIJr4V7Kk0cektjtCKzsHQ.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/pS/pStecU0QLgBBJhrlftzFIOIny1_1eJQ1wb006wR6hHI.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/pc/pcZ1fITskNzguH0ctYLXa_J-6KYGEwEZim8Zi7HHWuw.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/qC/qCk8n9E10BaN-4MSbOGm-aOocRuvKbUwnEzFSOEnyMk.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/qF/qF4Jxo_QusqFxZlTUufstoSMqM8BwxOeBYeeaUlMQMM.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/rN/rN0TBip7LVkikWIt7pr5pXpebCMu-Vszwr3JtNl85Rg.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/re/reY88CfGWWiGlDTj_aT-R1IQ4HwtgJ8M4x2QSZi3g1k.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/rf/rf9yIxeJnjcgy1j_Z0ZaBP5o1fRWnI4s6RKqXtXnfNY.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/s4/s4H_e7Jtc3bYP6_jcDC1djtCN0zmdIjgfCjszHdyYSU.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/sb/sbZBtfS1lz5ysnVhxOHQ3uQx2vuw0Dml_N69G5SnVSg.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/tM/tMjri0obeX3cWblgB5ANaxvz2r1Un5w-kdAgV2mnBUw.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/tR/tR4pe9KUkOD0dXQr0Rmz49lhvtLaTX2Va99AozZ-_tk.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/tR/tRmf4Ta_ZHZRBt4KuyLVmN-3QgPG4aCqy3nqmLrjTlE.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/u-/u-1XahJaVW5YYTRugzlxdg6JhZoVk2UMhLaJF3O1vg0.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/ub/ubOIJHHBsVau6eMNKfZu9D07kkX2uEsMNChK5vWQoQU.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/uf/ufSwWA73VH7bS7CMeQp_vUlRYsZNh4Hl_SxJORHxBs8.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/vI/vIR0VWobVpWydqbzq29IQ84VRHCYBzdk3YTRh4UbH1w.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/x_/x_AI1EzZWPpRoWC6lFtm6rpp5lycO0l-JeoBiiBsQuU.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/xe/xeBZETuoTTj0K-JS67s72_rtxLpAvc5L731R6Q8CjLw.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/xl/xlv-FINzwAUI9lLqHtM8Ml6TcP0fI1T7_1hASqmh1uw.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/xp/xpBi9YqwkljWG2uwGCwVtJFrzwGTNWjKSg_9YqqxsG0.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/yb/ybfHSoG4-2Xqjkk-hkTD4fAGZIBZWkIyHcBlQjIovJI.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/yk/ykudLIz9khw9ygFAJSj1FFiZFv8gE8hQqykRNB9gLNI.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/yr/yrLtWJQXs4lm9sonGNHNkFRzm8xpmrWQwGZHjIh5qXs.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v4.0.0/z-/z-PkdiKIZoqXSf6edzu84RnR9qQGGL_iD94rf6GSy-0.cache +1 -0
- data/test/models/ancestry_model.rb +16 -0
- data/test/models/auto_model.rb +3 -1
- data/test/models/model.rb +2 -0
- data/test/models/nested_set_model.rb +39 -0
- data/test/router_test.rb +10 -3
- data/test/schema.rb +9 -6
- data/test/test_helper.rb +47 -36
- data/test/tree_models_controller_test.rb +70 -0
- metadata +358 -11
- data/README.textile +0 -76
- /data/app/assets/stylesheets/{active_scaffold_sortable.css.scss → active_scaffold_sortable.scss} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 33121e6e1386e4f3802c52e705127873fae644c4058fbf76de119494c281c8fa
|
|
4
|
+
data.tar.gz: df471b954ff70f91201355d63deebae589be6410ccd2b518391f7b00dabbfad5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 24b658744b23cdec8a02d8312810e9577a8a49aeb5a0456d40e8e6c2d791a032497cf33e82428437383aae37fd4c8ebcea21f8d76096828003169b3920ac22bd
|
|
7
|
+
data.tar.gz: e3da06ae6819c09b945eaa66eb9d74df23802e06a952a96f4b7847156d8b064de66ff576a6ecbf73136a9cd688118b6295fd5e23f74bd1a18b81543f691d3911
|
data/README.md
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
# Drag-and-drop sorting for Active Scaffold
|
|
2
|
+
|
|
3
|
+
`active_scaffold_sortable` adds AJAX drag-and-drop ordering to Active Scaffold
|
|
4
|
+
lists and association subforms.
|
|
5
|
+
|
|
6
|
+
It supports:
|
|
7
|
+
|
|
8
|
+
- ordinary ordered lists, including automatic setup for `acts_as_list` models;
|
|
9
|
+
- sortable `has_many` association subforms;
|
|
10
|
+
- sibling ordering in nested-set trees using the `awesome_nested_set` API;
|
|
11
|
+
- sibling ordering in [Ancestry](https://github.com/stefankroes/ancestry)
|
|
12
|
+
trees;
|
|
13
|
+
- a dedicated drag-handle column, optional list refreshes, and custom DOM
|
|
14
|
+
selectors for non-standard list markup.
|
|
15
|
+
|
|
16
|
+
## Requirements
|
|
17
|
+
|
|
18
|
+
- Ruby 2.0 or newer
|
|
19
|
+
- Active Scaffold 4.4.0 or newer
|
|
20
|
+
- a Rails version supported by the selected Active Scaffold version
|
|
21
|
+
- jQuery UI Sortable on pages that use this plugin
|
|
22
|
+
|
|
23
|
+
For Rails 3 applications, use an `active_scaffold_sortable` 3.2.x release.
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
Add the gem to the application's `Gemfile`:
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
gem "active_scaffold_sortable"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Then run:
|
|
34
|
+
|
|
35
|
+
```console
|
|
36
|
+
bundle install
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The engine registers the Active Scaffold action, route, JavaScript,
|
|
40
|
+
stylesheet, and view overrides automatically.
|
|
41
|
+
|
|
42
|
+
## Ordered lists
|
|
43
|
+
|
|
44
|
+
### With `acts_as_list`
|
|
45
|
+
|
|
46
|
+
Add a position column and configure the model with
|
|
47
|
+
[`acts_as_list`](https://github.com/brendon/acts_as_list):
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
# db/migrate/..._add_position_to_entries.rb
|
|
51
|
+
add_column :entries, :position, :integer
|
|
52
|
+
add_index :entries, :position
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
class Entry < ApplicationRecord
|
|
57
|
+
acts_as_list
|
|
58
|
+
end
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The plugin detects `acts_as_list`, enables the `:sortable` action, and uses
|
|
62
|
+
the model's configured position column. No Active Scaffold controller
|
|
63
|
+
configuration is needed.
|
|
64
|
+
|
|
65
|
+
Scopes configured in `acts_as_list` still define the logical lists. A rendered
|
|
66
|
+
Active Scaffold list should contain records from only one scope so that a drag
|
|
67
|
+
does not mix independent lists.
|
|
68
|
+
|
|
69
|
+
### Without `acts_as_list`
|
|
70
|
+
|
|
71
|
+
Sorting can use any persisted column that accepts one-based integer positions.
|
|
72
|
+
Enable the action and select the column explicitly:
|
|
73
|
+
|
|
74
|
+
```ruby
|
|
75
|
+
class EntriesController < ApplicationController
|
|
76
|
+
active_scaffold :entry do |config|
|
|
77
|
+
config.actions << :sortable
|
|
78
|
+
config.sortable.column = :position
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
On every drop, the visible records receive consecutive values beginning at
|
|
84
|
+
`1`. Updates are made directly with `update_all`, so validations and model
|
|
85
|
+
callbacks do not run. If the table has an `updated_at` column, it is updated.
|
|
86
|
+
The reorder action uses Active Scaffold's update authorization check.
|
|
87
|
+
|
|
88
|
+
## Sortable association subforms
|
|
89
|
+
|
|
90
|
+
A collection association is draggable in a create or update form when the
|
|
91
|
+
associated model's Active Scaffold configuration includes `:sortable`. This
|
|
92
|
+
works whether sorting was enabled automatically by `acts_as_list` or manually:
|
|
93
|
+
|
|
94
|
+
```ruby
|
|
95
|
+
class TasksController < ApplicationController
|
|
96
|
+
active_scaffold :task do |config|
|
|
97
|
+
config.actions << :sortable
|
|
98
|
+
config.sortable.column = :position
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
For example, a `Project` form that renders a `has_many :tasks` subform will
|
|
104
|
+
allow its task rows to be reordered. Dragging updates the hidden position
|
|
105
|
+
fields in the form; the order is persisted when the parent form is submitted,
|
|
106
|
+
not through a separate reorder request. New associated records without a
|
|
107
|
+
position are placed after the highest existing position.
|
|
108
|
+
|
|
109
|
+
The association must be a collection. Singular associations are not sortable.
|
|
110
|
+
The associated scaffold may exclude the `:list` action when sorting is needed
|
|
111
|
+
only in a subform.
|
|
112
|
+
|
|
113
|
+
## Tree models
|
|
114
|
+
|
|
115
|
+
Tree support reorders nodes only among their current siblings. It does not move
|
|
116
|
+
a node to a different parent.
|
|
117
|
+
|
|
118
|
+
### Nested sets (`awesome_nested_set`)
|
|
119
|
+
|
|
120
|
+
Models using
|
|
121
|
+
[`awesome_nested_set`](https://github.com/collectiveidea/awesome_nested_set)
|
|
122
|
+
are detected automatically:
|
|
123
|
+
|
|
124
|
+
```ruby
|
|
125
|
+
class Category < ApplicationRecord
|
|
126
|
+
acts_as_nested_set
|
|
127
|
+
end
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The plugin enables `:sortable`, uses the model's configured left column, and
|
|
131
|
+
calls the nested-set movement methods to preserve valid left and right bounds.
|
|
132
|
+
Root nodes can be reordered as siblings as well.
|
|
133
|
+
|
|
134
|
+
Detection is API-based rather than gem-name-based. A different nested-set
|
|
135
|
+
implementation may work only if it provides the same API used here:
|
|
136
|
+
`nested_set_scope`, `left_column_name`, `self_and_siblings`, `move_left`, and
|
|
137
|
+
`move_right`. `awesome_nested_set` is the intended integration; no other
|
|
138
|
+
nested-set gem is explicitly supported by this project.
|
|
139
|
+
|
|
140
|
+
### Ancestry
|
|
141
|
+
|
|
142
|
+
Ancestry models are recognized during reordering, but they are **not** enabled
|
|
143
|
+
automatically. Add a separate position column and configure sorting manually:
|
|
144
|
+
|
|
145
|
+
```ruby
|
|
146
|
+
class Category < ApplicationRecord
|
|
147
|
+
has_ancestry
|
|
148
|
+
end
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
```ruby
|
|
152
|
+
class CategoriesController < ApplicationController
|
|
153
|
+
active_scaffold :category do |config|
|
|
154
|
+
config.actions << :sortable
|
|
155
|
+
config.sortable.column = :position
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
The submitted records are reordered within the first record's sibling set.
|
|
161
|
+
Both root nodes and children are supported. The `ancestry` column itself is a
|
|
162
|
+
path, not a sibling position, and should not be configured as the sortable
|
|
163
|
+
column.
|
|
164
|
+
|
|
165
|
+
## Configuration
|
|
166
|
+
|
|
167
|
+
### Drag handle
|
|
168
|
+
|
|
169
|
+
By default, the whole row is the drag handle. Add a dedicated handle column at
|
|
170
|
+
the beginning or end of the list with:
|
|
171
|
+
|
|
172
|
+
```ruby
|
|
173
|
+
config.sortable.add_handle_column = :first
|
|
174
|
+
# or
|
|
175
|
+
config.sortable.add_handle_column = :last
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Only `:first`, `:last`, and `false`/`nil` are accepted.
|
|
179
|
+
|
|
180
|
+
### Refresh after reordering
|
|
181
|
+
|
|
182
|
+
The default response only reapplies alternating row styles. Refresh the entire
|
|
183
|
+
Active Scaffold list after each reorder when other displayed values depend on
|
|
184
|
+
the order:
|
|
185
|
+
|
|
186
|
+
```ruby
|
|
187
|
+
config.sortable.refresh_list = true
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Advanced DOM options
|
|
191
|
+
|
|
192
|
+
`config.sortable.options` is merged into the sortable container's `data-*`
|
|
193
|
+
attributes. Supported overrides include:
|
|
194
|
+
|
|
195
|
+
```ruby
|
|
196
|
+
config.sortable.options = {
|
|
197
|
+
tag: "> tr", # selector for draggable items
|
|
198
|
+
handle: ".my-drag-handle", # selector that starts dragging
|
|
199
|
+
content_selector: ".my-records", # sortable content within the container
|
|
200
|
+
key: "as_entries-tbody", # serialized request parameter base
|
|
201
|
+
format: "^[^_-].*-(.*)-row$", # extracts the record ID from a row ID
|
|
202
|
+
with: "scope_id=42" # extra reorder request parameters
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
These are integration hooks for custom Active Scaffold markup. They are not a
|
|
207
|
+
general pass-through for every jQuery UI Sortable option. When overriding
|
|
208
|
+
`key`, keep it aligned with the parameter name expected by the reorder action.
|
|
209
|
+
|
|
210
|
+
The same settings can be used as defaults for every sortable scaffold. Set
|
|
211
|
+
them in an initializer before Active Scaffold configurations are built:
|
|
212
|
+
|
|
213
|
+
```ruby
|
|
214
|
+
ActiveScaffold::Config::Sortable.add_handle_column = :first
|
|
215
|
+
ActiveScaffold::Config::Sortable.refresh_list = true
|
|
216
|
+
ActiveScaffold::Config::Sortable.options = { handle: ".my-drag-handle" }
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### UI adapter support
|
|
220
|
+
|
|
221
|
+
Sortable list and association-subform wrappers expose the
|
|
222
|
+
`sortable_container` UI element. UI framework adapters can add or replace its
|
|
223
|
+
HTML attributes without overriding either partial:
|
|
224
|
+
|
|
225
|
+
```ruby
|
|
226
|
+
ActiveScaffold.add_element_attributes :sortable_container,
|
|
227
|
+
class: "overflow-auto"
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
The plugin keeps the `sortable-container` class and `data-*` attributes used
|
|
231
|
+
by its JavaScript and merges them with attributes supplied by the adapter.
|
|
232
|
+
|
|
233
|
+
## Effects on the Active Scaffold list
|
|
234
|
+
|
|
235
|
+
Enabling `:sortable` also:
|
|
236
|
+
|
|
237
|
+
- disables pagination so all draggable records are present in one list;
|
|
238
|
+
- orders the list ascending by the sortable column;
|
|
239
|
+
- disables sorting by other columns;
|
|
240
|
+
- hides the sortable column from normal action columns and configures its form
|
|
241
|
+
UI as hidden so subforms can carry positions without displaying the column.
|
|
242
|
+
|
|
243
|
+
Because the browser submits only rendered rows, filters and nested views update
|
|
244
|
+
only the matching subset. Non-rendered records retain their stored positions,
|
|
245
|
+
which can produce duplicate positions in an ordinary list. Keep each sortable
|
|
246
|
+
view within one logical list or sibling set, and use filtering with care.
|
|
247
|
+
|
|
248
|
+
## Support
|
|
249
|
+
|
|
250
|
+
For help, use the
|
|
251
|
+
[Active Scaffold discussion group](https://groups.google.com/group/activescaffold)
|
|
252
|
+
or [open an issue](https://github.com/activescaffold/active_scaffold_sortable/issues).
|
|
253
|
+
|
|
254
|
+
## Contributing
|
|
255
|
+
|
|
256
|
+
Fork the [repository](https://github.com/activescaffold/active_scaffold_sortable),
|
|
257
|
+
make the change with tests, and open a pull request.
|
|
258
|
+
|
|
259
|
+
## License
|
|
260
|
+
|
|
261
|
+
Released under the [MIT License](LICENSE.txt).
|
|
262
|
+
|
|
263
|
+
## Authors
|
|
264
|
+
|
|
265
|
+
- Tim Harper
|
|
266
|
+
- Sergio Cambra
|
|
267
|
+
- Volker Hochstein
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<% config = active_scaffold_config_for(column.association.klass) %>
|
|
2
2
|
<% if config.actions.include? :sortable %>
|
|
3
|
-
<%=
|
|
3
|
+
<%= as_element :sortable_container, render(:super), class: 'sortable-container', data: sort_params(config).merge(tag: "##{sub_form_list_id(association: column.name, id: parent_record.try(:id) || generated_id(parent_record) || 99999999999)} > .sub-form-record") %>
|
|
4
4
|
<% else %>
|
|
5
5
|
<%= render :super %>
|
|
6
6
|
<% end %>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<%=
|
|
1
|
+
<%= as_element :sortable_container, render(:super), class: 'sortable-container', data: sort_params %>
|
|
@@ -17,13 +17,13 @@ module ActiveScaffold::Config
|
|
|
17
17
|
cattr_accessor :plugin_directory
|
|
18
18
|
@@plugin_directory = File.expand_path(__FILE__).match(%{(^.*)/lib/active_scaffold/config/sortable.rb})[1]
|
|
19
19
|
|
|
20
|
-
cattr_accessor :add_handle_column
|
|
20
|
+
cattr_accessor :add_handle_column, instance_accessor: false
|
|
21
21
|
@@add_handle_column = false
|
|
22
22
|
|
|
23
|
-
cattr_accessor :options
|
|
23
|
+
cattr_accessor :options, instance_accessor: false
|
|
24
24
|
@@options = {}
|
|
25
25
|
|
|
26
|
-
cattr_accessor :refresh_list
|
|
26
|
+
cattr_accessor :refresh_list, instance_accessor: false
|
|
27
27
|
|
|
28
28
|
self.crud_type = :update
|
|
29
29
|
|
|
@@ -36,7 +36,7 @@ module ActiveScaffold::Config
|
|
|
36
36
|
@column.form_ui = :hidden
|
|
37
37
|
@column.css_class = 'sortable-handle'
|
|
38
38
|
@column.label = ''
|
|
39
|
-
@column.weight = -2**(0.size * 8 -2)
|
|
39
|
+
@column.weight = -(2**(0.size * 8 - 2))
|
|
40
40
|
end
|
|
41
41
|
@column
|
|
42
42
|
end
|
|
@@ -50,7 +50,7 @@ module ActiveScaffold::Config
|
|
|
50
50
|
raise(ArgumentError, "Unknown handle column position: #{where}") unless [:first, :last].include?(where)
|
|
51
51
|
@options[:handle] = 'td.sortable-handle'
|
|
52
52
|
define_handle_column
|
|
53
|
-
@column.weight = 2**(0.size * 8 -2) -1 unless where == :first
|
|
53
|
+
@column.weight = (2**(0.size * 8 - 2)) - 1 unless where == :first
|
|
54
54
|
if @core.actions.include? :list
|
|
55
55
|
if where == :first
|
|
56
56
|
@core.list.columns = [:active_scaffold_sortable] + @core.list.columns.to_a unless @core.list.columns.include? :active_scaffold_sortable
|
|
@@ -22,5 +22,6 @@ module ActiveScaffold
|
|
|
22
22
|
ActiveScaffold.autoload_subdir('helpers', self, File.dirname(__FILE__))
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
|
+
ActiveScaffold.set_element_tag(:sortable_container, :div)
|
|
25
26
|
ActiveScaffold.stylesheets << 'active_scaffold_sortable'
|
|
26
27
|
ActiveScaffold.javascripts << 'active_scaffold_sortable'
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class AttributeParamsTest < Minitest::Test
|
|
6
|
+
Record = Struct.new(:position)
|
|
7
|
+
AssociationConfig = Struct.new(:actions, :sortable)
|
|
8
|
+
SortableConfig = Struct.new(:column)
|
|
9
|
+
ColumnConfig = Struct.new(:name)
|
|
10
|
+
Reflection = Struct.new(:name) do
|
|
11
|
+
def collection?
|
|
12
|
+
true
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
FormColumn = Struct.new(:association)
|
|
16
|
+
|
|
17
|
+
class Parent
|
|
18
|
+
attr_reader :target
|
|
19
|
+
|
|
20
|
+
def association(_name)
|
|
21
|
+
self
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def target=(records)
|
|
25
|
+
@target = records
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class BaseUpdater
|
|
30
|
+
attr_accessor :submitted_records
|
|
31
|
+
|
|
32
|
+
def update_column_from_params(*)
|
|
33
|
+
submitted_records
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class Updater < BaseUpdater
|
|
38
|
+
prepend ActiveScaffoldSortable::AttributeParams
|
|
39
|
+
|
|
40
|
+
attr_accessor :associated_config
|
|
41
|
+
|
|
42
|
+
def active_scaffold_config_for(_klass)
|
|
43
|
+
associated_config
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def test_assigns_missing_subform_positions_and_sorts_the_target
|
|
48
|
+
updater = Updater.new
|
|
49
|
+
records = [Record.new(2), Record.new(nil), Record.new(1)]
|
|
50
|
+
updater.submitted_records = records
|
|
51
|
+
updater.associated_config = AssociationConfig.new(
|
|
52
|
+
[:sortable],
|
|
53
|
+
SortableConfig.new(ColumnConfig.new(:position))
|
|
54
|
+
)
|
|
55
|
+
reflection = Reflection.new(:records)
|
|
56
|
+
reflection.define_singleton_method(:klass) { Record }
|
|
57
|
+
parent = Parent.new
|
|
58
|
+
|
|
59
|
+
result = updater.update_column_from_params(
|
|
60
|
+
parent,
|
|
61
|
+
FormColumn.new(reflection),
|
|
62
|
+
:records
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
assert_same records, result
|
|
66
|
+
assert_equal [2, 3, 1], records.map(&:position)
|
|
67
|
+
assert_equal [1, 2, 3], parent.target.map(&:position)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -1,52 +1,61 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
2
4
|
|
|
3
5
|
class AutoModelsControllerTest < ActionController::TestCase
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
6
|
+
tests AutoModelsController
|
|
7
|
+
|
|
8
|
+
setup do
|
|
9
|
+
AutoModel.delete_all
|
|
10
|
+
@first = AutoModel.create!(name: "first", position: 1)
|
|
11
|
+
@second = AutoModel.create!(name: "second", position: 2)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
test "reorders records and renders the reorder response" do
|
|
15
|
+
post :reorder,
|
|
16
|
+
params: { "as_auto_models-tbody" => [@second.id, @first.id] },
|
|
17
|
+
xhr: true
|
|
18
|
+
|
|
19
|
+
assert_response :success
|
|
20
|
+
assert_equal 2, @first.reload.position
|
|
21
|
+
assert_equal 1, @second.reload.position
|
|
22
|
+
assert_operator @first.updated_at, :>, @first.created_at
|
|
23
|
+
assert_includes response.body, "ActiveScaffold.stripe('as_auto_models-tbody');"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
test "renders sortable metadata and a row drag handle" do
|
|
27
|
+
get :index
|
|
28
|
+
|
|
29
|
+
assert_response :success
|
|
30
|
+
assert_select ".sortable-container[data-reorder-url='/auto_models/reorder']"
|
|
31
|
+
assert_select ".sortable-container[data-column='position']"
|
|
32
|
+
assert_select ".records tr.record.sortable-handle", count: 2
|
|
19
33
|
end
|
|
20
34
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
35
|
+
test "applies UI adapter attributes to the sortable container" do
|
|
36
|
+
ActiveScaffold.add_element_attributes(:sortable_container, class: "adapter-container")
|
|
37
|
+
|
|
38
|
+
get :index
|
|
39
|
+
|
|
40
|
+
assert_response :success
|
|
41
|
+
assert_select ".sortable-container.adapter-container"
|
|
42
|
+
ensure
|
|
43
|
+
ActiveScaffold.set_element(:sortable_container, tag: :div)
|
|
29
44
|
end
|
|
30
45
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
should "update stripe" do
|
|
38
|
-
assert_match 'ActiveScaffold.stripe(\'as_auto_models-tbody\');', @response.body
|
|
39
|
-
end
|
|
40
|
-
should "update sortable" do
|
|
41
|
-
assert_match @@sortable_regexp, @response.body
|
|
42
|
-
end
|
|
46
|
+
test "keeps sorting active after creating a record" do
|
|
47
|
+
post :create, params: { record: { name: "third", position: 3 } }, xhr: true
|
|
48
|
+
|
|
49
|
+
assert_response :success
|
|
50
|
+
assert_equal 3, AutoModel.count
|
|
51
|
+
assert_includes response.body, "ActiveScaffold.sortable('as_auto_models-tbody');"
|
|
43
52
|
end
|
|
44
53
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
54
|
+
test "keeps sorting active after updating a record" do
|
|
55
|
+
put :update, params: { id: @first.id, record: { name: "updated" } }, xhr: true
|
|
56
|
+
|
|
57
|
+
assert_response :success
|
|
58
|
+
assert_equal "updated", @first.reload.name
|
|
59
|
+
assert_includes response.body, "ActiveScaffold.sortable('as_auto_models-tbody');"
|
|
51
60
|
end
|
|
52
61
|
end
|
data/test/config_test.rb
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
def test_not_enable_sortable
|
|
5
|
-
assert !ModelsController.active_scaffold_config.actions.include?(:sortable)
|
|
6
|
-
end
|
|
3
|
+
require "test_helper"
|
|
7
4
|
|
|
8
|
-
|
|
5
|
+
class ConfigTest < Minitest::Test
|
|
6
|
+
def test_sortable_activation
|
|
7
|
+
refute ModelsController.active_scaffold_config.actions.include?(:sortable)
|
|
9
8
|
assert AutoModelsController.active_scaffold_config.actions.include?(:sortable)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def test_manual_enable_sortable
|
|
13
9
|
assert SortableModelsController.active_scaffold_config.actions.include?(:sortable)
|
|
14
10
|
end
|
|
15
11
|
|
|
@@ -18,42 +14,53 @@ class ConfigTest < Test::Unit::TestCase
|
|
|
18
14
|
assert_equal :name, SortableModelsController.active_scaffold_config.sortable.column.name
|
|
19
15
|
end
|
|
20
16
|
|
|
21
|
-
def
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
assert !SortableModelsController.active_scaffold_config.list.columns.include?(:name)
|
|
30
|
-
assert !SortableModelsController.active_scaffold_config.update.columns.include?(:name)
|
|
31
|
-
assert !SortableModelsController.active_scaffold_config.create.columns.include?(:name)
|
|
32
|
-
assert !SortableModelsController.active_scaffold_config.show.columns.include?(:name)
|
|
17
|
+
def test_position_column_is_hidden_from_actions
|
|
18
|
+
config = AutoModelsController.active_scaffold_config
|
|
19
|
+
|
|
20
|
+
%i[list update create show search subform].each do |action|
|
|
21
|
+
refute config.public_send(action).columns.include?(:position), action
|
|
22
|
+
end
|
|
23
|
+
assert_equal :hidden, config.columns[:position].form_ui
|
|
33
24
|
end
|
|
34
25
|
|
|
35
|
-
def
|
|
36
|
-
|
|
37
|
-
assert ModelsController.active_scaffold_config.columns[:name].sortable?
|
|
38
|
-
assert ModelsController.active_scaffold_config.columns[:position].sortable?
|
|
26
|
+
def test_manually_selected_column_is_hidden
|
|
27
|
+
config = SortableModelsController.active_scaffold_config
|
|
39
28
|
|
|
40
|
-
|
|
41
|
-
|
|
29
|
+
%i[list update create show].each do |action|
|
|
30
|
+
refute config.public_send(action).columns.include?(:name), action
|
|
31
|
+
end
|
|
32
|
+
end
|
|
42
33
|
|
|
43
|
-
|
|
44
|
-
|
|
34
|
+
def test_sorting_configuration
|
|
35
|
+
regular = ModelsController.active_scaffold_config
|
|
36
|
+
automatic = AutoModelsController.active_scaffold_config
|
|
37
|
+
manual = SortableModelsController.active_scaffold_config
|
|
38
|
+
|
|
39
|
+
assert_equal [{id: "ASC"}], regular.list.sorting.clause
|
|
40
|
+
assert regular.columns[:name].sortable?
|
|
41
|
+
assert regular.columns[:position].sortable?
|
|
42
|
+
|
|
43
|
+
assert_equal [{position: "ASC"}], automatic.list.sorting.clause
|
|
44
|
+
refute automatic.columns[:name].sortable?
|
|
45
|
+
|
|
46
|
+
assert_equal [{name: "ASC"}], manual.list.sorting.clause
|
|
47
|
+
refute manual.columns[:position].sortable?
|
|
45
48
|
end
|
|
46
49
|
|
|
47
|
-
def
|
|
50
|
+
def test_sortable_lists_disable_pagination
|
|
48
51
|
assert ModelsController.active_scaffold_config.list.pagination
|
|
49
|
-
|
|
50
|
-
|
|
52
|
+
refute AutoModelsController.active_scaffold_config.list.pagination
|
|
53
|
+
refute SortableModelsController.active_scaffold_config.list.pagination
|
|
51
54
|
end
|
|
52
55
|
|
|
53
|
-
def
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
def test_sortable_controllers_register_the_plugin_view_path
|
|
57
|
+
plugin_path = File.join(
|
|
58
|
+
ActiveScaffold::Config::Sortable.plugin_directory,
|
|
59
|
+
"frontends/default"
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
refute ModelsController.view_paths.map(&:to_s).include?(plugin_path)
|
|
63
|
+
assert AutoModelsController.view_paths.map(&:to_s).include?(plugin_path)
|
|
64
|
+
assert SortableModelsController.view_paths.map(&:to_s).include?(plugin_path)
|
|
58
65
|
end
|
|
59
66
|
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//= link active_scaffold/manifest.js
|