@tooltwist/vue-contentservice
Version:
VueJS plugin for contentservice.io
569 lines (482 loc) • 16.9 kB
JavaScript
/* @flZZow */
/*
* Client API for Contentservice.io
* See https://contentservice.io
*/
import axios from 'axios'
import axiosError from './axiosError.js'
import QueryString from 'query-string'
import { assert, inBrowser } from '../components/misc'
// const debug = process.env.NODE_ENV !== 'production'
const NETWORK_ERROR_MSG = 'Could not contact authentication server'
let onceOnly = 0
class Contentservice {
// static install: (Vue) => void;
// static version: string;
// static install (Vue) {
// alert('Install 2...')
// // Vue.prototype.$auth = new Contentservice()
// Vue.prototype.$auth = 123
//
// Object.defineProperty(Vue.prototype, '$content', {
// get () { return 987 }
// })
// }
constructor (options) {
console.log('** initializing vue-contentservice')
console.log(options)
if (!options) {
console.error(`Contentservice was passed null options, so will be disabled.`)
this.disabled = true
return
}
this.disabled = false
// console.log('&&& Contentservice constructor', options)
// this.protocol = options.protocol ? options.protocol : 'https'
this.host = options.host ? options.host : 'tooltwist.io'
if (options.port) {
this.port = options.port
} else if (this.protocol == 'http') {
this.port = 80
} else {
this.port = 443
}
this.version = options.version ? options.version : '5.0'
this.apikey = options.apikey
// Check the UrlPrefix only has a trailing slash
this.urlPrefix = 'contentservice'
if (typeof (options.urlPrefix) !== 'undefined') {
if (options.debug) console.log(`- will use options.urlPrefix`)
this.urlPrefix = options.urlPrefix
}
while (this.urlPrefix.startsWith('/')) {
this.urlPrefix = this.urlPrefix.substring(1)
}
while (this.urlPrefix.endsWith('/')) {
this.urlPrefix = this.urlPrefix.substring(0, this.urlPrefix.length - 1)
}
if (this.urlPrefix) {
this.urlPrefix += '/'
}
// console.log(`UrlPrefix: ${this.urlPrefix}`)
// Determine what protocol to use
this.protocol = 'http'
if (options.protocol && (options.protocol === 'http' || options.protocol === 'https')) {
this.protocol = options.protocol
} else {
// See if we can determine the protocol from the port
if (this.port === 80) {
this.protocol = 'http'
} else if (this.port === 443) {
this.protocol = 'https'
} else {
// Non-standard port, probably during development
}
}
console.log(`YARP CS 3: ${this.endpoint()}`)
if (options.debug) console.log(`- endpoint: ${this.endpoint()}`)
this.knownElementTypes = [ ]
// Decide which icon set to use with a defaultIconPack option.
// Loosely based on:
// https://buefy.github.io/#/documentation/constructor-options
//
// Currently recognise:
// fa (font-awsome 4)
// fas (font-awsome 5)
this.defaultIconPack = options.defaultIconPack ? options.defaultIconPack : 'fa'
this.icons = (pack) => { return this.defaultIconPack === pack }
if (options.defaultIconPack) {
console.log(`Will use icon pack ${options.defaultIconPack}`);
}
// console.log(`---> icons ---> ${this.defaultIconPack}`);
// Remember the options
this.options = options
// Current user details
// this.user = null
// this.jwt = null
// this.fromCache = false
}
// init (app: any /* Vue component instance */) {
init (app /* Vue component instance */) {
// console.log('&&& ContentService.init')
// VVVVV This does not seem to be called
// alert('za init()')
process.env.NODE_ENV !== 'production' && assert(
install.installed,
`not installed. Make sure to call \`Vue.use(Contentservice)\` ` +
`before creating root instance.`
)
}
endpoint () {
let portStuff = ''
if (this.protocol === 'http' && this.port !== 80) {
portStuff = `:${this.port}`
} else if (this.protocol === 'https' && this.port !== 443) {
portStuff = `:${this.port}`
}
const endpoint = `${this.protocol}://${this.host}${portStuff}/${this.urlPrefix}${this.version}/${this.apikey}`
// console.log(`endpoint=${endpoint}`);
return endpoint
}
registerLayoutType (vm, layoutType, componentName, component, propertyComponent) {
let propertyComponentName = `${componentName}-props`
// Remember the component names used for this type of layout element.
this.knownElementTypes[layoutType] = {
layoutType,
label: layoutType,
name: layoutType,
category: '',
componentName,
propertyComponentName,
component,
propertyComponent
}
// Define the components
// console.log(`registering non-toolbox widget ${componentName}`)
vm.component(componentName, component)
vm.component(propertyComponentName, propertyComponent)
}
// -> { component, propertyComponent }
getLayoutType (layoutType) {
//console.error(`getLayoutType(${layoutType})`)
return this.knownElementTypes[layoutType]
}
registerWidget (vm, { name, label, category, iconClass, iconClass5, componentName, component, propertyComponent, data}) {
//console.error(`registerWidget(${name}, ${category})`)
if (!label) {
label = name
}
if (!category) {
category = ''
}
let propertyComponentName = `${componentName}-props`
// Remember the component names used for this type of layout element.
this.knownElementTypes[name] = {
layoutType: name,//ZZZ
name,
label,
category,
iconClass,
iconClass5,
componentName,
propertyComponentName,
component,
propertyComponent,
// The definition used when creating a new component.
data,
dragtype: 'component'
}
// Define the components
// console.log(`registering toolbox widget ${componentName}`)
vm.component(componentName, component)
vm.component(propertyComponentName, propertyComponent)
}
toolboxCategories () {
let categories = [ ] // category -> { type[] }
for (var name in this.knownElementTypes) {
if (this.knownElementTypes.hasOwnProperty(name)) {
let type = this.knownElementTypes[name]
//console.error(`Add tool ${name}`, type);
let categoryRec = categories[type.category]
//console.log(`category = ${type.category}`, categoryRec);
if ( !categoryRec) {
categoryRec = {
name: type.category,
types: [ ]
}
//console.error(`Add category ${type.category}`);
categories[type.category] = categoryRec
}
categoryRec.types[name] = type
}
}
//console.error(`Toolbox Types - `, categories);
// Convert categories to an array and sort
let arr = [ ]
for (var categoryName in categories) {
let category = categories[categoryName]
arr.push(category)
}
categories = arr
categories.sort((a,b) => {
if (a.name < b.name) return -1;
if (a.name > b.name) return +1
return 0
})
// Sort categories
// Convert the types in each category to an array
categories.forEach(category => {
let arr = [ ]
for (var name in category.types) {
if (category.types.hasOwnProperty(name)) {
let type = category.types[name]
arr.push(type)
}
}
category.types = arr
})
return categories
}
//----------------------------------------------------------------------------//
// WRAPPERS FOR STORE ACTIONS AND MUTATIONS //
//----------------------------------------------------------------------------//
// Same parameters as contentLayoutStore.setContent
// Action
setContent(params) {
this.store.dispatch('setContentAction', params)
}
// Same parameters as contentLayoutStore.deleteElementAction
// Action
deleteElement(params) {
this.store.dispatch('deleteElementAction', params)
}
// Same parameters as contentLayoutStore.insertLayoutAction
// Action
insertLayout(params) {
this.store.dispatch('insertLayoutAction', params)
}
// Same parameters as contentLayoutStore.moveChildAction
// Action
moveChild(params) {
this.store.dispatch('moveChildAction', params)
}
// Same parameters as contentLayoutStore.setProperty
// Action
setProperty({ vm, element, name, value, save }) {
this.store.dispatch('setPropertyAction', { vm, element, name, value, save })
}
// Same parameters as contentLayoutStore.setPropertyInElement
// Mutation
setPropertyInElement ({ vm, element, name, value } ) {
console.log(`$content.setPropertyInElement`, vm, element, name, value);
this.store.commit('setPropertyInElementMutation', { vm, element, name, value })
}
// This is only here, to match the setProperty functions.
getProperty({ element, name, defaultValue }) {
if (element.hasOwnProperty(name)) {
return element[name]
}
if (typeof(defaultValue) !== 'undefined') {
return defaultValue
}
return undefined
}
// Same parameters as contentLayoutStore.setLayout
// Mutation
setLayout (params) {
this.store.commit('setLayout', params)
}
// Same parameters as contentLayoutStore.setPropertyElement
// Mutation
setPropertyElement(params) {
this.store.commit('setPropertyElementMutation', params)
}
// Same parameters as contentLayoutStore.setExpandedElement
// Mutation
setExpandedElement (params) {
this.store.commit('setExpandedElementMutation', params)
}
// Same parameters as contentLayoutStore.setEditMode
// Mutation
setEditMode(params) {
this.store.commit('setEditMode', params)
}
// Toggle between view and {edit|layout|debug}
toggleEditMode() {
// When we switch to view mode, we remember which of the edit modes
// we were in, so we can toggle back to the same mode.
let mode = this.store.state.mode
let previousEditMode = this.store.state.previousEditMode
if (mode === 'view') {
// Switch to one of the edit modes
// console.log(` - toggle to ${previousEditMode}`)
this.setEditMode({ mode: previousEditMode })
} else {
// Switch back to view mode
// console.log(` - toggle to view mode`)
this.setEditMode({ mode: 'view', previousEditMode: mode })
}
}
// Same parameters as contentLayoutStore.setSaveMsg
// Mutation
setSaveMsg(params) {
this.store.commit('setSaveMsg', params)
}
// Same parameters as contentLayoutStore.updateElementPropertyMutation
// Mutation
updateElementProperty(params) {
this.store.commit('updateElementProperty', params)
}
// Same parameters as contentLayoutStore.insertLayoutMutation
// Mutation
insertLayoutMutation(params) {
this.store.commit('insertLayoutMutation', params)
}
// Same parameters as contentLayoutStore.deleteElement
// Mutation
deleteElementMutation(params) {
this.store.commit('deleteElementMutation', params)
}
// Same parameters as contentLayoutStore.refresh
// Mutation
refresh() {
this.store.commit('refreshMutation', { })
}
//----------------------------------------------------------------------------//
// NEW STUFF FROM CROWDHOUND //
//----------------------------------------------------------------------------//
/**
* Select may be in various formats:
* select(vm, '$my-anchor', 'user-list') - select a thread by it's anchor and anchorType.
* select(vm, rootId) - select a thread. Anchor will NOT be created if it doesn't exist.
* select(vm, params)
*/
select(vm, param1, param2) {
// console.log(`ContentService.js select()`)
// console.log(`param1=`, param1)
// console.log(`param2=`, param2)
return new Promise((resolve, reject) => {
if (this.options.debug) {
console.log('select()');
}
if (this.disabled) {
return reject(new Error('contentservice disabled'));
}
// Work out what combination of parameters we've been passed
var type1 = typeof(param1);
var type2 = typeof(param2);
var type3 = typeof(param3);
if (arguments.length === 3) {
// Short form: select(vm, anchor, anchorType)
// Check the anchor starts with $
var anchor = param1;
var anchorType = param2;
if (typeof(anchor) != 'string') {
console.log('CrowdHound.select: anchor must be a string: ' + anchor + ', ' + typeof(anchor));
return reject(new Error('invalid anchor parameter'));
}
if (anchor.charAt(0) != '$') {
console.log('CrowdHound.select: anchor must start with \'$\': ' + anchor);
return reject(new Error('invalid anchor parameter - must start with \'$\''));
}
if (typeof(anchorType) != 'string') {
console.log('CrowdHound.select: anchorType must be a string: ' + anchorType + ', ' + typeof(anchorType));
return reject(new Error('invalid anchor parameter'));
}
// console.log('select anchor')
var params = {
elementId: anchor,
type: anchorType
};
} else if (arguments.length === 2) {
if (type1 == 'object') {
// select(vm, params)
var params = param1
} else {
// select(vm, rootId) - select a thread. Anchor will NOT be created if it doesn't exist.
var params = {
elementId: '' + param1
};
}
} else {
reject('Unknown parameters to CrowdHound.select');
// if (type1 == 'function') {
// var callback = param1;
// return callback(new Error('Invalid parameters'));
// }
// if (typeof(type4) == 'function') {
// var callback = param4;
// return callback(new Error('Invalid parameters'));
// }
// if (typeof(type5) == 'function') {
// var callback = param5;
// return callback(new Error('Invalid parameters'));
// }
return;
}
//var elementType = 'file';
// var url = _API_URL + '/elements?type=' + elementType;
var url = `${this.endpoint()}/elements`;
// url = addAuthenticationToken(url);
if (this.options.debug) {
console.log('CrowdHound.select()')
console.log(' url=' + url)
console.log(' params=', params)
}
axios({
method: 'get',
url,
headers: {
'Authorization': 'Bearer ' + vm.$loginservice.jwt,
'Content-Type': 'application/json',
'Accept': 'application/json'
},
params: params
})
.then(response => {
// JSON responses are automatically parsed.
//console.log(`RESPONSE IS`, response.data)
let reply = response.data
// If the first item in the array is the current user, pluck it off the array now.
let userdata = null
if ((reply instanceof Array) && reply.length > 0 && reply[0].__currentUser) {
userdata = reply[0];
reply.shift(); // remove from the array
}
let selection = {
cooked: false,
params: params,
elements: reply,
};
return resolve(selection);
})
.catch(e => {
axiosError(vm, url, params, e)
reject(e)
})
// .then(() => {
// console.log(`YARP AFTER AXIOS`)
// })
})// new promise
} //- select()
/*
* Update an existing element.
* If an anchor and a type is provided, the element will be created
* if it does not already exist.
*/
update (vm, element) {
console.log(`ContentService.js:update()`, element)
console.log(`element.description.length=`, element.description.length)
return new Promise((resolve, reject) => {
if (this.options.debug) {
console.log('select()');
}
if (this.disabled) {
return reject(new Error('contentservice disabled'));
}
let url = `${this.endpoint()}/element`;
//let params = element
axios({
method: 'put',
url,
headers: {
'Authorization': 'Bearer ' + vm.$loginservice.jwt,
'Content-Type': 'application/json',
'Accept': 'application/json'
},
data: element
})
.then(response => {
// JSON responses are automatically parsed.
//console.log(`RESPONSE IS`, response.data)
// let reply = response.data
return resolve('ok');
})
.catch(e => {
axiosError(vm, url, element, e)
reject(e)
})
})//- promise
}// update()
}
export default Contentservice