← back to demon-of-fire__accessable-studio

Function bodies 189 total

All specs Real LLM only Function bodies
getSelectedClipId function · javascript · L1287-L1290 (4 LOC)
src/js/app.js
  function getSelectedClipId(selectId) {
    const select = document.getElementById(selectId);
    return select && select.value ? select.value : null;
  }
updateClipActionButtons function · javascript · L1292-L1304 (13 LOC)
src/js/app.js
  function updateClipActionButtons() {
    const videoId = getSelectedClipId('video-clip-select');
    const audioId = getSelectedClipId('audio-clip-select');

    ['btn-video-clip-jump', 'btn-video-clip-copy', 'btn-video-clip-cut', 'btn-video-clip-remove'].forEach(id => {
      const btn = document.getElementById(id);
      if (btn) btn.disabled = !videoId;
    });
    ['btn-audio-clip-jump', 'btn-audio-clip-copy', 'btn-audio-clip-cut', 'btn-audio-clip-remove'].forEach(id => {
      const btn = document.getElementById(id);
      if (btn) btn.disabled = !audioId;
    });
  }
jumpToClip function · javascript · L1306-L1317 (12 LOC)
src/js/app.js
  function jumpToClip(clipId) {
    const clip = Timeline.getClips().find(c => c.id === clipId);
    if (!clip) return;
    Timeline.selectClip(clipId);
    Player.seekTo(clip.startTime);
    if (clip.type === 'video') {
      Player.loadVideo(clip.filePath);
      showVideoPlayer();
    }
    Accessibility.announce(`Jumped to "${clip.name}" at ${Accessibility.formatTime(clip.startTime)}`);
    renderClipList();
  }
clipAction function · javascript · L1319-L1347 (29 LOC)
src/js/app.js
  function clipAction(selectId, action) {
    const clipId = getSelectedClipId(selectId);
    if (!clipId) return;
    const clip = Timeline.getClips().find(c => c.id === clipId);
    if (!clip) return;

    switch (action) {
      case 'jump':
        jumpToClip(clipId);
        break;
      case 'copy':
        clipboardClip = { ...clip };
        clipboardAction = 'copy';
        Accessibility.announce(`Copied "${clip.name}"`);
        break;
      case 'cut':
        clipboardClip = { ...clip };
        clipboardAction = 'cut';
        Timeline.removeClip(clipId);
        Accessibility.announce(`Cut "${clip.name}"`);
        renderClipList();
        break;
      case 'remove':
        Timeline.removeClip(clipId);
        Accessibility.announce(`Removed "${clip.name}"`);
        renderClipList();
        break;
    }
  }
