diff --git a/package-lock.json b/package-lock.json
index 53ef6545c6a4af7690456fe427581fabbc86502b..9c7af015632b1b077417c91ba155cfbc58e1a62c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12073,4 +12073,4 @@
       }
     }
   }
-}
\ No newline at end of file
+}
diff --git a/package.json b/package.json
index 31c65f330e25e38109eefbad6ebc78f3f0ac8b23..00c12e533679ed282ea319541d35e84aaa34bdce 100644
--- a/package.json
+++ b/package.json
@@ -75,4 +75,4 @@
     "type": "git",
     "url": "gitlab.phaidra.org:fairness/FAIR-v1.git"
   }
-}
\ No newline at end of file
+}
diff --git a/src/components/browse/PCollectionGallery.vue b/src/components/browse/PCollectionGallery.vue
new file mode 100644
index 0000000000000000000000000000000000000000..4e8a9925a2d5883ba429ad3f839d271880ba5910
--- /dev/null
+++ b/src/components/browse/PCollectionGallery.vue
@@ -0,0 +1,219 @@
+<template>
+  <v-container>
+    <v-row>
+      <v-toolbar>
+        <v-toolbar-title>Toolbar</v-toolbar-title>
+        <v-spacer></v-spacer>
+        <v-btn icon @click="mode = 'single'">
+          <v-icon>mdi-image-outline</v-icon>
+        </v-btn>
+        <v-btn icon @click="mode = 'gallery'">
+          <v-icon>mdi-grid</v-icon>
+        </v-btn>
+      </v-toolbar>
+    </v-row>
+    <v-row>
+      <v-col md="auto">
+        <v-treeview
+          :items="collections"
+          :load-children="getChildren"
+          :active.sync="active"
+          :open.sync="open"
+          activatable
+          transition
+          color="primary"
+        ></v-treeview>
+      </v-col>
+      <v-divider vertical></v-divider>
+      <v-col v-if="mode === 'single'">
+        <v-carousel hide-delimiters height="100%">
+          <v-carousel-item :src="'https://phaidra.univie.ac.at/preview/o:1039867/ImageManipulator/boxImage/800/jpg'"></v-carousel-item>
+          <v-carousel-item :src="'https://phaidra.univie.ac.at/preview/o:1039866/ImageManipulator/boxImage/800/jpg'"></v-carousel-item>
+          <v-carousel-item :src="'https://phaidra.univie.ac.at/preview/o:1039865/ImageManipulator/boxImage/800/jpg'"></v-carousel-item>
+          <v-carousel-item :src="'https://phaidra.univie.ac.at/preview/o:1039864/ImageManipulator/boxImage/800/jpg'"></v-carousel-item>
+          <v-carousel-item :src="'https://phaidra.univie.ac.at/preview/o:1039863/ImageManipulator/boxImage/800/jpg'"></v-carousel-item>
+          <v-carousel-item :src="'https://phaidra.univie.ac.at/preview/o:1039862/ImageManipulator/boxImage/800/jpg'"></v-carousel-item>
+          <v-carousel-item :src="'https://phaidra.univie.ac.at/preview/o:1039861/ImageManipulator/boxImage/800/jpg'"></v-carousel-item>
+          <v-carousel-item :src="'https://phaidra.univie.ac.at/preview/o:1039860/ImageManipulator/boxImage/800/jpg'"></v-carousel-item>
+          <v-carousel-item :src="'https://phaidra.univie.ac.at/preview/o:1039859/ImageManipulator/boxImage/800/jpg'"></v-carousel-item>
+        </v-carousel>
+      </v-col>
+      <v-col v-if="mode === 'gallery'">
+        <v-container>
+          <v-row>
+            <v-col class="d-flex child-flex" cols="4">
+              <v-card flat tile class="d-flex">
+                <v-img class="grey lighten-2" aspect-ratio="1" :src="'https://phaidra.univie.ac.at/preview/o:1039867/ImageManipulator/boxImage/800/jpg'">
+                  <template v-slot:placeholder>
+                    <v-row class="fill-height ma-0" align="center" justify="center">
+                      <v-progress-circular indeterminate color="grey lighten-5"></v-progress-circular>
+                    </v-row>
+                  </template>
+                </v-img>
+              </v-card>
+            </v-col>
+            <v-col class="d-flex child-flex" cols="4">
+              <v-card flat tile class="d-flex">
+                <v-img class="grey lighten-2" aspect-ratio="1" :src="'https://phaidra.univie.ac.at/preview/o:1039866/ImageManipulator/boxImage/800/jpg'">
+                  <template v-slot:placeholder>
+                    <v-row class="fill-height ma-0" align="center" justify="center">
+                      <v-progress-circular indeterminate color="grey lighten-5"></v-progress-circular>
+                    </v-row>
+                  </template>
+                </v-img>
+              </v-card>
+            </v-col>
+            <v-col class="d-flex child-flex" cols="4">
+              <v-card flat tile class="d-flex">
+                <v-img class="grey lighten-2" aspect-ratio="1" :src="'https://phaidra.univie.ac.at/preview/o:1039865/ImageManipulator/boxImage/800/jpg'">
+                  <template v-slot:placeholder>
+                    <v-row class="fill-height ma-0" align="center" justify="center">
+                      <v-progress-circular indeterminate color="grey lighten-5"></v-progress-circular>
+                    </v-row>
+                  </template>
+                </v-img>
+              </v-card>
+            </v-col>
+            <v-col class="d-flex child-flex" cols="4">
+              <v-card flat tile class="d-flex">
+                <v-img class="grey lighten-2" aspect-ratio="1" :src="'https://phaidra.univie.ac.at/preview/o:1039864/ImageManipulator/boxImage/800/jpg'">
+                  <template v-slot:placeholder>
+                    <v-row class="fill-height ma-0" align="center" justify="center">
+                      <v-progress-circular indeterminate color="grey lighten-5"></v-progress-circular>
+                    </v-row>
+                  </template>
+                </v-img>
+              </v-card>
+            </v-col>
+            <v-col class="d-flex child-flex" cols="4">
+              <v-card flat tile class="d-flex">
+                <v-img class="grey lighten-2" aspect-ratio="1" :src="'https://phaidra.univie.ac.at/preview/o:1039863/ImageManipulator/boxImage/800/jpg'">
+                  <template v-slot:placeholder>
+                    <v-row class="fill-height ma-0" align="center" justify="center">
+                      <v-progress-circular indeterminate color="grey lighten-5"></v-progress-circular>
+                    </v-row>
+                  </template>
+                </v-img>
+              </v-card>
+            </v-col>
+            <v-col class="d-flex child-flex" cols="4">
+              <v-card flat tile class="d-flex">
+                <v-img class="grey lighten-2" aspect-ratio="1" :src="'https://phaidra.univie.ac.at/preview/o:1039862/ImageManipulator/boxImage/800/jpg'">
+                  <template v-slot:placeholder>
+                    <v-row class="fill-height ma-0" align="center" justify="center">
+                      <v-progress-circular indeterminate color="grey lighten-5"></v-progress-circular>
+                    </v-row>
+                  </template>
+                </v-img>
+              </v-card>
+            </v-col>
+            <v-col class="d-flex child-flex" cols="4">
+              <v-card flat tile class="d-flex">
+                <v-img class="grey lighten-2" aspect-ratio="1" :src="'https://phaidra.univie.ac.at/preview/o:1039861/ImageManipulator/boxImage/800/jpg'">
+                  <template v-slot:placeholder>
+                    <v-row class="fill-height ma-0" align="center" justify="center">
+                      <v-progress-circular indeterminate color="grey lighten-5"></v-progress-circular>
+                    </v-row>
+                  </template>
+                </v-img>
+              </v-card>
+            </v-col>
+            <v-col class="d-flex child-flex" cols="4">
+              <v-card flat tile class="d-flex">
+                <v-img class="grey lighten-2" aspect-ratio="1" :src="'https://phaidra.univie.ac.at/preview/o:1039860/ImageManipulator/boxImage/800/jpg'">
+                  <template v-slot:placeholder>
+                    <v-row class="fill-height ma-0" align="center" justify="center">
+                      <v-progress-circular indeterminate color="grey lighten-5"></v-progress-circular>
+                    </v-row>
+                  </template>
+                </v-img>
+              </v-card>
+            </v-col>
+            <v-col class="d-flex child-flex" cols="4">
+              <v-card flat tile class="d-flex">
+                <v-img class="grey lighten-2" aspect-ratio="1" :src="'https://phaidra.univie.ac.at/preview/o:1039859/ImageManipulator/boxImage/800/jpg'">
+                  <template v-slot:placeholder>
+                    <v-row class="fill-height ma-0" align="center" justify="center">
+                      <v-progress-circular indeterminate color="grey lighten-5"></v-progress-circular>
+                    </v-row>
+                  </template>
+                </v-img>
+              </v-card>
+            </v-col>
+          </v-row>
+        </v-container>
+      </v-col>
+    </v-row>
+  </v-container>
+</template>
+
+<script>
+import qs from 'qs'
+
+export default {
+  name: 'p-collection-gallery',
+  props: {
+    collection: {
+      type: String,
+      required: true
+    }
+  },
+  data () {
+    return {
+      active: [],
+      open: [this.collection],
+      collections: [
+        {
+          id: this.collection,
+          name: 'Root',
+          children: []
+        }
+      ],
+      mode: 'gallery',
+      selectedImage: {
+        src: ''
+      }
+    }
+  },
+  methods: {
+    getChildren: async function (item) {
+      try {
+        let params = {
+          q: '*:*',
+          defType: 'edismax',
+          wt: 'json',
+          fq: 'ispartof:"' + item.id + '"',
+          start: 0,
+          rows: 5000
+        }
+        let response = await this.$http.request({
+          method: 'POST',
+          url: this.$store.state.instanceconfig.solr + '/select',
+          data: qs.stringify(params, { arrayFormat: 'repeat' }),
+          headers: {
+            'content-type': 'application/x-www-form-urlencoded'
+          }
+        })
+        let docs = response.data.response.docs
+        let total = response.data.response.numFound
+        if (total < 1) {
+          console.log(item.id + ' has ' + total + ' members')
+          return
+        }
+        for (let member of docs) {
+          let node = {
+            id: member.pid,
+            name: member.dc_title,
+            children: []
+          }
+          item.children.push(node)
+        }
+      } catch (error) {
+        console.log(error)
+        this.$store.commit('setAlerts', [{ type: 'danger', msg: error }])
+      }
+    }
+  }
+
+}
+</script>
diff --git a/src/components/display/phaidra_display/PDAdaptation.vue b/src/components/display/phaidra_display/PDAdaptation.vue
new file mode 100644
index 0000000000000000000000000000000000000000..0b95244c218e5fda447ae2904d1731e9b9fc2db3
--- /dev/null
+++ b/src/components/display/phaidra_display/PDAdaptation.vue
@@ -0,0 +1,80 @@
+<template>
+  <v-layout row>
+    <v-flex xs10>
+      <v-card>
+        <v-card-title class="subheading grey white--text">
+          <span>{{ $t(p) }}</span>
+        </v-card-title>
+        <v-divider></v-divider>
+        <v-card-text class="mt-4">
+          <v-layout row wrap>
+            <template v-for="(title, j) in o['dce:title']">
+              <template v-for="(mt, i) in title['bf:mainTitle']">
+                <v-flex md4 xs12 class="pdlabel primary--text" :key="'mt'+j+i">
+                  {{ $t(title['@type']) }}
+                  <template v-if="mt['@language']">({{ mt['@language'] }})</template>
+                </v-flex>
+                <v-flex md8 xs12 :key="'mtv'+i">
+                  <v-layout column>
+                    <v-flex class="valuefield">{{ mt['@value'] }}</v-flex>
+                    <template v-for="(st, i) in title['bf:subtitle']">
+                      <v-flex class="valuefield" :key="'stv'+i">{{ st['@value'] }}</v-flex>
+                    </template>
+                  </v-layout>
+                </v-flex>
+              </template>
+            </template>
+          </v-layout>
+          <v-layout v-for="(obj, pred, i) in o" :key="'role' + i" row wrap>
+            <template v-if="pred.startsWith('role')">
+              <v-flex
+                md4
+                xs12
+                class="pdlabel primary--text"
+              >{{ getLocalizedTermLabel('rolepredicate', pred) }}</v-flex>
+              <v-flex md8 xs12 v-for="(n, i) in obj" :key="'adpname' + i">
+                <v-layout column>
+                  <v-flex>
+                    <template
+                      class="valuefield"
+                      v-for="(gn) in n['schema:givenName']"
+                    >{{ gn['@value'] }}</template>
+                    <template
+                      class="valuefield"
+                      v-for="(fn) in n['schema:familyName']"
+                    >{{ fn['@value'] }}</template>
+                    <template class="valuefield" v-for="(fn) in n['schema:name']">{{ fn['@value'] }}</template>
+                    <template v-if="n['schema:affiliation']" class="grey--text">
+                      <template v-for="(af) in n['schema:affiliation']">
+                        <template class="valuefield" v-for="(afn) in af">{{ afn['@value'] }}</template>
+                      </template>
+                    </template>
+                  </v-flex>
+                </v-layout>
+              </v-flex>
+            </template>
+          </v-layout>
+        </v-card-text>
+      </v-card>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import { vocabulary } from "../../../mixins/vocabulary";
+
+export default {
+  name: "p-d-series",
+  mixins: [vocabulary],
+  props: {
+    o: {
+      type: Object,
+      required: true
+    },
+    p: {
+      type: String
+    }
+  }
+};
+</script>
+
diff --git a/src/components/display/phaidra_display/PDBfPublication.vue b/src/components/display/phaidra_display/PDBfPublication.vue
new file mode 100644
index 0000000000000000000000000000000000000000..d942c2745cf1eb0d74fb1a83bd5431ec19d6a67f
--- /dev/null
+++ b/src/components/display/phaidra_display/PDBfPublication.vue
@@ -0,0 +1,64 @@
+<template>
+  <v-layout row>
+    <v-flex xs10>
+      <v-card>
+        <v-card-title class="subheading grey white--text">
+          <span>{{ $t(p) }}</span>
+        </v-card-title>
+        <v-divider></v-divider>
+        <v-card-text class="mt-4">
+          <v-layout row wrap>
+            <template v-for="(publisher, j) in o['bf:agent']">
+              <template v-for="(publishername, i) in publisher['schema:name']">
+                <v-flex md4 xs12 class="pdlabel primary--text" :key="'publnamel'+j+i">{{ $t('ORG_PUBLISHER') }}</v-flex>
+                <v-flex md8 xs12 :key="'publname'+j+i">
+                  <v-layout column>
+                    <v-flex class="valuefield">{{ publishername['@value'] }}</v-flex>
+                  </v-layout>
+                </v-flex>
+              </template>
+            </template>
+          </v-layout>
+          <v-layout row wrap>
+            <template v-for="(publishingplace, j) in o['bf:place']">
+              <template v-for="(place, i) in publishingplace['skos:prefLabel']">
+                <v-flex md4 xs12 class="pdlabel primary--text" :key="'publplacel'+j+i">{{ $t('Place') }}</v-flex>
+                <v-flex md8 xs12 :key="'publplace'+j+i">
+                  <v-layout column>
+                    <v-flex class="valuefield">{{ place['@value'] }}</v-flex>
+                  </v-layout>
+                </v-flex>
+              </template>
+            </template>
+          </v-layout>
+          <v-layout row wrap>
+            <template v-for="(publishingdate, j) in o['bf:date']">
+              <v-flex md4 xs12 class="pdlabel primary--text" :key="'publdatel'+j">{{ $t('Date') }}</v-flex>
+              <v-flex md8 xs12 :key="'publdate'+j">
+                <v-layout column>
+                  <v-flex>{{ publishingdate }}</v-flex>
+                </v-layout>
+              </v-flex>
+            </template>
+          </v-layout>
+        </v-card-text>
+      </v-card>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+export default {
+  name: 'p-d-bf-publication',
+  props: {
+    o: {
+      type: Object,
+      required: true
+    },
+    p: {
+      type: String
+    }
+  }
+}
+</script>
+
diff --git a/src/components/display/phaidra_display/PDCitation.vue b/src/components/display/phaidra_display/PDCitation.vue
new file mode 100644
index 0000000000000000000000000000000000000000..5be1cda210ca4f8ff2fcfa8274c7c0eb71af69d2
--- /dev/null
+++ b/src/components/display/phaidra_display/PDCitation.vue
@@ -0,0 +1,34 @@
+<template>
+  <v-flex>
+    <v-layout column >
+      <v-flex>
+        <template v-for="(pl, i) in o['skos:prefLabel']">
+          <v-layout :key="'row'+i" row wrap>
+            <v-flex md4 xs12 class="pdlabel primary--text" :key="'mt'+i">{{ $t(p) }}<template v-if="pl['@language']"> ({{ pl['@language'] }})</template></v-flex>
+            <v-flex md8 xs12>
+              <v-layout row :key="'mtv'+i">
+                <v-flex class="valuefield">{{ pl['@value'] }}<template v-for="(identifier) in o['skos:exactMatch']"> ({{ identifier }})</template></v-flex>
+              </v-layout>
+            </v-flex>
+          </v-layout>
+        </template>
+      </v-flex>
+    </v-layout>
+  </v-flex>
+</template>
+
+<script>
+export default {
+  name: 'p-d-citation',
+  props: {
+    o: {
+      type: Object,
+      required: true
+    },
+    p: {
+      type: String
+    }
+  }
+}
+</script>
+
diff --git a/src/components/display/phaidra_display/PDDimension.vue b/src/components/display/phaidra_display/PDDimension.vue
new file mode 100644
index 0000000000000000000000000000000000000000..d029ecd4a3e6bd68ab6845599b650bf83d70895f
--- /dev/null
+++ b/src/components/display/phaidra_display/PDDimension.vue
@@ -0,0 +1,33 @@
+<template>
+  <v-flex>
+    <v-layout row wrap>
+      <v-flex md4 xs12 class="pdlabel primary--text" xs3>{{ $t(p) }}</v-flex>
+      <v-flex md8 xs12>
+        <span v-for="(v, i) in o['schema:value']" :key="'v'+i">{{ v }}</span>
+        <span
+          v-for="(v, i) in o['schema:unitCode']"
+          :key="'u'+i"
+        >{{ getLocalizedTermLabel('uncefact', v) }}</span>
+      </v-flex>
+    </v-layout>
+  </v-flex>
+</template>
+
+<script>
+import { vocabulary } from "../../../mixins/vocabulary";
+
+export default {
+  name: "p-d-dimension",
+  mixins: [vocabulary],
+  props: {
+    o: {
+      type: Object,
+      required: true
+    },
+    p: {
+      type: String
+    }
+  }
+};
+</script>
+
diff --git a/src/components/display/phaidra_display/PDDuration.vue b/src/components/display/phaidra_display/PDDuration.vue
new file mode 100644
index 0000000000000000000000000000000000000000..3f89989243995e3e7d609822f01a1f02eba038df
--- /dev/null
+++ b/src/components/display/phaidra_display/PDDuration.vue
@@ -0,0 +1,43 @@
+<template>
+  <v-flex>
+    <v-layout row wrap>
+      <v-flex md4 xs12 class="pdlabel primary--text" xs3>{{ $t(p) }}</v-flex>
+      <v-flex md8 xs12>
+        <template v-if="duration.hours > 0">{{ duration.hours }} {{$t('hours') + ' '}}</template>
+        <template v-if="duration.minutes > 0">{{ duration.minutes }} {{$t('minutes') + ' '}}</template>
+        <template v-if="duration.seconds > 0">{{ duration.seconds }} {{$t('seconds')}}</template>
+      </v-flex>
+    </v-layout>
+  </v-flex>
+</template>
+
+<script>
+import { vocabulary } from "../../../mixins/vocabulary";
+
+export default {
+  name: "p-d-duration",
+  mixins: [vocabulary],
+  props: {
+    o: {
+      type: String,
+      required: true
+    },
+    p: {
+      type: String
+    }
+  },
+  computed: {
+    duration: function() {
+      let m = this.o.match(/PT(\d+)H(\d+)M(\d+)S/);
+      if (m) {
+        return {
+          hours: m[1],
+          minutes: m[2],
+          seconds: m[3]
+        };
+      }
+    }
+  }
+};
+</script>
+
diff --git a/src/components/display/phaidra_display/PDEntity.vue b/src/components/display/phaidra_display/PDEntity.vue
new file mode 100644
index 0000000000000000000000000000000000000000..7c75ed000bdd2e0c5cc3d08c0b38fee28057a802
--- /dev/null
+++ b/src/components/display/phaidra_display/PDEntity.vue
@@ -0,0 +1,56 @@
+<template>
+  <v-flex>
+    <v-layout v-if="entity" row wrap>
+      <v-flex md4 xs12 class="pdlabel primary--text">{{ getLocalizedTermLabel(this.role) }}</v-flex>
+      <v-flex md8 xs12>
+        <v-layout column>
+          <v-flex>
+            <template
+              class="valuefield"
+              v-for="(gn) in entity['schema:givenName']"
+            >{{ gn['@value'] }}</template>
+            <template
+              class="valuefield"
+              v-for="(fn) in entity['schema:familyName']"
+            >{{ fn['@value'] }}</template>
+            <template class="valuefield" v-for="(fn) in entity['schema:name']">{{ fn['@value'] }}</template>
+            <template v-if="entity['schema:affiliation']" class="grey--text">
+              <template v-for="(af) in entity['schema:affiliation']">
+                <template class="valuefield" v-for="(afn) in af">{{ afn['@value'] }}</template>
+              </template>
+            </template>
+          </v-flex>
+        </v-layout>
+      </v-flex>
+    </v-layout>
+  </v-flex>
+</template>
+
+<script>
+import { vocabulary } from "../../../mixins/vocabulary";
+
+export default {
+  name: "p-d-entity",
+  mixins: [vocabulary],
+  props: {
+    entity: {
+      type: Object,
+      required: true
+    },
+    role: {
+      type: String,
+      required: true
+    }
+  },
+  methods: {
+    getLocalizedTermLabel: function(role) {
+      return this.$store.getters.getLocalizedTermLabel(
+        "rolepredicate",
+        role,
+        this.$i18n.locale
+      );
+    }
+  }
+};
+</script>
+
diff --git a/src/components/display/phaidra_display/PDExactMatch.vue b/src/components/display/phaidra_display/PDExactMatch.vue
new file mode 100644
index 0000000000000000000000000000000000000000..3e4daf424b57c1cb73cbd7abe03c199b2e431e73
--- /dev/null
+++ b/src/components/display/phaidra_display/PDExactMatch.vue
@@ -0,0 +1,55 @@
+<template>
+  <v-flex>
+    <v-layout row wrap>
+      <v-flex md4 xs12 class="pdlabel primary--text" xs3>{{ $t(p) }}</v-flex>
+      <v-flex md8 xs12>{{ resolve(p, o['skos:exactMatch']) }}</v-flex>
+    </v-layout>
+  </v-flex>
+</template>
+
+<script>
+import { vocabulary } from "../../../mixins/vocabulary";
+
+export default {
+  name: "p-d-exact-match",
+  mixins: [vocabulary],
+  props: {
+    o: {
+      type: Object,
+      required: true
+    },
+    p: {
+      type: String
+    }
+  },
+  data() {
+    return {
+      langCode2to3: {
+        en: "eng",
+        de: "deu",
+        it: "ita"
+      }
+    };
+  },
+  methods: {
+    resolve: function(p, v) {
+      var vocabulary = "";
+      switch (p) {
+        case "vra:hasInscription":
+          vocabulary = "https://phaidra.org/vocabulary/stamp";
+          break;
+
+        default:
+          console.error(
+            "p-d-exact-match resolve: unrecognized predicate ",
+            p,
+            v
+          );
+      }
+
+      return this.getLocalizedTermLabel(vocabulary, v);
+    }
+  }
+};
+</script>
+
diff --git a/src/components/display/phaidra_display/PDFunder.vue b/src/components/display/phaidra_display/PDFunder.vue
new file mode 100644
index 0000000000000000000000000000000000000000..09722aacb742f96107097aeee7c3ba789a96fb39
--- /dev/null
+++ b/src/components/display/phaidra_display/PDFunder.vue
@@ -0,0 +1,29 @@
+<template>
+  <v-flex>
+    <v-layout row wrap>
+      <template v-for="(l, i) in o['skos:prefLabel']">
+        <v-flex class="pdlabel primary--text" md4 xs12 :key="'fl'+i">{{ $t('Funder') }} ({{ l['@language'] }})</v-flex>
+        <v-flex class="valuefield" md8 xs12 :key="'fv'+i">{{ l['@value'] }}</v-flex>
+      </template>
+    </v-layout>
+    <v-layout row wrap>
+      <template v-for="(id, i) in o['skos:exactMatch']">
+        <v-flex class="pdlabel primary--text" md4 xs12 :key="'idl'+i">{{ $t('Funder Id') }}</v-flex>
+        <v-flex md8 xs12 :key="'idv'+i">{{ id }}</v-flex>
+      </template>
+    </v-layout>
+  </v-flex>
+</template>
+
+<script>
+export default {
+  name: 'p-d-funder',
+  props: {
+    o: {
+      type: Object,
+      required: true
+    }
+  }
+}
+</script>
+
diff --git a/src/components/display/phaidra_display/PDGeoreference.vue b/src/components/display/phaidra_display/PDGeoreference.vue
new file mode 100644
index 0000000000000000000000000000000000000000..c63c8124ed85b830cdb1417e932c8903dba870f6
--- /dev/null
+++ b/src/components/display/phaidra_display/PDGeoreference.vue
@@ -0,0 +1,33 @@
+<template>
+  <v-flex>
+    <template v-if="o['skos:prefLabel']">
+      <v-layout row wrap>
+        <v-flex class="pdlabel primary--text" md4 xs12>{{ $t(p) }}<template v-for="(l) in o['skos:prefLabel']"><template v-if="l['@language']"> ({{ l['@language'] }})</template></template></v-flex>
+        <v-flex md8 xs12>
+          <v-layout column>
+            <v-flex class="valuefield" v-for="(l, i) in o['skos:prefLabel']" :key="'gplv'+i">{{ l['@value'] }}</v-flex>
+            <template v-if="o['rdfs:label']">
+              <v-flex class="grey--text valuefield" v-for="(l, i) in o['rdfs:label']" :key="'gl'+i">[{{ l['@value'] }}]</v-flex>
+            </template>
+          </v-layout>
+        </v-flex>
+      </v-layout>
+    </template>
+  </v-flex>
+</template>
+
+<script>
+export default {
+  name: 'p-d-georeference',
+  props: {
+    o: {
+      type: Object,
+      required: true
+    },
+    p: {
+      type: String
+    }
+  }
+}
+</script>
+
diff --git a/src/components/display/phaidra_display/PDJsonld.vue b/src/components/display/phaidra_display/PDJsonld.vue
new file mode 100644
index 0000000000000000000000000000000000000000..bd08475ee33d0e670a92b713e7f59165e74fe615
--- /dev/null
+++ b/src/components/display/phaidra_display/PDJsonld.vue
@@ -0,0 +1,399 @@
+<template>
+  <p-d-jsonld-layout v-if="jsonld">
+    <template v-if="pid" slot="pid">
+      <v-flex>
+        <v-layout row wrap>
+          <v-flex md4 xs12 class="pdlabel primary--text">{{ $t('Persistent identifier') }}</v-flex>
+          <v-flex md8 xs12>https://{{ instance.baseurl }}/{{ pid }}</v-flex>
+        </v-layout>
+      </v-flex>
+    </template>
+
+    <template v-for="(o, p) in jsonld">
+      <template v-if="p==='dcterms:type'" slot="dcterms:type">
+        <p-d-skos-preflabel :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'type'+j"></p-d-skos-preflabel>
+      </template>
+
+      <template v-else-if="p==='edm:hasType'" slot="edm:hasType">
+        <p-d-skos-preflabel :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'objtyp'+j"></p-d-skos-preflabel>
+      </template>
+
+      <template v-else-if="p==='schema:genre'" slot="schema:genre">
+        <p-d-skos-preflabel :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'genre'+j"></p-d-skos-preflabel>
+      </template>
+
+      <template v-else-if="p==='rdau:P60059'" slot="rdau:P60059">
+        <p-d-skos-preflabel :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'P60059'+j"></p-d-skos-preflabel>
+      </template>
+
+      <template v-else-if="p==='dce:title'" slot="dce:title">
+        <p-d-title :o="t" v-for="(t, j) in o" :key="componentid+'title'+j"></p-d-title>
+      </template>
+
+      <template v-else-if="p.startsWith('role:')" slot="role">
+        <p-d-entity :role="p" :entity="e" v-for="(e, j) in o" :key="componentid+'entity'+p+j"></p-d-entity>
+      </template>
+
+      <template v-else-if="p==='bf:note'" slot="bf:note">
+        <p-d-skos-preflabel :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'text'+j"></p-d-skos-preflabel>
+      </template>
+
+      <template v-else-if="p==='bf:tableOfContents'" slot="bf:tableOfContents">
+        <p-d-skos-preflabel :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'toc'+j"></p-d-skos-preflabel>
+      </template>
+
+      <template v-else-if="p==='dce:subject'" slot="dce:subject">
+        <p-d-keyword :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'keyword'+j"></p-d-keyword>
+      </template>
+
+      <template v-else-if="p==='dcterms:language'" slot="dcterms:language">
+        <p-d-labeled-value :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'lan'+j"></p-d-labeled-value>
+      </template>
+
+      <template v-else-if="p==='schema:subtitleLanguage'" slot="schema:subtitleLanguage">
+        <p-d-labeled-value :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'sublan'+j"></p-d-labeled-value>
+      </template>
+
+      <template v-else-if="p==='dcterms:date'" slot="dcterms:date">
+        <p-d-value :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'date'+j"></p-d-value>
+      </template>
+
+      <template v-else-if="p==='dcterms:created'" slot="dcterms:created">
+        <p-d-value :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'created'+j"></p-d-value>
+      </template>
+
+      <template v-else-if="p==='dcterms:modified'" slot="dcterms:modified">
+        <p-d-value :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'modified'+j"></p-d-value>
+      </template>
+
+      <template v-else-if="p==='dcterms:available'" slot="dcterms:available">
+        <p-d-value :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'available'+j"></p-d-value>
+      </template>
+
+      <template v-else-if="p==='dcterms:issued'" slot="dcterms:issued">
+        <p-d-value :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'issued'+j"></p-d-value>
+      </template>
+
+      <template v-else-if="p==='dcterms:valid'" slot="dcterms:valid">
+        <p-d-value :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'valid'+j"></p-d-value>
+      </template>
+
+      <template v-else-if="p==='dcterms:dateAccepted'" slot="dcterms:dateAccepted">
+        <p-d-value :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'dateAccepted'+j"></p-d-value>
+      </template>
+
+      <template v-else-if="p==='dcterms:dateCopyrighted'" slot="dcterms:dateCopyrighted">
+        <p-d-value :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'dateCopyrighted'+j"></p-d-value>
+      </template>
+
+      <template v-else-if="p==='dcterms:dateSubmitted'" slot="dcterms:dateSubmitted">
+        <p-d-value :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'dateSubmitted'+j"></p-d-value>
+      </template>
+
+      <template v-else-if="p==='rdau:P60071'" slot="rdau:P60071">
+        <p-d-value :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'dateOfProduction'+j"></p-d-value>
+      </template>
+
+      <template v-else-if="p==='phaidra:dateAccessioned'" slot="phaidra:dateAccessioned">
+        <p-d-value
+          :p="p"
+          :o="item"
+          v-for="(item, j) in o"
+          :key="componentid+'phaidra:dateAccessioned'+j"
+        ></p-d-value>
+      </template>
+
+      <template v-else-if="p==='dcterms:temporal'" slot="dcterms:temporal">
+        <p-d-lang-value :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'temporal'+j"></p-d-lang-value>
+      </template>
+
+      <template v-else-if="p==='rdau:P60193'" slot="rdau:P60193">
+        <p-d-series :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'series'+j"></p-d-series>
+      </template>
+
+      <template v-else-if="p==='bf:provisionActivity'" slot="bf:provisionActivity">
+        <p-d-bf-publication :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'bfpubl'+j"></p-d-bf-publication>
+      </template>
+
+      <template v-else-if="p==='cito:cites'" slot="cito:cites">
+        <p-d-citation :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'cites'+j"></p-d-citation>
+      </template>
+
+      <template v-else-if="p==='cito:isCitedBy'" slot="cito:isCitedBy">
+        <p-d-citation :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'citedby'+j"></p-d-citation>
+      </template>
+
+      <template v-else-if="p==='rdau:P60227'" slot="rdau:P60227">
+        <p-d-adaptation :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'adaptation'+j"></p-d-adaptation>
+      </template>
+
+      <template v-else-if="p==='frapo:isOutputOf'" slot="frapo:isOutputOf">
+        <template v-for="(item, j) in o">
+          <template v-if="item['@type']==='aaiso:Programme'">
+            <p-d-study-plan :p="p" :o="item" :key="componentid+'study-plan'+j"></p-d-study-plan>
+          </template>
+          <template v-else-if="item['@type']==='foaf:Project'">
+            <p-d-project :p="p" :o="item" :key="componentid+'project'+j"></p-d-project>
+          </template>
+        </template>
+      </template>
+
+      <template v-else-if="p==='frapo:hasFundingAgency'" slot="frapo:hasFundingAgency">
+        <p-d-funder :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'funder'+j"></p-d-funder>
+      </template>
+
+      <template v-else-if="p==='rdax:P00009'" slot="rdax:P00009">
+        <p-d-skos-preflabel
+          :p="p"
+          :o="item"
+          v-for="(item, j) in o"
+          :key="componentid+'association'+j"
+        ></p-d-skos-preflabel>
+      </template>
+
+      <template v-else-if="p==='bf:physicalLocation'" slot="bf:physicalLocation">
+        <p-d-lang-value :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'physloc'+j"></p-d-lang-value>
+      </template>
+
+      <template v-else-if="p==='bf:shelfMark'" slot="bf:shelfMark">
+        <p-d-value :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'callnr'+j"></p-d-value>
+      </template>
+
+      <template v-else-if="p==='dcterms:provenance'" slot="dcterms:provenance">
+        <p-d-skos-preflabel :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'prov'+j"></p-d-skos-preflabel>
+      </template>
+
+      <template v-else-if="p==='dcterms:spatial'" slot="dcterms:spatial">
+        <p-d-georeference :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'spatial'+j"></p-d-georeference>
+      </template>
+
+      <template v-else-if="p==='vra:placeOfCreation'" slot="vra:placeOfCreation">
+        <p-d-georeference
+          :p="p"
+          :o="item"
+          v-for="(item, j) in o"
+          :key="componentid+'placeOfCreation'+j"
+        ></p-d-georeference>
+      </template>
+
+      <template v-else-if="p==='vra:placeOfRepository'" slot="vra:placeOfRepository">
+        <p-d-georeference :p="p" :o="item" v-for="(item, j) in o" :key="'placeOfRepository'+j"></p-d-georeference>
+      </template>
+
+      <template v-else-if="p==='vra:placeOfSite'" slot="vra:placeOfSite">
+        <p-d-georeference
+          :p="p"
+          :o="item"
+          v-for="(item, j) in o"
+          :key="componentid+'placeOfSite'+j"
+        ></p-d-georeference>
+      </template>
+
+      <template v-else-if="p==='ebucore:filename'" slot="ebucore:filename">
+        <p-d-value :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'filename'+j"></p-d-value>
+      </template>
+
+      <template v-else-if="p==='ebucore:hasMimeType'" slot="ebucore:hasMimeType">
+        <p-d-labeled-value :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'mime'+j"></p-d-labeled-value>
+      </template>
+
+      <template v-else-if="p==='opaque:cco_accessionNumber'" slot="opaque:cco_accessionNumber">
+        <p-d-value :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'accnr'+j"></p-d-value>
+      </template>
+
+      <template v-else-if="p==='vra:hasInscription'" slot="vra:hasInscription">
+        <p-d-skos-preflabel :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'inscr'+j"></p-d-skos-preflabel>
+      </template>
+
+      <template v-else-if="p==='vra:material'" slot="vra:material">
+        <p-d-skos-preflabel :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'material'+j"></p-d-skos-preflabel>
+      </template>
+
+      <template v-else-if="p==='vra:hasTechnique'" slot="vra:hasTechnique">
+        <p-d-skos-preflabel :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'techn'+j"></p-d-skos-preflabel>
+      </template>
+
+      <template v-else-if="p==='dce:format'" slot="dce:format">
+        <p-d-skos-preflabel :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'format'+j"></p-d-skos-preflabel>
+      </template>
+
+      <template v-else-if="p==='rdau:P60048'" slot="rdau:P60048">
+        <p-d-skos-preflabel
+          :p="p"
+          :o="item"
+          v-for="(item, j) in o"
+          :key="componentid+'carriertype'+j"
+        ></p-d-skos-preflabel>
+      </template>
+
+      <template v-else-if="p==='rdau:P60059'" slot="rdau:P60059">
+        <p-d-skos-preflabel :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'regenc'+j"></p-d-skos-preflabel>
+      </template>
+
+      <template v-else-if="p==='schema:width'" slot="schema:width">
+        <p-d-dimension :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'width'+j"></p-d-dimension>
+      </template>
+
+      <template v-else-if="p==='schema:height'" slot="schema:height">
+        <p-d-dimension :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'height'+j"></p-d-dimension>
+      </template>
+
+      <template v-else-if="p==='schema:depth'" slot="schema:depth">
+        <p-d-dimension :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'depth'+j"></p-d-dimension>
+      </template>
+
+      <template v-else-if="p==='schema:weight'" slot="schema:weight">
+        <p-d-dimension :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'weight'+j"></p-d-dimension>
+      </template>
+
+      <template v-else-if="p==='schema:duration'" slot="schema:duration">
+        <p-d-duration :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'duration'+j"></p-d-duration>
+      </template>
+
+      <template v-else-if="p==='schema:numberOfPages'" slot="schema:numberOfPages">
+        <p-d-value :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'numberOfPages'+j"></p-d-value>
+      </template>
+
+      <template v-else-if="p==='bf:soundCharacteristic'" slot="bf:soundCharacteristic">
+        <p-d-value
+          :p="p"
+          :o="item"
+          v-for="(item, j) in o"
+          :key="componentid+'soundCharacteristic'+j"
+        ></p-d-value>
+      </template>
+
+      <template v-else-if="p==='bf:supplementaryContent'" slot="bf:supplementaryContent">
+        <p-d-skos-preflabel
+          :p="p"
+          :o="item"
+          v-for="(item, j) in o"
+          :key="componentid+'supplementaryContent'+j"
+        ></p-d-skos-preflabel>
+      </template>
+
+      <template v-else-if="p==='dcterms:audience'" slot="dcterms:audience">
+        <p-d-skos-preflabel :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'audience'+j"></p-d-skos-preflabel>
+      </template>
+
+      <template v-else-if="p==='bf:awards'" slot="bf:awards">
+        <p-d-skos-preflabel :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'awards'+j"></p-d-skos-preflabel>
+      </template>
+
+      <template v-else-if="p==='edm:rights'" slot="edm:rights">
+        <p-d-license :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'license'+j"></p-d-license>
+      </template>
+
+      <template v-else-if="p==='dce:rights'" slot="dce:rights">
+        <p-d-lang-value :p="p" :o="item" v-for="(item, j) in o" :key="componentid+'rights'+j"></p-d-lang-value>
+      </template>
+
+      <template v-else-if="p==='dcterms:subject'" slot="dcterms:subject">
+        <template v-for="(subject, j) in o">
+          <v-card
+            class="mt-3"
+            v-if="subject['@type']==='phaidra:Subject'"
+            :key="componentid+'psubject'+j"
+          >
+            <v-toolbar dense flat>
+              <v-layout>
+                <v-toolbar-title class="font-weight-light">Subject</v-toolbar-title>
+              </v-layout>
+            </v-toolbar>
+            <v-card-text class="ma-2">
+              <p-d-jsonld :jsonld="subject"></p-d-jsonld>
+            </v-card-text>
+          </v-card>
+          <p-d-skos-preflabel v-else :p="p" :o="subject" :key="componentid+'subject'+j"></p-d-skos-preflabel>
+        </template>
+      </template>
+
+      <template v-else-if="p==='@type'"></template>
+
+      <template v-else slot="unknown-predicate">
+        <v-container :key="p">
+          <v-alert :type="'error'" :value="true" transition="fade-transition">
+            Unknown predicate
+            <b>{{p}}</b>
+          </v-alert>
+          <p-i-unknown-readonly :jsonld="o" :label="p"></p-i-unknown-readonly>
+        </v-container>
+      </template>
+    </template>
+  </p-d-jsonld-layout>
+</template>
+
+<script>
+import PDLicense from "../phaidra_display/PDLicense";
+import PDTitle from "../phaidra_display/PDTitle";
+import PDSkosPreflabel from "../phaidra_display/PDSkosPreflabel";
+import PDKeyword from "../phaidra_display/PDKeyword";
+import PDLangValue from "../phaidra_display/PDLangValue";
+import PDValue from "../phaidra_display/PDValue";
+import PDDimension from "../phaidra_display/PDDimension";
+import PDDuration from "../phaidra_display/PDDuration";
+import PDGeoreference from "../phaidra_display/PDGeoreference";
+import PDEntity from "../phaidra_display/PDEntity";
+import PDLabeledValue from "../phaidra_display/PDLabeledValue";
+import PDFunder from "../phaidra_display/PDFunder";
+import PDProject from "../phaidra_display/PDProject";
+import PDBfPublication from "../phaidra_display/PDBfPublication";
+import PDStudyPlan from "../phaidra_display/PDStudyPlan";
+import PDSeries from "../phaidra_display/PDSeries";
+import PDAdaptation from "../phaidra_display/PDAdaptation";
+import PDCitation from "../phaidra_display/PDCitation";
+import PDJsonldLayout from "../phaidra_display/PDJsonldLayout";
+import PIUnknownReadonly from "../../input/phaidra_inputs/PIUnknownReadonly";
+import { vocabulary } from "../../../mixins/vocabulary";
+
+export default {
+  name: "p-d-jsonld",
+  mixins: [vocabulary],
+  props: {
+    jsonld: {
+      type: Object,
+      default: null
+    },
+    pid: String
+  },
+  components: {
+    PDTitle,
+    PDEntity,
+    PDJsonldLayout,
+    PDSkosPreflabel,
+    PDKeyword,
+    PDLangValue,
+    PDLicense,
+    PDValue,
+    PDDimension,
+    PDDuration,
+    PDGeoreference,
+    PDLabeledValue,
+    PDFunder,
+    PDProject,
+    PDBfPublication,
+    PDStudyPlan,
+    PDSeries,
+    PDAdaptation,
+    PDCitation,
+    PIUnknownReadonly
+  },
+  computed: {
+    instance: function() {
+      return this.$store.state.settings.instance;
+    },
+    componentid: function() {
+      return Math.floor(Math.random() * 10000000);
+    }
+  },
+  mounted: function() {
+    this.$store.dispatch("loadLanguages");
+  }
+};
+</script>
+
+<style>
+.valuefield {
+  white-space: pre-wrap;
+}
+</style>
\ No newline at end of file
diff --git a/src/components/display/phaidra_display/PDJsonldLayout.vue b/src/components/display/phaidra_display/PDJsonldLayout.vue
new file mode 100644
index 0000000000000000000000000000000000000000..d9eeb652061639aa5f29cfeaae376d3d021d87bf
--- /dev/null
+++ b/src/components/display/phaidra_display/PDJsonldLayout.vue
@@ -0,0 +1,86 @@
+<template>
+  <v-container>
+    <v-layout column>
+      <slot name="dce:title"></slot>
+      <slot name="role"></slot>
+      <slot name="bf:note"></slot>
+      <slot name="bf:tableOfContents"></slot>
+      
+      <slot name="edm:hasType"></slot>
+      <slot name="schema:genre"></slot>
+
+      <slot name="dcterms:language"></slot>
+      <slot name="schema:subtitleLanguage"></slot>
+      <slot name="dce:subject"></slot>
+
+      <slot name="dcterms:date"></slot>
+      <slot name="dcterms:created"></slot>
+      <slot name="dcterms:modified"></slot>
+      <slot name="dcterms:available"></slot>
+      <slot name="dcterms:issued"></slot>
+      <slot name="dcterms:valid"></slot>
+      <slot name="dcterms:dateAccepted"></slot>
+      <slot name="dcterms:dateCopyrighted"></slot>
+      <slot name="dcterms:dateSubmitted"></slot>
+      <slot name="rdau:P60071"></slot>
+      <slot name="phaidra:dateAccessioned"></slot>
+      <slot name="dcterms:temporal"></slot>
+
+      <slot name="rdau:P60193"></slot>
+      <slot name="cito:cites"></slot>
+      <slot name="cito:isCitedBy"></slot>
+      <slot name="bf:provisionActivity"></slot>
+      <slot name="rdau:P60227"></slot>
+
+      <slot name="frapo:hasFundingAgency"></slot>
+      <slot name="frapo:isOutputOf"></slot>
+      <slot name="rdax:P00009"></slot>
+      <slot name="dcterms:provenance"></slot>
+
+      <slot name="dcterms:spatial"></slot>
+      <slot name="vra:placeOfCreation"></slot>
+      <slot name="vra:placeOfRepository"></slot>
+      <slot name="vra:placeOfSite"></slot>
+
+      <slot name="schema:numberOfPages"></slot>
+      <slot name="bf:soundCharacteristic"></slot>
+      <slot name="bf:supplementaryContent"></slot>
+      <slot name="bf:awards"></slot>
+      <slot name="dcterms:audience"></slot>
+      <slot name="rdau:P60059"></slot>
+
+      <slot name="ebucore:filename"></slot>
+      <slot name="ebucore:hasMimeType"></slot>
+
+      <slot name="opaque:cco_accessionNumber"></slot>
+      <slot name="bf:shelfMark"></slot>
+      <slot name="bf:physicalLocation"></slot>
+
+      <slot name="vra:hasInscription"></slot>
+      <slot name="vra:material"></slot>
+      <slot name="vra:hasTechnique"></slot>
+      <slot name="dce:format"></slot>
+      <slot name="rdau:P60048"></slot>
+      <slot name="schema:width"></slot>
+      <slot name="schema:height"></slot>
+      <slot name="schema:depth"></slot>
+      <slot name="schema:weight"></slot>
+      <slot name="schema:duration"></slot>
+
+      <slot name="dcterms:type"></slot>
+      <slot name="pid"></slot>
+
+      <slot name="edm:rights"></slot>
+      <slot name="dce:rights"></slot>
+
+      <slot name="dcterms:subject"></slot>
+
+      <slot name="unknown-predicate"></slot>
+    </v-layout>
+  </v-container>
+</template>
+<script>
+export default {
+  name: 'p-d-jsonld-layout'
+}
+</script>
\ No newline at end of file
diff --git a/src/components/display/phaidra_display/PDKeyword.vue b/src/components/display/phaidra_display/PDKeyword.vue
new file mode 100644
index 0000000000000000000000000000000000000000..f2560c4425b62a159120b7a4ab70947d7c79cbda
--- /dev/null
+++ b/src/components/display/phaidra_display/PDKeyword.vue
@@ -0,0 +1,41 @@
+<template>
+  <v-flex>
+    <v-layout column >
+      <v-flex>
+        <template v-for="(l, i) in o['skos:prefLabel']">
+          <v-layout row wrap :key="'row'+i">
+            <v-flex class="pdlabel primary--text" md4 xs12 :key="'l'+i">{{ $t(p) }}<template v-if="l['@language']"> ({{ l['@language'] }})</template></v-flex>
+            <v-flex md8 xs12 :key="'t'+i">
+              <v-chip v-for="(keyword, j) in getKeywords(l)" :key="'kw'+j">{{keyword}}</v-chip>
+            </v-flex>
+          </v-layout>
+        </template>
+      </v-flex>
+    </v-layout>
+  </v-flex>
+</template>
+
+<script>
+export default {
+  name: 'p-d-keyword',
+  props: {
+    o: {
+      type: Object,
+      required: true
+    },
+    p: {
+      type: String
+    }
+  },
+  methods: {
+    getKeywords: function (l) {
+      if (l['@value']) {
+        return l['@value'].split(',')
+      } else {
+        return []
+      }
+    }
+  }
+}
+</script>
+
diff --git a/src/components/display/phaidra_display/PDLabeledValue.vue b/src/components/display/phaidra_display/PDLabeledValue.vue
new file mode 100644
index 0000000000000000000000000000000000000000..59ee0c3b5f5fa2d6968bed91af6429f74f05eaab
--- /dev/null
+++ b/src/components/display/phaidra_display/PDLabeledValue.vue
@@ -0,0 +1,50 @@
+<template>
+  <v-flex>
+    <v-layout row wrap>
+      <v-flex md4 xs12 class="pdlabel primary--text">{{ $t(p) }}</v-flex>
+      <v-flex md8 xs12>
+        {{ resolve(p, o) }}
+        <span class="grey--text">[{{o}}]</span>
+      </v-flex>
+    </v-layout>
+  </v-flex>
+</template>
+
+<script>
+import { vocabulary } from "../../../mixins/vocabulary";
+
+export default {
+  name: "p-d-labeled-value",
+  mixins: [vocabulary],
+  props: {
+    o: {
+      type: String,
+      required: true
+    },
+    p: {
+      type: String
+    }
+  },
+  methods: {
+    resolve: function(p, v) {
+      var vocabulary = "";
+      switch (p) {
+        case "dcterms:language":
+        case "schema:subtitleLanguage":
+          vocabulary = "lang";
+          break;
+
+        case "ebucore:hasMimeType":
+          vocabulary = "mimetypes";
+          break;
+
+        default:
+        //console.error('p-d-uri resolve: unrecognized predicate ', p, v)
+      }
+
+      return this.getLocalizedTermLabel(vocabulary, v);
+    }
+  }
+};
+</script>
+
diff --git a/src/components/display/phaidra_display/PDLangValue.vue b/src/components/display/phaidra_display/PDLangValue.vue
new file mode 100644
index 0000000000000000000000000000000000000000..e75a707ee8429f29ce010767e6f895a3e7926eb3
--- /dev/null
+++ b/src/components/display/phaidra_display/PDLangValue.vue
@@ -0,0 +1,24 @@
+<template>
+  <v-flex>
+    <v-layout row wrap>
+      <v-flex md4 xs12 class="pdlabel primary--text" xs3>{{ $t(p) }}<template v-if="o['@language']"> ({{ o['@language'] }})</template></v-flex>
+      <v-flex class="valuefield" md8 xs12>{{ o['@value'] }}</v-flex>
+    </v-layout>
+  </v-flex>
+</template>
+
+<script>
+export default {
+  name: 'p-d-lang-value',
+  props: {
+    o: {
+      type: Object,
+      required: true
+    },
+    p: {
+      type: String
+    }
+  }
+}
+</script>
+
diff --git a/src/components/display/phaidra_display/PDLicense.vue b/src/components/display/phaidra_display/PDLicense.vue
new file mode 100644
index 0000000000000000000000000000000000000000..78b26296d1d7c23a87098806e5177d8909e2ec29
--- /dev/null
+++ b/src/components/display/phaidra_display/PDLicense.vue
@@ -0,0 +1,44 @@
+<template>
+  <v-flex>
+    <v-layout row wrap>
+      <v-flex md4 xs12 class="pdlabel primary--text">{{ $t(p) }}</v-flex>
+      <v-flex md8 xs12>
+        <a :href="o" target="_blank">{{ getLocalizedTermLabel('licenses', o) }}</a>
+        <!--
+        <v-flex>
+          <v-img :src="'../../assets/' + getTermProperty('licenses', o, 'img')" :alt="o" class="license-icon"/>
+        </v-flex>
+        -->
+      </v-flex>
+    </v-layout>
+  </v-flex>
+</template>
+
+<script>
+import { vocabulary } from "../../../mixins/vocabulary";
+
+export default {
+  name: "p-d-license",
+  mixins: [vocabulary],
+  props: {
+    o: {
+      type: String,
+      required: true
+    },
+    p: {
+      type: String
+    }
+  }
+};
+</script>
+
+<style scoped>
+.license-icon {
+  height: 1.3em;
+  vertical-align: text-bottom;
+}
+
+.license-label {
+  vertical-align: middle;
+}
+</style>
diff --git a/src/components/display/phaidra_display/PDProject.vue b/src/components/display/phaidra_display/PDProject.vue
new file mode 100644
index 0000000000000000000000000000000000000000..f9d9465b7f05d0d2365aa1a1b1e103f175c4fb7c
--- /dev/null
+++ b/src/components/display/phaidra_display/PDProject.vue
@@ -0,0 +1,44 @@
+<template>
+  <v-flex>
+    <v-layout row wrap>
+      <template v-for="(l, i) in o['skos:prefLabel']">
+        <v-flex md4 xs12 class="pdlabel primary--text" :key="'pl'+i">{{ $t('Project') }} ({{ l['@language'] }})</v-flex>
+        <v-flex class="valuefield" md8 xs12 :key="'pv'+i" >{{ l['@value'] }}</v-flex>
+      </template>
+    </v-layout>
+    <v-layout row wrap>
+      <template v-for="(id, i) in o['skos:exactMatch']">
+        <v-flex md4 xs12 class="pdlabel primary--text" :key="'idl'+i">{{ $t('Project Id') }}</v-flex>
+        <v-flex md8 xs12 :key="'idv'+i">{{ id }}</v-flex>
+      </template>
+    </v-layout>
+    <v-layout row wrap>
+      <template v-for="(d, i) in o['rdfs:comment']">
+        <v-flex md4 xs12 class="pdlabel primary--text" :key="'dl'+i">{{ $t('Project Description') }} ({{ d['@language'] }})</v-flex>
+        <v-flex class="valuefield" md8 xs12 :key="'dv'+i">{{ d['@value'] }}</v-flex>
+      </template>
+    </v-layout>
+    <v-layout row wrap>
+      <template v-for="(hp, i) in o['foaf:homepage']">
+        <v-flex md4 xs12 class="pdlabel primary--text" :key="'hpl'+i">{{ $t('Project Homepage') }}</v-flex>
+        <v-flex md8 xs12 :key="'hpv'+i">{{ hp }}</v-flex>
+      </template>
+    </v-layout>
+  </v-flex>
+</template>
+
+<script>
+export default {
+  name: 'p-d-project',
+  props: {
+    o: {
+      type: Object,
+      required: true
+    },
+    p: {
+      type: String
+    }
+  }
+}
+</script>
+
diff --git a/src/components/display/phaidra_display/PDSeries.vue b/src/components/display/phaidra_display/PDSeries.vue
new file mode 100644
index 0000000000000000000000000000000000000000..2775efcff6deddb86a0b89d2ba5caea5382a2179
--- /dev/null
+++ b/src/components/display/phaidra_display/PDSeries.vue
@@ -0,0 +1,72 @@
+<template>
+  <v-layout row wrap>
+    <v-flex xs10>
+      <v-card >
+        <v-card-title class="subheading grey white--text">
+          <span>{{ $t(p) }}</span>
+        </v-card-title>
+        <v-divider></v-divider>
+        <v-card-text class="mt-4">
+          <v-layout row wrap>
+            <template v-for="(title, j) in o['dce:title']">
+              <template v-for="(mt, i) in title['bf:mainTitle']">
+                <v-flex md4 xs12 class="pdlabel primary--text" :key="'mt'+j+i">{{ $t(title['@type']) }}<template v-if="mt['@language']"> ({{ mt['@language'] }})</template></v-flex>
+                <v-flex md8 xs12 :key="'mtv'+j+i">
+                  <v-layout column>
+                    <v-flex class="valuefield">{{ mt['@value'] }}</v-flex>
+                  </v-layout>
+                </v-flex>
+              </template>
+            </template>
+          </v-layout>
+          <v-layout row wrap>
+            <template v-for="(volume, i) in o['bibo:volume']">
+              <v-flex md4 xs12 class="pdlabel primary--text" :key="'vl'+i">{{ $t('Volume') }}</v-flex>
+              <v-flex md8 xs12 :key="'v'+i">{{ volume }}</v-flex>
+            </template>
+          </v-layout>
+          <v-layout row wrap>
+            <template v-for="(issue, i) in o['bibo:issue']">
+              <v-flex md4 xs12  class="pdlabel primary--text" :key="'il'+i">{{ $t('Issue') }}</v-flex>
+              <v-flex md8 xs12 :key="'i'+i">{{ issue }}</v-flex>
+            </template>
+          </v-layout>
+          <v-layout row wrap>
+            <template v-for="(issn, i) in o['identifiers:issn']">
+              <v-flex md4 xs12 class="pdlabel primary--text" :key="'isl'+i">{{ $t('ISSN') }}</v-flex>
+              <v-flex md8 xs12 :key="'is'+i">{{ issn }}</v-flex>
+            </template>
+          </v-layout>
+          <v-layout row wrap>
+            <template v-for="(issued, i) in o['dcterms:issued']">
+              <v-flex md4 xs12 class="pdlabel primary--text" :key="'idatel'+i">{{ $t('Issued') }}</v-flex>
+              <v-flex md8 xs12 :key="'idate'+i">{{ issued }}</v-flex>
+            </template>
+          </v-layout>
+          <v-layout row wrap>
+            <template v-for="(id, i) in o['skos:exactMatch']">
+              <v-flex md4 xs12 class="pdlabel primary--text" :key="'idatel'+i">{{ $t('Identifier') }}</v-flex>
+              <v-flex md8 xs12 :key="'id'+i">{{ id }}</v-flex>
+            </template>
+          </v-layout>
+        </v-card-text>
+      </v-card>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+export default {
+  name: 'p-d-series',
+  props: {
+    o: {
+      type: Object,
+      required: true
+    },
+    p: {
+      type: String
+    }
+  }
+}
+</script>
+
diff --git a/src/components/display/phaidra_display/PDSkosPreflabel.vue b/src/components/display/phaidra_display/PDSkosPreflabel.vue
new file mode 100644
index 0000000000000000000000000000000000000000..ba3f12cc83210d75085f7f45510291f4844d4c1c
--- /dev/null
+++ b/src/components/display/phaidra_display/PDSkosPreflabel.vue
@@ -0,0 +1,44 @@
+<template>
+  <v-flex>
+    <v-layout column >
+      <v-flex>
+        <template v-for="(l, i) in o['skos:prefLabel']">
+          <v-layout :key="'lay'+i" row wrap v-if="l['@language'] === displaylang">
+            <v-flex md4 xs12 v-if="p==='bf:note'" class="pdlabel primary--text" :key="'l'+i">{{ $t(o['@type']) }}<template v-if="l['@language']"> ({{ l['@language'] }})</template></v-flex>
+            <v-flex md4 xs12 v-else class="pdlabel primary--text" :key="'l'+i">{{ $t(p) }}<template v-if="l['@language']"> ({{ l['@language'] }})</template></v-flex>
+            <v-flex md8 xs12 v-if="o['skos:exactMatch']" :key="'t-id'+i"><a class="valuefield" :href="o['skos:exactMatch'][0]" target="_blank">{{ l['@value'] }}</a></v-flex>
+            <v-flex class="valuefield" md8 xs12 v-else :key="'t'+i">{{ l['@value'] }}</v-flex>
+          </v-layout>
+        </template>
+      </v-flex>
+    </v-layout>
+  </v-flex>
+</template>
+
+<script>
+export default {
+  name: 'p-d-skos-preflabel',
+  props: {
+    o: {
+      type: Object,
+      required: true
+    },
+    p: {
+      type: String
+    }
+  },
+  computed: {
+    displaylang: function() {
+      let lang
+      let somelang
+      for (let label of this.o['skos:prefLabel']) {
+        somelang = label['@language']
+        if (label['@language'] === this.$i18n.locale) {
+          lang = this.$i18n.locale
+        }
+      }
+      return lang ? lang : somelang
+    }
+  }
+}
+</script>
diff --git a/src/components/display/phaidra_display/PDStudyPlan.vue b/src/components/display/phaidra_display/PDStudyPlan.vue
new file mode 100644
index 0000000000000000000000000000000000000000..f278c574300ba1a43e0c30884057d050c1deaa29
--- /dev/null
+++ b/src/components/display/phaidra_display/PDStudyPlan.vue
@@ -0,0 +1,32 @@
+<template>
+  <v-flex>
+    <v-layout row wrap>
+      <template v-for="(l, i) in o['skos:prefLabel']">
+        <v-flex md4 xs12 class="pdlabel primary--text" :key="'pl'+i">{{ $t('Study plan') }}</v-flex>
+        <v-flex md8 xs12 :key="'spl'+i">
+          <v-layout column>
+            <v-flex class="valuefield" >{{ l['@value'] }}</v-flex>
+            <template v-for="(id, i) in o['skos:notation']">
+              <v-flex class="grey--text"  xs4 :key="'notation'+i">[{{ id }}]</v-flex>
+            </template>
+          </v-layout>
+        </v-flex>
+        
+      </template>
+    </v-layout>
+
+  </v-flex>
+</template>
+
+<script>
+export default {
+  name: 'p-d-study-plan',
+  props: {
+    o: {
+      type: Object,
+      required: true
+    }
+  }
+}
+</script>
+
diff --git a/src/components/display/phaidra_display/PDTitle.vue b/src/components/display/phaidra_display/PDTitle.vue
new file mode 100644
index 0000000000000000000000000000000000000000..a8d3911b09819fa5e7e1839109d0610a005a80b2
--- /dev/null
+++ b/src/components/display/phaidra_display/PDTitle.vue
@@ -0,0 +1,34 @@
+<template>
+  <v-flex>
+    <v-layout column >
+      <v-flex>
+        <template v-for="(mt, i) in o['bf:mainTitle']">
+          <v-layout :key="'row'+i" row wrap>
+            <v-flex md4 xs12 class="pdlabel primary--text" :key="'mt'+i">{{ $t(o['@type']) }}<template v-if="mt['@language']"> ({{ mt['@language'] }})</template></v-flex>
+            <v-flex md8 xs12>
+              <v-layout column :key="'mtv'+i">
+                <v-flex class="valuefield">{{ mt['@value'] }}</v-flex>
+                <template v-for="(st, i) in o['bf:subtitle']">
+                  <v-flex class="valuefield" :key="'stv'+i">{{ st['@value'] }}</v-flex>
+                </template>
+              </v-layout>
+            </v-flex>
+          </v-layout>
+        </template>
+      </v-flex>
+    </v-layout>
+  </v-flex>
+</template>
+
+<script>
+export default {
+  name: 'p-d-title',
+  props: {
+    o: {
+      type: Object,
+      required: true
+    }
+  }
+}
+</script>
+
diff --git a/src/components/display/phaidra_display/PDUwmetadata.vue b/src/components/display/phaidra_display/PDUwmetadata.vue
new file mode 100644
index 0000000000000000000000000000000000000000..e7ce685cb6bbbbc5845126c3faf7278db2809945
--- /dev/null
+++ b/src/components/display/phaidra_display/PDUwmetadata.vue
@@ -0,0 +1,212 @@
+<template>
+  <v-flex v-if="this.indexdata">
+    <v-flex v-for="(title,i) in getTitles()" :key="'title'+i" class="mt-3">
+      <v-container fluid>
+        <v-layout row>
+          <v-flex class="caption grey--text" xs2>{{ $t('Title') }} ({{ title.lang }})</v-flex>
+          <v-flex xs9>{{ title.value }}</v-flex>
+        </v-layout>
+      </v-container>
+    </v-flex>
+
+    <v-flex v-for="(role,i) in parsedRolesUwm()" :key="'role'+i" class="mt-3">
+      <v-container fluid>
+        <v-layout row>
+          <v-flex class="caption grey--text" xs2>{{ role.label }}</v-flex>
+          <v-flex xs9>
+            <v-layout column>
+              <v-flex v-for="(entity,j) in role.entities" :key="j">
+                {{ entity.firstname }} {{ entity.lastname }}
+                <span class="grey--text">{{ entity.institution }}</span>
+              </v-flex>
+            </v-layout>
+          </v-flex>
+        </v-layout>
+      </v-container>
+    </v-flex>
+
+    <v-flex v-if="indexdata.bib_journal" class="mt-3">
+      <v-container fluid>
+        <v-layout row>
+          <v-flex class="caption grey--text" xs2>{{ $t('Journal') }}</v-flex>
+          <v-flex xs9>
+            <v-layout column>
+              <v-flex v-for="(v,i) in indexdata.bib_journal" :key="i">{{v}}</v-flex>
+            </v-layout>
+          </v-flex>
+        </v-layout>
+      </v-container>
+    </v-flex>
+
+    <v-flex v-if="indexdata.bib_volume" class="mt-3">
+      <v-container fluid>
+        <v-layout row>
+          <v-flex class="caption grey--text" xs2>{{ $t('Volume') }}</v-flex>
+          <v-flex xs9>
+            <v-layout column>
+              <v-flex v-for="(v,i) in indexdata.bib_volume" :key="i">{{v}}</v-flex>
+            </v-layout>
+          </v-flex>
+        </v-layout>
+      </v-container>
+    </v-flex>
+
+    <v-flex v-if="indexdata.bib_publisher" class="mt-3">
+      <v-container fluid>
+        <v-layout row>
+          <v-flex class="caption grey--text" xs2>{{ $t('Publisher') }}</v-flex>
+          <v-flex xs9>
+            <v-layout column>
+              <v-flex v-for="(v,i) in indexdata.bib_publisher" :key="i">{{v}}</v-flex>
+            </v-layout>
+          </v-flex>
+        </v-layout>
+      </v-container>
+    </v-flex>
+
+    <v-flex v-if="indexdata.bib_published" class="mt-3">
+      <v-container fluid>
+        <v-layout row>
+          <v-flex class="caption grey--text" xs2>{{ $t('Published') }}</v-flex>
+          <v-flex xs9>
+            <v-layout column>
+              <v-flex v-for="(v,i) in indexdata.bib_published" :key="i">{{v}}</v-flex>
+            </v-layout>
+          </v-flex>
+        </v-layout>
+      </v-container>
+    </v-flex>
+
+    <v-flex v-if="indexdata.bib_publisherlocation" class="mt-3">
+      <v-container fluid>
+        <v-layout row>
+          <v-flex class="caption grey--text" xs2>{{ $t('Publisher location') }}</v-flex>
+          <v-flex xs9>
+            <v-layout column>
+              <v-flex v-for="(v,i) in indexdata.bib_publisherlocation" :key="i">{{v}}</v-flex>
+            </v-layout>
+          </v-flex>
+        </v-layout>
+      </v-container>
+    </v-flex>
+
+    <v-flex v-for="(desc,i) in getDescriptions()" :key="'desc'+i" class="mt-3">
+      <v-container fluid>
+        <v-layout row>
+          <v-flex class="caption grey--text" xs2>{{ $t('Description') }} ({{ desc.lang }})</v-flex>
+          <v-flex xs9>{{ desc.value }}</v-flex>
+        </v-layout>
+      </v-container>
+    </v-flex>
+
+    <v-flex class="mt-3" v-if="indexdata.dc_license">
+      <v-container fluid>
+        <v-layout row>
+          <v-flex class="caption grey--text" xs2>{{ $t('License') }}</v-flex>
+          <v-flex xs9>
+            <p-d-license v-if="indexdata.dc_license" :dclicense="indexdata.dc_license[0]"></p-d-license>
+          </v-flex>
+        </v-layout>
+      </v-container>
+    </v-flex>
+  </v-flex>
+</template>
+
+<script>
+import PDLicense from "./PDLicense";
+import { vocabulary } from "../../../mixins/vocabulary";
+
+export default {
+  name: "p-d-uwmetadata",
+  mixins: [vocabulary],
+  props: {
+    pid: {
+      type: String
+    },
+    indexdata: {
+      type: Object,
+      default: null
+    }
+  },
+  components: {
+    PDLicense
+  },
+  methods: {
+    getRoleLabel: function(role) {
+      var id = role.substring(role.indexOf(":") + 1);
+      var roleTerms = this.vocabularies["rolepredicate"].terms;
+      for (var i = 0; i < roleTerms.length; i++) {
+        if (roleTerms[i]["@id"] === id) {
+          return roleTerms[i]["skos:prefLabel"][0]["@value"];
+        }
+      }
+    },
+    getTitles: function() {
+      var titles = [];
+      var doc = this.indexdata;
+      Object.keys(doc).forEach(function(field) {
+        if (field.startsWith("dc_title_")) {
+          for (var i = 0; i < doc[field].length; i++) {
+            titles.push({
+              value: doc[field][i],
+              lang: field.substr(field.length - 3)
+            });
+          }
+        }
+      });
+      return titles;
+    },
+    getDescriptions: function() {
+      var descriptions = [];
+      var doc = this.indexdata;
+      Object.keys(doc).forEach(function(field) {
+        if (field.startsWith("dc_description_")) {
+          for (var i = 0; i < doc[field].length; i++) {
+            descriptions.push({
+              value: doc[field][i],
+              lang: field.substr(field.length - 3)
+            });
+          }
+        }
+      });
+      return descriptions;
+    },
+    parsedRolesUwm: function() {
+      var rolesHash = {};
+      if (this.indexdata.uwm_roles_json) {
+        var sortedContr = JSON.parse(this.indexdata.uwm_roles_json).sort(
+          function(a, b) {
+            return a.data_order - b.data_order;
+          }
+        );
+        for (var i = 0; i < sortedContr.length; i++) {
+          sortedContr[i].entities = sortedContr[i].entities.sort(function(
+            a,
+            b
+          ) {
+            return a.data_order - b.data_order;
+          });
+          // merge multiple entities and multiple contributions if they have the same role
+          if (!rolesHash[sortedContr[i].role]) {
+            rolesHash[sortedContr[i].role] = {
+              role: sortedContr[i].role,
+              label: this.getRoleLabel(sortedContr[i].role),
+              entities: []
+            };
+          }
+          for (var j = 0; j < sortedContr[i].entities.length; j++) {
+            rolesHash[sortedContr[i].role]["entities"].push(
+              sortedContr[i].entities[j]
+            );
+          }
+        }
+      }
+      var roles = [];
+      Object.keys(rolesHash).forEach(function(r) {
+        roles.push(rolesHash[r]);
+      });
+      return roles;
+    }
+  }
+};
+</script>
diff --git a/src/components/display/phaidra_display/PDValue.vue b/src/components/display/phaidra_display/PDValue.vue
new file mode 100644
index 0000000000000000000000000000000000000000..49c1e49fdca02065aeccbd5d0fad7ebbe866e9b7
--- /dev/null
+++ b/src/components/display/phaidra_display/PDValue.vue
@@ -0,0 +1,24 @@
+<template>
+  <v-flex>
+    <v-layout row wrap>
+      <v-flex md4 xs12 class="pdlabel primary--text">{{ $t(p) }}</v-flex>
+      <v-flex md8 xs12>{{ o }}</v-flex>
+    </v-layout>
+  </v-flex>
+</template>
+
+<script>
+export default {
+  name: 'p-d-value',
+  props: {
+    o: {
+      type: String,
+      required: true
+    },
+    p: {
+      type: String
+    }
+  }
+}
+</script>
+
diff --git a/src/components/input/phaidra_inputs/PIAdaptation.vue b/src/components/input/phaidra_inputs/PIAdaptation.vue
new file mode 100644
index 0000000000000000000000000000000000000000..ed5572afd95b71fd5e228f7d9b6544e72ef3e426
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PIAdaptation.vue
@@ -0,0 +1,192 @@
+<template>
+  <v-layout row>
+    <v-flex xs12>
+      <v-card>
+        <v-card-title class="subheading grey white--text">
+          <span>{{ $t(label) }}</span>
+          <v-spacer></v-spacer>
+          <v-menu open-on-hover bottom offset-y v-if="actions.length">
+            <v-btn slot="activator" icon dark>
+              <v-icon dark>more_vert</v-icon>
+            </v-btn>
+            <v-list>
+              <v-list-tile
+                v-for="(action, i) in actions"
+                :key="i"
+                @click="$emit(action.event, $event)"
+              >
+                <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+              </v-list-tile>
+            </v-list>
+          </v-menu>
+        </v-card-title>
+        <v-divider></v-divider>
+        <v-card-text class="mt-4">
+          <v-layout column>
+            <v-flex>
+              <v-layout row>
+                <v-flex xs4>
+                  <v-text-field
+                    :value="title"
+                    :label="$t('Title')"
+                    v-on:blur="$emit('input-title',$event.target.value)"
+                    box
+                  ></v-text-field>
+                </v-flex>
+                <v-flex xs4>
+                  <v-text-field
+                    :value="subtitle"
+                    :label="$t('Subtitle')"
+                    v-on:blur="$emit('input-subtitle',$event.target.value)"
+                    box
+                  ></v-text-field>
+                </v-flex>
+                <v-flex xs4>
+                  <v-autocomplete
+                    :value="getTerm('lang', titleLanguage)"
+                    v-on:input="$emit('input-title-language', $event)"
+                    :items="vocabularies['lang'].terms"
+                    :filter="autocompleteFilter"
+                    hide-no-data
+                    :label="$t('Language')"
+                    box
+                    return-object
+                    clearable
+                  >
+                    <template slot="item" slot-scope="{ item }">
+                      <v-list-tile-content two-line>
+                        <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+                        <v-list-tile-sub-title v-html="`${item['@id']}`"></v-list-tile-sub-title>
+                      </v-list-tile-content>
+                    </template>
+                    <template slot="selection" slot-scope="{ item }">
+                      <v-list-tile-content>
+                        <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+                      </v-list-tile-content>
+                    </template>
+                  </v-autocomplete>
+                </v-flex>
+              </v-layout>
+
+              <v-layout row>
+                <template v-if="showname">
+                  <v-flex xs4>
+                    <v-text-field
+                      :value="name"
+                      :label="$t('Name')"
+                      v-on:blur="$emit('input-name',$event.target.value)"
+                      box
+                    ></v-text-field>
+                  </v-flex>
+                </template>
+                <template v-else>
+                  <v-flex xs4>
+                    <v-text-field
+                      :value="firstname"
+                      :label="$t('Firstname')"
+                      v-on:blur="$emit('input-firstname',$event.target.value)"
+                      box
+                    ></v-text-field>
+                  </v-flex>
+                  <v-flex xs4>
+                    <v-text-field
+                      :value="lastname"
+                      :label="$t('Lastname')"
+                      v-on:blur="$emit('input-lastname',$event.target.value)"
+                      box
+                    ></v-text-field>
+                  </v-flex>
+                </template>
+                <v-flex xs4>
+                  <v-autocomplete
+                    :disabled="disablerole"
+                    v-on:input="$emit('input-role', $event)"
+                    :label="$t('Role')"
+                    :items="vocabularies['rolepredicate'].terms"
+                    :value="getTerm('rolepredicate', role)"
+                    :filter="autocompleteFilter"
+                    box
+                    return-object
+                    clearable
+                  >
+                    <template slot="item" slot-scope="{ item }">
+                      <v-list-tile-content two-line>
+                        <v-list-tile-title
+                          v-html="`${getLocalizedTermLabel('rolepredicate', item['@id'])}`"
+                        ></v-list-tile-title>
+                        <v-list-tile-sub-title v-html="`${item['@id']}`"></v-list-tile-sub-title>
+                      </v-list-tile-content>
+                    </template>
+                    <template slot="selection" slot-scope="{ item }">
+                      <v-list-tile-content>
+                        <v-list-tile-title
+                          v-html="`${getLocalizedTermLabel('rolepredicate', item['@id'])}`"
+                        ></v-list-tile-title>
+                      </v-list-tile-content>
+                    </template>
+                  </v-autocomplete>
+                </v-flex>
+              </v-layout>
+            </v-flex>
+          </v-layout>
+        </v-card-text>
+      </v-card>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import { vocabulary } from "../../../mixins/vocabulary";
+import { fieldproperties } from "../../../mixins/fieldproperties";
+
+export default {
+  name: "p-i-adaptation",
+  mixins: [vocabulary, fieldproperties],
+  props: {
+    type: {
+      type: String
+    },
+    label: {
+      type: String
+    },
+    title: {
+      type: String
+    },
+    subtitle: {
+      type: String
+    },
+    titleLanguage: {
+      type: String
+    },
+    firstname: {
+      type: String
+    },
+    lastname: {
+      type: String
+    },
+    name: {
+      type: String
+    },
+    role: {
+      type: String
+    },
+    disablerole: {
+      type: Boolean,
+      default: false
+    },
+    showname: {
+      type: Boolean,
+      default: false
+    }
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+.vertical-center {
+  align-items: center;
+}
+</style>
diff --git a/src/components/input/phaidra_inputs/PIAssociation.vue b/src/components/input/phaidra_inputs/PIAssociation.vue
new file mode 100644
index 0000000000000000000000000000000000000000..f5361b73d6d8fe8ebfb910bab77fccdd24da70c7
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PIAssociation.vue
@@ -0,0 +1,172 @@
+<template>
+  <v-layout row>
+    <v-flex xs8>
+      <v-autocomplete
+        :value="getTerm(value)"
+        :required="required"
+        v-on:input="handleInput($event)"
+        :rules="required ? [ v => !!v || 'Required'] : []"
+        :items="orgunits"
+        :loading="loading"
+        :filter="autocompleteFilter"
+        hide-no-data
+        :label="$t(label)"
+        box
+        return-object
+        clearable
+        :disabled="disabled"
+        :messages="path"
+      >
+        <template slot="item" slot-scope="{ item }">
+          <v-list-tile-content two-line>
+            <v-list-tile-title  v-html="`${getLocalizedTermLabel(item)}`"></v-list-tile-title>
+            <v-list-tile-sub-title  v-html="`${item['@id']}`"></v-list-tile-sub-title>
+          </v-list-tile-content>
+        </template>
+        <template slot="selection" slot-scope="{ item }">
+          <v-list-tile-content>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel(item)}`"></v-list-tile-title>
+          </v-list-tile-content>
+        </template>
+      </v-autocomplete>
+    </v-flex>
+    <v-flex xs1 v-if="actions.length">
+      <v-menu open-on-hover bottom offset-y>
+        <v-btn slot="activator" icon>
+          <v-icon>more_vert</v-icon>
+        </v-btn>
+        <v-list>
+          <v-list-tile v-for="(action, i) in actions" :key="i" @click="$emit(action.event, $event)">
+            <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+          </v-list-tile>
+        </v-list>
+      </v-menu>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import { fieldproperties } from "../../../mixins/fieldproperties";
+
+export default {
+  name: "p-i-association",
+  mixins: [fieldproperties],
+  methods: {
+    autocompleteFilter: function(item, queryText) {
+      const lab = item["skos:prefLabel"][this.$i18n.locale]
+        ? item["skos:prefLabel"][this.$i18n.locale].toLowerCase()
+        : item["skos:prefLabel"]["eng"].toLowerCase();
+      const query = queryText.toLowerCase();
+      return lab.indexOf(query) > -1;
+    },
+    getTerm: function(v) {
+      for (let u of this.orgunits) {
+        if (u["@id"] === v) {
+          return u;
+        }
+      }
+    },
+    getLocalizedTermLabel: function(item) {
+      return item["skos:prefLabel"][this.$i18n.locale]
+        ? item["skos:prefLabel"][this.$i18n.locale]
+        : item["skos:prefLabel"]["eng"];
+    },
+    addToOrgunits: function(units, parent) {
+      for (let u of units) {
+        this.orgunits.push(u);
+        u.parent = parent;
+        if (u["subunits"]) {
+          if (u.subunits.length > 0) {
+            this.addToOrgunits(u.subunits, u);
+          }
+        }
+      }
+    },
+    handleInput: function(unit) {
+      this.path = "";
+      let parentpath = [];
+      this.getParentPath(unit, parentpath);
+      for (let u of parentpath.reverse()) {
+        this.path = this.path + u["skos:prefLabel"][this.$i18n.locale] + " > ";
+      }
+      this.path = this.path + unit["skos:prefLabel"][this.$i18n.locale];
+      this.$emit("input", unit);
+    },
+    getParentPath: function(unit, parentpath) {
+      if (unit["parent"]) {
+        parentpath.push(unit.parent);
+        this.getParentPath(unit.parent, parentpath);
+      }
+    },
+    loadOrgUnits: function() {
+      var self = this;
+      this.loading = true;
+      var url =
+        self.$store.state.settings.instance.api + "/directory/org_get_units";
+      var promise = fetch(url, {
+        method: "GET",
+        mode: "cors",
+        headers: {
+          "X-XSRF-TOKEN": this.$store.state.user.token
+        }
+      })
+        .then(function(response) {
+          return response.json();
+        })
+        .then(function(json) {
+          if (json.alerts && json.alerts.length > 0) {
+            self.$store.commit("setAlerts", json.alerts);
+          }
+          self.loading = false;
+          self.templatedialog = false;
+          self.addToOrgunits(json.units, null);
+        })
+        .catch(function(error) {
+          console.log(error);
+        });
+      return promise;
+    }
+  },
+  props: {
+    value: {
+      type: String
+    },
+    label: {
+      type: String,
+      required: true
+    },
+    required: {
+      type: Boolean
+    },
+    disabled: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      loading: false,
+      orgunits: [],
+      path: ""
+    };
+  },
+  mounted: function() {
+    this.$nextTick(function() {
+      let self = this;
+      this.loadOrgUnits().then(function() {
+        if (self.value) {
+          let term = self.getTerm(self.value);
+          // emit input to set skos:prefLabel in parent
+          self.handleInput(term);
+        }
+      });
+    });
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+</style>
diff --git a/src/components/input/phaidra_inputs/PIBfPublication.vue b/src/components/input/phaidra_inputs/PIBfPublication.vue
new file mode 100644
index 0000000000000000000000000000000000000000..bfc0d40aa36cb1d11ef99798eafee2556fb60952
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PIBfPublication.vue
@@ -0,0 +1,105 @@
+<template>
+<v-layout row>
+    <v-flex xs12>
+
+      <v-card >
+        <v-card-title class="subheading grey white--text">
+            <span>{{ $t(label) }}</span>
+            <v-spacer></v-spacer>
+            <v-menu open-on-hover bottom offset-y v-if="actions.length">
+              <v-btn slot="activator" icon dark>
+                <v-icon dark>more_vert</v-icon>
+              </v-btn>
+              <v-list>
+                <v-list-tile v-for="(action, i) in actions" :key="i" @click="$emit(action.event, $event)">
+                  <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+                </v-list-tile>
+              </v-list>
+            </v-menu>
+        </v-card-title>
+        <v-divider></v-divider>
+        <v-card-text class="mt-4">
+
+          <v-layout row>
+            <v-flex xs4>
+              <v-text-field
+                :value="publisherName"
+                v-on:blur="$emit('input-publisher-name',$event.target.value)"
+                :label="$t(publisherNameLabel ? publisherNameLabel : '')"
+                :required="required"
+                :rules="required ? [ v => !!v || 'Required'] : []"
+                box
+              ></v-text-field>
+            </v-flex>
+            <v-flex xs4>
+              <v-text-field
+                :value="publishingPlace"
+                v-on:blur="$emit('input-publishing-place',$event.target.value)"
+                :label="$t(publishingPlaceLabel ? publishingPlaceLabel : '')"
+                :required="required"
+                :rules="required ? [ v => !!v || 'Required'] : []"
+                box
+              ></v-text-field>
+            </v-flex>
+            <v-flex xs4>
+              <v-text-field       
+                :value="publishingDate" 
+                v-on:blur="$emit('input-publishing-date',$event.target.value)"
+                :label="$t(publishingDateLabel ? publishingDateLabel : '')"
+                :required="required"
+                :hint="'Format YYYY-MM-DD'"
+                :rules="[validationrules.date]"
+                box
+              ></v-text-field>
+            </v-flex>
+          </v-layout>
+
+        </v-card-text>
+      </v-card>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import qs from "qs";
+import { fieldproperties } from "../../../mixins/fieldproperties";
+import { validationrules } from "../../../mixins/validationrules";
+
+export default {
+  name: "p-i-bf-publication",
+  mixins: [validationrules, fieldproperties],
+  props: {
+    publisherName: {
+      type: String,
+      required: true
+    },
+    publishingDate: {
+      type: String
+    },
+    publishingPlace: {
+      type: String
+    },
+    label: {
+      type: String
+    },
+    publisherNameLabel: {
+      type: String
+    },
+    publishingDateLabel: {
+      type: String
+    },
+    publishingPlaceLabel: {
+      type: String
+    },
+    required: {
+      type: Boolean
+    }
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+</style>
diff --git a/src/components/input/phaidra_inputs/PICitation.vue b/src/components/input/phaidra_inputs/PICitation.vue
new file mode 100644
index 0000000000000000000000000000000000000000..eba1b3d6a75339f6e89ab7ccaa4f50d64f6953cc
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PICitation.vue
@@ -0,0 +1,146 @@
+<template>
+  <v-layout row>
+    <v-flex xs2>
+      <v-autocomplete
+        v-on:input="$emit('input-citation-type', $event)"
+        :label="$t('Citation type')"
+        :items="vocabularies['citationpredicate'].terms"
+        :value="getTerm('citationpredicate', type)"
+        :filter="autocompleteFilter"
+        :disabled="disabletype"
+        box
+        return-object
+        clearable
+      >
+        <template slot="item" slot-scope="{ item }">
+          <v-list-tile-content two-line>
+            <v-list-tile-title
+              v-html="`${getLocalizedTermLabel('citationpredicate', item['@id'])}`"
+            ></v-list-tile-title>
+            <v-list-tile-sub-title v-html="`${item['@id']}`"></v-list-tile-sub-title>
+          </v-list-tile-content>
+        </template>
+        <template slot="selection" slot-scope="{ item }">
+          <v-list-tile-content>
+            <v-list-tile-title
+              v-html="`${getLocalizedTermLabel('citationpredicate', item['@id'])}`"
+            ></v-list-tile-title>
+          </v-list-tile-content>
+        </template>
+      </v-autocomplete>
+    </v-flex>
+    <v-flex xs4>
+      <v-text-field
+        :value="citation"
+        v-on:input="$emit('input-citation', $event)"
+        :label="$t(citationLabel)"
+        :required="required"
+        :rules="required ? [ v => !!v || 'Required'] : []"
+        box
+      ></v-text-field>
+    </v-flex>
+    <v-flex xs2>
+      <v-autocomplete
+        :value="getTerm('lang', citationLanguage)"
+        v-on:input="$emit('input-citation-language', $event)"
+        :items="vocabularies['lang'].terms"
+        :filter="autocompleteFilter"
+        hide-no-data
+        :label="$t('Language')"
+        box
+        return-object
+        clearable
+      >
+        <template slot="item" slot-scope="{ item }">
+          <v-list-tile-content two-line>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+            <v-list-tile-sub-title v-html="`${item['@id']}`"></v-list-tile-sub-title>
+          </v-list-tile-content>
+        </template>
+        <template slot="selection" slot-scope="{ item }">
+          <v-list-tile-content>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+          </v-list-tile-content>
+        </template>
+      </v-autocomplete>
+    </v-flex>
+    <v-flex xs4>
+      <v-text-field
+        :value="identifier"
+        v-on:input="$emit('input-identifier', $event)"
+        :label="$t(identifierLabel)"
+        :required="required"
+        :rules="required ? [ v => !!v || 'Required'] : []"
+        box
+      ></v-text-field>
+    </v-flex>
+    <v-flex xs1 v-if="actions.length">
+      <v-menu open-on-hover bottom offset-y>
+        <v-btn slot="activator" icon>
+          <v-icon>more_vert</v-icon>
+        </v-btn>
+        <v-list>
+          <v-list-tile v-for="(action, i) in actions" :key="i" @click="$emit(action.event, $event)">
+            <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+          </v-list-tile>
+        </v-list>
+      </v-menu>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import { vocabulary } from "../../../mixins/vocabulary";
+import { fieldproperties } from "../../../mixins/fieldproperties";
+
+export default {
+  name: "p-i-citation",
+  mixins: [vocabulary, fieldproperties],
+  props: {
+    citation: {
+      type: String
+    },
+    citationLanguage: {
+      type: String
+    },
+    identifier: {
+      type: String
+    },
+    type: {
+      type: String
+    },
+    citationLabel: {
+      type: String,
+      required: true
+    },
+    identifierLabel: {
+      type: String,
+      required: true
+    },
+    required: {
+      type: Boolean
+    },
+    disabletype: {
+      type: Boolean
+    }
+  },
+  mounted: function() {
+    this.$nextTick(function() {
+      this.loading = !this.vocabularies["citationpredicate"].loaded;
+      // emit input to set skos:prefLabel in parent
+      if (this.type) {
+        this.$emit(
+          "input-citation-type",
+          this.getTerm("citationpredicate", this.type)
+        );
+      }
+    });
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+</style>
diff --git a/src/components/input/phaidra_inputs/PIContainedIn.vue b/src/components/input/phaidra_inputs/PIContainedIn.vue
new file mode 100644
index 0000000000000000000000000000000000000000..937ebf41a72ce445670573cb329f4ac1e838c4a3
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PIContainedIn.vue
@@ -0,0 +1,408 @@
+<template>
+
+  <v-row>
+    <v-col cols="12">
+      <v-card >
+        <v-card-title class="title font-weight-light grey white--text">
+            <span>{{ $t(label) }}</span>
+        </v-card-title>
+        <v-divider></v-divider>
+        <v-card-text class="mt-4">
+          <v-row>
+            <v-col>
+              <v-row >
+                <v-col cols="12" :md="multilingual ? 4 : 6">
+                  <v-text-field
+                    :value="title"
+                    :label="$t('Title')"
+                    v-on:blur="$emit('input-title',$event.target.value)"
+                    :filled="inputStyle==='filled'"
+                    :outlined="inputStyle==='outlined'"
+                  ></v-text-field>
+                </v-col>
+                <v-col cols="12" :md="multilingual ? 4 : 6">
+                  <v-text-field
+                    :value="subtitle"
+                    :label="$t('Subtitle')"
+                    v-on:blur="$emit('input-subtitle',$event.target.value)"
+                    :filled="inputStyle==='filled'"
+                    :outlined="inputStyle==='outlined'"
+                  ></v-text-field>
+                </v-col>
+                <v-col cols="4" v-if="multilingual">
+                  <v-autocomplete
+                    :value="getTerm('lang', titleLanguage)"
+                    v-on:input="$emit('input-title-language', $event)"
+                    :items="vocabularies['lang'].terms"
+                    :filter="autocompleteFilter"
+                    hide-no-data
+                    :label="$t('Language')"
+                    :filled="inputStyle==='filled'"
+                    :outlined="inputStyle==='outlined'"
+                    return-object
+                    clearable
+                    :item-value="'@id'"
+                  >
+                    <template slot="item" slot-scope="{ item }">
+                      <v-list-item-content two-line>
+                        <v-list-item-title  v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-item-title>
+                        <v-list-item-subtitle v-if="showIds" v-html="`${item['@id']}`"></v-list-item-subtitle>
+                      </v-list-item-content>
+                    </template>
+                    <template slot="selection" slot-scope="{ item }">
+                      <v-list-item-content>
+                        <v-list-item-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-item-title>
+                      </v-list-item-content>
+                    </template>
+                  </v-autocomplete>
+                </v-col>
+              </v-row>
+              <v-row v-for="(role, i) in roles" :key="'role'+i">
+                <v-col cols="4">
+                  <v-autocomplete
+                    :disabled="disablerole"
+                    v-on:input="$emit('input-role', { role: role, roleTerm: $event })"
+                    :label="$t('Role')"
+                    :items="vocabularies['rolepredicate'].terms"
+                    :value="getTerm('rolepredicate', role.role)"
+                    :filter="autocompleteFilter"
+                    :filled="inputStyle==='filled'"
+                    :outlined="inputStyle==='outlined'"
+                    return-object
+                    clearable
+                    :item-value="'@id'"
+                  >
+                    <template slot="item" slot-scope="{ item }">
+                      <v-list-item-content two-line>
+                        <v-list-item-title  v-html="`${getLocalizedTermLabel('rolepredicate', item['@id'])}`"></v-list-item-title>
+                        <v-list-item-subtitle v-if="showIds" v-html="`${item['@id']}`"></v-list-item-subtitle>
+                      </v-list-item-content>
+                    </template>
+                    <template slot="selection" slot-scope="{ item }">
+                      <v-list-item-content>
+                        <v-list-item-title v-html="`${getLocalizedTermLabel('rolepredicate', item['@id'])}`"></v-list-item-title>
+                      </v-list-item-content>
+                    </template>
+                  </v-autocomplete>
+                </v-col>
+                <template v-if="showname">
+                  <v-col cols="4" >
+                    <v-text-field
+                      :value="role.name"
+                      :label="$t('Name')"
+                      v-on:blur="$emit('input-role',{ role: role, name: $event.target.value })"
+                      :filled="inputStyle==='filled'"
+                      :outlined="inputStyle==='outlined'"
+                    ></v-text-field>
+                  </v-col>
+                </template>
+                <template v-else>
+                  <v-col cols="3">
+                    <v-text-field
+                      :value="role.firstname"
+                      :label="$t('Firstname')"
+                      v-on:blur="$emit('input-role',{ role: role, firstname: $event.target.value })"
+                      :filled="inputStyle==='filled'"
+                      :outlined="inputStyle==='outlined'"
+                    ></v-text-field>
+                  </v-col>
+                  <v-col cols="3">
+                    <v-text-field
+                      :value="role.lastname"
+                      :label="$t('Lastname')"
+                      v-on:blur="$emit('input-role',{ role: role, lastname: $event.target.value })"
+                      :filled="inputStyle==='filled'"
+                      :outlined="inputStyle==='outlined'"
+                    ></v-text-field>
+                  </v-col>
+                </template>
+                <v-col cols="1" v-if="roleActions.length">
+                  <v-menu open-on-hover bottom offset-y>
+                    <template v-slot:activator="{ on }">
+                      <v-btn v-on="on" icon>
+                        <v-icon>mdi-dots-vertical</v-icon>
+                      </v-btn>
+                    </template>
+                    <v-list>
+                      <v-list-item v-for="(action, i) in roleActions" :key="i" @click="$emit(action.event, role)">
+                        <v-list-item-title>{{ action.title }}</v-list-item-title>
+                      </v-list-item>
+                    </v-list>
+                  </v-menu>
+                </v-col>
+              </v-row>
+              <v-row>
+                <v-col cols="12" md="6">
+                  <v-text-field
+                    :value="pageStart"
+                    :label="$t(pageStartLabel)"
+                    v-on:blur="$emit('input-page-start',$event.target.value)"
+                    :filled="inputStyle==='filled'"
+                    :outlined="inputStyle==='outlined'"
+                  ></v-text-field>
+                </v-col>
+                <v-col cols="12" md="6">
+                  <v-text-field
+                    :value="pageEnd"
+                    :label="$t(pageEndLabel)"
+                    v-on:blur="$emit('input-page-end',$event.target.value)"
+                    :filled="inputStyle==='filled'"
+                    :outlined="inputStyle==='outlined'"
+                  ></v-text-field>
+                </v-col>
+              </v-row>
+            </v-col>
+          </v-row>
+          <v-row no-gutters>
+            <v-col cols="12">
+              <v-card>
+                <v-card-title class="title font-weight-light grey white--text">
+                  <span>{{ $t(seriesLabel) }}</span>
+                  <v-spacer></v-spacer>
+                  <span>
+                    <v-icon dark v-show="collapseSeriesModel" @click="collapseSeriesModel=!collapseSeriesModel">mdi-arrow-right-drop-circle</v-icon>
+                    <v-icon dark v-show="!collapseSeriesModel" @click="collapseSeriesModel=!collapseSeriesModel">mdi-arrow-down-drop-circle</v-icon>
+                  </span>
+                </v-card-title>
+                <v-card-text class="mt-4" v-show="!collapseSeriesModel">
+                  <v-container>
+                    <v-row >
+                      <v-col cols="12" :md="multilingual ? 10 : 12">
+                        <v-text-field
+                          :value="seriesTitle"
+                          :label="$t('Title')"
+                          v-on:blur="$emit('input-series-title',$event.target.value)"
+                          :filled="inputStyle==='filled'"
+                          :outlined="inputStyle==='outlined'"
+                        ></v-text-field>
+                      </v-col>
+                      <v-col cols="12" md="2" v-if="multilingual">
+                        <v-autocomplete
+                          :value="getTerm('lang', seriesTitleLanguage)"
+                          v-on:input="$emit('input-series-title-language', $event )"
+                          :items="vocabularies['lang'].terms"
+                          :item-value="'@id'"
+                          :filter="autocompleteFilter"
+                          hide-no-data
+                          :label="$t('Language')"
+                          :filled="inputStyle==='filled'"
+                          :outlined="inputStyle==='outlined'"
+                          return-object
+                          clearable
+                        >
+                          <template slot="item" slot-scope="{ item }">
+                            <v-list-item-content two-line>
+                              <v-list-item-title  v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-item-title>
+                              <v-list-item-subtitle v-if="showIds" v-html="`${item['@id']}`"></v-list-item-subtitle>
+                            </v-list-item-content>
+                          </template>
+                          <template slot="selection" slot-scope="{ item }">
+                            <v-list-item-content>
+                              <v-list-item-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-item-title>
+                            </v-list-item-content>
+                          </template>
+                        </v-autocomplete>
+                      </v-col>
+
+                    </v-row>
+
+                    <v-row >
+
+                      <v-col cols="4" v-if="!hideSeriesVolume">
+                        <v-text-field
+                          :value="seriesVolume"
+                          :label="$t('Volume')"
+                          v-on:blur="$emit('input-series-volume',$event.target.value)"
+                          :filled="inputStyle==='filled'"
+                          :outlined="inputStyle==='outlined'"
+                        ></v-text-field>
+                      </v-col>
+
+                      <v-col cols="4" v-if="!hideSeriesIssue">
+                        <v-text-field
+                          :value="seriesIssue"
+                          :label="$t('Issue')"
+                          v-on:blur="$emit('input-series-issue',$event.target.value)"
+                          :filled="inputStyle==='filled'"
+                          :outlined="inputStyle==='outlined'"
+                        ></v-text-field>
+                      </v-col>
+
+                      <v-col cols="4" v-if="!hideSeriesIssued">
+
+                        <v-text-field
+                          :value="seriesIssued"
+                          v-on:blur="$emit('input-series-issued',$event.target.value)"
+                          :label="$t(seriesIssuedDateLabel ? seriesIssuedDateLabel : 'Issued')"
+                          :hint="'Format YYYY-MM-DD'"
+                          :rules="[validationrules.date]"
+                          :filled="inputStyle==='filled'"
+                          :outlined="inputStyle==='outlined'"
+                        ></v-text-field>
+
+                      </v-col>
+
+                    </v-row>
+
+                    <v-row >
+
+                      <v-col cols="4" v-if="!hideSeriesIssn">
+                        <v-text-field
+                          :value="seriesIssn"
+                          :label="$t('ISSN')"
+                          v-on:blur="$emit('input-series-issn',$event.target.value)"
+                          :filled="inputStyle==='filled'"
+                          :outlined="inputStyle==='outlined'"
+                        ></v-text-field>
+                      </v-col>
+
+                      <v-col cols="4" v-if="!hideSeriesIdentifier">
+                        <v-text-field
+                          :value="seriesIdentifier"
+                          :label="$t('Identifier')"
+                          v-on:blur="$emit('input-series-identifier',$event.target.value)"
+                          :filled="inputStyle==='filled'"
+                          :outlined="inputStyle==='outlined'"
+                        ></v-text-field>
+                      </v-col>
+
+                    </v-row>
+                  </v-container>
+                </v-card-text>
+              </v-card>
+            </v-col>
+          </v-row>
+        </v-card-text>
+      </v-card>
+    </v-col>
+  </v-row>
+</template>
+
+<script>
+import { fieldproperties } from "../../../mixins/fieldproperties";
+import { vocabulary } from "../../../mixins/vocabulary";
+import { validationrules } from "../../../mixins/validationrules";
+
+export default {
+  name: "p-i-contained-in",
+  mixins: [fieldproperties, vocabulary, validationrules],
+  props: {
+    type: {
+      type: String
+    },
+    multilingual: {
+      type: Boolean
+    },
+    label: {
+      type: String
+    },
+    title: {
+      type: String
+    },
+    subtitle: {
+      type: String
+    },
+    titleLanguage: {
+      type: String
+    },
+    roles: {
+      type: Array
+    },
+    disablerole: {
+      type: Boolean,
+      default: false
+    },
+    showname: {
+      type: Boolean,
+      default: false
+    },
+    showIds: {
+      type: Boolean,
+      default: false
+    },
+    pageStartLabel: {
+      type: String
+    },
+    pageEndLabel: {
+      type: String
+    },
+    pageStart: {
+      type: String
+    },
+    pageEnd: {
+      type: String
+    },
+    seriesLabel: {
+      type: String
+    },
+    seriesTitle: {
+      type: String
+    },
+    seriesTitleLanguage: {
+      type: String
+    },
+    hideSeriesVolume: {
+      type: Boolean
+    },
+    seriesVolume: {
+      type: String
+    },
+    hideSeriesIssue: {
+      type: Boolean
+    },
+    seriesIssue: {
+      type: String
+    },
+    hideSeriesIssued: {
+      type: Boolean
+    },
+    seriesIssued: {
+      type: String
+    },
+    seriesIssuedDateLabel: {
+      type: String
+    },
+    hideSeriesIssn: {
+      type: Boolean
+    },
+    seriesIssn: {
+      type: String
+    },
+    hideSeriesIdentifier: {
+      type: Boolean,
+      default: true
+    },
+    seriesIdentifier: {
+      type: String
+    },
+    collapseSeries: {
+      type: Boolean,
+      default: false
+    }
+  },
+  computed: {
+    roleActions: function() {
+      var arr = [];
+      arr.push({ title: this.$t("Remove"), event: "remove-role" });
+      arr.push({ title: this.$t("Duplicate"), event: "add-role" });
+      arr.push({ title: this.$t("Move up"), event: "up-role" });
+      arr.push({ title: this.$t("Move down"), event: "down-role" });
+      return arr;
+    }
+  },
+  data() {
+    return {
+      collapseSeriesModel: this.collapseSeries
+    };
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+.vertical-center {
+  align-items: center;
+}
+</style>
diff --git a/src/components/input/phaidra_inputs/PIDateEdtf.vue b/src/components/input/phaidra_inputs/PIDateEdtf.vue
new file mode 100644
index 0000000000000000000000000000000000000000..00f189a859cfddfdea08665d4f9e625335354daf
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PIDateEdtf.vue
@@ -0,0 +1,94 @@
+<template>
+  <v-layout row>
+    <v-flex xs4 v-if="!hideType">
+      <v-autocomplete
+        v-on:input="$emit('input-date-type', $event)"
+        :label="$t('Type of date')"
+        :items="vocabularies['datepredicate'].terms"
+        :value="getTerm('datepredicate', type)"
+        :filter="autocompleteFilter"
+        box
+        return-object
+        clearable
+      >
+        <template slot="item" slot-scope="{ item }">
+          <v-list-tile-content two-line>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('datepredicate', item['@id'])}`"></v-list-tile-title>
+            <v-list-tile-sub-title v-html="`${item['@id']}`"></v-list-tile-sub-title>
+          </v-list-tile-content>
+        </template>
+        <template slot="selection" slot-scope="{ item }">
+          <v-list-tile-content>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('datepredicate', item['@id'])}`"></v-list-tile-title>
+          </v-list-tile-content>
+        </template>
+      </v-autocomplete>
+    </v-flex>
+    <v-flex xs4>
+      <v-text-field
+        :value="value"
+        v-on:blur="$emit('input-date',$event.target.value)"
+        :label="$t(dateLabel ? dateLabel : '')"
+        :required="required"
+        :hint="'Format YYYY-MM-DD'"
+        :rules="[validationrules.date]"
+        box
+      ></v-text-field>
+    </v-flex>
+    <v-flex xs1 v-if="actions.length">
+      <v-menu open-on-hover bottom offset-y>
+        <v-btn slot="activator" icon>
+          <v-icon>more_vert</v-icon>
+        </v-btn>
+        <v-list>
+          <v-list-tile v-for="(action, i) in actions" :key="i" @click="$emit(action.event, $event)">
+            <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+          </v-list-tile>
+        </v-list>
+      </v-menu>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import { vocabulary } from "../../../mixins/vocabulary";
+import { fieldproperties } from "../../../mixins/fieldproperties";
+import { validationrules } from "../../../mixins/validationrules";
+
+export default {
+  name: "p-i-date-edtf",
+  mixins: [vocabulary, fieldproperties, validationrules],
+  props: {
+    value: {
+      type: String
+    },
+    dateLabel: {
+      type: String
+    },
+    type: {
+      type: String
+    },
+    hideType: {
+      type: Boolean
+    },
+    required: {
+      type: Boolean
+    }
+  },
+  mounted: function() {
+    this.$nextTick(function() {
+      this.loading = !this.vocabularies["datepredicate"].loaded;
+      // emit input to set skos:prefLabel in parent
+      if (this.type) {
+        this.$emit("input-date-type", this.getTerm("datepredicate", this.type));
+      }
+    });
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+</style>
diff --git a/src/components/input/phaidra_inputs/PIDimension.vue b/src/components/input/phaidra_inputs/PIDimension.vue
new file mode 100644
index 0000000000000000000000000000000000000000..0f93fe357e79154ba7379b8d767515e54322b987
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PIDimension.vue
@@ -0,0 +1,73 @@
+<template>
+  <v-layout row>
+    <v-flex xs2>
+      <v-text-field
+        :value="value" 
+        v-on:blur="$emit('input-value',$event.target.value)"
+        :label="$t(label)"
+        box
+      ></v-text-field>
+    </v-flex>
+    <v-flex xs2>
+      <v-select 
+        v-on:blur="$emit('input-unit',$event.target.value)"
+        :label="$t('Unit')"
+        :items="vocabularies['uncefact'].terms" 
+        :value="getTerm('uncefact', unit)"
+        box
+      >
+        <template slot="item" slot-scope="{ item }">
+          <v-list-tile-content two-line>
+            <v-list-tile-title  v-html="`${getLocalizedTermLabel('uncefact', item['@id'])}`"></v-list-tile-title>
+            <v-list-tile-sub-title  v-html="`${item['@id']}`"></v-list-tile-sub-title>
+          </v-list-tile-content>
+        </template>
+        <template slot="selection" slot-scope="{ item }">
+          <v-list-tile-content>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('uncefact', item['@id'])}`"></v-list-tile-title>
+          </v-list-tile-content>
+        </template>
+      </v-select>
+    </v-flex>   
+    <v-flex xs1 v-if="actions.length">
+      <v-menu open-on-hover bottom offset-y>
+        <v-btn slot="activator" icon>
+          <v-icon>more_vert</v-icon>
+        </v-btn>
+        <v-list>
+          <v-list-tile v-for="(action, i) in actions" :key="i" @click="$emit(action.event, $event)">
+            <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+          </v-list-tile>
+        </v-list>
+      </v-menu>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import { vocabulary } from "../../../mixins/vocabulary";
+import { fieldproperties } from "../../../mixins/fieldproperties";
+
+export default {
+  name: "p-i-dimension",
+  mixins: [vocabulary, fieldproperties],
+  props: {
+    unit: {
+      type: String
+    },
+    value: {
+      type: String
+    },
+    label: {
+      type: String,
+      required: true
+    }
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+</style>
\ No newline at end of file
diff --git a/src/components/input/phaidra_inputs/PIDuration.vue b/src/components/input/phaidra_inputs/PIDuration.vue
new file mode 100644
index 0000000000000000000000000000000000000000..229c28bcbc26a96e3665ea7f62d61e9f6aefe533
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PIDuration.vue
@@ -0,0 +1,128 @@
+<template>
+  <v-layout row>
+    <v-flex xs3 v-if="!hideHours">
+      <v-text-field
+        v-model="hours"
+        :rules="[v => (!v || (parseInt(v, 10) >= 0)) || 'Must be a non negative integer']"
+        type="number"
+        :label="$t('Duration')"
+        :suffix="$t('hours')"
+        box
+      ></v-text-field>
+    </v-flex>
+    <v-flex xs3 v-if="!hideMinutes">
+      <v-text-field
+        v-model="minutes"
+        :rules="[v => (!v || (parseInt(v, 10) >= 0)) || 'Must be a non negative integer']"
+        type="number"
+        :label="$t('Duration')"
+        :suffix="$t('minutes')"
+        box
+      ></v-text-field>
+    </v-flex>
+    <v-flex xs3 v-if="!hideSeconds">
+      <v-text-field
+        v-model="seconds"
+        :rules="[v => (!v || (parseInt(v, 10) >= 0)) || 'Must be a non negative integer']"
+        type="number"
+        :label="$t('Duration')"
+        :suffix="$t('seconds')"
+        box
+      ></v-text-field>
+    </v-flex>
+    <v-flex xs1 v-if="actions.length">
+      <v-menu open-on-hover bottom offset-y>
+        <v-btn slot="activator" icon>
+          <v-icon>more_vert</v-icon>
+        </v-btn>
+        <v-list>
+          <v-list-tile v-for="(action, i) in actions" :key="i" @click="$emit(action.event, $event)">
+            <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+          </v-list-tile>
+        </v-list>
+      </v-menu>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import { fieldproperties } from "../../../mixins/fieldproperties";
+
+export default {
+  name: "p-i-duration",
+  mixins: [fieldproperties],
+  props: {
+    /*
+    hoursValue: {
+      type: Number
+    },
+    minutesValue: {
+      type: Number
+    },
+    secondsValue: {
+      type: Number
+    },
+    */
+    value: {
+      type: String
+    },
+    hideHours: {
+      type: Boolean
+    },
+    hideMinutes: {
+      type: Boolean
+    },
+    hideSeconds: {
+      type: Boolean
+    },
+    label: {
+      type: String,
+      required: true
+    }
+  },
+  watch: {
+    hours: function(val) {
+      this.$emit("input", this.duration);
+    },
+    minutes: function(val) {
+      this.$emit("input", this.duration);
+    },
+    seconds: function(val) {
+      this.$emit("input", this.duration);
+    }
+  },
+  computed: {
+    duration: {
+      get: function() {
+        return (
+          "PT" + this.hours + "H" + this.minutes + "M" + this.seconds + "S"
+        );
+      },
+      set: function(v) {
+        let m = this.value.match(/PT(\d+)H(\d+)M(\d+)S/);
+        if (m) {
+          this.hours = m[1];
+          this.minutes = m[2];
+          this.seconds = m[3];
+        }
+      }
+    }
+  },
+  data() {
+    return {
+      hours: 0,
+      minutes: 0,
+      seconds: 0
+    };
+  },
+  mounted: function() {
+    this.duration = this.value;
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+</style>
\ No newline at end of file
diff --git a/src/components/input/phaidra_inputs/PIEntity.vue b/src/components/input/phaidra_inputs/PIEntity.vue
new file mode 100644
index 0000000000000000000000000000000000000000..b6965fec91f8331eabcb9401775704ad7196d4a0
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PIEntity.vue
@@ -0,0 +1,161 @@
+<template>
+  <v-layout row>
+    <v-flex xs4 v-if="!hideRole">
+      <v-autocomplete
+        :disabled="disablerole"
+        v-on:input="$emit('input-role', $event)"
+        :label="$t('Role')"
+        :items="vocabularies['rolepredicate'].terms"
+        :value="getTerm('rolepredicate', role)"
+        :filter="autocompleteFilter"
+        box
+        return-object
+        clearable
+      >
+        <template slot="item" slot-scope="{ item }">
+          <v-list-tile-content two-line>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('rolepredicate', item['@id'])}`"></v-list-tile-title>
+            <v-list-tile-sub-title v-html="`${item['@id']}`"></v-list-tile-sub-title>
+          </v-list-tile-content>
+        </template>
+        <template slot="selection" slot-scope="{ item }">
+          <v-list-tile-content>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('rolepredicate', item['@id'])}`"></v-list-tile-title>
+          </v-list-tile-content>
+        </template>
+      </v-autocomplete>
+    </v-flex>
+    <template v-if="type === 'schema:Person'">
+      <template v-if="showname">
+        <v-flex xs4>
+          <v-text-field
+            :value="name"
+            :label="$t('Name')"
+            v-on:blur="$emit('input-name',$event.target.value)"
+            box
+          ></v-text-field>
+        </v-flex>
+      </template>
+      <template v-else>
+        <v-flex xs2>
+          <v-text-field
+            :value="firstname"
+            :label="$t('Firstname')"
+            v-on:blur="$emit('input-firstname',$event.target.value)"
+            box
+          ></v-text-field>
+        </v-flex>
+        <v-flex xs2>
+          <v-text-field
+            :value="lastname"
+            :label="$t('Lastname')"
+            v-on:blur="$emit('input-lastname',$event.target.value)"
+            box
+          ></v-text-field>
+        </v-flex>
+      </template>
+    </template>
+    <v-flex xs4 v-if="type === 'schema:Organisation'">
+      <v-text-field
+        :value="institution"
+        :label="$t( institutionLabel ? institutionLabel : 'Institution' )"
+        v-on:blur="$emit('input-institution',$event.target.value)"
+        box
+      ></v-text-field>
+    </v-flex>
+    <v-flex xs2 v-if="showidentifier">
+      <v-text-field
+        :value="identifier"
+        :label="$t('Identifier')"
+        v-on:blur="$emit('input-identifier',$event.target.value)"
+        box
+      ></v-text-field>
+    </v-flex>
+    <v-flex xs1 v-if="actions.length">
+      <v-menu open-on-hover bottom offset-y>
+        <v-btn slot="activator" icon>
+          <v-icon>more_vert</v-icon>
+        </v-btn>
+        <v-list>
+          <v-list-tile v-for="(action, i) in actions" :key="i" @click="$emit(action.event, $event)">
+            <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+          </v-list-tile>
+        </v-list>
+      </v-menu>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import { vocabulary } from "../../../mixins/vocabulary";
+import { fieldproperties } from "../../../mixins/fieldproperties";
+
+export default {
+  name: "p-i-entity",
+  mixins: [vocabulary, fieldproperties],
+  props: {
+    firstname: {
+      type: String
+    },
+    lastname: {
+      type: String
+    },
+    name: {
+      type: String
+    },
+    institution: {
+      type: String
+    },
+    institutionLabel: {
+      type: String
+    },
+    identifier: {
+      type: String
+    },
+    role: {
+      type: String
+    },
+    hideRole: {
+      type: Boolean
+    },
+    type: {
+      type: String
+    },
+    required: {
+      type: Boolean
+    },
+    disablerole: {
+      type: Boolean,
+      default: false
+    },
+    showidentifier: {
+      type: Boolean,
+      default: true
+    },
+    showname: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      vocabulary: "rolepredicate"
+    };
+  },
+  mounted: function() {
+    this.$nextTick(function() {
+      this.loading = !this.vocabularies[this.vocabulary].loaded;
+      // emit input to set skos:prefLabel in parent
+      if (this.role) {
+        this.$emit("input", this.getTerm("rolepredicate", this.role));
+      }
+    });
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+</style>
diff --git a/src/components/input/phaidra_inputs/PIEntityExtended.vue b/src/components/input/phaidra_inputs/PIEntityExtended.vue
new file mode 100644
index 0000000000000000000000000000000000000000..c00152297180be1b198bd35005eca7ace319fcce
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PIEntityExtended.vue
@@ -0,0 +1,514 @@
+<template>
+  <v-row>
+    <v-col cols="12">
+      <v-card width="100%">
+        <v-card-title class="title font-weight-light grey white--text">
+          <span>{{ $t(label) }}</span>
+          <v-spacer></v-spacer>
+          <v-btn icon dark @click="$emit('add', $event)">
+            <v-icon>mdi-content-duplicate</v-icon>
+          </v-btn>
+          <v-btn icon dark @click="$emit('add-clear', $event)">
+            <v-icon>mdi-plus</v-icon>
+          </v-btn>
+          <v-btn icon dark @click="$emit('remove', $event)">
+            <v-icon>mdi-minus</v-icon>
+          </v-btn>
+          <v-btn icon dark @click="$emit('up', $event)">
+            <v-icon>mdi-chevron-up</v-icon>
+          </v-btn>
+          <v-btn icon dark @click="$emit('down', $event)">
+            <v-icon>mdi-chevron-down</v-icon>
+          </v-btn>
+        </v-card-title>
+        <v-divider></v-divider>
+        <v-card-text class="mt-4">
+          <v-container>
+            <v-row>
+              <v-col cols="8" v-if="!hideRole">
+                <v-autocomplete
+                  :disabled="disablerole"
+                  v-on:input="$emit('input-role', $event)"
+                  :label="$t('Role')"
+                  :items="vocabularies[roleVocabulary].terms"
+                  :item-value="'@id'"
+                  :value="getTerm(roleVocabulary, role)"
+                  :filter="autocompleteFilter"
+                  :filled="inputStyle==='filled'"
+                  :outlined="inputStyle==='outlined'"
+                  return-object
+                  clearable
+                  :error-messages="roleErrorMessages"
+                >
+                  <template slot="item" slot-scope="{ item }">
+                    <v-list-item-content two-line>
+                      <v-list-item-title  v-html="`${getLocalizedTermLabel(roleVocabulary, item['@id'])}`"></v-list-item-title>
+                      <v-list-item-subtitle v-if="showIds" v-html="`${item['@id']}`"></v-list-item-subtitle>
+                    </v-list-item-content>
+                  </template>
+                  <template slot="selection" slot-scope="{ item }">
+                    <v-list-item-content>
+                      <v-list-item-title v-html="`${getLocalizedTermLabel(roleVocabulary, item['@id'])}`"></v-list-item-title>
+                    </v-list-item-content>
+                  </template>
+                </v-autocomplete>
+              </v-col>
+              <v-col v-if="enableTypeSelect" cols="2">
+                <v-radio-group v-model="typeModel" class="mt-0" @change="$emit('change-type', $event)">
+                  <v-radio color="primary" :label="$t('Personal')" :value="'schema:Person'"></v-radio>
+                  <v-radio color="primary" :label="$t('Corporate')" :value="'schema:Organization'"></v-radio>
+                </v-radio-group>
+              </v-col>
+            </v-row>
+            <template v-if="typeModel === 'schema:Person'">
+              <v-row>
+                <template v-if="showname">
+                  <v-col cols="12" :md="(showIdentifier && !showIdentifierType) ? 8 : 12">
+                    <v-text-field
+                      :value="name"
+                      :label="$t('Name')"
+                      v-on:blur="$emit('input-name',$event.target.value)"
+                      :filled="inputStyle==='filled'"
+                      :outlined="inputStyle==='outlined'"
+                      :error-messages="nameErrorMessages"
+                    ></v-text-field>
+                  </v-col>
+                </template>
+                <template v-else>
+                  <v-col cols="12" :md="(showIdentifier && !showIdentifierType) ? 4 : 6">
+                    <v-text-field
+                      :value="firstname"
+                      :label="$t('Firstname')"
+                      v-on:blur="$emit('input-firstname',$event.target.value)"
+                      :filled="inputStyle==='filled'"
+                      :outlined="inputStyle==='outlined'"
+                      :error-messages="firstnameErrorMessages"
+                    ></v-text-field>
+                  </v-col>
+                  <v-col cols="12" :md="(showIdentifier && !showIdentifierType) ? 4 : 6">
+                    <v-text-field
+                      :value="lastname"
+                      :label="$t('Lastname')"
+                      v-on:blur="$emit('input-lastname',$event.target.value)"
+                      :filled="inputStyle==='filled'"
+                      :outlined="inputStyle==='outlined'"
+                      :error-messages="lastnameErrorMessages"
+                    ></v-text-field>
+                  </v-col>
+                </template>
+                <template v-if="showIdentifier && !showIdentifierType">
+                  <v-col cols="12" md="4">
+                    <v-text-field
+                      v-show="identifierType === 'ids:orcid'"
+                      v-mask="'####-####-####-####'"
+                      :value="identifierText"
+                      :label="identifierLabel ? identifierLabel : $t('Identifier')"
+                      v-on:blur="$emit('input-identifier', $event.target.value)"
+                      :placeholder="identifierTypePlaceholder"
+                      :rules="identifierType ? [validationrules['orcid']] : [validationrules['noop']]"
+                      :filled="inputStyle==='filled'"
+                      :outlined="inputStyle==='outlined'"
+                    ></v-text-field>
+                    <v-text-field
+                      v-show="identifierType !== 'ids:orcid'"
+                      :value="identifierText"
+                      :label="identifierLabel ? identifierLabel : $t('Identifier')"
+                      v-on:blur="$emit('input-identifier', $event.target.value)"
+                      :placeholder="identifierTypePlaceholder"
+                      :rules="identifierType ? [validationrules[getIdentifierRuleName(identifierType)]] : [validationrules['noop']]"
+                      :filled="inputStyle==='filled'"
+                      :outlined="inputStyle==='outlined'"
+                    ></v-text-field>
+                  </v-col>
+                </template>
+              </v-row>
+              <v-row v-if="showIdentifier && showIdentifierType">
+                <v-col cols="12" md="6">
+                  <v-autocomplete
+                    v-on:input="$emit('input-identifier-type', $event)"
+                    :label="$t('Type of identifier')"
+                    :items="vocabularies[identifierVocabulary].terms"
+                    :item-value="'@id'"
+                    :value="getTerm(identifierVocabulary, identifierType)"
+                    :filter="autocompleteFilter"
+                    :disabled="disableIdentifierType"
+                    :filled="inputStyle==='filled'"
+                    :outlined="inputStyle==='outlined'"
+                    return-object
+                    clearable
+                  >
+                    <template slot="item" slot-scope="{ item }">
+                      <v-list-item-content two-line>
+                        <v-list-item-title  v-html="`${getLocalizedTermLabel(identifierVocabulary, item['@id'])}`"></v-list-item-title>
+                      </v-list-item-content>
+                    </template>
+                    <template slot="selection" slot-scope="{ item }">
+                      <v-list-item-content>
+                        <v-list-item-title v-html="`${getLocalizedTermLabel(identifierVocabulary, item['@id'])}`"></v-list-item-title>
+                      </v-list-item-content>
+                    </template>
+                  </v-autocomplete>
+                </v-col>
+                <v-col cols="12" md="6" >
+                  <v-text-field
+                    v-show="identifierType === 'ids:orcid'"
+                    v-mask="'####-####-####-####'"
+                    :value="identifierText"
+                    :label="identifierLabel ? identifierLabel : $t('Identifier')"
+                    v-on:blur="$emit('input-identifier', $event.target.value)"
+                    :placeholder="identifierTypePlaceholder"
+                    :rules="identifierType ? [validationrules['orcid']] : [validationrules['noop']]"
+                    :filled="inputStyle==='filled'"
+                    :outlined="inputStyle==='outlined'"
+                  ></v-text-field>
+                  <v-text-field
+                    v-show="identifierType !== 'ids:orcid'"
+                    :value="identifierText"
+                    :label="identifierLabel ? identifierLabel : $t('Identifier')"
+                    v-on:blur="$emit('input-identifier', $event.target.value)"
+                    :placeholder="identifierTypePlaceholder"
+                    :rules="identifierType ? [validationrules[getIdentifierRuleName(identifierType)]] : [validationrules['noop']]"
+                    :filled="inputStyle==='filled'"
+                    :outlined="inputStyle==='outlined'"
+                  ></v-text-field>
+                </v-col>
+              </v-row>
+            </template>
+            <template v-if="typeModel === 'schema:Organization'">
+              <v-row>
+                <v-col cols="2">
+                  <v-radio-group v-model="organizationRadio" class="mt-0" @change="$emit('change-organization-type', $event)">
+                    <v-radio color="primary" :label="$t(instanceconfig.institution)" :value="'select'"></v-radio>
+                    <v-radio color="primary" :label="$t('OTHER_FEMININE')" :value="'other'"></v-radio>
+                  </v-radio-group>
+                </v-col>
+                <v-col cols="12" md="10" v-if="organizationRadio === 'select'">
+                  <v-autocomplete
+                    :value="getTerm('orgunits', organization)"
+                    :required="required"
+                    v-on:input="handleInput($event, 'organizationPath', 'input-organization-select')"
+                    :rules="required ? [ v => !!v || 'Required'] : []"
+                    :items="vocabularies['orgunits'].terms"
+                    :item-value="'@id'"
+                    :loading="loading"
+                    :filter="autocompleteFilter"
+                    hide-no-data
+                    :label="$t(organizationSelectLabel)"
+                    :filled="inputStyle==='filled'"
+                    :outlined="inputStyle==='outlined'"
+                    return-object
+                    clearable
+                    :disabled="disabled"
+                    :messages="organizationPath"
+                    :error-messages="organizationErrorMessages"
+                  >
+                    <template slot="item" slot-scope="{ item }">
+                      <v-list-item-content two-line>
+                        <v-list-item-title  v-html="`${getLocalizedTermLabel('orgunits', item['@id'])}`"></v-list-item-title>
+                        <v-list-item-subtitle v-if="showIds" v-html="`${item['@id']}`"></v-list-item-subtitle>
+                      </v-list-item-content>
+                    </template>
+                    <template slot="selection" slot-scope="{ item }">
+                      <v-list-item-content>
+                        <v-list-item-title v-html="`${getLocalizedTermLabel('orgunits', item['@id'])}`"></v-list-item-title>
+                      </v-list-item-content>
+                    </template>
+                    <template v-slot:append-outer>
+                      <v-icon @click="$refs.organizationstreedialog.open()">mdi-file-tree</v-icon>
+                    </template>
+                  </v-autocomplete>
+                </v-col>
+                <v-col cols="12" md="10" v-else>
+                  <v-text-field
+                    :value="organizationText"
+                    :label="$t('Organization')"
+                    v-on:blur="$emit('input-organization-other', $event.target.value)"
+                    :filled="inputStyle==='filled'"
+                    :outlined="inputStyle==='outlined'"
+                    :error-messages="organizationTextErrorMessages"
+                  ></v-text-field>
+                </v-col>
+              </v-row>
+            </template>
+            <v-row v-if="typeModel === 'schema:Person'">
+              <v-col cols="2">
+                <v-radio-group v-model="affiliationRadio" class="mt-0" @change="$emit('change-affiliation-type', $event)">
+                  <v-radio color="primary" :label="$t(instanceconfig.institution)" :value="'select'"></v-radio>
+                  <v-radio color="primary" :label="$t('OTHER_FEMININE')" :value="'other'"></v-radio>
+                </v-radio-group>
+              </v-col>
+              <v-col cols="12" md="10" v-if="affiliationRadio === 'select'">
+                <v-autocomplete
+                  :value="getTerm('orgunits', affiliation)"
+                  :required="required"
+                  v-on:input="handleInput($event, 'affiliationPath', 'input-affiliation-select')"
+                  :rules="required ? [ v => !!v || 'Required'] : []"
+                  :items="vocabularies['orgunits'].terms"
+                  :item-value="'@id'"
+                  :loading="loading"
+                  :filter="autocompleteFilter"
+                  hide-no-data
+                  :label="$t(affiliationSelectLabel)"
+                  :filled="inputStyle==='filled'"
+                  :outlined="inputStyle==='outlined'"
+                  return-object
+                  clearable
+                  :disabled="disabled"
+                  :messages="affiliationPath"
+                  :error-messages="affiliationErrorMessages"
+                >
+                  <template slot="item" slot-scope="{ item }">
+                    <v-list-item-content two-line>
+                      <v-list-item-title  v-html="`${getLocalizedTermLabel('orgunits', item['@id'])}`"></v-list-item-title>
+                      <v-list-item-subtitle v-if="showIds" v-html="`${item['@id']}`"></v-list-item-subtitle>
+                    </v-list-item-content>
+                  </template>
+                  <template slot="selection" slot-scope="{ item }">
+                    <v-list-item-content>
+                      <v-list-item-title v-html="`${getLocalizedTermLabel('orgunits', item['@id'])}`"></v-list-item-title>
+                    </v-list-item-content>
+                  </template>
+                  <template v-slot:append-outer>
+                    <v-icon @click="$refs.affiliationstreedialog.open()">mdi-file-tree</v-icon>
+                  </template>
+                </v-autocomplete>
+              </v-col>
+              <v-col cols="12" md="10" v-else>
+                <v-text-field
+                  :value="affiliationText"
+                  :label="$t('Affiliation')"
+                  v-on:blur="$emit('input-affiliation-other',$event.target.value)"
+                  :filled="inputStyle==='filled'"
+                  :outlined="inputStyle==='outlined'"
+                  :error-messages="affiliationTextErrorMessages"
+                ></v-text-field>
+              </v-col>
+            </v-row>
+          </v-container>
+        </v-card-text>
+      </v-card>
+    </v-col>
+    <org-units-tree-dialog ref="organizationstreedialog" @unit-selected="handleInput(getTerm('orgunits', $event), 'organizationPath', 'input-organization-select')"></org-units-tree-dialog>
+    <org-units-tree-dialog ref="affiliationstreedialog" @unit-selected="handleInput(getTerm('orgunits', $event), 'affiliationPath', 'input-affiliation-select')"></org-units-tree-dialog>
+  </v-row>
+</template>
+
+<script>
+import { mask } from "vue-the-mask";
+import { vocabulary } from "../../../mixins/vocabulary";
+import { fieldproperties } from "../../../mixins/fieldproperties";
+import { validationrules } from "../../../mixins/validationrules";
+import OrgUnitsTreeDialog from "../../select/OrgUnitsTreeDialog";
+
+export default {
+  name: "p-i-entity-extended",
+  mixins: [vocabulary, fieldproperties, validationrules],
+  components: {
+    OrgUnitsTreeDialog
+  },
+  directives: {
+    mask
+  },
+  props: {
+    label: {
+      type: String
+    },
+    firstname: {
+      type: String
+    },
+    lastname: {
+      type: String
+    },
+    name: {
+      type: String
+    },
+    affiliation: {
+      type: String
+    },
+    affiliationText: {
+      type: String
+    },
+    affiliationType: {
+      type: String
+    },
+    organization: {
+      type: String
+    },
+    organizationText: {
+      type: String
+    },
+    organizationType: {
+      type: String
+    },
+    identifierText: {
+      type: String
+    },
+    identifierType: {
+      type: String
+    },
+    identifierLabel: {
+      type: String
+    },
+    showIdentifier: {
+      type: Boolean
+    },
+    showIdentifierType: {
+      type: Boolean
+    },
+    disableIdentifierType: {
+      type: Boolean
+    },
+    role: {
+      type: String
+    },
+    hideRole: {
+      type: Boolean
+    },
+    type: {
+      type: String
+    },
+    required: {
+      type: Boolean
+    },
+    disablerole: {
+      type: Boolean,
+      default: false
+    },
+    nameErrorMessages: {
+      type: Array
+    },
+    firstnameErrorMessages: {
+      type: Array
+    },
+    lastnameErrorMessages: {
+      type: Array
+    },
+    roleErrorMessages: {
+      type: Array
+    },
+    affiliationErrorMessages: {
+      type: Array
+    },
+    affiliationTextErrorMessages: {
+      type: Array
+    },
+    organizationErrorMessages: {
+      type: Array
+    },
+    organizationTextErrorMessages: {
+      type: Array
+    },
+    showname: {
+      type: Boolean,
+      default: false
+    },
+    roleVocabulary: {
+      type: String,
+      default: "rolepredicate"
+    },
+    identifierVocabulary: {
+      type: String,
+      default: "entityidentifiertype"
+    },
+    showIds: {
+      type: Boolean,
+      default: false
+    },
+    enableTypeSelect: {
+      type: Boolean,
+      default: true
+    },
+    organizationSelectLabel: {
+      type: String,
+      default: "Please choose"
+    },
+    affiliationSelectLabel: {
+      type: String,
+      default: "Please choose"
+    }
+  },
+  computed: {
+    instanceconfig: function() {
+      return this.$root.$store.state.instanceconfig;
+    },
+    appconfig: function() {
+      return this.$root.$store.state.appconfig;
+    },
+    identifierTypePlaceholder: function() {
+      for (let i of this.vocabularies[this.identifierVocabulary].terms) {
+        if (i["@id"] === this.identifierType) {
+          return i["skos:example"];
+        }
+      }
+      return "";
+    }
+  },
+  data() {
+    return {
+      loading: false,
+      disabled: false,
+      typeModel: this.type,
+      affiliationRadio: this.affiliationType,
+      organizationRadio: this.organizationType,
+      affiliationPath: "",
+      organizationPath: ""
+    };
+  },
+  methods: {
+    getParentPath: function(unit, parentpath) {
+      if (unit) {
+        if (unit["parent"]) {
+          parentpath.push(unit.parent);
+          this.getParentPath(unit.parent, parentpath);
+        }
+      }
+    },
+    handleInput: function(unit, propName, eventName) {
+      this[propName] = "";
+      let parentpath = [];
+      if (unit) {
+        this.getParentPath(unit, parentpath);
+        for (let u of parentpath.reverse()) {
+          this[propName] =
+            this[propName] + u["skos:prefLabel"][this.$i18n.locale] + " > ";
+        }
+        this[propName] =
+          this[propName] + unit["skos:prefLabel"][this.$i18n.locale];
+      }
+      this.$emit(eventName, unit);
+    }
+  },
+  mounted: function() {
+    this.$nextTick(function() {
+      if (!this.vocabularies["orgunits"].loaded) {
+        this.$store.dispatch("loadOrgUnits", this.$i18n.locale);
+      }
+      this.loading = !this.vocabularies[this.roleVocabulary].loaded;
+      // emit input to set skos:prefLabel in parent
+      if (this.role) {
+        this.$emit("input", this.getTerm(this.roleVocabulary, this.role));
+      }
+      if (this.organization) {
+        this.handleInput(
+          this.getTerm("orgunits", this.organization),
+          "organizationPath",
+          "input-organization-select"
+        );
+      }
+      if (this.affiliation) {
+        this.handleInput(
+          this.getTerm("orgunits", this.affiliation),
+          "affiliationPath",
+          "input-affiliation-select"
+        );
+      }
+    });
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+</style>
diff --git a/src/components/input/phaidra_inputs/PIFile.vue b/src/components/input/phaidra_inputs/PIFile.vue
new file mode 100644
index 0000000000000000000000000000000000000000..6cd417e248455bf739663ba0a9f9facd7b3c3c69
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PIFile.vue
@@ -0,0 +1,50 @@
+<template>
+  <v-layout row>
+    <v-flex xs10>
+      <v-card class="mb-4">
+        <v-card-title class="headline grey white--text">
+          <span>{{ $t(label) }}</span>
+          <v-spacer></v-spacer>
+          <v-menu v-if="actions.length" open-on-hover bottom offset-y>
+            <v-btn slot="activator" icon dark>
+              <v-icon dark>more_vert</v-icon>
+            </v-btn>
+            <v-list>
+              <v-list-tile
+                v-for="(action, i) in actions"
+                :key="i"
+                @click="$emit(action.event, $event)"
+              >
+                <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+              </v-list-tile>
+            </v-list>
+          </v-menu>
+        </v-card-title>
+        <v-card-text class="mt-4">
+          <input type="file" v-on:input="$emit('input-file', $event)" />
+        </v-card-text>
+      </v-card>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import { fieldproperties } from "../../../mixins/fieldproperties";
+
+export default {
+  name: "p-i-file",
+  mixins: [fieldproperties],
+  props: {
+    label: {
+      type: String,
+      required: true
+    }
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+</style>
\ No newline at end of file
diff --git a/src/components/input/phaidra_inputs/PIFilename.vue b/src/components/input/phaidra_inputs/PIFilename.vue
new file mode 100644
index 0000000000000000000000000000000000000000..421aba3c143c86a6bf6f1b8e6e8e534d88ae9c5f
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PIFilename.vue
@@ -0,0 +1,30 @@
+<template>
+  <v-row >
+    <v-col cols="8">
+      <v-text-field
+        :value="value"
+        :label="$t('Filename')"
+        v-on:blur="$emit('input-value',$event.target.value)"
+        :filled="inputStyle==='filled'"
+        :outlined="inputStyle==='outlined'"
+      ></v-text-field>
+    </v-col>
+  </v-row>
+</template>
+<script>
+import { fieldproperties } from "../../../mixins/fieldproperties";
+
+export default {
+  name: "p-i-filename",
+  mixins: [fieldproperties],
+  props: {
+    value: {
+      type: String
+    },
+    label: {
+      type: String,
+      required: true
+    }
+  }
+};
+</script>
diff --git a/src/components/input/phaidra_inputs/PIFilenameReadonly.vue b/src/components/input/phaidra_inputs/PIFilenameReadonly.vue
new file mode 100644
index 0000000000000000000000000000000000000000..abc93518c015cd0b28239cf621c0fdca9293fc8b
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PIFilenameReadonly.vue
@@ -0,0 +1,27 @@
+<template>
+  <v-layout row>
+    <v-flex xs8>
+      <v-text-field
+        :value="value"
+        :label="$t('Filename')"
+        readonly
+        box
+      ></v-text-field>
+    </v-flex>
+  </v-layout>
+</template>
+<script>
+
+export default {
+  name: 'p-i-filename-readonly',
+  props: {
+    value: {
+      type: String
+    },
+    label: {
+      type: String,
+      required: true
+    }
+  }
+}
+</script>
\ No newline at end of file
diff --git a/src/components/input/phaidra_inputs/PIForm.vue b/src/components/input/phaidra_inputs/PIForm.vue
new file mode 100644
index 0000000000000000000000000000000000000000..0c598bef214b38bc1a3f31b0cef328a34ff64896
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PIForm.vue
@@ -0,0 +1,1128 @@
+<template>
+  <v-container fluid v-if="form && form.sections">
+    <v-tabs v-model="activetab" align-with-title>
+      <v-tab class="title font-weight-light text-capitalize">{{ $t('Metadata') }}<template v-if="targetpid">&nbsp;-&nbsp;<span class="text-lowercase">{{ targetpid }}</span></template></v-tab>
+      <v-tab @click="metadatapreview = getMetadata()" class="title font-weight-light text-capitalize">{{ $t('JSON-LD') }}</v-tab>
+      <v-tab v-if="templating" @click="loadTemplates()" class="title font-weight-light text-capitalize">{{ $t('Templates') }}</v-tab>
+    </v-tabs>
+
+    <v-tabs-items v-model="activetab">
+      <v-tab-item class="pa-3" v-if="form">
+
+        <v-row v-for="(s) in this.form.sections" :key="s.id" class="ma-3">
+
+          <v-card v-if="s.type === 'resourcelink'" width="100%">
+            <v-card-title class="title font-weight-light grey white--text">
+              <span>{{s.title}}</span>
+              <v-spacer></v-spacer>
+            </v-card-title>
+            <v-card-text class="mt-4">
+              <v-text-field v-model="s.resourcelink"
+                :label="$t('Resource link')"
+                :required="true"
+                :placeholder="$t('e.g.: https://phaidra.org')"
+                :rules="[ v => !!v || 'Required']"
+                filled
+              ></v-text-field>
+            </v-card-text>
+          </v-card>
+
+          <v-card v-else-if="(s.type !== 'accessrights')" width="100%">
+            <v-card-title class="title font-weight-light grey white--text">
+              <span v-t="s.title"></span>
+              <v-spacer></v-spacer>
+              <v-checkbox dark color="white" v-if="s.type === 'member'" v-model="previewMember" :label="$t('Container thumbnail')" :value="s.id"></v-checkbox>
+              <v-spacer></v-spacer>
+              <v-menu open-on-hover bottom offset-y v-if="!s.disablemenu">
+                <template v-slot:activator="{ on }">
+                  <v-btn v-on="on" icon dark>
+                    <v-icon dark>mdi-dots-vertical</v-icon>
+                  </v-btn>
+                </template>
+                <v-list>
+                  <v-list-item v-if="s.multiplicable && (s.type === 'member') || (s.type === 'phaidra:Subject')" @click="addSection(s)">
+                    <v-list-item-title><span v-t="'Duplicate'"></span></v-list-item-title>
+                  </v-list-item>
+                  <v-list-item v-if="s.removable && (s.type != 'digitalobject')" @click="removeSection(s)">
+                    <v-list-item-title><span v-t="'Remove'"></span></v-list-item-title>
+                  </v-list-item>
+                  <v-list-item v-if="s.type === 'member'" @click="sortMemberUp(s)">
+                    <v-list-item-title><span v-t="'Move up'"></span></v-list-item-title>
+                  </v-list-item>
+                  <v-list-item v-if="s.type === 'member'" @click="sortMemberDown(s)">
+                    <v-list-item-title><span v-t="'Move down'"></span></v-list-item-title>
+                  </v-list-item>
+                  <v-list-item v-if="s.type === 'digitalobject'" @click="$emit('add-phaidrasubject-section', s)">
+                    <v-list-item-title><span v-t="'Add subject metadata section'"></span></v-list-item-title>
+                  </v-list-item>
+                </v-list>
+              </v-menu>
+            </v-card-title>
+            <v-card-text class="mt-4">
+
+              <template v-for="(f) in s.fields">
+             
+                <v-row no-gutters :key="f.id">
+
+                  <template v-if="f.component === 'p-text-field'">
+                    <p-i-text-field
+                      v-bind.sync="f"
+                      v-on:input="f.value=$event"
+                      v-on:input-language="setSelected(f, 'language', $event)"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-text-field>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-text-field-suggest'">
+                    <p-i-text-field-suggest
+                      v-bind.sync="f"
+                      v-on:input="f.value=$event"
+                      v-on:input-language="setSelected(f, 'language', $event)"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-text-field-suggest>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-keyword'">
+                    <p-i-keyword
+                      v-bind.sync="f"
+                      v-on:input="f.value=$event"
+                      v-on:input-language="setSelected(f, 'language', $event)"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-keyword>
+                  </template>
+
+                  <template v-if="f.component === 'p-title'">
+                    <p-i-title
+                      v-bind.sync="f"
+                      v-on:input-title="f.title=$event"
+                      v-on:input-subtitle="f.subtitle=$event"
+                      v-on:input-language="setSelected(f, 'language', $event)"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                      v-on:up="sortFieldUp(s.fields, f)"
+                      v-on:down="sortFieldDown(s.fields, f)"
+                    ></p-i-title>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-select'">
+                    <p-i-select
+                      v-bind.sync="f"
+                      v-on:input="selectInput(f, $event)"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-select>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-select-text'">
+                    <p-i-select-text
+                      v-bind.sync="f"
+                      v-on:input="f.value=$event"
+                      v-on:input-select="f.selectvalue=$event"
+                      v-on:input-text="f.textvalue=$event"
+                      v-on:input-language="setSelected(f, 'language', $event)"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-select-text>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-date-edtf'">
+                    <p-i-date-edtf
+                      v-bind.sync="f"
+                      v-on:input-date="f.value=$event"
+                      v-on:input-date-type="setSelected(f, 'type', $event)"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-date-edtf>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-duration'">
+                    <p-i-duration
+                      v-bind.sync="f"
+                      v-on:input="f.value=$event"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-duration>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-series'">
+                    <p-i-series
+                      v-bind.sync="f"
+                      v-on:input-select-journal="selectJournal(f, $event)"
+                      v-on:input-title="f.title=$event"
+                      v-on:input-title-language="setSelected(f, 'titleLanguage', $event)"
+                      v-on:input-volume="f.volume=$event"
+                      v-on:input-issue="f.issue=$event"
+                      v-on:input-issued="f.issued=$event"
+                      v-on:input-issn="f.issn=$event"
+                      v-on:input-identifier="f.identifier=$event"
+                      v-on:input-page-start="f.pageStart=$event"
+                      v-on:input-page-end="f.pageEnd=$event"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-series>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-citation'">
+                    <p-i-citation
+                      v-bind.sync="f"
+                      v-on:input-citation-type="setSelected(f, 'type', $event)"
+                      v-on:input-citation="f.citation=$event"
+                      v-on:input-citation-language="setSelected(f, 'citationLanguage', $event)"
+                      v-on:input-identifier="f.identifier=$event"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-citation>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-bf-publication'">
+                    <p-i-bf-publication
+                      v-bind.sync="f"
+                      v-on:input-suggest-publisher="publisherSuggestInput(f, $event)"
+                      v-on:input-publisher-name="f.publisherName=$event"
+                      v-on:change-type="f.publisherType = $event"
+                      v-on:input-publisher-select="publisherSelectInput(f, $event)"
+                      v-on:input-publishing-place="f.publishingPlace=$event"
+                      v-on:input-publishing-date="f.publishingDate=$event"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-bf-publication>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-adaptation'">
+                    <p-i-adaptation
+                      v-bind.sync="f"
+                      v-on:input-title="f.title=$event"
+                      v-on:input-subtitle="f.subtitle=$event"
+                      v-on:input-title-language="setSelected(f, 'titleLanguage', $event)"
+                      v-on:input-firstname="f.firstname=$event"
+                      v-on:input-lastname="f.lastname=$event"
+                      v-on:input-name="f.name=$event"
+                      v-on:input-role="roleInput(f, $event)"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-adaptation>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-contained-in'">
+                    <p-i-contained-in
+                      v-bind.sync="f"
+                      v-on:input-title="f.title=$event"
+                      v-on:input-subtitle="f.subtitle=$event"
+                      v-on:input-title-language="setSelected(f, 'titleLanguage', $event)"
+                      v-on:input-role="containedInRoleInput(f, $event)"
+                      v-on:input-series-title="f.seriesTitle=$event"
+                      v-on:input-series-title-language="setSelected(f, 'seriesTitleLanguage', $event)"
+                      v-on:input-series-volume="f.seriesVolume=$event"
+                      v-on:input-series-issue="f.seriesIssue=$event"
+                      v-on:input-series-issued="f.seriesIssued=$event"
+                      v-on:input-series-issn="f.seriesIssn=$event"
+                      v-on:input-series-identifier="f.seriesIdentifier=$event"
+                      v-on:add-role="addContainedInRole(f.roles, $event)"
+                      v-on:remove-role="removeContainedInRole(f.roles, $event)"
+                      v-on:up-role="sortContainedInRoleUp(f.roles, $event)"
+                      v-on:down-role="sortContainedInRoleDown(f.roles, $event)"
+                    ></p-i-contained-in>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-entity'">
+                    <p-i-entity
+                      v-bind.sync="f"
+                      v-on:input-firstname="f.firstname=$event"
+                      v-on:input-lastname="f.lastname=$event"
+                      v-on:input-name="f.name=$event"
+                      v-on:input-organization="f.organization=$event"
+                      v-on:input-role="roleInput(f, $event)"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                      v-on:up="sortFieldUp(s.fields, f)"
+                      v-on:down="sortFieldDown(s.fields, f)"
+                    ></p-i-entity>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-entity-extended'">
+                    <p-i-entity-extended
+                      v-bind.sync="f"
+                      v-on:change-type="f.type = $event"
+                      v-on:input-firstname="f.firstname = $event"
+                      v-on:input-lastname="f.lastname = $event"
+                      v-on:input-name="f.name = $event"
+                      v-on:input-identifier-type="setSelected(f, 'identifierType', $event)"
+                      v-on:input-identifier="f.identifierText = $event"
+                      v-on:change-affiliation-type="f.affiliationType = $event"
+                      v-on:input-affiliation-select="affiliationSelectInput(f, $event)"
+                      v-on:input-affiliation-other="f.affiliationText = $event"
+                      v-on:change-organization-type="f.organizationType = $event"
+                      v-on:input-organization-select="organizationSelectInput(f, $event)"
+                      v-on:input-organization-other="f.organizationText = $event"
+                      v-on:input-role="roleInput(f, $event)"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:add-clear="addEntityClear(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                      v-on:up="sortFieldUp(s.fields, f)"
+                      v-on:down="sortFieldDown(s.fields, f)"
+                    ></p-i-entity-extended>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-subject-gnd'">
+                    <p-i-subject-gnd
+                      v-bind.sync="f"
+                      v-on:input="f.value=$event"
+                      v-on:resolve="updateSubject(f, $event)"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-subject-gnd>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-spatial-getty'">
+                    <p-i-spatial-getty
+                      v-bind.sync="f"
+                      v-on:input="f.value=$event"
+                      v-on:input-place-type="setSelected(f, 'type', $event)"
+                      v-on:resolve="updatePlace(f, $event)"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-spatial-getty>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-spatial-text'">
+                    <p-i-spatial-text
+                      v-bind.sync="f"
+                      v-on:input="f.value=$event"
+                      v-on:input-place-type="setSelected(f, 'type', $event)"
+                      v-on:input-language="setSelected(f, 'language', $event)"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-spatial-text>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-dimension'">
+                    <p-i-dimension
+                      v-bind.sync="f"
+                      v-on:input-value="f.value=$event"
+                      v-on:input-unit="setSelected(f, 'unitCode', $event)"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-dimension>
+                  </template>
+
+                  <template v-else-if="(f.component === 'p-literal') && (f.predicate !== 'schema:pageStart') && (f.predicate !== 'schema:pageEnd')">
+                    <p-i-literal
+                      v-bind.sync="f"
+                      v-on:input-value="f.value=$event"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-literal>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-alternate-identifier'">
+                    <p-i-alternate-identifier
+                      v-bind.sync="f"
+                      v-on:input-identifier="f.value=$event"
+                      v-on:input-identifier-type="setSelected(f, 'identifierType', $event)"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                      class="my-2"
+                    ></p-i-alternate-identifier>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-study-plan'">
+                    <p-i-study-plan
+                      v-bind.sync="f"
+                      v-on:input-name="f.name=$event"
+                      v-on:input-name-language="setSelected(f, 'nameLanguage', $event)"
+                      v-on:input-notation="f.notation=$event"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-study-plan>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-project'">
+                    <p-i-project
+                      v-bind.sync="f"
+                      v-on:input-name="f.name=$event"
+                      v-on:input-name-language="setSelected(f, 'nameLanguage', $event)"
+                      v-on:input-funder-name="f.funderName=$event"
+                      v-on:input-funder-name-language="setSelected(f, 'funderNameLanguage', $event)"
+                      v-on:input-description="f.description=$event"
+                      v-on:input-description-language="setSelected(f, 'descriptionLanguage', $event)"
+                      v-on:input-identifier="f.identifier=$event"
+                      v-on:input-funder-identifier="f.funderIdentifier=$event"
+                      v-on:input-homepage="f.homepage=$event"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-project>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-funder'">
+                    <p-i-funder
+                      v-bind.sync="f"
+                      v-on:input-name="f.name=$event"
+                      v-on:input-name-language="setSelected(f, 'nameLanguage', $event)"
+                      v-on:input-identifier="f.identifier=$event"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-funder>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-association'">
+                    <p-i-association
+                      v-bind.sync="f"
+                      v-on:input="selectInput(f, $event)"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-association>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-filename'">
+                    <p-i-filename
+                      v-bind.sync="f"
+                      v-on:input-value="f.value=$event"
+                    ></p-i-filename>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-filename-readonly'">
+                    <p-i-filename-readonly v-bind.sync="f"></p-i-filename-readonly>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-unknown-readonly'">
+                    <p-i-unknown-readonly v-bind.sync="f"></p-i-unknown-readonly>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-vocab-ext-readonly'">
+                    <p-i-vocab-ext-readonly
+                      v-bind.sync="f"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-vocab-ext-readonly>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-spatial-getty-readonly'">
+                    <p-i-spatial-getty-readonly
+                      v-bind.sync="f"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-spatial-getty-readonly>
+                  </template>
+
+                  <template v-else-if="f.component === 'p-file'">
+                    <p-i-file
+                      v-bind.sync="f"
+                      v-on:input-file="setFilename(f, $event)"
+                      v-on:input-mimetype="setSelected(f, 'mimetype', $event)"
+                      v-on:add="addField(s.fields, f)"
+                      v-on:remove="removeField(s.fields, f)"
+                    ></p-i-file>
+                  </template>
+
+                </v-row>
+              </template>
+
+              <v-row>
+                <v-col>
+                  <v-dialog v-if="addbutton" class="pb-4" v-model="s['adddialogue']" scrollable width="700px">
+                    <template v-slot:activator="{ on }">
+                      <v-btn v-on="on" fab depressed small color="grey lighten-3">
+                        <v-icon color="grey darken-1">mdi-plus</v-icon>
+                      </v-btn>
+                    </template>
+                    <v-card>
+                      <v-card-title class="grey white--text"><span v-t="'Add metadata fields'"></span></v-card-title>
+                      <v-card-text>
+                        <v-list three-line >
+                          <v-text-field clearable label="Search..." append-icon="mdi-magnify" v-model="searchfieldsinput"></v-text-field>
+                          <template v-for="field in filteredMetadatafields">
+                            <v-list-item :key="field.id" @click="addfieldselection.push(field)">
+                              <v-list-item-content>
+                                <v-list-item-title>{{field.fieldname}}</v-list-item-title>
+                                <v-list-item-subtitle>{{field.definition}}</v-list-item-subtitle>
+                              </v-list-item-content>
+                            </v-list-item>
+                            <v-divider :key="'divi'+field.id"></v-divider>
+                          </template>
+                        </v-list>
+                      </v-card-text>
+                      <v-divider :key="'divi'+s.id"></v-divider>
+                      <v-card-actions>
+                        <v-container>
+                          <v-row>
+                            <v-col v-if="addfieldselection.length > 0">
+                              <span v-t="'Selected fields:'" class="mr-2"></span> <v-chip :key="index" v-for="(ch, index) in addfieldselection" close @click:close="removeField(addfieldselection, ch)">{{ ch.fieldname }}</v-chip>
+                            </v-col>
+                            <v-col v-else><span v-t="'Please select metadata fields from the list'"></span></v-col>
+                          </v-row>
+                          <v-row justify="end">
+                            <v-btn color="grey" dark @click="addfieldselection = []; s['adddialogue'] = false"><span v-t="'Cancel'"></span></v-btn>
+                            <v-btn color="primary" @click="addFields(s)"><span v-t="'Add'"></span></v-btn>
+                          </v-row>
+                        </v-container>
+                      </v-card-actions>
+                    </v-card>
+
+                  </v-dialog>
+                </v-col>
+              </v-row>
+            </v-card-text>
+
+          </v-card>
+        </v-row>
+
+        <v-row align="center" justify="end"  class="ma-3">
+          <v-dialog v-if="templating" v-model="templatedialog" width="500">
+            <template v-slot:activator="{ on }">
+              <v-btn class="mr-3" v-on="on" dark raised :loading="loading" :disabled="loading" color="grey"><span v-t="'Save as template'"></span></v-btn>
+            </template>
+            <v-card>
+              <v-card-title class="title font-weight-light grey lighten-2" primary-title><span v-t="'Save as template'"></span></v-card-title>
+              <v-card-text>
+                <v-text-field class="mt-4" hide-details filled single-line v-model="templatename" :label="$t('Template name')" ></v-text-field>
+              </v-card-text>
+              <v-card-actions>
+                <v-spacer></v-spacer>
+                <v-btn :loading="loading" :disabled="loading" color="grey" dark @click="templatedialog= false"><span v-t="'Cancel'"></span></v-btn>
+                <v-btn :loading="loading" :disabled="loading" color="primary" @click="saveAsTemplate()"><span v-t="'Save'"></span></v-btn>
+              </v-card-actions>
+            </v-card>
+          </v-dialog>
+          <v-btn fixed bottom right v-if="targetpid && floatingsavebutton" raised :loading="loading" :disabled="loading" color="primary" @click="save()"><span v-t="'Save'"></span></v-btn>
+          <v-btn v-else-if="targetpid && !floatingsavebutton" raised :loading="loading" :disabled="loading" color="primary" @click="save()"><span v-t="'Save'"></span></v-btn>
+          <v-btn v-else raised :loading="loading" :disabled="loading" color="primary" @click="submit()"><span v-t="'Submit'"></span></v-btn>
+        </v-row>
+
+      </v-tab-item>
+      <v-tab-item class="pa-3">
+        <code>{{ metadatapreview }}</code>
+      </v-tab-item>
+      <v-tab-item class="ma-4">
+        <p-templates ref="templates" v-on:load-template="loadTemplate($event)"></p-templates>
+      </v-tab-item>
+    </v-tabs-items>
+
+  </v-container>
+
+</template>
+
+<script>
+import arrays from "../../../utils/arrays";
+import jsonLd from "../../../utils/json-ld";
+import fields from "../../../utils/fields";
+import PITextField from "./PITextField";
+import PITextFieldSuggest from "./PITextFieldSuggest";
+import PITitle from "./PITitle";
+import PIEntity from "./PIEntity";
+import PIEntityExtended from "./PIEntityExtended";
+import PIDateEdtf from "./PIDateEdtf";
+import PISelect from "./PISelect";
+import PISelectText from "./PISelectText";
+import PISubjectGnd from "./PISubjectGnd";
+import PISpatialGetty from "./PISpatialGetty";
+import PISpatialText from "./PISpatialText";
+import PIDimension from "./PIDimension";
+import PIDuration from "./PIDuration";
+import PIProject from "./PIProject";
+import PIFunder from "./PIFunder";
+import PIAssociation from "./PIAssociation";
+import PISeries from "./PISeries";
+import PIContainedIn from "./PIContainedIn";
+import PICitation from "./PICitation";
+import PIBfPublication from "./PIBfPublication";
+import PIAdaptation from "./PIAdaptation";
+import PIFilenameReadonly from "./PIFilenameReadonly";
+import PIFilename from "./PIFilename";
+import PIFile from "./PIFile";
+import PISpatialGettyReadonly from "./PISpatialGettyReadonly";
+import PIVocabExtReadonly from "./PIVocabExtReadonly";
+import PIUnknownReadonly from "./PIUnknownReadonly";
+import PILiteral from "./PILiteral";
+import PIStudyPlan from "./PIStudyPlan";
+import PIKeyword from "./PIKeyword";
+import PTemplates from "../../templates/PTemplates";
+export default {
+  name: "p-i-form",
+  components: {
+    PITextField,
+    PITextFieldSuggest,
+    PITitle,
+    PIEntity,
+    PIEntityExtended,
+    PIDateEdtf,
+    PISelect,
+    PISelectText,
+    PISubjectGnd,
+    PISpatialGetty,
+    PISpatialText,
+    PIDimension,
+    PIDuration,
+    PIStudyPlan,
+    PIProject,
+    PIFunder,
+    PIAssociation,
+    PISeries,
+    PIContainedIn,
+    PICitation,
+    PIBfPublication,
+    PIAdaptation,
+    PILiteral,
+    PIKeyword,
+    PIFilenameReadonly,
+    PIFilename,
+    PIFile,
+    PIVocabExtReadonly,
+    PISpatialGettyReadonly,
+    PIUnknownReadonly,
+    PTemplates
+  },
+  props: {
+    form: {
+      type: Object
+    },
+    targetpid: {
+      type: String
+    },
+    owner: {
+      // if defined, phaidra will transfer ownership to this user
+      // IIF the current user is authorized to do so in phaidra-api
+      type: String
+    },
+    addbutton: {
+      type: Boolean,
+      default: true
+    },
+    templating: {
+      type: Boolean,
+      default: true
+    },
+    floatingsavebutton: {
+      type: Boolean,
+      default: false
+    }
+  },
+  computed: {
+    submittype: function() {
+      for (let s of this.form.sections) {
+        if (s.fields && s.type !== "member") {
+          for (let field of s.fields) {
+            if (field.predicate === "dcterms:type") {
+              return this.getObjectType(field.value);
+            }
+          }
+        }
+      }
+      return null;
+    },
+    filteredMetadatafields() {
+      let list = fields.getEditableFields();
+      if (this.searchfieldsinput) {
+        return list.filter(
+          f =>
+            f.fieldname
+              .toLowerCase()
+              .includes(this.searchfieldsinput.toLowerCase()) ||
+            f.definition
+              .toLowerCase()
+              .includes(this.searchfieldsinput.toLowerCase())
+        );
+      } else {
+        return list;
+      }
+    }
+  },
+  data() {
+    return {
+      activetab: null,
+      loadedMetadata: [],
+      loading: false,
+      fab: false,
+      addfieldselection: [],
+      templatedialog: "",
+      templatename: "",
+      previewMember: "",
+      searchfieldsinput: "",
+      metadatapreview: {}
+    };
+  },
+  methods: {
+    getMetadata: function() {
+      let jsonlds;
+      if (!this.targetpid && this.submittype === "container") {
+        jsonlds = jsonLd.containerForm2json(this.form);
+      } else {
+        jsonlds = jsonLd.form2json(this.form);
+      }
+      let md = { metadata: { "json-ld": jsonlds } };
+      let colorder = [];
+      let i = 0;
+      for (let s of this.form.sections) {
+        if (s.type === "member") {
+          i++;
+          colorder.push({ member: "member_" + s.id, pos: i });
+        }
+        if (s.type === "accessrights") {
+          md["metadata"]["rights"] = s.rights;
+        }
+        if (s.type === "resourcelink") {
+          md["metadata"]["resourcelink"] = s.resourcelink;
+        }
+      }
+      if (colorder.length > 0) {
+        md["metadata"]["membersorder"] = colorder;
+      }
+      if (this.previewMember) {
+        md["metadata"]["relationships"] = [
+          {
+            s: "member_" + this.previewMember,
+            p: "http://phaidra.org/XML/V1.0/relations#isThumbnailFor",
+            o: "container"
+          }
+        ];
+      }
+      if (this.owner) {
+        md["metadata"]["ownerid"] = this.owner;
+      }
+      return md;
+    },
+    loadTemplates: function() {
+      if (this.$refs.templates) {
+        this.$refs.templates.loadTemplates();
+      }
+    },
+    loadTemplate: function(form) {
+      this.$emit("load-form", form);
+      this.activetab = 0;
+    },
+    saveAsTemplate: async function() {
+      var httpFormData = new FormData();
+      this.loading = true;
+      httpFormData.append("name", this.templatename);
+      httpFormData.append("form", JSON.stringify(this.form));
+      try {
+        let response = await this.$http.request({
+          method: "POST",
+          url: this.$store.state.instanceconfig.api + "/jsonld/template/add",
+          headers: {
+            "Content-Type": "multipart/form-data",
+            "X-XSRF-TOKEN": this.$store.state.user.token
+          },
+          data: httpFormData
+        });
+        if (response.data.alerts && response.data.alerts.length > 0) {
+          this.$store.commit("setAlerts", response.data.alerts);
+        }
+      } catch (error) {
+        console.log(error);
+        this.$store.commit("setAlerts", [{ type: "danger", msg: error }]);
+      } finally {
+        this.loading = false;
+        this.templatedialog = false;
+      }
+    },
+    getObjectType: function(contentmodel) {
+      switch (contentmodel) {
+        case "https://pid.phaidra.org/vocabulary/44TN-P1S0":
+          return "picture";
+        case "https://pid.phaidra.org/vocabulary/8YB5-1M0J":
+          return "audio";
+        case "https://pid.phaidra.org/vocabulary/B0Y6-GYT8":
+          return "video";
+        case "https://pid.phaidra.org/vocabulary/69ZZ-2KGX":
+          return "document";
+        case "https://pid.phaidra.org/vocabulary/8MY0-BQDQ":
+          return "container";
+        case "https://pid.phaidra.org/vocabulary/T8GH-F4V8":
+          return "resource";
+        case "https://pid.phaidra.org/vocabulary/GXS7-ENXJ":
+          return "collection";
+        default:
+          return "unknown";
+      }
+    },
+    submit: async function() {
+      this.loading = true;
+      var httpFormData = new FormData();
+      switch (this.submittype) {
+        case "container":
+          for (var i = 0; i < this.form.sections.length; i++) {
+            var s = this.form.sections[i];
+            if (s.type === "member") {
+              for (var j = 0; j < s.fields.length; j++) {
+                if (s.fields[j].component === "p-file") {
+                  if (s.fields[j].file !== "") {
+                    httpFormData.append("member_" + s.id, s.fields[j].file);
+                  }
+                }
+              }
+            }
+          }
+          break;
+        default:
+          for (i = 0; i < this.form.sections.length; i++) {
+            s = this.form.sections[i];
+            if (s.fields) {
+              for (j = 0; j < s.fields.length; j++) {
+                if (s.fields[j].component === "p-file") {
+                  if (s.fields[j].file !== "") {
+                    httpFormData.append("file", s.fields[j].file);
+                  }
+                }
+              }
+            }
+          }
+          break;
+      }
+      httpFormData.append("metadata", JSON.stringify(this.getMetadata()));
+      try {
+        let response = await this.$http.request({
+          method: "POST",
+          url:
+            this.$store.state.instanceconfig.api +
+            "/" +
+            this.submittype +
+            "/create",
+          headers: {
+            "Content-Type": "multipart/form-data",
+            "X-XSRF-TOKEN": this.$store.state.user.token
+          },
+          data: httpFormData
+        });
+        if (response.data.alerts && response.data.alerts.length > 0) {
+          this.$store.commit("setAlerts", response.data.alerts);
+        }
+        if (response.data.status === 200) {
+          if (response.data.pid) {
+            this.$emit("object-created", response.data.pid);
+          }
+        }
+      } catch (error) {
+        console.log(error);
+        this.$store.commit("setAlerts", [{ type: "danger", msg: error }]);
+      } finally {
+        this.$vuetify.goTo(0);
+        this.loading = false;
+      }
+    },
+    save: async function() {
+      this.loading = true;
+      var httpFormData = new FormData();
+      httpFormData.append("metadata", JSON.stringify(this.getMetadata()));
+      try {
+        let response = await this.$http.request({
+          method: "POST",
+          url:
+            this.$store.state.instanceconfig.api +
+            "/object/" +
+            this.targetpid +
+            "/metadata",
+          headers: {
+            "Content-Type": "multipart/form-data",
+            "X-XSRF-TOKEN": this.$store.state.user.token
+          },
+          data: httpFormData
+        });
+        if (response.data.alerts && response.data.alerts.length > 0) {
+          if (response.data.status === 401) {
+            response.data.alerts.push({ type: "danger", msg: "Please log in" });
+          }
+          this.$store.commit("setAlerts", response.data.alerts);
+        }
+        if (response.data.status === 200) {
+          if (response.data.pid) {
+            this.$emit("object-saved", this.targetpid);
+          }
+        }
+      } catch (error) {
+        console.log(error);
+        this.$store.commit("setAlerts", [{ type: "danger", msg: error }]);
+      } finally {
+        this.$vuetify.goTo(0);
+        this.loading = false;
+      }
+    },
+    addField: function(arr, f) {
+      var newField = arrays.duplicate(arr, f);
+      if (newField) {
+        newField.id = new Date().getTime();
+        newField.firstname = "";
+        newField.lastname = "";
+        newField.identifierText = "";
+        newField.removable = true;
+      }
+    },
+    addEntityClear: function(arr, f) {
+      var newField = arrays.duplicate(arr, f);
+      if (newField) {
+        newField.id = new Date().getTime();
+        newField.role = "";
+        newField.name = "";
+        newField.firstname = "";
+        newField.lastname = "";
+        newField.identifierText = "";
+        newField.affiliation = "";
+        newField.affiliationText = "";
+        newField.affiliationType = "select";
+        newField.organization = "";
+        newField.organizationText = "";
+        newField.organizationType = "select";
+        newField.type = "schema:Person";
+        newField.removable = true;
+      }
+    },
+    removeField: function(arr, f) {
+      arrays.remove(arr, f);
+    },
+    sortFieldUp: function(arr, f) {
+      var i = arr.indexOf(f);
+      if (arr[i - 1]) {
+        if (arr[i - 1].ordergroup === f.ordergroup) {
+          arrays.moveUp(arr, f);
+        }
+      }
+    },
+    sortFieldDown: function(arr, f) {
+      var i = arr.indexOf(f);
+      if (arr[i + 1]) {
+        if (arr[i + 1].ordergroup === f.ordergroup) {
+          arrays.moveDown(arr, f);
+        }
+      }
+    },
+    addContainedInRole: function(arr, f) {
+      var newField = arrays.duplicate(arr, f);
+      if (newField) {
+        newField.id = new Date().getTime();
+        newField.removable = true;
+      }
+    },
+    removeContainedInRole: function(arr, f) {
+      if (arr.length > 1) {
+        arrays.remove(arr, f);
+      }
+    },
+    sortContainedInRoleUp: function(arr, f) {
+      var i = arr.indexOf(f);
+      if (arr[i - 1]) {
+        if (arr[i - 1].ordergroup === f.ordergroup) {
+          arrays.moveUp(arr, f);
+        }
+      }
+    },
+    sortContainedInRoleDown: function(arr, f) {
+      var i = arr.indexOf(f);
+      if (arr[i + 1]) {
+        if (arr[i + 1].ordergroup === f.ordergroup) {
+          arrays.moveDown(arr, f);
+        }
+      }
+    },
+    sortMemberUp: function(s) {
+      var i = this.form.sections.indexOf(s);
+      if (this.form.sections[i - 1]) {
+        if (this.form.sections[i - 1].type === "member") {
+          arrays.moveUp(this.form.sections, s);
+        }
+      }
+    },
+    sortMemberDown: function(s) {
+      var i = this.form.sections.indexOf(s);
+      if (this.form.sections[i + 1]) {
+        if (this.form.sections[i + 1].type === "member") {
+          arrays.moveDown(this.form.sections, s);
+        }
+      }
+    },
+    addSection: function(s) {
+      var ns = arrays.duplicate(this.form.sections, s);
+      ns.id = new Date().getTime();
+      ns.removable = true;
+      for (var i = 0; i < ns.fields.length; i++) {
+        var id = new Date().getTime();
+        if (i > 0) {
+          id = ns.fields[i - 1].id + 1;
+        }
+        ns.fields[i].id = id;
+        ns.fields[i].value = "";
+        ns.fields[i].language = "";
+      }
+    },
+    removeSection: function(s) {
+      arrays.remove(this.form.sections, s);
+    },
+    selectJournal: function(f, event) {
+      if (event.title) {
+        f.title = event.title;
+      }
+      if (event.issn) {
+        f.issn = event.issn;
+      }
+    },
+    affiliationSelectInput: function(f, event) {
+      f.affiliation = "";
+      f.affiliationSelectedName = [];
+      if (event) {
+        f.affiliation = event["@id"];
+        var preflabels = event["skos:prefLabel"];
+        Object.entries(preflabels).forEach(([key, value]) => {
+          f.affiliationSelectedName.push({ "@value": value, "@language": key });
+        });
+      }
+    },
+    publisherSelectInput: function(f, event) {
+      f.publisherOrgUnit = "";
+      f.publisherSelectedName = [];
+      if (event) {
+        f.publisherOrgUnit = event["@id"];
+        var preflabels = event["skos:prefLabel"];
+        Object.entries(preflabels).forEach(([key, value]) => {
+          f.publisherSelectedName.push({ "@value": value, "@language": key });
+        });
+      }
+    },
+    publisherSuggestInput: function(f, event) {
+      if (event) {
+        f.publisherName = event["name"];
+      }
+    },
+    organizationSelectInput: function(f, event) {
+      f.organization = "";
+      f.organizationSelectedName = [];
+      if (event) {
+        f.organization = event["@id"];
+        var preflabels = event["skos:prefLabel"];
+        Object.entries(preflabels).forEach(([key, value]) => {
+          f.organizationSelectedName.push({
+            "@value": value,
+            "@language": key
+          });
+        });
+      }
+    },
+    setSelected: function(f, property, event) {
+      if (event) {
+        f[property] = event["@id"];
+      }
+      this.$emit("form-input-" + f.component, f);
+      // eg on
+      // v-on:input-identifier-type="setSelected(f, 'identifierType', $event)"
+      // the identifierType property of the component should be updated via
+      // v-bind.sync="f"
+      // because we changed f in this method
+      // but it seems to not work lately....
+      this.$forceUpdate();
+    },
+    updateSubject: function(f, event) {
+      f["skos:prefLabel"] = event["skos:prefLabel"];
+      if (f["skos:prefLabel"]) {
+        if (f["skos:prefLabel"].length > 0) {
+          // needed to init the search input if loading from template
+          // will be synced with component's initquery prop
+          f.initquery = f["skos:prefLabel"][0]["@value"];
+        }
+      }
+      f["rdfs:label"] = event["rdfs:label"];
+      this.$emit("form-input-" + f.component, f);
+    },
+    updatePlace: function(f, event) {
+      f["skos:prefLabel"] = event["skos:prefLabel"];
+      if (f["skos:prefLabel"]) {
+        if (f["skos:prefLabel"].length > 0) {
+          // needed to init the search input if loading from template
+          // will be synced with component's initquery prop
+          f.initquery = f["skos:prefLabel"][0]["@value"];
+        }
+      }
+      f["rdfs:label"] = event["rdfs:label"];
+      f.coordinates = event.coordinates;
+      this.$emit("form-input-" + f.component, f);
+    },
+    selectInput: function(f, event) {
+      if (event) {
+        f.value = event["@id"];
+        if (event["@type"]) {
+          f.type = event["@type"];
+        }
+        if (event["skos:prefLabel"]) {
+          let preflabels = event["skos:prefLabel"];
+          f["skos:prefLabel"] = [];
+          Object.entries(preflabels).forEach(([key, value]) => {
+            f["skos:prefLabel"].push({ "@value": value, "@language": key });
+          });
+        }
+        if (event["rdfs:label"]) {
+          let rdfslabels = event["rdfs:label"];
+          if (rdfslabels) {
+            f["rdfs:label"] = [];
+            Object.entries(rdfslabels).forEach(([key, value]) => {
+              f["rdfs:label"].push({ "@value": value, "@language": key });
+            });
+          }
+        }
+        if (event["skos:notation"]) {
+          f["skos:notation"] = event["skos:notation"];
+        }
+      } else {
+        f.value = "";
+        f["skos:prefLabel"] = [];
+        f["rdfs:label"] = [];
+        f["skos:notation"] = [];
+      }
+      this.$emit("form-input-" + f.component, f);
+    },
+    roleInput: function(f, event) {
+      f.role = event["@id"];
+      this.$emit("form-input-" + f.component, f);
+    },
+    containedInRoleInput: function(f, event) {
+      for (let r of f.roles) {
+        if (r.id === event.role.id) {
+          if (event.roleTerm) {
+            r.role = event.roleTerm["@id"];
+          }
+          if (event.name) {
+            r.name = event.name;
+          }
+          if (event.firstname) {
+            r.firstname = event.firstname;
+          }
+          if (event.lastname) {
+            r.lastname = event.lastname;
+          }
+        }
+      }
+    },
+    setFilename: function(f, event) {
+      f.value = event.name;
+      f.file = event;
+      this.$emit("form-input-" + f.component, f);
+    },
+    addFieldAutocompleteFilter: function(item, queryText) {
+      const lab = this.$t(item["fieldname"]).toLowerCase();
+      const query = queryText.toLowerCase();
+      return lab.indexOf(query) > -1;
+    },
+    removeFieldChip(item) {
+      const index = this.addfieldselection.indexOf(item);
+      if (index >= 0) this.addfieldselection.splice(index, 1);
+    },
+    addFields(section) {
+      for (var i = 0; i < this.addfieldselection.length; i++) {
+        let f = fields.getField(this.addfieldselection[i].id);
+        f.removable = true;
+        section.fields.push(f);
+      }
+      this.addfieldselection = [];
+      section["adddialogue"] = false;
+    }
+  },
+  mounted: function() {
+    this.$store.dispatch("loadLanguages", this.$i18n.locale);
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+.prewrap {
+  white-space: pre-wrap;
+}
+</style>
\ No newline at end of file
diff --git a/src/components/input/phaidra_inputs/PIFunder.vue b/src/components/input/phaidra_inputs/PIFunder.vue
new file mode 100644
index 0000000000000000000000000000000000000000..d7a4cd13561075791d117701fa08d8895920750c
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PIFunder.vue
@@ -0,0 +1,87 @@
+<template>
+  <v-layout row>
+    <v-flex xs4>
+      <v-text-field
+        :value="name"
+        :label="$t('Funder name')"
+        v-on:blur="$emit('input-name',$event.target.value)"
+        box
+      ></v-text-field>
+    </v-flex>
+    <v-flex xs2>
+      <v-autocomplete
+        :value="getTerm('lang', nameLanguage)"
+        v-on:input="$emit('input-name-language', $event )"
+        :items="vocabularies['lang'].terms"
+        :filter="autocompleteFilter"
+        hide-no-data
+        :label="$t('Language')"
+        box
+        return-object
+        clearable
+      >
+        <template slot="item" slot-scope="{ item }">
+          <v-list-tile-content two-line>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+            <v-list-tile-sub-title v-html="`${item['@id']}`"></v-list-tile-sub-title>
+          </v-list-tile-content>
+        </template>
+        <template slot="selection" slot-scope="{ item }">
+          <v-list-tile-content>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+          </v-list-tile-content>
+        </template>
+      </v-autocomplete>
+    </v-flex>
+    <v-flex xs4>
+      <v-text-field
+        :value="identifier"
+        :label="'Funder identifier'"
+        v-on:blur="$emit('input-identifier',$event.target.value)"
+        box
+      ></v-text-field>
+    </v-flex>
+    <v-flex xs1 v-if="actions.length">
+      <v-menu open-on-hover bottom offset-y>
+        <v-btn slot="activator" icon>
+          <v-icon>more_vert</v-icon>
+        </v-btn>
+        <v-list>
+          <v-list-tile v-for="(action, i) in actions" :key="i" @click="$emit(action.event, $event)">
+            <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+          </v-list-tile>
+        </v-list>
+      </v-menu>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import { vocabulary } from "../../../mixins/vocabulary";
+import { fieldproperties } from "../../../mixins/fieldproperties";
+
+export default {
+  name: "p-i-funder",
+  mixins: [vocabulary, fieldproperties],
+  props: {
+    name: {
+      type: String
+    },
+    nameLanguage: {
+      type: String
+    },
+    identifier: {
+      type: String
+    }
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+.vertical-center {
+  align-items: center;
+}
+</style>
diff --git a/src/components/input/phaidra_inputs/PIKeyword.vue b/src/components/input/phaidra_inputs/PIKeyword.vue
new file mode 100644
index 0000000000000000000000000000000000000000..2771f1a8fec1ac2ae1cc2d4074702a4dc70da847
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PIKeyword.vue
@@ -0,0 +1,193 @@
+<template>
+  <v-layout row>
+    <v-flex xs8>
+      <v-combobox
+        v-model="model"
+        v-on:input="$emit('input', htmlToPlaintext($event))"
+        v-on:change="$emit('input', htmlToPlaintext($event))"
+        :items="items"
+        :loading="loading"
+        :search-input.sync="search"
+        :required="required"
+        :rules="required ? [ v => !!v || 'Required'] : []"
+        hide-no-data
+        item-text="text"
+        item-value="value"
+        :label="$t(label)"
+        multiple
+        clearable
+        chips
+        deletable-chips
+        box
+      >
+        <template slot="item" slot-scope="{ item }">
+          <v-list-tile-content two-line>
+            <v-list-tile-title inset v-html="item"></v-list-tile-title>
+          </v-list-tile-content>
+        </template>
+        <template slot="selection" slot-scope="data">
+          <v-chip
+            close
+            :selected="data.selected"
+            :disabled="data.disabled"
+            class="v-chip--select-multi"
+            @input="data.parent.selectItem(data.item)"
+          >{{ htmlToPlaintext(data.item) }}</v-chip>
+        </template>
+      </v-combobox>
+    </v-flex>
+    <v-flex xs2 v-if="multilingual">
+      <v-autocomplete
+        :value="getTerm('lang', language)"
+        v-on:input="$emit('input-language', $event )"
+        :items="vocabularies['lang'].terms"
+        :filter="autocompleteFilter"
+        hide-no-data
+        :label="$t('Language')"
+        box
+        return-object
+        clearable
+      >
+        <template slot="item" slot-scope="{ item }">
+          <v-list-tile-content two-line>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+            <v-list-tile-sub-title v-html="`${item['@id']}`"></v-list-tile-sub-title>
+          </v-list-tile-content>
+        </template>
+        <template slot="selection" slot-scope="{ item }">
+          <v-list-tile-content>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+          </v-list-tile-content>
+        </template>
+      </v-autocomplete>
+    </v-flex>
+    <v-flex xs1 v-if="actions.length">
+      <v-menu open-on-hover bottom offset-y>
+        <v-btn slot="activator" icon>
+          <v-icon>more_vert</v-icon>
+        </v-btn>
+        <v-list>
+          <v-list-tile v-for="(action, i) in actions" :key="i" @click="$emit(action.event, $event)">
+            <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+          </v-list-tile>
+        </v-list>
+      </v-menu>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import qs from "qs";
+import { vocabulary } from "../../../mixins/vocabulary";
+import { fieldproperties } from "../../../mixins/fieldproperties";
+
+export default {
+  name: "p-i-keyword",
+  mixins: [vocabulary, fieldproperties],
+  props: {
+    value: {
+      type: String,
+      required: true
+    },
+    language: {
+      type: String
+    },
+    label: {
+      type: String,
+      required: true
+    },
+    required: {
+      type: Boolean
+    },
+    multilingual: {
+      type: Boolean
+    },
+    suggester: {
+      type: String,
+      required: true
+    },
+    debounce: {
+      type: Number,
+      default: 500
+    }
+  },
+  data() {
+    return {
+      items: [],
+      loading: false,
+      model: this.value ? this.value.split(",") : this.value,
+      search: null
+    };
+  },
+  watch: {
+    search(val) {
+      val && this.querySuggestionsDebounce(val);
+    }
+  },
+  methods: {
+    htmlToPlaintext: function(text) {
+      return text ? String(text).replace(/<[^>]+>/gm, "") : "";
+    },
+    querySuggestionsDebounce(value) {
+      this.showList = true;
+
+      if (this.debounce) {
+        if (this.debounceTask !== undefined) clearTimeout(this.debounceTask);
+        this.debounceTask = setTimeout(() => {
+          return this.querySuggestions(value);
+        }, this.debounce);
+      } else {
+        return this.querySuggestions(value);
+      }
+    },
+    querySuggestions(q) {
+      var self = this;
+
+      if (q.length < this.min || !this.suggester) return;
+
+      self.loading = true;
+
+      var params = {
+        suggest: true,
+        "suggest.dictionary": self.suggester,
+        wt: "json",
+        "suggest.q": q
+      };
+
+      var query = qs.stringify(params);
+
+      fetch(self.$store.state.settings.instance.solr + "/suggest?" + query, {
+        method: "GET",
+        mode: "cors"
+      })
+        .then(function(response) {
+          return response.json();
+        })
+        .then(function(json) {
+          self.items = [];
+          for (
+            var i = 0;
+            i < json.suggest[self.suggester][q].suggestions.length;
+            i++
+          ) {
+            self.items.push(
+              json.suggest[self.suggester][q].suggestions[i].term
+            );
+          }
+          self.loading = false;
+        })
+        .catch(function(error) {
+          //console.log(error)
+          self.loading = false;
+        });
+    }
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+</style>
+
diff --git a/src/components/input/phaidra_inputs/PILiteral.vue b/src/components/input/phaidra_inputs/PILiteral.vue
new file mode 100644
index 0000000000000000000000000000000000000000..969fef50780c2bd1e58ad2fa4ec56a9c72a91f3f
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PILiteral.vue
@@ -0,0 +1,48 @@
+<template>
+  <v-layout row>
+    <v-flex xs4>
+      <v-text-field
+        :value="value" 
+        v-on:blur="$emit('input-value',$event.target.value)"
+        :label="$t(label)"
+        box
+      ></v-text-field>
+    </v-flex>
+    <v-flex xs1 v-if="actions.length">
+      <v-menu open-on-hover bottom offset-y>
+        <v-btn slot="activator" icon>
+          <v-icon>more_vert</v-icon>
+        </v-btn>
+        <v-list>
+          <v-list-tile v-for="(action, i) in actions" :key="i" @click="$emit(action.event, $event)">
+            <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+          </v-list-tile>
+        </v-list>
+      </v-menu>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import { fieldproperties } from "../../../mixins/fieldproperties";
+
+export default {
+  name: "p-i-literal",
+  mixins: [fieldproperties],
+  props: {
+    value: {
+      type: String
+    },
+    label: {
+      type: String,
+      required: true
+    }
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+</style>
diff --git a/src/components/input/phaidra_inputs/PIProject.vue b/src/components/input/phaidra_inputs/PIProject.vue
new file mode 100644
index 0000000000000000000000000000000000000000..83937849d7376ddd6d04c870b36e5cc8defadad6
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PIProject.vue
@@ -0,0 +1,167 @@
+<template>
+  <v-layout row>
+    <v-flex xs10>
+      <v-card>
+        <v-card-title class="subheading grey white--text">
+          <span>{{ $t('Project') }}</span>
+          <v-spacer></v-spacer>
+          <v-menu open-on-hover bottom offset-y v-if="actions.length">
+            <v-btn slot="activator" icon dark>
+              <v-icon dark>more_vert</v-icon>
+            </v-btn>
+            <v-list>
+              <v-list-tile
+                v-for="(action, i) in actions"
+                :key="i"
+                @click="$emit(action.event, $event)"
+              >
+                <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+              </v-list-tile>
+            </v-list>
+          </v-menu>
+        </v-card-title>
+        <v-divider></v-divider>
+        <v-card-text class="mt-4">
+          <v-layout column>
+            <v-flex>
+              <v-layout row>
+                <v-flex xs8>
+                  <v-text-field
+                    :value="name"
+                    :label="$t('Name')"
+                    v-on:blur="$emit('input-name',$event.target.value)"
+                    box
+                  ></v-text-field>
+                </v-flex>
+                <v-flex xs3>
+                  <v-autocomplete
+                    :value="getTerm('lang', nameLanguage)"
+                    v-on:input="$emit('input-name-language', $event )"
+                    :items="vocabularies['lang'].terms"
+                    :filter="autocompleteFilter"
+                    hide-no-data
+                    :label="$t('Language')"
+                    box
+                    return-object
+                    clearable
+                  >
+                    <template slot="item" slot-scope="{ item }">
+                      <v-list-tile-content two-line>
+                        <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+                        <v-list-tile-sub-title v-html="`${item['@id']}`"></v-list-tile-sub-title>
+                      </v-list-tile-content>
+                    </template>
+                    <template slot="selection" slot-scope="{ item }">
+                      <v-list-tile-content>
+                        <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+                      </v-list-tile-content>
+                    </template>
+                  </v-autocomplete>
+                </v-flex>
+              </v-layout>
+
+              <v-layout row>
+                <v-flex xs8>
+                  <v-text-field
+                    :value="description"
+                    :label="'Description'"
+                    v-on:input="$emit('input-description', $event)"
+                    box
+                  ></v-text-field>
+                </v-flex>
+                <v-flex xs3>
+                  <v-autocomplete
+                    :value="getTerm('lang', descriptionLanguage)"
+                    v-on:input="$emit('input-description-language', $event )"
+                    :items="vocabularies['lang'].terms"
+                    :filter="autocompleteFilter"
+                    hide-no-data
+                    :label="$t('Language')"
+                    box
+                    return-object
+                    clearable
+                  >
+                    <template slot="item" slot-scope="{ item }">
+                      <v-list-tile-content two-line>
+                        <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+                        <v-list-tile-sub-title v-html="`${item['@id']}`"></v-list-tile-sub-title>
+                      </v-list-tile-content>
+                    </template>
+                    <template slot="selection" slot-scope="{ item }">
+                      <v-list-tile-content>
+                        <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+                      </v-list-tile-content>
+                    </template>
+                  </v-autocomplete>
+                </v-flex>
+              </v-layout>
+
+              <v-layout row>
+                <v-flex xs6>
+                  <v-text-field
+                    :value="identifier"
+                    :label="'Identifier'"
+                    v-on:blur="$emit('input-identifier',$event.target.value)"
+                    homepage
+                    box
+                  ></v-text-field>
+                </v-flex>
+
+                <v-flex xs6>
+                  <v-text-field
+                    :value="homepage"
+                    :label="'Homepage'"
+                    v-on:blur="$emit('input-homepage',$event.target.value)"
+                    box
+                  ></v-text-field>
+                </v-flex>
+              </v-layout>
+            </v-flex>
+          </v-layout>
+        </v-card-text>
+      </v-card>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import { vocabulary } from "../../../mixins/vocabulary";
+import { fieldproperties } from "../../../mixins/fieldproperties";
+
+export default {
+  name: "p-i-project",
+  mixins: [vocabulary, fieldproperties],
+  props: {
+    type: {
+      type: String
+    },
+    name: {
+      type: String
+    },
+    nameLanguage: {
+      type: String
+    },
+    identifier: {
+      type: String
+    },
+    description: {
+      type: String
+    },
+    descriptionLanguage: {
+      type: String
+    },
+    homepage: {
+      type: String
+    }
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+.vertical-center {
+  align-items: center;
+}
+</style>
diff --git a/src/components/input/phaidra_inputs/PISelect.vue b/src/components/input/phaidra_inputs/PISelect.vue
new file mode 100644
index 0000000000000000000000000000000000000000..ab1e200be667f7922b4aba57b6f5d529d4b433cd
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PISelect.vue
@@ -0,0 +1,107 @@
+<template>
+  <v-layout row>
+    <v-flex xs8>
+      <v-autocomplete
+        :value="getTerm(vocabulary, value)"
+        :required="required"
+        v-on:input="$emit('input', $event )"
+        :rules="required ? [ v => !!v || 'Required'] : []"
+        :items="vocabularies[vocabulary].terms"
+        :loading="loading"
+        :filter="autocompleteFilter"
+        hide-no-data
+        :label="$t(label)"
+        box
+        return-object
+        clearable
+        :disabled="disabled"
+      >
+        <template slot="item" slot-scope="{ item }">
+          <v-list-tile-content two-line>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel(vocabulary, item['@id'])}`"></v-list-tile-title>
+            <v-list-tile-sub-title v-html="`${item['@id']}`"></v-list-tile-sub-title>
+          </v-list-tile-content>
+        </template>
+        <template slot="selection" slot-scope="{ item }">
+          <v-list-tile-content>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel(vocabulary, item['@id'])}`"></v-list-tile-title>
+          </v-list-tile-content>
+        </template>
+      </v-autocomplete>
+    </v-flex>
+    <v-flex xs1 v-if="actions.length">
+      <v-menu open-on-hover bottom offset-y>
+        <v-btn slot="activator" icon>
+          <v-icon>more_vert</v-icon>
+        </v-btn>
+        <v-list>
+          <v-list-tile v-for="(action, i) in actions" :key="i" @click="$emit(action.event, $event)">
+            <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+          </v-list-tile>
+        </v-list>
+      </v-menu>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import { vocabulary } from "../../../mixins/vocabulary";
+import { fieldproperties } from "../../../mixins/fieldproperties";
+
+export default {
+  name: "p-i-select",
+  mixins: [vocabulary, fieldproperties],
+  props: {
+    value: {
+      type: String
+    },
+    label: {
+      type: String,
+      required: true
+    },
+    required: {
+      type: Boolean
+    },
+    vocabulary: {
+      type: String,
+      required: true
+    },
+    disabled: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      loading: false
+    };
+  },
+  mounted: function() {
+    this.$nextTick(function() {
+      if (this.vocabulary) {
+        this.loading = !this.vocabularies[this.vocabulary].loaded;
+        // emit input to set skos:prefLabel in parent
+        if (this.value) {
+          for (
+            var i = 0;
+            i < this.vocabularies[this.vocabulary].terms.length;
+            i++
+          ) {
+            if (
+              this.vocabularies[this.vocabulary].terms[i]["@id"] === this.value
+            ) {
+              this.$emit("input", this.vocabularies[this.vocabulary].terms[i]);
+            }
+          }
+        }
+      }
+    });
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+</style>
diff --git a/src/components/input/phaidra_inputs/PISelectText.vue b/src/components/input/phaidra_inputs/PISelectText.vue
new file mode 100644
index 0000000000000000000000000000000000000000..efb5e86a994dc8198a6ff4b7bac6041449cac800
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PISelectText.vue
@@ -0,0 +1,172 @@
+<template>
+  <v-layout row>
+    <v-flex xs3>
+      <v-autocomplete
+        :value="getTerm(vocabulary, selectvalue)"
+        :required="required"
+        v-on:input="updateLocation('select', $event)"
+        :rules="required ? [ v => !!v || 'Required'] : []"
+        :items="vocabularies[vocabulary].terms"
+        :filter="autocompleteFilter"
+        hide-no-data
+        :label="$t(selectlabel)"
+        box
+        return-object
+        clearable
+      >
+        <template slot="item" slot-scope="{ item }">
+          <v-list-tile-content two-line>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel(vocabulary, item['@id'])}`"></v-list-tile-title>
+            <v-list-tile-sub-title v-html="`${item['@id']}`"></v-list-tile-sub-title>
+          </v-list-tile-content>
+        </template>
+        <template slot="selection" slot-scope="{ item }">
+          <v-list-tile-content>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel(vocabulary, item['@id'])}`"></v-list-tile-title>
+          </v-list-tile-content>
+        </template>
+      </v-autocomplete>
+    </v-flex>
+    <v-flex xs4>
+      <v-text-field
+        :value="textvalue"
+        v-on:input="updateLocation('text', $event)"
+        :label="$t(label)"
+        :required="required"
+        :rules="required ? [ v => !!v || 'Required'] : []"
+        box
+      ></v-text-field>
+    </v-flex>
+    <v-flex xs3 v-if="multilingual">
+      <v-autocomplete
+        :value="getTerm('lang', language)"
+        v-on:input="$emit('input-language', $event )"
+        :items="vocabularies['lang'].terms"
+        :filter="autocompleteFilter"
+        hide-no-data
+        :label="$t('Language')"
+        box
+        return-object
+        clearable
+      >
+        <template slot="item" slot-scope="{ item }">
+          <v-list-tile-content two-line>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+            <v-list-tile-sub-title v-html="`${item['@id']}`"></v-list-tile-sub-title>
+          </v-list-tile-content>
+        </template>
+        <template slot="selection" slot-scope="{ item }">
+          <v-list-tile-content>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+          </v-list-tile-content>
+        </template>
+      </v-autocomplete>
+    </v-flex>
+    <v-flex xs1 v-if="actions.length">
+      <v-menu open-on-hover bottom offset-y>
+        <v-btn slot="activator" icon>
+          <v-icon>more_vert</v-icon>
+        </v-btn>
+        <v-list>
+          <v-list-tile v-for="(action, i) in actions" :key="i" @click="$emit(action.event, $event)">
+            <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+          </v-list-tile>
+        </v-list>
+      </v-menu>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import { vocabulary } from "../../../mixins/vocabulary";
+import { fieldproperties } from "../../../mixins/fieldproperties";
+
+export default {
+  name: "p-i-select-text",
+  mixins: [vocabulary, fieldproperties],
+  props: {
+    textvalue: {
+      type: String
+    },
+    language: {
+      type: String
+    },
+    selectvalue: {
+      type: String
+    },
+    label: {
+      type: String,
+      required: true
+    },
+    selectlabel: {
+      type: String,
+      required: true
+    },
+    selectdisabled: {
+      type: Boolean,
+      default: false
+    },
+    vocabulary: {
+      type: String,
+      required: true
+    },
+    required: {
+      type: Boolean
+    },
+    multilingual: {
+      type: Boolean
+    }
+  },
+  data() {
+    return {
+      location: "",
+      svalue: "",
+      tvalue: ""
+    };
+  },
+  methods: {
+    updateLocation: function(source, value) {
+      this.location = "";
+      if (source === "select") {
+        if (value) {
+          this.svalue = value["@id"];
+          this.$emit("input-select", this.svalue);
+        } else {
+          this.svalue = "";
+        }
+      }
+      if (source === "text") {
+        if (value) {
+          this.tvalue = value;
+          this.$emit("input-text", this.tvalue);
+        }
+      }
+      if (this.svalue) {
+        this.location = this.svalue;
+      }
+      if (this.tvalue) {
+        if (this.location !== "") {
+          this.location = this.location + "; ";
+        }
+        this.location = this.location + this.tvalue;
+      }
+      this.$emit("input", this.location);
+    }
+  },
+  mounted: function() {
+    if (this.selectvalue) {
+      this.location = this.selectvalue;
+    }
+    if (this.value) {
+      this.location = this.location + "; " + this.value;
+    }
+    this.$emit("input", this.location);
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+</style>
diff --git a/src/components/input/phaidra_inputs/PISeries.vue b/src/components/input/phaidra_inputs/PISeries.vue
new file mode 100644
index 0000000000000000000000000000000000000000..3af496aa8739f82c1c0b0749598d95bf0394e8fa
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PISeries.vue
@@ -0,0 +1,183 @@
+<template>
+  <v-layout row>
+    <v-flex xs12>
+      <v-card>
+        <v-card-title class="subheading grey white--text">
+          <span>{{ $t(label) }}</span>
+          <v-spacer></v-spacer>
+          <v-menu open-on-hover bottom offset-y v-if="actions.length">
+            <v-btn slot="activator" icon dark>
+              <v-icon dark>more_vert</v-icon>
+            </v-btn>
+            <v-list>
+              <v-list-tile
+                v-for="(action, i) in actions"
+                :key="i"
+                @click="$emit(action.event, $event)"
+              >
+                <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+              </v-list-tile>
+            </v-list>
+          </v-menu>
+        </v-card-title>
+        <v-divider></v-divider>
+        <v-card-text class="mt-4">
+          <v-layout column>
+            <v-flex>
+              <v-layout row>
+                <v-flex xs8>
+                  <v-text-field
+                    :value="title"
+                    :label="$t('Title')"
+                    v-on:blur="$emit('input-title',$event.target.value)"
+                    box
+                  ></v-text-field>
+                </v-flex>
+                <v-flex xs4>
+                  <v-autocomplete
+                    :value="getTerm('lang', titleLanguage)"
+                    v-on:input="$emit('input-title-language', $event )"
+                    :items="vocabularies['lang'].terms"
+                    :filter="autocompleteFilter"
+                    hide-no-data
+                    :label="$t('Language')"
+                    box
+                    return-object
+                    clearable
+                  >
+                    <template slot="item" slot-scope="{ item }">
+                      <v-list-tile-content two-line>
+                        <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+                        <v-list-tile-sub-title v-html="`${item['@id']}`"></v-list-tile-sub-title>
+                      </v-list-tile-content>
+                    </template>
+                    <template slot="selection" slot-scope="{ item }">
+                      <v-list-tile-content>
+                        <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+                      </v-list-tile-content>
+                    </template>
+                  </v-autocomplete>
+                </v-flex>
+              </v-layout>
+
+              <v-layout row>
+                <v-flex xs4 v-if="!hideVolume">
+                  <v-text-field
+                    :value="volume"
+                    :label="$t('Volume')"
+                    v-on:blur="$emit('input-volume',$event.target.value)"
+                    box
+                  ></v-text-field>
+                </v-flex>
+
+                <v-flex xs4 v-if="!hideIssue">
+                  <v-text-field
+                    :value="issue"
+                    :label="$t('Issue')"
+                    v-on:blur="$emit('input-issue',$event.target.value)"
+                    box
+                  ></v-text-field>
+                </v-flex>
+
+                <v-flex xs4 v-if="!hideIssued">
+                  <v-text-field
+                    :value="issued"
+                    :label="$t('Issued')"
+                    v-on:blur="$emit('input-issued',$event.target.value)"
+                    :hint="'Format YYYY-MM-DD'"
+                    :rules="[validationrules.date]"
+                    box
+                  ></v-text-field>
+                </v-flex>
+              </v-layout>
+
+              <v-layout row>
+                <v-flex xs6 v-if="!hideIssn">
+                  <v-text-field
+                    :value="issn"
+                    :label="$t('ISSN')"
+                    v-on:blur="$emit('input-issn',$event.target.value)"
+                    box
+                  ></v-text-field>
+                </v-flex>
+
+                <v-flex xs6 v-if="!hideIdentifier">
+                  <v-text-field
+                    :value="identifier"
+                    :label="$t('Identifier')"
+                    v-on:blur="$emit('input-identifier',$event.target.value)"
+                    box
+                  ></v-text-field>
+                </v-flex>
+              </v-layout>
+            </v-flex>
+          </v-layout>
+        </v-card-text>
+      </v-card>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import { vocabulary } from "../../../mixins/vocabulary";
+import { fieldproperties } from "../../../mixins/fieldproperties";
+import { validationrules } from "../../../mixins/validationrules";
+
+export default {
+  name: "p-i-series",
+  mixins: [vocabulary, fieldproperties, validationrules],
+  props: {
+    type: {
+      type: String
+    },
+    label: {
+      type: String
+    },
+    title: {
+      type: String
+    },
+    titleLanguage: {
+      type: String
+    },
+    hideVolume: {
+      type: Boolean
+    },
+    volume: {
+      type: String
+    },
+    hideIssue: {
+      type: Boolean
+    },
+    issue: {
+      type: String
+    },
+    hideIssued: {
+      type: Boolean
+    },
+    issued: {
+      type: String
+    },
+    hideIssn: {
+      type: Boolean
+    },
+    issn: {
+      type: String
+    },
+    hideIdentifier: {
+      type: Boolean
+    },
+    identifier: {
+      type: String
+    }
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+.vertical-center {
+  align-items: center;
+}
+</style>
diff --git a/src/components/input/phaidra_inputs/PISpatialGetty.vue b/src/components/input/phaidra_inputs/PISpatialGetty.vue
new file mode 100644
index 0000000000000000000000000000000000000000..324fced699266c40044e4ab520152afeb5612c97
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PISpatialGetty.vue
@@ -0,0 +1,239 @@
+<template>
+  <v-layout row>
+    <v-flex xs3>
+      <v-autocomplete
+        v-on:input="$emit('input-place-type', $event)"
+        :label="$t('Type of place')"
+        :items="vocabularies['placepredicate'].terms"
+        :value="getTerm('placepredicate', type)"
+        :filter="autocompleteFilter"
+        :disabled="disabletype"
+        box
+        return-object
+        clearable
+      >
+        <template slot="item" slot-scope="{ item }">
+          <v-list-tile-content two-line>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('placepredicate', item['@id'])}`"></v-list-tile-title>
+            <v-list-tile-sub-title v-html="`${item['@id']}`"></v-list-tile-sub-title>
+          </v-list-tile-content>
+        </template>
+        <template slot="selection" slot-scope="{ item }">
+          <v-list-tile-content>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('placepredicate', item['@id'])}`"></v-list-tile-title>
+          </v-list-tile-content>
+        </template>
+      </v-autocomplete>
+    </v-flex>
+    <v-flex xs6>
+      <v-autocomplete
+        v-model="model"
+        v-on:input="$emit('input', $event)"
+        :items="items"
+        :loading="loading"
+        :search-input.sync="search"
+        cache-items
+        hide-no-data
+        hide-selected
+        item-text="text"
+        item-value="value"
+        :label="$t(label)"
+        box
+        clearable
+        :messages="resolved"
+      ></v-autocomplete>
+    </v-flex>
+    <v-flex xs1 v-if="actions.length">
+      <v-menu open-on-hover bottom offset-y>
+        <v-btn slot="activator" icon>
+          <v-icon>more_vert</v-icon>
+        </v-btn>
+        <v-list>
+          <v-list-tile v-for="(action, i) in actions" :key="i" @click="$emit(action.event, $event)">
+            <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+          </v-list-tile>
+        </v-list>
+      </v-menu>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import qs from "qs";
+import { vocabulary } from "../../../mixins/vocabulary";
+import { fieldproperties } from "../../../mixins/fieldproperties";
+
+export default {
+  name: "p-i-spatial-getty",
+  mixins: [vocabulary, fieldproperties],
+  props: {
+    value: {
+      type: String,
+      required: true
+    },
+    type: {
+      type: String
+    },
+    label: {
+      type: String,
+      required: true
+    },
+    initquery: {
+      type: String
+    },
+    required: {
+      type: Boolean
+    },
+    debounce: {
+      type: Number,
+      default: 500
+    },
+    disabletype: {
+      type: Boolean
+    }
+  },
+  watch: {
+    search(val) {
+      val && this.querySuggestionsDebounce(val);
+    },
+    value(val) {
+      val && this.resolve(val);
+    }
+  },
+  data() {
+    return {
+      items: [],
+      loading: false,
+      model: null,
+      search: null,
+      debounceTask: undefined,
+      preflabel: "",
+      rdfslabel: "",
+      coordinates: [],
+      resolved: ""
+    };
+  },
+  methods: {
+    resolve: function(uri) {
+      var self = this;
+
+      if (uri) {
+        self.loading = true;
+
+        var params = {
+          uri: uri
+        };
+
+        var query = qs.stringify(params);
+
+        fetch(self.$store.state.settings.instance.api + "/resolve/?" + query, {
+          method: "GET",
+          mode: "cors"
+        })
+          .then(function(response) {
+            return response.json();
+          })
+          .then(function(json) {
+            self.loading = false;
+            self.preflabel = json[uri]["skos:prefLabel"];
+            self.rdfslabel = json[uri]["rdfs:label"];
+            for (var i = 0; i < self.rdfslabel.length; i++) {
+              self.resolved =
+                '<a href="' +
+                uri +
+                '" target="_blank">' +
+                self.rdfslabel[i]["@value"] +
+                "</a>";
+            }
+            if (json[uri]["schema:GeoCoordinates"]) {
+              self.coordinates = [
+                {
+                  "@type": "schema:GeoCoordinates",
+                  "schema:latitude": [
+                    json[uri]["schema:GeoCoordinates"]["schema:latitude"]
+                  ],
+                  "schema:longitude": [
+                    json[uri]["schema:GeoCoordinates"]["schema:longitude"]
+                  ]
+                }
+              ];
+            }
+            self.$emit("resolve", {
+              "skos:prefLabel": self.preflabel,
+              "rdfs:label": self.rdfslabel,
+              coordinates: self.coordinates
+            });
+          })
+          .catch(function(error) {
+            console.log(error);
+            self.loading = false;
+          });
+      }
+    },
+    querySuggestionsDebounce(q) {
+      if (this.debounce) {
+        if (this.debounceTask !== undefined) clearTimeout(this.debounceTask);
+        this.debounceTask = setTimeout(() => {
+          return this.querySuggestions(q);
+        }, this.debounce);
+      } else {
+        return this.querySuggestions(q);
+      }
+    },
+    querySuggestions(q) {
+      var self = this;
+
+      self.loading = true;
+
+      var params = {
+        voc: "tgn",
+        count: 20,
+        searchstring: q
+      };
+
+      var query = qs.stringify(params);
+
+      fetch(self.$store.state.settings.global.suggesters.getty + "?" + query, {
+        method: "GET",
+        mode: "cors"
+      })
+        .then(function(response) {
+          return response.json();
+        })
+        .then(function(json) {
+          for (var i = 0; i < json[1].length; i++) {
+            self.items.push({ text: json[1][i], value: json[3][i] });
+          }
+          self.loading = false;
+        })
+        .catch(function(error) {
+          console.log(error);
+        })
+        .finally(() => (self.loading = false));
+    }
+  },
+  mounted: function() {
+    this.$nextTick(function() {
+      this.loading = !this.vocabularies["placepredicate"].loaded;
+      // emit input to set skos:prefLabel in parent
+      if (this.type) {
+        this.$emit(
+          "input-place-type",
+          this.getTerm("placepredicate", this.type)
+        );
+      }
+    });
+    if (this.initquery) {
+      this.items = [{ value: this.value, text: this.initquery }];
+      this.model = { value: this.value, text: this.initquery };
+      this.resolve(this.value);
+    }
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+</style>
diff --git a/src/components/input/phaidra_inputs/PISpatialGettyReadonly.vue b/src/components/input/phaidra_inputs/PISpatialGettyReadonly.vue
new file mode 100644
index 0000000000000000000000000000000000000000..4b952e7e75f4257f8ee6265f3f2f1b43ae6c87da
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PISpatialGettyReadonly.vue
@@ -0,0 +1,85 @@
+<template>
+  <v-layout row>
+    <v-flex xs8>
+      <v-text-field
+        :value="prefLabel"
+        :persistent-hint="true"
+        :messages="value"
+        :label="$t(label)"
+        readonly
+        box
+      ></v-text-field>
+    </v-flex>
+    <v-flex xs1 v-if="actions.length">
+      <v-menu open-on-hover bottom offset-y>
+        <v-btn slot="activator" icon>
+          <v-icon>more_vert</v-icon>
+        </v-btn>
+        <v-list>
+          <v-list-tile v-for="(action, i) in actions" :key="i" @click="$emit(action.event, $event)">
+            <v-list-tile-title v-if="action.event === 'remove'">{{ action.title }}</v-list-tile-title>
+          </v-list-tile>
+        </v-list>
+      </v-menu>
+    </v-flex>
+  </v-layout>
+</template>
+<script>
+import { fieldproperties } from "../../../mixins/fieldproperties";
+
+export default {
+  name: "p-i-spatial-getty-readonly",
+  mixins: [fieldproperties],
+  computed: {
+    rdfsLabels: function() {
+      var i;
+      var arr = [];
+      if (this["rdfs:label"]) {
+        for (i = 0; i < this["rdfs:label"].length; i++) {
+          arr.push(this["rdfs:label"][i]["@value"]);
+        }
+      }
+      return arr;
+    },
+    prefLabel: function() {
+      var i;
+      var prefLabel = "";
+      // just return any now
+      if (this["skos:prefLabel"]) {
+        for (i = 0; i < this["skos:prefLabel"].length; i++) {
+          return this["skos:prefLabel"][i]["@value"];
+        }
+      }
+      return prefLabel;
+    }
+  },
+  props: {
+    "skos:prefLabel": {
+      type: Array,
+      required: true
+    },
+    "rdfs:label": {
+      type: Array
+    },
+    value: {
+      type: String,
+      required: true
+    },
+    coordinates: {
+      type: Array
+    },
+    label: {
+      type: String,
+      required: true
+    },
+    predicate: {
+      type: String,
+      required: true
+    },
+    removable: {
+      type: Boolean,
+      default: true
+    }
+  }
+};
+</script>
\ No newline at end of file
diff --git a/src/components/input/phaidra_inputs/PISpatialText.vue b/src/components/input/phaidra_inputs/PISpatialText.vue
new file mode 100644
index 0000000000000000000000000000000000000000..7325625b1bfe7a011794dbebd2e1640c3afc02e9
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PISpatialText.vue
@@ -0,0 +1,142 @@
+<template>
+  <v-layout row>
+    <v-flex xs5>
+      <v-autocomplete
+        v-on:input="$emit('input-place-type', $event)"
+        :label="$t('Type of place')"
+        :items="vocabularies['placepredicate'].terms"
+        :value="getTerm('placepredicate', type)"
+        :filter="autocompleteFilter"
+        :disabled="disabletype"
+        box
+        return-object
+        clearable
+      >
+        <template slot="item" slot-scope="{ item }">
+          <v-list-tile-content two-line>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('placepredicate', item['@id'])}`"></v-list-tile-title>
+            <v-list-tile-sub-title v-html="`${item['@id']}`"></v-list-tile-sub-title>
+          </v-list-tile-content>
+        </template>
+        <template slot="selection" slot-scope="{ item }">
+          <v-list-tile-content>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('placepredicate', item['@id'])}`"></v-list-tile-title>
+          </v-list-tile-content>
+        </template>
+      </v-autocomplete>
+    </v-flex>
+    <v-flex xs4>
+      <v-text-field
+        v-if="!multiline"
+        :value="value"
+        v-on:input="$emit('input', $event)"
+        :label="$t(label)"
+        :required="required"
+        :rules="required ? [ v => !!v || 'Required'] : []"
+        box
+      ></v-text-field>
+      <v-textarea
+        v-if="multiline"
+        :value="value"
+        v-on:input="$emit('input', $event)"
+        :label="$t(label)"
+        :required="required"
+        :rules="required ? [ v => !!v || 'Required'] : []"
+        box
+      ></v-textarea>
+    </v-flex>
+    <v-flex xs2 v-if="multilingual">
+      <v-autocomplete
+        :value="getTerm('lang', language)"
+        v-on:input="$emit('input-language', $event )"
+        :items="vocabularies['lang'].terms"
+        :filter="autocompleteFilter"
+        hide-no-data
+        :label="$t('Language')"
+        box
+        return-object
+        clearable
+      >
+        <template slot="item" slot-scope="{ item }">
+          <v-list-tile-content two-line>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+            <v-list-tile-sub-title v-html="`${item['@id']}`"></v-list-tile-sub-title>
+          </v-list-tile-content>
+        </template>
+        <template slot="selection" slot-scope="{ item }">
+          <v-list-tile-content>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+          </v-list-tile-content>
+        </template>
+      </v-autocomplete>
+    </v-flex>
+    <v-flex xs1 v-if="actions.length">
+      <v-menu open-on-hover bottom offset-y>
+        <v-btn slot="activator" icon>
+          <v-icon>more_vert</v-icon>
+        </v-btn>
+        <v-list>
+          <v-list-tile v-for="(action, i) in actions" :key="i" @click="$emit(action.event, $event)">
+            <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+          </v-list-tile>
+        </v-list>
+      </v-menu>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import { vocabulary } from "../../../mixins/vocabulary";
+import { fieldproperties } from "../../../mixins/fieldproperties";
+
+export default {
+  name: "p-i-text-field",
+  mixins: [vocabulary, fieldproperties],
+  props: {
+    value: {
+      type: String,
+      required: true
+    },
+    type: {
+      type: String
+    },
+    language: {
+      type: String
+    },
+    label: {
+      type: String,
+      required: true
+    },
+    required: {
+      type: Boolean
+    },
+    multiline: {
+      type: Boolean
+    },
+    multilingual: {
+      type: Boolean
+    },
+    disabletype: {
+      type: Boolean
+    }
+  },
+  mounted: function() {
+    this.$nextTick(function() {
+      this.loading = !this.vocabularies["placepredicate"].loaded;
+      // emit input to set skos:prefLabel in parent
+      if (this.type) {
+        this.$emit(
+          "input-place-type",
+          this.getTerm("placepredicate", this.type)
+        );
+      }
+    });
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+</style>
diff --git a/src/components/input/phaidra_inputs/PIStudyPlan.vue b/src/components/input/phaidra_inputs/PIStudyPlan.vue
new file mode 100644
index 0000000000000000000000000000000000000000..117702bab748e7af03e15edd9ce6063b98ba860f
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PIStudyPlan.vue
@@ -0,0 +1,99 @@
+<template>
+  <v-layout row>
+    <v-flex xs4>
+      <v-text-field      
+        :value="notation" 
+        v-on:blur="$emit('input-notation',$event.target.value)"
+        :label="$t('Study plan notation')" 
+        :required="required"
+        :rules="required ? [ v => !!v || 'Required'] : []"
+        box
+      ></v-text-field>
+    </v-flex>
+    <v-flex xs4>
+      <v-text-field      
+        :value="name" 
+        v-on:blur="$emit('input-name',$event.target.value)"
+        :label="$t('Study plan name')" 
+        :required="required"
+        :rules="required ? [ v => !!v || 'Required'] : []"
+        box
+      ></v-text-field>
+    </v-flex>
+    <v-flex xs2 v-if="multilingual">
+      <v-autocomplete
+        :value="getTerm('lang', nameLanguage)"
+        v-on:input="$emit('input-name-language', $event )"
+        :items="vocabularies['lang'].terms"
+        :filter="autocompleteFilter"
+        hide-no-data
+        :label="$t('Name language')"
+        box
+        return-object
+        clearable
+      >
+        <template slot="item" slot-scope="{ item }">
+          <v-list-tile-content two-line>
+            <v-list-tile-title  v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+            <v-list-tile-sub-title  v-html="`${item['@id']}`"></v-list-tile-sub-title>
+          </v-list-tile-content>
+        </template>
+        <template slot="selection" slot-scope="{ item }">
+          <v-list-tile-content>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+          </v-list-tile-content>
+        </template>
+      </v-autocomplete>
+    </v-flex>
+    <v-flex xs1 v-if="actions.length">
+      <v-menu open-on-hover bottom offset-y>
+        <v-btn slot="activator" icon>
+          <v-icon>more_vert</v-icon>
+        </v-btn>
+        <v-list>
+          <v-list-tile v-for="(action, i) in actions" :key="i" @click="$emit(action.event, $event)">
+            <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+          </v-list-tile>
+        </v-list>
+      </v-menu>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import { vocabulary } from '../../../mixins/vocabulary'
+import { fieldproperties } from '../../../mixins/fieldproperties'
+
+export default {
+  name: 'p-i-study-plan',
+  mixins: [vocabulary, fieldproperties],
+  props: {
+    notation: {
+      type: String,
+      required: true
+    },
+    name: {
+      type: String,
+      required: true
+    },
+    nameLanguage: {
+      type: String
+    },
+    required: {
+      type: Boolean
+    },
+    multiline: {
+      type: Boolean
+    },
+    multilingual: {
+      type: Boolean
+    }
+  }
+}
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+</style>
diff --git a/src/components/input/phaidra_inputs/PISubjectGnd.vue b/src/components/input/phaidra_inputs/PISubjectGnd.vue
new file mode 100644
index 0000000000000000000000000000000000000000..589a80c44893f6c574e26f43064a60948ee825f3
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PISubjectGnd.vue
@@ -0,0 +1,206 @@
+<template>
+  <v-layout row>
+    <v-flex xs8>
+      <v-autocomplete
+        v-model="model"
+        v-on:input="$emit('input', $event)"
+        :items="items"
+        :loading="loading"
+        :search-input.sync="search"
+        cache-items
+        hide-no-data
+        hide-selected
+        item-text="text"
+        item-value="value"
+        :label="$t(label)"
+        box
+        clearable
+        :messages="resolved"
+      ></v-autocomplete>
+    </v-flex>
+    <v-flex xs1 v-if="actions.length">
+      <v-menu open-on-hover bottom offset-y>
+        <v-btn slot="activator" icon>
+          <v-icon>more_vert</v-icon>
+        </v-btn>
+        <v-list>
+          <v-list-tile v-for="(action, i) in actions" :key="i" @click="$emit(action.event, $event)">
+            <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+          </v-list-tile>
+        </v-list>
+      </v-menu>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import qs from "qs";
+import { fieldproperties } from "../../../mixins/fieldproperties";
+
+export default {
+  name: "p-i-subject-gnd",
+  mixins: [fieldproperties],
+  props: {
+    value: {
+      type: String,
+      required: true
+    },
+    type: {
+      type: String
+    },
+    voc: {
+      type: String,
+      default: "SubjectHeading"
+    },
+    exactvoc: {
+      type: String
+    },
+    label: {
+      type: String,
+      required: true
+    },
+    initquery: {
+      type: String
+    },
+    required: {
+      type: Boolean
+    },
+    debounce: {
+      type: Number,
+      default: 500
+    }
+  },
+  watch: {
+    search(val) {
+      val && this.querySuggestionsDebounce(val);
+    },
+    value(val) {
+      val && this.resolve(val);
+    }
+  },
+  data() {
+    return {
+      items: [],
+      loading: false,
+      model: null,
+      search: null,
+      debounceTask: undefined,
+      preflabel: "",
+      rdfslabel: "",
+      coordinates: [],
+      resolved: ""
+    };
+  },
+  methods: {
+    resolve: function(uri) {
+      var self = this;
+
+      if (uri) {
+        self.loading = true;
+
+        var params = {
+          uri: uri
+        };
+
+        var query = qs.stringify(params);
+
+        fetch(self.$store.state.settings.instance.api + "/resolve/?" + query, {
+          method: "GET",
+          mode: "cors"
+        })
+          .then(function(response) {
+            return response.json();
+          })
+          .then(function(json) {
+            self.loading = false;
+            self.preflabel = json[uri]["skos:prefLabel"];
+            self.rdfslabel = json[uri]["rdfs:label"];
+            if (self.rdfslabel) {
+              var rdfslabelarr = [];
+              for (var i = 0; i < self.rdfslabel.length; i++) {
+                rdfslabelarr.push(self.rdfslabel[i]["@value"]);
+              }
+              self.resolved =
+                'Synonym: <a href="' +
+                uri +
+                '" target="_blank">' +
+                rdfslabelarr.join(", ") +
+                "</a>";
+            } else {
+              self.resolved = "";
+            }
+            self.$emit("resolve", {
+              "skos:prefLabel": self.preflabel,
+              "rdfs:label": self.rdfslabel
+            });
+          })
+          .catch(function(error) {
+            console.log(error);
+            self.loading = false;
+          });
+      }
+    },
+    querySuggestionsDebounce(q) {
+      if (this.debounce) {
+        if (this.debounceTask !== undefined) clearTimeout(this.debounceTask);
+        this.debounceTask = setTimeout(() => {
+          return this.querySuggestions(q);
+        }, this.debounce);
+      } else {
+        return this.querySuggestions(q);
+      }
+    },
+    querySuggestions(q) {
+      var self = this;
+
+      self.loading = true;
+
+      var params = {
+        count: 20,
+        searchterm: q
+      };
+
+      if (this.voc) {
+        params["type"] = this.voc;
+      }
+
+      if (this.exactvoc) {
+        params["exact_type"] = this.exactvoc;
+      }
+
+      var query = qs.stringify(params);
+
+      fetch(self.$store.state.settings.global.suggesters.gnd + "?" + query, {
+        method: "GET",
+        mode: "cors"
+      })
+        .then(function(response) {
+          return response.json();
+        })
+        .then(function(json) {
+          for (var i = 0; i < json[1].length; i++) {
+            self.items.push({ text: json[1][i], value: json[3][i] });
+          }
+          self.loading = false;
+        })
+        .catch(function(error) {
+          console.log(error);
+        })
+        .finally(() => (self.loading = false));
+    }
+  },
+  mounted: function() {
+    if (this.initquery) {
+      this.items = [{ value: this.value, text: this.initquery }];
+      this.model = { value: this.value, text: this.initquery };
+      this.resolve(this.value);
+    }
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+</style>
diff --git a/src/components/input/phaidra_inputs/PITextField.vue b/src/components/input/phaidra_inputs/PITextField.vue
new file mode 100644
index 0000000000000000000000000000000000000000..c6f3dd0d8c86a41d7ee8d4881e493634f49a2173
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PITextField.vue
@@ -0,0 +1,97 @@
+<template>
+  <v-layout row>
+    <v-flex xs8>
+      <v-text-field v-if="!multiline"
+        :value="value"
+        v-on:blur="$emit('input',$event.target.value)"
+        :label="$t(label)" 
+        :required="required"
+        :rules="required ? [ v => !!v || 'Required'] : []"
+        box
+      ></v-text-field>
+      <v-textarea v-if="multiline"
+        :value="value"
+        v-on:blur="$emit('input',$event.target.value)" 
+        :label="$t(label)" 
+        :required="required"
+        :rules="required ? [ v => !!v || 'Required'] : []"
+        box
+      ></v-textarea>
+    </v-flex>
+    <v-flex xs2 v-if="multilingual">
+      <v-autocomplete
+        :value="getTerm('lang', language)"
+        v-on:input="$emit('input-language', $event )"
+        :items="vocabularies['lang'].terms"
+        :filter="autocompleteFilter"
+        hide-no-data
+        :label="$t('Language')"
+        box
+        return-object
+        clearable
+      >
+        <template slot="item" slot-scope="{ item }">
+          <v-list-tile-content two-line>
+            <v-list-tile-title  v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+            <v-list-tile-sub-title v-html="`${item['@id']}`"></v-list-tile-sub-title>
+          </v-list-tile-content>
+        </template>
+        <template slot="selection" slot-scope="{ item }">
+          <v-list-tile-content>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+          </v-list-tile-content>
+        </template>
+      </v-autocomplete>
+    </v-flex>
+    <v-flex xs1 v-if="actions.length">
+      <v-menu open-on-hover bottom offset-y>
+        <v-btn slot="activator" icon>
+          <v-icon>more_vert</v-icon>
+        </v-btn>
+        <v-list>
+          <v-list-tile v-for="(action, i) in actions" :key="i" @click="$emit(action.event, $event)">
+            <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+          </v-list-tile>
+        </v-list>
+      </v-menu>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import { vocabulary } from '../../../mixins/vocabulary'
+import { fieldproperties } from '../../../mixins/fieldproperties'
+
+export default {
+  name: 'p-i-text-field',
+  mixins: [vocabulary, fieldproperties],
+  props: {
+    value: {
+      type: String,
+      required: true
+    },
+    language: {
+      type: String
+    },
+    label: {
+      type: String,
+      required: true
+    },
+    required: {
+      type: Boolean
+    },
+    multiline: {
+      type: Boolean
+    },
+    multilingual: {
+      type: Boolean
+    }
+  }
+}
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+</style>
diff --git a/src/components/input/phaidra_inputs/PITextFieldSuggest.vue b/src/components/input/phaidra_inputs/PITextFieldSuggest.vue
new file mode 100644
index 0000000000000000000000000000000000000000..942ec78ba2337a197dd4bc06e74850d0f1119921
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PITextFieldSuggest.vue
@@ -0,0 +1,199 @@
+<template>
+  <v-layout row>
+    <v-flex xs8>
+      <v-combobox
+        v-model="model"
+        v-on:input="$emit('input', htmlToPlaintext($event))"
+        v-on:change="$emit('input', htmlToPlaintext($event))"
+        :items="items"
+        :loading="loading"
+        :search-input.sync="search"
+        :required="required"
+        :rules="required ? [ v => !!v || 'Required'] : []"
+        cache-items
+        hide-no-data
+        hide-selected
+        item-text="text"
+        item-value="value"
+        :label="$t(label)"
+        box
+        clearable
+      >
+        <template slot="item" slot-scope="{ item }">
+          <v-list-tile-content two-line>
+            <v-list-tile-title inset v-html="item"></v-list-tile-title>
+          </v-list-tile-content>
+        </template>
+        <template slot="selection" slot-scope="{ item }">
+          <v-list-tile-content>
+            <v-list-tile-title inset>{{ htmlToPlaintext(item) }}</v-list-tile-title>
+          </v-list-tile-content>
+        </template>
+      </v-combobox>
+    </v-flex>
+    <v-flex xs2 v-if="multilingual">
+      <v-autocomplete
+        :value="getTerm('lang', language)"
+        v-on:input="$emit('input-language', $event )"
+        :items="vocabularies['lang'].terms"
+        :filter="autocompleteFilter"
+        hide-no-data
+        :label="$t('Language')"
+        box
+        return-object
+        clearable
+      >
+        <template slot="item" slot-scope="{ item }">
+          <v-list-tile-content two-line>
+            <v-list-tile-title  v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+            <v-list-tile-sub-title  v-html="`${item['@id']}`"></v-list-tile-sub-title>
+          </v-list-tile-content>
+        </template>
+        <template slot="selection" slot-scope="{ item }">
+          <v-list-tile-content>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+          </v-list-tile-content>
+        </template>
+      </v-autocomplete>
+    </v-flex>
+    <v-flex xs1 v-if="actions.length">
+      <v-menu open-on-hover bottom offset-y>
+        <v-btn slot="activator" icon>
+          <v-icon>more_vert</v-icon>
+        </v-btn>
+        <v-list>
+          <v-list-tile v-for="(action, i) in actions" :key="i" @click="$emit(action.event, $event)">
+            <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+          </v-list-tile>
+        </v-list>
+      </v-menu>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+  import qs from 'qs'
+  import { vocabulary } from '../../../mixins/vocabulary'
+  import { fieldproperties } from '../../../mixins/fieldproperties'
+
+  export default {
+    name: 'p-i-text-field-suggest',
+    mixins: [vocabulary, fieldproperties],
+    props: {
+      value: {
+        type: String,
+        required: true
+      },
+      language: {
+        type: String
+      },
+      label: {
+        type: String,
+        required: true
+      },
+      required: {
+        type: Boolean
+      },
+      multilingual: {
+        type: Boolean
+      },
+      suggester: {
+        type: String,
+        required: true
+      },
+      debounce: {
+        type: Number,
+        default: 500
+      }
+    },
+    data () {
+      return {
+        items: [],
+        loading: false,
+        model: this.value,
+        search: null
+      }
+    },
+    watch: {
+      search (val) {
+        val && this.querySuggestionsDebounce(val)
+      }
+    },
+    methods: {
+      htmlToPlaintext: function (text) {
+        return text ? String(text).replace(/<[^>]+>/gm, '') : ''
+      },
+      querySuggestionsDebounce (value) {
+        this.showList = true
+
+        if (this.debounce) {
+          if (this.debounceTask !== undefined) clearTimeout(this.debounceTask)
+          this.debounceTask = setTimeout(() => {
+            return this.querySuggestions(value)
+          }, this.debounce)
+        } else {
+          return this.querySuggestions(value)
+        }
+      },
+      querySuggestions (q) {
+        var self = this
+
+        if (q.length < this.min || !this.suggester) return
+
+        self.loading = true
+
+        var params = {
+          suggest: true,
+          'suggest.dictionary': self.suggester,
+          wt: 'json',
+          'suggest.q': q
+        }
+
+        var query = qs.stringify(params)
+
+        fetch(self.$store.state.settings.instance.solr + '/suggest?' + query, {
+          method: 'GET',
+          mode: 'cors'
+        })
+        .then(function (response) { return response.json() })
+        .then(function (json) {
+          self.items = []
+          for (var i = 0; i < json.suggest[self.suggester][q].suggestions.length; i++) {
+            self.items.push(json.suggest[self.suggester][q].suggestions[i].term)
+          }
+          self.loading = false
+        })
+        .catch(function (error) {
+          //console.log(error)
+          self.loading = false
+        })
+      }
+    }
+
+  }
+</script>
+
+<style scoped>
+.searchbox{
+  font-size: 14px;
+  box-sizing: border-box;
+  border: none;
+  box-shadow: none;
+  outline: 0;
+  background: 0 0;
+  width: 100%;
+  padding: 0 15px;
+  line-height: 40px;
+  height: 40px;
+}
+
+.autocomplete {
+  position: absolute;
+  z-index: 999;
+  margin-top: 2px;
+}
+.v-btn {
+  margin: 0;
+}
+</style>
+
diff --git a/src/components/input/phaidra_inputs/PITitle.vue b/src/components/input/phaidra_inputs/PITitle.vue
new file mode 100644
index 0000000000000000000000000000000000000000..b0ccb4aed6de5c00d083339af232670554a1a562
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PITitle.vue
@@ -0,0 +1,109 @@
+<template>
+  <v-layout row>
+    here in pi title
+    <v-flex xs4>
+      <v-text-field
+        :value="title"
+        :label="$t( titleLabel ? titleLabel : type )"
+        v-on:blur="$emit('input-title',$event.target.value)"
+        box
+      ></v-text-field>
+    </v-flex>
+    <v-flex xs4 v-if="!hideSubtitle">
+      <v-text-field
+        :value="subtitle"
+        :label="$t( subtitleLabel ? subtitleLabel : 'Subtitle' )"
+        v-on:blur="$emit('input-subtitle',$event.target.value)"
+        box
+      ></v-text-field>
+    </v-flex>
+    <v-flex xs2 v-if="multilingual">
+      <v-autocomplete
+        :value="getTerm('lang', language)"
+        v-on:input="$emit('input-language', $event )"
+        :items="vocabularies['lang'].terms"
+        :filter="autocompleteFilter"
+        hide-no-data
+        :label="$t('Language')"
+        box
+        return-object
+        clearable
+      >
+        <template slot="item" slot-scope="{ item }">
+          <v-list-tile-content two-line>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+            <v-list-tile-sub-title v-html="`${item['@id']}`"></v-list-tile-sub-title>
+          </v-list-tile-content>
+        </template>
+        <template slot="selection" slot-scope="{ item }">
+          <v-list-tile-content>
+            <v-list-tile-title v-html="`${getLocalizedTermLabel('lang', item['@id'])}`"></v-list-tile-title>
+          </v-list-tile-content>
+        </template>
+      </v-autocomplete>
+    </v-flex>
+    <v-flex xs1 v-if="actions.length">
+      <v-menu open-on-hover bottom offset-y>
+        <v-btn slot="activator" icon>
+          <v-icon>more_vert</v-icon>
+        </v-btn>
+        <v-list>
+          <v-list-tile v-for="(action, i) in actions" :key="i" @click="$emit(action.event, $event)">
+            <v-list-tile-title>{{ action.title }}</v-list-tile-title>
+          </v-list-tile>
+        </v-list>
+      </v-menu>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import { vocabulary } from "../../../mixins/vocabulary";
+import { fieldproperties } from "../../../mixins/fieldproperties";
+
+export default {
+  name: "p-i-title",
+  mixins: [vocabulary, fieldproperties],
+  props: {
+    title: {
+      type: String
+    },
+    titleLabel: {
+      type: String
+    },
+    type: {
+      type: String
+    },
+    subtitle: {
+      type: String
+    },
+    subtitleLabel: {
+      type: String
+    },
+    hideSubtitle: {
+      type: Boolean
+    },
+    language: {
+      type: String
+    },
+    required: {
+      type: Boolean
+    },
+    multilingual: {
+      type: Boolean
+    }
+  },
+  data() {
+    return {
+      datepicker: false,
+      selectedDate: ""
+    };
+  }
+};
+</script>
+
+<style scoped>
+.v-btn {
+  margin: 0;
+}
+</style>
diff --git a/src/components/input/phaidra_inputs/PIUnknownReadonly.vue b/src/components/input/phaidra_inputs/PIUnknownReadonly.vue
new file mode 100644
index 0000000000000000000000000000000000000000..86b65871d04251b7bed52dde166b212250e6bdc5
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PIUnknownReadonly.vue
@@ -0,0 +1,28 @@
+<template>
+  <v-layout>
+    <v-flex>
+      <v-flex class="primary--text" xs3>{{ label }}</v-flex>
+      <vue-json-pretty :data="jsonld"></vue-json-pretty>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import VueJsonPretty from 'vue-json-pretty'
+
+export default {
+  name: 'p-i-unknown-readonly',
+  components: {
+    VueJsonPretty
+  },
+  props: {
+    jsonld: {
+      type: Object
+    },
+    label: {
+      type: String,
+      required: true
+    }
+  }
+}
+</script>
\ No newline at end of file
diff --git a/src/components/input/phaidra_inputs/PIVocabExtReadonly.vue b/src/components/input/phaidra_inputs/PIVocabExtReadonly.vue
new file mode 100644
index 0000000000000000000000000000000000000000..147b6b622678cf864f3b5c660d9ed6646abd6418
--- /dev/null
+++ b/src/components/input/phaidra_inputs/PIVocabExtReadonly.vue
@@ -0,0 +1,109 @@
+<template>
+  <v-layout row>
+    <v-flex xs8>
+      <v-text-field
+        :value="prefLabel"
+        :persistent-hint="true"
+        :messages="messages"
+        :label="$t(label)"
+        readonly
+        box
+      ></v-text-field>
+    </v-flex>
+    <v-flex xs1 v-if="actions.length">
+      <v-menu open-on-hover bottom offset-y>
+        <v-btn slot="activator" icon>
+          <v-icon>more_vert</v-icon>
+        </v-btn>
+        <v-list>
+          <v-list-tile v-for="(action, i) in actions" :key="i" @click="$emit(action.event, $event)">
+            <v-list-tile-title v-if="action.event === 'remove'">{{ action.title }}</v-list-tile-title>
+          </v-list-tile>
+        </v-list>
+      </v-menu>
+    </v-flex>
+  </v-layout>
+</template>
+<script>
+import { fieldproperties } from "../../../mixins/fieldproperties";
+
+export default {
+  name: "p-i-vocab-ext-readonly",
+  mixins: [fieldproperties],
+  computed: {
+    rdfsLabels: function() {
+      var i;
+      var arr = [];
+      if (this["rdfs:label"]) {
+        for (i = 0; i < this["rdfs:label"].length; i++) {
+          arr.push(this["rdfs:label"][i]["@value"]);
+        }
+      }
+      return arr;
+    },
+    prefLabel: function() {
+      var i;
+      var prefLabel = "";
+      // just return any now
+      if (this["skos:prefLabel"]) {
+        for (i = 0; i < this["skos:prefLabel"].length; i++) {
+          return this["skos:prefLabel"][i]["@value"];
+        }
+      }
+      return prefLabel;
+    },
+    notation: function() {
+      var i;
+      if (this["skos:notation"]) {
+        for (i = 0; i < this["skos:notation"].length; i++) {
+          return this["skos:notation"][i];
+        }
+      }
+      return false;
+    },
+    messages: function() {
+      var ret;
+      if (this["skos:exactMatch"]) {
+        ret =
+          '<a href="' +
+          this["skos:exactMatch"][0] +
+          '" target="_blank">' +
+          this["skos:exactMatch"][0] +
+          "</a>";
+      }
+      if (this["skos:notation"]) {
+        ret = ret + (ret ? ret + " " : "") + "Notation: " + notation;
+      }
+      return ret;
+    }
+  },
+  props: {
+    "skos:prefLabel": {
+      type: Array,
+      required: true
+    },
+    "rdfs:label": {
+      type: Array
+    },
+    "skos:exactMatch": {
+      type: Array,
+      required: true
+    },
+    "skos:notation": {
+      type: Array
+    },
+    label: {
+      type: String,
+      required: true
+    },
+    predicate: {
+      type: String,
+      required: true
+    },
+    removable: {
+      type: Boolean,
+      default: true
+    }
+  }
+};
+</script>
\ No newline at end of file
diff --git a/src/components/management/PMDelete.vue b/src/components/management/PMDelete.vue
new file mode 100644
index 0000000000000000000000000000000000000000..9c39a2e0823c3ba076f69f2298d18678c29f6a71
--- /dev/null
+++ b/src/components/management/PMDelete.vue
@@ -0,0 +1,95 @@
+<template>
+  <v-card >
+    <v-card-title class="subheading grey white--text">{{ $t('Delete') }}</v-card-title>
+    <v-divider></v-divider>
+    <v-card-text class="mt-4">
+      <v-alert :type="'info'" :value="true" transition="slide-y-transition" v-if="(cmodel === 'Container') && (members.length > 0)">{{ $t('MEMBERS_DELETE_ALERT_CONTAINER', { nrmembers: members.length }) }}</v-alert>
+      <v-flex v-else>{{ $t('DELETE_OBJECT', { pid: 'https://' + instance.baseurl + '/' + pid }) }}</v-flex>
+    </v-card-text>
+    <v-card-actions>
+      <v-spacer></v-spacer>
+      <v-flex>
+        <v-dialog v-model="dialog" width="500" >
+          <template v-slot:activator="{ on }">
+            <v-btn color="red" class="white--text" v-on="on" :disabled="(members.length > 0) || !pid || !cmodel">{{ $t('Delete') }}</v-btn>
+          </template>
+          <v-card>
+            <v-card-title class="headline grey lighten-2" primary-title >{{ $t('Delete') }}</v-card-title>
+            <v-card-text>{{ $t('DELETE_OBJECT_CONFIRM', { pid: 'https://' + instance.baseurl + '/' +  pid })}}</v-card-text>
+            <v-divider></v-divider>
+            <v-card-actions>
+              <v-spacer></v-spacer>
+              <v-btn color="red" class="white--text" :loading="loading" :disabled="loading" @click="deleteObject(pid)">{{ $t('Delete') }}</v-btn>
+              <v-btn :disabled="loading" @click="dialog = false">{{ $t('Cancel') }}</v-btn>
+            </v-card-actions>
+          </v-card>
+        </v-dialog>
+      </v-flex>
+    </v-card-actions>
+  </v-card>
+</template>
+
+<script>
+
+export default {
+  name: 'p-m-delete',
+  props: {
+    pid: {
+      type: String
+    },
+    cmodel: {
+      type: String
+    },
+    members: {
+      type: Array,
+      default: []
+    }
+  },
+  computed: {
+    instance: function() {
+      return this.$store.state.settings.instance
+    }
+  },
+  data () {
+    return {
+      loading: false,
+      dialog: false
+    }
+  },
+  methods: {
+    deleteObject: function (pid) {
+      var self = this
+      self.loading = true
+      var url = self.$store.state.settings.instance.api + '/object/' + pid + '/delete'
+      var promise = fetch(url, {
+        method: 'POST',
+        mode: 'cors',
+        headers: {
+          'X-XSRF-TOKEN': this.$store.state.user.token
+        }
+      })
+      .then(function (response) { return response.json() })
+      .then(function (json) {
+        if (json.status === 200) {
+          self.$emit('object-deleted', self.pid)
+        } else {
+          if (json.alerts && json.alerts.length > 0) {
+            self.$store.commit('setAlerts', json.alerts)
+          }
+        }
+        self.loading = false
+        self.dialog = false
+        self.$vuetify.goTo(0)
+      })
+      .catch(function (error) {
+        self.$store.commit('setAlerts', [{ type: 'danger', msg: 'Error deleting object: ' + error}])
+        console.log(error)
+        self.loading = false
+        self.dialog = false
+        self.$vuetify.goTo(0)
+      })
+      return promise
+    }
+  }
+}
+</script>
diff --git a/src/components/management/PMFiles.vue b/src/components/management/PMFiles.vue
new file mode 100644
index 0000000000000000000000000000000000000000..7485601b382408f85ede26eccb2d71e8babbcfbf
--- /dev/null
+++ b/src/components/management/PMFiles.vue
@@ -0,0 +1,32 @@
+<template>
+  <v-card >
+    <v-card-title class="subheading grey white--text">{{ $t('Files') }}</v-card-title>
+    <v-divider></v-divider>
+    <v-card-text class="mt-4">
+      <v-flex>{{ $t('Here you can add or remove some of the files this digital object is composed of.') }}</v-flex>
+    </v-card-text>
+  </v-card>
+</template>
+
+<script>
+
+export default {
+  name: 'p-m-files',
+  props: {
+    pid: {
+      type: String,
+      required: true
+    }
+  },
+  computed: {
+    instance: function() {
+      return this.$store.state.settings.instance
+    }
+  },
+  data () {
+    return {
+      loading: false
+    }
+  }
+}
+</script>
diff --git a/src/components/management/PMRelationships.vue b/src/components/management/PMRelationships.vue
new file mode 100644
index 0000000000000000000000000000000000000000..1b527afc4634c36057de6378fecd39e043c84cbf
--- /dev/null
+++ b/src/components/management/PMRelationships.vue
@@ -0,0 +1,32 @@
+<template>
+  <v-card >
+    <v-card-title class="subheading grey white--text">{{ $t('Relationships') }}</v-card-title>
+    <v-divider></v-divider>
+    <v-card-text class="mt-4">
+      <v-flex>{{ $t('Here you can add or remove relationships to other objects inside this repository.') }}</v-flex>
+    </v-card-text>
+  </v-card>
+</template>
+
+<script>
+
+export default {
+  name: 'p-m-relationships',
+  props: {
+    pid: {
+      type: String,
+      required: true
+    }
+  },
+  computed: {
+    instance: function() {
+      return this.$store.state.settings.instance
+    }
+  },
+  data () {
+    return {
+      loading: false
+    }
+  }
+}
+</script>
diff --git a/src/components/management/PMRights.vue b/src/components/management/PMRights.vue
new file mode 100644
index 0000000000000000000000000000000000000000..373f99125b7556d7995f6547a95ed942b739a86f
--- /dev/null
+++ b/src/components/management/PMRights.vue
@@ -0,0 +1,32 @@
+<template>
+  <v-card >
+    <v-card-title class="subheading grey white--text">{{ $t('Access rights') }}</v-card-title>
+    <v-divider></v-divider>
+    <v-card-text class="mt-4">
+      <v-flex>{{ $t('Here you can restrict access to this object. Any other objects, like members (if this is a container or a collection), pages (if this is a book) different versions or related objects will not be affected.') }}</v-flex>
+    </v-card-text>
+  </v-card>
+</template>
+
+<script>
+
+export default {
+  name: 'p-m-rights',
+  props: {
+    pid: {
+      type: String,
+      required: true
+    }
+  },
+  computed: {
+    instance: function() {
+      return this.$store.state.settings.instance
+    }
+  },
+  data () {
+    return {
+      loading: false
+    }
+  }
+}
+</script>
diff --git a/src/components/management/PMSort.vue b/src/components/management/PMSort.vue
new file mode 100644
index 0000000000000000000000000000000000000000..e823200095cb326084fd95b44e8b0a3301d5efba
--- /dev/null
+++ b/src/components/management/PMSort.vue
@@ -0,0 +1,104 @@
+<template>
+  <v-card >
+    <v-card-title class="subheading grey white--text">{{ $t('Sort') }}</v-card-title>
+    <v-divider></v-divider>
+    <v-card-text class="mt-4" v-if="members.length > 0">
+      <v-flex>{{ $t('Here you can sort members of this object (drag & drop).') }}</v-flex>
+      <SortableList lockAxis="y" v-model="memberscomputed">
+        <SortableSolrDoc v-for="(item, index) in memberscomputed" :index="index" :key="index" :item="item"/>
+      </SortableList>
+    </v-card-text>
+    <v-card-actions v-if="members.length > 0">
+      <v-spacer></v-spacer>
+      <v-btn color="primary" :disabled="loading" :loading="loading" @click="save()">{{ $t('Save') }}</v-btn>
+    </v-card-actions>
+  </v-card>
+</template>
+
+<script>
+import SortableList from '../utils/SortableList'
+import SortableSolrDoc from '../utils/SortableSolrDoc'
+
+export default {
+  name: 'p-m-sort',
+  components: {
+    SortableSolrDoc,
+    SortableList
+  },
+  props: {
+    pid: {
+      type: String
+    },
+    cmodel: {
+      type: String
+    },
+    members: {
+      type: Array,
+      default: []
+    }
+  },
+  computed: {
+    instance: function() {
+      return this.$store.state.settings.instance
+    },
+    memberscomputed: {
+      get: function () {
+        if (this.membersdata.length === 0) {
+          this.membersdata = this.members
+        }
+        return this.membersdata
+      },
+      set: function (newValue) {
+        this.membersdata = newValue
+      }
+    }
+  },
+  data () {
+    return {
+      loading: false,
+      membersdata: []
+    }
+  },
+  methods: {
+    save: function () {
+      var self = this
+      self.loading = true
+      let colorder = []
+      let i = 0
+      for (let m of this.membersdata) {
+        i++
+        colorder.push({pid: m.pid, pos: i})
+      }
+      var httpFormData = new FormData()
+      httpFormData.append('metadata', JSON.stringify({metadata: {members: colorder}}))      
+      fetch(self.instance.api + '/' + this.cmodel.toLowerCase() + '/' + self.pid + '/members/order', {
+        method: 'POST',
+        mode: 'cors',
+        headers: {
+          'X-XSRF-TOKEN': self.$store.state.user.token
+        },
+        body: httpFormData
+      })
+      .then(response => response.json())
+      .then(function (json) {
+        if (json.alerts && json.alerts.length > 0) {
+          if (json.status === 401) {
+            json.alerts.push({ type: 'danger', msg: 'Please log in' })
+          }
+          self.$store.commit('setAlerts', json.alerts)
+        }
+        self.loading = false
+        if (json.status === 200){
+          self.$emit('order-saved', self.pid)
+        }
+        self.$vuetify.goTo(0)
+      })
+      .catch(function (error) {
+        self.$store.commit('setAlerts', [{ type: 'danger', msg: error }])
+        self.loading = false
+        self.$vuetify.goTo(0)
+      })
+    }
+  }
+}
+</script>
diff --git a/src/components/search/Autocomplete.vue b/src/components/search/Autocomplete.vue
new file mode 100644
index 0000000000000000000000000000000000000000..571c9874e3ca3984a052486360232d212a8d5220
--- /dev/null
+++ b/src/components/search/Autocomplete.vue
@@ -0,0 +1,269 @@
+<template>
+  <div :class="`${getClassName('wrapper')} autocomplete-wrapper`">
+    <input
+      class="searchbox elevation-1"
+      ref="input"
+      type="text"
+      :id="id"
+      :class="`${getClassName('input')} autocomplete-input`"
+      :placeholder="placeholder"
+      :name="name"
+      v-model="type"
+      @input="handleInput"
+      @blur="handleBlur"
+      @keydown="handleKeyDown"
+      @focus="handleFocus"
+      autocomplete="off"
+    />
+    <div :class="`${getClassName('list')} autocomplete autocomplete-list elevation-2`" v-show="showList && suggestions && suggestions.length">
+      <v-list>
+        <v-list-tile v-for="(data, i) in suggestions" :class="activeClass(i)" :key="i" @click.prevent="selectList(data)">
+          <v-list-tile-content>
+            <v-list-tile-title v-html="data.term"></v-list-tile-title>
+          </v-list-tile-content>
+        </v-list-tile>
+      </v-list>
+    </div>
+  </div>
+</template>
+
+<script>
+import qs from 'qs'
+
+export default {
+  props: {
+    id: String,
+    name: String,
+    className: String,
+    classes: {
+      type: Object,
+      default: () => ({
+        wrapper: false,
+        input: false,
+        list: false,
+        item: false
+      })
+    },
+    placeholder: String,
+    required: Boolean,
+    
+    // Intial Value
+    initValue: {
+      type: String,
+      default: ''
+    },
+    
+    // Debounce time
+    debounce: Number,
+    
+    suggester: {
+      type: String,
+      required: true
+    },
+    
+    // minimum length
+    min: {
+      type: Number,
+      default: 0
+    },
+    
+    onSelect: Function
+  },
+  
+  data () {
+    return {
+      showList: false,
+      type: '',
+      focusList: '',
+      debounceTask: undefined,
+      suggestions: []
+    }
+  },
+  
+  computed: {
+    solr: function () { // TODO: pass in app settings
+      return this.$root.$store.state.settings.instance.solr
+    },
+  },
+  methods: {
+    getClassName (part) {
+      const { classes, className } = this
+      if (classes[part]) return `${classes[part]}`
+      return className ? `${className}-${part}` : ''
+    },
+    
+    // Netralize Autocomplete (XXX not used anywhere)
+    // clearInput () {
+    //   debugger
+    //   this.showList = false
+    //   this.type = ''
+    //   this.suggestions = []
+    //   this.focusList = ''
+    // },
+    
+    // Get the original data (TODO move to single used place)
+    cleanUp (data) {
+      return JSON.parse(JSON.stringify(data))
+    },
+    
+    handleInput (e) {
+      const { value } = e.target
+      this.showList = true
+      
+      // If Debounce
+      if (this.debounce) {
+        if (this.debounceTask !== undefined) clearTimeout(this.debounceTask)
+        this.debounceTask = setTimeout(() => {
+          return this.getData(value)
+        }, this.debounce)
+      } else {
+        return this.getData(value)
+      }
+    },
+    
+    handleKeyDown (e) {
+      let key = e.keyCode
+      
+      // Disable when list isn't showing up
+      if (!this.showList) return
+      
+      // Key List
+      const DOWN = 40
+      const UP = 38
+      const ENTER = 13
+      const ESC = 27
+      
+      // Prevent Default for Prevent Cursor Move & Form Submit
+      switch (key) {
+      case DOWN:
+        e.preventDefault()
+        this.focusList++
+        break
+      case UP:
+        e.preventDefault()
+        this.focusList--
+        break
+      case ENTER:
+        e.preventDefault()
+        if (this.focusList === 0) {
+          this.onSelect ? this.onSelect({ term: this.type }) : null
+        } else {
+          this.selectList(this.suggestions[this.focusList])
+        }
+        this.showList = false
+        break
+      case ESC:
+        this.showList = false
+        break
+      }
+      
+      const listLength = this.suggestions.length - 1
+      const outOfRangeBottom = this.focusList > listLength
+      const outOfRangeTop = this.focusList < 0
+      const topItemIndex = 0
+      const bottomItemIndex = listLength
+      
+      let nextFocusList = this.focusList
+      if (outOfRangeBottom) nextFocusList = topItemIndex
+      if (outOfRangeTop) nextFocusList = bottomItemIndex
+      this.focusList = nextFocusList
+    },
+    
+    // unused?
+    // setValue (val) { // TODO used anywhere?
+    //   debugger
+    //   this.type = val
+    // },
+    
+    handleBlur () {
+      setTimeout(() => {
+        this.showList = false
+      }, 250)
+    },
+    
+    handleFocus () {
+      this.focusList = 0
+    },
+    
+    // unused?
+    // mousemove (i) {
+    //   debugger
+    //   this.focusList = i
+    // },
+    
+    activeClass (i) {
+      const focusClass = i === this.focusList ? 'grey lighten-4' : ''
+      return `${focusClass}`
+    },
+    
+    selectList (data) {
+      // Deep clone of the original object
+      const clean = this.cleanUp(data)
+      // Put the selected data to type (model)
+      this.type = clean['payload']
+      // Hide List
+      this.showList = false
+      
+      this.onSelect ? this.onSelect(clean) : null
+    },
+    
+    getData (value) {
+      if (value.length < this.min || !this.suggester) return
+      this.suggest(value)
+    },
+    
+    async suggest (value) {
+      let params = {
+        suggest: true,
+        'suggest.dictionary': this.suggester,
+        wt: 'json',
+        'suggest.q': value
+      }
+      let query = qs.stringify(params)
+      
+      let response = await fetch(this.solr + '/suggest', {
+        method: 'POST',
+        mode: 'cors',
+        headers: {
+          'Content-Type': 'application/x-www-form-urlencoded'
+        },
+        body: query
+      })
+      let json = await response.json()
+      this.suggestions = json.suggest[this.suggester][value].suggestions
+    }
+  },
+  
+  created () {
+    // Sync parent model with initValue Props
+    this.type = this.initValue ? this.initValue : null
+  },
+
+  mounted () {
+    if (this.required)
+      this.$refs.input.setAttribute('required', this.required)
+  }
+}
+</script>
+
+<style scoped>
+.searchbox{
+  font-size: 14px;
+  box-sizing: border-box;
+  border: none;
+  box-shadow: none;
+  outline: 0;
+  background: 0 0;
+  width: 100%;
+  padding: 0 15px;
+  line-height: 40px;
+  height: 40px;
+}
+
+.autocomplete {
+  position: absolute;
+  z-index: 999;
+  margin-top: 2px;
+}
+
+</style>
diff --git a/src/components/search/PSearch.vue b/src/components/search/PSearch.vue
new file mode 100644
index 0000000000000000000000000000000000000000..d02bf5865d208f05410c7b830dd028d102db9b63
--- /dev/null
+++ b/src/components/search/PSearch.vue
@@ -0,0 +1,224 @@
+<template>
+    <v-layout row >
+      <v-flex xs9 class="border-right" pr-2>
+        <v-layout column>
+          <v-flex>
+            <autocomplete
+              placeholder="Search..."
+              name="autocomplete"
+              :initValue="q"
+              :suggester="'titlesuggester'"
+              :customParams="{ token: 'dev' }"
+              :classes="{ input: 'form-control', wrapper: 'input-wrapper'}"
+              :onSelect="handleSelect"
+            ></autocomplete>
+          </v-flex>
+          <v-flex xs12>
+            <v-layout row class="pt-3 pb-2">
+              <v-flex xs2><span>{{ total }} {{ $t('objects') }}</span></v-flex>
+              <v-spacer />
+              <v-flex xs4>
+                <search-toolbar
+                  :setSort="setSort"
+                  :sortIsActive="sortIsActive"
+                  :link="link" />
+              </v-flex>
+            </v-layout>
+            <v-flex v-if="inCollection" class="display-2 primary--text">{{ $t('Members of') }} {{ inCollection }} <icon name="material-navigation-close" class="primary--text" height="100%" @click.native="removeCollectionFilter()"></icon></v-flex>
+            <search-results :docs="docs"></search-results>
+            <v-flex class="text-xs-center">
+              <v-pagination
+                v-if="total>pagesize"
+                v-bind:length="totalPages"
+                total-visible="10"
+                v-model="page"
+                class="mb-3" />
+            </v-flex>
+          </v-flex>
+        </v-layout>
+      </v-flex>
+      <v-flex xs3 class="pa-2">
+        <h3 class="border-bottom display-2 pa-2 primary--text">Filters</h3>
+        <search-filters
+          :search="search"
+          :facetQueries="facetQueries"
+          :pers_authors="pers_authors"
+          :corp_authors="corp_authors"
+          :rolesProp="roles"
+          :ownerProp="owner"
+          ></search-filters>
+      </v-flex>
+    </v-layout>
+</template>
+
+<script>
+import qs from 'qs'
+import Autocomplete from './Autocomplete'
+import SearchResults from './SearchResults'
+import SearchFilters from './SearchFilters'
+import SearchToolbar from './SearchToolbar'
+import '@/compiled-icons/fontello-sort-name-up'
+import '@/compiled-icons/fontello-sort-name-down'
+import '@/compiled-icons/fontello-sort-number-up'
+import '@/compiled-icons/fontello-sort-number-down'
+import '@/compiled-icons/material-content-link'
+import '@/compiled-icons/material-action-bookmark'
+import { facetQueries, updateFacetQueries, pers_authors, corp_authors } from './facets'
+import { buildParams, buildSearchDef, sortdef } from './utils'
+import { setSearchParams } from './location'
+
+export default {
+  name: 'p-search',
+  components: {
+    Autocomplete,
+    SearchResults,
+    SearchFilters,
+    SearchToolbar
+  },
+  computed: {
+    page: {
+      get () {
+        return this.currentPage
+      },
+      set (value) {
+        this.currentPage = value
+        this.search()
+      }
+    },
+    totalPages: function () {
+      return Math.ceil(this.total / this.pagesize)
+    },
+    solr: function () { // TODO: pass in app settings
+      return this.$root.$store.state.settings.instance.solr
+    },
+  },
+  props: {
+    collection: {
+      type: String,
+      default: ''
+    }
+  },
+  methods: {
+    search: async function (options) {
+      // `options` are combined into the PSearch component. The later are sent
+      // over from child components: e.g. SearchFilters.
+      // This allows us the buildSearchDef/buildParams functions to pick out
+      // whatever properties they might need.
+      
+      // exclude 'collection' from above manipulation, since it's passed a prop
+      let { collection } = options || {}
+      if (collection) {
+        this.inCollection = collection
+        delete options.collection
+      }
+      
+      Object.assign(this, options)
+      
+      let { searchdefarr, ands } = buildSearchDef(this)
+      let params = buildParams(this, ands)
+      
+      this.link = location.protocol + '//' + location.host + '/#/search?' + searchdefarr.join('&')
+      window.history.replaceState(null, this.$t('Search results'), this.link)
+      
+      let query = qs.stringify(params, { encodeValuesOnly: true, indices: false })
+      let url = this.solr + '/select'
+      let response = await fetch(url, {
+        method: 'POST',
+        mode: 'cors',
+        headers: {
+          'Content-Type': 'application/x-www-form-urlencoded'
+        },
+        body: query
+      })
+      let json = await response.json()
+      this.docs = json.response.docs
+      this.total = json.response.numFound
+      this.facet_counts = json.facet_counts
+      window.scrollTo({
+        top: 0,
+        left: 0,
+        behavior: 'smooth'
+      });
+      updateFacetQueries(json.facet_counts.facet_queries, facetQueries)
+    },
+    handleSelect: function ({ term, payload }) {
+      // called from Autocomplete
+      // When an item has been clicked on explicitly - issue a quoted search on it's title,
+      // otherwise too many unrealted results are returned
+      this.q = payload ? `"${payload}"` : term
+      this.search()
+    },
+    setSort: function (sort) {
+      for (let i = 0; i < this.sortdef.length; i++) {
+        if (this.sortdef[i].id === sort) {
+          this.sortdef[i].active = !this.sortdef[i].active
+        } else {
+          this.sortdef[i].active = false
+        }
+      }
+      this.search()
+    },
+    sortIsActive: function (sort) {
+      for (let i = 0; i < this.sortdef.length; i++) {
+        if (this.sortdef[i].id === sort) {
+          return this.sortdef[i].active
+        }
+      }
+    },
+    removeCollectionFilter: function () {
+      this.inCollection = ''
+      this.search()
+    }
+  },
+  mounted: function () {
+    setSearchParams(this, this.$route.query)
+    
+    // This call is delayed because at this point
+    // `setInstanceSolr` has not yet been executed and
+    // the solr url is missing.
+    setTimeout(() => { this.search()} , 100)
+  },
+  watch: {
+    collection: function (col) { // used by demo app
+      this.inCollection = col
+      this.search()
+    }
+  },
+  data () {
+    return {
+      link: '',
+      linkdialog: false,
+      q: '',
+      inCollection: this.collection,
+      currentPage: 1,
+      pagesize: 10,
+      sortdef,
+      lang: 'en',
+      facetQueries,
+      
+      corp_authors,
+      pers_authors,
+      roles: [],
+      owner: '',
+      
+      docs: [],
+      total: 0,
+      facet_counts: null,
+    }
+  }
+}
+</script>
+
+<style scoped>
+.border-right {
+  border-right: 1px solid #bdbdbd;
+}
+
+.border-bottom {
+  border-bottom: 1px solid #bdbdbd;
+}
+
+svg {
+  cursor: pointer
+}
+</style>
diff --git a/src/components/search/SearchFilters.vue b/src/components/search/SearchFilters.vue
new file mode 100644
index 0000000000000000000000000000000000000000..ecc9b62416e257e5a555089a3049ed988590fecd
--- /dev/null
+++ b/src/components/search/SearchFilters.vue
@@ -0,0 +1,357 @@
+<template>
+  <v-container fluid grid-list-md>
+    <ul class="main-ul">
+      <li v-for="(f, i) in facetQueries" :key="i">
+        <icon @click.native="showFacet(f)" v-if="f.show" name="univie-stop2" class="primary--text"></icon>
+        <icon @click.native="showFacet(f)" v-if="!f.show" name="univie-checkbox-unchecked" class="primary--text"></icon>
+        <span @click="showFacet(f)" class="facet-label primary--text" :class="{ active: f.show }">{{ $t(f.label) }}</span>
+        <ul v-if="f.show">
+          <li v-for="(q, j) in f.queries" :key="j">
+            <span @click="toggleFacet(q,f)">
+              <icon v-if="q.active" name="univie-stop2" class="primary--text"></icon>
+              <icon v-if="!q.active" name="univie-checkbox-unchecked" class="primary--text"></icon>
+              <span :class="{ active: q.active }" class="facet-label primary--text">{{ $t(q.label) }}</span>
+              <span class="facet-count grey--text" v-if="q.count > 0">({{q.count}})</span>
+            </span>
+            <ul v-if="q.active && q.childFacet" >
+              <li v-for="(q1, k) in q.childFacet.queries" :key="k">
+                <span @click="toggleFacet(q1,q.childFacet)">
+                  <icon v-if="q1.active" name="univie-stop2" class="primary--text"></icon>
+                  <icon v-if="!q1.active" name="univie-checkbox-unchecked" class="primary--text"></icon>
+                  <span :class="{ active: q1.active }" class="facet-label primary--text">{{ $t(q1.label) }}</span>
+                  <span class="facet-count grey--text" v-if="q1.count > 0">({{q1.count}})</span>
+                </span>
+                <ul v-if="q1.active && q1.childFacet" >
+                  <li v-for="(q2, l) in q1.childFacet.queries" :key="l">
+                    <span @click="toggleFacet(q2,q1.childFacet)">
+                      <icon v-if="q2.active" name="univie-stop2" class="primary--text"></icon>
+                      <icon v-if="!q2.active" name="univie-checkbox-unchecked" class="primary--text"></icon>
+                      <span :class="{ active: q2.active }" class="facet-label primary--text">{{ $t(q2.label) }}</span>
+                      <span class="facet-count grey--text" v-if="q2.count>0">({{q2.count}})</span>
+                    </span>
+                  </li>
+                </ul>
+              </li>
+            </ul>
+          </li>
+        </ul>
+      </li>
+      <li>
+        <v-layout column>
+          <v-flex>
+            <v-layout row>
+              <v-flex>
+                <icon @click.native="toggleOwnerFilter()" v-if="showOwnerFilter" name="univie-stop2" class="primary--text"></icon>
+                <icon @click.native="toggleOwnerFilter()" v-if="!showOwnerFilter" name="univie-checkbox-unchecked" class="primary--text"></icon>
+                <span @click="toggleOwnerFilter()" class="facet-label primary--text" :class="{ active: showOwnerFilter }">{{ $t('Owner') }}</span>
+              </v-flex>
+            </v-layout>
+            <autocomplete
+              v-if="showOwnerFilter"
+              searchaction="search"
+              placeholder="Search..."
+              name="autocomplete"
+              :initValue="owner"
+              :suggester="'ownersuggester'"
+              :customParams="{ token: 'dev' }"
+              :classes="{ input: 'form-control', wrapper: 'input-wrapper'}"
+              :onSelect="handleOwnerSelect"
+            ></autocomplete>
+          </v-flex>
+        </v-layout>
+      </li>
+      <li>
+        <v-layout column>
+          <v-flex>
+            <v-layout row>
+              <v-flex>
+                <icon @click.native="toggleAuthorFilter()" v-if="showAuthorFilter" name="univie-stop2" class="primary--text"></icon>
+                <icon @click.native="toggleAuthorFilter()" v-if="!showAuthorFilter" name="univie-checkbox-unchecked" class="primary--text"></icon>
+                <span @click="toggleAuthorFilter()" class="facet-label primary--text" :class="{ active: showAuthorFilter }">{{ $t('Authors') }}</span>
+              </v-flex>
+            </v-layout>
+            <v-layout row v-if="showAuthorFilter">
+              <v-flex xs2>
+                <icon name="material-social-person" class="primary--text" height="100%"></icon>
+              </v-flex>
+              <v-flex xs10>
+                <v-combobox
+                  :placeholder="selectPlaceholder('pers_authors')"
+                  chips
+                  clearable
+                  multiple
+                  v-model="persAuthorsValues" />
+              </v-flex>
+            </v-layout>
+            <v-layout row v-if="showAuthorFilter">
+              <v-flex xs2>
+                <icon name="material-action-account-balance" class="primary--text" height="100%"></icon>
+              </v-flex>
+              <v-flex xs10>
+                <v-combobox
+                  :placeholder="selectPlaceholder('corp_authors')"
+                  chips
+                  clearable
+                  multiple
+                  v-model="corpAuthorsValues" />
+              </v-flex>
+            </v-layout>
+          </v-flex>
+        </v-layout>
+      </li>
+      <li>
+        <v-layout column>
+          <v-flex>
+            <v-layout row>
+              <v-flex>
+                <icon @click.native="toggleRoleFilter()" v-if="showRoleFilter" name="univie-stop2" class="primary--text"></icon>
+                <icon @click.native="toggleRoleFilter()" v-if="!showRoleFilter" name="univie-checkbox-unchecked" class="primary--text"></icon>
+                <span @click="toggleRoleFilter()" class="facet-label primary--text" :class="{ active: showRoleFilter }">{{ $t('Roles') }}</span>
+              </v-flex>
+            </v-layout>
+            <v-layout column v-if="showRoleFilter">
+              <v-select
+                :placeholder="$t('Add role') + '...'"
+                :hint="$t('Personal')"
+                :items="marcRolesArray"
+                v-model="selectedRole.pers"
+                @input="addRoleFilter('pers')"
+                :menu-props="{maxHeight:'400'}"
+                persistent-hint
+              ></v-select>
+              <v-select
+                :placeholder="$t('Add role') + '...'"
+                :hint="$t('Corporate')"
+                :items="marcRolesArray"
+                v-model="selectedRole.corp"
+                @input="addRoleFilter('corp')"
+                :menu-props="{maxHeight:'400'}"
+                persistent-hint
+              ></v-select>
+              <div v-for="(role, i) in roles" :key="i" v-if="roles.length > 0" >
+                <v-layout row>
+                  <v-flex xs2>
+                    <icon v-if="role.type==='pers'" name="material-social-person" class="primary--text" height="100%"></icon>
+                    <icon v-if="role.type==='corp'" name="material-action-account-balance" class="primary--text" height="100%"></icon>
+                  </v-flex>
+                  <v-flex xs8>
+                    <v-combobox
+                      :placeholder="$t('ADD_PREFIX') + ' '  + $t(role.label) + ' ' + $t('ADD_SUFFIX') + '...'"
+                      chips
+                      clearable
+                      multiple
+                      :items="role.values"
+                      v-model="role.values"
+                      @input="setRoleFilterValues(role)" />
+                  </v-flex>
+                  <v-flex xs2>
+                    <icon name="material-navigation-close" class="primary--text" height="100%" @click.native="removeRoleFilter(role)"></icon>
+                  </v-flex>
+                </v-layout>
+              </div>
+            </v-layout>
+
+          </v-flex>
+        </v-layout>
+      </li>
+    </ul>
+  </v-container>
+</template>
+
+<script>
+import Autocomplete from './Autocomplete'
+import '@/compiled-icons/univie-stop2'
+import '@/compiled-icons/univie-checkbox-unchecked'
+import '@/compiled-icons/material-action-account-balance'
+import '@/compiled-icons/material-social-person'
+import '@/compiled-icons/material-navigation-close'
+import { marcRoles } from './filters'
+import { toggleFacet, showFacet } from './facets'
+
+export default {
+  name: 'search-filters',
+  components: {
+    Autocomplete
+  },
+  computed: {
+    persAuthorsValues: {
+      get () {
+        return this.pers_authors.values()
+      },
+      set (values) {
+        this.pers_authors[0].values = values
+      }
+    },
+    corpAuthorsValues: {
+      get () {
+        return this.corp_authors.values()
+      },
+      set (values) {
+        // it seems chips are manipulating the array directly anyways
+        // maybe should provide own filtering function
+        this.corp_authors[0].values = values
+      }
+    }
+  },
+  props: {
+    search: {
+      type: Function,
+      required: true
+    },
+    facetQueries: {
+      type: Array,
+      required: true
+    },
+    pers_authors: {
+      type: Array,
+      required: true
+    },
+    corp_authors: {
+      type: Array,
+      required: true
+    },
+    rolesProp: {
+      type: Array,
+      required: true
+    },
+    ownerProp: {
+      type: String,
+      required: true
+    }
+  },
+  data () {
+    return {
+      showOwnerFilter: false,
+      showAuthorFilter: false,
+      showRoleFilter: false,
+      selectedRole: { pers: '', corp: '' },
+      marcRoles,
+      marcRolesArray: [],
+      roles: [],
+      owner: '',
+    }
+  },
+  methods: {
+    showFacet: function (f) {
+      showFacet(f)
+      this.search({ facetQueries: this.facetQueries })
+    },
+    toggleFacet: function (q, f) {
+      toggleFacet(q, f)
+      this.search({ page: 1, facetQueries: this.facetQueries })
+    },
+    handleOwnerSelect: function (query) {
+      this.owner = query.payload
+      this.search({ owner: this.owner })
+    },
+    toggleOwnerFilter: function () {
+      this.showOwnerFilter = !this.showOwnerFilter
+      if (!this.showOwnerFilter) {
+        this.owner = '' // TODO change '' to null whereever it's used
+        this.search({ owner: this.owner }) // TODO: should this be in if clause?
+      }
+    },
+    toggleAuthorFilter: function () {
+      this.showAuthorFilter = !this.showAuthorFilter
+      if (!this.showAuthorFilter) {
+        this.pers_authors[0].values = []
+        this.corp_authors[0].values = []
+        this.search({ pers_authors: this.pers_authors, corp_authors: this.corp_authors }) // TODO: should this be in if clause?
+      }
+    },
+    toggleRoleFilter: function () {
+      this.showRoleFilter = !this.showRoleFilter
+      if (!this.showRoleFilter) {
+        this.roles = []
+      }
+      this.search({ roles: this.roles })
+    },
+    addRoleFilter: function (type) {
+      if (this.selectedRole[type]) {
+        this.roles.push({
+          field: 'bib_roles_' + type + '_' + this.selectedRole[type],
+          label: this.$t(this.marcRoles[this.selectedRole[type]]),
+          values: [],
+          type: type
+        })
+      }
+    },
+    removeRoleFilter: function (role) {
+      this.roles.splice(this.roles.indexOf(role), 1)
+      this.search({ roles: this.roles })
+    },
+    setRoleFilterValues: function (role) {
+      this.roles[this.roles.indexOf(role)].values = role.values
+      this.search({ roles: this.roles })
+    },
+    removeRoleFilterValue: function (role, value) {
+      this.roles[this.roles.indexOf(role)].values.splice(this.roles[this.roles.indexOf(role)].values.indexOf(value), 1)
+      this.search({ roles: this.roles })
+    },
+    selectPlaceholder: function (source) {
+      let label = ''
+      if (this[source].length) {
+        label = this[source][0].label
+      } else {
+        console.warn(`Label for ${source} not found`, this[source]) // eslint-disable-line no-console
+      }
+      return this.$t('ADD_PREFIX') + ' ' +
+        this.$t(label) + ' ' +
+        this.$t('ADD_SUFFIX') + '...'
+    }
+  },
+  mounted () {
+    for (let role in this.marcRoles) {
+      this.marcRolesArray.push({ value: role, text: this.$t(this.marcRoles[role]) })
+    }
+  },
+  watch: {
+    rolesProp: function (v) {
+      this.roles = v
+      if (v.length) {
+        this.showRoleFilter = true
+      }
+    },
+    ownerProp: function (v) {
+      this.owner = v
+      if (v.length) {
+        this.showOwnerFilter = true
+      }
+    },
+    pers_authors: function (v) {
+      if (v[0].values.length) {
+        this.showAuthorFilter = true
+        // this.selectedRole.pers // TODO might need something like this
+      }
+    },
+    corp_authors: function (v) {
+      if (v[0].values.length) {
+        this.showAuthorFilter = true
+      }
+    },
+  }
+}
+</script>
+
+<style lang="stylus" scoped>
+.container
+  padding-top: 1em
+  padding-left: 0
+
+ul
+  list-style: none
+  padding-left: 1em
+
+.facet-label
+  cursor: pointer
+
+.facet-count
+  margin-left: 5px
+
+svg
+  margin-bottom: 3px
+  cursor: pointer
+
+svg.primary--text
+  margin-right: 4px
+</style>
diff --git a/src/components/search/SearchResults.vue b/src/components/search/SearchResults.vue
new file mode 100644
index 0000000000000000000000000000000000000000..193e903aee834506309b8e2e7284f8d0917c6de3
--- /dev/null
+++ b/src/components/search/SearchResults.vue
@@ -0,0 +1,149 @@
+<template>
+  <v-container fluid grid-list-lg>
+    <v-layout column>
+      <v-flex xs12>
+        <v-expansion-panel popout expand>
+          <v-expansion-panel-content
+            v-for="(doc) in this.docs"
+            :key="doc.pid"
+            v-model="doc.showMore"
+          >
+            <div slot="header">
+              <v-card flat>
+                <v-container fluid grid-list-lg pa-3>
+                  <v-layout column>
+                    <v-layout row>
+                      <v-flex xs2>
+                        <p-img
+                          :src="'https://' + instance.baseurl + '/preview/' + doc.pid + '///120'"
+                          class="elevation-1"
+                        >
+                          <v-layout slot="placeholder" fill-height align-center justify-center ma-0>
+                            <v-progress-circular indeterminate color="grey lighten-5"></v-progress-circular>
+                          </v-layout>
+                        </p-img>
+                      </v-flex>
+                      <v-flex xs9>
+                        <v-layout column>
+                          <v-card-title primary-title>
+                            <v-container fluid>
+                              <v-layout row>
+                                <v-flex xs10>
+                                  <h3 class="display-2" @click.stop v-if="doc.dc_title">
+                                    <router-link
+                                      :to="{ name: 'detail', params: { pid: doc.pid } }"
+                                    >{{ doc.dc_title[0] }}</router-link>
+                                  </h3>
+                                  <v-spacer></v-spacer>
+                                </v-flex>
+                                <v-flex xs2 class="text-xs-right">
+                                  <span
+                                    v-if="doc.created"
+                                    class="grey--text"
+                                  >{{ doc.created | date }}</span>
+                                </v-flex>
+                              </v-layout>
+                            </v-container>
+                          </v-card-title>
+                          <v-card-text>
+                            <v-layout column>
+                              <v-flex>
+                                <span>
+                                  <span v-for="(aut,i) in doc.bib_roles_pers_aut" :key="'pers'+i">
+                                    {{aut}}
+                                    <span v-if="(i+1) < doc.bib_roles_pers_aut.length">;</span>
+                                  </span>
+                                  <span v-for="(aut,i) in doc.bib_roles_corp_aut" :key="'corp'+i">
+                                    {{aut}}
+                                    <span v-if="(i+1) < doc.bib_roles_corp_aut.length">;</span>
+                                  </span>
+                                </span>
+                              </v-flex>
+                            </v-layout>
+                          </v-card-text>
+                          <v-spacer></v-spacer>
+                        </v-layout>
+                      </v-flex>
+                    </v-layout>
+                  </v-layout>
+                </v-container>
+              </v-card>
+            </div>
+            <!--header -->
+            <v-container fluid grid-list-lg pa-3>
+              <v-layout column>
+                <v-flex
+                  v-if="doc.dc_description"
+                  class="search-description pb-3"
+                >{{ doc.dc_description[0] }}</v-flex>
+                <v-flex class="text-xs-right">
+                  <!--<v-btn :to="{ name: 'detail', params: { pid: doc.pid } }" raised>{{ $t('Details') }}</v-btn>-->
+                  <v-btn
+                    :href="instance.api + '/object/' + doc.pid + '/diss/Content/get'"
+                    primary
+                  >{{ $t('View') }}</v-btn>
+                  <v-btn
+                    :href="instance.api + '/object/' + doc.pid + '/diss/Content/download'"
+                    primary
+                  >{{ $t('Download') }}</v-btn>
+                </v-flex>
+                <v-flex class="pt-3">
+                  <v-layout row>
+                    <v-flex>
+                      <p-d-license class="pa-0" v-if="doc.dc_license" :o="doc.dc_license[0]"></p-d-license>
+                    </v-flex>
+                    <v-spacer></v-spacer>
+                    <v-flex class="text-xs-right">
+                      <span class="grey--text">https://{{ instance.baseurl }}/{{ doc.pid }}</span>
+                    </v-flex>
+                  </v-layout>
+                </v-flex>
+              </v-layout>
+            </v-container>
+          </v-expansion-panel-content>
+        </v-expansion-panel>
+      </v-flex>
+    </v-layout>
+  </v-container>
+</template>
+
+<script>
+import PDLicense from "../display/phaidra_display/PDLicense";
+import PImg from "../utils/PImg";
+
+export default {
+  name: "search-results",
+  components: {
+    PDLicense,
+    PImg
+  },
+  props: {
+    docs: {
+      type: Array
+    }
+  },
+  computed: {
+    instance() {
+      return this.$store.state.settings.instance;
+    }
+  }
+};
+</script>
+
+<style scoped>
+.card__title--primary {
+  padding-top: 10px;
+}
+
+.search-description {
+  white-space: pre-wrap;
+}
+
+.card__text {
+  padding-top: 0px;
+}
+
+.container {
+  padding: 0;
+}
+</style>
diff --git a/src/components/search/SearchToolbar.vue b/src/components/search/SearchToolbar.vue
new file mode 100644
index 0000000000000000000000000000000000000000..4b3da7d6ee05c5baeff54112db544b55a5c13a07
--- /dev/null
+++ b/src/components/search/SearchToolbar.vue
@@ -0,0 +1,78 @@
+<template lang="html">
+  <v-container class="toolbar" grid-list-md>
+    <v-layout row wrap>
+      <v-flex>
+        <v-tooltip bottom>
+          <icon @click.native="setSort('title asc')" name="fontello-sort-name-up" :color="sortIsActive('title asc') ? '#1A74B0' : '#777777'" slot="activator"></icon>
+          <span>{{ $t('Title ascending')}}</span>
+        </v-tooltip>
+      </v-flex>
+      <v-flex>
+        <v-tooltip bottom>
+          <icon @click.native="setSort('title desc')" name="fontello-sort-name-down" :color="sortIsActive('title desc') ? '#1A74B0' : '#777777'" slot="activator"></icon>
+          <span>{{ $t('Title descending')}}</span>
+        </v-tooltip>
+      </v-flex>
+      <v-flex>
+        <v-tooltip bottom>
+          <icon @click.native="setSort('created asc')" name="fontello-sort-number-up" :color="sortIsActive('created asc') ? '#1A74B0' : '#777777'" slot="activator"></icon>
+          <span>{{ $t('Upload date ascending')}}</span>
+        </v-tooltip>
+      </v-flex>
+      <v-flex>
+        <v-tooltip bottom>
+          <icon @click.native="setSort('created desc')" name="fontello-sort-number-down" :color="sortIsActive('created desc') ? '#1A74B0' : '#777777'" slot="activator"></icon>
+          <span>{{ $t('Upload date descending')}}</span>
+        </v-tooltip>
+      </v-flex>
+      <v-flex>
+        <v-dialog v-model="linkdialog" max-width="800px">
+          <v-card>
+            <v-card-title>
+              <h3 class="display-2">{{ $t('Link to search results') }}</h3>
+            </v-card-title>
+            <v-card-text>{{ link }}</v-card-text>
+            <v-card-actions>
+              <v-spacer></v-spacer>
+              <v-btn color="primary" flat @click.stop="linkdialog=false">Close</v-btn>
+            </v-card-actions>
+          </v-card>
+        </v-dialog>
+        <v-tooltip bottom>
+          <icon @click.native="linkdialog=true" name="material-content-link" slot="activator"></icon>
+          <span>{{ $t('Link to search results')}}</span>
+        </v-tooltip>
+      </v-flex>
+    </v-layout>
+  </v-container>
+</template>
+
+<script>
+export default  {
+  name: 'search-toolbar',
+  props: {
+    setSort: {
+      type: Function,
+      required: true
+    },
+    sortIsActive: {
+      type: Function,
+      required: true
+    },
+    link: {
+      type: String
+    }
+  },
+  data() {
+    return {
+      linkdialog: false
+    }
+  }
+}
+</script>
+
+<style scoped>
+.container .toolbar {
+  padding: 0px;
+}
+</style>
diff --git a/src/components/search/facets.js b/src/components/search/facets.js
new file mode 100644
index 0000000000000000000000000000000000000000..4df7f0def4e9c0e2a442bfd2782a6ab0a809dd49
--- /dev/null
+++ b/src/components/search/facets.js
@@ -0,0 +1,340 @@
+import Vue from 'vue'
+
+export const facetQueries = [
+  {
+    label: 'Access',
+    field: 'datastreams',
+    id: 'datastreams',
+    exclusive: 1,
+    show: 0,
+    queries: [
+      {
+        id: 'restricted',
+        query: 'datastreams:POLICY',
+        label: 'Restricted'
+      },
+      {
+        id: 'unrestricted',
+        query: '-datastreams:POLICY',
+        label: 'Unrestricted'
+      }
+    ]
+  },
+  {
+    label: 'Type',
+    field: 'resourcetype',
+    id: 'resourcetype',
+    show: 1,
+    queries: [
+      {
+        id: 'image',
+        query: 'resourcetype:image',
+        label: 'Image'
+      },
+      {
+        id: 'book',
+        query: 'resourcetype:book',
+        label: 'Book'
+      },
+      {
+        id: 'article',
+        query: 'resourcetype:journalarticle',
+        label: 'Article'
+      },
+      {
+        id: 'text',
+        query: 'resourcetype:text',
+        label: 'Text'
+      },
+      {
+        id: 'collection',
+        query: 'resourcetype:collection',
+        label: 'Collection'
+      },
+      {
+        id: 'video',
+        query: 'resourcetype:video',
+        label: 'Video'
+      },
+      {
+        id: 'other',
+        query: 'resourcetype:other',
+        label: 'Data'
+      },
+      {
+        id: 'dataset',
+        query: 'resourcetype:dataset',
+        label: 'Container'
+      },
+      {
+        id: 'map',
+        query: 'resourcetype:map',
+        label: 'Map'
+      },
+      {
+        id: 'resource',
+        query: 'resourcetype:interactiveresource',
+        label: 'Resource'
+      },
+      {
+        id: 'sound',
+        query: 'resourcetype:sound',
+        label: 'Sound'
+      }
+    ]
+  },
+  {
+    label: 'Size',
+    field: 'tsize',
+    id: 'size',
+    show: 0,
+    queries: [
+      {
+        id: 'less10',
+        query: 'tsize:[0 TO 10485760]',
+        label: 'less 10MB'
+      },
+      {
+        id: '10to50',
+        query: 'tsize:[10485760 TO 52428800]',
+        label: '10MB - 50MB'
+      },
+      {
+        id: '50to100',
+        query: 'tsize:[52428800 TO 104857600]',
+        label: '50MB - 100MB'
+      },
+      {
+        id: '100to200',
+        query: 'tsize:[104857600 TO 209715200]',
+        label: '100MB - 200MB'
+      },
+      {
+        id: '200to500',
+        query: 'tsize:[209715200 TO 524288000]',
+        label: '200MB - 500MB'
+      },
+      {
+        id: '500to1000',
+        query: 'tsize:[524288000 TO 1073741824]',
+        label: '500MB - 1GB'
+      },
+      {
+        id: 'more1000',
+        query: 'tsize:[1073741824 TO *]',
+        label: 'more 1GB'
+      }
+    ]
+  },
+  {
+    label: 'License',
+    field: 'dc_license',
+    id: 'license',
+    show: 0,
+    queries: [
+      {
+        id: 'all-rights-reserved',
+        query: 'dc_license:\'All rights reserved\'',
+        label: 'All rights reserved'
+      },
+      {
+        id: 'gplv3',
+        query: 'dc_license:\'GPLv3\'',
+        label: 'GPLv3'
+      },
+      {
+        id: 'pdm',
+        query: 'dc_license:\'Public Domain Mark\'',
+        label: 'Public Domain Mark'
+      },
+      {
+        id: 'cc-by',
+        query: '(dc_license:\'CC BY 2.0 AT\' OR dc_license:\'CC BY 2.0 Generic\' OR dc_license:\'CC BY 3.0 AT\' OR dc_license:\'CC BY 3.0 Unported\' OR dc_license:\'CC BY 4.0 International\')',
+        label: 'CC BY'
+      },
+      {
+        id: 'cc-by-sa',
+        query: '(dc_license:\'CC BY-SA 2.0 AT\' OR dc_license:\'CC BY-SA 2.0 Generic\' OR dc_license:\'CC BY-SA 3.0 AT\' OR dc_license:\'CC BY-SA 3.0 Unported\' OR dc_license:\'CC BY-SA 4.0 International\')',
+        label: 'CC BY-SA'
+      },
+      {
+        id: 'cc-by-nc',
+        query: '(dc_license:\'CC BY-NC 2.0 AT\' OR dc_license:\'CC BY-NC 2.0 Generic\' OR dc_license:\'CC BY-NC 3.0 AT\' OR dc_license:\'CC BY-NC 3.0 Unported\' OR dc_license:\'CC BY-NC 4.0 International\')',
+        label: 'CC BY-NC'
+      },
+      {
+        id: 'cc-by-nd',
+        query: '(dc_license:\'CC BY-ND 2.0 AT\' OR dc_license:\'CC BY-ND 2.0 Generic\' OR dc_license:\'CC BY-ND 3.0 AT\' OR dc_license:\'CC BY-ND 3.0 Unported\' OR dc_license:\'CC BY-ND 4.0 International\')',
+        label: 'CC BY-ND'
+      },
+      {
+        id: 'cc-by-nc-sa',
+        query: '(dc_license:\'CC BY-NC-SA 2.0 AT\' OR dc_license:\'CC BY-NC-SA 2.0 Generic\' OR dc_license:\'CC BY-NC-SA 3.0 AT\' OR dc_license:\'CC BY-NC-SA 3.0 Unported\' OR dc_license:\'CC BY-NC-SA 4.0 International\')',
+        label: 'CC BY-NC-SA'
+      },
+      {
+        id: 'cc-by-nc-nd',
+        query: '(dc_license:\'CC BY-NC-ND 2.0 AT\' OR dc_license:\'CC BY-NC-ND 2.0 Generic\' OR dc_license:\'CC BY-NC-ND 3.0 AT\' OR dc_license:\'CC BY-NC-ND 3.0 Unported\' OR dc_license:\'CC BY-NC-ND 4.0 International\')',
+        label: 'CC BY-NC-ND'
+      }
+    ]
+  }
+]
+
+function buildDateFacet() {
+  let months31 = [1, 3, 5, 7, 8, 10, 12]
+  let months30 = [4, 6, 9, 11]
+  let startYear = 2008
+  let currYear = new Date().getFullYear()
+  let yearsFacet = {
+    label: 'Date',
+    field: 'tcreated',
+    id: 'created',
+    show: 0,
+    queries: []
+  }
+
+  for (let year = startYear; year <= currYear; year++) {
+    let monthsFacet = {
+      label: 'Months of ' + year,
+      field: 'tcreated',
+      id: 'months-' + year,
+      queries: []
+    }
+
+    for (let month = 1; month <= 12; month++) {
+      let daysOfMonth
+      if (months30.indexOf(month) > -1) {
+        daysOfMonth = 30
+      } else {
+        if (months31.indexOf(month) > -1) {
+          daysOfMonth = 31
+        } else {
+          let isLeap = ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)
+          if (isLeap) {
+            daysOfMonth = 29
+          } else {
+            daysOfMonth = 28
+          }
+        }
+      }
+
+      let daysFacet = {
+        label: 'Days of ' + month + '.' + year,
+        field: 'tcreated',
+        id: 'days-' + year + '-' + month,
+        queries: []
+      }
+
+      for (let day = 1; day <= daysOfMonth; day++) {
+        if (day < 10) {
+          day = '0' + day
+        }
+        daysFacet.queries.push({
+          query: 'tcreated:[' + year + '-' + month + '-' + day + 'T00:00:00Z TO ' + year + '-' + month + '-' + day + 'T23:59:59Z]',
+          id: year + '-' + month + '-' + day,
+          label: day + '.' + month + '.' + year
+        })
+      }
+
+      monthsFacet.queries.push({
+        query: 'tcreated:[' + year + '-' + month + '-01T00:00:00Z TO ' + year + '-' + month + '-' + daysOfMonth + 'T00:00:00Z]',
+        id: year + '-' + month,
+        label: month + '.' + year,
+        childFacet: daysFacet
+      })
+    }
+
+    yearsFacet.queries.push({
+      query: 'tcreated:[' + year + '-01-01T00:00:00Z TO ' + year + '-12-31T00:00:00Z]',
+      id: year,
+      label: year,
+      childFacet: monthsFacet
+    })
+  }
+
+  return yearsFacet
+}
+
+// TODO: FIXME
+export function updateFacetQueries (facet_queries, facetQueries) {
+  // called by the `search` function
+  Object.keys(facet_queries).forEach(function (key) {
+    for (let i = 0; i < facetQueries.length; i++) {
+      for (let j = 0; j < facetQueries[i].queries.length; j++) {
+        if (facetQueries[i].queries[j].query === key) {
+          Vue.set(facetQueries[i].queries[j], 'count', facet_queries[key])
+        }
+        if (facetQueries[i].queries[j].childFacet) {
+          let lvl1 = facetQueries[i].queries[j].childFacet
+          for (let k = 0; k < lvl1.queries.length; k++) {
+            if (lvl1.queries[k].query === key) {
+              Vue.set(lvl1.queries[k], 'count', facet_queries[key])
+            }
+            if (lvl1.queries[k].childFacet) {
+              let lvl2 = lvl1.queries[k].childFacet
+              for (let l = 0; l < lvl2.queries.length; l++) {
+                if (lvl2.queries[l].query === key) {
+                  Vue.set(lvl2.queries[l], 'count', facet_queries[key])
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  })
+}
+
+export function toggleFacet (q, f) {
+  q.active = !q.active
+
+  if (f.exclusive) {
+    for (let i = 0; i < f.queries.length; i++) {
+      if (f.queries[i] !== q) {
+        f.queries[i].active = 0
+      }
+    }
+  }
+}
+
+export function showFacet (f) {
+  f.show = !f.show
+
+  if (!f.show) {
+    // when hiding facet, remove it's filters
+    for (var i = 0; i < f.queries.length; i++) {
+      f.queries[i].active = false;
+      if(f.queries[i].childFacet){
+        var lvl1 = f.queries[i].childFacet;
+        for (var j = 0; j < lvl1.queries.length; j++) {
+          lvl1.queries[j].active = false;
+          if(lvl1.queries[j].childFacet){
+            var lvl2 = lvl1.queries[j].childFacet;
+            for (var k = 0; k < lvl2.queries.length; k++) {
+              lvl2.queries[k].active = false;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+export const pers_authors = [
+  {
+    field: 'bib_roles_pers_aut',
+    label: 'Author',
+    values: []
+  }
+]
+
+export const corp_authors = [
+  {
+    field: 'bib_roles_corp_aut',
+    label: 'Author',
+    values: []
+  }
+]
+
+facetQueries.push(buildDateFacet())
diff --git a/src/components/search/filters.js b/src/components/search/filters.js
new file mode 100644
index 0000000000000000000000000000000000000000..97ae693410b8d085e81dbf969c963bba93867178
--- /dev/null
+++ b/src/components/search/filters.js
@@ -0,0 +1,106 @@
+// facetLabels: {
+//   datastreams: 'Access',
+//   resourcetype: 'Resource type',
+//   dc_license: 'License',
+//   tcreated: 'Created',
+//   tsize: 'Size'
+// },
+// resourcetypeLabels: {
+//   image: 'Image',
+//   book: 'Book',
+//   journalarticle: 'Journal article',
+//   text: 'Text',
+//   collection: 'Collection',
+//   video: 'Video',
+//   other: 'Other',
+//   dataset: 'Dataset',
+//   map: 'Map',
+//   interactiveresource: 'Resource',
+//   sound: 'Sound'
+// },
+export const marcRoles = {
+  'initiator': 'Initiator',
+  'evaluator': 'Evaluator',
+  'technicalinspector': 'Technical inspector',
+  'textprocessor': 'Textprocessor',
+  'pedagogicexpert': 'Pedagogic expert',
+  'interpreter': 'Interpreter',
+  'digitiser': 'Digitiser',
+  'keeperoftheoriginal': 'Keeper of the original',
+  'adviser': 'Adviser',
+  'degreegrantor': 'Degree grantor',
+  'uploader': 'Uploader',
+  'dtc': 'Data contributor',
+  // 'aut': 'Author', has a separate input box
+  'pbl': 'Publisher',
+  'edt': 'Editor',
+  'dsr': 'Designer',
+  'trl': 'Translator',
+  'exp': 'Expert',
+  'oth': 'Other',
+  'art': 'Artist',
+  'dnr': 'Donor',
+  'pht': 'Photographer',
+  'jud': 'Judge',
+  'prf': 'Performer',
+  'wde': 'Wood engraver',
+  'rce': 'Recording engineer',
+  'sce': 'Scenarist',
+  'ths': 'Thesis advisor',
+  'sds': 'Sound designer',
+  'lyr': 'Lyricist',
+  'ilu': 'Illuminator',
+  'eng': 'Engineer',
+  'cnd': 'Conductor',
+  'dto': 'Dedicator',
+  'opn': 'Opponent',
+  'cmp': 'Composer',
+  'ctg': 'Cartographer',
+  'dub': 'Dubious author',
+  'wam': 'Writer of accompanying material',
+  'arc': 'Architect',
+  'vdg': 'Videographer',
+  'scl': 'Sculptor',
+  'aus': 'Screenwriter',
+  'own': 'Owner',
+  'fmo': 'Former owner',
+  'mus': 'Musician',
+  'ive': 'Interviewee',
+  'ill': 'Illustrator',
+  'cng': 'Cinematographer',
+  'dte': 'Dedicatee',
+  'sad': 'Scientific advisor',
+  'mte': 'Metal-engraver',
+  'arr': 'Arranger',
+  'etr': 'Etcher',
+  'dis': 'Dissertant',
+  'prt': 'Printer',
+  'flm': 'Film editor',
+  'rev': 'Reviewer',
+  'pro': 'Producer',
+  'att': 'Attributed name',
+  'lbt': 'Librettist',
+  'ivr': 'Interviewer',
+  'egr': 'Engraver',
+  'msd': 'Musical director',
+  'ard': 'Artistic director',
+  'chr': 'Choreographer',
+  'com': 'Compiler',
+  'sng': 'Singer',
+  'act': 'Actor',
+  'adp': 'Adapter'
+}
+
+export function getMarcRoleLabel (r) {
+  // if possible, return label directly
+  if (marcRoles[r]) return marcRoles[r]
+
+  // try to use the last element for lookup, e.g. from 'bib_roles_pers_uploader'
+  // extracts 'Uploader'
+  let splitted = r.split('_')
+  if (splitted.length) {
+    let last = splitted[splitted.length - 1]
+    return marcRoles[last] || r
+  }
+}
+
diff --git a/src/components/search/location.js b/src/components/search/location.js
new file mode 100644
index 0000000000000000000000000000000000000000..44ea1f27fb77cad1c87921d032fbbdf02638dbd6
--- /dev/null
+++ b/src/components/search/location.js
@@ -0,0 +1,110 @@
+import { getMarcRoleLabel } from './filters'
+
+export function setSearchParams (self, { q, page, pagesize, sortdef, owner, collection, fq, fr }) {
+  if (q) {
+    self.q = q
+  }
+
+  if (page) {
+    self.currentPage = parseInt(page)
+  }
+
+  if (pagesize) {
+    self.pagesize = parseInt(pagesize)
+  }
+
+  if (sortdef) {
+    for (let i = 0; i < self.sortdef.length; i++) {
+      if (self.sortdef[i].id === sortdef) {
+        self.sortdef[i].active = true
+      }
+    }
+  }
+
+  if (owner) {
+    self.owner = owner
+    // SearchFilters.watch will set "showOwnerFilter = true"
+  }
+
+  if (collection) {
+    self.inCollection = collection
+  }
+
+  if (fq) {
+    if (typeof fq === 'string') {
+      fq = [fq]
+    }
+    for (let n = 0; n < fq.length; n++) {
+      let fqa = fq[n].split('_')
+      let facetId = fqa[0]
+      let queryId = fqa[1]
+      for (let j = 0; j < self.facetQueries.length; j++) {
+        if (self.facetQueries[j].id === facetId) {
+          self.facetQueries[j].show = 1
+          for (let k = 0; k < self.facetQueries[j].queries.length; k++) {
+            if (self.facetQueries[j].queries[k].id === queryId) {
+              self.facetQueries[j].queries[k].active = 1
+            }
+            if (self.facetQueries[j].queries[k].childFacet) {
+              let lvl1 = self.facetQueries[j].queries[k].childFacet
+              for (let l = 0; l < lvl1.queries.length; l++) {
+                if (lvl1.queries[l].id === queryId) {
+                  lvl1.queries[l].active = 1
+                  self.facetQueries[j].queries[k].active = 1
+                }
+                if (lvl1.queries[l].childFacet) {
+                  let lvl2 = lvl1.queries[l].childFacet
+                  for (let m = 0; m < lvl2.queries.length; m++) {
+                    if (lvl2.queries[m].id === queryId) {
+                      lvl2.queries[m].active = 1
+                      lvl1.queries[l].active = 1
+                      self.facetQueries[j].queries[k].active = 1
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  if (fr) {
+    if (typeof fr === 'string') {
+      fr = [fr]
+    }
+    let roles = {}
+    for (let o = 0; o < fr.length; o++) {
+      let idx = fr[o].lastIndexOf('_')
+      let role = fr[o].substring(0, idx)
+      let value = fr[o].substring(idx + 1)
+
+      if (roles[role]) {
+        roles[role].values.push(value)
+      } else {
+        roles[role] = { values: [value] }
+      }
+    }
+
+    Object.keys(roles).forEach(function (role) {
+      if (role === 'bib_roles_pers_aut') {
+        self.pers_authors[0].values = roles[role].values
+        // SearchFilters.watch will set "showAuthorFilter = true"
+      } else {
+        if (role === 'bib_roles_corp_aut') {
+          self.corp_authors[0].values = roles[role].values
+          // SearchFilters.watch will set "showAuthorFilter = true"
+        } else {
+          self.roles.push({
+            field: role,
+            label: getMarcRoleLabel(role),
+            values: roles[role].values,
+            type: role.includes('_pers_') ? 'pers' : 'corp'
+          })
+          // SearchFilters.watch will set "showRoleFilter = true"
+        }
+      }
+    })
+  }
+}
diff --git a/src/components/search/utils.js b/src/components/search/utils.js
new file mode 100644
index 0000000000000000000000000000000000000000..03c2720e18d7474c44fad9da1b770145ec4a9229
--- /dev/null
+++ b/src/components/search/utils.js
@@ -0,0 +1,205 @@
+export function buildSearchDef({ sortdef, q, page, pagesize, facetQueries, corp_authors, pers_authors, roles, owner, inCollection: collection }) {
+  let searchdefarr = []
+
+  for (let i = 0; i < sortdef.length; i++) {
+    if (sortdef[i].active) {
+      searchdefarr.push('sortdef=' + window.encodeURIComponent(sortdef[i].id))
+    }
+  }
+
+  if (q) {
+    searchdefarr.push('q=' + window.encodeURIComponent(q))
+  }
+  searchdefarr.push('page=' + page)
+  if (pagesize) {
+    searchdefarr.push('pagesize=' + pagesize)
+  }
+
+  let ands = []
+  for (let i = 0; i < facetQueries.length; i++) {
+    let ors = []
+    for (let j = 0; j < facetQueries[i].queries.length; j++) {
+      if (facetQueries[i].queries[j].active) {
+        // tag '{!tag=' + state.facetQueries[i].id + '}' +
+        if (facetQueries[i].queries[j].childFacet) {
+          // there are two levels, only take the lowest active levels
+          let lvl1 = facetQueries[i].queries[j].childFacet
+          let foundActiveLvl1Query = false
+          for (let k = 0; k < lvl1.queries.length; k++) {
+            if (lvl1.queries[k].active) {
+              foundActiveLvl1Query = true
+
+              let lvl2 = lvl1.queries[k].childFacet
+              let foundActiveLvl2Query = false
+              for (let l = 0; l < lvl2.queries.length; l++) {
+                if (lvl2.queries[l].active) {
+                  foundActiveLvl2Query = true
+                  ors.push(lvl2.queries[l].query)
+                  searchdefarr.push('fq=' + facetQueries[i].id + '_' + lvl2.queries[l].id)
+                }
+              }
+
+              if (!foundActiveLvl2Query) {
+                ors.push(lvl1.queries[k].query)
+                searchdefarr.push('fq=' + facetQueries[i].id + '_' + lvl1.queries[k].id)
+              }
+            }
+          }
+
+          if (!foundActiveLvl1Query) {
+            ors.push(facetQueries[i].queries[j].query)
+            searchdefarr.push('fq=' + facetQueries[i].id + '_' + facetQueries[i].queries[j].id)
+          }
+        } else {
+          ors.push(facetQueries[i].queries[j].query)
+          searchdefarr.push('fq=' + facetQueries[i].id + '_' + facetQueries[i].queries[j].id)
+        }
+      }
+    }
+    if (ors.length > 0) {
+      if (ors.length > 1) {
+        ands.push('(' + ors.join(' OR ') + ')')
+      } else {
+        ands.push(ors[0])
+      }
+    }
+  }
+
+  for (let i = 0; i < corp_authors.length; i++) {
+    let field = corp_authors[i]
+    for (let j = 0; j < field.values.length; j++) {
+      let v = field.values[j]
+      if (v !== '') {
+        ands.push('(' + field.field + ':"' + v + '")')
+        searchdefarr.push('fr=' + field.field + '_' + window.encodeURIComponent(v))
+      }
+    }
+  }
+
+  for (let i = 0; i < pers_authors.length; i++) {
+    let field = pers_authors[i]
+    for (let j = 0; j < field.values.length; j++) {
+      let v = field.values[j]
+      if (v !== '') {
+        ands.push('(' + field.field + ':"' + v + '")')
+        searchdefarr.push('fr=' + field.field + '_' + window.encodeURIComponent(v))
+      }
+    }
+  }
+
+  for (let i = 0; i < roles.length; i++) {
+    let field = roles[i]
+    for (let j = 0; j < field.values.length; j++) {
+      let v = field.values[j]
+      if (v !== '') {
+        ands.push('(' + field.field + ':"' + v + '")')
+        searchdefarr.push('fr=' + field.field + '_' + window.encodeURIComponent(v))
+      }
+    }
+  }
+
+  if (owner) {
+    ands.push('owner:"' + owner + '"')
+    searchdefarr.push('owner=' + owner)
+  } else {
+    // an object should have at least an owner, else it's garbage
+    ands.push('owner:*')
+  }
+
+  if (collection) {
+    ands.push('ispartof:"' + collection + '"')
+    searchdefarr.push('collection=' + collection)
+  }
+
+  return { searchdefarr, ands }
+}
+
+export function buildParams({ q, page, pagesize, sortdef, lang, facetQueries }, ands) {
+  let params = {
+    q,
+    defType: 'edismax',
+    wt: 'json',
+    qf: 'pid^5 dc_title^4 dc_creator^3 dc_subject^2 _text_',
+    start: (page - 1) * pagesize,
+    rows: pagesize,
+    sort: '',
+    facet: true,
+    'facet.query': []
+  }
+
+  if (q === '' || q === null) {
+    params.q = '*:*'
+    params.sort = 'created desc'
+  }
+
+  for (let i = 0; i < sortdef.length; i++) {
+    if (sortdef[i].active) {
+      if ((sortdef[i].id === 'title asc') || (sortdef[i].id === 'title desc')) {
+        params.sort = sortdef[i].def[lang]
+      } else {
+        params.sort = sortdef[i].def
+      }
+    }
+  }
+
+  // TODO: new fn: serializefacetQueries (careful, current implementation might be using mutation)
+  for (let i = 0; i < facetQueries.length; i++) {
+    if (facetQueries[i].show) {
+      for (let j = 0; j < facetQueries[i].queries.length; j++) {
+        // exclude '{!ex=' + state.facetQueries[i].id + '}' +
+        if (facetQueries[i].queries[j].active && facetQueries[i].queries[j].childFacet) {
+          let childFacetLvl1 = facetQueries[i].queries[j].childFacet
+          for (let k = 0; k < childFacetLvl1.queries.length; k++) {
+            if (childFacetLvl1.queries[k].active && childFacetLvl1.queries[k].childFacet) {
+              let childFacetLvl2 = childFacetLvl1.queries[k].childFacet
+              for (let l = 0; l < childFacetLvl2.queries.length; l++) {
+                // days
+                params['facet.query'].push(childFacetLvl2.queries[l].query)
+              }
+            }
+            // months
+            params['facet.query'].push(childFacetLvl1.queries[k].query)
+          }
+        }
+        params['facet.query'].push(facetQueries[i].queries[j].query)
+      }
+    }
+  }
+
+  if (ands.length > 0) {
+    params['fq'] = ands.join(' AND ')
+  }
+
+  return params
+}
+
+export const sortdef = [
+  {
+    id: 'title asc',
+    active: false,
+    def: {
+      'en': 'sort_eng_dc_title asc,sort_dc_title asc',
+      'de': 'sort_deu_dc_title asc,sort_dc_title asc',
+      'it': 'sort_ita_dc_title asc,sort_dc_title asc'
+    }
+  },
+  {
+    id: 'title desc',
+    active: false,
+    def: {
+      'en': 'sort_eng_dc_title desc,sort_dc_title desc',
+      'de': 'sort_deu_dc_title desc,sort_dc_title desc',
+      'it': 'sort_ita_dc_title desc,sort_dc_title desc'
+    }
+  },
+  {
+    id: 'created asc',
+    active: false,
+    def: 'created asc'
+  },
+  {
+    id: 'created desc',
+    active: false,
+    def: 'created desc'
+  }
+]
diff --git a/src/components/select/CollectionDialog.vue b/src/components/select/CollectionDialog.vue
new file mode 100644
index 0000000000000000000000000000000000000000..0697890bfe1f77e85fc929ecfc16cbf2425b9d1b
--- /dev/null
+++ b/src/components/select/CollectionDialog.vue
@@ -0,0 +1,116 @@
+<template>
+  <v-dialog v-model="dialog" width="700px">
+    <v-card>
+      <v-card-title class="grey white--text">{{ $t('Select a collection') }}</v-card-title>
+      <v-card-text>
+        <v-text-field
+          v-model="collectionsSearch"
+          append-icon="search"
+          :label="$t('Search...')"
+          single-line
+          hide-details
+          class="mb-4"
+        ></v-text-field>
+        <v-data-table
+          hide-default-header
+          :headers="collectionsHeaders"
+          :items="collections"
+          :search="collectionsSearch"
+          :custom-filter="filterTitle"
+          :loading="loading"
+          :loading-text="$t('Loading...')"
+          :items-per-page="5"
+        >
+          <template v-slot:item.title="{ item }">
+            <span v-if="item.dc_title">{{ item.dc_title[0] | truncate(50) }}</span>
+          </template>
+          <template v-slot:item.created="{ item }">
+            {{ item.created | date }}
+          </template>
+          <template v-slot:item.actions="{ item }">
+            <v-btn text color="primary" @click="selectCollection(item)">{{ $t('Select') }}</v-btn>
+          </template>
+        </v-data-table>
+      </v-card-text>
+      <v-divider></v-divider>
+      <v-card-actions>
+        <v-container>
+          <v-row justify="end" class="px-4">
+            <v-btn color="grey" dark @click="dialog = false">{{ $t('Cancel') }}</v-btn>
+          </v-row>
+        </v-container>
+      </v-card-actions>
+    </v-card>
+  </v-dialog>
+</template>
+
+<script>
+export default {
+  name: 'collection-dialog',
+  computed: {
+    instance: function () {
+      return this.$store.state.instanceconfig
+    }
+  },
+  data () {
+    return {
+      dialog: false,
+      loading: false,
+      collectionsSearch: '',
+      collectionsHeaders: [
+        { text: 'Pid', align: 'left', value: 'pid' },
+        { text: 'Title', align: 'left', value: 'title' },
+        { text: 'Created', align: 'right', value: 'created' },
+        { text: 'Actions', align: 'right', value: 'actions', sortable: false }
+      ],
+      collections: []
+    }
+  },
+  methods: {
+    filterTitle (value, search, item) {
+      if (item.dc_title) {
+        if (item.dc_title.length > 0) {
+          return item.dc_title[0].indexOf(search) !== -1
+        } else {
+          return false
+        }
+      } else {
+        return false
+      }
+    },
+    open: async function () {
+      this.dialog = true
+      this.loading = true
+      let params = {
+        q: '*:*',
+        defType: 'edismax',
+        wt: 'json',
+        start: 0,
+        rows: 1000,
+        sort: 'created desc',
+        fq: [ 'resourcetype:collection', 'owner:' + this.$store.state.user.username ]
+      }
+      try {
+        let response = await this.$http.request({
+          method: 'POST',
+          url: this.instance.solr + '/select',
+          headers: {
+            'X-XSRF-TOKEN': this.$store.state.user.token
+          },
+          params: params
+        })
+        this.collections = response.data.response.docs
+      } catch (error) {
+        console.log(error)
+        this.$store.commit('setAlerts', [{ type: 'danger', msg: error }])
+      } finally {
+        this.loading = false
+      }
+    },
+    selectCollection: function (item) {
+      this.$emit('collection-selected', item)
+      this.dialog = false
+    }
+  }
+}
+</script>
diff --git a/src/components/select/ListDialog.vue b/src/components/select/ListDialog.vue
new file mode 100644
index 0000000000000000000000000000000000000000..97ae7ca679e430bb427c862226c67b6abd6e7092
--- /dev/null
+++ b/src/components/select/ListDialog.vue
@@ -0,0 +1,102 @@
+<template>
+  <v-dialog v-model="dialog" width="700px">
+    <v-card>
+      <v-card-title class="grey white--text">{{ $t('Select a list') }}</v-card-title>
+      <v-card-text>
+        <v-text-field
+          v-model="listsSearch"
+          append-icon="search"
+          :label="$t('Search...')"
+          single-line
+          hide-details
+          class="mb-4"
+        ></v-text-field>
+        <v-data-table
+          hide-default-header
+          :headers="listsHeaders"
+          :items="lists"
+          :search="listsSearch"
+          :loading="loading"
+          :loading-text="$t('Loading...')"
+          :items-per-page="5"
+        >
+          <template v-slot:item.name="{ item }">
+            <v-tooltip bottom>
+              <template v-slot:activator="{ on }">
+                <span v-on="on">{{ item.name | truncate(50) }}</span>
+              </template>
+              <span>{{ item.listid }}</span>
+            </v-tooltip>
+          </template>
+          <template v-slot:item.created="{ item }">
+            {{ item.created | unixtime }}
+          </template>
+          <template v-slot:item.updated="{ item }">
+            {{ item.updated | unixtime }}
+          </template>
+          <template v-slot:item.actions="{ item }">
+            <v-btn text color="primary" @click="selectList(item)">{{ $t('Select') }}</v-btn>
+          </template>
+        </v-data-table>
+      </v-card-text>
+      <v-divider></v-divider>
+      <v-card-actions>
+        <v-container>
+          <v-row justify="end" class="px-4">
+            <v-btn color="grey" dark @click="dialog = false">{{ $t('Cancel') }}</v-btn>
+          </v-row>
+        </v-container>
+      </v-card-actions>
+    </v-card>
+  </v-dialog>
+</template>
+
+<script>
+export default {
+  name: 'list-dialog',
+  computed: {
+    instance: function () {
+      return this.$store.state.instanceconfig
+    }
+  },
+  data () {
+    return {
+      dialog: false,
+      loading: false,
+      listsSearch: '',
+      listsHeaders: [
+        { text: 'Name', align: 'left', value: 'name' },
+        { text: 'Created', align: 'right', value: 'created' },
+        { text: 'Updated', align: 'right', value: 'updated' },
+        { text: 'Actions', align: 'right', value: 'actions', sortable: false }
+      ],
+      lists: []
+    }
+  },
+  methods: {
+    open: async function () {
+      this.dialog = true
+      this.loading = true
+      try {
+        let response = await this.$http.request({
+          method: 'GET',
+          url: this.instance.api + '/lists',
+          headers: {
+            'X-XSRF-TOKEN': this.$store.state.user.token
+          }
+        })
+        this.lists = response.data.lists
+      } catch (error) {
+        console.log(error)
+        this.$store.commit('setAlerts', [{ type: 'danger', msg: error }])
+      } finally {
+        this.loading = false
+      }
+    },
+    selectList: function (item) {
+      this.$emit('list-selected', item)
+      this.dialog = false
+    }
+  }
+}
+</script>
diff --git a/src/components/select/OrgUnitsTreeDialog.vue b/src/components/select/OrgUnitsTreeDialog.vue
new file mode 100644
index 0000000000000000000000000000000000000000..a3ba47a001591d47ee5863a692c2643998f2f815
--- /dev/null
+++ b/src/components/select/OrgUnitsTreeDialog.vue
@@ -0,0 +1,77 @@
+<template>
+  <v-dialog v-model="dialog" width="700px">
+    <v-card :loading="loading">
+      <v-card-title class="grey white--text">{{ $t('Select an organizational unit') }}</v-card-title>
+      <v-card-text>
+        <v-treeview :items="orgunits" item-children="subunits" item-key="@id" hoverable activatable @update:active="selectUnit($event)"></v-treeview>
+      </v-card-text>
+      <v-divider></v-divider>
+      <v-card-actions>
+        <v-container>
+          <v-row justify="end" class="px-4">
+            <v-btn color="grey" dark @click="dialog = false">{{ $t('Cancel') }}</v-btn>
+          </v-row>
+        </v-container>
+      </v-card-actions>
+    </v-card>
+  </v-dialog>
+</template>
+
+<script>
+export default {
+  name: 'org-units-tree-dialog',
+  computed: {
+    instance: function () {
+      return this.$store.state.instanceconfig
+    }
+  },
+  data () {
+    return {
+      dialog: false,
+      loading: false,
+      orgunits: []
+    }
+  },
+  methods: {
+    open: async function () {
+      this.dialog = true
+      this.loading = true
+      try {
+        let response = await this.$http.request({
+          method: 'GET',
+          url: this.$store.state.instanceconfig.api + '/directory/org_get_units',
+          headers: {
+            'X-XSRF-TOKEN': this.$store.state.user.token
+          }
+        })
+        if (response.data.alerts && response.data.alerts.length > 0) {
+          this.$store.commit('setAlerts', response.data.alerts)
+        }
+        this.orgunits = response.data.units
+        this.addNames(this.orgunits)
+      } catch (error) {
+        console.log(error)
+        this.$store.commit('setAlerts', [{ type: 'danger', msg: error }])
+      } finally {
+        this.loading = false
+      }
+    },
+    addNames: function (units) {
+      for (let u of units) {
+        if (u['skos:prefLabel']) {
+          u['name'] = u['skos:prefLabel'][this.$i18n.locale]
+        }
+        if (u['subunits']) {
+          if (u.subunits.length > 0) {
+            this.addNames(u.subunits)
+          }
+        }
+      }
+    },
+    selectUnit: function (item) {
+      this.$emit('unit-selected', item[0])
+      this.dialog = false
+    }
+  }
+}
+</script>
diff --git a/src/components/templates/PTList.vue b/src/components/templates/PTList.vue
new file mode 100644
index 0000000000000000000000000000000000000000..7b4f6aba3bf2415ef385904077f0fe63de99bff3
--- /dev/null
+++ b/src/components/templates/PTList.vue
@@ -0,0 +1,142 @@
+<template>
+
+  <v-data-table
+    :headers="headers"
+    :items="templates"
+    :loading="loading"
+    class="elevation-1"
+  >
+    <template slot="items" slot-scope="props">
+      <td>
+        <v-tooltip bottom>
+          <template v-slot:activator="{ on }">
+            <span v-on="on">{{ props.item.name }}</span>
+          </template>
+          <span>{{ props.item.tid }}</span>
+        </v-tooltip>
+      </td>
+      <td class="text-xs-right">{{ props.item.created | unixtime }}</td>
+      <td class="text-xs-right" >
+        <v-btn flat color="primary" @click="loadTemplate(props.item.tid)">{{ $t('Load') }}</v-btn>
+        <v-btn flat color="grey" @click="deleteTemplate(props.item.tid)">{{ $t('Delete') }}</v-btn>
+        <!-- for some reason opening the dialog from here causes infinite cycle.. looks like vuetify bug..
+        <v-dialog v-model="deletetempconfirm" width="300" >
+          <template v-slot:activator="{ on }">
+            <v-btn flat color="grey" v-on="on">{{ $t('Delete') }}</v-btn>
+          </template>
+          <v-card>
+            <v-card-title class="headline grey lighten-2" primary-title >{{ $t('Delete') }}</v-card-title>
+            <v-card-text>{{ $t('Are you sure you want to delete template') }} "{{props.item.name}}" ?</v-card-text>
+            <v-divider></v-divider>
+            <v-card-actions>
+              <v-spacer></v-spacer>
+              <v-btn color="red" class="white--text" :loading="loading" :disabled="loading" @click="deleteTemplate(props.item.tid)">{{ $t('Delete') }}</v-btn>
+              <v-btn :disabled="loading" @click="deletetempconfirm = false">{{ $t('Cancel') }}</v-btn>
+            </v-card-actions>
+          </v-card>
+        </v-dialog>
+        -->
+      </td>
+    </template>
+  </v-data-table>
+
+</template>
+
+<script>
+
+export default {
+  name: 'p-t-list',
+  data () {
+    return {
+      headers: [
+        { text: 'Name', align: 'left', value: 'name' },
+        { text: 'Created', align: 'right', value: 'created' },
+        { text: 'Actions', align: 'right', value: 'load', sortable: false }
+      ],
+      templates: [],
+      deletetempconfirm: false,
+      loading: false
+    }
+  },
+  methods: {
+    loadTemplate: function (tid) {
+      var self = this
+      this.loading = true
+      var url = self.$store.state.settings.instance.api + '/jsonld/template/' + tid
+      var promise = fetch(url, {
+        method: 'GET',
+        mode: 'cors',
+        headers: {
+          'X-XSRF-TOKEN': this.$store.state.user.token
+        }
+      })
+      .then(function (response) { return response.json() })
+      .then(function (json) {
+        if (json.alerts && json.alerts.length > 0) {
+          self.$store.commit('setAlerts', json.alerts)
+        }
+        self.$emit('load-template', json.template.form)
+        self.loading = false
+      })
+      .catch(function (error) {
+        //console.log(error)
+        self.loading = false
+      })
+      return promise
+    },
+    deleteTemplate: function (tid) {
+      var self = this
+      this.loading = true
+      var url = self.$store.state.settings.instance.api + '/jsonld/template/' + tid + '/remove'
+      var promise = fetch(url, {
+        method: 'POST',
+        mode: 'cors',
+        headers: {
+          'X-XSRF-TOKEN': this.$store.state.user.token
+        }
+      })
+      .then(function (response) { return response.json() })
+      .then(function (json) {
+         if (json.alerts && json.alerts.length > 0) {
+          self.$store.commit('setAlerts', json.alerts)
+        }
+        self.loading = false
+        self.deletetempconfirm = false
+        self.loadTemplates()
+      })
+      .catch(function (error) {
+        //console.log(error)
+        self.loading = false
+      })
+      return promise
+    },
+    loadTemplates: function (pid) {
+      var self = this
+      this.loading = true
+      var url = self.$store.state.settings.instance.api + '/jsonld/templates'
+      var promise = fetch(url, {
+        method: 'GET',
+        mode: 'cors',
+        headers: {
+          'X-XSRF-TOKEN': this.$store.state.user.token
+        }
+      })
+      .then(function (response) { return response.json() })
+      .then(function (json) {
+        self.templates = json.templates
+        self.loading = false
+      })
+      .catch(function (error) {
+        //console.log(error)
+        self.loading = false
+      })
+      return promise
+    }
+  },
+  mounted: function () {
+    if (this.$store.state.user.token) {
+      this.loadTemplates()
+    }
+  }
+}
+</script>
diff --git a/src/components/templates/PTemplates.vue b/src/components/templates/PTemplates.vue
new file mode 100644
index 0000000000000000000000000000000000000000..5f5d7898ae5c1595bd0caf09d8a03ada50ea65d2
--- /dev/null
+++ b/src/components/templates/PTemplates.vue
@@ -0,0 +1,123 @@
+<template>
+
+  <v-data-table
+    :headers="headers"
+    :items="templates"
+    :loading="loading"
+    class="elevation-1"
+  >
+    <template v-slot:item.name="{ item }">
+      <v-tooltip bottom>
+        <template v-slot:activator="{ on }">
+          <span v-on="on">{{ item.name }}</span>
+        </template>
+        <span>{{ item.tid }}</span>
+      </v-tooltip>
+    </template>
+    <template v-slot:item.created="{ item }">
+      {{ item.created | unixtime }}
+    </template>
+    <template v-slot:item.load="{ item }">
+      <v-btn text color="primary" @click="loadTemplate(item.tid)">{{ $t('Load') }}</v-btn>
+      <v-btn text color="grey" @click="deleteTemplate(item.tid)">{{ $t('Delete') }}</v-btn>
+    </template>
+  </v-data-table>
+
+</template>
+
+<script>
+export default {
+  name: 'p-templates',
+  props: {
+    tag: {
+      type: String
+    }
+  },
+  data () {
+    return {
+      headers: [
+        { text: 'Name', align: 'left', value: 'name' },
+        { text: 'Created', align: 'right', value: 'created' },
+        { text: 'Actions', align: 'right', value: 'load', sortable: false }
+      ],
+      templates: [],
+      deletetempconfirm: false,
+      loading: false
+    }
+  },
+  methods: {
+    loadTemplate: async function (tid) {
+      this.loading = true
+      try {
+        let response = await this.$http.request({
+          method: 'GET',
+          url: this.$store.state.instanceconfig.api + '/jsonld/template/' + tid,
+          headers: {
+            'X-XSRF-TOKEN': this.$store.state.user.token
+          }
+        })
+        if (response.data.alerts && response.data.alerts.length > 0) {
+          this.$store.commit('setAlerts', response.data.alerts)
+        }
+        this.$emit('load-template', response.data.template.form)
+      } catch (error) {
+        console.log(error)
+        this.$store.commit('setAlerts', [{ type: 'danger', msg: error }])
+      } finally {
+        this.loading = false
+      }
+    },
+    deleteTemplate: async function (tid) {
+      if (confirm(this.$t('Are you sure you want to delete this template?'))) {
+        this.loading = true
+        try {
+          let response = await this.$http.request({
+            method: 'GET',
+            url: this.$store.state.instanceconfig.api + '/jsonld/template/' + tid + '/remove',
+            headers: {
+              'X-XSRF-TOKEN': this.$store.state.user.token
+            }
+          })
+          if (response.data.alerts && response.data.alerts.length > 0) {
+            this.$store.commit('setAlerts', response.data.alerts)
+          }
+          this.deletetempconfirm = false
+          this.loadTemplates()
+        } catch (error) {
+          console.log(error)
+          this.$store.commit('setAlerts', [{ type: 'danger', msg: error }])
+        } finally {
+          this.loading = false
+        }
+      }
+    },
+    loadTemplates: async function () {
+      this.loading = true
+      try {
+        let response = await this.$http.request({
+          method: 'GET',
+          url: this.$store.state.instanceconfig.api + '/jsonld/templates' + ((this.tag && this.tag.length > 1) ? '?tag=' + this.tag : ''),
+          headers: {
+            'X-XSRF-TOKEN': this.$store.state.user.token
+          }
+        })
+        if (response.data.alerts && response.data.alerts.length > 0) {
+          this.$store.commit('setAlerts', response.data.alerts)
+        }
+        this.templates = response.data.templates
+        this.loading = false
+      } catch (error) {
+        console.log(error)
+        this.$store.commit('setAlerts', [{ type: 'danger', msg: error }])
+      } finally {
+        this.loading = false
+      }
+    }
+  },
+  mounted: function () {
+    if (this.$store.state.user.token) {
+      this.loadTemplates()
+    }
+  }
+}
+</script>
\ No newline at end of file