{"version":3,"sources":["../src/index.ts","../src/youtube.ts","../src/utils.ts"],"sourcesContent":["import { Youtube } from './youtube.js'\n\nexport * from './youtube.js'\n\nexport default Youtube\n","import { createAtomBlockMarkdownSpec, mergeAttributes, Node, nodePasteRule } from '@tiptap/core'\n\nimport { getEmbedUrlFromYoutubeUrl, isValidYoutubeUrl, YOUTUBE_REGEX_GLOBAL } from './utils.js'\n\nexport interface YoutubeOptions {\n  /**\n   * Controls if the paste handler for youtube videos should be added.\n   * @default true\n   * @example false\n   */\n  addPasteHandler: boolean\n\n  /**\n   * Controls if the youtube video should be allowed to go fullscreen.\n   * @default true\n   * @example false\n   */\n  allowFullscreen: boolean\n\n  /**\n   * Controls if the youtube video should autoplay.\n   * @default false\n   * @example true\n   */\n  autoplay: boolean\n\n  /**\n   * The language of the captions shown in the youtube video.\n   * @default undefined\n   * @example 'en'\n   */\n  ccLanguage?: string\n\n  /**\n   * Controls if the captions should be shown in the youtube video.\n   * @default undefined\n   * @example true\n   */\n  ccLoadPolicy?: boolean\n\n  /**\n   * Controls if the controls should be shown in the youtube video.\n   * @default true\n   * @example false\n   */\n  controls: boolean\n\n  /**\n   * Controls if the keyboard controls should be disabled in the youtube video.\n   * @default false\n   * @example true\n   */\n  disableKBcontrols: boolean\n\n  /**\n   * Controls if the iframe api should be enabled in the youtube video.\n   * @default false\n   * @example true\n   */\n  enableIFrameApi: boolean\n\n  /**\n   * The end time of the youtube video.\n   * @default 0\n   * @example 120\n   */\n  endTime: number\n\n  /**\n   * The height of the youtube video.\n   * @default 480\n   * @example 720\n   */\n  height: number\n\n  /**\n   * The language of the youtube video.\n   * @default undefined\n   * @example 'en'\n   */\n  interfaceLanguage?: string\n\n  /**\n   * Controls if the video annotations should be shown in the youtube video.\n   * @default 0\n   * @example 1\n   */\n  ivLoadPolicy: number\n\n  /**\n   * Controls if the youtube video should loop.\n   * @default false\n   * @example true\n   */\n  loop: boolean\n\n  /**\n   * Controls if the youtube video should show a small youtube logo.\n   * @default false\n   * @example true\n   */\n  modestBranding: boolean\n\n  /**\n   * The HTML attributes for a youtube video node.\n   * @default {}\n   * @example { class: 'foo' }\n   */\n  HTMLAttributes: Record<string, any>\n\n  /**\n   * Controls if the youtube node should be inline or not.\n   * @default false\n   * @example true\n   */\n  inline: boolean\n\n  /**\n   * Controls if the youtube video should be loaded from youtube-nocookie.com.\n   * @default false\n   * @example true\n   */\n  nocookie: boolean\n\n  /**\n   * The origin of the youtube video.\n   * @default ''\n   * @example 'https://tiptap.dev'\n   */\n  origin: string\n\n  /**\n   * The playlist of the youtube video.\n   * @default ''\n   * @example 'PLQg6GaokU5CwiVmsZ0dZm6VeIg0V5z1tK'\n   */\n  playlist: string\n\n  /**\n   * The color of the youtube video progress bar.\n   * @default undefined\n   * @example 'red'\n   */\n  progressBarColor?: string\n\n  /**\n   * The width of the youtube video.\n   * @default 640\n   * @example 1280\n   */\n  width: number\n\n  /**\n   * Controls if the related youtube videos at the end are from the same channel.\n   * @default 1\n   * @example 0\n   */\n  rel: number\n}\n\n/**\n * The options for setting a youtube video.\n */\ntype SetYoutubeVideoOptions = { src: string; width?: number; height?: number; start?: number }\n\ndeclare module '@tiptap/core' {\n  interface Commands<ReturnType> {\n    youtube: {\n      /**\n       * Insert a youtube video\n       * @param options The youtube video attributes\n       * @example editor.commands.setYoutubeVideo({ src: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ' })\n       */\n      setYoutubeVideo: (options: SetYoutubeVideoOptions) => ReturnType\n    }\n  }\n}\n\n/**\n * This extension adds support for youtube videos.\n * @see https://www.tiptap.dev/api/nodes/youtube\n */\nexport const Youtube = Node.create<YoutubeOptions>({\n  name: 'youtube',\n\n  addOptions() {\n    return {\n      addPasteHandler: true,\n      allowFullscreen: true,\n      autoplay: false,\n      ccLanguage: undefined,\n      ccLoadPolicy: undefined,\n      controls: true,\n      disableKBcontrols: false,\n      enableIFrameApi: false,\n      endTime: 0,\n      height: 480,\n      interfaceLanguage: undefined,\n      ivLoadPolicy: 0,\n      loop: false,\n      modestBranding: false,\n      HTMLAttributes: {},\n      inline: false,\n      nocookie: false,\n      origin: '',\n      playlist: '',\n      progressBarColor: undefined,\n      width: 640,\n      rel: 1,\n    }\n  },\n\n  inline() {\n    return this.options.inline\n  },\n\n  group() {\n    return this.options.inline ? 'inline' : 'block'\n  },\n\n  draggable: true,\n\n  addAttributes() {\n    return {\n      src: {\n        default: null,\n      },\n      start: {\n        default: 0,\n      },\n      width: {\n        default: this.options.width,\n      },\n      height: {\n        default: this.options.height,\n      },\n    }\n  },\n\n  parseHTML() {\n    return [\n      {\n        tag: 'div[data-youtube-video] iframe',\n      },\n    ]\n  },\n\n  addCommands() {\n    return {\n      setYoutubeVideo:\n        (options: SetYoutubeVideoOptions) =>\n        ({ commands }) => {\n          if (!isValidYoutubeUrl(options.src)) {\n            return false\n          }\n\n          return commands.insertContent({\n            type: this.name,\n            attrs: options,\n          })\n        },\n    }\n  },\n\n  addPasteRules() {\n    if (!this.options.addPasteHandler) {\n      return []\n    }\n\n    return [\n      nodePasteRule({\n        find: YOUTUBE_REGEX_GLOBAL,\n        type: this.type,\n        getAttributes: match => {\n          return { src: match.input }\n        },\n      }),\n    ]\n  },\n\n  renderHTML({ HTMLAttributes }) {\n    const embedUrl = getEmbedUrlFromYoutubeUrl({\n      url: HTMLAttributes.src,\n      allowFullscreen: this.options.allowFullscreen,\n      autoplay: this.options.autoplay,\n      ccLanguage: this.options.ccLanguage,\n      ccLoadPolicy: this.options.ccLoadPolicy,\n      controls: this.options.controls,\n      disableKBcontrols: this.options.disableKBcontrols,\n      enableIFrameApi: this.options.enableIFrameApi,\n      endTime: this.options.endTime,\n      interfaceLanguage: this.options.interfaceLanguage,\n      ivLoadPolicy: this.options.ivLoadPolicy,\n      loop: this.options.loop,\n      modestBranding: this.options.modestBranding,\n      nocookie: this.options.nocookie,\n      origin: this.options.origin,\n      playlist: this.options.playlist,\n      progressBarColor: this.options.progressBarColor,\n      startAt: HTMLAttributes.start || 0,\n      rel: this.options.rel,\n    })\n\n    HTMLAttributes.src = embedUrl\n\n    return [\n      'div',\n      { 'data-youtube-video': '' },\n      [\n        'iframe',\n        mergeAttributes(\n          this.options.HTMLAttributes,\n          {\n            width: this.options.width,\n            height: this.options.height,\n            allowfullscreen: this.options.allowFullscreen,\n            autoplay: this.options.autoplay,\n            ccLanguage: this.options.ccLanguage,\n            ccLoadPolicy: this.options.ccLoadPolicy,\n            disableKBcontrols: this.options.disableKBcontrols,\n            enableIFrameApi: this.options.enableIFrameApi,\n            endTime: this.options.endTime,\n            interfaceLanguage: this.options.interfaceLanguage,\n            ivLoadPolicy: this.options.ivLoadPolicy,\n            loop: this.options.loop,\n            modestBranding: this.options.modestBranding,\n            origin: this.options.origin,\n            playlist: this.options.playlist,\n            progressBarColor: this.options.progressBarColor,\n            rel: this.options.rel,\n          },\n          HTMLAttributes,\n        ),\n      ],\n    ]\n  },\n\n  ...createAtomBlockMarkdownSpec({\n    nodeName: 'youtube',\n    allowedAttributes: ['src', 'width', 'height', 'start'],\n  }),\n})\n","export const YOUTUBE_REGEX =\n  /^((?:https?:)?\\/\\/)?((?:www|m|music)\\.)?((?:youtube\\.com|youtu\\.be|youtube-nocookie\\.com))(\\/(?:[\\w-]+\\?v=|embed\\/|v\\/)?)([\\w-]+)(\\S+)?$/\nexport const YOUTUBE_REGEX_GLOBAL =\n  /^((?:https?:)?\\/\\/)?((?:www|m|music)\\.)?((?:youtube\\.com|youtu\\.be|youtube-nocookie\\.com))(\\/(?:[\\w-]+\\?v=|embed\\/|v\\/)?)([\\w-]+)(\\S+)?$/g\n\nexport const isValidYoutubeUrl = (url: string) => {\n  return url.match(YOUTUBE_REGEX)\n}\n\nexport interface GetEmbedUrlOptions {\n  url: string\n  allowFullscreen?: boolean\n  autoplay?: boolean\n  ccLanguage?: string\n  ccLoadPolicy?: boolean\n  controls?: boolean\n  disableKBcontrols?: boolean\n  enableIFrameApi?: boolean\n  endTime?: number\n  interfaceLanguage?: string\n  ivLoadPolicy?: number\n  loop?: boolean\n  modestBranding?: boolean\n  nocookie?: boolean\n  origin?: string\n  playlist?: string\n  progressBarColor?: string\n  startAt?: number\n  rel?: number\n}\n\nexport const getYoutubeEmbedUrl = (nocookie?: boolean, isPlaylist?: boolean) => {\n  if (isPlaylist) {\n    return 'https://www.youtube-nocookie.com/embed/videoseries?list='\n  }\n  return nocookie ? 'https://www.youtube-nocookie.com/embed/' : 'https://www.youtube.com/embed/'\n}\n\nexport const getEmbedUrlFromYoutubeUrl = (options: GetEmbedUrlOptions) => {\n  const {\n    url,\n    allowFullscreen,\n    autoplay,\n    ccLanguage,\n    ccLoadPolicy,\n    controls,\n    disableKBcontrols,\n    enableIFrameApi,\n    endTime,\n    interfaceLanguage,\n    ivLoadPolicy,\n    loop,\n    modestBranding,\n    nocookie,\n    origin,\n    playlist,\n    progressBarColor,\n    startAt,\n    rel,\n  } = options\n\n  if (!isValidYoutubeUrl(url)) {\n    return null\n  }\n\n  // if is already an embed url, return it\n  if (url.includes('/embed/')) {\n    return url\n  }\n\n  // if is a youtu.be url, get the id after the /\n  if (url.includes('youtu.be')) {\n    const id = url.split('/').pop()\n\n    if (!id) {\n      return null\n    }\n    return `${getYoutubeEmbedUrl(nocookie)}${id}`\n  }\n\n  const videoIdRegex = /(?:(v|list)=|shorts\\/)([-\\w]+)/gm\n  const matches = videoIdRegex.exec(url)\n\n  if (!matches || !matches[2]) {\n    return null\n  }\n\n  let outputUrl = `${getYoutubeEmbedUrl(nocookie, matches[1] === 'list')}${matches[2]}`\n\n  const params = []\n\n  if (allowFullscreen === false) {\n    params.push('fs=0')\n  }\n\n  if (autoplay) {\n    params.push('autoplay=1')\n  }\n\n  if (ccLanguage) {\n    params.push(`cc_lang_pref=${ccLanguage}`)\n  }\n\n  if (ccLoadPolicy) {\n    params.push('cc_load_policy=1')\n  }\n\n  if (!controls) {\n    params.push('controls=0')\n  }\n\n  if (disableKBcontrols) {\n    params.push('disablekb=1')\n  }\n\n  if (enableIFrameApi) {\n    params.push('enablejsapi=1')\n  }\n\n  if (endTime) {\n    params.push(`end=${endTime}`)\n  }\n\n  if (interfaceLanguage) {\n    params.push(`hl=${interfaceLanguage}`)\n  }\n\n  if (ivLoadPolicy) {\n    params.push(`iv_load_policy=${ivLoadPolicy}`)\n  }\n\n  if (loop) {\n    params.push('loop=1')\n  }\n\n  if (modestBranding) {\n    params.push('modestbranding=1')\n  }\n\n  if (origin) {\n    params.push(`origin=${origin}`)\n  }\n\n  if (playlist) {\n    params.push(`playlist=${playlist}`)\n  }\n\n  if (startAt) {\n    params.push(`start=${startAt}`)\n  }\n\n  if (progressBarColor) {\n    params.push(`color=${progressBarColor}`)\n  }\n\n  if (rel !== undefined) {\n    params.push(`rel=${rel}`)\n  }\n\n  if (params.length) {\n    outputUrl += `${matches[1] === 'list' ? '&' : '?'}${params.join('&')}`\n  }\n\n  return outputUrl\n}\n"],"mappings":"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","names":[]}