var API_KEY = 'PIXABAY_API';
var GOOGLE_FONTS_API_KEY = 'GOOGLE_FONTS_API_KEY';

// for legacy browsers
const AudioContext = window.AudioContext || window.webkitAudioContext;
var oldsrc, oldobj;
var oldtimelinepos;
var speed = 1;
var page = 1;
var checkstatus = false;
let db = new Localbase('db');
var wip = false;
var paused = true;
var currenttime = 0;
var timelinetime = 5;
const offset_left = 20;
var duration = 30000;
var keyframes = [];
var p_keyframes = [];
var props = [
  'left',
  'top',
  'scaleX',
  'scaleY',
  'width',
  'height',
  'angle',
  'opacity',
  'fill',
  'strokeWidth',
  'stroke',
  'shadow.color',
  'shadow.opacity',
  'shadow.offsetX',
  'shadow.offsetY',
  'shadow.blur',
  'charSpacing',
  'lineHeight',
];
var objects = [];
var o_slider, o_letter_slider, o_line_slider;
var colormode = 'fill';
var spaceDown = false;
var selectedkeyframe;
var undo = [];
var undoarr = [];
var redo = [];
var groups = [];
var redoarr = [];
var state;
var statearr = [];
var recording = false;
var canvasrecord;
var clipboard;
var focus = false;
var editingpanel = false;
var files = [];
var re = /(?:\.([^.]+))?$/;
var filelist = [];
var spacehold = false;
var spacerelease = false;
var tempselection;
var line_h, line_v;
var tempgroup = [];
var editinggroup = false;
var tempgroupid;
var fontPicker;
var fonts = [];
var seeking = false;
var setting = false;
var handtool = false;
var canvasx = 0;
var canvasy = 0;
var overCanvas = false;
var draggingPanel = false;
var cropping = false;
var cropobj;
var cropscalex;
var cropscaley;
var croptop;
var cropleft;
var layer_count = 1;
var lockmovement = false;
var shiftx = 0;
var shifty = 0;
var editinglayer = false;
var editingproject = false;
var shiftkeys = [];
var shiftdown = false;
var cliptype = 'object';
var chromaslider, noiseslider, blurslider;
var isChrome =
  window.chrome && Object.values(window.chrome).length !== 0;
var eyeDropper;
if (isChrome && typeof EyeDropper !== 'undefined') {
  eyeDropper = new EyeDropper();
}
var presets = [
  {
    name: 'Dribbble shot',
    id: 'dribbble',
    width: 1600,
    height: 1200,
  },
  { name: 'Facebook post', id: 'facebook', width: 1280, height: 720 },
  {
    name: 'Facebook ad',
    id: 'facebook-ad',
    width: 1080,
    height: 1080,
  },
  { name: 'Youtube video', id: 'youtube', width: 1920, height: 1080 },
  {
    name: 'Instagram video',
    id: 'instagram-id',
    width: 1080,
    height: 1920,
  },
  {
    name: 'Instagram stories',
    id: 'instagram-stories',
    width: 1080,
    height: 1920,
  },
  { name: 'Twitter video', id: 'twitter', width: 1280, height: 720 },
  { name: 'Snapchat ad', id: 'snapchat', width: 1080, height: 1920 },
  {
    name: 'LinkedIn video',
    id: 'linkedin',
    width: 1920,
    height: 1080,
  },
  {
    name: 'Product Hunt thumbnail',
    id: 'product-hunt',
    width: 600,
    height: 600,
  },
  {
    name: 'Pinterest ad',
    id: 'pinterest',
    width: 1080,
    height: 1920,
  },
];
var activepreset = 'custom';
var uploaded_images = [];
var uploaded_videos = [];
var uploading = false;
var background_audio = false;
var temp_audio = false;
var background_key;
var sliders = [];
var hovertime = 0;
var animatedtext = [];

// Get list of fonts.
// Both API keys are placeholders in the repository - replace them to enable
// the Google Fonts list and the Pixabay browser.
const HAS_FONTS_KEY =
  GOOGLE_FONTS_API_KEY && GOOGLE_FONTS_API_KEY != 'GOOGLE_FONTS_API_KEY';
const HAS_PIXABAY_KEY = API_KEY && API_KEY != 'PIXABAY_API';
if (HAS_FONTS_KEY) {
  $.ajax({
    url:
      'https://www.googleapis.com/webfonts/v1/webfonts?key=' +
      GOOGLE_FONTS_API_KEY +
      '&sort=alpha',
    type: 'GET',
    dataType: 'json', // added data type
    success: function (response) {
      response.items.forEach(function (item) {
        fonts.push(item.family);
      });
    },
    error: function () {
      console.warn('Could not load the Google Fonts list');
    },
  });
}

// Panel variants
const canvas_panel =
  '<div id="canvas-properties" class="panel-section"><p class="property-title">Canvas settings</p><table><tr><th class="name-col">Preset</th><th class="value-col"><select id="preset"></select></th></tr><tr><th class="name-col">Size</th><th class="value-col"><div id="canvas-w" class="property-input" data-label="W"><input type="number" min=1 value=1000></div><div id="canvas-h" class="property-input" data-label="H"><input type="number" value=1000 min=1></div></th></tr><tr><th class="name-col">Color</th><th class="value-col"><div id="canvas-color" class="object-color"><div id="color-side" class="color-picker"></div><input value="#FFFFFF" disabled="disabled"></div><div id="canvas-color-opacity" class="property-input" data-label="%"><input type="number" value=100></div></th></tr><tr><th class="name-col">Duration</th><th class="value-col" id="duration-cell"><div id="canvas-duration" class="property-input" data-label="s"><input type="number" value=15.00></div></th></tr></table></div>';
const object_panel =
  '<div id="layout-properties" class="panel-section"><p class="property-title">Layout</p><table><tr><th class="name-col">Position</th><th class="value-col"><div id="object-x" class="property-input" data-label="X"><input type="number" value=1000></div><div id="object-y" class="property-input" data-label="Y"><input value=1000 type="number"></div></th></tr><tr><th class="name-col">Size</th><th class="value-col"><div id="object-w" class="property-input" data-label="W"><input type="number" min=1 value=1000></div><div id="object-h" class="property-input" data-label="H"><input type="number" value=1000 min=1></div></th></tr><tr><th class="name-col">Rotation</th><th class="value-col" id="duration-cell"><div id="object-r" class="property-input" data-label="&#176;"><input type="number" min=0 max=360 value=0></div></th></tr></table></div>';
