Added initial support for workspaces in core.
authorKasper Skårhøj <kasper@typo3.org>
Tue, 4 Oct 2005 12:03:20 +0000 (12:03 +0000)
committerKasper Skårhøj <kasper@typo3.org>
Tue, 4 Oct 2005 12:03:20 +0000 (12:03 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@809 709f56b5-9817-0410-a4d7-c38de5d9e867

79 files changed:
ChangeLog
TODO.txt
t3lib/class.t3lib_befunc.php
t3lib/class.t3lib_beuserauth.php
t3lib/class.t3lib_browsetree.php
t3lib/class.t3lib_db.php
t3lib/class.t3lib_diff.php
t3lib/class.t3lib_div.php
t3lib/class.t3lib_iconworks.php
t3lib/class.t3lib_loadmodules.php
t3lib/class.t3lib_page.php
t3lib/class.t3lib_pagetree.php
t3lib/class.t3lib_tceforms.php
t3lib/class.t3lib_tcemain.php
t3lib/class.t3lib_treeview.php
t3lib/class.t3lib_tsparser_ext.php
t3lib/class.t3lib_tstemplate.php
t3lib/class.t3lib_userauthgroup.php
t3lib/config_default.php
t3lib/gfx/i/shadow_delete.png [new file with mode: 0755]
t3lib/gfx/i/shadow_hide.png [new file with mode: 0755]
t3lib/gfx/i/sys_workspace.png [new file with mode: 0755]
t3lib/gfx/loginbox_image_dev.png
t3lib/gfx/swap.png [new file with mode: 0755]
t3lib/jsfunc.evalfield.js
t3lib/stddb/tables.php
t3lib/stddb/tables.sql
t3lib/stddb/tbl_be.php
typo3/alt_clickmenu.php
typo3/alt_db_navframe.php
typo3/alt_doc.php
typo3/alt_intro.php
typo3/alt_main.php
typo3/alt_menu.php
typo3/alt_menu_sel.php
typo3/alt_shortcut.php
typo3/alt_topmenu_dummy.php
typo3/browse_links.php
typo3/class.db_list.inc
typo3/class.db_list_extra.inc
typo3/db_list.php
typo3/file_list.php
typo3/init.php
typo3/mod/file/conf.php
typo3/mod/file/list/conf.php
typo3/mod/tools/conf.php
typo3/mod/user/ws/class.wslib.php [new file with mode: 0755]
typo3/mod/user/ws/clear.gif [new file with mode: 0755]
typo3/mod/user/ws/cli/conf.php [new file with mode: 0755]
typo3/mod/user/ws/cli/ws_cli.phpsh [new file with mode: 0755]
typo3/mod/user/ws/conf.php [new file with mode: 0755]
typo3/mod/user/ws/index.php [new file with mode: 0755]
typo3/mod/user/ws/sys_workspace.png [new file with mode: 0755]
typo3/mod/web/perm/index.php
typo3/stylesheet.css
typo3/sysext/beuser/mod/index.php
typo3/sysext/cms/ext_tables.php
typo3/sysext/cms/ext_tables.sql
typo3/sysext/cms/layout/class.tx_cms_layout.php
typo3/sysext/cms/tbl_cms.php
typo3/sysext/cms/tbl_tt_content.php
typo3/sysext/cms/tslib/class.tslib_content.php
typo3/sysext/cms/tslib/class.tslib_fe.php
typo3/sysext/cms/tslib/class.tslib_menu.php
typo3/sysext/cms/tslib/class.tslib_pibase.php
typo3/sysext/cms/tslib/index_ts.php
typo3/sysext/cms/web_info/class.tx_cms_webinfo_lang.php
typo3/sysext/css_styled_content/pi1/class.tx_cssstyledcontent_pi1.php
typo3/sysext/indexed_search/modfunc1/class.tx_indexedsearch_modfunc1.php
typo3/sysext/indexed_search/modfunc2/class.tx_indexedsearch_modfunc2.php
typo3/sysext/indexed_search/pi/class.tx_indexedsearch.php
typo3/sysext/lang/locallang_csh_corebe.xml
typo3/sysext/lang/locallang_csh_sysws.xml [new file with mode: 0755]
typo3/sysext/lang/locallang_misc.xml
typo3/sysext/lang/locallang_mod_user_ws.xml [new file with mode: 0755]
typo3/sysext/lang/locallang_tca.xml
typo3/sysext/version/class.tx_version_cm1.php
typo3/sysext/version/cm1/index.php
typo3/template.php

index fe9a428..7e84660 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,18 +1,23 @@
+2005-10-04  Kasper Skårhøj  <kasper2005@typo3.com>
+
+ * Added initial support for workspaces in core. 
+ * !!! Notice that all versioning features for tables are now enabled by the [ctrl] directive "versioningWS" and not "versioning". You will have to change this for all custom usages. At the same time you will have to add additional fields that are now mandatory for versioning to work. This is documented in the yet not published TYPO3 Core API for next version. Until the versioning API is final it is recommended to be very careful to apply versioning to custom tables.
+
 
 2005-10-04 Martin Kutschker <martin.t.kutschker@blackbox.net>
 
      * Fixed bug #1152: allow for nice filenames in Apache stat file (config.stat_apache_niceTitle)
      * optionally remove the site root from the Apache stat file path (config.stat_apache_noRoot)
+ * Fixed bug #1152: allow for nice filenames in Apache stat file (config.stat_apache_niceTitle)
+ * optionally remove the site root from the Apache stat file path (config.stat_apache_noRoot)
 
 2005-10-02 Bernhard Kraft  <kraftb@kraftb.at>
 
      * Integrated content-slide extension into core
      (http://wiki.typo3.org/index.php/Extensions_for_the_core)
      * Implemented "requestUpdate" feature of TCEforms for Flexform fields
+ * Integrated content-slide extension into core
+ (http://wiki.typo3.org/index.php/Extensions_for_the_core)
+ * Implemented "requestUpdate" feature of TCEforms for Flexform fields
 
 2005-09-19 Martin Kutschker <martin.t.kutschker@blackbox.net>
 
      * Fixed bug #1287: Detect Opera as Netscape3 (making image roll-overs work)
+ * Fixed bug #1287: Detect Opera as Netscape3 (making image roll-overs work)
 
 2005-09-18 Michael Stucki <michael@typo3.org>
 
index d308ff3..4cc5c5d 100755 (executable)
--- a/TODO.txt
+++ b/TODO.txt
@@ -5,29 +5,90 @@ Maintained by Kasper
 Do not modify without permission!
 *******************************************
 
+[@KASPER: ALSO SEE MY MAIL FOLDERS about Core development!]
 
-General:
+
+General Backend:
 - CHECK: What is the number of supported page levels? 20 or 100?
-- CHECK: possible XSS problem with alt_mod_frameset.php taking parameters for scripts to display in frames.
-- Option: Turn of "onBlur" in backend (Message-ID: <001801c2a28c$bb020c70$963afea9@bla8kdvxpl8glk>)
 - Feature: "admin" can click a button which wipes out all record-lockings. (Message-Id: <200301281752.23246.mundaun@gmx.ch>)
-- Feature: Controlling access to function menu modules as well (thus we could have a user-module inside ?Template? which could edit the constants field)
-- Feature: Web >plugins -> to be a main module where people can place modules for their extension.
+- Feature: Controlling access to function menu modules as well (thus we could have a user-module inside ?Template? which could edit the constants field) (including workspace access)
+- Feature: Web >plugins removed
 - Substitute "->include_once[] = ...." with "require_once()" directly in classes - BUT the problem is that class files accesses $TYPO3_CONF_VARS (for XCLASS inclusion) and that is not accessible from the function including the script unless "global $TYPO3_CONF_VARS" is set before inclusion. THEN all XCLASSes of that class will break!!!
+       - Check the source for "require_once()" calls inside of methods and make sure "global $TYPO3_CONF_VARS" are set before (also update CGL document).
 - Backend Interface: Dont show edit icons if editing cannot be performed due to recordEditAccessInternals() / editlock for pages (pid)
-
-TCEmain:
-- Commenting of the class.
-- Charset:
-       - Currently the upper/lower case conversion converts danish/german letters as if they were iso-8859-1. This will be a problem if other charsets are used. What to do?
+- class.t3lib_dmailer.php into direct_mail module?
+- Avoiding the symlinks in core?
+- GETll can be configured to show the label key so wrong labels can quickly be changed (using the key to find label in translator interface)
+- lock cHash to id as well (otherwise spamming cache-table can be done with a series of cHash values/parameters and traversing known page ids)
+
+TCEmain
+(Related: DBint, User Admin module, logging-display, TCEforms, Web>List)
+- Clean-up and commenting of the class.
+- CHARSET:
        - Note: No charset conversion is done in TCEmain. It is expected that the content enters TCEmain in the charset of the backend in general.
-- FEATURES:
+- LOGGING:
+       - Finally define the API to the "sys_log" table!
+               - Add detection of workspace
+       - Rewrite log-display, support writing to text-files, syslog on unix (API?)
+               - Reports/Monitoring: Show/send-by-email daily reports over accumulated activity (grouped by workspace/user/pagetree section/modules etc) [Richard at Dassault wanted this]
+                       - Activity of individual users in a summary form
+                       - Activity in branches of a page tree
+                       - Activity in a workspace
+       - Finish the logging of TCEmain actions (delete/copy)
+       - Versioning: sys history/sys_log track the "uid" of a record and version swapping will invalidate the integrity of this! How to deal with?
+       - Centralized logging:
+               - Create a core API for logging data from all kinds of places in the system. (substituting the current sys_log?)
+               - Create an extension which shows how the log data can be stored in a) database, b) files
+               - extension "logit" / PEAR::log package?
+- INTEGRITY / CLEAN_UP / REFERENCE TRACKING:
+       - Implement kill/restore of "deleted" records.
+       - Record Reference tracking in a table in TCEmain
+               - Tracks DB-references, Files and softrefs (including in FlexForms)
+               - Index is generated per record with an API call (both fe/be), making it easy to maintain it and possible to completely regenerate it
+               - Used for:
+                       - Check before deletion that a record is not used?
+                       - Used by applications (like TemplaVoila) where it is hard to track references in FlexForms
+                       - Used for import/export module and anywhere else where we are looking up references!
+                       - Basis for integrity checks
+                       - clearing caching more effectively
+       - Record clean-up functionality
+               - Remove references to deleted records (also deleted-to-recycler records? Maybe "deleted-to-recycler" references are important to remove in order to make sure "recycler" records are not selected!) (refs to MM for both tables/files)
+               - Remove references to lost files etc.
+               - Cleaning FlexForm XML according to the current DS (old XML garbage might be left if DS changed)
+       - Versioning:
+               - Flush old versions (requires general clean-up features to be complete!)
+               - Check for "lost" versions during swap?
+- PERMISSIONS:
+       - Permission API: Used for any DB-element in system (See Sune Vestergaards suggestion)
+               - More flexible setting of permissions
+               - Additional checks apart from read/edit/new/delete etc.
+               - Permissions for any record
+               - Can work in conjunction with current page permissions or simply work instead of them.
+               - Access Lists?
+       - CHECK: That permissions are properly evaluated, especially:
+               - Languages (there was a bug proved)
+               - Workspaces / Versioning
+               - Moving of records (source/destination PIDs)
+       - Security in tcemain: Uploaded/Attached files are allowed to be in ONLY a relative path OR in the "lockDir"!
+       - Roles (ideas about adding roles to the permission concept of TYPO3):
+               - There could be, say, 4 default roles:  author, editor, administrator, developer
+               - Users can be assigned "membership" of a role (basically a "role" is like a hardcoded "user-group")
+               - Like you can configure database fields in TCA to be an "excludeField" you could also configure which ROLES can edit the field.
+               - Possibly each role could assign membership of some groups.
+       - Tools > User Admin:
+               - Features helping to configure roles/users?
+       - Versioning:
+               - Versioning must work for non-admins!
+               - Backend user access to elements is based on the access restrictions for the official element (except pages?). This must be implemented on core level.
+- TCEforms/TCEmain available for frontend
+       - Makes portal features easier to create
+       - A rewrite of TCEmain might help very much!
+- VARIOUS FEATURES:
        - Support for submitting dates in non-UNIX-time format (eg. DD-MM-YYYY) (is there a PHP function to which you can directly pass something like "DD-MM-YYYY" and then it will clean it all up? Or convert?
        - Recyclebin: If an item is deleted and is NOT in the recyclebin, then move it (all pages to the root of) the closest recyclebin (in a rootline pid AND with write permissions) in the pagetree. If that is not present, then delete normally. If you delete anything in a recycle bin, it's totally deleted.
        - Implement field evaluation in TCEmain: Evaluate min/max? Checking references exists?
        - Implement a feature, "max_number_of_records_in_pid" which means the TCEmain will check if a number of records of a kind has been exceeded for the page.
        - "Pattern-control" for relation fields? (See "APPENDIX: PATTERN-control") Probably create an API by which you can do your own evaluating, return true/false, return an error message.
-       - pre and post processing by user functions of the data? (Message-ID: <C018FF617C61AB4588D15494126A5C0F23E431@Soulman.hanno-kirchhoff.de>)
        - "Tree-tables": Adding TCA-feature which can describe a field being a internal_pid for the table so tables can be listed as a tree in Web>List (and for TCEmain this means that copying an element). "parent" items. Rene needs this for "categories". See (Message-Id: <200212201257.24705.r.fritz@colorcube.de>)
        - Support for "grouping": - eg. tt_content elements are grouped by "column" + "language". But copy/cut operations must understand this. And Web>List should reflect this as categorizing.
        - "child records" - records which MUST be related to another table - and will be moved along with the main record if moved.
@@ -44,49 +105,27 @@ TCEmain:
        - Support for MM-records which does NOT get deleted, but is kept... and then support for having data in those!! NOTE 3/12 04: This will cause severe problems in the import/export interface and probably many other places where the MM relations are stored only as the uid of another table and nothing more. That makes it impossible to track the record in the middle....
        - Support that the content of a single field can be stored in an external file instead.
        - Support that a list of fields can be stored in an external XML file instead.
-       - Record Reference tracking in a table in TCEmain; Used to:
-               - Check before deletion that a record is not used.
-               - Used by TemplaVoila where it is hard to track references in FlexForms
-               - A backend module can regenerate the "index-table" if it becomes invalid over time for some reason...
-               - Used for import/export module and anywhere else where we are looking up references!
        - "uniquePerField"
                - used for pages_overlay_records "pid"
                - used for "tt_content"/"sys_language_uid", field "l18n_parent"
-- VERSIONING:
-       - See description in appendix.
-- LOGGING:
-       - Finish the logging of TCEmain actions (delete/copy) + finally define the API to the "sys_log" table!
-- CLEAN_UP:
-       - Implement kill/restore of "deleted" records.
-       - Remove references to records when deleting totally (or also deleted-to-recycler records? Maybe "deleted-to-recycler" references are important to remove in order to make sure "recycler" records are not selected!) (refs to MM for both tables/files)
-- PERMISSIONS:
-       - Permission management on selector box/radio button values
-               - so certain "CType" / "Insert plugin" / "FlexForm datatypes" values could be blocked
-               - Could it be considered to implement some "access pool" where elements on any level (like here selectorboxes or for FlexForms elements/types there) could add their element by an API and then it would A) automatically be listed for groups access lists and B) automatically enforced.
-       - Permission management for translations? Users are allowed to edit certain languages? (Setup with general access list API?)
-       - Permissions on record-level
-       - CHECK: That permissions are properly evaluated (especially for moving content?)
-       - Security in tcemain: Uploaded/Attached files are allowed to be in ONLY a relative path OR in the "lockDir"!
+       - Having references on the form [uid : filereference/] for fall-back abilities.
 - BUG:
        - if a file is uploaded (directly in the form) and there is an upper limit to the number of files which is then exceeded, the uploaded file is STILL copied to the upload folder and will thus be listed as "Files with no references at all (delete them!):"
        - TCEmain: If there is a comma in the filename supplied as an uploaded file it will confuse the handling of files because the comma is also used to split the filename from each other. (29/04/2003). This is a problem with Inter-Photo Netprint where files uploaded by FTP with comma in the name will not be attached as they should. I think the solution should be found in TCEmain so any filename can be supplied as uploaded.
-- RELATED: DBint/admin, logging-display, TCEforms, Web>List
 - IDEA: check for potential dangerous php-extension
-- TCEforms/TCEmain available for frontend?
 
 
 TCEmain/TCEforms for FlexForms:
-- Affects: "lowlevel" ext/DBint , "impexp" extension. Must/Should be extended.
 - Permissions handled per-field in FlexForms?
 - What to do if data structure was not found? (Both TCEmain, TCEforms, templavoila_pi1, t3lib_transferdata)
 - block the creation of FlexForm in FlexForm inside TCEforms.
 - ['pi_flexform']['config']['ds'] must be set to some default message making sense!
-- CSH for flexforms
+- Other XML formats for DS: - API / services?
+       - xml2array - supporting looking for <>&" and if found wrapping in CDATA instead! (or maybe for multiline values?)
 - TCEmain features:
-       - caching of references/files in meta data (for analysis tools)? --> NO, rather use the "new" planned reference index table, see above.
        - mapping values to a plain-text search field(s)
-       - Offering API functions for add/delete/move/copy
-       - Cleaning the original data in field since this may have an invalid structure if the data structure has changed in the meantime.
+       - Offering API functions for add/delete/move/copy/paste of FlexForm elements/sections
+       - Copy/Paste API for references? (see TemplaVoila page-module pioneer work)
        - Possibility to write the XML data values into a table instead (see Marc Schlingers idea, stored on paper in my red organizer).
 - TCEforms:
        - Support for checkboxes which can expand/collapse sections/containers? fold-in, fold-out, passing a list of fields to show (with sub-levels for horizontal display).
@@ -97,25 +136,31 @@ TCEmain/TCEforms for FlexForms:
                - visual: Table with condition in top header, condition value column + block column. Not user supplied. -> OR just a selector box deciding what is shown below!? (possibly "ALL")
        - Displaying partial branch of the data structure (and to a certain level)
        - FlexForms cannot be possible if the record is not saved? No, should be ok, BUT a data source can of course not be referenced from another field since that fields value is NOT actually there! So only for fixed references to flex form definitions can this be done.
-       - If you have a multiple selector field (or checkbox array) an array of objects could be forced to reflect exactly the fieldnames there 1-1 thus giving us configuration option possibilities per field! For newloginbox extension: You set up a selector box with multiple choice where you can select fields from the fe_users table to display. In an array of elements in the DS you configure that the VALUE of that field is dictating that the same number of objects should be shown for configuration of each field. A "hidden" value would point each object to which value from the field it was for! The same would be very useful for M-M lists of records.
+       - If you have a multiple selector field (or checkbox array) an array of objects could be forced to reflect exactly the fieldnames there 1-1 thus giving us configuration option possibilites per field! For newloginbox extension: You set up a selector box with multiple choice where you can select fields from the fe_users table to display. In an array of elements in the DS you configure that the VALUE of that field is dictating that the same number of objects should be shown for configuration of each field. A "hidden" value would point each object to which value from the field it was for! The same would be very useful for M-M lists of records.
        - Implement "<displayCond>EXT:templavoila:LOADED:true</displayCond>" for flexforms. (needed for mininews!!)
        - Implement CSH for FF fields.
-
+       - Localization of FlexForms:
+               - Permissions for specific language as well!
+               - Using DHTML tabs for langChildren = 0, making something else for langChildren = 1
 
 TCEforms:
-- Support for other backend charsets / right-aligned charsets!?
+- Support for right-aligned charsets?
 - FEATURES:
        - GENERAL:
-               - Customized display of a field, possibly passing an array with code that should be displayed and then people can themselves put it together from PHP?
-               - Ability to set up user functions for pre and post processing of the data?
-               - API for adding JS-functions to the onchange-event.
+               - Customized display of a field, possibly passing an array with code that should be displayed and then people can themselves put it together from PHP? (possible already?)
+               - Ability to set up user functions for pre and post processing of the data? (possible already?)
+               - API for adding JS-functions to the onchange-event. (possible already?)
                - Make STORAGE_FOLDERs a LIST of pages - not just one page (still the first page could be the default while other pages will be where stuff is selected from).
+               - Workspace-ReadOnly flag for fields
+                       Should be set for all fields which are used in where clauses in frontend. (Enables fields would candidate for example, but they must be handled otherwise since we WANT to be able to change those in new versions)
+                       - Generally for fields: $TCA[$table]['ctrl']['languageField'] and $TCA[$table]['ctrl']['transOrigPointerField']
+                       - field: pages_language_overlay:sys_language_uid
+                       - field: pages:doktype (used for selection many places!) - but then we cannot make mounts points etc! (?)
        - SELECT type:
                - Ability to see icon/image from record of selected value in the selector box.
                - IFRAME alternative for the selectorboxes where a HTML view can be shown. Possibly having an external script show the content which would be useful for display of tree-tables.
-               - Reflect possible tree-structure for records in Select/Items list
+               - Reflect possible tree-structure for records in Select/Items list.
                - a way to grant read for the selectors without displaying the storagefolder in the treeview?
-               - move one up / one down buttons for the list (also for GROUP element)
                - CHECK: "multiple" feature, single, sorted and non-sorted selections.
                - making copies of select fields etc - check that remapped records are OK treated (with foreign/neg_foreign + free string values)
                - Letting one selectorbox set another hidden fields value apart from its own? [USE: When selecting a template, that also sets the DS value! (Thus a template is always selected!)]
@@ -123,12 +168,14 @@ TCEforms:
                - BUG: itemsArrayProcFunc only active IF there is an array! Shouldn't it be in any case?
                - set the width of the selector field(s)
        - GROUP type:
-               - [file] allow the selection of files from the system to be added as REFERENCES, not copied! (Message-ID: <003f01c23503$8cdd69d0$55333bd4@comtech>, + notify "illuminatus")
+               - [file] FILE-REFERENCES: allow the selection of files from the system to be added as REFERENCES, not copies!
+                       - upload option to the folder specified in TCA
+               - Subfolders for uploads/ as well, detecting the first (#) a-z0-9 letters) (For large amounts of files!)
+                       - Storing files with "a3#FILENAME.jpg" which indicates a subdirectory.
                - In the thumbnail list add the Edit and view icons as in the good old days.
                - BUG: By the way, isn't there a bug in the listing of the thumbnails of records?
                - Nested records:
-                 - Group-fields of DB-type could be made to actually SHOW the records it contains in the very same form! Possibly with Add/Delete facilities.
-                 - See JH mail: Message-ID: <C018FF617C61AB4588D15494126A5C0F23E410@Soulman.hanno-kirchhoff.de>
+                 - Group-fields of DB-type could be made to actually SHOW the records it contains in the very same form! Possibly with Add/Delete facilities. (JH asked)
                - IFRAME alternative for Element Browser.
                - set the width of the selector field(s)
        - DISPLAY_CONDITIONS:
@@ -141,54 +188,64 @@ TCEforms:
        - CHECK: ###STORAGE_PID### incorrectly calculated?
 - DONE?: Support for label for main palette: (Rene: Message-Id: <200210011646.10346.r.fritz@colorcube.de>)
 
-Charset:
-- checking (for XML) if there is "character data" in a string?
-
 Element Browser:
 - Support for DAM
+- RTE API integration (rte_images + browselinks)
 - Support for browsing custom category-trees (passed by some PHP script)
 - Support for deleting files in the listing there.
-- Disable thumbnail option for faster display.
+- Disable thumbnail option for faster display. (Already done?)
 - Element Browser configurable a) without the page tree but hardcoded to specific PID, b) just default PID (possibly able to override from TSconfig)
 - Selecting files from other resource-fields of records (which the user can actually read) - maybe with the Element Browser, browsing for record, clicking it, seeing a list of files inside the record?)
 - Ability to insert images when their info page (larger thumbnail) is displayed. Maybe a small + (plus) icon would do. (Notify Patrick Roeder)
 - Some quick-lookup feature (like we have on TER)
 - Showing more than the title column for records listing and making it possible to sort by the columns.
+- BUG: fix bug when used as "wizard" for link fields!
+- Support realurl paths translation to IDs?
+       - Implementing a hook so "realurl" can intercept the "Edit page ID" field in the shortcut frame and allow people to paste in a URL from the website which will be analysed to find the page id from the URL
+       - Implementing a hook similar to this, but used in the RTE link selector box (browse_links.php) so a link to a page can be made in the same way. Such an interface will just link to the page if an ID could be found, otherwise tell that the URL din't have a page id associated with it.
+- Link selector: Disabling target box for selectors directly to HREf fields (DS case with templates...)
 
 Wizards:
 - Add wizard icon to TSconfig and Setup/Constants fields for immediate syntax highlighting (in popup window)
 - Add wizard icon to see/clean up FlexForm data? Convert language mode?
+- Wizard for editing FlexForm DS XML!
+
+Kickstarter:
+- Update kickstarter so new great options are not wastefully never known.
 
-Interface:
-- Showing in "frameset-modules" which submodule you are currently inside. And ability to change submodule in the rightmost frame anyways - maybe as a panel in top of the pages (must be cached so all submodules must not be loaded each time...)? (Message-ID: <3ADE655892793D499E2FBF623045AF4B54E9A4@dbwdfx2f.wdf.sap-ag.de>)
+Usability / Interface:
+- Review general backend logic
+- TCEform presentation
+       - How tables fields are currently organized for eg. pages, tt-content etc. and if Tabs should be used more for some of those (example "Standard" / "Advanced" pages)
+- Skin (WinXP skin, what difference would that heretic idea make?)
+- Showing in "frameset-modules" which submodule you are currently inside. And ability to change submodule in the rightmost frame anyways - maybe as a panel in top of the pages (must be cached so all submodules must not be loaded each time...)?
 - Ability to create another Main/sub module structure in the backend (Daniel H: Message-ID: <BAB9A920.E95D%daniel@typo3.com>)
        - Change order, level, title, icon.
        - Use User TSconfig... and allow someone to create an extension to visually create a TSconfig output
-       - See DHs mail: Message-ID: <mailman.1060763871.6396.typo3-metadev@lists.netfielders.de>
        - Links could be going directly to the function menus inside modules as well!
+- Review Skinning API:
+       - Better backend HTML?
+       - More consistent re-use of classes / icons?
 
 Localization:
-- Export/Import of "translation XML file" or spreadsheet:
-       - Will allow all translation of new and changed content to be done in ONE place, probably outside of TYPO3
-       - In TYPO3 tool for such a file format: Can also show diff-view like with ll-XML format.
-       - SOAP services(?)
-       - Contains fields similar to orig_hash and orig_text with values of translated content so diff can be shown
+[See "Localization workflow" below]
+
+Versioning/Workspaces:
+[See "Versioning/Workspaces" below]
 
 Context Sensitive Help (CSH):
 - Add multimedia?
-- Special Glossary Support?
 
 WEB main module/page tree:
-- Option: For a frameset module, register the ID per sub-module, not just globally (see JH mail: Message-ID: <C018FF617C61AB4588D15494126A5C0F1F67AB@Soulman.hanno-kirchhoff.de>)
+- Option: For a frameset module, register the ID per sub-module, not just globally (JH asked)
 
 Web>List:
 - Add "New" to the clickmenu of eg. "be_users" (non-sorted items) when you want to copy a user into the list.
 - Add email function where you can 0) send email to single records email field, 1) all records on the clipboard, 2) all emails in a list of shown records, 3) all records in the PID. By emailing you can select to receive a copy yourself. Backend user must have name/email configured as from/reply-to/return-path information. Mails can be sent Bcc,CC or seperately. Can be used for lightweight newsletter feature! Maybe implement through some API to the Web>List module.
 - Page-tree-stop: Click on red "+" brings forth some kind of browser (list of pages, browseable, Web>List module feature?)
-- Add flag to TCA/[interface] which keeps a table from being listed in the list module. Probably an option which allows the display for admin-users.
-- Check that permissions are respected for the buttons in the control-panel of the List module
+- Add flag to TCA/[interface] which keeps a table from being listed in the list module. Probably an option which allows the display for admin-users. (Already made?)
+- Check that permissions are respected for the buttons in the control-panel of the List module (including for workspaces)
 - Why is web>list slow on new typo3.org?
