Skip to content
Snippets Groups Projects
Article.vue 10.20 KiB
<template>
  <article v-bind:class="{'v-sheet v-card rounded-xl': !articleLookup, dictionary, 'collapsable': collapsable, 'collapsed': collapsed}" v-if="article">
    <Header :title_id="title_id" :lemmas="article.lemmas" :dictionary="dictionary" :article_id="article.article_id" @toggle-collapse = "toggle_collapse"/>
    <InflectionButton :lemmas="article.lemmas" :dictionary="dictionary" :article_id="article.article_id"/>
    
    <div class="article_content" :class="$vuetify.breakpoint.name" v-if="!collapsed">
      <section v-if="article.body.pronunciation && article.body.pronunciation.length" class="pronunciation">
        <h3>Uttale</h3>
          <ul>
            <DefElement v-for="(element, index) in article.body.pronunciation" :dictionary="dictionary" :key="index" :body='element' @article-click="article_link_click" />
          </ul>
      </section>
      <section v-if="article.body.etymology && article.body.etymology.length" class="etymology">
        <h3>Opphav</h3>
          <ul>
            <DefElement v-for="(element, index) in article.body.etymology" :dictionary="dictionary" :key="index" :body='element' @article-click="article_link_click" />
          </ul>
      </section>
      <section class="definitions" v-if="has_content">
        <h3>{{def_label}}</h3>
        <ol>
          <Definition v-for="definition in article.body.definitions" :dictionary="dictionary" :level="1" :key="definition.id" :body='definition' @article-click="article_link_click" />
        </ol>
      </section>
      <section v-if="sub_articles.length" class="expressions">
        <h3>Faste uttrykk</h3>
        <ul>
          <SubArticle :body="subart" v-for="(subart, index) in sub_articles" :dictionary="dictionary" :key="index" @article-click="article_link_click" />
        </ul>
      </section>
    </div>
    <ArticleFooter v-if="!collapsed" :article="article"/>
</article>
</template>

<script src="/dist/vue-social-sharing.js"></script>
<script>
import DefElement from './DefElement.vue'
import Definition from './Definition.vue'
import SubArticle from './SubArticle.vue'
import Header from './Header.vue'
import ArticleFooter from './ArticleFooter.vue'
import InflectionButton from './InflectionButton.vue'

import entities from '../utils/entities.js'

function find_sub_articles(definition) {
  let sub_art_list = []
  let sub_definitions = definition.elements.filter(el => el.type_ == 'definition')

  sub_definitions.forEach((subdef, i) => {
    sub_art_list = sub_art_list.concat(find_sub_articles(subdef))
  })

  let sub_articles = definition.elements.filter(el => el.type_ == 'sub_article' && el.lemmas)
  sub_art_list = sub_art_list.concat(sub_articles)
  return sub_art_list
}

function find_content(definition) {
  let content_list = []
  let sub_definitions = definition.elements.filter(el => el.type_ == 'definition')

  sub_definitions.forEach((subdef, i) => {
    content_list = content_list.concat(find_content(subdef))
  })

  let content_nodes = definition.elements.filter(el => ['explanation', 'example', 'compound_list'].includes(el.type_))
  content_list = content_list.concat(content_nodes)

  return content_list
}