const back_panel =
  '<hr><div id="back-properties" class="panel-section"><p class="property-title">Layer</p><table><tr><th class="name-col">Opacity</th><th class="value-col"><div id="select-opacity"></div><div id="object-o" class="property-input" data-label="%"><input type="number" value=100></div></th></tr><tr><th class="name-col">Mask</th><th class="value-col"><select id="masks"><option value="none">None</option></select></th></tr></table></div>';
const image_panel =
  '<hr><div id="back-properties" class="panel-section"><p class="property-title">Layer</p><table><tr><th class="name-col">Opacity</th><th class="value-col"><div id="select-opacity"></div><div id="object-o" class="property-input" data-label="%"><input type="number" value=100></div></th></tr><tr><th class="name-col">Mask</th><th class="value-col"><select id="masks"><option value="none">None</option></select></th></tr></table></div>';
const selection_panel =
  '<hr><div id="back-properties" class="panel-section"><p class="property-title">Layer</p><table><tr><th class="name-col">Opacity</th><th class="value-col"><div id="select-opacity"></div><div id="object-o" class="property-input" data-label="%"><input type="number" value=100></div></th></tr><tr><th class="name-col">Group</th><th class="value-col"><div id="group-objects">Group selection</div></th></tr></table></div>';
const group_panel =
  '<hr><div id="back-properties" class="panel-section"><p class="property-title">Layer</p><table><tr><th class="name-col">Opacity</th><th class="value-col"><div id="select-opacity"></div><div id="object-o" class="property-input" data-label="%"><input type="number" value=100></div></th></tr><tr><th class="name-col">Mask</th><th class="value-col"><select id="masks"><option value="none">None</option></select></th></tr><tr><th class="name-col">Group</th><th class="value-col"><div id="ungroup-objects">Ungroup selection</div></th></tr></table></div>';
const other_panel =
  '<hr><div id="back-properties" class="panel-section"><p class="property-title">Layer</p><table><tr><th class="name-col">Opacity</th><th class="value-col"><div id="select-opacity"></div><div id="object-o" class="property-input" data-label="%"><input type="number" value=100></div></th></tr><tr><th class="name-col">Mask</th><th class="value-col"><select id="masks"><option value="none">None</option></select></th></tr></table></div>';
const shape_panel =
  '<hr><div id="back-properties" class="panel-section"><p class="property-title">Rectangle</p><table><tr><th class="name-col">Color</th><th class="value-col"><div id="object-color-fill" class="object-color"><div id="color-fill-side" class="color-picker"></div><input value="#FFFFFF" disabled="disabled"></div><div id="object-color-fill-opacity" class="property-input" data-label="%"><input type="number" value=100></div></th></tr><tr><th class="name-col">Radius</th><th class="value-col" id="duration-cell"><div id="object-corners" class="property-input" data-label="px"><input type="number" value=0 min=0></div></th></tr></table></div>';
const path_panel =
  '<hr><div id="back-properties" class="panel-section"><p class="property-title">Shape</p><table><tr><th class="name-col">Color</th><th class="value-col"><div id="object-color-fill" class="object-color"><div id="color-fill-side" class="color-picker"></div><input value="#FFFFFF" disabled="disabled"></div><div id="object-color-fill-opacity" class="property-input" data-label="%"><input type="number" value=100></div></th></tr></table></div>';
const text_panel =
  '<hr><div id="back-properties" class="panel-section"><p class="property-title">Text</p><table><tr><th class="name-col">Font</th><th class="value-col"><select id="font-picker"></select></th></tr><tr><th class="name-col">Align</th><th class="value-col"><div class="align-text" id="align-text-left"><img src="assets/align-text-left.svg"></div><div class="align-text" id="align-text-center"><img src="assets/align-text-center.svg"></div><div class="align-text" id="align-text-right"><img src="assets/align-text-right.svg"></div><div class="align-text" id="align-text-justify"><img src="assets/align-text-justify.svg"></div></th></tr><tr><th class="name-col">Format</th><th class="value-col"><div class="format-text" id="format-bold"><img src="assets/bold.svg"></div><div class="format-text" id="format-italic"><img src="assets/italic.svg"></div><div class="format-text" id="format-underline"><img src="assets/underline.svg"></div><div class="format-text" id="format-strike"><img src="assets/strike.svg"></div></th></tr><tr><th class="name-col">Color</th><th class="value-col"><div id="object-color-fill" class="object-color"><div id="color-fill-side" class="color-picker"></div><input value="#FFFFFF" disabled="disabled"></div><div id="object-color-fill-opacity" class="property-input" data-label="%"><input type="number" value=100></div></th></tr><tr><th class="name-col">Letter</th><th class="value-col"><div id="select-letter"></div><div id="text-h" class="property-input" data-label="%"><input type="number" value=1></div></th></tr><tr><th class="name-col">Line</th><th class="value-col"><div id="select-line"></div><div id="text-v" class="property-input" data-label="%"><input type="number" value=1></div></th></tr></table></div>';
const stroke_panel =
  '<hr><div id="back-properties" class="panel-section"><p class="property-title">Stroke</p><table><tr><th class="name-col">Type</th><th class="value-col left-col"><div class="line-join" id="miter"><img src="assets/miter.svg"></div><div class="line-join" id="bevel"><img src="assets/bevel.svg"></div><div class="line-join" id="round"><img src="assets/round.svg"></div><div class="line-join" id="small-dash"><img src="assets/dash2.svg"></div></th></tr><tr><th class="name-col">Color</th><th class="value-col"><div id="object-color-stroke" class="object-color"><div id="color-stroke-side" class="color-picker"></div><input value="#FFFFFF" disabled="disabled"></div><div id="object-color-stroke-opacity" class="property-input" data-label="%"><input type="number" value=100></div></th></tr><tr><th class="name-col">Width</th><th class="value-col" id="duration-cell"><div id="object-stroke" class="property-input" data-label="px"><input type="number" min=0 value=0></div></th></tr></table></div>';
