Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/browser/extensions/screenshots/build/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 24 kB image not shown  

Quellcode-Bibliothek shot.js   Sprache: JAVA

 
/* 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/. */


/* globals process, require */

this.shot = (function () {
  let exports = {}; // Note: in this library we can't use any "system" dependencies because this can be used from multiple
  // environments

  const isNode =
    typeof process !== "undefined" &&
    Object.prototype.toString.call(process) === "[object process]";
  const URL = (isNode && require("url").URL) || window.URL;

  /** Throws an error if the condition isn't true.  Any extra arguments after the condition
    are used as console.error() arguments. */

  function assert(condition, ...args) {
    if (condition) {
      return;
    }
    console.error("Failed assertion", ...args);
    throw new Error(`Failed assertion: ${args.join(" ")}`);
  }

  /** True if `url` is a valid URL */
  function isUrl(url) {
    try {
      const parsed = new URL(url);

      if (parsed.protocol === "view-source:") {
        return isUrl(url.substr("view-source:".length));
      }

      return true;
    } catch (e) {
      return false;
    }
  }

  function isValidClipImageUrl(url) {
    return isUrl(url) && !(url.indexOf(")") > -1);
  }

  function assertUrl(url) {
    if (!url) {
      throw new Error("Empty value is not URL");
    }
    if (!isUrl(url)) {
      const exc = new Error("Not a URL");
      exc.scheme = url.split(":")[0];
      throw exc;
    }
  }

  function isSecureWebUri(url) {
    return isUrl(url) && url.toLowerCase().startsWith("https");
  }

  function assertOrigin(url) {
    assertUrl(url);
    if (url.search(/^https?:/i) !== -1) {
      let newUrl = new URL(url);
      if (newUrl.pathname != "/") {
        throw new Error("Bad origin, might include path");
      }
    }
  }

  function originFromUrl(url) {
    if (!url) {
      return null;
    }
    if (url.search(/^https?:/i) === -1) {
      // Non-HTTP URLs don't have an origin
      return null;
    }
    try {
      let tryUrl = new URL(url);
      return tryUrl.origin;
    } catch {
      return null;
    }
  }

  /** Check if the given object has all of the required attributes, and no extra
    attributes exception those in optional */

  function checkObject(obj, required, optional) {
    if (typeof obj !== "object" || obj === null) {
      throw new Error(
        "Cannot check non-object: " +
          typeof obj +
          " that is " +
          JSON.stringify(obj)
      );
    }
    required = required || [];
    for (const attr of required) {
      if (!(attr in obj)) {
        return false;
      }
    }
    optional = optional || [];
    for (const attr in obj) {
      if (!required.includes(attr) && !optional.includes(attr)) {
        return false;
      }
    }
    return true;
  }

  /** Create a JSON object from a normal object, given the required and optional
    attributes (filtering out any other attributes).  Optional attributes are
    only kept when they are truthy. */

  function jsonify(obj, required, optional) {
    required = required || [];
    const result = {};
    for (const attr of required) {
      result[attr] = obj[attr];
    }
    optional = optional || [];
    for (const attr of optional) {
      if (obj[attr]) {
        result[attr] = obj[attr];
      }
    }
    return result;
  }

  /** True if the two objects look alike.  Null, undefined, and absent properties
    are all treated as equivalent.  Traverses objects and arrays */

  function deepEqual(a, b) {
    if ((a === null || a === undefined) && (b === null || b === undefined)) {
      return true;
    }
    if (typeof a !== "object" || typeof b !== "object") {
      return a === b;
    }
    if (Array.isArray(a)) {
      if (!Array.isArray(b)) {
        return false;
      }
      if (a.length !== b.length) {
        return false;
      }
      for (let i = 0; i < a.length; i++) {
        if (!deepEqual(a[i], b[i])) {
          return false;
        }
      }
    }
    if (Array.isArray(b)) {
      return false;
    }
    const seen = new Set();
    for (const attr of Object.keys(a)) {
      if (!deepEqual(a[attr], b[attr])) {
        return false;
      }
      seen.add(attr);
    }
    for (const attr of Object.keys(b)) {
      if (!seen.has(attr)) {
        if (!deepEqual(a[attr], b[attr])) {
          return false;
        }
      }
    }
    return true;
  }

  function makeRandomId() {
    // Note: this isn't for secure contexts, only for non-conflicting IDs
    let id = "";
    while (id.length < 12) {
      let num;
      if (!id) {
        num = Date.now() % Math.pow(36, 3);
      } else {
        num = Math.floor(Math.random() * Math.pow(36, 3));
      }
      id += num.toString(36);
    }
    return id;
  }

  class AbstractShot {
    constructor(backend, id, attrs) {
      attrs = attrs || {};
      assert(
        /^[a-zA-Z0-9]{1,4000}\/[a-z0-9._-]{1,4000}$/.test(id),
        "Bad ID (should be alphanumeric):",
        JSON.stringify(id)
      );
      this._backend = backend;
      this._id = id;
      this.origin = attrs.origin || null;
      this.fullUrl = attrs.fullUrl || null;
      if (!attrs.fullUrl && attrs.url) {
        console.warn("Received deprecated attribute .url");
        this.fullUrl = attrs.url;
      }
      if (this.origin && !isSecureWebUri(this.origin)) {
        this.origin = "";
      }
      if (this.fullUrl && !isSecureWebUri(this.fullUrl)) {
        this.fullUrl = "";
      }
      this.docTitle = attrs.docTitle || null;
      this.userTitle = attrs.userTitle || null;
      this.createdDate = attrs.createdDate || Date.now();
      this.siteName = attrs.siteName || null;
      this.images = [];
      if (attrs.images) {
        this.images = attrs.images.map(json => new this.Image(json));
      }
      this.openGraph = attrs.openGraph || null;
      this.twitterCard = attrs.twitterCard || null;
      this.documentSize = attrs.documentSize || null;
      this.thumbnail = attrs.thumbnail || null;
      this.abTests = attrs.abTests || null;
      this.firefoxChannel = attrs.firefoxChannel || null;
      this._clips = {};
      if (attrs.clips) {
        for (const clipId in attrs.clips) {
          const clip = attrs.clips[clipId];
          this._clips[clipId] = new this.Clip(this, clipId, clip);
        }
      }

      const isProd =
        typeof process !== "undefined" && process.env.NODE_ENV === "production";

      for (const attr in attrs) {
        if (
          attr !== "clips" &&
          attr !== "id" &&
          !this.REGULAR_ATTRS.includes(attr) &&
          !this.DEPRECATED_ATTRS.includes(attr)
        ) {
          if (isProd) {
            console.warn("Unexpected attribute: " + attr);
          } else {
            throw new Error("Unexpected attribute: " + attr);
          }
        } else if (attr === "id") {
          console.warn("passing id in attrs in AbstractShot constructor");
          console.trace();
          assert(attrs.id === this.id);
        }
      }
    }

    /** Update any and all attributes in the json object, with deep updating
      of `json.clips` */

    update(json) {
      const ALL_ATTRS = ["clips"].concat(this.REGULAR_ATTRS);
      assert(
        checkObject(json, [], ALL_ATTRS),
        "Bad attr to new Shot():",
        Object.keys(json)
      );
      for (const attr in json) {
        if (attr === "clips") {
          continue;
        }
        if (
          typeof json[attr] === "object" &&
          typeof this[attr] === "object" &&
          this[attr] !== null
        ) {
          let val = this[attr];
          if (val.toJSON) {
            val = val.toJSON();
          }
          if (!deepEqual(json[attr], val)) {
            this[attr] = json[attr];
          }
        } else if (json[attr] !== this[attr] && (json[attr] || this[attr])) {
          this[attr] = json[attr];
        }
      }
      if (json.clips) {
        for (const clipId in json.clips) {
          if (!json.clips[clipId]) {
            this.delClip(clipId);
          } else if (!this.getClip(clipId)) {
            this.setClip(clipId, json.clips[clipId]);
          } else if (
            !deepEqual(this.getClip(clipId).toJSON(), json.clips[clipId])
          ) {
            this.setClip(clipId, json.clips[clipId]);
          }
        }
      }
    }

    /** Returns a JSON version of this shot */
    toJSON() {
      const result = {};
      for (const attr of this.REGULAR_ATTRS) {
        let val = this[attr];
        if (val && val.toJSON) {
          val = val.toJSON();
        }
        result[attr] = val;
      }
      result.clips = {};
      for (const attr in this._clips) {
        result.clips[attr] = this._clips[attr].toJSON();
      }
      return result;
    }

    /** A more minimal JSON representation for creating indexes of shots */
    asRecallJson() {
      const result = { clips: {} };
      for (const attr of this.RECALL_ATTRS) {
        let val = this[attr];
        if (val && val.toJSON) {
          val = val.toJSON();
        }
        result[attr] = val;
      }
      for (const name of this.clipNames()) {
        result.clips[name] = this.getClip(name).toJSON();
      }
      return result;
    }

    get backend() {
      return this._backend;
    }

    get id() {
      return this._id;
    }

    get url() {
      return this.fullUrl || this.origin;
    }
    set url(val) {
      throw new Error(".url is read-only");
    }

    get fullUrl() {
      return this._fullUrl;
    }
    set fullUrl(val) {
      if (val) {
        assertUrl(val);
      }
      this._fullUrl = val || undefined;
    }

    get origin() {
      return this._origin;
    }
    set origin(val) {
      if (val) {
        assertOrigin(val);
      }
      this._origin = val || undefined;
    }

    get isOwner() {
      return this._isOwner;
    }

    set isOwner(val) {
      this._isOwner = val || undefined;
    }

    get filename() {
      let filenameTitle = this.title;
      const date = new Date(this.createdDate);
      /* eslint-disable no-control-regex */
      filenameTitle = filenameTitle
        .replace(/[\\/]/g, "_")
        .replace(/[\u200e\u200f\u202a-\u202e]/g, "")
        .replace(/[\x00-\x1f\x7f-\x9f:*?|"<>;,+=\[\]]+/g, " ")
        .replace(/^[\s\u180e.]+|[\s\u180e.]+$/g, "");
      /* eslint-enable no-control-regex */
      filenameTitle = filenameTitle.replace(/\s{1,4000}/g, " ");
      const currentDateTime = new Date(
        date.getTime() - date.getTimezoneOffset() * 60 * 1000
      ).toISOString();
      const filenameDate = currentDateTime.substring(0, 10);
      const filenameTime = currentDateTime.substring(11, 19).replace(/:/g, "-");
      let clipFilename = `Screenshot ${filenameDate} at ${filenameTime} ${filenameTitle}`;

      // Crop the filename size at less than 246 bytes, so as to leave
      // room for the extension and an ellipsis [...]. Note that JS
      // strings are UTF16 but the filename will be converted to UTF8
      // when saving which could take up more space, and we want a
      // maximum of 255 bytes (not characters). Here, we iterate
      // and crop at shorter and shorter points until we fit into
      // 255 bytes.
      let suffix = "";
      for (let cropSize = 246; cropSize >= 0; cropSize -= 32) {
        if (new Blob([clipFilename]).size > 246) {
          clipFilename = clipFilename.substring(0, cropSize);
          suffix = "[...]";
        } else {
          break;
        }
      }

      clipFilename += suffix;

      const clip = this.getClip(this.clipNames()[0]);
      let extension = ".png";
      if (clip && clip.image && clip.image.type) {
        if (clip.image.type === "jpeg") {
          extension = ".jpg";
        }
      }
      return clipFilename + extension;
    }

    get urlDisplay() {
      if (!this.url) {
        return null;
      }
      if (/^https?:\/\//i.test(this.url)) {
        let txt = this.url;
        txt = txt.replace(/^[a-z]{1,4000}:\/\//i, "");
        txt = txt.replace(/\/.{0,4000}/, "");
        txt = txt.replace(/^www\./i, "");
        return txt;
      } else if (this.url.startsWith("data:")) {
        return "data:url";
      }
      let txt = this.url;
      txt = txt.replace(/\?.{0,4000}/, "");
      return txt;
    }

    get viewUrl() {
      const url = this.backend + "/" + this.id;
      return url;
    }

    get creatingUrl() {
      let url = `${this.backend}/creating/${this.id}`;
      url += `?title=${encodeURIComponent(this.title || "")}`;
      url += `&url=${encodeURIComponent(this.url)}`;
      return url;
    }

    get jsonUrl() {
      return this.backend + "/data/" + this.id;
    }

    get oembedUrl() {
      return this.backend + "/oembed?url=" + encodeURIComponent(this.viewUrl);
    }

    get docTitle() {
      return this._title;
    }
    set docTitle(val) {
      assert(val === null || typeof val === "string""Bad docTitle:", val);
      this._title = val;
    }

    get openGraph() {
      return this._openGraph || null;
    }
    set openGraph(val) {
      assert(val === null || typeof val === "object""Bad openGraph:", val);
      if (val) {
        assert(
          checkObject(val, [], this._OPENGRAPH_PROPERTIES),
          "Bad attr to openGraph:",
          Object.keys(val)
        );
        this._openGraph = val;
      } else {
        this._openGraph = null;
      }
    }

    get twitterCard() {
      return this._twitterCard || null;
    }
    set twitterCard(val) {
      assert(val === null || typeof val === "object""Bad twitterCard:", val);
      if (val) {
        assert(
          checkObject(val, [], this._TWITTERCARD_PROPERTIES),
          "Bad attr to twitterCard:",
          Object.keys(val)
        );
        this._twitterCard = val;
      } else {
        this._twitterCard = null;
      }
    }

    get userTitle() {
      return this._userTitle;
    }
    set userTitle(val) {
      assert(val === null || typeof val === "string""Bad userTitle:", val);
      this._userTitle = val;
    }

    get title() {
      // FIXME: we shouldn't support both openGraph.title and ogTitle
      const ogTitle = this.openGraph && this.openGraph.title;
      const twitterTitle = this.twitterCard && this.twitterCard.title;
      let title =
        this.userTitle || ogTitle || twitterTitle || this.docTitle || this.url;
      if (Array.isArray(title)) {
        title = title[0];
      }
      if (!title) {
        title = "Screenshot";
      }
      return title;
    }

    get createdDate() {
      return this._createdDate;
    }
    set createdDate(val) {
      assert(val === null || typeof val === "number""Bad createdDate:", val);
      this._createdDate = val;
    }

    clipNames() {
      const names = Object.getOwnPropertyNames(this._clips);
      names.sort(function (a, b) {
        return a.sortOrder < b.sortOrder ? 1 : 0;
      });
      return names;
    }
    getClip(name) {
      return this._clips[name];
    }
    addClip(val) {
      const name = makeRandomId();
      this.setClip(name, val);
      return name;
    }
    setClip(name, val) {
      const clip = new this.Clip(this, name, val);
      this._clips[name] = clip;
    }
    delClip(name) {
      if (!this._clips[name]) {
        throw new Error("No existing clip with id: " + name);
      }
      delete this._clips[name];
    }
    delAllClips() {
      this._clips = {};
    }
    biggestClipSortOrder() {
      let biggest = 0;
      for (const clipId in this._clips) {
        biggest = Math.max(biggest, this._clips[clipId].sortOrder);
      }
      return biggest;
    }
    updateClipUrl(clipId, clipUrl) {
      const clip = this.getClip(clipId);
      if (clip && clip.image) {
        clip.image.url = clipUrl;
      } else {
        console.warn("Tried to update the url of a clip with no image:", clip);
      }
    }

    get siteName() {
      return this._siteName || null;
    }
    set siteName(val) {
      assert(typeof val === "string" || !val);
      this._siteName = val;
    }

    get documentSize() {
      return this._documentSize;
    }
    set documentSize(val) {
      assert(typeof val === "object" || !val);
      if (val) {
        assert(
          checkObject(
            val,
            ["height""width"],
            "Bad attr to documentSize:",
            Object.keys(val)
          )
        );
        assert(typeof val.height === "number");
        assert(typeof val.width === "number");
        this._documentSize = val;
      } else {
        this._documentSize = null;
      }
    }

    get thumbnail() {
      return this._thumbnail;
    }
    set thumbnail(val) {
      assert(typeof val === "string" || !val);
      if (val) {
        assert(isUrl(val));
        this._thumbnail = val;
      } else {
        this._thumbnail = null;
      }
    }

    get abTests() {
      return this._abTests;
    }
    set abTests(val) {
      if (val === null || val === undefined) {
        this._abTests = null;
        return;
      }
      assert(
        typeof val === "object",
        "abTests should be an object, not:",
        typeof val
      );
      assert(!Array.isArray(val), "abTests should not be an Array");
      for (const name in val) {
        assert(
          val[name] && typeof val[name] === "string",
          `abTests.${name} should be a string:`,
          typeof val[name]
        );
      }
      this._abTests = val;
    }

    get firefoxChannel() {
      return this._firefoxChannel;
    }
    set firefoxChannel(val) {
      if (val === null || val === undefined) {
        this._firefoxChannel = null;
        return;
      }
      assert(
        typeof val === "string",
        "firefoxChannel should be a string, not:",
        typeof val
      );
      this._firefoxChannel = val;
    }
  }

  AbstractShot.prototype.REGULAR_ATTRS = `
origin fullUrl docTitle userTitle createdDate images
siteName openGraph twitterCard documentSize
thumbnail abTests firefoxChannel
`.split(/\s+/g);

  // Attributes that will be accepted in the constructor, but ignored/dropped
  AbstractShot.prototype.DEPRECATED_ATTRS = `
microdata history ogTitle createdDevice head body htmlAttrs bodyAttrs headAttrs
readable hashtags comments showPage isPublic resources url
fullScreenThumbnail favicon
`.split(/\s+/g);

  AbstractShot.prototype.RECALL_ATTRS = `
url docTitle userTitle createdDate openGraph twitterCard images thumbnail
`.split(/\s+/g);

  AbstractShot.prototype._OPENGRAPH_PROPERTIES = `
title type url image audio description determiner locale site_name video
image:secure_url image:type image:width image:height
video:secure_url video:type video:width image:height
audio:secure_url audio:type
article:published_time article:modified_time article:expiration_time article:author article:section article:tag
book:author book:isbn book:release_date book:tag
profile:first_name profile:last_name profile:username profile:gender
`.split(/\s+/g);

  AbstractShot.prototype._TWITTERCARD_PROPERTIES = `
card site title description image
player player:width player:height player:stream player:stream:content_type
`.split(/\s+/g);

  /** Represents one found image in the document (not a clip) */
  class _Image {
    // FIXME: either we have to notify the shot of updates, or make
    // this read-only
    constructor(json) {
      assert(typeof json === "object""Clip Image given a non-object", json);
      assert(
        checkObject(json, ["url"], ["dimensions""title""alt"]),
        "Bad attrs for Image:",
        Object.keys(json)
      );
      assert(isUrl(json.url), "Bad Image url:", json.url);
      this.url = json.url;
      assert(
        !json.dimensions ||
          (typeof json.dimensions.x === "number" &&
            typeof json.dimensions.y === "number"),
        "Bad Image dimensions:",
        json.dimensions
      );
      this.dimensions = json.dimensions;
      assert(
        typeof json.title === "string" || !json.title,
        "Bad Image title:",
        json.title
      );
      this.title = json.title;
      assert(
        typeof json.alt === "string" || !json.alt,
        "Bad Image alt:",
        json.alt
      );
      this.alt = json.alt;
    }

    toJSON() {
      return jsonify(this, ["url"], ["dimensions"]);
    }
  }

  AbstractShot.prototype.Image = _Image;

  /** Represents a clip, either a text or image clip */
  class _Clip {
    constructor(shot, id, json) {
      this._shot = shot;
      assert(
        checkObject(json, ["createdDate""image"], ["sortOrder"]),
        "Bad attrs for Clip:",
        Object.keys(json)
      );
      assert(typeof id === "string" && id, "Bad Clip id:", id);
      this._id = id;
      this.createdDate = json.createdDate;
      if ("sortOrder" in json) {
        assert(
          typeof json.sortOrder === "number" || !json.sortOrder,
          "Bad Clip sortOrder:",
          json.sortOrder
        );
      }
      if ("sortOrder" in json) {
        this.sortOrder = json.sortOrder;
      } else {
        const biggestOrder = shot.biggestClipSortOrder();
        this.sortOrder = biggestOrder + 100;
      }
      this.image = json.image;
    }

    toString() {
      return `[Shot Clip id=${this.id} sortOrder=${this.sortOrder} image ${this.image.dimensions.x}x${this.image.dimensions.y}]`;
    }

    toJSON() {
      return jsonify(this, ["createdDate"], ["sortOrder""image"]);
    }

    get id() {
      return this._id;
    }

    get createdDate() {
      return this._createdDate;
    }
    set createdDate(val) {
      assert(typeof val === "number" || !val, "Bad Clip createdDate:", val);
      this._createdDate = val;
    }

    get image() {
      return this._image;
    }
    set image(image) {
      if (!image) {
        this._image = undefined;
        return;
      }
      assert(
        checkObject(
          image,
          ["url"],
          ["dimensions""text""location""captureType""type"]
        ),
        "Bad attrs for Clip Image:",
        Object.keys(image)
      );
      assert(isValidClipImageUrl(image.url), "Bad Clip image URL:", image.url);
      assert(
        image.captureType === "madeSelection" ||
          image.captureType === "selection" ||
          image.captureType === "visible" ||
          image.captureType === "auto" ||
          image.captureType === "fullPage" ||
          image.captureType === "fullPageTruncated" ||
          !image.captureType,
        "Bad image.captureType:",
        image.captureType
      );
      assert(
        typeof image.text === "string" || !image.text,
        "Bad Clip image text:",
        image.text
      );
      if (image.dimensions) {
        assert(
          typeof image.dimensions.x === "number" &&
            typeof image.dimensions.y === "number",
          "Bad Clip image dimensions:",
          image.dimensions
        );
      }
      if (image.type) {
        assert(
          image.type === "png" || image.type === "jpeg",
          "Unexpected image type:",
          image.type
        );
      }
      assert(
        image.location &&
          typeof image.location.left === "number" &&
          typeof image.location.right === "number" &&
          typeof image.location.top === "number" &&
          typeof image.location.bottom === "number",
        "Bad Clip image pixel location:",
        image.location
      );
      if (
        image.location.topLeftElement ||
        image.location.topLeftOffset ||
        image.location.bottomRightElement ||
        image.location.bottomRightOffset
      ) {
        assert(
          typeof image.location.topLeftElement === "string" &&
            image.location.topLeftOffset &&
            typeof image.location.topLeftOffset.x === "number" &&
            typeof image.location.topLeftOffset.y === "number" &&
            typeof image.location.bottomRightElement === "string" &&
            image.location.bottomRightOffset &&
            typeof image.location.bottomRightOffset.x === "number" &&
            typeof image.location.bottomRightOffset.y === "number",
          "Bad Clip image element location:",
          image.location
        );
      }
      this._image = image;
    }

    isDataUrl() {
      if (this.image) {
        return this.image.url.startsWith("data:");
      }
      return false;
    }

    get sortOrder() {
      return this._sortOrder || null;
    }
    set sortOrder(val) {
      assert(typeof val === "number" || !val, "Bad Clip sortOrder:", val);
      this._sortOrder = val;
    }
  }

  AbstractShot.prototype.Clip = _Clip;

  if (typeof exports !== "undefined") {
    exports.AbstractShot = AbstractShot;
    exports.originFromUrl = originFromUrl;
    exports.isValidClipImageUrl = isValidClipImageUrl;
  }

  return exports;
})();
null;

Messung V0.5
C=97 H=93 G=94

¤ Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.0.8Bemerkung:  ¤

*Bot Zugriff






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.