diff --git a/.travis.yml b/.travis.yml index bac020e13c5..10a2b6e8347 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,6 +37,7 @@ php: - '5.6' - '7.0' - '7.1' +- '7.2' #- hhvm only with dist: trusty - nightly @@ -71,6 +72,8 @@ matrix: env: DB=postgresql - php: '7.0' env: DB=postgresql + - php: '7.1' + env: DB=postgresql - php: hhvm env: DB=postgresql - php: nightly @@ -79,7 +82,7 @@ matrix: notifications: email: on_success: never # [always|never|change] default: change - on_failure: change # [always|never|change] default: always + on_failure: never # [always|never|change] default: always irc: channels: - "chat.freenode.net#dolibarr" @@ -123,7 +126,10 @@ install: if [ "$TRAVIS_PHP_VERSION" = '5.3' ] || [ "$TRAVIS_PHP_VERSION" = '5.4' ] || [ "$TRAVIS_PHP_VERSION" = '5.5' ]; then composer -n require phpunit/phpunit ^4 fi - if [ "$TRAVIS_PHP_VERSION" = '5.6' ] || [ "$TRAVIS_PHP_VERSION" = '7.0' ] || [ "$TRAVIS_PHP_VERSION" = '7.1' ] || [ "$TRAVIS_PHP_VERSION" = 'nightly' ]; then + if [ "$TRAVIS_PHP_VERSION" = '5.6' ] || [ "$TRAVIS_PHP_VERSION" = '7.0' ] || [ "$TRAVIS_PHP_VERSION" = '7.1' ]; then + composer -n require phpunit/phpunit ^5 + fi + if [ "$TRAVIS_PHP_VERSION" = '7.2' ] || [ "$TRAVIS_PHP_VERSION" = 'nightly' ]; then composer -n require phpunit/phpunit ^5 fi echo @@ -163,7 +169,7 @@ before_script: #echo 'extension = apc.so' >> ~/.phpenv/versions/$PHP_VERSION_NAME/etc/php.ini echo echo "Enabling Memcached for PHP <= 5.4" - # Documentation says it should be available for all PHP versions but it's not for 5.5 and 5.6, 7.0, 7.1 and nightly! + # Documentation says it should be available for all PHP versions but it's not for 5.5 and 5.6, 7.0, 7.1, 7.2 and nightly! echo 'extension = memcached.so' >> ~/.phpenv/versions/$PHP_VERSION_NAME/etc/php.ini fi phpenv rehash @@ -237,7 +243,7 @@ before_script: echo "Setting up Apache + FPM" # enable php-fpm cp ~/.phpenv/versions/$PHP_VERSION_NAME/etc/php-fpm.conf.default ~/.phpenv/versions/$PHP_VERSION_NAME/etc/php-fpm.conf - if [ "$TRAVIS_PHP_VERSION" = '7.0' ] || [ "$TRAVIS_PHP_VERSION" = '7.1' ] || [ "$TRAVIS_PHP_VERSION" = 'nightly' ]; then + if [ "$TRAVIS_PHP_VERSION" = '7.0' ] || [ "$TRAVIS_PHP_VERSION" = '7.1' ] || [ "$TRAVIS_PHP_VERSION" = '7.2' ] || [ "$TRAVIS_PHP_VERSION" = 'nightly' ]; then # Copy the included pool cp ~/.phpenv/versions/$PHP_VERSION_NAME/etc/php-fpm.d/www.conf.default ~/.phpenv/versions/$PHP_VERSION_NAME/etc/php-fpm.d/www.conf fi @@ -313,30 +319,34 @@ script: php upgrade2.php 3.9.0 4.0.0 MAIN_MODULE_API,MAIN_MODULE_SUPPLIERPROPOSAL > $TRAVIS_BUILD_DIR/upgrade390400-2.log php step5.php 3.9.0 4.0.0 > $TRAVIS_BUILD_DIR/upgrade390400-3.log php upgrade.php 4.0.0 5.0.0 ignoredbversion > $TRAVIS_BUILD_DIR/upgrade400500.log - php upgrade2.php 4.0.0 5.0.0 MAIN_MODULE_API,MAIN_MODULE_SUPPLIERPROPOSAL > $TRAVIS_BUILD_DIR/upgrade400500-2.log + php upgrade2.php 4.0.0 5.0.0 > $TRAVIS_BUILD_DIR/upgrade400500-2.log php step5.php 4.0.0 5.0.0 > $TRAVIS_BUILD_DIR/upgrade400500-3.log php upgrade.php 5.0.0 6.0.0 ignoredbversion > $TRAVIS_BUILD_DIR/upgrade500600.log - php upgrade2.php 5.0.0 6.0.0 MAIN_MODULE_API,MAIN_MODULE_SUPPLIERPROPOSAL > $TRAVIS_BUILD_DIR/upgrade500600-2.log + php upgrade2.php 5.0.0 6.0.0 > $TRAVIS_BUILD_DIR/upgrade500600-2.log php step5.php 5.0.0 6.0.0 > $TRAVIS_BUILD_DIR/upgrade500600-3.log php upgrade.php 6.0.0 7.0.0 ignoredbversion > $TRAVIS_BUILD_DIR/upgrade600700.log - php upgrade2.php 6.0.0 7.0.0 MAIN_MODULE_API,MAIN_MODULE_SUPPLIERPROPOSAL > $TRAVIS_BUILD_DIR/upgrade600700-2.log + php upgrade2.php 6.0.0 7.0.0 MAIN_MODULE_WEBSITE,MAIN_MODULE_SUPPLIERPROPOSAL > $TRAVIS_BUILD_DIR/upgrade600700-2.log php step5.php 6.0.0 7.0.0 > $TRAVIS_BUILD_DIR/upgrade600700-3.log cd - set +e echo #cat $TRAVIS_BUILD_DIR/upgrade400500-2.log + #cat $TRAVIS_BUILD_DIR/upgrade500600.log + #cat $TRAVIS_BUILD_DIR/upgrade500600-2.log + #cat $TRAVIS_BUILD_DIR/upgrade500600-3.log #cat /tmp/dolibarr_install.log - | echo "Unit testing" - # Ensure we catch errors. Set this to +e if you want to go to the end to see log file. + phpunit --version + # Ensure we catch errors. Set this to +e if you want to go to the end to see dolibarr.log file. set -e phpunit -d memory_limit=-1 -c test/phpunit/phpunittest.xml test/phpunit/AllTests.php set +e - | #echo "Output dolibarr.log" - #echo cat documents/dolibarr.log + #cat documents/dolibarr.log after_script: - | diff --git a/COPYRIGHT b/COPYRIGHT index 427784a1552..bd3565c3bd1 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -34,12 +34,11 @@ Swift Mailer 5.4.2-DEV MIT license Yes Stripe 4.7.0 MIT licence Yes Library for Stripe module JS libraries: -jQuery 1.11.3 MIT License Yes JS library -jQuery UI 1.11.4 GPL and MIT License Yes JS library plugin UI -jQuery select2 3.5.2 GPL and Apache License Yes JS library plugin for sexier multiselect +jQuery 3.1.1 MIT License Yes JS library +jQuery UI 1.12.1 GPL and MIT License Yes JS library plugin UI +jQuery select2 4.0.5 GPL and Apache License Yes JS library plugin for sexier multiselect jQuery blockUI 2.70.0 GPL and MIT License Yes JS library plugin blockUI (to use ajax popups) jQuery Colorpicker 1.1 MIT License Yes JS library for color picker for a defined list of colors -jQuery FileUpload 5.0.3 GPL and MIT License Yes JS library to upload files jQuery Flot 0.8.3 MIT License Yes JS library to build graph jQuery JCrop 0.9.8 GPL and MIT License Yes JS library plugin Crop (to crop images) jQuery Jeditable 1.7.1 GPL and MIT License Yes JS library plugin jeditable (to edit in place) @@ -49,8 +48,7 @@ jQuery jqueryFileTree 1.0.1 GPL and MIT License Yes jQuery jquerytreeview 1.4.1 MIT License Yes JS library for filetree jQuery TableDnD 0.6 GPL and MIT License Yes JS library plugin TableDnD (to reorder table rows) jQuery Timepicker 1.1.0 GPL and MIT License Yes JS library Timepicker addon for Datepicker -jQuery Tiptip 1.3 GPL and MIT License Yes JS library for tooltips -jsGanttImproved 1.7.5.2 BSD License Yes JS library (to build Gantt reports) +jsGanttImproved 1.7.5.4 BSD License Yes JS library (to build Gantt reports) JsTimezoneDetect 1.0.6 MIT License Yes JS library to detect user timezone SwaggerUI 2.0.24 GPL-2+ Yes JS library to offer the REST API explorer Ace 1.2.8 BSD Yes JS library to get code syntaxique coloration in a textarea. diff --git a/ChangeLog b/ChangeLog index c64bec0d881..fadc6d705bb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,18 +2,181 @@ English Dolibarr ChangeLog -------------------------------------------------------------- +***** ChangeLog for 6.0.5 compared to 6.0.4 ***** +FIX: security vulnerability reported by ADLab of Venustech + CVE-2017-17897, CVE-2017-17898, CVE-2017-17899, CVE-2017-17900 +FIX: #7379: Compatibility with PRODUCT_USE_OLD_PATH_FOR_PHOTO variable +FIX: #7903 +FIX: #7933 +FIX: #8029 Unable to make leave request in holyday module +FIX: Edit accountancy account and warning message on loan +FIX: $accounts[$bid] is a label ! +FIX: $oldvatrateclean & $newvatrateclean must be set if preg_match === false +FIX: product best price on product list +FIX: search on contact list +FIX: stats trad for customerinvoice +FIX: translate unactivate on contractline + +***** ChangeLog for 6.0.4 compared to 6.0.3 ***** +FIX: #7737 +FIX: #7751 +FIX: #7756 Add better error message +FIX: #7786 +FIX: #7806 +FIX: #7824 +FIX: add line bad price and ref +FIX: A lot of several fix on local taxes and NPR tax +FIX: createfromorder +FIX: CSS for IE10 +FIX: external user cannot be set as internal +FIX: Filter type on actioncomm with multiselect doesn't work +FIX: list of donation not filtered on multicompany +FIX: list of module not complete when module mb_strlen not available +FIX: Locatax were not propagated when cloning order or proposal +FIX: Searching translation should not be case sensitive +FIX: Search into language is ok for file into external modules two. +FIX: test for filter fk_status +FIX: too much users on holiday list +FIX: Wrong alias sql + ***** ChangeLog for 7.0.0 compared to 6.0.* ***** +For users: + +For developers: +NEW: Add hook addAdminLdapOptions and doAction in ldap admin page +NEW: complete_head_from_modules() in ldap_prepare_head() WARNING: -Following changes may create regression for some external modules, but were necessary to make Dolibarr better: -* The methode "cloture" on contact were renamed into "closeAll". +If you enabled (for test) the experimental BlockedLog module before 7.0, you must purge the table llx_blockedlog because +way to save data for final version has changed. + +Following changes may create regressions for some external modules, but were necessary to make Dolibarr better: +* The methode "cloture" on contract were renamed into "closeAll". +* The method "is_erasable" of invoice return a value <= 0 if not erasable (value is meaning) instead of always 0. +* The substitution key for reference of objects is now __REF__ whatever is the object (it replaces __ORDERREF__, + __PROPALREF__, ...) +* The substition key __SIGNATURE__ was renamed into __USER_SIGNATURE__ to follow naming conventions. +* Substitution keys with syntax %XXX% were renamed into __XXX__ to match others. +* Removed old deprecated REST API (APIs found into '/root' section of the REST API explorer in Dolibarr v6). +* Some REST API to access setup features, like dictionaries (country, town, extrafields, ...) were moved into a + common API "/setup". +* The REST API /documents were renamed into /documents/download and /documents/upload. +* Page bank/index.php, bank/bankentries.php and comm/actions/listactions.php were renamed into + bank/list.php, bank/bankentries_list.php and comm/actions/list.php to follow page naming + conventions (so default filter/sort order features can also work for this pages). +* The trigger ORDER_SUPPLIER_STATUS_ONPROCESS was renamed into ORDER_SUPPLIER_STATUS_ORDERED. +* The trigger ORDER_SUPPLIER_STATUS_RECEIVED_ALL was renamed into ORDER_SUPPLIER_STATUS_RECEIVED_COMPLETELY. +* The parameter note into method cloture() is added at end of private note (previously in v6, it replaced). +* The parameter $user is now mandatory for method createFromOrder and createFromPropal. +* Removed js library 'fileupload' that was not used by core code. +* Jquery plugin tableDnd updated. You now need to use decodeURI on the return value of tableDnDSerialize() + and add 'td.' to the beginning of the dragHandle match string. +* IE8 and earlier and Firefox 12 and earlier (< 2012) are no more supported. +***** ChangeLog for 6.0.3 compared to 6.0.2 ***** +FIX: #7211 Update qty dispatched on qty change +FIX: #7458 +FIX: #7593 +FIX: #7616 +FIX: #7619 +FIX: #7626 +FIX: #7648 +FIX: #7675 +FIX: Agenda events are not exported in the ICAL, VCAL if begin exactly with the same $datestart +FIX: API to get object does not return data of linked objects +FIX: Bad localtax apply +FIX: Bad ressource list in popup in gantt view +FIX: bankentries search conciliated if val 0 +FIX: hook formObjectOptions() must use $expe and not $object +FIX: make of link to other object during creation +FIX: Missing function getLinesArray +FIX: old batch not shown in multi shipping +FIX: paid supplier invoices are shown as abandoned +FIX: selection of thirdparty was lost on stats page of invoices +FIX: sql syntax error because of old field accountancy_journal +FIX: Stats on invoices show nothing +FIX: substitution in ODT of thirdparties documents +FIX: wrong key in selectarray +FIX: wrong personnal project time spent +***** ChangeLog for 6.0.2 compared to 6.0.1 ***** +FIX: #7148 +FIX: #7288 +FIX: #7366 renaming table with pgsql +FIX: #7435 Can't add payment term +FIX: #7461 +FIX: #7464 +FIX: #7471 +FIX: #7473 Mass update of vat rates and other bugs on localtax +FIX: #7475 +FIX: #7486 Empty value for multicurrency rate must be forbidden +FIX: #7490 +FIX: #7505 +FIX: #7510 Bug: extrafield content disappear when generate pdf within intervention +FIX: #7514 +FIX: #7531 #7537 +FIX: #7541 +FIX: #7546 +FIX: #7550 +FIX: #7554 +FIX: #7567 +FIX: Accountancy export model for Agiris Isacompta +FIX: Allow create shipping if STOCK_SUPPORTS_SERVICES option is enabled +FIX: Bad preview on scroping when special file names +FIX: Generation of invoice from bulk action "Bill Orders" +FIX: Implementation of a Luracast recommandation for the REST api server (#7370) +FIX: Missing space in request +FIX: Only modified values must be modified +FIX: replenish if line test GETPOST on line 0 +FIX: Stripe not working on live mode +FIX: wrong basePath in the swagger view +FIX: Implementation of a Luracast recommandation for the REST api server + +***** ChangeLog for 6.0.1 compared to 6.0.* ***** +FIX: #7000 Dashboard link for late pending payment supplier invoices do not work +FIX: #7325 Default VAT rate when editing template invoices is 0% +FIX: #7330 +FIX: #7359 +FIX: #7367 +FIX: #7368 +FIX: #7391 +FIX: #7420 +FIX: Add some missing attributes in Adherent:makeSubstitution (type, phone… +FIX: Bad const name +FIX: Bad link to unpayed suppliers invoices +FIX: Better protection to no send email when we change limit +FIX: Calculation in the activity box +FIX: Clean bad parameters when inserting line of template invoice +FIX: dateSelector was not taken into account +FIX: hidden option MAIN_PROPAGATE_CONTACTS_FROM_ORIGIN +FIX: journalization for bank journal should not rely on a label. +FIX: menu enty when url is external link +FIX: missing supplier qty and supplier discount in available fields for product export. +FIX: multicompany better accuracy in rounding and with revenue stamp. +FIX: Must use pdf format page as default for merging PDF. +FIX: PDF output was sharing 2 different currencies in same total +FIX: Position of signature on strato template +FIX: Protection to avoid to apply credit note discount > remain to pay +FIX: Remove warning when using log into syslog +FIX: Responsive +FIX: Security fixes (filter onload js, less verbose error message in +FIX: SEPA recording payment must save one payment in bank per customer +FIX: Several problem with the last event box on project/tasks +FIX: Sign of amount in origin currency on credit note created from lines +FIX: Some page of admin were not responsive +FIX: SQL injection +FIX: time.php crashed without project id in param +FIX: transfer of line extrafields from order to invoice +FIX: Upgrade missing on field +FIX: View of timespent for another user +FIX: ODT generation +FIX: CVE-2017-9840, CVE-2017-14238, CVE-2017-14239, CVE-2017-14240, CVE-2017-14241, + CVE-2017-14242 + ***** ChangeLog for 6.0.0 compared to 5.0.* ***** - NEW: Add experimental BlockeLog module (to log business events in a non reversible log file). NEW: Add a payment module for Stripe. NEW: Add module "Product variant" (like red, blue for the product shoes) @@ -162,6 +325,23 @@ Following changes may create regression for some external modules, but were nece content by doing a print into function, sometimes by returning content into "resprint". This has been fixed to follow hook specifications so you must return output into "resprint". + +***** ChangeLog for 5.0.7 compared to 5.0.6 ***** +FIX: #7000 Dashboard link for late pending payment supplier invoices do not work +FIX: #7148 +FIX: #7325 Default VAT rate when editing template invoices is 0% +FIX: #7366 renaming table with pgsql +FIX: #7391 +FIX: #7510 Bug: extrafield content disappear when generate pdf within intervention +FIX: Agenda events are not exported in the ICAL, VCAL if begin exactly with the same $datestart +FIX: Bad link to unpayed suppliers invoices +FIX: bankentries search conciliated if val 0 +FIX: multicompany better accuracy in rounding and with revenue stamp. +FIX: PDF output was sharing 2 different currencies in same total +FIX: Upgrade missing on field +FIX: wrong key in selectarray +FIX: wrong personnal project time spent + ***** ChangeLog for 5.0.6 compared to 5.0.5 ***** FIX: Removed a bad symbolic link into custom directory. FIX: Renaming a resource ref rename also the directory of attached files. diff --git a/build/doxygen/dolibarr-doxygen.doxyfile b/build/doxygen/dolibarr-doxygen.doxyfile index 912c72b4d69..271b64f5481 100644 --- a/build/doxygen/dolibarr-doxygen.doxyfile +++ b/build/doxygen/dolibarr-doxygen.doxyfile @@ -442,7 +442,7 @@ SORT_BY_SCOPE_NAME = NO # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. -GENERATE_TODOLIST = YES +GENERATE_TODOLIST = NO # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test @@ -639,7 +639,7 @@ EXCLUDE_SYMBOLS = # directories that contain example code fragments that are included (see # the \include command). -EXAMPLE_PATH = ../../dev/skeletons +EXAMPLE_PATH = ../../htdocs/modulebuilder/template # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp diff --git a/build/exe/doliwamp/Languages/MyEnglish.isl b/build/exe/doliwamp/Languages/MyEnglish.isl index 6e70f3c12f3..11d2e4456bd 100644 --- a/build/exe/doliwamp/Languages/MyEnglish.isl +++ b/build/exe/doliwamp/Languages/MyEnglish.isl @@ -43,3 +43,5 @@ DoliWampWillStartApacheMysql=DoliWamp installer will now start or restart Apache OldVersionFoundAndMoveInNew=An old database version has been found and moved to be used by new Dolibarr version OldVersionFoundButFailedToMoveInNew=An old database version has been found but could not be moved to be used with new Dolibarr version +DLLMissing=The "Visual C++ Redistributable for Visual Studio 2012" component is missing. Please install the 32-bit version (vcredit_x86.exe) first from https://www.microsoft.com/en-us/download/details.aspx?id=30679 and restart DoliWamp installation/upgrade. +ContinueAnyway=Continue anyway (install process may fails without this prerequisite) diff --git a/build/exe/doliwamp/doliwamp.iss b/build/exe/doliwamp/doliwamp.iss index 2ef8ab32f22..7dcb8c738bd 100644 --- a/build/exe/doliwamp/doliwamp.iss +++ b/build/exe/doliwamp/doliwamp.iss @@ -32,7 +32,7 @@ AppPublisherURL=http://www.nltechno.com AppSupportURL=http://www.dolibarr.org AppUpdatesURL=http://www.dolibarr.org AppComments=DoliWamp includes Dolibarr, Apache, PHP and Mysql softwares. -AppCopyright=Copyright (C) 2008-2016 Laurent Destailleur, NLTechno +AppCopyright=Copyright (C) 2008-2017 Laurent Destailleur (NLTechno), Fabian Rodriguez (Le Goût du Libre) DefaultDirName=c:\dolibarr DefaultGroupName=Dolibarr ;LicenseFile=COPYING @@ -202,10 +202,30 @@ var value: String; function InitializeSetup(): Boolean; begin Result := MsgBox(CustomMessage('YouWillInstallDoliWamp')+#13#13+CustomMessage('ThisAssistantInstallOrUpgrade')+#13#13+CustomMessage('IfYouHaveTechnicalKnowledge')+#13#13+CustomMessage('ButIfYouLook')+#13#13+CustomMessage('DoYouWantToStart'), mbConfirmation, MB_YESNO) = IDYES; + + if Result then + begin + + //---------------------------------------------- + // Test if msvcr110 DLL has been installed + //---------------------------------------------- + + if not FileExists ('c:/windows/system32/msvcr110.dll') and not FileExists ('c:/windows/sysWOW64/msvcr110.dll') and not FileExists ('c:/winnt/system32/msvcr110.dll') and not FileExists ('c:/winnt/sysWOW64/msvcr110.dll') then + begin + // TODO - offer to install the component by opening the URL in the default browser, abort installation if user doesn't accept + Result := MsgBox(CustomMessage('DLLMissing')+#13#13+CustomMessage('ContinueAnyway'), mbConfirmation, MB_YESNO) = IDYES; + + end; + // Pb seems similar with msvcp110.dll + //vcredist_x64.exe + + end; + end; procedure InitializeWizard(); begin + //version des applis, a modifier pour chaque version de WampServer 2 apacheVersion := '2.4.9'; phpVersion := '5.5.12' ; @@ -217,6 +237,7 @@ begin mysqlPort := '3306'; newPassword := 'changeme'; + firstinstall := true; @@ -344,19 +365,6 @@ begin exedirold := pathWithSlashes+'/bin/mysql/mysql5.0.45'; exedirnew := pathWithSlashes+'/bin/mysql/mysql5.0.45'; - - //---------------------------------------------- - // Test if msvcr110 DLL has been installed - //---------------------------------------------- - - if not FileExists ('c:/windows/system32/msvcr110.dll') and not FileExists ('c:/windows/sysWOW64/msvcr110.dll') and not FileExists ('c:/winnt/system32/msvcr110.dll') and not FileExists ('c:/winnt/sysWOW64/msvcr110.dll') then - begin - // TODO Copy file or ask to install package ? - //CustomMessage('YouWillInstallDoliWamp')+#13#13 - MsgBox('The package vcredist_x86.exe must have been installed first. It seems it is not. Please install it first from http://www.microsoft.com/en-us/download/details.aspx?id=30679 then restart DoliWamp installation/upgrade.',mbInformation,MB_OK); - end; - // Pb seems similar with msvcp110.dll - //vcredist_x64.exe // If we have a new database version, we should only copy old my.ini file into new directory diff --git a/build/exe/doliwamp/index.php.install b/build/exe/doliwamp/index.php.install index 700f0707de2..1c657b35977 100644 --- a/build/exe/doliwamp/index.php.install +++ b/build/exe/doliwamp/index.php.install @@ -535,7 +535,7 @@ a:hover {
  • {$langues[$langue]['autreLangue1']} - {$langues[$langue]['autreLangue2']}


  • -
  • Provided by NLTechno
  • +
  • Provided by NLTechno

  • @@ -580,7 +580,7 @@ a:hover { diff --git a/build/generate_filelist_xml.php b/build/generate_filelist_xml.php index 0d3d90d54d4..e6336e30e97 100755 --- a/build/generate_filelist_xml.php +++ b/build/generate_filelist_xml.php @@ -131,7 +131,7 @@ $iterator1 = new RecursiveIteratorIterator($dir_iterator1); $files = new RegexIterator($iterator1, '#^(?:[A-Z]:)?(?:/(?!(?:'.($includecustom?'':'custom\/|').'documents\/|conf\/|install\/))[^/]+)+/[^/]+\.(?:php|css|html|js|json|tpl|jpg|png|gif|sql|lang)$#i'); */ $regextoinclude='\.(php|css|html|js|json|tpl|jpg|png|gif|sql|lang)$'; -$regextoexclude='('.($includecustom?'':'custom|').'documents|conf|install)$'; // Exclude dirs +$regextoexclude='('.($includecustom?'':'custom|').'documents|conf|install|public\/test|Shared\/PCLZip|nusoap\/lib\/Mail|php\/example|php\/test|geoip\/sample.*\.php|ckeditor\/samples|ckeditor\/adapters)$'; // Exclude dirs $files = dol_dir_list(DOL_DOCUMENT_ROOT, 'files', 1, $regextoinclude, $regextoexclude, 'fullname'); $dir=''; $needtoclose=0; diff --git a/build/makepack-dolibarr.pl b/build/makepack-dolibarr.pl index 80cc9b0856c..bc755ef52a3 100755 --- a/build/makepack-dolibarr.pl +++ b/build/makepack-dolibarr.pl @@ -366,7 +366,9 @@ if ($nboftargetok) { } else # For a maintenance release { - print 'cd ~/git/dolibarr_'.$MAJOR.'.'.$MINOR.'; git log '.$MAJOR.'.'.$MINOR.'.'.($BUILD-1).'.. --no-merges --pretty=short --oneline | sed -e "s/^[0-9a-z]* //" | grep -e \'^FIX\|NEW\' | sort -u | sed \'s/FIXED:/FIX:/g\' | sed \'s/FIXED :/FIX:/g\' | sed \'s/FIX :/FIX:/g\' | sed \'s/FIX /FIX: /g\' | sed \'s/NEW :/NEW:/g\' | sed \'s/NEW /NEW: /g\' > /tmp/aaa'; + #print 'cd ~/git/dolibarr_'.$MAJOR.'.'.$MINOR.'; git log '.$MAJOR.'.'.$MINOR.'.'.($BUILD-1).'.. --no-merges --pretty=short --oneline | sed -e "s/^[0-9a-z]* //" | grep -e \'^FIX\|NEW\' | sort -u | sed \'s/FIXED:/FIX:/g\' | sed \'s/FIXED :/FIX:/g\' | sed \'s/FIX :/FIX:/g\' | sed \'s/FIX /FIX: /g\' | sed \'s/NEW :/NEW:/g\' | sed \'s/NEW /NEW: /g\' > /tmp/aaa'; + print 'cd ~/git/dolibarr_'.$MAJOR.'.'.$MINOR.'; git log '.$MAJOR.'.'.$MINOR.'.'.($BUILD-1).'.. | grep -v "Merge branch" | grep -v "Merge pull" | grep "^ " | sed -e "s/^[0-9a-z]* *//" | grep -e \'^FIX\|NEW\' | sort -u | sed \'s/FIXED:/FIX:/g\' | sed \'s/FIXED :/FIX:/g\' | sed \'s/FIX :/FIX:/g\' | sed \'s/FIX /FIX: /g\' | sed \'s/NEW :/NEW:/g\' | sed \'s/NEW /NEW: /g\' > /tmp/aaa'; + } print "\n"; if (! $ret) @@ -554,9 +556,6 @@ if ($nboftargetok) { $ret=`rm -f $BUILDROOT/$PROJECT/.cvsignore $BUILDROOT/$PROJECT/*/.cvsignore $BUILDROOT/$PROJECT/*/*/.cvsignore $BUILDROOT/$PROJECT/*/*/*/.cvsignore $BUILDROOT/$PROJECT/*/*/*/*/.cvsignore $BUILDROOT/$PROJECT/*/*/*/*/*/.cvsignore $BUILDROOT/$PROJECT/*/*/*/*/*/*/.cvsignore`; $ret=`rm -f $BUILDROOT/$PROJECT/.gitignore $BUILDROOT/$PROJECT/*/.gitignore $BUILDROOT/$PROJECT/*/*/.gitignore $BUILDROOT/$PROJECT/*/*/*/.gitignore $BUILDROOT/$PROJECT/*/*/*/*/.gitignore $BUILDROOT/$PROJECT/*/*/*/*/*/.gitignore $BUILDROOT/$PROJECT/*/*/*/*/*/*/.gitignore`; $ret=`rm -f $BUILDROOT/$PROJECT/htdocs/includes/geoip/sample*.*`; - $ret=`rm -f $BUILDROOT/$PROJECT/htdocs/includes/jquery/plugins/jqueryFileTree/connectors/jqueryFileTree.pl`; # Avoid errors into rpmlint - $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/jquery/plugins/template`; # Package not valid for most linux distributions (errors reported into compile.js). Package should be embed by modules to avoid problems. - $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/phpmailer`; # Package not valid for most linux distributions (errors reported into file LICENSE). Package should be embed by modules to avoid problems. $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/ckeditor/ckeditor/adapters`; # Keep this removal in case we embed libraries $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/ckeditor/ckeditor/samples`; # Keep this removal in case we embed libraries #$ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/ckeditor/_source`; # _source must be kept into tarball @@ -569,6 +568,7 @@ if ($nboftargetok) { $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/mobiledetect/mobiledetectlib/.gitmodules`; $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/nusoap/lib/Mail`; $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/nusoap/samples`; + $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/parsedown/LICENSE.txt`; $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/php-iban/docs`; $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/phpoffice/phpexcel/.gitattributes`; $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/phpoffice/phpexcel/Classes/license.md`; @@ -577,6 +577,7 @@ if ($nboftargetok) { $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/phpoffice/phpexcel/Examples`; $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/phpoffice/phpexcel/unitTests`; $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/phpoffice/phpexcel/license.md`; + $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/stripe/LICENSE`; $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/tcpdf/fonts/dejavu-fonts-ttf-*`; $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/tcpdf/fonts/freefont-*`; $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/tcpdf/fonts/ae_fonts_*`; @@ -588,6 +589,8 @@ if ($nboftargetok) { $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/tecnickcom/tcpdf/fonts/utils`; $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/tecnickcom/tcpdf/tools`; $ret=`rm -f $BUILDROOT/$PROJECT/htdocs/includes/tecnickcom/tcpdf/LICENSE.TXT`; + $ret=`rm -f $BUILDROOT/$PROJECT/htdocs/theme/common/octicons/LICENSE`; + print "Remove subdir of custom dir\n"; print "find $BUILDROOT/$PROJECT/htdocs/custom/* -type d -exec rm -fr {} \\;\n"; diff --git a/build/makepack-dolibarrmodule.pl b/build/makepack-dolibarrmodule.pl index 62002fd063b..4a9a217b570 100755 --- a/build/makepack-dolibarrmodule.pl +++ b/build/makepack-dolibarrmodule.pl @@ -3,6 +3,7 @@ # \file build/makepack-dolibarrmodule.pl # \brief Package builder (tgz, zip, rpm, deb, exe) # \author (c)2005-2014 Laurent Destailleur +# \contributor (c)2017 Nicolas ZABOURI #---------------------------------------------------------------------------- use Cwd; @@ -134,7 +135,15 @@ foreach my $PROJECT (@PROJECTLIST) { # Get version $MAJOR, $MINOR and $BUILD print "Version detected for module ".$PROJECT.": "; $result=open(IN,"<".$SOURCE."/htdocs/".$PROJECTLC."/core/modules/mod".$PROJECT.".class.php"); - if (! $result) { die "Error: Can't open descriptor file ".$SOURCE."/htdocs/".$PROJECTLC."/core/modules/mod".$PROJECT.".class.php for reading.\n"; } + $custom=false; + if (! $result) { + $result=open(IN,"<".$SOURCE."/htdocs/custom/".$PROJECTLC."/core/modules/mod".$PROJECT.".class.php"); + if (! $result) { + die "Error: Can't open descriptor file ".$SOURCE."/htdocs/(or /htdocs/custom/)".$PROJECTLC."/core/modules/mod".$PROJECT.".class.php for reading.\n"; + }else{ + $custom = true; + } + } while() { if ($_ =~ /this->version\s*=\s*'([\d\.]+)'/) { $PROJVERSION=$1; break; } @@ -294,8 +303,11 @@ foreach my $PROJECT (@PROJECTLIST) { $ret=`rm -fr $BUILDROOT/$PROJECTLC/htdocs/conf/conf.php.old`; $ret=`rm -fr $BUILDROOT/$PROJECTLC/htdocs/conf/conf.php.postgres`; $ret=`rm -fr $BUILDROOT/$PROJECTLC/htdocs/conf/conf*sav*`; + if($custom){ + $ret=`cp -r $BUILDROOT/$PROJECTLC/htdocs/custom/* $BUILDROOT/$PROJECTLC/htdocs/.`; + } $ret=`rm -fr $BUILDROOT/$PROJECTLC/htdocs/custom`; - $ret=`rm -fr $BUILDROOT/$PROJECTLC/htdocs/custom2`; + $ret=`rm -fr $BUILDROOT/$PROJECTLC/htdocs/custom2`; $ret=`rm -fr $BUILDROOT/$PROJECTLC/test`; $ret=`rm -fr $BUILDROOT/$PROJECTLC/Thumbs.db $BUILDROOT/$PROJECTLC/*/Thumbs.db $BUILDROOT/$PROJECTLC/*/*/Thumbs.db $BUILDROOT/$PROJECTLC/*/*/*/Thumbs.db $BUILDROOT/$PROJECTLC/*/*/*/*/Thumbs.db`; $ret=`rm -fr $BUILDROOT/$PROJECTLC/CVS* $BUILDROOT/$PROJECTLC/*/CVS* $BUILDROOT/$PROJECTLC/*/*/CVS* $BUILDROOT/$PROJECTLC/*/*/*/CVS* $BUILDROOT/$PROJECTLC/*/*/*/*/CVS* $BUILDROOT/$PROJECTLC/*/*/*/*/*/CVS*`; diff --git a/build/rpm/dolibarr_fedora.spec b/build/rpm/dolibarr_fedora.spec index 55898481691..077aaeb9483 100755 --- a/build/rpm/dolibarr_fedora.spec +++ b/build/rpm/dolibarr_fedora.spec @@ -213,7 +213,7 @@ done >>%{name}.lang %_datadir/dolibarr/htdocs/user %_datadir/dolibarr/htdocs/variants %_datadir/dolibarr/htdocs/webservices -%_datadir/dolibarr/htdocs/websites +%_datadir/dolibarr/htdocs/website %_datadir/dolibarr/htdocs/*.ico %_datadir/dolibarr/htdocs/*.patch %_datadir/dolibarr/htdocs/*.php diff --git a/build/rpm/dolibarr_generic.spec b/build/rpm/dolibarr_generic.spec index e5b346278ab..5b39bac7761 100755 --- a/build/rpm/dolibarr_generic.spec +++ b/build/rpm/dolibarr_generic.spec @@ -293,7 +293,7 @@ done >>%{name}.lang %_datadir/dolibarr/htdocs/user %_datadir/dolibarr/htdocs/variants %_datadir/dolibarr/htdocs/webservices -%_datadir/dolibarr/htdocs/websites +%_datadir/dolibarr/htdocs/website %_datadir/dolibarr/htdocs/*.ico %_datadir/dolibarr/htdocs/*.patch %_datadir/dolibarr/htdocs/*.php diff --git a/build/rpm/dolibarr_mandriva.spec b/build/rpm/dolibarr_mandriva.spec index 3c8a5097c0e..1034615c80a 100755 --- a/build/rpm/dolibarr_mandriva.spec +++ b/build/rpm/dolibarr_mandriva.spec @@ -210,7 +210,7 @@ done >>%{name}.lang %_datadir/dolibarr/htdocs/user %_datadir/dolibarr/htdocs/variants %_datadir/dolibarr/htdocs/webservices -%_datadir/dolibarr/htdocs/websites +%_datadir/dolibarr/htdocs/website %_datadir/dolibarr/htdocs/*.ico %_datadir/dolibarr/htdocs/*.patch %_datadir/dolibarr/htdocs/*.php diff --git a/build/rpm/dolibarr_opensuse.spec b/build/rpm/dolibarr_opensuse.spec index c77661fe420..eb1887f229f 100755 --- a/build/rpm/dolibarr_opensuse.spec +++ b/build/rpm/dolibarr_opensuse.spec @@ -221,7 +221,7 @@ done >>%{name}.lang %_datadir/dolibarr/htdocs/user %_datadir/dolibarr/htdocs/variants %_datadir/dolibarr/htdocs/webservices -%_datadir/dolibarr/htdocs/websites +%_datadir/dolibarr/htdocs/website %_datadir/dolibarr/htdocs/*.ico %_datadir/dolibarr/htdocs/*.patch %_datadir/dolibarr/htdocs/*.php diff --git a/dev/dolibarr_changes.txt b/dev/dolibarr_changes.txt index 3b9ef4cc447..9e6ab3a8ddc 100644 --- a/dev/dolibarr_changes.txt +++ b/dev/dolibarr_changes.txt @@ -82,8 +82,14 @@ with // LDR To open in same window //var OpenWindow=window.open(pRef, "newwin", "height="+vHeight+",width="+vWidth); window.location.href=pRef -* Replace hard coded string with i18n["String"]; +* Replace +vTmpDiv=this.newNode(vTmpCell, 'div', null, null, vTaskList[i].getResource()); +with +var vTmpNode=this.newNode(vTmpCell, 'div', null, ''); +vTmpNode=this.newNode(vTmpNode, 'a', null, '', vLangs[vLang]['moreinfo']); +vTmpNode.setAttribute('href',vTaskList[i].getLink()); + JCROP: ------ @@ -99,7 +105,7 @@ JQUERYFILETREE: RESTLER: -------- -* Add 2 lines into function +* Add 2 lines into file AutoLoader.php to complete function private function alias($className, $currentClass) { ... @@ -110,4 +116,57 @@ to get if ($className == 'Luracast\Restler\string') return; if ($className == 'Luracast\Restler\mixed') return; ... - \ No newline at end of file + +Change also file Luracast/Restler/explorer/index.html + ++With swagger 2: + +* Add line into Util.php to complete function + + public static function getShortName($className) + { + // @CHANGE LDR + if (! is_string($className)) return; + //var_dump($className); + + + +PARSEDOWN +--------- + +* Add support of css by adding in Parsedown.php: + + // @CHANGE LDR + 'class' => $Link['element']['attributes']['class'] + + ... + + // @CHANGE LDR + if (preg_match('/{([^}]+)}/', $remainder, $matches2)) + { + $Element['attributes']['class'] = $matches2[1]; + $remainder = preg_replace('/{'.preg_quote($matches2[1],'/').'}/', '', $remainder); + } + + + // @CHANGE LDR + //$markup .= $this->{$Element['handler']}($Element['text']); + $markup .= preg_replace('/>{[^}]+}/', '>', $this->{$Element['handler']}($Element['text'])); + + + +* Fix to avoid fatal error when mb_strlen not available: + + // @CHANGE LDR Fix when mb_strlen is not available + //$shortage = 4 - mb_strlen($line, 'utf-8') % 4; + if (function_exists('mb_strlen')) $len = mb_strlen($line, 'utf-8'); + else $len = strlen($line); + $shortage = 4 - $len % 4; + + +JEDITABLE.JS +------------ + +* '; - } - else $retstring.=''; + // Icone calendrier + if (! $disabled) + { + $retstring.=''; + } + else $retstring.=''; - $retstring.=''."\n"; - $retstring.=''."\n"; - $retstring.=''."\n"; - } - elseif ($usecalendar == 'jquery') - { - if (! $disabled) - { - $retstring.=""; - } + $retstring.=''."\n"; + $retstring.=''."\n"; + $retstring.=''."\n"; + } + elseif ($usecalendar == 'jquery') + { + if (! $disabled) + { + // Output javascript for datepicker + $retstring.=""; + } - // Zone de saisie manuelle de la date - $retstring.='trans("FormatDateShortJavaInput").'\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript - $retstring.='>'; + // Zone de saisie manuelle de la date + $retstring.='trans("FormatDateShortJavaInput").'\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript + $retstring.='>'; - // Icone calendrier - if (! $disabled) - { - /* Not required. Managed by option buttonImage of jquery + // Icone calendrier + if (! $disabled) + { + /* Not required. Managed by option buttonImage of jquery $retstring.=img_object($langs->trans("SelectDate"),'calendarday','id="'.$prefix.'id" class="datecallink"'); $retstring.="";*/ - } - else - { - $retstring.=''; - } + } + else + { + $retstring.=''; + } - $retstring.=''."\n"; - $retstring.=''."\n"; - $retstring.=''."\n"; - } - else - { - $retstring.="Bad value of MAIN_POPUP_CALENDAR"; - } - } - // Show date with combo selects - else + $retstring.=''."\n"; + $retstring.=''."\n"; + $retstring.=''."\n"; + } + else + { + $retstring.="Bad value of MAIN_POPUP_CALENDAR"; + } + } + // Show date with combo selects + else { - //$retstring.='
    '; - // Day - $retstring.=''; + //$retstring.='
    '; + // Day + $retstring.=''; - if ($emptydate || $set_time == -1) - { - $retstring.=''; - } + if ($emptydate || $set_time == -1) + { + $retstring.=''; + } - for ($day = 1 ; $day <= 31; $day++) - { - $retstring.=''; - } + for ($day = 1 ; $day <= 31; $day++) + { + $retstring.=''; + } - $retstring.=""; + $retstring.=""; - $retstring.=''; - if ($emptydate || $set_time == -1) - { - $retstring.=''; - } + $retstring.=''; + if ($emptydate || $set_time == -1) + { + $retstring.=''; + } - // Month - for ($month = 1 ; $month <= 12 ; $month++) - { - $retstring.='"; - } - $retstring.=""; + // Month + for ($month = 1 ; $month <= 12 ; $month++) + { + $retstring.='"; + } + $retstring.=""; - // Year - if ($emptydate || $set_time == -1) - { - $retstring.=''; - } - else - { - $retstring.=''; + // Year + if ($emptydate || $set_time == -1) + { + $retstring.=''; + } + else + { + $retstring.=''; - for ($year = $syear - 10; $year < $syear + 10 ; $year++) - { - $retstring.=''; - } - $retstring.="\n"; - } - //$retstring.='
    '; - } - } + for ($year = $syear - 10; $year < $syear + 10 ; $year++) + { + $retstring.=''; + } + $retstring.="\n"; + } + //$retstring.='
    '; + } + } - if ($d && $h) $retstring.=($h==2?'
    ':' '); + if ($d && $h) $retstring.=($h==2?'
    ':' '); - if ($h) - { - // Show hour - $retstring.=''; - if ($emptyhours) $retstring.=''; - for ($hour = 0; $hour < 24; $hour++) - { - if (strlen($hour) < 2) $hour = "0" . $hour; - $retstring.=''; - } - $retstring.=''; - if ($m && empty($conf->dol_optimize_smallscreen)) $retstring.=":"; - } + if ($h) + { + // Show hour + $retstring.=''; + if ($emptyhours) $retstring.=''; + for ($hour = 0; $hour < 24; $hour++) + { + if (strlen($hour) < 2) $hour = "0" . $hour; + $retstring.=''; + } + $retstring.=''; + if ($m && empty($conf->dol_optimize_smallscreen)) $retstring.=":"; + } - if ($m) - { - // Show minutes - $retstring.=''; - if ($emptyhours) $retstring.=''; - for ($min = 0; $min < 60 ; $min++) - { - if (strlen($min) < 2) $min = "0" . $min; - $retstring.=''; - } - $retstring.=''; - } + if ($m) + { + // Show minutes + $retstring.=''; + if ($emptyhours) $retstring.=''; + for ($min = 0; $min < 60 ; $min++) + { + if (strlen($min) < 2) $min = "0" . $min; + $retstring.=''; + } + $retstring.=''; - // Add a "Now" link - if ($conf->use_javascript_ajax && $addnowlink) - { - // Script which will be inserted in the onClick of the "Now" link - $reset_scripts = ""; + $retstring.=''; + } - // Generate the date part, depending on the use or not of the javascript calendar - $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date(dol_now(),'day').'\');'; - $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date(dol_now(),'%d').'\');'; - $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date(dol_now(),'%m').'\');'; - $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date(dol_now(),'%Y').'\');'; - /*if ($usecalendar == "eldy") + // Add a "Now" link + if ($conf->use_javascript_ajax && $addnowlink) + { + // Script which will be inserted in the onClick of the "Now" link + $reset_scripts = ""; + + // Generate the date part, depending on the use or not of the javascript calendar + $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date(dol_now(),'day').'\');'; + $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date(dol_now(),'%d').'\');'; + $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date(dol_now(),'%m').'\');'; + $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date(dol_now(),'%Y').'\');'; + /*if ($usecalendar == "eldy") { $base=DOL_URL_ROOT.'/core/'; $reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');'; @@ -4923,305 +5024,506 @@ class Form $reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); '; $reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); '; }*/ - // Update the hour part - if ($h) - { - if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {"; - //$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); '; - $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date(dol_now(),'%H').'\');'; - if ($fullday) $reset_scripts .= ' } '; - } - // Update the minute part - if ($m) - { - if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {"; - //$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); '; - $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date(dol_now(),'%M').'\');'; - if ($fullday) $reset_scripts .= ' } '; - } - // If reset_scripts is not empty, print the link with the reset_scripts in the onClick - if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) - { - $retstring.=' '; - } - } + // Update the hour part + if ($h) + { + if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {"; + //$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); '; + $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date(dol_now(),'%H').'\');'; + if ($fullday) $reset_scripts .= ' } '; + } + // Update the minute part + if ($m) + { + if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {"; + //$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); '; + $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date(dol_now(),'%M').'\');'; + if ($fullday) $reset_scripts .= ' } '; + } + // If reset_scripts is not empty, print the link with the reset_scripts in the onClick + if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) + { + $retstring.=' '; + } + } - // Add a "Plus one hour" link - if ($conf->use_javascript_ajax && $addplusone) - { - // Script which will be inserted in the onClick of the "Add plusone" link - $reset_scripts = ""; + // Add a "Plus one hour" link + if ($conf->use_javascript_ajax && $addplusone) + { + // Script which will be inserted in the onClick of the "Add plusone" link + $reset_scripts = ""; - // Generate the date part, depending on the use or not of the javascript calendar - $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date(dol_now(),'day').'\');'; - $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date(dol_now(),'%d').'\');'; - $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date(dol_now(),'%m').'\');'; - $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date(dol_now(),'%Y').'\');'; - // Update the hour part - if ($h) - { - if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {"; - $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date(dol_now(),'%H').'\');'; - if ($fullday) $reset_scripts .= ' } '; - } - // Update the minute part - if ($m) - { - if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {"; - $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date(dol_now(),'%M').'\');'; - if ($fullday) $reset_scripts .= ' } '; - } - // If reset_scripts is not empty, print the link with the reset_scripts in the onClick - if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) - { - $retstring.=' '; - } - } + // Generate the date part, depending on the use or not of the javascript calendar + $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date(dol_now(),'day').'\');'; + $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date(dol_now(),'%d').'\');'; + $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date(dol_now(),'%m').'\');'; + $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date(dol_now(),'%Y').'\');'; + // Update the hour part + if ($h) + { + if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {"; + $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date(dol_now(),'%H').'\');'; + if ($fullday) $reset_scripts .= ' } '; + } + // Update the minute part + if ($m) + { + if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {"; + $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date(dol_now(),'%M').'\');'; + if ($fullday) $reset_scripts .= ' } '; + } + // If reset_scripts is not empty, print the link with the reset_scripts in the onClick + if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) + { + $retstring.=' '; + } + } - // Add a "Plus one hour" link - if ($conf->use_javascript_ajax && $adddateof) - { - $tmparray=dol_getdate($adddateof); - $retstring.=' - + jsGanttImproved + + + + + + +
    +
    +
    +

    jsGanttImproved

    +

    latest v1.7.5.4

    + Download + View on GitHub +
    +
    +
    +
    + +

    +

    100% HTML + CSS + JavaScript Gantt Chart

    +
    + +

    +

    Completely FREE

    +
    + +

    +

    Open source

    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    + +
    +

    Demo

    +
    + + +
    +
    + +
    +
    + +
    +
    + +
    +

    Features

    +

    jsGanttImproved is a fully featured gantt chart component built entirely in Javascript, CSS and AJAX. It is lightweight and there is no need of external libraries or additional images.

    +
    +
    +

    Basic Features

    +
      +
    • Tasks & Collapsible Task Groups
    • +
    • Multiple Dependencies
    • +
    • Task Completion
    • +
    • Task Style
    • +
    • Milestones
    • +
    • Resources
    • +
    +
    +
    +

    Advanced Features

    +
      +
    • Dynamic Loading of Tasks
    • +
    • Dynamic change of format: Hour, Day, Week, Month, Quarter
    • +
    • + Load Gantt from: +
        +
      • External XML files (including experimental support for Microsoft Project XML files)
      • +
      • JavaScript strings
      • +
      +
    • +
    • Export Gantt as XML string
    • +
    • Support for internationalization
    • +
    +
    +
    +

    Current Known Issues:

    +
      +
    • If the browser is viewing the page at anything other than 100% zoom then bars may not be sized or positioned correctly.
    • +
    +

    Changelog:

    +

    Check the full list of changes on GitHub releases page.

    +

    v1.7.5.4:

    +
      +
    • Left part of the chart is now created first on JavaScript and establishes the left floating reference
    • +
    • Minimum width updated to 632px so that the left part of the chart has a fixed width of 532px and the right part fills out the rest with a minimum of 100px
    • +
    +

    v1.7.5.3:

    +
      +
    • Fixed group completion percentage that now is a weighted average
    • +
    • Start and end dates specified on standard group tasks will now be respected if they fall outside of the calculated group date range
    • +
    • Fixed problem that would occur if Tool Tips were disabled
    • +
    • Moved example dates forward so the current date marker is visible
    • +
    +

    v1.7.5:

    +
      +
    • Project Migrated to GitHub
    • +
    • Instantiating a new JSGantt.TaskItem will now also accept Date objects for start and end dates
    • +
    • Fixed old Internet Explorer compatibilty broken by v1.7
    • +
    • Fixed bug in Iso week date format
    • +
    • Changed to solid arrows on dependency lines to be more printer friendly
    • +
    • Code refactoring and clean up
    • +
    +

    v1.7:

    +
      +
    • + Fixed nasty long-standing bug where the first Gantt chart created must be stored in a javascript variable named "g" +
        +
      • NOTE: This required a change in the method to instatiate a JSGantt.TaskItem object to pass the related chart.
      • +
      • A temporary fix is included that still assumes the use of "g" for the chart if the chart object is not passed, this will be removed in v1.8
      • +
      +
    • +
    • Altered XML export functionality so that dates are output in the specified input format for the chart
    • +
    • Added method to read XML directly from an input string
    • +
    • Prevented creation of a task with a duplicate "unique" ID
    • +
    • Fixed bug where attempting to remove the first task defined would prevent the chart from redrawing
    • +
    • Some general code clean up
    • +
    +
    + +
    +

    Usage

    +

    Following the steps below you will be able to get create a basic Gantt Chart. If you notice any bugs, please post them to GitHub issues.

    +
      +
    1. + Include JSGantt CSS and Javascript +
      <link rel="stylesheet" type="text/css" href="jsgantt.css" />
      +<script language="javascript" src="jsgantt.js"></script>
      +
    2. +
    3. + Create a div element to hold the gantt chart +
      <div style="position:relative" class="gantt" id="GanttChartDIV"></div>
      +
    4. +
    5. + Start a <script> block +
      <script type="text/javascript">
      +
    6. +
    7. + Instantiate JSGantt using GanttChart() +
      var g = new JSGantt.GanttChart(document.getElementById('GanttChartDIV'), 'day');
      +

      Method definition: + GanttChart(pDiv, pFormat) +

      +

      + + + + + + + + +
      pDiv:(required) this is a DIV object created in HTML
      pFormat:(required) - used to indicate whether chart should be drawn in "hour", "day", "week", "month", or "quarter" format

      +
    8. +
    9. +

      Customize the look and feel using configuration methods (see Configuration Options)

      +
    10. +
    11. + Add Tasks +
        +
      • + using AddTaskItem() +
        g.AddTaskItem(new JSGantt.TaskItem(1, 'Define Chart API','',          '',          'ggroupblack','', 0, 'Brian', 0,  1,0,1,'','','Some Notes text',g));
        +g.AddTaskItem(new JSGantt.TaskItem(11,'Chart Object',    '2016-02-20','2016-02-20','gmilestone', '', 1, 'Shlomy',100,0,1,1,'','','',g));
        +                
        +

        Method definition: + TaskItem(pID, pName, pStart, pEnd, pColor, pLink, pMile, pRes, pComp, pGroup, pParent, pOpen, pDepend, pCaption, pNotes, pGantt) +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        pID:(required) a unique numeric ID used to identify each row
        pName:(required) the task Label
        pStart:(required) the task start date, can enter empty date ('') for groups. You can also enter specific time (2016-02-20 12:00) for additional precision.
        pEnd:(required) the task end date, can enter empty date ('') for groups
        pClass:(required) the css class for this task
        pLink:(optional) any http link to be displayed in tool tip as the "More information" link.
        pMile:(optional) indicates whether this is a milestone task - Numeric; 1 = milestone, 0 = not milestone
        pRes:(optional) resource name
        pComp:(required) completion percent, numeric
        pGroup:(optional) indicates whether this is a group task (parent) - Numeric; 0 = normal task, 1 = standard group task, 2 = combined group task*
        pParent:(required) identifies a parent pID, this causes this task to be a child of identified task. Numeric, top level tasks should have pParent set to 0
        pOpen:(required) indicates whether a standard group task is open when chart is first drawn. Value must be set for all items but is only used by standard group tasks. Numeric, 1 = open, 0 = closed
        pDepend: + (optional) comma separated list of id's this task is dependent on. A line will be drawn from each listed task to this item
        Each id can optionally be followed by a dependency type suffix. Valid values are: +
        'FS' - Finish to Start (default if suffix is omitted)
        'SF' - Start to Finish
        'SS' - Start to Start
        'FF' - Finish to Finish
        + If present the suffix must be added directly to the id e.g. '123SS' +
        pCaption:(optional) caption that will be added after task bar if CaptionType set to "Caption"
        pNotes:(optional) Detailed task information that will be displayed in tool tip for this task
        pGantt:(required) javascript JSGantt.GanttChart object from which to take settings. Defaults to "g" for backwards compatibility
        +

        * Combined group tasks show all sub-tasks on one row. The information displayed in the task list and row caption are taken from the parent task. Tool tips are generated individually for each sub-task from its own information. Milestones are not valid as sub-tasks of a combined group task and will not be displayed. No bounds checking of start and end dates of sub-tasks is performed therefore it is possible for these task bars to overlap. Dependencies can be set to and from sub-tasks only.

        +
      • +
      • + using parseXML() with an external XML file +
        JSGantt.parseXML("project.xml",g);
        +

        Method definition: + JSGantt.parseXML(pFile, pGanttObj) +

        + + + + + + + + + +
        pFile:(required) this is the filename of the XML
        pGanttObj:(required) a GanttChart object returned by a call to JSGantt.GanttChart()
        +

        The structure of the native XML file:

        +
        <project>
        +  <task>
        +    <pID>25</pID>
        +    <pName>WCF Changes</pName>
        +    <pStart></pStart>
        +    <pEnd></pEnd>
        +    <pClass>gtaskred</pClass>
        +    <pLink></pLink>
        +    <pMile>0</pMile>
        +    <pRes></pRes>
        +    <pComp>0</pComp>
        +    <pGroup>1</pGroup>
        +    <pParent>2</pParent>
        +    <pOpen>1</pOpen>
        +    <pDepend>2,24</pDepend>
        +    <pCaption>A caption</pCaption>
        +    <pNotes>Text - can include limited HTML</pNotes>
        +  </task>
        +</project>
        +

        Field definitions are as described for the parameters to TaskItem above. The pClass element is optional in XML files and will default to "ggroupblack" for group tasks, "gtaskblue" for normal tasks and "gmilestone" for milestones. The pGantt element is not required for XML import.

        +

        JSGannt Improved will also test the provided XML file to see if it appears to be in Microsoft Project XML format. If so an attempt will be made to load up the project. This feature is experimental, the import is best effort and not guaranteed. Once loaded the project as interpreted by JSGantt Improved can be extracted using the XML Export methods provided.

        +
      • +
      • + using parseXMLString() with XML held in a javascript string object +
        JSGantt.parseXMLString("<project><task>...</task></project>",g);
        +

        Method definition: + JSGantt.parseXMLString(pStr, pGanttObj) +

        + + + + + + + + + +
        pStr:(required) this is a javascript String containing XML
        pGanttObj:(required) a GanttChart object returned by a call to JSGantt.GanttChart()
        +

        The XML provided will be parsed in exactly the same way as the contents of an external XML file and hence must match the format as described for JSGantt.parseXML() above

        +
      • +
      +
    12. +
    13. +

      Call Draw()

      +
      g.Draw();
      +
    14. +
    15. +

      Close the <script> block

      +
      </script>
      +
    16. +
    +

    It is possible to add items to the chart in realtime via javascript using either direct method calls or additional XML files. + It is also possible to delete tasks using RemoveTaskItem() method. +

    +
    g.RemoveTaskItem(11);
    +

    Method definition: + RemoveTaskItem(pID) +

    + + + + + +
    pID:(required) the unique numeric ID of the item to be removed
    +

    If the task removed is a group item, all child tasks will also be removed.

    +

    After adding or removing tasks a call to "g.Draw()" must be made to redraw the chart.

    +

    Configuration Options

    +

    Switches

    +

    Many of the features of jsGanttImproved can be customised through the use of setter methods available on the GanttChart object returned by a call to JSGantt.GanttChart()

    +

    The following options take a single numeric parameter; a value of 1 will enable the describe functionality, 0 will disable it

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    setUseToolTip():Controls the display of tool tip boxes, defaults to 1 (enabled)
    setUseFade():Controls use of the fade effect when showing/hiding tool tips, defaults to 1 (enabled)
    setUseMove():Controls use of the sliding effect when changing between different task tool tips, defaults to 1 (enabled)
    setUseRowHlt():Controls the use of row mouseover highlighting, defaults to 1 (enabled)
    setUseSort():Controls whether the task list is sorted into parent task / start time order or is simply displayed in the order created, defaults to 1 (sort enabled)
    setShowRes():Controls whether the Resource column is displayed in the task list, defaults to 1 (show column)
    setShowDur():Controls whether the Task Duration column is displayed in the task list, defaults to 1 (show column)
    setShowComp():Controls whether the Percentage Complete column is displayed in the task list, defaults to 1 (show column)
    setShowStartDate():Controls whether the Task Start Date column is displayed in the task list, defaults to 1 (show column)
    setShowEndDate():Controls whether the Task End Date column is displayed in the task list, defaults to 1 (show column)
    setShowTaskInfoRes():Controls whether the Resource information is displayed in the task tool tip, defaults to 1 (show information)
    setShowTaskInfoDur():Controls whether the Task Duration information is displayed in the task tool tip, defaults to 1 (show information)
    setShowTaskInfoComp():Controls whether the Percentage Complete information is displayed in the task tool tip, defaults to 1 (show information)
    setShowTaskInfoStartDate():Controls whether the Task Start Date information is displayed in the task tool tip, defaults to 1 (show information)
    setShowTaskInfoEndDate():Controls whether the Task End Date information is displayed in the task tool tip, defaults to 1 (show information)
    setShowTaskInfoLink():Controls whether the More Information link is displayed in the task tool tip, defaults to 0 (do NOT show link)
    setShowTaskInfoNotes():Controls whether the Additional Notes data is displayed in the task tool tip, defaults to 1 (show notes)
    setShowEndWeekDate():Controls whether the major heading in "Day" view displays the week end-date in the appropriate format (see below), defaults to 1 (show date)
    setShowDeps():Controls display of dependancy lines, defaults to 1 (show dependencies)
    +

    Key Values

    +

    The following options enable functionality using a set of specific key values

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    setShowSelector():Controls where the format selector is displayed, accepts multiple parameters.
    Valid parameter values are "Top", "Bottom".
    Defaults to "Top".
    setFormatArr():Controls which format options are shown in the format selector, accepts multiple parameters.
    Valid parameter values are "Hour", "Day", "Week", "Month", "Quarter".
    Defaults to all valid values.
    setCaptionType():Controls which task field to use as a caption on the Gantt Chart task bar, accepts a single parameter.
    Valid parameter values are "None", "Caption", "Resource", "Duration", "Complete".
    Defaults to "None"
    setDateInputFormat():Defines the input format used for dates in task creation, accepts a single parameter.
    Valid parameter values are "yyyy-mm-dd", "dd/mm/yyyy", "mm/dd/yyyy".
    Defaults to "yyyy-mm-dd"
    setScrollTo():Sets the date the Gantt Chart will be scrolled to, specified in the date input format set by setDateInputFormat() above. Also accepts the special value "today"
    Defaults to minimum display date
    setUseSingleCell():Sets the threshold total number of cells at which the task list will use a single table cell for each row rather than one cell per period. Useful to improve performance on large charts. A value of 0 disables this functionality (always use multiple cells), defaults to 25000
    setLang():Sets translation to use when drawing the chart. Defaults to "en" as this is the only language provided in the base installation (see internationalization below for details on how to add more translations.)
    +

    Layout

    +

    Most of the look and feel of the Gantt Chart can be controlled using CSS however, as the length of a task bar is determined by column width, the following methods take a single numeric parameter that defines the appropriate column width in pixels.

    +

    Note that the task bar sizing code assumes the use of collapsed table borders 1px wide.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    setHourColWidth():Width of Gantt Chart columns in pixels when drawn in "Hour" format. Defaults to 18.
    setDayColWidth():Width of Gantt Chart columns in pixels when drawn in "Day" format. Defaults to 18.
    setWeekColWidth():Width of Gantt Chart columns in pixels when drawn in "Week" format. Defaults to 36.
    setMonthColWidth():Width of Gantt Chart columns in pixels when drawn in "Month" format. Defaults to 36.
    setQuarterColWidth():Width of Gantt Chart columns in pixels when drawn in "Quarter" format, although not mandatory it is recommended that this be set to a value divisible by 3. Defaults to 18.
    setRowHeight():Height of Gantt Chart rows in pixels. Used to route dependency lines near end points. Defaults to 20.
    setMinGpLen():Group tasks have their task bars embellished with end points, this value specifies the width of one of these end points in pixels. A short task bar's length will be rounded up to display either a single or both endpoints correctly. Defaults to 8.
    +

    Display Date Formats

    +

    Date display formats can be individually controlled. The methods used to set these display formats each take a single format string parameter. The format string can be made up of the following components (case sensitive)

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    h:Hour (1-12)
    hh:Hour (01-12)
    pm:am/pm indicator
    PM:AM/PM indicator
    H:Hour (0-23)
    HH:Hour (01-23)
    mi:Minutes (1-59)
    MI:Minutes (01-59)
    d:Day (1-31)
    dd:Day (01-31)
    day:Abbreviated day of week
    DAY:Day of week
    m:Month (1-12)
    mm:Month (01-12)
    mon:Abbreviated month text
    month:Full month text
    yy:Year, excluding century
    yyyy:Year
    q:Quarter (1-4)
    qq:Quarter (Q1-Q4)
    w:ISO Week number (1-53)
    ww:ISO Week number (01-53)
    week:Full ISO Week date format
    +

    separated by one of the following characters: "/\-.,'<space>:

    +

    Any text between separators that does not match one of the components above will be checked using a case insensitive match for a valid internationalized string (see internationalization below). If the value is still not found the text will be output unchanged.

    +
    +

    The available date display methods are

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    setDateTaskTableDisplayFormat():Date format used for start and end dates in the main task list. Defaults to 'dd/mm/yyyy'.
    setDateTaskDisplayFormat():Date format used for start and end dates in task tool tips. Defaults to 'dd month yyyy'.
    setHourMajorDateDisplayFormat():Date format used for Gantt Chart major date headings displayed in "Hour" format. Defaults to 'day dd month yyyy'.
    setDayMajorDateDisplayFormat():Date format used for Gantt Chart major date headings displayed in "Day" format. Defaults to 'dd/mm/yyyy'.
    setWeekMajorDateDisplayFormat():Date format used for Gantt Chart major date headings displayed in "Week" format. Defaults to 'yyyy'.
    setMonthMajorDateDisplayFormat():Date format used for Gantt Chart major date headings displayed in "Month" format. Defaults to 'yyyy'.
    setQuarterMajorDateDisplayFormat():Date format used for Gantt Chart major date headings displayed in "Year" format. Defaults to 'yyyy'.
    setHourMinorDateDisplayFormat():Date format used for Gantt Chart minor date headings displayed in "Hour" format. Defaults to 'HH'.
    setDayMinorDateDisplayFormat():Date format used for Gantt Chart minor date headings displayed in "Day" format. Defaults to 'dd'.
    setWeekMinjorDateDisplayFormat():Date format used for Gantt Chart minor date headings displayed in "Week" format. Defaults to 'dd/mm'.
    setMonthMinorDateDisplayFormat():Date format used for Gantt Chart minor date headings displayed in "Month" format. Defaults to 'mon'.
    setQuarterMinorDateDisplayFormat():Date format used for Gantt Chart minor date headings displayed in "Year" format. Defaults to 'qq'.
    +

    Internationalization

    +

    jsGanttImproved only provides English text however all hard coded strings can be replaced by calling the addLang() method available on the GanttChart object returned by a call to JSGantt.GanttChart()

    +

    The addLang() method takes two parameters. The first is a string identifier for the language, the second is a javascript object containing all the replacement text pairs, the default English settings are:

    +
    + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    january:January
    february:February
    march:March
    april:April
    maylong:May
    june:June
    july:July
    august:August
    september:September
    october:October
    november:November
    december:December
    jan:Jan
    feb:Feb
    mar:Mar
    apr:Apr
    may:May
    jun:Jun
    jul:Jul
    aug:Aug
    sep:Sep
    oct:Oct
    nov:Nov
    dec:Dec
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    sunday:Sunday
    monday:Monday
    tuesday:Tuesday
    wednesday:Wednesday
    thursday:Thursday
    friday:Friday
    saturday:Saturday
    sun:Sun
    mon:Mon
    tue:Tue
    wed:Wed
    thu:Thu
    fri:Fri
    sat:Sat
    resource:Resource
    duration:Duration
    comp:% Comp.
    completion:Completion
    startdate:Start Date
    enddate:End Date
    moreinfo:More Information
    notes:Notes
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    format:Format
    hour:Hour
    day:Day
    week:Week
    month:Month
    quarter:Quarter
    hours:Hours
    days:Days
    weeks:Weeks
    months:Months
    quarters:Quarters
    hr:Hr
    dy:Day
    wk:Wk
    mth:Mth
    qtr:Qtr
    hrs:Hrs
    dys:Days
    wks:Wks
    mths:Mths
    qtrs:Qtrs
    +
    +
    +

    When adding a language any translations that are not provided will use the default English language value. This provides a simple way to override default strings e.g.

    +
    g.addLang('en2', {'format':'Select', 'comp':'Complete'});
    +

    would create a language called 'en2' where the text in the format selector was "Select" rather than "Format" and the header for the Percentage Complete column in the task list is "Complete" rather than "% Comp."

    +

    Once a translation has been added a call must be made to setLang() with the appropriate langage identifier before calling Draw().

    +

    Example Options

    +

    The configuration options used in the example chart above are:

    +
    g.setCaptionType('Complete');  // Set to Show Caption (None,Caption,Resource,Duration,Complete)
    +g.setQuarterColWidth(36);
    +g.setDateTaskDisplayFormat('day dd month yyyy'); // Shown in tool tip box
    +g.setDayMajorDateDisplayFormat('mon yyyy - Week ww'); // Set format to display dates in the "Major" header of the "Day" view
    +g.setWeekMinorDateDisplayFormat('dd mon'); // Set format to display dates in the "Minor" header of the "Week" view
    +g.setShowTaskInfoLink(1); //Show link in tool tip (0/1)
    +g.setShowEndWeekDate(0); // Show/Hide the date for the last day of the week in header for daily view (1/0)
    +g.setUseSingleCell(10000); // Set the threshold at which we will only use one cell per table row (0 disables).  Helps with rendering performance for large charts.
    +g.setFormatArr('Day', 'Week', 'Month', 'Quarter'); // Even with setUseSingleCell using Hour format on such a large chart can cause issues in some browsers
    +        
    +

    Putting all this information together the final code to produce the chart above is as follows:

    +
    <link rel="stylesheet" type="text/css" href="jsgantt.css" />
    +<script language="javascript" src="jsgantt.js"></script>
    +<div style="position:relative" class="gantt" id="GanttChartDIV"></div>
    +<script>
    +
    +var g = new JSGantt.GanttChart('g',document.getElementById('GanttChartDIV'), 'day');
    +
    +if( g.getDivId() != null ) {
    +g.setCaptionType('Complete');
    +g.setQuarterColWidth(36);
    +g.setDateTaskDisplayFormat('day dd month yyyy');
    +g.setDayMajorDateDisplayFormat('mon yyyy - Week ww');
    +g.setWeekMinorDateDisplayFormat('dd mon');
    +g.setShowTaskInfoLink(1);
    +g.setShowEndWeekDate(0);
    +g.setUseSingleCell(10000);
    +g.setFormatArr('Day', 'Week', 'Month', 'Quarter');
    +
    +g.AddTaskItem(new JSGantt.TaskItem(1,   'Define Chart API',     '',           '',          'ggroupblack',  '',       0, 'Brian',    0,   1, 0,  1, '',      '',      'Some Notes text', g ));
    +g.AddTaskItem(new JSGantt.TaskItem(11,  'Chart Object',         '2016-02-20','2016-02-20', 'gmilestone',   '',       1, 'Shlomy',   100, 0, 1,  1, '',      '',      '',      g));
    +g.AddTaskItem(new JSGantt.TaskItem(12,  'Task Objects',         '',           '',          'ggroupblack',  '',       0, 'Shlomy',   40,  1, 1,  1, '',      '',      '',      g));
    +g.AddTaskItem(new JSGantt.TaskItem(121, 'Constructor Proc',     '2016-02-21','2016-03-09', 'gtaskblue',    '',       0, 'Brian T.', 60,  0, 12, 1, '',      '',      '',      g));
    +g.AddTaskItem(new JSGantt.TaskItem(122, 'Task Variables',       '2016-03-06','2016-03-11', 'gtaskred',     '',       0, 'Brian',    60,  0, 12, 1, 121,     '',      '',      g));
    +g.AddTaskItem(new JSGantt.TaskItem(123, 'Task by Minute/Hour',  '2016-03-09','2016-03-14 12:00', 'gtaskyellow', '',  0, 'Ilan',     60,  0, 12, 1, '',      '',      '',      g));
    +g.AddTaskItem(new JSGantt.TaskItem(124, 'Task Functions',       '2016-03-09','2016-03-29', 'gtaskred',     '',       0, 'Anyone',   60,  0, 12, 1, '123SS', 'This is a caption', null, g));
    +g.AddTaskItem(new JSGantt.TaskItem(2,   'Create HTML Shell',    '2016-03-24','2016-03-24', 'gtaskyellow',  '',       0, 'Brian',    20,  0, 0,  1, 122,     '',      '',      g));
    +g.AddTaskItem(new JSGantt.TaskItem(3,   'Code Javascript',      '',           '',          'ggroupblack',  '',       0, 'Brian',    0,   1, 0,  1, '',      '',      '',      g));
    +g.AddTaskItem(new JSGantt.TaskItem(31,  'Define Variables',     '2016-02-25','2016-03-17', 'gtaskpurple',  '',       0, 'Brian',    30,  0, 3,  1, '',      'Caption 1','',   g));
    +g.AddTaskItem(new JSGantt.TaskItem(32,  'Calculate Chart Size', '2016-03-15','2016-03-24', 'gtaskgreen',   '',       0, 'Shlomy',   40,  0, 3,  1, '',      '',      '',      g));
    +g.AddTaskItem(new JSGantt.TaskItem(33,  'Draw Task Items',      '',           '',          'ggroupblack',  '',       0, 'Someone',  40,  2, 3,  1, '',      '',      '',      g));
    +g.AddTaskItem(new JSGantt.TaskItem(332, 'Task Label Table',     '2016-03-06','2016-03-09', 'gtaskblue',    '',       0, 'Brian',    60,  0, 33, 1, '',      '',      '',      g));
    +g.AddTaskItem(new JSGantt.TaskItem(333, 'Task Scrolling Grid',  '2016-03-11','2016-03-20', 'gtaskblue',    '',       0, 'Brian',    0,   0, 33, 1, '332',   '',      '',      g));
    +g.AddTaskItem(new JSGantt.TaskItem(34,  'Draw Task Bars',       '',           '',          'ggroupblack',  '',       0, 'Anybody',  60,  1, 3,  0, '',      '',      '',      g));
    +g.AddTaskItem(new JSGantt.TaskItem(341, 'Loop each Task',       '2016-03-26','2016-04-11', 'gtaskred',     '',       0, 'Brian',    60,  0, 34, 1, '',      '',      '',      g));
    +g.AddTaskItem(new JSGantt.TaskItem(342, 'Calculate Start/Stop', '2016-04-12','2016-05-18', 'gtaskpink',    '',       0, 'Brian',    60,  0, 34, 1, '',      '',      '',      g));
    +g.AddTaskItem(new JSGantt.TaskItem(343, 'Draw Task Div',        '2016-05-13','2016-05-17', 'gtaskred',     '',       0, 'Brian',    60,  0, 34, 1, '',      '',      '',      g));
    +g.AddTaskItem(new JSGantt.TaskItem(344, 'Draw Completion Div',  '2016-05-17','2016-06-04', 'gtaskred',     '',       0, 'Brian',    60,  0, 34, 1, "342,343",'',     '',      g));
    +g.AddTaskItem(new JSGantt.TaskItem(35,  'Make Updates',         '2016-07-17','2017-09-04', 'gtaskpurple',  '',       0, 'Brian',    30,  0, 3,  1, '333',   '',      '',      g));
    +
    +g.Draw();
    +}
    +else
    +{
    +alert("Error, unable to create Gantt Chart");
    +}
    +
    +</script>
    +

    XML Export

    +

    The following methods can be used to extract details of tasks in the project in XML format

    +

    Method definition: getXMLProject()

    +

    Returns a string containing the entire project in JSGantt Improved XML format. Dates will be exported in the currently defined input format as set by setDateInputFormat()

    +

    Method definition: getXMLTask(pID, pIdx)

    + + + + + + + + + +
    pID:(required) the numeric ID that identifies the task to extract
    pIdx:(optional) Boolean - if present and set to "true" the number passed in the pID parameter is treated as an array index for the task list rather than an ID
    +

    Returns a string containing the specified task item in JSGantt Improved XML format. Dates will be exported in the currently defined input format as set by setDateInputFormat()

    +
    + +
    +

    Credits

    +
    +
    + Eduardo Rodrigues +
    +

    Eduardo Rodrigues

    +

    Developer

    +
    + +
    +
    +
    +
    + Ricardo Cardoso +
    +

    Ricardo Cardoso

    +

    Developer

    +
    + +
    +
    +
    +
    +
    + + + + + + + diff --git a/htdocs/includes/jsgantt/jsgantt.css b/htdocs/includes/jsgantt/jsgantt.css index 78a7e83e971..f8f58017cca 100644 --- a/htdocs/includes/jsgantt/jsgantt.css +++ b/htdocs/includes/jsgantt/jsgantt.css @@ -1,5 +1,5 @@ -/* Sample CSS for jsGanttImproved v1.7.3 */ -div.gantt { font-family:tahoma, arial, verdana, Sans-serif; font-size:10px; color: #2F2F2F; } +/* Sample CSS for jsGanttImproved v1.7.5.4 */ +div.gantt { font-family:tahoma, arial, verdana, Sans-serif; font-size:10px; color: #656565; } .gantt table { border-collapse: collapse; } .gantt td { padding: 0px; } @@ -42,7 +42,7 @@ td.gspanning { border-left: none; border-right: none; } .genddate { text-align: center; min-width: 70px; max-width: 70px; width: 70px; font-size: 10px; } .gtaskheading { text-align: center; } .gtaskname div, /* needed for IE8 */ -.gtaskname { min-width: 170px; max-width: 170px; width: 170px;/* font-size: 9px;*/ border-left: none; } +.gtaskname { min-width: 170px; max-width: 170px; width: 170px; font-size: 9px; border-left: none; } .gselector { text-align: left; white-space: nowrap; min-width: 170px; max-width: 170px; width: 170px; } @@ -62,7 +62,7 @@ span.gfoldercollapse { color:#000000; cursor:pointer; font-weight:bold; font-si .glineitem { background-color: #ffffff; } /* highlight row (applied to row) */ -.gitemhighlight td { background-image: none; background-color: #fffaaa;} +.gitemhighlight td { background-image: none; background-color: #fffde5;} /* task bar caption text styles */ .gmilecaption, @@ -98,34 +98,34 @@ span.gfoldercollapse { color:#000000; cursor:pointer; font-weight:bold; font-si .ggroupblackendpointright { overflow: hidden; width:0px; height:0px; top: 2px; border-top: 4px solid black; border-left: 4px solid transparent; border-bottom: 4px solid transparent; border-right: 4px solid transparent; float: right; } .ggroupblackcomplete { float:left; overflow: hidden; height:3px; filter: alpha(opacity=80); opacity:0.8; background-color:#777777; margin-top:2px; margin-bottom: 2px; } .gtaskblue { - background: rgb(58,132,195); /* Old browsers */ - background: linear-gradient(to bottom, rgba(58,132,195,1) 0%,rgba(65,154,214,1) 20%,rgba(75,184,240,1) 40%,rgba(58,139,194,1) 70%,rgba(38,85,139,1) 100%); /* W3C */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#4bb8f0', endColorstr='#3a84c3',GradientType=0 ); /* IE6-9 */ + background: rgb(58,132,195); /* Old browsers */ + background: linear-gradient(to bottom, rgba(58,132,195,1) 0%,rgba(65,154,214,1) 20%,rgba(75,184,240,1) 40%,rgba(58,139,194,1) 70%,rgba(38,85,139,1) 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#4bb8f0', endColorstr='#3a84c3',GradientType=0 ); /* IE6-9 */ } .gtaskred { - background: rgb(196,58,58); /* Old browsers */ - background: linear-gradient(to bottom, rgba(196,58,58,1) 0%,rgba(211,65,65,1) 20%,rgba(239,76,76,1) 40%,rgba(196,58,58,1) 70%,rgba(135,37,37,1) 100%); /* W3C */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ef4c4c', endColorstr='#c43a3a',GradientType=0 ); /* IE6-9 */ + background: rgb(196,58,58); /* Old browsers */ + background: linear-gradient(to bottom, rgba(196,58,58,1) 0%,rgba(211,65,65,1) 20%,rgba(239,76,76,1) 40%,rgba(196,58,58,1) 70%,rgba(135,37,37,1) 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ef4c4c', endColorstr='#c43a3a',GradientType=0 ); /* IE6-9 */ } .gtaskgreen { - background: rgb(80,193,58); /* Old browsers */ - background: linear-gradient(to bottom, rgba(80,193,58,1) 0%,rgba(88,209,64,1) 20%,rgba(102,237,75,1) 40%,rgba(80,193,58,1) 70%,rgba(53,132,37,1) 100%); /* W3C */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#66ED4B', endColorstr='#50c13a',GradientType=0 ); /* IE6-9 */ + background: rgb(80,193,58); /* Old browsers */ + background: linear-gradient(to bottom, rgba(80,193,58,1) 0%,rgba(88,209,64,1) 20%,rgba(102,237,75,1) 40%,rgba(80,193,58,1) 70%,rgba(53,132,37,1) 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#66ED4B', endColorstr='#50c13a',GradientType=0 ); /* IE6-9 */ } .gtaskyellow { - background: rgb(247,228,56); /* Old browsers */ - background: linear-gradient(to bottom, rgba(247,228,56,1) 0%,rgba(239,239,55,1) 20%,rgba(255,255,58,1) 40%,rgba(242,236,55,1) 70%,rgba(241,218,54,1) 100%); /* W3C */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffff3a', endColorstr='#f7e438',GradientType=0 ); /* IE6-9 */ + background: rgb(247,228,56); /* Old browsers */ + background: linear-gradient(to bottom, rgba(247,228,56,1) 0%,rgba(239,239,55,1) 20%,rgba(255,255,58,1) 40%,rgba(242,236,55,1) 70%,rgba(241,218,54,1) 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffff3a', endColorstr='#f7e438',GradientType=0 ); /* IE6-9 */ } .gtaskpurple { - background: rgb(193,58,193); /* Old browsers */ - background: linear-gradient(to bottom, rgba(193,58,193,1) 0%,rgba(211,65,211,1) 20%,rgba(239,76,239,1) 40%,rgba(193,58,193,1) 70%,rgba(137,38,137,1) 100%); /* W3C */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ef4cef', endColorstr='#892689',GradientType=0 ); /* IE6-9 */ + background: rgb(193,58,193); /* Old browsers */ + background: linear-gradient(to bottom, rgba(193,58,193,1) 0%,rgba(211,65,211,1) 20%,rgba(239,76,239,1) 40%,rgba(193,58,193,1) 70%,rgba(137,38,137,1) 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ef4cef', endColorstr='#892689',GradientType=0 ); /* IE6-9 */ } .gtaskpink { - background: rgb(249,177,245); /* Old browsers */ - background: linear-gradient(to bottom, rgba(249,177,245,1) 0%,rgba(247,192,243,1) 20%,rgba(247,202,244,1) 40%,rgba(249,192,246,1) 70%,rgba(252,174,247,1) 100%); /* W3C */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f7caf4', endColorstr='#fcaef7',GradientType=0 ); /* IE6-9 */ + background: rgb(249,177,245); /* Old browsers */ + background: linear-gradient(to bottom, rgba(249,177,245,1) 0%,rgba(247,192,243,1) 20%,rgba(247,202,244,1) 40%,rgba(249,192,246,1) 70%,rgba(252,174,247,1) 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f7caf4', endColorstr='#fcaef7',GradientType=0 ); /* IE6-9 */ } .gtaskbluecomplete, .gtaskredcomplete, @@ -137,21 +137,21 @@ span.gfoldercollapse { color:#000000; cursor:pointer; font-weight:bold; font-si /* Printer friendly styles - we could use these all the time but they are not as pretty! */ /* note that "@media print" is not supported in IE6 or 7. Fully patched IE8 should be OK */ @media print { - .ggroupblack { height:0px; border-top: 7px solid; border-color: #000000; } - .gtaskblue { height:0px; border-top: 13px solid; border-color: rgb(58,132,195); } - .gtaskred { height:0px; border-top: 13px solid; border-color: rgb(196,58,58); } - .gtaskgreen { height:0px; border-top: 13px solid; border-color: rgb(80,193,58); } - .gtaskyellow { height:0px; border-top: 13px solid; border-color: rgb(247,228,56); } - .gtaskpurple { height:0px; border-top: 13px solid; border-color: rgb(193,58,193); } - .gtaskpink { height:0px; border-top: 13px solid; border-color: rgb(249,177,245); } + .ggroupblack { height:0px; border-top: 7px solid; border-color: #000000; } + .gtaskblue { height:0px; border-top: 13px solid; border-color: rgb(58,132,195); } + .gtaskred { height:0px; border-top: 13px solid; border-color: rgb(196,58,58); } + .gtaskgreen { height:0px; border-top: 13px solid; border-color: rgb(80,193,58); } + .gtaskyellow { height:0px; border-top: 13px solid; border-color: rgb(247,228,56); } + .gtaskpurple { height:0px; border-top: 13px solid; border-color: rgb(193,58,193); } + .gtaskpink { height:0px; border-top: 13px solid; border-color: rgb(249,177,245); } - .gtaskbluecomplete, - .gtaskredcomplete, - .gtaskgreencomplete, - .gtaskyellowcomplete, - .gtaskpurplecomplete, - .gtaskpinkcomplete { height:0px; filter: alpha(opacity=40); opacity:0.4; margin-top: -9px; border-top: 5px solid; border-color: #000000; } - .ggroupblackcomplete { height: 0px; filter: alpha(opacity=80); opacity:0.8; margin-top:-5px; border-top:3px solid; border-color:#777777; } + .gtaskbluecomplete, + .gtaskredcomplete, + .gtaskgreencomplete, + .gtaskyellowcomplete, + .gtaskpurplecomplete, + .gtaskpinkcomplete { height:0px; filter: alpha(opacity=40); opacity:0.4; margin-top: -9px; border-top: 5px solid; border-color: #000000; } + .ggroupblackcomplete { height: 0px; filter: alpha(opacity=80); opacity:0.8; margin-top:-5px; border-top:3px solid; border-color:#777777; } } /* END Task bar styles */ @@ -161,11 +161,11 @@ span.gfoldercollapse { color:#000000; cursor:pointer; font-weight:bold; font-si .gDepFS, .gDepSS, .gDepSF, -.gDepFF { border-color: #26558b; } +.gDepFF { border-color: #ff0000; } .gDepFSArw, -.gDepSSArw { overflow: hidden; width:0px; height:0px; border-bottom: 4px solid transparent; border-left: 4px solid #26558b; border-top: 4px solid transparent; border-right: 4px solid transparent;} +.gDepSSArw { overflow: hidden; width:0px; height:0px; border-bottom: 4px solid transparent; border-left: 4px solid #ff0000; border-top: 4px solid transparent; border-right: 4px solid transparent;} .gDepFFArw, -.gDepSFArw { overflow: hidden; width:0px; height:0px; border-bottom: 4px solid transparent; border-left: 4px solid transparent; border-top: 4px solid transparent; border-right: 4px solid #26558b;} +.gDepSFArw { overflow: hidden; width:0px; height:0px; border-bottom: 4px solid transparent; border-left: 4px solid transparent; border-top: 4px solid transparent; border-right: 4px solid #ff0000;} .gCurDate { border-color: #0000ff; } @@ -180,29 +180,30 @@ div.gtaskbarcontainer { z-index: 1; position: absolute; top: 0px } .gTaskNotes {font-size: 11px; font-weight: normal; color: #323232; padding: 0 15px; display: block;} .gTIn {padding-top: 10px;} -.gantt { min-width: 1064px; /* 2x LC width */ } -.gchartcontainer { padding-left: 532px; /* LC width */ } -.gcontainercol { position: relative; float: left; } /* Add a max-height value here if wanted */ -.glistgrid { width: 532px; /* LC width */ margin-left: -100%; right: 532px; /* LC width */ padding-right: 0px; padding-left: 0px; padding-bottom: 0px; padding-top: 0px; background-color: #ffffff; overflow: hidden; } -.glistlbl { width: 532px; /* LC width */ margin-left: -100%; right: 532px; /* LC width */ padding-right: 0px; padding-left: 0px; padding-bottom: 0px; padding-top: 0px; background-color: #ffffff; overflow: hidden; } +.gantt { min-width: 632px; /* 2x LC width */ } +.gchartcontainer { /* padding-left: 532px; LC width */ line-height: 1; /* Overrides inherited CSS (e.g. from Bootstrap) */ } +.gcontainercol { position: relative; } /* Add a max-height value here if wanted */ +.glistgrid { width: 532px; /* LC width */ float: left; /* LC width */ padding-right: 0px; padding-left: 0px; padding-bottom: 0px; padding-top: 0px; background-color: #ffffff; overflow: hidden; } +.glistlbl { width: 532px; /* LC width */ float: left; /* LC width */ padding-right: 0px; padding-left: 0px; padding-bottom: 0px; padding-top: 0px; background-color: #ffffff; overflow: hidden; } .glabelfooter { clear: both; } .ggridfooter { clear: both; } -/*.rhscrpad { width: 150px; position: absolute; top: 0px; height: 1px; }*/ +.rhscrpad { width: 150px; position: absolute; top: 0px; height: 1px; } -.gchartgrid { width: 100%; padding-right: 0px; padding-left: 0px; padding-bottom: 0px; padding-top: 0px; background-color: #ffffff; position: relative; overflow: auto; min-height: 0%; } -.gchartlbl { width: 100%; padding-right: 0px; padding-left: 0px; padding-bottom: 0px; padding-top: 0px; background-color: #ffffff; position: relative; overflow: hidden; } +.gchartgrid { padding-right: 0px; padding-left: 0px; padding-bottom: 0px; padding-top: 0px; background-color: #ffffff; position: relative; overflow: auto; min-height: 0%; } +.gchartlbl { padding-right: 0px; padding-left: 0px; padding-bottom: 0px; padding-top: 0px; background-color: #ffffff; position: relative; overflow: hidden; } /* Old Internet Explorer version hacks */ .gantt { _height: 100% } /* otherwise the chart disappears! */ -div .gantt { _width: 1064px; } /* ie6 fixed width */ +div .gantt { /* _width: 1064px; ie6 fixed width */ } div.gchartlbl, -div.gchartgrid { _width: 532px; } /* ie6 fixed width */ +div.gchartgrid {/* _width: 532px; */} /* ie6 fixed width */ div.glistlbl, div.glistgrid { - *right: 0px; /* ie7 pulls the content too far left with the negative margin */ - _right: 532px; /* but ie6 fixed width needs this */ - _margin-left: -532px; /* ie6 fixed width */ + *right: 0px; /* ie7 pulls the content too far left with the negative margin */ + _right: 532px; /* but ie6 fixed width needs this */ + _margin-left: -532px; /* ie6 fixed width */ + float: left; } div.gchartgrid { *padding-bottom: 20px; *overflow-y: hidden; } /* variable height design, no need for vertical scroll */ td.gmajorheading div { *overflow: hidden; } /* stops resizing fixed width columns if the text is too wide */ diff --git a/htdocs/includes/jsgantt/jsgantt.js b/htdocs/includes/jsgantt/jsgantt.js index 3360d832ec6..7a26eecb9fc 100644 --- a/htdocs/includes/jsgantt/jsgantt.js +++ b/htdocs/includes/jsgantt/jsgantt.js @@ -1,68 +1,67 @@ /* - _ ___ _____ _ _____ ____ ____ - (_) / _ \ \_ \ / ||___ | ___| |___ \ - | |/ /_\/ / /\/ | | / /|___ \ __) | - | / /_\\/\/ /_ | |_ / /_ ___) | / __/ - _/ \____/\____/ |_(_)_/(_)____(_)_____| - |__/ - jsGanttImproved 1.7.5.2 - Copyright (c) 2013-2016, Paul Geldart All rights reserved. + _ ___ _ _ _____ _ + (_)___ / _ \__ _ _ __ | |_| |_ \_ \_ __ ___ _ __ _ __ _____ _____ __| | + | / __| / /_\/ _` | '_ \| __| __| / /\/ '_ ` _ \| '_ \| '__/ _ \ \ / / _ \/ _` | + | \__ \/ /_\\ (_| | | | | |_| |_/\/ /_ | | | | | | |_) | | | (_) \ V / __/ (_| | + _/ |___/\____/\__,_|_| |_|\__|\__\____/ |_| |_| |_| .__/|_| \___/ \_/ \___|\__,_| + |__/ |_| + jsGanttImproved 1.7.5.4 - The current version of this code can be found at https://code.google.com/p/jsgantt-improved/ + The current version of this code can be found at https://github.com/jsGanttImproved/jsgantt-improved/ - * Copyright (c) 2013-2016, Paul Geldart. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Paul Geldart nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY PAUL GELDART. ''AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL PAUL GELDART BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * Copyright (c) 2013-2017, Paul Geldart, Eduardo Rodrigues and Ricardo Cardoso. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Paul Geldart, Eduardo Rodrigues and Ricardo Cardoso nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PAUL GELDART, EDUARDO RODRIGUES AND RICARDO CARDOSO ''AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL PAUL GELDART, EDUARDO RODRIGUES AND RICARDO CARDOSO BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - This project is based on jsGantt 1.2, (which can be obtained from - https://code.google.com/p/jsgantt/) and remains under the original BSD license. - The original project license follows: + This project is based on jsGantt 1.2, (which can be obtained from + https://code.google.com/p/jsgantt/) and remains under the original BSD license. + The original project license follows: - Copyright (c) 2009, Shlomy Gantz BlueBrick Inc. All rights reserved. + Copyright (c) 2009, Shlomy Gantz BlueBrick Inc. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Shlomy Gantz or BlueBrick Inc. nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY SHLOMY GANTZ/BLUEBRICK INC. ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL SHLOMY GANTZ/BLUEBRICK INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Shlomy Gantz or BlueBrick Inc. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY SHLOMY GANTZ/BLUEBRICK INC. ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL SHLOMY GANTZ/BLUEBRICK INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ var JSGantt; if (!JSGantt) JSGantt={}; @@ -70,202 +69,205 @@ var vBenchTime=new Date().getTime(); JSGantt.isIE=function () { - if(typeof document.all!='undefined') - { - if ('pageXOffset' in window) return false; // give IE9 and above the benefit of the doubt! - else return true; - } - else return false; + if(typeof document.all!='undefined') + { + if ('pageXOffset' in window) return false; // give IE9 and above the benefit of the doubt! + else return true; + } + else return false; }; JSGantt.TaskItem=function(pID, pName, pStart, pEnd, pClass, pLink, pMile, pRes, pComp, pGroup, pParent, pOpen, pDepend, pCaption, pNotes, pGantt) { - var vID=parseInt(document.createTextNode(pID).data); - var vName=document.createTextNode(pName).data; - var vStart=new Date(0); - var vEnd=new Date(0); - var vGroupMinStart=null; - var vGroupMinEnd=null; - var vClass=document.createTextNode(pClass).data; - var vLink=document.createTextNode(pLink).data; - var vMile=parseInt(document.createTextNode(pMile).data); - var vRes=document.createTextNode(pRes).data; - var vComp=parseFloat(document.createTextNode(pComp).data); - var vGroup=parseInt(document.createTextNode(pGroup).data); - var vParent=document.createTextNode(pParent).data; - var vOpen=(vGroup==2)?1:parseInt(document.createTextNode(pOpen).data); - var vDepend=new Array(); - var vDependType=new Array(); - var vCaption=document.createTextNode(pCaption).data; - var vDuration=''; - var vLevel=0; - var vNumKid=0; - var vVisible=1; - var vSortIdx=0; - var vToDelete=false; - var x1, y1, x2, y2; - var vNotes; - var vParItem=null; - var vCellDiv=null; - var vGantt=(pGantt instanceof JSGantt.GanttChart)? pGantt : g; //hack for backwards compatibility - var vBarDiv=null; - var vTaskDiv=null; - var vListChildRow=null; - var vChildRow=null; - var vGroupSpan=null; + var vID=parseInt(document.createTextNode(pID).data); + var vName=document.createTextNode(pName).data; + var vStart=new Date(0); + var vEnd=new Date(0); + var vGroupMinStart=null; + var vGroupMinEnd=null; + var vClass=document.createTextNode(pClass).data; + var vLink=document.createTextNode(pLink).data; + var vMile=parseInt(document.createTextNode(pMile).data); + var vRes=document.createTextNode(pRes).data; + var vComp=parseFloat(document.createTextNode(pComp).data); + var vGroup=parseInt(document.createTextNode(pGroup).data); + var vParent=document.createTextNode(pParent).data; + var vOpen=(vGroup==2)?1:parseInt(document.createTextNode(pOpen).data); + var vDepend=new Array(); + var vDependType=new Array(); + var vCaption=document.createTextNode(pCaption).data; + var vDuration=''; + var vLevel=0; + var vNumKid=0; + var vWeight=0; + var vVisible=1; + var vSortIdx=0; + var vToDelete=false; + var x1, y1, x2, y2; + var vNotes; + var vParItem=null; + var vCellDiv=null; + var vGantt=(pGantt instanceof JSGantt.GanttChart)? pGantt : g; //hack for backwards compatibility + var vBarDiv=null; + var vTaskDiv=null; + var vListChildRow=null; + var vChildRow=null; + var vGroupSpan=null; - vNotes=document.createElement('span'); - vNotes.className='gTaskNotes'; - if (pNotes!=null) - { - vNotes.innerHTML=pNotes; - JSGantt.stripUnwanted(vNotes); - } + vNotes=document.createElement('span'); + vNotes.className='gTaskNotes'; + if (pNotes!=null) + { + vNotes.innerHTML=pNotes; + JSGantt.stripUnwanted(vNotes); + } - if (pStart!=null && pStart!='') - { - vStart=(pStart instanceof Date)?pStart:JSGantt.parseDateStr(document.createTextNode(pStart).data,vGantt.getDateInputFormat()); - vGroupMinStart=vStart; - } + if (pStart!=null && pStart!='') + { + vStart=(pStart instanceof Date)?pStart:JSGantt.parseDateStr(document.createTextNode(pStart).data,vGantt.getDateInputFormat()); + vGroupMinStart=vStart; + } - if (pEnd!=null && pEnd!='') - { - vEnd =(pEnd instanceof Date)?pEnd:JSGantt.parseDateStr(document.createTextNode(pEnd).data,vGantt.getDateInputFormat()); - vGroupMinEnd=vEnd; - } + if (pEnd!=null && pEnd!='') + { + vEnd =(pEnd instanceof Date)?pEnd:JSGantt.parseDateStr(document.createTextNode(pEnd).data,vGantt.getDateInputFormat()); + vGroupMinEnd=vEnd; + } - if (pDepend!=null) - { - var vDependStr=pDepend+''; - var vDepList=vDependStr.split(','); - var n=vDepList.length; + if (pDepend!=null) + { + var vDependStr=pDepend+''; + var vDepList=vDependStr.split(','); + var n=vDepList.length; - for(var k=0;k1) - { - vFormatArr[j++]=arguments[i].toLowerCase(); - var vRegExp=new RegExp('(?:^|\s)'+arguments[i]+'(?!\S)', 'g'); - vValidFormats=vValidFormats.replace(vRegExp, ''); - } - } - }; - this.setShowRes=function(pVal){vShowRes=pVal;}; - this.setShowDur=function(pVal){vShowDur=pVal;}; - this.setShowComp=function(pVal){vShowComp=pVal;}; - this.setShowStartDate=function(pVal){vShowStartDate=pVal;}; - this.setShowEndDate=function(pVal){vShowEndDate=pVal;}; - this.setShowTaskInfoRes=function(pVal){vShowTaskInfoRes=pVal;}; - this.setShowTaskInfoDur=function(pVal){vShowTaskInfoDur=pVal;}; - this.setShowTaskInfoComp=function(pVal){vShowTaskInfoComp=pVal;}; - this.setShowTaskInfoStartDate=function(pVal){vShowTaskInfoStartDate=pVal;}; - this.setShowTaskInfoEndDate=function(pVal){vShowTaskInfoEndDate=pVal;}; - this.setShowTaskInfoNotes=function(pVal){vShowTaskInfoNotes=pVal;}; - this.setShowTaskInfoLink=function(pVal){vShowTaskInfoLink=pVal;}; - this.setShowEndWeekDate=function(pVal){vShowEndWeekDate=pVal;}; - this.setShowSelector=function() - { - var vValidSelectors='top bottom'; - vShowSelector=new Array(); - for(var i=0, j=0; i1) - { - vShowSelector[j++]=arguments[i].toLowerCase(); - var vRegExp=new RegExp('(?:^|\s)'+arguments[i]+'(?!\S)', 'g'); - vValidSelectors=vValidSelectors.replace(vRegExp, ''); - } - } - }; - this.setShowDeps=function(pVal){vShowDeps=pVal;}; - this.setDateInputFormat=function(pVal){vDateInputFormat=pVal;}; - this.setDateTaskTableDisplayFormat=function(pVal){vDateTaskTableDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; - this.setDateTaskDisplayFormat=function(pVal){vDateTaskDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; - this.setHourMajorDateDisplayFormat=function(pVal){vHourMajorDateDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; - this.setHourMinorDateDisplayFormat=function(pVal){vHourMinorDateDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; - this.setDayMajorDateDisplayFormat=function(pVal){vDayMajorDateDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; - this.setDayMinorDateDisplayFormat=function(pVal){vDayMinorDateDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; - this.setWeekMajorDateDisplayFormat=function(pVal){vWeekMajorDateDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; - this.setWeekMinorDateDisplayFormat=function(pVal){vWeekMinorDateDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; - this.setMonthMajorDateDisplayFormat=function(pVal){vMonthMajorDateDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; - this.setMonthMinorDateDisplayFormat=function(pVal){vMonthMinorDateDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; - this.setQuarterMajorDateDisplayFormat=function(pVal){vQuarterMajorDateDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; - this.setQuarterMinorDateDisplayFormat=function(pVal){vQuarterMinorDateDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; - this.setCaptionType=function(pType){vCaptionType=pType;}; - this.setFormat=function(pFormat) - { - vFormat=pFormat; - this.Draw(); - }; - this.setMinGpLen=function(pMinGpLen){vMinGpLen=pMinGpLen;}; - this.setScrollTo=function(pDate){vScrollTo=pDate;}; - this.setHourColWidth=function(pWidth){vHourColWidth=pWidth;}; - this.setDayColWidth=function(pWidth){vDayColWidth=pWidth;}; - this.setWeekColWidth=function(pWidth){vWeekColWidth=pWidth;}; - this.setMonthColWidth=function(pWidth){vMonthColWidth=pWidth;}; - this.setQuarterColWidth=function(pWidth){vQuarterColWidth=pWidth;}; - this.setRowHeight=function(pHeight){vRowHeight=pHeight;}; - this.setLang=function(pLang){if(vLangs[pLang])vLang=pLang;}; - this.setChartBody=function(pDiv){if(typeof HTMLDivElement !== 'function' || pDiv instanceof HTMLDivElement)vChartBody=pDiv;}; - this.setChartHead=function(pDiv){if(typeof HTMLDivElement !== 'function' || pDiv instanceof HTMLDivElement)vChartHead=pDiv;}; - this.setListBody=function(pDiv){if(typeof HTMLDivElement !== 'function' || pDiv instanceof HTMLDivElement)vListBody=pDiv;}; - this.setChartTable=function(pTable){if(typeof HTMLTableElement !== 'function' || pTable instanceof HTMLTableElement)vChartTable=pTable;}; - this.setLines=function(pDiv){if(typeof HTMLDivElement !== 'function' || pDiv instanceof HTMLDivElement)vLines=pDiv;}; - this.setTimer=function(pVal){vTimer=pVal*1;}; - this.addLang=function(pLang, pVals){ - if(!vLangs[pLang]) - { - vLangs[pLang]=new Object(); - for(var vKey in vLangs['en'])vLangs[pLang][vKey]=(pVals[vKey])?document.createTextNode(pVals[vKey]).data:vLangs['en'][vKey]; - } - }; + this.setUseFade=function(pVal){vUseFade=pVal;}; + this.setUseMove=function(pVal){vUseMove=pVal;}; + this.setUseRowHlt=function(pVal){vUseRowHlt=pVal;}; + this.setUseToolTip=function(pVal){vUseToolTip=pVal;}; + this.setUseSort=function(pVal){vUseSort=pVal;}; + this.setUseSingleCell=function(pVal){vUseSingleCell=pVal*1;}; + this.setFormatArr=function() + { + var vValidFormats='hour day week month quarter'; + vFormatArr=new Array(); + for(var i=0, j=0; i1) + { + vFormatArr[j++]=arguments[i].toLowerCase(); + var vRegExp=new RegExp('(?:^|\s)'+arguments[i]+'(?!\S)', 'g'); + vValidFormats=vValidFormats.replace(vRegExp, ''); + } + } + }; + this.setShowRes=function(pVal){vShowRes=pVal;}; + this.setShowDur=function(pVal){vShowDur=pVal;}; + this.setShowComp=function(pVal){vShowComp=pVal;}; + this.setShowStartDate=function(pVal){vShowStartDate=pVal;}; + this.setShowEndDate=function(pVal){vShowEndDate=pVal;}; + this.setShowTaskInfoRes=function(pVal){vShowTaskInfoRes=pVal;}; + this.setShowTaskInfoDur=function(pVal){vShowTaskInfoDur=pVal;}; + this.setShowTaskInfoComp=function(pVal){vShowTaskInfoComp=pVal;}; + this.setShowTaskInfoStartDate=function(pVal){vShowTaskInfoStartDate=pVal;}; + this.setShowTaskInfoEndDate=function(pVal){vShowTaskInfoEndDate=pVal;}; + this.setShowTaskInfoNotes=function(pVal){vShowTaskInfoNotes=pVal;}; + this.setShowTaskInfoLink=function(pVal){vShowTaskInfoLink=pVal;}; + this.setShowEndWeekDate=function(pVal){vShowEndWeekDate=pVal;}; + this.setShowSelector=function() + { + var vValidSelectors='top bottom'; + vShowSelector=new Array(); + for(var i=0, j=0; i1) + { + vShowSelector[j++]=arguments[i].toLowerCase(); + var vRegExp=new RegExp('(?:^|\s)'+arguments[i]+'(?!\S)', 'g'); + vValidSelectors=vValidSelectors.replace(vRegExp, ''); + } + } + }; + this.setShowDeps=function(pVal){vShowDeps=pVal;}; + this.setDateInputFormat=function(pVal){vDateInputFormat=pVal;}; + this.setDateTaskTableDisplayFormat=function(pVal){vDateTaskTableDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; + this.setDateTaskDisplayFormat=function(pVal){vDateTaskDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; + this.setHourMajorDateDisplayFormat=function(pVal){vHourMajorDateDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; + this.setHourMinorDateDisplayFormat=function(pVal){vHourMinorDateDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; + this.setDayMajorDateDisplayFormat=function(pVal){vDayMajorDateDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; + this.setDayMinorDateDisplayFormat=function(pVal){vDayMinorDateDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; + this.setWeekMajorDateDisplayFormat=function(pVal){vWeekMajorDateDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; + this.setWeekMinorDateDisplayFormat=function(pVal){vWeekMinorDateDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; + this.setMonthMajorDateDisplayFormat=function(pVal){vMonthMajorDateDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; + this.setMonthMinorDateDisplayFormat=function(pVal){vMonthMinorDateDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; + this.setQuarterMajorDateDisplayFormat=function(pVal){vQuarterMajorDateDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; + this.setQuarterMinorDateDisplayFormat=function(pVal){vQuarterMinorDateDisplayFormat=JSGantt.parseDateFormatStr(pVal);}; + this.setCaptionType=function(pType){vCaptionType=pType;}; + this.setFormat=function(pFormat) + { + vFormat=pFormat; + this.Draw(); + }; + this.setMinGpLen=function(pMinGpLen){vMinGpLen=pMinGpLen;}; + this.setScrollTo=function(pDate){vScrollTo=pDate;}; + this.setHourColWidth=function(pWidth){vHourColWidth=pWidth;}; + this.setDayColWidth=function(pWidth){vDayColWidth=pWidth;}; + this.setWeekColWidth=function(pWidth){vWeekColWidth=pWidth;}; + this.setMonthColWidth=function(pWidth){vMonthColWidth=pWidth;}; + this.setQuarterColWidth=function(pWidth){vQuarterColWidth=pWidth;}; + this.setRowHeight=function(pHeight){vRowHeight=pHeight;}; + this.setLang=function(pLang){if(vLangs[pLang])vLang=pLang;}; + this.setChartBody=function(pDiv){if(typeof HTMLDivElement !== 'function' || pDiv instanceof HTMLDivElement)vChartBody=pDiv;}; + this.setChartHead=function(pDiv){if(typeof HTMLDivElement !== 'function' || pDiv instanceof HTMLDivElement)vChartHead=pDiv;}; + this.setListBody=function(pDiv){if(typeof HTMLDivElement !== 'function' || pDiv instanceof HTMLDivElement)vListBody=pDiv;}; + this.setChartTable=function(pTable){if(typeof HTMLTableElement !== 'function' || pTable instanceof HTMLTableElement)vChartTable=pTable;}; + this.setLines=function(pDiv){if(typeof HTMLDivElement !== 'function' || pDiv instanceof HTMLDivElement)vLines=pDiv;}; + this.setTimer=function(pVal){vTimer=pVal*1;}; + this.addLang=function(pLang, pVals){ + if(!vLangs[pLang]) + { + vLangs[pLang]=new Object(); + for(var vKey in vLangs['en'])vLangs[pLang][vKey]=(pVals[vKey])?document.createTextNode(pVals[vKey]).data:vLangs['en'][vKey]; + } + }; - this.getDivId=function(){return vDivId;}; - this.getUseFade=function(){return vUseFade;}; - this.getUseMove=function(){return vUseMove;}; - this.getUseRowHlt=function(){return vUseRowHlt;}; - this.getUseToolTip=function(){return vUseToolTip;}; - this.getUseSort=function(){return vUseSort;}; - this.getUseSingleCell=function(){return vUseSingleCell;}; - this.getFormatArr=function(){return vFormatArr;}; - this.getShowRes=function(){return vShowRes;}; - this.getShowDur=function(){return vShowDur;}; - this.getShowComp=function(){return vShowComp;}; - this.getShowStartDate=function(){return vShowStartDate;}; - this.getShowEndDate=function(){return vShowEndDate;}; - this.getShowTaskInfoRes=function(){return vShowTaskInfoRes;}; - this.getShowTaskInfoDur=function(){return vShowTaskInfoDur;}; - this.getShowTaskInfoComp=function(){return vShowTaskInfoComp;}; - this.getShowTaskInfoStartDate=function(){return vShowTaskInfoStartDate;}; - this.getShowTaskInfoEndDate=function(){return vShowTaskInfoEndDate;}; - this.getShowTaskInfoNotes=function(){return vShowTaskInfoNotes;}; - this.getShowTaskInfoLink=function(){return vShowTaskInfoLink;}; - this.getShowEndWeekDate=function(){return vShowEndWeekDate;}; - this.getShowSelector=function(){return vShowSelector;}; - this.getShowDeps=function(){return vShowDeps;}; - this.getDateInputFormat=function(){return vDateInputFormat;}; - this.getDateTaskTableDisplayFormat=function(){return vDateTaskTableDisplayFormat;}; - this.getDateTaskDisplayFormat=function(){return vDateTaskDisplayFormat;}; - this.getHourMajorDateDisplayFormat=function(){return vHourMajorDateDisplayFormat;}; - this.getHourMinorDateDisplayFormat=function(){return vHourMinorDateDisplayFormat;}; - this.getDayMajorDateDisplayFormat=function(){return vDayMajorDateDisplayFormat;}; - this.getDayMinorDateDisplayFormat=function(){return vDayMinorDateDisplayFormat;}; - this.getWeekMajorDateDisplayFormat=function(){return vWeekMajorDateDisplayFormat;}; - this.getWeekMinorDateDisplayFormat=function(){return vWeekMinorDateDisplayFormat;}; - this.getMonthMajorDateDisplayFormat=function(){return vMonthMajorDateDisplayFormat;}; - this.getMonthMinorDateDisplayFormat=function(){return vMonthMinorDateDisplayFormat;}; - this.getQuarterMajorDateDisplayFormat=function(){return vQuarterMajorDateDisplayFormat;}; - this.getQuarterMinorDateDisplayFormat=function(){return vQuarterMinorDateDisplayFormat;}; - this.getCaptionType=function(){return vCaptionType;}; - this.getMinGpLen=function(){return vMinGpLen;}; - this.getScrollTo=function(){return vScrollTo;}; - this.getHourColWidth=function(){return vHourColWidth;}; - this.getDayColWidth=function(){return vDayColWidth;}; - this.getWeekColWidth=function(){return vWeekColWidth;}; - this.getMonthColWidth=function(){return vMonthColWidth;}; - this.getQuarterColWidth=function(){return vQuarterColWidth;}; - this.getRowHeight=function(){return vRowHeight;}; - this.getChartBody=function(){return vChartBody;}; - this.getChartHead=function(){return vChartHead;}; - this.getListBody=function(){return vListBody;}; - this.getChartTable=function(){return vChartTable;}; - this.getLines=function(){return vLines;}; - this.getTimer=function(){return vTimer;}; + this.getDivId=function(){return vDivId;}; + this.getUseFade=function(){return vUseFade;}; + this.getUseMove=function(){return vUseMove;}; + this.getUseRowHlt=function(){return vUseRowHlt;}; + this.getUseToolTip=function(){return vUseToolTip;}; + this.getUseSort=function(){return vUseSort;}; + this.getUseSingleCell=function(){return vUseSingleCell;}; + this.getFormatArr=function(){return vFormatArr;}; + this.getShowRes=function(){return vShowRes;}; + this.getShowDur=function(){return vShowDur;}; + this.getShowComp=function(){return vShowComp;}; + this.getShowStartDate=function(){return vShowStartDate;}; + this.getShowEndDate=function(){return vShowEndDate;}; + this.getShowTaskInfoRes=function(){return vShowTaskInfoRes;}; + this.getShowTaskInfoDur=function(){return vShowTaskInfoDur;}; + this.getShowTaskInfoComp=function(){return vShowTaskInfoComp;}; + this.getShowTaskInfoStartDate=function(){return vShowTaskInfoStartDate;}; + this.getShowTaskInfoEndDate=function(){return vShowTaskInfoEndDate;}; + this.getShowTaskInfoNotes=function(){return vShowTaskInfoNotes;}; + this.getShowTaskInfoLink=function(){return vShowTaskInfoLink;}; + this.getShowEndWeekDate=function(){return vShowEndWeekDate;}; + this.getShowSelector=function(){return vShowSelector;}; + this.getShowDeps=function(){return vShowDeps;}; + this.getDateInputFormat=function(){return vDateInputFormat;}; + this.getDateTaskTableDisplayFormat=function(){return vDateTaskTableDisplayFormat;}; + this.getDateTaskDisplayFormat=function(){return vDateTaskDisplayFormat;}; + this.getHourMajorDateDisplayFormat=function(){return vHourMajorDateDisplayFormat;}; + this.getHourMinorDateDisplayFormat=function(){return vHourMinorDateDisplayFormat;}; + this.getDayMajorDateDisplayFormat=function(){return vDayMajorDateDisplayFormat;}; + this.getDayMinorDateDisplayFormat=function(){return vDayMinorDateDisplayFormat;}; + this.getWeekMajorDateDisplayFormat=function(){return vWeekMajorDateDisplayFormat;}; + this.getWeekMinorDateDisplayFormat=function(){return vWeekMinorDateDisplayFormat;}; + this.getMonthMajorDateDisplayFormat=function(){return vMonthMajorDateDisplayFormat;}; + this.getMonthMinorDateDisplayFormat=function(){return vMonthMinorDateDisplayFormat;}; + this.getQuarterMajorDateDisplayFormat=function(){return vQuarterMajorDateDisplayFormat;}; + this.getQuarterMinorDateDisplayFormat=function(){return vQuarterMinorDateDisplayFormat;}; + this.getCaptionType=function(){return vCaptionType;}; + this.getMinGpLen=function(){return vMinGpLen;}; + this.getScrollTo=function(){return vScrollTo;}; + this.getHourColWidth=function(){return vHourColWidth;}; + this.getDayColWidth=function(){return vDayColWidth;}; + this.getWeekColWidth=function(){return vWeekColWidth;}; + this.getMonthColWidth=function(){return vMonthColWidth;}; + this.getQuarterColWidth=function(){return vQuarterColWidth;}; + this.getRowHeight=function(){return vRowHeight;}; + this.getChartBody=function(){return vChartBody;}; + this.getChartHead=function(){return vChartHead;}; + this.getListBody=function(){return vListBody;}; + this.getChartTable=function(){return vChartTable;}; + this.getLines=function(){return vLines;}; + this.getTimer=function(){return vTimer;}; - this.CalcTaskXY=function() - { - var vID; - var vList=this.getList(); - var vBarDiv; - var vTaskDiv; - var vParDiv; - var vLeft, vTop, vWidth; - var vHeight=Math.floor((this.getRowHeight()/2)); + this.CalcTaskXY=function() + { + var vID; + var vList=this.getList(); + var vBarDiv; + var vTaskDiv; + var vParDiv; + var vLeft, vTop, vWidth; + var vHeight=Math.floor((this.getRowHeight()/2)); - for(var i=0; i=x2 && y1!=y2) vBend=true; - break; - } + switch(pType) + { + case 'SF': + vShort*=-1; + if(x1-10<=x2 && y1!=y2) vBend=true; + vDir=-1; + break; + case 'SS': + if (x1=x2 && y1!=y2) vBend=true; + break; + } - if (vBend) - { - this.sLine(x1,y1,x1+vShort,y1,pClass); - this.sLine(x1+vShort,y1,x1+vShort,y2-vRow,pClass); - this.sLine(x1+vShort,y2-vRow,x2-(vShort*2),y2-vRow,pClass); - this.sLine(x2-(vShort*2),y2-vRow,x2-(vShort*2),y2,pClass); - this.sLine(x2-(vShort*2),y2,x2-(1*vDir),y2,pClass); - } - else if (y1!=y2) - { - this.sLine(x1,y1,x1+vShort,y1,pClass); - this.sLine(x1+vShort,y1,x1+vShort,y2,pClass); - this.sLine(x1+vShort,y2,x2-(1*vDir),y2,pClass); - } - else this.sLine(x1,y1,x2-(1*vDir),y2,pClass); + if (vBend) + { + this.sLine(x1,y1,x1+vShort,y1,pClass); + this.sLine(x1+vShort,y1,x1+vShort,y2-vRow,pClass); + this.sLine(x1+vShort,y2-vRow,x2-(vShort*2),y2-vRow,pClass); + this.sLine(x2-(vShort*2),y2-vRow,x2-(vShort*2),y2,pClass); + this.sLine(x2-(vShort*2),y2,x2-(1*vDir),y2,pClass); + } + else if (y1!=y2) + { + this.sLine(x1,y1,x1+vShort,y1,pClass); + this.sLine(x1+vShort,y1,x1+vShort,y2,pClass); + this.sLine(x1+vShort,y2,x2-(1*vDir),y2,pClass); + } + else this.sLine(x1,y1,x2-(1*vDir),y2,pClass); - var vTmpDiv=this.sLine(x2,y2,x2-3-((vDir<0)?1:0),y2-3-((vDir<0)?1:0),pClass+"Arw"); - vTmpDiv.style.width='0px'; - vTmpDiv.style.height='0px'; - }; + var vTmpDiv=this.sLine(x2,y2,x2-3-((vDir<0)?1:0),y2-3-((vDir<0)?1:0),pClass+"Arw"); + vTmpDiv.style.width='0px'; + vTmpDiv.style.height='0px'; + }; - this.DrawDependencies=function() - { - if (this.getShowDeps()==1) - { - //First recalculate the x,y - this.CalcTaskXY(); - this.clearDependencies(); + this.DrawDependencies=function() + { + if (this.getShowDeps()==1) + { + //First recalculate the x,y + this.CalcTaskXY(); + this.clearDependencies(); - var vList=this.getList(); - for(var i=0; i0 && vList[i].getVisible()==1) - { - for(var k=0;k=0 && vList[vTask].getGroup()!=2) - { - if(vList[vTask].getVisible()==1) - { - if(vDependType[k]=='SS')this.drawDependency(vList[vTask].getStartX()-1,vList[vTask].getStartY(),vList[i].getStartX()-1,vList[i].getStartY(),'SS','gDepSS'); - else if(vDependType[k]=='FF')this.drawDependency(vList[vTask].getEndX(),vList[vTask].getEndY(),vList[i].getEndX(),vList[i].getEndY(),'FF','gDepFF'); - else if(vDependType[k]=='SF')this.drawDependency(vList[vTask].getStartX()-1,vList[vTask].getStartY(),vList[i].getEndX(),vList[i].getEndY(),'SF','gDepSF'); - else if(vDependType[k]=='FS')this.drawDependency(vList[vTask].getEndX(),vList[vTask].getEndY(),vList[i].getStartX()-1,vList[i].getStartY(),'FS','gDepFS'); - } - } - } - } - } - } - // draw the current date line - if (vTodayPx>=0) this.sLine(vTodayPx, 0, vTodayPx, this.getChartTable().offsetHeight-1, 'gCurDate'); - }; + if(n>0 && vList[i].getVisible()==1) + { + for(var k=0;k=0 && vList[vTask].getGroup()!=2) + { + if(vList[vTask].getVisible()==1) + { + if(vDependType[k]=='SS')this.drawDependency(vList[vTask].getStartX()-1,vList[vTask].getStartY(),vList[i].getStartX()-1,vList[i].getStartY(),'SS','gDepSS'); + else if(vDependType[k]=='FF')this.drawDependency(vList[vTask].getEndX(),vList[vTask].getEndY(),vList[i].getEndX(),vList[i].getEndY(),'FF','gDepFF'); + else if(vDependType[k]=='SF')this.drawDependency(vList[vTask].getStartX()-1,vList[vTask].getStartY(),vList[i].getEndX(),vList[i].getEndY(),'SF','gDepSF'); + else if(vDependType[k]=='FS')this.drawDependency(vList[vTask].getEndX(),vList[vTask].getEndY(),vList[i].getStartX()-1,vList[i].getStartY(),'FS','gDepFS'); + } + } + } + } + } + } + // draw the current date line + if (vTodayPx>=0) this.sLine(vTodayPx, 0, vTodayPx, this.getChartTable().offsetHeight-1, 'gCurDate'); + }; - this.getArrayLocationByID=function(pId) - { - var vList=this.getList(); - for(var i=0; i0) - { - // Process all tasks, reset parent date and completion % if task list has altered - if (vProcessNeeded) JSGantt.processRows(vTaskList, 0, -1, 1, 1, this.getUseSort()); - vProcessNeeded=false; + if(vTaskList.length>0) + { + // Process all tasks, reset parent date and completion % if task list has altered + if (vProcessNeeded) JSGantt.processRows(vTaskList, 0, -1, 1, 1, this.getUseSort()); + vProcessNeeded=false; - // get overall min/max dates plus padding - vMinDate=JSGantt.getMinDate(vTaskList, vFormat); - vMaxDate=JSGantt.getMaxDate(vTaskList, vFormat); + // get overall min/max dates plus padding + vMinDate=JSGantt.getMinDate(vTaskList, vFormat); + vMaxDate=JSGantt.getMaxDate(vTaskList, vFormat); - // Calculate chart width variables. - if(vFormat=='day') vColWidth=vDayColWidth; - else if(vFormat=='week') vColWidth=vWeekColWidth; - else if(vFormat=='month') vColWidth=vMonthColWidth; - else if(vFormat=='quarter') vColWidth=vQuarterColWidth; - else if(vFormat=='hour') vColWidth=vHourColWidth; + // Calculate chart width variables. + if(vFormat=='day') vColWidth=vDayColWidth; + else if(vFormat=='week') vColWidth=vWeekColWidth; + else if(vFormat=='month') vColWidth=vMonthColWidth; + else if(vFormat=='quarter') vColWidth=vQuarterColWidth; + else if(vFormat=='hour') vColWidth=vHourColWidth; - // DRAW the Left-side of the chart (names, resources, comp%) - var vLeftHeader=document.createDocumentFragment(); + // DRAW the Left-side of the chart (names, resources, comp%) + var vLeftHeader=document.createDocumentFragment(); - var vTmpDiv=this.newNode(vLeftHeader, 'div', vDivId+'glisthead', 'glistlbl gcontainercol'); - var vTmpTab=this.newNode(vTmpDiv, 'table', null, 'gtasktableh'); - var vTmpTBody=this.newNode(vTmpTab, 'tbody'); - var vTmpRow=this.newNode(vTmpTBody, 'tr'); - this.newNode(vTmpRow, 'td', null, 'gtasklist', '\u00A0'); - var vTmpCell=this.newNode(vTmpRow, 'td', null, 'gspanning gtaskname'); - vTmpCell.appendChild(this.drawSelector('top')); - if(vShowRes==1)this.newNode(vTmpRow, 'td', null, 'gspanning gresource', '\u00A0'); - if(vShowDur==1)this.newNode(vTmpRow, 'td', null, 'gspanning gduration', '\u00A0'); - if(vShowComp==1)this.newNode(vTmpRow, 'td', null, 'gspanning gpccomplete', '\u00A0'); - if(vShowStartDate==1)this.newNode(vTmpRow, 'td', null, 'gspanning gstartdate', '\u00A0'); - if(vShowEndDate==1)this.newNode(vTmpRow, 'td', null, 'gspanning genddate', '\u00A0'); + var vTmpDiv=this.newNode(vLeftHeader, 'div', vDivId+'glisthead', 'glistlbl gcontainercol'); + var vTmpTab=this.newNode(vTmpDiv, 'table', null, 'gtasktableh'); + var vTmpTBody=this.newNode(vTmpTab, 'tbody'); + var vTmpRow=this.newNode(vTmpTBody, 'tr'); + this.newNode(vTmpRow, 'td', null, 'gtasklist', '\u00A0'); + var vTmpCell=this.newNode(vTmpRow, 'td', null, 'gspanning gtaskname'); + vTmpCell.appendChild(this.drawSelector('top')); + if(vShowRes==1)this.newNode(vTmpRow, 'td', null, 'gspanning gresource', '\u00A0'); + if(vShowDur==1)this.newNode(vTmpRow, 'td', null, 'gspanning gduration', '\u00A0'); + if(vShowComp==1)this.newNode(vTmpRow, 'td', null, 'gspanning gpccomplete', '\u00A0'); + if(vShowStartDate==1)this.newNode(vTmpRow, 'td', null, 'gspanning gstartdate', '\u00A0'); + if(vShowEndDate==1)this.newNode(vTmpRow, 'td', null, 'gspanning genddate', '\u00A0'); - vTmpRow=this.newNode(vTmpTBody, 'tr'); - this.newNode(vTmpRow, 'td', null, 'gtasklist', '\u00A0'); - this.newNode(vTmpRow, 'td', null, 'gtaskname', '\u00A0'); - if(vShowRes==1)this.newNode(vTmpRow, 'td', null, 'gtaskheading gresource', vLangs[vLang]['resource']); - if(vShowDur==1)this.newNode(vTmpRow, 'td', null, 'gtaskheading gduration', vLangs[vLang]['duration']); - if(vShowComp==1)this.newNode(vTmpRow, 'td', null, 'gtaskheading gpccomplete', vLangs[vLang]['comp']); - if(vShowStartDate==1)this.newNode(vTmpRow, 'td', null, 'gtaskheading gstartdate', vLangs[vLang]['startdate']); - if(vShowEndDate==1)this.newNode(vTmpRow, 'td', null, 'gtaskheading genddate', vLangs[vLang]['enddate']); + vTmpRow=this.newNode(vTmpTBody, 'tr'); + this.newNode(vTmpRow, 'td', null, 'gtasklist', '\u00A0'); + this.newNode(vTmpRow, 'td', null, 'gtaskname', '\u00A0'); + if(vShowRes==1)this.newNode(vTmpRow, 'td', null, 'gtaskheading gresource', vLangs[vLang]['resource']); + if(vShowDur==1)this.newNode(vTmpRow, 'td', null, 'gtaskheading gduration', vLangs[vLang]['duration']); + if(vShowComp==1)this.newNode(vTmpRow, 'td', null, 'gtaskheading gpccomplete', vLangs[vLang]['comp']); + if(vShowStartDate==1)this.newNode(vTmpRow, 'td', null, 'gtaskheading gstartdate', vLangs[vLang]['startdate']); + if(vShowEndDate==1)this.newNode(vTmpRow, 'td', null, 'gtaskheading genddate', vLangs[vLang]['enddate']); - vTmpDiv=this.newNode(vLeftHeader, 'div', null, 'glabelfooter'); + var vLeftTable=document.createDocumentFragment(); + var vTmpDiv2=this.newNode(vLeftTable, 'div', vDivId+'glistbody', 'glistgrid gcontainercol'); + this.setListBody(vTmpDiv2); + vTmpTab=this.newNode(vTmpDiv2, 'table', null, 'gtasktable'); + vTmpTBody=this.newNode(vTmpTab, 'tbody'); - var vLeftTable=document.createDocumentFragment(); - var vTmpDiv2=this.newNode(vLeftTable, 'div', vDivId+'glistbody', 'glistgrid gcontainercol'); - this.setListBody(vTmpDiv2); - vTmpTab=this.newNode(vTmpDiv2, 'table', null, 'gtasktable'); - vTmpTBody=this.newNode(vTmpTab, 'tbody'); + for(i=0; i1) - { - vTmpDate.setDate(vTmpDate.getDate()+1); - } - } - else if(vFormat=='quarter') - { - if(vTmpDate<=vMaxDate) - { - vTmpCell=this.newNode(vTmpRow, 'td', null, vHeaderCellClass); - this.newNode(vTmpCell, 'div', null, null, JSGantt.formatDateStr(vTmpDate,vQuarterMinorDateDisplayFormat,vLangs[vLang]), vColWidth); - vNumCols++; - } + while(vTmpDate.getDate()>1) + { + vTmpDate.setDate(vTmpDate.getDate()+1); + } + } + else if(vFormat=='quarter') + { + if(vTmpDate<=vMaxDate) + { + vTmpCell=this.newNode(vTmpRow, 'td', null, vHeaderCellClass); + this.newNode(vTmpCell, 'div', null, null, JSGantt.formatDateStr(vTmpDate,vQuarterMinorDateDisplayFormat,vLangs[vLang]), vColWidth); + vNumCols++; + } - vTmpDate.setDate(vTmpDate.getDate()+81); + vTmpDate.setDate(vTmpDate.getDate()+81); - while(vTmpDate.getDate()>1) vTmpDate.setDate(vTmpDate.getDate()+1); - } - else if(vFormat=='hour') - { - for(i=vTmpDate.getHours();i<24;i++) - { - vTmpDate.setHours(i);//works around daylight savings but may look a little odd on days where the clock goes forward - if(vTmpDate<=vMaxDate) - { - vTmpCell=this.newNode(vTmpRow, 'td', null, vHeaderCellClass); - this.newNode(vTmpCell, 'div', null, null, JSGantt.formatDateStr(vTmpDate,vHourMinorDateDisplayFormat,vLangs[vLang]), vColWidth); - vNumCols++; - } - } - vTmpDate.setHours(0); - vTmpDate.setDate(vTmpDate.getDate()+1); - } - } - vDateRow=vTmpRow; + while(vTmpDate.getDate()>1) vTmpDate.setDate(vTmpDate.getDate()+1); + } + else if(vFormat=='hour') + { + for(i=vTmpDate.getHours();i<24;i++) + { + vTmpDate.setHours(i);//works around daylight savings but may look a little odd on days where the clock goes forward + if(vTmpDate<=vMaxDate) + { + vTmpCell=this.newNode(vTmpRow, 'td', null, vHeaderCellClass); + this.newNode(vTmpCell, 'div', null, null, JSGantt.formatDateStr(vTmpDate,vHourMinorDateDisplayFormat,vLangs[vLang]), vColWidth); + vNumCols++; + } + } + vTmpDate.setHours(0); + vTmpDate.setDate(vTmpDate.getDate()+1); + } + } + vDateRow=vTmpRow; - vTaskLeftPx=(vNumCols *(vColWidth+1))+1; + vTaskLeftPx=(vNumCols *(vColWidth+1))+1; - if(vUseSingleCell!=0 && vUseSingleCell<(vNumCols*vNumRows))vSingleCell=true; + if(vUseSingleCell!=0 && vUseSingleCell<(vNumCols*vNumRows))vSingleCell=true; - this.newNode(vTmpDiv, 'div', null, 'rhscrpad', null, null, vTaskLeftPx+1); + this.newNode(vTmpDiv, 'div', null, 'rhscrpad', null, null, vTaskLeftPx+1); - var vRightTable=document.createDocumentFragment(); - vTmpDiv=this.newNode(vRightTable, 'div', vDivId+'gchartbody', 'gchartgrid gcontainercol'); - this.setChartBody(vTmpDiv); - vTmpTab=this.newNode(vTmpDiv, 'table', vDivId+'chartTable', 'gcharttable', null, vTaskLeftPx); - this.setChartTable(vTmpTab); - this.newNode(vTmpDiv, 'div', null, 'rhscrpad', null, null, vTaskLeftPx+1); - vTmpTBody=this.newNode(vTmpTab, 'tbody'); + vTmpDiv=this.newNode(vRightHeader, 'div', null, 'glabelfooter'); - // Draw each row + var vRightTable=document.createDocumentFragment(); + vTmpDiv=this.newNode(vRightTable, 'div', vDivId+'gchartbody', 'gchartgrid gcontainercol'); + this.setChartBody(vTmpDiv); + vTmpTab=this.newNode(vTmpDiv, 'table', vDivId+'chartTable', 'gcharttable', null, vTaskLeftPx); + this.setChartTable(vTmpTab); + this.newNode(vTmpDiv, 'div', null, 'rhscrpad', null, null, vTaskLeftPx+1); + vTmpTBody=this.newNode(vTmpTab, 'tbody'); - var i=0; - var j=0; - for(i=0; ivMinGpLen && vTaskWidthvMinGpLen && vTaskWidth=vMinGpLen*2) this.newNode(vTmpDiv, 'div', null, vTaskList[i].getClass() +'endpointright'); + this.newNode(vTmpDiv2, 'div', vDivId+'complete_'+vID, vTaskList[i].getClass() +'complete', null, vTaskList[i].getCompStr()); - vCaptClass='ggroupcaption'; - } + this.newNode(vTmpDiv, 'div', null, vTaskList[i].getClass() +'endpointleft'); + if (vTaskWidth>=vMinGpLen*2) this.newNode(vTmpDiv, 'div', null, vTaskList[i].getClass() +'endpointright'); - if(!vSingleCell && !vComb) - { - vCellFormat=''; - for(j=0; j=(new Date()).getTime()) vTodayPx=JSGantt.getOffset(vMinDate, new Date(), vColWidth, vFormat); - else vTodayPx=-1; - this.DrawDependencies(); - } - }; //this.draw + if(vScrollTo.substr(0,2)=='px') + { + vScrollPx=parseInt(vScrollTo.substr(2)); + } + else + { + vScrollDate=JSGantt.parseDateStr(vScrollTo, this.getDateInputFormat()); + if(vFormat=='hour')vScrollDate.setMinutes(0,0,0); + else vScrollDate.setHours(0,0,0,0); + vScrollPx=JSGantt.getOffset(vMinDate, vScrollDate, vColWidth, vFormat); + } + this.getChartBody().scrollLeft=vScrollPx; + } - this.mouseOver=function(pObj1, pObj2) - { - if (this.getUseRowHlt()) - { - pObj1.className+=' gitemhighlight'; - pObj2.className+=' gitemhighlight'; - } - }; + if (vMinDate.getTime()<=(new Date()).getTime() && vMaxDate.getTime()>=(new Date()).getTime()) vTodayPx=JSGantt.getOffset(vMinDate, new Date(), vColWidth, vFormat); + else vTodayPx=-1; + this.DrawDependencies(); + } + }; //this.draw - this.mouseOut=function(pObj1, pObj2) - { - if (this.getUseRowHlt()) - { - pObj1.className=pObj1.className.replace(/(?:^|\s)gitemhighlight(?!\S)/g, ''); - pObj2.className=pObj2.className.replace(/(?:^|\s)gitemhighlight(?!\S)/g, ''); - } - }; + this.mouseOver=function(pObj1, pObj2) + { + if (this.getUseRowHlt()) + { + pObj1.className+=' gitemhighlight'; + pObj2.className+=' gitemhighlight'; + } + }; - this.drawSelector=function(pPos) - { - var vOutput=document.createDocumentFragment(); - var vDisplay=false; + this.mouseOut=function(pObj1, pObj2) + { + if (this.getUseRowHlt()) + { + pObj1.className=pObj1.className.replace(/(?:^|\s)gitemhighlight(?!\S)/g, ''); + pObj2.className=pObj2.className.replace(/(?:^|\s)gitemhighlight(?!\S)/g, ''); + } + }; - for (var i=0; i=0 && vIdx'; - vTask+=''+vTaskList[vIdx].getName()+''; - vTask+=''+JSGantt.formatDateStr(vTaskList[vIdx].getStart(),vOutFrmt,vLangs[vLang])+''; - vTask+=''+JSGantt.formatDateStr(vTaskList[vIdx].getEnd(),vOutFrmt,vLangs[vLang])+''; - vTask+=''+vTaskList[vIdx].getClass()+''; - vTask+=''+vTaskList[vIdx].getLink()+''; - vTask+=''+vTaskList[vIdx].getMile()+''; - if(vTaskList[vIdx].getResource()!='\u00A0') vTask+=''+vTaskList[vIdx].getResource()+''; - vTask+=''+vTaskList[vIdx].getCompVal()+''; - vTask+=''+vTaskList[vIdx].getGroup()+''; - vTask+=''+vTaskList[vIdx].getParent()+''; - vTask+=''+vTaskList[vIdx].getOpen()+''; - vTask+=''; - var vDepList=vTaskList[vIdx].getDepend(); - for (i=0;i0)vTask+=','; - if(vDepList[i]>0)vTask+=vDepList[i]+vTaskList[vIdx].getDepType()[i]; - } - vTask+=''; - vTask+=''+vTaskList[vIdx].getCaption()+''; + this.getXMLProject=function() + { + var vProject=''; + for (var i=0; i'; - vTask+=''; - } - return vTask; - }; - if (vDiv && vDiv.nodeName.toLowerCase()=='div') vDivId=vDiv.id; + this.getXMLTask=function(pID,pIdx) + { + var i=0; + var vIdx=-1; + var vTask=''; + var vOutFrmt=JSGantt.parseDateFormatStr(this.getDateInputFormat()+' HH:MI'); + if (pIdx===true)vIdx=pID; + else + { + for (i=0; i=0 && vIdx'; + vTask+=''+vTaskList[vIdx].getName()+''; + vTask+=''+JSGantt.formatDateStr(vTaskList[vIdx].getStart(),vOutFrmt,vLangs[vLang])+''; + vTask+=''+JSGantt.formatDateStr(vTaskList[vIdx].getEnd(),vOutFrmt,vLangs[vLang])+''; + vTask+=''+vTaskList[vIdx].getClass()+''; + vTask+=''+vTaskList[vIdx].getLink()+''; + vTask+=''+vTaskList[vIdx].getMile()+''; + if(vTaskList[vIdx].getResource()!='\u00A0') vTask+=''+vTaskList[vIdx].getResource()+''; + vTask+=''+vTaskList[vIdx].getCompVal()+''; + vTask+=''+vTaskList[vIdx].getGroup()+''; + vTask+=''+vTaskList[vIdx].getParent()+''; + vTask+=''+vTaskList[vIdx].getOpen()+''; + vTask+=''; + var vDepList=vTaskList[vIdx].getDepend(); + for (i=0;i0)vTask+=','; + if(vDepList[i]>0)vTask+=vDepList[i]+vTaskList[vIdx].getDepType()[i]; + } + vTask+=''; + vTask+=''+vTaskList[vIdx].getCaption()+''; + + var vTmpFrag=document.createDocumentFragment(); + var vTmpDiv=this.newNode(vTmpFrag, 'div', null, null,vTaskList[vIdx].getNotes().innerHTML); + vTask+=''+vTmpDiv.innerHTML+''; + vTask+=''; + } + return vTask; + }; + if (vDiv && vDiv.nodeName.toLowerCase()=='div') vDivId=vDiv.id; }; //GanttChart JSGantt.updateFlyingObj=function (e, pGanttChartObj, pTimer) { - var vCurTopBuf=3; - var vCurLeftBuf=5; - var vCurBotBuf=3; - var vCurRightBuf=15; - var vMouseX=(e)?e.clientX:window.event.clientX; - var vMouseY=(e)?e.clientY:window.event.clientY; - var vViewportX=document.documentElement.clientWidth||document.getElementsByTagName('body')[0].clientWidth; - var vViewportY=document.documentElement.clientHeight||document.getElementsByTagName('body')[0].clientHeight; - var vNewX=vMouseX; - var vNewY=vMouseY; + var vCurTopBuf=3; + var vCurLeftBuf=5; + var vCurBotBuf=3; + var vCurRightBuf=15; + var vMouseX=(e)?e.clientX:window.event.clientX; + var vMouseY=(e)?e.clientY:window.event.clientY; + var vViewportX=document.documentElement.clientWidth||document.getElementsByTagName('body')[0].clientWidth; + var vViewportY=document.documentElement.clientHeight||document.getElementsByTagName('body')[0].clientHeight; + var vNewX=vMouseX; + var vNewY=vMouseY; - if (navigator.appName.toLowerCase ()=='microsoft internet explorer') { - // the clientX and clientY properties include the left and top borders of the client area - vMouseX-=document.documentElement.clientLeft; - vMouseY-=document.documentElement.clientTop; + if (navigator.appName.toLowerCase ()=='microsoft internet explorer') { + // the clientX and clientY properties include the left and top borders of the client area + vMouseX-=document.documentElement.clientLeft; + vMouseY-=document.documentElement.clientTop; - var vZoomFactor=JSGantt.getZoomFactor (); - if (vZoomFactor!=1) {// IE 7 at non-default zoom level - vMouseX=Math.round (vMouseX / vZoomFactor); - vMouseY=Math.round (vMouseY / vZoomFactor); - } - } + var vZoomFactor=JSGantt.getZoomFactor (); + if (vZoomFactor!=1) {// IE 7 at non-default zoom level + vMouseX=Math.round (vMouseX / vZoomFactor); + vMouseY=Math.round (vMouseY / vZoomFactor); + } + } - var vScrollPos=JSGantt.getScrollPositions(); + var vScrollPos=JSGantt.getScrollPositions(); - /* Code for positioned right of the mouse by default*/ - /* - if (vMouseX+vCurRightBuf+pGanttChartObj.vTool.offsetWidth>vViewportX) - { - if (vMouseX-vCurLeftBuf-pGanttChartObj.vTool.offsetWidth<0) vNewX=vScrollPos.x; - else vNewX=vMouseX+vScrollPos.x-vCurLeftBuf-pGanttChartObj.vTool.offsetWidth; - } - else vNewX=vMouseX+vScrollPos.x+vCurRightBuf; - */ + /* Code for positioned right of the mouse by default*/ + /* + if (vMouseX+vCurRightBuf+pGanttChartObj.vTool.offsetWidth>vViewportX) + { + if (vMouseX-vCurLeftBuf-pGanttChartObj.vTool.offsetWidth<0) vNewX=vScrollPos.x; + else vNewX=vMouseX+vScrollPos.x-vCurLeftBuf-pGanttChartObj.vTool.offsetWidth; + } + else vNewX=vMouseX+vScrollPos.x+vCurRightBuf; + */ - /* Code for positioned left of the mouse by default */ - if (vMouseX-vCurLeftBuf-pGanttChartObj.vTool.offsetWidth<0) - { - if (vMouseX+vCurRightBuf+pGanttChartObj.vTool.offsetWidth>vViewportX) vNewX=vScrollPos.x; - else vNewX=vMouseX+vScrollPos.x+vCurRightBuf; - } - else vNewX=vMouseX+vScrollPos.x-vCurLeftBuf-pGanttChartObj.vTool.offsetWidth; + /* Code for positioned left of the mouse by default */ + if (vMouseX-vCurLeftBuf-pGanttChartObj.vTool.offsetWidth<0) + { + if (vMouseX+vCurRightBuf+pGanttChartObj.vTool.offsetWidth>vViewportX) vNewX=vScrollPos.x; + else vNewX=vMouseX+vScrollPos.x+vCurRightBuf; + } + else vNewX=vMouseX+vScrollPos.x-vCurLeftBuf-pGanttChartObj.vTool.offsetWidth; - /* Code for positioned below the mouse by default */ - if (vMouseY+vCurBotBuf+pGanttChartObj.vTool.offsetHeight>vViewportY) - { - if (vMouseY-vCurTopBuf-pGanttChartObj.vTool.offsetHeight<0) vNewY=vScrollPos.y; - else vNewY=vMouseY+vScrollPos.y-vCurTopBuf-pGanttChartObj.vTool.offsetHeight; - } - else vNewY=vMouseY+vScrollPos.y+vCurBotBuf; + /* Code for positioned below the mouse by default */ + if (vMouseY+vCurBotBuf+pGanttChartObj.vTool.offsetHeight>vViewportY) + { + if (vMouseY-vCurTopBuf-pGanttChartObj.vTool.offsetHeight<0) vNewY=vScrollPos.y; + else vNewY=vMouseY+vScrollPos.y-vCurTopBuf-pGanttChartObj.vTool.offsetHeight; + } + else vNewY=vMouseY+vScrollPos.y+vCurBotBuf; - /* Code for positioned above the mouse by default */ - /* - if (vMouseY-vCurTopBuf-pGanttChartObj.vTool.offsetHeight<0) - { - if (vMouseY+vCurBotBuf+pGanttChartObj.vTool.offsetHeight>vViewportY) vNewY=vScrollPos.y; - else vNewY=vMouseY+vScrollPos.y+vCurBotBuf; - } - else vNewY=vMouseY+vScrollPos.y-vCurTopBuf-pGanttChartObj.vTool.offsetHeight; - */ + /* Code for positioned above the mouse by default */ + /* + if (vMouseY-vCurTopBuf-pGanttChartObj.vTool.offsetHeight<0) + { + if (vMouseY+vCurBotBuf+pGanttChartObj.vTool.offsetHeight>vViewportY) vNewY=vScrollPos.y; + else vNewY=vMouseY+vScrollPos.y+vCurBotBuf; + } + else vNewY=vMouseY+vScrollPos.y-vCurTopBuf-pGanttChartObj.vTool.offsetHeight; + */ - if (pGanttChartObj.getUseMove()) - { - clearInterval(pGanttChartObj.vTool.moveInterval); - pGanttChartObj.vTool.moveInterval=setInterval(function(){JSGantt.moveToolTip(vNewX, vNewY, pGanttChartObj.vTool, pTimer);},pTimer); - } - else - { - pGanttChartObj.vTool.style.left=vNewX +'px'; - pGanttChartObj.vTool.style.top=vNewY +'px'; - } + if (pGanttChartObj.getUseMove()) + { + clearInterval(pGanttChartObj.vTool.moveInterval); + pGanttChartObj.vTool.moveInterval=setInterval(function(){JSGantt.moveToolTip(vNewX, vNewY, pGanttChartObj.vTool, pTimer);},pTimer); + } + else + { + pGanttChartObj.vTool.style.left=vNewX +'px'; + pGanttChartObj.vTool.style.top=vNewY +'px'; + } }; JSGantt.showToolTip=function(pGanttChartObj, e, pContents, pWidth, pTimer){ - var vTtDivId=pGanttChartObj.getDivId()+'JSGanttToolTip'; - var vMaxW=500; - var vMaxAlpha=100; - var vShowing=pContents.id; + var vTtDivId=pGanttChartObj.getDivId()+'JSGanttToolTip'; + var vMaxW=500; + var vMaxAlpha=100; + var vShowing=pContents.id; - if(pGanttChartObj.getUseToolTip()) - { - if(pGanttChartObj.vTool==null){ - pGanttChartObj.vTool=document.createElement('div'); - pGanttChartObj.vTool.id=vTtDivId; - pGanttChartObj.vTool.className='JSGanttToolTip'; - pGanttChartObj.vTool.vToolCont=document.createElement('div'); - pGanttChartObj.vTool.vToolCont.id=vTtDivId+'cont'; - pGanttChartObj.vTool.vToolCont.className='JSGanttToolTipcont'; - pGanttChartObj.vTool.vToolCont.setAttribute('showing',''); - pGanttChartObj.vTool.appendChild(pGanttChartObj.vTool.vToolCont); - document.body.appendChild(pGanttChartObj.vTool); - pGanttChartObj.vTool.style.opacity=0; - pGanttChartObj.vTool.setAttribute('currentOpacity',0); - pGanttChartObj.vTool.setAttribute('fadeIncrement',10); - pGanttChartObj.vTool.setAttribute('moveSpeed',10); - pGanttChartObj.vTool.style.filter='alpha(opacity=0)'; - pGanttChartObj.vTool.style.visibility='hidden'; - pGanttChartObj.vTool.style.left=Math.floor(((e)?e.clientX:window.event.clientX)/2)+'px'; - pGanttChartObj.vTool.style.top=Math.floor(((e)?e.clientY:window.event.clientY)/2)+'px'; - JSGantt.addListener('mouseover', function () {clearTimeout(pGanttChartObj.vTool.delayTimeout);}, pGanttChartObj.vTool); - JSGantt.addListener('mouseout', function () {JSGantt.delayedHide(pGanttChartObj, pGanttChartObj.vTool, pTimer);}, pGanttChartObj.vTool); - } - clearTimeout(pGanttChartObj.vTool.delayTimeout); - if(pGanttChartObj.vTool.vToolCont.getAttribute('showing')!=vShowing || pGanttChartObj.vTool.style.visibility!='visible') - { - if (pGanttChartObj.vTool.vToolCont.getAttribute('showing')!=vShowing) - { - pGanttChartObj.vTool.vToolCont.setAttribute('showing',vShowing); + if(pGanttChartObj.getUseToolTip()) + { + if(pGanttChartObj.vTool==null){ + pGanttChartObj.vTool=document.createElement('div'); + pGanttChartObj.vTool.id=vTtDivId; + pGanttChartObj.vTool.className='JSGanttToolTip'; + pGanttChartObj.vTool.vToolCont=document.createElement('div'); + pGanttChartObj.vTool.vToolCont.id=vTtDivId+'cont'; + pGanttChartObj.vTool.vToolCont.className='JSGanttToolTipcont'; + pGanttChartObj.vTool.vToolCont.setAttribute('showing',''); + pGanttChartObj.vTool.appendChild(pGanttChartObj.vTool.vToolCont); + document.body.appendChild(pGanttChartObj.vTool); + pGanttChartObj.vTool.style.opacity=0; + pGanttChartObj.vTool.setAttribute('currentOpacity',0); + pGanttChartObj.vTool.setAttribute('fadeIncrement',10); + pGanttChartObj.vTool.setAttribute('moveSpeed',10); + pGanttChartObj.vTool.style.filter='alpha(opacity=0)'; + pGanttChartObj.vTool.style.visibility='hidden'; + pGanttChartObj.vTool.style.left=Math.floor(((e)?e.clientX:window.event.clientX)/2)+'px'; + pGanttChartObj.vTool.style.top=Math.floor(((e)?e.clientY:window.event.clientY)/2)+'px'; + JSGantt.addListener('mouseover', function () {clearTimeout(pGanttChartObj.vTool.delayTimeout);}, pGanttChartObj.vTool); + JSGantt.addListener('mouseout', function () {JSGantt.delayedHide(pGanttChartObj, pGanttChartObj.vTool, pTimer);}, pGanttChartObj.vTool); + } + clearTimeout(pGanttChartObj.vTool.delayTimeout); + if(pGanttChartObj.vTool.vToolCont.getAttribute('showing')!=vShowing || pGanttChartObj.vTool.style.visibility!='visible') + { + if (pGanttChartObj.vTool.vToolCont.getAttribute('showing')!=vShowing) + { + pGanttChartObj.vTool.vToolCont.setAttribute('showing',vShowing); - pGanttChartObj.vTool.vToolCont.innerHTML=pContents.innerHTML; - // as we are allowing arbitrary HTML we should remove any tag ids to prevent duplication - JSGantt.stripIds(pGanttChartObj.vTool.vToolCont); - } + pGanttChartObj.vTool.vToolCont.innerHTML=pContents.innerHTML; + // as we are allowing arbitrary HTML we should remove any tag ids to prevent duplication + JSGantt.stripIds(pGanttChartObj.vTool.vToolCont); + } - pGanttChartObj.vTool.style.visibility='visible'; - // Rather than follow the mouse just have it stay put - JSGantt.updateFlyingObj(e, pGanttChartObj, pTimer); - pGanttChartObj.vTool.style.width=(pWidth)? pWidth+'px' : 'auto'; - if(!pWidth && JSGantt.isIE()){ - pGanttChartObj.vTool.style.width=pGanttChartObj.vTool.offsetWidth; - } - if(pGanttChartObj.vTool.offsetWidth>vMaxW){pGanttChartObj.vTool.style.width=vMaxW+'px';} - } + pGanttChartObj.vTool.style.visibility='visible'; + // Rather than follow the mouse just have it stay put + JSGantt.updateFlyingObj(e, pGanttChartObj, pTimer); + pGanttChartObj.vTool.style.width=(pWidth)? pWidth+'px' : 'auto'; + if(!pWidth && JSGantt.isIE()){ + pGanttChartObj.vTool.style.width=pGanttChartObj.vTool.offsetWidth; + } + if(pGanttChartObj.vTool.offsetWidth>vMaxW){pGanttChartObj.vTool.style.width=vMaxW+'px';} + } - if (pGanttChartObj.getUseFade()) - { - clearInterval(pGanttChartObj.vTool.fadeInterval); - pGanttChartObj.vTool.fadeInterval=setInterval(function(){JSGantt.fadeToolTip(1, pGanttChartObj.vTool, vMaxAlpha);},pTimer); - } - else - { - pGanttChartObj.vTool.style.opacity=vMaxAlpha * 0.01; - pGanttChartObj.vTool.style.filter='alpha(opacity='+vMaxAlpha+')'; - } - } + if (pGanttChartObj.getUseFade()) + { + clearInterval(pGanttChartObj.vTool.fadeInterval); + pGanttChartObj.vTool.fadeInterval=setInterval(function(){JSGantt.fadeToolTip(1, pGanttChartObj.vTool, vMaxAlpha);},pTimer); + } + else + { + pGanttChartObj.vTool.style.opacity=vMaxAlpha * 0.01; + pGanttChartObj.vTool.style.filter='alpha(opacity='+vMaxAlpha+')'; + } + } }; JSGantt.stripIds=function(pNode){ - for(var i=0; i=0 && pList[i].getID()==pID)vCurItem=pList[i]; - } + for(i=0; i=0 && pList[i].getID()==pID)vCurItem=pList[i]; + } - for(i=0; ivMaxDate) - { - vMaxDate=pList[i].getEnd(); - vMaxSet=1; - } + if(vMaxSet==0 || pList[i].getEnd()>vMaxDate) + { + vMaxDate=pList[i].getEnd(); + vMaxSet=1; + } - vCompSum+=pList[i].getCompVal(); - pList[i].setSortIdx(i*pList.length); - } - } + vNumKid++; + vWeight+=pList[i].getEnd()-pList[i].getStart()+1; + vCompSum+=pList[i].getCompVal()*(pList[i].getEnd()-pList[i].getStart()+1); + pList[i].setSortIdx(i*pList.length); + } + } - if(pRow>=0) - { - if(pList[pRow].getGroupMinStart()!=null && pList[pRow].getGroupMinStart()=0) + { + if(pList[pRow].getGroupMinStart()!=null && pList[pRow].getGroupMinStart()vMaxDate) - { - vMaxDate=pList[pRow].getGroupMinEnd(); - } - pList[pRow].setStart(vMinDate); - pList[pRow].setEnd(vMaxDate); - pList[pRow].setNumKid(vNumKid); - pList[pRow].setCompVal(Math.ceil(vCompSum/vNumKid)); - } + if(pList[pRow].getGroupMinEnd()!=null && pList[pRow].getGroupMinEnd()>vMaxDate) + { + vMaxDate=pList[pRow].getGroupMinEnd(); + } + pList[pRow].setStart(vMinDate); + pList[pRow].setEnd(vMaxDate); + pList[pRow].setNumKid(vNumKid); + pList[pRow].setWeight(vWeight); + pList[pRow].setCompVal(Math.ceil(vCompSum/vWeight)); + } - if (pID==0 && pUseSort==1) - { - JSGantt.sortTasks(pList, 0, 0); - pList.sort(function(a,b){return a.getSortIdx()-b.getSortIdx();}); - } - if (pID==0 && pUseSort!=1) // Need to sort combined tasks regardless - { - for(i=0; i0) - { - sortArr.sort(function(a,b){ var i=a.getStart().getTime()-b.getStart().getTime(); - if (i==0) i=a.getEnd().getTime()-b.getEnd().getTime(); - if (i==0) return a.getID()-b.getID(); - else return i; }); - } + if (sortArr.length>0) + { + sortArr.sort(function(a,b){ var i=a.getStart().getTime()-b.getStart().getTime(); + if (i==0) i=a.getEnd().getTime()-b.getEnd().getTime(); + if (i==0) return a.getID()-b.getID(); + else return i; }); + } - for (var j=0; j1) vDate.setDate(vDate.getDate()-1); - } - else if (pFormat=='quarter') - { - vDate.setDate(vDate.getDate()-31); - if(vDate.getMonth()==0 || vDate.getMonth()==1 || vDate.getMonth()==2) - vDate.setFullYear(vDate.getFullYear(), 0, 1); - else if(vDate.getMonth()==3 || vDate.getMonth()==4 || vDate.getMonth()==5) - vDate.setFullYear(vDate.getFullYear(), 3, 1); - else if(vDate.getMonth()==6 || vDate.getMonth()==7 || vDate.getMonth()==8) - vDate.setFullYear(vDate.getFullYear(), 6, 1); - else if(vDate.getMonth()==9 || vDate.getMonth()==10 || vDate.getMonth()==11) - vDate.setFullYear(vDate.getFullYear(), 9, 1); - } - else if (pFormat=='hour') - { - vDate.setHours(vDate.getHours()-1); - while(vDate.getHours()%6!=0) vDate.setHours(vDate.getHours()-1); - } + // Adjust min date to specific format boundaries (first of week or first of month) + if (pFormat=='day') + { + vDate.setDate(vDate.getDate()-1); + while(vDate.getDay()%7!=1) vDate.setDate(vDate.getDate()-1); + } + else if (pFormat=='week') + { + vDate.setDate(vDate.getDate()-1); + while(vDate.getDay()%7!=1) vDate.setDate(vDate.getDate()-1); + } + else if (pFormat=='month') + { + vDate.setDate(vDate.getDate()-15); + while(vDate.getDate()>1) vDate.setDate(vDate.getDate()-1); + } + else if (pFormat=='quarter') + { + vDate.setDate(vDate.getDate()-31); + if(vDate.getMonth()==0 || vDate.getMonth()==1 || vDate.getMonth()==2) + vDate.setFullYear(vDate.getFullYear(), 0, 1); + else if(vDate.getMonth()==3 || vDate.getMonth()==4 || vDate.getMonth()==5) + vDate.setFullYear(vDate.getFullYear(), 3, 1); + else if(vDate.getMonth()==6 || vDate.getMonth()==7 || vDate.getMonth()==8) + vDate.setFullYear(vDate.getFullYear(), 6, 1); + else if(vDate.getMonth()==9 || vDate.getMonth()==10 || vDate.getMonth()==11) + vDate.setFullYear(vDate.getFullYear(), 9, 1); + } + else if (pFormat=='hour') + { + vDate.setHours(vDate.getHours()-1); + while(vDate.getHours()%6!=0) vDate.setHours(vDate.getHours()-1); + } - if(pFormat=='hour')vDate.setMinutes(0,0); - else vDate.setHours(0,0,0); - return(vDate); + if(pFormat=='hour')vDate.setMinutes(0,0); + else vDate.setHours(0,0,0); + return(vDate); }; // Used to determine the maximum date of all tasks and set upper bound based on format JSGantt.getMaxDate=function (pList, pFormat) { - var vDate=new Date(); + var vDate=new Date(); - vDate.setTime(pList[0].getEnd().getTime()); + vDate.setTime(pList[0].getEnd().getTime()); - // Parse all Task End dates to find max - for(var i=0; ivDate.getTime()) vDate.setTime(pList[i].getEnd().getTime()); - } + // Parse all Task End dates to find max + for(var i=0; ivDate.getTime()) vDate.setTime(pList[i].getEnd().getTime()); + } - // Adjust max date to specific format boundaries (end of week or end of month) - if (pFormat=='day') - { - vDate.setDate(vDate.getDate()+1); + // Adjust max date to specific format boundaries (end of week or end of month) + if (pFormat=='day') + { + vDate.setDate(vDate.getDate()+1); - while(vDate.getDay()%7!=0) vDate.setDate(vDate.getDate()+1); - } - else if (pFormat=='week') - { - //For weeks, what is the last logical boundary? - vDate.setDate(vDate.getDate()+1); + while(vDate.getDay()%7!=0) vDate.setDate(vDate.getDate()+1); + } + else if (pFormat=='week') + { + //For weeks, what is the last logical boundary? + vDate.setDate(vDate.getDate()+1); - while(vDate.getDay()%7!=0) vDate.setDate(vDate.getDate()+1); - } - else if (pFormat=='month') - { - // Set to last day of current Month - while(vDate.getDate()>1) vDate.setDate(vDate.getDate()+1); - vDate.setDate(vDate.getDate()-1); - } - else if (pFormat=='quarter') - { - // Set to last day of current Quarter - if(vDate.getMonth()==0 || vDate.getMonth()==1 || vDate.getMonth()==2) - vDate.setFullYear(vDate.getFullYear(), 2, 31); - else if(vDate.getMonth()==3 || vDate.getMonth()==4 || vDate.getMonth()==5) - vDate.setFullYear(vDate.getFullYear(), 5, 30); - else if(vDate.getMonth()==6 || vDate.getMonth()==7 || vDate.getMonth()==8) - vDate.setFullYear(vDate.getFullYear(), 8, 30); - else if(vDate.getMonth()==9 || vDate.getMonth()==10 || vDate.getMonth()==11) - vDate.setFullYear(vDate.getFullYear(), 11, 31); - } - else if (pFormat=='hour') - { - if(vDate.getHours()==0)vDate.setDate(vDate.getDate()+1); - vDate.setHours(vDate.getHours()+1); + while(vDate.getDay()%7!=0) vDate.setDate(vDate.getDate()+1); + } + else if (pFormat=='month') + { + // Set to last day of current Month + while(vDate.getDate()>1) vDate.setDate(vDate.getDate()+1); + vDate.setDate(vDate.getDate()-1); + } + else if (pFormat=='quarter') + { + // Set to last day of current Quarter + if(vDate.getMonth()==0 || vDate.getMonth()==1 || vDate.getMonth()==2) + vDate.setFullYear(vDate.getFullYear(), 2, 31); + else if(vDate.getMonth()==3 || vDate.getMonth()==4 || vDate.getMonth()==5) + vDate.setFullYear(vDate.getFullYear(), 5, 30); + else if(vDate.getMonth()==6 || vDate.getMonth()==7 || vDate.getMonth()==8) + vDate.setFullYear(vDate.getFullYear(), 8, 30); + else if(vDate.getMonth()==9 || vDate.getMonth()==10 || vDate.getMonth()==11) + vDate.setFullYear(vDate.getFullYear(), 11, 31); + } + else if (pFormat=='hour') + { + if(vDate.getHours()==0)vDate.setDate(vDate.getDate()+1); + vDate.setHours(vDate.getHours()+1); - while(vDate.getHours()%6!=5) vDate.setHours(vDate.getHours()+1); - } - return(vDate); + while(vDate.getHours()%6!=5) vDate.setHours(vDate.getHours()+1); + } + return(vDate); }; // This function finds the document id of the specified object JSGantt.findObj=function (theObj, theDoc) { - var p, i, foundObj; - if(!theDoc) theDoc=document; - if(document.getElementById) foundObj=document.getElementById(theObj); - return foundObj; + var p, i, foundObj; + if(!theDoc) theDoc=document; + if(document.getElementById) foundObj=document.getElementById(theObj); + return foundObj; }; JSGantt.changeFormat=function(pFormat,ganttObj) { - if(ganttObj) ganttObj.setFormat(pFormat); - else alert('Chart undefined'); + if(ganttObj) ganttObj.setFormat(pFormat); + else alert('Chart undefined'); }; // Function to open/close and hide/show children of specified task JSGantt.folder=function (pID,ganttObj) { - var vList=ganttObj.getList(); - var vDivId=ganttObj.getDivId(); + var vList=ganttObj.getList(); + var vDivId=ganttObj.getDivId(); - ganttObj.clearDependencies(); // clear these first so slow rendering doesn't look odd + ganttObj.clearDependencies(); // clear these first so slow rendering doesn't look odd - for(var i=0; i=52 && vMonthStr==1) vYear--; + if (vWeekNum==1 && vMonthStr==12) vYear++; + if (vWeekNum<10) vWeekNum='0'+vWeekNum; - - for (var i=0; i=52 && vMonthStr==1) vYear--; - if (vWeekNum==1 && vMonthStr==12) vYear++; - if (vWeekNum<10) vWeekNum='0'+vWeekNum; - - vDateStr+=vYear+'-W'+vWeekNum+'-'+vDayOfWeek; - break; - default: - if (pL[pDateFormatArr[i].toLowerCase()]) vDateStr+=pL[pDateFormatArr[i].toLowerCase()]; - else vDateStr+=pDateFormatArr[i]; - break; - } - } - return vDateStr; + vDateStr+=vYear+'-W'+vWeekNum+'-'+vDayOfWeek; + break; + default: + if (pL[pDateFormatArr[i].toLowerCase()]) vDateStr+=pL[pDateFormatArr[i].toLowerCase()]; + else vDateStr+=pDateFormatArr[i]; + break; + } + } + return vDateStr; }; JSGantt.parseDateFormatStr=function(pFormatStr) { - var vDateStr=''; - var vComponantStr=''; - var vCurrChar=''; - var vSeparators=new RegExp('[\/\\ -.,\'":]'); - var vDateFormatArray=new Array(); + var vDateStr=''; + var vComponantStr=''; + var vCurrChar=''; + var vSeparators=new RegExp('[\/\\ -.,\'":]'); + var vDateFormatArray=new Array(); - for (var i=0; i0) project=projNode[0].getAttribute('xmlns'); + var projNode=JSGantt.findXMLNode(pXmlDoc,'Project'); + if (typeof projNode!='undefined' && projNode.length>0) project=projNode[0].getAttribute('xmlns'); - if(project=='http://schemas.microsoft.com/project') - { - vMSP=true; - pGanttVar.setDateInputFormat('yyyy-mm-dd'); - Task=JSGantt.findXMLNode(pXmlDoc,'Task'); - if (typeof Task=='undefined')n=0; - else n=Task.length; + if(project=='http://schemas.microsoft.com/project') + { + vMSP=true; + pGanttVar.setDateInputFormat('yyyy-mm-dd'); + Task=JSGantt.findXMLNode(pXmlDoc,'Task'); + if (typeof Task=='undefined')n=0; + else n=Task.length; - var resources=JSGantt.findXMLNode(pXmlDoc,'Resource'); - if (typeof resources=='undefined'){n=0; m=0;} - else m=resources.length; + var resources=JSGantt.findXMLNode(pXmlDoc,'Resource'); + if (typeof resources=='undefined'){n=0; m=0;} + else m=resources.length; - for(i=0;i0 && uid>0) res[uid]=resname; - } + if (resname.length>0 && uid>0) res[uid]=resname; + } - var assignments=JSGantt.findXMLNode(pXmlDoc,'Assignment'); - if (typeof assignments=='undefined') j=0; - else j=assignments.length; + var assignments=JSGantt.findXMLNode(pXmlDoc,'Assignment'); + if (typeof assignments=='undefined') j=0; + else j=assignments.length; - for(i=0;i0) - { - if (resUID>0) assRes[uid]=res[resUID]; - ass[uid]=assignments[i]; - } - } + if (uid>0) + { + if (resUID>0) assRes[uid]=res[resUID]; + ass[uid]=assignments[i]; + } + } - // Store information about parent UIDs in an easily searchable form - for(i=0;i0) pars[vOutlineNumber]=uid; - if (uid>maxPID)maxPID=uid; - } + if(uid!=0) var vOutlineNumber=JSGantt.getXMLNodeValue(Task[i],'OutlineNumber',2,'0'); + if (uid>0) pars[vOutlineNumber]=uid; + if (uid>maxPID)maxPID=uid; + } - for(i=0;i1) - { - vOutlineNumber=JSGantt.getXMLNodeValue(Task[i],'OutlineNumber',2,'0'); - pParent=pars[vOutlineNumber.substr(0, vOutlineNumber.lastIndexOf('.'))]; - } + var vOutlineLevel=JSGantt.getXMLNodeValue(Task[i],'OutlineLevel',1,0); + if (vOutlineLevel>1) + { + vOutlineNumber=JSGantt.getXMLNodeValue(Task[i],'OutlineNumber',2,'0'); + pParent=pars[vOutlineNumber.substr(0, vOutlineNumber.lastIndexOf('.'))]; + } - try {var pNotes=Task[i].getElementsByTagName('Notes')[0].childNodes[1].nodeValue; //this should be a CDATA node - } catch (error) - {pNotes ='';} + try {var pNotes=Task[i].getElementsByTagName('Notes')[0].childNodes[1].nodeValue; //this should be a CDATA node + } catch (error) + {pNotes ='';} - if(typeof assRes[pID]!='undefined') var pRes=assRes[pID]; - else pRes=''; + if(typeof assRes[pID]!='undefined') var pRes=assRes[pID]; + else pRes=''; - var predecessors=JSGantt.findXMLNode(Task[i],'PredecessorLink'); - if (typeof predecessors=='undefined') j=0; - else j=predecessors.length; - var pDepend=''; + var predecessors=JSGantt.findXMLNode(Task[i],'PredecessorLink'); + if (typeof predecessors=='undefined') j=0; + else j=predecessors.length; + var pDepend=''; - for(k=0;k0) - { - if (pDepend.length>0)pDepend+=','; - switch(depType) - { - case 0: pDepend+=depUID+'FF'; break; - case 1: pDepend+=depUID+'FS'; break; - case 2: pDepend+=depUID+'SF'; break; - case 3: pDepend+=depUID+'SS'; break; - default: pDepend+=depUID+'FS'; break; - } - } - } + if (depUID>0) + { + if (pDepend.length>0)pDepend+=','; + switch(depType) + { + case 0: pDepend+=depUID+'FF'; break; + case 1: pDepend+=depUID+'FS'; break; + case 2: pDepend+=depUID+'SF'; break; + case 3: pDepend+=depUID+'SS'; break; + default: pDepend+=depUID+'FS'; break; + } + } + } - var pOpen=1; - var pCaption=''; + var pOpen=1; + var pCaption=''; - if(pGroup>0) var pClass ='ggroupblack'; - else if(pMile>0) pClass ='gmilestone'; - else pClass ='gtaskblue'; + if(pGroup>0) var pClass ='ggroupblack'; + else if(pMile>0) pClass ='gmilestone'; + else pClass ='gtaskblue'; - // check for split tasks + // check for split tasks - var splits=JSGantt.findXMLNode(ass[pID],'TimephasedData'); - if (typeof splits=='undefined') j=0; - else j=splits.length; + var splits=JSGantt.findXMLNode(ass[pID],'TimephasedData'); + if (typeof splits=='undefined') j=0; + else j=splits.length; - var vSplitStart=pStart; - var vSplitEnd=pEnd; - var vSubCreated=false; - var vDepend=pDepend.replace(/,*[0-9]+[FS]F/g,''); + var vSplitStart=pStart; + var vSplitEnd=pEnd; + var vSubCreated=false; + var vDepend=pDepend.replace(/,*[0-9]+[FS]F/g,''); - for(k=0;k0) pClass ='ggroupblack'; - else if(pMile>0) pClass ='gmilestone'; - else pClass ='gtaskblue'; - } + if(pID!=0) + { + pName=JSGantt.getXMLNodeValue(Task[i],'pName',2,'No Task Name'); + pStart=JSGantt.getXMLNodeValue(Task[i],'pStart',2,''); + pEnd=JSGantt.getXMLNodeValue(Task[i],'pEnd',2,''); + pLink=JSGantt.getXMLNodeValue(Task[i],'pLink',2,''); + pMile=JSGantt.getXMLNodeValue(Task[i],'pMile',1,0); + pComp=JSGantt.getXMLNodeValue(Task[i],'pComp',1,0); + pGroup=JSGantt.getXMLNodeValue(Task[i],'pGroup',1,0); + pParent=JSGantt.getXMLNodeValue(Task[i],'pParent',1,0); + pRes=JSGantt.getXMLNodeValue(Task[i],'pRes',2,''); + pOpen=JSGantt.getXMLNodeValue(Task[i],'pOpen',1,1); + pDepend=JSGantt.getXMLNodeValue(Task[i],'pDepend',2,''); + pCaption=JSGantt.getXMLNodeValue(Task[i],'pCaption',2,''); + pNotes=JSGantt.getXMLNodeValue(Task[i],'pNotes',2,''); + pClass=JSGantt.getXMLNodeValue(Task[i],'pClass',2); + if (typeof pClass=='undefined') + { + if(pGroup>0) pClass ='ggroupblack'; + else if(pMile>0) pClass ='gmilestone'; + else pClass ='gtaskblue'; + } - // Finally add the task - pGanttVar.AddTaskItem(new JSGantt.TaskItem(pID, pName, pStart, pEnd, pClass, pLink, pMile, pRes, pComp, pGroup, pParent, pOpen, pDepend, pCaption, pNotes, pGanttVar)); - } - } - } + // Finally add the task + pGanttVar.AddTaskItem(new JSGantt.TaskItem(pID, pName, pStart, pEnd, pClass, pLink, pMile, pRes, pComp, pGroup, pParent, pOpen, pDepend, pCaption, pNotes, pGanttVar)); + } + } + } }; JSGantt.benchMark=function(pItem) { - var vEndTime=new Date().getTime(); - alert(pItem+': Elapsed time: '+((vEndTime-vBenchTime)/1000)+' seconds.'); - vBenchTime=new Date().getTime(); + var vEndTime=new Date().getTime(); + alert(pItem+': Elapsed time: '+((vEndTime-vBenchTime)/1000)+' seconds.'); + vBenchTime=new Date().getTime(); }; JSGantt.getIsoWeek=function(pDate){ - // We have to compare against the monday of the first week of the year containing 04 jan *not* 01/01 - // 60*60*24*1000=86400000 - var dayMiliseconds=86400000; - var keyDay=new Date(pDate.getFullYear(),0,4,0,0,0); - var keyDayOfWeek=(keyDay.getDay()==0) ? 6 : keyDay.getDay()-1; // define monday as 0 - var firstMondayYearTime=keyDay.getTime()-(keyDayOfWeek * dayMiliseconds); - var thisDate=new Date(pDate.getFullYear(), pDate.getMonth(),pDate.getDate(),0,0,0); // This at 00:00:00 - var thisTime=thisDate.getTime(); - var daysFromFirstMonday=Math.round(((thisTime-firstMondayYearTime) / dayMiliseconds)); - var lastWeek=99; - var thisWeek=99; + // We have to compare against the monday of the first week of the year containing 04 jan *not* 01/01 + // 60*60*24*1000=86400000 + var dayMiliseconds=86400000; + var keyDay=new Date(pDate.getFullYear(),0,4,0,0,0); + var keyDayOfWeek=(keyDay.getDay()==0) ? 6 : keyDay.getDay()-1; // define monday as 0 + var firstMondayYearTime=keyDay.getTime()-(keyDayOfWeek * dayMiliseconds); + var thisDate=new Date(pDate.getFullYear(), pDate.getMonth(),pDate.getDate(),0,0,0); // This at 00:00:00 + var thisTime=thisDate.getTime(); + var daysFromFirstMonday=Math.round(((thisTime-firstMondayYearTime) / dayMiliseconds)); + var lastWeek=99; + var thisWeek=99; - var firstMondayYear=new Date(firstMondayYearTime); + var firstMondayYear=new Date(firstMondayYearTime); - thisWeek=Math.ceil((daysFromFirstMonday+1)/7); + thisWeek=Math.ceil((daysFromFirstMonday+1)/7); - if (thisWeek<=0) thisWeek=JSGantt.getIsoWeek(new Date(pDate.getFullYear()-1,11,31,0,0,0)); - else if (thisWeek==53 && (new Date(pDate.getFullYear(),0,1,0,0,0)).getDay()!=4 && (new Date(pDate.getFullYear(),11,31,0,0,0)).getDay()!=4) thisWeek=1; - return thisWeek; + if (thisWeek<=0) thisWeek=JSGantt.getIsoWeek(new Date(pDate.getFullYear()-1,11,31,0,0,0)); + else if (thisWeek==53 && (new Date(pDate.getFullYear(),0,1,0,0,0)).getDay()!=4 && (new Date(pDate.getFullYear(),11,31,0,0,0)).getDay()!=4) thisWeek=1; + return thisWeek; }; JSGantt.addListener=function (eventName, handler, control) { - // Check if control is a string - if (control===String(control)) control=JSGantt.findObj(control); + // Check if control is a string + if (control===String(control)) control=JSGantt.findObj(control); - if(control.addEventListener) //Standard W3C - { - return control.addEventListener(eventName, handler, false); - } - else if (control.attachEvent) //IExplore - { - return control.attachEvent('on'+eventName, handler); - } - else - { - return false; - } + if(control.addEventListener) //Standard W3C + { + return control.addEventListener(eventName, handler, false); + } + else if (control.attachEvent) //IExplore + { + return control.attachEvent('on'+eventName, handler); + } + else + { + return false; + } }; JSGantt.addTooltipListeners=function(pGanttChart, pObj1, pObj2) { - JSGantt.addListener('mouseover', function (e) {JSGantt.showToolTip(pGanttChart, e, pObj2, null, pGanttChart.getTimer());}, pObj1); - JSGantt.addListener('mouseout', function (e) {JSGantt.delayedHide(pGanttChart, pGanttChart.vTool, pGanttChart.getTimer());}, pObj1); + JSGantt.addListener('mouseover', function (e) {JSGantt.showToolTip(pGanttChart, e, pObj2, null, pGanttChart.getTimer());}, pObj1); + JSGantt.addListener('mouseout', function (e) {JSGantt.delayedHide(pGanttChart, pGanttChart.vTool, pGanttChart.getTimer());}, pObj1); }; JSGantt.addThisRowListeners=function(pGanttChart, pObj1, pObj2) { - JSGantt.addListener('mouseover', function () {pGanttChart.mouseOver(pObj1, pObj2);}, pObj1); - JSGantt.addListener('mouseover', function () {pGanttChart.mouseOver(pObj1, pObj2);}, pObj2); - JSGantt.addListener('mouseout', function () {pGanttChart.mouseOut(pObj1, pObj2);}, pObj1); - JSGantt.addListener('mouseout', function () {pGanttChart.mouseOut(pObj1, pObj2);}, pObj2); + JSGantt.addListener('mouseover', function () {pGanttChart.mouseOver(pObj1, pObj2);}, pObj1); + JSGantt.addListener('mouseover', function () {pGanttChart.mouseOver(pObj1, pObj2);}, pObj2); + JSGantt.addListener('mouseout', function () {pGanttChart.mouseOut(pObj1, pObj2);}, pObj1); + JSGantt.addListener('mouseout', function () {pGanttChart.mouseOut(pObj1, pObj2);}, pObj2); }; JSGantt.addFolderListeners=function(pGanttChart, pObj, pID) { - JSGantt.addListener('click', function () {JSGantt.folder(pID, pGanttChart);}, pObj); + JSGantt.addListener('click', function () {JSGantt.folder(pID, pGanttChart);}, pObj); }; JSGantt.addFormatListeners=function(pGanttChart, pFormat, pObj) { - JSGantt.addListener('click', function () {JSGantt.changeFormat(pFormat, pGanttChart);}, pObj); + JSGantt.addListener('click', function () {JSGantt.changeFormat(pFormat, pGanttChart);}, pObj); }; JSGantt.addScrollListeners=function(pGanttChart) { - JSGantt.addListener('scroll', function () {pGanttChart.getChartBody().scrollTop=pGanttChart.getListBody().scrollTop;}, pGanttChart.getListBody()); - JSGantt.addListener('scroll', function () {pGanttChart.getListBody().scrollTop=pGanttChart.getChartBody().scrollTop;}, pGanttChart.getChartBody()); - JSGantt.addListener('scroll', function () {pGanttChart.getChartHead().scrollLeft=pGanttChart.getChartBody().scrollLeft;}, pGanttChart.getChartBody()); - JSGantt.addListener('scroll', function () {pGanttChart.getChartBody().scrollLeft=pGanttChart.getChartHead().scrollLeft;}, pGanttChart.getChartHead()); - JSGantt.addListener('resize', function () {pGanttChart.getChartHead().scrollLeft=pGanttChart.getChartBody().scrollLeft;}, window); - JSGantt.addListener('resize', function () {pGanttChart.getListBody().scrollTop=pGanttChart.getChartBody().scrollTop;}, window); + JSGantt.addListener('scroll', function () {pGanttChart.getChartBody().scrollTop=pGanttChart.getListBody().scrollTop;}, pGanttChart.getListBody()); + JSGantt.addListener('scroll', function () {pGanttChart.getListBody().scrollTop=pGanttChart.getChartBody().scrollTop;}, pGanttChart.getChartBody()); + JSGantt.addListener('scroll', function () {pGanttChart.getChartHead().scrollLeft=pGanttChart.getChartBody().scrollLeft;}, pGanttChart.getChartBody()); + JSGantt.addListener('scroll', function () {pGanttChart.getChartBody().scrollLeft=pGanttChart.getChartHead().scrollLeft;}, pGanttChart.getChartHead()); + JSGantt.addListener('resize', function () {pGanttChart.getChartHead().scrollLeft=pGanttChart.getChartBody().scrollLeft;}, window); + JSGantt.addListener('resize', function () {pGanttChart.getListBody().scrollTop=pGanttChart.getChartBody().scrollTop;}, window); }; diff --git a/htdocs/includes/jsgantt/jsgantt.min.js b/htdocs/includes/jsgantt/jsgantt.min.js deleted file mode 100644 index 9ec44995993..00000000000 --- a/htdocs/includes/jsgantt/jsgantt.min.js +++ /dev/null @@ -1,2 +0,0 @@ -var JSGantt;JSGantt||(JSGantt={});var vBenchTime=(new Date).getTime();JSGantt.isIE=function(){return"undefined"!=typeof document.all?"pageXOffset"in window?!1:!0:!1},JSGantt.TaskItem=function(t,e,n,a,o,i,s,r,l,d,u,h,c,f,p,m){var v,S,w,D,T,y=parseInt(document.createTextNode(t).data),L=document.createTextNode(e).data,N=new Date(0),G=new Date(0),M=null,J=null,k=document.createTextNode(o).data,C=document.createTextNode(i).data,I=parseInt(document.createTextNode(s).data),F=document.createTextNode(r).data,b=parseFloat(document.createTextNode(l).data),H=parseInt(document.createTextNode(d).data),x=document.createTextNode(u).data,E=2==H?1:parseInt(document.createTextNode(h).data),X=new Array,Y=new Array,O=document.createTextNode(f).data,R="",A=0,V=0,P=1,B=0,U=!1,j=null,W=null,q=m instanceof JSGantt.GanttChart?m:g,_=null,Q=null,z=null,K=null,Z=null;if(T=document.createElement("span"),T.className="gTaskNotes",null!=p&&(T.innerHTML=p,JSGantt.stripUnwanted(T)),null!=n&&""!=n&&(N=n instanceof Date?n:JSGantt.parseDateStr(document.createTextNode(n).data,q.getDateInputFormat()),M=N),null!=a&&""!=a&&(G=a instanceof Date?a:JSGantt.parseDateStr(document.createTextNode(a).data,q.getDateInputFormat()),J=G),null!=c)for(var $=c+"",tt=$.split(","),et=tt.length,nt=0;et>nt;nt++)-1!=tt[nt].toUpperCase().indexOf("SS")?(X[nt]=tt[nt].substring(0,tt[nt].toUpperCase().indexOf("SS")),Y[nt]="SS"):-1!=tt[nt].toUpperCase().indexOf("FF")?(X[nt]=tt[nt].substring(0,tt[nt].toUpperCase().indexOf("FF")),Y[nt]="FF"):-1!=tt[nt].toUpperCase().indexOf("SF")?(X[nt]=tt[nt].substring(0,tt[nt].toUpperCase().indexOf("SF")),Y[nt]="SF"):-1!=tt[nt].toUpperCase().indexOf("FS")?(X[nt]=tt[nt].substring(0,tt[nt].toUpperCase().indexOf("FS")),Y[nt]="FS"):(X[nt]=tt[nt],Y[nt]="FS");this.getID=function(){return y},this.getName=function(){return L},this.getStart=function(){return N},this.getEnd=function(){return G},this.getGroupMinStart=function(){return M},this.getGroupMinEnd=function(){return J},this.getClass=function(){return k},this.getLink=function(){return C},this.getMile=function(){return I},this.getDepend=function(){return X?X:null},this.getDepType=function(){return Y?Y:null},this.getCaption=function(){return O?O:""},this.getResource=function(){return F?F:" "},this.getCompVal=function(){return b?b:0},this.getCompStr=function(){return b?b+"%":""},this.getNotes=function(){return T},this.getSortIdx=function(){return B},this.getToDelete=function(){return U},this.getDuration=function(t,e){if(I)R="-";else{var n=new Date(this.getEnd().getTime()),a=null;switch(t){case"week":a="day";break;case"month":a="week";break;case"quarter":a="month";break;default:a=t}(n.getTime()-6e4*n.getTimezoneOffset())%864e5==0&&(n=new Date(n.getFullYear(),n.getMonth(),n.getDate()+1,n.getHours(),n.getMinutes(),n.getSeconds()));var o=JSGantt.getOffset(this.getStart(),n,999,a)/1e3;switch(Math.floor(o)!=o&&(o=Math.round(10*o)/10),a){case"hour":R=o+" "+(1!=o?e.hrs:e.hr);break;case"day":R=o+" "+(1!=o?e.dys:e.dy);break;case"week":R=o+" "+(1!=o?e.wks:e.wk);break;case"month":R=o+" "+(1!=o?e.mths:e.mth);break;case"quarter":R=o+" "+(1!=o?e.qtrs:e.qtr)}}return R},this.getParent=function(){return x},this.getGroup=function(){return H},this.getOpen=function(){return E},this.getLevel=function(){return A},this.getNumKids=function(){return V},this.getStartX=function(){return v},this.getStartY=function(){return S},this.getEndX=function(){return w},this.getEndY=function(){return D},this.getVisible=function(){return P},this.getParItem=function(){return j},this.getCellDiv=function(){return W},this.getBarDiv=function(){return _},this.getTaskDiv=function(){return Q},this.getChildRow=function(){return K},this.getListChildRow=function(){return z},this.getGroupSpan=function(){return Z},this.setStart=function(t){t instanceof Date&&(N=t)},this.setEnd=function(t){t instanceof Date&&(G=t)},this.setGroupMinStart=function(t){t instanceof Date&&(M=t)},this.setGroupMinEnd=function(t){t instanceof Date&&(J=t)},this.setLevel=function(t){A=parseInt(document.createTextNode(t).data)},this.setNumKid=function(t){V=parseInt(document.createTextNode(t).data)},this.setCompVal=function(t){b=parseFloat(document.createTextNode(t).data)},this.setStartX=function(t){v=parseInt(document.createTextNode(t).data)},this.setStartY=function(t){S=parseInt(document.createTextNode(t).data)},this.setEndX=function(t){w=parseInt(document.createTextNode(t).data)},this.setEndY=function(t){D=parseInt(document.createTextNode(t).data)},this.setOpen=function(t){E=parseInt(document.createTextNode(t).data)},this.setVisible=function(t){P=parseInt(document.createTextNode(t).data)},this.setSortIdx=function(t){B=parseInt(document.createTextNode(t).data)},this.setToDelete=function(t){U=t?!0:!1},this.setParItem=function(t){t instanceof JSGantt.TaskItem&&(j=t)},this.setCellDiv=function(t){("function"!=typeof HTMLDivElement||t instanceof HTMLDivElement)&&(W=t)},this.setGroup=function(t){H=parseInt(document.createTextNode(t).data)},this.setBarDiv=function(t){("function"!=typeof HTMLDivElement||t instanceof HTMLDivElement)&&(_=t)},this.setTaskDiv=function(t){("function"!=typeof HTMLDivElement||t instanceof HTMLDivElement)&&(Q=t)},this.setChildRow=function(t){("function"!=typeof HTMLTableRowElement||t instanceof HTMLTableRowElement)&&(K=t)},this.setListChildRow=function(t){("function"!=typeof HTMLTableRowElement||t instanceof HTMLTableRowElement)&&(z=t)},this.setGroupSpan=function(t){("function"!=typeof HTMLSpanElement||t instanceof HTMLSpanElement)&&(Z=t)}},JSGantt.GanttChart=function(t,e){var n,a=t,o=e,i=null,s=1,r=1,l=1,g=1,d=1,u=25e3,h=1,c=1,f=1,p=1,m=1,v=1,S=1,w=1,D=1,T=1,y=1,L=1,N=1,G=1,M=new Array("top"),J="yyyy-mm-dd",k=JSGantt.parseDateFormatStr("dd/mm/yyyy"),C=JSGantt.parseDateFormatStr("dd month yyyy"),I=JSGantt.parseDateFormatStr("day dd month yyyy"),F=JSGantt.parseDateFormatStr("HH"),b=JSGantt.parseDateFormatStr("dd/mm/yyyy"),H=JSGantt.parseDateFormatStr("dd"),x=JSGantt.parseDateFormatStr("yyyy"),E=JSGantt.parseDateFormatStr("dd/mm"),X=JSGantt.parseDateFormatStr("yyyy"),Y=JSGantt.parseDateFormatStr("mon"),O=JSGantt.parseDateFormatStr("yyyy"),R=JSGantt.parseDateFormatStr("qq"),A=(JSGantt.parseDateFormatStr("dd/mm/yyyy"),1),V=new Array,P=new Array("hour","day","week","month","quarter"),B=(new Array(31,28,31,30,31,30,31,31,30,31,30,31),!0),U=8,j="",W=18,q=18,_=36,Q=36,z=18,K=20,Z=-1,$=null,tt=null,et=null,nt=null,at=null,ot=20;this.setUseFade=function(t){s=t},this.setUseMove=function(t){r=t},this.setUseRowHlt=function(t){l=t},this.setUseToolTip=function(t){g=t},this.setUseSort=function(t){d=t},this.setUseSingleCell=function(t){u=1*t},this.setFormatArr=function(){var t="hour day week month quarter";P=new Array;for(var e=0,n=0;e1){P[n++]=arguments[e].toLowerCase();var a=new RegExp("(?:^|s)"+arguments[e]+"(?!S)","g");t=t.replace(a,"")}},this.setShowRes=function(t){h=t},this.setShowDur=function(t){c=t},this.setShowComp=function(t){f=t},this.setShowStartDate=function(t){p=t},this.setShowEndDate=function(t){m=t},this.setShowTaskInfoRes=function(t){S=t},this.setShowTaskInfoDur=function(t){w=t},this.setShowTaskInfoComp=function(t){D=t},this.setShowTaskInfoStartDate=function(t){T=t},this.setShowTaskInfoEndDate=function(t){y=t},this.setShowTaskInfoNotes=function(t){L=t},this.setShowTaskInfoLink=function(t){N=t},this.setShowEndWeekDate=function(t){v=t},this.setShowSelector=function(){var t="top bottom";M=new Array;for(var e=0,n=0;e1){M[n++]=arguments[e].toLowerCase();var a=new RegExp("(?:^|s)"+arguments[e]+"(?!S)","g");t=t.replace(a,"")}},this.setShowDeps=function(t){G=t},this.setDateInputFormat=function(t){J=t},this.setDateTaskTableDisplayFormat=function(t){k=JSGantt.parseDateFormatStr(t)},this.setDateTaskDisplayFormat=function(t){C=JSGantt.parseDateFormatStr(t)},this.setHourMajorDateDisplayFormat=function(t){I=JSGantt.parseDateFormatStr(t)},this.setHourMinorDateDisplayFormat=function(t){F=JSGantt.parseDateFormatStr(t)},this.setDayMajorDateDisplayFormat=function(t){b=JSGantt.parseDateFormatStr(t)},this.setDayMinorDateDisplayFormat=function(t){H=JSGantt.parseDateFormatStr(t)},this.setWeekMajorDateDisplayFormat=function(t){x=JSGantt.parseDateFormatStr(t)},this.setWeekMinorDateDisplayFormat=function(t){E=JSGantt.parseDateFormatStr(t)},this.setMonthMajorDateDisplayFormat=function(t){X=JSGantt.parseDateFormatStr(t)},this.setMonthMinorDateDisplayFormat=function(t){Y=JSGantt.parseDateFormatStr(t)},this.setQuarterMajorDateDisplayFormat=function(t){O=JSGantt.parseDateFormatStr(t)},this.setQuarterMinorDateDisplayFormat=function(t){R=JSGantt.parseDateFormatStr(t)},this.setCaptionType=function(t){n=t},this.setFormat=function(t){o=t,this.Draw()},this.setMinGpLen=function(t){U=t},this.setScrollTo=function(t){j=t},this.setHourColWidth=function(t){W=t},this.setDayColWidth=function(t){q=t},this.setWeekColWidth=function(t){_=t},this.setMonthColWidth=function(t){Q=t},this.setQuarterColWidth=function(t){z=t},this.setRowHeight=function(t){K=t},this.setLang=function(t){vLangs[t]&&(vLang=t)},this.setChartBody=function(t){("function"!=typeof HTMLDivElement||t instanceof HTMLDivElement)&&($=t)},this.setChartHead=function(t){("function"!=typeof HTMLDivElement||t instanceof HTMLDivElement)&&(tt=t)},this.setListBody=function(t){("function"!=typeof HTMLDivElement||t instanceof HTMLDivElement)&&(et=t)},this.setChartTable=function(t){("function"!=typeof HTMLTableElement||t instanceof HTMLTableElement)&&(nt=t)},this.setLines=function(t){("function"!=typeof HTMLDivElement||t instanceof HTMLDivElement)&&(at=t)},this.setTimer=function(t){ot=1*t},this.addLang=function(t,e){if(!vLangs[t]){vLangs[t]=new Object;for(var n in vLangs.en)vLangs[t][n]=e[n]?document.createTextNode(e[n]).data:vLangs.en[n]}},this.getDivId=function(){return i},this.getUseFade=function(){return s},this.getUseMove=function(){return r},this.getUseRowHlt=function(){return l},this.getUseToolTip=function(){return g},this.getUseSort=function(){return d},this.getUseSingleCell=function(){return u},this.getFormatArr=function(){return P},this.getShowRes=function(){return h},this.getShowDur=function(){return c},this.getShowComp=function(){return f},this.getShowStartDate=function(){return p},this.getShowEndDate=function(){return m},this.getShowTaskInfoRes=function(){return S},this.getShowTaskInfoDur=function(){return w},this.getShowTaskInfoComp=function(){return D},this.getShowTaskInfoStartDate=function(){return T},this.getShowTaskInfoEndDate=function(){return y},this.getShowTaskInfoNotes=function(){return L},this.getShowTaskInfoLink=function(){return N},this.getShowEndWeekDate=function(){return v},this.getShowSelector=function(){return M},this.getShowDeps=function(){return G},this.getDateInputFormat=function(){return J},this.getDateTaskTableDisplayFormat=function(){return k},this.getDateTaskDisplayFormat=function(){return C},this.getHourMajorDateDisplayFormat=function(){return I},this.getHourMinorDateDisplayFormat=function(){return F},this.getDayMajorDateDisplayFormat=function(){return b},this.getDayMinorDateDisplayFormat=function(){return H},this.getWeekMajorDateDisplayFormat=function(){return x},this.getWeekMinorDateDisplayFormat=function(){return E},this.getMonthMajorDateDisplayFormat=function(){return X},this.getMonthMinorDateDisplayFormat=function(){return Y},this.getQuarterMajorDateDisplayFormat=function(){return O},this.getQuarterMinorDateDisplayFormat=function(){return R},this.getCaptionType=function(){return n},this.getMinGpLen=function(){return U},this.getScrollTo=function(){return j},this.getHourColWidth=function(){return W},this.getDayColWidth=function(){return q},this.getWeekColWidth=function(){return _},this.getMonthColWidth=function(){return Q},this.getQuarterColWidth=function(){return z},this.getRowHeight=function(){return K},this.getChartBody=function(){return $},this.getChartHead=function(){return tt},this.getListBody=function(){return et},this.getChartTable=function(){return nt},this.getLines=function(){return at},this.getTimer=function(){return ot},this.CalcTaskXY=function(){for(var t,e,n,a,o=this.getList(),i=Math.floor(this.getRowHeight()/2),s=0;sa&&(g*=-1),o){case"SF":l*=-1,n>=t-10&&e!=a&&(r=!0),s=-1;break;case"SS":n>t?l*=-1:l=n-t-2*l;break;case"FF":n>=t&&(l=n-t+2*l),s=-1;break;default:t+10>=n&&e!=a&&(r=!0)}r?(this.sLine(t,e,t+l,e,i),this.sLine(t+l,e,t+l,a-g,i),this.sLine(t+l,a-g,n-2*l,a-g,i),this.sLine(n-2*l,a-g,n-2*l,a,i),this.sLine(n-2*l,a,n-1*s,a,i)):e!=a?(this.sLine(t,e,t+l,e,i),this.sLine(t+l,e,t+l,a,i),this.sLine(t+l,a,n-1*s,a,i)):this.sLine(t,e,n-1*s,a,i);var d=this.sLine(n,a,n-3-(0>s?1:0),a-3-(0>s?1:0),i+"Arw");d.style.width="0px",d.style.height="0px"},this.DrawDependencies=function(){if(1==this.getShowDeps()){this.CalcTaskXY(),this.clearDependencies();for(var t=this.getList(),e=0;e0&&1==t[e].getVisible())for(var i=0;o>i;i++){var s=this.getArrayLocationByID(n[i]);s>=0&&2!=t[s].getGroup()&&1==t[s].getVisible()&&("SS"==a[i]?this.drawDependency(t[s].getStartX()-1,t[s].getStartY(),t[e].getStartX()-1,t[e].getStartY(),"SS","gDepSS"):"FF"==a[i]?this.drawDependency(t[s].getEndX(),t[s].getEndY(),t[e].getEndX(),t[e].getEndY(),"FF","gDepFF"):"SF"==a[i]?this.drawDependency(t[s].getStartX()-1,t[s].getStartY(),t[e].getEndX(),t[e].getEndY(),"SF","gDepSF"):"FS"==a[i]&&this.drawDependency(t[s].getEndX(),t[s].getEndY(),t[e].getStartX()-1,t[e].getStartY(),"FS","gDepFS"))}}}Z>=0&&this.sLine(Z,0,Z,this.getChartTable().offsetHeight-1,"gCurDate")},this.getArrayLocationByID=function(t){for(var e=this.getList(),n=0;n0){B&&JSGantt.processRows(V,0,-1,1,1,this.getUseSort()),B=!1,e=JSGantt.getMinDate(V,o),t=JSGantt.getMaxDate(V,o),"day"==o?T=q:"week"==o?T=_:"month"==o?T=Q:"quarter"==o?T=z:"hour"==o&&(T=W);var y=document.createDocumentFragment(),L=this.newNode(y,"div",i+"glisthead","glistlbl gcontainercol"),N=this.newNode(L,"table",null,"gtasktableh"),G=this.newNode(N,"tbody"),M=this.newNode(G,"tr");this.newNode(M,"td",null,"gtasklist"," ");var J=this.newNode(M,"td",null,"gspanning gtaskname");J.appendChild(this.drawSelector("top")),1==h&&this.newNode(M,"td",null,"gspanning gresource"," "),1==c&&this.newNode(M,"td",null,"gspanning gduration"," "),1==f&&this.newNode(M,"td",null,"gspanning gpccomplete"," "),1==p&&this.newNode(M,"td",null,"gspanning gstartdate"," "),1==m&&this.newNode(M,"td",null,"gspanning genddate"," "),M=this.newNode(G,"tr"),this.newNode(M,"td",null,"gtasklist"," "),this.newNode(M,"td",null,"gtaskname"," "),1==h&&this.newNode(M,"td",null,"gtaskheading gresource",vLangs[vLang].resource),1==c&&this.newNode(M,"td",null,"gtaskheading gduration",vLangs[vLang].duration),1==f&&this.newNode(M,"td",null,"gtaskheading gpccomplete",vLangs[vLang].comp),1==p&&this.newNode(M,"td",null,"gtaskheading gstartdate",vLangs[vLang].startdate),1==m&&this.newNode(M,"td",null,"gtaskheading genddate",vLangs[vLang].enddate),L=this.newNode(y,"div",null,"glabelfooter");var C=document.createDocumentFragment(),A=this.newNode(C,"div",i+"glistbody","glistgrid gcontainercol");for(this.setListBody(A),N=this.newNode(A,"table",null,"gtasktable"),G=this.newNode(N,"tbody"),st=0;st=n&&(J=this.newNode(M,"td",null,at),this.newNode(J,"div",null,null,JSGantt.formatDateStr(n,H,vLangs[vLang]),T),g++),n.setDate(n.getDate()+1);else if("week"==o)t>=n&&(J=this.newNode(M,"td",null,at),this.newNode(J,"div",null,null,JSGantt.formatDateStr(n,E,vLangs[vLang]),T),g++),n.setDate(n.getDate()+7);else if("month"==o)for(t>=n&&(J=this.newNode(M,"td",null,at),this.newNode(J,"div",null,null,JSGantt.formatDateStr(n,Y,vLangs[vLang]),T),g++),n.setDate(n.getDate()+1);n.getDate()>1;)n.setDate(n.getDate()+1);else if("quarter"==o)for(t>=n&&(J=this.newNode(M,"td",null,at),this.newNode(J,"div",null,null,JSGantt.formatDateStr(n,R,vLangs[vLang]),T),g++),n.setDate(n.getDate()+81);n.getDate()>1;)n.setDate(n.getDate()+1);else if("hour"==o){for(st=n.getHours();24>st;st++)n.setHours(st),t>=n&&(J=this.newNode(M,"td",null,at),this.newNode(J,"div",null,null,JSGantt.formatDateStr(n,F,vLangs[vLang]),T),g++);n.setHours(0),n.setDate(n.getDate()+1)}}D=M,s=g*(T+1)+1,0!=u&&g*d>u&&(S=!0),this.newNode(L,"div",null,"rhscrpad",null,null,s+1);var it=document.createDocumentFragment();L=this.newNode(it,"div",i+"gchartbody","gchartgrid gcontainercol"),this.setChartBody(L),N=this.newNode(L,"table",i+"chartTable","gcharttable",null,s),this.setChartTable(N),this.newNode(L,"div",null,"rhscrpad",null,null,s+1),G=this.newNode(N,"tbody");var st=0,rt=0;for(st=0;strt;rt++)ut="day"!=o||rt%7!=4&&rt%7!=5?"gtaskcell":"gtaskcellwkend",this.newNode(M,"td",null,ut,"  ")}else if(l=r-1,V[st].getGroup()){if(l=l>U&&2*U>l?2*U:l,l=U>l?U:l,M=this.newNode(G,"tr",i+"childrow_"+w,(2==V[st].getGroup()?"glineitem gitem":"ggroupitem ggroup")+o,null,null,null,0==V[st].getVisible()?"none":null),V[st].setChildRow(M),JSGantt.addThisRowListeners(this,V[st].getListChildRow(),M),J=this.newNode(M,"td",null,"gtaskcell"),L=this.newNode(J,"div",null,"gtaskcelldiv","  "),V[st].setCellDiv(L),1==V[st].getGroup()&&(L=this.newNode(L,"div",i+"bardiv_"+w,"gtaskbarcontainer",null,l,s),V[st].setBarDiv(L),A=this.newNode(L,"div",i+"taskbar_"+w,V[st].getClass(),null,l),V[st].setTaskDiv(A),this.newNode(A,"div",i+"complete_"+w,V[st].getClass()+"complete",null,V[st].getCompStr()),this.newNode(L,"div",null,V[st].getClass()+"endpointleft"),l>=2*U&&this.newNode(L,"div",null,V[st].getClass()+"endpointright"),ft="ggroupcaption"),!S&&!dt)for(ut="",rt=0;g-1>rt;rt++)ut="day"!=o||rt%7!=4&&rt%7!=5?"gtaskcell":"gtaskcellwkend",this.newNode(M,"td",null,ut,"  ")}else if(l=0>=l?1:l,dt?L=V[st].getParItem().getCellDiv():(M=this.newNode(G,"tr",i+"childrow_"+w,"glineitem gitem"+o,null,null,null,0==V[st].getVisible()?"none":null),V[st].setChildRow(M),JSGantt.addThisRowListeners(this,V[st].getListChildRow(),M),J=this.newNode(M,"td",null,"gtaskcell"),L=this.newNode(J,"div",null,"gtaskcelldiv","  ")),L=this.newNode(L,"div",i+"bardiv_"+w,"gtaskbarcontainer",null,l,s),V[st].setBarDiv(L),A=this.newNode(L,"div",i+"taskbar_"+w,V[st].getClass(),null,l),V[st].setTaskDiv(A),this.newNode(A,"div",i+"complete_"+w,V[st].getClass()+"complete",null,V[st].getCompStr()),dt&&(ht=V[st].getParItem()),(!dt||dt&&V[st].getParItem().getEnd()==V[st].getEnd())&&(ft="gcaption"),!S&&!dt)for(ut="",rt=0;g-1>rt;rt++)ut="day"!=o||rt%7!=4&&rt%7!=5?"gtaskcell":"gtaskcellwkend",this.newNode(M,"td",null,ut,"  ");if(this.getCaptionType()&&null!==ft){switch(this.getCaptionType()){case"Caption":var ct=ht.getCaption();break;case"Resource":ct=ht.getResource();break;case"Duration":ct=ht.getDuration(o,vLangs[vLang]);break;case"Complete":ct=ht.getCompStr()}this.newNode(L,"div",null,ft,ct,120,"gmilecaption"==ft?12:0)}V[st].getTaskDiv()&&L&&(A=this.newNode(L,"div",i+"tt"+w,null,null,null,null,"none"),A.appendChild(this.createTaskInfo(V[st])),JSGantt.addTooltipListeners(this,V[st].getTaskDiv(),A))}for(S||G.appendChild(D.cloneNode(!0));a.hasChildNodes();)a.removeChild(a.firstChild);if(L=this.newNode(a,"div",null,"gchartcontainer"),L.appendChild(et),L.appendChild(y),L.appendChild(it),L.appendChild(C),this.newNode(L,"div",null,"ggridfooter"),A=this.newNode(this.getChartBody(),"div",i+"Lines","glinediv"),A.style.visibility="hidden",this.setLines(A),JSGantt.addScrollListeners(this),""!=j){var pt=new Date(e.getTime()),mt=0;"px"==j.substr(0,2)?mt=parseInt(j.substr(2)):(pt=JSGantt.parseDateStr(j,this.getDateInputFormat()),"hour"==o?pt.setMinutes(0,0,0):pt.setHours(0,0,0,0),mt=JSGantt.getOffset(e,pt,T,o)),this.getChartBody().scrollLeft=mt}Z=e.getTime()<=(new Date).getTime()&&t.getTime()>=(new Date).getTime()?JSGantt.getOffset(e,new Date,T,o):-1,this.DrawDependencies()}},this.mouseOver=function(t,e){this.getUseRowHlt()&&(t.className+=" gitemhighlight",e.className+=" gitemhighlight")},this.mouseOut=function(t,e){this.getUseRowHlt()&&(t.className=t.className.replace(/(?:^|\s)gitemhighlight(?!\S)/g,""),e.className=e.className.replace(/(?:^|\s)gitemhighlight(?!\S)/g,""))},this.drawSelector=function(t){for(var e=document.createDocumentFragment(),n=!1,a=0;a=0&&a",o+=""+V[a].getID()+"",o+=""+V[a].getName()+"",o+=""+JSGantt.formatDateStr(V[a].getStart(),i,vLangs[vLang])+"",o+=""+JSGantt.formatDateStr(V[a].getEnd(),i,vLangs[vLang])+"",o+=""+V[a].getClass()+"",o+=""+V[a].getLink()+"",o+=""+V[a].getMile()+""," "!=V[a].getResource()&&(o+=""+V[a].getResource()+""),o+=""+V[a].getCompVal()+"",o+=""+V[a].getGroup()+"",o+=""+V[a].getParent()+"",o+=""+V[a].getOpen()+"",o+="";var s=V[a].getDepend();for(n=0;n0&&(o+=","),s[n]>0&&(o+=s[n]+V[a].getDepType()[n]);o+="",o+=""+V[a].getCaption()+"";var r=document.createDocumentFragment(),l=this.newNode(r,"div",null,null,V[a].getNotes().innerHTML);o+=""+l.innerHTML+"",o+=""}return o},a&&"div"==a.nodeName.toLowerCase()&&(i=a.id)},JSGantt.updateFlyingObj=function(t,e,n){var a=3,o=5,i=3,s=15,r=t?t.clientX:window.event.clientX,l=t?t.clientY:window.event.clientY,g=document.documentElement.clientWidth||document.getElementsByTagName("body")[0].clientWidth,d=document.documentElement.clientHeight||document.getElementsByTagName("body")[0].clientHeight,u=r,h=l;if("microsoft internet explorer"==navigator.appName.toLowerCase()){r-=document.documentElement.clientLeft,l-=document.documentElement.clientTop;var c=JSGantt.getZoomFactor();1!=c&&(r=Math.round(r/c),l=Math.round(l/c))}var f=JSGantt.getScrollPositions();u=r-o-e.vTool.offsetWidth<0?r+s+e.vTool.offsetWidth>g?f.x:r+f.x+s:r+f.x-o-e.vTool.offsetWidth,h=l+i+e.vTool.offsetHeight>d?l-a-e.vTool.offsetHeight<0?f.y:l+f.y-a-e.vTool.offsetHeight:l+f.y+i,e.getUseMove()?(clearInterval(e.vTool.moveInterval),e.vTool.moveInterval=setInterval(function(){JSGantt.moveToolTip(u,h,e.vTool,n)},n)):(e.vTool.style.left=u+"px", - e.vTool.style.top=h+"px")},JSGantt.showToolTip=function(t,e,n,a,o){var i=t.getDivId()+"JSGanttToolTip",s=500,r=100,l=n.id;t.getUseToolTip()&&(null==t.vTool&&(t.vTool=document.createElement("div"),t.vTool.id=i,t.vTool.className="JSGanttToolTip",t.vTool.vToolCont=document.createElement("div"),t.vTool.vToolCont.id=i+"cont",t.vTool.vToolCont.className="JSGanttToolTipcont",t.vTool.vToolCont.setAttribute("showing",""),t.vTool.appendChild(t.vTool.vToolCont),document.body.appendChild(t.vTool),t.vTool.style.opacity=0,t.vTool.setAttribute("currentOpacity",0),t.vTool.setAttribute("fadeIncrement",10),t.vTool.setAttribute("moveSpeed",10),t.vTool.style.filter="alpha(opacity=0)",t.vTool.style.visibility="hidden",t.vTool.style.left=Math.floor((e?e.clientX:window.event.clientX)/2)+"px",t.vTool.style.top=Math.floor((e?e.clientY:window.event.clientY)/2)+"px",JSGantt.addListener("mouseover",function(){clearTimeout(t.vTool.delayTimeout)},t.vTool),JSGantt.addListener("mouseout",function(){JSGantt.delayedHide(t,t.vTool,o)},t.vTool)),clearTimeout(t.vTool.delayTimeout),(t.vTool.vToolCont.getAttribute("showing")!=l||"visible"!=t.vTool.style.visibility)&&(t.vTool.vToolCont.getAttribute("showing")!=l&&(t.vTool.vToolCont.setAttribute("showing",l),t.vTool.vToolCont.innerHTML=n.innerHTML,JSGantt.stripIds(t.vTool.vToolCont)),t.vTool.style.visibility="visible",JSGantt.updateFlyingObj(e,t,o),t.vTool.style.width=a?a+"px":"auto",!a&&JSGantt.isIE()&&(t.vTool.style.width=t.vTool.offsetWidth),t.vTool.offsetWidth>s&&(t.vTool.style.width=s+"px")),t.getUseFade()?(clearInterval(t.vTool.fadeInterval),t.vTool.fadeInterval=setInterval(function(){JSGantt.fadeToolTip(1,t.vTool,r)},o)):(t.vTool.style.opacity=.01*r,t.vTool.style.filter="alpha(opacity="+r+")"))},JSGantt.stripIds=function(t){for(var e=0;en-i&&1==t?s=n-i:a>o&&-1==t&&(s=i),o=i+s*t,e.style.opacity=.01*o,e.style.filter="alpha(opacity="+o+")",e.setAttribute("currentOpacity",o)}else clearInterval(e.fadeInterval),-1==t&&(e.style.opacity=0,e.style.filter="alpha(opacity=0)",e.style.visibility="hidden")},JSGantt.moveToolTip=function(t,e,n){var a=parseInt(n.getAttribute("moveSpeed")),o=parseInt(n.style.left),i=parseInt(n.style.top);"visible"!=n.style.visibility?(n.style.left=t+"px",n.style.top=e+"px",clearInterval(n.moveInterval)):t!=o&&e!=i?(o+=Math.ceil((t-o)/a),i+=Math.ceil((e-i)/a),n.style.left=o+"px",n.style.top=i+"px"):clearInterval(n.moveInterval)},JSGantt.getZoomFactor=function(){var t=1;if(document.body.getBoundingClientRect){var e=document.body.getBoundingClientRect(),n=e.right-e.left,a=document.body.offsetWidth;t=Math.round(n/a*100)/100}return t},JSGantt.getScrollPositions=function(){var t=window.pageXOffset,e=window.pageYOffset;if(!("pageXOffset"in window)){var n=JSGantt.getZoomFactor();t=Math.round(document.documentElement.scrollLeft/n),e=Math.round(document.documentElement.scrollTop/n)}return{x:t,y:e}},JSGantt.getOffset=function(t,e,n,a){var o=new Array(31,28,31,30,31,30,31,31,30,31,30,31),i=new Date(t.getTime()),s=new Date(e.getTime()),r=0,l=Date.UTC(i.getFullYear(),i.getMonth(),i.getDate(),i.getHours(),0,0),g=Date.UTC(s.getFullYear(),s.getMonth(),s.getDate(),s.getHours(),0,0),d=(g-l)/36e5;if("day"==a)r=Math.ceil(d/24*(n+1));else if("week"==a)r=Math.ceil(d/24*(n+1)/7);else if("month"==a){var u=12*(s.getFullYear()-i.getFullYear())+(s.getMonth()-i.getMonth()),h=new Date(s.getTime());h.setDate(i.getDate());var c=(s.getTime()-h.getTime())/864e5;r=Math.ceil(u*(n+1)+c*(n/o[s.getMonth()]))}else if("quarter"==a)u=12*(s.getFullYear()-i.getFullYear())+(s.getMonth()-i.getMonth()),h=new Date(s.getTime()),h.setDate(i.getDate()),c=(s.getTime()-h.getTime())/864e5,r=Math.ceil(u*((n+1)/3)+c*(n/90));else if("hour"==a){h=new Date(s.getTime()),h.setMinutes(i.getMinutes(),0);var f=(s.getTime()-h.getTime())/36e5;r=Math.ceil(d*(n+1)+f*n)}return r},JSGantt.processRows=function(t,e,n,a,o,i){var s=new Date,r=new Date,l=o,g=null,d=0,u=0,h=0,c=0,f=a,p=t,m=!1,v=0;for(v=0;v=0&&t[v].getID()==e&&(g=t[v]);for(v=0;vr)&&(r=t[v].getEnd(),h=1),d+=t[v].getCompVal(),t[v].setSortIdx(v*t.length)}if(n>=0&&(null!=t[n].getGroupMinStart()&&t[n].getGroupMinStart()r&&(r=t[n].getGroupMinEnd()),t[n].setStart(s),t[n].setEnd(r),t[n].setNumKid(c),t[n].setCompVal(Math.ceil(d/c))),0==e&&1==i&&(JSGantt.sortTasks(t,0,0),t.sort(function(t,e){return t.getSortIdx()-e.getSortIdx()})),0==e&&1!=i){for(v=0;v0&&o.sort(function(t,e){var n=t.getStart().getTime()-e.getStart().getTime();return 0==n&&(n=t.getEnd().getTime()-e.getEnd().getTime()),0==n?t.getID()-e.getID():n});for(var s=0;s1;)n.setDate(n.getDate()-1);else if("quarter"==e)n.setDate(n.getDate()-31),0==n.getMonth()||1==n.getMonth()||2==n.getMonth()?n.setFullYear(n.getFullYear(),0,1):3==n.getMonth()||4==n.getMonth()||5==n.getMonth()?n.setFullYear(n.getFullYear(),3,1):6==n.getMonth()||7==n.getMonth()||8==n.getMonth()?n.setFullYear(n.getFullYear(),6,1):(9==n.getMonth()||10==n.getMonth()||11==n.getMonth())&&n.setFullYear(n.getFullYear(),9,1);else if("hour"==e)for(n.setHours(n.getHours()-1);n.getHours()%6!=0;)n.setHours(n.getHours()-1);return"hour"==e?n.setMinutes(0,0):n.setHours(0,0,0),n},JSGantt.getMaxDate=function(t,e){var n=new Date;n.setTime(t[0].getEnd().getTime());for(var a=0;an.getTime()&&n.setTime(t[a].getEnd().getTime());if("day"==e)for(n.setDate(n.getDate()+1);n.getDay()%7!=0;)n.setDate(n.getDate()+1);else if("week"==e)for(n.setDate(n.getDate()+1);n.getDay()%7!=0;)n.setDate(n.getDate()+1);else if("month"==e){for(;n.getDate()>1;)n.setDate(n.getDate()+1);n.setDate(n.getDate()-1)}else if("quarter"==e)0==n.getMonth()||1==n.getMonth()||2==n.getMonth()?n.setFullYear(n.getFullYear(),2,31):3==n.getMonth()||4==n.getMonth()||5==n.getMonth()?n.setFullYear(n.getFullYear(),5,30):6==n.getMonth()||7==n.getMonth()||8==n.getMonth()?n.setFullYear(n.getFullYear(),8,30):(9==n.getMonth()||10==n.getMonth()||11==n.getMonth())&&n.setFullYear(n.getFullYear(),11,31);else if("hour"==e)for(0==n.getHours()&&n.setDate(n.getDate()+1),n.setHours(n.getHours()+1);n.getHours()%6!=5;)n.setHours(n.getHours()+1);return n},JSGantt.findObj=function(t,e){var n;return e||(e=document),document.getElementById&&(n=document.getElementById(t)),n},JSGantt.changeFormat=function(t,e){e?e.setFormat(t):alert("Chart undefined")},JSGantt.folder=function(t,e){var n=e.getList();e.getDivId();e.clearDependencies();for(var a=0;a=10&&a.length>=3){for(;a.length<5;)a.push(0);switch(e){case"mm/dd/yyyy":n=new Date(a[2],a[0]-1,a[1],a[3],a[4]);break;case"dd/mm/yyyy":n=new Date(a[2],a[1]-1,a[0],a[3],a[4]);break;case"yyyy-mm-dd":n=new Date(a[0],a[1]-1,a[2],a[3],a[4])}}return n},JSGantt.formatDateStr=function(t,e,n){for(var a="",o=t.getFullYear().toString().substring(2,4),i=t.getMonth()+1+"",s=new Array(n.january,n.february,n.march,n.april,n.maylong,n.june,n.july,n.august,n.september,n.october,n.november,n.december),r=new Array(n.sunday,n.monday,n.tuesday,n.wednesday,n.thursday,n.friday,n.saturday),l=new Array(n.jan,n.feb,n.mar,n.apr,n.may,n.jun,n.jul,n.aug,n.sep,n.oct,n.nov,n.dec),g=new Array(n.sun,n.mon,n.tue,n.wed,n.thu,n.fri,n.sat),d=0;di&&(a+="0");case"m":a+=i;break;case"mon":a+=l[t.getMonth()];break;case"month":a+=s[t.getMonth()];break;case"yyyy":a+=t.getFullYear();break;case"yy":a+=o;break;case"qq":a+="Q";case"q":a+=Math.floor(t.getMonth()/3)+1;break;case"hh":(t.getHours()%12==0?12:t.getHours()%12)<10&&(a+="0");case"h":a+=t.getHours()%12==0?12:t.getHours()%12;break;case"HH":t.getHours()<10&&(a+="0");case"H":a+=t.getHours();break;case"MI":t.getMinutes()<10&&(a+="0");case"mi":a+=t.getMinutes();break;case"pm":a+=t.getHours()<12?"am":"pm";break;case"PM":a+=t.getHours()<12?"AM":"PM";break;case"ww":JSGantt.getIsoWeek(t)<10&&(a+="0");case"w":a+=JSGantt.getIsoWeek(t);break;case"week":var u=JSGantt.getIsoWeek(t),h=t.getFullYear(),c=0==t.getDay()?7:t.getDay();u>=52&&1==i&&h--,1==u&&12==i&&h++,10>u&&(u="0"+u),a+=h+"-W"+u+"-"+c;break;default:a+=n[e[d].toLowerCase()]?n[e[d].toLowerCase()]:e[d]}return a},JSGantt.parseDateFormatStr=function(t){for(var e="",n="",a=new RegExp("[/\\ -.,'\":]"),o=new Array,i=0;i0&&(a=p[0].getAttribute("xmlns")),"http://schemas.microsoft.com/project"==a){o=!0,t.setDateInputFormat("yyyy-mm-dd"),n=JSGantt.findXMLNode(e,"Task"),i="undefined"==typeof n?0:n.length;var m=JSGantt.findXMLNode(e,"Resource");for("undefined"==typeof m?(i=0,s=0):s=m.length,r=0;s>r;r++){var v=JSGantt.getXMLNodeValue(m[r],"Name",2,""),S=JSGantt.getXMLNodeValue(m[r],"UID",1,-1);v.length>0&&S>0&&(c[S]=v)}var w=JSGantt.findXMLNode(e,"Assignment");for(l="undefined"==typeof w?0:w.length,r=0;l>r;r++){var D=JSGantt.getXMLNodeValue(w[r],"ResourceUID",1,-1);S=JSGantt.getXMLNodeValue(w[r],"TaskUID",1,-1),S>0&&(D>0&&(h[S]=c[D]),u[S]=w[r])}for(r=0;i>r;r++){if(S=JSGantt.getXMLNodeValue(n[r],"UID",1,0),0!=S)var T=JSGantt.getXMLNodeValue(n[r],"OutlineNumber",2,"0");S>0&&(f[T]=S),S>d&&(d=S)}for(r=0;i>r;r++){var y=JSGantt.getXMLNodeValue(n[r],"UID",1,0);if(0!=y){var L=JSGantt.getXMLNodeValue(n[r],"Name",2,"No Task Name"),N=JSGantt.getXMLNodeValue(n[r],"Start",2,""),G=JSGantt.getXMLNodeValue(n[r],"Finish",2,""),M=JSGantt.getXMLNodeValue(n[r],"HyperlinkAddress",2,""),J=JSGantt.getXMLNodeValue(n[r],"Milestone",1,0),k=JSGantt.getXMLNodeValue(n[r],"PercentWorkComplete",1,0),C=JSGantt.getXMLNodeValue(n[r],"Summary",1,0),I=0,F=JSGantt.getXMLNodeValue(n[r],"OutlineLevel",1,0);F>1&&(T=JSGantt.getXMLNodeValue(n[r],"OutlineNumber",2,"0"),I=f[T.substr(0,T.lastIndexOf("."))]);try{var b=n[r].getElementsByTagName("Notes")[0].childNodes[1].nodeValue}catch(H){b=""}if("undefined"!=typeof h[y])var x=h[y];else x="";var E=JSGantt.findXMLNode(n[r],"PredecessorLink");l="undefined"==typeof E?0:E.length;var X="";for(g=0;l>g;g++){var Y=JSGantt.getXMLNodeValue(E[g],"PredecessorUID",1,-1),O=JSGantt.getXMLNodeValue(E[g],"Type",1,1);if(Y>0)switch(X.length>0&&(X+=","),O){case 0:X+=Y+"FF";break;case 1:X+=Y+"FS";break;case 2:X+=Y+"SF";break;case 3:X+=Y+"SS";break;default:X+=Y+"FS"}}var R=1,A="";if(C>0)var V="ggroupblack";else V=J>0?"gmilestone":"gtaskblue";var P=JSGantt.findXMLNode(u[y],"TimephasedData");l="undefined"==typeof P?0:P.length;var B=N,U=G,j=!1,W=X.replace(/,*[0-9]+[FS]F/g,"");for(g=0;l>g;g++){var q=JSGantt.getXMLNodeValue(P[g],"Value",2,"0");q="0"+q.replace(/\D/g,""),q*=1,0==q&&!j||g+1==l&&2==C?(C=2,g+1==l&&(W=X.replace(/,*[0-9]+[FS]S/g,"")),d++,U=JSGantt.getXMLNodeValue(P[g],g+1==l?"Finish":"Start",2,""),t.AddTaskItem(new JSGantt.TaskItem(d,L,B,U,"gtaskblue",M,J,x,k,0,y,R,W,A,b,t)),j=!0,W=""):0!=q&&j&&(B=JSGantt.getXMLNodeValue(P[g],"Start",2,""),j=!1)}j&&(X=""),t.AddTaskItem(new JSGantt.TaskItem(y,L,N,G,V,M,J,x,k,C,I,R,X,A,b,t))}}}else for(n=e.getElementsByTagName("task"),i=n.length,r=0;i>r;r++)y=JSGantt.getXMLNodeValue(n[r],"pID",1,0),0!=y&&(L=JSGantt.getXMLNodeValue(n[r],"pName",2,"No Task Name"),N=JSGantt.getXMLNodeValue(n[r],"pStart",2,""),G=JSGantt.getXMLNodeValue(n[r],"pEnd",2,""),M=JSGantt.getXMLNodeValue(n[r],"pLink",2,""),J=JSGantt.getXMLNodeValue(n[r],"pMile",1,0),k=JSGantt.getXMLNodeValue(n[r],"pComp",1,0),C=JSGantt.getXMLNodeValue(n[r],"pGroup",1,0),I=JSGantt.getXMLNodeValue(n[r],"pParent",1,0),x=JSGantt.getXMLNodeValue(n[r],"pRes",2,""),R=JSGantt.getXMLNodeValue(n[r],"pOpen",1,1),X=JSGantt.getXMLNodeValue(n[r],"pDepend",2,""),A=JSGantt.getXMLNodeValue(n[r],"pCaption",2,""),b=JSGantt.getXMLNodeValue(n[r],"pNotes",2,""),V=JSGantt.getXMLNodeValue(n[r],"pClass",2),"undefined"==typeof V&&(V=C>0?"ggroupblack":J>0?"gmilestone":"gtaskblue"),t.AddTaskItem(new JSGantt.TaskItem(y,L,N,G,V,M,J,x,k,C,I,R,X,A,b,t)))},JSGantt.benchMark=function(t){var e=(new Date).getTime();alert(t+": Elapsed time: "+(e-vBenchTime)/1e3+" seconds."),vBenchTime=(new Date).getTime()},JSGantt.getIsoWeek=function(t){var e=864e5,n=new Date(t.getFullYear(),0,4,0,0,0),a=0==n.getDay()?6:n.getDay()-1,o=n.getTime()-a*e,i=new Date(t.getFullYear(),t.getMonth(),t.getDate(),0,0,0),s=i.getTime(),r=Math.round((s-o)/e),l=99;new Date(o);return l=Math.ceil((r+1)/7),0>=l?l=JSGantt.getIsoWeek(new Date(t.getFullYear()-1,11,31,0,0,0)):53==l&&4!=new Date(t.getFullYear(),0,1,0,0,0).getDay()&&4!=new Date(t.getFullYear(),11,31,0,0,0).getDay()&&(l=1),l},JSGantt.addListener=function(t,e,n){return n===String(n)&&(n=JSGantt.findObj(n)),n.addEventListener?n.addEventListener(t,e,!1):n.attachEvent?n.attachEvent("on"+t,e):!1},JSGantt.addTooltipListeners=function(t,e,n){JSGantt.addListener("mouseover",function(e){JSGantt.showToolTip(t,e,n,null,t.getTimer())},e),JSGantt.addListener("mouseout",function(e){JSGantt.delayedHide(t,t.vTool,t.getTimer())},e)},JSGantt.addThisRowListeners=function(t,e,n){JSGantt.addListener("mouseover",function(){t.mouseOver(e,n)},e),JSGantt.addListener("mouseover",function(){t.mouseOver(e,n)},n),JSGantt.addListener("mouseout",function(){t.mouseOut(e,n)},e),JSGantt.addListener("mouseout",function(){t.mouseOut(e,n)},n)},JSGantt.addFolderListeners=function(t,e,n){JSGantt.addListener("click",function(){JSGantt.folder(n,t)},e)},JSGantt.addFormatListeners=function(t,e,n){JSGantt.addListener("click",function(){JSGantt.changeFormat(e,t)},n)},JSGantt.addScrollListeners=function(t){JSGantt.addListener("scroll",function(){t.getChartBody().scrollTop=t.getListBody().scrollTop},t.getListBody()),JSGantt.addListener("scroll",function(){t.getListBody().scrollTop=t.getChartBody().scrollTop},t.getChartBody()),JSGantt.addListener("scroll",function(){t.getChartHead().scrollLeft=t.getChartBody().scrollLeft},t.getChartBody()),JSGantt.addListener("scroll",function(){t.getChartBody().scrollLeft=t.getChartHead().scrollLeft},t.getChartHead()),JSGantt.addListener("resize",function(){t.getChartHead().scrollLeft=t.getChartBody().scrollLeft},window),JSGantt.addListener("resize",function(){t.getListBody().scrollTop=t.getChartBody().scrollTop},window)}; \ No newline at end of file diff --git a/htdocs/includes/jsgantt/jsgantt_Minutes.html b/htdocs/includes/jsgantt/jsgantt_Minutes.html deleted file mode 100644 index f49f8a2f5c5..00000000000 --- a/htdocs/includes/jsgantt/jsgantt_Minutes.html +++ /dev/null @@ -1,548 +0,0 @@ - - - - - - -FREE javascript gantt - JSGantt HTML and CSS only - - - - - - - - - - - - - - - - - - - - - - - - - -
      jsGantt - 1.2
      Bugs/Issues    Download    License    Usage    Examples    Documenation    Subscribe    Credits
    -

    -
    -
    - - -  100% Free Javascript / CSS/ HTML Gantt chart control. Completely buzzword compliant including AJAX !

    - - -
    - -
    - -Basic Features
    -
      -
    • Tasks & Collapsible Task Groups
    • -
    • Multiple Dependencies
    • -
    • Task Completion
    • -
    • Task Color
    • -
    • Milestones
    • -
    • Resources
    • -
    • No images needed
    • -
    - -Advanced Features
    -
      -
    • Dynamic Loading of Tasks
    • -
    • Dynamic change of format -
        -
      • Day
      • -
      • Week
      • -
      • Month
      • -
      • Quarter
      • -
      • Hour
      • -
      • Minute
      • -
      -
    • -
    • Load Gantt from XML file
    • -
    -
    -
    - -
    -Current Issues: -
      -
    1. Currently only one gantt chart is allowed per page.
    2. - -

    -New in 1.2: -
      -
    • Support for half-days
    • -
    • Hour/Minute format
    • -
    -
    -
    -Click here to download the jsgantt
    -You can download the latest bleeding edge version, request features and report issues at http://code.google.com/p/jsgantt/ -

    - -JSGantt is released under BSD license. If you require another license please contact shlomygantz@hotmail.com
    -If you plan to use it in a commercial product please consider donating the first sale to charity. -

    -

    - -

    1. Include JSGantt CSS and Javascript

    -
    -<link rel="stylesheet" type="text/css" href="jsgantt.css" />
    -<script language="javascript" src="jsgantt.js"></script>
    -
    - -

    2. Create a div element to hold the gantt chart

    -
    <div style="position:relative" class="gantt" id="GanttChartDIV"></div>
    -

    3. Start a <script> block

    -
    <script language="javascript">
    -

    4. Instantiate JSGantt using GanttChart()

    -
    var g = new JSGantt.GanttChart('g',document.getElementById('GanttChartDIV'), 'day');
    -
    -    
    - -

    GanttChart(pGanttVar, pDiv, pFormat)
    - pGanttVar: (required) name of the variable assigned
    - pDiv: (required) this is a DIV object created in HTML
    - pFormat: (required) - used to indicate whether chart should be drawn in "day", "week", "month", or "quarter" format

    -

    Customize the look and feel using the following setters

    -

    g.setShowRes(1); // Show/Hide Responsible (0/1)
    -g.setShowDur(1); // Show/Hide Duration (0/1)
    -g.setShowComp(1); // Show/Hide % Complete(0/1)
    -g.setCaptionType('Resource');  // Set to Show Caption (None,Caption,Resource,Duration,Complete)
    -g.setShowStartDate(1); // Show/Hide Start Date(0/1)
    -g.setShowEndDate(1); // Show/Hide End Date(0/1)
    -g.setDateInputFormat('mm/dd/yyyy')  // Set format of input dates ('mm/dd/yyyy', 'dd/mm/yyyy', 'yyyy-mm-dd')
    -g.setDateDisplayFormat('mm/dd/yyyy') // Set format to display dates ('mm/dd/yyyy', 'dd/mm/yyyy', 'yyyy-mm-dd')
    -g.setFormatArr("day","week","month","quarter") // Set format options (up to 4 : "minute","hour","day","week","month","quarter")
    -
    - -

    -

    5. Add Tasks using AddTaskItem()

    -
     
    -g.AddTaskItem(new JSGantt.TaskItem(1,   'Define Chart API',     '',          '',          'ff0000', 'http://help.com', 0, 'Brian',     0, 1, 0, 1));
    -g.AddTaskItem(new JSGantt.TaskItem(11,  'Chart Object',         '2/10/2008', '2/10/2008', 'ff00ff', 'http://www.yahoo.com', 1, 'Shlomy',  100, 0, 1, 1, "121,122", "My Caption"));
    -
    - -TaskItem(pID, pName, pStart, pEnd, pColor, pLink, pMile, pRes, pComp, pGroup, pParent, pOpen, pDepend)
    -pID: (required) is a unique ID used to identify each row for parent functions and for setting dom id for hiding/showing
    -pName: (required) is the task Label
    -pStart: (required) the task start date, can enter empty date ('') for groups. You can also enter specific time (2/10/2008 12:00) for additional percision or half days.
    -pEnd: (required) the task end date, can enter empty date ('') for groups
    -pColor: (required) the html color for this task; e.g. '00ff00'
    -pLink: (optional) any http link navigated to when task bar is clicked.
    -pMile:(optional) represent a milestone
    -pRes: (optional) resource name
    -pComp: (required) completion percent
    -pGroup: (optional) indicates whether this is a group(parent) - 0=NOT Parent; 1=IS Parent
    -pParent: (required) identifies a parent pID, this causes this task to be a child of identified task
    -pOpen: can be initially set to close folder when chart is first drawn
    -pDepend: optional list of id's this task is dependent on ... line drawn from dependent to this item
    -pCaption: optional caption that will be added after task bar if CaptionType set to "Caption"
    - -*You should be able to add items to the chart in realtime via javascript and issuing "g.Draw()" command. - -

    5a. Another way to add tasks is to use an external XML file with parseXML()

    -
     
    -JSGantt.parseXML("project.xml",g);
    -
    -The structure of the XML file:
    - - -

    6. Call Draw() and DrawDependencies()

    -
     
    -
    -g.Draw();	
    -g.DrawDependencies();
    -
    -
    - -
    -

    7. Close the <script> block

    -
    </script>
    - -

    -Final code should look like - -

    -
    - -

    -

    -

    - - - -

    -Enter your email address to receive JSGantt announcements
    -

    - - -

    -

    - -
    - -

    Developed by Shlomy Gantz and Brian Twidt
    -Contributed: Paul Labuschagne, Kevin Badgett, Ilan Admon
    -

    - - - - \ No newline at end of file diff --git a/htdocs/includes/jsgantt/jsgantt_exExternalXML.html b/htdocs/includes/jsgantt/jsgantt_exExternalXML.html deleted file mode 100644 index da571e056c8..00000000000 --- a/htdocs/includes/jsgantt/jsgantt_exExternalXML.html +++ /dev/null @@ -1,533 +0,0 @@ - - - - - - -FREE javascript gantt - JSGantt HTML and CSS only - - - - - - - - - - - - - - - - - - - - - - - - - -
      jsGantt - 1.2
      Bugs/Issues    Download    License    Usage    Examples    Documenation    Subscribe    Credits
    -

    -
    -
    - - -  100% Free Javascript / CSS/ HTML Gantt chart control. Completely buzzword compliant including AJAX !

    - - -
    - -
    - -Basic Features
    -
      -
    • Tasks & Collapsible Task Groups
    • -
    • Multiple Dependencies
    • -
    • Task Completion
    • -
    • Task Color
    • -
    • Milestones
    • -
    • Resources
    • -
    • No images needed
    • -
    - -Advanced Features
    -
      -
    • Dynamic Loading of Tasks
    • -
    • Dynamic change of format -
        -
      • Day
      • -
      • Week
      • -
      • Month
      • -
      • Quarter
      • -
      • Hour
      • -
      • Minute
      • -
      -
    • -
    • Load Gantt from XML file
    • -
    -
    -
    -
    -
    -Current Issues: -
      -
    1. Currently only one gantt chart is allowed per page.
    2. - -

    -New in 1.2: -
      -
    • Support for half-days
    • -
    • Hour/Minute format
    • -
    -
    -
    -Click here to download the jsgantt
    -You can download the latest bleeding edge version, request features and report issues at http://code.google.com/p/jsgantt/ -

    - -JSGantt is released under BSD license. If you require another license please contact shlomygantz@hotmail.com
    -If you plan to use it in a commercial product please consider donating the first sale to charity. -

    -

    - -

    1. Include JSGantt CSS and Javascript

    -
    -<link rel="stylesheet" type="text/css" href="jsgantt.css" />
    -<script language="javascript" src="jsgantt.js"></script>
    -
    - -

    2. Create a div element to hold the gantt chart

    -
    <div style="position:relative" class="gantt" id="GanttChartDIV"></div>
    -

    3. Start a <script> block

    -
    <script language="javascript">
    -

    4. Instantiate JSGantt using GanttChart()

    -
    var g = new JSGantt.GanttChart('g',document.getElementById('GanttChartDIV'), 'day');
    -
    -    
    - -

    GanttChart(pGanttVar, pDiv, pFormat)
    - pGanttVar: (required) name of the variable assigned
    - pDiv: (required) this is a DIV object created in HTML
    - pFormat: (required) - used to indicate whether chart should be drawn in "day", "week", "month", or "quarter" format

    -

    Customize the look and feel using the following setters

    -

    g.setShowRes(1); // Show/Hide Responsible (0/1)
    -g.setShowDur(1); // Show/Hide Duration (0/1)
    -g.setShowComp(1); // Show/Hide % Complete(0/1)
    -g.setCaptionType('Resource');  // Set to Show Caption (None,Caption,Resource,Duration,Complete)
    -g.setShowStartDate(1); // Show/Hide Start Date(0/1)
    -g.setShowEndDate(1); // Show/Hide End Date(0/1)
    -g.setDateInputFormat('mm/dd/yyyy')  // Set format of input dates ('mm/dd/yyyy', 'dd/mm/yyyy', 'yyyy-mm-dd')
    -g.setDateDisplayFormat('mm/dd/yyyy') // Set format to display dates ('mm/dd/yyyy', 'dd/mm/yyyy', 'yyyy-mm-dd')
    -g.setFormatArr("day","week","month","quarter") // Set format options (up to 4 : "minute","hour","day","week","month","quarter")
    -
    - -

    -

    5. Add Tasks using AddTaskItem()

    -
     
    -g.AddTaskItem(new JSGantt.TaskItem(1,   'Define Chart API',     '',          '',          'ff0000', 'http://help.com', 0, 'Brian',     0, 1, 0, 1));
    -g.AddTaskItem(new JSGantt.TaskItem(11,  'Chart Object',         '2/10/2008', '2/10/2008', 'ff00ff', 'http://www.yahoo.com', 1, 'Shlomy',  100, 0, 1, 1, "121,122", "My Caption"));
    -
    - -TaskItem(pID, pName, pStart, pEnd, pColor, pLink, pMile, pRes, pComp, pGroup, pParent, pOpen, pDepend)
    -pID: (required) is a unique ID used to identify each row for parent functions and for setting dom id for hiding/showing
    -pName: (required) is the task Label
    -pStart: (required) the task start date, can enter empty date ('') for groups. You can also enter specific time (2/10/2008 12:00) for additional percision or half days.
    -pEnd: (required) the task end date, can enter empty date ('') for groups
    -pColor: (required) the html color for this task; e.g. '00ff00'
    -pLink: (optional) any http link navigated to when task bar is clicked.
    -pMile:(optional) represent a milestone
    -pRes: (optional) resource name
    -pComp: (required) completion percent
    -pGroup: (optional) indicates whether this is a group(parent) - 0=NOT Parent; 1=IS Parent
    -pParent: (required) identifies a parent pID, this causes this task to be a child of identified task
    -pOpen: can be initially set to close folder when chart is first drawn
    -pDepend: optional list of id's this task is dependent on ... line drawn from dependent to this item
    -pCaption: optional caption that will be added after task bar if CaptionType set to "Caption"
    - -*You should be able to add items to the chart in realtime via javascript and issuing "g.Draw()" command. - -

    5a. Another way to add tasks is to use an external XML file with parseXML()

    -
     
    -JSGantt.parseXML("project.xml",g);
    -
    -The structure of the XML file:
    - - -

    6. Call Draw() and DrawDependencies()

    -
     
    -
    -g.Draw();	
    -g.DrawDependencies();
    -
    -
    - -
    -

    7. Close the <script> block

    -
    </script>
    - -

    -Final code should look like - -

    -
    - -

    -

    -

    - - - -

    -Enter your email address to receive JSGantt announcements
    -

    - - -

    -

    - -
    - -

    Developed by Shlomy Gantz and Brian Twidt
    -Contributed: Paul Labuschagne, Kevin Badgett, Ilan Admon
    -

    - - - - \ No newline at end of file diff --git a/htdocs/includes/jsgantt/main.css b/htdocs/includes/jsgantt/main.css new file mode 100644 index 00000000000..544192b1b2d --- /dev/null +++ b/htdocs/includes/jsgantt/main.css @@ -0,0 +1,126 @@ +body { + position: relative; +} + +.product-name { + font-family: Satisfy; +} + +#my-navbar-nav { + font-size: 16px; +} + +#my-nav-brand { + font-size: 24px; + margin: 2px 40px 0 10px; + color: #ffffff; +} + +#home { + background: #323232 url(home-bg.jpg) center 0 no-repeat; + background-attachment: fixed; + background-size: cover; + min-height: 660px; + color: #ffffff; +} +#home-title { + font-size: 70px; + margin-top: 180px; +} +#home-subtitle { + font-size: 36px; + margin-top: 40px; + margin-bottom: 50px; +} +#learn-more { + padding: 0; + width: 50px; + height: 50px; + border-radius: 50%; + font-size: 38px; + margin-top: 60px; +} +@media screen and (max-width: 991px) { + #learn-more { + display: none; + } +} + +.section { + margin: 0 15vw; + padding: 5px 0 0; +} + +h1 { + font-family: Kelly Slab; + font-size: 56px; + margin: 50px 0 20px; +} + +h2 { + font-family: Kelly Slab; + margin: 20px 0 10px; +} + +h3 { + font-family: Kelly Slab; +} +#embedded-Gantt, #external-Gantt { +} + +.code-block { + background-color: #222222; +} + +.contact-card { + max-width: 200px; + margin: auto; +} + +.contact-link { + font-size: 28px; +} + +.footer { + margin-top: 10px; + padding-top: 10px; + border-top: solid #bbbbbb 1px; +} + +#slide-card { + background: transparent; + border: none; + margin: 180px 50px 50px; +} +#slide-dots { + background: transparent; + border: none; +} +.dot { + cursor:pointer; + height: 13px; + width: 13px; + margin: 0 2px; + background-color: #ffffff; + opacity: 0.3; + border-radius: 50%; + display: inline-block; + -webkit-transition: all .5s; /* Safari */ + transition: all .5s; +} +.dot:hover { + opacity: 1; +} +.dot.active { + opacity: 1; +} +.slide { + width: 100%; + height: 150px; + font-size: 20px; + display: none; + opacity: 0; +} +.slide-icon { + font-size: 60px; +} diff --git a/htdocs/includes/jsgantt/main.js b/htdocs/includes/jsgantt/main.js new file mode 100644 index 00000000000..53f5f8f0c10 --- /dev/null +++ b/htdocs/includes/jsgantt/main.js @@ -0,0 +1,85 @@ +$(document).ready(function() { + + // Scrollspy changes navbar active links + $("body").scrollspy({target:"#my-navbar-nav", offset:50}); + + // Smooth scroll + $("a").click(function(event) { + if (this.hash !== "") { + event.preventDefault(); + var linkOffset = 0; + if ($.inArray(this.hash,["#options","#xmlExport","#optionsLanguage","#setDayMajorDateDisplayFormat"]) != -1) { + linkOffset = -25; + } + $("html, body").animate({ + scrollTop: $(this.hash).offset().top - $(".navbar").height() + linkOffset + }, 600); + } + }); + + // Demo buttons + $("#embedded-Gantt").hide(0); + $("#external-Gantt").hide(0); + + $(".btn-demo").click(function() { + if ($(this).html().indexOf("Embedded Code") != -1) { + if ($("#external-Gantt").is(":visible")) { + $("#external-Gantt").animate({ + height: "toggle", + opacity: "toggle"}, 300, function () { + $("#embedded-Gantt").animate({ + height: "toggle", + opacity: "toggle"}, 600 + ); + } + ); + $(".btn-demo:nth-child(2)").removeClass("active"); + } else { + $("#embedded-Gantt").animate({ + height: "toggle", + opacity: "toggle"}, 600 + ); + } + } else { + if ($("#embedded-Gantt").is(":visible")) { + $("#embedded-Gantt").animate({ + height: "toggle", + opacity: "toggle"}, 300, function() { + $("#external-Gantt").animate({ + height: "toggle", + opacity: "toggle"}, 600 + ); + } + ); + $(".btn-demo:nth-child(1)").removeClass("active"); + } else { + $("#external-Gantt").animate({ + height: "toggle", + opacity: "toggle"}, 600 + ); + } + } + }); + + // Slideshow + var slideIndex = 0; + carousel(); + + function carousel() { + var i; + var x = document.getElementsByClassName("slide"); + var d = document.getElementsByClassName("dot"); + for (i = 0; i < x.length; i++) { + x[i].style.display = "none"; + } + slideIndex++; + if (slideIndex > x.length) {slideIndex = 1} + x[slideIndex-1].style.display = "inline-block"; + $(".slide:nth-child(" + (slideIndex).toString() + ")").animate({ + opacity: 1 + }, 500); + $(".dot").removeClass("active"); + $(".dot:nth-child(" + (slideIndex).toString() + ")").addClass("active"); + setTimeout(carousel, 2000); // Change image every 2 seconds + } + }); diff --git a/htdocs/includes/jsgantt/project.xml b/htdocs/includes/jsgantt/project.xml index d43110a6a38..80637aa7cae 100644 --- a/htdocs/includes/jsgantt/project.xml +++ b/htdocs/includes/jsgantt/project.xml @@ -1,65 +1,131 @@ - - - 10 - WCF Changes - - - 0000ff - - 0 - - 0 - 1 - 0 - 1 - - - - 20 - Move to WCF from remoting - 9/11/2008 - 9/15/2008 - 0000ff - - 0 - Rich - 10 - 0 - 10 - 1 - - Brian - - - 30 - add Auditing - 9/19/2008 - 9/21/2008 - 0000ff - - 0 - Shlomy - 50 - 0 - 10 - 1 - 20 - Shlomy - - - 40 - Yet another task - 9/23/2008 - 9/24/2008 - 0000ff - - 0 - Shlomy - 30 - 0 - 0 - 1 - 20,30 - Shlomy - - \ No newline at end of file + + + + 10 + WCF Changes + + + ggroupblack + + 0 + + 0 + 1 + 0 + 1 + + + + 20 + Move to WCF from remoting + 2017-05-11 09:00 + 2017-05-15 + gtaskblue + + 0 + Paul + 10 + 0 + 10 + 1 + + Paul + This text is only available in tool tips + + + 30 + add Auditing + 2017-05-18 10:30 + 2017-05-20 12:00 + gtaskblue + + 0 + Eduardo + 50 + 0 + 10 + 1 + 20 + Eduardo + + + 40 + Yet another task + 2017-05-24 + 2017-05-25 + gtaskblue + + 0 + Ricardo + 30 + 0 + 0 + 1 + 20,30 + Ricardo + + + 50 + Another Group + + + ggroupblack + + 0 + + 0 + 1 + 0 + 1 + + + + 60 + Move to GitHub + 2017-05-14 09:00 + 2017-05-16 + gtaskblue + + 0 + Ricardo + 10 + 0 + 50 + 1 + + Ricardo + This text is only available in tool tips + + + 70 + Updating files + 2017-05-18 10:30 + 2017-05-21 12:00 + gtaskred + + 0 + Paul + 50 + 0 + 50 + 1 + 60 + Paul + + + 80 + Yet another task + 2017-05-23 + 2017-05-25 + gtaskyellow + + 0 + Eduardo + 30 + 0 + 50 + 1 + 60,70 + Eduardo + + diff --git a/htdocs/includes/nusoap/lib/nusoap.php b/htdocs/includes/nusoap/lib/nusoap.php index 56d1cf4c1a8..6bd651e512c 100644 --- a/htdocs/includes/nusoap/lib/nusoap.php +++ b/htdocs/includes/nusoap/lib/nusoap.php @@ -6374,7 +6374,9 @@ class wsdl extends nusoap_base { $elements = $eElements; } - if (count($attrs) > 0) { + // @CHANGE LDR FIX for PHP7.2 + //if (count($attrs) > 0) { + if (is_array($attrs) && count($attrs) > 0) { foreach($attrs as $n => $a){ // expand each attribute foreach ($a as $k => $v) { diff --git a/htdocs/includes/odtphp/Segment.php b/htdocs/includes/odtphp/Segment.php index 40668215647..8cea06db50b 100644 --- a/htdocs/includes/odtphp/Segment.php +++ b/htdocs/includes/odtphp/Segment.php @@ -24,7 +24,7 @@ class Segment implements IteratorAggregate, Countable protected $images = array(); protected $odf; protected $file; - + /** * Constructor * @@ -86,15 +86,15 @@ class Segment implements IteratorAggregate, Countable */ public function merge() { - // To provide debug information on line number processed + // To provide debug information on line number processed global $count; if (empty($count)) $count=1; else $count++; - + if (empty($this->savxml)) $this->savxml = $this->xml; // Sav content of line at first line merged, so we will reuse original for next steps $this->xml = $this->savxml; $tmpvars = $this->vars; // Store into $tmpvars so we won't modify this->vars when completing data with empty values - + // Search all tags fou into condition to complete $tmpvars, so we will proceed all tests even if not defined $reg='@\[!--\sIF\s([{}a-zA-Z0-9\.\,_]+)\s--\]@smU'; preg_match_all($reg, $this->xml, $matches, PREG_SET_ORDER); @@ -106,7 +106,7 @@ class Segment implements IteratorAggregate, Countable $tmpvars[$match[1]] = ''; // Not defined, so we set it to '', we just need entry into this->vars for next loop } } - + // Conditionals substitution // Note: must be done before static substitution, else the variable will be replaced by its value and the conditional won't work anymore foreach($tmpvars as $key => $value) @@ -133,7 +133,7 @@ class Segment implements IteratorAggregate, Countable $this->xml = preg_replace($reg, '', $this->xml); } } - + $this->xmlParsed .= str_replace(array_keys($tmpvars), array_values($tmpvars), $this->xml); if ($this->hasChildren()) { foreach ($this->children as $child) { @@ -143,7 +143,7 @@ class Segment implements IteratorAggregate, Countable } $reg = "/\[!--\sBEGIN\s$this->name\s--\](.*)\[!--\sEND\s$this->name\s--\]/sm"; $this->xmlParsed = preg_replace($reg, '$1', $this->xmlParsed); - // Miguel Erill 09704/2017 - Add macro replacement to invoice lines + // Miguel Erill 09704/2017 - Add macro replacement to invoice lines $this->xmlParsed = $this->macroReplace($this->xmlParsed); $this->file->open($this->odf->getTmpfile()); foreach ($this->images as $imageKey => $imageValue) { @@ -155,28 +155,39 @@ class Segment implements IteratorAggregate, Countable } } $this->file->close(); - + return $this->xmlParsed; } /** * Function to replace macros for invoice short and long month, invoice year - * + * * Substitution occur when the invoice is generated, not considering the invoice date * so do not (re)generate in a diferent date than the one that the invoice belongs to * Perhaps it would be better to use the invoice issued date but I still do not know * how to get it here * * Miguel Erill 09/04/2017 - * + * * @param string $value String to convert */ public function macroReplace($text) { + include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; global $langs; - $patterns=array( '__CURRENTDAY__','__CURRENTDAYTEXT__','__CURRENTMONTHSHORT__','__CURRENTMONTH__','__CURRENTYEAR__' ); - $values=array( date('j'), $langs->trans(date('l')), $langs->trans(date('M')), $langs->trans(date('F')), date('Y') ); + $hoy = dol_getdate(dol_now('tzuser')); + $dateinonemontharray = dol_get_next_month($hoy['mon'], $hoy['year']); + $nextMonth = $dateinonemontharray['month']; + + $patterns=array( '/__CURRENTDAY__/u','/__CURENTWEEKDAY__/u', + '/__CURRENTMONTH__/u','/__CURRENTMONTHLONG__/u', + '/__NEXTMONTH__/u','/__NEXTMONTHLONG__/u', + '/__CURRENTYEAR__/u','/__NEXTYEAR__/u' ); + $values=array( $hoy['mday'], $langs->transnoentitiesnoconv($hoy['weekday']), + $hoy['mon'], $langs->transnoentitiesnoconv($hoy['month']), + $nextMonth, monthArray($langs)[$nextMonth], + $hoy['year'], $hoy['year']+1 ); $text=preg_replace($patterns, $values, $text); @@ -203,7 +214,7 @@ class Segment implements IteratorAggregate, Countable } return $this; } - + /** * Assign a template variable to replace * diff --git a/htdocs/includes/odtphp/odf.php b/htdocs/includes/odtphp/odf.php index 01633634705..19fd3390937 100644 --- a/htdocs/includes/odtphp/odf.php +++ b/htdocs/includes/odtphp/odf.php @@ -36,14 +36,14 @@ class Odf protected $images = array(); protected $vars = array(); protected $segments = array(); - + public $creator; public $title; public $subject; public $userdefined=array(); - + const PIXEL_TO_CM = 0.026458333; - + /** * Class constructor * @@ -113,7 +113,7 @@ class Odf copy($filename, $this->tmpfile); - // Now file has been loaded, we must move the [!-- BEGIN and [!-- END tags outside the + // Now file has been loaded, we must move the [!-- BEGIN and [!-- END tags outside the // _moveRowSegments(); } @@ -124,7 +124,7 @@ class Odf * @param string $key Name of the variable within the template * @param string $value Replacement value * @param bool $encode If true, special XML characters are encoded - * @param string $charset Charset + * @param string $charset Charset * @throws OdfException * @return odf */ @@ -211,7 +211,7 @@ class Odf { preg_match_all('/[\{\<]\?(php)?\s+(?P.+)\?[\}\>]/iU',$this->contentXml, $matches); // detecting all {?php code ?} or $nbfound=count($matches['content']); - for ($i=0; $i < $nbfound; $i++) + for ($i=0; $i < $nbfound; $i++) { try { $ob_output = ''; // flush the output for each code. This var will be filled in by the eval($code) and output buffering : any print or echo or output will be redirected into this variable @@ -268,7 +268,7 @@ IMG; $this->contentXml = preg_replace('/\[!--\sBEGIN]>(row.[\S]*)\s--\]/sm', '[!-- BEGIN \\1 --]', $this->contentXml); // Replace ENDxxx into END xxx $this->contentXml = preg_replace('/\[!--\sEND]>(row.[\S]*)\s--\]/sm', '[!-- END \\1 --]', $this->contentXml); - + // Search all possible rows in the document $reg1 = "#]*>(.*)#smU"; preg_match_all($reg1, $this->contentXml, $matches); @@ -302,7 +302,7 @@ IMG; // Search all tags fou into condition to complete $this->vars, so we will proceed all tests even if not defined $reg='@\[!--\sIF\s([{}a-zA-Z0-9\.\,_]+)\s--\]@smU'; preg_match_all($reg, $this->contentXml, $matches, PREG_SET_ORDER); - + //var_dump($this->vars);exit; foreach($matches as $match) // For each match, if there is no entry into this->vars, we add it { @@ -312,7 +312,7 @@ IMG; } } //var_dump($this->vars);exit; - + // Conditionals substitution // Note: must be done before static substitution, else the variable will be replaced by its value and the conditional won't work anymore foreach($this->vars as $key => $value) @@ -358,7 +358,7 @@ IMG; if ($type == 'content') $this->contentXml = str_replace(array_keys($this->vars), array_values($this->vars), $this->contentXml); if ($type == 'styles') $this->stylesXml = str_replace(array_keys($this->vars), array_values($this->vars), $this->stylesXml); if ($type == 'meta') $this->metaXml = str_replace(array_keys($this->vars), array_values($this->vars), $this->metaXml); - + } /** @@ -467,7 +467,7 @@ IMG; $this->setMetaData(); //print $this->metaXml;exit; - + if (! $this->file->addFromString('content.xml', $this->contentXml)) { throw new OdfException('Error during file export addFromString content'); } @@ -477,7 +477,7 @@ IMG; if (! $this->file->addFromString('styles.xml', $this->stylesXml)) { throw new OdfException('Error during file export addFromString styles'); } - + foreach ($this->images as $imageKey => $imageValue) { // Add the image inside the ODT document $this->file->addFile($imageKey, 'Pictures/' . $imageValue); @@ -499,12 +499,12 @@ IMG; public function setMetaData() { if (empty($this->creator)) $this->creator=''; - + $this->metaXml = preg_replace('/.*<\/dc:date>/', ''.gmdate("Y-m-d\TH:i:s").'', $this->metaXml); $this->metaXml = preg_replace('/.*<\/dc:creator>/', ''.htmlspecialchars($this->creator).'', $this->metaXml); $this->metaXml = preg_replace('/.*<\/dc:title>/', ''.htmlspecialchars($this->title).'', $this->metaXml); $this->metaXml = preg_replace('/.*<\/dc:subject>/', ''.htmlspecialchars($this->subject).'', $this->metaXml); - + if (count($this->userdefined)) { foreach($this->userdefined as $key => $val) @@ -515,7 +515,7 @@ IMG; } } } - + /** * Update Manifest file according to added image files * @@ -569,24 +569,58 @@ IMG; { global $conf; - if( $name == "" ) $name = md5(uniqid()); + if( $name == "" ) $name = "temp".md5(uniqid()); dol_syslog(get_class($this).'::exportAsAttachedPDF $name='.$name, LOG_DEBUG); $this->saveToDisk($name); $execmethod=(empty($conf->global->MAIN_EXEC_USE_POPEN)?1:2); // 1 or 2 + // Method 1 sometimes hang the server. - $name=preg_replace('/\.odt/i', '', $name); - if (!empty($conf->global->MAIN_DOL_SCRIPTS_ROOT)) + if (preg_match('/unoconv/', $conf->global->MAIN_ODT_AS_PDF)) { - $command = $conf->global->MAIN_DOL_SCRIPTS_ROOT.'/scripts/odt2pdf/odt2pdf.sh '.escapeshellcmd($name).' '.(is_numeric($conf->global->MAIN_ODT_AS_PDF)?'jodconverter':$conf->global->MAIN_ODT_AS_PDF); + // If issue with unoconv, see https://github.com/dagwieers/unoconv/issues/87 + + // MAIN_ODT_AS_PDF should be "sudo -u unoconv /usr/bin/unoconv" and userunoconv must have sudo to be root by adding file /etc/sudoers.d/unoconv with content www-data ALL=(unoconv) NOPASSWD: /usr/bin/unoconv . + + // Try this with www-data user: /usr/bin/unoconv -vvvv -f pdf /tmp/document-example.odt + // It must return: + //Verbosity set to level 4 + //Using office base path: /usr/lib/libreoffice + //Using office binary path: /usr/lib/libreoffice/program + //DEBUG: Connection type: socket,host=127.0.0.1,port=2002;urp;StarOffice.ComponentContext + //DEBUG: Existing listener not found. + //DEBUG: Launching our own listener using /usr/lib/libreoffice/program/soffice.bin. + //LibreOffice listener successfully started. (pid=9287) + //Input file: /tmp/document-example.odt + //unoconv: file `/tmp/document-example.odt' does not exist. + //unoconv: RuntimeException during import phase: + //Office probably died. Unsupported URL : "type detection failed" + //DEBUG: Terminating LibreOffice instance. + //DEBUG: Waiting for LibreOffice instance to exit + + // It fails: + // - set shel of user to bash instead of nologin. + // - set permission to read/write to user on home directory /var/www so user can create the libreoffice , dconf and .cache dir and files then set permission back + + $command = $conf->global->MAIN_ODT_AS_PDF.' '.escapeshellcmd($name); + //$command = '/usr/bin/unoconv -vvv '.escapeshellcmd($name); } else { - dol_syslog(get_class($this).'::exportAsAttachedPDF is used but the constant MAIN_DOL_SCRIPTS_ROOT with path to script directory was not defined.', LOG_WARNING); - $command = '../../scripts/odt2pdf/odt2pdf.sh '.escapeshellcmd($name).' '.(is_numeric($conf->global->MAIN_ODT_AS_PDF)?'jodconverter':$conf->global->MAIN_ODT_AS_PDF); - } + // deprecated old method + $name=preg_replace('/\.odt/i', '', $name); + if (!empty($conf->global->MAIN_DOL_SCRIPTS_ROOT)) + { + $command = $conf->global->MAIN_DOL_SCRIPTS_ROOT.'/scripts/odt2pdf/odt2pdf.sh '.escapeshellcmd($name).' '.(is_numeric($conf->global->MAIN_ODT_AS_PDF)?'jodconverter':$conf->global->MAIN_ODT_AS_PDF); + } + else + { + dol_syslog(get_class($this).'::exportAsAttachedPDF is used but the constant MAIN_DOL_SCRIPTS_ROOT with path to script directory was not defined.', LOG_WARNING); + $command = '../../scripts/odt2pdf/odt2pdf.sh '.escapeshellcmd($name).' '.(is_numeric($conf->global->MAIN_ODT_AS_PDF)?'jodconverter':$conf->global->MAIN_ODT_AS_PDF); + } + } //$dirname=dirname($name); //$command = DOL_DOCUMENT_ROOT.'/includes/odtphp/odt2pdf.sh '.$name.' '.$dirname; @@ -598,16 +632,19 @@ IMG; } if ($execmethod == 2) { + $outputfile = DOL_DATA_ROOT.'/odt2pdf.log'; + $ok=0; $handle = fopen($outputfile, 'w'); if ($handle) { dol_syslog(get_class($this)."Run command ".$command,LOG_DEBUG); + fwrite($handle, $command."\n"); $handlein = popen($command, 'r'); while (!feof($handlein)) { $read = fgets($handlein); - fwrite($handle,$read); + fwrite($handle, $read); $output_arr[]=$read; } pclose($handlein); @@ -616,7 +653,7 @@ IMG; if (! empty($conf->global->MAIN_UMASK)) @chmod($outputfile, octdec($conf->global->MAIN_UMASK)); } - if($retval == 0) + if ($retval == 0) { dol_syslog(get_class($this).'::exportAsAttachedPDF $ret_val='.$retval, LOG_DEBUG); if (headers_sent($filename, $linenum)) { @@ -686,7 +723,7 @@ IMG; /** * Empty the temporary working directory recursively - * + * * @param string $dir The temporary working directory * @return void */ @@ -709,7 +746,7 @@ IMG; /** * return the value present on odt in [valuename][/valuename] - * + * * @param string $valuename Balise in the template * @return string The value inside the balise */ diff --git a/htdocs/includes/parsedown/Parsedown.php b/htdocs/includes/parsedown/Parsedown.php index 20863a7537a..df718bce111 100644 --- a/htdocs/includes/parsedown/Parsedown.php +++ b/htdocs/includes/parsedown/Parsedown.php @@ -141,7 +141,11 @@ class Parsedown foreach ($parts as $part) { - $shortage = 4 - mb_strlen($line, 'utf-8') % 4; + // @CHANGE LDR Fix when mb_strlen is not available + //$shortage = 4 - mb_strlen($line, 'utf-8') % 4; + if (function_exists('mb_strlen')) $len = mb_strlen($line, 'utf-8'); + else $len = strlen($line); + $shortage = 4 - $len % 4; $line .= str_repeat(' ', $shortage); $line .= $part; @@ -515,10 +519,10 @@ class Parsedown ), ); - if($name === 'ol') + if($name === 'ol') { $listStart = stristr($matches[0], '.', true); - + if($listStart !== '1') { $Block['element']['attributes'] = array('start' => $listStart); @@ -1176,7 +1180,9 @@ class Parsedown 'name' => 'img', 'attributes' => array( 'src' => $Link['element']['attributes']['href'], - 'alt' => $Link['element']['text'], + 'alt' => $Link['element']['text'], + // @CHANGE LDR + 'class' => $Link['element']['attributes']['class'] ), ), ); @@ -1227,6 +1233,13 @@ class Parsedown } $extent += strlen($matches[0]); + + // @CHANGE LDR + if (preg_match('/{([^}]+)}/', $remainder, $matches2)) + { + $Element['attributes']['class'] = $matches2[1]; + $remainder = preg_replace('/{'.preg_quote($matches2[1],'/').'}/', '', $remainder); + } } else { @@ -1422,7 +1435,9 @@ class Parsedown if (isset($Element['handler'])) { - $markup .= $this->{$Element['handler']}($Element['text']); + // @CHANGE LDR + //$markup .= $this->{$Element['handler']}($Element['text']); + $markup .= preg_replace('/>{[^}]+}/', '>', $this->{$Element['handler']}($Element['text'])); } else { diff --git a/htdocs/includes/restler/framework/Luracast/Restler/AutoLoader.php b/htdocs/includes/restler/framework/Luracast/Restler/AutoLoader.php index 20a33ee3b70..300eadb0f70 100644 --- a/htdocs/includes/restler/framework/Luracast/Restler/AutoLoader.php +++ b/htdocs/includes/restler/framework/Luracast/Restler/AutoLoader.php @@ -307,10 +307,10 @@ class AutoLoader */ private function alias($className, $currentClass) { - // @CHANGE LDR + // @CHANGE LDR if ($className == 'Luracast\Restler\string') return; if ($className == 'Luracast\Restler\mixed') return; - + if ($className != $currentClass && false !== strpos($className, $currentClass)) if (!class_exists($currentClass, false) diff --git a/htdocs/includes/restler/framework/Luracast/Restler/CommentParser.php b/htdocs/includes/restler/framework/Luracast/Restler/CommentParser.php index 8a3023cab20..e8248a385fa 100644 --- a/htdocs/includes/restler/framework/Luracast/Restler/CommentParser.php +++ b/htdocs/includes/restler/framework/Luracast/Restler/CommentParser.php @@ -505,7 +505,7 @@ class CommentParser $data = explode('|', $data); $r['type'] = count($data) == 1 ? $data[0] : $data; } - if (isset($r['type']) && is_string($r['type']) && Text::endsWith($r['type'], '[]')) { + if (isset($r['type']) && Text::endsWith($r['type'], '[]')) { $r[static::$embeddedDataName]['type'] = substr($r['type'], 0, -2); $r['type'] = 'array'; } diff --git a/htdocs/includes/restler/framework/Luracast/Restler/Data/Object.php b/htdocs/includes/restler/framework/Luracast/Restler/Data/Obj.php similarity index 99% rename from htdocs/includes/restler/framework/Luracast/Restler/Data/Object.php rename to htdocs/includes/restler/framework/Luracast/Restler/Data/Obj.php index 5ef5850b86e..003f1df8794 100644 --- a/htdocs/includes/restler/framework/Luracast/Restler/Data/Object.php +++ b/htdocs/includes/restler/framework/Luracast/Restler/Data/Obj.php @@ -13,7 +13,7 @@ namespace Luracast\Restler\Data; * @link http://luracast.com/products/restler/ * @version 3.0.0rc6 */ -class Object +class Obj { /** * @var bool|string|callable diff --git a/htdocs/includes/restler/framework/Luracast/Restler/Data/Validator.php b/htdocs/includes/restler/framework/Luracast/Restler/Data/Validator.php index be2ef28f40a..28202efb7ad 100644 --- a/htdocs/includes/restler/framework/Luracast/Restler/Data/Validator.php +++ b/htdocs/includes/restler/framework/Luracast/Restler/Data/Validator.php @@ -454,7 +454,10 @@ class Validator implements iValidate } if (isset ($info->choice)) { - if (is_array($input)) { + if (!$info->required && empty($input)) { + //since its optional, and empty let it pass. + $input = null; + } elseif (is_array($input)) { foreach ($input as $i) { if (!in_array($i, $info->choice)) { $error .= ". Expected one of (" . implode(',', $info->choice) . ")."; @@ -468,6 +471,11 @@ class Validator implements iValidate } if (method_exists($class = get_called_class(), $info->type) && $info->type != 'validate') { + if(!$info->required && empty($input)) + { + //optional parameter with a empty value assume null + return null; + } try { return call_user_func("$class::$info->type", $input, $info); } catch (Invalid $e) { @@ -669,4 +677,4 @@ class Validator implements iValidate throw $e; } } -} \ No newline at end of file +} diff --git a/htdocs/includes/restler/framework/Luracast/Restler/EventDispatcher.php b/htdocs/includes/restler/framework/Luracast/Restler/EventDispatcher.php index 1c173d38baa..f8cd883af46 100644 --- a/htdocs/includes/restler/framework/Luracast/Restler/EventDispatcher.php +++ b/htdocs/includes/restler/framework/Luracast/Restler/EventDispatcher.php @@ -44,7 +44,7 @@ class EventDispatcher public function __call($eventName, $params) { if (0 === strpos($eventName, 'on')) { - if (!@is_array($this->listeners[$eventName])) + if (!isset($this->listeners[$eventName]) || !is_array($this->listeners[$eventName])) $this->listeners[$eventName] = array(); $this->listeners[$eventName][] = $params[0]; } diff --git a/htdocs/includes/restler/framework/Luracast/Restler/Explorer.php b/htdocs/includes/restler/framework/Luracast/Restler/Explorer.php index 9522441c5b0..686c4c2fc23 100644 --- a/htdocs/includes/restler/framework/Luracast/Restler/Explorer.php +++ b/htdocs/includes/restler/framework/Luracast/Restler/Explorer.php @@ -16,7 +16,12 @@ use Luracast\Restler\Scope; */ class Explorer implements iProvideMultiVersionApi { - const SWAGGER_VERSION = '1.2'; + const SWAGGER = '2.0'; + + /** + * @var array http schemes supported. http or https or both http and https + */ + public static $schemes = array(); /** * @var bool should protected resources be shown to unauthenticated users? */ @@ -70,17 +75,17 @@ class Explorer implements iProvideMultiVersionApi */ public static $dataTypeAlias = array( //'string' => 'string', - 'int' => 'integer', - 'number' => 'number', - 'float' => array('number', 'float'), - 'bool' => 'boolean', + 'int' => 'integer', + 'number' => 'number', + 'float' => array('number', 'float'), + 'bool' => 'boolean', //'boolean' => 'boolean', //'NULL' => 'null', - 'array' => 'array', + 'array' => 'array', //'object' => 'object', 'stdClass' => 'object', - 'mixed' => 'string', - 'date' => array('string', 'date'), + 'mixed' => 'string', + 'date' => array('string', 'date'), 'datetime' => array('string', 'date-time'), ); @@ -89,9 +94,9 @@ class Explorer implements iProvideMultiVersionApi * protected api */ public static $apiDescriptionSuffixSymbols = array( - 0 => '  ', //public api - 1 => '  ', //hybrid api - 2 => '  ', //protected api + 0 => ' 🔓', //'  ', //public api + 1 => ' ◑', //'  ', //hybrid api + 2 => ' 🔐', //'  ', //protected api ); protected $models = array(); @@ -100,27 +105,23 @@ class Explorer implements iProvideMultiVersionApi */ protected $_fullDataRequested = false; protected $crud = array( - 'POST' => 'create', - 'GET' => 'retrieve', - 'PUT' => 'update', + 'POST' => 'create', + 'GET' => 'retrieve', + 'PUT' => 'update', 'DELETE' => 'delete', - 'PATCH' => 'partial update' + 'PATCH' => 'partial update' ); protected static $prefixes = array( - 'get' => 'retrieve', - 'index' => 'list', - 'post' => 'create', - 'put' => 'update', - 'patch' => 'modify', + 'get' => 'retrieve', + 'index' => 'list', + 'post' => 'create', + 'put' => 'update', + 'patch' => 'modify', 'delete' => 'remove', ); protected $_authenticated = false; protected $cacheName = ''; - public function __construct() - { - - } /** * Serve static files for exploring @@ -131,7 +132,7 @@ class Explorer implements iProvideMultiVersionApi */ public function get() { - if (func_num_args() > 1 && func_get_arg(0) == 'resources') { + if (func_num_args() > 1 && func_get_arg(0) == 'swagger') { /** * BUGFIX: * If we use common resourcePath (e.g. $r->addAPIClass([api-class], 'api/shop')), than we must determine resource-ID of e.g. 'api/shop'! @@ -141,6 +142,7 @@ class Explorer implements iProvideMultiVersionApi array_shift($arguments); // create ID $id = implode('/', $arguments); + return $this->getResources($id); } $filename = implode('/', func_get_args()); @@ -161,125 +163,75 @@ class Explorer implements iProvideMultiVersionApi ) { $filename .= '.js'; } - PassThrough::file(__DIR__ . '/explorer/' . (empty($filename) ? 'index.html' : $filename), false, 0); //60 * 60 * 24); + PassThrough::file(__DIR__ . '/explorer/' . (empty($filename) ? 'index.html' : $filename), false, + 0); //60 * 60 * 24); } - public function resources() + /** + * @return stdClass + */ + public function swagger() { $r = new stdClass(); - $r->apiVersion = (string)$this->restler->getRequestedApiVersion(); - $r->swaggerVersion = static::SWAGGER_VERSION; - $r->apis = $this->apis($r->apiVersion); - $r->authorizations = $this->authorizations(); - $r->info = array_filter(get_class_vars(static::$infoClass)); - return $r; - } + $version = (string)$this->restler->getRequestedApiVersion(); + $r->swagger = static::SWAGGER; - public function getResources($id) - { - $r = new stdClass(); - $r->apiVersion = (string)$this->restler->getRequestedApiVersion(); - $r->swaggerVersion = static::SWAGGER_VERSION; - $r->basePath = $this->restler->getBaseUrl(); - $r->resourcePath = "/$id"; - - $r->apis = $this->apis($r->apiVersion, $id); - $r->models = (object)$this->models; + $info = parse_url($this->restler->getBaseUrl()); + $r->host = $info['host']; + if (isset($info['port'])) { + $r->host .= ':' . $info['port']; + } + $r->basePath = isset($info['path']) ? $info['path'] : ''; + if (!empty(static::$schemes)) { + $r->schemes = static::$schemes; + } $r->produces = $this->restler->getWritableMimeTypes(); $r->consumes = $this->restler->getReadableMimeTypes(); - $r->authorizations = $this->authorizations(); + + $r->paths = $this->paths($version); + $r->definitions = (object)$this->models; + $r->securityDefinitions = $this->securityDefinitions(); + $r->info = compact('version') + array_filter(get_class_vars(static::$infoClass)); + return $r; } - private function apis($version = 1, $resource = false) + private function paths($version = 1) { $map = Routes::findAll(static::$excludedPaths + array($this->base()), static::$excludedHttpMethods, $version); - $r = array(); - $a = array(); + $paths = array(); foreach ($map as $path => $data) { - $route = $data[0]['route']; $access = $data[0]['access']; - if ($access && !Text::contains($path, '{')) { - $r[] = array( - 'path' => empty($path) ? '/root' : "/$path", - //'description' => '' - //TODO: Util::nestedValue($route, 'metadata', 'classDescription') ? : '' - ); - } - if (static::$hideProtected && !$access) + if (static::$hideProtected && !$access) { continue; - $grouper = array(); + } foreach ($data as $item) { $route = $item['route']; $access = $item['access']; - if (static::$hideProtected && !$access) + if (static::$hideProtected && !$access) { continue; + } $url = $route['url']; - if (isset($grouper[$url])) { - $grouper[$url]['operations'][] = $this->operation($route); - } else { - $api = array( - 'path' => "/$url", - 'description' => - Util::nestedValue($route, 'metadata', 'classDescription') ? : '', - 'operations' => array($this->operation($route)) - ); - static::$groupOperations - ? $grouper[$url] = $api - : $a[$path][] = $api; - } + $paths["/$url"][strtolower($route['httpMethod'])] = $this->operation($route); } - if (!empty($grouper)) { - $a[$path] = array_values($grouper); - // sort REST-endpoints by path - foreach ($a as & $b) { - usort( - $b, - function ($x, $y) { - return $x['path'] > $y['path']; - } - ); - } - } else { - $order = array( - 'GET' => 1, - 'POST' => 2, - 'PUT' => 3, - 'PATCH' => 4, - 'DELETE' => 5 - ); - foreach ($a as & $b) { - usort( - $b, - function ($x, $y) use ($order) { - return - $x['operations'][0]->method == - $y['operations'][0]->method - ? $x['path'] > $y['path'] - : $order[$x['operations'][0]->method] > - $order[$y['operations'][0]->method]; + } - } - ); - } - } - } - if (false !== $resource) { - if ($resource == 'root') $resource = ''; - if (isset($a[$resource])) return $a[$resource]; - } - return $r; + return $paths; } private function operation($route) { $r = new stdClass(); - $r->method = $route['httpMethod']; - $r->nickname = $this->nickname($route); + $m = $route['metadata']; + $r->operationId = $this->operationId($route); + $base = strtok($route['url'], '/'); + if (empty($base)) { + $base = 'root'; + } + $r->tags = array($base); $r->parameters = $this->parameters($route); - $m = $route['metadata']; $r->summary = isset($m['description']) ? $m['description'] @@ -287,13 +239,18 @@ class Explorer implements iProvideMultiVersionApi $r->summary .= $route['accessLevel'] > 2 ? static::$apiDescriptionSuffixSymbols[2] : static::$apiDescriptionSuffixSymbols[$route['accessLevel']]; - $r->notes = isset($m['longDescription']) + $r->description = isset($m['longDescription']) ? $m['longDescription'] : ''; - $r->responseMessages = $this->responseMessages($route); + $r->responses = $this->responses($route); + //TODO: avoid hard coding. Properly detect security + if ($route['accessLevel']) { + $r->security = array(array('api_key' => array())); + } + /* $this->setType( $r, - new ValidationInfo(Util::nestedValue($m, 'return') ? : array()) + new ValidationInfo(Util::nestedValue($m, 'return') ?: array()) ); if (is_null($r->type) || 'mixed' == $r->type) { $r->type = 'array'; @@ -302,7 +259,7 @@ class Explorer implements iProvideMultiVersionApi } elseif (Text::contains($r->type, '|')) { $r->type = 'array'; } - + */ //TODO: add $r->authorizations //A list of authorizations required to execute this operation. While not mandatory, if used, it overrides //the value given at the API Declaration's authorizations. In order to completely remove API Declaration's @@ -324,8 +281,9 @@ class Explorer implements iProvideMultiVersionApi $info = new ValidationInfo($param); $description = isset($param['description']) ? $param['description'] : ''; if ('body' == $info->from) { - if ($info->required) + if ($info->required) { $required = true; + } $param['description'] = $description; $children[] = $param; } else { @@ -341,31 +299,31 @@ class Explorer implements iProvideMultiVersionApi if (empty($firstChild['children'])) { $description = $firstChild['description']; } else { - $description = '
    '; + $description = ''; //'
    '; foreach ($firstChild['children'] as $child) { $description .= isset($child['required']) && $child['required'] - ? '' . $child['name'] . ' (required)
    ' - : $child['name'] . '
    '; + ? '**' . $child['name'] . '** (required) '.PHP_EOL + : $child['name'] . ' '.PHP_EOL; } - $description .= '
    '; + //$description .= '
    '; } $r[] = $this->parameter(new ValidationInfo($firstChild), $description); } else { - $description = '
    '; + $description = ''; //'
    '; foreach ($children as $child) { - $description .= isset($child['required']) && $child['required'] - ? '' . $child['name'] . ' (required)
    ' - : $child['name'] . '
    '; + $description .= isset($child['required']) && $child['required'] + ? '**' . $child['name'] . '** (required) '.PHP_EOL + : $child['name'] . ' '.PHP_EOL; } - $description .= '
    '; + //$description .= '
    '; //lets group all body parameters under a generated model name - $name = $this->nameModel($route); + $name = $this->modelName($route); $r[] = $this->parameter( new ValidationInfo(array( - 'name' => $name, - 'type' => $name, - 'from' => 'body', + 'name' => $name, + 'type' => $name, + 'from' => 'body', 'required' => $required, 'children' => $children )), @@ -373,196 +331,224 @@ class Explorer implements iProvideMultiVersionApi ); } } + return $r; } private function parameter(ValidationInfo $info, $description = '') { $p = new stdClass(); - if(isset($info->rules['model'])){ - $info->type = $info->rules['model']; + if (isset($info->rules['model'])) { + //$info->type = $info->rules['model']; } $p->name = $info->name; $this->setType($p, $info); if (empty($info->children) || $info->type != 'array') { //primitives - if ($info->default) + if ($info->default) { $p->defaultValue = $info->default; - if ($info->choice) + } + if ($info->choice) { $p->enum = $info->choice; - if ($info->min) + } + if ($info->min) { $p->minimum = $info->min; - if ($info->max) + } + if ($info->max) { $p->maximum = $info->max; + } //TODO: $p->items and $p->uniqueItems boolean } $p->description = $description; - $p->paramType = $info->from; //$info->from == 'body' ? 'form' : $info->from; + $p->in = $info->from; //$info->from == 'body' ? 'form' : $info->from; $p->required = $info->required; - $p->allowMultiple = false; + + //$p->allowMultiple = false; + + if (isset($p->{'$ref'})) { + $p->schema = (object)array('$ref' => ($p->{'$ref'})); + unset($p->{'$ref'}); + } + return $p; } - private function responseMessages(array $route) + private function responses(array $route) { - $r = array(); + $code = '200'; + $r = array( + $code => (object)array( + 'description' => 'Success', + 'schema' => new stdClass() + ) + ); + $return = Util::nestedValue($route, 'metadata', 'return'); + if (!empty($return)) { + $this->setType($r[$code]->schema, new ValidationInfo($return)); + } + if (is_array($throws = Util::nestedValue($route, 'metadata', 'throws'))) { foreach ($throws as $message) { - $m = (object)$message; - //TODO: add $m->responseModel from composer class - $r[] = $m; + $r[$message['code']] = array('description' => $message['message']); } } + return $r; } private function model($type, array $children) { - /** - * Bugfix: - * If we use namespaces, than the model will not be correct, if we use a short name for the type! - * - * Example (phpDoc/annotations in API-class, which uses custom domain-model with namespace): - * @param Car $car {@from body} {@type Aoe\RestServices\Domain\Model\Car} - * @return Car {@type Aoe\RestServices\Domain\Model\Car} - * Than, the model (in swagger-spec) must also be 'Aoe\RestServices\Domain\Model\Car' and not 'Car' - * - * When we use namespaces, than we must use the @type-annotation, otherwise the automatic reconstitution - * from request-data (e.g. when it is a POST-request) to custom domain-model-object will not work! - * - * Summary: - * - When we use no namespaces, than the type would not be changed, if we would call 'Util::getShortName' - * - When we use namespaces, than the model will not be correct, if we would call 'Util::getShortName' - * ...so this method-call is either needless or will create a bug/error - */ - //$type = Util::getShortName($type); - if (isset($this->models[$type])) + if (isset($this->models[$type])) { return $this->models[$type]; + } $r = new stdClass(); - $r->id = $type; - $r->description = "$type Model"; //TODO: enhance this on Router - $r->required = array(); $r->properties = array(); + $required = array(); foreach ($children as $child) { $info = new ValidationInfo($child); $p = new stdClass(); $this->setType($p, $info); $p->description = isset($child['description']) ? $child['description'] : ''; - if ($info->default) + if ($info->default) { $p->defaultValue = $info->default; - if ($info->choice) + } + if ($info->choice) { $p->enum = $info->choice; - if ($info->min) + } + if ($info->min) { $p->minimum = $info->min; - if ($info->max) + } + if ($info->max) { $p->maximum = $info->max; - if ($info->required) - $r->required[] = $info->name; + } + if ($info->required) { + $required[] = $info->name; + } $r->properties[$info->name] = $p; } + if (!empty($required)) { + $r->required = $required; + } //TODO: add $r->subTypes https://github.com/wordnik/swagger-spec/blob/master/versions/1.2.md#527-model-object //TODO: add $r->discriminator https://github.com/wordnik/swagger-spec/blob/master/versions/1.2.md#527-model-object $this->models[$type] = $r; + return $r; } private function setType(&$object, ValidationInfo $info) { //TODO: proper type management + $type = Util::getShortName($info->type); if ($info->type == 'array') { + $object->type = 'array'; if ($info->children) { - $this->model($info->contentType, $info->children); + $contentType = Util::getShortName($info->contentType); + $model = $this->model($contentType, $info->children); $object->items = (object)array( - '$ref' => $info->contentType + '$ref' => "#/definitions/$contentType" ); } elseif ($info->contentType && $info->contentType == 'associative') { unset($info->contentType); $this->model($info->type = 'Object', array( array( - 'name' => 'property', - 'type' => 'string', - 'default' => '', - 'required' => false, + 'name' => 'property', + 'type' => 'string', + 'default' => '', + 'required' => false, 'description' => '' ) )); } elseif ($info->contentType && $info->contentType != 'indexed') { - $object->items = (object)array( - 'type' => $info->contentType - ); + if (is_string($info->contentType) && $t = Util::nestedValue(static::$dataTypeAlias, + strtolower($info->contentType))) { + if (is_array($t)) { + $object->items = (object)array( + 'type' => $t[0], + 'format' => $t[1], + ); + } else { + $object->items = (object)array( + 'type' => $t, + ); + } + } else { + $contentType = Util::getShortName($info->contentType); + $object->items = (object)array( + '$ref' => "#/definitions/$contentType" + ); + } } else { $object->items = (object)array( 'type' => 'string' ); } } elseif ($info->children) { - $this->model($info->type, $info->children); + $this->model($type, $info->children); + $object->{'$ref'} = "#/definitions/$type"; } elseif (is_string($info->type) && $t = Util::nestedValue(static::$dataTypeAlias, strtolower($info->type))) { if (is_array($t)) { - list($info->type, $object->format) = $t; + $object->type = $t[0]; + $object->format = $t[1]; } else { - $info->type = $t; + $object->type = $t; } } else { - $info->type = 'string'; + $object->type = 'string'; } - $object->type = $info->type; $has64bit = PHP_INT_MAX > 2147483647; - if ($object->type == 'integer') { - $object->format = $has64bit - ? 'int64' - : 'int32'; - } elseif ($object->type == 'number') { - $object->format = $has64bit - ? 'double' - : 'float'; + if (isset($object->type)) { + if ($object->type == 'integer') { + $object->format = $has64bit + ? 'int64' + : 'int32'; + } elseif ($object->type == 'number') { + $object->format = $has64bit + ? 'double' + : 'float'; + } } } - private function nickname(array $route) + private function operationId(array $route) { static $hash = array(); + $id = $route['httpMethod'] . ' ' . $route['url']; + if (isset($hash[$id])) { + return $hash[$id]; + } + $class = Util::getShortName($route['className']); $method = $route['methodName']; + if (isset(static::$prefixes[$method])) { - $method = static::$prefixes[$method]; + $method = static::$prefixes[$method] . $class; } else { $method = str_replace( array_keys(static::$prefixes), array_values(static::$prefixes), $method ); + $method = lcfirst($class) . ucfirst($method); } - while (isset($hash[$method]) && $route['url'] != $hash[$method]) { - //create another one - $method .= '_'; - } - $hash[$method] = $route['url']; + $hash[$id] = $method; + return $method; } - private function nameModel(array $route) + private function modelName(array $route) { - static $hash = array(); - $count = 1; - //$name = str_replace('/', '-', $route['url']) . 'Model'; - $name = $route['className'] . 'Model'; - while (isset($hash[$name . $count])) { - //create another one - $count++; - } - $name .= $count; - $hash[$name] = $route['url']; - return $name; + return $this->operationId($route) . 'Model'; } - private function authorizations() + private function securityDefinitions() { $r = new stdClass(); - $r->apiKey = (object)array( + $r->api_key = (object)array( 'type' => 'apiKey', - 'passAs' => 'query', - 'keyname' => 'api_key', + 'name' => 'api_key', + 'in' => 'query', ); + return $r; } diff --git a/htdocs/includes/restler/framework/Luracast/Restler/ExplorerInfo.php b/htdocs/includes/restler/framework/Luracast/Restler/ExplorerInfo.php index 41d969f65d9..b55c5943fed 100644 --- a/htdocs/includes/restler/framework/Luracast/Restler/ExplorerInfo.php +++ b/htdocs/includes/restler/framework/Luracast/Restler/ExplorerInfo.php @@ -2,16 +2,22 @@ /** * Class ExplorerInfo - * @package Luracast\Restler - * + * @package Luracast\Restler + * * @version 3.0.0rc6 */ class ExplorerInfo { public static $title = 'Restler API Explorer'; public static $description = 'Live API Documentation'; - public static $termsOfServiceUrl = null; - public static $contact = 'arul@luracast.com'; - public static $license = 'LGPL-2.1'; - public static $licenseUrl = 'https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html'; + public static $termsOfService = null; + public static $contact = array( + 'name' => 'Restler Support', + 'url' => 'luracast.com/products/restler', + 'email' => 'arul@luracast.com', + ); + public static $license = array( + 'name' => 'LGPL-2.1', + 'url' => 'https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html', + ); } \ No newline at end of file diff --git a/htdocs/includes/restler/framework/Luracast/Restler/Format/CsvFormat.php b/htdocs/includes/restler/framework/Luracast/Restler/Format/CsvFormat.php index d6cdb63a943..4bed88251c8 100644 --- a/htdocs/includes/restler/framework/Luracast/Restler/Format/CsvFormat.php +++ b/htdocs/includes/restler/framework/Luracast/Restler/Format/CsvFormat.php @@ -2,7 +2,7 @@ namespace Luracast\Restler\Format; -use Luracast\Restler\Data\Object; +use Luracast\Restler\Data\Obj; use Luracast\Restler\RestException; /** @@ -44,10 +44,10 @@ class CsvFormat extends Format implements iDecodeStream */ public function encode($data, $humanReadable = false) { - $char = Object::$separatorChar; - Object::$separatorChar = false; - $data = Object::toArray($data); - Object::$separatorChar = $char; + $char = Obj::$separatorChar; + Obj::$separatorChar = false; + $data = Obj::toArray($data); + Obj::$separatorChar = $char; if (is_array($data) && array_values($data) == $data) { //if indexed array $lines = array(); @@ -109,10 +109,10 @@ class CsvFormat extends Format implements iDecodeStream while (($row = static::getRow(array_shift($lines), $keys)) !== FALSE) $decoded [] = $row; - $char = Object::$separatorChar; - Object::$separatorChar = false; - $decoded = Object::toArray($decoded); - Object::$separatorChar = $char; + $char = Obj::$separatorChar; + Obj::$separatorChar = false; + $decoded = Obj::toArray($decoded); + Obj::$separatorChar = $char; return $decoded; } @@ -172,10 +172,10 @@ class CsvFormat extends Format implements iDecodeStream while (($row = static::getRow(stream_get_line($stream, 0, PHP_EOL), $keys)) !== FALSE) $decoded [] = $row; - $char = Object::$separatorChar; - Object::$separatorChar = false; - $decoded = Object::toArray($decoded); - Object::$separatorChar = $char; + $char = Obj::$separatorChar; + Obj::$separatorChar = false; + $decoded = Obj::toArray($decoded); + Obj::$separatorChar = $char; return $decoded; } } \ No newline at end of file diff --git a/htdocs/includes/restler/framework/Luracast/Restler/Format/HtmlFormat.php b/htdocs/includes/restler/framework/Luracast/Restler/Format/HtmlFormat.php index 6e7d4b7303e..e871186c446 100644 --- a/htdocs/includes/restler/framework/Luracast/Restler/Format/HtmlFormat.php +++ b/htdocs/includes/restler/framework/Luracast/Restler/Format/HtmlFormat.php @@ -11,7 +11,7 @@ use Illuminate\View\Engines\EngineResolver; use Illuminate\View\Factory; use Illuminate\View\FileViewFinder; use Illuminate\View\View; -use Luracast\Restler\Data\Object; +use Luracast\Restler\Data\Obj; use Luracast\Restler\Defaults; use Luracast\Restler\RestException; use Luracast\Restler\Restler; @@ -315,7 +315,7 @@ class HtmlFormat extends DependentFormat $error = $success ? null : $exception->getMessage(); $data = array( 'response' => static::$convertResponseToArray - ? Object::toArray($data) + ? Obj::toArray($data) : $data, 'stages' => $this->restler->getEvents(), 'success' => $success, diff --git a/htdocs/includes/restler/framework/Luracast/Restler/Format/JsonFormat.php b/htdocs/includes/restler/framework/Luracast/Restler/Format/JsonFormat.php index 6986ce65c90..28dfd560969 100644 --- a/htdocs/includes/restler/framework/Luracast/Restler/Format/JsonFormat.php +++ b/htdocs/includes/restler/framework/Luracast/Restler/Format/JsonFormat.php @@ -1,7 +1,7 @@ handleJsonError(); return $result; } - $result = json_encode(Object::toArray($data, true)); + $result = json_encode(Obj::toArray($data, true)); $this->handleJsonError(); if ($humanReadable) { @@ -116,6 +127,10 @@ class JsonFormat extends Format public function decode($data) { + if(empty($data)){ + return null; + } + $options = 0; if (self::$bigIntAsString) { if ((PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) // PHP >= 5.4 @@ -142,7 +157,7 @@ class JsonFormat extends Format throw new RestException(400, 'Error parsing JSON'); } - return Object::toArray($decoded); + return Obj::toArray($decoded); } /** @@ -259,4 +274,4 @@ class JsonFormat extends Format throw new \RuntimeException('Error encoding/decoding JSON: '. $message); } } -} \ No newline at end of file +} diff --git a/htdocs/includes/restler/framework/Luracast/Restler/Format/PlistFormat.php b/htdocs/includes/restler/framework/Luracast/Restler/Format/PlistFormat.php index 2f4faa0769f..cc07066a33c 100644 --- a/htdocs/includes/restler/framework/Luracast/Restler/Format/PlistFormat.php +++ b/htdocs/includes/restler/framework/Luracast/Restler/Format/PlistFormat.php @@ -1,7 +1,7 @@ toCFType( - Object::toArray($data) + Obj::toArray($data) ); $plist->add($guessedStructure); diff --git a/htdocs/includes/restler/framework/Luracast/Restler/Format/UploadFormat.php b/htdocs/includes/restler/framework/Luracast/Restler/Format/UploadFormat.php index f785beeaa02..de41bf98c71 100644 --- a/htdocs/includes/restler/framework/Luracast/Restler/Format/UploadFormat.php +++ b/htdocs/includes/restler/framework/Luracast/Restler/Format/UploadFormat.php @@ -25,7 +25,9 @@ class UploadFormat extends Format 2 => "The uploaded file exceeds the maximum allowed size", 3 => "The uploaded file was only partially uploaded", 4 => "No file was uploaded", - 6 => "Missing a temporary folder" + 6 => "Missing a temporary folder", + 7 => "Failed to write file to disk", + 8 => "A PHP extension stopped the file upload" ); /** * use it if you need to restrict uploads based on file type diff --git a/htdocs/includes/restler/framework/Luracast/Restler/Format/XmlFormat.php b/htdocs/includes/restler/framework/Luracast/Restler/Format/XmlFormat.php index b006409e800..b51fa707a53 100644 --- a/htdocs/includes/restler/framework/Luracast/Restler/Format/XmlFormat.php +++ b/htdocs/includes/restler/framework/Luracast/Restler/Format/XmlFormat.php @@ -1,7 +1,7 @@ openMemory(); $xml->startDocument('1.0', $this->charset); diff --git a/htdocs/includes/restler/framework/Luracast/Restler/Format/YamlFormat.php b/htdocs/includes/restler/framework/Luracast/Restler/Format/YamlFormat.php index 0cb1564f4ed..07baae88b6f 100644 --- a/htdocs/includes/restler/framework/Luracast/Restler/Format/YamlFormat.php +++ b/htdocs/includes/restler/framework/Luracast/Restler/Format/YamlFormat.php @@ -2,7 +2,7 @@ namespace Luracast\Restler\Format; use Symfony\Component\Yaml\Yaml; -use Luracast\Restler\Data\Object; +use Luracast\Restler\Data\Obj; /** * YAML Format for Restler Framework @@ -26,7 +26,7 @@ class YamlFormat extends DependentFormat public function encode($data, $humanReadable = false) { - return @Yaml::dump(Object::toArray($data), $humanReadable ? 10 : 4); + return @Yaml::dump(Obj::toArray($data), $humanReadable ? 10 : 4); } public function decode($data) diff --git a/htdocs/includes/restler/framework/Luracast/Restler/PassThrough.php b/htdocs/includes/restler/framework/Luracast/Restler/PassThrough.php index e1fc21eae6b..a77e533b722 100644 --- a/htdocs/includes/restler/framework/Luracast/Restler/PassThrough.php +++ b/htdocs/includes/restler/framework/Luracast/Restler/PassThrough.php @@ -34,7 +34,6 @@ class PassThrough * @param bool $isPublic cache control, is it public or private * * @throws RestException - * @internal param string $pragma * */ public static function file($filename, $forceDownload = false, $expires = 0, $isPublic = true) diff --git a/htdocs/includes/restler/framework/Luracast/Restler/Restler.php b/htdocs/includes/restler/framework/Luracast/Restler/Restler.php index 0cef46a7e41..c2e9b1acb73 100644 --- a/htdocs/includes/restler/framework/Luracast/Restler/Restler.php +++ b/htdocs/includes/restler/framework/Luracast/Restler/Restler.php @@ -538,7 +538,7 @@ class Restler extends EventDispatcher if ($version && $version <= $this->apiVersion) { $this->requestedApiVersion = $version; $path = explode('/', $path, 2); - $path = $path[1]; + $path = count($path) == 2 ? $path[1] : ''; } } else { $this->requestedApiVersion = $this->apiMinimumVersion; @@ -718,7 +718,8 @@ class Restler extends EventDispatcher . $_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']); header('Access-Control-Allow-Origin: ' . - (Defaults::$accessControlAllowOrigin == '*' ? $_SERVER['HTTP_ORIGIN'] : Defaults::$accessControlAllowOrigin)); + ((Defaults::$accessControlAllowOrigin == '*' && isset($_SERVER['HTTP_ORIGIN'])) + ? $_SERVER['HTTP_ORIGIN'] : Defaults::$accessControlAllowOrigin)); header('Access-Control-Allow-Credentials: true'); exit(0); @@ -1195,7 +1196,7 @@ class Restler extends EventDispatcher foreach ($this->errorClasses as $className) { if (method_exists($className, $method)) { $obj = Scope::get($className); - if ($obj->$method()) + if ($obj->$method($exception)) $handled = true; } } @@ -1397,6 +1398,135 @@ class Restler extends EventDispatcher $this->errorClasses[] = $className; } + /** + * protected methods will need at least one authentication class to be set + * in order to allow that method to be executed. When multiple authentication + * classes are in use, this function provides better performance by setting + * all auth classes through a single function call. + * + * @param array $classNames array of associative arrays containing + * the authentication class name & optional + * url prefix for mapping. + */ + public function setAuthClasses(array $classNames) + { + $this->authClasses = array_merge($this->authClasses, array_values($classNames)); + } + + /** + * Add multiple api classes through this method. + * + * This method provides better performance when large number + * of API classes are in use as it processes them all at once, + * as opposed to hundreds (or more) addAPIClass calls. + * + * + * All the public methods that do not start with _ (underscore) + * will be will be exposed as the public api by default. + * + * All the protected methods that do not start with _ (underscore) + * will exposed as protected api which will require authentication + * + * @param array $map array of associative arrays containing + * the class name & optional url prefix + * for mapping. + * + * @return null + * + * @throws Exception when supplied with invalid class name + */ + public function mapAPIClasses(array $map) + { + try { + if ($this->productionMode && is_null($this->cached)) { + $routes = $this->cache->get('routes'); + if (isset($routes) && is_array($routes)) { + $this->apiVersionMap = $routes['apiVersionMap']; + unset($routes['apiVersionMap']); + Routes::fromArray($routes); + $this->cached = true; + } else { + $this->cached = false; + } + } + $maxVersionMethod = '__getMaximumSupportedVersion'; + if (!$this->productionMode || !$this->cached) { + foreach ($map as $className => $resourcePath) { + if (is_numeric($className)) { + $className = $resourcePath; + $resourcePath = null; + } + if (isset(Scope::$classAliases[$className])) { + $className = Scope::$classAliases[$className]; + } + if (class_exists($className)) { + if (method_exists($className, $maxVersionMethod)) { + $max = $className::$maxVersionMethod(); + for ($i = 1; $i <= $max; $i++) { + $this->apiVersionMap[$className][$i] = $className; + } + } else { + $this->apiVersionMap[$className][1] = $className; + } + } + //versioned api + if (false !== ($index = strrpos($className, '\\'))) { + $name = substr($className, 0, $index) + . '\\v{$version}' . substr($className, $index); + } else { + if (false !== ($index = strrpos($className, '_'))) { + $name = substr($className, 0, $index) + . '_v{$version}' . substr($className, $index); + } else { + $name = 'v{$version}\\' . $className; + } + } + + for ($version = $this->apiMinimumVersion; + $version <= $this->apiVersion; + $version++) { + + $versionedClassName = str_replace('{$version}', $version, + $name); + if (class_exists($versionedClassName)) { + Routes::addAPIClass($versionedClassName, + Util::getResourcePath( + $className, + $resourcePath + ), + $version + ); + if (method_exists($versionedClassName, $maxVersionMethod)) { + $max = $versionedClassName::$maxVersionMethod(); + for ($i = $version; $i <= $max; $i++) { + $this->apiVersionMap[$className][$i] = $versionedClassName; + } + } else { + $this->apiVersionMap[$className][$version] = $versionedClassName; + } + } elseif (isset($this->apiVersionMap[$className][$version])) { + Routes::addAPIClass($this->apiVersionMap[$className][$version], + Util::getResourcePath( + $className, + $resourcePath + ), + $version + ); + } + } + } + } + } catch (Exception $e) { + $e = new Exception( + "mapAPIClasses failed. " . $e->getMessage(), + $e->getCode(), + $e + ); + $this->setSupportedFormats('JsonFormat'); + $this->message($e); + } + } + /** * Associated array that maps formats to their respective format class name * @@ -1484,6 +1614,19 @@ class Restler extends EventDispatcher public function __destruct() { if ($this->productionMode && !$this->cached) { + if (empty($this->url) && empty($this->requestMethod)) { + // url and requestMethod is NOT set: + // This can only happen, when an exception was thrown outside of restler, so that the method Restler::handle was NOT called. + // In this case, the routes can now be corrupt/incomplete, because we don't know, if all API-classes could be registered + // before the exception was thrown. So, don't cache the routes, because the routes can now be corrupt/incomplete! + return; + } + if ($this->exception instanceof RestException && $this->exception->getStage() === 'setup') { + // An exception has occured during configuration of restler. Maybe we could not add all API-classes correctly! + // So, don't cache the routes, because the routes can now be corrupt/incomplete! + return; + } + $this->cache->set( 'routes', Routes::toArray() + diff --git a/htdocs/includes/restler/framework/Luracast/Restler/Routes.php b/htdocs/includes/restler/framework/Luracast/Restler/Routes.php index 067603a0f58..73e78dc0039 100644 --- a/htdocs/includes/restler/framework/Luracast/Restler/Routes.php +++ b/htdocs/includes/restler/framework/Luracast/Restler/Routes.php @@ -293,8 +293,6 @@ class Routes } $url = empty($methodUrl) ? rtrim($resourcePath, '/') : $resourcePath . $methodUrl; - $lastPathParam = array_keys($pathParams); - $lastPathParam = end($lastPathParam); for ($position = 0; $position < count($params); $position++) { $from = $metadata['param'][$position][$dataName]['from']; if ($from == 'body' && ($httpMethod == 'GET' || @@ -307,6 +305,7 @@ class Routes if (empty($pathParams) || $allowAmbiguity) { static::addPath($url, $call, $httpMethod, $version); } + $lastPathParam = end($pathParams); foreach ($pathParams as $position) { if (!empty($url)) $url .= '/'; diff --git a/htdocs/includes/restler/framework/Luracast/Restler/Scope.php b/htdocs/includes/restler/framework/Luracast/Restler/Scope.php index 91eea3ef6a1..fd4b41ff98d 100644 --- a/htdocs/includes/restler/framework/Luracast/Restler/Scope.php +++ b/htdocs/includes/restler/framework/Luracast/Restler/Scope.php @@ -52,7 +52,7 @@ class Scope 'MemcacheCache' => 'Luracast\Restler\MemcacheCache', //Utility classes - 'Object' => 'Luracast\Restler\Data\Object', + 'Obj' => 'Luracast\Restler\Data\Obj', 'Text' => 'Luracast\Restler\Data\Text', 'Arr' => 'Luracast\Restler\Data\Arr', @@ -194,6 +194,11 @@ class Scope { if (empty($className) || !is_string($className)) return false; + + if (self::isPrimitiveDataType($className)) { + return false; + } + $divider = '\\'; $qualified = false; if ($className{0} == $divider) { @@ -212,4 +217,14 @@ class Scope } return false; } + + /** + * @param string $stringName + * @return boolean + */ + private static function isPrimitiveDataType($stringName) + { + $primitiveDataTypes = array('Array', 'array', 'bool', 'boolean', 'float', 'int', 'integer', 'string'); + return in_array($stringName, $primitiveDataTypes); + } } diff --git a/htdocs/includes/restler/framework/Luracast/Restler/Util.php b/htdocs/includes/restler/framework/Luracast/Restler/Util.php index e1c6f60c317..e7324a3a620 100644 --- a/htdocs/includes/restler/framework/Luracast/Restler/Util.php +++ b/htdocs/includes/restler/framework/Luracast/Restler/Util.php @@ -226,6 +226,10 @@ class Util public static function getShortName($className) { + // @CHANGE LDR + if (! is_string($className)) return ''; + //var_dump($className); + $className = explode('\\', $className); return end($className); } diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/css/print.css b/htdocs/includes/restler/framework/Luracast/Restler/explorer/css/print.css new file mode 100644 index 00000000000..2e6b310300b --- /dev/null +++ b/htdocs/includes/restler/framework/Luracast/Restler/explorer/css/print.css @@ -0,0 +1,1187 @@ +/* Original style from softwaremaniacs.org (c) Ivan Sagalaev */ +.swagger-section pre code { + display: block; + padding: 0.5em; + background: #F0F0F0; +} +.swagger-section pre code, +.swagger-section pre .subst, +.swagger-section pre .tag .title, +.swagger-section pre .lisp .title, +.swagger-section pre .clojure .built_in, +.swagger-section pre .nginx .title { + color: black; +} +.swagger-section pre .string, +.swagger-section pre .title, +.swagger-section pre .constant, +.swagger-section pre .parent, +.swagger-section pre .tag .value, +.swagger-section pre .rules .value, +.swagger-section pre .rules .value .number, +.swagger-section pre .preprocessor, +.swagger-section pre .ruby .symbol, +.swagger-section pre .ruby .symbol .string, +.swagger-section pre .aggregate, +.swagger-section pre .template_tag, +.swagger-section pre .django .variable, +.swagger-section pre .smalltalk .class, +.swagger-section pre .addition, +.swagger-section pre .flow, +.swagger-section pre .stream, +.swagger-section pre .bash .variable, +.swagger-section pre .apache .tag, +.swagger-section pre .apache .cbracket, +.swagger-section pre .tex .command, +.swagger-section pre .tex .special, +.swagger-section pre .erlang_repl .function_or_atom, +.swagger-section pre .markdown .header { + color: #800; +} +.swagger-section pre .comment, +.swagger-section pre .annotation, +.swagger-section pre .template_comment, +.swagger-section pre .diff .header, +.swagger-section pre .chunk, +.swagger-section pre .markdown .blockquote { + color: #888; +} +.swagger-section pre .number, +.swagger-section pre .date, +.swagger-section pre .regexp, +.swagger-section pre .literal, +.swagger-section pre .smalltalk .symbol, +.swagger-section pre .smalltalk .char, +.swagger-section pre .go .constant, +.swagger-section pre .change, +.swagger-section pre .markdown .bullet, +.swagger-section pre .markdown .link_url { + color: #080; +} +.swagger-section pre .label, +.swagger-section pre .javadoc, +.swagger-section pre .ruby .string, +.swagger-section pre .decorator, +.swagger-section pre .filter .argument, +.swagger-section pre .localvars, +.swagger-section pre .array, +.swagger-section pre .attr_selector, +.swagger-section pre .important, +.swagger-section pre .pseudo, +.swagger-section pre .pi, +.swagger-section pre .doctype, +.swagger-section pre .deletion, +.swagger-section pre .envvar, +.swagger-section pre .shebang, +.swagger-section pre .apache .sqbracket, +.swagger-section pre .nginx .built_in, +.swagger-section pre .tex .formula, +.swagger-section pre .erlang_repl .reserved, +.swagger-section pre .prompt, +.swagger-section pre .markdown .link_label, +.swagger-section pre .vhdl .attribute, +.swagger-section pre .clojure .attribute, +.swagger-section pre .coffeescript .property { + color: #8888ff; +} +.swagger-section pre .keyword, +.swagger-section pre .id, +.swagger-section pre .phpdoc, +.swagger-section pre .title, +.swagger-section pre .built_in, +.swagger-section pre .aggregate, +.swagger-section pre .css .tag, +.swagger-section pre .javadoctag, +.swagger-section pre .phpdoc, +.swagger-section pre .yardoctag, +.swagger-section pre .smalltalk .class, +.swagger-section pre .winutils, +.swagger-section pre .bash .variable, +.swagger-section pre .apache .tag, +.swagger-section pre .go .typename, +.swagger-section pre .tex .command, +.swagger-section pre .markdown .strong, +.swagger-section pre .request, +.swagger-section pre .status { + font-weight: bold; +} +.swagger-section pre .markdown .emphasis { + font-style: italic; +} +.swagger-section pre .nginx .built_in { + font-weight: normal; +} +.swagger-section pre .coffeescript .javascript, +.swagger-section pre .javascript .xml, +.swagger-section pre .tex .formula, +.swagger-section pre .xml .javascript, +.swagger-section pre .xml .vbscript, +.swagger-section pre .xml .css, +.swagger-section pre .xml .cdata { + opacity: 0.5; +} +.swagger-section .swagger-ui-wrap { + line-height: 1; + font-family: "Droid Sans", sans-serif; + max-width: 960px; + margin-left: auto; + margin-right: auto; + /* JSONEditor specific styling */ +} +.swagger-section .swagger-ui-wrap b, +.swagger-section .swagger-ui-wrap strong { + font-family: "Droid Sans", sans-serif; + font-weight: bold; +} +.swagger-section .swagger-ui-wrap q, +.swagger-section .swagger-ui-wrap blockquote { + quotes: none; +} +.swagger-section .swagger-ui-wrap p { + line-height: 1.4em; + padding: 0 0 10px; + color: #333333; +} +.swagger-section .swagger-ui-wrap q:before, +.swagger-section .swagger-ui-wrap q:after, +.swagger-section .swagger-ui-wrap blockquote:before, +.swagger-section .swagger-ui-wrap blockquote:after { + content: none; +} +.swagger-section .swagger-ui-wrap .heading_with_menu h1, +.swagger-section .swagger-ui-wrap .heading_with_menu h2, +.swagger-section .swagger-ui-wrap .heading_with_menu h3, +.swagger-section .swagger-ui-wrap .heading_with_menu h4, +.swagger-section .swagger-ui-wrap .heading_with_menu h5, +.swagger-section .swagger-ui-wrap .heading_with_menu h6 { + display: block; + clear: none; + float: left; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + width: 60%; +} +.swagger-section .swagger-ui-wrap table { + border-collapse: collapse; + border-spacing: 0; +} +.swagger-section .swagger-ui-wrap table thead tr th { + padding: 5px; + font-size: 0.9em; + color: #666666; + border-bottom: 1px solid #999999; +} +.swagger-section .swagger-ui-wrap table tbody tr:last-child td { + border-bottom: none; +} +.swagger-section .swagger-ui-wrap table tbody tr.offset { + background-color: #f0f0f0; +} +.swagger-section .swagger-ui-wrap table tbody tr td { + padding: 6px; + font-size: 0.9em; + border-bottom: 1px solid #cccccc; + vertical-align: top; + line-height: 1.3em; +} +.swagger-section .swagger-ui-wrap ol { + margin: 0px 0 10px; + padding: 0 0 0 18px; + list-style-type: decimal; +} +.swagger-section .swagger-ui-wrap ol li { + padding: 5px 0px; + font-size: 0.9em; + color: #333333; +} +.swagger-section .swagger-ui-wrap ol, +.swagger-section .swagger-ui-wrap ul { + list-style: none; +} +.swagger-section .swagger-ui-wrap h1 a, +.swagger-section .swagger-ui-wrap h2 a, +.swagger-section .swagger-ui-wrap h3 a, +.swagger-section .swagger-ui-wrap h4 a, +.swagger-section .swagger-ui-wrap h5 a, +.swagger-section .swagger-ui-wrap h6 a { + text-decoration: none; +} +.swagger-section .swagger-ui-wrap h1 a:hover, +.swagger-section .swagger-ui-wrap h2 a:hover, +.swagger-section .swagger-ui-wrap h3 a:hover, +.swagger-section .swagger-ui-wrap h4 a:hover, +.swagger-section .swagger-ui-wrap h5 a:hover, +.swagger-section .swagger-ui-wrap h6 a:hover { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap h1 span.divider, +.swagger-section .swagger-ui-wrap h2 span.divider, +.swagger-section .swagger-ui-wrap h3 span.divider, +.swagger-section .swagger-ui-wrap h4 span.divider, +.swagger-section .swagger-ui-wrap h5 span.divider, +.swagger-section .swagger-ui-wrap h6 span.divider { + color: #aaaaaa; +} +.swagger-section .swagger-ui-wrap a { + color: #547f00; +} +.swagger-section .swagger-ui-wrap a img { + border: none; +} +.swagger-section .swagger-ui-wrap article, +.swagger-section .swagger-ui-wrap aside, +.swagger-section .swagger-ui-wrap details, +.swagger-section .swagger-ui-wrap figcaption, +.swagger-section .swagger-ui-wrap figure, +.swagger-section .swagger-ui-wrap footer, +.swagger-section .swagger-ui-wrap header, +.swagger-section .swagger-ui-wrap hgroup, +.swagger-section .swagger-ui-wrap menu, +.swagger-section .swagger-ui-wrap nav, +.swagger-section .swagger-ui-wrap section, +.swagger-section .swagger-ui-wrap summary { + display: block; +} +.swagger-section .swagger-ui-wrap pre { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + background-color: #fcf6db; + border: 1px solid #e5e0c6; + padding: 10px; +} +.swagger-section .swagger-ui-wrap pre code { + line-height: 1.6em; + background: none; +} +.swagger-section .swagger-ui-wrap .content > .content-type > div > label { + clear: both; + display: block; + color: #0F6AB4; + font-size: 1.1em; + margin: 0; + padding: 15px 0 5px; +} +.swagger-section .swagger-ui-wrap .content pre { + font-size: 12px; + margin-top: 5px; + padding: 5px; +} +.swagger-section .swagger-ui-wrap .icon-btn { + cursor: pointer; +} +.swagger-section .swagger-ui-wrap .info_title { + padding-bottom: 10px; + font-weight: bold; + font-size: 25px; +} +.swagger-section .swagger-ui-wrap .footer { + margin-top: 20px; +} +.swagger-section .swagger-ui-wrap p.big, +.swagger-section .swagger-ui-wrap div.big p { + font-size: 1em; + margin-bottom: 10px; +} +.swagger-section .swagger-ui-wrap form.fullwidth ol li.string input, +.swagger-section .swagger-ui-wrap form.fullwidth ol li.url input, +.swagger-section .swagger-ui-wrap form.fullwidth ol li.text textarea, +.swagger-section .swagger-ui-wrap form.fullwidth ol li.numeric input { + width: 500px !important; +} +.swagger-section .swagger-ui-wrap .info_license { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_tos { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .message-fail { + color: #cc0000; +} +.swagger-section .swagger-ui-wrap .info_url { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_email { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_name { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_description { + padding-bottom: 10px; + font-size: 15px; +} +.swagger-section .swagger-ui-wrap .markdown ol li, +.swagger-section .swagger-ui-wrap .markdown ul li { + padding: 3px 0px; + line-height: 1.4em; + color: #333333; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.string input, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.url input, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.numeric input { + display: block; + padding: 4px; + width: auto; + clear: both; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.string input.title, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.url input.title, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.numeric input.title { + font-size: 1.3em; +} +.swagger-section .swagger-ui-wrap table.fullwidth { + width: 100%; +} +.swagger-section .swagger-ui-wrap .model-signature { + font-family: "Droid Sans", sans-serif; + font-size: 1em; + line-height: 1.5em; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-nav a { + text-decoration: none; + color: #AAA; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-nav a:hover { + text-decoration: underline; + color: black; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-nav .selected { + color: black; + text-decoration: none; +} +.swagger-section .swagger-ui-wrap .model-signature .propType { + color: #5555aa; +} +.swagger-section .swagger-ui-wrap .model-signature pre:hover { + background-color: #ffffdd; +} +.swagger-section .swagger-ui-wrap .model-signature pre { + font-size: .85em; + line-height: 1.2em; + overflow: auto; + max-height: 200px; + cursor: pointer; +} +.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav { + display: block; + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav li:last-child { + padding-right: 0; + border-right: none; +} +.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav li { + float: left; + margin: 0 5px 5px 0; + padding: 2px 5px 2px 0; + border-right: 1px solid #ddd; +} +.swagger-section .swagger-ui-wrap .model-signature .propOpt { + color: #555; +} +.swagger-section .swagger-ui-wrap .model-signature .snippet small { + font-size: 0.75em; +} +.swagger-section .swagger-ui-wrap .model-signature .propOptKey { + font-style: italic; +} +.swagger-section .swagger-ui-wrap .model-signature .description .strong { + font-weight: bold; + color: #000; + font-size: .9em; +} +.swagger-section .swagger-ui-wrap .model-signature .description div { + font-size: 0.9em; + line-height: 1.5em; + margin-left: 1em; +} +.swagger-section .swagger-ui-wrap .model-signature .description .stronger { + font-weight: bold; + color: #000; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper { + border-spacing: 0; + position: absolute; + background-color: #ffffff; + border: 1px solid #bbbbbb; + display: none; + font-size: 11px; + max-width: 400px; + line-height: 30px; + color: black; + padding: 5px; + margin-left: 10px; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper th { + text-align: center; + background-color: #eeeeee; + border: 1px solid #bbbbbb; + font-size: 11px; + color: #666666; + font-weight: bold; + padding: 5px; + line-height: 15px; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper .optionName { + font-weight: bold; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown > p:first-child, +.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown > p:last-child { + display: inline; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown > p:not(:first-child):before { + display: block; + content: ''; +} +.swagger-section .swagger-ui-wrap .model-signature .description span:last-of-type.propDesc.markdown > p:only-child { + margin-right: -3px; +} +.swagger-section .swagger-ui-wrap .model-signature .propName { + font-weight: bold; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-container { + clear: both; +} +.swagger-section .swagger-ui-wrap .body-textarea { + width: 300px; + height: 100px; + border: 1px solid #aaa; +} +.swagger-section .swagger-ui-wrap .markdown p code, +.swagger-section .swagger-ui-wrap .markdown li code { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + background-color: #f0f0f0; + color: black; + padding: 1px 3px; +} +.swagger-section .swagger-ui-wrap .required { + font-weight: bold; +} +.swagger-section .swagger-ui-wrap .editor_holder { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap .editor_holder label { + font-weight: normal!important; + /* JSONEditor uses bold by default for all labels, we revert that back to normal to not give the impression that by default fields are required */ +} +.swagger-section .swagger-ui-wrap .editor_holder label.required { + font-weight: bold!important; +} +.swagger-section .swagger-ui-wrap input.parameter { + width: 300px; + border: 1px solid #aaa; +} +.swagger-section .swagger-ui-wrap h1 { + color: black; + font-size: 1.5em; + line-height: 1.3em; + padding: 10px 0 10px 0; + font-family: "Droid Sans", sans-serif; + font-weight: bold; +} +.swagger-section .swagger-ui-wrap .heading_with_menu { + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap .heading_with_menu ul { + display: block; + clear: none; + float: right; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + margin-top: 10px; +} +.swagger-section .swagger-ui-wrap h2 { + color: black; + font-size: 1.3em; + padding: 10px 0 10px 0; +} +.swagger-section .swagger-ui-wrap h2 a { + color: black; +} +.swagger-section .swagger-ui-wrap h2 span.sub { + font-size: 0.7em; + color: #999999; + font-style: italic; +} +.swagger-section .swagger-ui-wrap h2 span.sub a { + color: #777777; +} +.swagger-section .swagger-ui-wrap span.weak { + color: #666666; +} +.swagger-section .swagger-ui-wrap .message-success { + color: #89BF04; +} +.swagger-section .swagger-ui-wrap caption, +.swagger-section .swagger-ui-wrap th, +.swagger-section .swagger-ui-wrap td { + text-align: left; + font-weight: normal; + vertical-align: middle; +} +.swagger-section .swagger-ui-wrap .code { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.text textarea { + font-family: "Droid Sans", sans-serif; + height: 250px; + padding: 4px; + display: block; + clear: both; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.select select { + display: block; + clear: both; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean { + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean label { + display: block; + float: left; + clear: none; + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean input { + display: block; + float: left; + clear: none; + margin: 0 5px 0 0; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.required label { + color: black; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li label { + display: block; + clear: both; + width: auto; + padding: 0 0 3px; + color: #666666; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li label abbr { + padding-left: 3px; + color: #888888; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li p.inline-hints { + margin-left: 0; + font-style: italic; + font-size: 0.9em; + margin: 0; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.buttons { + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap span.blank, +.swagger-section .swagger-ui-wrap span.empty { + color: #888888; + font-style: italic; +} +.swagger-section .swagger-ui-wrap .markdown h3 { + color: #547f00; +} +.swagger-section .swagger-ui-wrap .markdown h4 { + color: #666666; +} +.swagger-section .swagger-ui-wrap .markdown pre { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + background-color: #fcf6db; + border: 1px solid #e5e0c6; + padding: 10px; + margin: 0 0 10px 0; +} +.swagger-section .swagger-ui-wrap .markdown pre code { + line-height: 1.6em; +} +.swagger-section .swagger-ui-wrap div.gist { + margin: 20px 0 25px 0 !important; +} +.swagger-section .swagger-ui-wrap ul#resources { + font-family: "Droid Sans", sans-serif; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource { + border-bottom: 1px solid #dddddd; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource:hover div.heading h2 a, +.swagger-section .swagger-ui-wrap ul#resources li.resource.active div.heading h2 a { + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource:hover div.heading ul.options li a, +.swagger-section .swagger-ui-wrap ul#resources li.resource.active div.heading ul.options li a { + color: #555555; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource:last-child { + border-bottom: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading { + border: 1px solid transparent; + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options { + overflow: hidden; + padding: 0; + display: block; + clear: none; + float: right; + margin: 14px 10px 0 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li { + float: left; + clear: none; + margin: 0; + padding: 2px 10px; + border-right: 1px solid #dddddd; + color: #666666; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a { + color: #aaaaaa; + text-decoration: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:hover { + text-decoration: underline; + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:hover, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:active, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a.active { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li.last { + padding-right: 0; + border-right: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 { + color: #999999; + padding-left: 0; + display: block; + clear: none; + float: left; + font-family: "Droid Sans", sans-serif; + font-weight: bold; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a { + color: #999999; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a:hover { + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation { + float: none; + clear: both; + overflow: hidden; + display: block; + margin: 0 0 10px; + padding: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading { + float: none; + clear: both; + overflow: hidden; + display: block; + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 { + display: block; + clear: none; + float: left; + width: auto; + margin: 0; + padding: 0; + line-height: 1.1em; + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path { + padding-left: 10px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a { + color: black; + text-decoration: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a:hover { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.http_method a { + text-transform: uppercase; + text-decoration: none; + color: white; + display: inline-block; + width: 50px; + font-size: 0.7em; + text-align: center; + padding: 7px 0 4px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + -o-border-radius: 2px; + -ms-border-radius: 2px; + -khtml-border-radius: 2px; + border-radius: 2px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span { + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options { + overflow: hidden; + padding: 0; + display: block; + clear: none; + float: right; + margin: 6px 10px 0 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li { + float: left; + clear: none; + margin: 0; + padding: 2px 10px; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li a { + text-decoration: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li.access { + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content { + border-top: none; + padding: 10px; + -moz-border-radius-bottomleft: 6px; + -webkit-border-bottom-left-radius: 6px; + -o-border-bottom-left-radius: 6px; + -ms-border-bottom-left-radius: 6px; + -khtml-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -moz-border-radius-bottomright: 6px; + -webkit-border-bottom-right-radius: 6px; + -o-border-bottom-right-radius: 6px; + -ms-border-bottom-right-radius: 6px; + -khtml-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + margin: 0 0 20px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content h4 { + font-size: 1.1em; + margin: 0; + padding: 15px 0 5px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header { + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header a { + padding: 4px 0 0 10px; + display: inline-block; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header input.submit { + display: block; + clear: none; + float: left; + padding: 6px 8px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header span.response_throbber { + background-image: url('../images/throbber.gif'); + width: 128px; + height: 16px; + display: block; + clear: none; + float: right; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content form input[type='text'].error { + outline: 2px solid black; + outline-color: #cc0000; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content form select[name='parameterContentType'] { + max-width: 300px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.response div.block pre { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + padding: 10px; + font-size: 0.9em; + max-height: 400px; + overflow-y: auto; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading { + background-color: #f9f2e9; + border: 1px solid #f0e0ca; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.http_method a { + background-color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #f0e0ca; + color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a { + color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content { + background-color: #faf5ee; + border: 1px solid #f0e0ca; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content h4 { + color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header a { + color: #dcb67f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading { + background-color: #fcffcd; + border: 1px solid black; + border-color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span.http_method a { + text-transform: uppercase; + background-color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #ffd20f; + color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li a { + color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content { + background-color: #fcffcd; + border: 1px solid black; + border-color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content h4 { + color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.sandbox_header a { + color: #6fc992; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading { + background-color: #f5e8e8; + border: 1px solid #e8c6c7; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.http_method a { + text-transform: uppercase; + background-color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #e8c6c7; + color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a { + color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content { + background-color: #f7eded; + border: 1px solid #e8c6c7; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content h4 { + color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header a { + color: #c8787a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading { + background-color: #e7f6ec; + border: 1px solid #c3e8d1; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.http_method a { + background-color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #c3e8d1; + color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a { + color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content { + background-color: #ebf7f0; + border: 1px solid #c3e8d1; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content h4 { + color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header a { + color: #6fc992; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading { + background-color: #FCE9E3; + border: 1px solid #F5D5C3; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span.http_method a { + background-color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #f0cecb; + color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li a { + color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content { + background-color: #faf0ef; + border: 1px solid #f0cecb; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content h4 { + color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.sandbox_header a { + color: #dcb67f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading { + background-color: #e7f0f7; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.http_method a { + background-color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #c3d9ec; + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content { + background-color: #ebf3f9; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content h4 { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header a { + color: #6fa5d2; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading { + background-color: #e7f0f7; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading h3 span.http_method a { + background-color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #c3d9ec; + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading ul.options li a { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content { + background-color: #ebf3f9; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content h4 { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content div.sandbox_header a { + color: #6fa5d2; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content { + border-top: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li.last { + padding-right: 0; + border-right: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a:hover, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a:active, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a.active { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap p#colophon { + margin: 0 15px 40px 15px; + padding: 10px 0; + font-size: 0.8em; + border-top: 1px solid #dddddd; + font-family: "Droid Sans", sans-serif; + color: #999999; + font-style: italic; +} +.swagger-section .swagger-ui-wrap p#colophon a { + text-decoration: none; + color: #547f00; +} +.swagger-section .swagger-ui-wrap h3 { + color: black; + font-size: 1.1em; + padding: 10px 0 10px 0; +} +.swagger-section .swagger-ui-wrap .markdown ol, +.swagger-section .swagger-ui-wrap .markdown ul { + font-family: "Droid Sans", sans-serif; + margin: 5px 0 10px; + padding: 0 0 0 18px; + list-style-type: disc; +} +.swagger-section .swagger-ui-wrap form.form_box { + background-color: #ebf3f9; + border: 1px solid #c3d9ec; + padding: 10px; +} +.swagger-section .swagger-ui-wrap form.form_box label { + color: #0f6ab4 !important; +} +.swagger-section .swagger-ui-wrap form.form_box input[type=submit] { + display: block; + padding: 10px; +} +.swagger-section .swagger-ui-wrap form.form_box p.weak { + font-size: 0.8em; +} +.swagger-section .swagger-ui-wrap form.form_box p { + font-size: 0.9em; + padding: 0 0 15px; + color: #7e7b6d; +} +.swagger-section .swagger-ui-wrap form.form_box p a { + color: #646257; +} +.swagger-section .swagger-ui-wrap form.form_box p strong { + color: black; +} +.swagger-section .swagger-ui-wrap .operation-status td.markdown > p:last-child { + padding-bottom: 0; +} +.swagger-section .title { + font-style: bold; +} +.swagger-section .secondary_form { + display: none; +} +.swagger-section .main_image { + display: block; + margin-left: auto; + margin-right: auto; +} +.swagger-section .oauth_body { + margin-left: 100px; + margin-right: 100px; +} +.swagger-section .oauth_submit { + text-align: center; +} +.swagger-section .api-popup-dialog { + z-index: 10000; + position: absolute; + width: 500px; + background: #FFF; + padding: 20px; + border: 1px solid #ccc; + border-radius: 5px; + display: none; + font-size: 13px; + color: #777; +} +.swagger-section .api-popup-dialog .api-popup-title { + font-size: 24px; + padding: 10px 0; +} +.swagger-section .api-popup-dialog .api-popup-title { + font-size: 24px; + padding: 10px 0; +} +.swagger-section .api-popup-dialog .error-msg { + padding-left: 5px; + padding-bottom: 5px; +} +.swagger-section .api-popup-dialog .api-popup-authbtn { + height: 30px; +} +.swagger-section .api-popup-dialog .api-popup-cancel { + height: 30px; +} +.swagger-section .api-popup-scopes { + padding: 10px 20px; +} +.swagger-section .api-popup-scopes li { + padding: 5px 0; + line-height: 20px; +} +.swagger-section .api-popup-scopes li input { + position: relative; + top: 2px; +} +.swagger-section .api-popup-scopes .api-scope-desc { + padding-left: 20px; + font-style: italic; +} +.swagger-section .api-popup-actions { + padding-top: 10px; +} +#header { + display: none; +} +.swagger-section .swagger-ui-wrap .model-signature pre { + max-height: none; +} +.swagger-section .swagger-ui-wrap .body-textarea { + width: 100px; +} +.swagger-section .swagger-ui-wrap input.parameter { + width: 100px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options { + display: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints { + display: block !important; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content { + display: block !important; +} diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/css/screen.css b/htdocs/includes/restler/framework/Luracast/Restler/explorer/css/screen.css index 478b99837d7..dc02468fdc0 100644 --- a/htdocs/includes/restler/framework/Luracast/Restler/explorer/css/screen.css +++ b/htdocs/includes/restler/framework/Luracast/Restler/explorer/css/screen.css @@ -126,6 +126,7 @@ max-width: 960px; margin-left: auto; margin-right: auto; + /* JSONEditor specific styling */ } .swagger-section .swagger-ui-wrap b, .swagger-section .swagger-ui-wrap strong { @@ -274,6 +275,9 @@ font-weight: bold; font-size: 25px; } +.swagger-section .swagger-ui-wrap .footer { + margin-top: 20px; +} .swagger-section .swagger-ui-wrap p.big, .swagger-section .swagger-ui-wrap div.big p { font-size: 1em; @@ -294,7 +298,13 @@ .swagger-section .swagger-ui-wrap .message-fail { color: #cc0000; } -.swagger-section .swagger-ui-wrap .info_contact { +.swagger-section .swagger-ui-wrap .info_url { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_email { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_name { padding-bottom: 5px; } .swagger-section .swagger-ui-wrap .info_description { @@ -350,7 +360,7 @@ font-size: .85em; line-height: 1.2em; overflow: auto; - max-height: 200px; + max-height: 400px; cursor: pointer; } .swagger-section .swagger-ui-wrap .model-signature ul.signature-nav { @@ -391,6 +401,43 @@ font-weight: bold; color: #000; } +.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper { + border-spacing: 0; + position: absolute; + background-color: #ffffff; + border: 1px solid #bbbbbb; + display: none; + font-size: 11px; + max-width: 400px; + line-height: 30px; + color: black; + padding: 5px; + margin-left: 10px; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper th { + text-align: center; + background-color: #eeeeee; + border: 1px solid #bbbbbb; + font-size: 11px; + color: #666666; + font-weight: bold; + padding: 5px; + line-height: 15px; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper .optionName { + font-weight: bold; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown > p:first-child, +.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown > p:last-child { + display: inline; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown > p:not(:first-child):before { + display: block; + content: ''; +} +.swagger-section .swagger-ui-wrap .model-signature .description span:last-of-type.propDesc.markdown > p:only-child { + margin-right: -3px; +} .swagger-section .swagger-ui-wrap .model-signature .propName { font-weight: bold; } @@ -412,6 +459,17 @@ .swagger-section .swagger-ui-wrap .required { font-weight: bold; } +.swagger-section .swagger-ui-wrap .editor_holder { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap .editor_holder label { + font-weight: normal!important; + /* JSONEditor uses bold by default for all labels, we revert that back to normal to not give the impression that by default fields are required */ +} +.swagger-section .swagger-ui-wrap .editor_holder label.required { + font-weight: bold!important; +} .swagger-section .swagger-ui-wrap input.parameter { width: 300px; border: 1px solid #aaa; @@ -761,6 +819,9 @@ outline: 2px solid black; outline-color: #cc0000; } +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content form select[name='parameterContentType'] { + max-width: 300px; +} .swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.response div.block pre { font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; padding: 10px; @@ -1034,6 +1095,9 @@ .swagger-section .swagger-ui-wrap form.form_box p strong { color: black; } +.swagger-section .swagger-ui-wrap .operation-status td.markdown > p:last-child { + padding-bottom: 0; +} .swagger-section .title { font-style: bold; } @@ -1072,14 +1136,14 @@ font-size: 24px; padding: 10px 0; } -.swagger-section .api-popup-dialog p.error-msg { +.swagger-section .api-popup-dialog .error-msg { padding-left: 5px; padding-bottom: 5px; } -.swagger-section .api-popup-dialog button.api-popup-authbtn { +.swagger-section .api-popup-dialog .api-popup-authbtn { height: 30px; } -.swagger-section .api-popup-dialog button.api-popup-cancel { +.swagger-section .api-popup-dialog .api-popup-cancel { height: 30px; } .swagger-section .api-popup-scopes { @@ -1089,14 +1153,14 @@ padding: 5px 0; line-height: 20px; } -.swagger-section .api-popup-scopes .api-scope-desc { - padding-left: 20px; - font-style: italic; -} .swagger-section .api-popup-scopes li input { position: relative; top: 2px; } +.swagger-section .api-popup-scopes .api-scope-desc { + padding-left: 20px; + font-style: italic; +} .swagger-section .api-popup-actions { padding-top: 10px; } @@ -1106,8 +1170,16 @@ .swagger-section .auth { float: right; } -.swagger-section #api_information_panel { - position: absolute; +.swagger-section .api-ic { + height: 18px; + vertical-align: middle; + display: inline-block; + background: url(../images/explorer_icons.png) no-repeat; +} +.swagger-section .api-ic .api_information_panel { + position: relative; + margin-top: 20px; + margin-left: -5px; background: #FFF; border: 1px solid #ccc; border-radius: 5px; @@ -1118,34 +1190,32 @@ color: black; padding: 5px; } -.swagger-section #api_information_panel p .api-msg-enabled { +.swagger-section .api-ic .api_information_panel p .api-msg-enabled { color: green; } -.swagger-section #api_information_panel p .api-msg-disabled { +.swagger-section .api-ic .api_information_panel p .api-msg-disabled { color: red; } -.swagger-section .api-ic { - height: 18px; - vertical-align: middle; - display: inline-block; - background: url(../images/explorer_icons.png) no-repeat; +.swagger-section .api-ic:hover .api_information_panel { + position: absolute; + display: block; } .swagger-section .ic-info { background-position: 0 0; width: 18px; - margin-top: -7px; + margin-top: -6px; margin-left: 4px; } .swagger-section .ic-warning { background-position: -60px 0; width: 18px; - margin-top: -7px; + margin-top: -6px; margin-left: 4px; } .swagger-section .ic-error { background-position: -30px 0; width: 18px; - margin-top: -7px; + margin-top: -6px; margin-left: 4px; } .swagger-section .ic-off { @@ -1161,42 +1231,39 @@ cursor: pointer; } .swagger-section #header { - background-color: #89bf04; + background-color: #646257; padding: 14px; } -.swagger-section #header a#logo { - font-size: 1.5em; - font-weight: bold; - text-decoration: none; - background: transparent url(../images/logo_small.png) no-repeat left center; - padding: 20px 0 20px 40px; - color: white; +.swagger-section #input_baseUrl { + width: 400px; } -.swagger-section #header form#api_selector { +.swagger-section #api_selector { display: block; clear: none; float: right; } -.swagger-section #header form#api_selector .input { +.swagger-section #api_selector .input { display: block; clear: none; float: left; margin: 0 10px 0 0; } -.swagger-section #header form#api_selector .input input#input_apiKey { +.swagger-section #api_selector input { + font-size: 0.9em; + padding: 3px; + margin: 0; +} +.swagger-section #input_apiKey { width: 200px; } -.swagger-section #header form#api_selector .input input#input_baseUrl { - width: 400px; -} -.swagger-section #header form#api_selector .input a#explore { +.swagger-section #explore { display: block; text-decoration: none; font-weight: bold; padding: 6px 8px; font-size: 0.9em; color: white; - background-color: #547f00; + background-color: #000000; -moz-border-radius: 4px; -webkit-border-radius: 4px; -o-border-radius: 4px; @@ -1204,13 +1271,16 @@ -khtml-border-radius: 4px; border-radius: 4px; } -.swagger-section #header form#api_selector .input a#explore:hover { - background-color: #547f00; +.swagger-section #explore:hover { + background-color: #a41e22; } -.swagger-section #header form#api_selector .input input { - font-size: 0.9em; - padding: 3px; - margin: 0; +.swagger-section #header #logo { + font-size: 1.5em; + font-weight: bold; + text-decoration: none; + background: transparent url(../images/logo_small.png) no-repeat left center; + padding: 20px 0 20px 40px; + color: white; } .swagger-section #content_message { margin: 10px 15px; @@ -1222,3 +1292,13 @@ text-align: center; padding-top: 10px; } +.swagger-section .swagger-collapse:before { + content: "-"; +} +.swagger-section .swagger-expand:before { + content: "+"; +} + +#input_baseUrl { + display: none; +} diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/css/style.css b/htdocs/includes/restler/framework/Luracast/Restler/explorer/css/style.css new file mode 100644 index 00000000000..fc21a31db54 --- /dev/null +++ b/htdocs/includes/restler/framework/Luracast/Restler/explorer/css/style.css @@ -0,0 +1,250 @@ +.swagger-section #header a#logo { + font-size: 1.5em; + font-weight: bold; + text-decoration: none; + background: transparent url(../images/logo.png) no-repeat left center; + padding: 20px 0 20px 40px; +} +#text-head { + font-size: 80px; + font-family: 'Roboto', sans-serif; + color: #ffffff; + float: right; + margin-right: 20%; +} +.navbar-fixed-top .navbar-nav { + height: auto; +} +.navbar-fixed-top .navbar-brand { + height: auto; +} +.navbar-header { + height: auto; +} +.navbar-inverse { + background-color: #000; + border-color: #000; +} +#navbar-brand { + margin-left: 20%; +} +.navtext { + font-size: 10px; +} +.h1, +h1 { + font-size: 60px; +} +.navbar-default .navbar-header .navbar-brand { + color: #a2dfee; +} +/* tag titles */ +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a { + color: #393939; + font-family: 'Arvo', serif; + font-size: 1.5em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a:hover { + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 { + color: #525252; + padding-left: 0px; + display: block; + clear: none; + float: left; + font-family: 'Arvo', serif; + font-weight: bold; +} +.navbar-default .navbar-collapse, +.navbar-default .navbar-form { + border-color: #0A0A0A; +} +.container1 { + width: 1500px; + margin: auto; + margin-top: 0; + background-image: url('../images/shield.png'); + background-repeat: no-repeat; + background-position: -40px -20px; + margin-bottom: 210px; +} +.container-inner { + width: 1200px; + margin: auto; + background-color: rgba(223, 227, 228, 0.75); + padding-bottom: 40px; + padding-top: 40px; + border-radius: 15px; +} +.header-content { + padding: 0; + width: 1000px; +} +.title1 { + font-size: 80px; + font-family: 'Vollkorn', serif; + color: #404040; + text-align: center; + padding-top: 40px; + padding-bottom: 100px; +} +#icon { + margin-top: -18px; +} +.subtext { + font-size: 25px; + font-style: italic; + color: #08b; + text-align: right; + padding-right: 250px; +} +.bg-primary { + background-color: #00468b; +} +.navbar-default .nav > li > a, +.navbar-default .nav > li > a:focus { + color: #08b; +} +.navbar-default .nav > li > a, +.navbar-default .nav > li > a:hover { + color: #08b; +} +.navbar-default .nav > li > a, +.navbar-default .nav > li > a:focus:hover { + color: #08b; +} +.text-faded { + font-size: 25px; + font-family: 'Vollkorn', serif; +} +.section-heading { + font-family: 'Vollkorn', serif; + font-size: 45px; + padding-bottom: 10px; +} +hr { + border-color: #00468b; + padding-bottom: 10px; +} +.description { + margin-top: 20px; + padding-bottom: 200px; +} +.description li { + font-family: 'Vollkorn', serif; + font-size: 25px; + color: #525252; + margin-left: 28%; + padding-top: 5px; +} +.gap { + margin-top: 200px; +} +.troubleshootingtext { + color: rgba(255, 255, 255, 0.7); + padding-left: 30%; +} +.troubleshootingtext li { + list-style-type: circle; + font-size: 25px; + padding-bottom: 5px; +} +.overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1000; +} +.block.response_body.json:hover { + cursor: pointer; +} +.backdrop { + color: blue; +} +#myModal { + height: 100%; +} +.modal-backdrop { + bottom: 0; + position: fixed; +} +.curl { + padding: 10px; + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + font-size: 0.9em; + max-height: 400px; + margin-top: 5px; + overflow-y: auto; + background-color: #fcf6db; + border: 1px solid #e5e0c6; + border-radius: 4px; +} +.curl_title { + font-size: 1.1em; + margin: 0; + padding: 15px 0 5px; + font-family: 'Open Sans', 'Helvetica Neue', Arial, sans-serif; + font-weight: 500; + line-height: 1.1; +} +.footer { + display: none; +} +.swagger-section .swagger-ui-wrap h2 { + padding: 0; +} +h2 { + margin: 0; + margin-bottom: 5px; +} +.markdown p { + font-size: 15px; + font-family: 'Arvo', serif; +} +.swagger-section .swagger-ui-wrap .code { + font-size: 15px; + font-family: 'Arvo', serif; +} +.swagger-section .swagger-ui-wrap b { + font-family: 'Arvo', serif; +} +#signin:hover { + cursor: pointer; +} +.dropdown-menu { + padding: 15px; +} +.navbar-right .dropdown-menu { + left: 0; + right: auto; +} +#signinbutton { + width: 100%; + height: 32px; + font-size: 13px; + font-weight: bold; + color: #08b; +} +.navbar-default .nav > li .details { + color: #000000; + text-transform: none; + font-size: 15px; + font-weight: normal; + font-family: 'Open Sans', sans-serif; + font-style: italic; + line-height: 20px; + top: -2px; +} +.navbar-default .nav > li .details:hover { + color: black; +} +#signout { + width: 100%; + height: 32px; + font-size: 13px; + font-weight: bold; + color: #08b; +} diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/css/typography.css b/htdocs/includes/restler/framework/Luracast/Restler/explorer/css/typography.css new file mode 100644 index 00000000000..3235edd9503 --- /dev/null +++ b/htdocs/includes/restler/framework/Luracast/Restler/explorer/css/typography.css @@ -0,0 +1,14 @@ +/* Google Font's Droid Sans */ +@font-face { + font-family: 'Droid Sans'; + font-style: normal; + font-weight: 400; + src: local('Droid Sans'), local('DroidSans'), url('../fonts/DroidSans.ttf') format('truetype'); +} +/* Google Font's Droid Sans Bold */ +@font-face { + font-family: 'Droid Sans'; + font-style: normal; + font-weight: 700; + src: local('Droid Sans Bold'), local('DroidSans-Bold'), url('../fonts/DroidSans-Bold.ttf') format('truetype'); +} diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/fonts/DroidSans-Bold.ttf b/htdocs/includes/restler/framework/Luracast/Restler/explorer/fonts/DroidSans-Bold.ttf new file mode 100644 index 00000000000..942bbf5ba3a Binary files /dev/null and b/htdocs/includes/restler/framework/Luracast/Restler/explorer/fonts/DroidSans-Bold.ttf differ diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/fonts/DroidSans.ttf b/htdocs/includes/restler/framework/Luracast/Restler/explorer/fonts/DroidSans.ttf new file mode 100644 index 00000000000..efd1f8bbd88 Binary files /dev/null and b/htdocs/includes/restler/framework/Luracast/Restler/explorer/fonts/DroidSans.ttf differ diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/images/collapse.gif b/htdocs/includes/restler/framework/Luracast/Restler/explorer/images/collapse.gif new file mode 100644 index 00000000000..8843e8ce5a4 Binary files /dev/null and b/htdocs/includes/restler/framework/Luracast/Restler/explorer/images/collapse.gif differ diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/images/expand.gif b/htdocs/includes/restler/framework/Luracast/Restler/explorer/images/expand.gif new file mode 100644 index 00000000000..477bf13718d Binary files /dev/null and b/htdocs/includes/restler/framework/Luracast/Restler/explorer/images/expand.gif differ diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/images/logo_small.png b/htdocs/includes/restler/framework/Luracast/Restler/explorer/images/logo_small.png index 5496a65579a..2ed3cf64be7 100644 Binary files a/htdocs/includes/restler/framework/Luracast/Restler/explorer/images/logo_small.png and b/htdocs/includes/restler/framework/Luracast/Restler/explorer/images/logo_small.png differ diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/images/pet_store_api.png b/htdocs/includes/restler/framework/Luracast/Restler/explorer/images/pet_store_api.png deleted file mode 100644 index f9f9cd4aeb3..00000000000 Binary files a/htdocs/includes/restler/framework/Luracast/Restler/explorer/images/pet_store_api.png and /dev/null differ diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/images/wordnik_api.png b/htdocs/includes/restler/framework/Luracast/Restler/explorer/images/wordnik_api.png deleted file mode 100644 index dca4f1455ac..00000000000 Binary files a/htdocs/includes/restler/framework/Luracast/Restler/explorer/images/wordnik_api.png and /dev/null differ diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/index.html b/htdocs/includes/restler/framework/Luracast/Restler/explorer/index.html index 0d73f19447e..c73f1981cc9 100644 --- a/htdocs/includes/restler/framework/Luracast/Restler/explorer/index.html +++ b/htdocs/includes/restler/framework/Luracast/Restler/explorer/index.html @@ -1,85 +1,126 @@ + + Api Explorer - + - - + + - + - - - + + + + + + + + @@ -87,22 +128,14 @@
    -
     
    +
     
    diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/en.js b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/en.js new file mode 100644 index 00000000000..9ccd65ad1d7 --- /dev/null +++ b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/en.js @@ -0,0 +1,55 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Warning: Deprecated", + "Implementation Notes":"Implementation Notes", + "Response Class":"Response Class", + "Status":"Status", + "Parameters":"Parameters", + "Parameter":"Parameter", + "Value":"Value", + "Description":"Description", + "Parameter Type":"Parameter Type", + "Data Type":"Data Type", + "Response Messages":"Response Messages", + "HTTP Status Code":"HTTP Status Code", + "Reason":"Reason", + "Response Model":"Response Model", + "Request URL":"Request URL", + "Response Body":"Response Body", + "Response Code":"Response Code", + "Response Headers":"Response Headers", + "Hide Response":"Hide Response", + "Headers":"Headers", + "Try it out!":"Try it out!", + "Show/Hide":"Show/Hide", + "List Operations":"List Operations", + "Expand Operations":"Expand Operations", + "Raw":"Raw", + "can't parse JSON. Raw result":"can't parse JSON. Raw result", + "Model Schema":"Model Schema", + "Model":"Model", + "Click to set as parameter value":"Click to set as parameter value", + "apply":"apply", + "Username":"Username", + "Password":"Password", + "Terms of service":"Terms of service", + "Created by":"Created by", + "See more at":"See more at", + "Contact the developer":"Contact the developer", + "api version":"api version", + "Response Content Type":"Response Content Type", + "Parameter content type:":"Parameter content type:", + "fetching resource":"fetching resource", + "fetching resource list":"fetching resource list", + "Explore":"Explore", + "Show Swagger Petstore Example Apis":"Show Swagger Petstore Example Apis", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Can't read from server. It may not have the appropriate access-control-origin settings.", + "Please specify the protocol for":"Please specify the protocol for", + "Can't read swagger JSON from":"Can't read swagger JSON from", + "Finished Loading Resource Information. Rendering Swagger UI":"Finished Loading Resource Information. Rendering Swagger UI", + "Unable to read api":"Unable to read api", + "from path":"from path", + "server returned":"server returned" +}); diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/es.js b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/es.js new file mode 100644 index 00000000000..a8dff60b6a9 --- /dev/null +++ b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/es.js @@ -0,0 +1,52 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Advertencia: Obsoleto", + "Implementation Notes":"Notas de implementación", + "Response Class":"Clase de la Respuesta", + "Status":"Status", + "Parameters":"Parámetros", + "Parameter":"Parámetro", + "Value":"Valor", + "Description":"Descripción", + "Parameter Type":"Tipo del Parámetro", + "Data Type":"Tipo del Dato", + "Response Messages":"Mensajes de la Respuesta", + "HTTP Status Code":"Código de Status HTTP", + "Reason":"Razón", + "Response Model":"Modelo de la Respuesta", + "Request URL":"URL de la Solicitud", + "Response Body":"Cuerpo de la Respuesta", + "Response Code":"Código de la Respuesta", + "Response Headers":"Encabezados de la Respuesta", + "Hide Response":"Ocultar Respuesta", + "Try it out!":"Pruébalo!", + "Show/Hide":"Mostrar/Ocultar", + "List Operations":"Listar Operaciones", + "Expand Operations":"Expandir Operaciones", + "Raw":"Crudo", + "can't parse JSON. Raw result":"no puede parsear el JSON. Resultado crudo", + "Model Schema":"Esquema del Modelo", + "Model":"Modelo", + "apply":"aplicar", + "Username":"Nombre de usuario", + "Password":"Contraseña", + "Terms of service":"Términos de Servicio", + "Created by":"Creado por", + "See more at":"Ver más en", + "Contact the developer":"Contactar al desarrollador", + "api version":"versión de la api", + "Response Content Type":"Tipo de Contenido (Content Type) de la Respuesta", + "fetching resource":"buscando recurso", + "fetching resource list":"buscando lista del recurso", + "Explore":"Explorar", + "Show Swagger Petstore Example Apis":"Mostrar Api Ejemplo de Swagger Petstore", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"No se puede leer del servidor. Tal vez no tiene la configuración de control de acceso de origen (access-control-origin) apropiado.", + "Please specify the protocol for":"Por favor, especificar el protocola para", + "Can't read swagger JSON from":"No se puede leer el JSON de swagger desde", + "Finished Loading Resource Information. Rendering Swagger UI":"Finalizada la carga del recurso de Información. Mostrando Swagger UI", + "Unable to read api":"No se puede leer la api", + "from path":"desde ruta", + "server returned":"el servidor retornó" +}); diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/fr.js b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/fr.js new file mode 100644 index 00000000000..2e095ad0948 --- /dev/null +++ b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/fr.js @@ -0,0 +1,53 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Avertissement : Obsolète", + "Implementation Notes":"Notes d'implementation", + "Response Class":"Classe de la réponse", + "Status":"Statut", + "Parameters":"Paramètres", + "Parameter":"Paramètre", + "Value":"Valeur", + "Description":"Description", + "Parameter Type":"Type du paramètre", + "Data Type":"Type de données", + "Response Messages":"Messages de la réponse", + "HTTP Status Code":"Code de statut HTTP", + "Reason":"Raison", + "Response Model":"Modèle de réponse", + "Request URL":"URL appelée", + "Response Body":"Corps de la réponse", + "Response Code":"Code de la réponse", + "Response Headers":"En-têtes de la réponse", + "Hide Response":"Cacher la réponse", + "Headers":"En-têtes", + "Try it out!":"Testez !", + "Show/Hide":"Afficher/Masquer", + "List Operations":"Liste des opérations", + "Expand Operations":"Développer les opérations", + "Raw":"Brut", + "can't parse JSON. Raw result":"impossible de décoder le JSON. Résultat brut", + "Model Schema":"Définition du modèle", + "Model":"Modèle", + "apply":"appliquer", + "Username":"Nom d'utilisateur", + "Password":"Mot de passe", + "Terms of service":"Conditions de service", + "Created by":"Créé par", + "See more at":"Voir plus sur", + "Contact the developer":"Contacter le développeur", + "api version":"version de l'api", + "Response Content Type":"Content Type de la réponse", + "fetching resource":"récupération de la ressource", + "fetching resource list":"récupération de la liste de ressources", + "Explore":"Explorer", + "Show Swagger Petstore Example Apis":"Montrer les Apis de l'exemple Petstore de Swagger", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Impossible de lire à partir du serveur. Il se peut que les réglages access-control-origin ne soient pas appropriés.", + "Please specify the protocol for":"Veuillez spécifier un protocole pour", + "Can't read swagger JSON from":"Impossible de lire le JSON swagger à partir de", + "Finished Loading Resource Information. Rendering Swagger UI":"Chargement des informations terminé. Affichage de Swagger UI", + "Unable to read api":"Impossible de lire l'api", + "from path":"à partir du chemin", + "server returned":"réponse du serveur" +}); diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/it.js b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/it.js new file mode 100644 index 00000000000..8529c2a90bc --- /dev/null +++ b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/it.js @@ -0,0 +1,52 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Attenzione: Deprecato", + "Implementation Notes":"Note di implementazione", + "Response Class":"Classe della risposta", + "Status":"Stato", + "Parameters":"Parametri", + "Parameter":"Parametro", + "Value":"Valore", + "Description":"Descrizione", + "Parameter Type":"Tipo di parametro", + "Data Type":"Tipo di dato", + "Response Messages":"Messaggi della risposta", + "HTTP Status Code":"Codice stato HTTP", + "Reason":"Motivo", + "Response Model":"Modello di risposta", + "Request URL":"URL della richiesta", + "Response Body":"Corpo della risposta", + "Response Code":"Oggetto della risposta", + "Response Headers":"Intestazioni della risposta", + "Hide Response":"Nascondi risposta", + "Try it out!":"Provalo!", + "Show/Hide":"Mostra/Nascondi", + "List Operations":"Mostra operazioni", + "Expand Operations":"Espandi operazioni", + "Raw":"Grezzo (raw)", + "can't parse JSON. Raw result":"non è possibile parsare il JSON. Risultato grezzo (raw).", + "Model Schema":"Schema del modello", + "Model":"Modello", + "apply":"applica", + "Username":"Nome utente", + "Password":"Password", + "Terms of service":"Condizioni del servizio", + "Created by":"Creato da", + "See more at":"Informazioni aggiuntive:", + "Contact the developer":"Contatta lo sviluppatore", + "api version":"versione api", + "Response Content Type":"Tipo di contenuto (content type) della risposta", + "fetching resource":"recuperando la risorsa", + "fetching resource list":"recuperando lista risorse", + "Explore":"Esplora", + "Show Swagger Petstore Example Apis":"Mostra le api di esempio di Swagger Petstore", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Non è possibile leggere dal server. Potrebbe non avere le impostazioni di controllo accesso origine (access-control-origin) appropriate.", + "Please specify the protocol for":"Si prega di specificare il protocollo per", + "Can't read swagger JSON from":"Impossibile leggere JSON swagger da:", + "Finished Loading Resource Information. Rendering Swagger UI":"Lettura informazioni risorse termianta. Swagger UI viene mostrata", + "Unable to read api":"Impossibile leggere la api", + "from path":"da cartella", + "server returned":"il server ha restituito" +}); diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/ja.js b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/ja.js new file mode 100644 index 00000000000..3207bfc0baf --- /dev/null +++ b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/ja.js @@ -0,0 +1,53 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"警告: 廃止予定", + "Implementation Notes":"実装メモ", + "Response Class":"レスポンスクラス", + "Status":"ステータス", + "Parameters":"パラメータ群", + "Parameter":"パラメータ", + "Value":"値", + "Description":"説明", + "Parameter Type":"パラメータタイプ", + "Data Type":"データタイプ", + "Response Messages":"レスポンスメッセージ", + "HTTP Status Code":"HTTPステータスコード", + "Reason":"理由", + "Response Model":"レスポンスモデル", + "Request URL":"リクエストURL", + "Response Body":"レスポンスボディ", + "Response Code":"レスポンスコード", + "Response Headers":"レスポンスヘッダ", + "Hide Response":"レスポンスを隠す", + "Headers":"ヘッダ", + "Try it out!":"実際に実行!", + "Show/Hide":"表示/非表示", + "List Operations":"操作一覧", + "Expand Operations":"操作の展開", + "Raw":"Raw", + "can't parse JSON. Raw result":"JSONへ解釈できません. 未加工の結果", + "Model Schema":"モデルスキーマ", + "Model":"モデル", + "apply":"実行", + "Username":"ユーザ名", + "Password":"パスワード", + "Terms of service":"サービス利用規約", + "Created by":"Created by", + "See more at":"See more at", + "Contact the developer":"開発者に連絡", + "api version":"APIバージョン", + "Response Content Type":"レスポンス コンテンツタイプ", + "fetching resource":"リソースの取得", + "fetching resource list":"リソース一覧の取得", + "Explore":"Explore", + "Show Swagger Petstore Example Apis":"SwaggerペットストアAPIの表示", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"サーバから読み込めません. 適切なaccess-control-origin設定を持っていない可能性があります.", + "Please specify the protocol for":"プロトコルを指定してください", + "Can't read swagger JSON from":"次からswagger JSONを読み込めません", + "Finished Loading Resource Information. Rendering Swagger UI":"リソース情報の読み込みが完了しました. Swagger UIを描画しています", + "Unable to read api":"APIを読み込めません", + "from path":"次のパスから", + "server returned":"サーバからの返答" +}); diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/pl.js b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/pl.js new file mode 100644 index 00000000000..ce41e91799d --- /dev/null +++ b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/pl.js @@ -0,0 +1,53 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Uwaga: Wycofane", + "Implementation Notes":"Uwagi Implementacji", + "Response Class":"Klasa Odpowiedzi", + "Status":"Status", + "Parameters":"Parametry", + "Parameter":"Parametr", + "Value":"Wartość", + "Description":"Opis", + "Parameter Type":"Typ Parametru", + "Data Type":"Typ Danych", + "Response Messages":"Wiadomości Odpowiedzi", + "HTTP Status Code":"Kod Statusu HTTP", + "Reason":"Przyczyna", + "Response Model":"Model Odpowiedzi", + "Request URL":"URL Wywołania", + "Response Body":"Treść Odpowiedzi", + "Response Code":"Kod Odpowiedzi", + "Response Headers":"Nagłówki Odpowiedzi", + "Hide Response":"Ukryj Odpowiedź", + "Headers":"Nagłówki", + "Try it out!":"Wypróbuj!", + "Show/Hide":"Pokaż/Ukryj", + "List Operations":"Lista Operacji", + "Expand Operations":"Rozwiń Operacje", + "Raw":"Nieprzetworzone", + "can't parse JSON. Raw result":"nie można przetworzyć pliku JSON. Nieprzetworzone dane", + "Model Schema":"Schemat Modelu", + "Model":"Model", + "apply":"użyj", + "Username":"Nazwa użytkownika", + "Password":"Hasło", + "Terms of service":"Warunki używania", + "Created by":"Utworzone przez", + "See more at":"Zobacz więcej na", + "Contact the developer":"Kontakt z deweloperem", + "api version":"wersja api", + "Response Content Type":"Typ Zasobu Odpowiedzi", + "fetching resource":"ładowanie zasobu", + "fetching resource list":"ładowanie listy zasobów", + "Explore":"Eksploruj", + "Show Swagger Petstore Example Apis":"Pokaż Przykładowe Api Swagger Petstore", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Brak połączenia z serwerem. Może on nie mieć odpowiednich ustawień access-control-origin.", + "Please specify the protocol for":"Proszę podać protokół dla", + "Can't read swagger JSON from":"Nie można odczytać swagger JSON z", + "Finished Loading Resource Information. Rendering Swagger UI":"Ukończono Ładowanie Informacji o Zasobie. Renderowanie Swagger UI", + "Unable to read api":"Nie można odczytać api", + "from path":"ze ścieżki", + "server returned":"serwer zwrócił" +}); diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/pt.js b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/pt.js new file mode 100644 index 00000000000..f2e7c13d413 --- /dev/null +++ b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/pt.js @@ -0,0 +1,53 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Aviso: Depreciado", + "Implementation Notes":"Notas de Implementação", + "Response Class":"Classe de resposta", + "Status":"Status", + "Parameters":"Parâmetros", + "Parameter":"Parâmetro", + "Value":"Valor", + "Description":"Descrição", + "Parameter Type":"Tipo de parâmetro", + "Data Type":"Tipo de dados", + "Response Messages":"Mensagens de resposta", + "HTTP Status Code":"Código de status HTTP", + "Reason":"Razão", + "Response Model":"Modelo resposta", + "Request URL":"URL requisição", + "Response Body":"Corpo da resposta", + "Response Code":"Código da resposta", + "Response Headers":"Cabeçalho da resposta", + "Headers":"Cabeçalhos", + "Hide Response":"Esconder resposta", + "Try it out!":"Tente agora!", + "Show/Hide":"Mostrar/Esconder", + "List Operations":"Listar operações", + "Expand Operations":"Expandir operações", + "Raw":"Cru", + "can't parse JSON. Raw result":"Falha ao analisar JSON. Resulto cru", + "Model Schema":"Modelo esquema", + "Model":"Modelo", + "apply":"Aplicar", + "Username":"Usuário", + "Password":"Senha", + "Terms of service":"Termos do serviço", + "Created by":"Criado por", + "See more at":"Veja mais em", + "Contact the developer":"Contate o desenvolvedor", + "api version":"Versão api", + "Response Content Type":"Tipo de conteúdo da resposta", + "fetching resource":"busca recurso", + "fetching resource list":"buscando lista de recursos", + "Explore":"Explorar", + "Show Swagger Petstore Example Apis":"Show Swagger Petstore Example Apis", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Não é possível ler do servidor. Pode não ter as apropriadas configurações access-control-origin", + "Please specify the protocol for":"Por favor especifique o protocolo", + "Can't read swagger JSON from":"Não é possível ler o JSON Swagger de", + "Finished Loading Resource Information. Rendering Swagger UI":"Carregar informação de recurso finalizada. Renderizando Swagger UI", + "Unable to read api":"Não foi possível ler api", + "from path":"do caminho", + "server returned":"servidor retornou" +}); diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/ru.js b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/ru.js new file mode 100644 index 00000000000..381f1b3fd0d --- /dev/null +++ b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/ru.js @@ -0,0 +1,55 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Предупреждение: Устарело", + "Implementation Notes":"Заметки", + "Response Class":"Пример ответа", + "Status":"Статус", + "Parameters":"Параметры", + "Parameter":"Параметр", + "Value":"Значение", + "Description":"Описание", + "Parameter Type":"Тип параметра", + "Data Type":"Тип данных", + "HTTP Status Code":"HTTP код", + "Reason":"Причина", + "Response Model":"Структура ответа", + "Request URL":"URL запроса", + "Response Body":"Тело ответа", + "Response Code":"HTTP код ответа", + "Response Headers":"Заголовки ответа", + "Hide Response":"Спрятать ответ", + "Headers":"Заголовки", + "Response Messages":"Что может прийти в ответ", + "Try it out!":"Попробовать!", + "Show/Hide":"Показать/Скрыть", + "List Operations":"Операции кратко", + "Expand Operations":"Операции подробно", + "Raw":"В сыром виде", + "can't parse JSON. Raw result":"Не удается распарсить ответ:", + "Model Schema":"Структура", + "Model":"Описание", + "Click to set as parameter value":"Нажмите, чтобы испльзовать в качестве значения параметра", + "apply":"применить", + "Username":"Имя пользователя", + "Password":"Пароль", + "Terms of service":"Условия использования", + "Created by":"Разработано", + "See more at":"Еще тут", + "Contact the developer":"Связаться с разработчиком", + "api version":"Версия API", + "Response Content Type":"Content Type ответа", + "Parameter content type:":"Content Type параметра:", + "fetching resource":"Получение ресурса", + "fetching resource list":"Получение ресурсов", + "Explore":"Показать", + "Show Swagger Petstore Example Apis":"Показать примеры АПИ", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Не удается получить ответ от сервера. Возможно, проблема с настройками доступа", + "Please specify the protocol for":"Пожалуйста, укажите протокол для", + "Can't read swagger JSON from":"Не получается прочитать swagger json из", + "Finished Loading Resource Information. Rendering Swagger UI":"Загрузка информации о ресурсах завершена. Рендерим", + "Unable to read api":"Не удалось прочитать api", + "from path":"по адресу", + "server returned":"сервер сказал" +}); diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/tr.js b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/tr.js new file mode 100644 index 00000000000..16426a9c34b --- /dev/null +++ b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/tr.js @@ -0,0 +1,53 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Uyarı: Deprecated", + "Implementation Notes":"Gerçekleştirim Notları", + "Response Class":"Dönen Sınıf", + "Status":"Statü", + "Parameters":"Parametreler", + "Parameter":"Parametre", + "Value":"Değer", + "Description":"Açıklama", + "Parameter Type":"Parametre Tipi", + "Data Type":"Veri Tipi", + "Response Messages":"Dönüş Mesajı", + "HTTP Status Code":"HTTP Statü Kodu", + "Reason":"Gerekçe", + "Response Model":"Dönüş Modeli", + "Request URL":"İstek URL", + "Response Body":"Dönüş İçeriği", + "Response Code":"Dönüş Kodu", + "Response Headers":"Dönüş Üst Bilgileri", + "Hide Response":"Dönüşü Gizle", + "Headers":"Üst Bilgiler", + "Try it out!":"Dene!", + "Show/Hide":"Göster/Gizle", + "List Operations":"Operasyonları Listele", + "Expand Operations":"Operasyonları Aç", + "Raw":"Ham", + "can't parse JSON. Raw result":"JSON çözümlenemiyor. Ham sonuç", + "Model Schema":"Model Şema", + "Model":"Model", + "apply":"uygula", + "Username":"Kullanıcı Adı", + "Password":"Parola", + "Terms of service":"Servis şartları", + "Created by":"Oluşturan", + "See more at":"Daha fazlası için", + "Contact the developer":"Geliştirici ile İletişime Geçin", + "api version":"api versiyon", + "Response Content Type":"Dönüş İçerik Tipi", + "fetching resource":"kaynak getiriliyor", + "fetching resource list":"kaynak listesi getiriliyor", + "Explore":"Keşfet", + "Show Swagger Petstore Example Apis":"Swagger Petstore Örnek Api'yi Gör", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Sunucudan okuma yapılamıyor. Sunucu access-control-origin ayarlarınızı kontrol edin.", + "Please specify the protocol for":"Lütfen istenen adres için protokol belirtiniz", + "Can't read swagger JSON from":"Swagger JSON bu kaynaktan okunamıyor", + "Finished Loading Resource Information. Rendering Swagger UI":"Kaynak baglantısı tamamlandı. Swagger UI gösterime hazırlanıyor", + "Unable to read api":"api okunamadı", + "from path":"yoldan", + "server returned":"sunucuya dönüldü" +}); diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/translator.js b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/translator.js new file mode 100644 index 00000000000..591f6d40943 --- /dev/null +++ b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/translator.js @@ -0,0 +1,39 @@ +'use strict'; + +/** + * Translator for documentation pages. + * + * To enable translation you should include one of language-files in your index.html + * after . + * For example - + * + * If you wish to translate some new texsts you should do two things: + * 1. Add a new phrase pair ("New Phrase": "New Translation") into your language file (for example lang/ru.js). It will be great if you add it in other language files too. + * 2. Mark that text it templates this way New Phrase or . + * The main thing here is attribute data-sw-translate. Only inner html, title-attribute and value-attribute are going to translate. + * + */ +window.SwaggerTranslator = { + + _words:[], + + translate: function(sel) { + var $this = this; + sel = sel || '[data-sw-translate]'; + + $(sel).each(function() { + $(this).html($this._tryTranslate($(this).html())); + + $(this).val($this._tryTranslate($(this).val())); + $(this).attr('title', $this._tryTranslate($(this).attr('title'))); + }); + }, + + _tryTranslate: function(word) { + return this._words[$.trim(word)] !== undefined ? this._words[$.trim(word)] : word; + }, + + learn: function(wordsMap) { + this._words = wordsMap; + } +}; diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/zh-cn.js b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/zh-cn.js new file mode 100644 index 00000000000..570319ba156 --- /dev/null +++ b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lang/zh-cn.js @@ -0,0 +1,53 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"警告:已过时", + "Implementation Notes":"实现备注", + "Response Class":"响应类", + "Status":"状态", + "Parameters":"参数", + "Parameter":"参数", + "Value":"值", + "Description":"描述", + "Parameter Type":"参数类型", + "Data Type":"数据类型", + "Response Messages":"响应消息", + "HTTP Status Code":"HTTP状态码", + "Reason":"原因", + "Response Model":"响应模型", + "Request URL":"请求URL", + "Response Body":"响应体", + "Response Code":"响应码", + "Response Headers":"响应头", + "Hide Response":"隐藏响应", + "Headers":"头", + "Try it out!":"试一下!", + "Show/Hide":"显示/隐藏", + "List Operations":"显示操作", + "Expand Operations":"展开操作", + "Raw":"原始", + "can't parse JSON. Raw result":"无法解析JSON. 原始结果", + "Model Schema":"模型架构", + "Model":"模型", + "apply":"应用", + "Username":"用户名", + "Password":"密码", + "Terms of service":"服务条款", + "Created by":"创建者", + "See more at":"查看更多:", + "Contact the developer":"联系开发者", + "api version":"api版本", + "Response Content Type":"响应Content Type", + "fetching resource":"正在获取资源", + "fetching resource list":"正在获取资源列表", + "Explore":"浏览", + "Show Swagger Petstore Example Apis":"显示 Swagger Petstore 示例 Apis", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"无法从服务器读取。可能没有正确设置access-control-origin。", + "Please specify the protocol for":"请指定协议:", + "Can't read swagger JSON from":"无法读取swagger JSON于", + "Finished Loading Resource Information. Rendering Swagger UI":"已加载资源信息。正在渲染Swagger UI", + "Unable to read api":"无法读取api", + "from path":"从路径", + "server returned":"服务器返回" +}); diff --git a/htdocs/includes/restler/framework/Luracast/Restler/explorer/lib/backbone-min.js b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lib/backbone-min.js index c1c0d4fff28..a3f544be6d9 100644 --- a/htdocs/includes/restler/framework/Luracast/Restler/explorer/lib/backbone-min.js +++ b/htdocs/includes/restler/framework/Luracast/Restler/explorer/lib/backbone-min.js @@ -1,38 +1,15 @@ -// Backbone.js 0.9.2 +// Backbone.js 1.1.2 -// (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc. -// Backbone may be freely distributed under the MIT license. -// For all details and documentation: -// http://backbonejs.org -(function(){var l=this,y=l.Backbone,z=Array.prototype.slice,A=Array.prototype.splice,g;g="undefined"!==typeof exports?exports:l.Backbone={};g.VERSION="0.9.2";var f=l._;!f&&"undefined"!==typeof require&&(f=require("underscore"));var i=l.jQuery||l.Zepto||l.ender;g.setDomLibrary=function(a){i=a};g.noConflict=function(){l.Backbone=y;return this};g.emulateHTTP=!1;g.emulateJSON=!1;var p=/\s+/,k=g.Events={on:function(a,b,c){var d,e,f,g,j;if(!b)return this;a=a.split(p);for(d=this._callbacks||(this._callbacks= -{});e=a.shift();)f=(j=d[e])?j.tail:{},f.next=g={},f.context=c,f.callback=b,d[e]={tail:g,next:j?j.next:f};return this},off:function(a,b,c){var d,e,h,g,j,q;if(e=this._callbacks){if(!a&&!b&&!c)return delete this._callbacks,this;for(a=a?a.split(p):f.keys(e);d=a.shift();)if(h=e[d],delete e[d],h&&(b||c))for(g=h.tail;(h=h.next)!==g;)if(j=h.callback,q=h.context,b&&j!==b||c&&q!==c)this.on(d,j,q);return this}},trigger:function(a){var b,c,d,e,f,g;if(!(d=this._callbacks))return this;f=d.all;a=a.split(p);for(g= -z.call(arguments,1);b=a.shift();){if(c=d[b])for(e=c.tail;(c=c.next)!==e;)c.callback.apply(c.context||this,g);if(c=f){e=c.tail;for(b=[b].concat(g);(c=c.next)!==e;)c.callback.apply(c.context||this,b)}}return this}};k.bind=k.on;k.unbind=k.off;var o=g.Model=function(a,b){var c;a||(a={});b&&b.parse&&(a=this.parse(a));if(c=n(this,"defaults"))a=f.extend({},c,a);b&&b.collection&&(this.collection=b.collection);this.attributes={};this._escapedAttributes={};this.cid=f.uniqueId("c");this.changed={};this._silent= -{};this._pending={};this.set(a,{silent:!0});this.changed={};this._silent={};this._pending={};this._previousAttributes=f.clone(this.attributes);this.initialize.apply(this,arguments)};f.extend(o.prototype,k,{changed:null,_silent:null,_pending:null,idAttribute:"id",initialize:function(){},toJSON:function(){return f.clone(this.attributes)},get:function(a){return this.attributes[a]},escape:function(a){var b;if(b=this._escapedAttributes[a])return b;b=this.get(a);return this._escapedAttributes[a]=f.escape(null== -b?"":""+b)},has:function(a){return null!=this.get(a)},set:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c||(c={});if(!d)return this;d instanceof o&&(d=d.attributes);if(c.unset)for(e in d)d[e]=void 0;if(!this._validate(d,c))return!1;this.idAttribute in d&&(this.id=d[this.idAttribute]);var b=c.changes={},h=this.attributes,g=this._escapedAttributes,j=this._previousAttributes||{};for(e in d){a=d[e];if(!f.isEqual(h[e],a)||c.unset&&f.has(h,e))delete g[e],(c.silent?this._silent: -b)[e]=!0;c.unset?delete h[e]:h[e]=a;!f.isEqual(j[e],a)||f.has(h,e)!=f.has(j,e)?(this.changed[e]=a,c.silent||(this._pending[e]=!0)):(delete this.changed[e],delete this._pending[e])}c.silent||this.change(c);return this},unset:function(a,b){(b||(b={})).unset=!0;return this.set(a,null,b)},clear:function(a){(a||(a={})).unset=!0;return this.set(f.clone(this.attributes),a)},fetch:function(a){var a=a?f.clone(a):{},b=this,c=a.success;a.success=function(d,e,f){if(!b.set(b.parse(d,f),a))return!1;c&&c(b,d)}; -a.error=g.wrapError(a.error,b,a);return(this.sync||g.sync).call(this,"read",this,a)},save:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c=c?f.clone(c):{};if(c.wait){if(!this._validate(d,c))return!1;e=f.clone(this.attributes)}a=f.extend({},c,{silent:!0});if(d&&!this.set(d,c.wait?a:c))return!1;var h=this,i=c.success;c.success=function(a,b,e){b=h.parse(a,e);if(c.wait){delete c.wait;b=f.extend(d||{},b)}if(!h.set(b,c))return false;i?i(h,a):h.trigger("sync",h,a,c)};c.error=g.wrapError(c.error, -h,c);b=this.isNew()?"create":"update";b=(this.sync||g.sync).call(this,b,this,c);c.wait&&this.set(e,a);return b},destroy:function(a){var a=a?f.clone(a):{},b=this,c=a.success,d=function(){b.trigger("destroy",b,b.collection,a)};if(this.isNew())return d(),!1;a.success=function(e){a.wait&&d();c?c(b,e):b.trigger("sync",b,e,a)};a.error=g.wrapError(a.error,b,a);var e=(this.sync||g.sync).call(this,"delete",this,a);a.wait||d();return e},url:function(){var a=n(this,"urlRoot")||n(this.collection,"url")||t(); -return this.isNew()?a:a+("/"==a.charAt(a.length-1)?"":"/")+encodeURIComponent(this.id)},parse:function(a){return a},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return null==this.id},change:function(a){a||(a={});var b=this._changing;this._changing=!0;for(var c in this._silent)this._pending[c]=!0;var d=f.extend({},a.changes,this._silent);this._silent={};for(c in d)this.trigger("change:"+c,this,this.get(c),a);if(b)return this;for(;!f.isEmpty(this._pending);){this._pending= -{};this.trigger("change",this,a);for(c in this.changed)!this._pending[c]&&!this._silent[c]&&delete this.changed[c];this._previousAttributes=f.clone(this.attributes)}this._changing=!1;return this},hasChanged:function(a){return!arguments.length?!f.isEmpty(this.changed):f.has(this.changed,a)},changedAttributes:function(a){if(!a)return this.hasChanged()?f.clone(this.changed):!1;var b,c=!1,d=this._previousAttributes,e;for(e in a)if(!f.isEqual(d[e],b=a[e]))(c||(c={}))[e]=b;return c},previous:function(a){return!arguments.length|| -!this._previousAttributes?null:this._previousAttributes[a]},previousAttributes:function(){return f.clone(this._previousAttributes)},isValid:function(){return!this.validate(this.attributes)},_validate:function(a,b){if(b.silent||!this.validate)return!0;var a=f.extend({},this.attributes,a),c=this.validate(a,b);if(!c)return!0;b&&b.error?b.error(this,c,b):this.trigger("error",this,c,b);return!1}});var r=g.Collection=function(a,b){b||(b={});b.model&&(this.model=b.model);b.comparator&&(this.comparator=b.comparator); -this._reset();this.initialize.apply(this,arguments);a&&this.reset(a,{silent:!0,parse:b.parse})};f.extend(r.prototype,k,{model:o,initialize:function(){},toJSON:function(a){return this.map(function(b){return b.toJSON(a)})},add:function(a,b){var c,d,e,g,i,j={},k={},l=[];b||(b={});a=f.isArray(a)?a.slice():[a];c=0;for(d=a.length;c=b))this.iframe=i('\') + .dialog({ + autoOpen: false, + modal: true, + height: 500, + width: \'80%\', + title: "'.dol_escape_js($langs->trans("FileManager")).'" + }); + $dialog.dialog(\'open\'); + }); + }); + '; + */ + } + + print ''; + + // Button for website + print '
    '; + + if ($action == 'preview' || $action == 'createfromclone' || $action == 'createpagefromclone') + { + print 'transnoentitiesnoconv("Site"), $langs->transnoentitiesnoconv("Site"), $urlint)).'">'; + print $form->textwithpicto('', $langs->trans("PreviewSiteServedByDolibarr", $langs->transnoentitiesnoconv("Site"), $langs->transnoentitiesnoconv("Site"), $urlint, $dataroot), 1, 'preview'); + print ''; + + print '
    '; + print ''; + //print ''; + $htmltext=$langs->trans("SetHereVirtualHost", $dataroot); + print $form->textwithpicto('', $htmltext, 1, 'help', '', 0, 2, 'helpvirtualhost'); + print '
    '; + + $urlext=$virtualurl; + $urlint=$urlwithroot.'/public/website/index.php?website='.$website; + print 'transnoentitiesnoconv("Site"), $langs->transnoentitiesnoconv("Site"), $dataroot, $urlext)).'">'; + print $form->textwithpicto('', $langs->trans("PreviewSiteServedByWebServer", $langs->transnoentitiesnoconv("Site"), $langs->transnoentitiesnoconv("Site"), $dataroot, $urlext?$urlext:''.$langs->trans("VirtualHostUrlNotDefined").''), 1, 'preview_ext'); + print ''; + } + + if (in_array($action, array('editcss','editmenu','file_manager'))) + { + if (preg_match('/^create/',$action) && $action != 'file_manager') print ''; + if (preg_match('/^edit/',$action) && $action != 'file_manager') print ''; + if ($action != 'preview') print ''; + } + + print '
    '; + + + // ***** Part for pages + + if ($website && ! in_array($action, array('editcss','editmenu'))) + { + print ''; // Close current websitebar to open a new one + + $array=$objectpage->fetchAll($object->id); + if (! is_array($array) && $array < 0) dol_print_error('', $objectpage->error, $objectpage->errors); + $atleastonepage=(is_array($array) && count($array) > 0); + + print '
    '; + + print '
    '; + print $langs->trans("PageContainer").': '; + print '
    '; + + print '
    '; + print ''; + print '
    '; + + print '
    '; + + if ($action != 'addcontainer') + { + $out=''; + $out.=''; + $out.=ajax_combobox('pageid'); + print $out; + } + else + { + print $langs->trans("New"); + } + + //print ''; + print ''; + + if ($action == 'preview' || $action == 'createfromclone' || $action == 'createpagefromclone') + { + $disabled=''; + if (empty($user->rights->website->write)) $disabled=' disabled="disabled"'; + + // Confirmation to clone + if ($action == 'createfromclone') { + // Create an array for form + $formquestion = array( + array('type' => 'text', 'name' => 'siteref', 'label'=> $langs->trans("WebSite") ,'value'=> 'copy_of_'.$object->ref), + //array('type' => 'checkbox', 'name' => 'is_a_translation', 'label' => $langs->trans("SiteIsANewTranslation"), 'value' => 0), + //array('type' => 'other','name' => 'newlang','label' => $langs->trans("Language"), 'value' => $formadmin->select_language(GETPOST('newlang', 'az09')?GETPOST('newlang', 'az09'):$langs->defaultlang, 'newlang', 0, null, '', 0, 0, 'minwidth200')), + //array('type' => 'other','name' => 'newwebsite','label' => $langs->trans("WebSite"), 'value' => $formwebsite->selectWebsite($object->id, 'newwebsite', 0)) + ); + + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id='.$object->id, $langs->trans('CloneSite'), '', 'confirm_createfromclone', $formquestion, 0, 1, 200); + + print $formconfirm; + } + + if ($pageid > 0) + { + // Confirmation to clone + if ($action == 'createpagefromclone') { + // Create an array for form + $formquestion = array( + array('type' => 'text', 'name' => 'pageurl', 'label'=> $langs->trans("WEBSITE_PAGENAME") ,'value'=> 'copy_of_'.$objectpage->pageurl), + array('type' => 'checkbox', 'name' => 'is_a_translation', 'label' => $langs->trans("PageIsANewTranslation"), 'value' => 0), + array('type' => 'other','name' => 'newlang','label' => $langs->trans("Language"), 'value' => $formadmin->select_language(GETPOST('newlang', 'az09')?GETPOST('newlang', 'az09'):$langs->defaultlang, 'newlang', 0, null, 1, 0, 0, 'minwidth200')), + array('type' => 'other','name' => 'newwebsite','label' => $langs->trans("WebSite"), 'value' => $formwebsite->selectWebsite($object->id, 'newwebsite', 0)), + ); + + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?website='.$object->ref.'&pageid=' . $pageid, $langs->trans('ClonePage'), '', 'confirm_createpagefromclone', $formquestion, 0, 1, 300, 550); + + print $formconfirm; + } + + print '   '; + + print ''; + print ''; + print ''; + if ($object->fk_default_home > 0 && $pageid == $object->fk_default_home) print ''; + else print ''; + print ''; + print ''; + } + } + + print '
    '; // end website selection + + print '
    '; + + if ($website && $pageid > 0 && ($action == 'preview' || $action == 'createfromclone' || $action == 'createpagefromclone')) + { + $websitepage = new WebSitePage($db); + $websitepage->fetch($pageid); + + $realpage=$urlwithroot.'/public/website/index.php?website='.$website.'&pageref='.$websitepage->pageurl; + $pagealias = $websitepage->pageurl; + + print 'transnoentitiesnoconv("Page"), $langs->transnoentitiesnoconv("Page"), $realpage)).'">'; + print $form->textwithpicto('', $langs->trans("PreviewSiteServedByDolibarr", $langs->transnoentitiesnoconv("Page"), $langs->transnoentitiesnoconv("Page"), $realpage, $dataroot), 1, 'preview'); + print ''; // View page in new Tab + + print '
    '; + print ''; + $htmltext=$langs->trans("PageNameAliasHelp", $langs->transnoentitiesnoconv("EditPageMeta")); + print $form->textwithpicto('', $htmltext, 1, 'help', '', 0, 2, 'helppagealias'); + print '
    '; + + $urlext=$virtualurl.'/'.$pagealias.'.php'; + $urlint=$urlwithroot.'/public/website/index.php?website='.$website; + print 'transnoentitiesnoconv("Page"), $langs->transnoentitiesnoconv("Page"), $dataroot, $urlext)).'">'; + print $form->textwithpicto('', $langs->trans("PreviewSiteServedByWebServer", $langs->transnoentitiesnoconv("Page"), $langs->transnoentitiesnoconv("Page"), $dataroot, $virtualurl?$urlext:''.$langs->trans("VirtualHostUrlNotDefined").''), 1, 'preview_ext'); + print ''; + //print ''; + + // TODO Add js to save alias like we save virtual host name and use dynamic virtual host for url of id=previewpageext + } + if (! in_array($action, array('editcss','editmenu','file_manager','createsite','createcontainer','createpagefromclone'))) + { + if (preg_match('/^create/',$action)) print ''; + if (preg_match('/^edit/',$action)) print ''; + if ($action != 'preview') print ''; + } + + print '
    '; // end websitetools + + print '
    '; + if (GETPOST('editsource', 'alpha') || GETPOST('editcontent', 'alpha')) + { + $htmltext=$langs->transnoentitiesnoconv("YouCanEditHtmlSource").'
    '; + print $form->textwithpicto($langs->trans("SyntaxHelp"), $htmltext, 1, 'help', 'inline-block', 1, 2, 'tooltipsubstitution'); + } + print '
    '; // end websitehelp + + + + if ($action == 'preview' || $action == 'createfromclone' || $action == 'createpagefromclone') + { + // Adding jquery code to change on the fly url of preview ext + if (! empty($conf->use_javascript_ajax)) + { + print ''; + } + } + } +} +else +{ + print '
    '; + $langs->load("errors"); + print $langs->trans("ErrorModuleSetupNotComplete"); + print '
    '; + $action=''; +} + +print '
    '; // end current websitebar +} + + + +$head = array(); + + +/* + * Edit Site HTML header and CSS + */ + +if ($action == 'editcss') +{ + print '
    '; + + print '
    '; + if (GETPOST('editcss','alpha') || GETPOST('refreshpage','alpha')) + { + $csscontent = @file_get_contents($filecss); + // Clean the php css file to remove php code and get only css part + $csscontent = preg_replace('/<\?php \/\/ BEGIN PHP[^\?]*END PHP \?>\n*/ims', '', $csscontent); + } + else + { + $csscontent = GETPOST('WEBSITE_CSS_INLINE'); + } + if (! trim($csscontent)) $csscontent='/* CSS content (all pages) */'."\n"."body.bodywebsite { margin: 0; font-family: 'Open Sans', sans-serif; }\n.bodywebsite h1 { margin-top: 0; margin-bottom: 0; padding: 10px;}"; + + if (GETPOST('editcss','alpha') || GETPOST('refreshpage','alpha')) + { + $jscontent = @file_get_contents($filejs); + // Clean the php js file to remove php code and get only js part + $jscontent = preg_replace('/<\?php \/\/ BEGIN PHP[^\?]*END PHP \?>\n*/ims', '', $jscontent); + } + else + { + $jscontent = GETPOST('WEBSITE_JS_INLINE'); + } + if (! trim($jscontent)) $jscontent='/* JS content (all pages) */'."\n"; + + if (GETPOST('editcss','alpha') || GETPOST('refreshpage','alpha')) + { + $htmlheadercontent = @file_get_contents($filehtmlheader); + // Clean the php htmlheader file to remove php code and get only html part + $htmlheadercontent = preg_replace('/<\?php \/\/ BEGIN PHP[^\?]*END PHP \?>\n*/ims', '', $htmlheadercontent); + } + else + { + $htmlheadercontent = GETPOST('WEBSITE_HTML_HEADER'); + } + if (! trim($htmlheadercontent)) + { + $htmlheadercontent ="\n"; + $htmlheadercontent.=$htmlheadercontentdefault; + $htmlheadercontent.=""; + } + else + { + $htmlheadercontent = preg_replace('/^\s*/ims', '', $htmlheadercontent); + $htmlheadercontent = preg_replace('/<\/html>\s*$/ims', '', $htmlheadercontent); + $htmlheadercontent=''."\n".trim($htmlheadercontent)."\n".''; + } + + if (GETPOST('editcss','alpha') || GETPOST('refreshpage','alpha')) + { + $robotcontent = @file_get_contents($filerobot); + // Clean the php htmlheader file to remove php code and get only html part + $robotcontent = preg_replace('/<\?php \/\/ BEGIN PHP[^\?]*END PHP \?>\n*/ims', '', $robotcontent); + } + else + { + $robotcontent = GETPOST('WEBSITE_ROBOT'); + } + if (! trim($robotcontent)) + { + $robotcontent.="# Robot file. Generated with ".DOL_APPLICATION_TITLE."\n"; + $robotcontent.="User-agent: *\n"; + $robotcontent.="Allow: /public/\n"; + $robotcontent.="Disallow: /administrator/\n"; + } + + if (GETPOST('editcss','alpha') || GETPOST('refreshpage','alpha')) + { + $htaccesscontent = @file_get_contents($filehtaccess); + // Clean the php htaccesscontent file to remove php code and get only html part + $htaccesscontent = preg_replace('/<\?php \/\/ BEGIN PHP[^\?]*END PHP \?>\n*/ims', '', $htaccesscontent); + } + else + { + $htaccesscontent = GETPOST('WEBSITE_HTACCESS'); + } + if (! trim($htaccesscontent)) + { + $htaccesscontent.="# Order allow,deny\n"; + $htaccesscontent.="# Deny from all\n"; + } + //else $htaccesscontent=''."\n".$htaccesscontent."\n".'';*/ + + dol_fiche_head(); + + print ''."\n"; + print ''; + + // Website + print ''; + + // CSS file + print ''; + + // JS file + print ''; + + // Common HTML header + print ''; + + // Robot file + print ''; + + // .htaccess + print ''; + + print '
    '; + print $langs->trans('WebSite'); + print ''; + print $website; + print '
    '; + print $langs->trans('WEBSITE_CSS_INLINE'); + print ''; + + $doleditor=new DolEditor('WEBSITE_CSS_INLINE', $csscontent, '', '220', 'ace', 'In', true, false, 'ace', 0, '100%', ''); + print $doleditor->Create(1, '', true, 'CSS', 'css'); + + print '
    '; + print $langs->trans('WEBSITE_JS_INLINE'); + print ''; + + $doleditor=new DolEditor('WEBSITE_JS_INLINE', $jscontent, '', '220', 'ace', 'In', true, false, 'ace', 0, '100%', ''); + print $doleditor->Create(1, '', true, 'JS', 'javascript'); + + print '
    '; + $htmlhelp=$langs->trans("Example").' :
    '; + $htmlhelp.=dol_htmlentitiesbr($htmlheadercontentdefault); + print $form->textwithpicto($langs->trans('WEBSITE_HTML_HEADER'), $htmlhelp, 1, 'help', '', 0, 2, 'htmlheadertooltip'); + print '
    '; + + $doleditor=new DolEditor('WEBSITE_HTML_HEADER', $htmlheadercontent, '', '220', 'ace', 'In', true, false, 'ace', 0, '100%', ''); + print $doleditor->Create(1, '', true, 'HTML Header', 'html'); + + print '
    '; + print $langs->trans('WEBSITE_ROBOT'); + print ''; + + $doleditor=new DolEditor('WEBSITE_ROBOT', $robotcontent, '', '220', 'ace', 'In', true, false, 'ace', 0, '100%', ''); + print $doleditor->Create(1, '', true, 'Robot file', 'text'); + + print '
    '; + print $langs->trans('WEBSITE_HTACCESS'); + print ''; + + $doleditor=new DolEditor('WEBSITE_HTACCESS', $htaccesscontent, '', '220', 'ace', 'In', true, false, 'ace', 0, '100%', ''); + print $doleditor->Create(1, '', true, $langs->trans("File").' .htaccess', 'text'); + + print '
    '; + + dol_fiche_end(); + + print '
    '; + + print '
    '; +} + +if ($action == 'createsite') +{ + print '
    '; + + print '
    '; + + /*$h = 0; + $head = array(); + + $head[$h][0] = dol_buildpath('/website/index.php',1).'?id='.$object->id; + $head[$h][1] = $langs->trans("AddSite"); + $head[$h][2] = 'card'; + $h++; + + dol_fiche_head($head, 'card', $langs->trans("AddSite"), -1, 'globe'); + */ + if ($action == 'createcontainer') print_fiche_titre($langs->trans("AddSite")); + + print ''."\n"; + //print '
    '; + + print ''; + + if (GETPOST('WEBSITE_REF')) $siteref=GETPOST('WEBSITE_REF','alpha'); + if (GETPOST('WEBSITE_DESCRIPTION')) $sitedesc=GETPOST('WEBSITE_DESCRIPTION','alpha'); + + print ''; + + print ''; + + print ''; + + + print '
    '; + print $langs->trans('Ref'); + print ''; + print ''; + print '
    '; + print $langs->trans('Description'); + print ''; + print ''; + print '
    '; + print $form->textwithpicto($langs->trans('Virtualhost'), $langs->trans("SetHereVirtualHost", DOL_DATA_ROOT.'/website/websiteref'), 1, 'help', '', 0, 2, 'tooltipvirtual'); + print ''; + print ''; + print '
    '; + + if ($action == 'createsite') + { + print '
    '; + + print ''; + print ''; + + print '
    '; + } + + + //print '
    '; + + //dol_fiche_end(); + + print '
    '; + + print '
    '; +} + +if ($action == 'editmeta' || $action == 'createcontainer') +{ + print '
    '; + + print '
    '; + + /*$h = 0; + $head = array(); + + $head[$h][0] = dol_buildpath('/website/index.php',1).'?id='.$object->id; + $head[$h][1] = $langs->trans("AddPage"); + $head[$h][2] = 'card'; + $h++; + + dol_fiche_head($head, 'card', $langs->trans("AddPage"), -1, 'globe'); + */ + if ($action == 'createcontainer') print_fiche_titre($langs->trans("AddPage")); + + print ''."\n"; + //print '
    '; + + if ($conf->global->MAIN_FEATURES_LEVEL >= 1) + { + if ($action == 'createcontainer') + { + print '
    '; + + print ' * '.$langs->trans("CreateByFetchingExternalPage").'

    '; + print ''; + print ''; + print '
    '; + print $langs->trans("URL"); + print ''; + print ' '; + print ''; + print '
    '; + + print '
    '; + + print ' * '.$langs->trans("OrEnterPageInfoManually").'

    '; + } + } + + print ''; + + if ($action != 'createcontainer') + { + print ''; + + print ''; + + /* + print ''; + */ + + $type_container=$objectpage->type_container; + $pageurl=$objectpage->pageurl; + $pagetitle=$objectpage->title; + $pagedescription=$objectpage->description; + $pagekeywords=$objectpage->keywords; + $pagelang=$objectpage->lang; + $pagehtmlheader=$objectpage->htmlheader; + } + if (GETPOST('WEBSITE_PAGENAME','alpha')) $pageurl=GETPOST('WEBSITE_PAGENAME','alpha'); + if (GETPOST('WEBSITE_TITLE','alpha')) $pagetitle=GETPOST('WEBSITE_TITLE','alpha'); + if (GETPOST('WEBSITE_DESCRIPTION','alpha')) $pagedescription=GETPOST('WEBSITE_DESCRIPTION','alpha'); + if (GETPOST('WEBSITE_KEYWORDS','alpha')) $pagekeywords=GETPOST('WEBSITE_KEYWORDS','alpha'); + if (GETPOST('WEBSITE_LANG','aZ09')) $pagelang=GETPOST('WEBSITE_LANG','aZ09'); + if (GETPOST('htmlheader','none')) $pagehtmlheader=GETPOST('htmlheader','none'); + + print ''; + + print ''; + + print ''; + + print ''; + + print ''; + + print ''; + + print ''; + + print '
    '; + print $langs->trans('IDOfPage'); + print ''; + print $pageid; + print '
    '; + print $langs->trans('WEBSITE_PAGEURL'); + print ''; + print '/public/website/index.php?website='.urlencode($website).'&pageid='.urlencode($pageid); + print '
    '; + print $langs->trans('InitiallyGrabbedFrom'); + print ''; + print $objectpage->grabbed_from; + print '
    '; + print $langs->trans('WEBSITE_TYPE_CONTAINER'); + print ''; + $arrayoftype=array('page'=>$langs->trans("Page"), 'banner'=>$langs->trans("Banner"), 'blogpost'=>$langs->trans("BlogPost"), 'other'=>$langs->trans("Other")); + print $form->selectarray('WEBSITE_TYPE_CONTAINER', $arrayoftype, $type_container); + print '
    '; + print $langs->trans('WEBSITE_PAGENAME'); + print ''; + print ''; + print '
    '; + print $langs->trans('WEBSITE_TITLE'); + print ''; + print ''; + print '
    '; + print $langs->trans('WEBSITE_DESCRIPTION'); + print ''; + print ''; + print '
    '; + print $langs->trans('WEBSITE_KEYWORDS'); + print ''; + print ''; + print '
    '; + print $langs->trans('Language'); + print ''; + print $formadmin->select_language($pagelang?$pagelang:$langs->defaultlang, 'WEBSITE_LANG', 0, null, '1'); + print '
    '; + $htmlhelp=$langs->trans("EditTheWebSiteForACommonHeader").'

    '; + + $htmlhelp=$langs->trans("Example").' :
    '; + $htmlhelp.=dol_htmlentitiesbr($htmlheadercontentdefault); + + print $form->textwithpicto($langs->trans('HtmlHeaderPage'), $htmlhelp, 1, 'help', '', 0, 2, 'htmlheadertooltip'); + print '
    '; + $doleditor=new DolEditor('htmlheader', $pagehtmlheader, '', '220', 'ace', 'In', true, false, 'ace', 0, '100%', ''); + print $doleditor->Create(1, '', true, 'HTML Header', 'html'); + print '
    '; + + if ($action == 'createcontainer') + { + print '
    '; + + print ''; + print ''; + + print '
    '; + } + + + //print '
    '; + + //dol_fiche_end(); + + print '
    '; + + print '
    '; +} + +if ($action == 'editfile' || $action == 'file_manager') +{ + print ''."\n"; + print '


    '; + //print '
    '.$langs->trans("FeatureNotYetAvailable").''; + + $module = 'medias'; + if (empty($url)) $url=DOL_URL_ROOT.'/website/index.php'; // Must be an url without param + include DOL_DOCUMENT_ROOT.'/core/tpl/filemanager.tpl.php'; + + print '
    '; + +} + +if ($action == 'editmenu') +{ + print ''."\n"; + print '
    '.$langs->trans("FeatureNotYetAvailable").''; +} + +if ($action == 'editsource') +{ + /* + * Editing with source editor + */ + + $contentforedit = ''; + /*$contentforedit.=''."\n";*/ + $contentforedit .= $objectpage->content; + + require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; + $doleditor=new DolEditor('PAGE_CONTENT',$contentforedit,'',500,'Full','',true,true,'ace',ROWS_5,'90%'); + $doleditor->Create(0, '', false, 'HTML Source', 'php'); +} + +if ($action == 'editcontent') +{ + /* + * Editing with default ckeditor + */ + + $contentforedit = ''; + /*$contentforedit.=''."\n";*/ + $contentforedit .= $objectpage->content; + + $contentforedit = preg_replace('/(Create(0, '', false); +} + +print "
    \n\n"; + + + +if ($action == 'preview' || $action == 'createfromclone' || $action == 'createpagefromclone') +{ + if ($pageid > 0) + { + // Ouput page under the Dolibarr top menu + $objectpage->fetch($pageid); + $csscontent = @file_get_contents($filecss); + $jscontent = @file_get_contents($filejs); + + $out = ''."\n"; + + $out.='
    '."\n"; + // TODO Use contenteditable="true" / document.getElementById("myP").contentEditable="true" for part coming from CKEditor + + + // REPLACEMENT OF LINKS When page called by website editor + + $out.=')', $objectpage->htmlheader); + $tmpstyleinheader =''; + $i=0; + foreach($tmp as $valtmp) + { + $i++; + if ($i % 2 == 0) $tmpstyleinheader.=$valtmp."\n"; + } + $tmpout.= $tmpstyleinheader."\n"; + // Clean style that may affect global style of Dolibarr + $tmpout=preg_replace('/}[\s\n]*body\s*{[^}]+}/ims','}',$tmpout); + $out.=$tmpout; + $out.=''."\n"; + + // Do not enable the contenteditable when page was grabbed, ckeditor is removing span and adding borders, + // so editable will be available from container created from scratch + //$out.='
    grabbed_from ? ' contenteditable="true"' : '').'>'."\n"; + $out.='
    '."\n"; + + $out.=dolWebsiteReplacementOfLinks($object, $objectpage->content)."\n"; + + $out.='
    '; + + $out.='
    '; + + $out.= "\n".''."\n\n"; + + // For jqueryscoped (does not work as expected) + //$out.=""; + + print $out; + + /*file_put_contents($filetpl, $out); + if (! empty($conf->global->MAIN_UMASK)) + @chmod($filetpl, octdec($conf->global->MAIN_UMASK)); + + // Output file on browser + dol_syslog("index.php include $filetpl $filename content-type=$type"); + $original_file_osencoded=dol_osencode($filetpl); // New file name encoded in OS encoding charset + + // This test if file exists should be useless. We keep it to find bug more easily + if (! file_exists($original_file_osencoded)) + { + dol_print_error(0,$langs->trans("ErrorFileDoesNotExists",$original_file)); + exit; + } + + //include_once $original_file_osencoded; + */ + + /*print '';*/ + } + else + { + print '

    '.$langs->trans("PreviewOfSiteNotYetAvailable", $website).'


    '; + print '
    '; + } +} + + + +llxFooter(); + +$db->close(); diff --git a/htdocs/website/lib/websiteaccount.lib.php b/htdocs/website/lib/websiteaccount.lib.php new file mode 100644 index 00000000000..95ae071d971 --- /dev/null +++ b/htdocs/website/lib/websiteaccount.lib.php @@ -0,0 +1,85 @@ + + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/website/lib/websiteaccount.lib.php + * \ingroup website + * \brief Library files with common functions for WebsiteAccount + */ + +/** + * Prepare array of tabs for WebsiteAccount + * + * @param WebsiteAccount $object WebsiteAccount + * @return array Array of tabs + */ +function websiteaccountPrepareHead($object) +{ + global $db, $langs, $conf; + + $langs->load("monmodule@monmodule"); + + $h = 0; + $head = array(); + + $head[$h][0] = dol_buildpath("/website/websiteaccount_card.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans("Card"); + $head[$h][2] = 'card'; + $h++; + + /*if (isset($object->fields['note_public']) || isset($object->fields['note_private'])) + { + $nbNote = 0; + if(!empty($object->fields['note_private'])) $nbNote++; + if(!empty($object->fields['note_public'])) $nbNote++; + $head[$h][0] = dol_buildpath('/monmodule/websiteaccount_note.php', 1).'?id='.$object->id; + $head[$h][1] = $langs->trans('Notes'); + if ($nbNote > 0) $head[$h][1].= ' '.$nbNote.''; + $head[$h][2] = 'note'; + $h++; + }*/ + + /* + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php'; + $upload_dir = $conf->monmodule->dir_output . "/websiteaccount/" . dol_sanitizeFileName($object->ref); + $nbFiles = count(dol_dir_list($upload_dir,'files',0,'','(\.meta|_preview.*\.png)$')); + $nbLinks=Link::count($db, $object->element, $object->id); + $head[$h][0] = dol_buildpath("/monmodule/websiteaccount_document.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans('Documents'); + if (($nbFiles+$nbLinks) > 0) $head[$h][1].= ' '.($nbFiles+$nbLinks).''; + $head[$h][2] = 'document'; + $h++; + + $head[$h][0] = dol_buildpath("/monmodule/websiteaccount_agenda.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans("Events"); + $head[$h][2] = 'agenda'; + $h++; + */ + + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + //$this->tabs = array( + // 'entity:+tabname:Title:@monmodule:/monmodule/mypage.php?id=__ID__' + //); // to add new tab + //$this->tabs = array( + // 'entity:-tabname:Title:@monmodule:/monmodule/mypage.php?id=__ID__' + //); // to remove a tab + complete_head_from_modules($conf, $langs, $object, $head, $h, 'websiteaccount@website'); + + return $head; +} diff --git a/htdocs/website/pagetemplate.html b/htdocs/website/pagetemplate.html new file mode 100644 index 00000000000..a6e4e64c871 --- /dev/null +++ b/htdocs/website/pagetemplate.html @@ -0,0 +1,15 @@ +
    +

    __[MAIN_INFO_SOCIETE_NOM]__


    +__(MyContainerTitle)__ +
    +
    +
    +
    +
    __(AnotherContainer)__
    +
    +
    +
    +
    +
    __WEBSITE_CREATE_BY__
    +
    +
    \ No newline at end of file diff --git a/htdocs/website/websiteaccount_card.php b/htdocs/website/websiteaccount_card.php new file mode 100644 index 00000000000..9918b0b3022 --- /dev/null +++ b/htdocs/website/websiteaccount_card.php @@ -0,0 +1,428 @@ + +* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/Website/websiteaccount_card.php + * \ingroup website + * \brief Page to create/edit/view websiteaccount + */ + +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER','1'); +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB','1'); +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC','1'); +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN','1'); +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION','1'); // Do not check anti CSRF attack test +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION','1'); // Do not check anti CSRF attack test +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK','1'); // Do not check anti CSRF attack test done when option MAIN_SECURITY_CSRF_WITH_TOKEN is on. +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK','1'); // Do not check style html tag into posted data +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL','1'); // Do not check anti POST attack test +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU','1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML','1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX','1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN",'1'); // If this page is public (can be called outside logged session) + +// Load Dolibarr environment +$res=0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (! $res && ! empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) $res=@include($_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"); +// Try main.inc.php into web root detected using web root caluclated from SCRIPT_FILENAME +$tmp=empty($_SERVER['SCRIPT_FILENAME'])?'':$_SERVER['SCRIPT_FILENAME'];$tmp2=realpath(__FILE__); $i=strlen($tmp)-1; $j=strlen($tmp2)-1; +while($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i]==$tmp2[$j]) { $i--; $j--; } +if (! $res && $i > 0 && file_exists(substr($tmp, 0, ($i+1))."/main.inc.php")) $res=@include(substr($tmp, 0, ($i+1))."/main.inc.php"); +if (! $res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i+1)))."/main.inc.php")) $res=@include(dirname(substr($tmp, 0, ($i+1)))."/main.inc.php"); +// Try main.inc.php using relative path +if (! $res && file_exists("../main.inc.php")) $res=@include("../main.inc.php"); +if (! $res && file_exists("../../main.inc.php")) $res=@include("../../main.inc.php"); +if (! $res && file_exists("../../../main.inc.php")) $res=@include("../../../main.inc.php"); +if (! $res) die("Include of main fails"); + +include_once(DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'); +include_once(DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'); +include_once(DOL_DOCUMENT_ROOT.'/website/class/websiteaccount.class.php'); +include_once(DOL_DOCUMENT_ROOT.'/website/lib/websiteaccount.lib.php'); + +// Load traductions files requiredby by page +$langs->loadLangs(array("website","other")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'alpha'); +$cancel = GETPOST('cancel', 'aZ09'); +$backtopage = GETPOST('backtopage', 'alpha'); + +// Initialize technical objects +$object=new WebsiteAccount($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction=$conf->website->dir_output . '/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('websiteaccountcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extralabels = $extrafields->fetch_name_optionals_label('websiteaccount'); +$search_array_options=$extrafields->getOptionalsFromPost($extralabels,'','search_'); + +// Initialize array of search criterias +$search_all=trim(GETPOST("search_all",'alpha')); +$search=array(); +foreach($object->fields as $key => $val) +{ + if (GETPOST('search_'.$key,'alpha')) $search[$key]=GETPOST('search_'.$key,'alpha'); +} + +if (empty($action) && empty($id) && empty($ref)) $action='view'; + +// Security check - Protection if external user +//if ($user->societe_id > 0) access_forbidden(); +//if ($user->societe_id > 0) $socid = $user->societe_id; +//$result = restrictedArea($user, 'website', $id); + +// fetch optionals attributes and labels +$extralabels = $extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals + + + +/* + * Actions + */ + +$parameters=array(); +$reshook=$hookmanager->executeHooks('doActions',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + +if (empty($reshook)) +{ + $error=0; + + $permissiontoadd = $user->rights->website->write; + $permissiontodelete = $user->rights->website->delete; + $backurlforlist = dol_buildpath('/website/websiteaccount_list.php',1); + + // Actions cancel, add, update or delete + include DOL_DOCUMENT_ROOT.'/core/actions_addupdatedelete.inc.php'; + + // Actions when printing a doc from card + include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php'; + + // Actions to send emails + $trigger_name='MYOBJECT_SENTBYMAIL'; + $autocopy='MAIN_MAIL_AUTOCOPY_MYOBJECT_TO'; + $trackid='websiteaccount'.$object->id; + include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php'; +} + + +/* + * View + */ + +$form=new Form($db); +$formfile=new FormFile($db); + +llxHeader('','WebsiteAccount',''); + +// Example : Adding jquery code +print ''; + + +// Part to create +if ($action == 'create') +{ + print load_fiche_titre($langs->trans("NewObject", $langs->transnoentitiesnoconv("WebsiteAccount"))); + + print '
    '; + print ''; + print ''; + print ''; + + dol_fiche_head(); + + print ''."\n"; + + // Common attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_add.tpl.php'; + + // Other attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_add.tpl.php'; + + print '
    '."\n"; + + dol_fiche_end(); + + print '
    '; + print ''; + print '  '; + print ''; // Cancel for create does not post form if we don't know the backtopage + print '
    '; + + print '
    '; +} + +// Part to edit record +if (($id || $ref) && $action == 'edit') +{ + print load_fiche_titre($langs->trans("WebsiteAccount")); + + print '
    '; + print ''; + print ''; + print ''; + + dol_fiche_head(); + + print ''."\n"; + + // Common attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_edit.tpl.php'; + + // Other attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_edit.tpl.php'; + + print '
    '; + + dol_fiche_end(); + + print '
    '; + print '   '; + print '
    '; + + print '
    '; +} + +// Part to show record +if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) +{ + if ($object->fk_soc >0 && empty($socid)) $socid = $object->fk_soc; + + $res = $object->fetch_optionals($object->id, $extralabels); + + $head = websiteaccountPrepareHead($object); + dol_fiche_head($head, 'card', $langs->trans("WebsiteAccount"), -1, 'websiteaccount@website'); + + $formconfirm = ''; + + // Confirmation to delete + if ($action == 'delete') { + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('DeleteWebsiteAccount'), $langs->trans('ConfirmDeleteWebsiteAccount'), 'confirm_delete', '', 0, 1); + } + + // Confirmation of action xxxx + if ($action == 'xxx') + { + $formquestion=array(); + /* + $formquestion = array( + // 'text' => $langs->trans("ConfirmClone"), + // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1), + // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1), + // array('type' => 'other', 'name' => 'idwarehouse', 'label' => $langs->trans("SelectWarehouseForStockDecrease"), 'value' => $formproduct->selectWarehouses(GETPOST('idwarehouse')?GETPOST('idwarehouse'):'ifone', 'idwarehouse', '', 1))); + }*/ + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('XXX'), $text, 'confirm_xxx', $formquestion, 0, 1, 220); + } + + if (! $formconfirm) { + $parameters = array('lineid' => $lineid); + $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if (empty($reshook)) $formconfirm.=$hookmanager->resPrint; + elseif ($reshook > 0) $formconfirm=$hookmanager->resPrint; + } + + // Print form confirm + print $formconfirm; + + + // Object card + // ------------------------------------------------------------ + $linkback=''; + if ($socid) $linkback = '' . $langs->trans("BackToListOfThirdParty") . ''; + if ($fk_website) $linkback = '' . $langs->trans("BackToList") . ''; + + $morehtmlref='
    '; + /* + // Ref bis + $morehtmlref.=$form->editfieldkey("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->website->creer, 'string', '', 0, 1); + $morehtmlref.=$form->editfieldval("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->website->creer, 'string', '', null, null, '', 1); + // Thirdparty + $morehtmlref.='
    '.$langs->trans('ThirdParty') . ' : ' . $soc->getNomUrl(1); + // Project + if (! empty($conf->projet->enabled)) + { + $langs->load("projects"); + $morehtmlref.='
    '.$langs->trans('Project') . ' '; + if ($user->rights->website->creer) + { + if ($action != 'classify') + { + $morehtmlref.='' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; + if ($action == 'classify') { + //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref.='
    '; + $morehtmlref.=''; + $morehtmlref.=''; + $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref.=''; + $morehtmlref.='
    '; + } else { + $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } + } + } else { + if (! empty($object->fk_project)) { + $proj = new Project($db); + $proj->fetch($object->fk_project); + $morehtmlref.=''; + $morehtmlref.=$proj->ref; + $morehtmlref.=''; + } else { + $morehtmlref.=''; + } + } + } + */ + $morehtmlref.='
    '; + + if ($socid > 0) $object->next_prev_filter = 'te.fk_soc = '.$socid; + + dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'rowid', $morehtmlref); + + + print '
    '; + print '
    '; + print '
    '; + print ''."\n"; + + // Common attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_view.tpl.php'; + + // Other attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php'; + + print '
    '; + print '
    '; + print '
    '; + print '
    '; + + print '

    '; + + dol_fiche_end(); + + + // Buttons for actions + if ($action != 'presend' && $action != 'editline') { + print '
    '."\n"; + $parameters=array(); + $reshook=$hookmanager->executeHooks('addMoreActionsButtons',$parameters,$object,$action); // Note that $action and $object may have been modified by hook + if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + + if (empty($reshook)) + { + // Send + print ''."\n"; + + if ($user->rights->website->write) + { + print ''."\n"; + } + + /* + if ($user->rights->sellyoursaas->create) + { + if ($object->status == 1) + { + print ''."\n"; + } + else + { + print ''."\n"; + } + } + */ + + if ($user->rights->website->delete) + { + print ''."\n"; + } + } + print '
    '."\n"; + } + + + // Select mail models is same action as presend + if (GETPOST('modelselected')) { + $action = 'presend'; + } + + if ($action != 'presend') + { + print '
    '; + print ''; // ancre + + // Documents + /*$comref = dol_sanitizeFileName($object->ref); + $relativepath = $comref . '/' . $comref . '.pdf'; + $filedir = $conf->website->dir_output . '/' . $comref; + $urlsource = $_SERVER["PHP_SELF"] . "?id=" . $object->id; + $genallowed = $user->rights->website->read; // If you can read, you can build the PDF to read content + $delallowed = $user->rights->website->create; // If you can create/edit, you can remove a file on card + print $formfile->showdocuments('website', $comref, $filedir, $urlsource, $genallowed, $delallowed, $object->modelpdf, 1, 0, 0, 28, 0, '', '', '', $soc->default_lang); + */ + + // Show links to link elements + /*$linktoelem = $form->showLinkToObjectBlock($object, null, array('websiteaccount')); + $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem); + */ + + print '
    '; + + $MAXEVENT = 10; + + // List of actions on element + /* + include_once DOL_DOCUMENT_ROOT . '/core/class/html.formactions.class.php'; + $formactions = new FormActions($db); + $somethingshown = $formactions->showactions($object, 'websiteaccount', $socid, 1, '', $MAXEVENT); + */ + + print '
    '; + } + + // Presend form + $modelmail='websiteaccount'; + $defaulttopic='Information'; + $diroutput = $conf->website->dir_output; + $trackid = 'websiteaccount'.$object->id; + + include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php'; +} + + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/websites/index.php b/htdocs/websites/index.php deleted file mode 100644 index 35731bc3bb0..00000000000 --- a/htdocs/websites/index.php +++ /dev/null @@ -1,1739 +0,0 @@ - - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * \file htdocs/website/index.php - * \ingroup website - * \brief Page to website view/edit - */ - -define('NOSCANPOSTFORINJECTION',1); -define('NOSTYLECHECK',1); - - -/** - * Show HTML header HTML + BODY + Top menu + left menu + DIV - * - * @param string $head Optionnal head lines - * @param string $title HTML title - * @param string $help_url Url links to help page - * Syntax is: For a wiki page: EN:EnglishPage|FR:FrenchPage|ES:SpanishPage - * For other external page: http://server/url - * @param string $target Target to use on links - * @param int $disablejs More content into html header - * @param int $disablehead More content into html header - * @param array $arrayofjs Array of complementary js files - * @param array $arrayofcss Array of complementary css files - * @param string $morequerystring Query string to add to the link "print" to get same parameters (set this only if autodetect fails) - * @return void - */ -function llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='') -{ - global $conf; - - // html header - top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss); - - print ''; - - // top menu and left menu area - if (empty($conf->dol_hide_topmenu)) - { - top_menu($head, $title, $target, $disablejs, $disablehead, $arrayofjs, $arrayofcss, $morequerystring, $help_url); - } - if (empty($conf->dol_hide_leftmenu)) - { - left_menu('', $help_url, '', '', 1, $title, 1); - } - - // main area - //main_area($title); - print ''."\n".'
    '."\n"; -} - - -require '../main.inc.php'; -require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; -require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; -require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.php'; -require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; -require_once DOL_DOCUMENT_ROOT.'/core/class/html.formadmin.class.php'; -require_once DOL_DOCUMENT_ROOT.'/core/class/html.formwebsite.class.php'; -require_once DOL_DOCUMENT_ROOT.'/websites/class/website.class.php'; -require_once DOL_DOCUMENT_ROOT.'/websites/class/websitepage.class.php'; - -$langs->load("admin"); -$langs->load("other"); -$langs->load("website"); - -if (! $user->admin) accessforbidden(); - -if (! ((GETPOST('testmenuhider','int') || ! empty($conf->global->MAIN_TESTMENUHIDER)) && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))) -{ - $conf->dol_hide_leftmenu = 1; // Force hide of left menu. -} - -$error=0; -$website=GETPOST('website', 'alpha'); -$page=GETPOST('page', 'alpha'); -$pageid=GETPOST('pageid', 'int'); -$pageref=GETPOST('pageref', 'aZ09'); -$action=GETPOST('action','alpha'); - -if (GETPOST('delete')) { $action='delete'; } -if (GETPOST('preview')) $action='preview'; -if (GETPOST('createsite')) { $action='createsite'; } -if (GETPOST('create')) { $action='create'; } -if (GETPOST('editmedias')) { $action='editmedias'; } -if (GETPOST('editcss')) { $action='editcss'; } -if (GETPOST('editmenu')) { $action='editmenu'; } -if (GETPOST('setashome')) { $action='setashome'; } -if (GETPOST('editmeta')) { $action='editmeta'; } -if (GETPOST('editsource')) { $action='editsource'; } -if (GETPOST('editcontent')) { $action='editcontent'; } -if (GETPOST('createfromclone')) { $action='createfromclone'; } -if (GETPOST('createpagefromclone')) { $action='createpagefromclone'; } - -if (empty($action)) $action='preview'; - -$object=new Website($db); -$objectpage=new WebsitePage($db); - -$object->fetchAll(); // Init $object->records - -// If website not defined, we take first found -if (empty($website)) -{ - foreach($object->records as $key => $valwebsite) - { - $website=$valwebsite->ref; - break; - } -} -if ($website) -{ - $res = $object->fetch(0, $website); -} - -if ($pageid < 0) $pageid = 0; -if (($pageid > 0 || $pageref) && $action != 'add') -{ - $res = $objectpage->fetch($pageid, ($object->id > 0 ? $object->id : null), $pageref); - $pageid = $objectpage->id; -} - -global $dolibarr_main_data_root; -$pathofwebsite=$dolibarr_main_data_root.'/websites/'.$website; -$filehtmlheader=$pathofwebsite.'/htmlheader.html'; -$filecss=$pathofwebsite.'/styles.css.php'; -$filerobot=$pathofwebsite.'/robots.txt'; -$filehtaccess=$pathofwebsite.'/.htaccess'; -$filetpl=$pathofwebsite.'/page'.$pageid.'.tpl.php'; -$fileindex=$pathofwebsite.'/index.php'; - -// Define $urlwithroot -$urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($dolibarr_main_url_root)); -$urlwithroot=$urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file -//$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current - - - -/* - * Actions - */ - -if (GETPOST('refreshsite')) // If we change the site, we reset the pageid and cancel addsite action. -{ - $pageid=0; - if ($action == 'addsite') $action = 'preview'; -} -if (GETPOST('refreshpage') && ! in_array($action, array('updatecss'))) $action='preview'; - - -// Add site -if ($action == 'addsite') -{ - $db->begin(); - - if (! $error && ! GETPOST('WEBSITE_REF','alpha')) - { - $error++; - setEventMessages($langs->transnoentities("ErrorFieldRequired", $langs->transnoentities("Ref")), null, 'errors'); - } - if (! $error && ! preg_match('/^[a-z0-9_\-\.]+$/i', GETPOST('WEBSITE_REF','alpha'))) - { - $error++; - setEventMessages($langs->transnoentities("ErrorFieldCanNotContainSpecialCharacters", $langs->transnoentities("Ref")), null, 'errors'); - } - - if (! $error) - { - $tmpobject=new Website($db); - $tmpobject->ref = GETPOST('WEBSITE_REF','alpha'); - $tmpobject->description = GETPOST('WEBSITE_DESCRIPTION','alpha'); - $tmpobject->virtualhost = GETPOST('WEBSITE_VIRTUALHOST','alpha'); - - $result = $tmpobject->create($user); - if ($result <= 0) - { - $error++; - setEventMessages($tmpobject->error, $tmpobject->errors, 'errors'); - } - } - - if (! $error) - { - $db->commit(); - setEventMessages($langs->trans("SiteAdded", $object->ref), null, 'mesgs'); - $action=''; - - header("Location: ".$_SERVER["PHP_SELF"].'?website='.$tmpobject->ref); - exit; - } - else - { - $db->rollback(); - $action='createsite'; - } - - if (! $error) - { - $action = 'preview'; - $id = $object->id; - } -} - -// Add page -if ($action == 'add') -{ - $db->begin(); - - $objectpage->fk_website = $object->id; - if (GETPOST('fetchexternalurl','alpha')) - { - $urltograb=GETPOST('externalurl','alpha'); - } - - if ($urltograb) - { - include_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php'; - - $tmp = getURLContent($urltograb); - if ($tmp['curl_error_no']) - { - $error++; - setEventMessages($tmp['curl_error_msg'], null, 'errors'); - $action='create'; - } - else - { - preg_match('/(.*)<\/head>/is', $tmp['content'], $reg); - $head = $reg[1]; - - $urltograbwithoutdomain = preg_replace('/^https?:\/\/[^\/]+\/?/i', '', $urltograbwithoutdomain); - $objectpage->pageurl = basename($urltograbwithoutdomain); - if (empty($objectpage->pageurl)) $objectpage->pageurl='home'; - - if (preg_match('/(.*)<\/title>/ims', $head, $regtmp)) - { - $objectpage->title = $regtmp[1]; - } - if (preg_match('/<meta name="description"[^"]+content="([^"]+)"/ims', $head, $regtmp)) - { - $objectpage->description = $regtmp[1]; - } - if (preg_match('/<meta name="keywords"[^"]+content="([^"]+)"/ims', $head, $regtmp)) - { - $objectpage->keywords = $regtmp[1]; - } - if (preg_match('/<html\s+lang="([^"]+)"/ims', $tmp['content'], $regtmp)) - { - $tmplang=explode('-', $regtmp[1]); - $objectpage->lang = $tmplang[0].($tmplang[1] ? '_'.strtoupper($tmplang[1]) : ''); - } - - $objectpage->content = $tmp['content']; - $objectpage->content = preg_replace('/^.*<body[^>]*>/ims', '', $objectpage->content); - $objectpage->content = preg_replace('/<\/body[^>]*>.*$/ims', '', $objectpage->content); - - $objectpage->grabbed_from = $urltograb; - } - } - else - { - $objectpage->title = GETPOST('WEBSITE_TITLE'); - $objectpage->pageurl = GETPOST('WEBSITE_PAGENAME'); - $objectpage->description = GETPOST('WEBSITE_DESCRIPTION'); - $objectpage->keywords = GETPOST('WEBSITE_KEYWORDS'); - $objectpage->lang = GETPOST('WEBSITE_LANG'); - } - - if (! $error) - { - if (empty($objectpage->pageurl)) - { - setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("WEBSITE_PAGENAME")), null, 'errors'); - $error++; - $action='create'; - } - else if (! preg_match('/^[a-z0-9\-\_]+$/i', $objectpage->pageurl)) - { - setEventMessages($langs->transnoentities("ErrorFieldCanNotContainSpecialCharacters", $langs->transnoentities('WEBSITE_PAGENAME')), null, 'errors'); - $error++; - $action='create'; - } - if (empty($objectpage->title)) - { - setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("WEBSITE_TITLE")), null, 'errors'); - $error++; - $action='create'; - } - } - - if (! $error) - { - $res = $objectpage->create($user); - if ($res <= 0) - { - $error++; - setEventMessages($objectpage->error, $objectpage->errors, 'errors'); - } - } - if (! $error) - { - $db->commit(); - setEventMessages($langs->trans("PageAdded", $objectpage->pageurl), null, 'mesgs'); - $action=''; - } - else - { - $db->rollback(); - } - - if (! $error) - { - $action = 'preview'; - $pageid = $objectpage->id; - } -} - -// Update page -if ($action == 'delete') -{ - $db->begin(); - - $res = $object->fetch(0, $website); - - $res = $objectpage->fetch($pageid, $object->fk_website); - - if ($res > 0) - { - $res = $objectpage->delete($user); - if (! $res > 0) - { - $error++; - setEventMessages($objectpage->error, $objectpage->errors, 'errors'); - } - - if (! $error) - { - $db->commit(); - setEventMessages($langs->trans("PageDeleted", $objectpage->pageurl, $website), null, 'mesgs'); - - header("Location: ".$_SERVER["PHP_SELF"].'?website='.$website); - exit; - } - else - { - $db->rollback(); - } - } - else - { - dol_print_error($db); - } -} - -// Update css -if ($action == 'updatecss') -{ - if (GETPOST('refreshsite') || GETPOST('refreshpage')) // If we tried to reload another site/page, we stay on editcss mode. - { - $action='editcss'; - } - else - { - $res = $object->fetch(0, $website); - - // Html header file - $htmlheadercontent =''; - - /* We disable php code since htmlheader is never executed as an include but only read by fgets_content. - $htmlheadercontent.= "<?php // BEGIN PHP\n"; - $htmlheadercontent.= '$websitekey=basename(dirname(__FILE__));'."\n"; - $htmlheadercontent.= "if (! defined('USEDOLIBARRSERVER')) { require_once './master.inc.php'; } // Not already loaded"."\n"; - $htmlheadercontent.= "require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.php';\n"; - $htmlheadercontent.= "require_once DOL_DOCUMENT_ROOT.'/core/website.inc.php';\n"; - $htmlheadercontent.= "ob_start();\n"; - // $htmlheadercontent.= "header('Content-type: text/html');\n"; // Not required. htmlheader.html is never call as a standalone page - $htmlheadercontent.= "// END PHP ?>\n";*/ - - $htmlheadercontent.= preg_replace(array('/<html>\n*/ims','/<\/html>\n*/ims'),array('',''),GETPOST('WEBSITE_HTML_HEADER')); - - /*$htmlheadercontent.= "\n".'<?php // BEGIN PHP'."\n"; - $htmlheadercontent.= '$tmp = ob_get_contents(); ob_end_clean(); dolWebsiteOutput($tmp);'."\n"; - $htmlheadercontent.= "// END PHP ?>"."\n";*/ - - $htmlheadercontent = trim($htmlheadercontent)."\n"; - - dol_syslog("Save html header into ".$filehtmlheader); - - dol_mkdir($pathofwebsite); - $result = file_put_contents($filehtmlheader, $htmlheadercontent); - if (! empty($conf->global->MAIN_UMASK)) - @chmod($filehtmlheader, octdec($conf->global->MAIN_UMASK)); - - if (! $result) - { - $error++; - setEventMessages('Failed to write file '.$filehtmlheader, null, 'errors'); - } - - // Css file - $csscontent =''; - - $csscontent.= "<?php // BEGIN PHP\n"; - $csscontent.= '$websitekey=basename(dirname(__FILE__));'."\n"; - $csscontent.= "if (! defined('USEDOLIBARRSERVER')) { require_once dirname(__FILE__).'/master.inc.php'; } // Not already loaded"."\n"; // For the css, we need to set path of master using the dirname of css file. - $csscontent.= "require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.php';\n"; - $csscontent.= "require_once DOL_DOCUMENT_ROOT.'/core/website.inc.php';\n"; - $csscontent.= "ob_start();\n"; - $csscontent.= "header('Content-type: text/css');\n"; - $csscontent.= "// END PHP ?>\n"; - - $csscontent.= GETPOST('WEBSITE_CSS_INLINE'); - - $csscontent.= "\n".'<?php // BEGIN PHP'."\n"; - $csscontent.= '$tmp = ob_get_contents(); ob_end_clean(); dolWebsiteOutput($tmp);'."\n"; - $csscontent.= "// END PHP ?>"."\n"; - - dol_syslog("Save css content into ".$filecss); - - dol_mkdir($pathofwebsite); - $result = file_put_contents($filecss, $csscontent); - if (! empty($conf->global->MAIN_UMASK)) - @chmod($filecss, octdec($conf->global->MAIN_UMASK)); - - if (! $result) - { - $error++; - setEventMessages('Failed to write file '.$filecss, null, 'errors'); - } - - - // Css file - $robotcontent =''; - - /*$robotcontent.= "<?php // BEGIN PHP\n"; - $robotcontent.= '$websitekey=basename(dirname(__FILE__));'."\n"; - $robotcontent.= "if (! defined('USEDOLIBARRSERVER')) { require_once './master.inc.php'; } // Not already loaded"."\n"; - $robotcontent.= "require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.php';\n"; - $robotcontent.= "require_once DOL_DOCUMENT_ROOT.'/core/website.inc.php';\n"; - $robotcontent.= "ob_start();\n"; - $robotcontent.= "header('Content-type: text/css');\n"; - $robotcontent.= "// END PHP ?>\n";*/ - - $robotcontent.= GETPOST('WEBSITE_ROBOT'); - - /*$robotcontent.= "\n".'<?php // BEGIN PHP'."\n"; - $robotcontent.= '$tmp = ob_get_contents(); ob_end_clean(); dolWebsiteOutput($tmp);'."\n"; - $robotcontent.= "// END PHP ?>"."\n";*/ - - dol_syslog("Save file robot into ".$filerobot); - - dol_mkdir($pathofwebsite); - $result = file_put_contents($filerobot, $robotcontent); - if (! empty($conf->global->MAIN_UMASK)) - @chmod($filerobot, octdec($conf->global->MAIN_UMASK)); - - if (! $result) - { - $error++; - setEventMessages('Failed to write file '.$filerobot, null, 'errors'); - } - - - // Css file - $htaccesscontent =''; - - /*$robotcontent.= "<?php // BEGIN PHP\n"; - $robotcontent.= '$websitekey=basename(dirname(__FILE__));'."\n"; - $robotcontent.= "if (! defined('USEDOLIBARRSERVER')) { require_once './master.inc.php'; } // Not already loaded"."\n"; - $robotcontent.= "require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.php';\n"; - $robotcontent.= "require_once DOL_DOCUMENT_ROOT.'/core/website.inc.php';\n"; - $robotcontent.= "ob_start();\n"; - $robotcontent.= "header('Content-type: text/css');\n"; - $robotcontent.= "// END PHP ?>\n";*/ - - $htaccesscontent.= GETPOST('WEBSITE_HTACCESS'); - - /*$robotcontent.= "\n".'<?php // BEGIN PHP'."\n"; - $robotcontent.= '$tmp = ob_get_contents(); ob_end_clean(); dolWebsiteOutput($tmp);'."\n"; - $robotcontent.= "// END PHP ?>"."\n";*/ - - dol_syslog("Save file htaccess into ".$filehtaccess); - - dol_mkdir($pathofwebsite); - $result = file_put_contents($filehtaccess, $htaccesscontent); - if (! empty($conf->global->MAIN_UMASK)) - @chmod($filehtaccess, octdec($conf->global->MAIN_UMASK)); - - if (! $result) - { - $error++; - setEventMessages('Failed to write file '.$filehtaccess, null, 'errors'); - } - - // Message if no error - if (! $error) - { - setEventMessages($langs->trans("Saved"), null, 'mesgs'); - } - - $action='preview'; - } -} - -// Update page -if ($action == 'setashome') -{ - $db->begin(); - $object->fetch(0, $website); - - $object->fk_default_home = $pageid; - $res = $object->update($user); - if (! $res > 0) - { - $error++; - setEventMessages($object->error, $object->errors, 'errors'); - } - - if (! $error) - { - $db->commit(); - - // Generate the index.php page to be the home page - //------------------------------------------------- - dol_mkdir($pathofwebsite); - dol_delete_file($fileindex); - - $indexcontent = '<?php'."\n"; - $indexcontent.= '// File generated to provide a shortcut to the Home Page - DO NOT MODIFY - It is just an include.'."\n"; - $indexcontent.= "include_once './".basename($filetpl)."'\n"; - $indexcontent.= '?>'."\n"; - $result = file_put_contents($fileindex, $indexcontent); - if (! empty($conf->global->MAIN_UMASK)) - @chmod($fileindex, octdec($conf->global->MAIN_UMASK)); - - if ($result) setEventMessages($langs->trans("Saved"), null, 'mesgs'); - else setEventMessages('Failed to write file '.$fileindex, null, 'errors'); - - $action='preview'; - } - else - { - $db->rollback(); - } -} - -// Update page (meta) -if ($action == 'updatemeta') -{ - $db->begin(); - $object->fetch(0, $website); - - $objectpage->fk_website = $object->id; - - // Check parameters - if (! preg_match('/^[a-z0-9\-\_]+$/i', $objectpage->pageurl)) - { - $error++; - setEventMessages($langs->transnoentities("ErrorFieldCanNotContainSpecialCharacters", $langs->transnoentities('WEBSITE_PAGENAME')), null, 'errors'); - $action='editmeta'; - } - - $res = $objectpage->fetch($pageid, $object->fk_website); - if ($res <= 0) - { - $error++; - dol_print_error($db, 'Page not found'); - } - - if (! $error) - { - $objectpage->old_object = clone $objectpage; - - $objectpage->pageurl = GETPOST('WEBSITE_PAGENAME'); - $objectpage->title = GETPOST('WEBSITE_TITLE'); - $objectpage->description = GETPOST('WEBSITE_DESCRIPTION'); - $objectpage->keywords = GETPOST('WEBSITE_KEYWORDS'); - $objectpage->lang = GETPOST('WEBSITE_LANG'); - - $res = $objectpage->update($user); - if (! $res > 0) - { - $error++; - setEventMessages($objectpage->error, $objectpage->errors, 'errors'); - } - - if (! $error) - { - $db->commit(); - - $filemaster=$pathofwebsite.'/master.inc.php'; - $fileoldalias=$pathofwebsite.'/'.$objectpage->old_object->pageurl.'.php'; - $filealias=$pathofwebsite.'/'.$objectpage->pageurl.'.php'; - - dol_mkdir($pathofwebsite); - - - // Now generate the master.inc.php page - dol_syslog("We regenerate the master file (because we update meta)"); - dol_delete_file($filemaster); - - $mastercontent = '<?php'."\n"; - $mastercontent.= '// File generated to link to the master file - DO NOT MODIFY - It is just an include'."\n"; - $mastercontent.= "if (! defined('USEDOLIBARRSERVER')) require_once '".DOL_DOCUMENT_ROOT."/master.inc.php';\n"; - //$mastercontent.= "include_once DOL_DOCUMENT_ROOT.'/websites/class/website.class.php';"."\n"; - //$mastercontent.= '$website = new WebSite($db)'."\n"; - $mastercontent.= '?>'."\n"; - $result = file_put_contents($filemaster, $mastercontent); - if (! empty($conf->global->MAIN_UMASK)) - @chmod($filemaster, octdec($conf->global->MAIN_UMASK)); - - if (! $result) setEventMessages('Failed to write file '.$filemaster, null, 'errors'); - - - // Now generate the alias.php page - if (! empty($fileoldalias)) - { - dol_syslog("We regenerate alias page new name=".$filealias.", old name=".$fileoldalias); - dol_delete_file($fileoldalias); - } - - // Save page alias - $result=dolSavePageAlias($filealias, $object, $objectpage); - if (! $result) setEventMessages('Failed to write file '.$filealias, null, 'errors'); - - // Save page of content - $result=dolSavePageContent($filetpl, $object, $objectpage); - if ($result) - { - setEventMessages($langs->trans("Saved"), null, 'mesgs'); - //header("Location: ".$_SERVER["PHP_SELF"].'?website='.$website.'&pageid='.$pageid); - //exit; - } - else - { - setEventMessages('Failed to write file '.$filetpl, null, 'errors'); - //header("Location: ".$_SERVER["PHP_SELF"].'?website='.$website.'&pageid='.$pageid); - //exit; - } - - $action='preview'; - } - else - { - $db->rollback(); - } - } -} - -// Update page -if (($action == 'updatesource' || $action == 'updatecontent' || $action == 'confirm_createfromclone' || $action == 'confirm_createpagefromclone') - || ($action == 'preview' && (GETPOST('refreshsite') || GETPOST('refreshpage') || GETPOST('preview')))) -{ - $object->fetch(0, $website); - - if ($action == 'confirm_createfromclone') - { - $objectnew = new Website($db); - $result = $objectnew->createFromClone($user, GETPOST('id','int'), GETPOST('siteref','aZ09'), (GETPOST('newlang','aZ09')?GETPOST('newlang','aZ09'):'')); - if ($result < 0) - { - $error++; - setEventMessages($objectnew->error, $objectnew->errors, 'errors'); - $action='preview'; - } - else - { - $object = $objectnew; - $id = $object->id; - $pageid = $object->fk_default_home; - } - } - - if ($action == 'confirm_createpagefromclone') - { - $istranslation=(GETPOST('is_a_translation','aZ09')=='on'?1:0); - if ($istranslation) - { - if (GETPOST('newlang','aZ09') == $objectpage->lang) - { - $error++; - setEventMessages($langs->trans("LanguageMustNotBeSameThanClonedPage"), null, 'errors'); - $action='preview'; - } - } - - if (! $error) - { - $objectpage = new WebsitePage($db); - $result = $objectpage->createFromClone($user, $pageid, GETPOST('pageurl','aZ09'), (GETPOST('newlang','aZ09')?GETPOST('newlang','aZ09'):''), $istranslation, GETPOST('newwebsite','int')); - if ($result < 0) - { - $error++; - setEventMessages($objectpage->error, $objectpage->errors, 'errors'); - $action='createpagefromclone'; - } - } - } - - $res = 0; - - if (! $error) - { - // Check symlink to medias and restore it if ko - $pathtomedias=DOL_DATA_ROOT.'/medias'; - $pathtomediasinwebsite=$pathofwebsite.'/medias'; - if (! is_link(dol_osencode($pathtomediasinwebsite))) - { - dol_syslog("Create symlink for ".$pathtomedias." into name ".$pathtomediasinwebsite); - dol_mkdir(dirname($pathtomediasinwebsite)); // To be sure dir for website exists - $result = symlink($pathtomedias, $pathtomediasinwebsite); - } - - /*if (GETPOST('savevirtualhost') && $object->virtualhost != GETPOST('previewsite')) - { - $object->virtualhost = GETPOST('previewsite', 'alpha'); - $object->update($user); - }*/ - - $objectpage->fk_website = $object->id; - - if ($pageid > 0) - { - $res = $objectpage->fetch($pageid); - } - else - { - $res=0; - if ($object->fk_default_home > 0) - { - $res = $objectpage->fetch($object->fk_default_home); - } - if (! ($res > 0)) - { - $res = $objectpage->fetch(0, $object->id); - } - } - } - - if (! $error && $res > 0) - { - if ($action == 'updatesource' || $action == 'updatecontent') - { - $db->begin(); - - $objectpage->content = GETPOST('PAGE_CONTENT','none'); - - // Clean data. We remove all the head section. - $objectpage->content = preg_replace('/<head>.*<\/head>/s', '', $objectpage->content); - /* $objectpage->content = preg_replace('/<base\s+href=[\'"][^\'"]+[\'"]\s/?>/s', '', $objectpage->content); */ - - - $res = $objectpage->update($user); - if ($res < 0) - { - $error++; - setEventMessages($objectpage->error, $objectpage->errors, 'errors'); - } - - if (! $error) - { - $db->commit(); - - $filemaster=$pathofwebsite.'/master.inc.php'; - //$fileoldalias=$pathofwebsite.'/'.$objectpage->old_object->pageurl.'.php'; - $filealias=$pathofwebsite.'/'.$objectpage->pageurl.'.php'; - - dol_mkdir($pathofwebsite); - - - // Now generate the master.inc.php page - dol_syslog("We regenerate the master file"); - dol_delete_file($filemaster); - - $mastercontent = '<?php'."\n"; - $mastercontent.= '// File generated to link to the master file'."\n"; - $mastercontent.= "if (! defined('USEDOLIBARRSERVER')) require_once '".DOL_DOCUMENT_ROOT."/master.inc.php';\n"; - $mastercontent.= '?>'."\n"; - $result = file_put_contents($filemaster, $mastercontent); - if (! empty($conf->global->MAIN_UMASK)) - @chmod($filemaster, octdec($conf->global->MAIN_UMASK)); - - if (! $result) setEventMessages('Failed to write file '.$filemaster, null, 'errors'); - - - // Now generate the alias.php page - if (! empty($fileoldalias)) - { - dol_syslog("We regenerate alias page new name=".$filealias.", old name=".$fileoldalias); - dol_delete_file($fileoldalias); - } - - // Save page alias - $result=dolSavePageAlias($filealias, $object, $objectpage); - if (! $result) setEventMessages('Failed to write file '.$filealias, null, 'errors'); - - // Save page content - $result=dolSavePageContent($filetpl, $object, $objectpage); - if ($result) - { - setEventMessages($langs->trans("Saved"), null, 'mesgs'); - header("Location: ".$_SERVER["PHP_SELF"].'?website='.$website.'&pageid='.$pageid); - exit; - } - else - { - setEventMessages('Failed to write file '.$filetpl, null, 'errors'); - header("Location: ".$_SERVER["PHP_SELF"].'?website='.$website.'&pageid='.$pageid); - exit; - } - } - else - { - $db->rollback(); - } - } - else - { - header("Location: ".$_SERVER["PHP_SELF"].'?website='.$website.'&pageid='.$pageid); - exit; - } - } - else - { - if (! $error) setEventMessages($langs->trans("NoPageYet"), null, 'warnings'); - } -} - -// Export site -if (GETPOST('exportsite')) -{ - $fileofzip = exportWebSite($object); - - $file_name = basename($yourfile); - - header("Content-Type: application/zip"); - header("Content-Disposition: attachment; filename=".$file_name); - header("Content-Length: " . filesize($yourfile)); - - readfile($fileofzip); - exit; -} - - - -/* - * View - */ - -$form = new Form($db); -$formadmin = new FormAdmin($db); -$formwebsite = new FormWebsite($db); - -$help_url=''; - -llxHeader('', $langs->trans("WebsiteSetup"), $help_url, '', 0, 0, - array( - '/includes/ace/ace.js', - '/includes/ace/ext-statusbar.js', - '/includes/ace/ext-language_tools.js', - //'/includes/ace/ext-chromevox.js' - ), array()); - -print "\n".'<form action="'.$_SERVER["PHP_SELF"].'" method="POST"><div>'; -print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">'; -if ($action == 'createsite') -{ - print '<input type="hidden" name="action" value="addsite">'; -} -if ($action == 'create') -{ - print '<input type="hidden" name="action" value="add">'; -} -if ($action == 'editcss') -{ - print '<input type="hidden" name="action" value="updatecss">'; -} -if ($action == 'editmenu') -{ - print '<input type="hidden" name="action" value="updatemenu">'; -} -if ($action == 'setashome') -{ - print '<input type="hidden" name="action" value="updateashome">'; -} -if ($action == 'editmeta') -{ - print '<input type="hidden" name="action" value="updatemeta">'; -} -if ($action == 'editsource') -{ - print '<input type="hidden" name="action" value="updatesource">'; -} -if ($action == 'editcontent') -{ - print '<input type="hidden" name="action" value="updatecontent">'; -} -if ($action == 'edit') -{ - print '<input type="hidden" name="action" value="update">'; -} - - -// Add a margin under toolbar ? -$style=''; -if ($action != 'preview' && $action != 'editcontent' && $action != 'editsource') $style=' margin-bottom: 5px;'; - -//var_dump($objectpage);exit; -print '<div class="centpercent websitebar">'; - -if (count($object->records) > 0) -{ - // ***** Part for web sites - - print '<div class="websiteselection hideonsmartphoneimp minwwidth100">'; - print '<input type="submit"'.$disabled.' class="button" value="'.dol_escape_htmltag($langs->trans("AddWebsite")).'" name="createsite">'; - print '</div>'; - - print '<div class="websiteselection hideonsmartphoneimp">'; - print $langs->trans("Website").': '; - print '</div>'; - - // List of websites - print '<div class="websiteselection">'; - $out=''; - $out.='<select name="website" class="minwidth100" id="website">'; - if (empty($object->records)) $out.='<option value="-1"> </option>'; - // Loop on each sites - $i=0; - foreach($object->records as $key => $valwebsite) - { - if (empty($website)) $website=$valwebsite->ref; - - $out.='<option value="'.$valwebsite->ref.'"'; - if ($website == $valwebsite->ref) $out.=' selected'; // To preselect a value - $out.='>'; - $out.=$valwebsite->ref; - $out.='</option>'; - $i++; - } - $out.='</select>'; - $out.=ajax_combobox('website'); - print $out; - print '<input type="submit" class="button" name="refreshsite" value="'.$langs->trans("Load").'">'; - - if ($website) - { - $virtualurl=''; - $dataroot=DOL_DATA_ROOT.'/websites/'.$website; - if (! empty($object->virtualhost)) $virtualurl=$object->virtualhost; - } - - if ($website && ($action == 'preview' || $action == 'createfromclone' || $action == 'createpagefromclone')) - { - $disabled=''; - if (empty($user->rights->websites->write)) $disabled=' disabled="disabled"'; - - print '   '; - - print '<input type="submit" class="button"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("EditCss")).'" name="editcss">'; - //print '<input type="submit" class="button"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("EditMenu")).'" name="editmenu">'; - print '<input type="submit" class="button"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("CloneSite")).'" name="createfromclone">'; - print '<input type="submit" class="button"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("ExportSite")).'" name="exportsite">'; - - print '   '; - - print '<input type="submit" class="button"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("MediaFiles")).'" name="editmedias">'; - } - - print '</div>'; - - // Button for websites - print '<div class="websitetools">'; - - if ($action == 'preview' || $action == 'createfromclone' || $action == 'createpagefromclone') - { - print '<div class="websiteinputurl" id="websiteinputurl">'; - print '<input type="text" id="previewsiteurl" class="minwidth200imp" name="previewsite" placeholder="'.$langs->trans("http://myvirtualhost").'" value="'.$virtualurl.'">'; - //print '<input type="submit" class="button" name="previewwebsite" target="tab'.$website.'" value="'.$langs->trans("ViewSiteInNewTab").'">'; - $htmltext=$langs->trans("SetHereVirtualHost", $dataroot); - print $form->textwithpicto('', $htmltext, 1, 'help', '', 0, 2, 'helpvirtualhost'); - print '</div>'; - - $urlext=$virtualurl; - $urlint=$urlwithroot.'/public/websites/index.php?website='.$website; - print '<a class="websitebuttonsitepreview'.($urlext?'':' websitebuttonsitepreviewdisabled cursornotallowed').'" id="previewsiteext" href="'.$urlext.'" target="tab'.$website.'ext" alt="'.dol_escape_htmltag($langs->trans("PreviewSiteServedByWebServer", $langs->transnoentitiesnoconv("Site"), $langs->transnoentitiesnoconv("Site"), $dataroot, $urlext)).'">'; - print $form->textwithpicto('', $langs->trans("PreviewSiteServedByWebServer", $langs->transnoentitiesnoconv("Site"), $langs->transnoentitiesnoconv("Site"), $dataroot, $urlext?$urlext:'<span class="error">'.$langs->trans("VirtualHostUrlNotDefined").'</span>'), 1, 'preview_ext'); - print '</a>'; - - print '<a class="websitebuttonsitepreview" id="previewsite" href="'.$urlwithroot.'/public/websites/index.php?website='.$website.'" target="tab'.$website.'" alt="'.dol_escape_htmltag($langs->trans("PreviewSiteServedByDolibarr", $langs->transnoentitiesnoconv("Site"), $langs->transnoentitiesnoconv("Site"), $urlint)).'">'; - print $form->textwithpicto('', $langs->trans("PreviewSiteServedByDolibarr", $langs->transnoentitiesnoconv("Site"), $langs->transnoentitiesnoconv("Site"), $urlint, $dataroot), 1, 'preview'); - print '</a>'; - } - - if (in_array($action, array('editcss','editmenu','editmedias'))) - { - if (preg_match('/^create/',$action) && $action != 'editmedias') print '<input type="submit" id="savefile" class="button buttonforacesave" value="'.dol_escape_htmltag($langs->trans("Save")).'" name="update">'; - if (preg_match('/^edit/',$action) && $action != 'editmedias') print '<input type="submit" id="savefile" class="button buttonforacesave" value="'.dol_escape_htmltag($langs->trans("Save")).'" name="update">'; - if ($action != 'preview') print '<input type="submit" class="button" value="'.dol_escape_htmltag($langs->trans("Cancel")).'" name="preview">'; - } - - print '</div>'; - - - // ***** Part for pages - - if ($website && ! in_array($action, array('editcss','editmenu','editmedias'))) - { - print '</div>'; // Close current websitebar to open a new one - - $array=$objectpage->fetchAll($object->id); - if (! is_array($array) && $array < 0) dol_print_error('', $objectpage->error, $objectpage->errors); - $atleastonepage=(is_array($array) && count($array) > 0); - - print '<div class="centpercent websitebar"'.($style?' style="'.$style.'"':'').'">'; - - print '<div class="websiteselection hideonsmartphoneimp monwidth100">'; - print '<input type="submit"'.$disabled.' class="button" value="'.dol_escape_htmltag($langs->trans("AddPage")).'" name="create">'; - print '</div>'; - - print '<div class="websiteselection hideonsmartphoneimp">'; - print $langs->trans("Page").': '; - print '</div>'; - print '<div class="websiteselection">'; - - if ($action != 'add') - { - $out=''; - $out.='<select name="pageid" id="pageid" class="minwidth200 maxwidth300">'; - if ($atleastonepage) - { - if (empty($pageid) && $action != 'create') // Page id is not defined, we try to take one - { - $firstpageid=0;$homepageid=0; - foreach($array as $key => $valpage) - { - if (empty($firstpageid)) $firstpageid=$valpage->id; - if ($object->fk_default_home && $key == $object->fk_default_home) $homepageid=$valpage->id; - } - $pageid=$homepageid?$homepageid:$firstpageid; // We choose home page and if not defined yet, we take first page - } - - foreach($array as $key => $valpage) - { - $out.='<option value="'.$key.'"'; - if ($pageid > 0 && $pageid == $key) $out.=' selected'; // To preselect a value - $out.='>'; - $out.=$valpage->pageurl.' - '.$valpage->title; - if ($object->fk_default_home && $key == $object->fk_default_home) $out.=' ('.$langs->trans("HomePage").')'; - $out.='</option>'; - } - } - else $out.='<option value="-1"> </option>'; - $out.='</select>'; - $out.=ajax_combobox('pageid'); - print $out; - } - else - { - print $langs->trans("New"); - } - - print '<input type="submit" class="button" name="refreshpage" value="'.$langs->trans("Load").'"'.($atleastonepage?'':' disabled="disabled"').'>'; - - if ($action == 'preview' || $action == 'createfromclone' || $action == 'createpagefromclone') - { - $disabled=''; - if (empty($user->rights->websites->write)) $disabled=' disabled="disabled"'; - - // Confirmation to clone - if ($action == 'createfromclone') { - // Create an array for form - $formquestion = array( - array('type' => 'text', 'name' => 'siteref', 'label'=> $langs->trans("Website") ,'value'=> 'copy_of_'.$object->ref), - //array('type' => 'checkbox', 'name' => 'is_a_translation', 'label' => $langs->trans("SiteIsANewTranslation"), 'value' => 0), - //array('type' => 'other','name' => 'newlang','label' => $langs->trans("Language"), 'value' => $formadmin->select_language(GETPOST('newlang', 'az09')?GETPOST('newlang', 'az09'):$langs->defaultlang, 'newlang', 0, null, '', 0, 0, 'minwidth200')), - //array('type' => 'other','name' => 'newwebsite','label' => $langs->trans("Website"), 'value' => $formwebsite->selectWebsite($object->id, 'newwebsite', 0)) - ); - - $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id='.$object->id, $langs->trans('CloneSite'), '', 'confirm_createfromclone', $formquestion, 0, 1, 200); - - print $formconfirm; - } - - if ($pageid > 0) - { - // Confirmation to clone - if ($action == 'createpagefromclone') { - // Create an array for form - $formquestion = array( - array('type' => 'text', 'name' => 'pageurl', 'label'=> $langs->trans("WEBSITE_PAGENAME") ,'value'=> 'copy_of_'.$objectpage->pageurl), - array('type' => 'checkbox', 'name' => 'is_a_translation', 'label' => $langs->trans("PageIsANewTranslation"), 'value' => 0), - array('type' => 'other','name' => 'newlang','label' => $langs->trans("Language"), 'value' => $formadmin->select_language(GETPOST('newlang', 'az09')?GETPOST('newlang', 'az09'):$langs->defaultlang, 'newlang', 0, null, '', 0, 0, 'minwidth200')), - array('type' => 'other','name' => 'newwebsite','label' => $langs->trans("Website"), 'value' => $formwebsite->selectWebsite($object->id, 'newwebsite', 0)) - ); - - $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?pageid=' . $pageid, $langs->trans('ClonePage'), '', 'confirm_createpagefromclone', $formquestion, 0, 1, 250); - - print $formconfirm; - } - - print '   '; - - print '<input type="submit" class="button"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("EditPageMeta")).'" name="editmeta">'; - print '<input type="submit" class="button"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("EditWithEditor")).'" name="editcontent">'; - print '<input type="submit" class="button"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("EditHTMLSource")).'" name="editsource">'; - if ($object->fk_default_home > 0 && $pageid == $object->fk_default_home) print '<input type="submit" class="button" disabled="disabled" value="'.dol_escape_htmltag($langs->trans("SetAsHomePage")).'" name="setashome">'; - else print '<input type="submit" class="button"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("SetAsHomePage")).'" name="setashome">'; - print '<input type="submit" class="button"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("ClonePage")).'" name="createpagefromclone">'; - print '<input type="submit" class="buttonDelete" name="delete" value="'.$langs->trans("Delete").'"'.($atleastonepage?'':' disabled="disabled"').'>'; - } - } - - print '</div>'; // end website selection - - print '<div class="websitetools">'; - - if ($website && $pageid > 0 && ($action == 'preview' || $action == 'createfromclone' || $action == 'createpagefromclone')) - { - $websitepage = new WebSitePage($db); - $websitepage->fetch($pageid); - - $realpage=$urlwithroot.'/public/websites/index.php?website='.$website.'&pageref='.$websitepage->pageurl; - $pagealias = $websitepage->pageurl; - - print '<div class="websiteinputurl" id="websiteinputpage">'; - print '<input type="text" id="previewpageurl" class="minwidth200imp" name="previewsite" value="'.$pagealias.'" disabled="disabled">'; - $htmltext=$langs->trans("PageNameAliasHelp", $langs->transnoentitiesnoconv("EditPageMeta")); - print $form->textwithpicto('', $htmltext, 1, 'help', '', 0, 2, 'helppagealias'); - print '</div>'; - - $urlext=$virtualurl.'/'.$pagealias.'.php'; - $urlint=$urlwithroot.'/public/websites/index.php?website='.$website; - print '<a class="websitebuttonsitepreview'.($virtualurl?'':' websitebuttonsitepreviewdisabled cursornotallowed').'" id="previewpageext" href="'.$urlext.'" target="tab'.$website.'ext" alt="'.dol_escape_htmltag($langs->trans("PreviewSiteServedByWebServer", $langs->transnoentitiesnoconv("Page"), $langs->transnoentitiesnoconv("Page"), $dataroot, $urlext)).'">'; - print $form->textwithpicto('', $langs->trans("PreviewSiteServedByWebServer", $langs->transnoentitiesnoconv("Page"), $langs->transnoentitiesnoconv("Page"), $dataroot, $virtualurl?$urlext:'<span class="error">'.$langs->trans("VirtualHostUrlNotDefined").'</span>'), 1, 'preview_ext'); - print '</a>'; - - print '<a class="websitebuttonsitepreview" id="previewpage" href="'.$realpage.'&nocache='.dol_now().'" class="button" target="tab'.$website.'" alt="'.dol_escape_htmltag($langs->trans("PreviewSiteServedByDolibarr", $langs->transnoentitiesnoconv("Page"), $langs->transnoentitiesnoconv("Page"), $realpage)).'">'; - print $form->textwithpicto('', $langs->trans("PreviewSiteServedByDolibarr", $langs->transnoentitiesnoconv("Page"), $langs->transnoentitiesnoconv("Page"), $realpage, $dataroot), 1, 'preview'); - print '</a>'; // View page in new Tab - //print '<input type="submit" class="button" name="previewpage" target="tab'.$website.'"value="'.$langs->trans("ViewPageInNewTab").'">'; - - // TODO Add js to save alias like we save virtual host name and use dynamic virtual host for url of id=previewpageext - } - if (! in_array($action, array('editcss','editmenu','editmedias','createsite','create','createpagefromclone'))) - { - if (preg_match('/^create/',$action)) print '<input type="submit" id="savefile" class="button buttonforacesave" value="'.dol_escape_htmltag($langs->trans("Save")).'" name="update">'; - if (preg_match('/^edit/',$action)) print '<input type="submit" id="savefile" class="button buttonforacesave" value="'.dol_escape_htmltag($langs->trans("Save")).'" name="update">'; - if ($action != 'preview') print '<input type="submit" class="button" value="'.dol_escape_htmltag($langs->trans("Cancel")).'" name="preview">'; - } - - print '</div>'; // end websitetools - - print '<div class="websitehelp">'; - if (GETPOST('editsource', 'alpha') || GETPOST('editcontent', 'alpha')) - { - $htmltext=$langs->transnoentitiesnoconv("YouCanEditHtmlSource"); - print $form->textwithpicto($langs->trans("SyntaxHelp"), $htmltext, 1, 'help', 'inline-block', 0, 2, 'tooltipsubstitution'); - } - print '</div>'; // end websitehelp - - - - if ($action == 'preview' || $action == 'createfromclone' || $action == 'createpagefromclone') - { - // Adding jquery code to change on the fly url of preview ext - if (! empty($conf->use_javascript_ajax)) - { - print '<script type="text/javascript" language="javascript"> - jQuery(document).ready(function() { - jQuery("#websiteinputurl").keyup(function() { - console.log("Website external url modified "+jQuery("#previewsiteurl").val()); - if (jQuery("#previewsiteurl").val() != "") jQuery("a.websitebuttonsitepreviewdisabled img").css({ opacity: 1 }); - else jQuery("a.websitebuttonsitepreviewdisabled img").css({ opacity: 0.2 }); - }); - jQuery("#previewsiteext,#previewpageext").click(function() { - newurl=jQuery("#previewsiteurl").val(); - newpage=jQuery("#previewsiteurl").val() + "/" + jQuery("#previewpageurl").val() + ".php"; - console.log("Open url "+newurl); - /* Save url */ - jQuery.ajax({ - method: "POST", - url: "'.DOL_URL_ROOT.'/core/ajax/saveinplace.php", - data: { - field: \'editval_virtualhost\', - element: \'websites\', - table_element: \'website\', - fk_element: '.$object->id.', - value: newurl, - }, - context: document.body - }); - - jQuery("#previewsiteext").attr("href",newurl); - jQuery("#previewpageext").attr("href",newpage); - }); - }); - </script>'; - } - } - } -} -else -{ - print '<div class="websiteselection">'; - $langs->load("errors"); - print $langs->trans("ErrorModuleSetupNotComplete"); - print '<div>'; - $action=''; -} - - -print '</div>'; // end current websitebar - -$head = array(); - - -/* - * Edit mode - */ - -if ($action == 'editcss') -{ - print '<div class="fiche">'; - - print '<br>'; - - $csscontent = @file_get_contents($filecss); - // Clean the php css file to remove php code and get only css part - $csscontent = preg_replace('/<\?php \/\/ BEGIN PHP[^\?]*END PHP \?>\n*/ims', '', $csscontent); - $csscontent.= GETPOST('WEBSITE_CSS_INLINE'); - if (! trim($csscontent)) $csscontent='/* CSS content (all pages) */'."\n".'body.bodywebsite { margin: 0; }'; - - $htmlheader = @file_get_contents($filehtmlheader); - // Clean the php htmlheader file to remove php code and get only html part - $htmlheader = preg_replace('/<\?php \/\/ BEGIN PHP[^\?]*END PHP \?>\n*/ims', '', $htmlheader); - if (! trim($htmlheader)) $htmlheader='<!-- HTML header content (common for all pages) -->'; - else $htmlheader='<html>'."\n".trim($htmlheader)."\n".'</html>'; - - $robotcontent = @file_get_contents($filerobot); - // Clean the php htmlheader file to remove php code and get only html part - $robotcontent = preg_replace('/<\?php \/\/ BEGIN PHP[^\?]*END PHP \?>\n*/ims', '', $robotcontent); - if (! trim($robotcontent)) - { - $robotcontent.="# Robot file. Generated with ".DOL_APPLICATION_TITLE."\n"; - $robotcontent.="User-agent: *\n"; - $robotcontent.="Allow: /public/\n"; - $robotcontent.="Disallow: /administrator/\n"; - } - - $htaccesscontent = @file_get_contents($filehtaccess); - // Clean the php htaccesscontent file to remove php code and get only html part - $htaccesscontent = preg_replace('/<\?php \/\/ BEGIN PHP[^\?]*END PHP \?>\n*/ims', '', $htaccesscontent); - if (! trim($htaccesscontent)) - { - $htaccesscontent.="# Order allow,deny\n"; - $htaccesscontent.="# Deny from all\n"; - } - //else $htaccesscontent='<html>'."\n".$htaccesscontent."\n".'</html>';*/ - - dol_fiche_head(); - - print '<!-- Edit CSS -->'."\n"; - print '<table class="border" width="100%">'; - - // Website - print '<tr><td class="titlefieldcreate">'; - print $langs->trans('WebSite'); - print '</td><td>'; - print $website; - print '</td></tr>'; - - // CSS file - print '<tr><td class="tdtop">'; - print $langs->trans('WEBSITE_CSS_INLINE'); - print '</td><td>'; - - $doleditor=new DolEditor('WEBSITE_CSS_INLINE', $csscontent, '', '220', 'ace', 'In', true, false, 'ace', 0, '100%', ''); - print $doleditor->Create(1, '', true, 'CSS', 'css'); - - print '</td></tr>'; - - // Common HTML header - print '<tr><td class="tdtop">'; - print $langs->trans('WEBSITE_HTML_HEADER'); - print '</td><td>'; - - $doleditor=new DolEditor('WEBSITE_HTML_HEADER', $htmlheader, '', '220', 'ace', 'In', true, false, 'ace', 0, '100%', ''); - print $doleditor->Create(1, '', true, 'HTML Header', 'html'); - - print '</td></tr>'; - - // Robot file - print '<tr><td class="tdtop">'; - print $langs->trans('WEBSITE_ROBOT'); - print '</td><td>'; - - $doleditor=new DolEditor('WEBSITE_ROBOT', $robotcontent, '', '220', 'ace', 'In', true, false, 'ace', 0, '100%', ''); - print $doleditor->Create(1, '', true, 'Robot file', 'txt'); - - print '</td></tr>'; - - // .htaccess - print '<tr><td class="tdtop">'; - print $langs->trans('WEBSITE_HTACCESS'); - print '</td><td>'; - - $doleditor=new DolEditor('WEBSITE_HTACCESS', $htaccesscontent, '', '220', 'ace', 'In', true, false, 'ace', 0, '100%', ''); - print $doleditor->Create(1, '', true, $langs->trans("File").' .htaccess', 'txt'); - - print '</td></tr>'; - - print '</table>'; - - dol_fiche_end(); - - print '</div>'; - - print '<br>'; -} - -if ($action == 'createsite') -{ - print '<div class="fiche">'; - - print '<br>'; - - /*$h = 0; - $head = array(); - - $head[$h][0] = dol_buildpath('/websites/index.php',1).'?id='.$object->id; - $head[$h][1] = $langs->trans("AddSite"); - $head[$h][2] = 'card'; - $h++; - - dol_fiche_head($head, 'card', $langs->trans("AddSite"), -1, 'globe'); - */ - if ($action == 'create') print_fiche_titre($langs->trans("AddSite")); - - print '<!-- Add site -->'."\n"; - //print '<div class="fichecenter">'; - - print '<table class="border" width="100%">'; - - if (GETPOST('WEBSITE_REF')) $siteref=GETPOST('WEBSITE_REF','alpha'); - if (GETPOST('WEBSITE_DESCRIPTION')) $sitedesc=GETPOST('WEBSITE_DESCRIPTION','alpha'); - - print '<tr><td class="titlefieldcreate fieldrequired">'; - print $langs->trans('Ref'); - print '</td><td>'; - print '<input type="text" class="flat maxwidth300" name="WEBSITE_REF" value="'.dol_escape_htmltag($siteref).'">'; - print '</td></tr>'; - - print '<tr><td>'; - print $langs->trans('Description'); - print '</td><td>'; - print '<input type="text" class="flat minwidth300" name="WEBSITE_DESCRIPTION" value="'.dol_escape_htmltag($sitedesc).'">'; - print '</td></tr>'; - - print '<tr><td>'; - print $form->textwithpicto($langs->trans('Virtualhost'), $langs->trans("SetHereVirtualHost", DOL_DATA_ROOT.'/websites/<i>websiteref</i>'), 1, 'help', '', 0, 2, 'tooltipvirtual'); - print '</td><td>'; - print '<input type="text" class="flat minwidth300" name="WEBSITE_DESCRIPTION" value="'.dol_escape_htmltag($sitedesc).'">'; - print '</td></tr>'; - - - print '</table>'; - - if ($action == 'createsite') - { - print '<div class="center">'; - - print '<input class="button" type="submit" name="add" value="'.$langs->trans("Create").'">'; - print '<input class="button" type="submit" name="preview" value="'.$langs->trans("Cancel").'">'; - - print '</div>'; - } - - - //print '</div>'; - - //dol_fiche_end(); - - print '</div>'; - - print '<br>'; -} - -if ($action == 'editmeta' || $action == 'create') -{ - print '<div class="fiche">'; - - print '<br>'; - - /*$h = 0; - $head = array(); - - $head[$h][0] = dol_buildpath('/websites/index.php',1).'?id='.$object->id; - $head[$h][1] = $langs->trans("AddPage"); - $head[$h][2] = 'card'; - $h++; - - dol_fiche_head($head, 'card', $langs->trans("AddPage"), -1, 'globe'); - */ - if ($action == 'create') print_fiche_titre($langs->trans("AddPage")); - - print '<!-- Edit or create page -->'."\n"; - //print '<div class="fichecenter">'; - - if ($action == 'create') - { - print '<br>'; - - print ' * '.$langs->trans("CreateByFetchingExternalPage").'<br><hr>'; - print '<table class="border" width="100%">'; - print '<tr><td class="titlefieldcreate">'; - print $langs->trans("URL"); - print '</td><td>'; - print '<input class="flat minwidth300" type="text" name="externalurl" value="'.dol_escape_htmltag(GETPOST('externalurl','alpha')).'" placeholder="http://externalsite/pagetofetch"> '; - print '<input class="button" type="submit" name="fetchexternalurl" value="'.dol_escape_htmltag($langs->trans("FetchAndCreate")).'">'; - print '</td></tr>'; - print '</table>'; - - print '<br>'; - - print ' * '.$langs->trans("OrEnterPageInfoManually").'<br><hr>'; - } - - print '<table class="border" width="100%">'; - - if ($action != 'create') - { - print '<tr><td class="titlefield">'; - print $langs->trans('WEBSITE_PAGEURL'); - print '</td><td>'; - print '/public/websites/index.php?website='.urlencode($website).'&pageid='.urlencode($pageid); - print '</td></tr>'; - - /* - print '<tr><td class="titlefield">'; - print $langs->trans('InitiallyGrabbedFrom'); - print '</td><td>'; - print $objectpage->grabbed_from; - print '</td></tr>'; - */ - - $pageurl=$objectpage->pageurl; - $pagetitle=$objectpage->title; - $pagedescription=$objectpage->description; - $pagekeywords=$objectpage->keywords; - $pagelang=$objectpage->lang; - } - if (GETPOST('WEBSITE_PAGENAME')) $pageurl=GETPOST('WEBSITE_PAGENAME','alpha'); - if (GETPOST('WEBSITE_TITLE')) $pagetitle=GETPOST('WEBSITE_TITLE','alpha'); - if (GETPOST('WEBSITE_DESCRIPTION')) $pagedescription=GETPOST('WEBSITE_DESCRIPTION','alpha'); - if (GETPOST('WEBSITE_KEYWORDS')) $pagekeywords=GETPOST('WEBSITE_KEYWORDS','alpha'); - if (GETPOST('WEBSITE_LANG')) $pagelang=GETPOST('WEBSITE_LANG','aZ09'); - - print '<tr><td class="titlefieldcreate fieldrequired">'; - print $langs->trans('WEBSITE_PAGENAME'); - print '</td><td>'; - print '<input type="text" class="flat maxwidth300" name="WEBSITE_PAGENAME" value="'.dol_escape_htmltag($pageurl).'">'; - print '</td></tr>'; - - print '<tr><td class="fieldrequired">'; - print $langs->trans('WEBSITE_TITLE'); - print '</td><td>'; - print '<input type="text" class="flat quatrevingtpercent" name="WEBSITE_TITLE" value="'.dol_escape_htmltag($pagetitle).'">'; - print '</td></tr>'; - - print '<tr><td>'; - print $langs->trans('WEBSITE_DESCRIPTION'); - print '</td><td>'; - print '<input type="text" class="flat quatrevingtpercent" name="WEBSITE_DESCRIPTION" value="'.dol_escape_htmltag($pagedescription).'">'; - print '</td></tr>'; - - print '<tr><td>'; - print $langs->trans('WEBSITE_KEYWORDS'); - print '</td><td>'; - print '<input type="text" class="flat quatrevingtpercent" name="WEBSITE_KEYWORDS" value="'.dol_escape_htmltag($pagekeywords).'">'; - print '</td></tr>'; - - print '<tr><td>'; - print $langs->trans('Language'); - print '</td><td>'; - print $formadmin->select_language($pagelang?$pagelang:$langs->defaultlang, 'WEBSITE_LANG'); - print '</td></tr>'; - - print '</table>'; - - if ($action == 'create') - { - print '<div class="center">'; - - print '<input class="button" type="submit" name="add" value="'.$langs->trans("Create").'">'; - print '<input class="button" type="submit" name="preview" value="'.$langs->trans("Cancel").'">'; - - print '</div>'; - } - - - //print '</div>'; - - //dol_fiche_end(); - - print '</div>'; - - print '<br>'; -} - -if ($action == 'editmedias') -{ - print '<!-- Edit Media -->'."\n"; - print '<div class="center">'.$langs->trans("FeatureNotYetAvailable").'</center>'; -} - -if ($action == 'editmenu') -{ - print '<!-- Edit Menu -->'."\n"; - print '<div class="center">'.$langs->trans("FeatureNotYetAvailable").'</center>'; -} - -if ($action == 'editsource') -{ - /* - * Editing global variables not related to a specific theme - */ - - //$csscontent = @file_get_contents($filecss); - - $contentforedit = ''; - /*$contentforedit.='<style scoped>'."\n"; // "scoped" means "apply to parent element only". Not yet supported by browsers - $contentforedit.=$csscontent; - $contentforedit.='</style>'."\n";*/ - $contentforedit .= $objectpage->content; - - require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; - $doleditor=new DolEditor('PAGE_CONTENT',$contentforedit,'',500,'Full','',true,true,'ace',ROWS_5,'90%'); - $doleditor->Create(0, '', false, 'HTML Source', 'php'); -} - -if ($action == 'editcontent') -{ - /* - * Editing global variables not related to a specific theme - */ - - //$csscontent = @file_get_contents($filecss); - - $contentforedit = ''; - /*$contentforedit.='<style scoped>'."\n"; // "scoped" means "apply to parent element only". Not yet supported by browsers - $contentforedit.=$csscontent; - $contentforedit.='</style>'."\n";*/ - $contentforedit .= $objectpage->content; - - $contentforedit = preg_replace('/(<img.*src=")(?!http)/', '\1'.DOL_URL_ROOT.'/viewimage.php?modulepart=medias&file=', $contentforedit, -1, $nbrep); - - require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; - $doleditor=new DolEditor('PAGE_CONTENT',$contentforedit,'',500,'Full','',true,true,true,ROWS_5,'90%'); - $doleditor->Create(0, '', false); -} - -print "</div>\n</form>\n"; - - - -if ($action == 'preview' || $action == 'createfromclone' || $action == 'createpagefromclone') -{ - if ($pageid > 0) - { - // Ouput page under the Dolibarr top menu - $objectpage->fetch($pageid); - $csscontent = @file_get_contents($filecss); - - $out = '<!-- Page content '.$filetpl.' : Div with (CSS + Page content from database) -->'."\n"; - - $out.='<div id="websitecontentundertopmenu" class="websitecontentundertopmenu">'."\n"; - - // REPLACEMENT OF LINKS When page called by website editor - - $out.='<style scoped>'."\n"; // "scoped" means "apply to parent element only". Not yet supported by browsers - $out.=dolWebsiteReplacementOfLinks($object, $csscontent); - $out.='</style>'."\n"; - - $out.='<div id="bodywebsite" class="bodywebsite">'."\n"; - - $out.=dolWebsiteReplacementOfLinks($object, $objectpage->content)."\n"; - - $out.='</div>'; - - $out.='</div>'; - - $out.= "\n".'<!-- End page content '.$filetpl.' -->'."\n\n"; - - print $out; - - /*file_put_contents($filetpl, $out); - if (! empty($conf->global->MAIN_UMASK)) - @chmod($filetpl, octdec($conf->global->MAIN_UMASK)); - - // Output file on browser - dol_syslog("index.php include $filetpl $filename content-type=$type"); - $original_file_osencoded=dol_osencode($filetpl); // New file name encoded in OS encoding charset - - // This test if file exists should be useless. We keep it to find bug more easily - if (! file_exists($original_file_osencoded)) - { - dol_print_error(0,$langs->trans("ErrorFileDoesNotExists",$original_file)); - exit; - } - - //include_once $original_file_osencoded; - */ - - /*print '<iframe class="websiteiframenoborder centpercent" src="'.DOL_URL_ROOT.'/public/websites/index.php?website='.$website.'&pageid='.$pageid.'"/>'; - print '</iframe>';*/ - } - else - { - print '<br><br><div class="center">'.$langs->trans("PreviewOfSiteNotYetAvailable", $website).'</center><br><br><br>'; - print '<div class="center"><div class="logo_setup"></div></div>'; - } -} - - - -llxFooter(); - -$db->close(); - - - - -/** - * Save content of a page on disk - * - * @param string $filealias Full path of filename to generate - * @param Website $object Object website - * @param WebsitePage $objectpage Object websitepage - * @return boolean True if OK - */ -function dolSavePageAlias($filealias, $object, $objectpage) -{ - global $conf; - - // Now create the .tpl file (duplicate code with actions updatesource or updatecontent but we need this to save new header) - dol_syslog("We regenerate the alias page filealias=".$filealias); - - $aliascontent = '<?php'."\n"; - $aliascontent.= "// File generated to wrap the alias page - DO NOT MODIFY - It is just a wrapper to real page\n"; - $aliascontent.= 'global $dolibarr_main_data_root;'."\n"; - $aliascontent.= 'if (empty($dolibarr_main_data_root)) require \'./page'.$objectpage->id.'.tpl.php\'; '; - $aliascontent.= 'else require $dolibarr_main_data_root.\'/websites/\'.$website->ref.\'/page'.$objectpage->id.'.tpl.php\';'."\n"; - $aliascontent.= '?>'."\n"; - $result = file_put_contents($filealias, $aliascontent); - if (! empty($conf->global->MAIN_UMASK)) - @chmod($filealias, octdec($conf->global->MAIN_UMASK)); - - return ($result?true:false); -} - - -/** - * Save content of a page on disk - * - * @param string $filetpl Full path of filename to generate - * @param Website $object Object website - * @param WebsitePage $objectpage Object websitepage - * @return boolean True if OK - */ -function dolSavePageContent($filetpl, $object, $objectpage) -{ - global $conf; - - // Now create the .tpl file (duplicate code with actions updatesource or updatecontent but we need this to save new header) - dol_syslog("We regenerate the tpl page filetpl=".$filetpl); - - dol_delete_file($filetpl); - - $shortlangcode = ''; - if ($objectpage->lang) $shortlangcode=preg_replace('/[_-].*$/', '', $objectpage->lang); // en_US or en-US -> en - - $tplcontent =''; - $tplcontent.= "<?php // BEGIN PHP\n"; - $tplcontent.= '$websitekey=basename(dirname(__FILE__));'."\n"; - $tplcontent.= "if (! defined('USEDOLIBARRSERVER')) { require_once './master.inc.php'; } // Not already loaded"."\n"; - $tplcontent.= "require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.php';\n"; - $tplcontent.= "require_once DOL_DOCUMENT_ROOT.'/core/website.inc.php';\n"; - $tplcontent.= "ob_start();\n"; - $tplcontent.= "// END PHP ?>\n"; - $tplcontent.= '<html'.($shortlangcode ? ' lang="'.$shortlangcode.'"':'').'>'."\n"; - $tplcontent.= '<head>'."\n"; - $tplcontent.= '<title>'.dol_string_nohtmltag($objectpage->title, 0, 'UTF-8').''."\n"; - $tplcontent.= ''."\n"; - $tplcontent.= ''."\n"; - $tplcontent.= ''."\n"; - $tplcontent.= ''."\n"; - $tplcontent.= ''."\n"; - $tplcontent.= ''."\n"; - $tplcontent.= ''."\n"; - $tplcontent.= ''."\n"; - $tplcontent.= ''."\n"; - $tplcontent.= ''."\n"; - $tplcontent.= ''."\n"; - $tplcontent.= 'ref.'/htmlheader.html"); ?>'."\n"; - $tplcontent.= ''."\n"; - - $tplcontent.= ''."\n"; - $tplcontent.= ''."\n"; - $tplcontent.= $objectpage->content."\n"; - $tplcontent.= ''."\n"; - - $tplcontent.= '"."\n"; - - //var_dump($filetpl);exit; - $result = file_put_contents($filetpl, $tplcontent); - if (! empty($conf->global->MAIN_UMASK)) - @chmod($filetpl, octdec($conf->global->MAIN_UMASK)); - - return $result; -} diff --git a/scripts/bank/export-bank-receipts.php b/scripts/bank/export-bank-receipts.php index ad70190b689..398ec1d7a19 100755 --- a/scripts/bank/export-bank-receipts.php +++ b/scripts/bank/export-bank-receipts.php @@ -262,7 +262,7 @@ if ($resql) $totalbefore = $total; $total = $total + $objp->amount; - + // Date operation $dateop=$db->jdate($objp->do); @@ -289,22 +289,28 @@ if ($resql) { $paymentstatic->fetch($links[$key]['url_id']); $tmparray=$paymentstatic->getBillsArray(''); - foreach($tmparray as $key => $val) + if (is_array($tmparray)) { - $invoicestatic->fetch($val); - if ($accountelem) $accountelem.= ', '; - $accountelem.=$invoicestatic->ref; + foreach($tmparray as $key => $val) + { + $invoicestatic->fetch($val); + if ($accountelem) $accountelem.= ', '; + $accountelem.=$invoicestatic->ref; + } } } elseif ($links[$key]['type']=='payment_supplier') { $paymentsupplierstatic->fetch($links[$key]['url_id']); $tmparray=$paymentsupplierstatic->getBillsArray(''); - foreach($tmparray as $key => $val) + if (is_array($tmparray)) { - $invoicesupplierstatic->fetch($val); - if ($accountelem) $accountelem.= ', '; - $accountelem.=$invoicesupplierstatic->ref; + foreach($tmparray as $key => $val) + { + $invoicesupplierstatic->fetch($val); + if ($accountelem) $accountelem.= ', '; + $accountelem.=$invoicesupplierstatic->ref; + } } } elseif ($links[$key]['type']=='payment_sc') diff --git a/scripts/emailings/mailing-send.php b/scripts/emailings/mailing-send.php index 0de6ca4f5fd..ef9a35fc1ed 100755 --- a/scripts/emailings/mailing-send.php +++ b/scripts/emailings/mailing-send.php @@ -32,7 +32,7 @@ $path=dirname(__FILE__).'/'; // Test if batch mode if (substr($sapi_type, 0, 3) == 'cgi') { - echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; + echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; exit(-1); } @@ -113,13 +113,13 @@ if ($resql) // On choisit les mails non deja envoyes pour ce mailing (statut=0) // ou envoyes en erreur (statut=-1) - $sql2 = "SELECT mc.rowid, mc.lastname as lastname, mc.firstname as firstname, mc.email, mc.other, mc.source_url, mc.source_id, mc.source_type, mc.tag"; + $sql2 = "SELECT mc.rowid, mc.fk_mailing, mc.lastname, mc.firstname, mc.email, mc.other, mc.source_url, mc.source_id, mc.source_type, mc.tag"; $sql2.= " FROM ".MAIN_DB_PREFIX."mailing_cibles as mc"; $sql2.= " WHERE mc.statut < 1 AND mc.fk_mailing = ".$id; - if ($conf->global->MAILING_LIMIT_SENDBYCLI > 0) - { - $sql2.= " LIMIT ".$conf->global->MAILING_LIMIT_SENDBYCLI; - } + if ($conf->global->MAILING_LIMIT_SENDBYCLI > 0) + { + $sql2.= " LIMIT ".$conf->global->MAILING_LIMIT_SENDBYCLI; + } $resql2=$db->query($sql2); if ($resql2) @@ -149,36 +149,40 @@ if ($resql) $res=1; $now=dol_now(); - $obj2 = $db->fetch_object($resql2); + $obj = $db->fetch_object($resql2); // sendto en RFC2822 - $sendto = str_replace(',',' ',dolGetFirstLastname($obj2->firstname, $obj2->lastname) ." <".$obj2->email.">"); + $sendto = str_replace(',',' ',dolGetFirstLastname($obj->firstname, $obj->lastname) ." <".$obj->email.">"); // Make subtsitutions on topic and body - $other=explode(';',$obj2->other); + $other=explode(';',$obj->other); $tmpfield=explode('=',$other[0],2); $other1=(isset($tmpfield[1])?$tmpfield[1]:$tmpfield[0]); - $tmpfield=explode('=',$other[1],2); $other2=(isset($tmpfield[1])?$tmpfield[1]:$tmpfield[0]); - $tmpfield=explode('=',$other[2],2); $other3=(isset($tmpfield[1])?$tmpfield[1]:$tmpfield[0]); - $tmpfield=explode('=',$other[3],2); $other4=(isset($tmpfield[1])?$tmpfield[1]:$tmpfield[0]); - $tmpfield=explode('=',$other[4],2); $other5=(isset($tmpfield[1])?$tmpfield[1]:$tmpfield[0]); - $signature = ((!empty($user->signature) && empty($conf->global->MAIN_MAIL_DO_NOT_USE_SIGN))?$user->signature:''); + $tmpfield=explode('=',$other[1],2); $other2=(isset($tmpfield[1])?$tmpfield[1]:$tmpfield[0]); + $tmpfield=explode('=',$other[2],2); $other3=(isset($tmpfield[1])?$tmpfield[1]:$tmpfield[0]); + $tmpfield=explode('=',$other[3],2); $other4=(isset($tmpfield[1])?$tmpfield[1]:$tmpfield[0]); + $tmpfield=explode('=',$other[4],2); $other5=(isset($tmpfield[1])?$tmpfield[1]:$tmpfield[0]); + $signature = ((!empty($user->signature) && empty($conf->global->MAIN_MAIL_DO_NOT_USE_SIGN))?$user->signature:''); + + $object = null; // Not defined with mass emailing + $parameters=array('mode'=>'emailing'); + $substitutionarray=getCommonSubstitutionArray($langs, 0, array('object','objectamount'), $object); // Note: On mass emailing, this is null because we don't know object // Array of possible substitutions (See also file mailing-send.php that should manage same substitutions) - $substitutionarray=array( - '__ID__' => $obj2->source_id, - '__EMAIL__' => $obj2->email, - '__LASTNAME__' => $obj2->lastname, - '__FIRSTNAME__' => $obj2->firstname, - '__MAILTOEMAIL__' => ''.$obj2->email.'', - '__OTHER1__' => $other1, - '__OTHER2__' => $other2, - '__OTHER3__' => $other3, - '__OTHER4__' => $other4, - '__OTHER5__' => $other5, - '__SIGNATURE__' => $signature, // Signature is empty when ran from command line or taken from user in parameter) - '__CHECK_READ__' => '', - '__UNSUBSCRIBE__' => ''.$langs->trans("MailUnsubcribe").'' - ); + $substitutionarray['__ID__'] = $obj->source_id; + $substitutionarray['__EMAIL__'] = $obj->email; + $substitutionarray['__LASTNAME__'] = $obj->lastname; + $substitutionarray['__FIRSTNAME__'] = $obj->firstname; + $substitutionarray['__MAILTOEMAIL__'] = ''.$obj->email.''; + $substitutionarray['__OTHER1__'] = $other1; + $substitutionarray['__OTHER2__'] = $other2; + $substitutionarray['__OTHER3__'] = $other3; + $substitutionarray['__OTHER4__'] = $other4; + $substitutionarray['__OTHER5__'] = $other5; + $substitutionarray['__USER_SIGNATURE__'] = $signature; // Signature is empty when ran from command line or taken from user in parameter) + $substitutionarray['__SIGNATURE__'] = $signature; // For backward compatibility + $substitutionarray['__CHECK_READ__'] = ''; + $substitutionarray['__UNSUBSCRIBE__'] = ''.$langs->trans("MailUnsubcribe").''; + $onlinepaymentenabled = 0; if (! empty($conf->paypal->enabled)) $onlinepaymentenabled++; if (! empty($conf->paybox->enabled)) $onlinepaymentenabled++; @@ -186,18 +190,20 @@ if ($resql) if ($onlinepaymentenabled && ! empty($conf->global->PAYMENT_SECURITY_TOKEN)) { $substitutionarray['__SECUREKEYPAYMENT__']=dol_hash($conf->global->PAYMENT_SECURITY_TOKEN, 2); - - if (empty($conf->global->PAYMENT_SECURITY_TOKEN_UNIQUE)) $substitutionarray['__SECUREKEYPAYMENT_MEMBER__']=dol_hash($conf->global->PAYMENT_SECURITY_TOKEN, 2); - else $substitutionarray['__SECUREKEYPAYMENT_MEMBER__']=dol_hash($conf->global->PAYMENT_SECURITY_TOKEN . 'membersubscription' . $obj->source_id, 2); - - if (empty($conf->global->PAYMENT_SECURITY_TOKEN_UNIQUE)) $substitutionarray['__SECUREKEYPAYMENT_ORDER__']=dol_hash($conf->global->PAYMENT_SECURITY_TOKEN, 2); - else $substitutionarray['__SECUREKEYPAYMENT_ORDER__']=dol_hash($conf->global->PAYMENT_SECURITY_TOKEN . 'order' . $obj->source_id, 2); - - if (empty($conf->global->PAYMENT_SECURITY_TOKEN_UNIQUE)) $substitutionarray['__SECUREKEYPAYMENT_INVOICE__']=dol_hash($conf->global->PAYMENT_SECURITY_TOKEN, 2); - else $substitutionarray['__SECUREKEYPAYMENT_INVOICE__']=dol_hash($conf->global->PAYMENT_SECURITY_TOKEN . 'invoice' . $obj->source_id, 2); - - if (empty($conf->global->PAYMENT_SECURITY_TOKEN_UNIQUE)) $substitutionarray['__SECUREKEYPAYMENT_CONTRACTLINE__']=dol_hash($conf->global->PAYMENT_SECURITY_TOKEN, 2); - else $substitutionarray['__SECUREKEYPAYMENT_CONTRACTLINE__']=dol_hash($conf->global->PAYMENT_SECURITY_TOKEN . 'contractline' . $obj->source_id, 2); + if (empty($conf->global->PAYMENT_SECURITY_TOKEN_UNIQUE)) + { + $substitutionarray['__SECUREKEYPAYMENT_MEMBER__']=dol_hash($conf->global->PAYMENT_SECURITY_TOKEN, 2); + $substitutionarray['__SECUREKEYPAYMENT_ORDER__']=dol_hash($conf->global->PAYMENT_SECURITY_TOKEN, 2); + $substitutionarray['__SECUREKEYPAYMENT_INVOICE__']=dol_hash($conf->global->PAYMENT_SECURITY_TOKEN, 2); + $substitutionarray['__SECUREKEYPAYMENT_CONTRACTLINE__']=dol_hash($conf->global->PAYMENT_SECURITY_TOKEN, 2); + } + else + { + $substitutionarray['__SECUREKEYPAYMENT_MEMBER__']=dol_hash($conf->global->PAYMENT_SECURITY_TOKEN . 'membersubscription' . $obj->source_id, 2); + $substitutionarray['__SECUREKEYPAYMENT_ORDER__']=dol_hash($conf->global->PAYMENT_SECURITY_TOKEN . 'order' . $obj->source_id, 2); + $substitutionarray['__SECUREKEYPAYMENT_INVOICE__']=dol_hash($conf->global->PAYMENT_SECURITY_TOKEN . 'invoice' . $obj->source_id, 2); + $substitutionarray['__SECUREKEYPAYMENT_CONTRACTLINE__']=dol_hash($conf->global->PAYMENT_SECURITY_TOKEN . 'contractline' . $obj->source_id, 2); + } } /* For backward compatibility */ if (! empty($conf->paypal->enabled) && ! empty($conf->global->PAYPAL_SECURITY_TOKEN)) @@ -216,6 +222,7 @@ if ($resql) if (empty($conf->global->PAYPAL_SECURITY_TOKEN_UNIQUE)) $substitutionarray['__SECUREKEYPAYPAL_CONTRACTLINE__']=dol_hash($conf->global->PAYPAL_SECURITY_TOKEN, 2); else $substitutionarray['__SECUREKEYPAYPAL_CONTRACTLINE__']=dol_hash($conf->global->PAYPAL_SECURITY_TOKEN . 'contractline' . $obj->source_id, 2); } + complete_substitutions_array($substitutionarray,$langs); $newsubject=make_substitutions($subject,$substitutionarray); $newmessage=make_substitutions($message,$substitutionarray); @@ -223,24 +230,24 @@ if ($resql) $substitutionisok=true; // Fabrication du mail - $trackid='emailing-'.$obj2->source_type.$obj2->source_id; + $trackid='emailing-'.$obj->fk_mailing.'-'.$obj->rowid; $mail = new CMailFile( - $newsubject, - $sendto, - $from, - $newmessage, - array(), - array(), - array(), - '', - '', - 0, - $msgishtml, - $errorsto, - '', - $trackid, - '', - 'emailing' + $newsubject, + $sendto, + $from, + $newmessage, + array(), + array(), + array(), + '', + '', + 0, + $msgishtml, + $errorsto, + '', + $trackid, + '', + 'emailing' ); if ($mail->error) @@ -270,13 +277,13 @@ if ($resql) // We must union table llx_mailing_taget for event tab OR enter 1 event with a special table link (id of email in event) // Run trigger /* - if ($obj2->source_type == 'contact') + if ($obj->source_type == 'contact') { - $emailing->sendtoid = $obj2->source_id; + $emailing->sendtoid = $obj->source_id; } - if ($obj2->source_type == 'thirdparty') + if ($obj->source_type == 'thirdparty') { - $emailing->socid = $obj2->source_id; + $emailing->socid = $obj->source_id; } // Call trigger $result=$emailing->call_trigger('EMAILING_SENTBYMAIL',$user); @@ -285,7 +292,7 @@ if ($resql) */ $sqlok ="UPDATE ".MAIN_DB_PREFIX."mailing_cibles"; - $sqlok.=" SET statut=1, date_envoi='".$db->idate($now)."' WHERE rowid=".$obj2->rowid; + $sqlok.=" SET statut=1, date_envoi='".$db->idate($now)."' WHERE rowid=".$obj->rowid; $resqlok=$db->query($sqlok); if (! $resqlok) { @@ -298,7 +305,7 @@ if ($resql) if (strpos($message, '__CHECK_READ__') !== false) { //Update status communication of thirdparty prospect - $sqlx = "UPDATE ".MAIN_DB_PREFIX."societe SET fk_stcomm=2 WHERE rowid IN (SELECT source_id FROM ".MAIN_DB_PREFIX."mailing_cibles WHERE rowid=".$obj2->rowid.")"; + $sqlx = "UPDATE ".MAIN_DB_PREFIX."societe SET fk_stcomm=2 WHERE rowid IN (SELECT source_id FROM ".MAIN_DB_PREFIX."mailing_cibles WHERE rowid=".$obj->rowid.")"; dol_syslog("card.php: set prospect thirdparty status", LOG_DEBUG); $resqlx=$db->query($sqlx); if (! $resqlx) @@ -307,8 +314,8 @@ if ($resql) $error++; } - //Update status communication of contact prospect - $sqlx = "UPDATE ".MAIN_DB_PREFIX."societe SET fk_stcomm=2 WHERE rowid IN (SELECT sc.fk_soc FROM ".MAIN_DB_PREFIX."socpeople AS sc INNER JOIN ".MAIN_DB_PREFIX."mailing_cibles AS mc ON mc.rowid=".$obj2->rowid." AND mc.source_type = 'contact' AND mc.source_id = sc.rowid)"; + //Update status communication of contact prospect + $sqlx = "UPDATE ".MAIN_DB_PREFIX."societe SET fk_stcomm=2 WHERE rowid IN (SELECT sc.fk_soc FROM ".MAIN_DB_PREFIX."socpeople AS sc INNER JOIN ".MAIN_DB_PREFIX."mailing_cibles AS mc ON mc.rowid=".$obj->rowid." AND mc.source_type = 'contact' AND mc.source_id = sc.rowid)"; dol_syslog("card.php: set prospect contact status", LOG_DEBUG); $resqlx=$db->query($sqlx); @@ -319,9 +326,9 @@ if ($resql) } } - if (!empty($conf->global->MAILING_DELAY)) { - sleep($conf->global->MAILING_DELAY); - } + if (!empty($conf->global->MAILING_DELAY)) { + sleep($conf->global->MAILING_DELAY); + } } } @@ -333,7 +340,7 @@ if ($resql) dol_syslog("error for emailing id ".$id." #".$i.($mail->error?' - '.$mail->error:''), LOG_DEBUG); $sqlerror="UPDATE ".MAIN_DB_PREFIX."mailing_cibles"; - $sqlerror.=" SET statut=-1, date_envoi=".$db->idate($now)." WHERE rowid=".$obj2->rowid; + $sqlerror.=" SET statut=-1, date_envoi=".$db->idate($now)." WHERE rowid=".$obj->rowid; $resqlerror=$db->query($sqlerror); if (! $resqlerror) { diff --git a/scripts/invoices/rebuild_merge_pdf.php b/scripts/invoices/rebuild_merge_pdf.php index 6727dc5cab7..30782d3b913 100755 --- a/scripts/invoices/rebuild_merge_pdf.php +++ b/scripts/invoices/rebuild_merge_pdf.php @@ -289,7 +289,7 @@ function usage() print "To exclude deposit invoices, use filter=nodeposit\n"; print "To exclude some thirdparties, use filter=excludethirdparties id1,id2...\n"; print "To limit to some thirdparties, use filter=onlythirdparties id1,id2...\n"; - print "To regenerate existing PDF, use regenerate=crabe\n"; + print "To regenerate existing PDF, use regenerate=templatename\n"; print "To generate invoices in a language, use lang=xx_XX\n"; print "To set prefix of generated file name, use prefix=myfileprefix\n"; print "\n"; diff --git a/scripts/members/sync_members_types_dolibarr2ldap.php b/scripts/members/sync_members_types_dolibarr2ldap.php new file mode 100755 index 00000000000..939a98c8728 --- /dev/null +++ b/scripts/members/sync_members_types_dolibarr2ldap.php @@ -0,0 +1,131 @@ +#!/usr/bin/env php + + * Copyright (C) 2006 Laurent Destailleur + * Copyright (C) 2017 Regis Houssin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file scripts/user/sync_members_types_dolibarr2ldap.php + * \ingroup ldap core + * \brief Script de mise a jour des types de membres dans LDAP depuis base Dolibarr + */ + +$sapi_type = php_sapi_name(); +$script_file = basename(__FILE__); +$path=dirname(__FILE__).'/'; + +// Test if batch mode +if (substr($sapi_type, 0, 3) == 'cgi') { + echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; + exit(-1); +} + +if (! isset($argv[1]) || ! $argv[1]) { + print "Usage: ".$script_file." now\n"; + exit(-1); +} +$now=$argv[1]; + +require_once($path."../../htdocs/master.inc.php"); +require_once(DOL_DOCUMENT_ROOT."/core/class/ldap.class.php"); +require_once(DOL_DOCUMENT_ROOT."/adherents/class/adherent_type.class.php"); + +// Global variables +$version=DOL_VERSION; +$error=0; + + +/* + * Main + */ + +@set_time_limit(0); +print "***** ".$script_file." (".$version.") pid=".dol_getmypid()." *****\n"; +dol_syslog($script_file." launched with arg ".join(',',$argv)); + +/* +if (! $conf->global->LDAP_SYNCHRO_ACTIVE) +{ + print $langs->trans("LDAPSynchronizationNotSetupInDolibarr"); + exit(-1); +} +*/ + +$sql = "SELECT rowid"; +$sql .= " FROM ".MAIN_DB_PREFIX."adherent_type"; + +$resql = $db->query($sql); +if ($resql) +{ + $num = $db->num_rows($resql); + $i = 0; + + $ldap=new Ldap(); + $result=$ldap->connect_bind(); + + if ($result > 0) + { + while ($i < $num) + { + $ldap->error=""; + + $obj = $db->fetch_object($resql); + + $membertype = new AdherentType($db); + $membertype->id = $obj->rowid; + $membertype->fetch($membertype->id); + + print $langs->trans("UpdateMemberType")." rowid=".$membertype->id." ".$membertype-label; + + $oldobject=$membertype; + + $oldinfo=$membertype->_load_ldap_info(); + $olddn=$membertype->_load_ldap_dn($oldinfo); + + $info=$membertype->_load_ldap_info(); + $dn=$membertype->_load_ldap_dn($info); + + $result=$ldap->add($dn,$info,$user); // Wil fail if already exists + $result=$ldap->update($dn,$info,$user,$olddn); + if ($result > 0) + { + print " - ".$langs->trans("OK"); + } + else + { + $error++; + print " - ".$langs->trans("KO").' - '.$ldap->error; + } + print "\n"; + + $i++; + } + + $ldap->unbind(); + $ldap->close(); + } + else { + print $ldap->error; + } +} +else +{ + dol_print_error($db); +} + +exit($error); diff --git a/scripts/members/sync_members_types_ldap2dolibarr.php b/scripts/members/sync_members_types_ldap2dolibarr.php new file mode 100755 index 00000000000..55d5606cd30 --- /dev/null +++ b/scripts/members/sync_members_types_ldap2dolibarr.php @@ -0,0 +1,221 @@ +#!/usr/bin/env php + + * Copyright (C) 2006-2012 Laurent Destailleur + * Copyright (C) 2013 Maxime Kohlhaas + * Copyright (C) 2017 Regis Houssin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file scripts/user/sync_members_types_ldap2dolibarr.php + * \ingroup ldap member + * \brief Script to update members types into Dolibarr from LDAP + */ + +$sapi_type = php_sapi_name(); +$script_file = basename(__FILE__); +$path=dirname(__FILE__).'/'; + +// Test if batch mode +if (substr($sapi_type, 0, 3) == 'cgi') { + echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; + exit(-1); +} + +require_once($path."../../htdocs/master.inc.php"); +require_once(DOL_DOCUMENT_ROOT."/core/lib/date.lib.php"); +require_once(DOL_DOCUMENT_ROOT."/core/class/ldap.class.php"); +require_once(DOL_DOCUMENT_ROOT."/adherents/class/adherent_type.class.php"); + +$langs->load("main"); +$langs->load("errors"); + + +// Global variables +$version=DOL_VERSION; +$error=0; +$forcecommit=0; +$confirmed=0; + + +/* + * Main + */ + +@set_time_limit(0); +print "***** ".$script_file." (".$version.") pid=".dol_getmypid()." *****\n"; +dol_syslog($script_file." launched with arg ".join(',',$argv)); + +// List of fields to get from LDAP +$required_fields = array( + $conf->global->LDAP_KEY_MEMBERS_TYPES, + $conf->global->LDAP_MEMBER_TYPE_FIELD_FULLNAME, + $conf->global->LDAP_MEMBER_TYPE_FIELD_DESCRIPTION, + $conf->global->LDAP_MEMBER_TYPE_FIELD_GROUPMEMBERS +); + +// Remove from required_fields all entries not configured in LDAP (empty) and duplicated +$required_fields=array_unique(array_values(array_filter($required_fields, "dolValidElementType"))); + + +if (! isset($argv[1])) { + //print "Usage: $script_file (nocommitiferror|commitiferror) [id_group]\n"; + print "Usage: $script_file (nocommitiferror|commitiferror) [--server=ldapserverhost] [--excludeuser=user1,user2...] [-y]\n"; + exit(-1); +} + +foreach($argv as $key => $val) +{ + if ($val == 'commitiferror') $forcecommit=1; + if (preg_match('/--server=([^\s]+)$/',$val,$reg)) $conf->global->LDAP_SERVER_HOST=$reg[1]; + if (preg_match('/--excludeuser=([^\s]+)$/',$val,$reg)) $excludeuser=explode(',',$reg[1]); + if (preg_match('/-y$/',$val,$reg)) $confirmed=1; +} + +print "Mails sending disabled (useless in batch mode)\n"; +$conf->global->MAIN_DISABLE_ALL_MAILS=1; // On bloque les mails +print "\n"; +print "----- Synchronize all records from LDAP database:\n"; +print "host=".$conf->global->LDAP_SERVER_HOST."\n"; +print "port=".$conf->global->LDAP_SERVER_PORT."\n"; +print "login=".$conf->global->LDAP_ADMIN_DN."\n"; +print "pass=".preg_replace('/./i','*',$conf->global->LDAP_ADMIN_PASS)."\n"; +print "DN to extract=".$conf->global->LDAP_MEMBER_TYPE_DN."\n"; +print 'Filter=('.$conf->global->LDAP_KEY_MEMBERS_TYPES.'=*)'."\n"; +print "----- To Dolibarr database:\n"; +print "type=".$conf->db->type."\n"; +print "host=".$conf->db->host."\n"; +print "port=".$conf->db->port."\n"; +print "login=".$conf->db->user."\n"; +print "database=".$conf->db->name."\n"; +print "----- Options:\n"; +print "commitiferror=".$forcecommit."\n"; +print "Mapped LDAP fields=".join(',',$required_fields)."\n"; +print "\n"; + +if (! $confirmed) +{ + print "Hit Enter to continue or CTRL+C to stop...\n"; + $input = trim(fgets(STDIN)); +} + +if (empty($conf->global->LDAP_MEMBER_TYPE_DN)) +{ + print $langs->trans("Error").': '.$langs->trans("LDAP setup for members types not defined inside Dolibarr"); + exit(-1); +} + + +$ldap = new Ldap(); +$result = $ldap->connect_bind(); +if ($result >= 0) +{ + $justthese=array(); + + + // We disable synchro Dolibarr-LDAP + $conf->global->LDAP_MEMBER_TYPE_ACTIVE=0; + + $ldaprecords = $ldap->getRecords('*',$conf->global->LDAP_MEMBER_TYPE_DN, $conf->global->LDAP_KEY_MEMBERS_TYPES, $required_fields, 0, array($conf->global->LDAP_MEMBER_TYPE_FIELD_GROUPMEMBERS)); + if (is_array($ldaprecords)) + { + $db->begin(); + + // Warning $ldapuser has a key in lowercase + foreach ($ldaprecords as $key => $ldapgroup) + { + $membertype = new AdherentType($db); + $membertype->fetch('', $ldapgroup[$conf->global->LDAP_KEY_MEMBERS_TYPES]); + $membertype->label = $ldapgroup[$conf->global->LDAP_MEMBER_TYPE_FIELD_FULLNAME]; + $membertype->description = $ldapgroup[$conf->global->LDAP_MEMBER_TYPE_FIELD_DESCRIPTION]; + $membertype->entity = $conf->entity; + + //print_r($ldapgroup); + + if ($membertype->id > 0) { // Member type update + print $langs->transnoentities("MemberTypeUpdate").' # '.$key.': name='.$membertype->label; + $res=$membertype->update($user); + + if ($res > 0) + { + print ' --> Updated member type id='.$membertype->id.' name='.$membertype->label; + } + else + { + $error++; + print ' --> '.$res.' '.$membertype->error; + } + print "\n"; + } else { // Member type creation + print $langs->transnoentities("MemberTypeCreate").' # '.$key.': name='.$membertype->label; + $res=$membertype->create($user); + + if ($res > 0) + { + print ' --> Created member type id='.$membertype->id.' name='.$membertype->label; + } + else + { + $error++; + print ' --> '.$res.' '.$membertype->error; + } + print "\n"; + } + + //print_r($membertype); + } + + if (! $error || $forcecommit) + { + if (! $error) print $langs->transnoentities("NoErrorCommitIsDone")."\n"; + else print $langs->transnoentities("ErrorButCommitIsDone")."\n"; + $db->commit(); + } + else + { + print $langs->transnoentities("ErrorSomeErrorWereFoundRollbackIsDone",$error)."\n"; + $db->rollback(); + } + print "\n"; + } + else + { + dol_print_error('',$ldap->error); + $error++; + } +} +else +{ + dol_print_error('',$ldap->error); + $error++; +} + + +exit($error); + + +/** + * Function to say if a value is empty or not + * + * @param string $element Value to test + * @return boolean True of false + */ +function dolValidElementType($element) +{ + return (trim($element) != ''); +} + diff --git a/scripts/modulebuilder/builddoc.php b/scripts/modulebuilder/builddoc.php index 2ac8d97ac32..f2c0eef421f 100755 --- a/scripts/modulebuilder/builddoc.php +++ b/scripts/modulebuilder/builddoc.php @@ -40,18 +40,49 @@ if (substr($sapi_type, 0, 3) == 'cgi') { } if (! isset($argv[1]) || ! $argv[1]) { - print "Usage: ".$script_file." inputfile1\n"; + print "Usage: ".$script_file." ModuleName\n"; exit(-1); } -$inputfile1=$argv[1]; +$modulename=$argv[1]; require_once ($path."../../htdocs/master.inc.php"); +require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formadmin.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/modulebuilder.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/utils.class.php'; + +$langs->loadLangs(array("admin", "modulebuilder", "other", "cron")); // Global variables $version=DOL_VERSION; $error=0; +// Dir for custom dirs +$tmp=explode(',', $dolibarr_main_document_root_alt); +$dirins = $tmp[0]; +$dirread = $dirins; +$forceddirread = 0; + +$tmpdir = explode('@', $module); +if (! empty($tmpdir[1])) +{ + $module=$tmpdir[0]; + $dirread=$tmpdir[1]; + $forceddirread=1; +} + +$FILEFLAG='modulebuilder.txt'; + +$now=dol_now(); +$newmask = 0; +if (empty($newmask) && ! empty($conf->global->MAIN_UMASK)) $newmask=$conf->global->MAIN_UMASK; +if (empty($newmask)) // This should no happen +{ + $newmask='0664'; +} /* @@ -60,8 +91,21 @@ $error=0; @set_time_limit(0); print "***** ".$script_file." (".$version.") pid=".dol_getmypid()." *****\n"; -print $inputfile1."
    "; +print "modulename=".$modulename."\n"; +print "dirins=".$dirins."\n"; +$FILENAMEDOC=strtolower($module).'.html'; // TODO Use/text PDF +$dirofmodule = dol_buildpath(strtolower($module), 0).'/doc'; +$outputfiledoc = $dirofmodule.'/'.$FILENAMEDOC; +$util = new Utils($db); +$result = $util->generateDoc($module); +if ($result <= 0) +{ + print $util->errors; + exit(1); +} +print $langs->trans("DocFileGeneratedInto", $outputfiledoc); +exit(0); diff --git a/scripts/modulebuilder/initmodule.php b/scripts/modulebuilder/initmodule.php new file mode 100755 index 00000000000..6c9801878d3 --- /dev/null +++ b/scripts/modulebuilder/initmodule.php @@ -0,0 +1,175 @@ +#!/usr/bin/env php + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +/** + * \file scripts/modulebuilder/initmodule.php + * \ingroup modulebuilder + * \brief Script to initialize a module. + */ + + +$sapi_type = php_sapi_name(); +$script_file = basename(__FILE__); +$path=dirname(__FILE__).'/'; + +// Test if batch mode +if (substr($sapi_type, 0, 3) == 'cgi') { + echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; + exit(-1); +} + +if (! isset($argv[1]) || ! $argv[1]) { + print "Usage: ".$script_file." ModuleName\n"; + exit(-1); +} +$modulename=$argv[1]; + +require_once ($path."../../htdocs/master.inc.php"); +require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formadmin.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/modulebuilder.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; + +$langs->loadLangs(array("admin", "modulebuilder", "other", "cron")); + + +// Global variables +$version=DOL_VERSION; +$error=0; + +// Dir for custom dirs +$tmp=explode(',', $dolibarr_main_document_root_alt); +$dirins = $tmp[0]; +$dirread = $dirins; +$forceddirread = 0; + +$tmpdir = explode('@', $module); +if (! empty($tmpdir[1])) +{ + $module=$tmpdir[0]; + $dirread=$tmpdir[1]; + $forceddirread=1; +} + +$FILEFLAG='modulebuilder.txt'; + +$now=dol_now(); +$newmask = 0; +if (empty($newmask) && ! empty($conf->global->MAIN_UMASK)) $newmask=$conf->global->MAIN_UMASK; +if (empty($newmask)) // This should no happen +{ + $newmask='0664'; +} + + +/* + * Main + */ + +@set_time_limit(0); +print "***** ".$script_file." (".$version.") pid=".dol_getmypid()." *****\n"; +print "modulename=".$modulename."\n"; +print "dirins=".$dirins."\n"; + +if (preg_match('/[^a-z0-9_]/i', $modulename)) +{ + $error++; + print 'Error '.$langs->trans("SpaceOrSpecialCharAreNotAllowed")."\n"; + exit(1); +} + +if (! $error) +{ + $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template'; + $destdir = $dirins.'/'.strtolower($modulename); + + $arrayreplacement=array( + 'mymodule'=>strtolower($modulename), + 'MyModule'=>$modulename + ); + + $result = dolCopyDir($srcdir, $destdir, 0, 0, $arrayreplacement); + //dol_mkdir($destfile); + if ($result <= 0) + { + if ($result < 0) + { + $error++; + $langs->load("errors"); + print $langs->trans("ErrorFailToCopyDir", $srcdir, $destdir)."\n"; + exit(2); + } + else // $result == 0 + { + print $langs->trans("AllFilesDidAlreadyExist", $srcdir, $destdir)."\n"; + } + } + + // Delete some files + dol_delete_file($destdir.'/myobject_card.php'); + dol_delete_file($destdir.'/myobject_note.php'); + dol_delete_file($destdir.'/myobject_document.php'); + dol_delete_file($destdir.'/myobject_agenda.php'); + dol_delete_file($destdir.'/myobject_list.php'); + dol_delete_file($destdir.'/lib/myobject.lib.php'); + dol_delete_file($destdir.'/test/phpunit/MyObjectTest.php'); + dol_delete_file($destdir.'/sql/llx_mymodule_myobject.sql'); + dol_delete_file($destdir.'/sql/llx_mymodule_myobject_extrafields.sql'); + dol_delete_file($destdir.'/sql/llx_mymodule_myobject.key.sql'); + dol_delete_file($destdir.'/scripts/myobject.php'); + dol_delete_file($destdir.'/img/object_myobject.png'); + dol_delete_file($destdir.'/class/myobject.class.php'); + dol_delete_file($destdir.'/class/api_mymodule.class.php'); +} + +// Edit PHP files +if (! $error) +{ + $listofphpfilestoedit = dol_dir_list($destdir, 'files', 1, '\.(php|MD|js|sql|txt|xml|lang)$', '', 'fullname', SORT_ASC, 0, 1); + foreach($listofphpfilestoedit as $phpfileval) + { + //var_dump($phpfileval['fullname']); + $arrayreplacement=array( + 'mymodule'=>strtolower($modulename), + 'MyModule'=>$modulename, + 'MYMODULE'=>strtoupper($modulename), + 'My module'=>$modulename, + 'my module'=>$modulename, + 'Mon module'=>$modulename, + 'mon module'=>$modulename, + 'htdocs/modulebuilder/template'=>strtolower($modulename), + '---Put here your own copyright and developer email---'=>dol_print_date($now,'%Y').' '.$user->getFullName($langs).($user->email?' <'.$user->email.'>':'') + ); + + + $result=dolReplaceInFile($phpfileval['fullname'], $arrayreplacement); + //var_dump($result); + if ($result < 0) + { + print $langs->trans("ErrorFailToMakeReplacementInto", $phpfileval['fullname'])."\n"; + exit(3); + } + } +} + +print 'Module initialized'."\n"; +exit(0); + diff --git a/scripts/odt2pdf/odt2pdf.sh b/scripts/odt2pdf/odt2pdf.sh index 4cf1ab54013..2a3550de29b 100755 --- a/scripts/odt2pdf/odt2pdf.sh +++ b/scripts/odt2pdf/odt2pdf.sh @@ -3,20 +3,26 @@ # @copyright GPL License 2013 - Florian HEnry - florian.henry@open-concept.pro # @copyright GPL License 2017 - Laurent Destailleur - eldy@users.sourceforge.net # -# Convert an ODT into a PDF using "jodconverter" or "pyodconverter" tool. -# Dolibarr variable MAIN_ODT_AS_PDF must be defined to value "jodconverter" to call jodconverter wrapper after ODT generation +# Convert an ODT into a PDF using "jodconverter" or "pyodconverter" or "unoconv" tool. +# Dolibarr variable MAIN_ODT_AS_PDF must be defined +# to value "unoconv" to call unoconv CLI tool after ODT generation. # or value "pyodconverter" to call DocumentConverter.py after ODT generation. +# or value "jodconverter" to call jodconverter wrapper after ODT generation # or value "/pathto/jodconverter-cli-file.jar" to call jodconverter java tool without wrapper after ODT generation. # Dolibarr variable MAIN_DOL_SCRIPTS_ROOT must be defined to path of script directories (otherwise dolibarr will try to guess). if [ "x$1" == "x" ] then - echo "Usage: odt2pdf.sh fullfilename [jodconverter|pyodconverter|pathtojodconverterjar]" + echo "Usage: odt2pdf.sh fullfilename [unoconv|jodconverter|pyodconverter|pathtojodconverterjar]" + echo "Example: odt2pdf.sh myfile unoconv" echo "Example: odt2pdf.sh myfile ~/jodconverter/jodconverter-cli-2.2.2.jar" exit fi + + + # Full patch where soffice is installed soffice="/usr/bin/soffice" @@ -26,7 +32,21 @@ home_java="/tmp" # Main program if [ -f "$1.odt" ] - then +then + + if [ "x$2" == "xunoconv" ] + then + # See issue https://github.com/dagwieers/unoconv/issues/87 + /usr/bin/unoconv -vvv "$1.odt" + retcode=$? + if [ $retcode -ne 0 ] + then + echo "Error while converting odt to pdf: $retcode" + exit 1 + fi + exit 0 + fi + nbprocess=$(pgrep -c soffice) if [ $nbprocess -ne 1 ] # If there is some soffice process running then @@ -59,8 +79,9 @@ if [ -f "$1.odt" ] echo "Error while converting odt to pdf: $retcode" exit 1 fi + sleep 1 - else +else echo "Error: Odt file $1.odt does not exist" exit 1 fi diff --git a/test/phpunit/AdherentTest.php b/test/phpunit/AdherentTest.php index 34ec0a80917..4c92f507f66 100644 --- a/test/phpunit/AdherentTest.php +++ b/test/phpunit/AdherentTest.php @@ -138,8 +138,8 @@ class AdherentTest extends PHPUnit_Framework_TestCase $localobject=new AdherentType($this->savdb); $localobject->statut=1; - $localobject->libelle='Adherent type test'; - $localobject->cotisation=1; + $localobject->label='Adherent type test'; + $localobject->subscription=1; $localobject->vote=1; $result=$localobject->create($user); print __METHOD__." result=".$result."\n"; @@ -196,7 +196,6 @@ class AdherentTest extends PHPUnit_Framework_TestCase $result=$localobject->fetch($id); print __METHOD__." id=".$id." result=".$result."\n"; $this->assertLessThan($result, 0); - return $localobject; } @@ -318,14 +317,13 @@ class AdherentTest extends PHPUnit_Framework_TestCase $langs=$this->savlangs; $db=$this->savdb; - $template = '%DOL_MAIN_URL_ROOT%,%ID%,%CIVILITY%,%FIRSTNAME%,%LASTNAME%,%FULLNAME%,%COMPANY%,'. - '%ADDRESS%,%ZIP%,%TOWN%,%COUNTRY%,%EMAIL%,%BIRTH%,%PHOTO%,%LOGIN%,%PASSWORD%,%PRENOM%,'. - '%NOM%,%SOCIETE%,%ADDRESS%,%ZIP%,%TOWN%,%COUNTRY%'; + $template = '__CIVILITY__,__FIRSTNAME__,__LASTNAME__,__FULLNAME__,__COMPANY__,'. + '__ADDRESS__,__ZIP__,__TOWN__,__COUNTRY__,__EMAIL__,__BIRTH__,__PHOTO__,__LOGIN__'; // If option to store clear password has been set, we get 'dolibspec' into PASSWORD field. - $expected = DOL_MAIN_URL_ROOT.','.$localobject->id.',,New firstname,New name,New firstname New name,'. + $expected = ',New firstname,New name,New firstname New name,'. 'New company,New address,New zip,New town,Belgium,newemail@newemail.com,'.dol_print_date($localobject->birth,'day').',,'. - 'newlogin,dolibspec,New firstname,New name,New company,New address,New zip,New town,Belgium'; + 'newlogin'; $result = $localobject->makeSubstitution($template); print __METHOD__." result=".$result."\n"; diff --git a/test/phpunit/AllTests.php b/test/phpunit/AllTests.php index 56c5541d0bb..d1f0e8b5158 100644 --- a/test/phpunit/AllTests.php +++ b/test/phpunit/AllTests.php @@ -85,12 +85,16 @@ class AllTests $suite->addTestSuite('CompanyLibTest'); require_once dirname(__FILE__).'/DateLibTest.php'; $suite->addTestSuite('DateLibTest'); + require_once dirname(__FILE__).'/UtilsTest.php'; + $suite->addTestSuite('UtilsTest'); //require_once dirname(__FILE__).'/DateLibTzFranceTest.php'; //$suite->addTestSuite('DateLibTzFranceTest'); require_once dirname(__FILE__).'/MarginsLibTest.php'; $suite->addTestSuite('MarginsLibTest'); require_once dirname(__FILE__).'/FilesLibTest.php'; $suite->addTestSuite('FilesLibTest'); + require_once dirname(__FILE__).'/GetUrlLibTest.php'; + $suite->addTestSuite('GetUrlLibTest'); require_once dirname(__FILE__).'/JsonLibTest.php'; $suite->addTestSuite('JsonLibTest'); require_once dirname(__FILE__).'/ImagesLibTest.php'; @@ -113,6 +117,11 @@ class AllTests require_once dirname(__FILE__).'/SecurityTest.php'; $suite->addTestSuite('SecurityTest'); + require_once dirname(__FILE__).'/UserTest.php'; + $suite->addTestSuite('UserTest'); + require_once dirname(__FILE__).'/UserGroupTest.php'; + $suite->addTestSuite('UserGroupTest'); + require_once dirname(__FILE__).'/NumberingModulesTest.php'; $suite->addTestSuite('NumberingModulesTest'); require_once dirname(__FILE__).'/PgsqlTest.php'; @@ -151,6 +160,9 @@ class AllTests require_once dirname(__FILE__).'/PropalTest.php'; $suite->addTestSuite('PropalTest'); + require_once dirname(__FILE__).'/SupplierProposalTest.php'; + $suite->addTestSuite('SupplierProposalTest'); + require_once dirname(__FILE__).'/CommandeTest.php'; $suite->addTestSuite('CommandeTest'); @@ -166,10 +178,6 @@ class AllTests require_once dirname(__FILE__).'/FactureFournisseurTest.php'; $suite->addTestSuite('FactureFournisseurTest'); - require_once dirname(__FILE__).'/UserTest.php'; - $suite->addTestSuite('UserTest'); - require_once dirname(__FILE__).'/UserGroupTest.php'; - $suite->addTestSuite('UserGroupTest'); require_once dirname(__FILE__).'/BankAccountTest.php'; $suite->addTestSuite('BankAccountTest'); require_once dirname(__FILE__).'/CompanyBankAccountTest.php'; @@ -195,18 +203,22 @@ class AllTests require_once dirname(__FILE__).'/RestAPIUserTest.php'; $suite->addTestSuite('RestAPIUserTest'); - require_once dirname(__FILE__).'/WebservicesProductsTest.php'; - $suite->addTestSuite('WebservicesProductsTest'); - require_once dirname(__FILE__).'/WebservicesInvoicesTest.php'; - $suite->addTestSuite('WebservicesInvoicesTest'); - require_once dirname(__FILE__).'/WebservicesOrdersTest.php'; - $suite->addTestSuite('WebservicesOrdersTest'); - require_once dirname(__FILE__).'/WebservicesOtherTest.php'; - $suite->addTestSuite('WebservicesOtherTest'); - require_once dirname(__FILE__).'/WebservicesThirdpartyTest.php'; - $suite->addTestSuite('WebservicesThirdpartyTest'); - require_once dirname(__FILE__).'/WebservicesUserTest.php'; - $suite->addTestSuite('WebservicesUserTest'); + // Test only with php7.2 or less + //if ((float) phpversion() < 7.3) + //{ + require_once dirname(__FILE__).'/WebservicesProductsTest.php'; + $suite->addTestSuite('WebservicesProductsTest'); + require_once dirname(__FILE__).'/WebservicesInvoicesTest.php'; + $suite->addTestSuite('WebservicesInvoicesTest'); + require_once dirname(__FILE__).'/WebservicesOrdersTest.php'; + $suite->addTestSuite('WebservicesOrdersTest'); + require_once dirname(__FILE__).'/WebservicesOtherTest.php'; + $suite->addTestSuite('WebservicesOtherTest'); + require_once dirname(__FILE__).'/WebservicesThirdpartyTest.php'; + $suite->addTestSuite('WebservicesThirdpartyTest'); + require_once dirname(__FILE__).'/WebservicesUserTest.php'; + $suite->addTestSuite('WebservicesUserTest'); + //} require_once dirname(__FILE__).'/ExportTest.php'; $suite->addTestSuite('ExportTest'); diff --git a/test/phpunit/BuildDocTest.php b/test/phpunit/BuildDocTest.php index 25b7bd15c03..c30bf1b9a96 100644 --- a/test/phpunit/BuildDocTest.php +++ b/test/phpunit/BuildDocTest.php @@ -172,7 +172,7 @@ class BuildDocTest extends PHPUnit_Framework_TestCase $localobjectcom->initAsSpecimen(); $localobject=new Facture($this->savdb); - $localobject->createFromOrder($localobjectcom); + $localobject->createFromOrder($localobjectcom, $user); $localobject->date_lim_reglement = dol_now() + 3600 * 24 *30; // Crabe (english) diff --git a/test/phpunit/CodingPhpTest.php b/test/phpunit/CodingPhpTest.php index 073adc8ef9a..2e4deb372eb 100644 --- a/test/phpunit/CodingPhpTest.php +++ b/test/phpunit/CodingPhpTest.php @@ -221,21 +221,20 @@ class CodingPhpTest extends PHPUnit_Framework_TestCase $this->assertTrue($ok, 'Found a use of print_liste_field_titre with fist parameter that is a translated value instead of just the translation key in file '.$file['fullname'].'. Bad.'); - // Test that output of $_SERVER\[\'PHP_SELF\'\] is escaped (not done for the moment, did not found a way to forge value of $_SERVER['PHP_SELF'] by extern access). - /*$ok=true; + // Test we don't have
    + $ok=true; $matches=array(); // Check string ='".$this->xxx with xxx that is not 'escape'. It means we forget a db->escape when forging sql request. - preg_match_all('/(...................)\$_SERVER\[\'PHP_SELF\'\]/', $filecontent, $matches, PREG_SET_ORDER); + preg_match_all('/
    /', $filecontent, $matches, PREG_SET_ORDER); foreach($matches as $key => $val) { - if ($val[1] != 'dol_escape_htmltag(') + if ($file['name'] != 'functions.lib.php') { $ok=false; break; } } - $this->assertTrue($ok, 'Found a $_SERVER[\'PHP_SELF\'] without dol_escape_htmltag around in file '.$file['fullname'].' ('.$val[1].'$_SERVER[\'PHP_SELF\']). Bad.'); - */ + $this->assertTrue($ok, 'Found a tag
    that is for xml in file '.$file['fullname'].' You may use
    instead.'); } return; diff --git a/test/phpunit/CommandeTest.php b/test/phpunit/CommandeTest.php index aaba882cc87..1d0e4fbf616 100644 --- a/test/phpunit/CommandeTest.php +++ b/test/phpunit/CommandeTest.php @@ -165,13 +165,38 @@ class CommandeTest extends PHPUnit_Framework_TestCase return $localobject; } + /** + * testCommandeUpdate + * + * @param Object $localobject Commande + * @return Commande + * + * @depends testCommandeFetch + * The depends says test is run only if previous is ok + */ + public function testCommandUpdate($localobject) + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $localobject->note_private='New note private after update'; + $result=$localobject->update($user); + + $this->assertLessThan($result, 0); + print __METHOD__." id=".$id." result=".$result."\n"; + return $localobject; + } + /** * testCommandeValid * * @param Object $localobject Order - * @return void + * @return Commande * - * @depends testCommandeFetch + * @depends testCommandUpdate * The depends says test is run only if previous is ok */ public function testCommandeValid($localobject) @@ -193,7 +218,7 @@ class CommandeTest extends PHPUnit_Framework_TestCase * testCommandeCancel * * @param Object $localobject Order - * @return void + * @return Commande * * @depends testCommandeValid * The depends says test is run only if previous is ok @@ -217,7 +242,7 @@ class CommandeTest extends PHPUnit_Framework_TestCase * testCommandeOther * * @param Object $localobject Order - * @return void + * @return int Order id * * @depends testCommandeCancel * The depends says test is run only if previous is ok diff --git a/test/phpunit/FactureTest.php b/test/phpunit/FactureTest.php index 8c3d4a2374a..d3e202f33c2 100644 --- a/test/phpunit/FactureTest.php +++ b/test/phpunit/FactureTest.php @@ -135,7 +135,6 @@ class FactureTest extends PHPUnit_Framework_TestCase $localobject=new Facture($this->savdb); $localobject->initAsSpecimen(); $result=$localobject->create($user); - $this->assertLessThan($result, 0); print __METHOD__." result=".$result."\n"; return $result; @@ -272,12 +271,41 @@ class FactureTest extends PHPUnit_Framework_TestCase $langs=$this->savlangs; $db=$this->savdb; + // Force default setup + unset($conf->global->INVOICE_CAN_ALWAYS_BE_REMOVED); + unset($conf->global->INVOICE_CAN_NEVER_BE_REMOVED); + $localobject=new Facture($this->savdb); $result=$localobject->fetch($id); - $result=$localobject->delete($user); - print __METHOD__." id=".$id." result=".$result."\n"; - $this->assertGreaterThanOrEqual(0, $result); + // Create another invoice and validate it after $localobject + $localobject2=new Facture($this->savdb); + $result=$localobject2->initAsSpecimen(); + $result=$localobject2->create($user); + $result=$localobject2->validate($user); + print 'Invoice $localobject ref = '.$localobject->ref."\n"; + print 'Invoice $localobject2 created with ref = '.$localobject2->ref."\n"; + + $conf->global->INVOICE_CAN_NEVER_BE_REMOVED = 1; + + $result=$localobject2->delete($user); // Deletion is KO, option INVOICE_CAN_NEVER_BE_REMOVED is on + print __METHOD__." id=".$localobject2->id." ref=".$localobject2->ref." result=".$result."\n"; + $this->assertEquals(0, $result, 'Deletion should fail, option INVOICE_CAN_NEVER_BE_REMOVED is on'); + + unset($conf->global->INVOICE_CAN_NEVER_BE_REMOVED); + + $result=$localobject->delete($user); // Deletion is KO, it is not last invoice + print __METHOD__." id=".$localobject->id." ref=".$localobject->ref." result=".$result."\n"; + $this->assertEquals(0, $result, 'Deletion should fail, it is not last invoice'); + + $result=$localobject2->delete($user); // Deletion is OK, it is last invoice + print __METHOD__." id=".$localobject2->id." ref=".$localobject2->ref." result=".$result."\n"; + $this->assertGreaterThan(0, $result, 'Deletion should work, it is last invoice'); + + $result=$localobject->delete($user); // Deletion is KO, it is not last invoice + print __METHOD__." id=".$localobject->id." ref=".$localobject->ref." result=".$result."\n"; + $this->assertGreaterThan(0, $result, 'Deletion should work, it is again last invoice'); + return $result; } diff --git a/test/phpunit/FunctionsLibTest.php b/test/phpunit/FunctionsLibTest.php index 77953ed0141..d2dce75b4a5 100644 --- a/test/phpunit/FunctionsLibTest.php +++ b/test/phpunit/FunctionsLibTest.php @@ -812,15 +812,11 @@ class FunctionsLibTest extends PHPUnit_Framework_TestCase $s=img_picto('title','/fullpath/img.png','',1); print __METHOD__." s=".$s."\n"; - $this->assertEquals('',$s,'testImgPicto3'); + $this->assertEquals('',$s,'testImgPicto3'); $s=img_picto('title','/fullpath/img.png','',true); print __METHOD__." s=".$s."\n"; - $this->assertEquals('',$s,'testImgPicto4'); - - $s=img_picto('title:alt','/fullpath/img.png','',true); - print __METHOD__." s=".$s."\n"; - $this->assertEquals('alt',$s,'testImgPicto5'); + $this->assertEquals('',$s,'testImgPicto4'); } /** @@ -1144,4 +1140,23 @@ class FunctionsLibTest extends PHPUnit_Framework_TestCase return true; } + + /** + * testDolGetDate + * + * @return boolean + */ + public function testMakeSubstitutions() + { + global $conf, $langs; + $langs->load("main"); + + $substit=array("AAA"=>'Not used', "BBB"=>'Not used', "CCC"=>"C replaced"); + $chaine='This is a string with __[MAIN_THEME]__ and __(DIRECTION)__ and __CCC__'; + $newstring = make_substitutions($chaine, $substit); + $this->assertEquals($newstring, 'This is a string with eldy and ltr and __C replaced__'); + + return true; + } + } diff --git a/test/phpunit/GetUrlLibTest.php b/test/phpunit/GetUrlLibTest.php new file mode 100644 index 00000000000..21dacd5a0f1 --- /dev/null +++ b/test/phpunit/GetUrlLibTest.php @@ -0,0 +1,192 @@ + + * Copyright (C) 2012 Regis Houssin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see http://www.gnu.org/ + */ + +/** + * \file test/phpunit/GetUrlLibTest.php + * \ingroup test + * \brief PHPUnit test + * \remarks To run this script as CLI: phpunit filename.php + */ + +global $conf,$user,$langs,$db; +//define('TEST_DB_FORCE_TYPE','mysql'); // This is to force using mysql driver +//require_once 'PHPUnit/Autoload.php'; +require_once dirname(__FILE__).'/../../htdocs/master.inc.php'; +require_once dirname(__FILE__).'/../../htdocs/core/lib/geturl.lib.php'; + +if (empty($user->id)) +{ + print "Load permissions for admin user nb 1\n"; + $user->fetch(1); + $user->getrights(); +} +$conf->global->MAIN_DISABLE_ALL_MAILS=1; + + +/** + * Class for PHPUnit tests + * + * @backupGlobals disabled + * @backupStaticAttributes enabled + * @remarks backupGlobals must be disabled to have db,conf,user and lang not erased. + */ +class GetUrlLibTest extends PHPUnit_Framework_TestCase +{ + protected $savconf; + protected $savuser; + protected $savlangs; + protected $savdb; + + /** + * Constructor + * We save global variables into local variables + * + * @return FilesLibTest + */ + function __construct() + { + //$this->sharedFixture + global $conf,$user,$langs,$db; + $this->savconf=$conf; + $this->savuser=$user; + $this->savlangs=$langs; + $this->savdb=$db; + + print __METHOD__." db->type=".$db->type." user->id=".$user->id; + //print " - db ".$db->db; + print "\n"; + } + + // Static methods + public static function setUpBeforeClass() + { + global $conf,$user,$langs,$db; + $db->begin(); // This is to have all actions inside a transaction even if test launched without suite. + + print __METHOD__."\n"; + } + + // tear down after class + public static function tearDownAfterClass() + { + global $conf,$user,$langs,$db; + $db->rollback(); + + print __METHOD__."\n"; + } + + /** + * Init phpunit tests + * + * @return void + */ + protected function setUp() + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + print __METHOD__."\n"; + } + /** + * End phpunit tests + * + * @return void + */ + protected function tearDown() + { + print __METHOD__."\n"; + } + + + /** + * testGetRootURLFromURL + * + * @return int + */ + public function testGetRootURLFromURL() + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $result=getRootURLFromURL('http://www.dolimed.com/screenshots/afile'); + print __METHOD__." result=".$result."\n"; + $this->assertEquals('http://www.dolimed.com',$result,'Test 1'); + + $result=getRootURLFromURL('https://www.dolimed.com/screenshots/afile'); + print __METHOD__." result=".$result."\n"; + $this->assertEquals('https://www.dolimed.com',$result,'Test 2'); + + $result=getRootURLFromURL('http://www.dolimed.com/screenshots'); + print __METHOD__." result=".$result."\n"; + $this->assertEquals('http://www.dolimed.com',$result); + + $result=getRootURLFromURL('https://www.dolimed.com/screenshots'); + print __METHOD__." result=".$result."\n"; + $this->assertEquals('https://www.dolimed.com',$result); + + $result=getRootURLFromURL('http://www.dolimed.com/'); + print __METHOD__." result=".$result."\n"; + $this->assertEquals('http://www.dolimed.com',$result); + + $result=getRootURLFromURL('https://www.dolimed.com/'); + print __METHOD__." result=".$result."\n"; + $this->assertEquals('https://www.dolimed.com',$result); + + $result=getRootURLFromURL('http://www.dolimed.com'); + print __METHOD__." result=".$result."\n"; + $this->assertEquals('http://www.dolimed.com',$result); + + $result=getRootURLFromURL('https://www.dolimed.com'); + print __METHOD__." result=".$result."\n"; + $this->assertEquals('https://www.dolimed.com',$result); + + return 1; + } + + + /** + * testRemoveHtmlComment + * + * @return int + */ + public function testRemoveHtmlComment() + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $result=removeHtmlComment('abcdef'); + print __METHOD__." result=".$result."\n"; + $this->assertEquals('abcdef',$result,'Test 1'); + + $result=removeHtmlComment('abcbbdef'); + print __METHOD__." result=".$result."\n"; + $this->assertEquals('abcbbdef',$result,'Test 1'); + + return 1; + } +} diff --git a/test/phpunit/HolidayTest.php b/test/phpunit/HolidayTest.php index a04646a8a14..3204e9f07b1 100644 --- a/test/phpunit/HolidayTest.php +++ b/test/phpunit/HolidayTest.php @@ -201,11 +201,11 @@ class HolidayTest extends PHPUnit_Framework_TestCase $localobject->email='newemail@newemail.com'; $localobject->jabberid='New im id'; $localobject->default_lang='es_ES'; - + $result=$localobject->update($localobject->id,$user); print __METHOD__." id=".$localobject->id." result=".$result."\n"; $this->assertLessThan($result, 0, 'Holiday::update error'); - + $result=$localobject->update_note($localobject->note_private,'_private'); print __METHOD__." id=".$localobject->id." result=".$result."\n"; $this->assertLessThan($result, 0, 'Holiday::update_note (private) error'); @@ -213,7 +213,7 @@ class HolidayTest extends PHPUnit_Framework_TestCase $result=$localobject->update_note($localobject->note_public, '_public'); print __METHOD__." id=".$localobject->id." result=".$result."\n"; $this->assertLessThan($result, 0, 'Holiday::update_note (public) error'); - + $newobject=new Holiday($this->savdb); $result=$newobject->fetch($localobject->id); @@ -291,4 +291,63 @@ class HolidayTest extends PHPUnit_Framework_TestCase return $result; } + /** + * testVerifDateHolidayCP + * + * @return void + */ + public function testVerifDateHolidayCP() + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + // Create a leave request the 1st morning only + $localobjecta=new Holiday($this->savdb); + $localobjecta->initAsSpecimen(); + $localobjecta->date_debut = dol_mktime(0, 0, 0, 1, 1, 2020); + $localobjecta->date_fin = dol_mktime(0, 0, 0, 1, 1, 2020); + $localobjecta->halfday = 1; + $result=$localobjecta->create($user); + + // Create a leave request the 2 afternoon only + $localobjectb=new Holiday($this->savdb); + $localobjectb->initAsSpecimen(); + $localobjectb->date_debut = dol_mktime(0, 0, 0, 1, 2, 2020); + $localobjectb->date_fin = dol_mktime(0, 0, 0, 1, 2, 2020); + $localobjectb->halfday = -1; + $result=$localobjectb->create($user); + + $date_debut = dol_mktime(0, 0, 0, 1, 1, 2020); + $date_fin = dol_mktime(0, 0, 0, 1, 2, 2020); + + $localobjectc=new Holiday($this->savdb); + + $result=$localobjectc->verifDateHolidayCP($user->id, $date_debut, $date_debut, 0); + $this->assertFalse($result, 'result should be false, there is overlapping, full day is not available.'); + $result=$localobjectc->verifDateHolidayCP($user->id, $date_debut, $date_fin, 0); + $this->assertFalse($result, 'result should be false, there is overlapping, full day is not available.'); + $result=$localobjectc->verifDateHolidayCP($user->id, $date_fin, $date_fin, 0); + $this->assertFalse($result, 'result should be false, there is overlapping, full day is not available.'); + + $result=$localobjectc->verifDateHolidayCP($user->id, $date_debut, $date_debut, 1); + $this->assertFalse($result, 'result should be false, there is overlapping, morning of first day is not available.'); + $result=$localobjectc->verifDateHolidayCP($user->id, $date_debut, $date_fin, 1); + $this->assertFalse($result, 'result should be false, there is overlapping, morning of first day is not available.'); + $result=$localobjectc->verifDateHolidayCP($user->id, $date_fin, $date_fin, 1); + $this->assertTrue($result, 'result should be true, there is no overlapping'); + + $result=$localobjectc->verifDateHolidayCP($user->id, $date_debut, $date_debut, -1); + $this->assertTrue($result, 'result should be true, there is no overlapping'); + $result=$localobjectc->verifDateHolidayCP($user->id, $date_debut, $date_fin, -1); + $this->assertFalse($result, 'result should be false, there is overlapping, afternoon of second day is not available'); + $result=$localobjectc->verifDateHolidayCP($user->id, $date_fin, $date_fin, -1); + $this->assertFalse($result, 'result should be false, there is overlapping, afternoon of second day is not available'); + + $result=$localobjectc->verifDateHolidayCP($user->id, $date_debut, $date_fin, 2); // start afternoon and end morning + $this->assertTrue($result, 'result should be true, there is no overlapping'); + } + } diff --git a/test/phpunit/ModulesTest.php b/test/phpunit/ModulesTest.php index a4ff51333e0..3c62ed52c70 100755 --- a/test/phpunit/ModulesTest.php +++ b/test/phpunit/ModulesTest.php @@ -127,13 +127,13 @@ class ModulesTest extends PHPUnit_Framework_TestCase $langs=$this->savlangs; $db=$this->savdb; - $modulelist=array('Accounting','Adherent','Agenda','Banque','Barcode','Bookmark', - 'CashDesk','Categorie','ClickToDial','Commande','Comptabilite','Contrat','Cron','Deplacement','DocumentGeneration','Don','DynamicPrices', - 'ECM','Expedition','Export','ExternalRss','ExternalSite', + $modulelist=array('Accounting','Adherent','Agenda','Banque','Barcode','BlockedLog','Bookmark', + 'CashDesk','Categorie','ClickToDial','Collab','Commande','Comptabilite','Contrat','Cron','Deplacement','DocumentGeneration','Don','DynamicPrices', + 'ECM','Expedition','ExpenseReport','Export','ExternalRss','ExternalSite', 'Facture','Fckeditor','Ficheinter','Fournisseur','FTP','GeoIPMaxmind','Gravatar','Holiday','HRM','Import','Incoterm','Label','Ldap','Loan', - 'Mailing','MailmanSpip','Margin', - 'Notification','Oauth','OpenSurvey','Paybox','Paypal','Prelevement','Product','ProductBatch','Projet','Propale','ReceiptPrinter','Resource', - 'Salaries','Service','Skype','Societe','Stock','SupplierProposal','Syslog','Tax','User','WebServices','WebServicesClient','Websites','Workflow'); + 'Mailing','MailmanSpip','Margin','ModuleBuilder','MultiCurrency', + 'Notification','Oauth','OpenSurvey','Paybox','Paypal','Prelevement','Printing','Product','ProductBatch','Projet','Propale','ReceiptPrinter','Resource', + 'Salaries','Service','Skype','Societe','Stock','Stripe','SupplierProposal','Syslog','Tax','User','Variants','WebServices','WebServicesClient','Website','Workflow'); foreach($modulelist as $modlabel) { require_once(DOL_DOCUMENT_ROOT.'/core/modules/mod'.$modlabel.'.class.php'); @@ -143,7 +143,7 @@ class ModulesTest extends PHPUnit_Framework_TestCase $result=$mod->init(); $this->assertLessThan($result, 0, $modlabel); print __METHOD__." test remove/init for module ".$modlabel.", result=".$result."\n"; - + if (in_array($modlabel, array('Ldap', 'MailmanSpip'))) { $result=$mod->remove(); diff --git a/test/phpunit/NumberingModulesTest.php b/test/phpunit/NumberingModulesTest.php index 401b7ce0058..4a3dfb7c1c9 100644 --- a/test/phpunit/NumberingModulesTest.php +++ b/test/phpunit/NumberingModulesTest.php @@ -75,7 +75,7 @@ class NumberingModulesTest extends PHPUnit_Framework_TestCase public static function setUpBeforeClass() { global $conf,$user,$langs,$db; - + $db->begin(); // This is to have all actions inside a transaction even if test launched without suite. print __METHOD__."\n"; @@ -128,7 +128,7 @@ class NumberingModulesTest extends PHPUnit_Framework_TestCase $user=$this->savuser; $langs=$this->savlangs; $db=$this->savdb; - + require_once dirname(__FILE__).'/../../htdocs/compta/facture/class/facture.class.php'; require_once dirname(__FILE__).'/../../htdocs/core/modules/facture/mod_facture_mercure.php'; @@ -153,7 +153,7 @@ class NumberingModulesTest extends PHPUnit_Framework_TestCase $this->assertEquals(1, $result3, 'Test validation of invoice with forced ref is ok'); // counter must start to 1 $result=$localobject->is_erasable(); print __METHOD__." is_erasable=".$result."\n"; - $this->assertEquals(1, $result, 'Test for is_erasable, 1st invoice'); // Can be deleted + $this->assertGreaterThanOrEqual(1, $result, 'Test for is_erasable, 1st invoice'); // Can be deleted $localobject2=new Facture($this->savdb); $localobject2->initAsSpecimen(); $localobject2->date=dol_mktime(12, 0, 0, 1, 1, 1916); // we use following year for second invoice (there is no reset into mask) @@ -171,10 +171,10 @@ class NumberingModulesTest extends PHPUnit_Framework_TestCase $this->assertEquals(1, $result3, 'Test validation of invoice with forced ref is ok'); // counter must start to 1 $result=$localobject2->is_erasable(); print __METHOD__." is_erasable=".$result."\n"; - $this->assertEquals(1, $result); // Can be deleted + $this->assertGreaterThanOrEqual(1, $result); // Can be deleted $result=$localobject->is_erasable(); print __METHOD__." is_erasable=".$result."\n"; - $this->assertEquals(0, $result, 'Test for {yyyy}-{0000} that is_erasable is 0 for 1st invoice'); // 1 can no more be deleted (2 is more recent) + $this->assertLessThanOrEqual(0, $result, 'Test for {yyyy}-{0000} that is_erasable is 0 for 1st invoice'); // 1 can no more be deleted (2 is more recent) // Now we try with a reset $conf->global->FACTURE_MERCURE_MASK_CREDIT='{yyyy}-{0000@1}'; @@ -218,7 +218,7 @@ class NumberingModulesTest extends PHPUnit_Framework_TestCase $this->assertEquals('192001-0001', $result, 'Test for {yyyy}{mm}-{0000@1} 1st invoice'); // counter must start to 1 $result=$localobject->is_erasable(); print __METHOD__." is_erasable=".$result."\n"; - $this->assertEquals(1, $result); // Can be deleted + $this->assertGreaterThanOrEqual(1, $result); // Can be deleted $localobject2=new Facture($this->savdb); $localobject2->initAsSpecimen(); $localobject2->date=dol_mktime(12, 0, 0, 1, 1, 1921); // we use following year for second invoice (and there is a reset required) @@ -230,10 +230,10 @@ class NumberingModulesTest extends PHPUnit_Framework_TestCase $this->assertEquals('192101-0001', $result); // counter must be reseted to 1 $result=$localobject2->is_erasable(); print __METHOD__." is_erasable=".$result."\n"; - $this->assertEquals(1, $result); // Can be deleted + $this->assertGreaterThanOrEqual(1, $result); // Can be deleted $result=$localobject->is_erasable(); print __METHOD__." is_erasable=".$result."\n"; - $this->assertEquals(1, $result); // Case 1 can be deleted (because there was a reset for case 2) + $this->assertGreaterThanOrEqual(1, $result); // Case 1 can be deleted (because there was a reset for case 2) // Same but we add month before year and use a year on 2 digits $conf->global->FACTURE_MERCURE_MASK_CREDIT='[mm}{yy}-{0000@1}'; @@ -249,7 +249,7 @@ class NumberingModulesTest extends PHPUnit_Framework_TestCase $this->assertEquals('0125-0001', $result, 'Test for {mm}{yy}-{0000@1} 1st invoice'); // counter must start to 1 $result=$localobject->is_erasable(); // This call get getNextNumRef with param 'last' print __METHOD__." is_erasable=".$result."\n"; - $this->assertEquals(1, $result); // Can be deleted + $this->assertGreaterThanOrEqual(1, $result); // Can be deleted $localobject2=new Facture($this->savdb); $localobject2->initAsSpecimen(); $localobject2->date=dol_mktime(12, 0, 0, 1, 1, 1925); // we use same year 1925 for second invoice (and there is a reset required) @@ -261,10 +261,10 @@ class NumberingModulesTest extends PHPUnit_Framework_TestCase $this->assertEquals('0125-0002', $result, 'Test for {mm}{yy}-{0000@1} 2st invoice'); // counter must be now 2 $result=$localobject2->is_erasable(); print __METHOD__." is_erasable=".$result."\n"; - $this->assertEquals(1, $result); // Can be deleted + $this->assertGreaterThanOrEqual(1, $result); // Can be deleted $result=$localobject->is_erasable(); print __METHOD__." is_erasable=".$result."\n"; - $this->assertEquals(0, $result); // Case 1 can not be deleted (because there is an invoice 2) + $this->assertLessThanOrEqual(0, $result); // Case 1 can not be deleted (because there is an invoice 2) $localobject3=new Facture($this->savdb); $localobject3->initAsSpecimen(); $localobject3->date=dol_mktime(12, 0, 0, 1, 1, 1926); // we use following year for third invoice (and there is a reset required) diff --git a/test/phpunit/PropalTest.php b/test/phpunit/PropalTest.php index 707673e0d0f..3d45673074a 100644 --- a/test/phpunit/PropalTest.php +++ b/test/phpunit/PropalTest.php @@ -142,7 +142,7 @@ class PropalTest extends PHPUnit_Framework_TestCase * testPropalFetch * * @param int $id Id of object - * @return void + * @return Propal * * @depends testPropalCreate * The depends says test is run only if previous is ok @@ -164,14 +164,39 @@ class PropalTest extends PHPUnit_Framework_TestCase } /** - * testPropalAddLine + * testPropalUpdate * - * @param int $localobject Proposal - * @return void + * @param Propal $localobject Proposal + * @return Propal * * @depends testPropalFetch * The depends says test is run only if previous is ok */ + public function testPropalUpdate($localobject) + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $localobject->note_private='New note private after update'; + $result=$localobject->update($user); + + $this->assertLessThan($result, 0); + print __METHOD__." id=".$id." result=".$result."\n"; + return $localobject; + } + + /** + * testPropalAddLine + * + * @param Propal $localobject Proposal + * @return Propal + * + * @depends testPropalUpdate + * The depends says test is run only if previous is ok + */ public function testPropalAddLine($localobject) { global $conf,$user,$langs,$db; @@ -180,6 +205,7 @@ class PropalTest extends PHPUnit_Framework_TestCase $langs=$this->savlangs; $db=$this->savdb; + $localobject->fetch_thirdparty(); $result=$localobject->addline('Added line', 10, 2, 19.6); $this->assertLessThan($result, 0); @@ -190,8 +216,8 @@ class PropalTest extends PHPUnit_Framework_TestCase /** * testPropalValid * - * @param Proposal $localobject Proposal - * @return Proposal + * @param Propal $localobject Proposal + * @return Propal * * @depends testPropalAddLine * The depends says test is run only if previous is ok @@ -214,7 +240,7 @@ class PropalTest extends PHPUnit_Framework_TestCase /** * testPropalOther * - * @param Proposal $localobject Proposal + * @param Propal $localobject Proposal * @return int * * @depends testPropalValid diff --git a/test/phpunit/SecurityTest.php b/test/phpunit/SecurityTest.php index 288a15c317e..87a5fdeb905 100644 --- a/test/phpunit/SecurityTest.php +++ b/test/phpunit/SecurityTest.php @@ -148,7 +148,7 @@ class SecurityTest extends PHPUnit_Framework_TestCase $_GET["param3"]='"a/b#e(pr)qq-rr\cc'; // Same than param2 + " $_GET["param4"]='../dir'; $_GET["param5"]="a_1-b"; - + // Test int $result=GETPOST('id','int'); // Must return nothing print __METHOD__." result=".$result."\n"; @@ -179,19 +179,19 @@ class SecurityTest extends PHPUnit_Framework_TestCase $result=GETPOST("param1",'aZ09'); // Must return '' as there is a forbidden char ../ print __METHOD__." result=".$result."\n"; $this->assertEquals($result,$_GET["param1"]); - + $result=GETPOST("param2",'aZ09'); // Must return '' as there is a forbidden char ../ print __METHOD__." result=".$result."\n"; $this->assertEquals($result,''); - + $result=GETPOST("param3",'aZ09'); // Must return '' as there is a forbidden char ../ print __METHOD__." result=".$result."\n"; $this->assertEquals($result,''); - + $result=GETPOST("param4",'aZ09'); // Must return '' as there is a forbidden char ../ print __METHOD__." result=".$result."\n"; $this->assertEquals($result,''); - + $result=GETPOST("param5",'aZ09'); print __METHOD__." result=".$result."\n"; $this->assertEquals($result,$_GET["param5"]); @@ -255,17 +255,17 @@ class SecurityTest extends PHPUnit_Framework_TestCase $genpass1=getRandomPassword(true); // Should be a string return by dol_hash (if no option set, will be md5) print __METHOD__." genpass1=".$genpass1."\n"; - $this->assertEquals(strlen($genpass1),32); + $this->assertEquals(strlen($genpass1), 32); $conf->global->USER_PASSWORD_GENERATED='None'; $genpass2=getRandomPassword(false); // Should be an empty string print __METHOD__." genpass2=".$genpass2."\n"; - $this->assertEquals($genpass2,''); + $this->assertEquals($genpass2, ''); $conf->global->USER_PASSWORD_GENERATED='Standard'; $genpass3=getRandomPassword(false); print __METHOD__." genpass3=".$genpass3."\n"; - $this->assertEquals(strlen($genpass3),8); + $this->assertEquals(strlen($genpass3), 8); return 0; } diff --git a/test/phpunit/SupplierProposalTest.php b/test/phpunit/SupplierProposalTest.php new file mode 100644 index 00000000000..ee4729ed47f --- /dev/null +++ b/test/phpunit/SupplierProposalTest.php @@ -0,0 +1,275 @@ + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see http://www.gnu.org/ + */ + +/** + * \file test/phpunit/SupplierProposalTest.php + * \ingroup test + * \brief PHPUnit test + * \remarks To run this script as CLI: phpunit filename.php + */ + +global $conf,$user,$langs,$db; +//define('TEST_DB_FORCE_TYPE','mysql'); // This is to force using mysql driver +//require_once 'PHPUnit/Autoload.php'; +require_once dirname(__FILE__).'/../../htdocs/master.inc.php'; +require_once dirname(__FILE__).'/../../htdocs/supplier_proposal/class/supplier_proposal.class.php'; + +if (empty($user->id)) +{ + print "Load permissions for admin user nb 1\n"; + $user->fetch(1); + + //$user->addrights(0, 'supplier_proposal'); + + $user->getrights(); +} +$conf->global->MAIN_DISABLE_ALL_MAILS=1; + + +/** + * Class for PHPUnit tests + * + * @backupGlobals disabled + * @backupStaticAttributes enabled + * @remarks backupGlobals must be disabled to have db,conf,user and lang not erased. + */ +class SupplierProposalTest extends PHPUnit_Framework_TestCase +{ + protected $savconf; + protected $savuser; + protected $savlangs; + protected $savdb; + + /** + * Constructor + * We save global variables into local variables + * + * @return PropalTest + */ + function __construct() + { + //$this->sharedFixture + global $conf,$user,$langs,$db; + $this->savconf=$conf; + $this->savuser=$user; + $this->savlangs=$langs; + $this->savdb=$db; + + print __METHOD__." db->type=".$db->type." user->id=".$user->id; + //print " - db ".$db->db; + print "\n"; + } + + // Static methods + public static function setUpBeforeClass() + { + global $conf,$user,$langs,$db; + $db->begin(); // This is to have all actions inside a transaction even if test launched without suite. + + if (empty($conf->global->MAIN_MODULE_SUPPLIERPROPOSAL)) { print "\n".__METHOD__." module Supplier proposal must be enabled.\n"; die(); } + + print __METHOD__."\n"; + } + + // tear down after class + public static function tearDownAfterClass() + { + global $conf,$user,$langs,$db; + $db->rollback(); + + print __METHOD__."\n"; + } + + /** + * Init phpunit tests + * + * @return void + */ + protected function setUp() + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + print __METHOD__."\n"; + //print $db->getVersion()."\n"; + } + /** + * End phpunit tests + * + * @return void + */ + protected function tearDown() + { + print __METHOD__."\n"; + } + + /** + * testSupplierProposalCreate + * + * @return void + */ + public function testSupplierProposalCreate() + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $localobject=new SupplierProposal($this->savdb); + $localobject->initAsSpecimen(); + $result=$localobject->create($user); + + $this->assertLessThan($result, 0); + print __METHOD__." result=".$result."\n"; + return $result; + } + + /** + * testSupplierProposalFetch + * + * @param int $id Id of object + * @return void + * + * @depends testSupplierProposalCreate + * The depends says test is run only if previous is ok + */ + public function testSupplierProposalFetch($id) + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $localobject=new SupplierProposal($this->savdb); + $result=$localobject->fetch($id); + + $this->assertLessThan($result, 0); + print __METHOD__." id=".$id." result=".$result."\n"; + return $localobject; + } + + /** + * testSupplierProposalAddLine + * + * @param int $localobject Proposal + * @return void + * + * @depends testSupplierProposalFetch + * The depends says test is run only if previous is ok + */ + public function testSupplierProposalAddLine($localobject) + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $localobject->fetch_thirdparty(); + $result=$localobject->addline('Added line', 10, 2, 19.6); + + $this->assertLessThan($result, 0); + print __METHOD__." id=".$localobject->id." result=".$result."\n"; + return $localobject; + } + + /** + * testSupplierProposalValid + * + * @param Proposal $localobject Proposal + * @return Proposal + * + * @depends testSupplierProposalAddLine + * The depends says test is run only if previous is ok + */ + public function testSupplierProposalValid($localobject) + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $result=$localobject->valid($user); + + print __METHOD__." id=".$localobject->id." result=".$result."\n"; + $this->assertLessThan($result, 0); + return $localobject; + } + + /** + * testSupplierProposalOther + * + * @param Proposal $localobject Proposal + * @return int + * + * @depends testSupplierProposalValid + * The depends says test is run only if previous is ok + */ + public function testSupplierProposalOther($localobject) + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + /*$result=$localobject->setstatus(0); + print __METHOD__." id=".$localobject->id." result=".$result."\n"; + $this->assertLessThan($result, 0); + */ + + $localobject->info($localobject->id); + print __METHOD__." localobject->date_creation=".$localobject->date_creation."\n"; + $this->assertNotEquals($localobject->date_creation, ''); + + return $localobject->id; + } + + /** + * testSupplierProposalDelete + * + * @param int $id Id of proposal + * @return void + * + * @depends testSupplierProposalOther + * The depends says test is run only if previous is ok + */ + public function testSupplierProposalDelete($id) + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $localobject=new SupplierProposal($this->savdb); + $result=$localobject->fetch($id); + $result=$localobject->delete($user); + + print __METHOD__." id=".$id." result=".$result."\n"; + $this->assertLessThan($result, 0); + return $result; + } + +} diff --git a/test/phpunit/UserTest.php b/test/phpunit/UserTest.php index b932d2e2221..8eaa1888412 100644 --- a/test/phpunit/UserTest.php +++ b/test/phpunit/UserTest.php @@ -77,7 +77,7 @@ class UserTest extends PHPUnit_Framework_TestCase global $conf,$user,$langs,$db; if (! empty($conf->global->MAIN_MODULE_LDAP)) { print "\n".__METHOD__." module LDAP must be disabled.\n"; die(); } - + $db->begin(); // This is to have all actions inside a transaction even if test launched without suite. print __METHOD__."\n"; @@ -272,6 +272,32 @@ class UserTest extends PHPUnit_Framework_TestCase return $result; } + /** + * testUserAddPermission + * + * @param Object $id User + * @return void + * @depends testUserDelete + * The depends says test is run only if previous is ok + */ + public function testUserAddPermission($id) + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $localobject=new User($this->savdb); + $result=$localobject->fetch(1); // Other tests use the user id 1 + $result=$localobject->addrights(0, 'supplier_proposal'); + + print __METHOD__." id=".$id." result=".$result."\n"; + $this->assertLessThan($result, 0); + return $result; + } + + /** * Edit an object to test updates diff --git a/test/phpunit/UtilsTest.php b/test/phpunit/UtilsTest.php new file mode 100644 index 00000000000..b80ce84f624 --- /dev/null +++ b/test/phpunit/UtilsTest.php @@ -0,0 +1,152 @@ + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see http://www.gnu.org/ + */ + +/** + * \file test/phpunit/UtilsTest.php + * \ingroup test + * \brief PHPUnit test + * \remarks To run this script as CLI: phpunit filename.php + */ + +global $conf,$user,$langs,$db; +//define('TEST_DB_FORCE_TYPE','mysql'); // This is to force using mysql driver +//require_once 'PHPUnit/Autoload.php'; +require_once dirname(__FILE__).'/../../htdocs/master.inc.php'; +require_once dirname(__FILE__).'/../../htdocs/core/class/utils.class.php'; + +if (empty($user->id)) { + print "Load permissions for admin user nb 1\n"; + $user->fetch(1); + $user->getrights(); +} +$conf->global->MAIN_DISABLE_ALL_MAILS=1; + + +/** + * Class for PHPUnit tests + * + * @backupGlobals disabled + * @backupStaticAttributes enabled + * @remarks backupGlobals must be disabled to have db,conf,user and lang not erased. + */ +class UtilsTest extends PHPUnit_Framework_TestCase +{ + protected $savconf; + protected $savuser; + protected $savlangs; + protected $savdb; + + /** + * Constructor + * We save global variables into local variables + * + * @return UserTest + */ + function __construct() + { + //$this->sharedFixture + global $conf,$user,$langs,$db; + $this->savconf=$conf; + $this->savuser=$user; + $this->savlangs=$langs; + $this->savdb=$db; + + print __METHOD__." db->type=".$db->type." user->id=".$user->id; + //print " - db ".$db->db; + print "\n"; + } + + // Static methods + public static function setUpBeforeClass() + { + global $conf,$user,$langs,$db; + + $db->begin(); // This is to have all actions inside a transaction even if test launched without suite. + + print __METHOD__."\n"; + } + + // tear down after class + public static function tearDownAfterClass() + { + global $conf,$user,$langs,$db; + $db->rollback(); + + print __METHOD__."\n"; + } + + /** + * Init phpunit tests + * + * @return void + */ + protected function setUp() + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + print __METHOD__."\n"; + } + + /** + * End phpunit tests + * + * @return void + */ + protected function tearDown() + { + print __METHOD__."\n"; + } + + /** + * testExecuteCLI + * + * @return void + */ + public function testExecuteCLI() + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $localobject=new Utils($this->savdb); + $result = $localobject->executeCLI('ls', $conf->admin->dir_temp.'/out.tmp', 1); + print var_export($result, true); + $this->assertEquals($result['result'], 0); + $this->assertEquals($result['error'], ''); + //$this->assertEquals(preg_match('/phpunit/', $result['output']), 1); + + $localobject=new Utils($this->savdb); + $result = $localobject->executeCLI('ls', $conf->admin->dir_temp.'/out.tmp', 2); + print var_export($result, true); + $this->assertEquals($result['result'], 0); + $this->assertEquals($result['error'], ''); + //$this->assertEquals(preg_match('/phpunit/', $result['output']), 1); + + print __METHOD__." result=".$result."\n"; + return $result; + } + + + +} diff --git a/test/phpunit/WebservicesInvoicesTest.php b/test/phpunit/WebservicesInvoicesTest.php index 07bd95e01f2..75cc767b8ee 100644 --- a/test/phpunit/WebservicesInvoicesTest.php +++ b/test/phpunit/WebservicesInvoicesTest.php @@ -56,11 +56,11 @@ class WebservicesInvoicesTest extends PHPUnit_Framework_TestCase protected $savlangs; protected $savdb; protected $soapclient; - + private static $socid; - + protected $ns = 'http://www.dolibarr.org/ns/'; - + /** * Constructor * We save global variables into local variables @@ -75,7 +75,7 @@ class WebservicesInvoicesTest extends PHPUnit_Framework_TestCase $this->savuser=$user; $this->savlangs=$langs; $this->savdb=$db; - + // Set the WebService URL $WS_DOL_URL = DOL_MAIN_URL_ROOT.'/webservices/server_invoice.php'; print __METHOD__." create nusoap_client for URL=".$WS_DOL_URL."\n"; @@ -85,7 +85,7 @@ class WebservicesInvoicesTest extends PHPUnit_Framework_TestCase $this->soapclient->soap_defencoding='UTF-8'; $this->soapclient->decodeUTF8(false); } - + print __METHOD__." db->type=".$db->type." user->id=".$user->id; //print " - db ".$db->db; print "\n"; @@ -114,11 +114,13 @@ class WebservicesInvoicesTest extends PHPUnit_Framework_TestCase $societe->ref_ext='ref-phpunit'; $societe->status=1; $societe->client=1; + $societe->code_client='CU0901-1234'; + $societe->code_fournisseur='SU0901-1234'; $societe->fournisseur=0; $societe->date_creation=$now; $societe->tva_assuj=0; $societe->particulier=0; - + $societe->create($user); self::$socid = $societe->id; @@ -259,13 +261,13 @@ class WebservicesInvoicesTest extends PHPUnit_Framework_TestCase return $result; } - + /** * testWSInvoicesGetInvoiceByRefExt - * + * * Retrieve an invoice using ref_ext * @depends testWSInvoicesCreateInvoice - * + * * @param array $result Invoice created by create method * @return array Invoice */ @@ -315,13 +317,13 @@ class WebservicesInvoicesTest extends PHPUnit_Framework_TestCase return $result; } - + /** * testWSInvoicesUpdateInvoiceByRefExt - * + * * Update an invoice using ref_ext * @depends testWSInvoicesCreateInvoice - * + * * @param array $result invoice created by create method * @return array Invoice */ diff --git a/test/phpunit/WebservicesThirdpartyTest.php b/test/phpunit/WebservicesThirdpartyTest.php index 59907b36194..e0e22125afe 100644 --- a/test/phpunit/WebservicesThirdpartyTest.php +++ b/test/phpunit/WebservicesThirdpartyTest.php @@ -55,12 +55,12 @@ class WebservicesThirdpartyTest extends PHPUnit_Framework_TestCase protected $savlangs; protected $savdb; protected $soapclient; - + private $_WS_DOL_URL; private $_ns='http://www.dolibarr.org/ns/'; - - - + + + /** * Constructor @@ -76,9 +76,9 @@ class WebservicesThirdpartyTest extends PHPUnit_Framework_TestCase $this->savuser=$user; $this->savlangs=$langs; $this->savdb=$db; - + $this->_WS_DOL_URL = DOL_MAIN_URL_ROOT.'/webservices/server_thirdparty.php'; - + // Set the WebService URL print __METHOD__." create nusoap_client for URL=".$this->_WS_DOL_URL."\n"; $this->soapclient = new nusoap_client($this->_WS_DOL_URL); @@ -148,10 +148,10 @@ class WebservicesThirdpartyTest extends PHPUnit_Framework_TestCase $user=$this->savuser; $langs=$this->savlangs; $db=$this->savdb; - + $WS_METHOD = 'createThirdParty'; - - + + // Call the WebService method and store its result in $result. $authentication=array( 'dolibarrkey'=>$conf->global->WEBSERVICES_KEY, @@ -159,7 +159,7 @@ class WebservicesThirdpartyTest extends PHPUnit_Framework_TestCase 'login'=>'admin', 'password'=>'admin', 'entity'=>''); - + $body = array ( "id" => NULL, "ref" => "name", @@ -168,8 +168,8 @@ class WebservicesThirdpartyTest extends PHPUnit_Framework_TestCase "status" => NULL, "client" => 1, "supplier" => 0, - "customer_code" => "", - "supplier_code" => "", + "customer_code" => "CU0901-5678", + "supplier_code" => "SU0901-5678", "customer_code_accountancy" => "", "supplier_code_accountancy" => "", "date_creation" => "", // dateTime @@ -197,7 +197,7 @@ class WebservicesThirdpartyTest extends PHPUnit_Framework_TestCase "vat_used" => "", "vat_number" => "" ); - + // Test URL $result=''; $parameters = array('authentication'=>$authentication, 'thirdparty'=>$body); @@ -217,20 +217,20 @@ class WebservicesThirdpartyTest extends PHPUnit_Framework_TestCase print $this->soapclient->response; print "\n"; } - + print __METHOD__." result=".$result['result']['result_code']."\n"; $this->assertEquals('OK',$result['result']['result_code']); - $this->assertEquals('name',$result['ref']); - + $this->assertEquals('name',$result['ref']); + return $result; } /** * testWSThirdpartygetThirdPartyById - * + * * Use id to retrieve thirdparty * @depends testWSThirdpartycreateThirdParty - * + * * @param array $result thirdparty created by create method * @return array thirpdarty updated */ @@ -280,18 +280,18 @@ class WebservicesThirdpartyTest extends PHPUnit_Framework_TestCase $this->assertEquals('0', $result['thirdparty']['status']); $this->assertEquals('1', $result['thirdparty']['client']); $this->assertEquals('0', $result['thirdparty']['supplier']); - - + + return $result; } - + /** * testWSThirdpartygetThirdPartyByRefExt * * Use ref_ext to retrieve thirdparty * * @depends testWSThirdpartycreateThirdParty - * + * * @param array $result thirdparty created by create method * @return array thirdparty */ @@ -303,9 +303,9 @@ class WebservicesThirdpartyTest extends PHPUnit_Framework_TestCase $langs=$this->savlangs; $db=$this->savdb; $id = $result['id']; - + $WS_METHOD = 'getThirdParty'; - + // Call the WebService method and store its result in $result. $authentication=array( 'dolibarrkey'=>$conf->global->WEBSERVICES_KEY, @@ -313,7 +313,7 @@ class WebservicesThirdpartyTest extends PHPUnit_Framework_TestCase 'login'=>'admin', 'password'=>'admin', 'entity'=>''); - + // Test URL $result=''; $parameters = array('authentication'=>$authentication, 'id'=>'', 'ref'=>'', 'ref_ext'=>'12'); @@ -334,7 +334,7 @@ class WebservicesThirdpartyTest extends PHPUnit_Framework_TestCase print $this->soapclient->response; print "\n"; } - + print __METHOD__." result=".$result['result']['result_code']."\n"; $this->assertEquals('OK',$result['result']['result_code']); $this->assertEquals($id, $result['thirdparty']['id']); @@ -343,11 +343,11 @@ class WebservicesThirdpartyTest extends PHPUnit_Framework_TestCase $this->assertEquals('0', $result['thirdparty']['status']); $this->assertEquals('1', $result['thirdparty']['client']); $this->assertEquals('0', $result['thirdparty']['supplier']); - - + + return $result; } - + /** * testWSThirdpartydeleteThirdParty * @@ -364,9 +364,9 @@ class WebservicesThirdpartyTest extends PHPUnit_Framework_TestCase $langs=$this->savlangs; $db=$this->savdb; $id = $result['id']; - + $WS_METHOD = 'deleteThirdParty'; - + // Call the WebService method and store its result in $result. $authentication=array( 'dolibarrkey'=>$conf->global->WEBSERVICES_KEY, @@ -374,7 +374,7 @@ class WebservicesThirdpartyTest extends PHPUnit_Framework_TestCase 'login'=>'admin', 'password'=>'admin', 'entity'=>''); - + $result=''; $parameters = array('authentication'=>$authentication, 'id'=>$id, 'ref'=>'', 'ref_ext'=>''); print __METHOD__." call method ".$WS_METHOD."\n"; @@ -395,7 +395,7 @@ class WebservicesThirdpartyTest extends PHPUnit_Framework_TestCase print __METHOD__." result=".$result['result']['result_code']."\n"; $this->assertEquals('OK',$result['result']['result_code']); - + return $result; }