const shadow_panel =
  '<hr><div id="back-properties" class="panel-section"><p class="property-title">Shadow</p><table><tr><th class="name-col">Offset</th><th class="value-col"><div id="object-shadow-x" class="property-input" data-label="X"><input type="number" value=0></div><div id="object-shadow-y" class="property-input" data-label="Y"><input value=0 type="number"></div></th></tr><tr><th class="name-col">Color</th><th class="value-col"><div id="object-color-shadow" class="object-color"><div id="color-shadow-side" class="color-picker"></div><input value="#FFFFFF" disabled="disabled"></div><div id="object-color-shadow-opacity" class="property-input" data-label="%"><input type="number" value=100></div></th></tr><tr><th class="name-col">Blur</th><th class="value-col" id="duration-cell"><div id="object-blur" class="property-input" data-label="px"><input type="number" value=0 min=0></div></th></tr></table></div>';
const image_more_panel =
  '<hr><div id="back-properties" class="panel-section"><p class="property-title">Image</p><div id="image-buttons"><div id="filters-button"><img src="assets/filters.svg"> Edit filters</div><div id="crop-image"><img src="assets/crop-icon.svg">Crop image</div></div></div></hr>';
const video_more_panel =
  '<hr><div id="back-properties" class="panel-section"><p class="property-title">Video</p><div id="image-buttons"><div id="filters-button" class="filters-video"><img src="assets/filters.svg"> Edit filters</div></div></div></hr>';
const animated_text_panel =
  '<hr><div id="back-properties" class="panel-section"><p class="property-title">Text</p><table><tr><th class="name-col">Content</th><th class="value-col" id="duration-cell"><div id="animated-text" class="property-input" data-label=""><input id="animatedinput" type="text" value="text"><div id="animatedset">Set</div></div></th></tr><tr><th class="name-col">Font</th><th class="value-col"><select id="font-picker"></select></th></tr><tr><th class="name-col">Color</th><th class="value-col"><div id="text-color" class="object-color"><div id="color-text-side" class="color-picker"></div><input value="#FFFFFF" disabled="disabled"></div><div id="color-text-opacity" class="property-input" data-label="%"><input type="number" value=100></div></th></tr></table></div>';
const start_animation_panel =
  '<hr><div id="back-properties" class="panel-section"><p class="property-title">Start animation</p><table><tr><th class="name-col">Preset</th><th class="value-col"><select id="preset-picker"></select></th></tr><tr><th class="name-col">Easing</th><th class="value-col"><select id="easing-picker"><option value="linear">Linear</option><option value="easeInQuad">Ease in</option><option value="easeOutQuad">Ease out</option><option value="easeinOutQuad">Ease in-out</option><option value="easeOutInQuad">Ease out-in</option><option value="easeInBounce">Ease in bounce</option><option value="easeOutBounce">Ease out bounce</option><option value="easeinOutBounce">Ease in-out bounce</option><option value="easeOutInBouce">Ease out-in bounce</option><option value="easeOutInBouce">Ease out-in bounce</option><option value="easeInSine">Ease in sine</option><option value="easeOutSine">Ease out sine</option><option value="easeinOutSine">Ease in-out sine</option><option value="easeOutInSine">Ease out-in sine</option><option value="easeOutInSine">Ease out-in sine</option><option value="easeInCubic">Ease in cubic</option><option value="easeOutCubic">Ease out cubic</option><option value="easeinOutCubic">Ease in-out cubic</option><option value="easeOutInCubic">Ease out-in cubic</option><option value="easeOutInCubic">Ease out-in cubic</option></select></th></tr><tr><th class="name-col">Order</th><th class="value-col"><div id="order-toggle"><div id="order-backward" class="order-toggle-item">Backward</div><div id="order-forward" class="order-toggle-item order-toggle-item-active">Forward</div></div></th></tr><tr><th class="name-col">Order</th><th class="value-col"><div id="order-toggle"><div id="type-letters" class="order-toggle-item-2">Letters</div><div id="type-words" class="order-toggle-item-2 order-toggle-item-active-2">Words</div></div></th></tr><tr><th class="name-col">Duration</th><th class="value-col" id="duration-cell"><div id="animated-text-duration" class="property-input" data-label="s"><input id="durationinput" type="number" value="0"></div></th></tr></table></div>';
const audio_panel =
  '<div id="layout-properties" class="panel-section"><p class="property-title">Audio</p><table><tr><th class="name-col">Volume</th><th class="value-col" id="duration-cell"><div id="object-volume" class="property-input" data-label="%"><input type="number" value=0></div></th></tr></table></div>';

// Browser variants
const shape_browser =
  '<div id="search-fixed"><p class="property-title">Objects</p><img id="collapse" src="assets/collapse.svg"><div id="browser-search"><input placeholder="Search..."><img src="assets/search.svg" id="search-icon"><img src="assets/delete.svg" id="delete-search"><div id="search-button">Go</div></div></div><div id="shapes-cont"><p class="row-title">Shapes</p><div class="gallery-row" id="shapes-row"></div><p class="row-title">Emojis</p><div class="gallery-row" id="emojis-row"></div></div>';
const image_browser =
  '<div id="search-fixed"><p class="property-title">Images</p><img id="collapse" src="assets/collapse.svg"><div id="browser-search"><input placeholder="Search..."><a href="https://pixabay.com" target="_blank" id="pixabay"><img src="assets/pixabay.svg"></a><img src="assets/search.svg" id="search-icon"><img src="assets/delete.svg" id="delete-search"><div id="search-button">Go</div></div></div><div id="shapes-cont"><div id="landing"><div id="landing-text">Browse millions of high quality images from Pixabay. Use the search bar above or choose from popular categories below.</div><div id="categories"></div></div><div id="images-grid"></div></div>';
