Source: src/recipes/shared/recipeExpand.js

/**
 * @module recipeExpand
 */

class RecipeExpand extends HTMLElement {
  constructor () {
    super()
    this.attachShadow({ mode: 'open' })

    // Create styles and root element
    const styles = document.createElement('link')
    styles.rel = 'stylesheet'
    styles.type = 'text/css'
    styles.href = '/assets/styles/recipeExpand.css'
    const article = document.createElement('article')

    // Fill in styles and root element
    article.innerHTML = `
          <body>
          <header>
            <h1></h1>
            
            <img src="" alt="" class="thumbnail" />
            <p class="description"></p>
            <div>
              <p> Calories: <span class="meta--calories"></span></p>
              <button> + Add to plan</button>
            </div>
          </header>
          <hr>
          <main>
            <section class="sectionIngredients">
              <h2>Ingredients</h2>
              <ul></ul>
            </section>
            <section class="sectionInstructions">
              <h2>Instructions</h2>
              <ol></ol>
            </section>
          </main>
        </body>
      `

    // Append elements to the shadow root
    this.shadowRoot.append(styles, article)
  }

  /**
     * Sets the recipe that will be used inside the <recipe-expand> element.
     * Overwrites the previous recipe, fair warning.
     */
  set data (data) {
    this.json = data

    // Reset HTML
    this.shadowRoot.querySelector('article').innerHTML = `
        <body>
          <header>
            <h1></h1>
            
            <img src="" alt="" class="thumbnail" />
            <p class="description"></p>
            <div>
              <p> Calories: <span class="meta--calories"></span></p>
              <button> + Add to plan</button>
            </div>
          </header>
          <hr>
          <main>
            <section class="sectionIngredients">
              <h2>Ingredients</h2>
              <ul></ul>
            </section>
            <section class="sectionInstructions">
              <h2>Instructions</h2>
              <ol></ol>
            </section>
          </main>
        </body>
      `

    // Set Title
    const title = getTitle(data)
    this.shadowRoot.querySelector('header > h1').innerHTML = title

    // Set Calories
    const calories = getCalories(data)
    this.shadowRoot.querySelector('.meta--calories').innerHTML = calories

    // Set Description
    const description = getDescription(data)
    this.shadowRoot.querySelector('p.description').innerHTML = description

    // Set Image
    const imgSrc = getImage(data)
    const img = this.shadowRoot.querySelector('img.thumbnail')
    img.setAttribute('src', imgSrc)
    img.setAttribute('alt', title)

    // Set Ingredients
    const ingredients = getIngredients(data)
    ingredients.forEach(ingredient => {
      const listItem = document.createElement('li')
      listItem.innerHTML = ingredient
      this.shadowRoot.querySelector('.sectionIngredients > ul').append(listItem)
    })

    // Set Instructions / URL
    const instructions = getInstructions(data)
    const url = getUrl(data)
    if (instructions) {
      instructions.forEach(instruction => {
        const listItem = document.createElement('li')
        listItem.innerHTML = instruction
        this.shadowRoot.querySelector('.sectionInstructions > ol').append(listItem)
      })
    } else {
      const header = this.shadowRoot.querySelector('.sectionInstructions > h2')
      const list = this.shadowRoot.querySelector('.sectionInstructions > ol')
      header.innerHTML = 'Recipe URL'
      list.parentElement.removeChild(list)
      const recipeUrl = document.createElement('a')
      recipeUrl.setAttribute('href', url)
      recipeUrl.setAttribute('target', '_blank')
      recipeUrl.innerHTML = url
      this.shadowRoot.querySelector('.sectionInstructions').append(recipeUrl)
    }
  }

  /**
     * Returns the object of the currect recipe being used.
     */
  get data () {
    return this.json
  }
}

/**
   * Extract the calories of the recipe from the given recipe JSON object
   * @param {Object} data Raw recipe JSON to find the calories of
   * @returns {Number} If found, returns the calories of the recipe
   */
function getCalories (data) {
  if (data.calories) return data.calories
  return null
}

/**
   * Extract the description of the recipe from the given recipe schema JSON obejct
   * @param {Object} data Raw recipe JSON to find the image of
   * @returns {String} If found, returns the recipe description
   */
function getDescription (data) {
  if (data.description) return data.description
  return null
}

/**
   * Extract a usable image from the given recipe schema JSON object
   * @param {Object} data Raw recipe JSON to find the image of
   * @returns {String} If found, returns the URL of the image as a string, otherwise null
   */
function getImage (data) {
  if (data.image_url) return data.image_url
  return null
}

/**
   * Extract the title of the recipe from the given recipe schema JSON obejct
   * @param {Object} data Raw recipe JSON to find the image of
   * @returns {String} If found, returns the recipe title
   */
function getTitle (data) {
  if (data.name) return data.name
  return null
}

/**
   * Extract the instructions of the recipe from the given recipe schema JSON object
   * @param {Object} data Raw recipe JSON to find the instructions of
   * @returns {Array} If found, returns the recipe instructions
   */
function getInstructions (data) {
  if (data.instructions) return data.instructions
  return null
}

/**
   * Extract the ingredients of the recipe from the given recipe schema JSON obejct
   * @param {Object} data Raw recipe JSON to find the image of
   * @returns {Array} If found, returns the recipe ingredients
   */
function getIngredients (data) {
  if (data.recipe_ingredient) return data.recipe_ingredient

  return null
}

/**
 * Extract the url of the recipe from the given recipe schema JSON obejct
 * @param {Object} data Raw recipe JSON to find the url of
 * @returns {String} If found, returns the url of the recipe
 */
function getUrl (data) {
  if (data.recipeUrl) return data.recipeUrl
  return null
}

customElements.define('recipe-expand', RecipeExpand)