-- Page TSconfig option: Only to select the table-headers for display (with record count), and only the extended view will show the records inside.
 - Support for "grouping": - eg. tt_content elements are grouped by "column" + "language". This should be reflected in the LISTING order (before ordered by the "sorting" column) OR maybe in a hierarchical display?
 - Support for tree-tables (that can be browsed).
 - Support for a "tree-group" -> a chain of tables which are displayed in a tree since each table has a config for a parent field in a former table. (Eg. DS: brand -> domain -> product).
@@ -196,21 +253,16 @@ Web>List:
 - FlexForm tree view / editing:
        - When a record contains a FlexForm the web>List module could display the fields inside in a nice tree structure which one could expand/collapse! Then by clicking "edit" for a brand you get an interface where you can edit *that branch* of the flexform! Brilliant way to manage large structures inside of flexforms!
                - Can you picture it? That would be like expanding an XML document by a node-tree and add/edit/delete/rearrange any of the internal informational pieces!
-- Fikse copy/paste s�at list-module reloader (lser ogs�problemet med paste fra sidetr�t/foldertr�t?)
 
 File>List:
-- BUG: UNIX: "RW" flag looks only on the permissions for the USER - not the group. So even if PHP via the group of a file can delete it, it is reported that it cannot.
+- BUG: UNIX: "RW" flag looks only on the permissions for the USER - not the group. So even if PHP via the group of a file can delete it, it is reported that it cannot. (Already made?)
 - Adding possibility to show files recursively (more levels), filter on a file name, search file content
+- From click-menu: Access to index files with indexed-search / create a "Indexing configuration" record for that folder / Initiate indexing of the "Indexing Configuration" for folder
 
 History/Undo:
-- Must present a page/content element view, so a page with content elements can be restored as a whole
 - Undo must be able to restore attached files as well
 - Should be possible to disable for certain tables (can it be done already with TSconfig?)
 - Delete saved states (and save whole record content).
-- Need to implement the diff-feature for windows as well (that is; set configuration)
-
-LDAP support:
-- See "APPENDIX: LDAP"
 
 EM:
 - Display: review-flag + link to review - cannot be overridden?
@@ -218,7 +270,6 @@ EM:
 - Display: Better filtering, quicker listing
 - Feature: [suggested by robert] resolving of dependencies like in apt-get (Debian package manager). Necessary extensions can be downloaded and installed automatically (idea: create dummy extension which depends on several extensions and acts like a package of extensions)
 - Feature: EM suggest clear-cache af scripts?
-- Install: Select other repository URLS in selector box?
 - Install: Extensions which can point the import/export to a directory with import-files.
 - Install: Getting from TER only already installed extensions.
 - Install: Flag: "Import ext"; "Show non-secure extensions" (show ALL ext., not only reviewed ones)
@@ -228,26 +279,289 @@ EM:
 - BUG: EM-extMgm: caching af localconf + extTables configuration in ARRAY? Plus ?ndringer til API specs. (problem when those files includes classes etc... probably not possible)
 - BUG: Clear cache files should remove ALL "temp_CACHED_*" files in typo3conf/ (not just the current two)
 - BUG: Download of extensions (compressed...) will sometimes NOT get the same MD5 key after being saved (with any browser it seems) as shown at the download link. Origin of error not know. Please help if you encounter the problem.
-- DOC: "Extension API" manual.sxw!
-- Check mailbox for more... ?
-- Related: The KickStarter Wizard, in particular a) cleaner code output, b) merging updates.
 
 The REGEX-{} problem:
 - BUG: Regexs; "Warning: Unmatched \{ in /home/sites/site14/typo3_src-3.5b3/typo3/mod/tools/em/index.php on line 1983" which is a ereg with { WITHOUT preceeding slash! (Message-ID: <003c01c275aa$c0c60c10$e3a1a33e@pentiumriv4v9a>, Message-ID: <20030729082437.79900.qmail@web11305.mail.yahoo.com>)
        - Should be fixed by "[{]..." instead!
 
-Install/Servers:
-- FIX: To get PHP to handle PATH_INFO and PATH_TRANSLATED information correctly with this setup, the php parser should be compiled with the --enable-discard-path configure option.
-- FIX: The "php_sapi_name()=="cgi"||php_sapi_name()=="isapi"" problems (Message-ID: <ADEEJCHPNMOFKAAOJJKKCEKMCAAA.martin.kokes@sitewell.cz>, Message-ID: <200304071146520757.0097D495@smtp.worldonline.dk>, Message-ID: <BACDA028.F428%daniel@typo3.com>)
-- CHECK: Security: Can HTTP_SERVER_VARS be overridden from URL if global vars are enabled???
-- TYPO3_PORT bug (Message-ID: <005f01c2df3f$4006db00$0100a8c0@knoell>)
-
 Filepermissions of source:
 - Test that these permissions work OK:
   - chmod 555 typo3_src/ -R
   - cd typo3_src/typo3/
   - chmod 755 ext/
 
+SQLengine (t3lib_sqlengine):
+- Finish t3lib_sqlengine
+  - Test and compare against MySQL lookups
+  - XMLdb: Lave table locks
+  - Open Office / CSV tests (proof-of-concept)
+
+
+*******************************
+Versioning/Workspaces:
+*******************************
+
+- "They are also the only ones who can eventually publish the workspace content (except "admin" users)."
+- "If set, records from tables where versioning is not enabled can still be edited "live" inside the workspace."
+- "Admin user is the only one who can publish": Add that field, add flag in workspace table that "publish workspace gradually"
+       - "t3ver_stage" (only draft content in custom workspace): 0 = being edited (editing possible for members), 1 = pending for review (edit possible for reviewer), 2 = ready for publish (editing possible for admin), -1 = rejected, ready for editing (using sys-log for notice)
+
+Next steps for workspaces:
+- Overlays implemented in backend
+- Permissions / UIDs reflected in buttons and clickmenus.
+- Frontend previews done
+
+- Clean-up of TCEmain/logging/permissions [in particular for versioning/workspaces!]
+       - Perform as much logic and re-mapping in tcemain as possible so applications doesn't have to (for instance re-mapping of source and target uids in paste operations.)
+
+
+Testing:
+       t3lib_BEfunc::getFlexFormDS(), workspaceOL/fixVersioningPid ??
+       Page and (User) TSconfig?
+       Mounts points and versionized branches?
+       TemplateRecord previews?
+       - Apply versioning to other tables than the current.
+       - check page trees around for display of color backgrounds...
+       - check editing icons, overlays in various modules.
+       - Workspace access to Filelist module ?? (Should be OK)
+       - copy/cut/paste between versionized branches and other places (new pages).
+       - delete something twice?
+       template::getVersionSelector()
+       - overview of permissions handling?
+       - samspil med version module?
+
+Dassault:
+       - Change "class.user_3dsplm_fakepage.php"
+
+Manual:
+- Overview
+       - Concept:
+               - Workspace is Container for draft versions => Solves all issues of previewing, managing versions, overviews, comparisons etc.
+               - All is draft, consequence; a) works only with versionizable records, b) no files can be managed in fileadmin (unless exception accepted for custom workspaces)! => Safe playground
+               - Must work transparently for user => No training needed.
+               - THE implementation of versioning!
+       - state, not process!
+       - Define:
+               - lifecycle
+               - workspace
+               - publish/swap  workspace
+               - versioning modes: element, page, branch
+       - Modes:
+               - Live mode (online):
+                       - Editing live content
+                       - Like TYPO3 always was, however users can be excluded from online mode now.
+               - Draft mode (offline):
+                       - Editing draft versions of content
+                       - All editors can publish individual content or whole workspace at any time
+                       - Usage: AdHoc needs for trusted editors etc.
+               - Custom mode:
+                       - Editing draft versions of content
+                       - Workspace owner is only person to publish (highest review authority) and edit workspace properties
+                       - Workspace options: filemounts, reviewers, publishing time, Db mount
+                       - Usage: For specific projects on a sitebranch, for simple review-cycle needs etc.
+- Using Workspaces
+       - Transparency in action
+       - Colors for feedback
+       - What is "[#VEP#]" in the path (visually)
+       - Workspace manager
+       - Setting up users (draft/live etc)
+               - "options.pageTree.onlineWorkspaceInfo"
+       - Preview in frontend by workspace ID
+- API
+       Intro:
+               - "versioningWS" instead of "versioning" in TCA
+                       workspace 0 = online (live)
+                       workspace -1 = offline (draft)
+                       workspace > 0 = custom (projects)
+                       workspace -99 = none selected at all.
+                       [-99 is ERROR (none available), -1 is offline, 0 is online, >0 is custom workspaces.]
+       API:
+               Frontend:
+                       Preview issues:
+                               - Challenge: Previewing elements which are disabled by enableFields in the online version but not necessarily in offline versions! Also, new records with "t3ver_state" set to 1 (placeholder" must be filtered out as well - but not when previewed!
+                               - Solution:
+                                       - Disable enableFields()/->where_del_hidden and check for them in versionOL on input record!
+                               - Implementation:
+                                       - Any place where enableFields() are not used for selecting in frontend, the t3ver_state==1 flag must be checked in online display - otherwise placeholder records might be selected!
+                                       ->versionOL(): Check if record has enable-fields that prevents display and if so, unset!
+                                       ->fixVersioningPid(): For tracing back (getRootLine())
+                                       ->getWorkspaceVersionOfRecord()
+                               - Scenarios for preview that is not planned to be implemented:
+                                       - Searching will probably never work in offline mode: All SQL selection happens on online records and the overlay is applied only after.
+                                       - It is impossible to preview "count(*)" selections since we would have to traverse all records and pass them through versionOL() before we could count on the result!
+                                       - In tslib_fe::getPageShortcut() sys_page->getMenu() is called with an additional WHERE clause which will not respect if those fields are changed for a future version. This could be the case other places where getmenu() is used (but a search shows it is not a big problem). In this case we will for now accept that a wrong shortcut destination can be experienced during previews.
+                                       - Whenever a SQL query is made which also selects on other fields than enableFields, THEN it is out of control to preview. See the example described above (tslib_fe::getPageShortcut)
+               Backend modules:
+                       $MCONF['workspaces'] = online,offline,custom
+               Backend, overlay/checking:
+                       t3lib_BEfunc::workspaceOL()
+                       t3lib_BEfunc::fixVersioningPid()
+                       t3lib_BEfunc::isPidInVersionizedBranch
+                       t3lib_BEfunc::getWorkspaceVersionOfRecord
+                       t3lib_BEfunc::selectVersionsOfRecord()
+
+                       BE_USER:
+                       ->workspaceEditState
+                       ->workspaceTestPID
+                       ->workspaceInit()
+                       ->checkWorkspace()
+                       ->setWorkspace()
+                       ->setWorkspacePreview()
+                       ->getDefaultWorkspace()
+
+View/Preview:
+- Frontend:
+       - ONLINE PREVIEW: Versionized pages should be previewed just by their UID (which will select the offline version!) - only in "Live" space, disabled at the moment inside tslib_fe!
+       OK - Workspace is used to set frontend in preview mode and display versions
+       ?!      - TEST: Mounts points and versionized branches?
+       ?       - tslib_content::getPidList(); TEST Mount points / Use offline UID values for "page" swapmodes; This is probably more natural for preview cases.
+       ?       - versionOL() implementations missing:
+                       - tslib_pibase::pi_getCategoryTableContents()
+                       - tslib_content::checkPidArray()
+                       - tslib_content::checkPid()
+                       - tslib_content::exec_mm_query()/-_uidList() [These seems NOT to be used anymore!]
+       - Difficult frontend previews:
+               - All fields selected upon in frontend:
+                       - $TCA[$table]['ctrl']['languageField'] and $TCA[$table]['ctrl']['transOrigPointerField']
+                       - field: pages_language_overlay:sys_language_uid
+                       - field: pages:doktype (used for selection many places!) - but then we cannot make mounts points etc! (?)
+               - Suggested solution:
+                       - Setting a workspace-readonly flag for such values!
+                       - However,
+                               - menu previews are bypassing the problem already,
+                               - page shortcut has trouble but is known,
+                               - mount points will not be possible to preview (?)
+                               - For new translations we might have the problem, for existing translations probably not since it is unlikely that the fields $TCA[$table]['ctrl']['languageField'] and $TCA[$table]['ctrl']['transOrigPointerField'] at changed later!
+                       - For new records, maybe the placeholder record is updated along with offline version? (At least for non-file fields). This would solve the problem of build translations in a workspace and also offer the preview as working!
+
+       - In tslib_fe, this->contentPid is set to "_ORIG_UID" when a versionized page have swapmode set to "0". However this is not completely correct to do: Strictly the "_ORIG_UID" value should be used for tables where "versioning_followPages" is set and for others not. However this is a working quick-fix to display content elements at least!
+               t3lib_page::getPageOverlay() - because pages_language_overlay records have "versioning_followPages" set this should be observed when selecting language overlay records. But should it be hardcoded or something better?
+- Backend:
+       - Page TSconfig, Access evaluation, TCEmain/ TCEforms, Flexforms etc: When to fixVersioningPid() / versionOL()?
+       - Quick Edit?
+
+Workspace Manager TODO:
+- Details view for versions
+       - versions inside branch?
+       - display change log for specific element
+       - warning if page is worked on in other workspace
+       - preview links on items
+       - Difference view in online mode as well.
+       - Publishing must be possible ONLY if Online mode is available for a user?
+- Workspace list
+       - Admin features
+       - Implement the disabling of swap-mode on publish links when that is supported in the core (which I think it should be first...?)
+- TEMPORARY? Disabled backend reloading when changing workspace.
+- Click menu implementation of: Diff-view, raise level / publish. => Guess this is what the versioning element should hold!
+
+Workflows:
+- Workflows can regard a whole workspace!
+- Special permission required for:
+       - Publishing workspace / Setting publishing time
+       - Freezing/unfreezing workspace
+
+Swapping:
+       - (Support for) swapping using temporary file (instead of using negative ID)
+       - When swapping; Check "unique" fields (like pages.alias) etc.
+       - permissions?
+       - Problem: When a page+content or branch is versionized, the records that the user is NOT allowed to create/edit are NOT versionized. That mean that records are swapped out that should not be! Imagine if a user has no access to page language overlay but creates a new page+content. Then only page and tt_content is versionized but when swapped the page_language_overlay records are lost since none exist in the versionized page!
+
+Various Notes:
+- Pages-versioning and the impact of NOT swapping tt_content element uids:
+       - Loose anchor-points, manually made (could be hack-fixed by some intelligent copying tracking)
+       - TemplaVoila references to elements from other pages (will break, however bad practice to reference elements not in some sort of central library which will NEVER be page-versioned anyways)
+       - Insert-records could potentially do the same
+       - Impact assesment: Low.
+       - Clean-up module (in templavoila?) could also track such things
+       - Problems for non-templavoila sites would be low.
+    - What about a page alias?
+
+- Trunk/Branch:
+       - Requirement: Intelligent swapping of "sub-element" ids that CAN be traced back to the original!
+
+- MySQL:
+       - 4.0.14 fails with -1 uid! (4.0.18 is ok eg.)
+       - Correction possible:
+               -> ALTER TABLE jlajlajla AUTO_INCREMENT = 123
+       - Problems with other RDBMS because ID values cannot be changed at all!
+
+Preview modes with no BE login; For single pages, for whole workspace?
+- Can bypass hidden pages, fe_groups, set workspace
+- Works for certain timespan
+- Sets cookie
+- Respects permissions of backend users issuing that permission!?
+
+
+
+
+
+*************************
+Localization workflow:
+*************************
+- Export Flow:
+       - Select language
+       - Select tree levels / exclude individual pages/branches from translation / Way to exclude specific elements from localization
+               - We can imagine having translation configuration records in branches defining some presets that export files are related to: Thus we can ensure the same settings are used for both import and export. Also they could contains diff-info for flexforms!
+       - Export mode:
+               - Export needs only (updates/new)
+                       - Options (depending on file format):
+                               - Include other data for view of context
+                               - Include any diff-source data? (alternatively based on previously written file in XML/ser. array format!)
+                               - Include current translation or not (if not, if would be because of TRADOS based situations where a previous file exists to compare a new file with and a file with only the translation is returned.)
+               - each page in single file OR all pages in one file
+       - Export Formats:
+               - Generic XML/ser.array (for TYPO3 translation module which will be made for this purpose: Contains data, existing translation, diff-source, timestamps and hashes, like locallang-XML...)
+                       - Can contain meta data so their starting point and configuration can be re-loaded from a location on the filesystem to where they can also be re-written!!!
+               - HTML (for TRADOS etc.)
+               - XLS/SXC (for excel translation)
+               - SXW / HTML (for OO Writer translation: Put into a table with columns: id/data/translation/colored-diff-view/OK-sign-off
+               - Create workflow items to work from!
+- Import Flow:
+       - Select file / upload
+               - Formats:
+                       - ANY format is converted into internal standard array
+               - Create new elements via localization API in tcemain (to have l10n_mode per. field respected!)
+               - Generate $data array for tcemain from file IDs
+                       - Options:
+                               - Can deselect certain parts manually
+                               - If original has changed, automatically warn/hide/deselect?
+                               - If translation matches current already (if a previous import was done), automatically hidden/deselect/notify? (preference can depend on type of file format)
+- Analyse a page:
+       - Pages:
+               - If no Page Translation Overlay: New
+               - If Page Translation Overlay: Update
+               (Maybe use hidden page translation overlays to identify pages picked for localization? This would work pretty fine I think.)
+       - Records in general:
+               - if [ctrl][languageField] AND [ctrl][transOrigPointerField] is set, select all records with 'default' language (ignoring 'ALL'/-1) and for each:
+                       - if no translation found: new
+                       - if translation found: update
+                       - NOTICE: translations can be found in external tables (like pages_language_overlay)
+               - selected by sorting order according to [ctrl]
+               - TemplaVoila: Here a special selection could apply for tt_content elements based on references in the DS. That would leave out all non-placed content elements. But in fact I rather say that we should NOT do it this way and instead clear out such elements so a general selection of the elements from the page is enough. Anyway, it should be possible though.
+       - Field selection:
+               - Option: Work only on fields where "l10n_cat" is "text" or "image" (selected!). Alternatively, use "l10n_mode" to filter as default (do not show "exclude" fields for instance!)
+       - ERROR reporting:
+               - If two or more records are claiming to be translations of another (for pages_language_overlay, tt_content etc.)
+- Limitations:
+       - Cannot work with content which has no parent/child relationship. This is the case for:
+               - Old style column based localization
+               - FlexForm fields with <langChildren> = 0
+- Translation module:
+       - Based on concepts from llxmltranslate and supporting the generic XML fileformat translations can be exported in.
+
+
+- Localization document!!!
+- Needs:
+       - Clean-up for Unused TemplaVoila elements on a page!
+               -> Would need a reference index available.
+
+
+
+
+
+
+
+
 
 
 **************************
@@ -256,31 +570,46 @@ DOCUMENTATION TODO list
 Extensions:
 - Document how to make "static_template_files" in an extension (Example: How to make a standard templates in extensions to TYPO3) => Rene Fritz doing that?
 
+About Versioning ("Inside TYPO3")
+- Versions can be done on element, page or branch level
+       - In any case a pure copy of the element/branch is produced
+       - "element": Copy of element (pages, tt_content, pages_lang_overlay, sys_template)
+       - "page": Copy of element + tables configured "versioning_followPages" (tt_content, pages_lang_overlay)
+       - "branch": COMPLETE copy of the branch to predefined level.
+- About unique fields:
+       - They are NOT enforced in versionizing - this may be a problem when BRANCHES are exchanged because currently there is no check done if a value inside a versionized branch collides with values in the main branch!
+       - 'AND pid>=0' should be used to avoid problems!
+       - In tcemain::getUnique() there already is a check if "pid>=0"
+- Backend user access to elements is based on the access restrictions (editing) for the official element. For pages; they carry their own access permissions with them. Notice that page permissions are NOT changed to the user making the new version!!!
 
+About Charsets ("Inside TYPO3")
+       In TYPO3s backend charsets used have traditionally been the charset of the backend user language. This is of course a big problem (when other than western european languages are involved) since the encoding of content is thus depending on the charset of the user and not of the system
+       From TYPO3 3.6.0 you can define a global charset for the whole database. This can be any local charset like iso-8859-1 or windows-1250. But for multilingual sites it is recommended to use utf-8 since that can represent all languages.
+       You set the global charset in a localconf file like this: $TYPO3_CONF_VARS["BE"]["forceCharset"] = "utf-8";
 
+       Here are a few notes:
+       - JavaScript functions to convert cases to upper/lower seemed to work with all letters from any charset. In the old days this was not the case and thus functions in eg. "jsfunc.evalfield.js" compensated. This is now disabled since it is apparently not needed anymore.
+       - When one enters eg. danish letters in a form when the russian charset is used, these letters are converted to HTML entities, eg. "&#248;" - this is NOT changed. The philosophy is that IF anyone needs to use characters outside the range of the used backend character set he should use UTF-8 instead. Theoretically we COULD allow the entities to be shown correctly but we dont for now. Better use the right charset.
 
 
-*****************
-PHP issues
-*****************
-Generally: TYPO3 works with PHP5. But...:
-- UTF-8 strings to freetype doesn't work! Renders box instead.
-- array_merge must always have arrays as arguments. When this problem is found in TYPO3 it is regarded a TYPO3 bug and we fix it.
-- Errors regarding treating strings as arrays: Normally, just check if the variable is an array first.
-       - Details: Non-existing indexes is not a problem if the variable is unset - only if it is another type (eg. string). This means we can normally just check if the first index is an array and it will work: is (is_array($a) && $a[key1][key2][key3]) ...
+About System Extension:
+- Explain that they are the only ones distributed with TYPO3 core.
 
+Write:
+- "css_styled_content" documentation
+- Extension Programming Tutorials: What is status??
 
+Review:
+- doc_core_tstemplates (badly needs it!), doc_core_tsbyex, doc_tut_frontend, doc_tut_n1/n2/n3
+- TSref overhaul
+- "doc_tut_backend" revised/updated.
 
-*****************
-NOTES
-*****************
-- Undo/Redo behaviour strange?  => This bug report turned out to be about frontend caching: If you saved a value and quickly after (probably within a second) pressed "Undo" button, then the (browser)cached content would be shown. It was obvious because the sys_history table WAS updated, only the form wasnt.
-
-
+Remove:
+- doc_core_usermgm : DELETE THIS!
 
 
 ******************************************
-APPENDIX 1: CLEANING UP FOR TYPO3 3.6.0
+APPENDIX: CLEANING UP FOR TYPO3 3.6.0
 ******************************************
 Cleaning for 3.6 involves:
 - XHTML transitional compliance
@@ -423,8 +752,8 @@ XQCR: t3lib/class.t3lib_recordlist.php
 -QCR: t3lib/class.t3lib_stdgraphic.php
 XQCR: t3lib/class.t3lib_superadmin.php
 -QC-: t3lib/class.t3lib_svbase.php
--QCR: t3lib/class.t3lib_tceforms.php                   [Kasper]
-               t3lib/class.t3lib_tcemain.php                   [Kasper]
+-QCR: t3lib/class.t3lib_tceforms.php                   [Kasper - 4.0]
+               t3lib/class.t3lib_tcemain.php                   [Kasper - 4.0]
 XQCR: t3lib/class.t3lib_timetrack.php
 -QCR: t3lib/class.t3lib_transferdata.php
 XQCR: t3lib/class.t3lib_treeview.php
@@ -486,9 +815,9 @@ XQCR: layout/db_new_content_el.php
 
 typo3/sysext/___________________________________________:
 OK             aboutmodules/
-               belog                   (2 / 500)
+               belog                   (2 / 500) [Kasper - 4.0]
                        - Needs a vision! Couldn't the Log be more useful?
-               beuser                  (1 / 1300)
+               beuser                  (1 / 1300) [Kasper - 4.0]
                        - Add option to Create backend users there! (backend users, groups, filemounts)
 OK             cms/
 OK             context_help/
@@ -497,15 +826,12 @@ OK                context_help/
 XQCR:  extra_page_cm_options/
 XQCR:  func_wizards/
 XQC-:  impexp
-               indexed_search          (4/3500)
-                       - Templates?
-                       - Speedoptimizations?
-                       - Kasper has some objections regarding complex code parts.
+XQC-:  indexed_search
 XQCR   info_pagetsconfig/
                install/                                        [ingmar]
                        - Clean-up of the Install Tool in general!
 OK             lang/
-               lowlevel                        (2/800)
+               lowlevel                        (2/800) [Kasper - 4.0]
                        - Extend support and finish it with the efforts soon to be done for TCEmain.
 OK             setup/
 OK             sv/
@@ -516,7 +842,7 @@ OK          sys_note
                taskcenter                      (4/400) [Julle]
 OK             tsconfig_help
                        - Needs maintenance plan
-               version                         [Kasper]
+               version                         [Kasper - 4.0]
                        - (See Kaspers personal todo and Appendix about versioning in this document)
                viewpage                        (2/200)
 XQRC:  wizard_crpages/
@@ -534,7 +860,7 @@ For all extensions (even those approved):
 
 
 *******************
-APPENDIX 2: XHTML
+APPENDIX: XHTML / XSS
 *******************
 Overview of implications before implementation:
 - UTF-8 encoding is in fact expected by XML! So the real charset must be set
@@ -564,146 +890,14 @@ Practical steps for creating XHTML compliance:
 ([[:space:]]+)(class|face|hspace|vspace|rowspan|bgcolor|src|colspan|align|color|valign|border|width|height|cellpadding|cellspacing)=([^[:space:]>"']+)
 ... and replace with: \1\2="\3"
 
-
-
-
-
-*******************
-APPENDIX 2: Debugging / varoius
-*******************
-
+-----------
 Teststring for XSS bugs and SQL injection:
        >><b><i>asdf</i></b>-\-\\-\"-\'-"-'-
 
-debug_backtrace() - nice function for debug-output.
-
-
-*****************
-APPENDIX: Versioning thoughts:
-Authors: Julle and Kasper.
-*****************
-
-- Versioning (for single elements including single "pages" record) is based on
-       OK - ONE element having an official position in the TYPO3 page tree, thus holding the official "uid" of the element! (If this element was deleted from the system, so are all versions of that element!)
-       OK - All versions of this one element being a) at pid "-1" and b) a field "real_id" pointing to the official UID
-       OK - Pages-versioning: For all elements belonging to a version of a page; They are just copied and has no official new version or binding back to whatever element they came from. They just came along. And in fact, they could even have their own version history for them selves!
-       ? - Backend user access to elements is based on the access restrictions for the official element. THis must be implemented on core level.
-
-- Preview in frontend:
-  OK - Pages can be previewed just by their UID (which will select the offline version!)
-  OK - For other elements, sending ADMCMD_vPrev array
-  - Selector in the AdminPanel selects:
-       - Version of page for current ID?
-       - TAG (across many records)
-
-- Tagging:
-       - Setting tags across records for mass-swapping:
-               - A tag can only be set for ONE version of a record
-               - There is a default tag used when new versions are created called "draft". Users can create own tags and select one of those instead.
-               - Implicitly the published version is tagged "published"
-               - When a tag is swapped into published, the records swapped into archive will get a new tag to remind us that they were swapped out instead of that TAG. Something like "TAG-archive". Only done when TAG-swapping is used, not for spontaneous swapping.
-               - We might set states like "draft (never published, many), published (online, only 1), archive  (has been published, many) - but what significance does that carry?
-
-- Permission setting:
-       - That NO record with PID!=-1 OR PID!=-1 in rootline can be edited or otherwise! This will effectively LOCK every single record capable of versioning in the live tree!
-               Enabled for tables with:
-               - versioning enabled
-               - a certain extra flag set in [ctrl] (eg. "versioning_freezeOnline"
-               - Globally set with a flag in TYPO3_CONF_VARS (so we can build the first version of the site)
-               - "admin" users can circumvent it.
-
-- Swapping versions:
-  OK - clear-cache actions when swapping?
-  OK - Swapping might need to exclude fields like "sorting" etc. Others could be imagined.
-  OK - copies:
-  OK - Swapping should consider if a PAGE record should be swapped record-only OR including its content!!
-  - Swapping pages (pids) should consider that some records might be left inside a versionized branch. Question is; Should ALL records swap pids, not only the versioning_followPages ones?
-  - TODO: When swapping; Check "unique" fields (like pages.alias) etc.
-  - Swap by TAG (across many records)
-
-- Trunk/Branch:
-    OK - Create version of single page (as above)
-       OK - Create version of page branch (1-... levels)
-               OK (API) - Either create version of EACH page individually (like tagging in CVS)
-               OK (API) - Or create single-point-of-reference so that pages INSIDE can be swapped, deleted and created (just like content elements can)
-                       - Requirement: Intelligent swapping of "sub-element" ids that CAN be traced back to the original!
-
-- Backend:
-  OK - In list-module we might display a) an icon to a version selector (where diff-ing could be done, swapping performed etc.), b) show archive versions as children in the listing.
-  OK - In Page module + TemplaVoila page module: There will be a version selector implemented so users can switch around between versions.
-
-
-- Pages-versioning and the impact of NOT swapping tt_content element uids:
-       - Loose anchor-points, manually made (could be hack-fixed by some intelligent copying tracking)
-       - TemplaVoila references to elements from other pages (will break, however bad practice to reference elements not in some sort of central library which will NEVER be page-versioned anyways)
-       - Insert-records could potentially do the same
-       - Impact assesment: Low.
-       - Clean-up module (in templavoila?) could also track such things
-       - Problems for non-templavoila sites would be low.
-    - What about a page alias?
-
-
-
-
-
-
-
-
-******************
-APPENDIX: Charsets
-******************
-In TYPO3s backend charsets used have traditionally been the charset of the backend user language. This is of course a big problem (when other than western european languages are involved) since the encoding of content is thus depending on the charset of the user and not of the system
-From TYPO3 3.6.0 you can define a global charset for the whole database. This can be any local charset like iso-8859-1 or windows-1250. But for multilingual sites it is recommended to use utf-8 since that can represent all languages.
-You set the global charset in a localconf file like this: $TYPO3_CONF_VARS["BE"]["forceCharset"] = "utf-8";
-
-Here are a few notes:
-- JavaScript functions to convert cases to upper/lower seemed to work with all letters from any charset. In the old days this was not the case and thus functions in eg. "jsfunc.evalfield.js" compensated. This is now disabled since it is apparently not needed anymore.
-- PHP Upper/Lowercase - not tested.
-- When one enters eg. danish letters in a form when the russian charset is used, these letters are converted to HTML entities, eg. "&#248;" - this is NOT changed. The philosophy is that IF anyone needs to use characters outside the range of the used backend character set he should use UTF-8 instead. Theoretically we COULD allow the entities to be shown correctly but we dont for now. Better use the right charset.
-
-
-
-******************
-APPENDIX: LDAP
-******************
-- hash of base-dn skal v?re cleaned op. M?ske prefixe usernames med 10-char hash af base-dn.
-- Moduler som "User Admin" og andre steder, hvor "usergroups" feltet benyttes skal sl? det op i LDAP uden authentication. -> Faktisk er det IKKE kun usergroups men ALLE felter, som kan mappes!!!
-- Ved record creation: LDAP default group.
-
-? Getting info like usergroups, email, name?
-? Case-sensitivity of the DN in general?
-? DN entering..
-! MD5-hashed passwords
-
-1) AUTO -DN : Array of DN's, searched in order.
-2) Select dn: User selects the DN he is from.
---------------------------
-So we are looking at two scenarios:
-1) fe_/be_user records are automatically created when a LDAP authenticated user loggs in. Configurable is: Where it applies (fe/be) and if any additional LDAP info we can get should be mapped to MySQL records (like name, email, address or user-groups uid's)
-2) fe_/be_user records basically is the same as before (they hold a reference to LDAP user) and authentication is the same, BUT in this case fe_/be_ users are created manually, maybe using a tool of some sort which can look up the whole list of users in LDAP and allow the T3 admin to check off which users to make references to (this would be "Batch create").
-3) Mapping of ONE typo3 user to MANY LDAP users...
 