const text_browser =
  '<div id="search-fixed"><p class="property-title">Text</p><img id="collapse" src="assets/collapse.svg"><div id="browser-search"><input placeholder="Search..."><img src="assets/search.svg" id="search-icon"><img src="assets/delete.svg" id="delete-search"><div id="search-button">Go</div></div></div><div id="shapes-cont"><p class="row-title">Basic text</p><div id="heading-text" data-font="Inter" class="add-text noselect">Add a heading</div><div id="subheading-text" data-font="Inter" class="add-text noselect">Add a subheading</div><div id="body-text" data-font="Inter" class="add-text noselect">Add body text</div></div>';
const video_browser =
  '<div id="search-fixed"><p class="property-title">Videos</p><img id="collapse" src="assets/collapse.svg"><div id="browser-search"><input placeholder="Search..."><a href="https://pixabay.com" target="_blank" id="pixabay"><img src="assets/pixabay.svg"></a><img src="assets/search.svg" id="search-icon"><img src="assets/delete.svg" id="delete-search"><div id="search-button">Go</div></div></div><div id="shapes-cont"><div id="landing"><div id="landing-text">Browse millions of high quality images from Pixabay. Use the search bar above or choose from popular categories below.</div><div id="categories"></div></div><div id="images-grid"></div></div>';
const upload_browser =
  '<div id="search-fixed"><p class="property-title">Uploads</p><div id="upload-button"><img src="assets/upload.svg"> Upload media</div><img id="collapse" src="assets/collapse.svg"><div id="upload-tabs"><div id="images-tab" class="upload-tab upload-tab-active">Images</div><div id="videos-tab" class="upload-tab">Videos</div></div></div><div id="images-grid"></div>';
const audio_browser =
  '<div id="search-fixed" class="audio-browser"><p class="property-title">Audio</p><div id="audio-upload-button"><img src="assets/upload.svg"> Upload audio</div><img id="collapse" src="assets/collapse.svg"></div><div id="audio-list-parent"><div id="landing-text" class="audio-landing-text">Audio provided by Pixabay. Browse millions of assets from Pixabay by <a href="https://pixabay.com/music/" target="_blank">clicking here.</a></div><div id="audio-list"></div></div>';

// Text animation list
var text_animation_list = [
  { name: 'fade in', label: 'Fade in', src: 'assets/fade-in.svg' },
  {
    name: 'typewriter',
    label: 'Typewriter',
    src: 'assets/typewriter.svg',
  },
  {
    name: 'slide top',
    label: 'Slide top',
    src: 'assets/slide-top.svg',
  },
  {
    name: 'slide bottom',
    label: 'Slide bottom',
    src: 'assets/slide-bottom.svg',
  },
  {
    name: 'slide left',
    label: 'Slide left',
    src: 'assets/slide-left.svg',
  },
  {
    name: 'slide right',
    label: 'Slide right',
    src: 'assets/slide-right.svg',
  },
  { name: 'scale', label: 'Scale', src: 'assets/scale.svg' },
  { name: 'shrink', label: 'Shrink', src: 'assets/shrink.svg' },
];

// Shapes list
var shape_grid_items = [
  'assets/shapes/rectangle.svg',
  'assets/shapes/circle.svg',
  'assets/shapes/triangle.svg',
  'assets/shapes/polygon.svg',
  'assets/shapes/star.svg',
  'assets/thingy.svg',
  'assets/shapes/heart.svg',
  'assets/shapes/arrow.svg',
];
var emoji_items = [
  'assets/twemojis/laughing-emoji.png',
  'assets/twemojis/crying-emoji.png',
  'assets/twemojis/surprised-emoji.png',
  'assets/twemojis/smiling-emoji.png',
  'assets/twemojis/tongue-emoji.png',
  'assets/twemojis/heart-eyes-emoji.png',
  'assets/twemojis/heart-kiss-emoji.png',
  'assets/twemojis/sunglasses-cool-emoji.png',
  'assets/twemojis/ghost-emoji.png',
  'assets/twemojis/skull-emoji.png',
  'assets/twemojis/mindblown-emoji.png',
  'assets/twemojis/bomb-emoji.png',
  'assets/twemojis/hundred-100-points-emoji.png',
  'assets/twemojis/thought-balloon-emoji.png',
  'assets/twemojis/wave-emoji.png',
  'assets/twemojis/point-emoji.png',
  'assets/twemojis/thumbs-up-emoji.png',
  'assets/twemojis/clap-emoji.png',
  'assets/twemojis/raising-hands-emoji.png',
  'assets/twemojis/praying-hands-emoji.png',
  'assets/twemojis/nail-polish-emoji.png',
  'assets/twemojis/eyes-emoji.png',
  'assets/twemojis/cat-face-emoji.png',
  'assets/twemojis/dog-face-emoji.png',
  'assets/twemojis/rose-emoji.png',
  'assets/twemojis/tulip-emoji.png',
  'assets/twemojis/pizza-emoji.png',
  'assets/twemojis/construction-emoji.png',
  'assets/twemojis/plane-emoji.png',
  'assets/twemojis/rocket-emoji.png',
  'assets/twemojis/clock-emoji.png',
  'assets/twemojis/star-emoji.png',
  'assets/twemojis/sun-emoji.png',
  'assets/twemojis/moon-emoji.png',
  'assets/twemojis/fire-emoji.png',
  'assets/twemojis/sparkles-emoji.png',
  'assets/twemojis/party-popper-emoji.png',
  'assets/twemojis/gift-emoji.png',
  'assets/twemojis/trophy-emoji.png',
  'assets/twemojis/target-emoji.png',
  'assets/twemojis/gem-emoji.png',
  'assets/twemojis/money-emoji.png',
  'assets/twemojis/pencil-emoji.png',
  'assets/twemojis/graph-emoji.png',
  'assets/twemojis/wip-emoji.png',
  'assets/twemojis/winking-face-emoji.png',
  'assets/twemojis/pleading-face-emoji.png',
  'assets/twemojis/thinking-face-emoji.png',
];

