1import { getRequiredElement } from "./utilities.js?v=2.2.2.0"; 2import { removeAllFileEntries } from "./io.js?v=2.2.2.0"; 3 4const _instances = []; 5let nextFileId = 0; 6export function initialize(adapter, element, elementId) { 7 element = getRequiredElement(element, elementId); 8 9 if (!element) 10 return; 11 12 // save an instance of adapter 13 _instances[elementId] = new FileInputInfo(adapter, element, elementId); 14 element.addEventListener("drop", async (e) => await onDrop(e, element), false); 15 element.addEventListener('change', function handleInputFileChange(event) { 16 17 var fileList = mapElementFilesToFileEntries(element); 18 19 adapter.invokeMethodAsync('NotifyChange', fileList).then(null, function (err) { 20 throw new Error(err); 21 }); 22 }); 23} 24 25export function removeFile(element, elementId, fileId) { 26 element = getRequiredElement(element, elementId); 27 28 if (element && element.files && element.files.length > 0) { 29 const dt = new DataTransfer(); 30 31 for (let i = 0; i < element.files.length; i++) { 32 const file = element.files[i]; 33 if (file.id != fileId) 34 dt.items.add(file); 35 } 36 37 element.files = dt.files; 38 element.dispatchEvent(new Event("change")); 39 } 40} 41 42export function destroy(element, elementId) { 43 const instances = _instances || {}; 44 45 const instance = instances[elementId]; 46 47 if (instance) { 48 if (element) { 49 removeAllFileEntries(element); 50 } 51 52 delete instances[elementId]; 53 } 54} 55 56export function reset(element, elementId) { 57 element = getRequiredElement(element, elementId); 58 59 if (element) { 60 element.value = ''; 61 62 var fileInputInfo = _instances[elementId]; 63 64 if (fileInputInfo) { 65 fileInputInfo.adapter.invokeMethodAsync('NotifyChange', []).then(null, function (err) { 66 throw new Error(err); 67 }); 68 } 69 } 70} 71 72export function open(element, elementId) { 73 element = getRequiredElement(element, elementId); 74 75 if (!element) 76 return; 77 78 if ('showPicker' in HTMLInputElement.prototype) { 79 element.showPicker(); 80 } 81 else { 82 element.click(); 83 } 84} 85 86// Reduce to purely serializable data, plus build an index by ID 87function mapElementFilesToFileEntries(element) { 88 if (!element._blazorFilesById) { 89 element._blazorFilesById = {}; 90 } 91 92 removeAllFileEntries(element); 93 94 let fileList = Array.prototype.map.call(element.files, function (file) { 95 file.id = file.id ?? ++nextFileId; 96 var fileEntry = { 97 id: file.id, 98 lastModified: new Date(file.lastModified).toISOString(), 99 name: file.name, 100 size: file.size, 101 type: file.type, 102 relativePath: file.webkitRelativePath 103 }; 104 element._blazorFilesById[fileEntry.id] = fileEntry; 105 106 // Attach the blob data itself as a non-enumerable property so it doesn't appear in the JSON 107 Object.defineProperty(fileEntry, 'blob', { value: file }); 108 109 return fileEntry; 110 }); 111 return fileList; 112} 113 114async function onDrop(e, element) { 115 e.preventDefault(); 116 let fileInput = element; 117 118 if (fileInput.disabled) 119 return; 120 121 let _files = await getFilesAsync(e.dataTransfer, fileInput.webkitdirectory, fileInput.multiple); 122 fileInput.files = _files; 123 124 const event = new Event('change', { bubbles: true }); 125 fileInput.dispatchEvent(event); 126} 127 128export async function getFilesAsync(dataTransfer, directory, multiple) { 129 const files = []; 130 const queue = []; 131 132 let fileCount = 1 133 if (multiple) { 134 fileCount = dataTransfer.items.length 135 } 136 137 for (let i = 0; i < fileCount; i++) { 138 const item = dataTransfer.items[i]; 139 if (item.kind === "file") { 140 if (typeof item.webkitGetAsEntry === "function") { 141 const entry = item.webkitGetAsEntry(); 142 if (entry.isDirectory) { 143 if (!directory) { 144 continue; 145 } 146 } 147 queue.push(readEntryContentAsync(entry).then(x => files.push(...x))); 148 continue; 149 } 150 151 const file = item.getAsFile(); 152 if (file) { 153 files.push(file); 154 } 155 } 156 } 157 await Promise.all(queue); 158 159 var dt = new DataTransfer(); 160 161 for (var i = 0; i < files.length; i++) { 162 dt.items.add(files[i]); 163 } 164 165 return dt.files; 166} 167 168// Returns a promise with all the files of the directory hierarchy 169function readEntryContentAsync(entry) { 170 return new Promise((resolve, reject) => { 171 let reading = 0; 172 const contents = []; 173 174 readEntry(entry); 175 176 function readEntry(entry) { 177 if (entry.isFile) { 178 reading++; 179 entry.file(file => { 180 reading--; 181 contents.push(file); 182 183 if (reading === 0) { 184 resolve(contents); 185 } 186 }); 187 } else if (entry.isDirectory) { 188 readReaderContent(entry.createReader()); 189 } 190 } 191 192 function readReaderContent(reader) { 193 reading++; 194 195 reader.readEntries(function (entries) { 196 reading--;
197 for (const entry of entries) { 198 readEntry(entry); 199 } 200 201 if (reading === 0) { 202 resolve(contents); 203 } 204 }); 205 } 206 }); 207} 208 209 210class FileInputInfo { 211 constructor(adapter, element, elementId) { 212 this.adapter = adapter; 213 this.element = element; 214 this.elementId = elementId; 215 } 216}
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.