diff --git a/.gitignore b/.gitignore index 382af639cdb20aabc9dacb507b27603170953004..9ddf9fedfccade4ea309b4bee1d13235c0a4dd2c 100644 --- a/.gitignore +++ b/.gitignore @@ -52,9 +52,11 @@ composer.lock /extension/Documentation/html /extension/Resources/Public/Css /extension/Resources/Public/fonts +/extension/Resources/Public/webfonts /extension/Resources/Public/JavaScript /extension/Tests/selenium/tmp /fonts +/webfonts /js /node_modules /packages diff --git a/Documentation/Index.rst b/Documentation/Index.rst index 3890ccf653cd93c37336762394181c7cf737c653..0a181277635ed3597fda86faf4a71ccc8931533b 100644 --- a/Documentation/Index.rst +++ b/Documentation/Index.rst @@ -44,30 +44,28 @@ Quick Form Query Extension **TYPO3** - The content of this document is related to TYPO3 CMS, - a GNU/GPL CMS/Framework available from `typo3.org - <https://typo3.org/>`_ . +The content of this document is related to TYPO3 CMS, +a GNU/GPL CMS/Framework available from `typo3.org +<https://typo3.org/>`_ . **About this manual:** - This manual is a reference. Some basic examples are at the end. +This manual is a reference. Some basic examples are at the end. **Community documentation:** - This document is *not* official TYPO3 documentation. +This document is *not* official TYPO3 documentation. - It is maintained as part of a third party extension. +It is maintained as part of a third party extension. - If you find an error or something is missing, please report - an `issue <https://project.math.uzh.ch/projects/qfq>`_ +If you find an error or something is missing, please report +an `issue <https://project.math.uzh.ch/projects/qfq>`_ **Extension Manual** - This documentation is for the TYPO3 extension **qfq**. +This documentation is for the TYPO3 extension **qfq**. -**Sitemap:** - - :ref:`sitemap` +:ref:`sitemap` .. toctree:: diff --git a/Documentation/Manual.rst b/Documentation/Manual.rst index cdcbe50f9ac5db5ead9fe8af8b9283c04667d55f..a95ee28adc8aa9bc0b4dcb6d6ab54cbcf1ff1879 100644 --- a/Documentation/Manual.rst +++ b/Documentation/Manual.rst @@ -1,5 +1,6 @@ .. ================================================== .. ================================================== +.. ================================================== .. Header hierarchy .. == .. -- @@ -19,8 +20,8 @@ .. .. .. Admonitions -.. .. note:: .. important:: .. tip:: .. warning:: -.. Color: (grey) (orange) (green) (red) +.. .. note:: .. important:: .. tip:: .. warning:: +.. Color: (blue) (orange) (green) (red) .. .. Definition: .. some text becomes strong (only one line) @@ -74,7 +75,7 @@ For the `download`_ function, the programs `pdfunite`, `qpdf`, `gs` and `file` a Preparation for Ubuntu:: sudo apt install php-intl - sudo apt install poppler-utils libxrender1 file pdf2svg pdfunite qpdf ghostscript # for file upload, PDF and 'HTML to PDF' (wkhtmltopdf), PDF split + sudo apt install poppler-utils libxrender1 file pdf2svg qpdf ghostscript # for file upload, PDF and 'HTML to PDF' (wkhtmltopdf), PDF split sudo apt install inkscape imagemagick # to render thumbnails .. _wkhtml: @@ -403,6 +404,12 @@ Extension Manager: QFQ Configuration +-----------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+ | cmdWkhtmltopdf | /usr/bin/wkhtmltopdf | PathFilename of wkhtmltopdf. Optional variables like LD_LIBRARY_PATH=... | +-----------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+ +| cmdQpdf | qpdf | PathFilename of qpdf. Optional variables like LD_LIBRARY_PATH=... | ++-----------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+ +| cmdGs | gs | PathFilename of gs. Optional variables like LD_LIBRARY_PATH=... | ++-----------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+ +| cmdPdfunite | pdfunite | PathFilename of pdfunite. Optional variables like LD_LIBRARY_PATH=... | ++-----------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+ | sendEMailOptions | -o tls=yes | General options. Check: http://caspian.dotconf.net/menu/Software/SendEmail | +-----------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+ | documentation | http://docs.typo3.org... | Link to the online documentation of QFQ. Every QFQ installation also | @@ -601,7 +608,7 @@ E.g. to setup a contact address and reuse the information inside your installati custom2: ADMINISTRATIVE_ADDRESS = John Doe, Hollywood Blvd. 1, L.A. custom3: ADMINISTRATIVE_NAME = John Doe - * Somewhere in a `Form` or in `Report`:: +* Somewhere in a `Form` or in `Report`:: {{ADMINISTRATIVE_CONTACT:Y}}, {{ADMINISTRATIVE_ADDRESS:Y}}, {{ADMINISTRATIVE_NAME}} @@ -756,77 +763,77 @@ QFQ Keywords (Bodytext) **All of these parameters are optional.** - +-------------------+---------------------------------------------------------------------------------+ - | Name | Explanation | - +===================+=================================================================================+ - | form | | Formname. | - | | | Static: **form = person** | - | | | By SIP: **form = {{form:SE}}** | - | | | By SQL: **form = {{SELECT c.form FROM Config AS c WHERE c.id={{a:C}} }}** | - +-------------------+---------------------------------------------------------------------------------+ - | r | | <record id>. The form will load the record with the specified id. | - | | | Static: **r = 123** | - | | | By SQL: **r = {{SELECT ...}}** | - | | | If not specified, the SIP parameter 'r' is used. | - +-------------------+---------------------------------------------------------------------------------+ - | dbIndex | E.g. `dbIndex = {{indexQfq:Y}}` Select a DB index. Only necessary if a | - | | different than the standard DB should be used. | - +-------------------+---------------------------------------------------------------------------------+ - | debugShowBodyText | If='1' and configuration_:*showDebugInfo: yes*, shows a tooltip with bodytext | - +-------------------+---------------------------------------------------------------------------------+ - | sqlLog | Overwrites configuration_: `SQL_LOG`_ . Only affects `Report`, not `Form`. | - +-------------------+---------------------------------------------------------------------------------+ - | sqlLogMode | Overwrites configuration_: `SQL_LOG_MODE`_ . Only affects `Report`, not `Form`. | - +-------------------+---------------------------------------------------------------------------------+ - | render | See `report-render`_. Overwrites configuration_: render. | - +-------------------+---------------------------------------------------------------------------------+ - | <level>.fbeg | Start token for every field (=column) | - +-------------------+---------------------------------------------------------------------------------+ - | <level>.fend | End token for every field (=column) | - +-------------------+---------------------------------------------------------------------------------+ - | <level>.fsep | Separator token between fields (=columns) | - +-------------------+---------------------------------------------------------------------------------+ - | <level>.fskipwrap | Skip wrapping (via fbeg, fsep, fend) of named columns. Comma separated list of | - | | column id's (starting at 1). See also the special column name '_noWrap' to | - | | suppress wrapping. | - +-------------------+---------------------------------------------------------------------------------+ - | <level>.shead | Static start token for whole <level>, independent if records are selected | - | | Shown before `head`. | - +-------------------+---------------------------------------------------------------------------------+ - | <level>.stail | Static end token for whole <level>, independent if records are selected. | - | | Shown after `tail`. | - +-------------------+---------------------------------------------------------------------------------+ - | <level>.head | Dynamic start token for whole <level>. Only if at least one record is select. | - +-------------------+---------------------------------------------------------------------------------+ - | <level>.tail | Dynamic end token for whole <level>. Only if at least one record is select. | - +-------------------+---------------------------------------------------------------------------------+ - | <level>.rbeg | Start token for row. | - +-------------------+---------------------------------------------------------------------------------+ - | <level>.rbgd | Alternating (per row) token. | - +-------------------+---------------------------------------------------------------------------------+ - | <level>.rend | End token for row. Will be rendered **before** subsequent levels are processed | - +-------------------+---------------------------------------------------------------------------------+ - | <level>.renr | End token for row. Will be rendered **after** subsequent levels are processed | - +-------------------+---------------------------------------------------------------------------------+ - | <level>.rsep | Seperator token between rows | - +-------------------+---------------------------------------------------------------------------------+ - | <level>.sql | SQL Query | - +-------------------+---------------------------------------------------------------------------------+ - | <level>.twig | Twig Template | - +-------------------+---------------------------------------------------------------------------------+ - | <level>.althead | If <level>.sql has no rows selected (empty), these token will be rendered. | - +-------------------+---------------------------------------------------------------------------------+ - | <level>.altsql | If <level>.sql has no rows selected (empty) or affected (delete, update, insert)| - | | the <altsql> will be fired. Note: Sub queries of <level> are not fired, even if | - | | <altsql> selects some rows. | - +-------------------+---------------------------------------------------------------------------------+ - | <level>.content | | *show* (default): content of current and sub level are directly shown. | - | | | *hide*: content of current and sub levels are stored and not shown. | - | | | *hideLevel*: content of current and sub levels are stored and only sub levels | - | | | are shown. | - | | | *store*: content of current and sub levels are stored and shown. | - | | | To retrieve the content: `{{<level>.line.content}}`. See `syntax-of-report`_ | - +-------------------+---------------------------------------------------------------------------------+ ++-------------------+---------------------------------------------------------------------------------+ +| Name | Explanation | ++===================+=================================================================================+ +| form | | Formname. | +| | | Static: **form = person** | +| | | By SIP: **form = {{form:SE}}** | +| | | By SQL: **form = {{SELECT c.form FROM Config AS c WHERE c.id={{a:C}} }}** | ++-------------------+---------------------------------------------------------------------------------+ +| r | | <record id>. The form will load the record with the specified id. | +| | | Static: **r = 123** | +| | | By SQL: **r = {{SELECT ...}}** | +| | | If not specified, the SIP parameter 'r' is used. | ++-------------------+---------------------------------------------------------------------------------+ +| dbIndex | E.g. `dbIndex = {{indexQfq:Y}}` Select a DB index. Only necessary if a | +| | different than the standard DB should be used. | ++-------------------+---------------------------------------------------------------------------------+ +| debugShowBodyText | If='1' and configuration_:*showDebugInfo: yes*, shows a tooltip with bodytext | ++-------------------+---------------------------------------------------------------------------------+ +| sqlLog | Overwrites configuration_: `SQL_LOG`_ . Only affects `Report`, not `Form`. | ++-------------------+---------------------------------------------------------------------------------+ +| sqlLogMode | Overwrites configuration_: `SQL_LOG_MODE`_ . Only affects `Report`, not `Form`. | ++-------------------+---------------------------------------------------------------------------------+ +| render | See `report-render`_. Overwrites configuration_: render. | ++-------------------+---------------------------------------------------------------------------------+ +| <level>.fbeg | Start token for every field (=column) | ++-------------------+---------------------------------------------------------------------------------+ +| <level>.fend | End token for every field (=column) | ++-------------------+---------------------------------------------------------------------------------+ +| <level>.fsep | Separator token between fields (=columns) | ++-------------------+---------------------------------------------------------------------------------+ +| <level>.fskipwrap | Skip wrapping (via fbeg, fsep, fend) of named columns. Comma separated list of | +| | column id's (starting at 1). See also the special column name '_noWrap' to | +| | suppress wrapping. | ++-------------------+---------------------------------------------------------------------------------+ +| <level>.shead | Static start token for whole <level>, independent if records are selected | +| | Shown before `head`. | ++-------------------+---------------------------------------------------------------------------------+ +| <level>.stail | Static end token for whole <level>, independent if records are selected. | +| | Shown after `tail`. | ++-------------------+---------------------------------------------------------------------------------+ +| <level>.head | Dynamic start token for whole <level>. Only if at least one record is select. | ++-------------------+---------------------------------------------------------------------------------+ +| <level>.tail | Dynamic end token for whole <level>. Only if at least one record is select. | ++-------------------+---------------------------------------------------------------------------------+ +| <level>.rbeg | Start token for row. | ++-------------------+---------------------------------------------------------------------------------+ +| <level>.rbgd | Alternating (per row) token. | ++-------------------+---------------------------------------------------------------------------------+ +| <level>.rend | End token for row. Will be rendered **before** subsequent levels are processed | ++-------------------+---------------------------------------------------------------------------------+ +| <level>.renr | End token for row. Will be rendered **after** subsequent levels are processed | ++-------------------+---------------------------------------------------------------------------------+ +| <level>.rsep | Seperator token between rows | ++-------------------+---------------------------------------------------------------------------------+ +| <level>.sql | SQL Query | ++-------------------+---------------------------------------------------------------------------------+ +| <level>.twig | Twig Template | ++-------------------+---------------------------------------------------------------------------------+ +| <level>.althead | If <level>.sql has no rows selected (empty), these token will be rendered. | ++-------------------+---------------------------------------------------------------------------------+ +| <level>.altsql | If <level>.sql has no rows selected (empty) or affected (delete, update, insert)| +| | the <altsql> will be fired. Note: Sub queries of <level> are not fired, even if | +| | <altsql> selects some rows. | ++-------------------+---------------------------------------------------------------------------------+ +| <level>.content | | *show* (default): content of current and sub level are directly shown. | +| | | *hide*: content of current and sub levels are stored and not shown. | +| | | *hideLevel*: content of current and sub levels are stored and only sub levels | +| | | are shown. | +| | | *store*: content of current and sub levels are stored and shown. | +| | | To retrieve the content: `{{<level>.line.content}}`. See `syntax-of-report`_ | ++-------------------+---------------------------------------------------------------------------------+ .. _`report-render`: @@ -835,10 +842,10 @@ Report: render QFQ will render Report or Form in three situations: - #. Browser: The QFQ content is described by QFQ-Report syntax. - #. Browser: The QFQ content is described by a QFQ-Form. - #. API: The QFQ content is handled without Typo3. Typically a single tt-content record is specified in the request - only - that one is rendered by QFQ. This mode is typically used to export data like Excel Export. +#. Browser: The QFQ content is described by QFQ-Report syntax. +#. Browser: The QFQ content is described by a QFQ-Form. +#. API: The QFQ content is handled without Typo3. Typically a single tt-content record is specified in the request - only + that one is rendered by QFQ. This mode is typically used to export data like Excel Export. Option 1 and 2 are distinguished by the parameter `form` (STORE_SIP or STORE_TYPO3). If 'form' is given, in most cases only a Form should be shown (not the report). @@ -854,6 +861,14 @@ should be shown (not the report). | api | Create output only when called via API (no Typo3). | +--------+-------------------------------------------------------------------------+ +Example:: + + render = both + form = {{form:SE}} + + 10 { + sql = SELECT ... + } .. _`qfq-database`: @@ -1271,8 +1286,8 @@ Some examples, including nesting:: Leading and trailing spaces inside curly braces are removed. - * *{{ SELECT "Hello World" }}* becomes *{{SELECT "Hello World"}}* - * *{{ varname }}* becomes *{{varname}}* +* *{{ SELECT "Hello World" }}* becomes *{{SELECT "Hello World"}}* +* *{{ varname }}* becomes *{{varname}}* Types ----- @@ -1282,18 +1297,11 @@ Types Store variables ^^^^^^^^^^^^^^^ -Syntax: *{{VarName[:<store(s)[:<sanitize class>[:<escape>[:<default value>[:type violate message]]]]]}}* - -See also: - - * `store`_ - * `sanitize-class`_ - * `variable-escape`_ - * `variable-default`_ - * `variable-type-message-violate`_ +.. note:: + Syntax: {{ `store`_ : `sanitize-class`_ : `variable-escape`_ : `variable-default`_ : `variable-type-message-violate`_ }} -* Example:: +Example:: {{pId}} {{pId:FSE}} @@ -1472,11 +1480,11 @@ Type message violate If a value violates the sanitize class, the following actions are possible: - * 'c' - The violated class will be set as content, surrounded by '!!'. E.g. '!!digit!!'. This is the default. - * 'e' - Instead of the value an empty string will be set as content. - * '0' - Instead of the value the string '0' will be set as content. - * 'custom text ...' - Instead of the value, the custom text will be set as content. If the text contains a ':', that one - needs to be escaped by \\ . Check `variable-escape`_ qualifier 'C' to let QFQ do the colon escaping. +* 'c' - The violated class will be set as content, surrounded by '!!'. E.g. '!!digit!!'. This is the default. +* 'e' - Instead of the value an empty string will be set as content. +* '0' - Instead of the value the string '0' will be set as content. +* 'custom text ...' - Instead of the value, the custom text will be set as content. If the text contains a ':', that one +needs to be escaped by \\ . Check `variable-escape`_ qualifier 'C' to let QFQ do the colon escaping. .. _`sql-variables`: @@ -1729,44 +1737,44 @@ Store Only variables that are known in a specified store can be substituted. - +-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ - |Name |Description | Content | - +=====+========================================================================================+================================================================================+ - | B | :ref:`STORE_BEFORE`: Record - the current record loaded in the form before any update. | All columns of the current record from the current table. See `STORE_BEFORE`_. | - +-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ - | C | :ref:`STORE_CLIENT`: POST variable, if not found: GET variable. | Parameter sent from the Client (=Browser). See `STORE_CLIENT`_. | - +-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ - | D | Default values column : The *table.column* specified *default value*. | | - +-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ - | E | *Empty* - always an empty string, might be helpful if a variable is empty or undefined | Any key | - | | and will be used in an SQL statement. | | - +-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ - | F | :ref:`STORE_FORM`: data not saved in database yet. | All native *FormElements*. Recent values from the Browser. See: `STORE_FORM`_ | - +-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ - | L | :ref:`STORE_LDAP`: Will be filled on demand during processing of a *FormElement*. | Custom specified list of LDAP attributes. See `STORE_LDAP`_. | - +-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ - | M | Column type: The *table.column* specified *type*. | | - +-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ - | P | Parent record. E.g.: on multi & copy forms the current record of the outer query. | All columns of the MultiSQL Statement from the table for the current row | - +-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ - | R | :ref:`STORE_RECORD`: Record - the current record loaded in the form. | All columns of the current record from the current table. See `STORE_RECORD`_. | - +-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ - | S | :ref:`STORE_SIP`: Client parameter 's' will indicate the current SIP, which will be | sip, r (recordId), form. See `STORE_SIP`_. | - | | loaded from the SESSION repo to the SIP-Store. | | - +-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ - | T | :ref:`STORE_TYPO3`: a) Bodytext (ttcontent record), b) Typo3 internal variables. | See Typo3 tt_content record configuration. See `STORE_TYPO3`_. | - +-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ - | U | :ref:`STORE_USER`: per user variables, valid as long as the browser session lives. | Set via report: '...' AS '_=<var name>' See: `STORE_USER`_, | - | | | `store_user_examples`_ | - +-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ - | V | :ref:`STORE_VARS`: Generic variables. | See `STORE_VARS`_. | - +-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ - | Y | :ref:`STORE_SYSTEM`: a) Database, b) helper vars for logging/debugging: | See `STORE_SYSTEM`_. | - | | SYSTEM_SQL_RAW ... SYSTEM_FORM_ELEMENT_COLUMN, c) Any custom fields: CONTACT, HELP, ...| | - +-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ - | 0 | *Zero* - always value: 0, might be helpful if a variable is empty or undefined and | Any key | - | | will be used in an SQL statement. | | - +-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ ++-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ +|Name |Description | Content | ++=====+========================================================================================+================================================================================+ +| B | :ref:`STORE_BEFORE`: Record - the current record loaded in the form before any update. | All columns of the current record from the current table. See `STORE_BEFORE`_. | ++-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ +| C | :ref:`STORE_CLIENT`: POST variable, if not found: GET variable. | Parameter sent from the Client (=Browser). See `STORE_CLIENT`_. | ++-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ +| D | Default values column : The *table.column* specified *default value*. | | ++-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ +| E | *Empty* - always an empty string, might be helpful if a variable is empty or undefined | Any key | +| | and will be used in an SQL statement. | | ++-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ +| F | :ref:`STORE_FORM`: data not saved in database yet. | All native *FormElements*. Recent values from the Browser. See: `STORE_FORM`_ | ++-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ +| L | :ref:`STORE_LDAP`: Will be filled on demand during processing of a *FormElement*. | Custom specified list of LDAP attributes. See `STORE_LDAP`_. | ++-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ +| M | Column type: The *table.column* specified *type*. | | ++-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ +| P | Parent record. E.g.: on multi & copy forms the current record of the outer query. | All columns of the MultiSQL Statement from the table for the current row | ++-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ +| R | :ref:`STORE_RECORD`: Record - the current record loaded in the form. | All columns of the current record from the current table. See `STORE_RECORD`_. | ++-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ +| S | :ref:`STORE_SIP`: Client parameter 's' will indicate the current SIP, which will be | sip, r (recordId), form. See `STORE_SIP`_. | +| | loaded from the SESSION repo to the SIP-Store. | | ++-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ +| T | :ref:`STORE_TYPO3`: a) Bodytext (ttcontent record), b) Typo3 internal variables. | See Typo3 tt_content record configuration. See `STORE_TYPO3`_. | ++-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ +| U | :ref:`STORE_USER`: per user variables, valid as long as the browser session lives. | Set via report: '...' AS '_=<var name>' See: `STORE_USER`_, | +| | | `store_user_examples`_ | ++-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ +| V | :ref:`STORE_VARS`: Generic variables. | See `STORE_VARS`_. | ++-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ +| Y | :ref:`STORE_SYSTEM`: a) Database, b) helper vars for logging/debugging: | See `STORE_SYSTEM`_. | +| | SYSTEM_SQL_RAW ... SYSTEM_FORM_ELEMENT_COLUMN, c) Any custom fields: CONTACT, HELP, ...| | ++-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ +| 0 | *Zero* - always value: 0, might be helpful if a variable is empty or undefined and | Any key | +| | will be used in an SQL statement. | | ++-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ * Default *<prio>*: *FSRVD* - Form / SIP / Record / Vars / Table definition. * Hint: Preferable, parameter should be submitted by SIP, not by Client (=URL). @@ -1788,11 +1796,11 @@ Store: *FORM* - F * *FormElement* actions, before saving the form. * Values will be sanitized by the class configured in corresponding the *FormElement*. By default, the sanitize class is `alnumx`. - +---------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ - | Name | Explanation | - +=================================+============================================================================================================================================+ - | <FormElement name> | Name of native *FormElement*. To get, exactly and only, the specified *FormElement* (for 'pId'): *{{pId:F}}* | - +---------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ ++---------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| Name | Explanation | ++=================================+============================================================================================================================================+ +| <FormElement name> | Name of native *FormElement*. To get, exactly and only, the specified *FormElement* (for 'pId'): *{{pId:F}}* | ++---------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ .. _STORE_SIP: @@ -1805,21 +1813,21 @@ Store: *SIP* - S * in `Report` by using `_page?` or `_link` (with active 's') * in `Form` by using subrecords: 'new', 'edit', 'delete' links (system) or by column type `_page?`, `_link`. - +-------------------------+-----------------------------------------------------------+ - | Name | Explanation | - +=========================+===========================================================+ - | sip | 13 char uniqid | - +-------------------------+-----------------------------------------------------------+ - | r | current record id | - +-------------------------+-----------------------------------------------------------+ - | form | current form name | - +-------------------------+-----------------------------------------------------------+ - | table | current table name | - +-------------------------+-----------------------------------------------------------+ - | urlparam | all non Typo3 parameter in one string | - +-------------------------+-----------------------------------------------------------+ - | <user defined> | additional user defined link parameter | - +-------------------------+-----------------------------------------------------------+ ++-------------------------+-----------------------------------------------------------+ +| Name | Explanation | ++=========================+===========================================================+ +| sip | 13 char uniqid | ++-------------------------+-----------------------------------------------------------+ +| r | current record id | ++-------------------------+-----------------------------------------------------------+ +| form | current form name | ++-------------------------+-----------------------------------------------------------+ +| table | current table name | ++-------------------------+-----------------------------------------------------------+ +| urlparam | all non Typo3 parameter in one string | ++-------------------------+-----------------------------------------------------------+ +| <user defined> | additional user defined link parameter | ++-------------------------+-----------------------------------------------------------+ .. _STORE_RECORD: @@ -1832,17 +1840,17 @@ Store: *RECORD* - R * *Report*: See `access-column-values`_ * If r=0, all values are empty. - +------------------------+-------------------------------------------------------------------------------------------------------------------------+ - | Name | Type | Explanation | - +========================+==========+==============================================================================================================+ - | <column name> | Form | Name of a column of the primary table (as defined in the current form). Example: *{{pId:R}}* | - +------------------------+----------+--------------------------------------------------------------------------------------------------------------+ - | <column name> | Report | Name of a column of a previous fired SQL query. Example: *{{pId:R}}* | - +------------------------+----------+--------------------------------------------------------------------------------------------------------------+ - | &<column name> | Report | Name of a column of a previous fired SQL query, typically used by columns with a `special-column-names`_. | - | | (final) | Final value. Example: '{{link:R}}' returns 'p:home&form=Person|s|b:success|t:Edit'. | - | | | Whereas '{{&link:R}}' returns '<span class="btn btn-success"><a href="?home&s=badcaffee1234">Edit</a></span> | - +------------------------+----------+--------------------------------------------------------------------------------------------------------------+ ++------------------------+-------------------------------------------------------------------------------------------------------------------------+ +| Name | Type | Explanation | ++========================+==========+==============================================================================================================+ +| <column name> | Form | Name of a column of the primary table (as defined in the current form). Example: *{{pId:R}}* | ++------------------------+----------+--------------------------------------------------------------------------------------------------------------+ +| <column name> | Report | Name of a column of a previous fired SQL query. Example: *{{pId:R}}* | ++------------------------+----------+--------------------------------------------------------------------------------------------------------------+ +| &<column name> | Report | Name of a column of a previous fired SQL query, typically used by columns with a `special-column-names`_. | +| | (final) | Final value. Example: '{{link:R}}' returns 'p:home&form=Person|s|b:success|t:Edit'. | +| | | Whereas '{{&link:R}}' returns '<span class="btn btn-success"><a href="?home&s=badcaffee1234">Edit</a></span> | ++------------------------+----------+--------------------------------------------------------------------------------------------------------------+ .. _STORE_BEFORE: @@ -1856,11 +1864,11 @@ Store: *BEFORE* - B This store is handy to compare new and old values of a form. - +------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+ - | Name | Explanation | - +========================+==================================================================================================================================================+ - | <column name> | Name of a column of the primary table (as defined in the current form). To get, exactly and only, the specified form *FormElement*: *{{pId:B}}* | - +------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+ ++------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+ +| Name | Explanation | ++========================+==================================================================================================================================================+ +| <column name> | Name of a column of the primary table (as defined in the current form). To get, exactly and only, the specified form *FormElement*: *{{pId:B}}* | ++------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+ .. _STORE_CLIENT: @@ -1869,23 +1877,29 @@ Store: *CLIENT* - C * Sanitized: *yes* - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ - | Name | Explanation | - +=========================+==========================================================================================================================================+ - | s | =SIP | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ - | r | record id. Only if specified as GET parameter - typically stored in SIP (=STORE_SIP) | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ - | form | Name of form to load. Only if specified as GET parameter - typically stored in SIP (=STORE_SIP) | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ - | HTTP_HOST | current HTTP HOST | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ - | REMOTE_ADDR | Client IP address | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ - | '$_SERVER[*]' | All other variables accessible by *$_SERVER[]*. Only the often used have a pre-defined sanitize class. | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ - | Authorization | Value of the HTTP Header 'Authorization'. This is typically not set. Mostly used for authentication of REST requests | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ +| Name | Explanation | ++=========================+==========================================================================================================================================+ +| s | =SIP | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ +| r | record id. Only if specified as GET parameter - typically stored in SIP (=STORE_SIP) | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ +| form | Name of form to load. Only if specified as GET parameter - typically stored in SIP (=STORE_SIP) | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ +| HTTP_HOST | current HTTP HOST | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ +| REMOTE_ADDR | Client IP address | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ +| All HTTP Header | SERVER_ADDR, SERVER_NAME, SERVER_SOFTWARE,SERVER_PROTOCOL, REQUEST_METHOD, REQUEST_TIME, REQUEST_TIME_FLOAT, QUERY_STRING, DOCUMENT_ROOT,| +| variables | HTTP_ACCEPT, HTTP_ACCEPT_CHARSET, HTTP_ACCEPT_ENCODING, HTTP_ACCEPT_LANGUAGE, HTTP_CONNECTION, HTTP_HOST, HTTP_REFERER, | +| | HTTP_USER_AGENT, HTTPS, REMOTE_ADDR, REMOTE_HOST, REMOTE_PORT, REMOTE_USER, REDIRECT_REMOTE_USER, SCRIPT_FILENAME, SERVER_ADMIN, | +| | SERVER_PORT, SERVER_SIGNATURE, PATH_TRANSLATED, SCRIPT_NAME, REQUEST_URI, PHP_AUTH_DIGEST, PHP_AUTH_USER, PHP_AUTH_PW, | +| | AUTH_TYPE, PATH_INFO, ORIG_PATH_INFO | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ +| Authorization | Value of the HTTP Header 'Authorization'. This is typically not set. Mostly used for authentication of REST requests | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ + + .. _STORE_TYPO3: @@ -1894,35 +1908,35 @@ Store: *TYPO3* (Bodytext) - T * Sanitized: *no* - +-------------------------+-------------------------------------------------------------------+----------+ - | Name | Explanation | Note | - +=========================+===================================================================+==========+ - | form | | Formname defined in ttcontent record bodytext | see note | - | | | * Fix. E.g. *form = person* | | - | | | * via SIP. E.g. *form = {{form:SE}}* | | - +-------------------------+-------------------------------------------------------------------+----------+ - | pageId | Record id of current Typo3 page | see note | - +-------------------------+-------------------------------------------------------------------+----------+ - | pageAlias | Alias of current Typo3 page. If empty, take pageId. | see note | - +-------------------------+-------------------------------------------------------------------+----------+ - | pageTitle | Title of current Typo3 page | see note | - +-------------------------+-------------------------------------------------------------------+----------+ - | pageType | Current selected page type (typically URL parameter 'type') | see note | - +-------------------------+-------------------------------------------------------------------+----------+ - | pageLanguage | Current selected page language (typically URL parameter 'L') | see note | - +-------------------------+-------------------------------------------------------------------+----------+ - | ttcontentUid | Record id of current Typo3 content element | see note | - +-------------------------+-------------------------------------------------------------------+----------+ - | feUser | Logged in Typo3 FE User | | - +-------------------------+-------------------------------------------------------------------+----------+ - | feUserUid | Logged in Typo3 FE User uid | | - +-------------------------+-------------------------------------------------------------------+----------+ - | feUserGroup | FE groups of logged in Typo3 FE User | | - +-------------------------+-------------------------------------------------------------------+----------+ - | beUser | Logged in Typo3 BE User | | - +-------------------------+-------------------------------------------------------------------+----------+ - | beUserLoggedIn | 'yes' | 'no' - Status if a BE-User is logged in | | - +-------------------------+-------------------------------------------------------------------+----------+ ++-------------------------+-------------------------------------------------------------------+----------+ +| Name | Explanation | Note | ++=========================+===================================================================+==========+ +| form | | Formname defined in ttcontent record bodytext | see note | +| | | * Fix. E.g. *form = person* | | +| | | * via SIP. E.g. *form = {{form:SE}}* | | ++-------------------------+-------------------------------------------------------------------+----------+ +| pageId | Record id of current Typo3 page | see note | ++-------------------------+-------------------------------------------------------------------+----------+ +| pageAlias | Alias of current Typo3 page. If empty, take pageId. | see note | ++-------------------------+-------------------------------------------------------------------+----------+ +| pageTitle | Title of current Typo3 page | see note | ++-------------------------+-------------------------------------------------------------------+----------+ +| pageType | Current selected page type (typically URL parameter 'type') | see note | ++-------------------------+-------------------------------------------------------------------+----------+ +| pageLanguage | Current selected page language (typically URL parameter 'L') | see note | ++-------------------------+-------------------------------------------------------------------+----------+ +| ttcontentUid | Record id of current Typo3 content element | see note | ++-------------------------+-------------------------------------------------------------------+----------+ +| feUser | Logged in Typo3 FE User | | ++-------------------------+-------------------------------------------------------------------+----------+ +| feUserUid | Logged in Typo3 FE User uid | | ++-------------------------+-------------------------------------------------------------------+----------+ +| feUserGroup | FE groups of logged in Typo3 FE User | | ++-------------------------+-------------------------------------------------------------------+----------+ +| beUser | Logged in Typo3 BE User | | ++-------------------------+-------------------------------------------------------------------+----------+ +| beUserLoggedIn | 'yes' | 'no' - Status if a BE-User is logged in | | ++-------------------------+-------------------------------------------------------------------+----------+ * **note**: not available: @@ -1936,38 +1950,38 @@ Store: *VARS* - V * Sanitized: *no* - +-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ - | Name | Explanation | - +=========================+============================================================================================================================================+ - | random | Random string with length of 32 alphanum chars (lower & upper case). This is variable is always filled. | - +-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ - | slaveId | see `slaveId`_ | - +-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ - | allRequiredGiven | Form save - Set during check of all required FE. If every *required* FE is given: *1*. Else: *0*. If there is no required FE: *1*. | - | | Even with `formModeGlobal` = `requiredOff` | `requiredOffButMark` the variable will be set. | - +-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| Name | Explanation | ++=========================+============================================================================================================================================+ +| random | Random string with length of 32 alphanum chars (lower & upper case). This is variable is always filled. | ++-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| slaveId | see `slaveId`_ | ++-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| allRequiredGiven | Form save - Set during check of all required FE. If every *required* FE is given: *1*. Else: *0*. If there is no required FE: *1*. | +| | Even with `formModeGlobal` = `requiredOff` | `requiredOffButMark` the variable will be set. | ++-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ .. _`store_vars_form_element_upload`: * FormElement 'upload': - +-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ - | Name | Explanation | - +=========================+============================================================================================================================================+ - | filename | Original filename of an uploaded file via an 'upload'-FormElement. Valid only during processing of the current 'upload'-formElement. | - +-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ - | filenameOnly | Like filename, but without path. | - +-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ - | filenameBase | Like `filename`, but without an optional extension. E.g. filename='image.png' comes to filenameBase='image' | - +-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ - | filenameExt | Like `filename`, but only the optional extension. E.g. filename='image.png' comes to filenameExt='png' | - +-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ - | fileDestination | Destination (path & filename) for an uploaded file. Defined in an 'upload'-FormElement.parameter. Valid: same as 'filename'. | - +-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ - | fileSize | Size of the uploaded file. | - +-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ - | mimeType | Mime type of the uploaded file. | - +-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| Name | Explanation | ++=========================+============================================================================================================================================+ +| filename | Original filename of an uploaded file via an 'upload'-FormElement. Valid only during processing of the current 'upload'-formElement. | ++-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| filenameOnly | Like filename, but without path. | ++-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| filenameBase | Like `filename`, but without an optional extension. E.g. filename='image.png' comes to filenameBase='image' | ++-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| filenameExt | Like `filename`, but only the optional extension. E.g. filename='image.png' comes to filenameExt='png' | ++-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| fileDestination | Destination (path & filename) for an uploaded file. Defined in an 'upload'-FormElement.parameter. Valid: same as 'filename'. | ++-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| fileSize | Size of the uploaded file. | ++-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| mimeType | Mime type of the uploaded file. | ++-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ The directive `fillStoreVar` will fill the store VARS with custom values. Existing Store VARS values will be merged together with them. @@ -1988,11 +2002,11 @@ Store: *LDAP* - L * Sanitized: *yes* * See also :ref:`LDAP`: - +-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ - | Name | Explanation | - +=========================+============================================================================================================================================+ - | <custom defined> | See *ldapAttributes* | - +-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| Name | Explanation | ++=========================+============================================================================================================================================+ +| <custom defined> | See *ldapAttributes* | ++-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+ @@ -3264,7 +3278,7 @@ See also at specific *FormElement* definitions. +---------------------------------+----------------------------------------------------------------------------------------------------------+ - * `s/d/n`: string or date or number. +* `s/d/n`: string or date or number. slaveId, sqlBefore, sqlAfter, ... """"""""""""""""""""""""""""""""" @@ -3402,8 +3416,8 @@ Checkboxes can be rendered in mode: * *FormElement.sql1* = ``{{!SELECT id, value FROM SomeTable}}`` * *FormElement.maxlength* - vertical or horizontal alignment: - * Value: '', 0, 1 - The check boxes will be aligned vertical. - * Value: >1 - The check boxes will be aligned horizontal, with a linebreak every 'value' elements. + * Value: '', 0, 1 - The check boxes will be aligned vertical. + * Value: >1 - The check boxes will be aligned horizontal, with a linebreak every 'value' elements. * *FormElement.parameter*: @@ -3647,20 +3661,20 @@ Usage: assign favourite fruits to a person. The fruits are the tags, the glue re The form will be open with a person record and has only one FormElement. - * Form.name=personFavouriteFruits - * Form.title=Person Favourite Fruits - * Form.primaryTable = Person +* Form.name=personFavouriteFruits +* Form.title=Person Favourite Fruits +* Form.primaryTable = Person - * FormElement[1].name = myFavoriteFruits - * FormElement[1].type = Text - * FormElement[1].value = {{SELECT GROUP_CONCAT( CONCAT(f.id, ':', f.name)) FROM FruitPerson AS fp, Fruit AS f WHERE fp.pId={{id:R}} AND fp.fruitId=f.id ORDER BY f.name}} - * FormElement[1].parameter: +* FormElement[1].name = myFavoriteFruits +* FormElement[1].type = Text +* FormElement[1].value = {{SELECT GROUP_CONCAT( CONCAT(f.id, ':', f.name)) FROM FruitPerson AS fp, Fruit AS f WHERE fp.pId={{id:R}} AND fp.fruitId=f.id ORDER BY f.name}} +* FormElement[1].parameter: - * typeAheadTag = 1 - * typeAheadSql = SELECT f.id AS 'id', f.name AS 'value' FROM Fruit AS f WHERE f.name LIKE ? - * typeAheadMinLength = 1 - * typeAheadGlueInsert = {{INSERT INTO FruitPerson (pId, fruitId) VALUES ({{id:R}}, {{tagId:V}} ) }} - * typeAheadGlueDelete = {{DELETE FROM FruitPerson WHERE pId={{id:R}} AND fruitId={{tagId:V}} }} + * typeAheadTag = 1 + * typeAheadSql = SELECT f.id AS 'id', f.name AS 'value' FROM Fruit AS f WHERE f.name LIKE ? + * typeAheadMinLength = 1 + * typeAheadGlueInsert = {{INSERT INTO FruitPerson (pId, fruitId) VALUES ({{id:R}}, {{tagId:V}} ) }} + * typeAheadGlueDelete = {{DELETE FROM FruitPerson WHERE pId={{id:R}} AND fruitId={{tagId:V}} }} Explanation: @@ -3839,27 +3853,27 @@ Type: radio 1. 'sql1': E.g. *{{!SELECT type AS label FROM Car }}* or *{{!SELECT type AS label, typeNr AS id FROM Car}}* or *{{!SHOW tables}}*. - * Resultset format 'named': column 'label' and optional a column 'id'. - * Resultset format 'index': + * Resultset format 'named': column 'label' and optional a column 'id'. + * Resultset format 'index': - * One column in resultset >> first column represents *label* - * Two or more columns in resultset >> first column represents *id* and second column represents *label*. + * One column in resultset >> first column represents *label* + * Two or more columns in resultset >> first column represents *id* and second column represents *label*. 2. *FormElement.parameter*: - * *itemList* = `<attribute>` E.g.: *itemList=red,blue,orange* or *itemList=1:red,2:blue,3:orange* - * If ':' or ',' are part of key or value, it needs to escaped by \\ . E.g.: `itemList=1:red\\: (with colon),2:blue\\, (with comma),3:orange` + * *itemList* = `<attribute>` E.g.: *itemList=red,blue,orange* or *itemList=1:red,2:blue,3:orange* + * If ':' or ',' are part of key or value, it needs to escaped by \\ . E.g.: `itemList=1:red\\: (with colon),2:blue\\, (with comma),3:orange` 3. Definition of the *enum* or *set* field (only labels, ids are not possible). * *FormElement.maxlength* = `<value>` - * Applies only to 'plain' radio elements (not the Bootstrap 'buttonClass' from below) - * *vertical* or *horizontal* alignment: + * Applies only to 'plain' radio elements (not the Bootstrap 'buttonClass' from below) + * *vertical* or *horizontal* alignment: - * `<value>`: '', 0, 1 - The radios will be aligned *vertical*. - * `<value>`: >1 - The readios will be aligned *horizontal*, with a linebreak every 'value' elements. + * `<value>`: '', 0, 1 - The radios will be aligned *vertical*. + * `<value>`: >1 - The readios will be aligned *horizontal*, with a linebreak every 'value' elements. * *FormElement.parameter*: @@ -3948,7 +3962,7 @@ will be rendered inside the form as a HTML table. * *sql1* = `{{!SQL Query}}` - * SQL query to select records. E.g.:: + * SQL query to select records. E.g.:: {{!SELECT addr.id AS id, CONCAT(addr.street, addr.streetnumber) AS a, addr.city AS b, addr.zip AS c FROM Address AS addr}} @@ -4018,13 +4032,13 @@ will be rendered inside the form as a HTML table. statements) might be used. * *subrecordTableClass*: Optional. Default: 'table table-hover qfq-subrecord-table qfq-color-grey-2'. If given, the default will be - overwritten. Example: :: + overwritten. Example:: subrecordTableClass = table table-hover qfq-subrecord-table qfq-table-50 - * Tablesorter in Subrecord: + * Tablesorter in Subrecord:: - subrecordTableClass = table table-hover qfq-subrecord-table tablesorter tablesorter-pager tablesorter-filter + subrecordTableClass = table table-hover qfq-subrecord-table tablesorter tablesorter-pager tablesorter-filter * *subrecordColumnTitleEdit*: Optional. Will be rendered as the column title for the new/edit column. * *subrecordColumnTitleDelete*: Optional. Will be rendered as the column title for the delete column. @@ -4104,129 +4118,130 @@ and will be processed after saving the primary record and before any action Form See also `downloadButton`_ to offer a download of an uploaded file. -* *FormElement.parameter*: +FormElement.parameter +""""""""""""""""""""" - * *fileButtonText*: Overwrite default ‘Choose File’ - * *capture* = `camera` - On a smartphone, after pressing the 'open file' button, the camera will be opened and a - choosen picture will be uploaded. Automatically set/overwrite `accept=image/*`. +* *fileButtonText*: Overwrite default ‘Choose File’ +* *capture* = `camera` - On a smartphone, after pressing the 'open file' button, the camera will be opened and a + choosen picture will be uploaded. Automatically set/overwrite `accept=image/*`. - * *accept* = `<mime type>,image/*,video/*,audio/*,.doc,.docx,.pdf` +* *accept* = `<mime type>,image/*,video/*,audio/*,.doc,.docx,.pdf` - * List of mime types (also known as 'media types'): http://www.iana.org/assignments/media-types/media-types.xhtml - * If none mime type is specified, 'application/pdf' is set. This forces that always (!) one type is specified. - * To allow any type, specify ``*`` or ``*/*`` or ``*.*``. - * One or more media types might be specified, separated by ','. - * Different browser respect the given definitions in different ways. Typically the 'file choose' dialog offer: + * List of mime types (also known as 'media types'): http://www.iana.org/assignments/media-types/media-types.xhtml + * If none mime type is specified, 'application/pdf' is set. This forces that always (!) one type is specified. + * To allow any type, specify ``*`` or ``*/*`` or ``*.*``. + * One or more media types might be specified, separated by ','. + * Different browser respect the given definitions in different ways. Typically the 'file choose' dialog offer: - * the specified mime type (some browers only show 'custom', if more than one mime type is given), - * the option 'All files' (the user is always free to **try** to upload other file types) - but the server won't accept them, - * the 'file choose' dialog only offers files of the selected (in the dialog) type. + * the specified mime type (some browers only show 'custom', if more than one mime type is given), + * the option 'All files' (the user is always free to **try** to upload other file types) - but the server won't accept them, + * the 'file choose' dialog only offers files of the selected (in the dialog) type. - * If for a specific file type is no mime type available, the definition of file extension(s) is possible. This is **less - secure**, cause there is no *content* check on the server after the upload. + * If for a specific file type is no mime type available, the definition of file extension(s) is possible. This is **less + secure**, cause there is no *content* check on the server after the upload. - * *maxFileSize* = `<size>` - max filesize in bytes (no unit), kilobytes (k/K) or megabytes (m/M) for an uploaded file. - If empty or not given, take value from Form, System or System default. +* *maxFileSize* = `<size>` - max filesize in bytes (no unit), kilobytes (k/K) or megabytes (m/M) for an uploaded file. + If empty or not given, take value from Form, System or System default. - * *fileTrash* = [0|1] - Default: '1'. This option en-/disables the trash button right beside the file chooser. By default - the trash is visible. The trash is only visible if a) there is already a file uploaded or b) a new file has been chosen. +* *fileTrash* = [0|1] - Default: '1'. This option en-/disables the trash button right beside the file chooser. By default + the trash is visible. The trash is only visible if a) there is already a file uploaded or b) a new file has been chosen. - * *fileTrashText* = `<string>` - Default: ''. Will be shown right beside the trash glyph-icon. +* *fileTrashText* = `<string>` - Default: ''. Will be shown right beside the trash glyph-icon. - * *fileDestination* = `<pathFileName>` - Destination where to copy the file. A good practice is to specify a relative `fileDestination` - - such an installation (filesystem and database) are moveable. +* *fileDestination* = `<pathFileName>` - Destination where to copy the file. A good practice is to specify a relative `fileDestination` - + such an installation (filesystem and database) are moveable. - * If the original filename should be part of `fileDestination`, the variable *{{filename}}* (STORE_VARS) can be used. Example :: + * If the original filename should be part of `fileDestination`, the variable *{{filename}}* (STORE_VARS) can be used. Example :: - fileDestination={{SELECT 'fileadmin/user/pictures/', p.name, '-{{filename}}' FROM Person AS p WHERE p.id={{id:R0}} }} + fileDestination={{SELECT 'fileadmin/user/pictures/', p.name, '-{{filename}}' FROM Person AS p WHERE p.id={{id:R0}} }} - * Several more variants of the filename and also mimetype and filesize are available. See `store_vars_form_element_upload`_. + * Several more variants of the filename and also mimetype and filesize are available. See `store_vars_form_element_upload`_. - * The original filename will be sanitized: only '<alnum>', '.' and '_' characters are allowed. German 'umlaut' will - be replaced by 'ae', 'ue', 'oe'. All non valid characters will be replaced by '_'. + * The original filename will be sanitized: only '<alnum>', '.' and '_' characters are allowed. German 'umlaut' will + be replaced by 'ae', 'ue', 'oe'. All non valid characters will be replaced by '_'. - * If a file already exist under `fileDestination`, an error message is shown and 'save' is aborted. The user has no - possibility to overwrite the already existing file. If the whole workflow is correct, this situation should no - arise. Check also *fileReplace* below. + * If a file already exist under `fileDestination`, an error message is shown and 'save' is aborted. The user has no + possibility to overwrite the already existing file. If the whole workflow is correct, this situation should no + arise. Check also *fileReplace* below. - * All necessary subdirectories in `fileDestination` are automatically created. + * All necessary subdirectories in `fileDestination` are automatically created. - * Using the current record id in the `fileDestination`: Using {{r}} is problematic for a 'new' primary record: that - one is still '0' at the time of saving. Use `{{id:R0}}` instead. + * Using the current record id in the `fileDestination`: Using {{r}} is problematic for a 'new' primary record: that + one is still '0' at the time of saving. Use `{{id:R0}}` instead. - * Uploading of malicious code (e.g. PHP files) is hard to detect. The default mime type check can be easily faked - by an attacker. Therefore it's recommended to use a `fileDestination`-directory, which is secured against script - execution (even if the file has been uploaded, the webserver won't execute it) - see `SecureDirectFileAccess`_. + * Uploading of malicious code (e.g. PHP files) is hard to detect. The default mime type check can be easily faked + by an attacker. Therefore it's recommended to use a `fileDestination`-directory, which is secured against script + execution (even if the file has been uploaded, the webserver won't execute it) - see `SecureDirectFileAccess`_. - * *sqlBefore*, *sqlAfter*: available in :ref:`Upload simple mode` and :ref:`Upload advanced mode`. - * *slaveId*, *sqlInsert*, *sqlUpdate*, *sqlDelete*, *sqlUpdate*: available only in :ref:`Upload advanced mode`. +* *sqlBefore*, *sqlAfter*: available in :ref:`Upload simple mode` and :ref:`Upload advanced mode`. +* *slaveId*, *sqlInsert*, *sqlUpdate*, *sqlDelete*, *sqlUpdate*: available only in :ref:`Upload advanced mode`. - * `fileSize` / `mimeType` +* `fileSize` / `mimeType` - * In :ref:`Upload simple mode` the information of `fileSize` and `mimeType` will be automatically updated on the current - record, if table columns `fileSize` and/or `mimeType` exist. + * In :ref:`Upload simple mode` the information of `fileSize` and `mimeType` will be automatically updated on the current + record, if table columns `fileSize` and/or `mimeType` exist. - * If there are more than one Upload FormElement in a form, the automatically update for `fileSize` and/or `mimeType` - are not done automatically. + * If there are more than one Upload FormElement in a form, the automatically update for `fileSize` and/or `mimeType` + are not done automatically. - * In :ref:`Upload advanced mode` the `fileSize` and / or `mimeType` have to be updated with an explicit SQL statement:: + * In :ref:`Upload advanced mode` the `fileSize` and / or `mimeType` have to be updated with an explicit SQL statement:: - sqlAfter = {{UPDATE Data SET mimeType='{{mimeType:V}}', fileSize={{fileSize:V}} WHERE id={{id:R}} }} + sqlAfter = {{UPDATE Data SET mimeType='{{mimeType:V}}', fileSize={{fileSize:V}} WHERE id={{id:R}} }} - * *fileReplace* = `always` - If `fileDestination` exist - replace it by the new one. +* *fileReplace* = `always` - If `fileDestination` exist - replace it by the new one. - * *chmodFile* = <unix file permission mode> - e.g. `660` for owner and group read and writeable. Only the numeric mode is allowed. - * *chmodDir* = <unix file permission mode> - e.g. `770` for owner and group read, writeable and executable. Only the - numeric mode is allowed. Will be applied to all new created directories. +* *chmodFile* = <unix file permission mode> - e.g. `660` for owner and group read and writeable. Only the numeric mode is allowed. +* *chmodDir* = <unix file permission mode> - e.g. `770` for owner and group read, writeable and executable. Only the + numeric mode is allowed. Will be applied to all new created directories. - * *autoOrient:* images might contain EXIF data (e.g. captured via mobile phones) incl. an orientation tag like TopLeft, - BottomRight and so on. Web-Browser and other grafic programs often understand and respect those information and rotate - such images automatically. If not, the image might be displayed in an unwanted oritentation. - With active option 'autoOrient', QFQ tries to normalize such images via 'convert' (part of ImageMagick). Especially - if images are processed by the QFQ internal 'Fabric'-JS it's recommended to normalize images first. The normalization - process does not solve all orientation problems. +* *autoOrient:* images might contain EXIF data (e.g. captured via mobile phones) incl. an orientation tag like TopLeft, + BottomRight and so on. Web-Browser and other grafic programs often understand and respect those information and rotate + such images automatically. If not, the image might be displayed in an unwanted oritentation. + With active option 'autoOrient', QFQ tries to normalize such images via 'convert' (part of ImageMagick). Especially + if images are processed by the QFQ internal 'Fabric'-JS it's recommended to normalize images first. The normalization + process does not solve all orientation problems. - * *autoOrient* = [0|1] - * *autoOrientCmd* = 'convert -auto-orient {{fileDestination:V}} {{fileDestination:V}}.new; mv {{fileDestination:V}}.new {{fileDestination:V}}' - * *autoOrientMimeType* = image/jpeg,image/png,image/tiff + * *autoOrient* = [0|1] + * *autoOrientCmd* = 'convert -auto-orient {{fileDestination:V}} {{fileDestination:V}}.new; mv {{fileDestination:V}}.new {{fileDestination:V}}' + * *autoOrientMimeType* = image/jpeg,image/png,image/tiff - If the defaults for `autoOrientCmd` and `autoOrientMimeType` are sufficient, it's not necessary to specify them. + If the defaults for `autoOrientCmd` and `autoOrientMimeType` are sufficient, it's not necessary to specify them. .. _`downloadButton`: - * *downloadButton* = `t:<string>` - If given, shows a button to download the previous uploaded file - instead of the string given in - `fe.value`. The button is only shown if `fe.value` points to a readable file on the server. - - * If `downloadButton` is empty, just shows the regular download glyph. - * To just show the filename: `downloadButton = t:{{filenameOnly:V}}` - * Additional attributes might be given like `downloadButton = t:Download|o:check file`. Please check `download`_. - - * The following attributes are hard coded (can't be changed): `s|M:file|d|F` - - * fileSplit, fileDestinationSplit, tableNameSplit: see split-pdf-upload_ - - * Excel Import: QFQ offers functionality to directly import excel data into the database. This functionality can - optionally be combined with saving the file by using the above parameters like `fileDestination`. - The data is imported without formatting. Please note that this means Excel dates will be imported as a number - (e.g. 43214), which is the serial value date in Excel. To convert such a number to a MariaDb date, use: - `DATE_ADD('1899-12-30', INTERVAL serialValue DAY)`. - - * *importToTable* = <[db.]tablename> - **Required**. Providing this parameter activates the import. If the table - doesn't exist, it will be created. - * *importToColumns* = <col1>,<col2>,... - If none provided, the Excel column names A, B, ... are used. Note: These - have to match the table's column names if the table already exists. - * *importRegion* = [tab],[startColumn],[startRow],[endColumn],[endRow]|... - All parts are optional (default: - entire 1st sheet). Tab can either be given as an index (1-based) or a name. start/endColumn can be given either - numerically (1, 2, ...) or by column name (A, B, ...). Note that you can specify several regions to import. - * *importMode* = `append` (default) | `replace` - The data is either appended or replace in the specified table. - * *importType* = `auto` (default) | `xls` | `xlsx` | `ods` | `csv` - Define what kind of data should be expected by the - Spreadsheet Reader. - * *importNamedSheetsOnly* = <comma separated list of sheet names>. Use this option if specific sheets cause problems - during import and should be skipped, by naming only those sheets, who will be read. This will also reduce the memory - usage. - * *importSetReadDataOnly* = 0|1. Read only cell data, not the cell formatting. Warning: cell types other than numerical - will be misinterpreted. - * *importListSheetNames* = 0|1. For debug use only. Will open a dialog and report all found worksheet names. +* *downloadButton* = `t:<string>` - If given, shows a button to download the previous uploaded file - instead of the string given in + `fe.value`. The button is only shown if `fe.value` points to a readable file on the server. + + * If `downloadButton` is empty, just shows the regular download glyph. + * To just show the filename: `downloadButton = t:{{filenameOnly:V}}` + * Additional attributes might be given like `downloadButton = t:Download|o:check file`. Please check `download`_. + + * The following attributes are hard coded (can't be changed): `s|M:file|d|F` + +* fileSplit, fileDestinationSplit, tableNameSplit: see split-pdf-upload_ + +* Excel Import: QFQ offers functionality to directly import excel data into the database. This functionality can + optionally be combined with saving the file by using the above parameters like `fileDestination`. + The data is imported without formatting. Please note that this means Excel dates will be imported as a number + (e.g. 43214), which is the serial value date in Excel. To convert such a number to a MariaDb date, use: + `DATE_ADD('1899-12-30', INTERVAL serialValue DAY)`. + + * *importToTable* = <[db.]tablename> - **Required**. Providing this parameter activates the import. If the table + doesn't exist, it will be created. + * *importToColumns* = <col1>,<col2>,... - If none provided, the Excel column names A, B, ... are used. Note: These + have to match the table's column names if the table already exists. + * *importRegion* = [tab],[startColumn],[startRow],[endColumn],[endRow]|... - All parts are optional (default: + entire 1st sheet). Tab can either be given as an index (1-based) or a name. start/endColumn can be given either + numerically (1, 2, ...) or by column name (A, B, ...). Note that you can specify several regions to import. + * *importMode* = `append` (default) | `replace` - The data is either appended or replace in the specified table. + * *importType* = `auto` (default) | `xls` | `xlsx` | `ods` | `csv` - Define what kind of data should be expected by the + Spreadsheet Reader. + * *importNamedSheetsOnly* = <comma separated list of sheet names>. Use this option if specific sheets cause problems + during import and should be skipped, by naming only those sheets, who will be read. This will also reduce the memory + usage. + * *importSetReadDataOnly* = 0|1. Read only cell data, not the cell formatting. Warning: cell types other than numerical + will be misinterpreted. + * *importListSheetNames* = 0|1. For debug use only. Will open a dialog and report all found worksheet names. Immediately after the upload finished (before the user press save), the file will be checked on the server for it's @@ -4326,22 +4341,22 @@ Currently, QFQ can only split PDF files. If the source file is not of type PDF, activating ``fileSplit`` has no impact: no split and NO complain about invalid file type. - * *FormElement.parameter*: +* *FormElement.parameter*: - * *fileSplit* = `<type>` - Activate the splitting process. Possible values: `svg` or `jpeg`. No default. - * *fileSplitOptions* = `<command line options>`. + * *fileSplit* = `<type>` - Activate the splitting process. Possible values: `svg` or `jpeg`. No default. + * *fileSplitOptions* = `<command line options>`. - * [svg] - no default - * [jpeg] - default: `-density 150 -quality 90` + * [svg] - no default + * [jpeg] - default: `-density 150 -quality 90` - * *fileDestinationSplit* = `<pathFileName (pattern)>` - Target directory and filename pattern for the created & + * *fileDestinationSplit* = `<pathFileName (pattern)>` - Target directory and filename pattern for the created & split'ed files. Default <fileDestination>.split/split.<nr>.<fileSplit>. If explicit given, respect that SVG needs a printf style for <nr>, whereas JPEG is numbered automatically. E.g. :: [svg] fileDestinationSplit = fileadmin/protected/{{id:R}}.{{filenameBase:V}}.%02d.svg [jpeg] fileDestinationSplit = fileadmin/protected/{{id:R}}.{{filenameBase:V}}.jpg - * *tableNameSplit* = `<tablename>` - Default: name of table of current form. This name will be saved in table `Split` + * *tableNameSplit* = `<tablename>` - Default: name of table of current form. This name will be saved in table `Split` The splitting happens immediately after the user pressed `save`. @@ -4376,17 +4391,17 @@ These type of 'action' *FormElements* will be used to implement data validation Types: - * beforeLoad (e.g. good to check access permission) - * afterLoad - * beforeSave (e.g. to prohibit creating of duplicate records) - * afterSave (e.g. to to create & update additional records) - * beforeInsert - * afterInsert - * beforeUpdate - * afterUpdate - * beforeDelete (e.g. to delete slave records) - * afterDelete - * paste (configure copy/paste forms) +* beforeLoad (e.g. good to check access permission) +* afterLoad +* beforeSave (e.g. to prohibit creating of duplicate records) +* afterSave (e.g. to to create & update additional records) +* beforeInsert +* afterInsert +* beforeUpdate +* afterUpdate +* beforeDelete (e.g. to delete slave records) +* afterDelete +* paste (configure copy/paste forms) .. _sqlValidate: @@ -4395,49 +4410,50 @@ Parameter: sqlValidate Perform checks by firing an SQL query and expecting a predefined number of selected records. - * OK: the `expectRecords` number of records has been selected. Continue processing the next *FormElement*. - * Fail: the `expectRecords` number of records has not been selected (less or more): Display the error message - `messageFail` and abort the whole (!) current form load or save. +* OK: the `expectRecords` number of records has been selected. Continue processing the next *FormElement*. +* Fail: the `expectRecords` number of records has not been selected (less or more): Display the error message + `messageFail` and abort the whole (!) current form load or save. - *FormElement.parameter*: +*FormElement.parameter*: - * *requiredList* = `<fe.name[s]>` - List of `native`-*FormElement* names: only if all of those elements are filled - (!=0 and !=''), the *current* `action`-*FormElement* will be processed. This will enable or disable the check, - based on the user input! If no `native`-*FormElement* names are given, the specified check will always be performed. +* *requiredList* = `<fe.name[s]>` - List of `native`-*FormElement* names: only if all of those elements are filled + (!=0 and !=''), the *current* `action`-*FormElement* will be processed. This will enable or disable the check, + based on the user input! If no `native`-*FormElement* names are given, the specified check will always be performed. - * *sqlValidate* = `{{<query>}}` - validation query. E.g.: `sqlValidate={{SELECT id FROM Person AS p WHERE p.name LIKE {{name:F:all}} AND p.firstname LIKE {{firstname:F:all}} }}` +* *sqlValidate* = `{{<query>}}` - validation query. E.g.: `sqlValidate={{SELECT id FROM Person AS p WHERE p.name LIKE {{name:F:all}} AND p.firstname LIKE {{firstname:F:all}} }}` - * *expectRecords* = `<value>`- number of expected records. +* *expectRecords* = `<value>`- number of expected records. - * *expectRecords* = `0` or *expectRecords* = `0,1` or *expectRecords* = `{{SELECT COUNT(id) FROM Person}}` - * Separate multiple valid record numbers by ','. If at least one of those matches, the check will pass successfully. + * *expectRecords* = `0` or *expectRecords* = `0,1` or *expectRecords* = `{{SELECT COUNT(id) FROM Person}}` + * Separate multiple valid record numbers by ','. If at least one of those matches, the check will pass successfully. - * *messageFail* = `<string>` - Message to show. E.g.: *messageFail* = `There is already a person called {{firstname:F:all}} {{name:F:all}}` +* *messageFail* = `<string>` - Message to show. E.g.: *messageFail* = `There is already a person called {{firstname:F:all}} {{name:F:all}}` .. _slave-id: Parameter: slaveId """""""""""""""""" -*FormElement.parameter*: +FormElement.parameter +;;;;;;;;;;;;;;;;;;;;; - * *slaveId* = `<id>`: +* *slaveId* = `<id>`: - * Auto fill: name the action `action`-*FormElement* equal to an existing column (table from the current form definition). - *slaveId* will be automatically filled with the value of the named column. + * Auto fill: name the action `action`-*FormElement* equal to an existing column (table from the current form definition). + *slaveId* will be automatically filled with the value of the named column. - * If there is no such named column name, set *slaveId* = `0`. + * If there is no such named column name, set *slaveId* = `0`. - * Explicit definition: *slaveId* = `123` or *slaveId* = `{{SELECT id ...}}` + * Explicit definition: *slaveId* = `123` or *slaveId* = `{{SELECT id ...}}` Note: - * `{{slaveId:V}}` can be used in any query of the current *FormElement*. - * If the `action`-*FormElement* name exist as a column in the master record: Update that column *automatically* with the - recent slaveId - * After an INSERT the `last_insert_id()` becomes the *{{slaveId:V}}*. - * `fillStoreVar` is fired first, than `slaveId`. - * If `slaveId` is known in `fillStoreVar`, set: `slaveId={{someId:V}}`. +* `{{slaveId:V}}` can be used in any query of the current *FormElement*. +* If the `action`-*FormElement* name exist as a column in the master record: Update that column *automatically* with the + recent slaveId +* After an INSERT the `last_insert_id()` becomes the *{{slaveId:V}}*. +* `fillStoreVar` is fired first, than `slaveId`. +* If `slaveId` is known in `fillStoreVar`, set: `slaveId={{someId:V}}`. @@ -4447,27 +4463,28 @@ Parameter: sqlBefore / sqlInsert / sqlUpdate / sqlDelete / sqlAfter * Save values of a form to different record(s), optionally on different table(s). * Typically useful on 'afterSave' - be careful when using it earlier, e.g. beforeLoad. -*FormElement.parameter*: +FormElement.parameter +;;;;;;;;;;;;;;;;;;;;; - * *requiredList* = `<fe.name[s]>` - List of `native`-*FormElement*: only if all of those elements are filled, the current - `action`-*FormElement* will be processed. +* *requiredList* = `<fe.name[s]>` - List of `native`-*FormElement*: only if all of those elements are filled, the current + `action`-*FormElement* will be processed. - * *sqlBefore* = `{{<query>}}` - always fired (before any *sqlInsert*, *sqlUpdate*, ..) - * *sqlInsert* = `{{<query>}}` - fired if *slaveId* == `0` or *slaveId* == `''`. - * *sqlUpdate* = `{{<query>}}` - fired if *slaveId* > `0`. - * *sqlDelete* = `{{<query>}}` - fired if *slaveId* > `0`, after *sqlInsert* or *sqlUpdate*. Be careful not to delete filled records! - Always add a check, if values given, not to delete the record! *sqlHonorFormElements* helps to skip such checks. - * *sqlAfter* = `{{<query>}}` - always fired (after *sqlInsert*, *sqlUpdate* or *sqlDelete*). - * *sqlHonorFormElements* = `<fe.name[s]>` list of *FormElement* names (this parameter is optional). +* *sqlBefore* = `{{<query>}}` - always fired (before any *sqlInsert*, *sqlUpdate*, ..) +* *sqlInsert* = `{{<query>}}` - fired if *slaveId* == `0` or *slaveId* == `''`. +* *sqlUpdate* = `{{<query>}}` - fired if *slaveId* > `0`. +* *sqlDelete* = `{{<query>}}` - fired if *slaveId* > `0`, after *sqlInsert* or *sqlUpdate*. Be careful not to delete filled records! + Always add a check, if values given, not to delete the record! *sqlHonorFormElements* helps to skip such checks. +* *sqlAfter* = `{{<query>}}` - always fired (after *sqlInsert*, *sqlUpdate* or *sqlDelete*). +* *sqlHonorFormElements* = `<fe.name[s]>` list of *FormElement* names (this parameter is optional). - * If one of the named *FormElements* is not empty: + * If one of the named *FormElements* is not empty: - * fire *sqlInsert* if *slaveId* == `0`, - * fire *sqlUpdate* if *slaveId* > `0` + * fire *sqlInsert* if *slaveId* == `0`, + * fire *sqlUpdate* if *slaveId* > `0` - * If all of the named *FormElements* are empty: + * If all of the named *FormElements* are empty: - * fire *sqlDelete* if *slaveId* > `0` + * fire *sqlDelete* if *slaveId* > `0` Example @@ -4475,26 +4492,26 @@ Example Situation 1: master.xId=slave.id (1:1) - * Name the action element 'xId': than {{slaveId}} will be automatically set to the value of 'master.xId' +* Name the action element 'xId': than {{slaveId}} will be automatically set to the value of 'master.xId' - * {{slaveId}} == 0 ? 'sqlInsert' will be fired. - * {{slaveId}} != 0 ? 'sqlUpdate' will be fired. + * {{slaveId}} == 0 ? 'sqlInsert' will be fired. + * {{slaveId}} != 0 ? 'sqlUpdate' will be fired. - * In case of firing 'sqlInsert', the 'slave.id' of the new created record are copied to master.xId (the database will - be updated automatically). +* In case of firing 'sqlInsert', the 'slave.id' of the new created record are copied to master.xId (the database will + be updated automatically). - * If the automatic update of the master record is not suitable, the action element should have no name or a name - which does not exist as a column of the master record. Define `slaveId={{SELECT id ...}}` +* If the automatic update of the master record is not suitable, the action element should have no name or a name + which does not exist as a column of the master record. Define `slaveId={{SELECT id ...}}` - * Two *FormElements* `myStreet` and `myCity`: +* Two *FormElements* `myStreet` and `myCity`: - * Without *sqlHonorFormElements*. Parameter: :: + * Without *sqlHonorFormElements*. Parameter: :: sqlInsert = {{INSERT INTO address (`street`, `city`) VALUES ('{{myStreet:FE:alnumx:s}}', '{{myCity:FE:alnumx:s}}') }} sqlUpdate = {{UPDATE address SET `street` = '{{myStreet:FE:alnumx:s}}', `city` = '{{myCity:FE:alnumx:s}}' WHERE id={{slaveId}} LIMIT 1 }} sqlDelete = {{DELETE FROM Address WHERE id={{slaveId}} AND '{{myStreet:FE:alnumx:s}}'='' AND '{{myCity:FE:alnumx:s}}'='' LIMIT 1 }} - * With *sqlHonorFormElements*. Parameter: :: + * With *sqlHonorFormElements*. Parameter: :: sqlHonorFormElements = myStreet, myCity # Non Templategroup sqlInsert = {{INSERT INTO address (`street`, `city`) VALUES ('{{myStreet:FE:alnumx:s}}', '{{myCity:FE:alnumx:s}}') }} @@ -4505,22 +4522,22 @@ Situation 1: master.xId=slave.id (1:1) Situation 2: master.id=slave.xId (1:n) - * Name the action element *different* to any column name of the master record (or no name). - * Determine the slaveId: `slaveId={{SELECT id FROM Slave WHERE slave.xxx={{...}} LIMIT 1}}` +* Name the action element *different* to any column name of the master record (or no name). +* Determine the slaveId: `slaveId={{SELECT id FROM Slave WHERE slave.xxx={{...}} LIMIT 1}}` - * {{slaveId}} == 0 ? 'sqlInsert' will be fired. - * {{slaveId}} != 0 ? 'sqlUpdate' will be fired. + * {{slaveId}} == 0 ? 'sqlInsert' will be fired. + * {{slaveId}} != 0 ? 'sqlUpdate' will be fired. - * Two *FormElements* `myStreet` and `myCity`. The `person` is the master record, `address` is the slave: +* Two *FormElements* `myStreet` and `myCity`. The `person` is the master record, `address` is the slave: - * Without *sqlHonorFormElements*. Parameter: :: + * Without *sqlHonorFormElements*. Parameter: :: slaveId = {{SELECT id FROM Address WHERE personId={{id}} ORDER BY id LIMIT 1 }} sqlInsert = {{INSERT INTO address (`personId`, `street`, `city`) VALUES ({{id}}, '{{myStreet:FE:alnumx:s}}', '{{myCity:FE:alnumx:s}}') }} sqlUpdate = {{UPDATE address SET `street` = '{{myStreet:FE:alnumx:s}}', `city` = '{{myCity:FE:alnumx:s}}' WHERE id={{slaveId}} LIMIT 1 }} sqlDelete = {{DELETE FROM Address WHERE id={{slaveId}} AND '{{myStreet:FE:alnumx:s}}'='' AND '{{myCity:FE:alnumx:s}}'='' LIMIT 1 }} - * With *sqlHonorFormElements*. Parameter: :: + * With *sqlHonorFormElements*. Parameter: :: slaveId = {{SELECT id FROM Address WHERE personId={{id}} ORDER BY id LIMIT 1 }} sqlHonorFormElements = myStreet, myCity # Non Templategroup @@ -4535,9 +4552,9 @@ Type: sendmail * Send mail(s) will be processed after: - * saving the record , - * processing all uploads, - * together with `after...` action `FormElements` in the given order. + * saving the record , + * processing all uploads, + * together with `after...` action `FormElements` in the given order. * *FormElement.value* = `<string>` - Body of the email. See also: `html-formatting`_ @@ -4920,60 +4937,60 @@ of type `paste` are fired (incl. the creating of slave records). E.g. if there is a basket with different items and you want to duplicate the whole basket including new items, create a form with the following parameter - * Form +* Form - * Name: `copyBasket` - * Table: `Clipboard` - * Show Button: only `close` and `save` + * Name: `copyBasket` + * Table: `Clipboard` + * Show Button: only `close` and `save` - * FormElement 1: Record id of the source record. +* FormElement 1: Record id of the source record. - * Name: `idSrc` - * Lable: `Source Form` - * Class: `native` - * Type: `select` - * sql1: `{{! SELECT id, title FROM Basket }}` + * Name: `idSrc` + * Lable: `Source Form` + * Class: `native` + * Type: `select` + * sql1: `{{! SELECT id, title FROM Basket }}` - * FormElement 2: New name of the copied record. +* FormElement 2: New name of the copied record. - * Name: `myNewName` - * Class: `native` - * Type: `text` + * Name: `myNewName` + * Class: `native` + * Type: `text` - * FormElement 3: a) Check that there is no name conflict. b)Purge any old clipboard content of the current user. +* FormElement 3: a) Check that there is no name conflict. b)Purge any old clipboard content of the current user. - * Name: `clearClipboard` - * Class: `action` - * Type: `beforeSave` - * Parameter: + * Name: `clearClipboard` + * Class: `action` + * Type: `beforeSave` + * Parameter: - * `sqlValidate={{SELECT f.id FROM Form AS f WHERE f.name LIKE '{{myName:FE:alnumx}}' LIMIT 1}}` - * `expectRecords = 0` - * `messageFail = There is already a form with this name` - * `sqlAfter={{DELETE FROM Clipboard WHERE cookie='{{cookieQfq:C0:alnumx}}' }}` + * `sqlValidate={{SELECT f.id FROM Form AS f WHERE f.name LIKE '{{myName:FE:alnumx}}' LIMIT 1}}` + * `expectRecords = 0` + * `messageFail = There is already a form with this name` + * `sqlAfter={{DELETE FROM Clipboard WHERE cookie='{{cookieQfq:C0:alnumx}}' }}` - * FormElement 4: Update the clipboard source reference, with current {{cookieQfq:C}} identifier. +* FormElement 4: Update the clipboard source reference, with current {{cookieQfq:C}} identifier. - * Name: `updateClipboardRecord` - * Class: `action` - * Type: `afterSave` - * Parameter: `sqlAfter={{UPDATE Clipboard SET cookie='{{cookieQfq:C0:alnumx}}', formIdPaste={{formId:S0}} /* PasteForm */ WHERE id={{id:R}} LIMIT 1 }}` + * Name: `updateClipboardRecord` + * Class: `action` + * Type: `afterSave` + * Parameter: `sqlAfter={{UPDATE Clipboard SET cookie='{{cookieQfq:C0:alnumx}}', formIdPaste={{formId:S0}} /* PasteForm */ WHERE id={{id:R}} LIMIT 1 }}` - * FormElement 5: Copy basket identifier. +* FormElement 5: Copy basket identifier. - * Name: `basketId` - * Class: `action` - * Type: `paste` - * sql1: `{{!SELECT {{id:P}} AS id, '{{myNewName:FE:allbut}}' AS name}}` - * Parameter: `recordDestinationTable=Basket` + * Name: `basketId` + * Class: `action` + * Type: `paste` + * sql1: `{{!SELECT {{id:P}} AS id, '{{myNewName:FE:allbut}}' AS name}}` + * Parameter: `recordDestinationTable=Basket` - * FormElement 6: Copy items of basket. +* FormElement 6: Copy items of basket. - * Name: `itemId` - * Class: `action` - * Type: `paste` - * sql1: `{{!SELECT i.id AS id, {{basketId:P}} AS basketId FROM Item AS i WHERE i.basketId={{id:P}} }}` - * Parameter: `recordDestinationTable=Item` + * Name: `itemId` + * Class: `action` + * Type: `paste` + * sql1: `{{!SELECT i.id AS id, {{basketId:P}} AS basketId FROM Item AS i WHERE i.basketId={{id:P}} }}` + * Parameter: `recordDestinationTable=Item` Table self referencing records @@ -4985,7 +5002,7 @@ corresponding `FormElements` all internal references needs to be updated as well On each FormElement.type=`paste` record, the column to be updated is defined via: - * parameter: translateIdColumn = <column name> +* parameter: translateIdColumn = <column name> For the 'copyForm' this would be 'feIdContainer'. @@ -5116,8 +5133,8 @@ Best for debugging is to specify in the tt-content record:: Note: Debug information is only display if it's enabled in configuration_ by - * *showDebugInfo: yes* or - * *showDebugInfo: auto* and logged in in the same Browser as a Typo3 backend user. +* *showDebugInfo: yes* or +* *showDebugInfo: auto* and logged in in the same Browser as a Typo3 backend user. More detailed error messages ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -5282,7 +5299,7 @@ Icons Template Group This example will display graphics instead of text 'add' and 'remove'. Also there is a distance between the templateGroups. - * FormElement.parameter:: +* FormElement.parameter:: tgClass = qfq-child-margin-top tgAddClass = btn alert-success @@ -5396,27 +5413,27 @@ Upload Form Advanced 1 Table: Person - +---------------------+--------------+ - | Name | Type | - +=====================+==============+ - | id | int | - +---------------------+--------------+ - | name | varchar(255) | - +---------------------+--------------+ ++---------------------+--------------+ +| Name | Type | ++=====================+==============+ +| id | int | ++---------------------+--------------+ +| name | varchar(255) | ++---------------------+--------------+ Table: Note - +---------------------+--------------+ - | Name | Type | - +=====================+==============+ - | id | int | - +---------------------+--------------+ - | pId | int | - +---------------------+--------------+ - | type | varchar(255) | - +---------------------+--------------+ - | pathFileName | varchar(255) | - +---------------------+--------------+ ++---------------------+--------------+ +| Name | Type | ++=====================+==============+ +| id | int | ++---------------------+--------------+ +| pId | int | ++---------------------+--------------+ +| type | varchar(255) | ++---------------------+--------------+ +| pathFileName | varchar(255) | ++---------------------+--------------+ * Form: @@ -5461,27 +5478,27 @@ Upload Form Advanced 2 Table: Person - +---------------------+--------------+ - | Name | Type | - +=====================+==============+ - | id | int | - +---------------------+--------------+ - | name | varchar(255) | - +---------------------+--------------+ - | noteIdPicture | int | - +---------------------+--------------+ - | noteIdAvatar | int | - +---------------------+--------------+ ++---------------------+--------------+ +| Name | Type | ++=====================+==============+ +| id | int | ++---------------------+--------------+ +| name | varchar(255) | ++---------------------+--------------+ +| noteIdPicture | int | ++---------------------+--------------+ +| noteIdAvatar | int | ++---------------------+--------------+ Table: Note - +---------------------+--------------+ - | Name | Type | - +=====================+==============+ - | id | int | - +---------------------+--------------+ - | pathFileName | varchar(255) | - +---------------------+--------------+ ++---------------------+--------------+ +| Name | Type | ++=====================+==============+ +| id | int | ++---------------------+--------------+ +| pathFileName | varchar(255) | ++---------------------+--------------+ * Form: @@ -5528,13 +5545,13 @@ Typeahead: SQL Table: Person - +---------------------+--------------+ - | Name | Type | - +=====================+==============+ - | id | int | - +---------------------+--------------+ - | name | varchar(255) | - +---------------------+--------------+ ++---------------------+--------------+ +| Name | Type | ++=====================+==============+ +| id | int | ++---------------------+--------------+ +| name | varchar(255) | ++---------------------+--------------+ * Form: @@ -5554,17 +5571,17 @@ Typeahead: LDAP with additional values Table: Person - +---------------------+--------------+ - | Name | Type | - +=====================+==============+ - | id | int | - +---------------------+--------------+ - | name | varchar(255) | - +---------------------+--------------+ - | firstname | varchar(255) | - +---------------------+--------------+ - | email | varchar(255) | - +---------------------+--------------+ ++---------------------+--------------+ +| Name | Type | ++=====================+==============+ +| id | int | ++---------------------+--------------+ +| name | varchar(255) | ++---------------------+--------------+ +| firstname | varchar(255) | ++---------------------+--------------+ +| email | varchar(255) | ++---------------------+--------------+ * Form: @@ -5953,9 +5970,9 @@ To get better human readable SQL queries, it's possible to split a line across s with keywords are on their own (`QFQ Keywords (Bodytext)`_ start a new line). If a line is not a 'keyword' line, it will be appended to the last keyword line. 'Keyword' lines are detected on: - * <level>.<keyword> = - * { - * <level>[.<sub level] { +* <level>.<keyword> = +* { +* <level>[.<sub level] { Example:: @@ -6094,8 +6111,8 @@ Access column values Columns of the upper / outer level result can be accessed via variables in two ways - * STORE_RECORD: `{{pId:R}}` - * Level Key: `{{10.pId}}` +* STORE_RECORD: `{{pId:R}}` +* Level Key: `{{10.pId}}` The STORE_RECORD will always be merged with previous content. The Level Keys are unique. @@ -6946,25 +6963,25 @@ Column: _exec Run any command on the web server. - * The command is run via web server, so with the uid of the web server. - * The current working directory is the current web instance (e.g. ``/var/www/html``) . - * All text send to 'stdout' will be returned. - * Text send to 'stderr' is not returned at all. - * If 'stderr' should be shown, redirect the output:: +* The command is run via web server, so with the uid of the web server. +* The current working directory is the current web instance (e.g. ``/var/www/html``) . +* All text send to 'stdout' will be returned. +* Text send to 'stderr' is not returned at all. +* If 'stderr' should be shown, redirect the output:: SELECT 'touch /root 2>&1' AS _exec - * If 'stdout' / 'stderr' should not be displayed, redirect the output:: +* If 'stdout' / 'stderr' should not be displayed, redirect the output:: SELECT 'touch /tmp >/dev/null' AS _exec SELECT 'touch /root 2>&1 >/dev/null' AS _exec - * Multiple commands can be concatenated by `;`:: +* Multiple commands can be concatenated by `;`:: SELECT 'date; date' AS _exec - * If the return code is not 0, the string '[<rc>] ', will be prepended. - * If it is not wished to see the return code, just add ``true`` to fake rc of 0 (only the last rc will be reported):: +* If the return code is not 0, the string '[<rc>] ', will be prepended. +* If it is not wished to see the return code, just add ``true`` to fake rc of 0 (only the last rc will be reported):: SELECT 'touch /root; true' AS _exec @@ -7280,6 +7297,22 @@ Output:: 31.12.2019 23:55 / - / - +.. _qlugify: + +QSLUGIFY: clean a string +^^^^^^^^^^^^^^^^^^^^^^^^ + +Convert a string to only use alphanumerical characters and '-'. Characters with accent will be replaced without the accent. +Non alphanumerical characters are stripped off. Spaces are replaced by '-'. All characters are lowercase. + +Example:: + + 10.sql = SELECT QSLUGIFY('abcd ABCD ae.ä.oe.ö.ue.ü z[]{}()<>.,?Z') + +Output:: + + abcd-abcd-ae-a-oe-o-ue-u-z-z + .. _strip_tags: strip_tags: strip html tags @@ -7345,16 +7378,16 @@ Parameter and (element) sources * *mode* = <file | pdf | zip | excel> - * If `M:file`, the mime type is derived dynamically from the specified file. In this mode, only one element source - is allowed per download link (no concatenation). + * If `M:file`, the mime type is derived dynamically from the specified file. In this mode, only one element source + is allowed per download link (no concatenation). - * In case of multiple element sources, only `pdf`, `zip` and `excel` (template mode) is supported. - * If `M:zip` is used together with `p:...`, `U:...` or `u:..`, those HTML pages will be converted to PDF. Those files - get generic filenames inside the archive. - * If not specified, the **default** 'Mode' depends on the number of specified element sources (=file or web page): + * In case of multiple element sources, only `pdf`, `zip` and `excel` (template mode) is supported. + * If `M:zip` is used together with `p:...`, `U:...` or `u:..`, those HTML pages will be converted to PDF. Those files + get generic filenames inside the archive. + * If not specified, the **default** 'Mode' depends on the number of specified element sources (=file or web page): - * If only one `file` is specified, the default is `file`. - * If there is a) a page defined or b) multiple elements, the default is `pdf`. + * If only one `file` is specified, the default is `file`. + * If there is a) a page defined or b) multiple elements, the default is `pdf`. * *element sources* - for `M:pdf` or `M:zip`, all of the following element sources may be specified multiple times. Any combination and order of these options are allowed. @@ -7738,10 +7771,10 @@ Format the dropdown menu symbol: Format a menu entry: - * *qfq link*: All options as with a regular QFQ link. - * *header*: If a text starts with '===', it becomes a header in the dropdown menu. Multiple headers are possible. Headers can't be a link. An additional `r:1` is necessary. - * *separator*: If a text is exactly '---', it becomes a separator line between two menu entries. An additional `r:1` is necessary. - * *disabled menu entry*: If a text starts with '---' (like separator), the following text becomes a disable menu entry. An additional `r:1` is necessary. +* *qfq link*: All options as with a regular QFQ link. +* *header*: If a text starts with '===', it becomes a header in the dropdown menu. Multiple headers are possible. Headers can't be a link. An additional `r:1` is necessary. +* *separator*: If a text is exactly '---', it becomes a separator line between two menu entries. An additional `r:1` is necessary. +* *disabled menu entry*: If a text starts with '---' (like separator), the following text becomes a disable menu entry. An additional `r:1` is necessary. Example 2:: @@ -8009,9 +8042,9 @@ The *tablesorter* options: * 'Views' can be saved as: - * public: every user will see the `view` and can modify it. - * private: only the user who created the `view` will see/modify it. - * readonly: manually mark a `view` as readonly (no FE User can change it) by setting column `readonly='true'` in table + * public: every user will see the `view` and can modify it. + * private: only the user who created the `view` will see/modify it. + * readonly: manually mark a `view` as readonly (no FE User can change it) by setting column `readonly='true'` in table `Setting` of the corresponding view (identified by `name`). * Views will be saved in the table 'Setting'. diff --git a/Documentation/Release.rst b/Documentation/Release.rst index 246f1be3144d8075fed3c7e2ee878531463ff433..76d4e71d0102ef0b9d72540874022c11b7b7cc4e 100644 --- a/Documentation/Release.rst +++ b/Documentation/Release.rst @@ -44,31 +44,31 @@ Date: 05.04.2020 Notes ^^^^^ - * New Feature: `typeAheadTag <https://docs.typo3.org/p/IMATHUZH/qfq/master/en-us/Manual.html#type-ahead-tag>` - extend regular input with multiple values via typeAhead. _ - * MySQL StoredProcedure: +* New Feature: `typeAheadTag <https://docs.typo3.org/p/IMATHUZH/qfq/master/en-us/Manual.html#type-ahead-tag>`_ - extend regular input with multiple values via typeAhead. _ +* MySQL StoredProcedure: - * strip_tags() - Simple strip html tags. - * QCC() - Escape colon / coma. Useful for QFQ link arguments like 'text' or 'tooltip'. + * strip_tags() - Simple strip html tags. + * QCC() - Escape colon / coma. Useful for QFQ link arguments like 'text' or 'tooltip'. Features ^^^^^^^^ - * #9686 / Download: sanitize output filename. - * #10358 / Configure path/environment via QFQ config: qpdf, gs, pdfunite. - * #9517, #10145, #10177, #10117 / typeAheadTag. - * #10152 / QCC() - Stored Procedure to escape colon / coma. - * FabricJS: replaced glyphicons with font awesome. - * Rename config.qfq.example.php config-example.qfq.php. +* #9686 / Download: sanitize output filename. +* #10358 / Configure path/environment via QFQ config: qpdf, gs, pdfunite. +* #9517, #10145, #10177, #10117 / typeAheadTag. +* #10152 / QCC() - Stored Procedure to escape colon / coma. +* FabricJS: replaced glyphicons with font awesome. +* Rename config.qfq.example.php config-example.qfq.php. Bug Fixes ^^^^^^^^^ - * #6798 / Close didn't worked with r=0. - * #10199 / Form.forwardMode: missing mode 'Close' / 'Auto'. - * #10173 / Dynamic Update: Readonly element can't be activated via dynamic update. - * Fix broken default value for Form.forwardMode. - * Fix problem with reporting broken TG-FormElements. - * Add error message if primary table does not exist. +* #6798 / Close didn't worked with r=0. +* #10199 / Form.forwardMode: missing mode 'Close' / 'Auto'. +* #10173 / Dynamic Update: Readonly element can't be activated via dynamic update. +* Fix broken default value for Form.forwardMode. +* Fix problem with reporting broken TG-FormElements. +* Add error message if primary table does not exist. Version 20.2.0 -------------- @@ -198,7 +198,7 @@ Bug Fixes * #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. +* #9733 / Identify 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. @@ -220,12 +220,12 @@ Features * #9655 / Checkboxes and radios now defined with a min-width in horizontal plain mode. * #9617 / formModeGlobal: - * Two modes of 'formModeGlobal' available: 'requiredOff' and 'requiredOffButMark'. - * 'requiredOffButMark': + * Two modes of 'formModeGlobal' available: 'requiredOff' and 'requiredOffButMark'. + * 'requiredOffButMark': - * Renamed temporary 'skipRequiredCheck' to 'requiredOffButMark'. - * Keep required marks after save. - * Stop hiding helpblocks per default, set with class qfq-only-active-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. @@ -240,11 +240,11 @@ Bug Fixes * #3995 / Implemented partly: CheckBox and Radio can now be locked. * #8091 / Checkbox required: - * If radio or checkbox is required and empty on submit, form save brings the element to front. - * Fix radio plain vertical. - * Fix label2 not to be bold. - * Checkbox Plain Vertical: forces 'font-weight: 400;'. - * Updated colors for checkboxes/radios. + * If radio or checkbox is required and empty on submit, form save brings the element to front. + * Fix radio plain vertical. + * Fix label2 not to be bold. + * Checkbox Plain Vertical: forces 'font-weight: 400;'. + * Updated colors for checkboxes/radios. * #9638 / Textarea Sizing: Now also listens for paste. * #7891 / Added missing 'type="button"' to button element. @@ -281,12 +281,12 @@ Bug Fixes * #7639 / subrecord drag n drop: - * `orderInterval` has not been respected. - * Update Manual.rst. - * Fake STORE_SIP so it can be used during processing sql1. - * The record, currently loaded into form, is available via STORE_RECORD. - * Check for id/_id and ord/_ord. - * Throw meaningful exception if missing 'id' or 'ord'. + * `orderInterval` has not been respected. + * Update Manual.rst. + * Fake STORE_SIP so it can be used during processing sql1. + * The record, currently loaded into form, is available via STORE_RECORD. + * Check for id/_id and ord/_ord. + * Throw meaningful exception if missing 'id' or 'ord'. * Fixes bug that no mime_type_content is called if there is on file. * Fix broken regex101 url. @@ -299,7 +299,7 @@ Date: 11.11.2019 Bug Fixes ^^^^^^^^^ - * #9532 / 'Advanced Upload' broken - slaveId/sqlUpdate/... have been processed two times, after multiform code changes. +* #9532 / 'Advanced Upload' broken - slaveId/sqlUpdate/... have been processed two times, after multiform code changes. Version 19.11.0 --------------- @@ -455,11 +455,11 @@ Features * Manual.rst: - * Update tablesorter `class="sorter-false"`. - * Add note to include font-awesome. - * QFQ_LOG documentation. - * Enhance wkhtml debug info. - * Add link to https://mariadb.com/kb/en/library/stored-routine-privileges/ + * Update tablesorter `class="sorter-false"`. + * Add note to include font-awesome. + * QFQ_LOG documentation. + * Enhance wkhtml debug info. + * Add link to https://mariadb.com/kb/en/library/stored-routine-privileges/ * Increase Length of column Form.forwardPage limit from 255 to 511. * Index.rst: Add Rafi, Elias, Nicola as further contributors. @@ -497,9 +497,9 @@ Features * TWIG: - * Add Twig Extension to parse QFQ Links - * Pass assoc-array of query result as context - * allow to pass template as string + * Add Twig Extension to parse QFQ Links + * Pass assoc-array of query result as context + * allow to pass template as string * Database.php: extend function sql error message * #8179 / extraButtonLock and extraButtonPassword might be specified without a value or with 0 or with 1. @@ -742,8 +742,8 @@ Date: 15.03.2019 Bug Fixes ^^^^^^^^^ - * 8058 / Form > fillStoreVar: broken for TemplateGroup - Form.fillStoreVar not available during fillStoreForm(). - * 8048 / A retype FE should not be checked for 'required' during save. +* 8058 / Form > fillStoreVar: broken for TemplateGroup - Form.fillStoreVar not available during fillStoreForm(). +* 8048 / A retype FE should not be checked for 'required' during save. Version 19.3.0 @@ -1238,13 +1238,13 @@ Notes 'jquery.tablesorter.pager.min.js', 'widget-columnSelector.min.js' in your Typo3 template record. See https://docs.typo3.org/p/IMATHUZH/qfq/master/en-us/Manual.html#setup-css-js - * *Existing* QFQ installations: update your CSS/JS includes! The new tablesorter jquery plugin might break (JS errors - seen on the console) your installation, if it isn't included! + * *Existing* QFQ installations: update your CSS/JS includes! The new tablesorter jquery plugin might break (JS errors + seen on the console) your installation, if it isn't included! - * If you use the extension 'UZH Corporate Design Template': + * If you use the extension 'UZH Corporate Design Template': - * Update to the latest version 18.9.0. - * Add constants in the Typo3 template record 'ext: main': :: + * Update to the latest version 18.9.0. + * Add constants in the Typo3 template record 'ext: main': :: cd.extra.css.file5 = typo3conf/ext/qfq/Resources/Public/Css/tablesorter-bootstrap.css @@ -1451,8 +1451,8 @@ Notes * NEW: Drag and drop to sort elements! Check the Manual. * `URL forwardMode` - * `client` renamed to `auto`. - * `close` added. + * `client` renamed to `auto`. + * `close` added. Features ^^^^^^^^ @@ -2582,47 +2582,47 @@ Version 0.15 Changes ^^^^^^^ - * Play formEditor.sql. +* Play formEditor.sql. - * Form 'FormElement' failed to display the formtitle of the current form in case of a new FE. - * Updated subrecord in 'Form' for 'FormElements' - columns 'size' and 'sql1' removed and 'dyn' inserted. Play formEditor.sql. +* Form 'FormElement' failed to display the formtitle of the current form in case of a new FE. +* Updated subrecord in 'Form' for 'FormElements' - columns 'size' and 'sql1' removed and 'dyn' inserted. Play formEditor.sql. - * #3431, Parameter keyword 'typeAheadLdapKeyPrintf' changed to 'typeAheadLdapIdPrintf'.:: +* #3431, Parameter keyword 'typeAheadLdapKeyPrintf' changed to 'typeAheadLdapIdPrintf'.:: - UPDATE FormElement SET parameter = REPLACE(parameter, 'typeAheadLdapKeyPrintf', 'typeAheadLdapIdPrintf') + UPDATE FormElement SET parameter = REPLACE(parameter, 'typeAheadLdapKeyPrintf', 'typeAheadLdapIdPrintf') - * Size 'placeholder' increased:: +* Size 'placeholder' increased:: - ALTER TABLE `FormElement` CHANGE `placeholder` `placeholder` VARCHAR( 2048 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ''; + ALTER TABLE `FormElement` CHANGE `placeholder` `placeholder` VARCHAR( 2048 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ''; Features ^^^^^^^^ - * Introduce new config.qfq.ini setting 'EDIT_FORM_PAGE' - by default set to 'form' - the wrench symbol on every Form - will direct to that page. Fix #3420 / Quicklink 'editform' on form: directs to the current T3 page which might be insufficient. - * Form 'subrecord' columns: the default width limit of 20 chars are disabled if 'nostrip' is specifed. - * #3431 / typeAheadSql: columnname 'key' is a reserverd SQL statement - replace by 'id'. Additional the parametername - 'typeAheadLdapKeyPrintf' renamed to 'typeAheadLdapIdPrintf'. By using 'id' instead of 'key' the quoting of the columnname - is not necessary anoymore. +* Introduce new config.qfq.ini setting 'EDIT_FORM_PAGE' - by default set to 'form' - the wrench symbol on every Form + will direct to that page. Fix #3420 / Quicklink 'editform' on form: directs to the current T3 page which might be insufficient. +* Form 'subrecord' columns: the default width limit of 20 chars are disabled if 'nostrip' is specifed. +* #3431 / typeAheadSql: columnname 'key' is a reserverd SQL statement - replace by 'id'. Additional the parametername + 'typeAheadLdapKeyPrintf' renamed to 'typeAheadLdapIdPrintf'. By using 'id' instead of 'key' the quoting of the columnname + is not necessary anoymore. Bug Fixes ^^^^^^^^^ - * #3419 / typeAheadSql: Array with only one column or non standard columnnames are not handeld properbly. - Detection of missing LIMIT implemented. - * #3425 / Form.parameter, FormElement.parameter: comment handling, trailing & leading spaces - Manual.rst: commented handling of 'comment character' and 'escaping of leading/trailing spaces' - Support.php: new funtion handleEscapeSpaceComment(). - * Evaluate.php: parse all F|FE.parameter via handleEscapeSpaceComment(). A leading '#' or ' ' might be escaped by '\'. - * Saving 'extra' FE in STORE_SIP has been done with inappropiate FE_NAME. Correct is the pure FE_NAME, without any - extension like recordId. Unessary and broken decoding removed. - * #3426 / Dynamic Update: Inputs loose the new content and shows the old value. - * Through fix #2064 the FE.checkType has not been used anymore. This is fixed now. - * #3433 / templateGroup on primary Record: Values of removed copies are not deleted. The new implementation creates empty - fake instances of all copies of templateGroup FormElements. Those are empty. Before save, the submitted form values - will be expanded with the empty fake templateGroup FormElements and such empty values will be saved. +* #3419 / typeAheadSql: Array with only one column or non standard columnnames are not handeld properbly. + Detection of missing LIMIT implemented. +* #3425 / Form.parameter, FormElement.parameter: comment handling, trailing & leading spaces + Manual.rst: commented handling of 'comment character' and 'escaping of leading/trailing spaces' + Support.php: new funtion handleEscapeSpaceComment(). +* Evaluate.php: parse all F|FE.parameter via handleEscapeSpaceComment(). A leading '#' or ' ' might be escaped by '\'. +* Saving 'extra' FE in STORE_SIP has been done with inappropiate FE_NAME. Correct is the pure FE_NAME, without any + extension like recordId. Unessary and broken decoding removed. +* #3426 / Dynamic Update: Inputs loose the new content and shows the old value. +* Through fix #2064 the FE.checkType has not been used anymore. This is fixed now. +* #3433 / templateGroup on primary Record: Values of removed copies are not deleted. The new implementation creates empty + fake instances of all copies of templateGroup FormElements. Those are empty. Before save, the submitted form values + will be expanded with the empty fake templateGroup FormElements and such empty values will be saved. Version 0.14 @@ -2631,47 +2631,47 @@ Version 0.14 Changes ^^^^^^^ - * Play formEditor.sql. +* Play formEditor.sql. - * All Form & FormEditor input elements now have a maxlength definition of 0, which means take the column definition value. - * Drop-down list of container assignment: +* All Form & FormEditor input elements now have a maxlength definition of 0, which means take the column definition value. +* Drop-down list of container assignment: - * Display 'type' ('pill', 'fieldset', 'templategroup') instead of 'class' (always 'container'). - * Display 'name' (internal name) instead of 'label' (shown on the website and might not so usefull as 'name' which - is nowhere else used than in that drop-down. +* Display 'type' ('pill', 'fieldset', 'templategroup') instead of 'class' (always 'container'). +* Display 'name' (internal name) instead of 'label' (shown on the website and might not so usefull as 'name' which + is nowhere else used than in that drop-down. - * FormElement.placeholder colum width extended to 512: +* FormElement.placeholder colum width extended to 512: - ALTER TABLE `FormElement` CHANGE `placeholder` `placeholder` VARCHAR(512) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' + ALTER TABLE `FormElement` CHANGE `placeholder` `placeholder` VARCHAR(512) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' - * New class Ldap.php. +* New class Ldap.php. Features ^^^^^^^^ - * Typeahead for SQL and LDAP Datasources implemented. - * formEditor.sql: Changed width of column FormElement.placeholder from 255 to 512. Removed hardcoded 'size' in FormElement 'placeholder'. - * Character Count: Display a `counter` on input or textarea fields, activated by specifying the formElement.parameter 'characterCountWrap'. - * Evaluate.php: Two new escape options 'l' and 'L'. Backport of ldap_escape() for PHP <5.6. Multiple escaping for one value now possible. - * Manual.rst: add some example for TypeAhead and for saving LDAP value. - * Load foreign values in templatGroups - saving is not implemented yet. - * Manual: Added howto prevent <p>-wrap in TinyMCE. - * TemplateGroup: Add button now disabled if max. number of copies reached. - * #3414 / QuickFormQuery.php: wrap whole form in 'col-md-XX' - User controls the width of an QFQ form. +* Typeahead for SQL and LDAP Datasources implemented. +* formEditor.sql: Changed width of column FormElement.placeholder from 255 to 512. Removed hardcoded 'size' in FormElement 'placeholder'. +* Character Count: Display a `counter` on input or textarea fields, activated by specifying the formElement.parameter 'characterCountWrap'. +* Evaluate.php: Two new escape options 'l' and 'L'. Backport of ldap_escape() for PHP <5.6. Multiple escaping for one value now possible. +* Manual.rst: add some example for TypeAhead and for saving LDAP value. +* Load foreign values in templatGroups - saving is not implemented yet. +* Manual: Added howto prevent <p>-wrap in TinyMCE. +* TemplateGroup: Add button now disabled if max. number of copies reached. +* #3414 / QuickFormQuery.php: wrap whole form in 'col-md-XX' - User controls the width of an QFQ form. 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. - * 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 - moment this is the only way to transmit any error messages. - * formEditor.sql: removed all 'maxLength' string values for 'Form' and 'FormElement' forms. - * Save button becomes active if a templateGroup copy is removed. - * #3413 / Form ohne Pill hat kein padding am Rand. Fix: if there are no pills, an additinal col-md-12 will be rendered. +* 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. +* 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 + moment this is the only way to transmit any error messages. +* formEditor.sql: removed all 'maxLength' string values for 'Form' and 'FormElement' forms. +* Save button becomes active if a templateGroup copy is removed. +* #3413 / Form ohne Pill hat kein padding am Rand. Fix: if there are no pills, an additinal col-md-12 will be rendered. Version 0.13 @@ -2680,55 +2680,55 @@ Version 0.13 Changes ^^^^^^^ - * Play formEditor.sql. - * formEditor.sql: +* Play formEditor.sql. +* formEditor.sql: - * Checktype of `Form.name` restricted to `alnumx` (prior `all`). - * Changed `access` for Form `form` & '`ormElement` from `always` to `sip`. + * Checktype of `Form.name` restricted to `alnumx` (prior `all`). + * Changed `access` for Form `form` & '`ormElement` from `always` to `sip`. - * Table `FormElement`: +* Table `FormElement`: - * Modified column: `checkType` - new value `numerical`. + * Modified column: `checkType` - new value `numerical`. ALTER TABLE FormElement MODIFY COLUMN checkType ENUM('alnumx','digit','numerical','email','min|max','min|max date', 'pattern','allbut','all') NOT NULL DEFAULT 'alnumx' - * Example Report for `forms` extended by a delete button per row. +* Example Report for `forms` extended by a delete button per row. Features ^^^^^^^^ - * print.php: offers 'print page' for any local page - create a PDF on the fly (printout is then browser independent). +* print.php: offers 'print page' for any local page - create a PDF on the fly (printout is then browser independent). - * Install `wkhtmltopdf` on the webserver (http://wkhtmltopdf.org/). - * In config.qfq.ini setup: + * Install `wkhtmltopdf` on the webserver (http://wkhtmltopdf.org/). + * In config.qfq.ini setup: BASE_URL_PRINT=http://www.../ WKHTMLTOPDF=/opt/wkhtmltox/bin/wkhtmltopdf - * Check and error report if 'php_intl' is missing. - * New Checktype 'allow numerical'. - * Documentation: example for 'radio' with no pre selection. - * #3063 / Radios and checkboxes optional rendered in Bootstrap layout. - * Added 'help-box with-errors'-DIV after radios and checkboxes. - * Respect attribute `data-class-on-change` on save buttons. +* Check and error report if 'php_intl' is missing. +* New Checktype 'allow numerical'. +* Documentation: example for 'radio' with no pre selection. +* #3063 / Radios and checkboxes optional rendered in Bootstrap layout. +* Added 'help-box with-errors'-DIV after radios and checkboxes. +* Respect attribute `data-class-on-change` on save buttons. Bug Fixes ^^^^^^^^^ - * #2138 / digit sanitize: new class 'numerical' implemented. - * Fixed recursive thrown exception. - * #2064 / search of a default value for a non existing tablecolumn returns 'false'. +* #2138 / digit sanitize: new class 'numerical' implemented. +* Fixed recursive thrown exception. +* #2064 / search of a default value for a non existing tablecolumn returns 'false'. - * Fixed setting of STORE_SYSTEM / showDebugInfo during API call. + * Fixed setting of STORE_SYSTEM / showDebugInfo during API call. - * #2081, #3180 / Form: Label & note - update via `DynamicUpdate`. - * #3253 / if there is no STORE_TYPO3 (calls through .../api/ like save, delete, load): use SIP / CLIENT_TYPO3VARS. - * qfq-bs.css: +* #2081, #3180 / Form: Label & note - update via `DynamicUpdate`. +* #3253 / if there is no STORE_TYPO3 (calls through .../api/ like save, delete, load): use SIP / CLIENT_TYPO3VARS. +* qfq-bs.css: - * Alignment of checkboxes and radios optimized. - * CSS class 'qfq-note' for 'notes' (third column in a form). + * Alignment of checkboxes and radios optimized. + * CSS class 'qfq-note' for 'notes' (third column in a form). Version 0.12 @@ -2737,101 +2737,103 @@ Version 0.12 Changes ^^^^^^^ - * Table 'FormElement' - * New column: rowLabelInputNote: +* Table 'FormElement' + * New column: rowLabelInputNote: ALTER TABLE `FormElement` ADD `rowLabelInputNote` set('row','label','/label','input','/input','note','/note','/row') NOT NULL DEFAULT 'row,label,/label,input,/input,note,/note,/row' AFTER `bsNoteColumns` ; - * Modified column: 'type' - new value 'templateGroup': + * Modified column: 'type' - new value 'templateGroup': ALTER TABLE `FormElement` CHANGE `type` `type` ENUM( 'checkbox', 'date', 'datetime', 'dateJQW', 'datetimeJQW', 'extra', 'gridJQW', 'text', 'editor', 'time', 'note', 'password', 'radio', 'select', 'subrecord', 'upload', 'fieldset', 'pill', 'templateGroup', 'beforeLoad', 'beforeSave', 'beforeInsert', 'beforeUpdate', 'beforeDelete', 'afterLoad', 'afterSave', 'afterInsert', 'afterUpdate', 'afterDelete', 'sendMail' ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'text' - * formEditor.sql: Added HTML 'placeholder' in FormEditor for bs*Columns. +* formEditor.sql: Added HTML 'placeholder' in FormEditor for bs*Columns. - * PLAY 'formEditor.sql'. + * PLAY 'formEditor.sql'. - * User Input will be UTF8 normalized. +* User Input will be UTF8 normalized. - * INSTALL 'php5-intl' or 'php7.0-intl' on Webserver. + * INSTALL 'php5-intl' or 'php7.0-intl' on Webserver. - * Add globalize.js to be included. Needed by jqx-all.js. +* Add globalize.js to be included. Needed by jqx-all.js. - * UPDATE EXISTING TypoScript TEMPLATES of QFQ Installation. + * UPDATE EXISTING TypoScript TEMPLATES of QFQ Installation. - * Name of variable '_filename' (used in field 'parameter') has changed. Old: '_filename', New: 'filename'. +* Name of variable '_filename' (used in field 'parameter') has changed. Old: '_filename', New: 'filename'. - * UPDATE `FormElement` SET parameter = REPLACE(parameter, "_filename", "filename") + * UPDATE `FormElement` SET parameter = REPLACE(parameter, "_filename", "filename") Features ^^^^^^^^ - * User input will be UTF8 normalized. - * config.qfq-ini: +* User input will be UTF8 normalized. +* config.qfq-ini: - * New configuration values: FORM_BS_LABEL_COLUMNS / FORM_BS_INPUT_COLUMNS / FORM_BS_NOTE_COLUMNS. - * Comment empty variables - the new default setting is, that empty parameter in config.qfq.ini means EMPTY + * New configuration values: FORM_BS_LABEL_COLUMNS / FORM_BS_INPUT_COLUMNS / FORM_BS_NOTE_COLUMNS. + * Comment empty variables - the new default setting is, that empty parameter in config.qfq.ini means EMPTY (=parameter is set and will not be overwritten by internal default), not UNDEFINED (overwritten by internal default). - * FileUpload: +* FileUpload: - * Implemented new Formelement.parameter: fileReplace=always - will replace existing files. - * Multiple / Advanced Upload: new logic implements slaveId, sqlInsert, sqlUpdate, sqlDelete. + * Implemented new Formelement.parameter: fileReplace=always - will replace existing files. + * Multiple / Advanced Upload: new logic implements slaveId, sqlInsert, sqlUpdate, sqlDelete. - * FormElement.parameter: sqlBefore / sqlAfter fired during 'Form' save for action elements. - * STORE FORM: variable 'filename' moved to STORE VAR - sanatize class needs no longer specified. - * STORE VAR: two new variables 'filename' and 'fileDestination' valid during processing of current upload FormElement. - * Default store priority list changed. Old: 'FSRD', New: 'FSRVD'. - * CODING.md: update doc for FormElement 'upload' and general 'Form' rendering & save (recursive rendering). - * User manual: +* FormElement.parameter: sqlBefore / sqlAfter fired during 'Form' save for action elements. +* STORE FORM: variable 'filename' moved to STORE VAR - sanatize class needs no longer specified. +* STORE VAR: two new variables 'filename' and 'fileDestination' valid during processing of current upload FormElement. +* Default store priority list changed. Old: 'FSRD', New: 'FSRVD'. +* CODING.md: update doc for FormElement 'upload' and general 'Form' rendering & save (recursive rendering). +* User manual: - * Described form layout options: description for bsLabelColumn, bsInputColumn, bsNoteColumn. - * Update 'file-upload' doc. - * Described 3 examples for upload forms. + * Described form layout options: description for bsLabelColumn, bsInputColumn, bsNoteColumn. + * Update 'file-upload' doc. + * Described 3 examples for upload forms. - * Administrator manual: +* Administrator manual: - * Add description page.meta... + * Add description page.meta... - * New FormElement (type= 'container') added: 'templateGroup'. +* New FormElement (type= 'container') added: 'templateGroup'. - * FormElement.parameter.tgAddClass | tgAddText | tgRemoveClass | tgRemoveText | tgClass. - * FormElement.maxSize: max number of duplicates. - * #3230 / templateGroup: margin between copies. 'tgClass' implemented. + * FormElement.parameter.tgAddClass | tgAddText | tgRemoveClass | tgRemoveText | tgClass. + * FormElement.maxSize: max number of duplicates. + * #3230 / templateGroup: margin between copies. 'tgClass' implemented. - * Native FormElements: +* Native FormElements: - * FormElement.parameter.htlmlBefore|htmlAfter - add the specified HTML code before or after the element (outside of any wrapping). - * #3224, #3231 / Html Tag <hr> als FormElement. >> htmlBefore | htmlAfter. - * FormElement.parameter.wrapLabel | wrapInput | wrapAfter | wrapRow - if specified, any default wrapping is omitted. - * FormElement.bsNoteColumns | bsInputColumns | bsNoteColumns - a '0' will suppress the whole rendering of the item. - * FormElement.rowLabelInputNote - switch on/off rendering of the corresponding system wrapping items. + * FormElement.parameter.htlmlBefore|htmlAfter - add the specified HTML code before or after the element (outside of any wrapping). + * #3224, #3231 / Html Tag <hr> als FormElement. >> htmlBefore | htmlAfter. + * FormElement.parameter.wrapLabel | wrapInput | wrapAfter | wrapRow - if specified, any default wrapping is omitted. + * FormElement.bsNoteColumns | bsInputColumns | bsNoteColumns - a '0' will suppress the whole rendering of the item. + * FormElement.rowLabelInputNote - switch on/off rendering of the corresponding system wrapping items. - * #3232 / Define custom 'on-change' color - used for the save button: Form.parameter.buttonOnChangeClass=... - * Form.parameter & FormElement.parameter: Lines starting with '#' are treated as comments and will not be parsed. +* #3232 / Define custom 'on-change' color - used for the save button: Form.parameter.buttonOnChangeClass=... +* Form.parameter & FormElement.parameter: Lines starting with '#' are treated as comments and will not be parsed. Bug fixes ^^^^^^^^^ - * User manual: - * Fixed double include of validator.js in T3 Typoscript template example. - * Fixed wrong store name SYSTEM: S > Y. - * Fixed wrong STORE_FORM variable names. - * Reformat FormElement.parameter description. - * Styling errors fixed. - * Use of 'decryptCurlyBraces()' to get better error messages. - * Skip unwanted parameter expansion during save. - * Fixed bug with uninitialized FE_SLAVE_ID. - * formEditor.sql: - * The defintion as 'editor' (not text) for FormElement 'note' has been lost - reinserted. - * Fixed problem while playing SQL query - deleting old FormElements of Formeditor deleted also FormElements of other forms. - * #3066 / help-text with-error - CSS class 'hidden' will be rendered by default (as long there is no error). - * Labels are skipped, if FormElement.bsLabelColumns=0. - * Respect attribute `data-class-on-change` on save buttons. +* User manual: + + * Fixed double include of validator.js in T3 Typoscript template example. + * Fixed wrong store name SYSTEM: S > Y. + * Fixed wrong STORE_FORM variable names. + * Reformat FormElement.parameter description. + * Styling errors fixed. + +* Use of 'decryptCurlyBraces()' to get better error messages. +* Skip unwanted parameter expansion during save. +* Fixed bug with uninitialized FE_SLAVE_ID. +* formEditor.sql: + * The defintion as 'editor' (not text) for FormElement 'note' has been lost - reinserted. + * Fixed problem while playing SQL query - deleting old FormElements of Formeditor deleted also FormElements of other forms. +* #3066 / help-text with-error - CSS class 'hidden' will be rendered by default (as long there is no error). +* Labels are skipped, if FormElement.bsLabelColumns=0. +* Respect attribute `data-class-on-change` on save buttons. Version 0.11 ------------ @@ -2839,21 +2841,21 @@ Version 0.11 Features ^^^^^^^^ - * Added STORE_BEFORE, #3146 - Mainly used to compare old and new values during a form 'save' action. - * Added 'best practice' for defining and using of 'Central configure values' in UserManual. - * Added accent characters to sanatize class 'alnumx', #3183. - * Set default all QFQ send mails to 'auto-submit'. - * Added possibility to customize error messages ('data-pattern-error', 'data-rquired-error', 'data-match-error', - 'data-error') if validation fails. Customization can be done on global level (config.qfq.ini), per Form or per FormElement. - * *FormElement*: Double an input element and validate that the input match: FormElement.parameter.retype=1. - * Autofocus in Forms is now supported. By default the first Input Element receives the focus. Can be customized. - * Added a timestamp in shown exceptions. Usefull for screenshots, send by customer, to find the problem in SQL logfiles. +* Added STORE_BEFORE, #3146 - Mainly used to compare old and new values during a form 'save' action. +* Added 'best practice' for defining and using of 'Central configure values' in UserManual. +* Added accent characters to sanatize class 'alnumx', #3183. +* Set default all QFQ send mails to 'auto-submit'. +* Added possibility to customize error messages ('data-pattern-error', 'data-rquired-error', 'data-match-error', + 'data-error') if validation fails. Customization can be done on global level (config.qfq.ini), per Form or per FormElement. +* *FormElement*: Double an input element and validate that the input match: FormElement.parameter.retype=1. +* Autofocus in Forms is now supported. By default the first Input Element receives the focus. Can be customized. +* Added a timestamp in shown exceptions. Usefull for screenshots, send by customer, to find the problem in SQL logfiles. Bug fixes ^^^^^^^^^ - * Fixed missing docutmentation for FormElement 'note'. - * Failed SQL queries will now always be logged, even if they do not modify some data. +* Fixed missing docutmentation for FormElement 'note'. +* Failed SQL queries will now always be logged, even if they do not modify some data. Version 0.10 ------------ @@ -2861,14 +2863,14 @@ Version 0.10 Features ^^^^^^^^ - * Implemented Parameter 'extraDeleteForm' for 'forms' and 'subrecords'. Update doc. +* Implemented Parameter 'extraDeleteForm' for 'forms' and 'subrecords'. Update doc. Bug fixes ^^^^^^^^^ - * Suppress rendering of form title during a 'delete' call. No one will see it and required parameters are not supplied. - * In case of broken SQL queries, print them in ajax error message. - * Remove parameter 'table' from Delete SIP URLs. ToolTip updated. +* Suppress rendering of form title during a 'delete' call. No one will see it and required parameters are not supplied. +* In case of broken SQL queries, print them in ajax error message. +* Remove parameter 'table' from Delete SIP URLs. ToolTip updated. Version 0.9 ----------- @@ -2876,43 +2878,43 @@ Version 0.9 Features ^^^^^^^^ - * FormEditor: - * design update - new default background color: grey. - * per form configureable background colors. - * Optional right align of all form element labels. - * Added config.qfq.ini values CSS_CLASS_QFQ_FORM_PILL, CSS_CLASS_QFQ_FORM_BODY, CSS_CLASS_QFQ_CONTAINER. +* FormEditor: + * design update - new default background color: grey. + * per form configureable background colors. + * Optional right align of all form element labels. + * Added config.qfq.ini values CSS_CLASS_QFQ_FORM_PILL, CSS_CLASS_QFQ_FORM_BODY, CSS_CLASS_QFQ_CONTAINER. Bug fixes ^^^^^^^^^ - * BuildFormBootstrap.php: added new class name 'qfq-label' to form labels - needed to assign 'qfq-form-right' class. - Changed wrapping of formelements from 'col-md-8' (wrong) to 'col-md-12'. - * QuickFormQuery.php: Set default for new F_CLASS_PILL & F_CLASS_BODY. - * formEditor.sql: New default background color for formElements is blue. - * qfq-bs.css.less: add classes qfq-form-pill, qfq-form-body, form-group (center), qfq-color-..., qfq-form-right. - * Index.rst: Add note to hierachy chars. Fixed uncomplete doc to a) bs*Columns, showButton. Add classPill, classBody. - Rewrote form.paramter.class. - * QuickFormQuery.php: Button save/ close/ delete/ new - align to right border of form. - * UsersManual/index.rst: renamed chapter for formelements. Cleanup formelement types. Wrote chapter 'Detailed concept'. - * QuickFormQuery.php, FormAction.php: '#2931 / afterSave Hauptrecord xId nicht direkt verfügbar' - load master record - again, after 'action'-elements has been processed. - * UsersManual/index.rst: Startet FAQ section. - * config.qfq.example.ini: Added comment where to save config.qfq.ini. - * UsersManual/index.rst: Rewrite of 'action'-FormElement definition. - * #2739 / beforeDelete / afterDelete. - * PROTOCOL.md: update 'delete' description. - * delete.php: fixed unwanted loose of MSG_CONTENT. - * Report.php: Fixed double '&&' in building UrlParam. - * FormAction.php: In case of 'AFTER_DELETE', do not try to load primary record - that one is already deleted. - * Sip.php: Do not skip SIP_TARGET_URL as parameter for the SIP. - * #3001 / Report: delete implementieren. - * Index.rst, Constants.php: reverted parameter '_table' in delete links back to 'table' - Reason: 'form' needs to be - 'form' (instead of '_form') due to many used places already. - * Sip.php: move SIP_TARGET_URL back to stored inside SIP - it's necessary for 'delete'-links. - * Report.php, Constants.php: Remove code to handle unecessary 'p:' tag for delete links. - * Link.php: Check paged / Paged that the parameter r, table and form are given in the right combination. - * Link.php, Report.php: New '_link' token 'x'. '_paged' and '_Paged' are rendered via Link() class, Link() class now - supports delete links. - * QuickFormQuery.php: for modeForm='Form Delete' the 'required param' are not respected - this makes sense, cause these - parameters typically filled in newly created records. - * #3076 / Delete Button bei Subrecords erzeugt sporadisch Javascript Exceptions (Webkit: Chrome / Vivaldi) - kein loeschen moeglich. +* BuildFormBootstrap.php: added new class name 'qfq-label' to form labels - needed to assign 'qfq-form-right' class. + Changed wrapping of formelements from 'col-md-8' (wrong) to 'col-md-12'. +* QuickFormQuery.php: Set default for new F_CLASS_PILL & F_CLASS_BODY. +* formEditor.sql: New default background color for formElements is blue. +* qfq-bs.css.less: add classes qfq-form-pill, qfq-form-body, form-group (center), qfq-color-..., qfq-form-right. +* Index.rst: Add note to hierachy chars. Fixed uncomplete doc to a) bs*Columns, showButton. Add classPill, classBody. + Rewrote form.paramter.class. +* QuickFormQuery.php: Button save/ close/ delete/ new - align to right border of form. +* UsersManual/index.rst: renamed chapter for formelements. Cleanup formelement types. Wrote chapter 'Detailed concept'. +* QuickFormQuery.php, FormAction.php: '#2931 / afterSave Hauptrecord xId nicht direkt verfügbar' - load master record + again, after 'action'-elements has been processed. +* UsersManual/index.rst: Startet FAQ section. +* config.qfq.example.ini: Added comment where to save config.qfq.ini. +* UsersManual/index.rst: Rewrite of 'action'-FormElement definition. +* #2739 / beforeDelete / afterDelete. +* PROTOCOL.md: update 'delete' description. +* delete.php: fixed unwanted loose of MSG_CONTENT. +* Report.php: Fixed double '&&' in building UrlParam. +* FormAction.php: In case of 'AFTER_DELETE', do not try to load primary record - that one is already deleted. +* Sip.php: Do not skip SIP_TARGET_URL as parameter for the SIP. +* #3001 / Report: delete implementieren. +* Index.rst, Constants.php: reverted parameter '_table' in delete links back to 'table' - Reason: 'form' needs to be + 'form' (instead of '_form') due to many used places already. +* Sip.php: move SIP_TARGET_URL back to stored inside SIP - it's necessary for 'delete'-links. +* Report.php, Constants.php: Remove code to handle unecessary 'p:' tag for delete links. +* Link.php: Check paged / Paged that the parameter r, table and form are given in the right combination. +* Link.php, Report.php: New '_link' token 'x'. '_paged' and '_Paged' are rendered via Link() class, Link() class now + supports delete links. +* QuickFormQuery.php: for modeForm='Form Delete' the 'required param' are not respected - this makes sense, cause these + parameters typically filled in newly created records. +* #3076 / Delete Button bei Subrecords erzeugt sporadisch Javascript Exceptions (Webkit: Chrome / Vivaldi) - kein loeschen moeglich. diff --git a/Gruntfile.js b/Gruntfile.js index ac811bdaa8b9431c21ef09f41438ff4b918146a0..49e26fd5301f801f708d979f5fc28743ed4f20cc 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -5,6 +5,7 @@ module.exports = function (grunt) { var typo3_css = 'extension/Resources/Public/Css/'; var typo3_js = 'extension/Resources/Public/JavaScript/'; var typo3_fonts = 'extension/Resources/Public/fonts/'; + var typo3_webfonts = 'extension/Resources/Public/webfonts/'; var js_sources = [ 'javascript/src/Helper/*.js', 'javascript/src/Element/*.js', @@ -463,17 +464,20 @@ module.exports = function (grunt) { fontAwesome: { files: [ { - cwd: 'node_modules/font-awesome/css/', + cwd: 'node_modules/@fortawesome/fontawesome-free/css/', src: [ - 'font-awesome.min.css' + 'all.min.css' ], dest: typo3_css, filter: 'isFile', expand: true, - flatten: true + flatten: true, + rename: function(dest, src) { + return dest + src.replace('all','font-awesome'); + } }, { - cwd: 'node_modules/font-awesome/css/', + cwd: 'node_modules/@fortawesome/fontawesome-free/css/', src: [ 'font-awesome.min.css' ], @@ -483,21 +487,21 @@ module.exports = function (grunt) { flatten: true }, { - cwd: 'node_modules/font-awesome/fonts/', + cwd: 'node_modules/@fortawesome/fontawesome-free/webfonts', expand: true, src: [ '*' ], - dest: typo3_fonts, + dest: typo3_webfonts, flatten: true }, { - cwd: 'node_modules/font-awesome/fonts/', + cwd: 'node_modules/@fortawesome/fontawesome-free/webfonts', expand: true, src: [ '*' ], - dest: 'fonts/', + dest: 'webfonts/', flatten: true } ] diff --git a/extension/Classes/Sql/function.sql b/extension/Classes/Sql/function.sql index 48809db97bc259a6274e44f5b2fddb9c39655179..821ffce85c4f6bfac6efb215dcc9809aa3474f2e 100644 --- a/extension/Classes/Sql/function.sql +++ b/extension/Classes/Sql/function.sql @@ -1,4 +1,5 @@ ### +### # # GETFUNCTIONSHASH() is used for checking whether this file has been played properly in DatabaseUpdate.php # @@ -128,12 +129,122 @@ END; # DROP FUNCTION IF EXISTS QDATE_FORMAT; CREATE FUNCTION `QDATE_FORMAT`(ts DATETIME) - RETURNS TEXT - DETERMINISTIC - SQL SECURITY INVOKER + RETURNS TEXT + DETERMINISTIC + SQL SECURITY INVOKER BEGIN - DECLARE output TEXT; - SET output = IF(ts = 0, '-', DATE_FORMAT(ts, "%d.%m.%Y %H:%i")); - RETURN output; + DECLARE output TEXT; + SET output = IF(ts = 0, '-', DATE_FORMAT(ts, "%d.%m.%Y %H:%i")); + RETURN output; +END; + +### +# +# QSLUGIFY(string) +# + +/* +The MIT License (MIT) +Copyright (c) 2014 jose reis<jose.reis@artbit.pt> +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +Credits: +- http://stackoverflow.com/questions/5409831/mysql-stored-function-to-create-a-slug +*/ + +DROP FUNCTION IF EXISTS `QSLUGIFY`; +CREATE FUNCTION `QSLUGIFY`(dirty_string varchar(255)) RETURNS varchar(255) CHARSET utf8 + DETERMINISTIC +BEGIN + DECLARE x, y , z , k INT; + DECLARE temp_string, new_string, accents, noAccents VARCHAR(255); + DECLARE is_allowed BOOL; + DECLARE c, check_char VARCHAR(1); + + -- IF NULL DO NOT PROCEED + If dirty_string IS NULL Then + return dirty_string; + End If; + + set temp_string = LOWER(dirty_string); + + -- REPLACE ACCENTS + -- WITH CAPS + -- set accents = 'ŠšŽžÀÃÂÃÄÅÆÇÈÉÊËÌÃÃŽÃÑÒÓÔÕÖØÙÚÛÜßÞà áâãäåæçèéêëìÃîïñòóôõöøùúûüýÿþƒ'; + -- set noAccents = 'SsZzAAAAAAACEEEEIIIINOOOOOOUUUUYYBaaaaaaaceeeeiiiinoooooouuuuyybf'; + -- ONLY SMALL CAPS + set accents = 'šžà áâãäåæçèéêëìÃîïñòóôõöøùúûüýÿþƒ'; + set noAccents = 'szaaaaaaaceeeeiiiinoooooouuuuyybf'; + set k = CHAR_LENGTH(accents); + + while k > 0 + do + set temp_string = REPLACE(temp_string, SUBSTRING(accents, k, 1), SUBSTRING(noAccents, k, 1)); + set k = k - 1; + end while; + + -- CONVERT & TO EMPTY SPACE + Set temp_string = REPLACE(temp_string, '&', ''); + + -- REPLACE ALL UNWANTED CHARS + Select temp_string REGEXP ('[^a-z0-9\-]+') into x; + If x = 1 then + set z = 1; + set k = CHAR_LENGTH(temp_string); + While z <= k + Do + Set c = SUBSTRING(temp_string, z, 1); + Set is_allowed = FALSE; + If !((ascii(c) = 45) or (ascii(c) >= 48 and ascii(c) <= 57) or + (ascii(c) >= 97 and ascii(c) <= 122)) Then + Set temp_string = REPLACE(temp_string, c, '-'); + End If; + set z = z + 1; + End While; + End If; + + Select temp_string REGEXP ("^-|-$|'") into x; + If x = 1 Then + Set temp_string = Replace(temp_string, "'", ''); + Set z = CHAR_LENGTH(temp_string); + Set y = CHAR_LENGTH(temp_string); + Dash_check: + While z > 1 + Do + If STRCMP(SUBSTRING(temp_string, -1, 1), '-') = 0 Then + Set temp_string = SUBSTRING(temp_string, 1, y - 1); + Set y = y - 1; + Else + Leave Dash_check; + End If; + Set z = z - 1; + End While; + End If; + + Repeat + Select temp_string REGEXP ("--") into x; + If x = 1 Then + Set temp_string = REPLACE(temp_string, "--", "-"); + End If; + Until x <> 1 End Repeat; + + If LOCATE('-', temp_string) = 1 Then + Set temp_string = SUBSTRING(temp_string, 2); + End If; + + Return temp_string; END; diff --git a/less/qfq-bs.css.less b/less/qfq-bs.css.less index 39f3da3c300b60cdd43b367677c7a7afbc90c9ac..7d4feee42948b978483bf822fe62caa6ef5188f1 100644 --- a/less/qfq-bs.css.less +++ b/less/qfq-bs.css.less @@ -566,6 +566,15 @@ select.qfq-locked:invalid { // Fabric Plugin classes +.qfq-fabric-fullscreen { + position: absolute; + top: 0; + left: 0; + z-index: 200; + width: 100vw; + height: 100vh; +} + .qfq-fabric-bar { position: -webkit-sticky; position: sticky; diff --git a/package.json b/package.json index e609fe7312963089efa8b8163eccfbd89696a8b0..f08064aa535f5289f943f720d056d7011cd3be3c 100644 --- a/package.json +++ b/package.json @@ -2,13 +2,13 @@ "name": "qfq", "version": "1.0.0", "dependencies": { + "@fortawesome/fontawesome-free": "^5.13.0", "bootlint": "^0.14.2", "bootstrap": "^3.3.6", "bootstrap-validator": "^0.11.5", "chart.js": "^2.1.2", - "codemirror": "^5.24.0", - "corejs-typeahead": "^1.1.1", - "font-awesome": "^4.7.0", + "codemirror": "^5.53.2", + "corejs-typeahead": "^1.3.1", "fullcalendar": "^3.10.1", "grunt": "^1.0.4", "grunt-concat-in-order": "^0.2.6", @@ -21,14 +21,14 @@ "grunt-contrib-watch": "^1.0.0", "jquery": "latest", "jqwidgets-framework": "4.2.1", - "jsdoc": "^3.4.0", + "jsdoc": "^3.6.4", "mocha": "^3.2.0", "moment": "^2.24.0", "popper.js": "^1.14.3", "selenium-webdriver": "^3.3.0", "should": "^11.2.1", "tablesorter": "^2.31.0", - "tinymce": "^4.4.3", + "tinymce": "^4.9.10", "wolfy87-eventemitter": "^4.3.0" }, "devDependencies": {}, @@ -37,4 +37,4 @@ }, "license": "ISC", "repository": "https://git.math.uzh.ch/typo3/qfq" -} \ No newline at end of file +}