// Image list
var image_grid_items = [
  'https://images.unsplash.com/photo-1609153259378-a8b23c766aec?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1866&q=80',
  'https://images.unsplash.com/photo-1614435082296-ef0cbdb16b70?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=934&q=80',
  'https://images.unsplash.com/photo-1614432254115-7e756705e910?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxMHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=900&q=60',
  'https://images.unsplash.com/photo-1614423234685-544477464e15?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw4fHx8ZW58MHx8fA%3D%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=900&q=60',
  'https://images.unsplash.com/photo-1614357235247-99fabbee67f9?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxNHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=900&q=60',
  'https://images.unsplash.com/photo-1614373371549-c7d2e4885f17?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxOXx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=900&q=60',
];
var image_categories = [
  { name: 'background', image: 'assets/background.png' },
  { name: 'wallpaper', image: 'assets/wallpaper.png' },
  { name: 'nature', image: 'assets/nature.png' },
  { name: 'summer', image: 'assets/summer.png' },
  { name: 'beach', image: 'assets/beach.png' },
  { name: 'space', image: 'assets/space.png' },
  { name: 'office', image: 'assets/office.png' },
  { name: 'food', image: 'assets/food.png' },
];

// Video list
var video_categories = [
  { name: 'rain', image: 'assets/rain.png' },
  { name: 'cars', image: 'assets/cars.png' },
  { name: 'meditation', image: 'assets/meditation.png' },
  { name: 'forest', image: 'assets/forest.png' },
  { name: 'animals', image: 'assets/animals.png' },
  { name: 'street', image: 'assets/street.png' },
  { name: 'travel', image: 'assets/travel.png' },
  { name: 'work', image: 'assets/work.png' },
];

// Audio list
var audio_items = [
  {
    name: 'Lofi Study',
    desc: 'FASSounds',
    duration: '2:27',
    thumb: 'assets/audio/lofi-thumb.png',
    src: 'assets/audio/lofi.mp3',
    link: 'https://pixabay.com/users/fassounds-3433550/',
  },
  {
    name: 'Stomping Rock (Four Shots)',
    desc: 'AlexGrohl',
    duration: '1:59',
    thumb: 'assets/audio/stomping-rock-thumb.png',
    src: 'assets/audio/stomping-rock.mp3',
    link: 'https://pixabay.com/users/alexgrohl-25289918/',
  },
  {
    name: 'Everything Feels New',
    desc: 'EvgenyBardyuzha',
    duration: '1:06',
    thumb: 'assets/audio/everything-feels-new-thumb.png',
    src: 'assets/audio/everything-feels-new.mp3',
    link: 'https://pixabay.com/users/evgenybardyuzha-25235210/',
  },
  {
    name: 'Both of Us',
    desc: 'madiRFAN',
    duration: '2:48',
    thumb: 'assets/audio/both-of-us-thumb.png',
    src: 'assets/audio/both-of-us.mp3',
    link: 'https://pixabay.com/users/madirfan-50411/',
  },
  {
    name: 'The Podcast Intro',
    desc: 'Music Unlimited',
    duration: '1:51',
    thumb: 'assets/audio/the-podcast-intro-thumb.png',
    src: 'assets/audio/the-podcast-intro.mp3',
    link: 'https://pixabay.com/users/music_unlimited-27600023/',
  },
  {
    name: 'Epic Cinematic Trailer',
    desc: 'PavelYudin',
    duration: '2:27',
    thumb: 'assets/audio/epic-cinematic-trailer-thumb.png',
    src: 'assets/audio/epic-cinematic-trailer.mp3',
    link: 'https://pixabay.com/users/pavelyudin-27739282/',
  },
  {
    name: 'Inspirational Background',
    desc: 'AudioCoffee',
    duration: '2:19',
    thumb: 'assets/audio/inspirational-background-thumb.png',
    src: 'assets/audio/inspirational-background.mp3',
    link: 'https://pixabay.com/users/audiocoffee-27005420/',
  },
  {
    name: 'Tropical Summer Music',
    desc: 'Music Unlimited',
    duration: '2:35',
    thumb: 'assets/audio/tropical-summer-music-thumb.png',
    src: 'assets/audio/tropical-summer-music.mp3',
    link: 'https://pixabay.com/users/music_unlimited-27600023/',
  },
];

// Text list
var text_items = {
  sansserif: [
    { name: 'Roboto', fontname: 'Roboto' },
    { name: 'Montserrat', fontname: 'Montserrat' },
    { name: 'Poppins', fontname: 'Poppins' },
  ],
  serif: [
    { name: 'Playfair Display', fontname: 'Playfair Display' },
    { name: 'Merriweather', fontname: 'Merriweather' },
    { name: 'IBM Plex Serif', fontname: 'IBM Plex Serif' },
  ],
  monospace: [
    { name: 'Roboto Mono', fontname: 'Roboto Mono' },
    { name: 'Inconsolata', fontname: 'Inconsolata' },
    { name: 'Source Code Pro', fontname: 'Source Code Pro' },
  ],
  handwriting: [
    { name: 'Dancing Script', fontname: 'Dancing Script' },
    { name: 'Pacifico', fontname: 'Pacifico' },
    { name: 'Indie Flower', fontname: 'Indie Flower' },
  ],
  display: [
    { name: 'Lobster', fontname: 'Lobster' },
    { name: 'Bebas Neue', fontname: 'Bebas Neue' },
    { name: 'Titan One', fontname: 'Titan One' },
  ],
};

// Without a Google Fonts key the font pickers would be empty, so fall back
// to the families that are already bundled in the text browser.
// (Declared here because it reads text_items, defined just above.)
if (!HAS_FONTS_KEY) {
  Object.keys(text_items).forEach(function (group) {
    text_items[group].forEach(function (item) {
      if (fonts.indexOf(item.fontname) == -1) {
        fonts.push(item.fontname);
      }
    });
  });
  ['Inter', 'Syne'].forEach(function (name) {
    if (fonts.indexOf(name) == -1) {
      fonts.push(name);
    }
  });
  fonts.sort();
}

WebFont.load({
  google: {
    families: ['Syne'],
  },
  active: () => {},
});

var webglBackend;
try {
  webglBackend = new fabric.WebglFilterBackend();
} catch (e) {
  console.log(e);
}
var canvas2dBackend = new fabric.Canvas2dFilterBackend();

fabric.filterBackend = fabric.initFilterBackend();
// Only take over the backend if WebGL actually initialized, otherwise filters
// would silently break on machines without a usable WebGL context.
if (webglBackend) {
  fabric.filterBackend = webglBackend;
}

