Comme indiqué dans notre Politique de confidentialité, nous recueillons des renseignements personnels lors de vos interactions avec nous et notre site Web, notamment grâce à l'utilisation de témoins (cookies) et de technologies similaires. Nous pouvons également partager ces renseignements personnels avec des tiers, y compris des partenaires publicitaires. Nous le faisons afin de vous présenter des publicités sur d'autres sites Web qui correspondent davantage à vos centres d'intérêt, et pour d'autres raisons décrites dans notre Politique de confidentialité.
En vertu des lois sur la protection de la vie privée en vigueur dans certains États américains, le partage de vos informations personnelles, basé sur vos interactions sur différents sites web, à des fins de publicité ciblée peut être considéré comme de la « vente », du « partage » ou de la « publicité ciblée ». Selon votre lieu de résidence, vous pouvez avoir le droit de vous opposer à ces pratiques. Si vous souhaitez exercer ce droit, veuillez suivre les instructions ci-dessous.
Si vous visitez notre site Web avec l'option de désactivation « Contrôles globaux de confidentialité » activée, nous considérerons automatiquement, en fonction de votre localisation, qu'il s'agit d'une demande de désactivation des activités suivantes : les activités pouvant être considérées comme de la « vente » ou du « partage » d'informations personnelles, ou d'autres activités pouvant être considérées comme de la publicité ciblée sur l'appareil et le navigateur que vous utilisez pour accéder au site Web.
Find Your Part By Brand and Model OR OEM Part Number
Loading...
Loading products...
(function() {
var STOREFRONT_TOKEN = '023adb4fad851d8f82aa1eefdb4ed95c';
var SHOP_DOMAIN = 'meckorn.com';
var API_URL = 'https://' + SHOP_DOMAIN + '/api/2025-01/graphql.json';
var PER_PAGE = 24;
var allProducts = [];
var selections = { brand: '', model: '', barLength: '', pitch: '', gauge: '', dl: '' };
var currentPage = 1;
var QUERY = 'query GetChainProducts($cursor: String) {'
+ ' products(first: 50, after: $cursor, query: "product_type:*Chainsaw Chain*") {'
+ ' pageInfo { hasNextPage endCursor }'
+ ' edges { node {'
+ ' id title handle'
+ ' featuredImage { url altText }'
+ ' priceRange { minVariantPrice { amount currencyCode } }'
+ ' barLength: metafield(namespace: "custom", key: "bar_length") { value }'
+ ' pitch: metafield(namespace: "custom", key: "pitch") { value }'
+ ' gauge: metafield(namespace: "custom", key: "gauge") { value }'
+ ' driveLinks: metafield(namespace: "custom", key: "drive_links") { value }'
+ ' modelRef: metafield(namespace: "custom", key: "model") {'
+ ' references(first: 25) { nodes { ... on Metaobject {'
+ ' modelField: field(key: "model") { value }'
+ ' brandRef: field(key: "numbers") { reference { ... on Metaobject { displayName: field(key: "name") { value } } } }'
+ ' } } }'
+ ' }'
+ ' } } }'
+ '}';
function gql(query, variables) {
return fetch(API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Shopify-Storefront-Access-Token': STOREFRONT_TOKEN
},
body: JSON.stringify({ query: query, variables: variables || {} })
}).then(function(res) { return res.json(); });
}
function fetchAllProducts() {
var products = [];
var cursor = null;
var hasMore = true;
function next() {
if (!hasMore) return Promise.resolve(products);
return gql(QUERY, { cursor: cursor }).then(function(data) {
var conn = data && data.data && data.data.products;
if (!conn) return products;
conn.edges.forEach(function(edge) {
var node = edge.node;
var brands = [], models = [];
var nodes = (node.modelRef && node.modelRef.references && node.modelRef.references.nodes) || [];
nodes.forEach(function(mo) {
var modelVal = mo.modelField && mo.modelField.value;
if (modelVal) {
modelVal.split(/[,\uff0c]/).forEach(function(s) {
var t = s.trim();
if (t) models.push(t);
});
}
var brandName = mo.brandRef && mo.brandRef.reference && mo.brandRef.reference.displayName && mo.brandRef.reference.displayName.value;
if (brandName && brands.indexOf(brandName) === -1) brands.push(brandName);
});
products.push({
id: node.id,
title: node.title,
handle: node.handle,
imageUrl: node.featuredImage ? node.featuredImage.url : null,
imageAlt: node.featuredImage ? node.featuredImage.altText : node.title,
price: node.priceRange && node.priceRange.minVariantPrice ? node.priceRange.minVariantPrice.amount : null,
currency: node.priceRange && node.priceRange.minVariantPrice ? node.priceRange.minVariantPrice.currencyCode : null,
_dims: {
brand: brands,
model: models,
barLength: node.barLength && node.barLength.value ? [node.barLength.value] : [],
pitch: node.pitch && node.pitch.value ? [node.pitch.value] : [],
gauge: node.gauge && node.gauge.value ? [node.gauge.value] : [],
dl: node.driveLinks && node.driveLinks.value ? [node.driveLinks.value] : []
}
});
});
hasMore = conn.pageInfo.hasNextPage;
cursor = conn.pageInfo.endCursor;
return next();
});
}
return next();
}
function getOptions(dim) {
var others = Object.keys(selections).filter(function(d) { return d !== dim; });
var compatible = allProducts.filter(function(p) {
return others.every(function(d) {
if (!selections[d]) return true;
var vals = p._dims[d];
return !vals || vals.length === 0 || vals.indexOf(selections[d]) !== -1;
});
});
var set = {};
compatible.forEach(function(p) {
(p._dims[dim] || []).forEach(function(v) { if (v) set[v] = true; });
});
return Object.keys(set).sort(function(a, b) {
return a.localeCompare(b, undefined, { numeric: true });
});
}
function getMatched() {
return allProducts.filter(function(p) {
return Object.keys(selections).every(function(d) {
if (!selections[d]) return true;
var vals = p._dims[d];
return !vals || vals.length === 0 || vals.indexOf(selections[d]) !== -1;
});
});
}
function formatPrice(amount, currency) {
if (!amount) return '';
try {
return new Intl.NumberFormat(undefined, { style: 'currency', currency: currency || 'USD' }).format(amount);
} catch(e) {
return '$' + parseFloat(amount).toFixed(2);
}
}
function renderDropdown(dim) {
var input = document.querySelector('input[data-dim="' + dim + '"]');
var ul = document.querySelector('.cf-dropdown[data-dim="' + dim + '"]');
if (!input || !ul) return;
var opts = getOptions(dim);
var query = input.value.trim().toLowerCase();
var effectiveQuery = (query && query !== (selections[dim] || '').toLowerCase()) ? query : '';
var filtered = effectiveQuery ? opts.filter(function(o) { return o.toLowerCase().indexOf(effectiveQuery) !== -1; }) : opts;
ul.innerHTML = '';
if (selections[dim]) {
var li = document.createElement('li');
li.className = 'clear-item';
li.textContent = '— Clear selection —';
li.addEventListener('mousedown', function(e) {
e.preventDefault();
selections[dim] = '';
input.value = '';
input.classList.remove('has-value');
updateAll();
});
ul.appendChild(li);
}
if (filtered.length === 0) {
var li2 = document.createElement('li');
li2.className = 'no-match';
li2.textContent = effectiveQuery ? 'No matches' : 'No options available';
ul.appendChild(li2);
} else {
filtered.forEach(function(opt) {
var li3 = document.createElement('li');
li3.textContent = opt;
if (opt === selections[dim]) li3.classList.add('selected');
li3.addEventListener('mousedown', function(e) {
e.preventDefault();
selections[dim] = opt;
input.value = opt;
input.classList.add('has-value');
ul.classList.remove('open');
updateAll();
});
ul.appendChild(li3);
});
}
}
function renderResults() {
var matched = getMatched();
var total = matched.length;
var totalPages = Math.max(1, Math.ceil(total / PER_PAGE));
if (currentPage > totalPages) currentPage = 1;
var paged = matched.slice((currentPage - 1) * PER_PAGE, currentPage * PER_PAGE);
document.getElementById('cf-count').textContent = total + ' product' + (total !== 1 ? 's' : '') + ' matched';
var grid = document.getElementById('cf-grid');
if (paged.length === 0) {
grid.innerHTML = '
No products match your selection. Try adjusting your filters.
';
} else {
var html = '';
paged.forEach(function(p) {
var imgHtml = p.imageUrl
? ''
: '