-- Also have the possibility of local users: Thus 1) FIRST a lookup is done in LDAP, 2) THEN if this fails we look in the local mysql table. (Well, this solution is straight forward since a user must ALWAYS have a record in the local MySQL table...)
-
-- Make API so that other authentication solutions than LDAP can be used (eg. another MySQL table!)  [See Rene Fritz's prototype work with services...]
-
-
-Also see:
-- [Kasper] "LDAP" folder in Mailbox
-
-
-********************
-APPENDIX: DBAL (moved to TODO.txt of extension "dbal")
-********************
-
-
-
-**********************
+****************
 APPENDIX: LPE
-*********************
-Also see:
-- [Kasper] "LPE" folder in Mailbox
-
+****************
 Syncronization (JH thoughts, general LPE):
 DB -> DB (1):
 - Production environment, which can dump configured set of tables to live server database and back. This is controlled from Production env.
@@ -737,23 +931,10 @@ Create an extension which syncronizes a set of tables to/from another TYPO3 inst
 _____________________________________
 Static publishing ("staticpub" extension)
 [2/2005: Today, a reverse proxy (using cache control) is a better solution than static publishing if you want to speed up a TYPO3 site. Therefore static publishing is a concept mostly interesting if you want to export a TYPO3 site as static files to an ordinary webhoster.]
-- Writes static file (automatically) IF simulateStaticDocument uses HTML / Speaking URLs and allows caching of page
-       - root of the publishing dir MUST be hardcoded in TYPO3_CONF_VARS etc.; The extension has full power inside of this dir!
-       - Support for both speaking URLs (hierarchy of directories) and regular simulate static document types (flat dir)
-       - Using mod_rewrite to access static versions of documents.
-               - Checks existence of files
-               - Can bypass GET/QUERY string and POST requests!
-       - File location is tracked in a table tied to page-cache table uids - thus making a flush very easy
-       - File write should probably happen together with inserting cached version in database (system hook)
-               - Resource files on the page can optionally be written to a sub-dir of the publishing dir.
-- setting a "config.disableStaticCreation = 1" flag (in TS template) can disable it (for conditions situations)
-- Also registeres: a) resources on the page (images/stylesheets), b) GET parameters from M5/B6 encryption. (not used yet!)
-- Publishing can be done by remote-client requests (default) or using the general crawler (for re-caching pages)
-- Web>Info module "Static publishing": overview showing all files and which pages they are related to, possible "lost files" (those not registered in database) and "missing files" (in the database but not there).
-- To create new versions doesn't have to REMOVE the existing! Just overwrite!
-
-
-******************************
+- The extension "staticpub" has now been made for this purpose.
+
+
+*****************************
 APPENDIX: Image Processing
 *****************************
 Generally we want:
@@ -790,19 +971,21 @@ Also see:
 - [Kasper] "ImageManipulation" folder in Mailbox
 
 
-******************************
-APPENDIX: Idea about "Roles"
-******************************
-This is a few ideas about adding roles to the permission concept of TYPO3:
-- There could be, say, 4 default roles:  author, editor, administrator, developer
-- Users can be assigned "membership" of a role (basically a "role" is like a hardcoded "user-group"?)
-- Like you can configure database fields in TCA to be an "excludeField" you could also configure which ROLES can edit the field.
-- Possibly each role could assign membership of some groups.
+
+*****************
+APPENDIX: PHP5 issues
+*****************
+Generally: TYPO3 works with PHP5. But...:
+- UTF-8 strings to freetype doesn't work! Renders box instead.
+- array_merge must always have arrays as arguments. When this problem is found in TYPO3 it is regarded a TYPO3 bug and we fix it.
+- Errors regarding treating strings as arrays: Normally, just check if the variable is an array first.
+       - Details: Non-existing indexes is not a problem if the variable is unset - only if it is another type (eg. string). This means we can normally just check if the first index is an array and it will work: is (is_array($a) && $a[key1][key2][key3]) ...
 
 
-*************************************
+
+***************************************
 APPENDIX: Various ideas for extensions
-*************************************
+***************************************
 EMAIL publication:
 - People can publish stuff by sending email to certain adresse piping the content into database.
 - This could also be upload of files, eg. a word document to a place in fileadmin/ (such a document could contain information inside which was displayed on the website).
@@ -811,15 +994,8 @@ EMAIL publication:
 IMPORT WEBSITE:
 - Import external website! (Rene's extension). Includes some crawler feature (locally og external url)
 
-SITE-CRAWLER:
-- A crawler which crawls either local or external site, invoked from a) backend or b) cron-script.
-- Used for 1) Indexed Search, 2) External website import, 3) Just walking through a site for indexing/caching all pages.
-- Trying to define a sitemap/menu structure + find "content" on page
-  - maybe with some kind of "hint" facility to tell what html-elements wraps content or maybe for each page visually pick out the content area: OR this could be done by the TemplaVoila tool?
-
 BACKEND TOOLS:
 - Global search and replace of records (Rene F?)
-- Export the complete typo3 site/database, in a big file like mycompletesite.t3d
 
 Repeated intervals extension:
 - Cron-job which alters the start/end times according to some schedule.
@@ -876,58 +1052,55 @@ Bugs, considerations, notes
 - many files in typo3temp/ slows down processing. Eg. a image resize with 33.000 files in typo3temp/ took 3 seconds where it would take 40 ms when the folder is clean. (on linux)
 
 
-**************************************
-Innovation, brainstorming for future
-**************************************
-- TSconfig defined through FlexForms?
-- Drop tt_content for content rendering and let extensions be the sole source of new content element types?
-- Check sitecore ideas for adding new fields etc.
-- Backend for PDAs/Lynx
-
 
 *********************************
 Translation of Backend
 *********************************
-Overview of missing translations. (UPDATED 18/11 after major change to ll-XML and csh_* language packs)
+Overview of missing translations. (1547 normal core labels, updated 22/5 2005 before release of TYPO3 3.8.0)
 Numbers are new labels needing translation (changed labels are not measured)
 
-- dk [Danish]          55
-- de [German]          9
-- no [Norwegian]       57
-- it [Italian]         9
-- fr [French]          36
-- es [Spanish]         63
-- nl [Dutch]           9
-- cz [Czech]           9
-- pl [Polish]          9
-- si [Slovenian]       90
-- fi [Finnish]         9
-- tr [Turkish]         9
-- se [Swedish]         9
-- pt [Portuguese]      136
-- ru [Russian]         79
-- ro [Romanian]                74
-- ch [Chinese (Simpl)] 282
-- sk [Slovak]          188
-- lt [Lithuanian]      142
-- is [Icelandic]       624
-- hr [Croatian]                121
-- hu [Hungarian]       9
-- gl [Greenlandic]     1031
-- th [Thai]                    141
-- gr [Greek]           1262
-- hk [Chinese (Trad)]  168
-- eu [Basque]          938
-- bg [Bulgarian]       319
-- br [Brazilian Portuguese]    15
-- et [Estonian]                243
-- ar [Arabic]          691
-- he [Hebrew]          153
-- ua [Ukrainian]       662
-- lv [Latvian]         307
-- jp [Japanese]                1261
-- vn [Vietnamese]      1245
-- ca [Catalan]         1262
-- ba [Bosnian]         141
-- kr [Korean]          1262
+- dk [Danish]          0
+- de [German]          1
+- no [Norwegian]       0
+- it [Italian]         0
+- fr [French]          134
+- es [Spanish]         0
+- nl [Dutch]           1
+- cz [Czech]           202
+- pl [Polish]          4
+- si [Slovenian]       304
+- fi [Finnish]         0
+- tr [Turkish]         254
+- se [Swedish]         0
+- pt [Portuguese]      421
+- ru [Russian]         235
+- ro [Romanian]                358
+- ch [Chinese (Simpl)] 0
+- sk [Slovak]          113
+- lt [Lithuanian]      332
+- is [Icelandic]       904
+- hr [Croatian]                0
+- hu [Hungarian]       1
+- gl [Greenlandic]     1316
+- th [Thai]                    426
+- gr [Greek]           1547
+- hk [Chinese (Trad)]  3
+- eu [Basque]          1223
+- bg [Bulgarian]       302
+- br [Brazilian Portuguese]    0
+- et [Estonian]                457
+- ar [Arabic]          149
+- he [Hebrew]          438
+- ua [Ukrainian]       292
+- lv [Latvian]         35
+- jp [Japanese]                123
+- vn [Vietnamese]      1530
+- ca [Catalan]         1547
+- ba [Bosnian]         1
+- kr [Korean]          1547
+- eo [Esperanto]       1536
+- my [Bahasa Malaysia] 1545
+- hi [Hindi]           1547
+
+
 
index def246c..7531240 100755 (executable)
  *
  *
  *
- *  171: class t3lib_BEfunc
+ *  176: class t3lib_BEfunc
  *
  *              SECTION: SQL-related, selecting records, searching
- *  191:     function deleteClause($table)
- *  214:     function getRecord($table,$uid,$fields='*',$where='')
- *  236:     function getRecordRaw($table,$where='',$fields='*')
- *  258:     function getRecordsByField($theTable,$theField,$theValue,$whereClause='',$groupBy='',$orderBy='',$limit='')
- *  289:     function fixVersioningPid($table,&$rr)
- *  323:     function searchQuery($searchWords,$fields,$table='')
- *  338:     function listQuery($field,$value)
- *  350:     function splitTable_Uid($str)
- *  365:     function getSQLselectableList($in_list,$tablename,$default_tablename)
- *  393:     function BEenableFields($table,$inv=0)
+ *  197:     function deleteClause($table,$tableAlias='')
+ *  220:     function getRecord($table,$uid,$fields='*',$where='')
+ *  242:     function getRecordRaw($table,$where='',$fields='*')
+ *  264:     function getRecordsByField($theTable,$theField,$theValue,$whereClause='',$groupBy='',$orderBy='',$limit='')
+ *  296:     function searchQuery($searchWords,$fields,$table='')
+ *  311:     function listQuery($field,$value)
+ *  323:     function splitTable_Uid($str)
+ *  338:     function getSQLselectableList($in_list,$tablename,$default_tablename)
+ *  366:     function BEenableFields($table,$inv=0)
  *
  *              SECTION: SQL-related, DEPRECIATED functions
- *  457:     function mm_query($select,$local_table,$mm_table,$foreign_table,$whereClause='',$groupBy='',$orderBy='',$limit='')
- *  479:     function DBcompileInsert($table,$fields_values)
- *  493:     function DBcompileUpdate($table,$where,$fields_values)
+ *  430:     function mm_query($select,$local_table,$mm_table,$foreign_table,$whereClause='',$groupBy='',$orderBy='',$limit='')
+ *  452:     function DBcompileInsert($table,$fields_values)
+ *  466:     function DBcompileUpdate($table,$where,$fields_values)
  *
  *              SECTION: Page tree, TCA related
- *  522:     function BEgetRootLine($uid,$clause='')
- *  571:     function openPageTree($pid,$clearExpansion)
- *  616:     function getRecordPath($uid, $clause, $titleLimit, $fullTitleLimit=0)
- *  658:     function getExcludeFields()
- *  688:     function getExplicitAuthFieldValues()
- *  759:     function getSystemLanguages()
- *  784:     function readPageAccess($id,$perms_clause)
- *  813:     function getTCAtypes($table,$rec,$useFieldNameAsKey=0)
- *  866:     function getTCAtypeValue($table,$rec)
- *  889:     function getSpecConfParts($str, $defaultExtras)
- *  919:     function getSpecConfParametersFromArray($pArr)
- *  945:     function getFlexFormDS($conf,$row,$table)
+ *  495:     function BEgetRootLine($uid,$clause='')
+ *  547:     function openPageTree($pid,$clearExpansion)
+ *  592:     function getRecordPath($uid, $clause, $titleLimit, $fullTitleLimit=0)
+ *  635:     function getExcludeFields()
+ *  665:     function getExplicitAuthFieldValues()
+ *  736:     function getSystemLanguages()
+ *  761:     function readPageAccess($id,$perms_clause)
+ *  790:     function getTCAtypes($table,$rec,$useFieldNameAsKey=0)
+ *  843:     function getTCAtypeValue($table,$rec)
+ *  866:     function getSpecConfParts($str, $defaultExtras)
+ *  896:     function getSpecConfParametersFromArray($pArr)
+ *  923:     function getFlexFormDS($conf,$row,$table, $fieldName = '')
  *
  *              SECTION: Caching related
- * 1051:     function storeHash($hash,$data,$ident)
- * 1071:     function getHash($hash,$expTime)
+ * 1043:     function storeHash($hash,$data,$ident)
+ * 1063:     function getHash($hash,$expTime=0)
  *
  *              SECTION: TypoScript related
- * 1107:     function getPagesTSconfig($id,$rootLine='',$returnPartArray=0)
- * 1158:     function updatePagesTSconfig($id,$pageTS,$TSconfPrefix,$impParams='')
- * 1213:     function implodeTSParams($p,$k='')
+ * 1099:     function getPagesTSconfig($id,$rootLine='',$returnPartArray=0)
+ * 1150:     function updatePagesTSconfig($id,$pageTS,$TSconfPrefix,$impParams='')
+ * 1205:     function implodeTSParams($p,$k='')
  *
  *              SECTION: Users / Groups related
- * 1250:     function getUserNames($fields='username,usergroup,usergroup_cached_list,uid',$where='')
- * 1268:     function getGroupNames($fields='title,uid', $where='')
- * 1285:     function getListGroupNames($fields='title,uid')
- * 1304:     function blindUserNames($usernames,$groupArray,$excludeBlindedFlag=0)
- * 1337:     function blindGroupNames($groups,$groupArray,$excludeBlindedFlag=0)
+ * 1242:     function getUserNames($fields='username,usergroup,usergroup_cached_list,uid',$where='')
+ * 1260:     function getGroupNames($fields='title,uid', $where='')
+ * 1277:     function getListGroupNames($fields='title,uid')
+ * 1296:     function blindUserNames($usernames,$groupArray,$excludeBlindedFlag=0)
+ * 1329:     function blindGroupNames($groups,$groupArray,$excludeBlindedFlag=0)
  *
  *              SECTION: Output related
- * 1378:     function daysUntil($tstamp)
- * 1390:     function date($tstamp)
- * 1401:     function datetime($value)
- * 1413:     function time($value)
- * 1429:     function calcAge($seconds,$labels = 'min|hrs|days|yrs')
- * 1455:     function dateTimeAge($tstamp,$prefix=1,$date='')
- * 1473:     function titleAttrib($content='',$hsc=0)
- * 1486:     function titleAltAttrib($content)
- * 1510:     function thumbCode($row,$table,$field,$backPath,$thumbScript='',$uploaddir=NULL,$abs=0,$tparams='',$size='')
- * 1579:     function getThumbNail($thumbScript,$theFile,$tparams='',$size='')
- * 1596:     function titleAttribForPages($row,$perms_clause='',$includeAttrib=1)
- * 1655:     function getRecordIconAltText($row,$table='pages')
- * 1692:     function getLabelFromItemlist($table,$col,$key)
- * 1718:     function getItemLabel($table,$col,$printAllWrap='')
- * 1743:     function getRecordTitle($table,$row,$prep=0)
- * 1781:     function getProcessedValue($table,$col,$value,$fixed_lgd_chars=0,$defaultPassthrough=0,$noRecordLookup=FALSE,$uid=0)
- * 1899:     function getProcessedValueExtra($table,$fN,$fV,$fixed_lgd_chars=0,$uid=0)
- * 1923:     function getFileIcon($ext)
- * 1937:     function getCommonSelectFields($table,$prefix)
- * 1977:     function makeConfigForm($configArray,$defaults,$dataPrefix)
+ * 1370:     function daysUntil($tstamp)
+ * 1382:     function date($tstamp)
+ * 1393:     function datetime($value)
+ * 1405:     function time($value)
+ * 1421:     function calcAge($seconds,$labels = 'min|hrs|days|yrs')
+ * 1447:     function dateTimeAge($tstamp,$prefix=1,$date='')
+ * 1465:     function titleAttrib($content='',$hsc=0)
+ * 1478:     function titleAltAttrib($content)
+ * 1502:     function thumbCode($row,$table,$field,$backPath,$thumbScript='',$uploaddir=NULL,$abs=0,$tparams='',$size='')
+ * 1571:     function getThumbNail($thumbScript,$theFile,$tparams='',$size='')
+ * 1588:     function titleAttribForPages($row,$perms_clause='',$includeAttrib=1)
+ * 1647:     function getRecordIconAltText($row,$table='pages')
+ * 1684:     function getLabelFromItemlist($table,$col,$key)
+ * 1710:     function getItemLabel($table,$col,$printAllWrap='')
+ * 1735:     function getRecordTitle($table,$row,$prep=0)
+ * 1773:     function getProcessedValue($table,$col,$value,$fixed_lgd_chars=0,$defaultPassthrough=0,$noRecordLookup=FALSE,$uid=0)
+ * 1894:     function getProcessedValueExtra($table,$fN,$fV,$fixed_lgd_chars=0,$uid=0)
+ * 1918:     function getFileIcon($ext)
+ * 1932:     function getCommonSelectFields($table,$prefix)
+ * 1974:     function makeConfigForm($configArray,$defaults,$dataPrefix)
  *
  *              SECTION: Backend Modules API functions
- * 2052:     function helpTextIcon($table,$field,$BACK_PATH,$force=0)
- * 2074:     function helpText($table,$field,$BACK_PATH,$styleAttrib='')
- * 2126:     function cshItem($table,$field,$BACK_PATH,$wrap='',$onlyIconMode=FALSE, $styleAttrib='')
- * 2164:     function editOnClick($params,$backPath='',$requestUri='')
- * 2182:     function viewOnClick($id,$backPath='',$rootLine='',$anchor='',$altUrl='',$addGetVars='')
- * 2208:     function getModTSconfig($id,$TSref)
- * 2229:     function getFuncMenu($mainParams,$elementName,$currentValue,$menuItems,$script='',$addparams='')
- * 2272:     function getFuncCheck($mainParams,$elementName,$currentValue,$script='',$addparams='',$tagParams='')
- * 2297:     function getFuncInput($mainParams,$elementName,$currentValue,$size=10,$script="",$addparams="")
- * 2318:     function unsetMenuItems($modTSconfig,$itemArray,$TSref)
- * 2341:     function getSetUpdateSignal($set='')
- * 2392:     function getModuleData($MOD_MENU, $CHANGED_SETTINGS, $modName, $type='', $dontValidateList='', $setDefaultList='')
+ * 2049:     function helpTextIcon($table,$field,$BACK_PATH,$force=0)
+ * 2071:     function helpText($table,$field,$BACK_PATH,$styleAttrib='')
+ * 2123:     function cshItem($table,$field,$BACK_PATH,$wrap='',$onlyIconMode=FALSE, $styleAttrib='')
+ * 2161:     function editOnClick($params,$backPath='',$requestUri='')
+ * 2180:     function viewOnClick($id,$backPath='',$rootLine='',$anchor='',$altUrl='',$addGetVars='',$switchFocus=TRUE)
+ * 2207:     function getModTSconfig($id,$TSref)
+ * 2228:     function getFuncMenu($mainParams,$elementName,$currentValue,$menuItems,$script='',$addparams='')
+ * 2271:     function getFuncCheck($mainParams,$elementName,$currentValue,$script='',$addparams='',$tagParams='')
+ * 2296:     function getFuncInput($mainParams,$elementName,$currentValue,$size=10,$script="",$addparams="")
+ * 2317:     function unsetMenuItems($modTSconfig,$itemArray,$TSref)
+ * 2340:     function getSetUpdateSignal($set='')
+ * 2391:     function getModuleData($MOD_MENU, $CHANGED_SETTINGS, $modName, $type='', $dontValidateList='', $setDefaultList='')
  *
  *              SECTION: Core
- * 2467:     function lockRecords($table='',$uid=0,$pid=0)
- * 2496:     function isRecordLocked($table,$uid)
- * 2536:     function exec_foreign_table_where_query($fieldValue,$field='',$TSconfig=array(),$prefix='')
- * 2617:     function getTCEFORM_TSconfig($table,$row)
+ * 2464:     function lockRecords($table='',$uid=0,$pid=0)
+ * 2493:     function isRecordLocked($table,$uid)
+ * 2533:     function exec_foreign_table_where_query($fieldValue,$field='',$TSconfig=array(),$prefix='')
+ * 2614:     function getTCEFORM_TSconfig($table,$row)
  * 2664:     function getTSconfig_pidValue($table,$uid,$pid)
  * 2692:     function getPidForModTSconfig($table,$uid,$pid)
  * 2708:     function getTSCpid($table,$uid,$pid)
  * 2724:     function firstDomainRecord($rootLine)
  * 2746:     function getDomainStartPage($domain, $path='')
- * 2773:     function selectVersionsOfRecord($table, $uid, $fields='*')
- * 2819:     function RTEsetup($RTEprop,$table,$field,$type='')
- * 2838:     function &RTEgetObj()
- * 2877:     function &softRefParserObj($spKey)
- * 2909:     function explodeSoftRefParserList($parserList, $table, $field)
- * 2941:     function isModuleSetInTBE_MODULES($modName)
+ * 2776:     function RTEsetup($RTEprop,$table,$field,$type='')
+ * 2795:     function &RTEgetObj()
+ * 2834:     function &softRefParserObj($spKey)
+ * 2866:     function explodeSoftRefParserList($parserList, $table, $field)
+ * 2898:     function isModuleSetInTBE_MODULES($modName)
+ *
+ *              SECTION: Workspaces / Versioning
+ * 2942:     function selectVersionsOfRecord($table, $uid, $fields='*', $workspace=0)
+ * 2986:     function fixVersioningPid($table,&$rr)
+ * 3018:     function workspaceOL($table,&$row,$wsid=-99)
+ * 3062:     function getWorkspaceVersionOfRecord($workspace, $table, $uid, $fields='*')
+ * 3087:     function isPidInVersionizedBranch($pid)
  *
  *              SECTION: Miscellaneous
- * 2990:     function typo3PrintError($header,$text,$js='',$head=1)
- * 3034:     function TYPO3_copyRightNotice()
- * 3058:     function displayWarningMessages()
- * 3094:     function getPathType_web_nonweb($path)
- * 3106:     function ADMCMD_previewCmds($pageinfo)
- * 3128:     function processParams($params)
- * 3154:     function getListOfBackendModules($name,$perms_clause,$backPath='',$script='index.php')
+ * 3120:     function typo3PrintError($header,$text,$js='',$head=1)
+ * 3164:     function TYPO3_copyRightNotice()
+ * 3188:     function displayWarningMessages()
+ * 3230:     function getPathType_web_nonweb($path)
+ * 3242:     function ADMCMD_previewCmds($pageinfo)
+ * 3264:     function processParams($params)
+ * 3290:     function getListOfBackendModules($name,$perms_clause,$backPath='',$script='index.php')
  *
- * TOTAL FUNCTIONS: 89
+ * TOTAL FUNCTIONS: 92
  * (This index is automatically created/updated by the extension "extdeveval")
  *
  */