// Lottie support
fabric.Lottie = fabric.util.createClass(fabric.Image, {
  type: 'lottie',
  lockRotation: true,
  lockSkewingX: true,
  lockSkewingY: true,
  srcFromAttribute: false,

  initialize: function (path, options) {
    if (!options.width) options.width = 480;
    if (!options.height) options.height = 480;

    this.path = path;
    this.tmpCanvasEl = fabric.util.createCanvasElement();
    this.tmpCanvasEl.width = options.width;
    this.tmpCanvasEl.height = options.height;

    this.lottieItem = bodymovin.loadAnimation({
      renderer: 'canvas',
      loop: false,
      autoplay: false,
      path: path,
      rendererSettings: {
        context: this.tmpCanvasEl.getContext('2d'),
        preserveAspectRatio: 'xMidYMid meet',
      },
    });

    this.lottieItem.addEventListener('enterFrame', (e) => {
      if (this.canvas) {
        this.canvas.requestRenderAll();
      }
    });

    this.lottieItem.addEventListener('DOMLoaded', () => {
      this.lottieItem.goToAndStop(currenttime, false);
      this.lottieItem.duration =
        this.lottieItem.getDuration(false) * 1000;
      if (this.canvas) {
        this.canvas.requestRenderAll();
      }
      canvas.renderAll();
      canvas.fire('lottie:loaded', { any: 'payload' });
    });

    this.callSuper('initialize', this.tmpCanvasEl, options);
  },

  goToSeconds: function (seconds) {
    this.lottieItem.goToAndStop(seconds, false);
    if (this.canvas) {
      this.canvas.requestRenderAll();
    }
  },
  goToFrame: function (frame) {
    this.lottieItem.goToAndStop(frame, true);
  },
  getDuration: function () {
    return this.lottieItem.getDuration(false);
  },
  play: function () {
    this.lottieItem.play();
  },
  pause: function () {
    this.lottieItem.pause();
  },
  getSrc: function () {
    return this.path;
  },
});

fabric.Lottie.fromObject = function (_object, callback) {
  const object = fabric.util.object.clone(_object);
  fabric.Image.prototype._initFilters.call(
    object,
    object.filters,
    function (filters) {
      object.filters = filters || [];
      fabric.Image.prototype._initFilters.call(
        object,
        [object.resizeFilter],
        function (resizeFilters) {
          object.resizeFilter = resizeFilters[0];
          fabric.util.enlivenObjects(
            [object.clipPath],
            function (enlivedProps) {
              object.clipPath = enlivedProps[0];
              const fabricLottie = new fabric.Lottie(
                object.src,
                object
              );
              callback(fabricLottie, false);
            }
          );
        }
      );
    }
  );
};

// Initialize canvas
var canvas = new fabric.Canvas('canvas', {
  preserveObjectStacking: true,
  backgroundColor: '#FFF',
  stateful: true,
});
canvas.selection = false;
canvas.controlsAboveOverlay = true;

// Customize controls
fabric.Object.prototype.set({
  transparentCorners: false,
  borderColor: '#51B9F9',
  cornerColor: '#FFF',
  borderScaleFactor: 2.5,
  cornerStyle: 'circle',
  cornerStrokeColor: '#0E98FC',
  borderOpacityWhenMoving: 1,
});

canvas.selectionColor = 'rgba(46, 115, 252, 0.11)';
canvas.selectionBorderColor = 'rgba(98, 155, 255, 0.81)';
canvas.selectionLineWidth = 1.5;

var img = document.createElement('img');
img.src = 'assets/middlecontrol.svg';

var img2 = document.createElement('img');
img2.src = 'assets/middlecontrolhoz.svg';

var img3 = document.createElement('img');
img3.src = 'assets/edgecontrol.svg';

var img4 = document.createElement('img');
img4.src = 'assets/rotateicon.svg';

function renderIcon(ctx, left, top, styleOverride, fabricObject) {
  const wsize = 20;
  const hsize = 25;
  ctx.save();
  ctx.translate(left, top);
  ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
  ctx.drawImage(img, -wsize / 2, -hsize / 2, wsize, hsize);
  ctx.restore();
}
function renderIconHoz(ctx, left, top, styleOverride, fabricObject) {
  const wsize = 25;
  const hsize = 20;
  ctx.save();
  ctx.translate(left, top);
  ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
  ctx.drawImage(img2, -wsize / 2, -hsize / 2, wsize, hsize);
  ctx.restore();
}
function renderIconEdge(ctx, left, top, styleOverride, fabricObject) {
  const wsize = 25;
  const hsize = 25;
  ctx.save();
  ctx.translate(left, top);
  ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
  ctx.drawImage(img3, -wsize / 2, -hsize / 2, wsize, hsize);
  ctx.restore();
}

