PageSourceSearch

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

js edtechbooks.org collected 2026-09-24 08:52:06 UTC 5,210 bytes, 102 lines download raw bytes

1class AuthorshipTable {
2
3    constructor(entity, element) {
4        this.entity = entity;
5        this.element = element;
6        this.list = $(this.element).find('#author-list');
7        this.search = $(this.element).find('#author-search');
8        this.searchResults = $(this.element).find('#author-search-results');
9    }
10
11    DoAuthorRow(authorship) {
12        let d = $('<div></div>').addClass('d-flex flex-row align-items-center border rounded my-1').text(authorship.name).attr('data-entity-type', 'author').attr('data-entity-id', authorship.author_id);
13        let img = $('<img>').attr('src', authorship.bio_pic).addClass('rounded-circle me-2 border').css({ 'max-height': '40px' }).prependTo(d);
14        let p = $('<a></a>').attr('href', '/author/' + authorship.author_id + '/view').attr('target', '_blank').addClass('bi-person btn ms-auto rounded-end-0').appendTo(d);
15        let grip = $('<grip></grip>').addClass('btn bi-arrows-vertical').attr('data-role', 'grip').prependTo(d);
16        let shadow = $('<button></button>').addClass('btn rounded-0').appendTo(d);
17        if (authorship.shadow_author == 1) {
18            shadow.removeClass('bi-eye').addClass('bi-eye-slash');
19        } else {
20            shadow.removeClass('bi-eye-slash').addClass('bi-eye');
21        }
22        shadow.on('click', async (event) => {
23            if ($(event.target).is('[disabled]')) return;
24            $(event.target).attr('disabled', true);
25            let shadow_author = ($(event.target).hasClass('bi-eye')) ? 1 : 0;
26            await ChangeAuthorVisibility(this.entity, $(event.target).closest('[data-entity-type="author"][data-entity-id]').attr('data-entity-id'), shadow_author);
27            $(event.target).toggleClass('bi-eye').toggleClass('bi-eye-slash');
28            $(event.target).removeAttr('disabled');
29        });
30        let del = $('<button></button>').addClass('btn text-danger bi-x-lg rounded-start-0').appendTo(d);
31        del.on('click', async (event) => {
32            await RemoveAuthor(this.entity, $(event.target).closest('[data-entity-type="author"][data-entity-id]').attr('data-entity-id'));
33            $(event.target).off('click');
34            $(event.target).parent().remove();
35        });
36        return d;
37    }
38
39    Render() {
40        this.list.empty();
41        this.searchResults.empty();
42        this.search.val('');
43        for (let authorship of this.entity.authorships) {
44            this.list.append(this.DoAuthorRow(authorship));
45        }
46        this.search.on('input', async (event) => {
47            clearTimeout(searchTimeout);
48            let v = $(event.target).val();
49            if (v.length > 0) {
50                searchTimeout = setTimeout(async (event) => {
51                    this.searchResults.empty();
52                    let results = await Search(v, ['authors'], 20, { method: 'show_all' });
53                    for (let id in results.authors) {
54                        let authorship = results.authors[id];
55                        let b = $('<button></button>').text(authorship.name).addClass('btn btn-light text-start m-1 bi-plus-lg icon-text-link w-100').attr('data-entity-type', 'author').attr('data-entity-id', authorship.author_id);
56                        this.searchResults.append(b);
57                        b.on('click', async (event) => {
58                            let author_id = $(event.target).closest('[data-entity-type="author"][data-entity-id]').attr('data-entity-id');
59                            let authorship = await AddAuthor(this.entity, author_id);
60                            console.log(authorship);
61                            switch (this.entity.type) {
62                                case 'chapter':
63                                    this.entity = await GetChapterFromID(this.entity.id, true);
64                                    this.Render();
65                                    break;
66                                case 'book':
67                                    this.entity = await GetBook(this.entity.id, true);
68                                    this.Render();
69                                    break;
70                            }
71                        });
72                    }
73                }, searchDelay);
74            } else {
75                this.searchResults.empty();
76            }
77        });
78        $(this.list).sortable({
79            handle: 'grip[data-role="grip"]',
80            items: 'div[data-entity-id]',
81            axis: 'y',
82            revert: true,
83            scrollSpeed: 6,
84            opacity: 0.8,
85            update: async (event) => {
86                let e = event.target;
87                $(e).sortable('disable');
88                let authors = [];
89                $(e).children('div[data-entity-id]').each(function () {
90                    authors.push($(this).attr('data-entity-id'));
91                });
92                    try {
93                        if (await SortAuthors(this.entity, authors)) {
94                            Toast('Author Order Saved', 'The author order has been saved.', 'bg-success text-light');
95                        }
96                    } finally {
97                        $(e).sortable('enable');
98                    }
99            }
100        });
101    }
102}

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.