initClipList function · javascript · L1349-L1394 (46 LOC)
src/js/app.js
  function initClipList() {
    // Select change events
    const videoSelect = document.getElementById('video-clip-select');
    const audioSelect = document.getElementById('audio-clip-select');
    if (videoSelect) videoSelect.addEventListener('change', updateClipActionButtons);
    if (audioSelect) audioSelect.addEventListener('change', updateClipActionButtons);

    // Video clip action buttons
    document.getElementById('btn-video-clip-jump')?.addEventListener('click', () => clipAction('video-clip-select', 'jump'));
    document.getElementById('btn-video-clip-copy')?.addEventListener('click', () => clipAction('video-clip-select', 'copy'));
    document.getElementById('btn-video-clip-cut')?.addEventListener('click', () => clipAction('video-clip-select', 'cut'));
    document.getElementById('btn-video-clip-remove')?.addEventListener('click', () => clipAction('video-clip-select', 'remove'));

    // Audio clip action buttons
    document.getElementById('btn-audio-clip-jump')?.addEve
initUserGuide function · javascript · L1396-L1490 (95 LOC)
src/js/app.js
  function initUserGuide() {
    // Page-based navigation — only one section visible at a time
    const navBtns = document.querySelectorAll('.guide-nav-btn');
    const allSections = document.querySelectorAll('.guide-section');
    const pageInfo = document.getElementById('guide-page-info');

    function showGuidePage(targetId, focusHeading = true) {
      const target = document.getElementById(targetId);
      if (!target) return;

      // Hide all sections, show only the target
      allSections.forEach(s => s.style.display = 'none');
      target.style.display = 'block';

      // Update active nav button
      navBtns.forEach(b => {
        const isActive = b.getAttribute('data-target') === targetId;
        b.classList.toggle('active', isActive);
        b.setAttribute('aria-current', isActive ? 'page' : 'false');
      });

      // Update page indicator and prev/next button states
      const pageIndex = Array.from(navBtns).findIndex(b => b.getAttribute('data-target') === tar
showGuidePage function · javascript · L1402-L1434 (33 LOC)
src/js/app.js
    function showGuidePage(targetId, focusHeading = true) {
      const target = document.getElementById(targetId);
      if (!target) return;

      // Hide all sections, show only the target
      allSections.forEach(s => s.style.display = 'none');
      target.style.display = 'block';

      // Update active nav button
      navBtns.forEach(b => {
        const isActive = b.getAttribute('data-target') === targetId;
        b.classList.toggle('active', isActive);
        b.setAttribute('aria-current', isActive ? 'page' : 'false');
      });

      // Update page indicator and prev/next button states
      const pageIndex = Array.from(navBtns).findIndex(b => b.getAttribute('data-target') === targetId);
      if (pageInfo) pageInfo.textContent = `Page ${pageIndex + 1} of ${navBtns.length}`;
      const prevBtn = document.getElementById('guide-prev-page');
      const nextBtn = document.getElementById('guide-next-page');
      if (prevBtn) prevBtn.disabled = (pageIndex <= 0);
      if (
Provenance: Repobility (https://repobility.com) — every score reproducible from /scan/
showResponse function · javascript · L12-L18 (7 LOC)
src/js/chatbot.js
  function showResponse(text) {
    if (!responseInline || !responseBody) return;
    responseBody.innerHTML = text;
    responseInline.classList.remove('hidden');
    // Announce for screen readers
    Accessibility.announceStatus(responseBody.textContent.substring(0, 200));
  }
has function · javascript · L21-L23 (3 LOC)
src/js/chatbot.js
  function has(text, ...words) {
    return words.some(w => text.includes(w));
  }
means function · javascript · L26-L32 (7 LOC)
src/js/chatbot.js
  function means(text, ...concepts) {
    const t = ' ' + text + ' ';
    return concepts.some(c => {
      // Each concept can be a pipe-separated list of alternatives
      return c.split('|').some(alt => t.includes(alt.trim()));
    });
  }
extractNumber function · javascript · L35-L38 (4 LOC)
src/js/chatbot.js
  function extractNumber(text) {
    const match = text.match(/(\d+(?:\.\d+)?)/);
    return match ? parseFloat(match[1]) : null;
  }
extractNumbers function · javascript · L41-L44 (4 LOC)
src/js/chatbot.js
  function extractNumbers(text) {
    const matches = text.match(/\d+(?:\.\d+)?/g);
    return matches ? matches.map(Number) : [];
  }
requireClip function · javascript · L47-L49 (3 LOC)
src/js/chatbot.js
  function requireClip() {
    return Timeline.getSelectedClip();
  }
fmtTime function · javascript · L52-L54 (3 LOC)
src/js/chatbot.js
  function fmtTime(seconds) {
    return Accessibility.formatTimeDisplay(seconds);
  }
describeImage function · javascript · L712-L809 (98 LOC)
src/js/chatbot.js
  function describeImage() {
    const canvas = document.getElementById('photo-canvas');
    if (!canvas) return 'Cannot access the photo canvas.';
    const ctx = canvas.getContext('2d');
    const w = canvas.width;
    const h = canvas.height;

    if (w === 0 || h === 0) return 'The image canvas is empty.';

    const imageData = ctx.getImageData(0, 0, w, h);
    const data = imageData.data;
    const totalPixels = w * h;

    // Analyze colors
    let rTotal = 0, gTotal = 0, bTotal = 0;
    let brightPixels = 0, darkPixels = 0;
    let redPixels = 0, greenPixels = 0, bluePixels = 0;
    let whitePixels = 0, blackPixels = 0;

    for (let i = 0; i < data.length; i += 4) {
      const r = data[i], g = data[i + 1], b = data[i + 2];
      rTotal += r; gTotal += g; bTotal += b;

      const brightness = (r + g + b) / 3;
      if (brightness > 200) brightPixels++;
      if (brightness < 55) darkPixels++;
      if (brightness > 240 && Math.abs(r - g) < 20 && Math.abs(g - b) < 20) whitePix
About: code-quality intelligence by Repobility · https://repobility.com
init function · javascript · L812-L841 (30 LOC)
src/js/chatbot.js
  function init() {
    const sendBtn = document.getElementById('btn-send-chat');
    const dismissBtn = document.getElementById('btn-chat-dismiss');

    if (chatInput) {
      chatInput.addEventListener('keydown', (e) => {
        if (e.key === 'Enter') {
          e.preventDefault();
          processCommand(chatInput.value);
          chatInput.value = '';
        }
      });
    }

    if (sendBtn) {
      sendBtn.addEventListener('click', () => {
        processCommand(chatInput.value);
        chatInput.value = '';
        chatInput.focus();
      });
    }

    // Dismiss inline response
    if (dismissBtn) {
      dismissBtn.addEventListener('click', () => {
        if (responseInline) responseInline.classList.add('hidden');
        chatInput.focus();
      });
    }
  }
getFormatArgs function · javascript · L19-L43 (25 LOC)
src/js/converter.js
  function getFormatArgs(format, quality = 'medium') {
    const qArgs = qualityMap[quality] || qualityMap.medium;
    const formatArgs = {
      mp4: ['-c:v', 'libx264', '-c:a', 'aac', ...qArgs],
      avi: ['-c:v', 'mpeg4', '-c:a', 'mp3', '-q:v', '5'],
      mkv: ['-c:v', 'libx264', '-c:a', 'aac', ...qArgs],
      mov: ['-c:v', 'libx264', '-c:a', 'aac', ...qArgs],
      webm: ['-c:v', 'libvpx-vp9', '-c:a', 'libopus', '-b:v', '2M'],
      wmv: ['-c:v', 'wmv2', '-c:a', 'wmav2'],
      flv: ['-c:v', 'flv1', '-c:a', 'mp3'],
      mpeg: ['-c:v', 'mpeg2video', '-c:a', 'mp2'],
      m4v: ['-c:v', 'libx264', '-c:a', 'aac', ...qArgs],
      ts: ['-c:v', 'libx264', '-c:a', 'aac', '-f', 'mpegts'],
      gif: ['-vf', 'fps=10,scale=480:-1:flags=lanczos', '-loop', '0'],
      mp3: ['-vn', '-c:a', 'libmp3lame', '-q:a', '2'],
      wav: ['-vn', '-c:a', 'pcm_s16le'],
      ogg: ['-vn', '-c:a', 'libvorbis', '-q:a', '5'],
      flac: ['-vn', '-c:a', 'flac'],
      aac: ['-vn', '-c:a', 'aac', '-b:a', '1
convertMedia function · javascript · L46-L106 (61 LOC)
src/js/converter.js
  async function convertMedia(inputPath, outputFormat, quality = 'medium') {
    if (!inputPath) {
      Accessibility.announce('No file selected for conversion');
      return;
    }
    if (!window.api) {
      Accessibility.announce('File conversion requires the desktop application.');
      const statusEl = document.getElementById('conv-media-status');
      if (statusEl) statusEl.textContent = 'Error: Conversion requires the desktop application with FFmpeg installed.';
      return;
    }

    const outputPath = inputPath.replace(/\.[^.]+$/, `.${outputFormat}`);
    const args = getFormatArgs(outputFormat, quality);

    // Show progress
    const progressEl = document.getElementById('conv-media-progress');
    const statusEl = document.getElementById('conv-media-status');
    if (progressEl) {
      progressEl.classList.remove('hidden');
      progressEl.setAttribute('aria-valuenow', '50');
    }
    if (statusEl) statusEl.textContent = 'Converting... Please wait.';

    Accessib
init function · javascript · L109-L279 (171 LOC)
src/js/converter.js
  function init() {
    // Media file selection
    const selectMediaBtn = document.getElementById('btn-conv-select-media');
    const mediaDisplay = document.getElementById('conv-media-file-display');
    const convertMediaBtn = document.getElementById('btn-conv-media-start');

    if (selectMediaBtn) {
      selectMediaBtn.addEventListener('click', async () => {
        if (!window.api) return;
        const result = await window.api.showOpenDialog({
          title: 'Select Video or Audio File',
          filters: [
            { name: 'Media Files', extensions: ['mp4', 'avi', 'mkv', 'mov', 'wmv', 'webm', 'flv', 'mp3', 'wav', 'ogg', 'flac', 'aac', 'wma', 'm4a'] },
            { name: 'All Files', extensions: ['*'] },
          ],
          properties: ['openFile'],
        });
        if (!result.canceled && result.filePaths.length > 0) {
          mediaInputPath = result.filePaths[0];
          const fileName = mediaInputPath.split(/[\\/]/).pop();
          if (mediaDisplay) mediaD
getFilterString function · javascript · L30-L32 (3 LOC)
src/js/effects.js
  function getFilterString() {
    return `brightness(${filters.brightness}%) contrast(${filters.contrast}%) saturate(${filters.saturation}%) blur(${filters.blur}px) grayscale(${filters.grayscale}%) sepia(${filters.sepia}%) hue-rotate(${filters.hue}deg) invert(${filters.invert}%)`;
  }
setFilter function · javascript · L35-L41 (7 LOC)
src/js/effects.js
  function setFilter(name, value) {
    if (name in filters) {
      filters[name] = parseFloat(value);
      applyFilters();
      updateSlider(name, value);
    }
  }
applyPreset function · javascript · L44-L55 (12 LOC)
src/js/effects.js
  function applyPreset(presetName) {
    const preset = presets[presetName];
    if (!preset) {
      Accessibility.announce(`Unknown preset: ${presetName}`);
      return false;
    }
    Object.assign(filters, preset);
    applyFilters();
    updateAllSliders();
    Accessibility.announce(`Applied ${presetName} filter preset`);
    return true;
  }
resetAll function · javascript · L58-L63 (6 LOC)
src/js/effects.js
  function resetAll() {
    Object.assign(filters, presets.none);
    applyFilters();
    updateAllSliders();
    Accessibility.announce('All filters reset to default');
  }
Repobility (the analyzer behind this table) · https://repobility.com
applyFilters function · javascript · L66-L68 (3 LOC)
src/js/effects.js
  function applyFilters() {
    Player.applyFilter(getFilterString());
  }
updateSlider function · javascript · L71-L85 (15 LOC)
src/js/effects.js
  function updateSlider(name, value) {
    // Try both ID patterns: filter-{name} and filter-{name}-slider
    const slider = document.getElementById(`filter-${name}`) || document.getElementById(`filter-${name}-slider`);
    const display = document.getElementById(`${name}-value`) || document.getElementById(`filter-${name}-val`);
    if (slider) {
      slider.value = value;
      let unit = '%';
      if (name === 'blur') unit = 'px';
      else if (name === 'hue') unit = '\u00B0';
      const displayText = `${value}${unit}`;
      slider.setAttribute('aria-valuetext', displayText);
      slider.setAttribute('aria-label', `${name.charAt(0).toUpperCase() + name.slice(1)}, currently ${displayText}`);
      if (display) display.textContent = displayText;
    }
  }
updateAllSliders function · javascript · L88-L92 (5 LOC)
src/js/effects.js
  function updateAllSliders() {
    for (const [name, value] of Object.entries(filters)) {
      updateSlider(name, value);
    }
  }
getFilters function · javascript · L95-L97 (3 LOC)
src/js/effects.js
  function getFilters() {
    return { ...filters };
  }
getFFmpegFilters function · javascript · L100-L122 (23 LOC)
src/js/effects.js
  function getFFmpegFilters() {
    const ffFilters = [];
    if (filters.brightness !== 100) {
      ffFilters.push(`eq=brightness=${(filters.brightness - 100) / 100}`);
    }
    if (filters.contrast !== 100) {
      ffFilters.push(`eq=contrast=${filters.contrast / 100}`);
    }
    if (filters.saturation !== 100) {
      ffFilters.push(`eq=saturation=${filters.saturation / 100}`);
    }
    if (filters.blur > 0) {
      const sigma = Math.max(1, Math.round(filters.blur * 2));
      ffFilters.push(`boxblur=${sigma}:${sigma}`);
    }
    if (filters.grayscale > 0) {
      ffFilters.push(`hue=s=${1 - filters.grayscale / 100}`);
    }
    if (filters.hue !== 0) {
      ffFilters.push(`hue=h=${filters.hue}`);
    }
    return ffFilters.join(',') || 'null';
  }
getPresetNames function · javascript · L125-L127 (3 LOC)
src/js/effects.js
  function getPresetNames() {
    return Object.keys(presets);
  }
init function · javascript · L130-L140 (11 LOC)
src/js/effects.js
  function init() {
    const filterNames = ['brightness', 'contrast', 'saturation', 'blur', 'grayscale', 'sepia', 'hue', 'invert'];
    filterNames.forEach(name => {
      const slider = document.getElementById(`filter-${name}`);
      if (slider) {
        slider.addEventListener('input', () => {
          setFilter(name, parseFloat(slider.value));
        });
      }
    });
  }
setApiKey function · javascript · L16-L19 (4 LOC)
src/js/gemini.js
  function setApiKey(key) {
    apiKey = key.trim();
    localStorage.setItem('as-gemini-key', apiKey);
  }
If a scraper extracted this row, it came from Repobility (https://repobility.com)
getApiKey function · javascript · L21-L24 (4 LOC)
src/js/gemini.js
  function getApiKey() {
    if (!apiKey) apiKey = localStorage.getItem('as-gemini-key') || '';
    return apiKey;
  }
isAvailable function · javascript · L26-L28 (3 LOC)
src/js/gemini.js
  function isAvailable() {
    return !!getApiKey();
  }
buildSystemPrompt function · javascript · L33-L155 (123 LOC)
src/js/gemini.js
  function buildSystemPrompt() {
    const clips = typeof Timeline !== 'undefined' ? Timeline.getClips() : [];
    const selectedClip = typeof Timeline !== 'undefined' ? Timeline.getSelectedClip() : null;
    const currentTime = typeof Player !== 'undefined' && Player.getCurrentTime ? Player.getCurrentTime() : 0;
    const totalDuration = typeof Timeline !== 'undefined' ? Timeline.getTotalDuration() : 0;
    const hasPhoto = typeof PhotoEditor !== 'undefined' && PhotoEditor.hasImage;

    let clipInfo = 'Timeline is empty.';
    if (clips.length > 0) {
      clipInfo = clips.map((c, i) => {
        let line = `  ${i}: "${c.name}" (${c.type}) ${c.startTime.toFixed(1)}s–${(c.startTime + c.duration).toFixed(1)}s`;
        if (c.volume !== undefined && c.volume !== 100) line += ` vol=${c.volume}%`;
        if (c.speed !== undefined && c.speed !== 1) line += ` speed=${c.speed}x`;
        if (c.text) line += ` text="${c.text}"`;
        return line;
      }).join('\n');
    }

    let select
send function · javascript · L160-L260 (101 LOC)
src/js/gemini.js
  async function send(userMessage) {
    const key = getApiKey();
    if (!key) throw new Error('No Gemini API key set');

    const systemPrompt = buildSystemPrompt();
    const parts = [{ text: userMessage }];

    // Always attach the photo if one is loaded — Gemini can see it
    // Downscale to max 1024px so Gemini sees the FULL image without hitting size limits
    const hasPhoto = typeof PhotoEditor !== 'undefined' && PhotoEditor.hasImage;
    if (hasPhoto) {
      try {
        const dataURL = PhotoEditor.getImageDataURL();
        if (dataURL) {
          // Downscale large images so Gemini can see the entire thing
          const tempImg = new Image();
          const scaled = await new Promise((resolve) => {
            tempImg.onload = () => {
              const maxDim = 1024;
              let sw = tempImg.width, sh = tempImg.height;
              if (sw > maxDim || sh > maxDim) {
                const ratio = Math.min(maxDim / sw, maxDim / sh);
                sw = Math.
extractText function · javascript · L265-L270 (6 LOC)
src/js/gemini.js
  function extractText(data) {
    if (!data.candidates || data.candidates.length === 0) return 'No response from Gemini.';
    const parts = data.candidates[0].content?.parts;
    if (!parts || parts.length === 0) return 'Empty response.';
    return parts.map(p => p.text || '').join('');
  }
parseActions function · javascript · L272-L282 (11 LOC)
src/js/gemini.js
  function parseActions(responseText) {
    const actionsMatch = responseText.match(/```actions\s*\n?([\s\S]*?)```/);
    if (!actionsMatch) return { text: responseText, actions: [] };
    try {
      const actions = JSON.parse(actionsMatch[1].trim());
      const text = responseText.replace(/```actions\s*\n?[\s\S]*?```/, '').trim();
      return { text, actions: Array.isArray(actions) ? actions : [actions] };
    } catch (e) {
      return { text: responseText, actions: [] };
    }
  }
ensureClipSelected function · javascript · L288-L298 (11 LOC)
src/js/gemini.js
  function ensureClipSelected() {
    let clip = Timeline.getSelectedClip();
    if (!clip) {
      const clips = Timeline.getClips();
      if (clips.length > 0) {
        Timeline.selectClip(clips[0].id);
        clip = clips[0];
      }
    }
    return clip;
  }
executeAction function · javascript · L300-L485 (186 LOC)
src/js/gemini.js
  async function executeAction(action) {
    const p = action.params || {};

    switch (action.action) {
      // --- Clip selection ---
      case 'selectClip': {
        const clips = Timeline.getClips();
        if (p.index >= 0 && p.index < clips.length) Timeline.selectClip(clips[p.index].id);
        break;
      }
      case 'selectClipByName': {
        const clips = Timeline.getClips();
        const target = (p.name || '').toLowerCase();
        const match = clips.find(c => c.name.toLowerCase().includes(target));
        if (match) Timeline.selectClip(match.id);
        break;
      }

      // --- Timeline editing ---
      case 'trim': {
        const clip = ensureClipSelected();
        if (clip) Timeline.trimClip(clip.id, p.trimStart, p.trimEnd);
        break;
      }
      case 'split': {
        if (p.time === 'playhead') { Timeline.splitAtPlayhead(); break; }
        const clip = ensureClipSelected();
        if (clip) {
          // p.time is relative to clip start 
Provenance: Repobility (https://repobility.com) — every score reproducible from /scan/
processResponse function · javascript · L490-L511 (22 LOC)
src/js/gemini.js
  async function processResponse(responseText) {
    const { text, actions } = parseActions(responseText);

    for (const action of actions) {
      try {
        await executeAction(action);
        // Small yield so the UI updates between chained actions (e.g. select then trim)
        await new Promise(r => setTimeout(r, 50));
      } catch (e) {
        console.error('Error executing action:', action, e);
      }
    }

    // Markdown-ish → HTML
    let html = text
      .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
      .replace(/\*(.*?)\*/g, '<em>$1</em>')
      .replace(/`(.*?)`/g, '<code>$1</code>')
      .replace(/\n/g, '<br>');

    return { html, actionsExecuted: actions.length };
  }
loadImage function · javascript · L21-L46 (26 LOC)
src/js/photoeditor.js
  function loadImage(filePath) {
    currentFilePath = filePath;
    const img = new Image();
    img.onload = () => {
      originalImage = img;
      baseImage = img;
      undoStack = [];
      redoStack = [];
      canvas.width = img.width;
      canvas.height = img.height;
      resetAdjustments();
      drawImage();
      if (noPhotoMsg) noPhotoMsg.style.display = 'none';
      Accessibility.announce(`Image loaded: ${filePath.split(/[\\/]/).pop()}, ${img.width} by ${img.height} pixels`);
      Accessibility.setStatus(`Image loaded: ${img.width}x${img.height}`);

      const resizeW = document.getElementById('resize-width');
      const resizeH = document.getElementById('resize-height');
      if (resizeW) resizeW.value = img.width;
      if (resizeH) resizeH.value = img.height;
    };
    img.onerror = () => {
      Accessibility.announce('Error loading image file');
    };
    img.src = filePath.startsWith('file://') ? filePath : `file:///${filePath.replace(/\\/g, '/')}`;
  }
drawImage function · javascript · L49-L71 (23 LOC)
src/js/photoeditor.js
  function drawImage() {
    if (!originalImage || !ctx) return;

    const img = originalImage;
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    ctx.save();
    ctx.translate(canvas.width / 2, canvas.height / 2);
    ctx.rotate((rotation * Math.PI) / 180);
    ctx.scale(flipH ? -1 : 1, flipV ? -1 : 1);

    let filterStr = '';
    filterStr += `brightness(${100 + adjustments.brightness}%) `;
    filterStr += `contrast(${100 + adjustments.contrast}%) `;
    filterStr += `saturate(${100 + adjustments.saturation}%) `;
    ctx.filter = filterStr.trim();

    const drawW = rotation % 180 === 0 ? canvas.width : canvas.height;
    const drawH = rotation % 180 === 0 ? canvas.height : canvas.width;
    ctx.drawImage(img, -drawW / 2, -drawH / 2, drawW, drawH);

    ctx.restore();
  }
drawImageRaw function · javascript · L74-L79 (6 LOC)
src/js/photoeditor.js
  function drawImageRaw() {
    if (!originalImage || !ctx) return;
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.filter = 'none';
    ctx.drawImage(originalImage, 0, 0, canvas.width, canvas.height);
  }
saveState function · javascript · L82-L94 (13 LOC)
src/js/photoeditor.js
  function saveState() {
    undoStack.push({
      adjustments: { ...adjustments },
      rotation,
      flipH,
      flipV,
      width: canvas.width,
      height: canvas.height,
      imageSrc: originalImage ? originalImage.src : null,
    });
    if (undoStack.length > 20) undoStack.shift();
    redoStack = [];
  }
restoreState function · javascript · L97-L117 (21 LOC)
src/js/photoeditor.js
  function restoreState(state) {
    adjustments = state.adjustments;
    rotation = state.rotation;
    flipH = state.flipH;
    flipV = state.flipV;
    canvas.width = state.width;
    canvas.height = state.height;

    if (state.imageSrc && state.imageSrc !== originalImage.src) {
      const img = new Image();
      img.onload = () => {
        originalImage = img;
        drawImage();
        updateAdjustmentSliders();
      };
      img.src = state.imageSrc;
    } else {
      drawImage();
      updateAdjustmentSliders();
    }
  }
undo function · javascript · L120-L133 (14 LOC)
src/js/photoeditor.js
  function undo() {
    if (undoStack.length === 0) {
      Accessibility.announce('Nothing to undo');
      return;
    }
    redoStack.push({
      adjustments: { ...adjustments },
      rotation, flipH, flipV,
      width: canvas.width, height: canvas.height,
      imageSrc: originalImage ? originalImage.src : null,
    });
    restoreState(undoStack.pop());
    Accessibility.announce('Undone');
  }
redo function · javascript · L136-L149 (14 LOC)
src/js/photoeditor.js
  function redo() {
    if (redoStack.length === 0) {
      Accessibility.announce('Nothing to redo');
      return;
    }
    undoStack.push({
      adjustments: { ...adjustments },
      rotation, flipH, flipV,
      width: canvas.width, height: canvas.height,
      imageSrc: originalImage ? originalImage.src : null,
    });
    restoreState(redoStack.pop());
    Accessibility.announce('Redone');
  }
About: code-quality intelligence by Repobility · https://repobility.com
bakeCanvas function · javascript · L152-L179 (28 LOC)
src/js/photoeditor.js
  function bakeCanvas() {
    return new Promise((resolve) => {
      let dataURL;
      try {
        dataURL = canvas.toDataURL('image/png');
      } catch (e) {
        console.error('bakeCanvas: toDataURL failed:', e);
        resolve(); // edits are already visible on canvas via putImageData
        return;
      }
      const img = new Image();
      img.onload = () => {
        originalImage = img;
        rotation = 0;
        flipH = false;
        flipV = false;
        adjustments = { brightness: 0, contrast: 0, saturation: 0, sharpness: 0 };
        updateAdjustmentSliders();
        drawImage();
        resolve();
      };
      img.onerror = () => {
        console.error('bakeCanvas: image load failed');
        resolve();
      };
      img.src = dataURL;
    });
  }
rotateLeft function · javascript · L182-L195 (14 LOC)
src/js/photoeditor.js
  function rotateLeft() {
    if (!originalImage) return;
    saveState();
    rotation = (rotation - 90 + 360) % 360;
    if (rotation % 180 !== 0) {
      canvas.width = originalImage.height;
      canvas.height = originalImage.width;
    } else {
      canvas.width = originalImage.width;
      canvas.height = originalImage.height;
    }
    drawImage();
    Accessibility.announce(`Rotated left. Rotation: ${rotation} degrees`);
  }
rotateRight function · javascript · L198-L211 (14 LOC)
src/js/photoeditor.js
  function rotateRight() {
    if (!originalImage) return;
    saveState();
    rotation = (rotation + 90) % 360;
    if (rotation % 180 !== 0) {
      canvas.width = originalImage.height;
      canvas.height = originalImage.width;
    } else {
      canvas.width = originalImage.width;
      canvas.height = originalImage.height;
    }
    drawImage();
    Accessibility.announce(`Rotated right. Rotation: ${rotation} degrees`);
  }
‹ prevpage 2 / 4next ›