function renderIconRotate(
  ctx,
  left,
  top,
  styleOverride,
  fabricObject
) {
  const wsize = 40;
  const hsize = 40;
  ctx.save();
  ctx.translate(left, top);
  ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
  ctx.drawImage(img4, -wsize / 2, -hsize / 2, wsize, hsize);
  ctx.restore();
}
function resetControls() {
  fabric.Object.prototype.controls.ml = new fabric.Control({
    x: -0.5,
    y: 0,
    offsetX: -1,
    cursorStyleHandler:
      fabric.controlsUtils.scaleSkewCursorStyleHandler,
    actionHandler: fabric.controlsUtils.scalingXOrSkewingY,
    getActionName: fabric.controlsUtils.scaleOrSkewActionName,
    render: renderIcon,
  });

  fabric.Object.prototype.controls.mr = new fabric.Control({
    x: 0.5,
    y: 0,
    offsetX: 1,
    cursorStyleHandler:
      fabric.controlsUtils.scaleSkewCursorStyleHandler,
    actionHandler: fabric.controlsUtils.scalingXOrSkewingY,
    getActionName: fabric.controlsUtils.scaleOrSkewActionName,
    render: renderIcon,
  });

  fabric.Object.prototype.controls.mb = new fabric.Control({
    x: 0,
    y: 0.5,
    offsetY: 1,
    cursorStyleHandler:
      fabric.controlsUtils.scaleSkewCursorStyleHandler,
    actionHandler: fabric.controlsUtils.scalingYOrSkewingX,
    getActionName: fabric.controlsUtils.scaleOrSkewActionName,
    render: renderIconHoz,
  });

  fabric.Object.prototype.controls.mt = new fabric.Control({
    x: 0,
    y: -0.5,
    offsetY: -1,
    cursorStyleHandler:
      fabric.controlsUtils.scaleSkewCursorStyleHandler,
    actionHandler: fabric.controlsUtils.scalingYOrSkewingX,
    getActionName: fabric.controlsUtils.scaleOrSkewActionName,
    render: renderIconHoz,
  });

  fabric.Object.prototype.controls.tl = new fabric.Control({
    x: -0.5,
    y: -0.5,
    cursorStyleHandler: fabric.controlsUtils.scaleCursorStyleHandler,
    actionHandler: fabric.controlsUtils.scalingEqually,
    render: renderIconEdge,
  });

  fabric.Object.prototype.controls.tr = new fabric.Control({
    x: 0.5,
    y: -0.5,
    cursorStyleHandler: fabric.controlsUtils.scaleCursorStyleHandler,
    actionHandler: fabric.controlsUtils.scalingEqually,
    render: renderIconEdge,
  });

  fabric.Object.prototype.controls.bl = new fabric.Control({
    x: -0.5,
    y: 0.5,
    cursorStyleHandler: fabric.controlsUtils.scaleCursorStyleHandler,
    actionHandler: fabric.controlsUtils.scalingEqually,
    render: renderIconEdge,
  });

  fabric.Object.prototype.controls.br = new fabric.Control({
    x: 0.5,
    y: 0.5,
    cursorStyleHandler: fabric.controlsUtils.scaleCursorStyleHandler,
    actionHandler: fabric.controlsUtils.scalingEqually,
    render: renderIconEdge,
  });

  fabric.Object.prototype.controls.mtr = new fabric.Control({
    x: 0,
    y: 0.5,
    cursorStyleHandler: fabric.controlsUtils.rotationStyleHandler,
    actionHandler: fabric.controlsUtils.rotationWithSnapping,
    offsetY: 30,
    withConnecton: false,
    actionName: 'rotate',
    render: renderIconRotate,
  });
}
resetControls();
var textBoxControls = (fabric.Textbox.prototype.controls = {});

textBoxControls.mtr = fabric.Object.prototype.controls.mtr;
textBoxControls.tr = fabric.Object.prototype.controls.tr;
textBoxControls.br = fabric.Object.prototype.controls.br;
textBoxControls.tl = fabric.Object.prototype.controls.tl;
textBoxControls.bl = fabric.Object.prototype.controls.bl;
textBoxControls.mt = fabric.Object.prototype.controls.mt;
textBoxControls.mb = fabric.Object.prototype.controls.mb;

textBoxControls.ml = new fabric.Control({
  x: -0.5,
  y: 0,
  offsetX: -1,
  cursorStyleHandler:
    fabric.controlsUtils.scaleSkewCursorStyleHandler,
  actionHandler: fabric.controlsUtils.changeWidth,
  actionName: 'resizing',
  render: renderIcon,
});

textBoxControls.mr = new fabric.Control({
  x: 0.5,
  y: 0,
  offsetX: 1,
  cursorStyleHandler:
    fabric.controlsUtils.scaleSkewCursorStyleHandler,
  actionHandler: fabric.controlsUtils.changeWidth,
  actionName: 'resizing',
  render: renderIcon,
});

// Get any object by ID
fabric.Canvas.prototype.getItemById = function (name) {
  function search(list) {
    for (var i = 0; i < list.length; i++) {
      const item = list[i];
      if (item.id && item.id === name) {
        return item;
      }
      // Recurse so groups nested more than one level deep are found too
      if (item._objects && item._objects.length > 0) {
        const found = search(item._objects);
        if (found) {
          return found;
        }
      }
    }
    return null;
  }
  return search(this.getObjects());
};

// Create the artboard
var a_width = 600;
var a_height = 500;
var artboard = new fabric.Rect({
  left: canvas.get('width') / 2 - a_width / 2,
  top: canvas.get('height') / 2 - a_height / 2,
  width: a_width,
  height: a_height,
  absolutePositioned: true,
  rx: 0,
  ry: 0,
  fill: '#FFF',
  hasControls: true,
  transparentCorners: false,
  borderColor: '#0E98FC',
  cornerColor: '#0E98FC',
  cursorWidth: 1,
  cursorDuration: 1,
  cursorDelay: 250,
  id: 'overlay',
});
canvas.renderAll();

// Clip canvas to the artboard
canvas.clipPath = artboard;
canvas.renderAll();

// Initialize color picker (fill)
var o_fill = Pickr.create({
  el: '#color-picker-fill',
  theme: 'nano',
  inline: true,
  useAsButton: true,
  swatches: null,
  default: '#FFFFFF',
  showAlways: true,
  components: {
    preview: true,
    opacity: true,
    hue: true,
    interaction: {
      hex: true,
      rgba: true,
      hsla: false,
      hsva: false,
      cmyk: false,
      input: true,
      clear: false,
      save: false,
    },
  },
});

