if (!URI_BASE) throw "Missing URI_BASE"; // => Request::getPathUri() if (!global.jQuery) throw "Missing jQuery" var $ = global.jQuery var DBG = DBG || false; var createReactClass = global.p5VendorJs.createReactClass; var h = global.p5VendorJs.React.createElement; var ReactDOM = global.p5VendorJs.ReactDOM; var Redux = global.p5VendorJs.Redux; var ReduxThunk = global.p5VendorJs.ReduxThunk; var createStoreWithThunkMiddleware = Redux.applyMiddleware(ReduxThunk)(Redux.createStore); // TODO: to vendor.js var p5UI__FieldCheckboxSearch = global.p5VendorJs['p5UI__FieldCheckboxSearch']; var p5UI__FieldCheckboxLoading = global.p5VendorJs['p5UI__FieldCheckboxLoading']; function p5Utils__arrayRemove(array, element) { return array.filter(e => e !== element); } function selectedStore(state, action) { // TODO: fetch from ajax on init, and on change rows in table var prevState = state || { isLoading: false, selected: [], loading: [], listPrimaryKeys: [] }; DBG && console.log('DBG::selectedStore', { prevState, action }); switch (action.type) { case 'SET_CHECKED': return Object.assign(prevState, { loading: p5Utils__arrayRemove(prevState.loading, action.primaryKey), selected: prevState.selected.concat(action.primaryKey) }); case 'SET_UNCHECKED': return Object.assign(prevState, { loading: p5Utils__arrayRemove(prevState.loading, action.primaryKey), selected: p5Utils__arrayRemove(prevState.selected, action.primaryKey) }); case 'SET_LIST_CHECKED': return Object.assign(prevState, { loading: [], // TODO: p5Utils__arrayExcept(prevState.loading, action.listPrimaryKeys), selected: [].concat(action.listPrimaryKeys), // TODO: p5Utils__arrayUniqueUnion(prevState.selected, action.listPrimaryKeys) }); case 'SET_LIST_UNCHECKED': return Object.assign(prevState, { loading: [], // TODO: p5Utils__arrayExcept(prevState.loading, action.listPrimaryKeys), selected: [], // TODO: p5Utils__arrayUniqueUnion(prevState.selected, action.listPrimaryKeys) }); case 'SET_LOADING': return Object.assign(prevState, { loading: prevState.loading.concat(action.primaryKey) }); case 'SET_LIST_LOADING': return Object.assign(prevState, { loading: [].concat(action.listPrimaryKeys) }); case 'SET_PRIMARY_KEYS': return Object.assign(prevState, { // TODO: remove from loading and selected pks which are not in action.listPrimaryKeys, exclude 'select-all' listPrimaryKeys: [].concat(action.listPrimaryKeys), }); default: return prevState; } } function selectedActions() { function setChecked(primaryKey) { return { type: 'SET_CHECKED', primaryKey: primaryKey } } function setUnchecked(primaryKey) { return { type: 'SET_UNCHECKED', primaryKey: primaryKey } } function setLoading(primaryKey) { return { type: 'SET_LOADING', primaryKey: primaryKey } } function setListChecked(listPrimaryKeys) { return { type: 'SET_LIST_CHECKED', listPrimaryKeys: listPrimaryKeys } } function setListUnchecked(listPrimaryKeys) { return { type: 'SET_LIST_UNCHECKED', listPrimaryKeys: listPrimaryKeys } } function setListLoading(listPrimaryKeys) { return { type: 'SET_LIST_LOADING', listPrimaryKeys: listPrimaryKeys } } function toggle(primaryKey, checked) { if ('select-all' === primaryKey) return toggleAll(checked); return function(dispatch, getState) { // var state = getState(); dispatch(setLoading(primaryKey)); p5UI__notifyAjaxCallback({type: 'warning', msg: 'TODO: toggle checkbox for row:' + primaryKey + ' ...'}); return new Promise(function (resolve, reject) { setTimeout(function () { var returnCode = Math.round(Math.random()); DBG && console.log('DBG::async toggle action: (pk:'+primaryKey+') fetched resultCode', returnCode); if (!returnCode) { reject("Error"); return; } resolve(); }, 1000); }).then(function () { p5UI__notifyAjaxCallback({type: 'warning', msg: 'TODO: toggle checkbox for row:' + primaryKey + '; return random success'}); DBG && console.log('DBG::async toggle action: (pk:'+primaryKey+') dispatch(SET_CHECKED)'); dispatch( checked ? setChecked(primaryKey) : setUnchecked(primaryKey) ); }).catch(function (e) { p5UI__notifyAjaxCallback({type: 'error', msg: 'TODO: toggle checkbox for row:' + primaryKey + '; return random fail - error: ' + e}); DBG && console.warn('DBG::async toggle action: (pk:'+primaryKey+') ERROR dispatch(SET_UNCHECKED)'); dispatch( checked ? setUnchecked(primaryKey) : setChecked(primaryKey) ); }); } } function setPrimaryKeys(listPrimaryKeys) { // TODO: should set list primaryKeys, change checkboxes to loading and fetch its state, then update gui DBG && console.log('DBG::setPrimaryKeys action: (pks:['+listPrimaryKeys.join(',')+'])...'); return function(dispatch, getState) { dispatch({ type: 'SET_PRIMARY_KEYS', listPrimaryKeys: listPrimaryKeys }); dispatch( setListLoading(listPrimaryKeys) ); p5UI__notifyAjaxCallback({type: 'warning', msg: 'TODO: update primary keys list:' + listPrimaryKeys.join(',') + '...'}); return new Promise(function (resolve, reject) { setTimeout(function () { var returnCode = 1; var listSelected = listPrimaryKeys.filter(function (pk) { return Math.round(Math.random()); }) DBG && console.log('DBG::setPrimaryKeys action: (pks:['+listPrimaryKeys.join(',')+']) fetched', { returnCode, listSelected }); if (!returnCode) { reject("Error"); return; } resolve(listSelected); }, 1000); }).then(function (listSelected) { p5UI__notifyAjaxCallback({type: 'warning', msg: 'TODO: update primary keys list:' + listPrimaryKeys.join(',') + '; return success'}); DBG && console.log('DBG::setPrimaryKeys action: (pks:['+listPrimaryKeys.join(',')+']) dispatch success'); var fullListPks = ['select-all'].concat(listPrimaryKeys); dispatch( setListUnchecked(fullListPks) ); dispatch( setListChecked(listSelected) ); }).catch(function (e) { p5UI__notifyAjaxCallback({type: 'error', msg: 'TODO: update primary keys list:' + listPrimaryKeys.join(',') + '; return fail - error: ' + e}); DBG && console.warn('DBG::setPrimaryKeys action: (pks:['+listPrimaryKeys.join(',')+']) ERROR dispatch error'); var fullListPks = ['select-all'].concat(listPrimaryKeys); dispatch( setListUnchecked(fullListPks) ); }); } } function toggleAll(checked) { var primaryKey = 'select-all'; return function(dispatch, getState) { // var state = getState(); dispatch(setLoading(primaryKey)); var state = getState(); var listPrimaryKeys = state.listPrimaryKeys; p5UI__notifyAjaxCallback({type: 'warning', msg: 'TODO: toggle all:' + listPrimaryKeys.join(',') + '...'}); return new Promise(function (resolve, reject) { setTimeout(function () { var returnCode = 1; DBG && console.log('DBG::setPrimaryKeys action: (pks:['+listPrimaryKeys.join(',')+']) fetched resultCode', returnCode); if (!returnCode) { reject("Error"); return; } resolve(); }, 1000); }).then(function () { p5UI__notifyAjaxCallback({type: 'warning', msg: 'TODO: toggle all:' + listPrimaryKeys.join(',') + '; return success'}); DBG && console.log('DBG::setPrimaryKeys action: (pks:['+listPrimaryKeys.join(',')+']) dispatch success'); var fullListPks = ['select-all'].concat(listPrimaryKeys) dispatch( checked ? setListChecked(fullListPks) : setListUnchecked(fullListPks) ); }).catch(function (e) { p5UI__notifyAjaxCallback({type: 'error', msg: 'TODO: toggle all:' + listPrimaryKeys.join(',') + '; return fail - error: ' + e}); DBG && console.warn('DBG::setPrimaryKeys action: (pks:['+listPrimaryKeys.join(',')+']) ERROR dispatch error'); var fullListPks = ['select-all'].concat(listPrimaryKeys) dispatch( checked ? setListUnchecked(fullListPks) : setListChecked(fullListPks) ); }); } } return { setPrimaryKeys: setPrimaryKeys, setChecked: setChecked, setUnchecked: setUnchecked, toggle: toggle } } global['P5UI__TableAjaxRowCheckbox'] = createReactClass({ // props.primaryKey: PropTypes.string.isRequired // props.store: Redux store with state: { isLoading bool, selected array of strings } // props.actions: Redux store actions getStateFromStore: function () { var state = this.props.store.getState(); return { disabled: this.props.disabled ? true : false, isLoading: (-1 !== state.loading.indexOf(this.props.primaryKey)), checked: (-1 !== state.selected.indexOf(this.props.primaryKey)) }; }, getInitialState: function() { return this.getStateFromStore(); }, componentDidMount: function () { DBG && console.log('DBG::P5UI__TableAjaxRowCheckbox::componentDidMount', { primaryKey: this.props.primaryKey }); this.unsubscribe = this.props.store.subscribe(this.storeUpdated) }, componentWillUnmount: function () { this.unsubscribe() }, storeUpdated: function () { DBG && console.log('DBG::P5UI__TableAjaxRowCheckbox::storeUpdated', { primaryKey: this.props.primaryKey }); this.setState(this.getStateFromStore()) }, shouldComponentUpdate: function (nextProps, nextState) { DBG && console.log('DBG::P5UI__TableAjaxRowCheckbox::shouldComponentUpdate', { primaryKey: this.props.primaryKey }, {state: this.state, nextState}); return ( this.state.isLoading !== nextState.isLoading || this.state.checked !== nextState.checked ); }, handleChange: function (checked) { // handleChange: function (event) { DBG && console.log('DBG::P5UI__TableAjaxRowCheckbox::handleChange', { primaryKey: this.props.primaryKey, checked: checked }); this.props.store.dispatch( this.props.actions.toggle( this.props.primaryKey, checked ) ) }, render: function () { DBG && console.log('DBG::P5UI__TableAjaxRowCheckbox::render', { primaryKey: this.props.primaryKey, checked: this.state.checked, isLoading: this.state.isLoading }); return h(p5UI__FieldCheckboxLoading, { size: 20, color: '#999', checked: this.state.checked, disabled: this.state.disabled, isLoading: this.state.isLoading, onChange: this.handleChange }); } }); var TableAjax = function() { var priv = {}; //private api var publ = {}; //public api priv.options = {}; var defaults = { namespace: '', url: '', //webservice url urlPost: false, //use POST instead of GET getCsvTheGeomAjaxUrl: '', removeTheGeomAjaxUrl: '', moreFunctionsCellAjaxUrl: '', editInlineSaveUrl: '', theGeomSaveUrl: '', pageSizeSave: '', hiddenColsSaveUrl: '', editInlineUrl: '', addUserTableFilterAjaxUrl: '', rmUserTableFilterAjaxUrl: '', hasAdditionalLayers: 0, labelHtml: '', debug: false, //prints debug info to console filter: false, //show filter row filterInit: false,// init filters data forceFilterInit: false, columnPicker: false, //show columnpicker checkboxes: false, //show body checkboxes actions: '', //holds action links pageSize: 10, //current pagesize pageSizes: [10, 20, 30, 40, 50, 'All'], //available pagesizes hidePagerOnEmpty: false, //removes pager if no rows types: { //type specific options string: {}, number: {}, bool: {}, date: {} }, rowFunctions: false, tblFunctions: false, specialFilterFunctions: false, filtersClean: false, router: false, longDesc: false, exportFields: [], mapEditor: false, // mapEditor visible or not mapEditorContainer: 'window' // 'window' or 'dock' }; var _uiNodeCont; // container holding table var _uiNode$Table; // the table node var _head; // table header var _headSort; // table header sorting row var _headFilter; // table header columns filter row var _headSpecialFilter; // table header special filter row var _bodyNode; // table body var _body; // TODO: table body need render? var _foot; // table footer var _inlineEditBox; // inline edit box with form var _popoverCell; // inline popover cell var _popoverCellCurrent; // inline popover cell var _popoverCellAjaxXhr; var _mapEditor; // map editor node var _mapEditorWrap; // map editor wrapper node var _mapEditorDialog; // map editor jquery ui dialog node var _state = {};// state - to replace variables below (date, ...) var _data; //columns and rows var _totalPages; // total pages var _currDpOp; // clicked datetimepicker operator var _filterFields = {}; // array with filter DOM elements var _filterTimeout; // timer for delayed filtering var _checkToggleChecked = false; // check-all toggle state var _exportFieldsSelect = {}; var _tableWidth; var _fieldWidgets = {}; /* initialize the plugin. */ priv.init = function() { _uiNodeCont = priv.options.id; _state = {};// init state _state.page = 1; _state.specialFilters = {}; _state.filters = {}; _state.filters.currSortCol = ''; _state.filters.currSortFlip = false; _state.filters.filterCols = {}; { // init events jQuery(_uiNodeCont).on('TableAjax:render', priv.onRender); jQuery(window).on('resize', priv.onWindowResize) } priv.initialRender();// set up _uiNode$... priv.options.types.string = ((priv.options.types || {}).string || {}); priv.options.types.number = ((priv.options.types || {}).number || {}); priv.options.types.bool = ((priv.options.types || {}).bool || {}); priv.options.types.date = ((priv.options.types || {}).date || {}); if (priv.options.mapEditorContainer != 'dock' && priv.options.mapEditorContainer != 'window') { priv.options.mapEditorContainer = 'window'; } if (priv.options.filterInit) { priv.setStateFilters(priv.options.filterInit); } if (priv.options.exportFields) { $.each(priv.options.exportFields, function(ind, col) { _exportFieldsSelect[col] = true; }); } if (location.hash) { priv.options.router() } else { priv.update(priv.options.router) } if (typeof priv.options.router == "function") { $(window).bind('hashchange', function() { priv.options.router.apply(this); }); } if (priv.options.checkboxes) { priv.options.selectedStore = createStoreWithThunkMiddleware(selectedStore) priv.options.selectedActions = selectedActions() } }; priv.onRender = function(e) { if (priv.options.debug || DBG) console.log('onRender.arguments:', arguments.length, arguments, 'e:', e); // console.log("priv.onRender arguments:", arguments); // console.trace(); if (arguments.length > 1) { for (var i=1; i