PageSourceSearch

https://topfood.app/assets/controllers/social_links_controller-7bbd3c09.js

js topfood.app collected 2026-09-30 22:17:55 UTC 4,562 bytes, 86 lines download raw bytes

1import NestedForm from '@stimulus-components/rails-nested-form'
2
3const PLATFORM_CONFIG = {
4  instagram: { prefix: 'instagram.com/',    hosts: ['instagram.com'],                                   stripAt: false, stripPath: null },
5  facebook:  { prefix: 'facebook.com/',     hosts: ['facebook.com', 'fb.com', 'fb.me', 'm.facebook.com'], stripAt: false, stripPath: null },
6  tiktok:    { prefix: 'tiktok.com/@',      hosts: ['tiktok.com', 'vm.tiktok.com'],                     stripAt: true,  stripPath: null },
7  x:         { prefix: 'x.com/',            hosts: ['x.com', 'twitter.com'],                            stripAt: false, stripPath: null },
8  youtube:   { prefix: 'youtube.com/@',     hosts: ['youtube.com', 'youtu.be', 'm.youtube.com'],        stripAt: true,  stripPath: null },
9  whatsapp:  { prefix: 'wa.me/',            hosts: ['wa.me', 'whatsapp.com', 'chat.whatsapp.com'],      stripAt: false, stripPath: null },
10  linkedin:  { prefix: 'linkedin.com/',     hosts: ['linkedin.com'],                                    stripAt: false, stripPath: null },
11  threads:   { prefix: 'threads.net/@',     hosts: ['threads.net', 'threads.com'],                      stripAt: true,  stripPath: null },
12  pinterest: { prefix: 'pinterest.com/',    hosts: ['pinterest.com', 'pin.it'],                         stripAt: false, stripPath: null },
13  snapchat:  { prefix: 'snapchat.com/add/', hosts: ['snapchat.com'],                                    stripAt: false, stripPath: 'add/' },
14  telegram:  { prefix: 't.me/',             hosts: ['t.me', 'telegram.me', 'telegram.org'],             stripAt: false, stripPath: null },
15  other:     { prefix: null,                hosts: null,                                                stripAt: false, stripPath: null }
16}
17
18export default class extends NestedForm {
19  static targets = [
20    "platformSelect", "handleWrapper", "handlePrefix", "handleField",
21    "urlWrapper", "urlField", "labelField", "iconPreview"
22  ]
23
24  connect() {
25    super.connect()
26    this.element.addEventListener('rails-nested-form:add', () => {
27      const newRow = this.targetTarget.previousElementSibling
28      if (newRow && newRow.matches(this.wrapperSelectorValue)) this.refreshRow(newRow)
29    })
30  }
31
32  platformChanged(event) {
33    const wrapper = event.target.closest(this.wrapperSelectorValue)
34    if (wrapper) this.refreshRow(wrapper)
35  }
36
37  refreshRow(wrapper) {
38    const select = wrapper.querySelector('[data-social-links-target="platformSelect"]')
39    if (!select) return
40    const platform = select.value
41    const cfg = PLATFORM_CONFIG[platform] || PLATFORM_CONFIG.other
42    const isOther = platform === 'other'
43
44    const handleWrapper = wrapper.querySelector('[data-social-links-target="handleWrapper"]')
45    const urlWrapper = wrapper.querySelector('[data-social-links-target="urlWrapper"]')
46    const labelField = wrapper.querySelector('[data-social-links-target="labelField"]')
47    const handlePrefix = wrapper.querySelector('[data-social-links-target="handlePrefix"]')
48    const icon = wrapper.querySelector('[data-social-links-target="iconPreview"]')
49
50    if (handleWrapper) handleWrapper.classList.toggle('hidden', isOther)
51    if (urlWrapper)    urlWrapper.classList.toggle('hidden', !isOther)
52    if (labelField)    labelField.classList.toggle('hidden', !isOther)
53    if (handlePrefix && cfg.prefix) handlePrefix.textContent = cfg.prefix
54    if (icon) icon.src = `/social/${platform}.svg`
55  }
56
57  handlePaste(event) {
58    const wrapper = event.target.closest(this.wrapperSelectorValue)
59    if (!wrapper) return
60    const select = wrapper.querySelector('[data-social-links-target="platformSelect"]')
61    if (!select) return
62    const cfg = PLATFORM_CONFIG[select.value]
63    if (!cfg || !cfg.hosts) return
64
65    const pasted = (event.clipboardData || window.clipboardData)?.getData('text') || ''
66    const handle = this.extractHandle(pasted, cfg)
67    if (handle === null) return
68
69    event.preventDefault()
70    event.target.value = handle
71  }
72
73  extractHandle(text, cfg) {
74    const trimmed = text.trim()
75    if (!trimmed) return null
76    if (!/^https?:\/\//i.test(trimmed)) return null
77    let url
78    try { url = new URL(trimmed) } catch (_) { return null }
79    const host = url.hostname.replace(/^www\./, '')
80    if (!cfg.hosts.some(h => host === h || host.endsWith('.' + h))) return null
81    let path = url.pathname.replace(/^\/+/, '')
82    if (cfg.stripPath && path.startsWith(cfg.stripPath)) path = path.slice(cfg.stripPath.length)
83    if (cfg.stripAt && path.startsWith('@')) path = path.slice(1)
84    return path
85  }
86}

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.