// Color picker events
o_fill
  .on('init', (instance) => {
    o_fill.hide();
  })
  .on('change', (instance) => {
    if (canvas.getActiveObject()) {
      const object = canvas.getActiveObject();
      if (colormode == 'fill') {
        $('#object-color-fill input').val(
          o_fill.getColor().toHEXA().toString().substring(0, 7)
        );
        $('#object-color-fill-opacity input').val(
          Math.round(o_fill.getColor().toRGBA()[3] * 100 * 100) / 100
        );
        $('#color-fill-side').css(
          'background-color',
          o_fill.getColor().toHEXA().toString().substring(0, 7)
        );
        object.set('fill', o_fill.getColor().toRGBA().toString());
        if (!seeking && !setting) {
          newKeyframe(
            'fill',
            object,
            currenttime,
            object.get('fill'),
            true
          );
        }
      } else if (colormode == 'stroke') {
        $('#object-color-stroke input').val(
          o_fill.getColor().toHEXA().toString().substring(0, 7)
        );
        $('#object-color-stroke-opacity input').val(
          Math.round(o_fill.getColor().toRGBA()[3] * 100 * 100) / 100
        );
        $('#color-stroke-side').css(
          'background-color',
          o_fill.getColor().toHEXA().toString().substring(0, 7)
        );
        object.set('stroke', o_fill.getColor().toRGBA().toString());
        if (!seeking && !setting) {
          newKeyframe(
            'stroke',
            object,
            currenttime,
            object.get('stroke'),
            true
          );
          newKeyframe(
            'strokeWidth',
            object,
            currenttime,
            object.get('strokeWidth'),
            true
          );
        }
      } else if (colormode == 'shadow') {
        $('#object-color-shadow input').val(
          o_fill.getColor().toHEXA().toString().substring(0, 7)
        );
        $('#object-color-shadow-opacity input').val(
          Math.round(o_fill.getColor().toRGBA()[3] * 100 * 100) / 100
        );
        $('#color-shadow-side').css(
          'background-color',
          o_fill.getColor().toHEXA().toString().substring(0, 7)
        );
        object.set(
          'shadow',
          new fabric.Shadow({
            color: o_fill.getColor().toRGBA().toString(),
            offsetX: object.shadow.offsetX,
            offsetY: object.shadow.offsetY,
            blur: object.shadow.blur,
            opacity: object.shadow.opacity,
          })
        );
        if (!seeking && !setting) {
          newKeyframe(
            'shadow.color',
            object,
            currenttime,
            object.shadow.color,
            true
          );
        }
      } else if (colormode == 'chroma') {
        var obj = canvas.getActiveObject();
        $('#chroma-color input').val(
          o_fill.getColor().toHEXA().toString().substring(0, 7)
        );
        $('#color-chroma-side').css(
          'background-color',
          o_fill.getColor().toHEXA().toString().substring(0, 7)
        );
        if (obj.filters.find((x) => x.type == 'RemoveColor')) {
          obj.filters.find((x) => x.type == 'RemoveColor').color =
            o_fill.getColor().toRGBA().toString();
        }
        updateChromaValues();
      } else if (colormode == 'text') {
        var obj = canvas.getActiveObject();
        $('#text-color input').val(
          o_fill.getColor().toHEXA().toString().substring(0, 7)
        );
        $('#color-text-side').css(
          'background-color',
          o_fill.getColor().toHEXA().toString().substring(0, 7)
        );
        animatedtext
          .find((x) => x.id == obj.id)
          .setProps(
            { fill: o_fill.getColor().toRGBA().toString() },
            canvas
          );
      }
      canvas.renderAll();
    } else {
      if (colormode == 'back') {
        $('#canvas-color input').val(
          o_fill.getColor().toHEXA().toString().substring(0, 7)
        );
        $('#canvas-color-opacity input').val(
          Math.round(o_fill.getColor().toRGBA()[3] * 100 * 100) / 100
        );
        $('#color-side').css(
          'background-color',
          o_fill.getColor().toHEXA().toString().substring(0, 7)
        );
        canvas.setBackgroundColor(
          o_fill.getColor().toRGBA().toString()
        );
        canvas.renderAll();
      }
    }
  })
  .on('show', (instance) => {
    $('.pcr-current-color').html(
      "<img id='eyedropper' src='assets/eyedropper.svg'>"
    );
  });

var f = fabric.Image.filters;

// Canvas recorder initialization
var canvasrecord = new fabric.Canvas('canvasrecord', {
  preserveObjectStacking: true,
  backgroundColor: '#FFF',
  width: artboard.width,
  height: artboard.height,
  // Objects are repositioned to artboard-relative coordinates while
  // recording. Their cached aCoords are not always refreshed in step, and
  // fabric's offscreen culling would then skip drawing them entirely,
  // producing blank frames.
  skipOffscreen: false,
});

var timelineslider = document.getElementById('timeline-zoom');
var t_slider = new RangeSlider(timelineslider, {
  design: '2d',
  theme: 'default',
  handle: 'round',
  popup: null,
  showMinMaxLabels: false,
  unit: '%',
  min: 5,
  max: 47,
  value: 47,
  onmove: function (x) {
    setTimelineZoom(-1 * (x - 51));
  },
  onfinish: function (x) {
    setTimelineZoom(-1 * (x - 51));
  },
  onstart: function (x) {},
});

const selectbox = new SelectionArea({
  class: 'selection-area',
  selectables: ['.keyframe'],
  container: '#timeline',
  // Query selectors for elements from where a selection can be started from.
  startareas: ['html'],

  // Query selectors for elements which will be used as boundaries for the selection.
  boundaries: ['#timeline'],

  startThreshold: 10,

  allowTouch: true,

  intersect: 'touch',

  overlap: 'invert',

  // Configuration in case a selectable gets just clicked.
  singleTap: {
    allow: false,
    intersect: 'native',
  },

  // Scroll configuration.
  scrolling: {
    speedDivider: 10,
    manualSpeed: 750,
  },
});

selectbox
  .on('beforestart', (evt) => {
    if (
      $(evt.event.target).hasClass('keyframe') ||
      $(evt.event.target).attr('id') == 'seekbar' ||
      $(evt.event.target).parent().hasClass('main-row') ||
      $(evt.event.target).hasClass('main-row') ||
      $(evt.event.target).hasClass('trim-row') ||
      evt.event.which === 3
    ) {
      return false;
    }
  })
  .on('start', (evt) => {})
  .on('move', (evt) => {})
  .on('stop', (evt) => {
    $('.keyframe-selected').removeClass('keyframe-selected');
    shiftkeys = [];
    if (evt.store.selected.length == 0) {
      $('.keyframe-selected').removeClass('keyframe-selected');
    } else {
      canvas.discardActiveObject();
      canvas.renderAll();
      evt.store.selected.forEach(function (key) {
        shiftkeys.push({
          keyframe: key,
          offset: $(key).offset().left,
        });
        $(key).addClass('keyframe-selected');
      });
    }
  });
