Commit 90a229a6 authored by bbaer's avatar bbaer
Browse files

Merge branch 'b9789-earlyRelease' of git.math.uzh.ch:typo3/qfq into b9789-earlyRelease

parents c3a3609b 41784427
Pipeline #3058 failed with stages
in 7 minutes and 19 seconds
...@@ -53,6 +53,7 @@ composer.lock ...@@ -53,6 +53,7 @@ composer.lock
/extension/Resources/Public/Css /extension/Resources/Public/Css
/extension/Resources/Public/fonts /extension/Resources/Public/fonts
/extension/Resources/Public/JavaScript /extension/Resources/Public/JavaScript
/extension/Tests/selenium/tmp
/fonts /fonts
/js /js
/node_modules /node_modules
...@@ -63,3 +64,7 @@ composer.lock ...@@ -63,3 +64,7 @@ composer.lock
/javascript/src/.vscode /javascript/src/.vscode
/javascript/src/npm-debug.log /javascript/src/npm-debug.log
/docker/chromedriver
/docker/geckodriver
/docker/run_qfq_docker.output
...@@ -65,7 +65,12 @@ selenium: ...@@ -65,7 +65,12 @@ selenium:
- mkdir "$SELENIUM_LOGS_PATH/$CI_COMMIT_SHORT_SHA" - mkdir "$SELENIUM_LOGS_PATH/$CI_COMMIT_SHORT_SHA"
- cp extension/Tests/selenium/selenium_logs/* "$SELENIUM_LOGS_PATH/$CI_COMMIT_SHORT_SHA/" - cp extension/Tests/selenium/selenium_logs/* "$SELENIUM_LOGS_PATH/$CI_COMMIT_SHORT_SHA/"
- echo "Selenium Logs copied to $SELENIUM_LOGS_PATH/$CI_COMMIT_SHORT_SHA/" - echo "Selenium Logs copied to $SELENIUM_LOGS_PATH/$CI_COMMIT_SHORT_SHA/"
- echo "Or download result (log/screenshot) in gitlab under CI/CD > Pipelines <job> > right side 'Artifacts'"
artifacts:
expire_in: 1 week
paths:
- extension/Tests/selenium/selenium_logs/
.. ================================================== .. ==================================================
.. Header hierachy .. Header hierarchy
.. == .. ==
.. -- .. --
.. ^^ .. ^^
...@@ -36,6 +36,56 @@ Features ...@@ -36,6 +36,56 @@ Features
Bug Fixes Bug Fixes
^^^^^^^^^ ^^^^^^^^^
Version 19.12.0
---------------
Date: <date>
Notes
^^^^^
* Switch the whole homepage to readonly: FormModeGlobal and STORE_USER
Features
^^^^^^^^
* TinyMCE: grey out controls when readonly.
* Mockup:
* Update files to get CSS & JS files from their own directory structure (not an installed QFQ extension).
* Add fontawesome, tablesorter to mockup 'formCheckbox.html'.
* CI: Download selenium logs (only failed) under artifacts.
* Dev: .gitignore: exclude some docker & selenium.
* Merge Selenium Python Checks into Master.
* #9686 / html decode and sanitize an export filename to become the 'save as'-filename.
* #9666 / min-width for extraButtonInfo.
* FormEditor: optimize minWidth for 'rowLabelInputNote' field.
Bug Fixes
^^^^^^^^^
* #9720 / Checkbox dynamic update varoious settings:
* Multi Plain Vertical & Horizontal, Checkbox Multi BS.
* Fixed that label of 'checkbox' are bold and label of 'checkbox-inline' are normal.
* #7974 / TinyMCE: ReadOnly.
* #9424 / modeSql: skip if it starts with '#'.
* #9531 / File Upload Required.
* #9674 / Select Required Dynamic Update.
* #9678 / textarea now trigger DynamicUpdate.
* #9679 / FormModeGlobal: add STORE_USER - system wide readonly.
* #9690 / Select Required.
* #9691 / Checkbox: dynamic update > readonly. HTML ID for checkbox elements. Dynamic update switch 'readonly' for 'checkbox plain multi' and 'radio plain multi'.
* #9692 / Keyboard Select Checkbox.
* #9720 / Checkbox: Various setups with dynamic update.
* #9733 / Identiy different tabs. Record lock for same tab will always be granted.
* #9734 / Fix 'dirty lock release' - leaving a dirty form without closing, leaves a stale lock record. Added a releaselock() before window.unload. Dirty remove on goBack.
* #9735 / File Delete: no dirty trigger.
* Download / PDF merge: skip leading errors, interpret only 'Could not merge encrypted files'.
* DragAndDrop broken: after refactoring Support.php, the dragAndDrop was broken - missed init of '$store'.
Version 19.11.3 Version 19.11.3
--------------- ---------------
...@@ -49,14 +99,17 @@ Features ...@@ -49,14 +99,17 @@ Features
* #8886 / Check pattern: after focus lost. * #8886 / Check pattern: after focus lost.
* #9655 / Checkboxes and radios now defined with a min-width in horizontal plain mode. * #9655 / Checkboxes and radios now defined with a min-width in horizontal plain mode.
* #9617: * #9617 / formModeGlobal:
* Two modes now implemented 'requiredOff' and 'requiredOffButMark'. * Two modes of 'formModeGlobal' available: 'requiredOff' and 'requiredOffButMark'.
* formModeGlobal: renamed skipRequiredCheck to requiredOffButMark . * 'requiredOffButMark':
* Keep required marks after save.
* Stop hiding helpblocks per default, set with class qfq-only-active-error.
* Radio: new class 'qfq-disabled' if readonly is set. softer blue. mark disabled - changed hover. text in darker orange. simple-error renamed to qfq-notify - removed box around error. * Renamed temporary 'skipRequiredCheck' to 'requiredOffButMark'.
* Keep required marks after save.
* Stop hiding helpblocks per default, set with class qfq-only-active-error.
* Radio: new class 'qfq-disabled' if readonly is set. Softer blue. Mark disabled - changed hover. Text in darker orange.
Simple-error renamed to qfq-notify - removed box around error.
* New default class for 'form' tag: 'qfq-notify'. * New default class for 'form' tag: 'qfq-notify'.
* Manual.rst: Add info for 'letter-no-break'. * Manual.rst: Add info for 'letter-no-break'.
* Add validator.js to list of used packages. * Add validator.js to list of used packages.
...@@ -86,21 +139,17 @@ Date: 25.11.2019 ...@@ -86,21 +139,17 @@ Date: 25.11.2019
Notes Notes
^^^^^ ^^^^^
* Fantastic new formModeGlobal=skipRequiredCheck: fill's '{{allRequiredGiven:V}}' before save to 1 (all given) else 0. * Enhance formModeGlobal=requiredOff/-ButMark (temporarily skipRequiredCheck): fill's '{{allRequiredGiven:V}}' before
save to 1 (all given) else 0.
Offers user to save form, even if not all required data are given and offers application logic to check easily if all Offers user to save form, even if not all required data are given and offers application logic to check easily if all
required fields has been fillled. required fields has been filled.
* formModeGlobal=requiredOff is now deprecated but will still work.
Features Features
^^^^^^^^ ^^^^^^^^
* #9526 / Mark required fields more visible * #9526 / Mark required fields more visible.
* #9617 / Improve 'formModeGlobal=requiredOff'. * #9617 / Improve 'formModeGlobal=requiredOff'.
* New mode name 'skipRequiredCheck'.
* 'requiredOff' is replaced by 'skipRequiredCheck' and now deprecated.
* Add documentation for 'skipRequiredCheck:S' & 'allRequiredGiven:V'
* Feature `Form.formModeGlobal` implemented - STORE_SIP overwrites form definition. * Feature `Form.formModeGlobal` implemented - STORE_SIP overwrites form definition.
* New STORE_VAR variable 'allRequiredGiven'. Becomes '1' if all required fields are given, else 0. * New STORE_VAR variable 'allRequiredGiven'. Becomes '1' if all required fields are given, else 0.
...@@ -114,11 +163,11 @@ Bug Fixes ...@@ -114,11 +163,11 @@ Bug Fixes
* #7639 / subrecord drag n drop: * #7639 / subrecord drag n drop:
* `orderInterval` has not been respected. * `orderInterval` has not been respected.
* Update Manual.rst * Update Manual.rst.
* Fake STORE_SIP so it can be used during processing sql1. * Fake STORE_SIP so it can be used during processing sql1.
* The record, currently loaded into form, is available via STORE_RECORD. * The record, currently loaded into form, is available via STORE_RECORD.
* Check for id/_id and ord/_ord * Check for id/_id and ord/_ord.
* Throw meaningful exception if missing 'id' or 'ord' * Throw meaningful exception if missing 'id' or 'ord'.
* Fixes bug that no mime_type_content is called if there is on file. * Fixes bug that no mime_type_content is called if there is on file.
* Fix broken regex101 url. * Fix broken regex101 url.
......
...@@ -54,12 +54,12 @@ Neue Versionsnummer ...@@ -54,12 +54,12 @@ Neue Versionsnummer
* Update the version number in this document (topic 6) * Update the version number in this document (topic 6)
* Commit & Push new version changes to master branch: * Commit & Push new version changes to master branch:
New version 19.11.3 New version 19.12.0
6) **New Tag**: 6) **New Tag**:
git tag v19.11.3 git tag v19.12.0
git push -u origin v19.11.3 git push -u origin v19.12.0
7) Tickets: 7) Tickets:
* Schliessen und der QFQ Version zuweisen. * Schliessen und der QFQ Version zuweisen.
......
...@@ -518,6 +518,13 @@ On `"conflict"` the Client opens the alert as modal dialog (user can't change an ...@@ -518,6 +518,13 @@ On `"conflict"` the Client opens the alert as modal dialog (user can't change an
form' button. form' button.
On `"conflict_allow_force"` the Client opens the alert non-modal (default). On `"conflict_allow_force"` the Client opens the alert non-modal (default).
### tabUniqId
Every tab get's a uniq id (timestamp) on page load: window.name.
This 'tabUniqId' is saved in dirty record on lock acquire.
On page reload, when the 'release' comes after 'acquire' (unwished async behaviour), the locking is skipped (if same user
session) - on reload there is no variable 'tabUniqId'. On real lock acquire, the tab ID is compared and will be denied
if not matching. The 'tabUniqId' might not work in IE - doesn't matter: it's a seldom special situation.
### Drag And Drop (sort) ### Drag And Drop (sort)
......
**To run/update SELENIUM test, please check docker/README.md.**
Create new Tests
================
* Set up new forms and reports.
* Dump new database.
* Copy dump to become now initial database
* Update SELENIUM Python tests
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
.. ;; .. ;;
.. ,, .. ,,
.. ..
.. -------------------------------------------------- .. --------------------------------------------used to the update the records specified ------
.. Best Practice T3 reST: https://docs.typo3.org/m/typo3/docs-how-to-document/master/en-us/WritingReST/CheatSheet.html .. Best Practice T3 reST: https://docs.typo3.org/m/typo3/docs-how-to-document/master/en-us/WritingReST/CheatSheet.html
.. Reference: https://docs.typo3.org/m/typo3/docs-how-to-document/master/en-us/WritingReST/Index.html .. Reference: https://docs.typo3.org/m/typo3/docs-how-to-document/master/en-us/WritingReST/Index.html
.. Italic *italic* .. Italic *italic*
...@@ -7618,7 +7618,7 @@ A dedicated `Form`, without any `FormElements`, is used to define the reorder lo ...@@ -7618,7 +7618,7 @@ A dedicated `Form`, without any `FormElements`, is used to define the reorder lo
Fields: Fields:
* Name: <custom form name> - used in Part 1 in the `_data-dnd-api` variable. * Name: <custom form name> - used in Part 1 in the `_data-dnd-api` variable.
* Table: <table with the element records> - used to the update the records specified by `dragAndDropOrderSql`. * Table: <table with the element records> - used to update the records specified by `dragAndDropOrderSql`.
* Parameter: * Parameter:
...@@ -7663,6 +7663,7 @@ QFQ CSS Classes ...@@ -7663,6 +7663,7 @@ QFQ CSS Classes
* `qfq-100` - assigned to different tags, makes an element 'width: 100%'. * `qfq-100` - assigned to different tags, makes an element 'width: 100%'.
* `qfq-left`- assigned to different tags, Text align left. * `qfq-left`- assigned to different tags, Text align left.
* `qfq-sticky` - assigned to `<thead>`, makes the header sticky. * `qfq-sticky` - assigned to `<thead>`, makes the header sticky.
* `qfq-badge`, `qfq-badge-error`, `qfq-badge-warning`, `qfq-badge-success`, `qfq-badge-info`, `qfq-badge-invers` - colorized BS3 badges.
* `letter-no-break` - assigned to a `div` will protect a paragraph (CSS: page-break-before: avoid;) not to break around * `letter-no-break` - assigned to a `div` will protect a paragraph (CSS: page-break-before: avoid;) not to break around
a page border (converted to PDF via wkhtml). Take care that `qfq-letter.css` is included in TypoScript setup. a page border (converted to PDF via wkhtml). Take care that `qfq-letter.css` is included in TypoScript setup.
......
...@@ -36,6 +36,57 @@ Features ...@@ -36,6 +36,57 @@ Features
Bug Fixes Bug Fixes
^^^^^^^^^ ^^^^^^^^^
Version 19.12.0
---------------
Date: 17.12.2019
Notes
^^^^^
* Switch the whole homepage to readonly: FormModeGlobal and STORE_USER
Features
^^^^^^^^
* TinyMCE: grey out controls when readonly.
* Mockup:
* Update files to get CSS & JS files from their own directory structure (not an installed QFQ extension).
* Add fontawesome, tablesorter to mockup 'formCheckbox.html'.
* CI: Download selenium logs (only failed) under artifacts.
* Dev: .gitignore: exclude some docker & selenium.
* Merge Selenium Python Checks into Master.
* #9686 / html decode and sanitize an export filename to become the 'save as'-filename.
* #9666 / min-width for extraButtonInfo.
* FormEditor: optimize minWidth for 'rowLabelInputNote' field.
Bug Fixes
^^^^^^^^^
* #9720 / Checkbox dynamic update varoious settings:
* Multi Plain Vertical & Horizontal, Checkbox Multi BS.
* Fixed that label of 'checkbox' are bold and label of 'checkbox-inline' are normal.
* #7974 / TinyMCE: ReadOnly.
* #9424 / modeSql: skip if it starts with '#'.
* #9531 / File Upload Required.
* #9674 / Select Required Dynamic Update.
* #9678 / textarea now trigger DynamicUpdate.
* #9679 / FormModeGlobal: add STORE_USER - system wide readonly.
* #9690 / Select Required.
* #9691 / Checkbox: dynamic update > readonly. HTML ID for checkbox elements. Dynamic update switch 'readonly' for 'checkbox plain multi' and 'radio plain multi'.
* #9692 / Keyboard Select Checkbox.
* #9720 / Checkbox: Various setups with dynamic update.
* #9733 / Identiy different tabs. Record lock for same tab will always be granted.
* #9734 / Fix 'dirty lock release' - leaving a dirty form without closing, leaves a stale lock record. Added a releaselock() before window.unload. Dirty remove on goBack.
* #9735 / File Delete: no dirty trigger.
* Download / PDF merge: skip leading errors, interpret only 'Could not merge encrypted files'.
* DragAndDrop broken: after refactoring Support.php, the dragAndDrop was broken - missed init of '$store'.
Version 19.11.3 Version 19.11.3
--------------- ---------------
......
...@@ -21,8 +21,8 @@ ...@@ -21,8 +21,8 @@
; you can use in 'conf.py' ; you can use in 'conf.py'
project = QFQ - Quick Form Query project = QFQ - Quick Form Query
version = 19.11 version = 19.12
release = 19.11.3 release = 19.12.0
t3author = Carsten Rose t3author = Carsten Rose
copyright = since 2017 by the author copyright = since 2017 by the author
......
...@@ -440,6 +440,16 @@ module.exports = function (grunt) { ...@@ -440,6 +440,16 @@ module.exports = function (grunt) {
expand: true, expand: true,
flatten: true flatten: true
}, },
{
cwd: 'node_modules/font-awesome/css/',
src: [
'font-awesome.min.css'
],
dest: 'css/',
filter: 'isFile',
expand: true,
flatten: true
},
{ {
cwd: 'node_modules/font-awesome/fonts/', cwd: 'node_modules/font-awesome/fonts/',
expand: true, expand: true,
...@@ -448,6 +458,15 @@ module.exports = function (grunt) { ...@@ -448,6 +458,15 @@ module.exports = function (grunt) {
], ],
dest: typo3_fonts, dest: typo3_fonts,
flatten: true flatten: true
},
{
cwd: 'node_modules/font-awesome/fonts/',
expand: true,
src: [
'*'
],
dest: 'fonts/',
flatten: true
} }
] ]
}, },
......
This diff is collapsed.
This diff is collapsed.
...@@ -772,6 +772,11 @@ EOF; ...@@ -772,6 +772,11 @@ EOF;
if ($wrapName == FE_WRAP_LABEL) { if ($wrapName == FE_WRAP_LABEL) {
$wrapArray[0] = Support::insertAttribute($wrapArray[0], 'style', 'text-align: ' . $formElement[F_FE_LABEL_ALIGN] . ';'); // might be problematic, if there is already a 'class' defined. $wrapArray[0] = Support::insertAttribute($wrapArray[0], 'style', 'text-align: ' . $formElement[F_FE_LABEL_ALIGN] . ';'); // might be problematic, if there is already a 'class' defined.
} }
// Insert 'required="required"' for checkboxes and radios
if ($wrapName == FE_WRAP_INPUT && $formElement[FE_MODE] == FE_MODE_REQUIRED &&
($formElement[FE_TYPE] == FE_TYPE_CHECKBOX || $formElement[FE_TYPE] == FE_TYPE_RADIO)) {
$wrapArray[0] = Support::insertAttribute($wrapArray[0], 'required', 'required'); // might be problematic, if there is already a 'class' defined.
}
} }
return $wrapArray[0] . $htmlElement . $wrapArray[1]; return $wrapArray[0] . $htmlElement . $wrapArray[1];
...@@ -807,7 +812,7 @@ EOF; ...@@ -807,7 +812,7 @@ EOF;
// Label // Label
if ($formElement[FE_BS_LABEL_COLUMNS] != '0') { if ($formElement[FE_BS_LABEL_COLUMNS] != '0') {
$htmlLabel = $this->buildLabel($htmlFormElementName, $formElement[FE_LABEL], $addClassRequired[FE_LABEL] ?? ''); $htmlLabel = HelperFormElement::buildLabel($htmlFormElementName, $formElement[FE_LABEL], $addClassRequired[FE_LABEL] ?? '');
} }
$html .= $this->customWrap($formElement, $htmlLabel, FE_WRAP_LABEL, $formElement[FE_BS_LABEL_COLUMNS], $html .= $this->customWrap($formElement, $htmlLabel, FE_WRAP_LABEL, $formElement[FE_BS_LABEL_COLUMNS],
......
...@@ -1252,6 +1252,7 @@ const FE_INPUT_AUTOCOMPLETE = 'autocomplete'; ...@@ -1252,6 +1252,7 @@ const FE_INPUT_AUTOCOMPLETE = 'autocomplete';
const FE_TMP_EXTRA_BUTTON_HTML = '_extraButtonHtml'; // will be filled on the fly during building extrabutton const FE_TMP_EXTRA_BUTTON_HTML = '_extraButtonHtml'; // will be filled on the fly during building extrabutton
const FE_CHECKBOX_CHECKED = 'checked'; const FE_CHECKBOX_CHECKED = 'checked';
const FE_CHECKBOX_UNCHECKED = 'unchecked'; const FE_CHECKBOX_UNCHECKED = 'unchecked';
const FE_ITEM_LIST = 'itemList';
const FE_RECORD_DESTINATION_TABLE = 'recordDestinationTable'; const FE_RECORD_DESTINATION_TABLE = 'recordDestinationTable';
const FE_RECORD_SOURCE_TABLE = 'recordSourceTable'; const FE_RECORD_SOURCE_TABLE = 'recordSourceTable';
const FE_TRANSLATE_ID_COLUMN = 'translateIdColumn'; const FE_TRANSLATE_ID_COLUMN = 'translateIdColumn';
...@@ -1328,6 +1329,8 @@ const FE_ORDER_INTERVAL_DEFAULT = '10'; ...@@ -1328,6 +1329,8 @@ const FE_ORDER_INTERVAL_DEFAULT = '10';
const FE_ORDER_COLUMN = 'orderColumn'; const FE_ORDER_COLUMN = 'orderColumn';
const FE_DND_TABLE = 'dndTable'; const FE_DND_TABLE = 'dndTable';
const FE_TMP_CLASS_OPTION = '_classOption';
const MODE_ENCODE = 'encode'; const MODE_ENCODE = 'encode';
const MODE_DECODE = 'decode'; const MODE_DECODE = 'decode';
const MODE_NONE = 'none'; const MODE_NONE = 'none';
...@@ -1812,6 +1815,7 @@ const DIRTY_API_ACTION_EXTEND = 'extend'; ...@@ -1812,6 +1815,7 @@ const DIRTY_API_ACTION_EXTEND = 'extend';
const LOCK_NOT_FOUND = 0; const LOCK_NOT_FOUND = 0;
const LOCK_FOUND_OWNER = 1; const LOCK_FOUND_OWNER = 1;
const LOCK_FOUND_CONFLICT = 2; const LOCK_FOUND_CONFLICT = 2;
const TAB_UNIQ_ID = 'tabUniqId'; // Currently only only a uniq identifier: no values stored behind the identifier - might change.
// AutoCron // AutoCron
const AUTOCRON_MAX_AGE_MINUTES = 10; const AUTOCRON_MAX_AGE_MINUTES = 10;
...@@ -1949,3 +1953,20 @@ const SETTING_TABLESORTER_MODE = 'mode'; ...@@ -1949,3 +1953,20 @@ const SETTING_TABLESORTER_MODE = 'mode';
const SETTING_TABLESORTER_MODE_DELETE = 'delete'; const SETTING_TABLESORTER_MODE_DELETE = 'delete';
const SETTING_TABLESORTER_CLEAR = 'Clear'; const SETTING_TABLESORTER_CLEAR = 'Clear';
// Object: Type
const T_LABEL = 't_label';
const T_INPUT = 't_input';
const T_NOTE = 't_note';
const T_ = 't_note';
// Object: Item
const I_TYPE = 'type';
const I_ID = 'id';
const I_VALUE = 'value';
const I_CLASS = 'class';
const I_ATTRIBUTE = 'attribute';
// Object: extra for checkboxes
const I_CHECKED = 'checked';
const I_UNCHECKED = 'unchecked';
...@@ -185,6 +185,10 @@ $UPDATE_ARRAY = array( ...@@ -185,6 +185,10 @@ $UPDATE_ARRAY = array(
"ALTER TABLE `Setting` CHANGE `created` `created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP; ", "ALTER TABLE `Setting` CHANGE `created` `created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP; ",
], ],
'19.12.0' => [
"ALTER TABLE `Dirty` ADD `tabUniqId` VARCHAR(32) NOT NULL AFTER `recordHashMd5`;",
],
); );
......
This diff is collapsed.
...@@ -8,13 +8,12 @@ ...@@ -8,13 +8,12 @@
namespace IMATHUZH\Qfq\Core\Form; namespace IMATHUZH\Qfq\Core\Form;
use IMATHUZH\Qfq\Core\Store\Session;
use IMATHUZH\Qfq\Core\Store\Store;
use IMATHUZH\Qfq\Core\Database\Database; use IMATHUZH\Qfq\Core\Database\Database;
use IMATHUZH\Qfq\Core\Helper\OnArray;
use IMATHUZH\Qfq\Core\Store\Client; use IMATHUZH\Qfq\Core\Store\Client;
use IMATHUZH\Qfq\Core\Store\Session;
use IMATHUZH\Qfq\Core\Store\Sip; use IMATHUZH\Qfq\Core\Store\Sip;
use IMATHUZH\Qfq\Core\Helper\OnArray; use IMATHUZH\Qfq\Core\Store\Store;
/** /**
* Class Dirty * Class Dirty
...@@ -27,7 +26,7 @@ use IMATHUZH\Qfq\Core\Helper\OnArray; ...@@ -27,7 +26,7 @@ use IMATHUZH\Qfq\Core\Helper\OnArray;
class Dirty { class Dirty {
/** /**
* @var Database instantiated class * @var Database[] - Array of Database instantiated class
*/ */
protected $dbArray = null; protected $dbArray = null;
...@@ -134,7 +133,7 @@ class Dirty { ...@@ -134,7 +133,7 @@ class Dirty {
switch ($this->client[API_LOCK_ACTION]) { switch ($this->client[API_LOCK_ACTION]) {
case API_LOCK_ACTION_LOCK: case API_LOCK_ACTION_LOCK:
case API_LOCK_ACTION_EXTEND: case API_LOCK_ACTION_EXTEND:
$answer = $this->acquireDirty($recordId, $tableVars, $this->client[DIRTY_RECORD_HASH_MD5]); $answer = $this->acquireDirty($recordId, $tableVars, $this->client[DIRTY_RECORD_HASH_MD5], $this->client[TAB_UNIQ_ID]);
break; break;
case API_LOCK_ACTION_RELEASE: case API_LOCK_ACTION_RELEASE:
$answer = $this->checkDirtyAndRelease(FORM_SAVE, $tableVars[F_RECORD_LOCK_TIMEOUT_SECONDS], $tableVars[F_DIRTY_MODE], $tableVars[F_TABLE_NAME], $tableVars[F_PRIMARY_KEY], $recordId); $answer = $this->checkDirtyAndRelease(FORM_SAVE, $tableVars[F_RECORD_LOCK_TIMEOUT_SECONDS], $tableVars[F_DIRTY_MODE], $tableVars[F_TABLE_NAME], $tableVars[F_PRIMARY_KEY], $recordId);
...@@ -153,10 +152,13 @@ class Dirty { ...@@ -153,10 +152,13 @@ class Dirty {
* @param array $tableVars * @param array $tableVars
* @param string $recordHashMd5 * @param string $recordHashMd5
* *
* @param $tabUniqId
* @return array * @return array
* @throws \CodeException * @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/ */
private function acquireDirty($recordId, array $tableVars, $recordHashMd5) { private function acquireDirty($recordId, array $tableVars, $recordHashMd5, $tabUniqId) {
$tableName = $tableVars[F_TABLE_NAME]; $tableName = $tableVars[F_TABLE_NAME];
$primaryKey = $tableVars[F_PRIMARY_KEY]; $primaryKey = $tableVars[F_PRIMARY_KEY];
...@@ -179,10 +181,14 @@ class Dirty { ...@@ -179,10 +181,14 @@ class Dirty {
$answer = [API_STATUS => 'success', API_MESSAGE => '']; $answer = [API_STATUS => 'success', API_MESSAGE => ''];
} else { } else {
// No dirty record found. // No dirty record found.
$answer = $this->writeDirty($this->client[SIP_SIP], $recordId, $tableVars, $feUser, $rcMd5); $answer = $this->writeDirty($this->client[SIP_SIP], $recordId, $tableVars, $feUser, $rcMd5, $tabUniqId);
} }
} else { } else {
$answer = $this->conflict($recordDirty, $formDirtyMode, $primaryKey); if ($tabUniqId == $recordDirty[TAB_UNIQ_ID]) {
$answer = [API_STATUS => 'success', API_MESSAGE => ''];
} else {
$answer = $this->conflict($recordDirty, $formDirtyMode, $primaryKey);
}