diff --git a/CHANGELOG.md b/CHANGELOG.md
index 69bee416733fb2a5d668b1a0b749d91c5ebfe3ea..7f6c59c50137d82263e90c166e7cadf237b2e530 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1203,7 +1203,7 @@ Bug Fixes
 
  * Dynamic Update has been broken since implementing of 'element-update' (#3180). Now both methods, 'element-update' and 'form-update' should be fine.
  * qfq-bs.css.less: Fixed problem with 'typeahead input elements' not expanded to Bootstrap column width. Changed
-   Layout/Design Typeahead drop-down box. Add hoover for the drop-down box with a blue background
+   Layout/Design Typeahead drop-down box. Add hover for the drop-down box with a blue background
  * AbstractBuildForm.php: #3374 - textarea elements now contains 'maxlength' attribute.
  * BuildFormBootstrap.php: wrapping of optional 'submitButtonText' now done with the 'per form' values.
  * typeahead.php: if there is an exception, the message body is sent as regular 'content' for the drop-down box. At the
diff --git a/doc/DRAGANDDROP.md b/doc/DRAGANDDROP.md
new file mode 100644
index 0000000000000000000000000000000000000000..14d9b9cd5216ac4d23fdc6d8b618fc8810067b7b
--- /dev/null
+++ b/doc/DRAGANDDROP.md
@@ -0,0 +1,22 @@
+# Drag And Drop
+
+## Sort
+Initialize a dnd container by adding the class "qfq-dnd"
+
+Set container object class to `class="qfq-dnd qfq-dnd-sort"`.
+
+Add the data elements: `data-dnd-api="url"` and `data-dnd-key="key"`.
+
+For the children inside of the container (just the first children):
+add `data-dnd-id` to a reference you can handle (probably record id).
+
+Request will be sent containing following GET variables:
+
+* dragId = `data-dnd-id` of the dragged object,
+* dragPosition = client internal old position of the dragged object.
+* setTo = "after" or "before",
+* hoverId = `data-dnd-id` id of the element the dragged element is now hovering, meaning before or after.
+* hoverPosition = client internal position of currently hovered element.
+
+
+Example: http://something/bla?dragId=uno&dragPosition=1&setTo=before&hoverId=tre&hoverPosition=3
\ No newline at end of file
diff --git a/doc/PROTOCOL.md b/doc/PROTOCOL.md
index 6f7b93bc536bf8b7976f3e6d711549d3c100ca06..40565f2079627978752e0c71af46dea30a6285fe 100644
--- a/doc/PROTOCOL.md
+++ b/doc/PROTOCOL.md
@@ -73,11 +73,11 @@ the Client by adding following name/value pairs to the response JSON
 Stream
 
 	{
-		"status": "error",
-		...
-	   "field-name": "<field name>",
-		"field-message": "<message>",
-		...
+        "status": "error",
+        ...
+        "field-name": "<field name>",
+        "field-message": "<message>",
+        ...
 	}
 	
 Only one validation failure per request can be reported to Client.
@@ -465,7 +465,7 @@ Request Method
 :	GET
 
 URL Parameters
-:	`s=<SIP>`   (form, r)
+:  `s=<SIP>`   (form, r)
 :  `action=lock`, `action=extend`, `action=release>`
 :  `recordHashMd5=<value of hidden form element 'recordHashMd5'>`
 
@@ -489,24 +489,28 @@ On `"conflict"` the Client opens the alert as modal dialog (user can't change an
 form' button.
 On `"conflict_allow_force"` the Client opens the alert non-modal (default).
 
-## Drag And Drop
-Initialize a dnd container by adding the class "qfq-dnd"
 
-### Sorting
-Set container object class to "qfq-dnd qfq-dnd-sort".
-Add the data elements: data-dnd-api="url" and data-dnd-key="key"
-For the childrens inside of the container (just the first children):
-add data-dnd-id to a reference you can handle (probably SQL id)
+### Drag And Drop (sort)
 
-Request will be sent containing following information:
-{"id":2,"value":50,"position":5,"setTo":"after","otherId":4}
+Request
+:	api/dragAndDrop.php
 
-dragId = id of the dragged object
-dragPosition = counted original position of the dragged object
-setTo = "after" or "before"
-hoverId = id of the element the dragged element is now hovering, meaning before or after.
-hoverPosition = Position of currently hovered element.
+Request Method
+:	GET
+
+URL Parameters:
+
+: `s=<SIP>`  (`form=<formname>`)
+:  
+: `dragId=<data-dnd-id of dragged element>`
+: `dragPosition=<client internal position (numbering) of element before dragging>`
+: `setTo=before`, `setTo=after`
+: `hoverId=<data-dnd-id of dragged element>`
+: `hoverPosition=<client internal position (numbering) of element after dragging>`
 
+Server Response
+:   The response contains at least a [Minimal Response]. In addition, a
+	[HTML Element Response] (need to be defined) may be included.
   
 ## Glossary
 
diff --git a/extension/Documentation/Manual.rst b/extension/Documentation/Manual.rst
index 353e8e9ea3f7bccee6bcf629c9283d38a50bfd5d..1d2209d9a555ef7d4ccb3df03c1e300af63e5c16 100644
--- a/extension/Documentation/Manual.rst
+++ b/extension/Documentation/Manual.rst
@@ -6218,8 +6218,95 @@ E.g.::
 
     10.sql = SELECT "p:home&r=0|t:Home|c:qfq-100 qfq-left" AS _pagev
 
-Examples
---------
+
+Drag and drop
+-------------
+
+Sort/order elements
+^^^^^^^^^^^^^^^^^^^
+
+Manually sorting and ordering of elements via `HTML5 drag and drop` is supported via QFQ. Any sortable element
+should be represented by a database record with an order column. If the elements are unordered, they will be ordered after
+the first manual move of an element.
+
+Functionality is divided into:
+
+* Display list: the records will be displayed via QFQ/report.
+* Update database: updates of the order column are managed by a specific 'drag and drop' definition Form.
+
+Part 1: Display list
+''''''''''''''''''''
+
+Display the list of elements via a regular QFQ content record. All 'drag and drop' elements have to be nested by an HTML
+element:
+
+* With `class="qfq-dnd-sort"`.
+* With an automatically SIP protected form name: `{{'form=<form name>' AS _data-dnd-api}}`
+* Only direct children of such element can be dragged.
+* Every children needs a unique identifier `data-dnd-id="<unique>"`. Typically this is the corresponding record id.
+* The record needs a dedicated order column, which will be updated through API calls in time.
+
+The final HTML output: ::
+
+    <div class="qfq-dnd-sort" data-dnd-api="typo3conf/ext/qfq/qfq/api/dragAndDrop.php?s=badcaffee1234">
+        <div class="anyClass" id="<uniq1>" data-dnd-id="55">
+            Numbero Uno
+        </div>
+        <div class="anyClass" id="<uniq2>" data-dnd-id="18">
+            Numbero Deux
+        </div>
+        <div class="anyClass" id="<uniq3>" data-dnd-id="27">
+            Numbero Tre
+        </div>
+    </div>
+
+
+A typical QFQ report which generates those HTML: ::
+
+    10 {
+      sql = SELECT '<div id="anytag-', n.id,'" data-dnd-id="', n.id,'">' , n.note, '</div>'
+                   FROM Note AS n
+                   ORDER BY n.ord
+
+      head = <div class="qfq-dnd-sort" {{'form=dndSortNote&grId=28' AS _data-dnd-api}}>
+      tail = </div>
+    }
+
+
+Part 2: Update database
+'''''''''''''''''''''''
+
+A dedicated `Form`, without any `FormElements`, is needed to define the database update definition.
+
+Fields:
+
+* 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`.
+
+* Parameter:
+
++-------------------------------------+--------------------------------------------------------------------------------+
+| Attribute                           | Description                                                                    |
++=====================================+================================================================================+
+| orderInterval = <number>            | Optional. By default '10'. Might be any number > 0.                            |
++-------------------------------------+--------------------------------------------------------------------------------+
+| orderColumn = <column name>         | Optional. By default 'ord'.                                                    |
++-------------------------------------+--------------------------------------------------------------------------------+
+| dragAndDropOrderSql =                                 | Query to selects the *same* records as the report in the     |
+| {{!SELECT n.id AS id, n.ord AS ord FROM Note AS n     | same *order!* Inconsistencies results in sort differences.   |
+| ORDER BY n.ord}}                                      | The columns `id` and `ord` are *mandatory.*                  |
++-------------------------------------------------------+--------------------------------------------------------------+
+
+The form related to the example of part 1: ::
+
+  Form.name: dndSortNote
+  Form.table: Note
+  Form.parameter: orderInterval = 1
+  Form.parameter: orderColumn = ord
+  Form.parameter: dragAndDropOrderSql = {{!SELECT n.id AS id, n.ord AS ord FROM Note AS n WHERE n.grId={{grId:S0}} ORDER BY n.ord}}
+
+Report Examples
+---------------
 
 The following section gives some examples of typical reports
 
diff --git a/extension/qfq/api/draganddrop.php b/extension/qfq/api/dragAndDrop.php
similarity index 81%
rename from extension/qfq/api/draganddrop.php
rename to extension/qfq/api/dragAndDrop.php
index f5e57c466ef0872c8f9552ea5f6b3295d9811979..f4b8d21895ebd490bda0bf5ef90e26e2d44d7ddb 100644
--- a/extension/qfq/api/draganddrop.php
+++ b/extension/qfq/api/dragAndDrop.php
@@ -13,6 +13,10 @@ use qfq;
 require_once(__DIR__ . '/../qfq/store/Store.php');
 require_once(__DIR__ . '/../qfq/Constants.php');
 require_once(__DIR__ . '/../qfq/QuickFormQuery.php');
+//require_once(__DIR__ . '/../qfq/exceptions/UserFormException.php');
+//require_once(__DIR__ . '/../qfq/exceptions/CodeException.php');
+//require_once(__DIR__ . '/../qfq/exceptions/DbException.php');
+//require_once(__DIR__ . '/../qfq/exceptions/ErrorHandler.php');
 
 
 /**
@@ -55,24 +59,14 @@ try {
 
     $data = $qfq->dragAndDrop();
 
-//    $answer[API_REDIRECT] = $qfq->getForwardMode($answer[API_REDIRECT_URL]);
     $answer[API_STATUS] = API_ANSWER_STATUS_SUCCESS;
-    $answer[API_MESSAGE] = 'load: success';
-    $answer[API_FORM_UPDATE] = $data[API_FORM_UPDATE];
-    $answer[API_ELEMENT_UPDATE] = $data[API_ELEMENT_UPDATE];
+    $answer[API_MESSAGE] = 'reorder: success';
+//    $answer[API_FORM_UPDATE] = $data[API_FORM_UPDATE];
+//    $answer[API_ELEMENT_UPDATE] = $data[API_ELEMENT_UPDATE];
 //    unset($answer[API_FORM_UPDATE][API_ELEMENT_UPDATE]);
 
 } catch (qfq\UserFormException $e) {
     $answer[API_MESSAGE] = $e->formatMessage();
-
-    $val = Store::getVar(SYSTEM_FORM_ELEMENT, STORE_SYSTEM);
-    if ($val !== false)
-        $answer[API_FIELD_NAME] = $val;
-
-    $val = Store::getVar(SYSTEM_FORM_ELEMENT_MESSAGE, STORE_SYSTEM);
-    if ($val !== false)
-        $answer[API_FIELD_MESSAGE] = $val;
-
 } catch (qfq\CodeException $e) {
     $answer[API_MESSAGE] = $e->formatMessage();
 } catch (qfq\DbException $e) {
diff --git a/extension/qfq/qfq/AbstractBuildForm.php b/extension/qfq/qfq/AbstractBuildForm.php
index 6dc85c838d5026dbce982f9eef30a0b89d0ff66f..bbea73faf0f94c9a4a4918e5dadb2e2ac7adc5e4 100644
--- a/extension/qfq/qfq/AbstractBuildForm.php
+++ b/extension/qfq/qfq/AbstractBuildForm.php
@@ -86,6 +86,8 @@ abstract class AbstractBuildForm {
      * @param array $feSpecAction
      * @param array $feSpecNative
      * @param array $db
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function __construct(array $formSpec, array $feSpecAction, array $feSpecNative, array $db = null) {
         $this->formSpec = $formSpec;
@@ -172,6 +174,8 @@ abstract class AbstractBuildForm {
      * @param array $latestFeSpecNative
      * @return array|string $mode=LOAD_FORM: The whole form as HTML, $mode=FORM_UPDATE: array of all
      *                        formElement.dynamicUpdate-yes  values/states
+     * @throws CodeException
+     * @throws DbException
      * @throws UserFormException
      */
     public function process($mode, $htmlElementNameIdZero = false, $latestFeSpecNative = array()) {
@@ -247,6 +251,8 @@ abstract class AbstractBuildForm {
      *
      * @param string $mode
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function head($mode = FORM_LOAD) {
         $html = '';
@@ -276,6 +282,8 @@ abstract class AbstractBuildForm {
      *
      * @return string String: <a href="?pageId&sip=....">Edit</a> <small>[sip:..., r:..., urlparam:...,
      *                ...]</small>
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function createFormEditorUrl($form, $recordId, array $param = array()) {
 
@@ -338,6 +346,8 @@ abstract class AbstractBuildForm {
      * Build MD5 from the current record. Return HTML Input element.
      *
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function buildInputRecordHashMd5() {
 
@@ -357,6 +367,9 @@ abstract class AbstractBuildForm {
      * @param $recordId
      *
      * @return string
+     * @throws CodeException
+     * @throws DbException
+     * @throws UserFormException
      */
     public function buildRecordHashMd5($tableName, $recordId) {
         $record = array();
@@ -372,6 +385,8 @@ abstract class AbstractBuildForm {
      * Create HTML Input vars to detect bot automatic filling of forms.
      *
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function getHoneypotVars() {
         $html = '';
@@ -442,6 +457,9 @@ abstract class AbstractBuildForm {
      * See: https://www.w3.org/wiki/HTML/Elements/form#HTML_Attributes
      *
      * @return string
+     * @throws CodeException
+     * @throws DbException
+     * @throws UserFormException
      */
     public function getEncType() {
 
@@ -457,6 +475,10 @@ abstract class AbstractBuildForm {
      * @param array|string $value
      *
      * @return array|string
+     * @throws CodeException
+     * @throws DbException
+     * @throws UserFormException
+     * @throws UserReportException
      */
     private function processReportSyntax($value) {
 
@@ -502,6 +524,10 @@ abstract class AbstractBuildForm {
      * @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE
      *
      * @return string
+     * @throws CodeException
+     * @throws DbException
+     * @throws UserFormException
+     * @throws UserReportException
      */
     public function elements($recordId, $filter = FORM_ELEMENTS_NATIVE, $feIdContainer = 0, array &$json,
                              $modeCollectFe = FLAG_DYNAMIC_UPDATE, $htmlElementNameIdZero = false,
@@ -672,6 +698,10 @@ abstract class AbstractBuildForm {
      * @param array $formElement
      *
      * @return array
+     * @throws CodeException
+     * @throws DbException
+     * @throws UserFormException
+     * @throws UserReportException
      */
     private function prepareFillStoreFireLdap(array $formElement) {
 
@@ -767,6 +797,8 @@ abstract class AbstractBuildForm {
      * save/update.
      *
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     private function prepareT3VarsForSave() {
 
@@ -802,6 +834,8 @@ abstract class AbstractBuildForm {
      * Get all elements from STORE_ADDITIONAL_FORM_ELEMENTS and return them as a string.
      *
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     private function buildAdditionalFormElements() {
 
@@ -816,6 +850,8 @@ abstract class AbstractBuildForm {
      * @param array $json
      *
      * @return string  <input type='hidden' name='s' value='<sip>'>
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function buildHiddenSip(array &$json) {
 
@@ -921,6 +957,7 @@ abstract class AbstractBuildForm {
      * @param array $feMode
      *
      * @return array
+     * @throws UserFormException
      */
     private function getJsonFeMode($feMode) {
 
@@ -970,6 +1007,7 @@ abstract class AbstractBuildForm {
      * @param string $addClass
      *
      * @return string
+     * @throws CodeException
      */
     public function buildLabel($htmlFormElementName, $label, $addClass = '') {
         $attributes = Support::doAttribute('for', $htmlFormElementName);
@@ -985,6 +1023,8 @@ abstract class AbstractBuildForm {
      *
      * @param $toolTipNew
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function deriveNewRecordUrlFromExistingSip(&$toolTipNew) {
 
@@ -1048,6 +1088,8 @@ abstract class AbstractBuildForm {
      * @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE
      *
      * @return string complete rendered HTML input element.
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function buildInput(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
         $textarea = '';
@@ -1192,6 +1234,7 @@ abstract class AbstractBuildForm {
      * @param array $formElement
      *
      * @return string
+     * @throws CodeException
      * @throws UserFormException
      */
     private function typeAheadBuildParam(array &$formElement) {
@@ -1297,6 +1340,7 @@ abstract class AbstractBuildForm {
      * @param bool $flagOmitEmpty
      *
      * @return string
+     * @throws CodeException
      */
     private function getAttributeList(array $formElement, array $attributeList, $flagOmitEmpty = true) {
         $attribute = '';
@@ -1315,6 +1359,7 @@ abstract class AbstractBuildForm {
      *
      * @param bool $cssDisable
      * @return string
+     * @throws CodeException
      * @throws UserFormException
      */
     private function getAttributeFeMode($feMode, $cssDisable = true) {
@@ -1371,6 +1416,7 @@ abstract class AbstractBuildForm {
      * @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE*
      *
      * @return string
+     * @throws CodeException
      * @throws UserFormException
      */
     public function buildCheckbox(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
@@ -1426,6 +1472,7 @@ abstract class AbstractBuildForm {
      * @param array $itemKey
      * @param array $itemValue
      *
+     * @throws CodeException
      * @throws UserFormException
      */
     public function getKeyValueListFromSqlEnumSpec(array $formElement, array &$itemKey, array &$itemValue) {
diff --git a/extension/qfq/qfq/BuildFormBootstrap.php b/extension/qfq/qfq/BuildFormBootstrap.php
index 0a686799147e0d6012c59bf732b373e44f83aa12..15e25e47e970109b3b404872682973c75f1c0a96 100644
--- a/extension/qfq/qfq/BuildFormBootstrap.php
+++ b/extension/qfq/qfq/BuildFormBootstrap.php
@@ -383,7 +383,9 @@ class BuildFormBootstrap extends AbstractBuildForm {
      * @param array $json
      * @return string
      * @throws CodeException
+     * @throws DbException
      * @throws UserFormException
+     * @throws UserReportException
      */
     private function buildPillNavigation($mode = FORM_LOAD, array $pillArray, array &$json) {
         $pillButton = '';
@@ -595,6 +597,7 @@ class BuildFormBootstrap extends AbstractBuildForm {
                     fileDeleteUrl: '$apiDir/file.php?$actionDelete'
                 });
 
+               
                 var qfqRecordList = new QfqNS.QfqRecordList('$apiDeletePhp');
             })
          </script>
diff --git a/extension/qfq/qfq/Constants.php b/extension/qfq/qfq/Constants.php
index 9a78fe60cd2a0c9514ba7635f0a26f355e49ca07..969a84179d703c67433e90a8f88806506739cded 100644
--- a/extension/qfq/qfq/Constants.php
+++ b/extension/qfq/qfq/Constants.php
@@ -248,6 +248,7 @@ const ERROR_DOWNLOAD_NO_FILES = 1701;
 const ERROR_DOWNLOAD_NOTHING_TO_DO = 1702;
 const ERROR_DOWNLOAD_UNEXPECTED_MIME_TYPE = 1703;
 const ERROR_DOWNLOAD_UNEXPECTED_NUMBER_OF_SOURCES = 1704;
+const ERROR_DOWNLOAD_FILE_NOT_READABLE = 1705;
 
 // KeyValueParser
 const ERROR_KVP_VALUE_HAS_NO_KEY = 1900;
@@ -547,6 +548,7 @@ const SYSTEM_DOWNLOAD_POPUP = 'hasDownloadPopup'; // Marker which is set to 'tru
 const DOWNLOAD_POPUP_REQUEST = 'true';
 const DOWNLOAD_POPUP_REPLACE_TEXT = '#downloadPopupReplaceText#';
 const DOWNLOAD_POPUP_REPLACE_TITLE = '#downloadPopupReplaceTitle#';
+const SYSTEM_DRAG_AND_DROP_JS = 'hasDragAndDropJS';
 
 const SYSTEM_PARAMETER_LANGUAGE_FIELD_NAME = 'parameterLanguageFieldName';
 const CSS_REQUIRED = 'required-field';
@@ -648,6 +650,7 @@ const MODE_LDAP_MULTI = 'ldapMulti';
 // api/save.php, api/delete.php, api/load.php
 const API_DELETE_PHP = 'delete.php';
 const API_DOWNLOAD_PHP = 'download.php';
+const API_DRAG_AND_DROP_PHP = 'dragAndDrop.php';
 
 const API_STATUS = 'status';
 const API_MESSAGE = 'message';
@@ -853,6 +856,9 @@ const F_NEW_BUTTON_GLYPH_ICON = SYSTEM_NEW_BUTTON_GLYPH_ICON;
 const F_ENTER_AS_SUBMIT = SYSTEM_ENTER_AS_SUBMIT;
 
 const F_DRAG_AND_DROP_ORDER_SQL = 'dragAndDropOrderSql';
+const F_ORDER_INTERVAL = 'orderInterval';
+const F_ORDER_COLUMN = 'orderColumn';
+const F_ORDER_COLUMN_NAME = 'ord';
 
 // FORM_ELEMENT_STATI
 const FE_MODE_SHOW = 'show';
@@ -1423,3 +1429,15 @@ const EXCEPTION_STACKTRACE = 'Stacktrace';
 
 const EXCEPTION_TABLE_CLASS = 'table table-hover qfq-table-80';
 
+// Drag And Drop
+const DND_DRAG_ID = 'dragId';
+const DND_DRAG_POSITION = 'dragPosition';
+const DND_SET_TO = 'setTo';
+const DND_SET_TO_BEFORE = 'before';
+const DND_SET_TO_AFTER = 'after';
+const DND_HOVER_ID = 'hoverId';
+const DND_HOVER_POSITION = 'hoverPosition';
+const DND_COLUMN_ID = 'id';
+const DND_COLUMN_ORD = 'ord';
+const DND_COLUMN_ORD_NEW = 'ordNew';
+const DND_DATA_DND_API = 'data-dnd-api';
\ No newline at end of file
diff --git a/extension/qfq/qfq/Evaluate.php b/extension/qfq/qfq/Evaluate.php
index b29a27101aadbd1475977026aea2108a6b3cd00c..c84538ac9283f2ad88ad4ef3c9ac6888c4a7d0f5 100644
--- a/extension/qfq/qfq/Evaluate.php
+++ b/extension/qfq/qfq/Evaluate.php
@@ -197,6 +197,59 @@ class Evaluate {
         return $result;
     }
 
+    /**
+     * @param $arrToken
+     * @param $dbIndex
+     * @param $foundInStore
+     * @return string
+     * @throws CodeException
+     * @throws UserFormException
+     * @throws UserReportException
+     */
+    private function inlineLink($arrToken, $dbIndex, &$foundInStore){
+
+        $token = OnString::trimQuote(trim(implode(' ', $arrToken)));
+
+        if ($this->link === null) {
+            $this->link = new Link($this->store->getSipInstance(), $dbIndex);
+        }
+
+        $foundInStore = TOKEN_FOUND_AS_COLUMN;
+
+        return $this->link->renderLink($token);
+    }
+
+    /**
+     * @param $arrToken
+     * @param $dbIndex
+     * @param $foundInStore
+     * @return string
+     * @throws CodeException
+     * @throws UserFormException
+     * @throws UserReportException
+     */
+    private function inlineDataDndApi($arrToken, $dbIndex, &$foundInStore){
+
+        $token = OnString::trimQuote(trim(implode(' ', $arrToken)));
+        if(empty($token)){
+            throw new UserReportException('Missing form name for "data-dnd-api"', ERROR_MISSING_FORM);
+        }
+
+        if ($this->link === null) {
+            $this->link = new Link($this->store->getSipInstance(), $dbIndex);
+        }
+
+        $foundInStore = TOKEN_FOUND_AS_COLUMN;
+
+        $s = $this->link->renderLink('U:' . $token . '|s|r:8');
+
+        // Flag to add DND JS code later on.
+        $this->store->setVar(SYSTEM_DRAG_AND_DROP_JS, 'true', STORE_SYSTEM);
+
+        // data-dnd-api="typo3conf/ext/qfq/qfq/api/dragAndDrop.php?s={{'U:form=<form name>[&paramX=<any value>]|s|r:8' AS _link}}"
+        return DND_DATA_DND_API . '="' . API_DIR . '/' . API_DRAG_AND_DROP_PHP . '?s=' . $s . '"';
+    }
+
     /**
      * Tries to substitute $token.
      * Token might be:
@@ -244,7 +297,7 @@ class Evaluate {
             $sqlMode = ROW_REGULAR;
         }
 
-        // Extract token: check if this is a SQL Statement
+        // Extract token: check if this is a 'variable', 'SQL Statement', 'link', 'data-dnd-api'
         $arrToken = explode(' ', $token);
 
         // Variable Type 'SQL Statement'
@@ -254,23 +307,22 @@ class Evaluate {
             return $this->dbArray[$dbIndex]->sql($token, $sqlMode);
         }
 
-        // Variable Type '... AS LINK'
+        // Variable Type '... AS _link', '... as data-dnd-api'
         $countToken = count($arrToken);
         if ($countToken > 2 && strcasecmp($arrToken[$countToken - 2], 'as') == 0) {
 
             $type = OnString::stripFirstCharIf('_', $arrToken[$countToken - 1]);
 
-            if (strcasecmp($type, 'link') == 0) {
-
-                $str = OnString::trimQuote(substr($token, 0, strlen($token) - 8));  // strlen('_as_link')=8
+            array_pop($arrToken); // remove 'link' | 'data-dnd-api'
+            array_pop($arrToken); // remove 'as'
 
-                if ($this->link === null) {
-                    $this->link = new Link($this->store->getSipInstance(), $dbIndex);
-                }
+            if (strcasecmp($type, COLUMN_LINK ) == 0) {
+                return($this->inlineLink($arrToken, $dbIndex,$foundInStore));
+            }
 
-                $foundInStore = TOKEN_FOUND_AS_COLUMN;
+            if($type == DND_DATA_DND_API){
+                return($this->inlineDataDndApi($arrToken, $dbIndex,$foundInStore));
 
-                return $this->link->renderLink($str);
             }
         }
 
diff --git a/extension/qfq/qfq/QuickFormQuery.php b/extension/qfq/qfq/QuickFormQuery.php
index 87f91c84021fb3fb8d67520d030e2c54cc15de52..49df976d0fd4ce20185a75cdac1e3f14bf04c898 100644
--- a/extension/qfq/qfq/QuickFormQuery.php
+++ b/extension/qfq/qfq/QuickFormQuery.php
@@ -44,6 +44,7 @@ require_once(__DIR__ . '/BodytextParser.php');
 require_once(__DIR__ . '/Delete.php');
 require_once(__DIR__ . '/form/FormAction.php');
 require_once(__DIR__ . '/form/Dirty.php');
+require_once(__DIR__ . '/form/DragAndDrop.php');
 
 /*
  * Form will be called
@@ -61,8 +62,7 @@ require_once(__DIR__ . '/form/Dirty.php');
  * Class Qfq
  * @package qfq
  */
-class QuickFormQuery
-{
+class QuickFormQuery {
 
     /**
      * @var \qfq\Store instantiated class
@@ -127,8 +127,7 @@ class QuickFormQuery
      * @throws UserFormException
      * @throws UserReportException
      */
-    public function __construct(array $t3data = array(), $phpUnit = false)
-    {
+    public function __construct(array $t3data = array(), $phpUnit = false) {
 
         $this->phpUnit = $phpUnit;
 
@@ -197,8 +196,7 @@ class QuickFormQuery
      * @throws CodeException
      * @throws UserFormException
      */
-    public function getForwardMode()
-    {
+    public function getForwardMode() {
 
         $forwardPage = $this->formSpec[F_FORWARD_PAGE];
 
@@ -222,11 +220,11 @@ class QuickFormQuery
      * @return string
      * @throws CodeException
      * @throws DbException
+     * @throws DownloadException
      * @throws UserFormException
      * @throws UserReportException
      */
-    public function process()
-    {
+    public function process() {
         $html = '';
 
         if ($this->store->getVar(TYPO3_DEBUG_SHOW_BODY_TEXT, STORE_TYPO3) === 'yes') {
@@ -242,6 +240,11 @@ class QuickFormQuery
             $html .= $this->getModalCode();
         }
 
+        // Only needed if there are 'drag and drop' elements.
+        if ($this->store->getVar(SYSTEM_DRAG_AND_DROP_JS, STORE_SYSTEM) == 'true') {
+            $html .= $this->getDragAndDropCode();
+        }
+
         $class = $this->store->getVar(SYSTEM_CSS_CLASS_QFQ_CONTAINER, STORE_SYSTEM);
         if ($class) {
             $html = Support::wrapTag("<div class='$class'>", $html);
@@ -253,8 +256,7 @@ class QuickFormQuery
     /**
      * Determine the name of the language parameter field, which has to be taken to fill language specific defintions.
      */
-    private function setParameterLanguageFieldName()
-    {
+    private function setParameterLanguageFieldName() {
 
         $typo3PageLanguage = $this->store->getVar(TYPO3_PAGE_LANGUAGE, STORE_TYPO3);
         if (empty($typo3PageLanguage)) {
@@ -284,11 +286,11 @@ class QuickFormQuery
      * @return array|string
      * @throws CodeException
      * @throws DbException
+     * @throws DownloadException
      * @throws UserFormException
      * @throws UserReportException
      */
-    private function doForm($formMode)
-    {
+    private function doForm($formMode) {
         $data = '';
         $foundInStore = '';
 
@@ -493,8 +495,8 @@ class QuickFormQuery
             case FORM_DRAG_AND_DROP:
                 $formAction->elements($recordId, $this->feSpecAction, FE_TYPE_BEFORE_LOAD);
 
-                $draganddrop = new DragAndDrop();
-                $draganddrop->process($this->formSpec[F_TABLE_NAME], $this->formSpec[F_DRAG_AND_DROP_ORDER_SQL]);
+                $dragAndDrop = new DragAndDrop($this->formSpec);
+                $dragAndDrop->process($this->formSpec);
 
                 $formAction->elements($recordId, $this->feSpecAction, FE_TYPE_AFTER_LOAD);
                 break;
@@ -533,8 +535,7 @@ class QuickFormQuery
      * @throws UserFormException
      * @throws UserReportException
      */
-    private function setForwardModePage()
-    {
+    private function setForwardModePage() {
 
         if ('url' != substr($this->formSpec[F_FORWARD_MODE], 0, 3)) {
             return false;
@@ -592,8 +593,7 @@ class QuickFormQuery
      * @throws UserFormException
      * @throws UserReportException
      */
-    private function pasteClipboard($formId, FormAction $formAction)
-    {
+    private function pasteClipboard($formId, FormAction $formAction) {
 
         if (!$this->isPasteRecord()) {
             return;
@@ -618,8 +618,7 @@ class QuickFormQuery
     /**
      * @return bool  true if there is at least one paste record, else false.
      */
-    private function isPasteRecord()
-    {
+    private function isPasteRecord() {
 
         foreach ($this->feSpecAction as $formElement) {
             if ($formElement[FE_TYPE] == FE_TYPE_PASTE) {
@@ -642,8 +641,7 @@ class QuickFormQuery
      * @throws CodeException
      * @throws UserFormException
      */
-    private function buildNSetReloadUrl(array $formSpec, $recordId)
-    {
+    private function buildNSetReloadUrl(array $formSpec, $recordId) {
 
         $formSpec[F_FORWARD_MODE] = API_ANSWER_REDIRECT_URL_SKIP_HISTORY;
 
@@ -681,8 +679,7 @@ class QuickFormQuery
      * @throws UserFormException
      * @throws UserReportException
      */
-    private function loadFormSpecification($mode, $recordId, &$foundInStore = '')
-    {
+    private function loadFormSpecification($mode, $recordId, &$foundInStore = '') {
 
         // formName
         if (false === ($formName = $this->getFormName($mode, $foundInStore))) {
@@ -823,8 +820,7 @@ class QuickFormQuery
      * @throws UserFormException
      * @throws UserReportException
      */
-    public function getNativeFormElements($sql, array $param, $formSpec)
-    {
+    public function getNativeFormElements($sql, array $param, $formSpec) {
 
         $feSpecNative = $this->dbArray[$this->dbIndexQfq]->sql($sql, ROW_REGULAR, $param);
 
@@ -864,8 +860,7 @@ class QuickFormQuery
      * @throws UserFormException
      * @throws UserReportException
      */
-    private function explodeTemplateGroupElements(array $elements)
-    {
+    private function explodeTemplateGroupElements(array $elements) {
         $new = array();
 
         // No FormElements or no NAME_TG_COPIES column: nothing to do, return.
@@ -921,8 +916,7 @@ class QuickFormQuery
      * @throws UserFormException
      * @throws UserReportException
      */
-    public function getFormName($mode, &$foundInStore = '')
-    {
+    public function getFormName($mode, &$foundInStore = '') {
         $dummy = array();
 
         switch ($mode) {
@@ -932,6 +926,7 @@ class QuickFormQuery
             case FORM_SAVE:
             case FORM_UPDATE:
             case FORM_DELETE:
+            case FORM_DRAG_AND_DROP:
                 $store = STORE_SIP;
                 break;
             default:
@@ -960,8 +955,7 @@ class QuickFormQuery
      * @throws CodeException
      * @throws UserFormException
      */
-    private function modeCleanFormConfig($mode, array $form)
-    {
+    private function modeCleanFormConfig($mode, array $form) {
 
         switch ($mode) {
             case FORM_DELETE:
@@ -992,8 +986,7 @@ class QuickFormQuery
      * @throws CodeException
      * @throws UserFormException
      */
-    private function syncSystemFormConfig(array $formSpec)
-    {
+    private function syncSystemFormConfig(array $formSpec) {
 
         $keys = [F_BS_COLUMNS,
             F_BS_LABEL_COLUMNS,
@@ -1063,8 +1056,7 @@ class QuickFormQuery
      * @throws CodeException
      * @throws UserFormException
      */
-    private function initForm(array $formSpec)
-    {
+    private function initForm(array $formSpec) {
 
         Support::setIfNotSet($formSpec, F_EXTRA_DELETE_FORM, '');
         Support::setIfNotSet($formSpec, F_SUBMIT_BUTTON_TEXT, '');
@@ -1105,8 +1097,7 @@ class QuickFormQuery
      * @throws \qfq\UserFormException
      * @internal param $foundInStore
      */
-    private function validateForm($formNameFoundInStore, $formMode)
-    {
+    private function validateForm($formNameFoundInStore, $formMode) {
 
         // Retrieve record_id either from SIP (prefered) or via URL
         $r = $this->store->getVar(SIP_RECORD_ID, STORE_SIP . STORE_TYPO3 . STORE_CLIENT, '', $recordIdFoundInStore);
@@ -1201,8 +1192,7 @@ class QuickFormQuery
      * @throws DbException
      * @throws UserFormException
      */
-    private function fillStoreWithRecord($table, $recordId, $store = STORE_RECORD)
-    {
+    private function fillStoreWithRecord($table, $recordId, $store = STORE_RECORD) {
         if ($recordId !== false && $recordId > 0) {
             $record = $this->dbArray[$this->dbIndexData]->sql("SELECT * FROM $table WHERE id = ?", ROW_EXPECT_1, [$recordId]);
             $this->store->setStore($record, $store, true);
@@ -1217,8 +1207,7 @@ class QuickFormQuery
      *
      * @return array to build JSON
      */
-    private function groupElementUpdateEntries(array $dataArray)
-    {
+    private function groupElementUpdateEntries(array $dataArray) {
         $collect = array();
 
         foreach ($dataArray as $data) {
@@ -1247,15 +1236,13 @@ class QuickFormQuery
      * @throws UserFormException
      * @throws UserReportException
      */
-    private function doReport()
-    {
+    private function doReport() {
 
         $report = new Report($this->t3data, $this->eval, $this->phpUnit);
 
         $html = $report->process($this->t3data['bodytext']);
 
         return $html;
-
     }
 
     /**
@@ -1264,11 +1251,11 @@ class QuickFormQuery
      * @return string
      * @throws CodeException
      * @throws DbException
+     * @throws DownloadException
      * @throws UserFormException
      * @throws UserReportException
      */
-    public function saveForm()
-    {
+    public function saveForm() {
 
         $json = $this->doForm(FORM_SAVE);
 
@@ -1281,11 +1268,11 @@ class QuickFormQuery
      * @return array
      * @throws CodeException
      * @throws DbException
+     * @throws DownloadException
      * @throws UserFormException
      * @throws UserReportException
      */
-    public function updateForm()
-    {
+    public function updateForm() {
 
         $json = $this->doForm(FORM_UPDATE);
 
@@ -1298,11 +1285,11 @@ class QuickFormQuery
      * @return array
      * @throws CodeException
      * @throws DbException
+     * @throws DownloadException
      * @throws UserFormException
      * @throws UserReportException
      */
-    public function dragAndDrop()
-    {
+    public function dragAndDrop() {
 
         $json = $this->doForm(FORM_DRAG_AND_DROP);
 
@@ -1315,11 +1302,11 @@ class QuickFormQuery
      * @return array
      * @throws CodeException
      * @throws DbException
+     * @throws DownloadException
      * @throws UserFormException
      * @throws UserReportException
      */
-    public function delete()
-    {
+    public function delete() {
 
         return $this->doForm(FORM_DELETE);
 
@@ -1333,8 +1320,7 @@ class QuickFormQuery
      * @throws CodeException
      * @throws UserFormException
      */
-    private function newRecordCreateSip(array $sipArray, $recordId)
-    {
+    private function newRecordCreateSip(array $sipArray, $recordId) {
 
         $tmpParam = array();
 
@@ -1372,8 +1358,7 @@ class QuickFormQuery
     /**
      * @return string
      */
-    private function getModalCode()
-    {
+    private function getModalCode() {
 
         $code = <<<EOF
     <!-- Modal -->
@@ -1402,5 +1387,21 @@ EOF;
         return $code;
     }
 
+    /**
+     * @return string
+     */
+    private function getDragAndDropCode() {
+
+        $code = <<<EOF
+            <script type = "text/javascript" >
+            var dragi = new QfqNS . DragAndDrop($('.qfq-dnd-sort'));
+            dragi . makeSortable();
+            </script>
+EOF;
+
+        return $code;
+
+    }
+
 
 }
\ No newline at end of file
diff --git a/extension/qfq/qfq/form/DragAndDrop.php b/extension/qfq/qfq/form/DragAndDrop.php
index 39f18f231896ab8f17cda1a4781f63a333e6cff7..9be716f0fe64059ca7972cbe5a07c17bcf0c2f9a 100644
--- a/extension/qfq/qfq/form/DragAndDrop.php
+++ b/extension/qfq/qfq/form/DragAndDrop.php
@@ -10,11 +10,13 @@ namespace qfq;
 
 //use TYPO3\CMS\Core\FormProtection\Exception;
 
-require_once(__DIR__ . '/../store/Sip.php');
-require_once(__DIR__ . '/../store/Session.php');
+//require_once(__DIR__ . '/../store/Sip.php');
+//require_once(__DIR__ . '/../store/Session.php');
+require_once(__DIR__ . '/../store/Store.php');
 require_once(__DIR__ . '/../Constants.php');
-require_once(__DIR__ . '/../helper/Ldap.php');
+//require_once(__DIR__ . '/../helper/Ldap.php');
 require_once(__DIR__ . '/../database/Database.php');
+require_once(__DIR__ . '/../Evaluate.php');
 
 
 /**
@@ -29,140 +31,132 @@ class DragAndDrop {
     private $db = null;
 
     /**
-     * @var array
+     * @var Store
      */
-    private $vars = array();
+    private $store = null;
 
+    /**
+     * @var Evaluate instantiated class
+     */
+    protected $evaluate = null;  // copy of the loaded form
 
     /**
-     * @return array|int
+     * @var array
+     */
+    private $formSpec = null;
+
+    /**
+     * @param array $formSpec F_TABLE_NAME, F_DRAG_AND_DROP_ORDER_SQL, F_DRAG_AND_DROP_INTERVAL
+     * @param bool|false $phpUnit
+     *
      * @throws CodeException
      * @throws DbException
      * @throws UserFormException
      */
-    public function process($tableName, $dragAndDropOrderSql) {
-
-        $arr = array();
-        $dbIndex = DB_INDEX_DEFAULT;  //TODO hier muss noch die aktuelle DB ermittelt werden (kann im iform angegeben sein)
-
-        $sipClass = new Sip();
+    public function __construct(array $formSpec = array(), $phpUnit = false) {
 
-        $sipVars = $sipClass->getVarsFromSip($this->vars[TYPEAHEAD_API_SIP]);
-
-        // Check for an optional given dbIndex: '[<int>]SELECT ...'
-        $sql = $sipVars[FE_TYPEAHEAD_SQL];
-        if ($sql[0] === '[') {
-            $pos = strpos($sql, ']');
-            $dbIndex = substr($sql, 1, $pos - 1);
-            $sipVars[FE_TYPEAHEAD_SQL] = substr($sql, $pos + 1);
-        }
+        $this->formSpec = $formSpec;
 
+        $dbIndex = DB_INDEX_DEFAULT;  //TODO hier muss noch die aktuelle DB ermittelt werden (kann im Form angegeben sein) - Gerade im Formular FORM Editor genau testen!
         $this->db = new Database($dbIndex);
 
-        if (isset($sipVars[FE_TYPEAHEAD_SQL])) {
-            if($this->vars[TYPEAHEAD_API_PREFETCH] == '') {
-                $arr = $this->typeAheadSql($sipVars, $this->vars[TYPEAHEAD_API_QUERY]);
-            } else {
-                $arr = $this->typeAheadSqlPrefetch($sipVars, $this->vars[TYPEAHEAD_API_PREFETCH]);
-            }
-        } elseif (isset($sipVars[FE_LDAP_SERVER])) {
-            $ldap = new Ldap();
-
-            if ($this->vars[TYPEAHEAD_API_PREFETCH] == '') {
-                $mode = MODE_LDAP_MULTI;
-                $key = $this->vars[TYPEAHEAD_API_QUERY];
-            } else {
-                $mode = MODE_LDAP_PREFETCH;
-                $key = $this->vars[TYPEAHEAD_API_PREFETCH];
-            }
-
-            $arr = $ldap->process($sipVars, $key, $mode);
-        }
-
-        return $arr;
+        $this->store = Store::getInstance('', $phpUnit);
+//        $this->evaluate = new Evaluate($this->store, $this->db);
     }
 
     /**
-     * Do a wildcard search on the prepared statement $config[FE_TYPEAHEAD_SQL].
-     * All '?' will be replaced by '%$value%'.
-     * If there is no 'LIMIT x' defined, append it.
-     * Returns an dict array [ API_TYPEAHEAD_KEY => key, API_TYPEAHEAD_VALUE => value ]
      *
-     * @param array $config
-     * @param string $value
-     *
-     * @return array
+     * @return array|int
      * @throws CodeException
      * @throws DbException
      * @throws UserFormException
+     * @throws UserReportException
      */
-    private function typeAheadSql(array $config, $value) {
-        $values = array();
-
-        $sql = $config[FE_TYPEAHEAD_SQL];
-        $value = '%' . $value . '%';
-        $cnt = substr_count($sql, '?');
+    public function process() {
 
-        if ($cnt == 0) {
-            throw new UserFormException("Missing at least one '?' in " . FE_TYPEAHEAD_SQL);
-        }
+        $dragId = $this->store->getVar(DND_DRAG_ID, STORE_CLIENT, SANITIZE_ALLOW_ALNUMX);
+        $setTo = $this->store->getVar(DND_SET_TO, STORE_CLIENT, SANITIZE_ALLOW_ALNUMX);
+        $hoverId = $this->store->getVar(DND_HOVER_ID, STORE_CLIENT, SANITIZE_ALLOW_ALNUMX);
 
-        for ($ii = 0; $ii < $cnt; $ii++) {
-            $values[] = $value;
-        }
+        $orderInterval = empty($this->formSpec[F_ORDER_INTERVAL]) ? 1 : $this->formSpec[F_ORDER_INTERVAL];
+        $orderColumn = empty($this->formSpec[F_ORDER_COLUMN]) ? F_ORDER_COLUMN_NAME : $this->formSpec[F_ORDER_COLUMN];
 
-        if (!$this->db->hasLimit($sql)) {
-            $sql .= ' LIMIT ' . $config[FE_TYPEAHEAD_LIMIT];
+        if (!is_array($this->formSpec[F_DRAG_AND_DROP_ORDER_SQL])) {
+            return [];
         }
 
-        $arr = $this->db->sql($sql, ROW_REGULAR, $values);
-        if ($arr == false || count($arr) == 0) {
-            return array();
-        }
+        $this->reorder($this->formSpec[F_DRAG_AND_DROP_ORDER_SQL], $dragId, $setTo, $hoverId, $orderColumn, $orderInterval, $this->formSpec[F_TABLE_NAME]);
 
-        return $this->db->makeArrayDict($arr, TYPEAHEAD_SQL_KEY_NAME, API_TYPEAHEAD_VALUE, API_TYPEAHEAD_KEY, API_TYPEAHEAD_VALUE);
+        return [];
     }
 
     /**
-     * Returns a dict array [ API_TYPEAHEAD_KEY => key, API_TYPEAHEAD_VALUE => value ] with the prefetch result
-     *
-     * @param array $config
-     * @param string $key
-     *
-     * @return array
+     * @param array $rows
+     * @param $dragId
+     * @param $setTo
+     * @param $hoverId
+     * @param $orderColumn
+     * @param $orderInterval
+     * @param $tableName
      * @throws CodeException
      * @throws DbException
      * @throws UserFormException
      */
+    private function reorder(array $rows, $dragId, $setTo, $hoverId, $orderColumn, $orderInterval, $tableName) {
+        $ord = $orderInterval;
+        $ordDragOld = -1;
 
-    private function typeAheadSqlPrefetch(array $config, $key) {
-        $keys = array();
+        // Reorder. Get index for 'drag' and 'hover'
+        foreach ($rows as $key => $row) {
 
-        $sql = $config[FE_TYPEAHEAD_SQL_PREFETCH];
-        if ($config[FE_TYPEAHEAD_SQL_PREFETCH] == '') {
-            throw new UserFormException("Missing definition for `" . FE_TYPEAHEAD_SQL_PREFETCH . "`", ERROR_MISSING_TYPE_AHEAD_SQL_PREFETCH);
-        }
+            // the dragged element: skip old position.
+            if ($row[DND_COLUMN_ID] == $dragId) {
+                $ordDragOld = $row[DND_COLUMN_ORD];
+                continue;
+            }
 
-        $cnt = substr_count($sql, '?');
-        if ($cnt == 0) {
-            throw new UserFormException("Missing at least one '?' in " . FE_TYPEAHEAD_SQL_PREFETCH);
+            // the dragged element: new position.
+            if ($row[DND_COLUMN_ID] == $hoverId) {
+
+                switch ($setTo) {
+                    case DND_SET_TO_BEFORE:
+                        $this->setNewOrder($tableName, $orderColumn, $dragId, $ordDragOld, $ord);
+                        $ord += $orderInterval;
+                        $this->setNewOrder($tableName, $orderColumn, $row[DND_COLUMN_ID], $row[DND_COLUMN_ORD], $ord);
+                        break;
+
+                    case DND_SET_TO_AFTER:
+                        $this->setNewOrder($tableName, $orderColumn, $row[DND_COLUMN_ID], $row[DND_COLUMN_ORD], $ord);
+                        $ord += $orderInterval;
+                        $this->setNewOrder($tableName, $orderColumn, $dragId, $ordDragOld, $ord);
+                        break;
+
+                    default:
+                        throw new CodeException('Unkown setTo string', $setTo, ERROR_UNKNOWN_TOKEN);
+                }
+            } else {
+                $this->setNewOrder($tableName, $orderColumn, $row[DND_COLUMN_ID], $row[DND_COLUMN_ORD], $ord);
+            }
+            $ord += $orderInterval;
         }
+    }
 
-        for ($ii = 0; $ii < $cnt; $ii++) {
-            $keys[] = $key;
-        }
+    /**
+     * @param $tableName
+     * @param $orderColumn
+     * @param $id
+     * @param $ordOld
+     * @param $ordNew
+     * @throws CodeException
+     * @throws DbException
+     * @throws UserFormException
+     */
+    private function setNewOrder($tableName, $orderColumn, $id, $ordOld, $ordNew) {
 
-        $arr = $this->db->sql($sql, ROW_REGULAR, $keys);
-        if ($arr == false || count($arr) == 0) {
-            return array();
+        if ($ordNew == $ordOld) {
+            return;
         }
 
-        // return first result as key-value pair (concatenate columns)
-        $value = '';
-        foreach($arr[0] AS $name => $column) {
-            $value .= $column;
-        }
-        return [ [ API_TYPEAHEAD_KEY => $key, API_TYPEAHEAD_VALUE => $value ] ];
+        $this->db->sql("UPDATE $tableName SET $orderColumn=? WHERE id=?", ROW_REGULAR, [$ordNew, $id]);
     }
-
 }
\ No newline at end of file
diff --git a/extension/qfq/qfq/form/FormAction.php b/extension/qfq/qfq/form/FormAction.php
index 43edcf6bfb3b36bf92e7cddd736b6c0784d91c0b..dd57b7ffee2e6e8b294d14d476c2e903cfd0add3 100644
--- a/extension/qfq/qfq/form/FormAction.php
+++ b/extension/qfq/qfq/form/FormAction.php
@@ -28,12 +28,15 @@ class FormAction {
      * @var Evaluate instantiated class
      */
     protected $evaluate = null;  // copy of the loaded form
+
     private $formSpec = array();
     private $primaryTableName = '';
+
     /**
      * @var Database
      */
     private $db = null;
+
     /**
      * @var Store
      */
@@ -71,6 +74,7 @@ class FormAction {
      *              ACTION_ELEMENT_DELETED:  if a record has been deleted (only in recursive calls, not the initial one)
      * @throws CodeException
      * @throws DbException
+     * @throws DownloadException
      * @throws UserFormException
      * @throws UserReportException
      */
@@ -245,6 +249,7 @@ class FormAction {
      * @param array $feSpecAction
      * @throws CodeException
      * @throws DbException
+     * @throws DownloadException
      * @throws UserFormException
      * @throws UserReportException
      */
diff --git a/extension/qfq/qfq/report/Download.php b/extension/qfq/qfq/report/Download.php
index 6d63a592887bb689e75ce6e15c84572c97970d67..8a2b0ac9f6ed52ec36be5b0135c7a12b347c8594 100644
--- a/extension/qfq/qfq/report/Download.php
+++ b/extension/qfq/qfq/report/Download.php
@@ -94,6 +94,16 @@ class Download {
      */
     private function concatPdfFiles(array $files) {
 
+        // Remove empty entries. Might happen if there was no upload
+        $files = OnArray::removeEmptyElementsFromArray($files);
+
+        // Check that all files exist and readable
+        foreach ($files AS $filename) {
+            if(!is_readable($filename)){
+                throw new downloadException("Error reading file $filename. Not found or no permission", ERROR_DOWNLOAD_FILE_NOT_READABLE);
+            }
+        }
+
         switch (count($files)) {
             case 0:
                 return '';
diff --git a/extension/qfq/qfq/report/Link.php b/extension/qfq/qfq/report/Link.php
index 6e3a6990ca9d7585d42d489c230470db91ed4008..578df997a038386fe3652a5899bf6f9685ad17bd 100644
--- a/extension/qfq/qfq/report/Link.php
+++ b/extension/qfq/qfq/report/Link.php
@@ -262,6 +262,7 @@ class Link {
          * 4: <a href=url>Text</a>
          * 5: text
          * 6: url
+         * 8: SIP only - 's=badcaffee1234'
          *
          *  r=render mode, u=url, t:text and/or image.
          *
@@ -308,10 +309,15 @@ class Link {
         $this->renderControl[7][1][0] = 6;
         $this->renderControl[7][1][1] = 6;
 
+        $this->renderControl[8][0][0] = 0;
+        $this->renderControl[8][0][1] = 0;
+        $this->renderControl[8][1][0] = 8;
+        $this->renderControl[8][1][1] = 8;
+
     }
 
     /**
-     * In render mode 3,4,5 there is no '<a href ...>'. Nevertheless, tooltip and BS Button should be displaye.
+     * In render mode 3,4,5 there is no '<a href ...>'. Nevertheless, tooltip and BS Button should be displayed.
      * Do this by applying a '<span>' attribute around the text.
      *
      * @param array $vars
@@ -421,10 +427,10 @@ class Link {
             case '22':
             case '23':
             case '24':
-            //TODO: Alter Code, umstellen auf JS Client von RO. Vorlage koennte 'Delete' in Subrecord sein.
-            $link = "<a href=\"javascript: void(0);\" onClick=\"var del = new FR.Delete({recordId:'',sip:'',forward:'" .
-                $vars[NAME_PAGE] . "'});\" " . $vars[NAME_LINK_CLASS] . ">" . $vars[NAME_TEXT] . "</a>";
-            break;
+                //TODO: Alter Code, umstellen auf JS Client von RO. Vorlage koennte 'Delete' in Subrecord sein.
+                $link = "<a href=\"javascript: void(0);\" onClick=\"var del = new FR.Delete({recordId:'',sip:'',forward:'" .
+                    $vars[NAME_PAGE] . "'});\" " . $vars[NAME_LINK_CLASS] . ">" . $vars[NAME_TEXT] . "</a>";
+                break;
 
             // 5: plain text, no <span> around
             case '5':
@@ -442,7 +448,9 @@ class Link {
             case '26':
                 throw new UserReportException ("Mode not implemented. internal render mode=$mode", ERROR_UNKNOWN_MODE);
                 break;
-
+            case '8':
+                $link = substr($vars[FINAL_HREF],12); // strip 'index.php?s='
+                break;
 
             default:
                 throw new UserReportException ("Mode not implemented. internal render mode=$mode", ERROR_UNKNOWN_MODE);
@@ -1321,7 +1329,7 @@ EOF;
 //        if ($vars[NAME_BOOTSTRAP_BUTTON] == '0') {
 //            $vars[NAME_EXTRA_CONTENT_WRAP] = '<button type="button" ' . $attributes . $onClick . '>';
 //        } else {
-            $vars[NAME_EXTRA_CONTENT_WRAP] = '<span ' . $attributes . $onClick . '>';
+        $vars[NAME_EXTRA_CONTENT_WRAP] = '<span ' . $attributes . $onClick . '>';
         $vars[NAME_BOOTSTRAP_BUTTON] = '0';
 
 //        }
diff --git a/extension/qfq/qfq/report/Report.php b/extension/qfq/qfq/report/Report.php
index 6c44a55ce5723e5c50cd22bcb170773563f3bad0..1afd6c4fd33f2b5b544f1e7d6e9ad9c83e760b59 100644
--- a/extension/qfq/qfq/report/Report.php
+++ b/extension/qfq/qfq/report/Report.php
@@ -668,6 +668,7 @@ class Report {
      * @return string rendered column
      * @throws CodeException
      * @throws DbException
+     * @throws DownloadException
      * @throws UserFormException
      * @throws UserReportException
      */
@@ -709,10 +710,10 @@ class Report {
             case COLUMN_PPAGEI:
             case COLUMN_PPAGEN:
             case COLUMN_PPAGES:
-            $lowerColumnName = strtolower($columnName);
+                $lowerColumnName = strtolower($columnName);
                 $tokenizedValue = $this->doFixColPosPage($columnName, $columnValue);
-            $linkValue = $this->doPage($lowerColumnName, $tokenizedValue);
-            $content .= $this->link->renderLink($linkValue);
+                $linkValue = $this->doPage($lowerColumnName, $tokenizedValue);
+                $content .= $this->link->renderLink($linkValue);
                 break;
 
             // Lowercase 'P'
@@ -725,7 +726,7 @@ class Report {
             case COLUMN_PAGEN:
             case COLUMN_PAGES:
                 $linkValue = $this->doPage($columnName, $columnValue);
-            $content .= $this->link->renderLink($linkValue);
+                $content .= $this->link->renderLink($linkValue);
                 break;
 
             case COLUMN_PPDF:
diff --git a/extension/qfq/qfq/store/FillStoreForm.php b/extension/qfq/qfq/store/FillStoreForm.php
index 9eadf27730d98b3f8f8f3bc9f3434bedfef804c6..d2f435afefcd08a6a8df35d7b151d66f9b256c8f 100644
--- a/extension/qfq/qfq/store/FillStoreForm.php
+++ b/extension/qfq/qfq/store/FillStoreForm.php
@@ -81,7 +81,7 @@ class FillStoreForm {
         // Preparation for Log, Debug
         $this->store->setVar(SYSTEM_FORM, $formName, STORE_SYSTEM);
 
-        $feSpecNative = $this->dbArray[$this->dbIndexQfq]->sql(SQL_FORM_ELEMENT_SIMPLE_ALL_CONTAINER, ROW_EXPECT_GE_1, [$formName],
+        $feSpecNative = $this->dbArray[$this->dbIndexQfq]->sql(SQL_FORM_ELEMENT_SIMPLE_ALL_CONTAINER, ROW_REGULAR, [$formName],
             'Form or FormElements not found: ' . ERROR_FORM_NOT_FOUND);
         HelperFormElement::explodeParameterInArrayElements($feSpecNative, FE_PARAMETER);