|
|
@@ -0,0 +1,258 @@
|
|
|
+// @require var JS_GLOBAL_FUNCTION_NAME
|
|
|
+// @require var INITIAL_DROPDOWN_DATA
|
|
|
+// @require var NAMESPACE
|
|
|
+// @require var SET_INSTANCE_URL
|
|
|
+if (!JS_GLOBAL_FUNCTION_NAME) throw "Missing JS_GLOBAL_FUNCTION_NAME!";
|
|
|
+if (!NAMESPACE) throw "Missing NAMESPACE!";
|
|
|
+if (!SET_INSTANCE_URL) throw "Missing SET_INSTANCE_URL!";
|
|
|
+if (!DBG) var DBG = false
|
|
|
+if (!INITIAL_DROPDOWN_DATA) throw "Missing INITIAL_DROPDOWN_DATA!";
|
|
|
+if (!INITIAL_DROPDOWN_DATA.allowed_instances) throw "Missing INITIAL_DROPDOWN_DATA.allowed_instances!";
|
|
|
+if (!INITIAL_DROPDOWN_DATA.items) throw "Missing INITIAL_DROPDOWN_DATA.items!";
|
|
|
+
|
|
|
+var instances = {}
|
|
|
+
|
|
|
+var getDropdown = function (pk) {
|
|
|
+ if(DBG)console.log('>>> getDropdown('+pk+')...')
|
|
|
+ if (!instances[pk]) instances[pk] = buildDropdown(pk)
|
|
|
+ return instances[pk]
|
|
|
+}
|
|
|
+
|
|
|
+var dropdown = function(pk) {
|
|
|
+ if(DBG)console.log('>>> dropdown('+pk+')...')
|
|
|
+ return getDropdown(pk)
|
|
|
+}
|
|
|
+
|
|
|
+var buildDropdown = function(pk) {
|
|
|
+ if (!window.p5VendorJs.React) throw 'Missing p5VendorJs.React'
|
|
|
+ if (!window.p5VendorJs.ReactDOM) throw 'Missing p5VendorJs.ReactDOM'
|
|
|
+ if (!window.p5VendorJs.Redux) throw 'Missing p5VendorJs.Redux'
|
|
|
+ if (!window.p5VendorJs.ReduxThunk) throw 'Missing p5VendorJs.ReduxThunk'
|
|
|
+ if (!window.fetch) throw 'Missing window.fetch'
|
|
|
+ var React = window.p5VendorJs.React
|
|
|
+ var ReactDOM = window.p5VendorJs.ReactDOM
|
|
|
+ var h = React.createElement
|
|
|
+ var createStore = window.p5VendorJs.Redux.createStore
|
|
|
+ var applyMiddleware = window.p5VendorJs.Redux.applyMiddleware
|
|
|
+ var ReduxThunk = window.p5VendorJs.ReduxThunk
|
|
|
+ if(DBG)console.log('>>> buildDropdown('+pk+')... ', { INITIAL_DROPDOWN_DATA: INITIAL_DROPDOWN_DATA })
|
|
|
+ var _btnNode = null
|
|
|
+ var _dropdownNode = null
|
|
|
+
|
|
|
+ var _reducer_instance_set_send = function (payload) {
|
|
|
+ if(DBG)console.log('RX:_reducer_instance_set_send() payload', payload)
|
|
|
+ return function (dispatch, getState) { // ReduxThunk
|
|
|
+ if(DBG)console.log('RX:_reducer_instance_set_send() thunk() payload', payload)
|
|
|
+ if(DBG)console.log('RX:_reducer_instance_set_send() thunk() getState().item.pk', getState().item.pk)
|
|
|
+ var instanceToSet = payload
|
|
|
+ dispatch({ type: 'instance_set_request', payload: instanceToSet })
|
|
|
+ // return window.fetch(SET_INSTANCE_URL, {
|
|
|
+ window.fetch(SET_INSTANCE_URL, {
|
|
|
+ method: 'POST',
|
|
|
+ headers: { 'Content-Type': 'application/json' },
|
|
|
+ credentials: 'same-origin',
|
|
|
+ body: JSON.stringify({
|
|
|
+ namespace: NAMESPACE,
|
|
|
+ primaryKey: getState().item.pk,
|
|
|
+ instance: payload,
|
|
|
+ toConnect: 'yes',
|
|
|
+ })
|
|
|
+ }).then(function (response) {
|
|
|
+ return response.json()
|
|
|
+ }).then(function (response) {
|
|
|
+ dispatch({ type: 'instance_set_receive', payload: { instance: instanceToSet, response: response } })
|
|
|
+ // }).catch(function (e) {
|
|
|
+ // dispatch({ type: 'instance_set_error', payload: e })
|
|
|
+ })
|
|
|
+ if(DBG)console.log('RX:_reducer_instance_set_send() thunk() END payload', payload)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ var _reducer_instance_set_request = function (state, payload) {
|
|
|
+ if(DBG)console.log('RX:_reducer_instance_set_request() payload', payload)
|
|
|
+ state.waitingSet.push(payload)
|
|
|
+ return state
|
|
|
+ }
|
|
|
+ var _reducer_instance_set_receive = function (state, payload) {
|
|
|
+ if(DBG)console.log('RX:_reducer_instance_set_receive() payload', payload)
|
|
|
+ // payload: { instance: instanceToSet, response: response }
|
|
|
+ p5UI__notifyAjaxCallback(payload.response)
|
|
|
+ // TODO: update whole list in state by response => render list
|
|
|
+ state.item.instances.push(payload.instance)
|
|
|
+ state.waitingSet = state.waitingSet.filter(function (inst) {
|
|
|
+ return inst !== payload.instance
|
|
|
+ })
|
|
|
+ return state
|
|
|
+ }
|
|
|
+ var _reducer_instance_set_error = function (state, payload) {
|
|
|
+ if(DBG)console.log('RX:_reducer_instance_set_error() payload', payload)
|
|
|
+ if(DBG)console.log('DBG network error for set namespace:', payload)
|
|
|
+ }
|
|
|
+
|
|
|
+ var _reducer_instance_unset_send = function (payload) {
|
|
|
+ if(DBG)console.log('RX:_reducer_instance_unset_send() payload', payload)
|
|
|
+ return function (dispatch, getState) { // ReduxThunk
|
|
|
+ if(DBG)console.log('RX:_reducer_instance_unset_send() thunk() payload', payload)
|
|
|
+ if(DBG)console.log('RX:_reducer_instance_unset_send() thunk() getState().item.pk', getState().item.pk)
|
|
|
+ var instanceToUnset = payload
|
|
|
+ dispatch({ type: 'instance_unset_request', payload: instanceToUnset })
|
|
|
+ window.fetch(SET_INSTANCE_URL, {
|
|
|
+ method: 'POST',
|
|
|
+ headers: { 'Content-Type': 'application/json' },
|
|
|
+ credentials: 'same-origin',
|
|
|
+ body: JSON.stringify({
|
|
|
+ namespace: NAMESPACE,
|
|
|
+ primaryKey: getState().item.pk,
|
|
|
+ instance: payload,
|
|
|
+ toConnect: 'no',
|
|
|
+ })
|
|
|
+ }).then(function (response) {
|
|
|
+ return response.json()
|
|
|
+ }).then(function (response) {
|
|
|
+ dispatch({ type: 'instance_unset_receive', payload: { instance: instanceToUnset, response: response } })
|
|
|
+ // }).catch(function (e) {
|
|
|
+ // dispatch({ type: 'instance_set_error', payload: e })
|
|
|
+ })
|
|
|
+ if(DBG)console.log('RX:_reducer_instance_unset_send() thunk() END payload', payload)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ var _reducer_instance_unset_request = function (state, payload) {
|
|
|
+ if(DBG)console.log('RX:_reducer_instance_unset_request() payload', payload)
|
|
|
+ state.waitingUnSet.push(payload)
|
|
|
+ return state
|
|
|
+ }
|
|
|
+ var _reducer_instance_unset_receive = function (state, payload) {
|
|
|
+ if(DBG)console.log('RX:_reducer_instance_unset_receive() payload', payload)
|
|
|
+ // payload: { instance: instanceToSet, response: response }
|
|
|
+ p5UI__notifyAjaxCallback(payload.response)
|
|
|
+ // TODO: update whole list in state by response => render list
|
|
|
+ state.item.instances = state.item.instances.filter(function (inst) {
|
|
|
+ return inst !== payload.instance
|
|
|
+ })
|
|
|
+ state.waitingUnSet = state.waitingUnSet.filter(function (inst) {
|
|
|
+ return inst !== payload.instance
|
|
|
+ })
|
|
|
+ return state
|
|
|
+ }
|
|
|
+ var _reducer_instance_unset_error = function (state, payload) {
|
|
|
+ if(DBG)console.log('RX:_reducer_instance_unset_error() payload', payload)
|
|
|
+ if(DBG)console.log('DBG network error for set namespace:', payload)
|
|
|
+ }
|
|
|
+
|
|
|
+ var dropdown = function (state, action) {
|
|
|
+ if(DBG)console.log('RX:dropdown()', {type: action.type, payload: action.payload, state: state})
|
|
|
+ switch (action.type) {
|
|
|
+ case 'INIT': return action.payload
|
|
|
+ case 'instance_set_request': return _reducer_instance_set_request(state, action.payload)
|
|
|
+ case 'instance_set_receive': return _reducer_instance_set_receive(state, action.payload)
|
|
|
+ case 'instance_set_error': return _reducer_instance_set_error(state, action.payload)
|
|
|
+ case 'instance_unset_request': return _reducer_instance_unset_request(state, action.payload)
|
|
|
+ case 'instance_unset_receive': return _reducer_instance_unset_receive(state, action.payload)
|
|
|
+ case 'instance_unset_error': return _reducer_instance_unset_error(state, action.payload)
|
|
|
+ case 'filter': {
|
|
|
+ var filtrInstance = action.payload
|
|
|
+ state.query = filtrInstance
|
|
|
+ state.filter = state.allowed_instances.filter(function (inst) {
|
|
|
+ return (-1 !== inst.label.toLowerCase().indexOf(filtrInstance.toLowerCase()))
|
|
|
+ })
|
|
|
+ return state
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ return state
|
|
|
+ }
|
|
|
+ }
|
|
|
+ var store = createStore(
|
|
|
+ dropdown,
|
|
|
+ applyMiddleware(ReduxThunk)
|
|
|
+ )
|
|
|
+
|
|
|
+ var render = function () {
|
|
|
+ var state = store.getState()
|
|
|
+ if(DBG)console.log('RX:render()...')
|
|
|
+ if (!_dropdownNode) return // throw 'Missing dropdownNode'
|
|
|
+ if (!_btnNode) return // throw 'Missing btnNode'
|
|
|
+ ReactDOM.render(
|
|
|
+ h('div', {}, [].concat(
|
|
|
+ h('input', { type: 'text',
|
|
|
+ placeholder: 'Szukaj...',
|
|
|
+ className: 'p5UI__dropdown-input',
|
|
|
+ onChange: function (e) { store.dispatch({ type: 'filter', payload: e.target.value }); },
|
|
|
+ autoFocus: true,
|
|
|
+ value: state.query,
|
|
|
+ })
|
|
|
+ ).concat(
|
|
|
+ state.filter.map(function (inst) {
|
|
|
+ return h('div', { className: 'p5UI__dropdown-item', style: {padding: '4px 0'} }, [
|
|
|
+ _renderReactBtnToggleInstance({ namespace: inst.namespace, store: store }),
|
|
|
+ inst.label,
|
|
|
+ ])
|
|
|
+ })
|
|
|
+ )
|
|
|
+ ),
|
|
|
+ _dropdownNode
|
|
|
+ );
|
|
|
+ setTimeout(function () {
|
|
|
+ if (_dropdownNode.firstChild && _dropdownNode.firstChild.firstChild)
|
|
|
+ _dropdownNode.firstChild.firstChild.focus()
|
|
|
+ }, 100)
|
|
|
+ }
|
|
|
+ var _renderReactBtnToggleInstance = function (props) {
|
|
|
+ var state = props.store.getState()
|
|
|
+ if (-1 === state.item.instances.indexOf(props.namespace)) {
|
|
|
+ if (-1 === state.waitingSet.indexOf(props.namespace)) {
|
|
|
+ return h('button', { style: { margin: '0 6px 0 0' },
|
|
|
+ className: 'btn btn-xs btn-default',
|
|
|
+ onClick: function () { props.store.dispatch(_reducer_instance_set_send(props.namespace)); }
|
|
|
+ }, 'ustaw')
|
|
|
+ } else {
|
|
|
+ return h('button', { style: { margin: '0 6px 0 0' },
|
|
|
+ className: 'btn btn-xs btn-default disabled',
|
|
|
+ }, 'ustaw...')
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (-1 === state.waitingUnSet.indexOf(props.namespace)) {
|
|
|
+ return h('button', { style: { margin: '0 6px 0 0' },
|
|
|
+ className: 'btn btn-xs btn-default',
|
|
|
+ onClick: function () { props.store.dispatch(_reducer_instance_unset_send(props.namespace)); }
|
|
|
+ }, 'usuń')
|
|
|
+ } else {
|
|
|
+ return h('button', { style: { margin: '0 6px 0 0' },
|
|
|
+ className: 'btn btn-xs btn-default disabled',
|
|
|
+ }, 'usuń...')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ store.subscribe(render)
|
|
|
+ store.dispatch({
|
|
|
+ type: 'INIT',
|
|
|
+ payload: {
|
|
|
+ allowed_instances: INITIAL_DROPDOWN_DATA.allowed_instances,
|
|
|
+ query: '',
|
|
|
+ filter: INITIAL_DROPDOWN_DATA.allowed_instances,
|
|
|
+ item: INITIAL_DROPDOWN_DATA.items.filter(function (data) {
|
|
|
+ return data['pk'] == pk
|
|
|
+ }).pop(),
|
|
|
+ waitingSet: [],
|
|
|
+ waitingUnSet: [],
|
|
|
+ }
|
|
|
+ })
|
|
|
+ // render(); // shows the initial state - send INIT action
|
|
|
+
|
|
|
+ var _state = {
|
|
|
+ allowed_instances: INITIAL_DROPDOWN_DATA.allowed_instances,
|
|
|
+ query: '',
|
|
|
+ filter: INITIAL_DROPDOWN_DATA.allowed_instances,
|
|
|
+ item: INITIAL_DROPDOWN_DATA.items.filter(function (data) { return data['pk'] == pk; }).pop(),
|
|
|
+ waitingSet: [],
|
|
|
+ waitingUnSet: [],
|
|
|
+ }
|
|
|
+
|
|
|
+ return function (btnNode, dropdownNode) {
|
|
|
+ _btnNode = btnNode
|
|
|
+ _dropdownNode = dropdownNode
|
|
|
+ if(DBG)console.log('### F.'+JS_GLOBAL_FUNCTION_NAME, { pk: pk, INITIAL_DROPDOWN_DATA: INITIAL_DROPDOWN_DATA, btnNode: btnNode, dropdownNode: dropdownNode, state: _state }) // TODO: rm globals
|
|
|
+ render()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+global[JS_GLOBAL_FUNCTION_NAME] = dropdown
|