ViewObject.php.instancesDropdown.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. // @require var JS_GLOBAL_FUNCTION_NAME
  2. // @require var INITIAL_DROPDOWN_DATA
  3. // @require var NAMESPACE
  4. // @require var SET_INSTANCE_URL
  5. if (!JS_GLOBAL_FUNCTION_NAME) throw "Missing JS_GLOBAL_FUNCTION_NAME!";
  6. if (!NAMESPACE) throw "Missing NAMESPACE!";
  7. if (!SET_INSTANCE_URL) throw "Missing SET_INSTANCE_URL!";
  8. if (!DBG) var DBG = false
  9. if (!INITIAL_DROPDOWN_DATA) throw "Missing INITIAL_DROPDOWN_DATA!";
  10. if (!INITIAL_DROPDOWN_DATA.allowed_instances) throw "Missing INITIAL_DROPDOWN_DATA.allowed_instances!";
  11. if (!INITIAL_DROPDOWN_DATA.items) throw "Missing INITIAL_DROPDOWN_DATA.items!";
  12. var instances = {}
  13. var getDropdown = function (pk) {
  14. if(DBG)console.log('>>> getDropdown('+pk+')...')
  15. if (!instances[pk]) instances[pk] = buildDropdown(pk)
  16. return instances[pk]
  17. }
  18. var dropdown = function(pk) {
  19. if(DBG)console.log('>>> dropdown('+pk+')...')
  20. return getDropdown(pk)
  21. }
  22. var buildDropdown = function(pk) {
  23. if (!window.p5VendorJs.React) throw 'Missing p5VendorJs.React'
  24. if (!window.p5VendorJs.ReactDOM) throw 'Missing p5VendorJs.ReactDOM'
  25. if (!window.p5VendorJs.Redux) throw 'Missing p5VendorJs.Redux'
  26. if (!window.p5VendorJs.ReduxThunk) throw 'Missing p5VendorJs.ReduxThunk'
  27. if (!window.fetch) throw 'Missing window.fetch'
  28. var React = window.p5VendorJs.React
  29. var ReactDOM = window.p5VendorJs.ReactDOM
  30. var h = React.createElement
  31. var createStore = window.p5VendorJs.Redux.createStore
  32. var applyMiddleware = window.p5VendorJs.Redux.applyMiddleware
  33. var ReduxThunk = window.p5VendorJs.ReduxThunk
  34. if(DBG)console.log('>>> buildDropdown('+pk+')... ', { INITIAL_DROPDOWN_DATA: INITIAL_DROPDOWN_DATA })
  35. var _btnNode = null
  36. var _dropdownNode = null
  37. var _reducer_instance_set_send = function (payload) {
  38. if(DBG)console.log('RX:_reducer_instance_set_send() payload', payload)
  39. return function (dispatch, getState) { // ReduxThunk
  40. if(DBG)console.log('RX:_reducer_instance_set_send() thunk() payload', payload)
  41. if(DBG)console.log('RX:_reducer_instance_set_send() thunk() getState().item.pk', getState().item.pk)
  42. var instanceToSet = payload
  43. dispatch({ type: 'instance_set_request', payload: instanceToSet })
  44. // return window.fetch(SET_INSTANCE_URL, {
  45. window.fetch(SET_INSTANCE_URL, {
  46. method: 'POST',
  47. headers: { 'Content-Type': 'application/json' },
  48. credentials: 'same-origin',
  49. body: JSON.stringify({
  50. namespace: NAMESPACE,
  51. primaryKey: getState().item.pk,
  52. instance: payload,
  53. toConnect: 'yes',
  54. })
  55. }).then(function (response) {
  56. return response.json()
  57. }).then(function (response) {
  58. dispatch({ type: 'instance_set_receive', payload: { instance: instanceToSet, response: response } })
  59. // }).catch(function (e) {
  60. // dispatch({ type: 'instance_set_error', payload: e })
  61. })
  62. if(DBG)console.log('RX:_reducer_instance_set_send() thunk() END payload', payload)
  63. }
  64. }
  65. var _reducer_instance_set_request = function (state, payload) {
  66. if(DBG)console.log('RX:_reducer_instance_set_request() payload', payload)
  67. state.waitingSet.push(payload)
  68. return state
  69. }
  70. var _reducer_instance_set_receive = function (state, payload) {
  71. if(DBG)console.log('RX:_reducer_instance_set_receive() payload', payload)
  72. // payload: { instance: instanceToSet, response: response }
  73. p5UI__notifyAjaxCallback(payload.response)
  74. // TODO: update whole list in state by response => render list
  75. state.item.instances.push(payload.instance)
  76. state.waitingSet = state.waitingSet.filter(function (inst) {
  77. return inst !== payload.instance
  78. })
  79. return state
  80. }
  81. var _reducer_instance_set_error = function (state, payload) {
  82. if(DBG)console.log('RX:_reducer_instance_set_error() payload', payload)
  83. if(DBG)console.log('DBG network error for set namespace:', payload)
  84. }
  85. var _reducer_instance_unset_send = function (payload) {
  86. if(DBG)console.log('RX:_reducer_instance_unset_send() payload', payload)
  87. return function (dispatch, getState) { // ReduxThunk
  88. if(DBG)console.log('RX:_reducer_instance_unset_send() thunk() payload', payload)
  89. if(DBG)console.log('RX:_reducer_instance_unset_send() thunk() getState().item.pk', getState().item.pk)
  90. var instanceToUnset = payload
  91. dispatch({ type: 'instance_unset_request', payload: instanceToUnset })
  92. window.fetch(SET_INSTANCE_URL, {
  93. method: 'POST',
  94. headers: { 'Content-Type': 'application/json' },
  95. credentials: 'same-origin',
  96. body: JSON.stringify({
  97. namespace: NAMESPACE,
  98. primaryKey: getState().item.pk,
  99. instance: payload,
  100. toConnect: 'no',
  101. })
  102. }).then(function (response) {
  103. return response.json()
  104. }).then(function (response) {
  105. dispatch({ type: 'instance_unset_receive', payload: { instance: instanceToUnset, response: response } })
  106. // }).catch(function (e) {
  107. // dispatch({ type: 'instance_set_error', payload: e })
  108. })
  109. if(DBG)console.log('RX:_reducer_instance_unset_send() thunk() END payload', payload)
  110. }
  111. }
  112. var _reducer_instance_unset_request = function (state, payload) {
  113. if(DBG)console.log('RX:_reducer_instance_unset_request() payload', payload)
  114. state.waitingUnSet.push(payload)
  115. return state
  116. }
  117. var _reducer_instance_unset_receive = function (state, payload) {
  118. if(DBG)console.log('RX:_reducer_instance_unset_receive() payload', payload)
  119. // payload: { instance: instanceToSet, response: response }
  120. p5UI__notifyAjaxCallback(payload.response)
  121. // TODO: update whole list in state by response => render list
  122. state.item.instances = state.item.instances.filter(function (inst) {
  123. return inst !== payload.instance
  124. })
  125. state.waitingUnSet = state.waitingUnSet.filter(function (inst) {
  126. return inst !== payload.instance
  127. })
  128. return state
  129. }
  130. var _reducer_instance_unset_error = function (state, payload) {
  131. if(DBG)console.log('RX:_reducer_instance_unset_error() payload', payload)
  132. if(DBG)console.log('DBG network error for set namespace:', payload)
  133. }
  134. var dropdown = function (state, action) {
  135. if(DBG)console.log('RX:dropdown()', {type: action.type, payload: action.payload, state: state})
  136. switch (action.type) {
  137. case 'INIT': return action.payload
  138. case 'instance_set_request': return _reducer_instance_set_request(state, action.payload)
  139. case 'instance_set_receive': return _reducer_instance_set_receive(state, action.payload)
  140. case 'instance_set_error': return _reducer_instance_set_error(state, action.payload)
  141. case 'instance_unset_request': return _reducer_instance_unset_request(state, action.payload)
  142. case 'instance_unset_receive': return _reducer_instance_unset_receive(state, action.payload)
  143. case 'instance_unset_error': return _reducer_instance_unset_error(state, action.payload)
  144. case 'filter': {
  145. var filtrInstance = action.payload
  146. state.query = filtrInstance
  147. state.filter = state.allowed_instances.filter(function (inst) {
  148. return (-1 !== inst.label.toLowerCase().indexOf(filtrInstance.toLowerCase()))
  149. })
  150. return state
  151. }
  152. default:
  153. return state
  154. }
  155. }
  156. var store = createStore(
  157. dropdown,
  158. applyMiddleware(ReduxThunk)
  159. )
  160. var render = function () {
  161. // <div class="popover fade right in" role="tooltip" style="max-width: 600px; width: 400px; display: block; top: 281.5px; left: 68px;" id="popover623735">
  162. // <div class="arrow" style="top: 53.5px;"></div>
  163. // <div style="display:block;position:relative;">
  164. // <div class="popover-title">Więcej funkcji dla rekordu nr 163</div>
  165. // <button type="button" class="close" onclick="return hidePopover();" style="position:absolute;right:8px;top:6px;">×</button>
  166. // </div>
  167. // <div class="popover-content">
  168. // <ul class="list-unstyled popoverRowFunctions">
  169. // <li><a href="index.php?_route=TableMsgs&amp;_task=tableRow&amp;idTable=25873&amp;idRow=163" style="margin:0 2px;" title="Wiadomości" class="func_name-msgs"><span class="glyphicon glyphicon-envelope"></span> Wiadomości</a></li>
  170. // <li><a href="#HIST/163" style="margin:0 2px;" title="Historia" class="func_name-hist"><span class="glyphicon glyphicon-book"></span> Historia</a></li>
  171. // </ul>
  172. // <div class="popoverCellContent" style="white-space:normal">
  173. // <p class="text-muted">Pobieranie funkcji...</p><p></p>
  174. // </div>
  175. // </div>
  176. // </div>
  177. var state = store.getState()
  178. if(DBG)console.log('RX:render()...')
  179. if (!_dropdownNode) return // throw 'Missing dropdownNode'
  180. if (!_btnNode) return // throw 'Missing btnNode'
  181. ReactDOM.render(
  182. h('div', {}, [
  183. h('div', { style: { backgroundColor: '#f7f7f7', padding: '8px', borderBottom: '1px solid #ddd' } }, [
  184. h('input', { type: 'text',
  185. placeholder: 'Szukaj...',
  186. className: 'p5UI__dropdown-input input-sm',
  187. onChange: function (e) { store.dispatch({ type: 'filter', payload: e.target.value }); },
  188. autoFocus: true,
  189. value: state.query,
  190. })
  191. ]),
  192. h('div', { style: { backgroundColor: '#fff', padding: '0' } },
  193. state.filter.map(function (inst) {
  194. return h('div', { className: 'p5UI__dropdown-item', style: {padding: '8px'} }, [
  195. _renderReactBtnToggleInstance({ namespace: inst.namespace, store: store }),
  196. inst.label,
  197. ])
  198. })
  199. ),
  200. ]),
  201. _dropdownNode
  202. );
  203. setTimeout(function () {
  204. if (!_dropdownNode) return false
  205. if (!_dropdownNode.firstChild) return false
  206. if (!_dropdownNode.firstChild.firstChild) return false
  207. if (!_dropdownNode.firstChild.firstChild.firstChild) return false
  208. _dropdownNode.firstChild.firstChild.firstChild.focus()
  209. }, 100)
  210. }
  211. var _renderReactBtnToggleInstance = function (props) {
  212. var state = props.store.getState()
  213. if (-1 === state.item.instances.indexOf(props.namespace)) {
  214. if (-1 === state.waitingSet.indexOf(props.namespace)) {
  215. return h('button', { style: { margin: '0 6px 0 0' },
  216. className: 'btn btn-xs btn-default',
  217. onClick: function () { props.store.dispatch(_reducer_instance_set_send(props.namespace)); }
  218. }, 'ustaw')
  219. } else {
  220. return h('button', { style: { margin: '0 6px 0 0' },
  221. className: 'btn btn-xs btn-default disabled',
  222. }, 'ustaw...')
  223. }
  224. } else {
  225. if (-1 === state.waitingUnSet.indexOf(props.namespace)) {
  226. return h('button', { style: { margin: '0 6px 0 0' },
  227. className: 'btn btn-xs btn-default',
  228. onClick: function () { props.store.dispatch(_reducer_instance_unset_send(props.namespace)); }
  229. }, 'usuń')
  230. } else {
  231. return h('button', { style: { margin: '0 6px 0 0' },
  232. className: 'btn btn-xs btn-default disabled',
  233. }, 'usuń...')
  234. }
  235. }
  236. }
  237. store.subscribe(render)
  238. store.dispatch({
  239. type: 'INIT',
  240. payload: {
  241. allowed_instances: INITIAL_DROPDOWN_DATA.allowed_instances,
  242. query: '',
  243. filter: INITIAL_DROPDOWN_DATA.allowed_instances,
  244. item: INITIAL_DROPDOWN_DATA.items.filter(function (data) {
  245. return data['pk'] == pk
  246. }).pop(),
  247. waitingSet: [],
  248. waitingUnSet: [],
  249. }
  250. })
  251. // render(); // shows the initial state - send INIT action
  252. var _state = {
  253. allowed_instances: INITIAL_DROPDOWN_DATA.allowed_instances,
  254. query: '',
  255. filter: INITIAL_DROPDOWN_DATA.allowed_instances,
  256. item: INITIAL_DROPDOWN_DATA.items.filter(function (data) { return data['pk'] == pk; }).pop(),
  257. waitingSet: [],
  258. waitingUnSet: [],
  259. }
  260. return function (btnNode, dropdownNode) {
  261. _btnNode = btnNode
  262. _dropdownNode = dropdownNode
  263. 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
  264. render()
  265. }
  266. }
  267. global[JS_GLOBAL_FUNCTION_NAME] = dropdown