export default {
  name: 'Article',
  props: {
    article: Object,
    articleLookup: Boolean,
    title_id: String

  },
  data: function() {
    return {
      is_collapsed: true
    }
  },
  computed: {
    collapsable: function() {
      if (this.$parent.$options.name != 'SearchResults') {
        this.is_collapsed = false
        return false
      }
      let collapsable = this.$store.state.collapseArticles
      if (collapsable == 'never') {
        this.is_collapsed = false
      }
      if (collapsable == 'always') {
        this.is_collapsed = true
      }
      if (collapsable == 'auto') {
        this.is_collapsed = this.$parent.$options.name == 'SearchResults' && (this.$parent.results_bm.length + this.$parent.results_nn.length > 2)
      }


      return this.$store.state.collapseArticles == 'always' || this.$parent.$options.name == 'SearchResults' && (this.$parent.results_bm.length + this.$parent.results_nn.length > 2)//getters.collapsable(this.$parent.$options.name, this.$parent.results_bm.length + this.$parent.results_nn.length)
    },
    collapsed: {
      get() {
        if (this.$parent.$options.name != 'SearchResults') {
          return false
        }
        if (!this.collapsable) {
          this.is_collapsed = false
        }
        return this.is_collapsed
      },
      set(value) {
        this.is_collapsed = value
      }
    },
    snippet: function() {
    if (this.collapsable && this.article.body.definitions) {
      return this.parse_definitions(this.article.body.definitions)
    }
    return null
      
    },
    link_to_self: function() {
      try {
      return  {
        ref: '/' + this.dictionary + '/' + this.article.article_id + '/' + encodeURIComponent(this.article.lemmas[0].lemma),
        article: this.article
      }
      } catch(error) {
        console.log("LINK TO SELF ERROR:",this.article)
        console.error(error)
        return {ref: "", article: this.article}
      }
    },
    dictionary: function() {
      return this.article.dictionary
    },
    def_label: function() {
      return this.dictionary == 'bm' ? 'Betydning og bruk' : 'Tyding og bruk'
    },
    example_label: function() {
      return this.dictionary == 'bm' ? 'Eksempel' : 'Døme'
    },
    sub_articles: function() {
      return this.article.body.definitions.reduce((acc, val) => acc.concat(find_sub_articles(val)), []).sort((s1, s2) => s1.lemmas[0].localeCompare(s2.lemmas[0]))
    },
    has_content: function() {
      return this.article.body.definitions.reduce((acc, val) => acc.concat(find_content(val)), []).length > 0
    },
  },
  components: {
    DefElement,
    Definition,
    SubArticle,
    Header,
    ArticleFooter,
    InflectionButton
  },
  mounted: function() {
    if (this.$route.hash == "#"+ this.title_id) {
      let focused = document.getElementById(this.title_id)
      if (focused) focused.focus()
    }
    else if (this.$route.hash) {
      let focused =document.getElementById(this.$route.hash.replace("#",""))
      if (focused) focused.scrollIntoView({block: "center"})
    }
    else if (this.$parent.article) {
      document.getElementById("return_link").focus()

    }
  },
  methods: {
    parse_definitions: function(node) {
      let definitionTexts = []
      try {
      node.forEach((definition) => {
        if (definition.elements) {
        if (definition.elements[0].content) {
          let new_string = ""
          let old_parts = definition.elements[0].content.split(/(\$)/)
          let linkIndex = 0
          old_parts.forEach((item) => {
            if (item == '$') {
              let subitem = definition.elements[0].items[linkIndex]
              if (subitem.id) {
                new_string += entities[this.dictionary][definition.elements[0].items[linkIndex].id].expansion
              }
              else if (subitem.text) new_string += subitem.text
              else  {
                if (definition.elements[0].items[linkIndex].lemmas) {
                new_string +=  definition.elements[0].items[linkIndex].lemmas[0].lemma
                }
                

              }
              
              if (!definition.elements[0].items[linkIndex].id) {
              }
              linkIndex += 1
            }
            else {
              new_string += item
            }
            
          })

          if (new_string.substring(new_string.length, new_string.length - 1) == ":") {
            new_string = new_string.slice(0, -1)
          }
          definitionTexts.push(new_string)

        }
        else if (definition.elements[0].elements) {
          definitionTexts.push(this.parse_definitions(definition.elements))
        }
      }
      })
      } catch(error) {
        console.log(this.article)
        console.error(error)
        definitionTexts = []
      }

      let definitions = definitionTexts.join("\u00A0•\u00A0")
      return definitions

    },
    toggle_collapse: function() {
      this.collapsed = !this.collapsed
    },

    article_link_click: function(item) {
      this.$emit('article-click', item)
    },
    details_click: function(item) {
      item.title_id = this.title_id
      this.$emit('details-click', item)
    }
  }
}
</script>

<style>
article {
  position: relative;
  padding: 24px;
  margin-bottom: 20px;
  margin-right: 10px;
  margin-left: 10px;
  background-color: #ffffff;
}

section.xs article, section.sm article {
  margin-bottom: 10px !important;
}


.welcome .article_footer {
  display: block;
}

#single_article_container article {
  border: none;
  margin-top: 10px;
}


section {
  padding-top: 10px;
  padding-bottom: 10px
}

h3 {
  color: var(--v-primary-base);
  font-variant: all-small-caps;
}


section.etymology > h3, section.pronunciation > h3 {
  display: inline;
}

section.etymology ul, section.pronunciation ul, section.etymology li, section.pronunciation li {
  display: inline;
}

section.etymology li:not(:first-child):not(:last-child):before, section.pronunciation li:not(:first-child):not(:last-child):before {
  content: ", ";
}

section.etymology li:not(:first-child):last-child:before, section.pronunciation li:not(:first-child):last-child:before {
  content: "; ";
  font-size: smaller;
}

li {
  padding-bottom: 4px;
}

li.level1.definition {
  list-style: upper-alpha;
}

li.level2.definition {
  list-style: decimal;
}

li.level3.definition {
  /* Norsk ordbok skal ha "lower.alpha" her */
  list-style: disc;
}

li.sub_article > ul {
  padding-left: 0px;
}

::marker {
  font-weight: bold;
  color: var(--v-primary-base);
}

ol > li:only-child.level1, li:only-child.level2 {
  /* level3 a.k.a. underdefinisjoner skal vises med bullet selv om de står alene */
  list-style: none;
}

li:only-child.level1 > ol {
  padding-left: 0px;
}

ul, ol {
  padding-left: 12px !important;
}

ul li {
  list-style:none;
}

ul li.definition {
  list-style: disc;
}




.choose {
  color: var(--v-primary-base) !important;
  text-decoration: none;
}

.info-card {
  padding: 12px;
}

.collapsable {
  padding-bottom: 34px;
}


.collapsed .header{
  
      display: -webkit-box;
      width: 100%;
    -webkit-line-clamp: 4;
    -webkit-box-orient: vertical;
    overflow-y: hidden;  
    overflow-x: auto;
}

.header {
  border-radius: 0px !important;
}



</style>