Skip to content

Commit

Permalink
Merge pull request #268 from csfloat/feature/inline-charms
Browse files Browse the repository at this point in the history
Inlines Charms in Market Row Listings
  • Loading branch information
Step7750 authored Nov 5, 2024
2 parents 6e2da25 + 5b8e303 commit 472a633
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 39 deletions.
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

0 comments on commit 472a633

Please sign in to comment.