Ogólnie najwięcej rozbiega się o strukturę menu w pamięci. Widzę dwie opcje.
Zacznijmy od jakichś konwencji:
Każde submenu to także menu.
Każde menu to zbiór linków.
Każde menu to obiekt.
Każde menu może zawierać submenu oraz linki jednocześnie.
Opcja A)
Tworzymy strukturę drzewa bezpośrednio:
{
name: 'Menu 1',
links: ['link-1', 'link-2', 'link-3'],
submenus: [
{
name: 'Submenu 1',
links: ['link-1'],
submenus: [
{
name: 'Subsubmenu 1',
links: []
}
]
}
]
}
Taka struktura jest bardzo wygodna do parsowania, natomiast jest w niej taki problem, że brak jest luźnego powiązania rodzic-dziecko. Elementy są ze sobą ściśle związane. Luźne powiązanie przyda nam się, skoro chcemy je zmieniać poprzez przenoszenie
Opcja B
{
id: '1',
name: 'Menu 1',
links: ['link-1', 'link-2', 'link-3'],
}
{
id: '2',
name: 'submenu 2',
links: ['link-1'],
parent: '1' // Link do 'id' innego menu
}
Jest to struktura podobna do zapytań z bazy danych. Po pierwsze taką strukturę bardzo łatwo zapisać do bazy danych, po drugie bardzo łatwo przerzucać linki między menu, oraz submenu z menu do menu.
Jedyny problem to utrudnione parsowanie do HTMLa.
Teraz zakładając, że wybierzesz opcję B, bo jest lepsza do stworzenia luźnego menu, to kwestia przeciągania elementów jest prosta. Wystarczy, że do HTMLa menu w atrybucie data-id zapiszesz jego id. W momencie przeciągania musisz tylko znaleźć data-id elementu, na który został upuszczony dany element. Jeśli przeciągasz całe menu to musisz zmienić id przeciąganego menu na pobrane data-id, a jeśli przeciągasz pojedynczy link, to musisz jedynie przerzucić go do tablicy docelowego menu (id znasz). No i zrobić po tym re-rendrer.
Można pójść o krok dalej i zapisać również linki jako osobne obiekty i przypisać im tylko własność "parent".
To są oczywiście ogólne wskazówki. Szczegóły implementacji zależą od Ciebie. Ale jak widzisz nie jest to aż takie trudne.
Dość hardkorowe jest jedynie parsowanie tej struktury, bo parsowanie od dziecka do rodzica nigdy nie jest fajne xd W gruncie rzeczy musisz przeparsować opcję B do opcji A. Pierwsze, co przychodzi mi do głowy, to rekurencyjne parsowanie całości, aż nie zostanie żaden obiekt submenu (czyli takie menu, które posiada "parent").
No cóż, zawsze możesz zrobić to tak samo, ale zamiast trzymać referencje do rodzica w postaci własności "parent", to trzymać referencje do dzieci w postaci "submenus", ale to też niesie ze sobą konsekwencje.
Możesz też się pobawić w coś, co napisałem do mojego range'a:
https://github.com/mm-jsr/jsr/blob/master/src/assets/js/core/renderer.js#L33L70
https://github.com/mm-jsr/jsr/blob/master/src/assets/js/core/structureParser.js
Powyższy skrypt konwertuje drzewo z pliku renderer.js (to drzewo może być rozszerzane o elementy dodawane przez inne moduły) do formy drzewa HTML. Może coś z tego wyniesiesz. Ponieważ jest to skrypt rekurencyjny, to trzeba się wysilić, żeby go zinterpretować :P Zależności rodzic-dziecko budowane są bezpośrednio na poziomie HTML (appendChild), natomiast w zmiennej `body` znajdują się ogólnie wszystkie obiekty wrzucone razem, żeby można było się do nich odnosić.