Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 84 additions & 33 deletions src/lib/components/market/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {rgAsset} from '../../types/steam';
import {rgAsset, rgInternalDescription} from '../../types/steam';
import {ItemInfo} from '../../bridge/handlers/fetch_inspect_info';
import {AppId, ContextId} from '../../types/steam_constants';

Expand All @@ -17,58 +17,109 @@ export function getMarketInspectLink(listingId: string): string | undefined {
return asset.market_actions[0].link.replace('%listingid%', listingId).replace('%assetid%', asset.id);
}

/**
* Inlines stickers into a market item row HTML showing the image and wear
*
* @param itemNameBlock Element with `.market_listing_item_name_block`
* @param itemInfo Item Info for the item from csfloat API
* @param asset Steam Asset for the item
*/
export function inlineStickers(itemNameBlock: JQuery<Element>, itemInfo: ItemInfo, asset: rgAsset) {
if (!itemNameBlock) return;

if (itemNameBlock.find('.csfloat-stickers-container').length) {
// Don't inline stickers if they're already inlined
function getStickerDescription(itemInfo: ItemInfo, asset: rgAsset): rgInternalDescription | undefined {
if (!itemInfo.stickers?.length) {
return;
}

const lastDescription = asset.descriptions[asset.descriptions.length - 1];
if (itemInfo.keychains?.length > 0) {
// if they have a keychain, it is the second last description
return asset.descriptions[asset.descriptions.length - 2];
} else {
return asset.descriptions[asset.descriptions.length - 1];
}
}

if (lastDescription.type !== 'html' || !lastDescription.value.includes('sticker')) {
function getKeychainDescription(itemInfo: ItemInfo, asset: rgAsset): rgInternalDescription | undefined {
if (!itemInfo.keychains?.length) {
return;
}

const nameMatch = lastDescription.value.match(/<br>([^<].*?): (.*)<\/center>/);
const imagesHtml = lastDescription.value.match(/(<img .*?>)/g);
return asset.descriptions[asset.descriptions.length - 1];
}

enum AppliedType {
Charm = 'Charm',
Sticker = 'Sticker',
}

function generateAppliedInlineHTML(
description: rgInternalDescription,
type: AppliedType,
textFormatFn: (index: number) => string
) {
const nameMatch = description.value.match(/<br>([^<].*?): (.*)<\/center>/);
const imagesHtml = description.value.match(/(<img .*?>)/g);

if (!nameMatch || !imagesHtml) {
return;
return [];
}

const stickerLang = nameMatch[1];
const stickerNames = nameMatch[2].split(', ');
const parsedType = nameMatch[1];
const names = nameMatch[2].split(', ');

const result = imagesHtml
.map((imageHtml, i) => {
const url =
stickerLang === 'Sticker'
? `https://steamcommunity.com/market/listings/730/${stickerLang} | ${stickerNames[i]}`
: `https://steamcommunity.com/market/search?q=${stickerLang} | ${stickerNames[i]}`;
return imagesHtml.map((imageHtml, i) => {
const url =
parsedType === type
? `https://steamcommunity.com/market/listings/730/${parsedType} | ${names[i]}`
: `https://steamcommunity.com/market/search?q=${parsedType} | ${names[i]}`;

const sticker = itemInfo.stickers[i];

return `<span style="display: inline-block; text-align: center;">
return `<span style="display: inline-block; text-align: center;">
<a target="_blank" href="${url}">${imagesHtml[i]}</a>
<span style="display: block;">
${Math.round(100 * (sticker?.wear || 0)) + '%'}
${textFormatFn(i)}
</span>
</span>`;
})
.reduce((acc, v) => acc + v, '');
});
}

function generateStickerInlineHTML(itemInfo: ItemInfo, asset: rgAsset): string[] {
const description = getStickerDescription(itemInfo, asset);

if (!description || description.type !== 'html' || !description.value.includes('sticker')) {
return [];
}

return generateAppliedInlineHTML(description, AppliedType.Sticker, (index) => {
return `${Math.round(100 * (itemInfo.stickers[index]?.wear || 0)) + '%'}`;
});
}

function generateKeychainInlineHTML(itemInfo: ItemInfo, asset: rgAsset): string[] {
const description = getKeychainDescription(itemInfo, asset);

if (!description || description.type !== 'html' || !description.value.includes('sticker')) {
return [];
}

return generateAppliedInlineHTML(description, AppliedType.Charm, (index) => {
return `#${itemInfo.keychains[index]?.pattern}`;
});
}

/**
* Inlines stickers into a market item row HTML showing the image and wear
*
* @param itemNameBlock Element with `.market_listing_item_name_block`
* @param itemInfo Item Info for the item from csfloat API
* @param asset Steam Asset for the item
*/
export function inlineStickersAndKeychains(itemNameBlock: JQuery<Element>, itemInfo: ItemInfo, asset: rgAsset) {
if (!itemNameBlock) return;

if (itemNameBlock.find('.csfloat-stickers-container').length) {
// Don't inline stickers if they're already inlined
return;
}

const blobs = [...generateStickerInlineHTML(itemInfo, asset), ...generateKeychainInlineHTML(itemInfo, asset)];
if (blobs.length === 0) {
return;
}

itemNameBlock.prepend(`
<div class="csfloat-stickers-container">
${result}
${blobs.reduce((acc, v) => acc + v, '')}
</div>
`);
}
Expand Down
4 changes: 2 additions & 2 deletions src/lib/components/market/item_row_wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {cache} from 'decorator-cache-getter';
import {rgAsset, ListingData} from '../../types/steam';
import {gFloatFetcher} from '../../services/float_fetcher';
import {ItemInfo} from '../../bridge/handlers/fetch_inspect_info';
import {getMarketInspectLink, inlineEasyInspect, inlineStickers} from './helpers';
import {getMarketInspectLink, inlineEasyInspect, inlineStickersAndKeychains} from './helpers';
import {formatSeed, getFadePercentage, isSkin, renderClickableRank, floor, isCharm} from '../../utils/skin';
import {gFilterService} from '../../services/filter';
import {AppId, ContextId, Currency} from '../../types/steam_constants';
Expand Down Expand Up @@ -112,7 +112,7 @@ export class ItemRowWrapper extends FloatElement {
}

if (this.itemInfo && this.asset) {
inlineStickers(
inlineStickersAndKeychains(
$J(this).parent().parent().find('.market_listing_item_name_block'),
this.itemInfo,
this.asset
Expand Down
10 changes: 6 additions & 4 deletions src/lib/types/steam.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,19 @@ export interface WalletInfo {
wallet_currency: number;
}

export interface rgInternalDescription {
type: string;
value: string;
}

// rgDescriptions
export interface rgDescription {
appid: AppId;
actions?: Action[];
background_color: string;
classid: string;
commodity: number;
descriptions: {
type: string;
value: string;
}[];
descriptions: rgInternalDescription[];
fraudwarnings?: string[];
icon_url: string;
icon_url_large: string;
Expand Down
Loading