forked from mirrors/gecko-dev
106 lines
3 KiB
JavaScript
106 lines
3 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
"use strict";
|
|
|
|
var EXPORTED_SYMBOLS = ["OpenGraphPageData"];
|
|
|
|
const { PageDataCollector } = ChromeUtils.import(
|
|
"resource:///modules/pagedata/PageDataCollector.jsm"
|
|
);
|
|
|
|
/**
|
|
* @typedef {object} GeneralPageData
|
|
* Data about a product.
|
|
* @property {string | undefined} title
|
|
* The title describing the page.
|
|
* @property {string | undefined} site_name
|
|
* The name of the site the page is on.
|
|
* @property {string | undefined} type
|
|
* The type of the object being described by Open Graph. See
|
|
* https://ogp.me/#types for a list of possible types.
|
|
* @property {string | undefined} image
|
|
* A URL pointing to an image that describes the page.
|
|
* @property {string | undefined} url
|
|
* The permalink to the page.
|
|
*/
|
|
|
|
const RELEVANT_TAGS = ["title", "site_name", "image", "type", "url"];
|
|
|
|
/**
|
|
* Collects Open Graph related data from a page.
|
|
*
|
|
* TODO: Respond to DOM mutations to trigger recollection.
|
|
*/
|
|
class OpenGraphPageData extends PageDataCollector {
|
|
/**
|
|
* @see PageDataCollector.init
|
|
*/
|
|
async init() {
|
|
return this.#collect();
|
|
}
|
|
|
|
/**
|
|
* Collects data from the meta tags on the page.
|
|
* See https://ogp.me/ for the parsing spec.
|
|
*
|
|
* @param {NodeList} tags
|
|
* A NodeList of Open Graph meta tags.
|
|
* @returns {GeneralPageData}
|
|
* Data describing the webpage.
|
|
*/
|
|
#collectOpenGraphTags(tags) {
|
|
// Ensure all tags are present in the returned object, even if their values
|
|
// are undefined.
|
|
let pageData = Object.fromEntries(
|
|
RELEVANT_TAGS.map(tag => [tag, undefined])
|
|
);
|
|
|
|
for (let tag of tags) {
|
|
// Stripping "og:" from the property name.
|
|
let propertyName = tag.getAttribute("property").substring(3);
|
|
if (RELEVANT_TAGS.includes(propertyName)) {
|
|
pageData[propertyName] = tag.getAttribute("content");
|
|
}
|
|
}
|
|
|
|
return pageData;
|
|
}
|
|
|
|
/**
|
|
* Collects the existing data from the page.
|
|
*
|
|
* @returns {Data[]}
|
|
*/
|
|
#collect() {
|
|
/**
|
|
* A map from item type to an array of the items found in the page.
|
|
*/
|
|
let items = new Map();
|
|
let insert = (type, item) => {
|
|
let data = items.get(type);
|
|
if (!data) {
|
|
data = [];
|
|
items.set(type, data);
|
|
}
|
|
data.push(item);
|
|
};
|
|
|
|
// Sites can technically define an Open Graph prefix other than `og:`.
|
|
// However, `og:` is one of the default RDFa prefixes and it's likely
|
|
// uncommon that sites use a custom prefix. If we find that metadata is
|
|
// missing for common sites due to this issue, we could consider adding a
|
|
// basic RDFa parser.
|
|
let openGraphTags = this.document.querySelectorAll("meta[property^='og:'");
|
|
if (!openGraphTags.length) {
|
|
return [];
|
|
}
|
|
insert(
|
|
PageDataCollector.DATA_TYPE.GENERAL,
|
|
this.#collectOpenGraphTags(openGraphTags)
|
|
);
|
|
|
|
return Array.from(items, ([type, data]) => ({ type, data }));
|
|
}
|
|
}
|