Преглед изворни кода

updated ViewObject instance selector

Piotr Labudda пре 9 година
родитељ
комит
1dd196e13f
3 измењених фајлова са 269 додато и 156 уклоњено
  1. 11 156
      SE/se-lib/Route/ViewObject.php
  2. 258 0
      SE/se-lib/Route/ViewObject.php.instancesDropdown.js
  3. 0 0
      SE/static/vendor.js

+ 11 - 156
SE/se-lib/Route/ViewObject.php

@@ -200,7 +200,14 @@ class Route_ViewObject extends Route_ViewTableAjax {
 					'SET_INSTANCE_URL' => $this->getLink('setInstanceAjax'),
 					'NAMESPACE' => $namespace,
 					'DBG' => DBG::isActive() ? 'true' : 'false',
-					'INITIAL_DROPDOWN_DATA' => json_encode([
+				];
+
+				UI::inlineJS(__FILE__ . '.instancesDropdown.js', [
+					'JS_GLOBAL_FUNCTION_NAME' => $jsRenderFunName,
+					'NAMESPACE' => $namespace,
+					'SET_INSTANCE_URL' => $this->getLink('setInstanceAjax'),
+					'DBG' => DBG::isActive() ? 1 : 0,
+					'INITIAL_DROPDOWN_DATA' => [
 						// 'allowed_instances' => $siblings,
 						'allowed_instances' => array_map(function ($sibling) use ($rootNamespace) {
 							return [
@@ -214,161 +221,8 @@ class Route_ViewObject extends Route_ViewTableAjax {
 								'instances' => explode(',', $row['@instances']),
 							];
 						}, $items)
-					])
-				];
-				echo UI::h('script', [], "
-					var DBG = {$jsArgs['DBG']};
-					var NAMESPACE = '{$jsArgs['NAMESPACE']}'
-					var SET_INSTANCE_URL = '{$jsArgs['SET_INSTANCE_URL']}'
-					var initialData = {$jsArgs['INITIAL_DROPDOWN_DATA']};
-					function {$jsRenderFunName}(pk) {
-						if (!window.p5VendorJs.React) throw 'Missing p5VendorJs React'
-						if (!window.p5VendorJs.ReactDOM) throw 'Missing p5VendorJs ReactDOM'
-						var React = window.p5VendorJs.React
-						var ReactDOM = window.p5VendorJs.ReactDOM
-						var h = React.createElement
-						if(DBG)console.log('F.{$jsRenderFunName}', { pk: pk, initialData: initialData })
-						var _state = {
-							allowed_instances: initialData.allowed_instances,
-							query: '',
-							filter: initialData.allowed_instances,
-							item: initialData.items.filter(function (data) {
-								return data['pk'] == pk
-							}).pop(),
-							waitingSet: [],
-							waitingUnSet: [],
-						}
-						var _btnNode = null
-						var _dropdownNode = null
-						var _update = function (type, payload) {
-							if(DBG)console.log('_update', { pk: pk, type: type, payload: payload, state: _state, btnNode: _btnNode, dropdownNode: _dropdownNode })
-							switch (type) {
-								case 'filter': {
-									if(DBG)console.log('TODO: filter payload:', payload)
-									_state.query = payload
-									_state.filter = _state.allowed_instances.filter(function (inst) {
-										return (-1 !== inst.label.toLowerCase().indexOf(payload.toLowerCase()))
-									})
-								} break;
-								case 'send_set': {
-									_state.waitingSet.push(payload)
-									window.fetch(SET_INSTANCE_URL, {
-										method: 'POST',
-										headers: { 'Content-Type': 'application/json' },
-										credentials: 'same-origin',
-										body: JSON.stringify({
-											namespace: NAMESPACE,
-											primaryKey: _state.item.pk,
-											instance: payload,
-											toConnect: 'yes',
-										})
-									}).then(function (response) {
-										return response.json()
-									}).then(function (response) {
-										p5UI__notifyAjaxCallback(response)
-										if(DBG)console.log('response', response) // TODO: render list
-										_update('set', payload)
-									})
-								} break;
-								case 'send_unset': {
-									_state.waitingUnSet.push(payload)
-									window.fetch(SET_INSTANCE_URL, {
-										method: 'POST',
-										headers: { 'Content-Type': 'application/json' },
-										credentials: 'same-origin',
-										body: JSON.stringify({
-											namespace: NAMESPACE,
-											primaryKey: _state.item.pk,
-											instance: payload,
-											toConnect: 'no',
-										})
-									}).then(function (response) {
-										return response.json()
-									}).then(function (response) {
-										p5UI__notifyAjaxCallback(response)
-										if(DBG)console.log('response', response) // TODO: render list
-										_update('unset', payload)
-									})
-								} break;
-								case 'set': {
-									_state.item.instances.push(payload)
-									_state.waitingSet = _state.waitingSet.filter(function (inst) {
-										return inst !== payload
-									})
-								} break; // TODO: sync url
-								case 'unset': {
-									_state.item.instances = _state.item.instances.filter(function (inst) {
-										return inst !== payload
-									})
-									_state.waitingUnSet = _state.waitingSet.filter(function (inst) {
-										return inst !== payload
-									})
-								} break; // TODO: sync url
-							}
-							_render()
-						}
-
-						var btnToggleInstance = function (props) {
-							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 () { _update('send_set', 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 () { _update('send_unset', props.namespace) }
-									}, 'usuń')
-								} else {
-									return h('button', { style: { margin: '0 6px 0 0' },
-										className: 'btn btn-xs btn-default disabled',
-									}, 'usuń...')
-								}
-							}
-						}
-						var _render = function () {
-							if(DBG)console.log('_render', { pk: pk, state: _state, btnNode: _btnNode, dropdownNode: _dropdownNode })
-							if (!_dropdownNode) throw 'Missing dropdownNode'
-							ReactDOM.render(
-								h('div', {}, [].concat(
-										h('input', { type: 'text',
-											placeholder: 'Szukaj...',
-											className: 'p5UI__dropdown-input',
-											onChange: function (e) { _update('filter', 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'} }, [
-												btnToggleInstance({ namespace: inst.namespace }),
-												inst.label,
-											])
-										})
-									)
-								),
-								_dropdownNode
-							);
-							setTimeout(function () {
-								if (_dropdownNode.firstChild && _dropdownNode.firstChild.firstChild)
-									_dropdownNode.firstChild.firstChild.focus()
-							}, 100)
-						}
-						return function (btnNode, dropdownNode) {
-							_btnNode = btnNode
-							_dropdownNode = dropdownNode
-							if(DBG)console.log('F.{$jsRenderFunName}', { pk: pk, initialData: initialData, btnNode: btnNode, dropdownNode: dropdownNode, state: _state })
-							_render()
-						}
-					}
-				");
+					],
+				]);
 				echo UI::h('script', [], "
 					var SET_INSTANCE_URL = '{$jsArgs['SET_INSTANCE_URL']}'
 					var NAMESPACE = '{$jsArgs['NAMESPACE']}'
@@ -520,6 +374,7 @@ class Route_ViewObject extends Route_ViewTableAjax {
 	}
 
 	public function setInstanceAjaxAction() {
+		sleep(3); // TODO: DBG
 		Response::sendTryCatchJson(array($this, 'setInstanceAjax'), $args = 'JSON_FROM_REQUEST_BODY');
 	}
 	public function setInstanceAjax($args) {

+ 258 - 0
SE/se-lib/Route/ViewObject.php.instancesDropdown.js

@@ -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

Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
SE/static/vendor.js


Неке датотеке нису приказане због велике количине промена