@@ -186,12 +191,13 @@ class t3lib_BEfunc        {
         * Usage: 71
         *
         * @param       string          Table name present in $TCA
+        * @param       string          Table alias if any
         * @return      string          WHERE clause for filtering out deleted records, eg " AND tablename.deleted=0"
         */
-       function deleteClause($table)   {
+       function deleteClause($table,$tableAlias='')    {
                global $TCA;
                if ($TCA[$table]['ctrl']['delete'])     {
-                       return ' AND '.$table.'.'.$TCA[$table]['ctrl']['delete'].'=0';
+                       return ' AND '.($tableAlias ? $tableAlias : $table).'.'.$TCA[$table]['ctrl']['delete'].'=0';
                } else {
                        return '';
                }
@@ -221,6 +227,21 @@ class t3lib_BEfunc {
        }
 
        /**
+        * Like getRecord(), but overlays workspace version if any.
+        *
+        * @param       string          Table name present in $TCA
+        * @param       integer         UID of record
+        * @param       string          List of fields to select
+        * @param       string          Additional WHERE clause, eg. " AND blablabla=0"
+        * @return      array           Returns the row if found, otherwise nothing
+        */
+       function getRecordWSOL($table,$uid,$fields='*',$where='')       {
+               $row = t3lib_BEfunc::getRecord($table,$uid,$fields,$where);
+               t3lib_BEfunc::workspaceOL($table,$row);
+               return $row;
+       }
+
+       /**
         * Returns the first record found from $table with $where as WHERE clause
         * This function does NOT check if a record has the deleted flag set.
         * $table does NOT need to be configured in $TCA
@@ -278,39 +299,6 @@ class t3lib_BEfunc {
        }
 
        /**
-        * Find page-tree PID for versionized record
-        * Will look if the "pid" value of the input record is -1 and if the table supports versioning - if so, it will translate the -1 PID into the PID of the original record
-        *
-        * @param       string          Table name
-        * @param       array           Record array passed by reference. As minimum, "pid" and "uid" fields must exist! "t3ver_oid" is nice and will save you a DB query.
-        * @return      void            (Passed by ref).
-        * @see t3lib_page::fixVersioningPid()
-        */
-       function fixVersioningPid($table,&$rr)  {
-               global $TCA;
-
-               if ($rr['pid']==-1 && $TCA[$table]['ctrl']['versioning'])       {
-                       if ($rr['t3ver_oid']>0) {       // If "t3ver_oid" is already a field, just set this:
-                               $oid = $rr['t3ver_oid'];
-                       } else {        // Otherwise we have to expect "uid" to be in the record and look up based on this:
-                               $newPidRec = t3lib_BEfunc::getRecord($table,$rr['uid'],'t3ver_oid');
-                               if (is_array($newPidRec))       {
-                                       $oid = $newPidRec['t3ver_oid'];
-                               }
-                       }
-
-                               // If ID of current online version is found, look up the PID value of that:
-                       if ($oid)       {
-                               $oidRec = t3lib_BEfunc::getRecord($table,$oid,'pid');
-                               if (is_array($oidRec))  {
-                                       $rr['_ORIG_pid'] = $rr['pid'];
-                                       $rr['pid'] = $oidRec['pid'];
-                               }
-                       }
-               }
-       }
-
-       /**
         * Returns a WHERE clause which will make an AND search for the words in the $searchWords array in any of the fields in array $fields.
         * Usage: 0
         *
@@ -516,29 +504,31 @@ class t3lib_BEfunc        {
         * Usage: 1
         *
         * @param       integer         Page id for which to create the root line.
-        * @param       string          $clause can be used to select other criteria. It would typically be where-clauses that stops the proces if we meet a page, the user has no reading access to.
+        * @param       string          $clause can be used to select other criteria. It would typically be where-clauses that stops the process if we meet a page, the user has no reading access to.
+        * @param       boolean         If true, version overlay is applied. This must be requested specifically because it is usually only wanted when the rootline is used for visual output while for permission checking you want the raw thing!
         * @return      array           Root line array, all the way to the page tree root (or as far as $clause allows!)
         */
-       function BEgetRootLine($uid,$clause='') {
+       function BEgetRootLine($uid,$clause='',$workspaceOL=FALSE)      {
                $loopCheck = 100;
                $theRowArray = Array();
                $output = Array();
                while ($uid!=0 && $loopCheck>0) {
                        $loopCheck--;
                        $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
-                                                       'pid,uid,title,TSconfig,is_siteroot,storage_pid',
-                                                       'pages',
-                                                       'uid='.intval($uid).' '.
-                                                               t3lib_BEfunc::deleteClause('pages').' '.
-                                                               $clause         // whereClauseMightContainGroupOrderBy
-                                               );
+                               'pid,uid,title,TSconfig,is_siteroot,storage_pid,t3ver_oid,t3ver_wsid,t3ver_state,t3ver_swapmode',
+                               'pages',
+                               'uid='.intval($uid).' '.
+                                       t3lib_BEfunc::deleteClause('pages').' '.
+                                       $clause         // whereClauseMightContainGroupOrderBy
+                       );
                        if ($GLOBALS['TYPO3_DB']->sql_error())  {
                                debug($GLOBALS['TYPO3_DB']->sql_error(),1);
                        }
                        if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
+                               if($workspaceOL)        t3lib_BEfunc::workspaceOL('pages',$row);
                                t3lib_BEfunc::fixVersioningPid('pages',$row);
                                $uid = $row['pid'];
-                               $theRowArray[]=$row;
+                               $theRowArray[] = $row;
                        } else {
                                break;
                        }
@@ -556,8 +546,13 @@ class t3lib_BEfunc {
                                $output[$c]['TSconfig'] = $val['TSconfig'];
                                $output[$c]['is_siteroot'] = $val['is_siteroot'];
                                $output[$c]['storage_pid'] = $val['storage_pid'];
+                               $output[$c]['t3ver_oid'] = $val['t3ver_oid'];
+                               $output[$c]['t3ver_wsid'] = $val['t3ver_wsid'];
+                               $output[$c]['t3ver_state'] = $val['t3ver_state'];
+                               $output[$c]['t3ver_swapmode'] = $val['t3ver_swapmode'];
                        }
                }
+
                return $output;
        }
 
@@ -621,16 +616,17 @@ class t3lib_BEfunc        {
                while ($uid!=0 && $loopCheck>0) {
                        $loopCheck--;
                        $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
-                                               'uid,pid,title',
+                                               'uid,pid,title,t3ver_oid,t3ver_wsid,t3ver_swapmode',
                                                'pages',
                                                'uid='.intval($uid).
                                                        t3lib_BEfunc::deleteClause('pages').
                                                        (strlen(trim($clause)) ? ' AND '.$clause : '')
                                        );
                        if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
+                               t3lib_BEfunc::workspaceOL('pages',$row);
                                t3lib_BEfunc::fixVersioningPid('pages',$row);
 
-                               if ($row['_ORIG_pid'])  {
+                               if ($row['_ORIG_pid'] && $row['t3ver_swapmode']>0)      {       // Branch points
                                        $output = ' [#VEP#]'.$output;           // Adding visual token - Versioning Entry Point - that tells that THIS position was where the versionized branch got connected to the main tree. I will have to find a better name or something...
                                }
                                $uid = $row['pid'];
@@ -939,6 +935,7 @@ class t3lib_BEfunc  {
         * @param       array           Field config array
         * @param       array           Record data
         * @param       string          The table name
+        * @param       [type]          $fieldName: ...
         * @return      mixed           If array, the data structure was found and returned as an array. Otherwise (string) it is an error message.
         * @see t3lib_TCEforms::getSingleField_typeFlex()
         */
@@ -977,6 +974,7 @@ class t3lib_BEfunc  {
                                // Searching recursively back if 'ds_pointerField_searchParent' is defined (typ. a page rootline, or maybe a tree-table):
                        if ($ds_searchParentField && !$srcPointer)      {
                                $rr = t3lib_BEfunc::getRecord($table,$row['uid'],'uid,'.$ds_searchParentField); // Get the "pid" field - we cannot know that it is in the input record!
+                               #t3lib_BEfunc::workspaceOL($table,$rr); // KASPER: Not tested, but assumed correct
                                t3lib_BEfunc::fixVersioningPid($table,$rr);
                                $uidAcc=array();        // Used to avoid looping, if any should happen.
                                $subFieldPointer = $conf['ds_pointerField_searchParent_subField'];
@@ -992,6 +990,7 @@ class t3lib_BEfunc  {
                                        if (!is_array($rr) || isset($uidAcc[$rr['uid']]))       break;
                                        $uidAcc[$rr['uid']]=1;
 
+                                       #t3lib_BEfunc::workspaceOL($table,$rr); // KASPER: Not tested, but assumed correct
                                        t3lib_BEfunc::fixVersioningPid($table,$rr);
                                        $srcPointer = ($subFieldPointer && $rr[$subFieldPointer]) ? $rr[$subFieldPointer] : $rr[$ds_pointerField];
                                }
@@ -1610,7 +1609,7 @@ class t3lib_BEfunc        {
                $parts=array();
                $parts[] = 'id='.$row['uid'];
                if ($row['alias'])      $parts[]=$LANG->sL($TCA['pages']['columns']['alias']['label']).' '.$row['alias'];
-               if ($row['t3ver_id'])   $parts[] = 'v#'.$row['t3ver_id'];
+               if ($row['pid']<0)      $parts[] = 'v#1.'.$row['t3ver_id'];
                if ($row['doktype']=='3')       {
                        $parts[]=$LANG->sL($TCA['pages']['columns']['url']['label']).' '.$row['url'];
                } elseif ($row['doktype']=='4') {
@@ -1674,8 +1673,8 @@ class t3lib_BEfunc        {
                        if ($table=='pages' && $row['alias'])   {
                                $out.=' / '.$row['alias'];
                        }
-                       if ($GLOBALS['TCA'][$table]['ctrl']['versioning'] && $row['t3ver_id'])  {
-                               $out.=' - v#'.$row['t3ver_id'];
+                       if ($GLOBALS['TCA'][$table]['ctrl']['versioningWS'] && $row['pid']<0)   {
+                               $out.=' - v#1.'.$row['t3ver_id'];
                        }
                        if ($ctrl['disabled'])  {               // Hidden ...
                                $out.=($row[$ctrl['disabled']]?' - '.$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.hidden'):'');
@@ -1849,11 +1848,14 @@ class t3lib_BEfunc      {
                                                                                $lA[]=$rVal?'['.$rVal.'!]':'';
                                                                        }
                                                                }
-                                                               $l = implode(',',$lA);
+                                                               $l = implode(', ',$lA);
                                                        }
                                                }
                                        }
                                break;
+                               case 'group':
+                                       $l = implode(', ',t3lib_div::trimExplode(',',$value,1));
+                               break;
                                case 'check':
                                        if (!is_array($theColConf['items']) || count($theColConf['items'])==1)  {
                                                $l = $value ? 'Yes' : '';
@@ -1863,7 +1865,7 @@ class t3lib_BEfunc        {
                                                while(list($key,$val)=each($theColConf['items']))       {
                                                        if ($value & pow(2,$key))       {$lA[]=$GLOBALS['LANG']->sL($val[0]);}
                                                }
-                                               $l = implode($lA,', ');
+                                               $l = implode(', ',$lA);
                                        }
                                break;
                                case 'input':
@@ -1959,8 +1961,9 @@ class t3lib_BEfunc        {
                                $fields[] = $prefix.$fieldN;
                        }
                }
-               if ($TCA[$table]['ctrl']['versioning']) {
+               if ($TCA[$table]['ctrl']['versioningWS'])       {
                        $fields[] = $prefix.'t3ver_id';
+                       $fields[] = $prefix.'t3ver_state';
                }
 
                if ($TCA[$table]['ctrl']['selicon_field'])      $fields[] = $prefix.$TCA[$table]['ctrl']['selicon_field'];
@@ -1973,7 +1976,7 @@ class t3lib_BEfunc        {
                        if ($TCA[$table]['ctrl']['enablecolumns']['fe_group'])  $fields[] = $prefix.$TCA[$table]['ctrl']['enablecolumns']['fe_group'];
                }
 
-               return implode(',',array_unique($fields));
+               return implode(',', array_unique($fields));
        }
 
        /**
@@ -2465,8 +2468,6 @@ class t3lib_BEfunc        {
         *
         *******************************************/
 
-
-
        /**
         * Unlock or Lock a record from $table with $uid
         * If $table and $uid is not set, then all locking for the current BE_USER is removed!
@@ -2630,6 +2631,8 @@ class t3lib_BEfunc        {
         * @see t3lib_transferData::renderRecord(), t3lib_TCEforms::setTSconfig(), SC_wizard_list::main(), SC_wizard_add::main()
         */
        function getTCEFORM_TSconfig($table,$row) {
+               t3lib_BEfunc::fixVersioningPid($table,$row);
+
                $res = array();
                $typeVal = t3lib_BEfunc::getTCAtypeValue($table,$row);
 
@@ -2656,6 +2659,7 @@ class t3lib_BEfunc        {
                $res['_THIS_UID']=$row['uid'];
                $res['_THIS_CID']=$row['cid'];
                $res['_THIS_ROW']=$row; // So the row will be passed to foreign_table_where_query()
+
                reset($rootLine);
                while(list(,$rC)=each($rootLine))       {
                        if (!$res['_STORAGE_PID'])      $res['_STORAGE_PID']=intval($rC['storage_pid']);
@@ -2778,49 +2782,6 @@ class t3lib_BEfunc       {
        }
 
        /**
-        * Select all versions of a record, ordered by version id (DESC)
-        *
-        * @param       string          Table name to select from
-        * @param       integer         Record uid for which to find versions.
-        * @param       string          Field list to select
-        * @return      array           Array of versions of table/uid
-        */
-       function selectVersionsOfRecord($table, $uid, $fields='*')      {
-               global $TCA;
-
-               if ($TCA[$table] && $TCA[$table]['ctrl']['versioning']) {
-
-                               // Select all versions of record:
-                       $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
-                               $fields,
-                               $table,
-                               '(t3ver_oid='.intval($uid).' || uid='.intval($uid).')'.
-                                       t3lib_BEfunc::deleteClause($table),
-                               '',
-                               't3ver_id DESC'
-                       );
-
-                               // Add rows to output array:
-                       $realPid = 0;
-                       $outputRows = array();
-                       while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))       {
-                               if ($uid==$row['uid'])  {
-                                       $row['_CURRENT_VERSION']=TRUE;
-                                       $realPid = $row['pid'];
-                               }
-                               $outputRows[] = $row;
-                       }
-
-                               // Set real-pid:
-                       foreach($outputRows as $idx => $oRow)   {
-                               $outputRows[$idx]['_REAL_PID'] = $realPid;
-                       }
-
-                       return $outputRows;
-               }
-       }
-
-       /**
         * Returns overlayered RTE setup from an array with TSconfig. Used in TCEforms and TCEmain
         * Usage: 8
         *
@@ -2982,6 +2943,207 @@ class t3lib_BEfunc      {
 
 
 
+       /*******************************************
+        *
+        * Workspaces / Versioning
+        *
+        *******************************************/
+
+       /**
+        * Select all versions of a record, ordered by version id (DESC)
+        *
+        * @param       string          Table name to select from
+        * @param       integer         Record uid for which to find versions.
+        * @param       string          Field list to select
+        * @param       integer         Workspace ID, if zero all versions regardless of workspace is found.
+        * @return      array           Array of versions of table/uid
+        */
+       function selectVersionsOfRecord($table, $uid, $fields='*', $workspace=0)        {
+               global $TCA;
+
+               if ($TCA[$table] && $TCA[$table]['ctrl']['versioningWS'])       {
+
+                               // Select all versions of record:
+                       $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
+                               $fields,
+                               $table,
+                               '((t3ver_oid='.intval($uid).($workspace!=0?' AND t3ver_wsid='.intval($workspace):'').') OR uid='.intval($uid).')'.
+                                       t3lib_BEfunc::deleteClause($table),
+                               '',
+                               't3ver_id DESC'
+                       );
+
+                               // Add rows to output array:
+                       $realPid = 0;
+                       $outputRows = array();
+                       while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))       {
+                               if ($uid==$row['uid'])  {
+                                       $row['_CURRENT_VERSION']=TRUE;
+                                       $realPid = $row['pid'];
+                               }
+                               $outputRows[] = $row;
+                       }
+
+                               // Set real-pid:
+                       foreach($outputRows as $idx => $oRow)   {
+                               $outputRows[$idx]['_REAL_PID'] = $realPid;
+                       }
+
+                       return $outputRows;
+               }
+       }
+
+       /**
+        * Find page-tree PID for versionized record
+        * Will look if the "pid" value of the input record is -1 and if the table supports versioning - if so, it will translate the -1 PID into the PID of the original record
+        * Used whenever you are tracking something back, like making the root line.
+        * Principle; Record offline! => Find online?
+        *
+        * @param       string          Table name
+        * @param       array           Record array passed by reference. As minimum, "pid" and "uid" fields must exist! "t3ver_oid" and "t3ver_wsid" is nice and will save you a DB query.
+        * @return      void            (Passed by ref). If the record had its pid corrected to the online versions pid, then "_ORIG_pid" is set to the original pid value (-1 of course). The field "_ORIG_pid" is used by various other functions to detect if a record was in fact in a versionized branch.
+        * @see t3lib_page::fixVersioningPid()
+        */
+       function fixVersioningPid($table,&$rr)  {
+               global $TCA;
+
+                       // Check that the input record is an offline version from a table that supports versioning:
+               if (is_array($rr) && $rr['pid']==-1 && $TCA[$table]['ctrl']['versioningWS'])    {
+
+                               // Check values for t3ver_oid and t3ver_wsid:
+                       if (isset($rr['t3ver_oid']) && isset($rr['t3ver_wsid']))        {       // If "t3ver_oid" is already a field, just set this:
+                               $oid = $rr['t3ver_oid'];
+                               $wsid = $rr['t3ver_wsid'];
+                       } else {        // Otherwise we have to expect "uid" to be in the record and look up based on this:
+                               $newPidRec = t3lib_BEfunc::getRecord($table,$rr['uid'],'t3ver_oid,t3ver_wsid');
+                               if (is_array($newPidRec))       {
+                                       $oid = $newPidRec['t3ver_oid'];
+                                       $wsid = $newPidRec['t3ver_wsid'];
+                               }
+                       }
+
+                               // If ID of current online version is found, look up the PID value of that:
+                       if ($oid && !strcmp((int)$wsid,$GLOBALS['BE_USER']->workspace)) {
+                               $oidRec = t3lib_BEfunc::getRecord($table,$oid,'pid');
+                               if (is_array($oidRec))  {
+                                       $rr['_ORIG_pid'] = $rr['pid'];
+                                       $rr['pid'] = $oidRec['pid'];
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Workspace Preview Overlay
+        * Generally ALWAYS used when records are selected based on uid or pid. If records are selected on other fields than uid or pid (eg. "email = ....") then usage might produce undesired results and that should be evaluated on individual basis.
+        * Principle; Record online! => Find offline?
+        *
+        * @param       string          Table name
+        * @param       array           Record array passed by reference. As minimum, the "uid", "pid" and "t3ver_swapmode" (pages) fields must exist!
+        * @param       integer         Workspace ID, if not specified will use $GLOBALS['BE_USER']->workspace
+        * @return      void            (Passed by ref).
+        * @see fixVersioningPid()
+        */
+       function workspaceOL($table,&$row,$wsid=-99)    {
+
+                       // Initialize workspace ID:
+               if ($wsid == -99)       $wsid = $GLOBALS['BE_USER']->workspace;
+
+                       // Check if workspace is different from zero and record is set:
+               if ($wsid!==0 && is_array($row))        {
+                       $wsAlt = t3lib_BEfunc::getWorkspaceVersionOfRecord($wsid, $table, $row['uid'], implode(',',array_keys($row)));
+
+                               // If version was found, swap the default record with that one.
+                       if (is_array($wsAlt))   {
+
+                                       // Always correct PID from -1 to what it should be:
+                               if (isset($wsAlt['pid']))       {
+                                       $wsAlt['_ORIG_pid'] = $wsAlt['pid'];    // Keep the old (-1) - indicates it was a version...
+                                       $wsAlt['pid'] = $row['pid'];            // Set in the online versions PID.
+                               }
+
+                                       // For versions of single elements or page+content, swap UID and PID:
+                               if ($table!=='pages' || $wsAlt['t3ver_swapmode']<=0)    {
+                                       $wsAlt['_ORIG_uid'] = $wsAlt['uid'];
+                                       $wsAlt['uid'] = $row['uid'];
+
+                                               // Backend css class:
+                                       $wsAlt['_CSSCLASS'] = $table==='pages' && $wsAlt['t3ver_swapmode']==0 ? 'ver-page' : 'ver-element';
+                               } else {        // This is only for page-versions with BRANCH below!
+                                       $wsAlt['_ONLINE_uid'] = $row['uid'];
+
+                                               // Backend css class:
+                                       $wsAlt['_CSSCLASS'] = 'ver-branchpoint';
+                                       $wsAlt['_SUBCSSCLASS'] = 'ver-branch';
+                               }
+
+                                       // Changing input record to the workspace version alternative:
+                               $row = $wsAlt;
+                       }
+               }
+       }
+
+       /**
+        * Select the workspace version of a record, if exists
+        *
+        * @param       integer         Workspace ID
+        * @param       string          Table name to select from
+        * @param       integer         Record uid for which to find workspace version.
+        * @param       string          Field list to select
+        * @return      array           If found, return record, otherwise false
+        */
+       function getWorkspaceVersionOfRecord($workspace, $table, $uid, $fields='*')     {
+               global $TCA;
+
+               if ($workspace!==0 && $TCA[$table] && $TCA[$table]['ctrl']['versioningWS'])     {
+
+                               // Select workspace version of record:
+                       $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
+                               $fields,
+                               $table,
+                               'pid=-1 AND
+                                t3ver_oid='.intval($uid).' AND
+                                t3ver_wsid='.intval($workspace).
+                                       t3lib_BEfunc::deleteClause($table)
+                       );
+
+                       if (is_array($rows[0])) return $rows[0];
+               }
+
+               return FALSE;
+       }
+
+       /**
+        * Will fetch the rootline for the pid, then check if anywhere in the rootline there is a branch point and if so everything is allowed of course.
+        * Alternatively; if the page of the PID itself is a version and swapmode is zero (page+content) then tables from versioning_followPages are allowed as well.
+        *
+        * @param       integer         Page id inside of which you want to edit/create/delete something.
+        * @return      boolean         Returns true if PID was in versionized branch.
+        */
+       function isPidInVersionizedBranch($pid, $table='')      {
+               $rl = t3lib_BEfunc::BEgetRootLine($pid);
+               $c = 0;
+
+               foreach($rl as $rec)    {
+                       if ($rec['_ORIG_pid']==-1)      {
+                                       // In any case: is it a branchpoint, then OK...
+                               if ($rec['t3ver_swapmode']>0)   {
+                                       return 'branchpoint';   // OK, we are in a versionized branch
+                               } elseif ($c==0 && $rec['t3ver_swapmode']==0 && $table && $GLOBALS['TCA'][$table]['ctrl']['versioning_followPages'])    {       // First level: So either $table must be versioning_followPages
+                                       return 'first'; // OK, we are in a versionized branch
+                               }
+                       }
+                       $c++;
+               }
+       }
+
+
+
+
+
+
+
+
 
 
 
@@ -2991,7 +3153,6 @@ class t3lib_BEfunc        {
         *
         *******************************************/
 
-
        /**
         * Print error message with header, text etc.
         * Usage: 19
index 2ff4a76..67f6fbf 100644 (file)
@@ -119,7 +119,6 @@ class t3lib_beUserAuth extends t3lib_userAuthGroup {
                        moduleSessionID
                */
        var $uc_default = Array (
-//             'lang' => 'dk',         // this value will be transferred from $BE_USER->user[lang] if not set...
                'interfaceSetup' => '', // serialized content that is used to store interface pane and menu positions. Set by the logout.php-script
                'moduleData' => Array(),        // user-data for the modules
                'thumbnailsByDefault' => 0,
@@ -261,6 +260,7 @@ class t3lib_beUserAuth extends t3lib_userAuthGroup {
                        $this->uc['lang']=$this->user['lang'];
                        $U=1;
                }
+
                        // Saving if updated.
                if ($U) {
                        $this->writeUC();       // Method from the t3lib_userauth class.
index 1d3b389..431b709 100755 (executable)
@@ -91,7 +91,7 @@ class t3lib_browseTree extends t3lib_treeView {
                $this->title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
                $this->MOUNTS = $GLOBALS['WEBMOUNTS'];
 
-               $this->fieldArray = array_merge($this->fieldArray,array('doktype','php_tree_stop','t3ver_id'));
+               $this->fieldArray = array_merge($this->fieldArray,array('doktype','php_tree_stop','t3ver_id','t3ver_state','t3ver_swapmode'));
                if (t3lib_extMgm::isLoaded('cms'))      {
                        $this->fieldArray = array_merge($this->fieldArray,array('hidden','starttime','endtime','fe_group','module','extendToSubpages'));
                }
index 1eab201..dff2c15 100755 (executable)
@@ -977,7 +977,7 @@ class t3lib_DB {
                                'caller' => 't3lib_DB::'.$func,
                                'ERROR' => $error,
                                'lastBuiltQuery' => $this->debug_lastBuiltQuery,
-                               'debug_backtrace' => function_exists('debug_backtrace') ? next(debug_backtrace()) : 'N/A'
+                               'debug_backtrace' => t3lib_div::debug_trail()
                        ));
                }
        }
index a92a562..7d6a1e8 100755 (executable)
@@ -71,7 +71,7 @@ class t3lib_diff {
 
                // Internal, dynamic:
        var $clearBufferIdx=0;          // This indicates the number of times the function addClearBuffer has been called - and used to detect the very first call...
-
+       var $differenceLgd=0;
 
 
 
@@ -80,9 +80,10 @@ class t3lib_diff {
         *
         * @param       string          String 1
         * @param       string          String 2
+        * @param       string          Setting the wrapping tag name
         * @return      string          Formatted output.
         */
-       function makeDiffDisplay($str1,$str2)   {
+       function makeDiffDisplay($str1,$str2,$wrapTag='span')   {
                if ($this->stripTags)   {
                        $str1 = strip_tags($str1);
                        $str2 = strip_tags($str2);
@@ -99,19 +100,22 @@ class t3lib_diff {
                        reset($diffRes);
                        $c=0;
                        $diffResArray=array();
+                       $differenceStr = '';
                        while(list(,$lValue)=each($diffRes))    {
                                if (intval($lValue))    {
                                        $c=intval($lValue);
                                        $diffResArray[$c]['changeInfo']=$lValue;
                                }
                                if (substr($lValue,0,1)=='<')   {
-                                       $diffResArray[$c]['old'][]=substr($lValue,2);
+                                       $differenceStr.= $diffResArray[$c]['old'][] = substr($lValue,2);
                                }
                                if (substr($lValue,0,1)=='>')   {
-                                       $diffResArray[$c]['new'][]=substr($lValue,2);
+                                       $differenceStr.= $diffResArray[$c]['new'][] = substr($lValue,2);
                                }
                        }
 
+                       $this->differenceLgd = strlen($differenceStr);
+
                        $outString='';
                        $clearBuffer='';
                        for ($a=-1;$a<count($str1Lines);$a++)   {
@@ -123,10 +127,10 @@ class t3lib_diff {
                                        $outString.=$this->addClearBuffer($clearBuffer);
                                        $clearBuffer='';
                                        if (is_array($diffResArray[$a+1]['old']))       {
-                                               $outString.='<span class="diff-r">'.htmlspecialchars(implode(' ',$diffResArray[$a+1]['old'])).'</span> ';
+                                               $outString.='<'.$wrapTag.' class="diff-r">'.htmlspecialchars(implode(' ',$diffResArray[$a+1]['old'])).'</'.$wrapTag.'> ';
                                        }
                                        if (is_array($diffResArray[$a+1]['new']))       {
-                                               $outString.='<span class="diff-g">'.htmlspecialchars(implode(' ',$diffResArray[$a+1]['new'])).'</span> ';
+                                               $outString.='<'.$wrapTag.' class="diff-g">'.htmlspecialchars(implode(' ',$diffResArray[$a+1]['new'])).'</'.$wrapTag.'> ';
                                        }
                                        $chInfParts = explode(',',$diffResArray[$a+1]['changeInfo']);
                                        if (!strcmp($chInfParts[0],$a+1))       {
index b2a5464..177fa54 100755 (executable)
@@ -2493,7 +2493,23 @@ class t3lib_div {
                }
        }
 
+       /**
+        *
+        */
+       function debug_trail()  {
+               if (function_exists('debug_backtrace')) {
+                       $trail = debug_backtrace();
+                       $trail = array_reverse($trail);
+                       array_pop($trail);
 
+                       $path = array();
+                       foreach($trail as $dat) {
+                               $path[] = $dat['class'].$dat['type'].$dat['function'];
+                       }
+
+                       return implode(' // ',$path);
+               } else return 'N/A';
+       }
 
 
 
index 472024a..1a7252b 100755 (executable)
@@ -122,6 +122,14 @@ class t3lib_iconWorks      {
                $doNotGenerateIcon = $GLOBALS['TYPO3_CONF_VARS']['GFX']['noIconProc'];                          // If set, the icon will NOT be generated with GDlib. Rather the icon will be looked for as [iconfilename]_X.[extension]
                $doNotRenderUserGroupNumber = TRUE;             // If set, then the usergroup number will NOT be printed unto the icon. NOTICE. the icon is generated only if a default icon for groups is not found... So effectively this is ineffective...
 
+                       // Shadow:
+               if ($TCA[$table]['ctrl']['versioningWS'] && (int)$row['t3ver_state']===1)       {
+                       return 'gfx/i/shadow_hide.png';
+               }
+               if ($TCA[$table]['ctrl']['versioningWS'] && (int)$row['t3ver_state']===2)       {
+                       return 'gfx/i/shadow_delete.png';
+               }
+
                        // First, find the icon file name. This can depend on configuration in TCA, field values and more:
                if ($table=='pages')    {
                        if (!$iconfile = $PAGES_TYPES[$row['doktype']]['icon']) {
index c5f4266..9cf2bf5 100644 (file)
@@ -83,6 +83,7 @@ class t3lib_loadModules {
        var $modListUser = Array();             // this array will hold the elements that should go into the select-list of modules for users...
 
        var $BE_USER = '';      // The backend user for use internally
+       var $observeWorkspaces = FALSE;         // If set true, workspace "permissions" will be observed so non-allowed modules will not be included in the array of modules.
 
 
        /**
@@ -387,7 +388,7 @@ class t3lib_loadModules {
                $path = ereg_replace ('/[^/.]+/\.\./', '/', $fullpath); // because 'path/../path' does not work
                if (@is_dir($path) && @file_exists($path.'/conf.php'))  {
                        include($path.'/conf.php');     // The conf-file is included. This must be valid PHP.
-                       if (!$MCONF['shy'] && $this->checkModAccess($name,$MCONF))      {
+                       if (!$MCONF['shy'] && $this->checkModAccess($name,$MCONF) && $this->checkModWorkspace($name,$MCONF))    {
                                $modconf['name']=$name;
                                        // language processing. This will add module labels and image reference to the internal ->moduleLabels array of the LANG object.
                                if (is_object($GLOBALS['LANG']))        {
@@ -479,6 +480,31 @@ class t3lib_loadModules {
        }
 
        /**
+        * Check if a module is allowed inside the current workspace for be user
+        * Processing happens only if $this->observeWorkspaces is TRUE
+        *
+        * @param       string          Module name
+        * @param       array           MCONF array (module configuration array) from the modules conf.php file (contains settings about workspace restrictions)
+        * @return      boolean         True if access is granted for $this->BE_USER
+        */
+       function checkModWorkspace($name,$MCONF)        {
+               if ($this->observeWorkspaces)   {
+                       $status = TRUE;
+                       if ($MCONF['workspaces'])       {
+                               $status = FALSE;
+                               if (($this->BE_USER->workspace===0 && t3lib_div::inList($MCONF['workspaces'],'online')) ||
+                                       ($this->BE_USER->workspace===-1 && t3lib_div::inList($MCONF['workspaces'],'offline')) ||
+                                       ($this->BE_USER->workspace>0 && t3lib_div::inList($MCONF['workspaces'],'custom')))      {
+                                               $status = TRUE;
+                               }
+                       } elseif ($this->BE_USER->workspace===-99)      {
+                               $status = FALSE;
+                       }
+                       return $status;
+               } else return TRUE;
+       }
+
+       /**
         * Parses the moduleArray ($TBE_MODULES) into a internally useful structure.
         * Returns an array where the keys are names of the module and the values may be true (only module) or an array (of submodules)
         *
index dbe83fc..47a01e2 100755 (executable)
  *
  *
  *
- *  107: class t3lib_pageSelect
- *  132:     function init($show_hidden)
+ *  108: class t3lib_pageSelect
+ *  133:     function init($show_hidden)
  *
  *              SECTION: Selecting page records
- *  171:     function getPage($uid)
- *  187:     function getPage_noCheck($uid)
- *  203:     function getFirstWebPage($uid)
- *  221:     function getPageIdFromAlias($alias)
- *  237:     function getPageOverlay($pageInput,$lUid=-1)
- *  300:     function getRecordOverlay($table,$row,$sys_language_content,$OLmode='')
+ *  179:     function getPage($uid, $disableGroupAccessCheck=FALSE)
+ *  195:     function getPage_noCheck($uid)
+ *  211:     function getFirstWebPage($uid)
+ *  229:     function getPageIdFromAlias($alias)
+ *  245:     function getPageOverlay($pageInput,$lUid=-1)
+ *  309:     function getRecordOverlay($table,$row,$sys_language_content,$OLmode='')
  *
  *              SECTION: Page related: Menu, Domain record, Root line
- *  396:     function getMenu($uid,$fields='*',$sortField='sorting',$addWhere='')
- *  431:     function getDomainStartPage($domain, $path='',$request_uri='')
- *  479:     function getRootLine($uid, $MP='', $ignoreMPerrors=FALSE)
- *  597:     function getPathFromRootline($rl,$len=20)
- *  618:     function getExtURL($pagerow,$disable=0)
- *  642:     function getMountPointInfo($pageId, $pageRec=FALSE, $prevMountPids=array(), $firstPageUid=0)
+ *  405:     function getMenu($uid,$fields='*',$sortField='sorting',$addWhere='')
+ *  443:     function getDomainStartPage($domain, $path='',$request_uri='')
+ *  491:     function getRootLine($uid, $MP='', $ignoreMPerrors=FALSE)
+ *  612:     function getPathFromRootline($rl,$len=20)
+ *  633:     function getExtURL($pagerow,$disable=0)
+ *  657:     function getMountPointInfo($pageId, $pageRec=FALSE, $prevMountPids=array(), $firstPageUid=0)
  *
  *              SECTION: Selecting records in general
- *  719:     function checkRecord($table,$uid,$checkPage=0)
- *  750:     function getRawRecord($table,$uid,$fields='*')
- *  774:     function getRecordsByField($theTable,$theField,$theValue,$whereClause='',$groupBy='',$orderBy='',$limit='')
+ *  734:     function checkRecord($table,$uid,$checkPage=0)
+ *  768:     function getRawRecord($table,$uid,$fields='*')
+ *  792:     function getRecordsByField($theTable,$theField,$theValue,$whereClause='',$groupBy='',$orderBy='',$limit='')
  *
  *              SECTION: Caching and standard clauses
- *  826:     function getHash($hash,$expTime=0)
- *  849:     function storeHash($hash,$data,$ident)
- *  867:     function deleteClause($table)
- *  886:     function enableFields($table,$show_hidden=-1,$ignore_array=array())
+ *  844:     function getHash($hash,$expTime=0)
+ *  867:     function storeHash($hash,$data,$ident)
+ *  885:     function deleteClause($table)
+ *  904:     function enableFields($table,$show_hidden=-1,$ignore_array=array())
  *
  *              SECTION: Versioning Preview
- *  954:     function fixVersioningPid($table,&$rr)
- *  986:     function versionOL($table,&$row)
+ *  998:     function fixVersioningPid($table,&$rr)
+ * 1039:     function versionOL($table,&$row,$TEMPCHECK=0)
+ * 1093:     function getWorkspaceVersionOfRecord($workspace, $table, $uid, $fields='*')
  *
- * TOTAL FUNCTIONS: 22
+ * TOTAL FUNCTIONS: 23
  * (This index is automatically created/updated by the extension "extdeveval")
  *
  */
@@ -112,9 +113,8 @@ class t3lib_pageSelect {
 
                // Versioning preview related:
        var $versioningPreview = FALSE;         // If true, preview of other record versions is allowed. THIS MUST ONLY BE SET IF the page is not cached and truely previewed by a backend user!!!
-       var $versionPreviewMap = array(
-# EXAMPLE:             'tt_content:421' => 427
-       );
+       var $versioningWorkspaceId = 0;         // Workspace ID for preview
+
 
 
                // Internal, dynamic:
@@ -124,7 +124,7 @@ class t3lib_pageSelect {
 
        /**
         * init() MUST be run directly after creating a new template-object
-        * This sets the internal variable $this->where_hid_del to the correct where clause for page records taking deleted/hidden/starttime/endtime into account
+        * This sets the internal variable $this->where_hid_del to the correct where clause for page records taking deleted/hidden/starttime/endtime/t3ver_state into account
         *
         * @param       boolean         If $show_hidden is true, the hidden-field is ignored!! Normally this should be false. Is used for previewing.
         * @return      void
@@ -137,6 +137,15 @@ class t3lib_pageSelect {
                        $this->where_hid_del.= 'AND pages.hidden=0 ';
                }
                $this->where_hid_del.= 'AND (pages.starttime<='.$GLOBALS['SIM_EXEC_TIME'].') AND (pages.endtime=0 OR pages.endtime>'.$GLOBALS['SIM_EXEC_TIME'].') ';
+
+                       // Filter out new place-holder pages in case we are NOT in a versioning preview (that means we are online!)
+               if (!$this->versioningPreview)  {
+                       $this->where_hid_del.= ' AND pages.t3ver_state!=1';
+               } else {
+                               // For version previewing, make sure that enable-fields are not de-selecting hidden pages - we need versionOL() to unset them only if the overlay record instructs us to.
+                       $this->versioningPreview_where_hid_del = $this->where_hid_del;  // Copy where_hid_del to other variable (used in relation to versionOL())
+                       $this->where_hid_del = '';      // Clear where_hid_del
+               }
        }
 
 
@@ -174,8 +183,8 @@ class t3lib_pageSelect {
        function getPage($uid, $disableGroupAccessCheck=FALSE)  {
                $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'pages', 'uid='.intval($uid).$this->where_hid_del.($disableGroupAccessCheck ? '' : $this->where_groupAccess));
                if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
-#??                    $this->versionOL('pages',$row);
-                       return $this->getPageOverlay($row);
+                       $this->versionOL('pages',$row);
+                       if (is_array($row))             return $this->getPageOverlay($row);
                }
                return Array();
        }
@@ -190,8 +199,8 @@ class t3lib_pageSelect {
        function getPage_noCheck($uid)  {
                $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'pages', 'uid='.intval($uid).$this->deleteClause('pages'));
                if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
-#??                    $this->versionOL('pages',$row);
-                       return $this->getPageOverlay($row);
+                       $this->versionOL('pages',$row);
+                       if (is_array($row))             return $this->getPageOverlay($row);
                }
                return Array();
        }
@@ -207,8 +216,8 @@ class t3lib_pageSelect {
                $output = '';
                $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'pages', 'pid='.intval($uid).$this->where_hid_del.$this->where_groupAccess, '', 'sorting', '1');
                if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
-#??                    $this->versionOL('pages',$row);
-                       $output = $this->getPageOverlay($row);
+                       $this->versionOL('pages',$row);
+                       if (is_array($row))             $output = $this->getPageOverlay($row);
                }
                $GLOBALS['TYPO3_DB']->sql_free_result($res);
                return $output;
@@ -223,7 +232,7 @@ class t3lib_pageSelect {
         */
        function getPageIdFromAlias($alias)     {
                $alias = strtolower($alias);
-               $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'pages', 'alias='.$GLOBALS['TYPO3_DB']->fullQuoteStr($alias, 'pages').' AND pid>=0 AND pages.deleted=0');  // "AND pid>=0" is because of versioning...
+               $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'pages', 'alias='.$GLOBALS['TYPO3_DB']->fullQuoteStr($alias, 'pages').' AND pid>=0 AND pages.deleted=0');  // "AND pid>=0" because of versioning (means that aliases sent MUST be online!)
                if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
                        return $row['uid'];
                }
@@ -272,9 +281,10 @@ class t3lib_pageSelect {
                                                        '1'
                                                );
                                $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
+                               $this->versionOL('pages_language_overlay',$row);
+
                                if (is_array($row))     {
                                        $row['_PAGES_OVERLAY'] = TRUE;
-                                       $this->versionOL('pages_language_overlay',$row);
 
                                                // Unset vital fields that are NOT allowed to be overlaid:
                                        unset($row['uid']);
@@ -397,25 +407,28 @@ class t3lib_pageSelect {
         * @see tslib_fe::getPageShortcut(), tslib_menu::makeMenu(), tx_wizardcrpages_webfunc_2, tx_wizardsortpages_webfunc_2
         */
        function getMenu($uid,$fields='*',$sortField='sorting',$addWhere='')    {
+
                $output = Array();
                $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($fields, 'pages', 'pid='.intval($uid).$this->where_hid_del.$this->where_groupAccess.' '.$addWhere, '', $sortField);
                while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))      {
-#??                    $this->versionOL('pages',$row);
-
-                               // Keep mount point:
-                       $origUid = $row['uid'];
-                       $mount_info = $this->getMountPointInfo($origUid, $row); // $row MUST have "uid", "pid", "doktype", "mount_pid", "mount_pid_ol" fields in it
-                       if (is_array($mount_info) && $mount_info['overlay'])    {       // There is a valid mount point.
-                               $mp_row = $this->getPage($mount_info['mount_pid']);             // Using "getPage" is OK since we need the check for enableFields AND for type 2 of mount pids we DO require a doktype < 200!
-                               if (count($mp_row))     {
-                                       $row = $mp_row;
-                                       $row['_MP_PARAM'] = $mount_info['MPvar'];
-                               } else unset($row);     // If the mount point could not be fetched with respect to enableFields, unset the row so it does not become a part of the menu!
-                       }
+                       $this->versionOL('pages',$row);
 
-                               // Add to output array after overlaying language:
                        if (is_array($row))     {
-                               $output[$origUid] = $this->getPageOverlay($row);
+                                       // Keep mount point:
+                               $origUid = $row['uid'];
+                               $mount_info = $this->getMountPointInfo($origUid, $row); // $row MUST have "uid", "pid", "doktype", "mount_pid", "mount_pid_ol" fields in it
+                               if (is_array($mount_info) && $mount_info['overlay'])    {       // There is a valid mount point.
+                                       $mp_row = $this->getPage($mount_info['mount_pid']);             // Using "getPage" is OK since we need the check for enableFields AND for type 2 of mount pids we DO require a doktype < 200!
+                                       if (count($mp_row))     {
+                                               $row = $mp_row;
+                                               $row['_MP_PARAM'] = $mount_info['MPvar'];
+                                       } else unset($row);     // If the mount point could not be fetched with respect to enableFields, unset the row so it does not become a part of the menu!
+                               }
+
+                                       // Add to output array after overlaying language:
+                               if (is_array($row))     {
+                                       $output[$origUid] = $this->getPageOverlay($row);
+                               }
                        }
                }
                return $output;
@@ -482,7 +495,7 @@ class t3lib_pageSelect {
        function getRootLine($uid, $MP='', $ignoreMPerrors=FALSE)       {
 
                        // Initialize:
-               $selFields = t3lib_div::uniqueList('pid,uid,t3ver_oid,title,alias,nav_title,media,layout,hidden,starttime,endtime,fe_group,extendToSubpages,doktype,TSconfig,storage_pid,is_siteroot,mount_pid,mount_pid_ol,fe_login_mode,'.$GLOBALS['TYPO3_CONF_VARS']['FE']['addRootLineFields']);
+               $selFields = t3lib_div::uniqueList('pid,uid,t3ver_oid,t3ver_wsid,t3ver_state,title,alias,nav_title,media,layout,hidden,starttime,endtime,fe_group,extendToSubpages,doktype,TSconfig,storage_pid,is_siteroot,mount_pid,mount_pid_ol,fe_login_mode,'.$GLOBALS['TYPO3_CONF_VARS']['FE']['addRootLineFields']);
                $this->error_getRootLine = '';
                $this->error_getRootLine_failPid = 0;
 
@@ -503,60 +516,63 @@ class t3lib_pageSelect {
                while ($uid!=0 && $loopCheck<20)        {       // Max 20 levels in the page tree.
                        $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($selFields, 'pages', 'uid='.intval($uid).' AND pages.deleted=0 AND pages.doktype!=255');
                        if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
-                               $this->fixVersioningPid('pages',$row);
-#??                            $this->versionOL('pages',$row);
-
-                                       // Mount Point page types are allowed ONLY a) if they are the outermost record in rootline and b) if the overlay flag is not set:
-                               if ($GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids'] && $row['doktype']==7 && !$ignoreMPerrors)   {
-                                       $mount_info = $this->getMountPointInfo($row['uid'], $row);
-                                       if ($loopCheck>0 || $mount_info['overlay'])     {
-                                               $this->error_getRootLine = 'Illegal Mount Point found in rootline';
-                                               return array();
+                               $this->versionOL('pages',$row);
+                               $this->fixVersioningPid('pages',$row,1);
+
+                               if (is_array($row))     {
+                                               // Mount Point page types are allowed ONLY a) if they are the outermost record in rootline and b) if the overlay flag is not set:
+                                       if ($GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids'] && $row['doktype']==7 && !$ignoreMPerrors)   {
+                                               $mount_info = $this->getMountPointInfo($row['uid'], $row);
+                                               if ($loopCheck>0 || $mount_info['overlay'])     {
+                                                       $this->error_getRootLine = 'Illegal Mount Point found in rootline';
+                                                       return array();
+                                               }
                                        }
-                               }
 
-                               $uid = $row['pid'];     // Next uid
-
-                               if (count($MPA) && $GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids'])      {
-                                       $curMP = end($MPA);
-                                       if (!strcmp($row['uid'],$curMP[0]))     {
-
-                                               array_pop($MPA);
-                                               $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($selFields, 'pages', 'uid='.intval($curMP[1]).' AND pages.deleted=0 AND pages.doktype!=255');
-                                               $mp_row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
-
-                                               if (is_array($mp_row))  {
-                                                       $this->fixVersioningPid('pages',$mp_row);
-#??                                                    $this->versionOL('pages',$mp_row);
-                                                       $mount_info = $this->getMountPointInfo($mp_row['uid'], $mp_row);
-                                                       if (is_array($mount_info) && $mount_info['mount_pid']==$curMP[0])       {
-                                                               $uid = $mp_row['pid'];  // Setting next uid
-
-                                                               if ($mount_info['overlay'])     {       // Symlink style: Keep mount point (current row).
-                                                                       $row['_MOUNT_OL'] = TRUE;       // Set overlay mode:
-                                                                       $row['_MOUNT_PAGE'] = array(
-                                                                               'uid' => $mp_row['uid'],
-                                                                               'pid' => $mp_row['pid'],
-                                                                               'title' =>  $mp_row['title'],
-                                                                       );
-                                                               } else {        // Normal operation: Insert the mount page row in rootline instead mount point.
-                                                                       if ($loopCheck>0)       {
-                                                                               $row = $mp_row;
-                                                                       } else {
-                                                                               $this->error_getRootLine = 'Current Page Id is a mounted page of the overlay type and cannot be accessed directly!';
-                                                                               return array(); // Matching the page id (first run, $loopCheck = 0) with the MPvar is ONLY allowed if the mount point is the "overlay" type (otherwise it could be forged!)
+                                       $uid = $row['pid'];     // Next uid
+
+                                       if (count($MPA) && $GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids'])      {
+                                               $curMP = end($MPA);
+                                               if (!strcmp($row['uid'],$curMP[0]))     {
+
+                                                       array_pop($MPA);
+                                                       $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($selFields, 'pages', 'uid='.intval($curMP[1]).' AND pages.deleted=0 AND pages.doktype!=255');
+                                                       $mp_row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
+
+                                                       $this->versionOL('pages',$mp_row);
+                                                       $this->fixVersioningPid('pages',$mp_row,2);
+
+                                                       if (is_array($mp_row))  {
+                                                               $mount_info = $this->getMountPointInfo($mp_row['uid'], $mp_row);
+                                                               if (is_array($mount_info) && $mount_info['mount_pid']==$curMP[0])       {
+                                                                       $uid = $mp_row['pid'];  // Setting next uid
+
+                                                                       if ($mount_info['overlay'])     {       // Symlink style: Keep mount point (current row).
+                                                                               $row['_MOUNT_OL'] = TRUE;       // Set overlay mode:
+                                                                               $row['_MOUNT_PAGE'] = array(
+                                                                                       'uid' => $mp_row['uid'],
+                                                                                       'pid' => $mp_row['pid'],
+                                                                                       'title' =>  $mp_row['title'],
+                                                                               );
+                                                                       } else {        // Normal operation: Insert the mount page row in rootline instead mount point.
+                                                                               if ($loopCheck>0)       {
+                                                                                       $row = $mp_row;
+                                                                               } else {
+                                                                                       $this->error_getRootLine = 'Current Page Id is a mounted page of the overlay type and cannot be accessed directly!';
+                                                                                       return array(); // Matching the page id (first run, $loopCheck = 0) with the MPvar is ONLY allowed if the mount point is the "overlay" type (otherwise it could be forged!)
+                                                                               }
                                                                        }
-                                                               }
 
-                                                               $row['_MOUNTED_FROM'] = $curMP[0];
-                                                               $row['_MP_PARAM'] = $mount_info['MPvar'];
+                                                                       $row['_MOUNTED_FROM'] = $curMP[0];
+                                                                       $row['_MP_PARAM'] = $mount_info['MPvar'];
+                                                               } else {
+                                                                       $this->error_getRootLine = 'MP var was corrupted';
+                                                                       return array(); // The MP variables did NOT connect proper mount points:
+                                                               }
                                                        } else {
-                                                               $this->error_getRootLine = 'MP var was corrupted';
-                                                               return array(); // The MP variables did NOT connect proper mount points:
+                                                               $this->error_getRootLine = 'No moint point record found according to PID in MP var';
+                                                               return array(); // The second PID in MP var was NOT a valid page.
                                                        }
-                                               } else {
-                                                       $this->error_getRootLine = 'No moint point record found according to PID in MP var';
-                                                       return array(); // The second PID in MP var was NOT a valid page.
                                                }
                                        }
                                }
@@ -647,9 +663,9 @@ class t3lib_pageSelect {
 
                                // Get pageRec if not supplied:
                        if (!is_array($pageRec))        {
-                               $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,pid,doktype,mount_pid,mount_pid_ol', 'pages', 'uid='.intval($pageId).' AND pages.deleted=0 AND pages.doktype!=255');
+                               $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,pid,doktype,mount_pid,mount_pid_ol,t3ver_state', 'pages', 'uid='.intval($pageId).' AND pages.deleted=0 AND pages.doktype!=255');
                                $pageRec = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
-#??                            $this->versionOL('pages',$pageRec);
+                               $this->versionOL('pages',$pageRec);             // Only look for version overlay if page record is not supplied; This assumes that the input record is overlaid with preview version, if any!
                        }
 
                                // Set first Page uid:
@@ -660,11 +676,11 @@ class t3lib_pageSelect {
                        if (is_array($pageRec) && $pageRec['doktype']==7 && $mount_pid>0 && !in_array($mount_pid, $prevMountPids))      {
 
                                        // Get the mount point record (to verify its general existence):
-                               $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,pid,doktype,mount_pid,mount_pid_ol', 'pages', 'uid='.$mount_pid.' AND pages.deleted=0 AND pages.doktype!=255');
+                               $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,pid,doktype,mount_pid,mount_pid_ol,t3ver_state', 'pages', 'uid='.$mount_pid.' AND pages.deleted=0 AND pages.doktype!=255');
                                $mount_rec = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
-                               if (is_array($mount_rec))       {
-#??                                    $this->versionOL('pages',$mount_rec);
+                               $this->versionOL('pages',$mount_rec);
 
+                               if (is_array($mount_rec))       {
                                                // Look for recursive mount point:
                                        $prevMountPids[] = $mount_pid;
                                        $recursiveMountPid = $this->getMountPointInfo($mount_pid, $mount_rec, $prevMountPids, $firstPageUid);
@@ -725,17 +741,20 @@ class t3lib_pageSelect {
                if (is_array($TCA[$table])) {
                        $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, 'uid='.intval($uid).$this->enableFields($table));
                        if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
-#??                            $this->versionOL($table,$row);
+                               $this->versionOL($table,$row);
                                $GLOBALS['TYPO3_DB']->sql_free_result($res);
-                               if ($checkPage) {
-                                       $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'pages', 'uid='.intval($row['pid']).$this->enableFields('pages'));
-                                       if ($GLOBALS['TYPO3_DB']->sql_num_rows($res))   {
-                                               return $row;
+
+                               if (is_array($row))     {
+                                       if ($checkPage) {
+                                               $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'pages', 'uid='.intval($row['pid']).$this->enableFields('pages'));
+                                               if ($GLOBALS['TYPO3_DB']->sql_num_rows($res))   {
+                                                       return $row;
+                                               } else {
+                                                       return 0;
+                                               }
                                        } else {
-                                               return 0;
+                                               return $row;
                                        }
-                               } else {
-                                       return $row;
                                }
                        }
                }
@@ -756,8 +775,8 @@ class t3lib_pageSelect {
                if (is_array($TCA[$table]) || $table=='pages') {        // Excluding pages here so we can ask the function BEFORE TCA gets initialized. Support for this is followed up in deleteClause()...
                        $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($fields, $table, 'uid='.intval($uid).$this->deleteClause($table));
                        if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
-#??                            $this->versionOL($table,$row);
-                               return $row;
+                               $this->versionOL($table,$row);
+                               if (is_array($row))     return $row;
                        }
                }
        }
@@ -789,8 +808,8 @@ class t3lib_pageSelect {
                                        );
                        $rows = array();
                        while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))       {
-#??                            $this->versionOL($theTable,$row);
-                               $rows[] = $row;
+                               #$this->versionOL($theTable,$row);      // not used since records here are fetched based on other fields than uid!
+                               if (is_array($row)) $rows[] = $row;
                        }
                        $GLOBALS['TYPO3_DB']->sql_free_result($res);
                        if (count($rows))       return $rows;
@@ -869,7 +888,7 @@ class t3lib_pageSelect {
         */
        function deleteClause($table)   {
                global $TCA;
-               if (!strcmp($table,'pages'))    {       // Hardcode for pages...:
+               if (!strcmp($table,'pages'))    {       // Hardcode for pages because TCA might not be loaded yet (early frontend initialization)
                        return ' AND pages.deleted=0';
                } else {
                        return $TCA[$table]['ctrl']['delete'] ? ' AND '.$table.'.'.$TCA[$table]['ctrl']['delete'].'=0' : '';
@@ -886,7 +905,7 @@ class t3lib_pageSelect {
         * @return      string          The clause starting like " AND ...=... AND ...=..."
         * @see tslib_cObj::enableFields(), deleteClause()
         */
-       function enableFields($table,$show_hidden=-1,$ignore_array=array())     {
+       function enableFields($table,$show_hidden=-1,$ignore_array=array(),$noVersionPreview=FALSE)     {
                if ($show_hidden==-1 && is_object($GLOBALS['TSFE']))    {       // If show_hidden was not set from outside and if TSFE is an object, set it based on showHiddenPage and showHiddenRecords from TSFE
                        $show_hidden = $table=='pages' ? $GLOBALS['TSFE']->showHiddenPage : $GLOBALS['TSFE']->showHiddenRecords;
                }
@@ -895,38 +914,49 @@ class t3lib_pageSelect {
                $ctrl = $GLOBALS['TCA'][$table]['ctrl'];
                $query='';
                if (is_array($ctrl))    {
+
+                               // Delete field check:
                        if ($ctrl['delete'])    {
                                $query.=' AND '.$table.'.'.$ctrl['delete'].'=0';
                        }
-                       if (is_array($ctrl['enablecolumns']))   {
-                               if ($ctrl['enablecolumns']['disabled'] && !$show_hidden && !$ignore_array['disabled'])  {
-                                       $field = $table.'.'.$ctrl['enablecolumns']['disabled'];
-                                       $query.=' AND '.$field.'=0';
-                               }
-                               if ($ctrl['enablecolumns']['starttime'] && !$ignore_array['starttime']) {
-                                       $field = $table.'.'.$ctrl['enablecolumns']['starttime'];
-                                       $query.=' AND ('.$field.'<='.$GLOBALS['SIM_EXEC_TIME'].')';
-                               }
-                               if ($ctrl['enablecolumns']['endtime'] && !$ignore_array['endtime'])     {
-                                       $field = $table.'.'.$ctrl['enablecolumns']['endtime'];
-                                       $query.=' AND ('.$field.'=0 OR '.$field.'>'.$GLOBALS['SIM_EXEC_TIME'].')';
-                               }
-                               if ($ctrl['enablecolumns']['fe_group'] && !$ignore_array['fe_group'])   {
-                                       $field = $table.'.'.$ctrl['enablecolumns']['fe_group'];
-                                       $query.= $this->getMultipleGroupsWhereClause($field, $table);
-                               }
 
-                                       // Call hook functions for additional enableColumns
-                                       // It is used by the extension ingmar_accessctrl which enables assigning more than one usergroup to content and page records
-                               if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_page.php']['addEnableColumns']))    {
-                                       $_params = array(
-                                               'table' => $table,
-                                               'show_hidden' => $show_hidden,
-                                               'ignore_array' => $ignore_array,
-                                               'ctrl' => $ctrl
-                                       );
-                                       foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_page.php']['addEnableColumns'] as $_funcRef)    {
-                                               $query .= t3lib_div::callUserFunction($_funcRef,$_params,$this);
+                               // Filter out new place-holder records in case we are NOT in a versioning preview (that means we are online!)
+                       if ($ctrl['versioningWS'] && !$this->versioningPreview) {
+                               $query.=' AND '.$table.'.t3ver_state!=1';       // Shadow state for new items MUST be ignored!
+                       }
+
+                               // Enable fields:
+                       if (is_array($ctrl['enablecolumns']))   {
+    if (!$this->versioningPreview || !$ctrl['versioningWS'] || $noVersionPreview) { // In case of versioning-preview, enableFields are ignored (checked in versionOL())
+     if ($ctrl['enablecolumns']['disabled'] && !$show_hidden && !$ignore_array['disabled']) {
+      $field = $table.'.'.$ctrl['enablecolumns']['disabled'];
+      $query.=' AND '.$field.'=0';
+     }
+     if ($ctrl['enablecolumns']['starttime'] && !$ignore_array['starttime']) {
+      $field = $table.'.'.$ctrl['enablecolumns']['starttime'];
+      $query.=' AND ('.$field.'<='.$GLOBALS['SIM_EXEC_TIME'].')';
+     }
+     if ($ctrl['enablecolumns']['endtime'] && !$ignore_array['endtime']) {
+      $field = $table.'.'.$ctrl['enablecolumns']['endtime'];
+      $query.=' AND ('.$field.'=0 OR '.$field.'>'.$GLOBALS['SIM_EXEC_TIME'].')';
+     }
+     if ($ctrl['enablecolumns']['fe_group'] && !$ignore_array['fe_group']) {
+      $field = $table.'.'.$ctrl['enablecolumns']['fe_group'];
+      $query.= $this->getMultipleGroupsWhereClause($field, $table);
+     }
+
+      // Call hook functions for additional enableColumns
+      // It is used by the extension ingmar_accessctrl which enables assigning more than one usergroup to content and page records
+     if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_page.php']['addEnableColumns']))    {
+      $_params = array(
+       'table' => $table,
+       'show_hidden' => $show_hidden,
+       'ignore_array' => $ignore_array,
+       'ctrl' => $ctrl
+      );
+      foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_page.php']['addEnableColumns'] as $_funcRef)    {
+       $query .= t3lib_div::callUserFunction($_funcRef,$_params,$this);
+      }
                                        }
                                }
                        }
@@ -973,31 +1003,39 @@ class t3lib_pageSelect {
         **********************************/
 
        /**
-        * Find page-tree PID for versionized record
-        * Will look if the "pid" value of the input record is -1 and if the table supports versioning - if so, it will translate the -1 PID into the PID of the original record
+        * Finding online PID for offline version record
+        * ONLY active when backend user is previewing records. MUST NEVER affect a site served which is not previewed by backend users!!!
+        * Will look if the "pid" value of the input record is -1 (it is an offline version) and if the table supports versioning; if so, it will translate the -1 PID into the PID of the original record
+        * Used whenever you are tracking something back, like making the root line.
+        * Principle; Record offline! => Find online?
         *
         * @param       string          Table name
-        * @param       array           Record array passed by reference. As minimum, "pid" and "uid" fields must exist! "t3ver_oid" is nice and will save you a DB query.
+        * @param       array           Record array passed by reference. As minimum, "pid" and "uid" fields must exist! "t3ver_oid" and "t3ver_wsid" is nice and will save you a DB query.
         * @return      void            (Passed by ref).
-        * @see t3lib_BEfunc::fixVersioningPid()
+        * @see t3lib_BEfunc::fixVersioningPid(), versionOL(), getRootLine()
         */
        function fixVersioningPid($table,&$rr)  {
                global $TCA;
-# SWAP uid as well???
-               if ($this->versioningPreview && $rr['pid']==-1 && ($table=='pages' || $TCA[$table]['ctrl']['versioning']))      {       // Have to hardcode it for "pages" table since TCA is not loaded at this moment!
-                       if ($rr['t3ver_oid']>0) {       // If "t3ver_oid" is already a field, just set this:
+
+               if ($this->versioningPreview && is_array($rr) && $rr['pid']==-1 && ($table=='pages' || $TCA[$table]['ctrl']['versioningWS']))   {       // Have to hardcode it for "pages" table since TCA is not loaded at this moment!
+
+                               // Check values for t3ver_oid and t3ver_wsid:
+                       if (isset($rr['t3ver_oid']) && isset($rr['t3ver_wsid']))        {       // If "t3ver_oid" is already a field, just set this:
                                $oid = $rr['t3ver_oid'];
+                               $wsid = $rr['t3ver_wsid'];
                        } else {        // Otherwise we have to expect "uid" to be in the record and look up based on this:
-                               $newPidRec = $this->getRawRecord($table,$rr['uid'],'t3ver_oid');
+                               $newPidRec = $this->getRawRecord($table,$rr['uid'],'t3ver_oid,t3ver_wsid');
                                if (is_array($newPidRec))       {
                                        $oid = $newPidRec['t3ver_oid'];
+                                       $wsid = $newPidRec['t3ver_wsid'];
                                }
                        }
 
-                               // If ID of current online version is found, look up the PID value of that:
-                       if ($oid)       {
+                               // If workspace ids matches and ID of current online version is found, look up the PID value of that:
+                       if ($oid && !strcmp((int)$wsid,$this->versioningWorkspaceId))   {
                                $oidRec = $this->getRawRecord($table,$oid,'pid');
                                if (is_array($oidRec))  {
+                                       # SWAP uid as well? Well no, because when fixing a versioning PID happens it is assumed that this is a "branch" type page and therefore the uid should be kept (like in versionOL()). However if the page is NOT a branch version it should not happen - but then again, direct access to that uid should not happen!
                                        $rr['_ORIG_pid'] = $rr['pid'];
                                        $rr['pid'] = $oidRec['pid'];
                                }
@@ -1008,36 +1046,120 @@ class t3lib_pageSelect {
        /**
         * Versioning Preview Overlay
         * ONLY active when backend user is previewing records. MUST NEVER affect a site served which is not previewed by backend users!!!
+        * Generally ALWAYS used when records are selected based on uid or pid. If records are selected on other fields than uid or pid (eg. "email = ....") then usage might produce undesired results and that should be evaluated on individual basis.
+        * Principle; Record online! => Find offline?
         *
         * @param       string          Table name
-        * @param       array           Record array passed by reference. As minimum, the "uid" field must exist!
+        * @param       array           Record array passed by reference. As minimum, the "uid", "pid" and "t3ver_state" fields must exist! The record MAY be set to FALSE in which case the calling function should act as if the record is forbidden to access!
         * @return      void            (Passed by ref).
+        * @see fixVersioningPid(), t3lib_BEfunc::workspaceOL()
         */
        function versionOL($table,&$row)        {
                global $TCA;
 
-               if ($this->versioningPreview && $TCA[$table]['ctrl']['versioning'])     {
-#debug($row,$table);
-#debug($this->versionPreviewMap);
-                       if (is_array($row) && isset($this->versionPreviewMap[$table.':'.$row['uid']]))  {
-
-                                       // ID to look for:
-                               $lookFor = $this->versionPreviewMap[$table.':'.$row['uid']];
-
-                                       // Select the alternative version:
-                               $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, 'uid='.intval($lookFor).$this->deleteClause($table));
-                               if ($altrow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))      {
-                                       if ($altrow['pid']==-1 && $altrow['t3ver_oid']==$row['uid'])    {
-                                               unset($altrow['pid']);  // Unsetting PID since this is basically the same as what fixVersioningPid would do to the record...
-                                               unset($altrow['uid']);  // Unsetting UID because the overlaid record should KEEP its own UID.
-                                               # unset(...);   // more fields being unset???
-                                               $row = t3lib_div::array_merge_recursive_overrule($row,$altrow,TRUE);
-#debug($row,'Found:');
+               if ($this->versioningPreview && is_array($row)) {
+                       if ($wsAlt = $this->getWorkspaceVersionOfRecord($this->versioningWorkspaceId, $table, $row['uid'], implode(',',array_keys($row))))      {       // implode(',',array_keys($row)) = Using fields from original record to make sure no additional fields are selected. This is best for eg. getPageOverlay()
+                               if (is_array($wsAlt))   {
+
+                                               // Always fix PID (like in fixVersioningPid() above). [This is usually not the important factor for versioning OL]
+                                       $wsAlt['_ORIG_pid'] = $wsAlt['pid'];    // Keep the old (-1) - indicates it was a version...
+                                       $wsAlt['pid'] = $row['pid'];            // Set in the online versions PID.
+
+                                               // For versions of single elements or page+content, preserve online UID and PID (this will produce true "overlay" of element _content_, not any references)
+                                               // For page+content the "_ORIG_uid" should strictly speaking be used as PID for selection of tables with "versioning_followPages" enabled.
+                                       if ($table!=='pages' || $wsAlt['t3ver_swapmode']<=0)    {
+                                               $wsAlt['_ORIG_uid'] = $wsAlt['uid'];
+                                               $wsAlt['uid'] = $row['uid'];
+
+                                                       // Translate page alias as well so links are pointing to the _online_ page:
+                                               if ($table==='pages')   {
+                                                       $wsAlt['alias'] = $row['alias'];
+                                               }
+                                       } else {        // Keeping overlay uid and pid so references are changed. This is only for page-versions with BRANCH below!
+                                               $wsAlt['_ONLINE_uid'] = $row['uid'];    // The UID of the versionized record is kept and the uid of the online version is stored
+                                       }
+
+                                               // Changing input record to the workspace version alternative:
+                                       $row = $wsAlt;
+
+                                               // Check if it is deleted in workspace:
+                                       if ((int)$row['t3ver_state']===2)       {
+                                               $row = FALSE;   // Unset record if it turned out to be deleted in workspace
+                                       }
+                               } else {
+                                               // No version found, then check if t3ver_state =1 (online version is dummy-representation)
+                                       if ($wsAlt==-1 || (int)$row['t3ver_state']===1) {
+                                               $row = FALSE;   // Unset record if it turned out to be "hidden"
                                        }
                                }
                        }
                }
        }
+
+       /**
+        * Select the version of a record for a workspace
+        *
+        * @param       integer         Workspace ID
+        * @param       string          Table name to select from
+        * @param       integer         Record uid for which to find workspace version.
+        * @param       string          Field list to select
+        * @return      array           If found, return record, otherwise false. Returns 1 if version was sought for but not found, returns -1 if record existed but had enableFields that would disable it.
+        * @see t3lib_befunc::getWorkspaceVersionOfRecord()
+        */
+       function getWorkspaceVersionOfRecord($workspace, $table, $uid, $fields='*')     {
+               global $TCA;
+
+               if ($workspace!==0 && ($table=='pages' || $TCA[$table]['ctrl']['versioningWS']))        {       // Have to hardcode it for "pages" table since TCA is not loaded at this moment!
+
+                               // Setting up enableFields for record:
+                       if ($table=='pages')    {
+                               $enFields = $this->versioningPreview_where_hid_del;
+                       } else {
+                               $enFields = $this->enableFields($table,-1,array(),TRUE);
+                       }
+#debug($enFields,$table);
+
+                               // Select workspace version of record, only testing for deleted.
+                       list($newrow) = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
+                               $fields,
+                               $table,
+                               'pid=-1 AND
+                                t3ver_oid='.intval($uid).' AND
+                                t3ver_wsid='.intval($workspace).
+                                       $this->deleteClause($table)
+                       );
+
+                               // If version found, check if it could have been selected with enableFields on as well:
+                       if (is_array($newrow))  {
+#debug(array($newrow,$enFields));
+                               if ($GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
+                                       'uid',
+                                       $table,
+                                       'pid=-1 AND
+                                               t3ver_oid='.intval($uid).' AND
+                                               t3ver_wsid='.intval($workspace).
+                                               $enFields
+                               )) {
+                                       return $newrow; // Return row
+                               } else {
+                                       return -1;      // Unset row!
+                               }
+                       } else {
+                                       // Otherwise, check if online version can be selected with full enable fields and if so, return 1:
+                               if ($GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
+                                       'uid',
+                                       $table,
+                                       'uid='.intval($uid).$enFields
+                               ))      {
+                                       return 1;       // Means search was done.
+                               } else {
+                                       return -1;      // Unset row!
+                               }
+                       }
+               }
+
+               return FALSE;   // No look up in database because versioning not enabled / or workspace not offline
+       }
 }
 
 
@@ -1045,4 +1167,4 @@ class t3lib_pageSelect {
 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_page.php'])     {
        include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_page.php']);
 }
-?>
+?>
\ No newline at end of file
index 7bbc250..4e68447 100755 (executable)
@@ -76,7 +76,7 @@ require_once (PATH_t3lib.'class.t3lib_treeview.php');
  * @subpackage t3lib
  */
 class t3lib_pageTree extends t3lib_treeView    {
-       var $fieldArray = Array('uid','title','doktype','php_tree_stop');
+       var $fieldArray = Array('uid','title','doktype','php_tree_stop','t3ver_id','t3ver_state','t3ver_swapmode');
        var $defaultList = 'uid,pid,tstamp,sorting,deleted,perms_userid,perms_groupid,perms_user,perms_group,perms_everybody,crdate,cruser_id';
        var $setRecs = 0;
 
index 273291f..857255d 100755 (executable)
@@ -218,6 +218,7 @@ class t3lib_TCEforms        {
        var $palettesCollapsed=0;                       // Can be set true/false to whether palettes (secondary options) are in the topframe or in form. True means they are NOT IN-form. So a collapsed palette is one, which is shown in the top frame, not in the page.
        var $disableRTE=0;                                      // If set, the RTE is disabled (from form display, eg. by checkbox in the bottom of the page!)
        var $globalShowHelp=1;                          // If false, then all CSH will be disabled, regardless of settings in $this->edit_showFieldHelp
+       var $localizationMode='';               // If true, the forms are rendering only localization relevant fields of the records.
        var $fieldOrder='';                                     // Overrule the field order set in TCA[types][showitem], eg for tt_content this value, 'bodytext,image', would make first the 'bodytext' field, then the 'image' field (if set for display)... and then the rest in the old order.
        var $doPrintPalette=1;                          // If set to false, palettes will NEVER be rendered.
        var $clipObj=FALSE;                                     // Set to initialized clipboard object; Then the element browser will offer a link to paste in records from clipboard.
@@ -716,7 +717,8 @@ class t3lib_TCEforms        {
                                $PA['fieldConf']['config']['form_type']!='passthrough' &&
                                ($this->RTEenabled || !$PA['fieldConf']['config']['showIfRTE']) &&
                                (!$PA['fieldConf']['displayCond'] || $this->isDisplayCondition($PA['fieldConf']['displayCond'],$row)) &&
-                               (!$TCA[$table]['ctrl']['languageField'] || strcmp($PA['fieldConf']['l10n_mode'],'exclude') || $row[$TCA[$table]['ctrl']['languageField']]<=0)
+                               (!$TCA[$table]['ctrl']['languageField'] || strcmp($PA['fieldConf']['l10n_mode'],'exclude') || $row[$TCA[$table]['ctrl']['languageField']]<=0) &&
+                               (!$TCA[$table]['ctrl']['languageField'] || !$this->localizationMode || $this->localizationMode===$PA['fieldConf']['l10n_cat'])
                        )       {
 
                                // Fetching the TSconfig for the current table/field. This includes the $row which means that
@@ -1896,20 +1898,33 @@ class t3lib_TCEforms    {
                        $langChildren = $dataStructArray['meta']['langChildren'] ? 1 : 0;
                        $langDisabled = $dataStructArray['meta']['langDisable'] ? 1 : 0;
 
+                       $editData['meta']['currentLangId']=array();
                        $languages = $this->getAvailableLanguages();
 
+                       foreach($languages as $lInfo)   {
+                               if ($GLOBALS['BE_USER']->checkLanguageAccess($lInfo['uid']))    {
+                                       $editData['meta']['currentLangId'][] =  $lInfo['ISOcode'];
+                               }
+                       }
                        if (!is_array($editData['meta']['currentLangId']) || !count($editData['meta']['currentLangId']))        {
                                $editData['meta']['currentLangId']=array('DEF');
                        }
+
                        $editData['meta']['currentLangId'] = array_unique($editData['meta']['currentLangId']);
 
-                       if (!$langDisabled && count($languages) > 1)    {
-                               $item.=$this->getSingleField_typeFlex_langMenu($languages, $PA['itemFormElName'].'[meta][currentLangId]', $editData['meta']['currentLangId']).'<br />';
-                       }
 
+//                     if (!$langDisabled && count($languages) > 1)    {
+//                             $item.=$this->getSingleField_typeFlex_langMenu($languages, $PA['itemFormElName'].'[meta][currentLangId]', $editData['meta']['currentLangId']).'<br />';
+//                     }
+
+                       $PA['_noEditDEF'] = FALSE;
                        if ($langChildren || $langDisabled)     {
                                $rotateLang = array('DEF');
                        } else {
+                               if (!in_array('DEF',$editData['meta']['currentLangId']))        {
+                                       array_unshift($editData['meta']['currentLangId'],'DEF');
+                                       $PA['_noEditDEF'] = TRUE;
+                               }
                                $rotateLang = $editData['meta']['currentLangId'];
                        }
 
@@ -1935,6 +1950,7 @@ class t3lib_TCEforms      {
                                                $cmdData = t3lib_div::_GP('flexFormsCmdData');
                                                $lang = 'l'.$lKey;      // Default language, other options are "lUK" or whatever country code (independant of system!!!)
                                                $PA['_valLang'] = $langChildren && !$langDisabled ? $editData['meta']['currentLangId'] : 'DEF'; // Default language, other options are "lUK" or whatever country code (independant of system!!!)
+                                               $PA['_lang'] = $lang;
 
                                                        // Render flexform:
                                                $tRows = $this->getSingleField_typeFlex_draw(
@@ -2145,43 +2161,52 @@ class t3lib_TCEforms    {
                                                foreach($rotateLang as $vDEFkey)        {
                                                        $vDEFkey = 'v'.$vDEFkey;
 
-                                                       $fakePA=array();
-                                                       $fakePA['fieldConf']=array(
-                                                               'label' => $this->sL($value['TCEforms']['label']),
-                                                               'config' => $value['TCEforms']['config'],
-                                                               'defaultExtras' => $value['TCEforms']['defaultExtras'],
-                                                               'displayCond' => $value['TCEforms']['displayCond'],     // Haven't tested this...
-                                                       );
-                                                       if (
+                                                       if (!$value['TCEforms']['displayCond'] || $this->isDisplayCondition($value['TCEforms']['displayCond'],$editData,$vDEFkey)) {
+                                                               $fakePA=array();
+                                                               $fakePA['fieldConf']=array(
+                                                                       'label' => $this->sL($value['TCEforms']['label']),
+                                                                       'config' => $value['TCEforms']['config'],
+                                                                       'defaultExtras' => $value['TCEforms']['defaultExtras']
+                                                               );
+                                                               if ($PA['_noEditDEF'] && $PA['_lang']==='lDEF') {
+                                                                       $fakePA['fieldConf']['config'] = array(
+                                                                               'type' => 'none',
+                                                                               'rows' => 2
+                                                                       );
+                                                               }
+                                                               if (
                                                                        (($GLOBALS['TCA'][$table]['ctrl']['type'] && !strcmp($key,$GLOBALS['TCA'][$table]['ctrl']['type'])) ||
                                                                        ($GLOBALS['TCA'][$table]['ctrl']['requestUpdate'] && t3lib_div::inList($GLOBALS['TCA'][$table]['ctrl']['requestUpdate'],$key)))
-                                                                       && !$GLOBALS['BE_USER']->uc['noOnChangeAlertInTypeFields'])     {
-                                                               $alertMsgOnChange = 'if (confirm('.$GLOBALS['LANG']->JScharCode($this->getLL('m_onChangeAlert')).') && TBE_EDITOR_checkSubmit(-1)){ TBE_EDITOR_submitForm() };';
-                                                       } else {$alertMsgOnChange='';}
-                                                       $fakePA['fieldChangeFunc']=$PA['fieldChangeFunc'];
-                                                       if (strlen($alertMsgOnChange))  {
-                                                               $fakePA['fieldChangeFunc']['alert']=$alertMsgOnChange;
-                                                       }
-                                                       $fakePA['onFocus']=$PA['onFocus'];
-                                                       $fakePA['label']==$PA['label'];
+                                                                       && !$GLOBALS['BE_USER']->uc['noOnChangeAlertInTypeFields']) {
+                                                                       $alertMsgOnChange = 'if (confirm('.$GLOBALS['LANG']->JScharCode($this->getLL('m_onChangeAlert')).') && TBE_EDITOR_checkSubmit(-1)){ TBE_EDITOR_submitForm() };';
+                                                               } else {$alertMsgOnChange='';}
+                                                               $fakePA['fieldChangeFunc']=$PA['fieldChangeFunc'];
+                                                               if (strlen($alertMsgOnChange)) {
+                                                                       $fakePA['fieldChangeFunc']['alert']=$alertMsgOnChange;
+                                                               }
+                                                               $fakePA['onFocus']=$PA['onFocus'];
+                                                               $fakePA['label']==$PA['label'];
 
-                                                       $fakePA['itemFormElName']=$PA['itemFormElName'].$formPrefix.'['.$key.']['.$vDEFkey.']';
-                                                       $fakePA['itemFormElName_file']=$PA['itemFormElName_file'].$formPrefix.'['.$key.']['.$vDEFkey.']';
-                                                       if(isset($editData[$key][$vDEFkey])) {
-                                                         $fakePA['itemFormElValue']=$editData[$key][$vDEFkey];
-                                                       }
-                                                       else {
-                                                         $fakePA['itemFormElValue']=$fakePA['fieldConf']['config']['default'];
-                                                       }
+                                                               $fakePA['itemFormElName']=$PA['itemFormElName'].$formPrefix.'['.$key.']['.$vDEFkey.']';
+                                                               $fakePA['itemFormElName_file']=$PA['itemFormElName_file'].$formPrefix.'['.$key.']['.$vDEFkey.']';
+                                                               if(isset($editData[$key][$vDEFkey])) {
+                                                                       $fakePA['itemFormElValue']=$editData[$key][$vDEFkey];
+                                                               } else {
+                                                                       $fakePA['itemFormElValue']=$fakePA['fieldConf']['config']['default'];
+                                                               }
 
-                                                       $rowCells['formEl']= $this->getSingleField_SW($table,$field,$row,$fakePA);
-                                                       $rowCells['title']= htmlspecialchars($fakePA['fieldConf']['label']);
+                                                               if (!in_array('DEF',$rotateLang))       {
+                                                                       $defInfo = '<div class="typo3-TCEforms-originalLanguageValue">'.nl2br(htmlspecialchars($editData[$key]['vDEF'])).'&nbsp;</div>';
+                                                               } else {
+                                                                       $defInfo = '';
+                                                               }
 
-                                                               // Put row together
-                                                       $tRows[]='<tr>
-                                                               <td nowrap="nowrap" valign="top" class="bgColor5">'.$rowCells['title'].($vDEFkey=='vDEF' ? '' : ' ('.$vDEFkey.')').'</td>
-                                                               <td class="bgColor4">'.$rowCells['formEl'].'</td>
-                                                       </tr>';
+                                                                       // Put row together
+                                                               $tRows[]='<tr>
+                                                                       <td nowrap="nowrap" valign="top" class="bgColor5">'.$rowCells['title'].($vDEFkey=='vDEF' ? '' : ' ('.$vDEFkey.')').'</td>
+                                                                       <td class="bgColor4">'.$rowCells['formEl'].$defInfo.'</td>
+                                                               </tr>';
+                                                       }
                                                }
                                        }
                                }
@@ -4328,6 +4353,7 @@ class t3lib_TCEforms      {
                                }
                                var TS = new typoSetup();
                                var evalFunc = new evalFunc();
+                               evalFunc.USmode = '.($GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat']?'1':'0').';
 
                                function typo3FormFieldSet(theField, evallist, is_in, checkbox, checkboxValue)  {       //
                                        if (document.'.$formname.'[theField])   {
@@ -4836,46 +4862,48 @@ class t3lib_TCEforms    {
         * @param       array           The record to evaluate
         * @return      boolean
         */
-       function isDisplayCondition($displayCond,$row)  {
+       function isDisplayCondition($displayCond,$row,$ffValueKey='')   {
                $output = FALSE;
 
                $parts = explode(':',$displayCond);
                switch((string)$parts[0])       {       // Type of condition:
                        case 'FIELD':
+                               $theFieldValue = $ffValueKey ? $row[$parts[1]][$ffValueKey] : $row[$parts[1]];
+
                                switch((string)$parts[2])       {
                                        case 'REQ':
                                                if (strtolower($parts[3])=='true')      {
-                                                       $output = $row[$parts[1]] ? TRUE : FALSE;
+                                                       $output = $theFieldValue ? TRUE : FALSE;
                                                } elseif (strtolower($parts[3])=='false') {
-                                                       $output = !$row[$parts[1]] ? TRUE : FALSE;
+                                                       $output = !$theFieldValue ? TRUE : FALSE;
                                                }
                                        break;
                                        case '>':
-                                               $output = $row[$parts[1]] > $parts[3];
+                                               $output = $theFieldValue > $parts[3];
                                        break;
                                        case '<':
-                                               $output = $row[$parts[1]] < $parts[3];
+                                               $output = $theFieldValue < $parts[3];
                                        break;
                                        case '>=':
-                                               $output = $row[$parts[1]] >= $parts[3];
+                                               $output = $theFieldValue >= $parts[3];
                                        break;
                                        case '<=':
-                                               $output = $row[$parts[1]] <= $parts[3];
+                                               $output = $theFieldValue <= $parts[3];
                                        break;
                                        case '-':
                                        case '!-':
                                                $cmpParts = explode('-',$parts[3]);
-                                               $output = $row[$parts[1]] >= $cmpParts[0] && $row[$parts[1]] <= $cmpParts[1];
+                                               $output = $theFieldValue >= $cmpParts[0] && $theFieldValue <= $cmpParts[1];
                                                if ($parts[2]{0}=='!')  $output = !$output;
                                        break;
                                        case 'IN':
                                        case '!IN':
-                                               $output = t3lib_div::inList($parts[3],$row[$parts[1]]);
+                                               $output = t3lib_div::inList($parts[3],$theFieldValue);
                                                if ($parts[2]{0}=='!')  $output = !$output;
                                        break;
                                        case '=':
                                        case '!=':
-                                               $output = t3lib_div::inList($parts[3],$row[$parts[1]]);
+                                               $output = t3lib_div::inList($parts[3],$theFieldValue);
                                                if ($parts[2]{0}=='!')  $output = !$output;
                                        break;
                                }
@@ -4902,6 +4930,13 @@ class t3lib_TCEforms     {
                                        break;
                                }
                        break;
+                       case 'HIDE_L10N_SIBLINGS':
+                               if ($ffValueKey==='vDEF')       {
+                                       $output = TRUE;
+                               } elseif ($parts[1]==='except_admin' && $GLOBALS['BE_USER']->isAdmin()) {
+                                       $output = TRUE;
+                               }
+                       break;
                }
 
                return $output;
index 6f3b543..cd25c27 100755 (executable)
  * 3316:     function versionizeRecord($table,$id,$label)
  * 3369:     function versionizePages($uid,$label)
  * 3426:     function rawCopyPageContent($old_pid,$new_pid,$copyTablesArray)
- * 3451:     function version_swap($table,$id,$swapWith,$swapContent)
+ * 3451:     function version_swap($table,$id,$swapWith)
  * 3575:     function int_pageTreeInfo($CPtable,$pid,$counter, $rootID)
  * 3596:     function compileAdminTables()
  * 3613:     function fixUniqueInPid($table,$uid)
@@ -260,6 +260,7 @@ class t3lib_TCEmain {
        var $cachedTSconfig = array();
        var $substNEWwithIDs = Array();
        var $substNEWwithIDs_table = Array();
+       var $autoVersionIdMap = array();                        // Contains mapping of auto-versionized records.
        var $recUpdateAccessCache = Array();    // Used by function checkRecordUpdateAccess() to store whether a record is updateable or not.
        var $recInsertAccessCache = Array();
        var $isRecordInWebMount_Cache=array();
@@ -367,7 +368,15 @@ class t3lib_TCEmain        {
         * @return      void
         */
        function process_uploads($postFiles)    {
+
                if (is_array($postFiles))       {
+
+                               // Editing frozen:
+                       if ($this->BE_USER->workspace!==0 && $this->BE_USER->workspaceRec['freeze'])    {
+                               $this->log('',0,4,0,1,'All editing in this workspace has been frozen!');
+                               return FALSE;
+                       }
+
                        reset($postFiles);
                        $subA = current($postFiles);
                        if (is_array($subA))    {
@@ -435,6 +444,12 @@ class t3lib_TCEmain        {
        function process_datamap() {
                global $TCA, $TYPO3_CONF_VARS;
 
+                       // Editing frozen:
+               if ($this->BE_USER->workspace!==0 && $this->BE_USER->workspaceRec['freeze'])    {
+                       $this->log('',0,4,0,1,'All editing in this workspace has been frozen!');
+                       return FALSE;
+               }
+
                        // First prepare user defined objects (if any) for hooks which extend this function:
                $hookObjectsArr = array();
                if (is_array ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'])) {
@@ -488,7 +503,8 @@ class t3lib_TCEmain {
                                                        // ******************************
                                                        // Checking access to the record
                                                        // ******************************
-                                               $recordAccess = 0;
+                                               $createNewVersion = FALSE;
+                                               $recordAccess = FALSE;
                                                $old_pid_value = '';
                                                if (!t3lib_div::testInt($id)) {               // Is it a new record? (Then Id is a string)
                                                        $fieldArray = $this->newFieldArray($table);     // Get a fieldArray with default values
@@ -504,6 +520,12 @@ class t3lib_TCEmain        {
                                                                                $old_pid_value = $pid_value;
                                                                                $pid_value=intval($negFlag*$this->substNEWwithIDs[$pid_value]);
                                                                        } else {$OK = 0;}       // If not found in the substArray we must stop the proces...
+                                                               } elseif ($pid_value>=0 && $this->BE_USER->workspace!==0 && $TCA[$table]['ctrl']['versioning_followPages'])     {       // PID points to page, the workspace is an offline space and the table follows page during versioning: This means we must check if the PID page has a version in the workspace with swapmode set to o (zero = page+content) and if so, change the pid to the uid of that version.
+                                                                       if ($WSdestPage = t3lib_BEfunc::getWorkspaceVersionOfRecord($this->BE_USER->workspace, 'pages', $pid_value, 'uid,t3ver_swapmode'))      {       // Looks for workspace version of page.
+                                                                               if ($WSdestPage['t3ver_swapmode']==0)   {       // if swapmode is zero, then change pid value.
+                                                                                       $pid_value = $WSdestPage['uid'];
+                                                                               }
+                                                                       }
                                                                }
                                                                $pid_value = intval($pid_value);
 
@@ -530,13 +552,23 @@ class t3lib_TCEmain       {
                                                        $theRealPid = $fieldArray['pid'];
                                                                // Now, check if we may insert records on this pid.
                                                        if ($theRealPid>=0)     {
-                                                               $recordAccess = $this->checkRecordInsertAccess($table,$theRealPid);     // Checks if records can be inserted on this $pid.
+                                                               $recordAccess = $this->checkRecordInsertAccess($table,$theRealPid);             // Checks if records can be inserted on this $pid.
+
+                                                                       // If records cannot be created in the current PID due to workspace restrictions, prepare creation of placeholder-record
+                                                               if ($recordAccess && !$this->BE_USER->workspaceTestPID($theRealPid,$table))     {
+                                                                       if ($TCA[$table]['ctrl']['versioningWS'])       {
+                                                                               $createNewVersion = TRUE;
+                                                                       } else {
+                                                                               $recordAccess = FALSE;
+                                                                               $this->log($table,$id,2,0,1,'Record could not be created in this workspace in this branch');
+                                                                       }
+                                                               }
                                                        } else {
                                                                debug('Internal ERROR: pid should not be less than zero!');
                                                        }
                                                        $status = 'new';                                                // Yes new record, change $record_status to 'insert'
                                                } else {        // Nope... $id is a number
-                                                       $fieldArray = Array();
+                                                       $fieldArray = array();
                                                        $recordAccess = $this->checkRecordUpdateAccess($table,$id);
                                                        if (!$recordAccess)             {
                                                                $propArr = $this->getRecordProperties($table,$id);
@@ -547,8 +579,45 @@ class t3lib_TCEmain        {
                                                                        $propArr = $this->getRecordProperties($table,$id);
                                                                        $this->log($table,$id,2,0,1,"recordEditAccessInternals() check failed. [".$this->BE_USER->errorMsg."]",2,array($propArr['header'],$table.':'.$id),$propArr['event_pid']);
                                                                } else {        // Here we fetch the PID of the record that we point to...
-                                                                       $tempdata = $this->recordInfo($table,$id,'pid');
+                                                                       $tempdata = $this->recordInfo($table,$id,'pid'.($TCA[$table]['ctrl']['versioningWS']?',t3ver_wsid':''));
                                                                        $theRealPid = $tempdata['pid'];
+
+                                                                               // Checking access in case of offline workspace:
+                                                                       if ($errorCode = $this->BE_USER->workspaceEditState($table,$theRealPid,$tempdata['t3ver_wsid']))        {
+
+                                                                                       // Auto-creation of version: In offline workspace, test if versioning is enabled and look for workspace version of input record. If there is no versionized record found we will create one and save to that.
+                                                                               if ($TCA[$table]['ctrl']['versioningWS']
+                                                                                               && $theRealPid >= 0
+                                                                                               && !t3lib_BEfunc::getWorkspaceVersionOfRecord($this->BE_USER->workspace, $table, $id, 'uid'))   {       // If offline workspace:
+                                                                                       if (!$this->BE_USER->workspaceRec['disable_autocreate'])        {
+                                                                                               $tce = t3lib_div::makeInstance('t3lib_TCEmain');
+                                                                                               $tce->stripslashes_values = 0;
+
+                                                                                                       // Setting up command for creating a new version of the record:
+                                                                                               $cmd = array();
+                                                                                               $cmd[$table][$id]['version'] = array(
+                                                                                                       'action' => 'new',
+                                                                                                       'treeLevels' => -1,     // Default is to create a version of the individual records...
+                                                                                                       'label' => 'Auto-created for WS #'.$this->BE_USER->workspace
+                                                                                               );
+                                                                                               $tce->start(array(),$cmd);
+                                                                                               $tce->process_cmdmap();
+
+                                                                                               if ($tce->copyMappingArray[$table][$id])        {
+                                                                                                       $id = $this->autoVersionIdMap[$table][$id] = $tce->copyMappingArray[$table][$id];
+                                                                                               } else {
+                                                                                                       $this->log($table,$id,2,0,1,"Auto-creation of version failed!");
+                                                                                                       $recordAccess = FALSE;          // Versioning is required and it must be offline version!
+                                                                                               }
+                                                                                       } else {
+                                                                                               $this->log($table,$id,2,0,1,"Auto-creation of version not allowed in workspace!");
+                                                                                               $recordAccess = FALSE;          // Versioning is required and it must be offline version!
+                                                                                       }
+                                                                               } else {
+                                                                                       $this->log($table,$id,2,0,1,"Could not be edited in offline workspace in the branch where found (failure state ".$errorCode.").",2,array($propArr['header'],$table.':'.$id),$propArr['event_pid']);
+                                                                                       $recordAccess = FALSE;          // Versioning is required and it must be offline version!
+                                                                               }
+                                                                       }
                                                                }
                                                        }
                                                        $status = 'update';     // the default is 'update'
@@ -564,26 +633,30 @@ class t3lib_TCEmain       {
                                                        if ($status=='new' && $table=='pages' && is_array($TSConfig['permissions.']))   {
                                                                $fieldArray = $this->setTSconfigPermissions($fieldArray,$TSConfig['permissions.']);
                                                        }
-
+                                                       if ($createNewVersion)  $newVersion_placeholderFieldArray = $fieldArray;
                                                        $fieldArray = $this->fillInFieldArray($table,$id,$fieldArray,$incomingFieldArray,$theRealPid,$status,$tscPID);
 
                                                                // NOTICE! All manipulation beyond this point bypasses both "excludeFields" AND possible "MM" relations / file uploads to field!
 
                                                        $fieldArray = $this->overrideFieldArray($table,$fieldArray);    // NOTICE: This overriding is potentially dangerous; permissions per field is not checked!!!
+                                                       if ($createNewVersion)  $newVersion_placeholderFieldArray = $this->overrideFieldArray($table,$newVersion_placeholderFieldArray);
 
                                                                // Setting system fields
                                                        if ($status=='new')     {
                                                                if ($TCA[$table]['ctrl']['crdate'])     {
                                                                        $fieldArray[$TCA[$table]['ctrl']['crdate']]=time();
+                                                                       if ($createNewVersion)  $newVersion_placeholderFieldArray[$TCA[$table]['ctrl']['crdate']]=time();
                                                                }
                                                                if ($TCA[$table]['ctrl']['cruser_id'])  {
                                                                        $fieldArray[$TCA[$table]['ctrl']['cruser_id']]=$this->userid;
+                                                                       if ($createNewVersion)  $newVersion_placeholderFieldArray[$TCA[$table]['ctrl']['cruser_id']]=$this->userid;
                                                                }
                                                        } elseif ($this->checkSimilar) {        // Removing fields which are equal to the current value:
                                                                $fieldArray = $this->compareFieldArrayWithCurrentAndUnset($table,$id,$fieldArray);
                                                        }
                                                        if ($TCA[$table]['ctrl']['tstamp'])     {
                                                                $fieldArray[$TCA[$table]['ctrl']['tstamp']]=time();
+                                                               if ($createNewVersion)  $newVersion_placeholderFieldArray[$TCA[$table]['ctrl']['tstamp']]=time();
                                                        }
 
                                                                // Hook: processDatamap_postProcessFieldArray
@@ -597,8 +670,25 @@ class t3lib_TCEmain        {
                                                                // Kasper: Unsetting the fieldArray is dangerous; MM relations might be saved already and files could have been uploaded that are now "lost"
                                                        if (is_array($fieldArray)) {
                                                                if ($status=='new')     {
-       //                                                              if ($pid_value<0)       {$fieldArray = $this->fixCopyAfterDuplFields($table,$id,abs($pid_value),0,$fieldArray);}        // Out-commented 02-05-02: I couldn't understand WHY this is needed for NEW records. Obviously to proces records being copied? Problem is that the fields are not set anyways and the copying function should basically take care of this!
-                                                                       $this->insertDB($table,$id,$fieldArray,FALSE,$incomingFieldArray['uid']);
+                                                                       if ($createNewVersion)  {       // This creates a new version of the record with online placeholder and offline version
+                                                                               $newVersion_placeholderFieldArray['t3ver_label'] = 'INITIAL PLACEHOLDER';
+                                                                               $newVersion_placeholderFieldArray['t3ver_state'] = 1;   // Setting placeholder state value for temporary record
+                                                                               $newVersion_placeholderFieldArray[$TCA[$table]['ctrl']['label']] = '[PLACEHOLDER]';
+                                                                               $this->insertDB($table,$id,$newVersion_placeholderFieldArray,FALSE);    // Saving placeholder as 'original'
+
+                                                                                       // For the actual new offline version, set versioning values to point to placeholder:
+                                                                               $fieldArray['pid']=-1;
+                                                                               $fieldArray['t3ver_oid'] = $this->substNEWwithIDs[$id];
+                                                                               $fieldArray['t3ver_id'] = 1;
+                                                                               $fieldArray['t3ver_label'] = 'First offline version';
+                                                                               $fieldArray['t3ver_wsid'] = $this->BE_USER->workspace;
+                                                                               if ($table==='pages') {         // Swap mode set to "branch" so we can build branches for pages.
+                                                                                       $fieldArray['t3ver_swapmode'] = 1;
+                                                                               }
+                                                                               $this->insertDB($table,$id,$fieldArray,TRUE,0,TRUE);    // When inserted, $this->substNEWwithIDs[$id] will be changed to the uid of THIS version and so the interface will pick it up just nice!
+                                                                       } else {
+                                                                               $this->insertDB($table,$id,$fieldArray,FALSE,$incomingFieldArray['uid']);
+                                                                       }
                                                                } else {
                                                                        $this->updateDB($table,$id,$fieldArray);
                                                                }
@@ -721,6 +811,11 @@ class t3lib_TCEmain        {
                                                break;
                                                case 't3ver_oid':
                                                case 't3ver_id':
+                                               case 't3ver_wsid':
+                                               case 't3ver_state':
+                                               case 't3ver_swapmode':
+                                               case 't3ver_count':
+                                               case 't3ver_tstamp':
                                                        // t3ver_label is not here because it CAN be edited as a regular field!
                                                break;
                                                default:
@@ -736,9 +831,9 @@ class t3lib_TCEmain {
                                                                                $diffStorageFlag = TRUE;
                                                                        }
                                                                }
+                                                       } elseif ($TCA[$table]['ctrl']['origUid']===$field) {   // Allow value for original UID to pass by...
+                                                               $fieldArray[$field] = $fieldValue;
                                                        }
-
-
                                                break;
                                        }
                                }       // Checking language.
@@ -1142,7 +1237,9 @@ class t3lib_TCEmain       {
                        $out = array(
                                'header' => $row[$TCA[$table]['ctrl']['label']],
                                'pid' => $row['pid'],
-                               'event_pid' => ($table=='pages'?$row['uid']:$row['pid'])
+                               'event_pid' => ($table=='pages'?$row['uid']:$row['pid']),
+                               't3ver_state' => $TCA[$table]['ctrl']['versioningWS'] ? $row['t3ver_state'] : '',
+                               '_ORIG_pid' => $row['_ORIG_pid']
                        );
                        return $out;
                }
@@ -2359,7 +2456,7 @@ class t3lib_TCEmain       {
         * @param       integer         Suggested UID value for the inserted record. See the array $this->suggestedInsertUids; Admin-only feature
         * @return      void
         */
-       function insertDB($table,$id,$fieldArray,$newVersion=FALSE,$suggestedUid=0    {
+       function insertDB($table,$id,$fieldArray,$newVersion=FALSE,$suggestedUid=0,$dontSetNewIdIndex=FALSE)    {
                global $TCA;
 
                if (is_array($fieldArray) && is_array($TCA[$table]) && isset($fieldArray['pid']))       {
@@ -2390,8 +2487,10 @@ class t3lib_TCEmain      {
                                                // Set mapping for NEW... -> real uid:
                                        $NEW_id = $id;          // the NEW_id now holds the 'NEW....' -id
                                        $id = $GLOBALS['TYPO3_DB']->sql_insert_id();
-                                       $this->substNEWwithIDs[$NEW_id] = $id;
-                                       $this->substNEWwithIDs_table[$NEW_id] = $table;
+                                       if (!$dontSetNewIdIndex)        {
+                                               $this->substNEWwithIDs[$NEW_id] = $id;
+                                               $this->substNEWwithIDs_table[$NEW_id] = $table;
+                                       }
 
                                                // Checking the record is properly saved and writing to log
                                        if ($this->checkStoredRecords)  {
@@ -2650,6 +2749,13 @@ class t3lib_TCEmain      {
        function process_cmdmap() {
                global $TCA, $TYPO3_CONF_VARS;
 
+                       // Editing frozen:
+               if ($this->BE_USER->workspace!==0 && $this->BE_USER->workspaceRec['freeze'])    {
+                       $this->log('',0,4,0,1,'All editing in this workspace has been frozen!');
+                       return FALSE;
+               }
+
+                       // Hook initialization:
                $hookObjectsArr = array();
                if (is_array ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processCmdmapClass'])) {
                        foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processCmdmapClass'] as $classRef) {
@@ -2677,7 +2783,7 @@ class t3lib_TCEmain       {
                                                        // Get command and value (notice, only one command is observed at a time!):
                                                reset($incomingCmdArray);
                                                $command = key($incomingCmdArray);
-                                               $value = current($incomingCmdArray);
+                                               $value = current($incomingCmdArray);
 
                                                foreach($hookObjectsArr as $hookObj) {
                                                        if (method_exists($hookObj, 'processCmdmap_preProcess')) {
@@ -2694,14 +2800,16 @@ class t3lib_TCEmain     {
                                                                $this->moveRecord($table,$id,$value);
                                                        break;
                                                        case 'copy':
-                                                               if ($table == 'pages')  {
+                                                               if ($table === 'pages') {
                                                                        $this->copyPages($id,$value);
                                                                } else {
                                                                        $this->copyRecord($table,$id,$value,1);
                                                                }
                                                        break;
                                                        case 'localize':
-                                                               $this->copyRecord_localize($table,$id,$value);
+                                                               if ($this->BE_USER->workspace===0)      {               // TEMPORARY: Disabled for now...
+                                                                       $this->copyRecord_localize($table,$id,$value);
+                                                               }
                                                        break;
                                                        case 'version':
                                                                switch ((string)$value['action'])       {
@@ -2714,15 +2822,26 @@ class t3lib_TCEmain     {
                                                                                }
                                                                        break;
                                                                        case 'swap':
-                                                                               $this->version_swap($table,$id,$value['swapWith'],$value['swapContent']);
+                                                                               $this->version_swap($table,$id,$value['swapWith'],$value['swapIntoWS']);
+                                                                       break;
+                                                                       case 'clearWSID':
+                                                                               $this->version_clearWSID($table,$id);
                                                                        break;
                                                                }
                                                        break;
                                                        case 'delete':
-                                                               if ($table == 'pages')  {
-                                                                       $this->deletePages($id);
-                                                               } else {
-                                                                       $this->deleteRecord($table,$id, 0);
+                                                               $delRec = t3lib_BEfunc::getRecord($table, $id);
+                                                               if (is_array($delRec))  {
+                                                                       if ($this->BE_USER->workspaceTestPID($delRec['pid'], $table))   {       // Directly delete:
+                                                                               if ($table === 'pages') {
+                                                                                       $this->deletePages($id);
+                                                                               } else {
+                                                                                       $this->deleteRecord($table,$id, 0);
+                                                                               }
+                                                                       } else {
+                                                                               $this->versionizeTree = -1;
+                                                                               $this->versionizeRecord($table,$id,'DELETED!',TRUE);
+                                                                       }
                                                                }
                                                        break;
                                                }
@@ -2739,7 +2858,6 @@ class t3lib_TCEmain       {
                                }
                        }
                }
-
 #debug($this->copyMappingArray_merged,'$this->copyMappingArray_merged');
 #debug($this->registerDBList,'$this->registerDBList');
 
@@ -2766,7 +2884,7 @@ class t3lib_TCEmain       {
                if ($TCA[$table])       {
                        $propArr = $this->getRecordProperties($table,$uid);     // Get this before we change the pid (for logging)
                        $resolvedPid = $this->resolvePid($table,$destPid);      // This is the actual pid of the moving.
-
+#debug($propArr);
                                // Finding out, if the record may be moved from where it is. If the record is a non-page, then it depends on edit-permissions.
                                // If the record is a page, then there are two options: If the page is moved within itself, (same pid) it's edit-perms of the pid. If moved to another place then its both delete-perms of the pid and new-page perms on the destination.
                        if ($table!='pages' || $resolvedPid==$propArr['pid'])   {
@@ -2782,6 +2900,19 @@ class t3lib_TCEmain      {
                                $mayInsertAccess = $this->checkRecordUpdateAccess($table,$uid);
                        }
 
+                               // Check workspace permissions:
+                       if (!strcmp($propArr['_ORIG_pid'],'') && (int)$propArr['t3ver_state']==1)       {               // Element was an online version AND it was in "New state" so it can be moved...
+                               // Nothing.
+                       } else {
+                               $workspaceAccessBlocked = '';
+                               if (!$this->BE_USER->workspaceTestPID($resolvedPid,$table))     {
+                                       $workspaceAccessBlocked.='Could not insert record from table "'.$table.'" in destination PID "'.$resolvedPid.'" ';
+                               }
+                               if (!$this->BE_USER->workspaceTestPID($propArr['pid'],$table))  {
+                                       $workspaceAccessBlocked.='Could not remove record from table "'.$table.'" from its page "'.$propArr['pid'].'" ';
+                               }
+                       }
+
                                // Checking if the pid is negativ, but no sorting row is defined. In that case, find the correct pid. Basically this check make the error message 4-13 meaning less... But you can always remove this check if you prefer the error instead of a no-good action (which is to move the record to its own page...)
                        if ($destPid<0 && !$sortRow)    {
                                $destPid = $resolvedPid;
@@ -2794,6 +2925,7 @@ class t3lib_TCEmain       {
                        }
 
                                // If moving is allowed, begin the processing:
+               if (!$workspaceAccessBlocked)   {
                        if ($mayMoveAccess)     {
                                if ($destPid>=0)        {       // insert as first element on page (where uid = $destPid)
                                        if ($mayInsertAccess)   {
@@ -2885,6 +3017,9 @@ class t3lib_TCEmain       {
                        } else {
                                $this->log($table,$uid,4,0,1,"Attempt to move record '%s' (%s) without having permissions to do so",14,array($propArr['header'],$table.':'.$uid),$propArr['event_pid']);
                        }
+               } else {
+                       $this->log($table,$uid,4,0,1,"Move attempt failed due to workspace restrictions: ".$workspaceAccessBlocked,14,array($propArr['header'],$table.':'.$uid),$propArr['event_pid']);
+               }
                }
        }
 
@@ -2908,7 +3043,7 @@ class t3lib_TCEmain       {
                        if ($this->doesRecordExist($table,$uid,'show')) {               // This checks if the record can be selected which is all that a copy action requires.
                                $data = Array();
 
-                               $nonFields = array_unique(t3lib_div::trimExplode(',','uid,perms_userid,perms_groupid,perms_user,perms_group,perms_everybody,t3ver_oid,t3ver_id,t3ver_label,'.$excludeFields,1));
+                               $nonFields = array_unique(t3lib_div::trimExplode(',','uid,perms_userid,perms_groupid,perms_user,perms_group,perms_everybody,t3ver_oid,t3ver_wsid,t3ver_id,t3ver_label,t3ver_state,t3ver_swapmode,t3ver_count,t3ver_tstamp,'.$excludeFields,1));
 
                                $row = $this->recordInfo($table,$uid,'*');
                                if (is_array($row))     {
@@ -2962,11 +3097,16 @@ class t3lib_TCEmain     {
                                                                // Add value to array.
                                                        $data[$table][$theNewID][$field] = $value;
                                                }
+                                       }
 
-                                                       // Overriding values:
-                                               if ($TCA[$table]['ctrl']['editlock'])   {
-                                                       $data[$table][$theNewID][$TCA[$table]['ctrl']['editlock']] = 0;
-                                               }
+                                               // Overriding values:
+                                       if ($TCA[$table]['ctrl']['editlock'])   {
+                                               $data[$table][$theNewID][$TCA[$table]['ctrl']['editlock']] = 0;
+                                       }
+
+                                               // Setting original UID:
+                                       if ($TCA[$table]['ctrl']['origUid'])    {
+                                               $data[$table][$theNewID][$TCA[$table]['ctrl']['origUid']] = $uid;
                                        }
 
                                                // Do the copy by simply submitting the array through TCEmain:
@@ -2996,7 +3136,7 @@ class t3lib_TCEmain       {
 
        /**
         * Copying records, but makes a "raw" copy of a record.
-        * Basically the only thing observed is field processing like the copying of files and correct of ids. All other fields are 1-1 copied.
+        * Basically the only thing observed is field processing like the copying of files and correction of ids. All other fields are 1-1 copied.
         * Technically the copy is made with THIS instance of the tcemain class contrary to copyRecord() which creates a new instance and uses the processData() function.
         * The copy is created by insertNewCopyVersion() which bypasses most of the regular input checking associated with processData() - maybe copyRecord() should even do this as well!?
         * This function is used to create new versions of a record.
@@ -3017,7 +3157,7 @@ class t3lib_TCEmain       {
                        if ($this->doesRecordExist($table,$uid,'show')) {
 
                                        // Set up fields which should not be processed. They are still written - just passed through no-questions-asked!
-                               $nonFields = array('uid','pid','t3ver_id','t3ver_oid','t3ver_label','perms_userid','perms_groupid','perms_user','perms_group','perms_everybody');
+                               $nonFields = array('uid','pid','t3ver_id','t3ver_oid','t3ver_wsid','t3ver_label','t3ver_state','t3ver_swapmode','t3ver_count','t3ver_tstamp','perms_userid','perms_groupid','perms_user','perms_group','perms_everybody');
 
                                        // Select main record:
                                $row = $this->recordInfo($table,$uid,'*');
@@ -3045,6 +3185,11 @@ class t3lib_TCEmain      {
                                                // Force versioning related fields:
                                        $row['pid'] = $pid;
 
+                                               // Setting original UID:
+                                       if ($TCA[$table]['ctrl']['origUid'])    {
+                                               $row[$TCA[$table]['ctrl']['origUid']] = $uid;
+                                       }
+
                                                // Do the copy by internal function
                                        $theNewSQLID = $this->insertNewCopyVersion($table,$row,$pid);
                                        if ($theNewSQLID)       {
@@ -3391,12 +3536,12 @@ class t3lib_TCEmain     {
         * @return      integer         Returns the id of the new version (if any)
         * @see copyRecord()
         */
-       function versionizeRecord($table,$id,$label)    {
+       function versionizeRecord($table,$id,$label,$delete=FALSE)      {
                global $TCA;
 
                $id = intval($id);
 
-               if ($TCA[$table] && $TCA[$table]['ctrl']['versioning'] && $id>0)        {
+               if ($TCA[$table] && $TCA[$table]['ctrl']['versioningWS'] && $id>0)      {
                        if ($this->doesRecordExist($table,$id,'show') && $this->doesRecordExist($table,$id,'edit'))     {
 
                                        // Select main record:
@@ -3404,32 +3549,54 @@ class t3lib_TCEmain     {
                                if (is_array($row))     {
                                        if ($row['pid']>=0)     {
 
-                                                       // Look for next version number:
-                                               $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
-                                                       't3ver_id',
-                                                       $table,
-                                                       '(t3ver_oid='.$id.' || uid='.$id.')'.$this->deleteClause($table),
-                                                       '',
-                                                       't3ver_id DESC',
-                                                       '1'
-                                               );
-                                               list($highestVerNumber) = $GLOBALS['TYPO3_DB']->sql_fetch_row($res);
-
-                                                       // Look for version number of the current:
-                                               $subVer = $row['t3ver_id'].'.'.($highestVerNumber+1);
-
-                                                       // Set up the values to override when making a raw-copy:
-                                               $overrideArray = array(
-                                                       't3ver_id' => $highestVerNumber+1,
-                                                       't3ver_oid' => $id,
-                                                       't3ver_label' => ($label ? $label : $subVer.' / '.date('d-m-Y H:m:s'))
-                                               );
-                                               if ($TCA[$table]['ctrl']['editlock'])   {
-                                                       $overrideArray[$TCA[$table]['ctrl']['editlock']] = 0;
+                                                       // Checking if the record already has a version in the current workspace of the backend user
+                                               $workspaceCheck = TRUE;
+                                               if ($this->BE_USER->workspace!==0)      {
+                                                               // Look for version already in workspace:
+                                                       $workspaceCheck = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
+                                                               'uid',
+                                                               $table,
+                                                               '(t3ver_oid='.$id.' || uid='.$id.')
+                                                                       AND t3ver_wsid='.intval($this->BE_USER->workspace).
+                                                                       $this->deleteClause($table)
+                                                       ) ? FALSE : TRUE;
                                                }
 
-                                                       // Create raw-copy and return result:
-                                               return $this->copyRecord_raw($table,$id,-1,$overrideArray);
+                                               if ($workspaceCheck)    {
+                                                               // Look for next version number:
+                                                       $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
+                                                               't3ver_id',
+                                                               $table,
+                                                               '(t3ver_oid='.$id.' || uid='.$id.')'.$this->deleteClause($table),
+                                                               '',
+                                                               't3ver_id DESC',
+                                                               '1'
+                                                       );
+                                                       list($highestVerNumber) = $GLOBALS['TYPO3_DB']->sql_fetch_row($res);
+
+                                                               // Look for version number of the current:
+                                                       $subVer = $row['t3ver_id'].'.'.($highestVerNumber+1);
+
+                                                               // Set up the values to override when making a raw-copy:
+                                                       $overrideArray = array(
+                                                               't3ver_id' => $highestVerNumber+1,
+                                                               't3ver_oid' => $id,
+                                                               't3ver_label' => ($label ? $label : $subVer.' / '.date('d-m-Y H:m:s')),
+                                                               't3ver_wsid' => $this->BE_USER->workspace,
+                                                               't3ver_state' => $delete ? 2 : 0,
+                                                               't3ver_count' => 0,
+                                                               't3ver_tstamp' => 0
+                                                       );
+                                                       if ($TCA[$table]['ctrl']['editlock'])   {
+                                                               $overrideArray[$TCA[$table]['ctrl']['editlock']] = 0;
+                                                       }
+                                                       if ($table==='pages')   {
+                                                               $overrideArray['t3ver_swapmode'] = $this->versionizeTree;
+                                                       }
+
+                                                               // Create raw-copy and return result:
+                                                       return $this->copyRecord_raw($table,$id,-1,$overrideArray);
+                                               } else $this->log($table,$id,0,0,1,'Record you wanted to versionize was already a version in the workspace (wsid='.$this->BE_USER->workspace.')!');
                                        } else $this->log($table,$id,0,0,1,'Record you wanted to versionize was already a version in archive (pid=-1)!');
                                } else $this->log($table,$id,0,0,1,'Record you wanted to versionize didnt exist!');
                        } else $this->log($table,$id,0,0,1,'You didnt have correct permissions to make a new version (copy) of this record "'.$table.'" / '.$id);
@@ -3456,7 +3623,7 @@ class t3lib_TCEmain       {
                $verTablesArray = array();
                $allTables = array_keys($TCA);
                foreach($allTables as $tN)      {
-                       if ($tN!='pages' && $TCA[$tN]['ctrl']['versioning_followPages'] && ($this->admin || in_array($tN, $allowedTablesArray)))        {
+                       if ($tN!='pages' && ($this->versionizeTree>0 || $TCA[$tN]['ctrl']['versioning_followPages']) && ($this->admin || in_array($tN, $allowedTablesArray)))   {
                                $verTablesArray[] = $tN;
                        }
                }
@@ -3469,7 +3636,7 @@ class t3lib_TCEmain       {
                        $this->rawCopyPageContent($uid,$theNewRootID,$verTablesArray);
 
                                // If we're going to copy recursively...:
-                       if ($theNewRootID && $this->versionizeTree > 0) {
+                       if ($theNewRootID && $this->versionizeTree>0)   {
 
                                        // Get ALL subpages to copy:
                                $CPtable = $this->int_pageTreeInfo(Array(), $uid, intval($this->versionizeTree), $theNewRootID);
@@ -3523,10 +3690,10 @@ class t3lib_TCEmain     {
         * @param       string          Table name
         * @param       integer         UID of the online record to swap
         * @param       integer         UID of the archived version to swap with!
-        * @param       string          If set, swap content; If set then - for pages - the page content PIDs are swapped as well. If set to "ALL" then subpages are swapped as well!
+        * @param       boolean         If set, swaps online into workspace instead of publishing out of workspace.
         * @return      void
         */
-       function version_swap($table,$id,$swapWith,$swapContent)        {
+       function version_swap($table,$id,$swapWith,$swapIntoWS=0)       {
                global $TCA;
 
                /*
@@ -3553,14 +3720,17 @@ class t3lib_TCEmain     {
                */
 
                        // First, check if we may actually edit this record:
-               if ($this->checkRecordUpdateAccess($table,$id)) {
+               if ($this->checkRecordUpdateAccess($table,$id) && $this->BE_USER->checkWorkspace(0))    {
 
                                // Find fields to select:
                        $keepFields = array();  // Keep-fields can be used for other fields than "sortby" if needed in the future...
-                       $selectFields = array('uid','pid','t3ver_oid');
+                       $selectFields = array('uid','pid','t3ver_oid','t3ver_wsid','t3ver_state','t3ver_count');
                        if ($TCA[$table]['ctrl']['sortby'])     {
                                $selectFields[] = $keepFields[] = $TCA[$table]['ctrl']['sortby'];
                        }
+                       if ($table==='pages')   {
+                               $selectFields[] = 't3ver_swapmode';
+                       }
                        $selectFields = array_unique($selectFields);
 
                                // Select the two versions:
@@ -3575,45 +3745,62 @@ class t3lib_TCEmain     {
                                        foreach($keepFields as $fN)     {
                                                $swapVerBaseArray[$fN] = $curVersion[$fN];
                                        }
-#debug($swapVerBaseArray);
+
                                                // Check if the swapWith record really IS a version of the original!
-                                       if ($swapVersion['pid']==-1 && $swapVersion['t3ver_oid']==$id)  {
-#debug($curVersion,'$curVersion');
-#debug($swapVersion,'$swapVersion');
+                                       if ((int)$swapVersion['pid']==-1 && (int)$curVersion['pid']>=0 && !strcmp($swapVersion['t3ver_oid'],$id))       {
+
                                                $sqlErrors=array();
 
-                                                       // Step 1:
+                                                       // Step 1: Negate ID of online version:
                                                $sArray = array();
                                                $sArray['uid'] = -intval($id);
                                                $sArray['t3ver_oid'] = intval($swapWith);
                                                $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table,'uid='.intval($id),$sArray);
                                                if ($GLOBALS['TYPO3_DB']->sql_error())  $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error();
 
-                                                       // Step 2:
+                                                       // Step 2: Set online ID for offline version:
                                                $sArray = $swapVerBaseArray;
                                                $sArray['uid'] = intval($id);
+                                               $sArray['pid'] = intval($curVersion['pid']);    // Set pid for ONLINE
                                                $sArray['t3ver_oid'] = intval($id);
-                                               $sArray['pid'] = intval($curVersion['pid']);
+                                               $sArray['t3ver_wsid'] = $swapIntoWS ? intval($curVersion['t3ver_wsid']) : 0;
+                                               $sArray['t3ver_tstamp'] = time();
                                                $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table,'uid='.intval($swapWith),$sArray);
                                                if ($GLOBALS['TYPO3_DB']->sql_error())  $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error();
 
-                                                       // Step 3:
+                                                       // Step 3: Set offline id for the previously online version:
                                                $sArray = array();
                                                $sArray['uid'] = intval($swapWith);
+                                               $sArray['pid'] = -1;    // Set pid for OFFLINE
                                                $sArray['t3ver_oid'] = intval($id);
-                                               $sArray['pid'] = -1;
+                                               $sArray['t3ver_wsid'] = $swapIntoWS ? intval($swapVersion['t3ver_wsid']) : 0;
+                                               $sArray['t3ver_tstamp'] = time();
+                                               $sArray['t3ver_count'] = $curVersion['t3ver_count']+1;  // Increment lifecycle counter
+                                               if ($table==='pages') {         // Keeping the swapmode state
+                                                       $sArray['t3ver_swapmode'] = $swapVersion['t3ver_swapmode'];
+                                               }
                                                $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table,'uid=-'.intval($id),$sArray);
                                                if ($GLOBALS['TYPO3_DB']->sql_error())  $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error();
 
+                                                       // Checking for delete:
+                                               if ($swapVersion['t3ver_state']==2)     {
+                                                       if ($table == 'pages')  {
+                                                               $this->deletePages($id);
+                                                       } else {
+                                                               $this->deleteRecord($table,$id, 1);
+                                                       }
+                                               }
+
                                                if (!count($sqlErrors)) {
                                                        $this->log($table,$id,0,0,0,'Swapping successful for table "'.$table.'" uid '.$id.'=>'.$swapWith);
 
                                                                // SWAPPING pids for subrecords:
-                                                       if ($table=='pages' && $swapContent)    {
+                                                       if ($table=='pages' && $swapVersion['t3ver_swapmode']>=0)       {
 
-                                                               // Collect table names that should be copied along with the tables:
+                                                                       // Collect table names that should be copied along with the tables:
                                                                foreach($TCA as $tN => $tCfg)   {
-                                                                       if ($TCA[$tN]['ctrl']['versioning_followPages'] || ($tN=='pages' && $swapContent==='ALL'))      {               // THIS produces the problem that some records might be left inside a versionized branch. Question is; Should ALL records swap pids, not only the versioning_followPages ones?
+                                                                       if ($swapVersion['t3ver_swapmode']>0 || $TCA[$tN]['ctrl']['versioning_followPages'])    {       // For "Branch" publishing swap ALL, otherwise for "page" publishing, swap only "versioning_followPages" tables
+#debug($tN,'SWAPPING pids for subrecords:');
                                                                                $temporaryPid = -($id+1000000);
 
                                                                                $GLOBALS['TYPO3_DB']->exec_UPDATEquery($tN,'pid='.intval($id),array('pid'=>$temporaryPid));
@@ -3641,6 +3828,17 @@ class t3lib_TCEmain      {
                } else $this->log($table,$id,0,0,1,'Error: You cannot swap versions for a record you do not have access to edit!');
        }
 
+       function version_clearWSID($table,$id)  {
+               if ($GLOBALS['TCA'][$table]['ctrl']['versioningWS'])    {
+                               // Clear workspace ID:
+                       $sArray = array();
+                       $sArray['t3ver_wsid'] = 0;
+                       $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table,'uid='.intval($id),$sArray);
+               } else {
+                       $this->log($table,$id,3,0,1,'Attempt to reset workspace for record from table which doesn\'t support versioning');
+               }
+       }
+
        /**
         * Returns array, $CPtable, of pages under the $pid going down to $counter levels
         *
@@ -4154,6 +4352,9 @@ class t3lib_TCEmain       {
                }
        }
 
+       function delete_setStateFlag($table, $id)       {
+       }
+
        /**
         * [Describe function...]
         *
index e2af995..fcec6c8 100755 (executable)
@@ -212,6 +212,7 @@ class t3lib_treeView {
 
        /**
         * If true, HTML code is also accumulated in ->tree array during rendering of the tree.
+        * If 2, then also the icon prefix code (depthData) is stored
         */
        var $makeHTML=1;
 
@@ -380,15 +381,17 @@ class t3lib_treeView {
                        }
 
                        if (is_array($rootRec)) {
+                               $uid = $rootRec['uid'];         // In case it was swapped inside getRecord due to workspaces.
+
                                        // Add the root of the mount to ->tree
-                               $this->tree[]=array('HTML'=>$firstHtml,'row'=>$rootRec,'bank'=>$this->bank);
+                               $this->tree[]=array('HTML'=>$firstHtml, 'row'=>$rootRec, 'bank'=>$this->bank);
 
                                        // If the mount is expanded, go down:
                                if ($isOpen)    {
                                                // Set depth:
                                        $depthD='<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/ol/blank.gif','width="18" height="16"').' alt="" />';
                                        if ($this->addSelfId)   $this->ids[] = $uid;
-                                       $this->getTree($uid,999,$depthD);
+                                       $this->getTree($uid,999,$depthD,'',$rootRec['_SUBCSSCLASS']);
                                }
 
                                        // Add tree:
@@ -421,9 +424,11 @@ class t3lib_treeView {
 
                foreach($treeArr as $k => $v)   {
                        $idAttr = htmlspecialchars($this->domIdPrefix.$this->getId($v['row']).'_'.$v['bank']);
+
                        $out.='
                                <tr>
-                                       <td id="'.$idAttr.'">'.
+                                       <td id="'.$idAttr.'"'.
+                                               ($v['row']['_CSSCLASS'] ? ' class="'.$v['row']['_CSSCLASS'].'"' : '').'>'.
                                                $v['HTML'].
                                                $this->wrapTitle($this->getTitleStr($v['row'],$titleLen),$v['row'],$v['bank']).
                                        '</td>
@@ -646,9 +651,9 @@ class t3lib_treeView {
         */
        function getIcon($row) {
                if ($this->iconPath && $this->iconName) {
-                       $icon = '<img'.t3lib_iconWorks::skinImg('',$this->iconPath.$this->iconName,'width="18" height="16"').' alt="" />';
+                       $icon = '<img'.t3lib_iconWorks::skinImg('',$this->iconPath.$this->iconName,'width="18" height="16"').' alt="" title="UID: '.$row['uid'].'" />';
                } else {
-                       $icon = t3lib_iconWorks::getIconImage($this->table,$row,$this->backPath,'align="top" class="c-recIcon"');
+                       $icon = t3lib_iconWorks::getIconImage($this->table,$row,$this->backPath,'align="top" class="c-recIcon" title="UID: '.$row['uid'].'"');
                }
 
                return $this->wrapIcon($icon,$row);
@@ -726,9 +731,10 @@ class t3lib_treeView {
         * @param       integer         Max depth (recursivity limit)
         * @param       string          HTML-code prefix for recursive calls.
         * @param       string          ? (internal)
+        * @param       string          CSS class to use for <td> sub-elements
         * @return      integer         The count of items on the level
         */
-       function getTree($uid, $depth=999, $depthData='',$blankLineCode='')     {
+       function getTree($uid, $depth=999, $depthData='',$blankLineCode='',$subCSSclass='')     {
 
                        // Buffer for id hierarchy is reset:
                $this->buffer_idH=array();
@@ -739,12 +745,12 @@ class t3lib_treeView {
                $HTML='';
                $a=0;
 
-               $res = $this->getDataInit($uid);
+               $res = $this->getDataInit($uid,$subCSSclass);
                $c = $this->getDataCount($res);
                $crazyRecursionLimiter = 999;
 
                        // Traverse the records:
-               while ($crazyRecursionLimiter>0 && $row = $this->getDataNext($res))     {
+               while ($crazyRecursionLimiter>0 && $row = $this->getDataNext($res,$subCSSclass))        {
                        $a++;
                        $crazyRecursionLimiter--;
 
@@ -760,16 +766,18 @@ class t3lib_treeView {
                        }
 
                                // Accumulate the id of the element in the internal arrays
-                       $this->ids[]=$idH[$row['uid']]['uid']=$row['uid'];
-                       $this->ids_hierarchy[$depth][]=$row['uid'];
+                       $this->ids[]=$idH[$row['uid']]['uid'] = $row['uid'];
+                       $this->ids_hierarchy[$depth][] = $row['uid'];
 
                                // Make a recursive call to the next level
+                       $HTML_depthData = $depthData.'<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/ol/'.$LN.'.gif','width="18" height="16"').' alt="" />';
                        if ($depth>1 && $this->expandNext($newID) && !$row['php_tree_stop'])    {
                                $nextCount=$this->getTree(
                                                $newID,
                                                $depth-1,
-                                               $this->makeHTML?$depthData.'<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/ol/'.$LN.'.gif','width="18" height="16"').' alt="" />':'',
-                                               $blankLineCode.','.$LN
+                                               $this->makeHTML ? $HTML_depthData : '',
+                                               $blankLineCode.','.$LN,
+                                               $row['_SUBCSSCLASS']
                                        );
                                if (count($this->buffer_idH))   $idH[$row['uid']]['subrow']=$this->buffer_idH;
                                $exp=1; // Set "did expand" flag
@@ -789,6 +797,7 @@ class t3lib_treeView {
                        $this->tree[$treeKey] = Array(
                                'row'=>$row,
                                'HTML'=>$HTML,
+                               'HTML_depthData' => $this->makeHTML==2 ? $HTML_depthData : '',
                                'invertedDepth'=>$depth,
                                'blankLineCode'=>$blankLineCode,
                                'bank' => $this->bank
@@ -869,7 +878,10 @@ class t3lib_treeView {
                if (is_array($this->data)) {
                        return $this->dataLookup[$uid];
                } else {
-                       return t3lib_befunc::getRecord($this->table,$uid);
+                       $row = t3lib_befunc::getRecord($this->table,$uid);
+                       t3lib_BEfunc::workspaceOL($this->table, $row, $this->BE_USER->workspace);
+
+                       return $row;
                }
        }
 
@@ -882,7 +894,7 @@ class t3lib_treeView {
         * @return      mixed           data handle (Tables: An sql-resource, arrays: A parentId integer. -1 is returned if there were NO subLevel.)
         * @access private
         */
-       function getDataInit($parentId) {
+       function getDataInit($parentId,$subCSSclass='') {
                if (is_array($this->data)) {
                        if (!is_array($this->dataLookup[$parentId][$this->subLevelID])) {
                                $parentId = -1;
@@ -929,24 +941,30 @@ class t3lib_treeView {
         * @access private
         * @see getDataInit()
         */
-       function getDataNext(&$res){
+       function getDataNext(&$res,$subCSSclass=''){
                if (is_array($this->data)) {
                        if ($res<0) {
                                $row=FALSE;
                        } else {
                                list(,$row) = each($this->dataLookup[$res][$this->subLevelID]);
 
-                               /*
-                               if (!is_array($row))    {
-                                       $row=FALSE;
-                               } else {
-                                       unset($row['subLevel']);
+                                       // Passing on default <td> class for subelements:
+                               if (is_array($row) && $subCSSclass!=='')        {
+                                       $row['_CSSCLASS'] = $row['_SUBCSSCLASS'] = $subCSSclass;
                                }
-                               */
                        }
                        return $row;
                } else {
-                       return @$GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
+                       $row = @$GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
+                       t3lib_BEfunc::workspaceOL($this->table, $row, $this->BE_USER->workspace);
+
+                               // Passing on default <td> class for subelements:
+                       if (is_array($row) && $subCSSclass!=='')        {
+                               if (!isset($row['_CSSCLASS']))  $row['_CSSCLASS'] = $subCSSclass;
+                               if (!isset($row['_SUBCSSCLASS']))       $row['_SUBCSSCLASS'] = $subCSSclass;
+                       }
+
+                       return $row;
                }
        }
 
index aadc3d5..1b56a3b 100755 (executable)
@@ -756,6 +756,7 @@ class t3lib_tsparser_ext extends t3lib_TStemplate   {
                        }
                        $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_template', 'pid='.intval($id).$addC.' '.$this->whereClause, '', 'sorting', '1');
                        $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
+                       t3lib_BEfunc::workspaceOL('sys_template',$row);
                        $GLOBALS['TYPO3_DB']->sql_free_result($res);
                        return $row;    // Returns the template row if found.
                }
@@ -773,7 +774,8 @@ class t3lib_tsparser_ext extends t3lib_TStemplate   {
                        $outRes=array();
                        $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_template', 'pid='.intval($id).' '.$this->whereClause, '', 'sorting');
                        while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))       {
-                               $outRes[] = $row;
+                               t3lib_BEfunc::workspaceOL('sys_template',$row);
+                               if (is_array($row))             $outRes[] = $row;
                        }
                        $GLOBALS['TYPO3_DB']->sql_free_result($res);
                        return $outRes; // Returns the template rows in an array.
@@ -1632,8 +1634,10 @@ class t3lib_tsparser_ext extends t3lib_TStemplate        {
                        $resList = $tmp_upload_name.",".$resList;
                        $resList=implode(t3lib_div::trimExplode(",",$resList,1),",");
                                // Making data-array
+                       $saveId = $tplRow['_ORIG_uid'] ? $tplRow['_ORIG_uid'] : $tplRow['uid'];
+debug($saveId);
                        $recData=array();
-                       $recData["sys_template"][$tplRow["uid"]]["resources"] = $resList;
+                       $recData["sys_template"][$saveId]["resources"] = $resList;
                                // Saving
                        $tce = t3lib_div::makeInstance("t3lib_TCEmain");
                        $tce->stripslashes_values=0;
@@ -1643,7 +1647,8 @@ class t3lib_tsparser_ext extends t3lib_TStemplate {
 
                        t3lib_div::unlink_tempfile($tmp_upload_name);
 
-                       $tmpRow = t3lib_BEfunc::getRecord("sys_template",$tplRow["uid"],"resources");
+                       $tmpRow = t3lib_BEfunc::getRecord("sys_template",$saveId,"resources");
+
                        $tplRow["resources"] = $tmpRow["resources"];
 
                                // Setting the value
index 4f4a2e4..4df74c0 100755 (executable)
@@ -207,7 +207,7 @@ class t3lib_TStemplate      {
         * @see tslib_fe::initTemplate()
         */
        function init() {
-                       // $this->whereClause is used only to select templates from sys_template.
+                       // $this->whereClause is used only to select templates from sys_template.
                        // $GLOBALS['SIM_EXEC_TIME'] is used so that we're able to simulate a later time as a test...
                $this->whereClause='AND deleted=0 ';
                if (!$GLOBALS['TSFE']->showHiddenRecords)       {
@@ -416,8 +416,11 @@ class t3lib_TStemplate     {
                                $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_template', 'uid='.intval($this->nextLevel).' '.$this->whereClause);
                                $this->nextLevel = 0;
                                if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
-                                       $this->processTemplate($row,'sys_'.$row['uid'],$this->absoluteRootLine[$a]['uid'],'sys_'.$row['uid']);
-                                       $this->outermostRootlineIndexWithTemplate=$a;
+                                       $this->versionOL($row);
+                                       if (is_array($row))     {
+                                               $this->processTemplate($row,'sys_'.$row['uid'],$this->absoluteRootLine[$a]['uid'],'sys_'.$row['uid']);
+                                               $this->outermostRootlineIndexWithTemplate=$a;
+                                       }
                                }
                                $GLOBALS['TYPO3_DB']->sql_free_result($res);
                        }
@@ -428,8 +431,11 @@ class t3lib_TStemplate     {
 
                        $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_template', 'pid='.intval($this->absoluteRootLine[$a]['uid']).$addC.' '.$this->whereClause,'','sorting',1);
                        if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
-                               $this->processTemplate($row,'sys_'.$row['uid'],$this->absoluteRootLine[$a]['uid'],'sys_'.$row['uid']);
-                               $this->outermostRootlineIndexWithTemplate=$a;
+                               $this->versionOL($row);
+                               if (is_array($row))     {
+                                       $this->processTemplate($row,'sys_'.$row['uid'],$this->absoluteRootLine[$a]['uid'],'sys_'.$row['uid']);
+                                       $this->outermostRootlineIndexWithTemplate=$a;
+                               }
                        }
                        $GLOBALS['TYPO3_DB']->sql_free_result($res);
                        $this->rootLine[] = $this->absoluteRootLine[$a];
@@ -486,7 +492,10 @@ class t3lib_TStemplate     {
                                if ($id && !t3lib_div::inList($idList,'sys_'.$id))      {       // if $id is not allready included ...
                                        $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_template', 'uid='.$id.' '.$this->whereClause);
                                        if ($subrow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))      {       // there was a template, then we fetch that
-                                               $this->processTemplate($subrow,$idList.',sys_'.$id,$pid, 'sys_'.$id,$templateID);
+                                               $this->versionOL($subrow);
+                                               if (is_array($subrow))  {
+                                                       $this->processTemplate($subrow,$idList.',sys_'.$id,$pid, 'sys_'.$id,$templateID);
+                                               }
                                        }
                                        $GLOBALS['TYPO3_DB']->sql_free_result($res);
                                }
@@ -496,7 +505,10 @@ class t3lib_TStemplate     {
                                        if (!t3lib_div::inList($idList,'sys_'.$id))     {       // if $id is not allready included ...
                                                $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_template', 'uid='.intval($id).' '.$this->whereClause);
                                                if ($subrow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))      {       // there was a template, then we fetch that
-                                                       $this->processTemplate($subrow,$idList.',sys_'.$id,$pid, 'sys_'.$id,$templateID);
+                                                       $this->versionOL($subrow);
+                                                       if (is_array($subrow))  {
+                                                               $this->processTemplate($subrow,$idList.',sys_'.$id,$pid, 'sys_'.$id,$templateID);
+                                                       }
                                                }
                                                $GLOBALS['TYPO3_DB']->sql_free_result($res);
                                        }
@@ -665,6 +677,14 @@ class t3lib_TStemplate     {
                return $subrow;
        }
 
+       function versionOL(&$row)       {
+               if (is_object($GLOBALS['TSFE']))        {       // Frontend:
+                       $GLOBALS['TSFE']->sys_page->versionOL('sys_template',$row);
+               } else {        // Backend:
+                       t3lib_BEfunc::workspaceOL('sys_template',$row);
+               }
+       }
+
 
 
 
index f381970..e314586 100755 (executable)
@@ -120,6 +120,8 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
        var $groupData = Array(                         // This array holds lists of eg. tables, fields and other values related to the permission-system. See fetchGroupData
                'filemounts' => Array()                 // Filemounts are loaded here
        );
+       var $workspace = -99;                           // User workspace. -99 is ERROR (none available), -1 is offline, 0 is online, >0 is custom workspaces.
+       var $workspaceRec = array();            // Custom workspace record if any
 
        var $userGroups = Array();                      // This array will hold the groups that the user is a member of
        var $userGroupsUID = Array();           // This array holds the uid's of the groups in the listed order
@@ -134,6 +136,7 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
                'non_exclude_fields'=>'',
                'explicit_allowdeny'=>'',
                'allowed_languages' => '',
+               'workspace_perms' => '',
                'custom_options' => '',
        );
        var $includeHierarchy=array();          // For debugging/display of order in which subgroups are included.
@@ -231,7 +234,6 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
                if ($id>0)      {
                        $wM = $this->returnWebmounts();
                        $rL = t3lib_BEfunc::BEgetRootLine($id,' AND '.$readPerms);
-
                        foreach($rL as $v)      {
                                if ($v['uid'] && in_array($v['uid'],$wM))       {
                                        return $v['uid'];
@@ -257,11 +259,26 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
                                t3lib_BEfunc::typo3PrintError ('Fatal Error','This module "'.$conf['name'].'" is not enabled in TBE_MODULES',0);
                                exit;
                        }
-                       return false;
+                       return FALSE;
+               }
+
+                       // Workspaces check:
+               if ($conf['workspaces'])        {</