PageSourceSearch

https://edtechbooks.org/js/etb-editor/editor.toc.js

js edtechbooks.org collected 2026-09-24 08:52:13 UTC 4,523 bytes, 104 lines download raw bytes

1class TOCEditor {
2    constructor(editorWindow, book) {
3        this.editorWindow = editorWindow;
4        this.book = book;
5        this.dragging = null;
6        this.tocStartX = 0;
7        this.Initialize();
8        editors.push(this);
9    }
10    async Initialize() {
11        $(this.editorWindow).empty();
12        this.ribbon = $(await RenderTemplate('book-toc-ribbon', this.book))[0];
13        $(this.ribbon).appendTo(this.editorWindow);
14        $(this.ribbon).find('[data-ribbon-action]').on('click', async (event) => {
15            try {
16                return await this[$(event.target).attr('data-ribbon-action')]();
17            } catch (error) {
18                console.error(error);
19                return error;
20            }
21        });
22        for (let chapter_link of this.book.chapter_links) {
23            chapter_link.book_short_name = this.book.short_name;
24            let e = $(await RenderTemplate('book-toc-row-edit', chapter_link));
25            e.css({ 'margin-left': (chapter_link.chapter_level * 20) + 'px' }).attr('data-children', chapter_link.children.join(',')).appendTo($('#book-nav-links'));
26            $(this.editorWindow).append(e);
27            $(e).find('[data-role="grip"]').off().on('mousedown', (event) => {
28                this.dragging = event.target;
29                this.tocStartX = event.pageX;
30            });
31            $(e).find('input').off('change').on('change', (event) => {
32                console.log('Saving');
33                SaveSettingFromElement(event.target);
34            });
35        }
36        $(this.editorWindow).sortable({
37            handle: 'grip[data-role="grip"]',
38            items: 'div[data-entity-id]',
39            axis: 'y',
40            scrollSpeed: 6,
41            opacity: 0.8,
42            start: (event) => {
43                $(this.editorWindow).on('mousemove', (event) => this.Dragging(event));
44            },
45            stop: (event) => {
46                this.dragging = null;
47                $(this.editorWindow).find('[data-chapter-level-target]').each((index, element) => {
48                    $(element).attr('data-chapter-level', $(element).attr('data-chapter-level-target')).removeAttr('data-chapter-level-target');
49                });
50                $(this.editorWindow).off('mousemove');
51                this.SetDirty();
52            },
53            update: (event) => {
54                // Nothing for now
55            }
56        });
57    }
58    async Save() {
59        $(this.editorWindow).sortable('disable');
60        try {
61            let chapters = [];
62            $(this.editorWindow).children('div').each((index, element) => {
63                if(!HasAttr(element, 'data-entity-id')) return;
64                let chapter = {};
65                chapter.id = $(element).attr('data-entity-id');
66                chapter.chapter_level = $(element).attr('data-chapter-level');
67                chapters.push(chapter);
68            });
69            if (await SortBookChapters(chapters)) {
70                this.SetClean();
71                Toast('Chapter Order Saved', 'The chapter order has been saved.', 'bg-success text-light');
72            }
73        } finally {
74            $(this.editorWindow).sortable('enable');
75        }
76    }
77    SetClean() {
78        if (!this.dirty) return;
79        console.log('Setting clean');
80        this.dirty = false;
81        if(this.ribbon!==undefined) $(this.ribbon).find('#save-status').addClass('bi-check-lg').removeClass('bi-floppy2').removeClass('btn-danger').text('Saved');
82    }
83    SetDirty() {
84        if (this.dirty) return;
85        console.log('Setting dirty');
86        this.dirty = true;
87        if (this.ribbon !== undefined) $(this.ribbon).find('#save-status').removeClass('bi-check-lg').addClass('bi-floppy2').addClass('btn-danger').text('Unsaved');
88    }
89    Destroy() {
90        $(this.editorWindow).sortable('destroy')
91    }
92    Dragging(event) {
93        if (this.dragging !== null && $(this.dragging).hasClass('bi-arrows-move')) {
94            let currentX = event.pageX;
95            let distance = currentX - this.tocStartX;
96            let chapter_level = parseInt($(this.dragging).parent().attr('data-chapter-level'));
97            let chapter_level_adjustment = Math.round(distance / 20);
98            chapter_level += chapter_level_adjustment;
99            if (chapter_level < 0) chapter_level = 0;
100            if (chapter_level > 4) chapter_level = 4;
101            $(this.dragging).parent().css({ 'margin-left': (chapter_level * 20) + 'px' }).attr('data-chapter-level-target', chapter_level);
102        }
103    }
104}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.