1 2async function RenderSettingHeading(table, text) { 3 let th = $('<th></th>').attr('colspan', 2).text(text).addClass('fs-4 pt-3'); 4 let tr = $('<tr></tr>').append(th); 5 table.append(tr); 6} 7 8async function RenderSettingRole(table, entity, label, role) { 9 let v = entity.roles.includes(role); 10 let rt = $('<tr><th></th><td></td></tr>'); 11 let h = rt.children('th'); 12 let cell = rt.children('td').first(); 13 h.first().html(label).off('click').on('click', function () { 14 $(this).next('td').find('input, textarea, select').first().focus(); 15 }); 16 input = $('<input></input>').addClass('form-check-input m-0 fs-3 mb-2').attr('type', 'checkbox').attr('role', 'switch'); 17 let s = $('<div class="form-check form-switch"></div>'); 18 if (v) $(input).prop('checked', true); 19 s.append(input).appendTo(cell); 20 input.off('change').on('change', {id: entity.id, role: role}, async (event) => { 21 if ($(event.target).is(':checked')) { 22 await GrantRole(event.data.id, event.data.role); 23 } else { 24 await RevokeRole(event.data.id, event.data.role); 25 } 26 }); 27 table.append(rt); 28} 29 30/** 31 * Render a form for selecting a user role 32 * @param {*} table 33 * @param {*} entity 34 * @param {*} label 35 * @param {*} options 36 */ 37async function RenderSettingRoleSelect(table, entity, label, options) { 38 let rt = $('<tr><th></th><td></td></tr>'); 39 let h = rt.children('th'); 40 let cell = rt.children('td').first(); 41 h.first().html(label).off('click').on('click', function () { 42 $(this).next('td').find('input, textarea, select').first().focus(); 43 }); 44 input = $('<select></select>').addClass('form-select m-0 fs-5 mb-2').appendTo(cell); 45 let roles = []; 46 for(let option of options) { 47 roles.push(option.value); 48 let o = $('<option></option>').text(option.label).val(option.value).appendTo(input); 49 if(entity.roles.includes(option.value)) o.attr('selected',true); 50 } 51 input.off('change').on('change', {id: entity.id, roles: roles}, async (event) => { 52 await GrantRole(event.data.id, $(event.target).val(), {conflicts: event.data.roles}); 53 }); 54 table.append(rt); 55} 56 57async function RenderSetting(table, entity, name, label, type = 'text', options = []) { 58 let v = entity[name]; 59 if (v == undefined) v = entity.settings[name]; 60 if (v == undefined) v = ''; 61 let rt = $('<tr><th></th><td></td></tr>'); 62 let h = rt.children('th'); 63 let s = null; 64 let cell = rt.children('td').first(); 65 h.first().html(label).off('click').on('click', function () { 66 $(this).next('td').find('input, textarea, select').first().focus(); 67 }); 68 let input = null; 69 switch (type) { 70 case 'select': 71 let select = $('<select></select>'); 72 select.addClass('form-select'); 73 for (let option of options) { 74 let o = $('<option></option>'); 75 o.val(option.value).html(option.label); 76 if (option.value == entity.settings[name] || option.value == entity[name]) o.attr('selected', true); 77 select.append(o); 78 } 79 cell.append(select); 80 select.off('change').on('change', async function () { 81 let settings = {}; 82 settings[name] = $(this).val(); 83 $(this).attr('disabled', true); 84 if (SaveSetting(entity.type, entity.id, settings)) { 85 $(this).removeAttr('disabled'); 86 } else { 87 $(this).addClass('is-invalid'); 88 } 89 }); 90 break; 91 case 'switch': 92 input = $('<input></input>').addClass('form-check-input m-0 fs-3 mb-2').attr('type', 'checkbox').attr('role', 'switch'); 93 s = $('<div class="form-check form-switch"></div>'); 94 if (v == 1) $(input).prop('checked', true); 95 s.append(input).appendTo(cell); 96 input.off('change').on('change', async function () { 97 let settings = {}; 98 settings[name] = ($(this).is(':checked')) ? 1 : 0; 99 $(this).attr('disabled', true); 100 if (await SaveSetting(entity.type, entity.id, settings)) { 101 $(this).removeAttr('disabled'); 102 } else { 103 $(this).addClass('is-invalid'); 104 } 105 }); 106 break; 107 case 'switch-invert': 108 input = $('<input></input>').addClass('form-check-input m-0 fs-3 mb-2').attr('type', 'checkbox').attr('role', 'switch'); 109 s = $('<div class="form-check form-switch"></div>'); 110 if (v == undefined || v == 0) $(input).prop('checked', true); 111 s.append(input).appendTo(cell); 112 input.off('change').on('change', async function () { 113 let settings = {}; 114 settings[name] = ($(this).is(':checked')) ? 0 : 1; 115 $(this).attr('disabled', true); 116 if (await SaveSetting(entity.type, entity.id, settings)) { 117 $(this).removeAttr('disabled'); 118 } else { 119 $(this).addClass('is-invalid'); 120 } 121 }); 122 break; 123 case 'move-chapter': 124 input = $('<select></select>').addClass('form-select').addClass('rounded-start-0').attr('data-entity-id', entity.id); 125 if (current_user !== null) { 126 for (let link of await GetBookLinksForAuthor(current_user.id)) { 127 let option = $('<option></option>').text(link.text).attr('value', link.entity_id).appendTo(input); 128 if (link.entity_id == entity.book_id) option.attr('selected', true); 129 } 130 cell.append(input); 131 input.off('change').on('change', async function () { 132 $(this).attr('disabled', true); 133 if (await MoveChapter($(this).closest('[data-entity-id]').attr('data-entity-id'), $(this).val())) { 134 Toast('Content Moved', 'The content was moved to a new publication.', 'bg-success text-light'); 135 $(this).removeAttr('disabled'); 136 } else { 137 $(this).addClass('is-invalid'); 138 } 139 }); 140 } 141 break; 142 case 'rename-chapter': 143 input = $('<input></input>'); 144 input.val(v).addClass('rounded-start-0').addClass('form-control').attr('required', true); 145 cell.append(input).attr('data-field', name); 146 input.off('change').on('change', async function () { 147 if ($(this).val() == '') return; 148 $(this).removeClass('is-invalid'); 149 $(this).attr('disabled', true); 150 let short_name = $(this).val(); 151 console.log("Changing the chapter URI to " + short_name); 152 if (await (RenameChapter(entity.id, entity.book_id, short_name))) { 153 Toast('Address Changed', 'The address (location or URI) was successfully changed.', 'bg-success text-light'); 154 $(this).removeAttr('disabled'); 155 } else { 156 $(this).removeAttr('disabled'); 157 $(this).addClass('is-invalid'); 158 } 159 }); 160 break; 161 case 'rename-book': 162 input = $('<input></input>'); 163 input.val(v).addClass('rounded-start-0').addClass('form-control').attr('required', true); 164 cell.append(input).attr('data-field', name); 165 input.off('change').on('change', async function () { 166 if ($(this).val() == '') return; 167 $(this).removeClass('is-invalid'); 168 $(this).attr('disabled', true); 169 try { 170 if (await RenameBook(entity.id, $(this).val())) { 171 Toast('Address Changed', 'The address (location or URI) was successfully changed.', 'bg-success text-light'); 172 $(this).removeAttr('disabled'); 173 } else { 174 $(this).removeAttr('disabled'); 175 $(this).addClass('is-invalid'); 176 } 177 $(this).val(current_book.short_name); 178 } catch (error) { 179 console.error(error); 180 $(this).removeAttr('disabled'); 181 $(this).addClass('is-invalid'); 182 Toast('Error', error, 'bg-danger text-light'); 183 } 184 }); 185 break; 186 case 'button': 187 let b = $('<button></button>').text(label).addClass('btn btn-primary').attr('data-action', options[0]); 188 if (options.length > 0) b.attr('data-action-value', options[1]); 189 cell.append(b); 190 break; 191 case 'textarea': 192 input = $('<textarea></textarea>').attr('rows', 4); 193 default: 194 if (input == null) input = $('<input></input>'); 195 input.val(v).addClass('rounded-start-0'); 196 cell.append(input).attr('data-field', name); 197 input.addClass('form-control').off('change').on('change', async function () { 198 let settings = {}; 199 settings[name] = $(this).val(); 200 $(this).attr('disabled', true); 201 if (await SaveSetting(entity.type, entity.id, settings)) { 202 $(this).removeAttr('disabled'); 203 } else { 204 $(this).addClass('is-invalid'); 205 } 206 }); 207 } 208 table.append(rt); 209}
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.