// @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', {}, [ h('div', { style: { backgroundColor: '#f7f7f7', padding: '8px 12px', borderBottom: '1px solid #ddd' }, }, [ h('div', { className: 'form-group', style: { padding: 0, margin: 0 } }, [ h('div', { className: 'input-group', style: { padding: 0, margin: 0 } }, [ h('input', { type: 'text', placeholder: 'Szukaj...', className: 'p5UI__dropdown-input form-control input-sm', onChange: function (e) { store.dispatch({ type: 'filter', payload: e.target.value }); }, autoFocus: true, value: state.query, }), h('span', { className: 'input-group-addon', style: { padding: '6px', backgroundColor: '#fff' } }, [ h('span', { className: 'glyphicon glyphicon-remove hover-gray', style: { cursor: 'pointer' }, title: "wyczyść", onClick: function (e) { store.dispatch({ type: 'filter', payload: '' }); }, }) ]) ]) ]) ]), h('div', { style: { backgroundColor: '#fff', padding: '0' } }, state.filter.map(function (inst) { return h('label', { className: 'p5UI__dropdown-item', style: {padding: '8px 12px'} }, [ _renderReactToggleInstance({ namespace: inst.namespace, store: store }), inst.label, ]) }) ), ]), _dropdownNode ); setTimeout(function () { if (!_dropdownNode) return false var searchNode = _dropdownNode.getElementsByTagName('input')[0] if (!searchNode) return false searchNode.focus() }, 100) } var _renderReactToggleInstance = function (props) { var state = props.store.getState() if (-1 === state.item.instances.indexOf(props.namespace)) { if (-1 === state.waitingSet.indexOf(props.namespace)) { return h('input', { type: "checkbox", style: { margin: '0 6px 0 0' }, onClick: function () { props.store.dispatch(_reducer_instance_set_send(props.namespace)); } }) } else { return h('input', { type: "checkbox", checked: "checked", disabled: "disabled", style: { margin: '0 6px 0 0' } }) } } else { if (-1 === state.waitingUnSet.indexOf(props.namespace)) { return h('input', { type: "checkbox", checked: "checked", style: { margin: '0 6px 0 0' }, onClick: function () { props.store.dispatch(_reducer_instance_unset_send(props.namespace)); } }) } else { return h('input', { type: "checkbox", style: { margin: '0 6px 0 0' } }) } } } 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