diff --git a/admin/exportclases/class.pdfIzvoz.php b/admin/exportclases/class.pdfIzvoz.php index 262b2e8ae..292a805ea 100644 --- a/admin/exportclases/class.pdfIzvoz.php +++ b/admin/exportclases/class.pdfIzvoz.php @@ -1953,7 +1953,7 @@ class PdfIzvoz { // Prelom strani ce je kateri od naslovov gridov predolg $sqlVsehVrednsti = sisplet_query("SELECT g.naslov, g.variable FROM srv_grid g, srv_grid_multiple m WHERE m.parent='".$spremenljivke['id']."' AND g.spr_id=m.spr_id"); - $sqlMultiple = sisplet_query("SELECT g.*, s.tip, s.enota, s.dostop FROM srv_grid g, srv_grid_multiple m, srv_spremenljivka s WHERE s.id=g.spr_id AND g.spr_id=m.spr_id AND m.spr_id IN (".implode($multiple, ',').") ORDER BY m.vrstni_red, g.vrstni_red"); + $sqlMultiple = sisplet_query("SELECT g.*, s.tip, s.enota, s.dostop FROM srv_grid g, srv_grid_multiple m, srv_spremenljivka s WHERE s.id=g.spr_id AND g.spr_id=m.spr_id AND m.spr_id IN (".implode(',', $multiple).") ORDER BY m.vrstni_red, g.vrstni_red"); $linecount = 0; while ($rowVsehVrednosti = mysqli_fetch_assoc($sqlVsehVrednsti)) { @@ -1984,7 +1984,7 @@ class PdfIzvoz { // izišemo header celice $sqlVsehVrednsti = sisplet_query("SELECT g.naslov,g.variable,m.vrstni_red FROM srv_grid g, srv_grid_multiple m WHERE m.parent='".$spremenljivke['id']."' AND g.spr_id=m.spr_id ORDER BY m.vrstni_red"); - $sqlMultiple = sisplet_query("SELECT g.*, s.tip, s.enota, s.dostop FROM srv_grid g, srv_grid_multiple m, srv_spremenljivka s WHERE s.id=g.spr_id AND g.spr_id=m.spr_id AND m.spr_id IN (".implode($multiple, ',').") ORDER BY m.vrstni_red, g.vrstni_red"); + $sqlMultiple = sisplet_query("SELECT g.*, s.tip, s.enota, s.dostop FROM srv_grid g, srv_grid_multiple m, srv_spremenljivka s WHERE s.id=g.spr_id AND g.spr_id=m.spr_id AND m.spr_id IN (".implode(',', $multiple).") ORDER BY m.vrstni_red, g.vrstni_red"); while ($rowVsehVrednosti = mysqli_fetch_assoc($sqlVsehVrednsti)) { # priredimo naslov če prevajamo anketo diff --git a/admin/survey/Branching.php b/admin/survey/Branching.php index f8c84d9a2..5cb29e147 100644 --- a/admin/survey/Branching.php +++ b/admin/survey/Branching.php @@ -1641,13 +1641,30 @@ class Branching { echo ''; } // Kvota - else if($row['tip'] == 25){ + elseif($row['tip'] == 25){ echo '
'; echo $row['naslov']; echo '
'; } + // GDPR vprasanje in prevajanje - prevedemo v anglescino + elseif($prevajanje && $row['variable'] == 'gdpr'){ + + // nastavimo na jezik za respondentov vmesnik + $language_id_bck = $lang['id']; + $file = ($this->lang_id == '1') ? '../../lang/1.php' : '../../lang/2.php'; + @include($file); + + $gdpr_naslov = GDPR::getSurveyIntro($this->anketa); + + echo '
lang_id!=null ? ' default="1"':'').'>'; + echo $gdpr_naslov; + echo '
'; + + // nastavimo nazaj na admin jezik + $file = '../../lang/'.$language_id_bck.'.php'; + @include($file); + } else{ - //echo '
lang_id!=null ? ' default="1"':'').'>'; echo '
lang_id!=null ? ' default="1"':'').'>'; echo $row['naslov']; echo '
'; @@ -1929,6 +1946,23 @@ class Branching { save('lang_id', $this->lang_id); $naslov = \App\Controllers\LanguageController::getInstance()->srv_language_vrednost($row1['id']); if ($naslov != '') $row1['naslov'] = $naslov; + + // Prevajanje in gdpr + if($prevajanje && $row['variable'] == 'gdpr'){ + + $gdpr_answer = ''; + + if($row1['variable'] == '2') + $gdpr_answer = 'yes'; + + if($row1['variable'] == '1') + $gdpr_answer = 'no'; + + // Prevedemo gdpr odgovore + if($gdpr_answer != ''){ + $row1['naslov'] = $lang['srv_gdpr_intro_'.$gdpr_answer]; + } + } } // Ce je variabla ne vem in imamo vklopljen prikaz ob opozorilu -> rdec @@ -5043,7 +5077,7 @@ class Branching { while ($rowM = mysqli_fetch_array($sqlM)) { $multiple[] = $rowM['spr_id']; } - $sql2 = sisplet_query("SELECT g.*, s.tip, s.enota, s.dostop FROM srv_grid g, srv_grid_multiple m, srv_spremenljivka s WHERE s.id=g.spr_id AND g.spr_id=m.spr_id AND m.spr_id IN (".implode($multiple, ',').") ORDER BY m.vrstni_red, g.vrstni_red"); + $sql2 = sisplet_query("SELECT g.*, s.tip, s.enota, s.dostop FROM srv_grid g, srv_grid_multiple m, srv_spremenljivka s WHERE s.id=g.spr_id AND g.spr_id=m.spr_id AND m.spr_id IN (".implode(',', $multiple).") ORDER BY m.vrstni_red, g.vrstni_red"); $row2 = mysqli_fetch_array($sql2); for ($i = 1; $i <= mysqli_num_rows($sql2); $i++) { @@ -6921,8 +6955,6 @@ class Branching { echo ''; } else { echo ''; -// echo ''; -// echo ''; } echo ''; @@ -7228,12 +7260,6 @@ class Branching { echo ''; echo ''."\n\r"; - - /* kaj je to?? - echo ' '."\n\r"; - */ } /** diff --git a/admin/survey/Glasovanje.php b/admin/survey/Glasovanje.php index 51bffbed0..6f42b6e93 100644 --- a/admin/survey/Glasovanje.php +++ b/admin/survey/Glasovanje.php @@ -2,7 +2,7 @@ global $site_path; -define('NEW_LINE', "\n", true); +define('NEW_LINE', "\n"); class Glasovanje { diff --git a/admin/survey/R/class.SurveyAnalysisR.php b/admin/survey/R/class.SurveyAnalysisR.php index b42a4c27e..0a21388b3 100644 --- a/admin/survey/R/class.SurveyAnalysisR.php +++ b/admin/survey/R/class.SurveyAnalysisR.php @@ -9,8 +9,8 @@ * */ -define("DATA_FOLDER", "admin/survey/R/TempData", true); -define("SCRIPT_FOLDER", "admin/survey/R/script", true); +define("DATA_FOLDER", "admin/survey/R/TempData"); +define("SCRIPT_FOLDER", "admin/survey/R/script"); class SurveyAnalysisR { diff --git a/admin/survey/SurveyAdmin.php b/admin/survey/SurveyAdmin.php index 9cf037a1e..a553b369a 100644 --- a/admin/survey/SurveyAdmin.php +++ b/admin/survey/SurveyAdmin.php @@ -61,23 +61,23 @@ // STARO -define("A_IZVOZI", "izvozi", true); +define("A_IZVOZI", "izvozi"); -define("M_IZVOZI_EXCEL", "excel", true); -define("M_IZVOZI_SPSS", "spss", true); -define("M_IZVOZI_txt", "txt", true); +define("M_IZVOZI_EXCEL", "excel"); +define("M_IZVOZI_SPSS", "spss"); +define("M_IZVOZI_txt", "txt"); -define("A_REPORT_VPRASALNIK_PDF", "vprasalnik_pdf", true); -define("A_REPORT_VPRASALNIK_RTF", "vprasalnik_rtf", true); +define("A_REPORT_VPRASALNIK_PDF", "vprasalnik_pdf"); +define("A_REPORT_VPRASALNIK_RTF", "vprasalnik_rtf"); -define("M_REPORT_TEXT", "text", true); -define("M_REPORT_GRAPHICAL", "graphical", true); -define("M_REPORT_TOTAL", "total", true); +define("M_REPORT_TEXT", "text"); +define("M_REPORT_GRAPHICAL", "graphical"); +define("M_REPORT_TOTAL", "total"); // ali je enka še v fazi razvoja (za potrebe skrivanja navigacije,zavihkov,ipd...) // skrite elemente prikaže samo administratorju -define("SRV_DEVELOPMENT_VERSION", true, true); +define("SRV_DEVELOPMENT_VERSION", true); // tipi uporabnikov, (za kontrolo prikaza posameznih elementov) za preverjanje kličemo funkcijo user_role_cehck define("U_ROLE_ADMIN", 0); @@ -122,13 +122,12 @@ class SurveyAdmin $this->skin = 0; // polovimo anketa ID - if (isset ($_GET['anketa'])) + if ($anketa != 0) + $this->anketa = $anketa; + elseif (isset ($_GET['anketa'])) $this->anketa = $_GET['anketa']; elseif (isset ($_POST['anketa'])) $this->anketa = $_POST['anketa']; - elseif ($anketa != 0) - $this->anketa = $anketa; - # clearing E_NOTICE if (!isset($_GET['a'])) { @@ -264,6 +263,8 @@ class SurveyAdmin global $global_user_id; global $lang; global $admin_type; + global $site_domain; + global $aai_instalacija; $sql = sisplet_query("SELECT email FROM users WHERE id='$global_user_id'"); $row = mysqli_fetch_assoc($sql); @@ -289,7 +290,8 @@ class SurveyAdmin echo '
'; - echo ''; + echo ''; + echo ' '; echo ''; echo ''; @@ -328,11 +330,13 @@ class SurveyAdmin $text = $row['name'] . ' ' . $row['surname']; $text = (strlen($text) > 25) ? substr($text, 0, 25) . '...' : $text; - - echo '
' . $text . ' '; + + + echo '
' . $text . ' '; echo '
'; - echo '' . $lang['edit_data'] . ''; + echo '' . $lang['edit_data'] . ''; + // Odjava na nov nacin preko frontend/api echo ''; echo '' . $lang['logout'] . ''; @@ -371,7 +375,7 @@ class SurveyAdmin // Prikaze podatke o anketi in navigacijo - na vrhu (top bar) $this->displayAnketaTop(); - echo '
'; + echo '
'; $this->displayAnketa(); echo '
'; @@ -454,6 +458,9 @@ class SurveyAdmin echo '
'; + // Generičen popup + echo ''; + // urejanje calculation-ov echo '
'; @@ -564,6 +571,8 @@ class SurveyAdmin global $lang; global $app_settings; global $site_frontend; + global $aai_instalacija; + global $mysql_database_name; echo ''; + echo '
'; } } @@ -376,7 +383,6 @@ class Library { echo ' '."\n"; echo ' '."\n"; - } if ($parent == 0) { @@ -910,7 +916,6 @@ class Library { sisplet_query("DELETE FROM srv_library_anketa WHERE ank_id='$anketa' AND uid='0'"); - //$this->display(); $this->display_folders(); } @@ -921,7 +926,6 @@ class Library { sisplet_query("DELETE FROM srv_library_anketa WHERE ank_id='$anketa' AND uid='$global_user_id'"); - //$this->display(); $this->display_folders(); } diff --git a/admin/survey/classes/class.Prevajanje.php b/admin/survey/classes/class.Prevajanje.php index e58854db2..5a81263e5 100644 --- a/admin/survey/classes/class.Prevajanje.php +++ b/admin/survey/classes/class.Prevajanje.php @@ -563,12 +563,8 @@ class Prevajanje { $this->Branching->introduction_conclusion(-1); elseif ($spremenljivka == -2) $this->Branching->introduction_conclusion(-2); - else{ + else $this->Branching->vprasanje($spremenljivka); - if ($row['tip'] == 7 && $row['ranking_k'] == 1){ //ce je tip vprasanja stevilo in je postavitev slider - //echo '
'; //pokomentiral, ker se sedaj pojavi težava pri izpisu v prevodu - } - } echo '
'; @@ -585,13 +581,8 @@ class Prevajanje { $this->Branching->introduction_conclusion(-1); elseif ($spremenljivka == -2) $this->Branching->introduction_conclusion(-2); - else{ + else $this->Branching->vprasanje($spremenljivka, true); //poklici izris vprasanja za prevajanje (za enkrat je drugi argument pomemben le za slider) - - if ($row['tip'] == 7 && $row['ranking_k'] == 1){ //ce je tip vprasanja stevilo in je postavitev slider - //echo '
'; //pokomentiral, ker se sedaj pojavi težava pri izpisu v prevodu - } - } echo '
'; diff --git a/admin/survey/classes/class.SurveyAapor.php b/admin/survey/classes/class.SurveyAapor.php index 0386402e9..55dde7004 100644 --- a/admin/survey/classes/class.SurveyAapor.php +++ b/admin/survey/classes/class.SurveyAapor.php @@ -481,7 +481,7 @@ class SurveyAapor { # od direktnega klika odštejemo e-mail vabila if (count($user_id_to_check_link)> 0) { - $qry_stringEmail = "SELECT COUNT(*) as cnt FROM srv_userstatus WHERE usr_id IN (".implode($user_id_to_check_link,',').") AND status IN (".implode($this->emailStatus,',').")"; + $qry_stringEmail = "SELECT COUNT(*) as cnt FROM srv_userstatus WHERE usr_id IN (".implode(',', $user_id_to_check_link).") AND status IN (".implode(',', $this->emailStatus).")"; $qryEmail = sisplet_query($qry_stringEmail); $rwsEmail = mysqli_fetch_assoc($qryEmail); $this->userRedirections["email"] = (int)$rwsEmail['cnt']; diff --git a/admin/survey/classes/class.SurveyAktivnost.php b/admin/survey/classes/class.SurveyAktivnost.php index a0b0405e2..63a4a496f 100644 --- a/admin/survey/classes/class.SurveyAktivnost.php +++ b/admin/survey/classes/class.SurveyAktivnost.php @@ -884,10 +884,10 @@ class SurveyAktivnost{ $filter .= " ((user_access.package_id='2' OR user_access.package_id='3') AND user_access.time_expire > NOW()) AND "; } if($package_2ka == 0){ - $filter .= " (user_access.package_id!='2' OR user_access.time_expire < NOW()) AND "; + $filter .= " (user_access.package_id!='2' OR user_access.time_expire < NOW() OR user_access.package_id IS NULL) AND "; } if($package_3ka == 0){ - $filter .= " (user_access.package_id!='3' OR user_access.time_expire < NOW()) AND "; + $filter .= " (user_access.package_id!='3' OR user_access.time_expire < NOW() OR user_access.package_id IS NULL) AND "; } } diff --git a/admin/survey/classes/class.SurveyDiagnostics.php b/admin/survey/classes/class.SurveyDiagnostics.php index cf0dc88b9..47329191d 100644 --- a/admin/survey/classes/class.SurveyDiagnostics.php +++ b/admin/survey/classes/class.SurveyDiagnostics.php @@ -9,27 +9,27 @@ */ if(session_id() == '') {session_start();} -define("SPR_ON_PAGE_LIMIT", 8, true); # priporočeno število spremenljivk na stran -define("SPR_IN_BLOCK_LIMIT", 15, true); # priporočeno število spremenljivk na blok -define("SUB_Q_IN_GRID_LIMIT", 8, true); # priporočeno število podvprašanj na grid -define("SPR_UNAPROPRIATE_START_LIMIT", 30, true); # koliko % spremenljivk preverjamo na pravilen začetek -define("SPR_REMINDER_ON_MGRID_LIMIT", 10, true); # koliko % spremenljivk preverjamo na pravilen začetek -define("TIME_SOFT_LIMIT", 120, true); # čas izpolnjevanja 2 minuti priporočilo -define("TIME_HARD_LIMIT", 900, true); # čas izpolnjevanja 15 minut opozorilo +define("SPR_ON_PAGE_LIMIT", 8); # priporočeno število spremenljivk na stran +define("SPR_IN_BLOCK_LIMIT", 15); # priporočeno število spremenljivk na blok +define("SUB_Q_IN_GRID_LIMIT", 8); # priporočeno število podvprašanj na grid +define("SPR_UNAPROPRIATE_START_LIMIT", 30); # koliko % spremenljivk preverjamo na pravilen začetek +define("SPR_REMINDER_ON_MGRID_LIMIT", 10); # koliko % spremenljivk preverjamo na pravilen začetek +define("TIME_SOFT_LIMIT", 120); # čas izpolnjevanja 2 minuti priporočilo +define("TIME_HARD_LIMIT", 900); # čas izpolnjevanja 15 minut opozorilo -define("DIAG_SPR_ON_PAGE", "DIAG_SPR_ON_PAGE", true); # Zaznali smo preveč spremenljivk na stran -define("DIAG_SPR_IN_BLOCK", "DIAG_SPR_IN_BLOCK", true); # Zaznali smo preveč spremenljivk na blok -define("DIAG_SUB_Q_IN_GRID", "DIAG_SUB_Q_IN_GRID", true); # Zaznali smo preveč podvprašanj v gridu -define("DIAG_REMINDER_ON_IF", "DIAG_REMINDER_ON_IF", true); # Manjka reminder na spremenljvko na katero se sklicuje if -define("DIAG_REMINDER_ON_MGRID", "DIAG_REMINDER_ON_MGRID", true); # Reminder na spremenljvko z veliko podvprašanji -define("DIAG_UNAPROPRIATE_START", "DIAG_UNAPROPRIATE_START", true); # ali imamo na začetku ankete neprimerna vprašanja -define("DIAG_INVALID_CONDITIONS", "DIAG_INVALID_CONDITIONS", true); # Ali so napake v ifih -define("DIAG_INVALID_VARIABLENAMES", "DIAG_INVALID_VARIABLENAMES", true); # Ali so varable podvojene -define("DIAG_INVALID_VALIDATIONS", "DIAG_INVALID_VALIDATIONS", true); # Ali so napacne validacije na spremenljivkah -define("DIAG_TIME_SOFT_LIMIT", "DIAG_TIME_SOFT_LIMIT", true); # predolga anketa 1 -define("DIAG_TIME_HARD_LIMIT", "DIAG_TIME_HARD_LIMIT", true); # predolga anketa 2 +define("DIAG_SPR_ON_PAGE", "DIAG_SPR_ON_PAGE"); # Zaznali smo preveč spremenljivk na stran +define("DIAG_SPR_IN_BLOCK", "DIAG_SPR_IN_BLOCK"); # Zaznali smo preveč spremenljivk na blok +define("DIAG_SUB_Q_IN_GRID", "DIAG_SUB_Q_IN_GRID"); # Zaznali smo preveč podvprašanj v gridu +define("DIAG_REMINDER_ON_IF", "DIAG_REMINDER_ON_IF"); # Manjka reminder na spremenljvko na katero se sklicuje if +define("DIAG_REMINDER_ON_MGRID", "DIAG_REMINDER_ON_MGRID"); # Reminder na spremenljvko z veliko podvprašanji +define("DIAG_UNAPROPRIATE_START", "DIAG_UNAPROPRIATE_START"); # ali imamo na začetku ankete neprimerna vprašanja +define("DIAG_INVALID_CONDITIONS", "DIAG_INVALID_CONDITIONS"); # Ali so napake v ifih +define("DIAG_INVALID_VARIABLENAMES", "DIAG_INVALID_VARIABLENAMES"); # Ali so varable podvojene +define("DIAG_INVALID_VALIDATIONS", "DIAG_INVALID_VALIDATIONS"); # Ali so napacne validacije na spremenljivkah +define("DIAG_TIME_SOFT_LIMIT", "DIAG_TIME_SOFT_LIMIT"); # predolga anketa 1 +define("DIAG_TIME_HARD_LIMIT", "DIAG_TIME_HARD_LIMIT"); # predolga anketa 2 class SurveyDiagnostics { diff --git a/admin/survey/classes/class.SurveyExport.php b/admin/survey/classes/class.SurveyExport.php index f1f93d8f6..844ad0c59 100644 --- a/admin/survey/classes/class.SurveyExport.php +++ b/admin/survey/classes/class.SurveyExport.php @@ -11,13 +11,12 @@ * */ -DEFINE (NEW_LINE, "\n", true); -DEFINE (TMP_EXT, '.tmp', true); -DEFINE (STR_DLMT, '|', true); -DEFINE (DAT_EXT, '.dat', true); +DEFINE (NEW_LINE, "\n"); +DEFINE (TMP_EXT, '.tmp'); +DEFINE (STR_DLMT, '|'); +DEFINE (DAT_EXT, '.dat'); -#define("EXPORT_FOLDER", "tmp", true); -define("EXPORT_FOLDER", "admin/survey/SurveyData", true); +define("EXPORT_FOLDER", "admin/survey/SurveyData"); class SurveyExport { diff --git a/admin/survey/classes/class.SurveyInpect.php b/admin/survey/classes/class.SurveyInpect.php index e9066c487..2aa62210d 100644 --- a/admin/survey/classes/class.SurveyInpect.php +++ b/admin/survey/classes/class.SurveyInpect.php @@ -5,10 +5,10 @@ * */ -define('SI_DEFAULT_PROFILE', false, true); -define('SI_GOTO_ANALIZE', 0, true); -define('SI_GOTO_VPOGLED', 1, true); -define('SI_GOTO_PODATKI', 2, true); +define('SI_DEFAULT_PROFILE', false); +define('SI_GOTO_ANALIZE', 0); +define('SI_GOTO_VPOGLED', 1); +define('SI_GOTO_PODATKI', 2); class SurveyInspect { diff --git a/admin/survey/classes/class.SurveyList.php b/admin/survey/classes/class.SurveyList.php index 534081e00..a7e362a58 100644 --- a/admin/survey/classes/class.SurveyList.php +++ b/admin/survey/classes/class.SurveyList.php @@ -7,14 +7,14 @@ * */ -define('SRV_LIST_ORDER_BY', 16, true); # privzeto: sortiranje po stolpcu 1 -define('SRV_LIST_ORDER_TYPE', 1, true); # privzeto: sortiranje padajoče -define('SRV_LIST_REC_PER_PAGE', 25, true); # privzeto: koliko zapisov na stran prikažemo -define('SRV_LIST_GET_AS_LIST', true, true); # privzeto: ali lovimo kot seznam ali kot drevo folderjev -define('SRV_LIST_GET_SUB_FOLDERS', true, true); # privzeto: ali poizvedujemo po poddirektorijih -define('SRV_LIST_CHECK_DOSTOP', true, true); # ali preverja dostop na nivoju ankete -define('SRV_LIST_GROUP_PAGINATE', 5, true); # po kolko strani grupira pri paginaciji -define('SRV_LIST_UPDATE_TIME_LIMIT', 900, true); # na koliko minut updejtamo: 15min = 60s*15 +define('SRV_LIST_ORDER_BY', 16); # privzeto: sortiranje po stolpcu 1 +define('SRV_LIST_ORDER_TYPE', 1); # privzeto: sortiranje padajoče +define('SRV_LIST_REC_PER_PAGE', 25); # privzeto: koliko zapisov na stran prikažemo +define('SRV_LIST_GET_AS_LIST', true); # privzeto: ali lovimo kot seznam ali kot drevo folderjev +define('SRV_LIST_GET_SUB_FOLDERS', true); # privzeto: ali poizvedujemo po poddirektorijih +define('SRV_LIST_CHECK_DOSTOP', true); # ali preverja dostop na nivoju ankete +define('SRV_LIST_GROUP_PAGINATE', 5); # po kolko strani grupira pri paginaciji +define('SRV_LIST_UPDATE_TIME_LIMIT', 900); # na koliko minut updejtamo: 15min = 60s*15 if(session_id() == '') {session_start();} @@ -231,7 +231,7 @@ class SurveyList { * @desc prikaze zgornjo navigacijo */ function display_sub_tabs () { - global $lang, $global_user_id, $admin_type; + global $lang, $global_user_id, $admin_type, $site_domain, $aai_instalacija; $SLCount = $this->countSurveys(); @@ -239,14 +239,26 @@ class SurveyList { echo '
'; if ($_GET['a']=='diagnostics') { - if ($_GET['t'] == 'uporabniki') { - if ($admin_type == 0) { + + if ($_GET['t'] == 'uporabniki') { + + // Admini imajo pregled nad vsemi zavihki uporabnikov + if ($admin_type == 0) { echo ''; + } + + // Menegerji imajo samo osnovni pregled svojih uporabnikov + if ($admin_type == 1) { - + echo ''; } - - } else { + } + else { + if ($admin_type == 0) { echo ''; } @@ -701,7 +725,7 @@ class SurveyList { # ni smiselno da ostali uporabniki vidijo zavihek, ker so tako prikazane samo njihove ankete echo '
  •  
  • '; echo '
  • '; - echo ''; + echo ''; echo '
    '. $lang['hour_users'] . '
    '; echo '
    '; echo '
  • '; @@ -3047,7 +3071,7 @@ class SurveyList { $to_update = $meta_surveys_ids; # poiščemmo katere ankete so OK, in jih odstranimo iz seznama anket potrebnih za update - $stringSurveyList = "SELECT id FROM srv_survey_list WHERE id IN (".implode($meta_surveys_ids,',').")" + $stringSurveyList = "SELECT id FROM srv_survey_list WHERE id IN (".implode(',', $meta_surveys_ids).")" #. " AND (updated = '0' OR (updated = '1' AND TIME_TO_SEC(TIMEDIFF(NOW(),last_updated)) < ".SRV_LIST_UPDATE_TIME_LIMIT.")) AND ( last_updated IS NOT NULL)"; . " AND updated = '0' AND last_updated IS NOT NULL"; $sqlSurveyList = sisplet_query($stringSurveyList); @@ -3061,7 +3085,7 @@ class SurveyList { $to_update = $this->surveys_ids; # poiščemmo katere ankete so OK, in jih odstranimo iz seznama anket potrebnih za update - $stringSurveyList = "SELECT id FROM srv_survey_list WHERE id IN (".implode($this->surveys_ids,',').")" + $stringSurveyList = "SELECT id FROM srv_survey_list WHERE id IN (".implode(',', $this->surveys_ids).")" #. " AND (updated = '0' OR (updated = '1' AND TIME_TO_SEC(TIMEDIFF(NOW(),last_updated)) < ".SRV_LIST_UPDATE_TIME_LIMIT.")) AND ( last_updated IS NOT NULL)"; . " AND updated = '0' AND last_updated IS NOT NULL"; $sqlSurveyList = sisplet_query($stringSurveyList); @@ -3091,24 +3115,24 @@ class SurveyList { . ' FROM srv_anketa sa' - . " LEFT OUTER JOIN ( SELECT ank_id, uid, COUNT(*) AS lib_glb FROM srv_library_anketa as sla WHERE sla.uid = '0' AND sla.ank_id IN (".implode($to_update,',').") GROUP BY ank_id ) + . " LEFT OUTER JOIN ( SELECT ank_id, uid, COUNT(*) AS lib_glb FROM srv_library_anketa as sla WHERE sla.uid = '0' AND sla.ank_id IN (".implode(',', $to_update).") GROUP BY ank_id ) AS sla1 ON sla1.ank_id = sa.id" - . " LEFT OUTER JOIN ( SELECT ank_id, uid, COUNT(*) AS lib_usr FROM srv_library_anketa as sla WHERE sla.uid = '".$this->g_uid."' AND sla.ank_id IN (".implode($to_update,',').") GROUP BY ank_id ) + . " LEFT OUTER JOIN ( SELECT ank_id, uid, COUNT(*) AS lib_usr FROM srv_library_anketa as sla WHERE sla.uid = '".$this->g_uid."' AND sla.ank_id IN (".implode(',', $to_update).") GROUP BY ank_id ) AS sla2 ON sla2.ank_id = sa.id" //. ' LEFT OUTER JOIN users AS us1 ON us1.id = sa.edit_uid' //. ' LEFT OUTER JOIN users AS us2 ON us2.id = sa.insert_uid' - . ' LEFT OUTER JOIN ( SELECT us3.ank_id, COUNT(us3.ank_id) as answers, MIN( us3.time_insert ) as vnos_time_first, MAX( us3.time_insert ) as vnos_time_last, preview FROM srv_user as us3 WHERE us3.ank_id IN ('.implode($to_update,',').') AND us3.preview = \'0\' AND us3.deleted=\'0\' GROUP BY us3.ank_id ) + . ' LEFT OUTER JOIN ( SELECT us3.ank_id, COUNT(us3.ank_id) as answers, MIN( us3.time_insert ) as vnos_time_first, MAX( us3.time_insert ) as vnos_time_last, preview FROM srv_user as us3 WHERE us3.ank_id IN ('.implode(',', $to_update).') AND us3.preview = \'0\' AND us3.deleted=\'0\' GROUP BY us3.ank_id ) AS us3 ON us3.ank_id = sa.id' - . ' LEFT OUTER JOIN ( SELECT g.ank_id, COUNT(s.gru_id) as variables FROM srv_grupa g, srv_spremenljivka s WHERE g.id = s.gru_id AND g.ank_id IN ('.implode($to_update,',').') GROUP BY g.ank_id ) + . ' LEFT OUTER JOIN ( SELECT g.ank_id, COUNT(s.gru_id) as variables FROM srv_grupa g, srv_spremenljivka s WHERE g.id = s.gru_id AND g.ank_id IN ('.implode(',', $to_update).') GROUP BY g.ank_id ) AS g ON g.ank_id = sa.id' //spodaj dodaj AND us5.lurker=\'0\' - . ' LEFT OUTER JOIN ( SELECT us5.ank_id, COUNT(us5.ank_id) as approp, preview FROM srv_user as us5 WHERE last_status IN (' . $this->appropriateStatus . ') AND us5.ank_id IN ('.implode($to_update,',').') AND us5.preview =\'0\' AND us5.deleted=\'0\' GROUP BY us5.ank_id ) + . ' LEFT OUTER JOIN ( SELECT us5.ank_id, COUNT(us5.ank_id) as approp, preview FROM srv_user as us5 WHERE last_status IN (' . $this->appropriateStatus . ') AND us5.ank_id IN ('.implode(',', $to_update).') AND us5.preview =\'0\' AND us5.deleted=\'0\' GROUP BY us5.ank_id ) AS us5 ON us5.ank_id = sa.id' - . ' WHERE sa.id IN ('.implode($to_update,',').')'; + . ' WHERE sa.id IN ('.implode(',', $to_update).')'; $sqlUpdateList = sisplet_query($stringUpdateList); if (!$sqlUpdateList) echo mysqli_error($GLOBALS['connect_db']); @@ -3122,7 +3146,7 @@ class SurveyList { FROM srv_anketa sa LEFT OUTER JOIN users AS us1 ON us1.id = sa.edit_uid LEFT OUTER JOIN users AS us2 ON us2.id = sa.insert_uid - WHERE sa.id IN (".implode($to_update,',').")"); + WHERE sa.id IN (".implode(',', $to_update).")"); while($rowUsers = mysqli_fetch_array($sqlUsers)){ $users[$rowUsers['ank_id']] = $rowUsers; } @@ -3147,7 +3171,7 @@ class SurveyList { } $updateString = "INSERT INTO srv_survey_list (id, lib_glb, lib_usr, answers, variables, approp, i_name, i_surname, i_email, e_name, e_surname, e_email, a_first, a_last, updated, last_updated) " - ." VALUES ".implode($values,',')." ON DUPLICATE KEY UPDATE id=VALUES(id), lib_glb=VALUES(lib_glb), lib_usr=VALUES(lib_usr), answers=VALUES(answers), variables=VALUES(variables), approp=VALUES(approp), i_name=VALUES(i_name), i_surname=VALUES(i_surname), i_email=VALUES(i_email), e_name=VALUES(e_name), e_surname=VALUES(e_surname), e_email=VALUES(e_email), a_first=VALUES(a_first), a_last=VALUES(a_last), updated='0', last_updated=NOW()"; + ." VALUES ".implode(',', $values)." ON DUPLICATE KEY UPDATE id=VALUES(id), lib_glb=VALUES(lib_glb), lib_usr=VALUES(lib_usr), answers=VALUES(answers), variables=VALUES(variables), approp=VALUES(approp), i_name=VALUES(i_name), i_surname=VALUES(i_surname), i_email=VALUES(i_email), e_name=VALUES(e_name), e_surname=VALUES(e_surname), e_email=VALUES(e_email), a_first=VALUES(a_first), a_last=VALUES(a_last), updated='0', last_updated=NOW()"; sisplet_query($updateString); @@ -3193,7 +3217,7 @@ class SurveyList { } $sqlSurveyList = sisplet_query($stringSurveyList); - list($count) = mysqli_fetch_row($sqlSurveyList); + [$count] = mysqli_fetch_row($sqlSurveyList); return (int)$count; } diff --git a/admin/survey/classes/class.SurveyParaGraph.php b/admin/survey/classes/class.SurveyParaGraph.php index fe251d09c..d161ebb55 100644 --- a/admin/survey/classes/class.SurveyParaGraph.php +++ b/admin/survey/classes/class.SurveyParaGraph.php @@ -208,7 +208,7 @@ class SurveyParaGraph{ SurveySetting::getInstance()->Init($this->anketa); // Preberemo tabelo s podatki za izbrane filtre (ce ze obstaja) - $filterString = implode($this->paraGraph_filter, '_'); + $filterString = implode('_', $this->paraGraph_filter); $paraData = unserialize(SurveySetting::getInstance()->getSurveyMiscSetting('para_graph_data_'.$filterString)); // Pogledamo kdaj je bila kreirana datoteka (ce imamo nove podatke) diff --git a/admin/survey/classes/class.SurveyStatistic.php b/admin/survey/classes/class.SurveyStatistic.php index e217491c1..ca2b4bf28 100644 --- a/admin/survey/classes/class.SurveyStatistic.php +++ b/admin/survey/classes/class.SurveyStatistic.php @@ -548,12 +548,6 @@ class SurveyStatistic { } } - /*$qry = sisplet_query("SELECT id, last_status, lurker, testdata, inv_res_id, referer, language - FROM srv_user - WHERE ank_id = '".$this->getSurveyId()."' AND preview = '0' AND deleted='0' - AND ( (time_insert BETWEEN '".$this->startDate."' AND '".$this->endDate."' + INTERVAL 1 DAY) OR (last_status IN (".implode($this->emailStatus,',').") ) )" - .$email_filter_string - );*/ // Tukaj ne vem zakaj filtriramo po datumu? Itak rabimo vse $qry = sisplet_query("SELECT id, last_status, lurker, testdata, inv_res_id, referer, language FROM srv_user @@ -647,7 +641,7 @@ class SurveyStatistic { # od direktnega klika odštejemo e-mail vabila if (count($user_id_to_check_link)> 0) { - $qryEmail = sisplet_query("SELECT COUNT(*) as cnt FROM srv_userstatus WHERE usr_id IN (".implode($user_id_to_check_link,',').") AND status IN (".implode($this->emailStatus,',').")"); + $qryEmail = sisplet_query("SELECT COUNT(*) as cnt FROM srv_userstatus WHERE usr_id IN (".implode(',', $user_id_to_check_link).") AND status IN (".implode(',', $this->emailStatus).")"); $rwsEmail = mysqli_fetch_assoc($qryEmail); $this->userRedirections["email"] = (int)$rwsEmail['cnt']; diff --git a/admin/survey/classes/class.SurveyStatusProfiles.php b/admin/survey/classes/class.SurveyStatusProfiles.php index 383258571..947ce80ea 100644 --- a/admin/survey/classes/class.SurveyStatusProfiles.php +++ b/admin/survey/classes/class.SurveyStatusProfiles.php @@ -6,7 +6,7 @@ */ session_start(); -DEFINE (STR_DLMT, "|", true); +DEFINE (STR_DLMT, "|"); class SurveyStatusProfiles { diff --git a/admin/survey/classes/class.SurveyTelephone.php b/admin/survey/classes/class.SurveyTelephone.php index 1d66b1597..e8fab94ba 100644 --- a/admin/survey/classes/class.SurveyTelephone.php +++ b/admin/survey/classes/class.SurveyTelephone.php @@ -5,9 +5,9 @@ * * @author Gorazd_Veselic */ -define('GROUP_PAGINATE', 4, true); # po kolko strani grupira pri paginaciji -define('REC_ON_PAGE', 50, true); # kolko zapisov na stran pri urejanju respondentov -define('REC_ON_SEND_PAGE', 20, true); # kolko zapisov na stran pri pošiljanju +define('GROUP_PAGINATE', 4); # po kolko strani grupira pri paginaciji +define('REC_ON_PAGE', 50); # kolko zapisov na stran pri urejanju respondentov +define('REC_ON_SEND_PAGE', 20); # kolko zapisov na stran pri pošiljanju set_time_limit(2400); # 30 minut @@ -698,7 +698,7 @@ class SurveyTelephone { $onlyThisSurvey = (isset($_SESSION['inv_rec_only_this_survey']) && $_SESSION['inv_rec_only_this_survey'] == false) ? 0 : 1; if ($onlyThisSurvey == 0) { #id-ji profilov do katerih lahko dostopamo - $sql_string = "SELECT name, pid FROM srv_invitations_recipients_profiles WHERE uid in('0', '".$global_user_id."') OR pid IN (SELECT DISTINCT pid FROM srv_invitations_recipients_profiles_access where uid = '$global_user_id')"; + $sql_string = "SELECT name, pid FROM srv_invitations_recipients_profiles WHERE uid in('".$global_user_id."') OR pid IN (SELECT DISTINCT pid FROM srv_invitations_recipients_profiles_access where uid = '$global_user_id')"; $sql_query = sisplet_query($sql_string); } else { # 1 @@ -2865,7 +2865,7 @@ class SurveyTelephone { $array_profiles = array(); # polovimo še ostale porfile - $sql_string = "SELECT pid, name,comment FROM srv_invitations_recipients_profiles WHERE uid in('0', '".$global_user_id."') AND from_survey = '".$this->sid. "'"; + $sql_string = "SELECT pid, name,comment FROM srv_invitations_recipients_profiles WHERE uid in('".$global_user_id."') AND from_survey = '".$this->sid. "'"; $sql_query = sisplet_query($sql_string); while ($sql_row = mysqli_fetch_assoc($sql_query)) { $array_profiles[$sql_row['pid']] = array('name' => $sql_row['name'], 'comment'=>$sql_row['comment']); @@ -3415,7 +3415,7 @@ class SurveyTelephone { $res_row = mysqli_fetch_assoc($res_query); #preverimo ali že obstaja povezava med respondentom in userjem - $chk_user = "SELECT id, pass FROM srv_user WHERE inv_res_id='$usr_id'"; + $chk_user = "SELECT id, pass FROM srv_user WHERE inv_res_id='$usr_id' AND ank_id='".$this->sid."'"; $chk_query = sisplet_query($chk_user); $return['msg'] = $chk_user; if (mysqli_num_rows($chk_query) > 0) { @@ -3423,7 +3423,7 @@ class SurveyTelephone { $user_data = mysqli_fetch_assoc($chk_query); # sestavimo še url za odpiranje izpolnjevanja ankete - $return['surveyUrl'] = $site_url.'a/'.Common::encryptAnketaID($this->sid).'&survey-'.$this->sid.'&code='.$user_data[pass]; + $return['surveyUrl'] = $site_url.'a/'.Common::encryptAnketaID($this->sid).'&survey-'.$this->sid.'&code='.$user_data['pass']; $return['error'] = ''; } else { diff --git a/admin/survey/classes/class.SurveyVariablesProfiles.php b/admin/survey/classes/class.SurveyVariablesProfiles.php index 332405c97..15ad1103c 100644 --- a/admin/survey/classes/class.SurveyVariablesProfiles.php +++ b/admin/survey/classes/class.SurveyVariablesProfiles.php @@ -11,7 +11,7 @@ * */ DEFINE ('SVP_DEFAULT_PROFILE', 0); -DEFINE (NEW_LINE, "\n", true); +DEFINE (NEW_LINE, "\n"); class SurveyVariablesProfiles { diff --git a/admin/survey/classes/class.SurveyZankaProfiles.php b/admin/survey/classes/class.SurveyZankaProfiles.php index fecaba8ff..cac04d57d 100644 --- a/admin/survey/classes/class.SurveyZankaProfiles.php +++ b/admin/survey/classes/class.SurveyZankaProfiles.php @@ -19,7 +19,7 @@ */ session_start(); -define('SZP_DEFAULT_PROFILE', 0, true); +define('SZP_DEFAULT_PROFILE', 0); class SurveyZankaProfiles { diff --git a/admin/survey/classes/class.Vprasanje.php b/admin/survey/classes/class.Vprasanje.php index 99363b201..1138b91c1 100644 --- a/admin/survey/classes/class.Vprasanje.php +++ b/admin/survey/classes/class.Vprasanje.php @@ -3380,11 +3380,7 @@ class Vprasanje { echo ''; // Custom picture za radio tip echo ''; //image hotspot echo ''; //vizualna analaogna skala - smeški - if ($admin_type == 0){ - //echo ''; - echo ''; - //echo ''; //image hotspot - } + echo ''; echo ''; echo '

    '; } @@ -4893,6 +4889,14 @@ class Vprasanje { function set_GDPR () { global $lang; + $lang_admin = SurveyInfo::getInstance()->getSurveyColumn('lang_admin'); + $lang_resp = SurveyInfo::getInstance()->getSurveyColumn('lang_resp'); + + // nastavimo na jezik za respondentov vmesnik + $file = '../../lang/'.$lang_resp.'.php'; + include($file); + + $user_settings = GDPR::getSurveySettings($this->anketa); // GDPR je radio (da / ne) tip vprasanja z predefiniranim textom @@ -4910,6 +4914,11 @@ class Vprasanje { // Popravimo, da ima anketa vklopljen gdpr sisplet_query("INSERT INTO srv_gdpr_anketa (ank_id) VALUES ('".$this->anketa."')"); + + + // nastavimo nazaj na admin jezik + $file = '../../lang/'.$lang_admin.'.php'; + include($file); } /** @@ -7407,7 +7416,7 @@ class Vprasanje { echo '

    '; echo ''.$lang['srv_gridmultiple_width'].': '; echo '' . "\n\r"; echo ' ' . "\n\r"; @@ -9880,21 +9861,39 @@ class SurveyInvitationsNew { $MA = new MailAdapter($this->sid, $type='invitation'); // Dostop za posiljanje mailov preko 1ka serverja - $enabled1ka = ( $MA->is1KA() || (($admin_type == 0) && ($mysql_database_name == 'www1kasi' || $mysql_database_name == 'test1kasi' || $mysql_database_name == 'real1kasi' || $mysql_database_name == '1kaarnessi')) ) ? true : false; + $enabled1ka = $MA->is1KA() ? true : false; + // Admini na testu, www in virtualkah imajo 1ka smtp + if(($admin_type == 0) && ($mysql_database_name == 'www1kasi' || $mysql_database_name == 'test1kasi' || $mysql_database_name == 'real1kasi')) + $enabled1ka = true; + + // Opozorilo, ce imamo vklopljena vabila, da gre za iste nastavitve + echo '

    '.$lang['srv_email_server_settings_warning'].'

    '; + + // Izbira SMTP streznika echo ''.$lang['srv_email_setting_select_server'].' '; - echo ''; + + // AAI ima Arnesov smtp + if($aai_instalacija){ + echo ''; + } + else{ + echo ''; + } + // Google smtp je viden samo starim, kjer je ze vklopljen if($MA->isGoogle()){ echo ''; } - echo ''; - echo Help :: display('srv_mail_mode'); - + // Lastni smtp + echo ''; + + echo Help :: display('srv_mail_mode'); #1KA $enkaSettings = $MA->get1KASettings($raziskave=true); @@ -10051,4 +10050,25 @@ class SurveyInvitationsNew { SurveySession::set('inv_noEmailing_type', (int)$_POST['value']); } } + + // Prikazemo popup za vklop arnes smtp-ja na aai + private function showAAISmtpPopup(){ + global $lang; + + echo ''; + + echo '

    '.$lang['srv_email_setting_adapter0_aai_title'].'

    '; + + echo ''; + + echo '
    '; + echo ''; + echo ''.$lang['srv_cancel'].''; + echo '
    '; + } } diff --git a/admin/survey/classes/class.SurveySimpleMailInvitation.php b/admin/survey/classes/surveyEmails/class.SurveySimpleMailInvitation.php similarity index 99% rename from admin/survey/classes/class.SurveySimpleMailInvitation.php rename to admin/survey/classes/surveyEmails/class.SurveySimpleMailInvitation.php index d850ca938..b548c1328 100644 --- a/admin/survey/classes/class.SurveySimpleMailInvitation.php +++ b/admin/survey/classes/surveyEmails/class.SurveySimpleMailInvitation.php @@ -5,7 +5,8 @@ * */ -define("SIMPLE_MAIL_QUOTA", 20, true); +define("SIMPLE_MAIL_QUOTA", 20); + class SurveySimpleMailInvitation { public $sid; # id ankete diff --git a/admin/survey/classes/class.SurveyUnsubscribe.php b/admin/survey/classes/surveyEmails/class.SurveyUnsubscribe.php similarity index 100% rename from admin/survey/classes/class.SurveyUnsubscribe.php rename to admin/survey/classes/surveyEmails/class.SurveyUnsubscribe.php diff --git a/admin/survey/classes/CrossRoad.php b/admin/survey/classes/tracking/CrossRoad.php similarity index 100% rename from admin/survey/classes/CrossRoad.php rename to admin/survey/classes/tracking/CrossRoad.php diff --git a/admin/survey/classes/TrackingClass.php b/admin/survey/classes/tracking/TrackingClass.php similarity index 100% rename from admin/survey/classes/TrackingClass.php rename to admin/survey/classes/tracking/TrackingClass.php diff --git a/admin/survey/classes/UserTrackingClass.php b/admin/survey/classes/tracking/UserTrackingClass.php similarity index 85% rename from admin/survey/classes/UserTrackingClass.php rename to admin/survey/classes/tracking/UserTrackingClass.php index 505c74604..4d0eecb69 100644 --- a/admin/survey/classes/UserTrackingClass.php +++ b/admin/survey/classes/tracking/UserTrackingClass.php @@ -43,7 +43,7 @@ class UserTrackingClass echo '' . $lang['srv_survey_archives_tracking'] . ''; // Izvoz v Excel - echo '

    Download Excel

    '; + echo '

    '.$lang['srv_survey_archives_tracking_last_changes'].'

    '; echo ''; @@ -51,26 +51,19 @@ class UserTrackingClass // Prva vrstica echo ''; echo ' '; - //echo ' '; echo ' '; - //echo ' '; echo ' '; echo ' '; echo ''; // Vrstice s podatki - $sql = sisplet_query("SELECT * FROM user_tracking WHERE user = '$global_user_id' ORDER BY datetime DESC"); + $sql = sisplet_query("SELECT * FROM user_tracking WHERE user = '$global_user_id' ORDER BY datetime DESC LIMIT 25"); - //$sqlu = sisplet_query("SELECT name, surname FROM users WHERE id = '$global_user_id'"); - //$rowu = mysqli_fetch_array($sqlu); - while ($row = mysqli_fetch_array($sql)) { echo ''; echo ' '; - //echo ' '; echo ' '; - //echo ' '; echo ' '; echo ' '; diff --git a/admin/survey/definition.php b/admin/survey/definition.php index 5b4e2d74d..2c265a256 100644 --- a/admin/survey/definition.php +++ b/admin/survey/definition.php @@ -4,245 +4,245 @@ define('IS_LINUX', (DIRECTORY_SEPARATOR === '\\') ? FALSE : TRUE); # NASTAVITVE ANKETE - define('ANKETA_NASLOV_MAXLENGTH', '40', true); # KOLIKO ZNAKOV LAHKO VSEBUJE INTERNO IME ANKETE - define('ANKETA_AKRONIM_MAXLENGTH', '100', true); # KOLIKO ZNAKOV LAHKO VSEBUJE AKRONIM ANKETE - define('ANKETA_NOTE_MAXLENGTH', '250', true); # KOLIKO ZNAKOV LAHKO VSEBUJE OPIS ANKETE + define('ANKETA_NASLOV_MAXLENGTH', '40'); # KOLIKO ZNAKOV LAHKO VSEBUJE INTERNO IME ANKETE + define('ANKETA_AKRONIM_MAXLENGTH', '100'); # KOLIKO ZNAKOV LAHKO VSEBUJE AKRONIM ANKETE + define('ANKETA_NOTE_MAXLENGTH', '250'); # KOLIKO ZNAKOV LAHKO VSEBUJE OPIS ANKETE # za url-je za navigacijo - define('NEW_LINE', "\n", true); + define('NEW_LINE', "\n"); ##### NAVIGACIJA #### - define("NAVI_STATUS", "NAVI_STATUS", true); - define("NAVI_STATUS_OSNOVNI", "NAVI_STATUS_OSNOVNI", true); - define("NAVI_STATUS_TRAJANJE", "NAVI_STATUS_TRAJANJE", true); - define("NAVI_AAPOR","AAPOR",true); - define("NAVI_UREJANJE", "NAVI_UREJANJE", true); - define("NAVI_TESTIRANJE", "NAVI_TESTIRANJE", true); - define("NAVI_TESTIRANJE_KOMENTARJI", "NAVI_TESTIRANJE_KOMENTARJI", true); - define("NAVI_TESTIRANJE_PREDVIDENI", "NAVI_TESTIRANJE_PREDVIDENI", true); - define("NAVI_TESTIRANJE_CAS", "NAVI_TESTIRANJE_CAS", true); - define("NAVI_TESTIRANJE_VNOSI", "NAVI_TESTIRANJE_VNOSI", true); - define("NAVI_TESTIRANJE_LANGUAGE_TECHNOLOGY", "NAVI_TESTIRANJE_LANGUAGE_TECHNOLOGY", true); - define("NAVI_TESTIRANJE_LANGUAGE_TECHNOLOGY_OLD", "NAVI_TESTIRANJE_LANGUAGE_TECHNOLOGY_OLD", true); - define("NAVI_UREJANJE_BRANCHING", "NAVI_UREJANJE_BRANCHING", true); - define("NAVI_UREJANJE_ANKETA", "NAVI_UREJANJE_ANKETA", true); - define("NAVI_UREJANJE_TEMA", "NAVI_UREJANJE_TEMA", true); - define("NAVI_UREJANJE_ALERT", "NAVI_UREJANJE_ALERT", true); - define("NAVI_UREJANJE_TESTIRANJE", "NAVI_UREJANJE_TESTIRANJE", true); - define("NAVI_TESTIRANJE_KOMENTARJI_ANKETA", "NAVI_TESTIRANJE_KOMENTARJI_ANKETA", true); - define("NAVI_UREJANJE_PREVAJANJE", "NAVI_UREJANJE_PREVAJANJE", true); - define("NAVI_OBJAVA", "NAVI_OBJAVA", true); - define("NAVI_ANALYSIS", "NAVI_ANALYSIS", true); - define("NAVI_RESULTS", "NAVI_RESULTS", true); - define("NAVI_ADVANCED", "NAVI_ADVANCED", true); - define("NAVI_UPORABNOST", "NAVI_UPORABNOST", true); - define("NAVI_HIERARHIJA_SUPERADMIN", "NAVI_HIERARHIJA_SUPERADMIN", true); - define("NAVI_HIERARHIJA", "NAVI_HIERARHIJA", true); - define("NAVI_KVIZ", "NAVI_KVIZ", true); - define("NAVI_VNOS", "NAVI_VNOS", true); - define("NAVI_PHONE", "NAVI_PHONE", true); - define("NAVI_360", "NAVI_360", true); - define("NAVI_SOCIAL_NETWORK", "NAVI_SOCIAL_NETWORK", true); - define("NAVI_SLIDESHOW", "NAVI_SLIDESHOW", true); - define("NAVI_STATISTIC_ANALYSIS", "NAVI_STATISTIC_ANALYSIS", true); - define("NAVI_ANALYSIS_LINKS", "NAVI_ANALYSIS_LINKS", true); - define("NAVI_ANALYSIS_TIMES", "NAVI_ANALYSIS_TIMES", true); - define("NAVI_DATA", "NAVI_DATA", true); - define("NAVI_DATA_EXPORT", "NAVI_DATA_EXPORT", true); + define("NAVI_STATUS", "NAVI_STATUS"); + define("NAVI_STATUS_OSNOVNI", "NAVI_STATUS_OSNOVNI"); + define("NAVI_STATUS_TRAJANJE", "NAVI_STATUS_TRAJANJE"); + define("NAVI_AAPOR", "AAPOR"); + define("NAVI_UREJANJE", "NAVI_UREJANJE"); + define("NAVI_TESTIRANJE", "NAVI_TESTIRANJE"); + define("NAVI_TESTIRANJE_KOMENTARJI", "NAVI_TESTIRANJE_KOMENTARJI"); + define("NAVI_TESTIRANJE_PREDVIDENI", "NAVI_TESTIRANJE_PREDVIDENI"); + define("NAVI_TESTIRANJE_CAS", "NAVI_TESTIRANJE_CAS"); + define("NAVI_TESTIRANJE_VNOSI", "NAVI_TESTIRANJE_VNOSI"); + define("NAVI_TESTIRANJE_LANGUAGE_TECHNOLOGY", "NAVI_TESTIRANJE_LANGUAGE_TECHNOLOGY"); + define("NAVI_TESTIRANJE_LANGUAGE_TECHNOLOGY_OLD", "NAVI_TESTIRANJE_LANGUAGE_TECHNOLOGY_OLD"); + define("NAVI_UREJANJE_BRANCHING", "NAVI_UREJANJE_BRANCHING"); + define("NAVI_UREJANJE_ANKETA", "NAVI_UREJANJE_ANKETA"); + define("NAVI_UREJANJE_TEMA", "NAVI_UREJANJE_TEMA"); + define("NAVI_UREJANJE_ALERT", "NAVI_UREJANJE_ALERT"); + define("NAVI_UREJANJE_TESTIRANJE", "NAVI_UREJANJE_TESTIRANJE"); + define("NAVI_TESTIRANJE_KOMENTARJI_ANKETA", "NAVI_TESTIRANJE_KOMENTARJI_ANKETA"); + define("NAVI_UREJANJE_PREVAJANJE", "NAVI_UREJANJE_PREVAJANJE"); + define("NAVI_OBJAVA", "NAVI_OBJAVA"); + define("NAVI_ANALYSIS", "NAVI_ANALYSIS"); + define("NAVI_RESULTS", "NAVI_RESULTS"); + define("NAVI_ADVANCED", "NAVI_ADVANCED"); + define("NAVI_UPORABNOST", "NAVI_UPORABNOST"); + define("NAVI_HIERARHIJA_SUPERADMIN", "NAVI_HIERARHIJA_SUPERADMIN"); + define("NAVI_HIERARHIJA", "NAVI_HIERARHIJA"); + define("NAVI_KVIZ", "NAVI_KVIZ"); + define("NAVI_VNOS", "NAVI_VNOS"); + define("NAVI_PHONE", "NAVI_PHONE"); + define("NAVI_360", "NAVI_360"); + define("NAVI_SOCIAL_NETWORK", "NAVI_SOCIAL_NETWORK"); + define("NAVI_SLIDESHOW", "NAVI_SLIDESHOW"); + define("NAVI_STATISTIC_ANALYSIS", "NAVI_STATISTIC_ANALYSIS"); + define("NAVI_ANALYSIS_LINKS", "NAVI_ANALYSIS_LINKS"); + define("NAVI_ANALYSIS_TIMES", "NAVI_ANALYSIS_TIMES"); + define("NAVI_DATA", "NAVI_DATA"); + define("NAVI_DATA_EXPORT", "NAVI_DATA_EXPORT"); # Dashboard - status - report - define("A_REPORTI", "reporti", true); - define("A_NONRESPONSE_GRAPH", "nonresponse_graph", true); - define("A_PARA_GRAPH", "para_graph", true); - define("A_USABLE_RESP", "usable_resp", true); - define("A_SPEEDER_INDEX", "speeder_index", true); - define("A_TEXT_ANALYSIS", "text_analysis", true); - define("A_GEOIP_LOCATION", "geoip_location", true); - define("A_EDITS_ANALYSIS", "edits_analysis", true); - define("A_UL_EVALVATION", "ul_evalvation", true); - define("A_REMINDER_TRACKING", "reminder_tracking", true); - define("A_REMINDER_TRACKING_RECNUM", "recnum", true); - define("A_REMINDER_TRACKING_VAR", "vars", true); + define("A_REPORTI", "reporti"); + define("A_NONRESPONSE_GRAPH", "nonresponse_graph"); + define("A_PARA_GRAPH", "para_graph"); + define("A_USABLE_RESP", "usable_resp"); + define("A_SPEEDER_INDEX", "speeder_index"); + define("A_TEXT_ANALYSIS", "text_analysis"); + define("A_GEOIP_LOCATION", "geoip_location"); + define("A_EDITS_ANALYSIS", "edits_analysis"); + define("A_UL_EVALVATION", "ul_evalvation"); + define("A_REMINDER_TRACKING", "reminder_tracking"); + define("A_REMINDER_TRACKING_RECNUM", "recnum"); + define("A_REMINDER_TRACKING_VAR", "vars"); #urejanje - define("A_BRANCHING", "branching", true); - define("A_SETTINGS", "nastavitve", true); - define("A_NAGOVORI", "nagovori", true); - define("A_ALERT", "alert", true); - define("A_TESTIRANJE", "testiranje", true); - define("A_ARHIVI", "arhivi", true); - define("A_TRACKING", "tracking", true); - define("A_TRACKING_HIERARHIJA", "tracking-hierarhija", true); - define("A_GLASOVANJE", "glasovanja", true); + define("A_BRANCHING", "branching"); + define("A_SETTINGS", "nastavitve"); + define("A_NAGOVORI", "nagovori"); + define("A_ALERT", "alert"); + define("A_TESTIRANJE", "testiranje"); + define("A_ARHIVI", "arhivi"); + define("A_TRACKING", "tracking"); + define("A_TRACKING_HIERARHIJA", "tracking-hierarhija"); + define("A_GLASOVANJE", "glasovanja"); # TESTIRANJE - define('M_TESTIRANJE_REVIEW', 'pregled', true); - define('M_TESTIRANJE_DIAGNOSTIKA', 'diagnostika', true); - define('M_TESTIRANJE_KOMENTARJI', 'komentarji', true); - define('M_TESTIRANJE_KOMENTARJI_ANKETA', 'komentarji_anketa', true); - define('M_TESTIRANJE_VNOSI', 'testnipodatki', true); - define('M_TESTIRANJE_TRAJANJE', 'trajanje', true); - define('M_TESTIRANJE_PREDVIDENI', 'predvidenicas', true); - define("M_TESTIRANJE_CAS", "cas", true); + define('M_TESTIRANJE_REVIEW', 'pregled'); + define('M_TESTIRANJE_DIAGNOSTIKA', 'diagnostika'); + define('M_TESTIRANJE_KOMENTARJI', 'komentarji'); + define('M_TESTIRANJE_KOMENTARJI_ANKETA', 'komentarji_anketa'); + define('M_TESTIRANJE_VNOSI', 'testnipodatki'); + define('M_TESTIRANJE_TRAJANJE', 'trajanje'); + define('M_TESTIRANJE_PREDVIDENI', 'predvidenicas'); + define("M_TESTIRANJE_CAS", "cas"); # objava - define('A_VABILA', 'vabila', true); - define('A_EMAIL', 'email', true); - define('A_INVITATIONS', 'invitations', true); - define('M_INVITATIONS_STATUS', 'inv_status', true); - define('M_INVITATIONS_SETTINGS', 'inv_settings', true); - define('M_INVITATIONS', 'vabila', true); + define('A_VABILA', 'vabila'); + define('A_EMAIL', 'email'); + define('A_INVITATIONS', 'invitations'); + define('M_INVITATIONS_STATUS', 'inv_status'); + define('M_INVITATIONS_SETTINGS', 'inv_settings'); + define('M_INVITATIONS', 'vabila'); # TELEFON - define('A_TELEPHONE', 'telephone', true); + define('A_TELEPHONE', 'telephone'); # CHAT - define('A_CHAT', 'chat', true); + define('A_CHAT', 'chat'); # PANEL - define('A_PANEL', 'panel', true); + define('A_PANEL', 'panel'); # FIELDWORK (tablice, notebooki) - define('A_FIELDWORK', 'fieldwork', true); + define('A_FIELDWORK', 'fieldwork'); # Mobilna aplikacija za anketirance - define('A_MAZA', 'maza', true); + define('A_MAZA', 'maza'); # Web push notifications - define('A_WPN', 'wpn', true); + define('A_WPN', 'wpn'); # 360 STOPINJ - define('A_360', '360_stopinj', true); - define('A_360_1KA', '360_stopinj_1ka', true); + define('A_360', '360_stopinj'); + define('A_360_1KA', '360_stopinj_1ka'); # SA- HIERARHIJA - define('A_HIERARHIJA', 'hierarhija', true); #izgradnja hierarhije - define('M_ADMIN_UREDI_SIFRANTE', 'uredi-sifrante', true); #hierarhija - uredi šifrante za kasnejšo izgradno - define('M_ADMIN_UVOZ_SIFRANTOV', 'uvoz-sifrantov', true); #hierarhija - uvoz sifrantov - define('M_ADMIN_UPLOAD_LOGO', 'upload-logo', true); #hierarhija - upload logo - define('M_ADMIN_IZVOZ_SIFRANTOV', 'izvoz-sifrantov', true); #hierarhija - izvoz sifrantov - define('M_UREDI_UPORABNIKE', 'uredi-uporabnike', true); #hierarhija - uredi uporabnike - define('M_ADMIN_AKTIVACIJA', 'aktivacija-strukture-ankete', true); #aktivacija hierarhije - define('M_ADMIN_KOPIRANJE', 'kopiranje-strukture-in-uporabnikov', true); #kopiranje hierarhije - define('M_ANALIZE', 'analize', true); #hierarhija analize - define('M_HIERARHIJA_STATUS', 'status', true); #hierarhija - statusi + define('A_HIERARHIJA', 'hierarhija'); #izgradnja hierarhije + define('M_ADMIN_UREDI_SIFRANTE', 'uredi-sifrante'); #hierarhija - uredi šifrante za kasnejšo izgradno + define('M_ADMIN_UVOZ_SIFRANTOV', 'uvoz-sifrantov'); #hierarhija - uvoz sifrantov + define('M_ADMIN_UPLOAD_LOGO', 'upload-logo'); #hierarhija - upload logo + define('M_ADMIN_IZVOZ_SIFRANTOV', 'izvoz-sifrantov'); #hierarhija - izvoz sifrantov + define('M_UREDI_UPORABNIKE', 'uredi-uporabnike'); #hierarhija - uredi uporabnike + define('M_ADMIN_AKTIVACIJA', 'aktivacija-strukture-ankete'); #aktivacija hierarhije + define('M_ADMIN_KOPIRANJE', 'kopiranje-strukture-in-uporabnikov'); #kopiranje hierarhije + define('M_ANALIZE', 'analize'); #hierarhija analize + define('M_HIERARHIJA_STATUS', 'status'); #hierarhija - statusi # REZULTATI #analize - define('A_ANALYSIS', 'analysis', true); - define('M_ANALYSIS_DESCRIPTOR', 'descriptor', true); - define('M_ANALYSIS_FREQUENCY', 'frequency', true); - define('M_ANALYSIS_SUMMARY', 'sumarnik', true); - define('M_ANALYSIS_SUMMARY_NEW', 'sums_new', true); - define('M_ANALYSIS_CROSSTAB', 'crosstabs', true); - define("M_ANALYSIS_MULTICROSSTABS", "multicrosstabs", true); - define('M_ANALYSIS_MEANS', 'means', true); - define('M_ANALYSIS_MEANS_HIERARHY', 'hierarhy-means', true); - define('M_ANALYSIS_TTEST', 'ttest', true); - define('M_ANALYSIS_BREAK', 'break', true); - define('M_ANALYSIS_STATISTICS', 'statistics', true); - define('M_ANALYSIS_ARCHIVE', 'anal_arch', true); - define("M_ANALYSIS_LINKS", "analysis_links", true); - define("M_ANALYSIS_CREPORT", "analysis_creport", true); - define("M_ANALYSIS_CHARTS", "charts", true); - define("M_ANALYSIS_PARA", "para", true); - define("M_ANALYSIS_NONRESPONSES", "nonresponses", true); - define("M_ANALYSIS_VIZUALIZACIJA", "vizualizacija", true); - define("M_ANALYSIS_360", "360_stopinj", true); - define("M_ANALYSIS_360_1KA", "360_stopinj_1ka", true); - define('M_ANALYSIS_HEATMAP', 'heatmap', true); + define('A_ANALYSIS', 'analysis'); + define('M_ANALYSIS_DESCRIPTOR', 'descriptor'); + define('M_ANALYSIS_FREQUENCY', 'frequency'); + define('M_ANALYSIS_SUMMARY', 'sumarnik'); + define('M_ANALYSIS_SUMMARY_NEW', 'sums_new'); + define('M_ANALYSIS_CROSSTAB', 'crosstabs'); + define("M_ANALYSIS_MULTICROSSTABS", "multicrosstabs"); + define('M_ANALYSIS_MEANS', 'means'); + define('M_ANALYSIS_MEANS_HIERARHY', 'hierarhy-means'); + define('M_ANALYSIS_TTEST', 'ttest'); + define('M_ANALYSIS_BREAK', 'break'); + define('M_ANALYSIS_STATISTICS', 'statistics'); + define('M_ANALYSIS_ARCHIVE', 'anal_arch'); + define("M_ANALYSIS_LINKS", "analysis_links"); + define("M_ANALYSIS_CREPORT", "analysis_creport"); + define("M_ANALYSIS_CHARTS", "charts"); + define("M_ANALYSIS_PARA", "para"); + define("M_ANALYSIS_NONRESPONSES", "nonresponses"); + define("M_ANALYSIS_VIZUALIZACIJA", "vizualizacija"); + define("M_ANALYSIS_360", "360_stopinj"); + define("M_ANALYSIS_360_1KA", "360_stopinj_1ka"); + define('M_ANALYSIS_HEATMAP', 'heatmap'); # vnosi - zbiranje podatkov - define('A_COLLECT_DATA', 'data', true); - define('M_COLLECT_DATA_VIEW', 'view', true); - define('M_COLLECT_DATA_VARIABLE_VIEW', 'variables', true); - define('M_COLLECT_DATA_EDIT', 'edit', true); - define('M_COLLECT_DATA_QUICKEDIT', 'quick_edit', true); - define('M_COLLECT_DATA_MONITORING', 'monitoring', true); - define('M_COLLECT_DATA_PRINT', 'print', true); - define('M_COLLECT_DATA_CALCULATION', 'calculation', true); - define('M_COLLECT_DATA_CODING', 'coding', true); - define('M_COLLECT_DATA_RECODING', 'recoding', true); - define('M_COLLECT_DATA_RECODING_DASHBOARD', 'recoding_dashboard', true); - define('A_COLLECT_DATA_EXPORT', 'export', true); - define('A_COLLECT_DATA_EXPORT_ALL', 'export_PDF', true); - define('M_EXPORT_EXCEL', 'excel', true); - define('M_EXPORT_EXCEL_XLS', 'excel_xls', true); - define('M_EXPORT_SPSS', 'spss', true); - define('M_EXPORT_SAV', 'sav', true); - define('M_EXPORT_TXT', 'txt', true); + define('A_COLLECT_DATA', 'data'); + define('M_COLLECT_DATA_VIEW', 'view'); + define('M_COLLECT_DATA_VARIABLE_VIEW', 'variables'); + define('M_COLLECT_DATA_EDIT', 'edit'); + define('M_COLLECT_DATA_QUICKEDIT', 'quick_edit'); + define('M_COLLECT_DATA_MONITORING', 'monitoring'); + define('M_COLLECT_DATA_PRINT', 'print'); + define('M_COLLECT_DATA_CALCULATION', 'calculation'); + define('M_COLLECT_DATA_CODING', 'coding'); + define('M_COLLECT_DATA_RECODING', 'recoding'); + define('M_COLLECT_DATA_RECODING_DASHBOARD', 'recoding_dashboard'); + define('A_COLLECT_DATA_EXPORT', 'export'); + define('A_COLLECT_DATA_EXPORT_ALL', 'export_PDF'); + define('M_EXPORT_EXCEL', 'excel'); + define('M_EXPORT_EXCEL_XLS', 'excel_xls'); + define('M_EXPORT_SPSS', 'spss'); + define('M_EXPORT_SAV', 'sav'); + define('M_EXPORT_TXT', 'txt'); # dodatne nastavitve - define('A_ADVANCED', 'advanced', true); - define('A_UPORABNOST', 'uporabnost', true); - define('A_HIERARHIJA_SUPERADMIN', 'hierarhija_superadmin', true); - define('A_KVIZ', 'kviz', true); - define('A_VNOS', 'vnos', true); - define('A_PHONE', 'telefon', true); # Telefon - define('T_PHONE', 'telefon', true); # Telefon - define('A_SOCIAL_NETWORK', 'social_network', true); - define('A_SLIDESHOW', 'slideshow', true); - define('A_ADVANCED_PARADATA', 'advanced_paradata', true); - define('A_JSON_SURVEY_EXPORT', 'json_survey_export', true); + define('A_ADVANCED', 'advanced'); + define('A_UPORABNOST', 'uporabnost'); + define('A_HIERARHIJA_SUPERADMIN', 'hierarhija_superadmin'); + define('A_KVIZ', 'kviz'); + define('A_VNOS', 'vnos'); + define('A_PHONE', 'telefon'); # Telefon + define('T_PHONE', 'telefon'); # Telefon + define('A_SOCIAL_NETWORK', 'social_network'); + define('A_SLIDESHOW', 'slideshow'); + define('A_ADVANCED_PARADATA', 'advanced_paradata'); + define('A_JSON_SURVEY_EXPORT', 'json_survey_export'); # primerno redirektamo klik na link anketo (dashboard .vs. urejanje) - define("A_REDIRECTLINK", "redirectLink", true); + define("A_REDIRECTLINK", "redirectLink"); - define("A_QUICK_SETTINGS", "quicksettings", true); + define("A_QUICK_SETTINGS", "quicksettings"); # za tretji nivo navigacije - define("A_OSNOVNI_PODATKI", "osn_pod", true); # urejanje ankete - osnovni podatki - define('A_MISSING', 'missing', true); # urejanje ankete - manjkajoče vrednosti - define('A_TEMA', 'tema', true); # urejanje ankete - manjkajoče vrednosti - define('A_COOKIE', 'piskot', true); # urejanje ankete - manjkajoče vrednosti - define("A_KOMENTARJI", "komentarji", true); # urejanje ankete - komentarjivrednosti - define("A_KOMENTARJI_ANKETA", "komentarji_anketa", true); # urejanje ankete - komentarjivrednosti - define("A_TRAJANJE", "trajanje", true); # urejanje ankete - komentarjivrednosti - define("A_TRAJANJE_PREDVIDENI", "predvidenicas", true); # urejanje ankete - komentarjivrednosti - define("A_TRAJANJE_CAS", "cas", true); # urejanje ankete - komentarjivrednosti - define('A_UREJANJE', 'urejanje', true); # urejanje ankete - komentarjivrednosti - define('A_DOSTOP', 'dostop', true); # urejanje ankete - manjkajoče vrednosti - define('A_JEZIK', 'jezik', true); # urejanje ankete - manjkajoče vrednosti - define('A_PREVAJANJE', 'prevajanje', true); # urejanje ankete - manjkajoče vrednosti - define('A_FORMA', 'forma', true); # urejanje ankete - manjkajoče vrednosti - define('A_METADATA', 'metadata', true); # urejanje ankete - prikaz metapodatkov - define('A_MOBILESETTINGS', 'mobile_settings', true); # urejanje ankete - nastavitve prikaza pri mobitelih - define('A_PRIKAZ', 'prikaz', true); # prikaz podatkov in analiz - define('A_MAILING', 'advanced_email', true); # nastavitve email strežnika - define('A_SKUPINE', 'skupine', true); # skupine - define('A_EXPORTSETTINGS', 'export_settings', true); # nastavitve pdf/rtf izvozov - define('A_GDPR', 'gdpr_settings', true); # GDPR nastavitve posamezne ankete - define('A_LANGUAGE_TECHNOLOGY', 'language_technology', true); # skupine - define('A_LANGUAGE_TECHNOLOGY_OLD', 'language_technology_old', true); # skupine + define("A_OSNOVNI_PODATKI", "osn_pod"); # urejanje ankete - osnovni podatki + define('A_MISSING', 'missing'); # urejanje ankete - manjkajoče vrednosti + define('A_TEMA', 'tema'); # urejanje ankete - manjkajoče vrednosti + define('A_COOKIE', 'piskot'); # urejanje ankete - manjkajoče vrednosti + define("A_KOMENTARJI", "komentarji"); # urejanje ankete - komentarjivrednosti + define("A_KOMENTARJI_ANKETA", "komentarji_anketa"); # urejanje ankete - komentarjivrednosti + define("A_TRAJANJE", "trajanje"); # urejanje ankete - komentarjivrednosti + define("A_TRAJANJE_PREDVIDENI", "predvidenicas"); # urejanje ankete - komentarjivrednosti + define("A_TRAJANJE_CAS", "cas"); # urejanje ankete - komentarjivrednosti + define('A_UREJANJE', 'urejanje'); # urejanje ankete - komentarjivrednosti + define('A_DOSTOP', 'dostop'); # urejanje ankete - manjkajoče vrednosti + define('A_JEZIK', 'jezik'); # urejanje ankete - manjkajoče vrednosti + define('A_PREVAJANJE', 'prevajanje'); # urejanje ankete - manjkajoče vrednosti + define('A_FORMA', 'forma'); # urejanje ankete - manjkajoče vrednosti + define('A_METADATA', 'metadata'); # urejanje ankete - prikaz metapodatkov + define('A_MOBILESETTINGS', 'mobile_settings'); # urejanje ankete - nastavitve prikaza pri mobitelih + define('A_PRIKAZ', 'prikaz'); # prikaz podatkov in analiz + define('A_MAILING', 'advanced_email'); # nastavitve email strežnika + define('A_SKUPINE', 'skupine'); # skupine + define('A_EXPORTSETTINGS', 'export_settings'); # nastavitve pdf/rtf izvozov + define('A_GDPR', 'gdpr_settings'); # GDPR nastavitve posamezne ankete + define('A_LANGUAGE_TECHNOLOGY', 'language_technology'); # skupine + define('A_LANGUAGE_TECHNOLOGY_OLD', 'language_technology_old'); # skupine ##### NAVIGACIJA #### # profili mankjajočih vrednosti - define('MISSING_TYPE_SUMMARY', '0', true); - define('MISSING_TYPE_DESCRIPTOR', '1', true); - define('MISSING_TYPE_FREQUENCY', '2', true); - define('MISSING_TYPE_CROSSTAB', '3', true); + define('MISSING_TYPE_SUMMARY', '0'); + define('MISSING_TYPE_DESCRIPTOR', '1'); + define('MISSING_TYPE_FREQUENCY', '2'); + define('MISSING_TYPE_CROSSTAB', '3'); # za vnose ali analize in kreacijo datotek - define('EXPORT_FOLDER', 'admin/survey/SurveyData', true); - define('VALID_USER_LIMIT_STRING', ' AND u.last_status IN (5,6) ', true); - define('ALLOW_CREATE_LIMIT', 80, true); # prvih 100 userjev vedno spustimo skozi - define('AUTO_CREATE_LIMIT', 150, true); # Koliko je meja, ko ne prikazujemo progresbara, in avtomatsko skreiramo datoteko ON THE FLY - define('AUTO_CREATE_TIME_LIMIT', 10, true); # Na koliko sekund pustimo da se generira inkrementalno s progressbarom - define('AUTO_CREATE_PREVENT_LIMIT', 1000, true); # Koliko je meja, ko avtomatsko sploh ne generiramo datoteke s podatki - define('ONLY_VALID_LIMIT', 3000, true); # nad koliko respondentov lovimo samo ustrezne - define('MAX_USER_PER_LOOP', 250, true); - define('FILE_STATUS_OK', '1', true); # datoteka je ažurna - define('FILE_STATUS_OLD', '0', true); # datoteka je stara - define('FILE_STATUS_NO_FILE', '-1', true); # datoteka ne obstaja - define('FILE_STATUS_NO_DATA', '-2', true); # v bazi nipodatkov - define('FILE_STATUS_SRV_DELETED', '-3', true); # Anketa je bila izbrisana + define('EXPORT_FOLDER', 'admin/survey/SurveyData'); + define('VALID_USER_LIMIT_STRING', ' AND u.last_status IN (5,6) '); + define('ALLOW_CREATE_LIMIT', 80); # prvih 100 userjev vedno spustimo skozi + define('AUTO_CREATE_LIMIT', 150); # Koliko je meja, ko ne prikazujemo progresbara, in avtomatsko skreiramo datoteko ON THE FLY + define('AUTO_CREATE_TIME_LIMIT', 10); # Na koliko sekund pustimo da se generira inkrementalno s progressbarom + define('AUTO_CREATE_PREVENT_LIMIT', 1000); # Koliko je meja, ko avtomatsko sploh ne generiramo datoteke s podatki + define('ONLY_VALID_LIMIT', 3000); # nad koliko respondentov lovimo samo ustrezne + define('MAX_USER_PER_LOOP', 250); + define('FILE_STATUS_OK', '1'); # datoteka je ažurna + define('FILE_STATUS_OLD', '0'); # datoteka je stara + define('FILE_STATUS_NO_FILE', '-1'); # datoteka ne obstaja + define('FILE_STATUS_NO_DATA', '-2'); # v bazi nipodatkov + define('FILE_STATUS_SRV_DELETED', '-3'); # Anketa je bila izbrisana - define('INCREMENTAL_LOCK_TIMEOUT', 10, true); # po kolikem času tajmoutamo možnost ponovnega generiranja (10min) + define('INCREMENTAL_LOCK_TIMEOUT', 10); # po kolikem času tajmoutamo možnost ponovnega generiranja (10min) - define("SYSTEM_VARIABLES", serialize (array('geslo','email','telefon','ime','priimek','naziv','drugo','odnos')), true); + define("SYSTEM_VARIABLES", serialize (array('geslo','email','telefon','ime','priimek','naziv','drugo','odnos'))); # fiksna polja v tabeli s podatki (prvo je 0) # polja po vrsti : @@ -254,34 +254,34 @@ # - lurker (6) # - time insered (unix) (7) # - record_number (8) - define('USER_ID_FIELD', '$1', true); - define('RELEVANCE_FIELD', '$2', true); - define('EMAIL_FIELD', '$3', true); - define('STATUS_FIELD', '$4', true); - define('LURKER_FIELD', '$5', true); - define('TIME_FIELD', '$6', true); - define('MOD_REC_FIELD', '$7', true); - define('ITIME_FIELD', '$8', true); + define('USER_ID_FIELD', '$1'); + define('RELEVANCE_FIELD', '$2'); + define('EMAIL_FIELD', '$3'); + define('STATUS_FIELD', '$4'); + define('LURKER_FIELD', '$5'); + define('TIME_FIELD', '$6'); + define('MOD_REC_FIELD', '$7'); + define('ITIME_FIELD', '$8'); - define('SCP_DEFAULT_PROFILE', 1, true); - define('SSP_DEFAULT_PROFILE', 2, true); #ustrezni + define('SCP_DEFAULT_PROFILE', 1); + define('SSP_DEFAULT_PROFILE', 2); #ustrezni - define('PERMANENT_DATE', '2099-01-01', true); # Kateri datum velja kot datum trajne ankete + define('PERMANENT_DATE', '2099-01-01'); # Kateri datum velja kot datum trajne ankete # privzete nastavitve analiz - define('NUM_DIGIT_PERCENT', 0, true); # stevilo digitalnih mest za odstotek - define('NUM_DIGIT_AVERAGE', 1, true); # stevilo digitalnih mest za povprecje - define('NUM_DIGIT_DEVIATION', 2, true); # stevilo digitalnih mest za odklon - define('NUM_DIGIT_RESIDUAL', 3, true); # stevilo digitalnih mest za residuale - define('NUM_DIGIT_PERCENT_MAX', 6, true); # max stevilo digitalnih mest za odstotek - define('NUM_DIGIT_AVERAGE_MAX', 6, true); # max stevilo digitalnih mest za povprecje - define('NUM_DIGIT_DEVIATION_MAX', 6, true); # max stevilo digitalnih mest za odklon - define('NUM_DIGIT_RESIDUAL_MAX', 6, true); # max stevilo digitalnih mest za residual + define('NUM_DIGIT_PERCENT', 0); # stevilo digitalnih mest za odstotek + define('NUM_DIGIT_AVERAGE', 1); # stevilo digitalnih mest za povprecje + define('NUM_DIGIT_DEVIATION', 2); # stevilo digitalnih mest za odklon + define('NUM_DIGIT_RESIDUAL', 3); # stevilo digitalnih mest za residuale + define('NUM_DIGIT_PERCENT_MAX', 6); # max stevilo digitalnih mest za odstotek + define('NUM_DIGIT_AVERAGE_MAX', 6); # max stevilo digitalnih mest za povprecje + define('NUM_DIGIT_DEVIATION_MAX', 6); # max stevilo digitalnih mest za odklon + define('NUM_DIGIT_RESIDUAL_MAX', 6); # max stevilo digitalnih mest za residual - define('TEXT_ANSWER_LIMIT', 100, true); # max stevilo text odgovorov pri izvozih + define('TEXT_ANSWER_LIMIT', 100); # max stevilo text odgovorov pri izvozih - define('SURVEY_LIST_DATE_FORMAT', '%d.%m.%y', true); # max stevilo digitalnih mest za residual + define('SURVEY_LIST_DATE_FORMAT', '%d.%m.%y'); # max stevilo digitalnih mest za residual define('STP_DATE_FORMAT', 'd.m.Y'); # format v katerem operiramo v tem klasu define('STP_OUTPUT_DATE_FORMAT', 'Y-m-d'); # format v katerem vrne @@ -291,14 +291,14 @@ define('SDS_DEFAULT_PROFILE', 0); - define ('STR_OTHER_TEXT', '_text', true); - define ('STR_DLMT', "|", true); - define ('DAT_EXT', '.dat', true); - define ('TMP_EXT', '.tmp', true); - define ('PIPE_CHAR', "\x7C",true); - define ('STR_LESS_THEN', '\x3C', true); - define ('STR_GREATER_THEN', '\x3E', true); - define ('STR_EQUALS', '\x3D', true); + define ('STR_OTHER_TEXT', '_text'); + define ('STR_DLMT', "|"); + define ('DAT_EXT', '.dat'); + define ('TMP_EXT', '.tmp'); + define ('PIPE_CHAR', '\x7C'); + define ('STR_LESS_THEN', '\x3C'); + define ('STR_GREATER_THEN', '\x3E'); + define ('STR_EQUALS', '\x3D'); ?> \ No newline at end of file diff --git a/admin/survey/export/export_definitions.php b/admin/survey/export/export_definitions.php index 2c629e15c..eadbe1fe4 100644 --- a/admin/survey/export/export_definitions.php +++ b/admin/survey/export/export_definitions.php @@ -5,93 +5,93 @@ define('IS_WINDOWS', (DIRECTORY_SEPARATOR === '\\') ? TRUE : FALSE); define('IS_LINUX', (DIRECTORY_SEPARATOR === '\\') ? FALSE : TRUE); -define("M_ANALIZA_DESCRIPTOR", "descriptor", true); -define("M_ANALIZA_FREQUENCY", "frequency", true); -define("M_ANALIZA_CROSSTAB", "crosstabs", true); -define("M_ANALIZA_STATISTICS", "statistics", true); -define("M_ANALIZA_SUMS", "sums", true); +define("M_ANALIZA_DESCRIPTOR", "descriptor"); +define("M_ANALIZA_FREQUENCY", "frequency"); +define("M_ANALIZA_CROSSTAB", "crosstabs"); +define("M_ANALIZA_STATISTICS", "statistics"); +define("M_ANALIZA_SUMS", "sums"); /*PDF*/ -define("A_REPORT_VPRASALNIK_PDF", "vprasalnik_pdf", true); -define("A_REPORT_PDF_RESULTS","pdf_results",true); -define("A_REPORT_PDF_COMMENT","pdf_comment",true); +define("A_REPORT_VPRASALNIK_PDF", "vprasalnik_pdf"); +define("A_REPORT_PDF_RESULTS","pdf_results"); +define("A_REPORT_PDF_COMMENT","pdf_comment"); -define("M_REPORT_ANALIZA_PDF_FREKVENCA","frequency",true); -define("M_REPORT_ANALIZA_PDF_CROSSTAB_IZPIS","crosstabs_izpis",true); -define("M_REPORT_ANALIZA_PDF_MULTICROSSTAB_IZPIS","multicrosstabs_izpis",true); -define("M_REPORT_ANALIZA_PDF_MEAN_IZPIS","mean_izpis",true); -define("M_REPORT_ANALIZA_PDF_TTEST_IZPIS","ttest_izpis",true); -define("M_REPORT_ANALIZA_PDF_BREAK_IZPIS","break_izpis",true); -define("M_REPORT_ANALIZA_PDF_STAT","statistics",true); -define("M_REPORT_ANALIZA_PDF_CHARTS","charts",true); -define("M_REPORT_ANALIZA_PDF_SUMS","sums",true); -define("M_REPORT_ANALIZA_PDF_CREPORT","creport_pdf",true); +define("M_REPORT_ANALIZA_PDF_FREKVENCA","frequency"); +define("M_REPORT_ANALIZA_PDF_CROSSTAB_IZPIS","crosstabs_izpis"); +define("M_REPORT_ANALIZA_PDF_MULTICROSSTAB_IZPIS","multicrosstabs_izpis"); +define("M_REPORT_ANALIZA_PDF_MEAN_IZPIS","mean_izpis"); +define("M_REPORT_ANALIZA_PDF_TTEST_IZPIS","ttest_izpis"); +define("M_REPORT_ANALIZA_PDF_BREAK_IZPIS","break_izpis"); +define("M_REPORT_ANALIZA_PDF_STAT","statistics"); +define("M_REPORT_ANALIZA_PDF_CHARTS","charts"); +define("M_REPORT_ANALIZA_PDF_SUMS","sums"); +define("M_REPORT_ANALIZA_PDF_CREPORT","creport_pdf"); -define("A_REPORT_PDF_STATUS","status",true); -define("A_REPORT_PDF_EDITS_ANALYSIS","editsAnalysis",true); -define("A_REPORT_PDF_LIST","list_pdf",true); -define("M_REPORT_PDF_EVOLI","pdf_evoli",true); -define("M_REPORT_PDF_TEAMMETER","pdf_teammeter",true); -define("M_REPORT_PDF_MFDPS","pdf_mfpds",true); -define("M_REPORT_PDF_HEATMAP_IMAGE","heatmap_image_pdf",true); +define("A_REPORT_PDF_STATUS","status"); +define("A_REPORT_PDF_EDITS_ANALYSIS","editsAnalysis"); +define("A_REPORT_PDF_LIST","list_pdf"); +define("M_REPORT_PDF_EVOLI","pdf_evoli"); +define("M_REPORT_PDF_TEAMMETER","pdf_teammeter"); +define("M_REPORT_PDF_MFDPS","pdf_mfpds"); +define("M_REPORT_PDF_HEATMAP_IMAGE","heatmap_image_pdf"); -define("M_REPORT_HIERARHIJA_PDF_IZPIS", "hierarhija_pdf_izpis", true); +define("M_REPORT_HIERARHIJA_PDF_IZPIS", "hierarhija_pdf_izpis"); -define("A_GDPR_PDF_INDIVIDUAL", "pdf_gdpr_individual", true); -define("A_GDPR_PDF_ACTIVITY", "pdf_gdpr_activity", true); +define("A_GDPR_PDF_INDIVIDUAL", "pdf_gdpr_individual"); +define("A_GDPR_PDF_ACTIVITY", "pdf_gdpr_activity"); /*RTF*/ -define("A_REPORT_VPRASALNIK_RTF", "vprasalnik_rtf", true); -define("A_REPORT_RTF_RESULTS", "rtf_results", true); -define("A_REPORT_RTF_COMMENT","rtf_comment",true); +define("A_REPORT_VPRASALNIK_RTF", "vprasalnik_rtf"); +define("A_REPORT_RTF_RESULTS", "rtf_results"); +define("A_REPORT_RTF_COMMENT", "rtf_comment"); -define("M_REPORT_ANALIZA_RTF_FREKVENCA", "frequency_rtf", true); -define("M_REPORT_ANALIZA_RTF_CROSSTAB_IZPIS", "crosstabs_izpis_rtf", true); -define("M_REPORT_ANALIZA_RTF_MULTICROSSTAB_IZPIS", "multicrosstabs_izpis_rtf", true); -define("M_REPORT_ANALIZA_RTF_MEAN_IZPIS", "mean_izpis_rtf", true); -define("M_REPORT_ANALIZA_RTF_TTEST_IZPIS", "ttest_izpis_rtf", true); -define("M_REPORT_ANALIZA_RTF_BREAK_IZPIS", "break_izpis_rtf", true); -define("M_REPORT_ANALIZA_RTF_STAT", "statistics_rtf", true); -define("M_REPORT_ANALIZA_RTF_SUMS", "sums_rtf", true); -define("M_REPORT_ANALIZA_RTF_CHARTS", "charts_rtf", true); -define("M_REPORT_ANALIZA_RTF_CREPORT", "creport_rtf", true); +define("M_REPORT_ANALIZA_RTF_FREKVENCA", "frequency_rtf"); +define("M_REPORT_ANALIZA_RTF_CROSSTAB_IZPIS", "crosstabs_izpis_rtf"); +define("M_REPORT_ANALIZA_RTF_MULTICROSSTAB_IZPIS", "multicrosstabs_izpis_rtf"); +define("M_REPORT_ANALIZA_RTF_MEAN_IZPIS", "mean_izpis_rtf"); +define("M_REPORT_ANALIZA_RTF_TTEST_IZPIS", "ttest_izpis_rtf"); +define("M_REPORT_ANALIZA_RTF_BREAK_IZPIS", "break_izpis_rtf"); +define("M_REPORT_ANALIZA_RTF_STAT", "statistics_rtf"); +define("M_REPORT_ANALIZA_RTF_SUMS", "sums_rtf"); +define("M_REPORT_ANALIZA_RTF_CHARTS", "charts_rtf"); +define("M_REPORT_ANALIZA_RTF_CREPORT", "creport_rtf"); -define("A_REPORT_RTF_LIST", "list_rtf", true); -define("M_REPORT_ANALIZA_RTF_HEATMAP_IMAGE","heatmap_image_rtf",true); +define("A_REPORT_RTF_LIST", "list_rtf"); +define("M_REPORT_ANALIZA_RTF_HEATMAP_IMAGE","heatmap_image_rtf"); -define("A_GDPR_RTF_INDIVIDUAL", "rtf_gdpr_individual", true); -define("A_GDPR_RTF_ACTIVITY", "rtf_gdpr_activity", true); +define("A_GDPR_RTF_INDIVIDUAL", "rtf_gdpr_individual"); +define("A_GDPR_RTF_ACTIVITY", "rtf_gdpr_activity"); /*XLS*/ -define("M_REPORT_ANALIZA_XLS_STAT", "statistics_xls", true); -define("M_REPORT_ANALIZA_XLS_FREKVENCA", "frequency_xls", true); -define("M_REPORT_ANALIZA_XLS_CROSSTAB_IZPIS", "crosstabs_izpis_xls", true); -define("M_REPORT_ANALIZA_XLS_MULTICROSSTAB_IZPIS", "multicrosstabs_izpis_xls", true); -define("M_REPORT_ANALIZA_XLS_SUMS", "sums_xls", true); -define("M_REPORT_ANALIZA_XLS_MEAN_IZPIS", "mean_izpis_xls", true); -define("M_REPORT_ANALIZA_XLS_TTEST_IZPIS", "ttest_izpis_xls", true); -define("M_REPORT_ANALIZA_XLS_BREAK_IZPIS", "break_izpis_xls", true); +define("M_REPORT_ANALIZA_XLS_STAT", "statistics_xls"); +define("M_REPORT_ANALIZA_XLS_FREKVENCA", "frequency_xls"); +define("M_REPORT_ANALIZA_XLS_CROSSTAB_IZPIS", "crosstabs_izpis_xls"); +define("M_REPORT_ANALIZA_XLS_MULTICROSSTAB_IZPIS", "multicrosstabs_izpis_xls"); +define("M_REPORT_ANALIZA_XLS_SUMS", "sums_xls"); +define("M_REPORT_ANALIZA_XLS_MEAN_IZPIS", "mean_izpis_xls"); +define("M_REPORT_ANALIZA_XLS_TTEST_IZPIS", "ttest_izpis_xls"); +define("M_REPORT_ANALIZA_XLS_BREAK_IZPIS", "break_izpis_xls"); -define("A_REPORT_XLS_LIST", "list_xls", true); -define("A_REPORT_XLS_USABLE", "usable_xls", true); -define("A_REPORT_XLS_SPEEDER", "speeder_xls", true); -define("A_REPORT_XLS_TEXT_ANALYSIS", "text_analysis_xls", true); -define("A_REPORT_CSV_TEXT_ANALYSIS", "text_analysis_csv", true); -define("A_LANGUAGE_TECHNOLOGY_XLS", "lt_excel", true); +define("A_REPORT_XLS_LIST", "list_xls"); +define("A_REPORT_XLS_USABLE", "usable_xls"); +define("A_REPORT_XLS_SPEEDER", "speeder_xls"); +define("A_REPORT_XLS_TEXT_ANALYSIS", "text_analysis_xls"); +define("A_REPORT_CSV_TEXT_ANALYSIS", "text_analysis_csv"); +define("A_LANGUAGE_TECHNOLOGY_XLS", "lt_excel"); /*PPT*/ -define("M_REPORT_ANALIZA_PPT_CHARTS", "charts_ppt", true); -define("M_REPORT_ANALIZA_PPT_HEATMAP_IMAGE","heatmap_image_ppt",true); +define("M_REPORT_ANALIZA_PPT_CHARTS", "charts_ppt"); +define("M_REPORT_ANALIZA_PPT_HEATMAP_IMAGE", "heatmap_image_ppt"); /*IMAGE*/ -define("M_REPORT_ANALIZA_HEATMAP_IMAGE", "heatmap_image", true); +define("M_REPORT_ANALIZA_HEATMAP_IMAGE", "heatmap_image"); /*XML*/ -define("A_REPORT_VPRASALNIK_XML", "vprasalnik_xml", true); +define("A_REPORT_VPRASALNIK_XML", "vprasalnik_xml"); ?> \ No newline at end of file diff --git a/admin/survey/export/latexclasses/Analize/AnalizaBreak.php b/admin/survey/export/latexclasses/Analize/AnalizaBreak.php index 6b8bcbbea..b8c23b480 100644 --- a/admin/survey/export/latexclasses/Analize/AnalizaBreak.php +++ b/admin/survey/export/latexclasses/Analize/AnalizaBreak.php @@ -4,33 +4,32 @@ include_once('../../function.php'); include_once('../survey/definition.php'); -/* include_once('../exportclases/class.pdfIzvozAnalizaFunctions.php'); - require_once('../exportclases/class.enka.pdf.php'); */ + define("ALLOW_HIDE_ZERRO_REGULAR", false); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za navadne odgovore define("ALLOW_HIDE_ZERRO_MISSING", true); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za missinge - define("NUM_DIGIT_AVERAGE", 2, true); // stevilo digitalnih mest za povprecje - define("NUM_DIGIT_DEVIATION", 2, true); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_AVERAGE", 2); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_DEVIATION", 2); // stevilo digitalnih mest za povprecje - define("M_ANALIZA_DESCRIPTOR", "descriptor", true); - define("M_ANALIZA_FREQUENCY", "frequency", true); + define("M_ANALIZA_DESCRIPTOR", "descriptor"); + define("M_ANALIZA_FREQUENCY", "frequency"); - define("FNT_FREESERIF", "freeserif", true); - define("FNT_FREESANS", "freesans", true); - define("FNT_HELVETICA", "helvetica", true); + define("FNT_FREESERIF", "freeserif"); + define("FNT_FREESANS", "freesans"); + define("FNT_HELVETICA", "helvetica"); - define("FNT_MAIN_TEXT", FNT_FREESANS, true); - define("FNT_QUESTION_TEXT", FNT_FREESANS, true); - define("FNT_HEADER_TEXT", FNT_FREESANS, true); + define("FNT_MAIN_TEXT", FNT_FREESANS); + define("FNT_QUESTION_TEXT", FNT_FREESANS); + define("FNT_HEADER_TEXT", FNT_FREESANS); - define("FNT_MAIN_SIZE", 10, true); - define("FNT_QUESTION_SIZE", 9, true); - define("FNT_HEADER_SIZE", 10, true); + define("FNT_MAIN_SIZE", 10); + define("FNT_QUESTION_SIZE", 9); + define("FNT_HEADER_SIZE", 10); - define("RADIO_BTN_SIZE", 3, true); - define("CHCK_BTN_SIZE", 3, true); - define("LINE_BREAK", 6, true); + define("RADIO_BTN_SIZE", 3); + define("CHCK_BTN_SIZE", 3); + define("LINE_BREAK", 6); define ('PDF_MARGIN_HEADER', 8); define ('PDF_MARGIN_FOOTER', 12); diff --git a/admin/survey/export/latexclasses/Analize/AnalizaCReport.php b/admin/survey/export/latexclasses/Analize/AnalizaCReport.php index 47da9e740..6e0ca2310 100644 --- a/admin/survey/export/latexclasses/Analize/AnalizaCReport.php +++ b/admin/survey/export/latexclasses/Analize/AnalizaCReport.php @@ -10,27 +10,27 @@ define("ALLOW_HIDE_ZERRO_REGULAR", false); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za navadne odgovore define("ALLOW_HIDE_ZERRO_MISSING", true); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za missinge - define("NUM_DIGIT_AVERAGE", 2, true); // stevilo digitalnih mest za povprecje - define("NUM_DIGIT_DEVIATION", 2, true); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_AVERAGE", 2); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_DEVIATION", 2); // stevilo digitalnih mest za povprecje - define("M_ANALIZA_DESCRIPTOR", "descriptor", true); - define("M_ANALIZA_FREQUENCY", "frequency", true); + define("M_ANALIZA_DESCRIPTOR", "descriptor"); + define("M_ANALIZA_FREQUENCY", "frequency"); - define("FNT_FREESERIF", "freeserif", true); - define("FNT_FREESANS", "freesans", true); - define("FNT_HELVETICA", "helvetica", true); + define("FNT_FREESERIF", "freeserif"); + define("FNT_FREESANS", "freesans"); + define("FNT_HELVETICA", "helvetica"); - define("FNT_MAIN_TEXT", FNT_FREESANS, true); - define("FNT_QUESTION_TEXT", FNT_FREESANS, true); - define("FNT_HEADER_TEXT", FNT_FREESANS, true); + define("FNT_MAIN_TEXT", FNT_FREESANS); + define("FNT_QUESTION_TEXT", FNT_FREESANS); + define("FNT_HEADER_TEXT", FNT_FREESANS); - define("FNT_MAIN_SIZE", 10, true); - define("FNT_QUESTION_SIZE", 9, true); - define("FNT_HEADER_SIZE", 10, true); + define("FNT_MAIN_SIZE", 10); + define("FNT_QUESTION_SIZE", 9); + define("FNT_HEADER_SIZE", 10); - define("RADIO_BTN_SIZE", 3, true); - define("CHCK_BTN_SIZE", 3, true); - define("LINE_BREAK", 6, true); + define("RADIO_BTN_SIZE", 3); + define("CHCK_BTN_SIZE", 3); + define("LINE_BREAK", 6); define ('PDF_MARGIN_HEADER', 8); define ('PDF_MARGIN_FOOTER', 12); @@ -1105,14 +1105,6 @@ class AnalizaCReport extends LatexAnalysisElement{ //TODO: Potrebno je v LATEX določiti ali je stran obrnjena landscape $width = $this->landscapeTest() ? 270 : 165; - //$this->pdf->ln(15); - - //$this->pdf->setFont('','b','7'); - //$this->pdf->MultiCell($width, 1, $this->encodeText($title . $subtitle), 0, 'C', 0, 1, 0 ,0, true); - /*$this->pdf->setFont('','','7'); - $this->pdf->MultiCell($width, 1, $subtitle, 0, 'C', 0, 1, 0 ,0, true);*/ - - //$this->pdf->ln(5); $boldedTitle = $this->returnBold($this->encodeText($this->encodeText($title . $subtitle))); $texTitle .= $this->returnCentered($boldedTitle); diff --git a/admin/survey/export/latexclasses/Analize/AnalizaCharts.php b/admin/survey/export/latexclasses/Analize/AnalizaCharts.php index 62c436992..0a6e41e77 100644 --- a/admin/survey/export/latexclasses/Analize/AnalizaCharts.php +++ b/admin/survey/export/latexclasses/Analize/AnalizaCharts.php @@ -12,27 +12,27 @@ define("ALLOW_HIDE_ZERRO_REGULAR", false); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za navadne odgovore define("ALLOW_HIDE_ZERRO_MISSING", true); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za missinge - define("NUM_DIGIT_AVERAGE", 2, true); // stevilo digitalnih mest za povprecje - define("NUM_DIGIT_DEVIATION", 2, true); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_AVERAGE", 2); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_DEVIATION", 2); // stevilo digitalnih mest za povprecje - define("M_ANALIZA_DESCRIPTOR", "descriptor", true); - define("M_ANALIZA_FREQUENCY", "frequency", true); + define("M_ANALIZA_DESCRIPTOR", "descriptor"); + define("M_ANALIZA_FREQUENCY", "frequency"); - define("FNT_FREESERIF", "freeserif", true); - define("FNT_FREESANS", "freesans", true); - define("FNT_HELVETICA", "helvetica", true); + define("FNT_FREESERIF", "freeserif"); + define("FNT_FREESANS", "freesans"); + define("FNT_HELVETICA", "helvetica"); - define("FNT_MAIN_TEXT", FNT_FREESANS, true); - define("FNT_QUESTION_TEXT", FNT_FREESANS, true); - define("FNT_HEADER_TEXT", FNT_FREESANS, true); + define("FNT_MAIN_TEXT", FNT_FREESANS); + define("FNT_QUESTION_TEXT", FNT_FREESANS); + define("FNT_HEADER_TEXT", FNT_FREESANS); - define("FNT_MAIN_SIZE", 10, true); - define("FNT_QUESTION_SIZE", 9, true); - define("FNT_HEADER_SIZE", 10, true); + define("FNT_MAIN_SIZE", 10); + define("FNT_QUESTION_SIZE", 9); + define("FNT_HEADER_SIZE", 10); - define("RADIO_BTN_SIZE", 3, true); - define("CHCK_BTN_SIZE", 3, true); - define("LINE_BREAK", 6, true); + define("RADIO_BTN_SIZE", 3); + define("CHCK_BTN_SIZE", 3); + define("LINE_BREAK", 6); define ('PDF_MARGIN_HEADER', 8); define ('PDF_MARGIN_FOOTER', 12); diff --git a/admin/survey/export/latexclasses/Analize/AnalizaCrosstab.php b/admin/survey/export/latexclasses/Analize/AnalizaCrosstab.php index 78140a712..01e1932e0 100644 --- a/admin/survey/export/latexclasses/Analize/AnalizaCrosstab.php +++ b/admin/survey/export/latexclasses/Analize/AnalizaCrosstab.php @@ -11,27 +11,27 @@ define("ALLOW_HIDE_ZERRO_REGULAR", false); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za navadne odgovore define("ALLOW_HIDE_ZERRO_MISSING", true); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za missinge - define("NUM_DIGIT_AVERAGE", 2, true); // stevilo digitalnih mest za povprecje - define("NUM_DIGIT_DEVIATION", 2, true); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_AVERAGE", 2); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_DEVIATION", 2); // stevilo digitalnih mest za povprecje - define("M_ANALIZA_DESCRIPTOR", "descriptor", true); - define("M_ANALIZA_FREQUENCY", "frequency", true); + define("M_ANALIZA_DESCRIPTOR", "descriptor"); + define("M_ANALIZA_FREQUENCY", "frequency"); - define("FNT_FREESERIF", "freeserif", true); - define("FNT_FREESANS", "freesans", true); - define("FNT_HELVETICA", "helvetica", true); + define("FNT_FREESERIF", "freeserif"); + define("FNT_FREESANS", "freesans"); + define("FNT_HELVETICA", "helvetica"); - define("FNT_MAIN_TEXT", FNT_FREESANS, true); - define("FNT_QUESTION_TEXT", FNT_FREESANS, true); - define("FNT_HEADER_TEXT", FNT_FREESANS, true); + define("FNT_MAIN_TEXT", FNT_FREESANS); + define("FNT_QUESTION_TEXT", FNT_FREESANS); + define("FNT_HEADER_TEXT", FNT_FREESANS); - define("FNT_MAIN_SIZE", 10, true); - define("FNT_QUESTION_SIZE", 9, true); - define("FNT_HEADER_SIZE", 10, true); + define("FNT_MAIN_SIZE", 10); + define("FNT_QUESTION_SIZE", 9); + define("FNT_HEADER_SIZE", 10); - define("RADIO_BTN_SIZE", 3, true); - define("CHCK_BTN_SIZE", 3, true); - define("LINE_BREAK", 6, true); + define("RADIO_BTN_SIZE", 3); + define("CHCK_BTN_SIZE", 3); + define("LINE_BREAK", 6); define ('PDF_MARGIN_HEADER', 8); define ('PDF_MARGIN_FOOTER', 12); @@ -179,86 +179,7 @@ class AnalizaCrosstab extends LatexAnalysisElement{ //set image scale factor $this->pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); return true; - } - - -/* function createPdf() - { - global $site_path; - global $lang; - global $global_user_id; - - // izpisemo prvo stran - //$this->createFrontPage(); - - $this->pdf->AddPage(); - - $this->pdf->setFont('','B','11'); - $this->pdf->MultiCell(150, 5, $lang['export_analisys_sums'], 0, 'L', 0, 1, 0 ,0, true); - $this->pdf->ln(5); - - $this->pdf->SetDrawColor(128, 128, 128); - $this->pdf->setFont('','','6'); - - # preberemo header - if ($this->dataFileStatus == FILE_STATUS_NO_DATA || $this->dataFileStatus == FILE_STATUS_NO_FILE || $this->dataFileStatus == FILE_STATUS_SRV_DELETED) { - - $this->pdf->MultiCell(150, 5, 'NAPAKA!!! Manjkajo datoteke s podatki.', 0, 'L', 0, 1, 0 ,0, true); - - } else { - - //polovimo podatke o nastavitvah trenutnega profila (missingi..) - SurveyAnalysis::$missingProfileData = SurveyMissingProfiles::getProfile(SurveyAnalysis::$currentMissingProfile); - - - // Preverimo ce imamo zanke (po skupinah) - SurveyAnalysis::$_LOOPS = SurveyZankaProfiles::getFiltersForLoops(); - - # če nimamo zank - if(count(SurveyAnalysis::$_LOOPS) == 0){ - - $this->displayTables(); - } - else{ - // izrisemo samo eno tabelo iz enega loopa - if($this->current_loop > 0){ - - $loop = SurveyAnalysis::$_LOOPS[(int)$this->current_loop-1]; - $loop['cnt'] = $this->current_loop; - SurveyAnalysis::$_CURRENT_LOOP = $loop; - - // Izpisemo naslov zanke za skupino - $this->pdf->setFont('','B','10'); - $this->pdf->ln(5); - $this->pdf->MultiCell(200, 5, $this->encodeText($lang['srv_zanka_note'].$loop['text']), 0, 'L', 0, 1, 0 ,0, true); - $this->pdf->setFont('','','6'); - - $this->displayTables(); - } - // Izrisemo vse tabele spremenljivka (iz vseh loopov) - else{ - $loop_cnt = 0; - # če mamo zanke - foreach(SurveyAnalysis::$_LOOPS AS $loop) { - $loop_cnt++; - $loop['cnt'] = $loop_cnt; - SurveyAnalysis::$_CURRENT_LOOP = $loop; - - // Izpisemo naslov zanke za skupino - $this->pdf->setFont('','B','10'); - $this->pdf->ln(5); - $this->pdf->MultiCell(200, 5, $this->encodeText($lang['srv_zanka_note'].$loop['text']), 0, 'L', 0, 1, 0 ,0, true); - $this->pdf->setFont('','','6'); - - $this->displayTables(); - } - } - } - - } // end if else ($_headFileName == null) - - } */ - + } public function showCrosstabsTable($crosstabClass=null, $export_format='', $creport=false) { global $lang; diff --git a/admin/survey/export/latexclasses/Analize/AnalizaDesc.php b/admin/survey/export/latexclasses/Analize/AnalizaDesc.php index 2548fba14..a2252e108 100644 --- a/admin/survey/export/latexclasses/Analize/AnalizaDesc.php +++ b/admin/survey/export/latexclasses/Analize/AnalizaDesc.php @@ -11,27 +11,27 @@ define("ALLOW_HIDE_ZERRO_REGULAR", false); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za navadne odgovore define("ALLOW_HIDE_ZERRO_MISSING", true); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za missinge - define("NUM_DIGIT_AVERAGE", 2, true); // stevilo digitalnih mest za povprecje - define("NUM_DIGIT_DEVIATION", 2, true); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_AVERAGE", 2); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_DEVIATION", 2); // stevilo digitalnih mest za povprecje - define("M_ANALIZA_DESCRIPTOR", "descriptor", true); - define("M_ANALIZA_FREQUENCY", "frequency", true); + define("M_ANALIZA_DESCRIPTOR", "descriptor"); + define("M_ANALIZA_FREQUENCY", "frequency"); - define("FNT_FREESERIF", "freeserif", true); - define("FNT_FREESANS", "freesans", true); - define("FNT_HELVETICA", "helvetica", true); + define("FNT_FREESERIF", "freeserif"); + define("FNT_FREESANS", "freesans"); + define("FNT_HELVETICA", "helvetica"); - define("FNT_MAIN_TEXT", FNT_FREESANS, true); - define("FNT_QUESTION_TEXT", FNT_FREESANS, true); - define("FNT_HEADER_TEXT", FNT_FREESANS, true); + define("FNT_MAIN_TEXT", FNT_FREESANS); + define("FNT_QUESTION_TEXT", FNT_FREESANS); + define("FNT_HEADER_TEXT", FNT_FREESANS); - define("FNT_MAIN_SIZE", 10, true); - define("FNT_QUESTION_SIZE", 9, true); - define("FNT_HEADER_SIZE", 10, true); + define("FNT_MAIN_SIZE", 10); + define("FNT_QUESTION_SIZE", 9); + define("FNT_HEADER_SIZE", 10); - define("RADIO_BTN_SIZE", 3, true); - define("CHCK_BTN_SIZE", 3, true); - define("LINE_BREAK", 6, true); + define("RADIO_BTN_SIZE", 3); + define("CHCK_BTN_SIZE", 3); + define("LINE_BREAK", 6); define ('PDF_MARGIN_HEADER', 8); define ('PDF_MARGIN_FOOTER', 12); diff --git a/admin/survey/export/latexclasses/Analize/AnalizaFreq.php b/admin/survey/export/latexclasses/Analize/AnalizaFreq.php index 3a333ed59..24b1f8324 100644 --- a/admin/survey/export/latexclasses/Analize/AnalizaFreq.php +++ b/admin/survey/export/latexclasses/Analize/AnalizaFreq.php @@ -11,27 +11,27 @@ define("ALLOW_HIDE_ZERRO_REGULAR", false); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za navadne odgovore define("ALLOW_HIDE_ZERRO_MISSING", true); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za missinge - define("NUM_DIGIT_AVERAGE", 2, true); // stevilo digitalnih mest za povprecje - define("NUM_DIGIT_DEVIATION", 2, true); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_AVERAGE", 2); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_DEVIATION", 2); // stevilo digitalnih mest za povprecje - define("M_ANALIZA_DESCRIPTOR", "descriptor", true); - define("M_ANALIZA_FREQUENCY", "frequency", true); + define("M_ANALIZA_DESCRIPTOR", "descriptor"); + define("M_ANALIZA_FREQUENCY", "frequency"); - define("FNT_FREESERIF", "freeserif", true); - define("FNT_FREESANS", "freesans", true); - define("FNT_HELVETICA", "helvetica", true); + define("FNT_FREESERIF", "freeserif"); + define("FNT_FREESANS", "freesans"); + define("FNT_HELVETICA", "helvetica"); - define("FNT_MAIN_TEXT", FNT_FREESANS, true); - define("FNT_QUESTION_TEXT", FNT_FREESANS, true); - define("FNT_HEADER_TEXT", FNT_FREESANS, true); + define("FNT_MAIN_TEXT", FNT_FREESANS); + define("FNT_QUESTION_TEXT", FNT_FREESANS); + define("FNT_HEADER_TEXT", FNT_FREESANS); - define("FNT_MAIN_SIZE", 10, true); - define("FNT_QUESTION_SIZE", 9, true); - define("FNT_HEADER_SIZE", 10, true); + define("FNT_MAIN_SIZE", 10); + define("FNT_QUESTION_SIZE", 9); + define("FNT_HEADER_SIZE", 10); - define("RADIO_BTN_SIZE", 3, true); - define("CHCK_BTN_SIZE", 3, true); - define("LINE_BREAK", 6, true); + define("RADIO_BTN_SIZE", 3); + define("CHCK_BTN_SIZE", 3); + define("LINE_BREAK", 6); define ('PDF_MARGIN_HEADER', 8); define ('PDF_MARGIN_FOOTER', 12); diff --git a/admin/survey/export/latexclasses/Analize/AnalizaMean.php b/admin/survey/export/latexclasses/Analize/AnalizaMean.php index 0e896739e..3dc136e25 100644 --- a/admin/survey/export/latexclasses/Analize/AnalizaMean.php +++ b/admin/survey/export/latexclasses/Analize/AnalizaMean.php @@ -10,27 +10,27 @@ define("ALLOW_HIDE_ZERRO_REGULAR", false); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za navadne odgovore define("ALLOW_HIDE_ZERRO_MISSING", true); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za missinge - define("NUM_DIGIT_AVERAGE", 2, true); // stevilo digitalnih mest za povprecje - define("NUM_DIGIT_DEVIATION", 2, true); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_AVERAGE", 2); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_DEVIATION", 2); // stevilo digitalnih mest za povprecje - define("M_ANALIZA_DESCRIPTOR", "descriptor", true); - define("M_ANALIZA_FREQUENCY", "frequency", true); + define("M_ANALIZA_DESCRIPTOR", "descriptor"); + define("M_ANALIZA_FREQUENCY", "frequency"); - define("FNT_FREESERIF", "freeserif", true); - define("FNT_FREESANS", "freesans", true); - define("FNT_HELVETICA", "helvetica", true); + define("FNT_FREESERIF", "freeserif"); + define("FNT_FREESANS", "freesans"); + define("FNT_HELVETICA", "helvetica"); - define("FNT_MAIN_TEXT", FNT_FREESANS, true); - define("FNT_QUESTION_TEXT", FNT_FREESANS, true); - define("FNT_HEADER_TEXT", FNT_FREESANS, true); + define("FNT_MAIN_TEXT", FNT_FREESANS); + define("FNT_QUESTION_TEXT", FNT_FREESANS); + define("FNT_HEADER_TEXT", FNT_FREESANS); - define("FNT_MAIN_SIZE", 10, true); - define("FNT_QUESTION_SIZE", 9, true); - define("FNT_HEADER_SIZE", 10, true); + define("FNT_MAIN_SIZE", 10); + define("FNT_QUESTION_SIZE", 9); + define("FNT_HEADER_SIZE", 10); - define("RADIO_BTN_SIZE", 3, true); - define("CHCK_BTN_SIZE", 3, true); - define("LINE_BREAK", 6, true); + define("RADIO_BTN_SIZE", 3); + define("CHCK_BTN_SIZE", 3); + define("LINE_BREAK", 6); define ('PDF_MARGIN_HEADER', 8); define ('PDF_MARGIN_FOOTER', 12); diff --git a/admin/survey/export/latexclasses/Analize/AnalizaMultiCrosstab.php b/admin/survey/export/latexclasses/Analize/AnalizaMultiCrosstab.php index ec614f514..156a3c2c0 100644 --- a/admin/survey/export/latexclasses/Analize/AnalizaMultiCrosstab.php +++ b/admin/survey/export/latexclasses/Analize/AnalizaMultiCrosstab.php @@ -10,27 +10,27 @@ define("ALLOW_HIDE_ZERRO_REGULAR", false); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za navadne odgovore define("ALLOW_HIDE_ZERRO_MISSING", true); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za missinge - define("NUM_DIGIT_AVERAGE", 2, true); // stevilo digitalnih mest za povprecje - define("NUM_DIGIT_DEVIATION", 2, true); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_AVERAGE", 2); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_DEVIATION", 2); // stevilo digitalnih mest za povprecje - define("M_ANALIZA_DESCRIPTOR", "descriptor", true); - define("M_ANALIZA_FREQUENCY", "frequency", true); + define("M_ANALIZA_DESCRIPTOR", "descriptor"); + define("M_ANALIZA_FREQUENCY", "frequency"); - define("FNT_FREESERIF", "freeserif", true); - define("FNT_FREESANS", "freesans", true); - define("FNT_HELVETICA", "helvetica", true); + define("FNT_FREESERIF", "freeserif"); + define("FNT_FREESANS", "freesans"); + define("FNT_HELVETICA", "helvetica"); - define("FNT_MAIN_TEXT", FNT_FREESANS, true); - define("FNT_QUESTION_TEXT", FNT_FREESANS, true); - define("FNT_HEADER_TEXT", FNT_FREESANS, true); + define("FNT_MAIN_TEXT", FNT_FREESANS); + define("FNT_QUESTION_TEXT", FNT_FREESANS); + define("FNT_HEADER_TEXT", FNT_FREESANS); - define("FNT_MAIN_SIZE", 10, true); - define("FNT_QUESTION_SIZE", 9, true); - define("FNT_HEADER_SIZE", 10, true); + define("FNT_MAIN_SIZE", 10); + define("FNT_QUESTION_SIZE", 9); + define("FNT_HEADER_SIZE", 10); - define("RADIO_BTN_SIZE", 3, true); - define("CHCK_BTN_SIZE", 3, true); - define("LINE_BREAK", 6, true); + define("RADIO_BTN_SIZE", 3); + define("CHCK_BTN_SIZE", 3); + define("LINE_BREAK", 6); define ('PDF_MARGIN_HEADER', 8); define ('PDF_MARGIN_FOOTER', 12); @@ -130,74 +130,6 @@ class AnalizaMultiCrosstab extends LatexAnalysisElement { $this->pdf->Output($fileName, 'I'); } - -/* function init(){ - global $lang; - - // array used to define the language and charset of the pdf file to be generated - $language_meta = Array(); - $language_meta['a_meta_charset'] = 'UTF-8'; - $language_meta['a_meta_dir'] = 'ltr'; - $language_meta['a_meta_language'] = 'sl'; - $language_meta['w_page'] = $lang['page']; - - //set some language-dependent strings - $this->pdf->setLanguageArray($language_meta); - - //set margins - $this->pdf->setPrintHeaderFirstPage(true); - $this->pdf->setPrintFooterFirstPage(true); - $this->pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT); - $this->pdf->SetHeaderMargin(PDF_MARGIN_HEADER); - $this->pdf->SetFooterMargin(PDF_MARGIN_FOOTER); - - // set header and footer fonts - $this->pdf->setHeaderFont(Array(FNT_HEADER_TEXT, "I", FNT_HEADER_SIZE)); - $this->pdf->setFooterFont(Array(FNT_HEADER_TEXT, 'I', FNT_HEADER_SIZE)); - - - // set document information - $this->pdf->SetAuthor('An Order Form'); - $this->pdf->SetTitle('An Order'); - $this->pdf->SetSubject('An Order'); - - // set default header data - $this->pdf->SetHeaderData(null, null, "www.1ka.si", $this->encodeText(SurveyInfo::getInstance()->getSurveyAkronim())); - - //set auto page breaks - $this->pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM); - - $this->pdf->SetFont(FNT_MAIN_TEXT, '', FNT_MAIN_SIZE); - //set image scale factor - $this->pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); - - return true; - } */ - - -/* function createPdf(){ - global $site_path; - global $lang; - - $this->pdf->AddPage(); - - $this->pdf->setFont('','B','11'); - $this->pdf->MultiCell(150, 5, $lang['srv_multicrosstabs'], 0, 'L', 0, 1, 0 ,0, true); - $this->pdf->ln(5); - - $this->pdf->setDrawColor(128, 128, 128); - $this->pdf->setFont('','','6'); - - // Napolnimo variable s katerimi lahko operiramo - $this->multiCrosstabClass->getVariableList(); - - // Izris tabele - $this->displayTable(); - - // Izris legende - $this->displayLegend(); - } */ - public function displayTable($multiCrosstabClass=null, $export_format=''){ global $site_path; global $lang; diff --git a/admin/survey/export/latexclasses/Analize/AnalizaSums.php b/admin/survey/export/latexclasses/Analize/AnalizaSums.php index f81860375..2a6225f59 100644 --- a/admin/survey/export/latexclasses/Analize/AnalizaSums.php +++ b/admin/survey/export/latexclasses/Analize/AnalizaSums.php @@ -11,27 +11,27 @@ define("ALLOW_HIDE_ZERRO_REGULAR", false); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za navadne odgovore define("ALLOW_HIDE_ZERRO_MISSING", true); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za missinge - define("NUM_DIGIT_AVERAGE", 2, true); // stevilo digitalnih mest za povprecje - define("NUM_DIGIT_DEVIATION", 2, true); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_AVERAGE", 2); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_DEVIATION", 2); // stevilo digitalnih mest za povprecje - define("M_ANALIZA_DESCRIPTOR", "descriptor", true); - define("M_ANALIZA_FREQUENCY", "frequency", true); + define("M_ANALIZA_DESCRIPTOR", "descriptor"); + define("M_ANALIZA_FREQUENCY", "frequency"); - define("FNT_FREESERIF", "freeserif", true); - define("FNT_FREESANS", "freesans", true); - define("FNT_HELVETICA", "helvetica", true); + define("FNT_FREESERIF", "freeserif"); + define("FNT_FREESANS", "freesans"); + define("FNT_HELVETICA", "helvetica"); - define("FNT_MAIN_TEXT", FNT_FREESANS, true); - define("FNT_QUESTION_TEXT", FNT_FREESANS, true); - define("FNT_HEADER_TEXT", FNT_FREESANS, true); + define("FNT_MAIN_TEXT", FNT_FREESANS); + define("FNT_QUESTION_TEXT", FNT_FREESANS); + define("FNT_HEADER_TEXT", FNT_FREESANS); - define("FNT_MAIN_SIZE", 10, true); - define("FNT_QUESTION_SIZE", 9, true); - define("FNT_HEADER_SIZE", 10, true); + define("FNT_MAIN_SIZE", 10); + define("FNT_QUESTION_SIZE", 9); + define("FNT_HEADER_SIZE", 10); - define("RADIO_BTN_SIZE", 3, true); - define("CHCK_BTN_SIZE", 3, true); - define("LINE_BREAK", 6, true); + define("RADIO_BTN_SIZE", 3); + define("CHCK_BTN_SIZE", 3); + define("LINE_BREAK", 6); define ('PDF_MARGIN_HEADER', 8); define ('PDF_MARGIN_FOOTER', 12); @@ -557,40 +557,25 @@ class AnalizaSums extends LatexAnalysisElement{ //zacetek latex tabele z obrobo za prvo tabelo - konec //prva vrstica - //$tex .= $this->encodeText($spremenljivka['variable'])." & \multicolumn{8}{l|}{".$this->encodeText($spremenljivka['naslov'])."} ".$this->texNewLine; - //$tex .= $this->encodeText($spremenljivka['variable'])." & \multicolumn{8}{X|}{".$this->encodeText($spremenljivka['naslov'])."} ".$this->texNewLine; $dolzinaVprasanja = strlen($this->encodeText($spremenljivka['naslov'])); - //echo $dolzinaVprasanja."
    "; - if($dolzinaVprasanja > MEJA_DOLZINA_VPRASANJA){ //ce je dolzina vprasanja daljsa od ene vrstice v tabeli + + if($dolzinaVprasanja > MEJA_DOLZINA_VPRASANJA){ //ce je dolzina vprasanja daljsa od ene vrstice v tabeli $tex .= $this->encodeText($spremenljivka['variable'])." & \multicolumn{8}{X|}{".$this->encodeText($spremenljivka['naslov'])."} ".$this->texNewLine; - }else{ + } + else{ $tex .= $this->encodeText($spremenljivka['variable'])." & \multicolumn{8}{l|}{".$this->encodeText($spremenljivka['naslov'])."} ".$this->texNewLine; } - - //$variableTex = $this->encodeText($spremenljivka['variable']); - //$naslovTex = $this->encodeText($spremenljivka['naslov']); - //$tex .= $variableTex.' & \multicolumn{8}{>{\hsize=\dimexpr 9\hsize + 9\tabcolsep + \arrayrulewidth}X|}{'.$naslovTex.'} '.$this->texNewLine; + if($export_format != 'xls'){ $tex .= $this->horizontalLineTex; /*obroba*/ } - - -/* $this->pdf->setFont('','b','6'); - $this->pdf->ln(5); - $this->pdf->MultiCell(18, 5, $this->encodeText($spremenljivka['variable']), 1, 'C', 0, 0, 0 ,0, true); - $this->pdf->MultiCell(162, 5, $this->encodeText($spremenljivka['naslov']), 1, 'L', 0, 1, 0 ,0, true); */ - + //druga vrstica $tex .= " & ".$this->encodeText($lang['srv_analiza_opisne_subquestion1'])." & \multicolumn{5}{c|}{".$this->encodeText($lang['srv_analiza_opisne_units'])."} & \multicolumn{2}{c|}{".$this->encodeText($lang['srv_analiza_opisne_arguments'])."} ".$this->texNewLine; if($export_format != 'xls'){ $tex .= $this->horizontalLineTex; /*obroba*/ } -/* $this->pdf->MultiCell(18, 5, $this->encodeText(''), 1, 'L', 0, 0, 0 ,0, true); - $this->pdf->MultiCell(50, 5, $this->encodeText($lang['srv_analiza_opisne_subquestion']), 1, 'C', 0, 0, 0 ,0, true); - $this->pdf->MultiCell(80, 5, $this->encodeText($lang['srv_analiza_opisne_units']), 1, 'C', 0, 0, 0 ,0, true); - $this->pdf->MultiCell(32, 5, $this->encodeText($lang['srv_analiza_opisne_arguments']), 1, 'C', 0, 1, 0 ,0, true); */ - //tretja vrstica $text = array(); $text[] = ''; diff --git a/admin/survey/export/latexclasses/Analize/AnalizaTTest.php b/admin/survey/export/latexclasses/Analize/AnalizaTTest.php index 539fd225d..ff17dc420 100644 --- a/admin/survey/export/latexclasses/Analize/AnalizaTTest.php +++ b/admin/survey/export/latexclasses/Analize/AnalizaTTest.php @@ -4,33 +4,32 @@ include_once('../../function.php'); include_once('../survey/definition.php'); -/* include_once('../exportclases/class.pdfIzvozAnalizaFunctions.php'); - require_once('../exportclases/class.enka.pdf.php'); */ + define("ALLOW_HIDE_ZERRO_REGULAR", false); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za navadne odgovore define("ALLOW_HIDE_ZERRO_MISSING", true); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za missinge - define("NUM_DIGIT_AVERAGE", 2, true); // stevilo digitalnih mest za povprecje - define("NUM_DIGIT_DEVIATION", 2, true); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_AVERAGE", 2); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_DEVIATION", 2); // stevilo digitalnih mest za povprecje - define("M_ANALIZA_DESCRIPTOR", "descriptor", true); - define("M_ANALIZA_FREQUENCY", "frequency", true); + define("M_ANALIZA_DESCRIPTOR", "descriptor"); + define("M_ANALIZA_FREQUENCY", "frequency"); - define("FNT_FREESERIF", "freeserif", true); - define("FNT_FREESANS", "freesans", true); - define("FNT_HELVETICA", "helvetica", true); + define("FNT_FREESERIF", "freeserif"); + define("FNT_FREESANS", "freesans"); + define("FNT_HELVETICA", "helvetica"); - define("FNT_MAIN_TEXT", FNT_FREESANS, true); - define("FNT_QUESTION_TEXT", FNT_FREESANS, true); - define("FNT_HEADER_TEXT", FNT_FREESANS, true); + define("FNT_MAIN_TEXT", FNT_FREESANS); + define("FNT_QUESTION_TEXT", FNT_FREESANS); + define("FNT_HEADER_TEXT", FNT_FREESANS); - define("FNT_MAIN_SIZE", 10, true); - define("FNT_QUESTION_SIZE", 9, true); - define("FNT_HEADER_SIZE", 10, true); + define("FNT_MAIN_SIZE", 10); + define("FNT_QUESTION_SIZE", 9); + define("FNT_HEADER_SIZE", 10); - define("RADIO_BTN_SIZE", 3, true); - define("CHCK_BTN_SIZE", 3, true); - define("LINE_BREAK", 6, true); + define("RADIO_BTN_SIZE", 3); + define("CHCK_BTN_SIZE", 3); + define("LINE_BREAK", 6); define ('PDF_MARGIN_HEADER', 8); define ('PDF_MARGIN_FOOTER', 12); diff --git a/admin/survey/export/latexclasses/Vprasanja/BesediloLatex.php b/admin/survey/export/latexclasses/Vprasanja/BesediloLatex.php index 5c2a9e9fb..1443e99cc 100644 --- a/admin/survey/export/latexclasses/Vprasanja/BesediloLatex.php +++ b/admin/survey/export/latexclasses/Vprasanja/BesediloLatex.php @@ -10,8 +10,8 @@ *****************************************/ -define("PIC_SIZE", "\includegraphics[width=10cm]", true); //slika sirine 50mm -define("ICON_SIZE", "\includegraphics[width=0.5cm]", true); //za ikone @ slikovni tip +define("PIC_SIZE", "\includegraphics[width=10cm]"); //slika sirine 50mm +define("ICON_SIZE", "\includegraphics[width=0.5cm]"); //za ikone @ slikovni tip class BesediloLatex extends LatexSurveyElement { diff --git a/admin/survey/export/latexclasses/Vprasanja/DatumLatex.php b/admin/survey/export/latexclasses/Vprasanja/DatumLatex.php index f252f7fc2..0c7ef33d2 100644 --- a/admin/survey/export/latexclasses/Vprasanja/DatumLatex.php +++ b/admin/survey/export/latexclasses/Vprasanja/DatumLatex.php @@ -13,7 +13,7 @@ class DatumLatex extends LatexSurveyElement { var $internalCellHeight; - protected $texBigSkip = '\bigskip'; + protected $texBigSkip = '\bigskip '; protected $loop_id = null; // id trenutnega loopa ce jih imamo public function __construct() diff --git a/admin/survey/export/latexclasses/Vprasanja/GridMultipleLatex.php b/admin/survey/export/latexclasses/Vprasanja/GridMultipleLatex.php index 0b60d28e1..ae718efcf 100644 --- a/admin/survey/export/latexclasses/Vprasanja/GridMultipleLatex.php +++ b/admin/survey/export/latexclasses/Vprasanja/GridMultipleLatex.php @@ -10,9 +10,9 @@ *****************************************/ -define("PIC_SIZE", "\includegraphics[width=10cm]", true); //slika sirine 50mm -define("ICON_SIZE", "\includegraphics[width=0.5cm]", true); //za ikone @ slikovni tip -define("RADIO_BTN_SIZE", 0.13, true); +define("PIC_SIZE", "\includegraphics[width=10cm]"); //slika sirine 50mm +define("ICON_SIZE", "\includegraphics[width=0.5cm]"); //za ikone @ slikovni tip +define("RADIO_BTN_SIZE", 0.13); class GridMultipleLatex extends LatexSurveyElement { @@ -65,7 +65,8 @@ class GridMultipleLatex extends LatexSurveyElement if($userDataPresent!=0||$export_subtype=='q_empty'||$export_subtype=='q_comment'||$preveriSpremenljivko){ //ce je kaj v bazi ali je prazen vprasalnik ali je potrebno pokazati tudi ne odgovorjena vprasanja global $lang; - // iz baze preberemo vse moznosti - ko nimamo izpisa z odgovori respondenta + // iz baze preberemo vse moznosti - ko nimamo izpisa z odgovori respondenta + //echo "SELECT id, naslov, naslov2, variable, other FROM srv_vrednost WHERE spr_id='".$spremenljivke['id']."' AND hidden='0' ORDER BY vrstni_red"."
    "; $sqlVrednosti = sisplet_query("SELECT id, naslov, naslov2, variable, other FROM srv_vrednost WHERE spr_id='".$spremenljivke['id']."' AND hidden='0' ORDER BY vrstni_red"); $numRowsSql = mysqli_num_rows($sqlVrednosti); //za filanje navpicnih odgovorov //echo "SELECT id, naslov, naslov2, variable, other FROM srv_vrednost WHERE spr_id='".$spremenljivke['id']."' ORDER BY vrstni_red"; @@ -84,7 +85,7 @@ class GridMultipleLatex extends LatexSurveyElement $sqlMultiple = sisplet_query("SELECT g.*, s.tip, s.enota, s.dostop FROM srv_grid g, srv_grid_multiple m, srv_spremenljivka s WHERE s.id=g.spr_id AND g.spr_id=m.spr_id AND m.spr_id IN (".implode($multipleSprId, ',').") ORDER BY m.vrstni_red, g.vrstni_red"); //echo "SELECT g.*, s.tip, s.enota, s.dostop FROM srv_grid g, srv_grid_multiple m, srv_spremenljivka s WHERE s.id=g.spr_id AND g.spr_id=m.spr_id AND m.spr_id IN (".implode($multipleSprId, ',').") ORDER BY m.vrstni_red, g.vrstni_red"; //poizvedba podnaslovov v kombinirani tabeli - $sqlMultiplePodNaslovi = sisplet_query("SELECT naslov FROM srv_spremenljivka WHERE id IN (".implode($multipleSprId, ',').")"); + $sqlMultiplePodNaslovi = sisplet_query("SELECT naslov FROM srv_spremenljivka WHERE id IN (".implode($multipleSprId, ',').")"); //novo za kombinirano tabelo - konec $spremenljivkaParams = new enkaParameters($spremenljivke['params']); @@ -108,6 +109,29 @@ class GridMultipleLatex extends LatexSurveyElement $oznakaVprasanja = $this->UrediOznakoVprasanja($spremenljivke['id']); //uredi oznako vprasanja, ker ne sme biti stevilska + + //ce je prisoten id uporabnika - ureditev belezenja vnesenega odgovora pod Drugo: + if($usr_id){ + $multipleVredIdDrugo = array(); //polje za shranjevanje vre_id, kjer je prisotna moznost Drugo: + //poizvedba vrednosti polj, kjer se pojavijo polja Drugo: + $sqlMultipleVredIdZaDrugo = sisplet_query("SELECT id FROM srv_vrednost WHERE spr_id IN (".implode($multipleSprId, ',').") AND other = 1"); + while ($rowsqlMultipleVredIdZaDrugo = mysqli_fetch_array($sqlMultipleVredIdZaDrugo)) { + $multipleVredIdDrugo[] = $rowsqlMultipleVredIdZaDrugo['id']; + } + + if(!empty($multipleVredIdDrugo)){ + $multipleBesediloDrugo = array(); //polje za shranjevanje vnesenega besedila iz strani respondenta, kjer je prisotna moznost Drugo: + $sqlStavekMultipleBesediloDrugo = "SELECT text FROM srv_data_text_active WHERE vre_id IN (".implode($multipleVredIdDrugo, ',').") AND usr_id=".$usr_id." "; + $sqlMultipleBesediloDrugo = sisplet_query($sqlStavekMultipleBesediloDrugo); + while ($rowsqlMultipleBesediloDrugo = mysqli_fetch_array($sqlMultipleBesediloDrugo)) { + $multipleBesediloDrugo[] = $rowsqlMultipleBesediloDrugo['text']; + } + } + + $indeksBesediloDrugo = 0; //definiranje indeksa za izpis vnesenega besedila v Drugo: + } + //ce je prisoten id uporabnika - ureditev belezenja vnesenega odgovora pod Drugo: - konec + //pregled vseh moznih vrednosti (kategorij) po $sqlVrednosti - navpicni odgovori while ($rowVrednost = mysqli_fetch_assoc($sqlVrednosti)){ $stringTitleRow = ((( $rowVrednost['naslov'] ) ? $rowVrednost['naslov'] : ( ( $rowVrednost['naslov2'] ) ? $rowVrednost['naslov2'] : $rowVrednost['variable'] ) )); @@ -116,8 +140,21 @@ class GridMultipleLatex extends LatexSurveyElement if ($naslov != '') { //$rowVrednost['naslov'] = $naslov; $stringTitleRow = $naslov; - } - array_push($navpicniOdgovori, $this->encodeText($stringTitleRow) ); //filanje polja z navpicnimi odgovori (po vrsticah) + } + + $besediloDrugo = ''; + + //ce je drugo vnesen kot odgovor in je prisoten id uporabnika + if($rowVrednost['other'] && $usr_id){ + //zabelezi besedilo, ki je trenuten uporabnik za trenuten odgovor zapisal pod Drugo: + $besediloDrugo = $multipleBesediloDrugo[$indeksBesediloDrugo]; + $this->encodeText($besediloDrugo); + $besediloDrugo = ' \\textcolor{crta}{\footnotesize{'.$besediloDrugo.'}} '; + $indeksBesediloDrugo++; //povecaj indeks za izpis vnesenega besedila v Drugo: + } + //ce je drugo vnesen kot odgovor in je prisoten id uporabnika - konec + + array_push($navpicniOdgovori, $this->encodeText($stringTitleRow)." ".$besediloDrugo); //filanje polja z navpicnimi odgovori (po vrsticah) } //pregled vseh moznih vrednosti (kategorij) po $sqlVrednosti - navpicni odgovori - konec @@ -423,7 +460,7 @@ class GridMultipleLatex extends LatexSurveyElement if(($vodoravniOdgovoriEnota[0] == 2 || $vodoravniOdgovoriEnota[0] == 6) && $izpisOdgovorov && $export_data_type == 1 || ($izpisOdgovorov && $export_data_type == 2 && $vodoravniOdgovoriTip[0] == 6 )){ //(ce je roleta ALI seznam) IN je izpis odgovorov IN razsirjen izvoz ALI (je izpis odgovorov IN skrcen izvoz IN radio button) }else{ - array_push($vodoravniOdgovori, $stringTitleCol); //filanje polja z vodoravnimi odgovori (po stolpcih) + array_push($vodoravniOdgovori, $stringTitleCol); //filanje polja z vodoravnimi odgovori (po stolpcih) } //array_push($vodoravniOdgovori, $stringTitleCol); //filanje polja z vodoravnimi odgovori (po stolpcih) //echo $rowMultiple['naslov']."
    "; diff --git a/admin/survey/export/latexclasses/Vprasanja/HeatmapLatex.php b/admin/survey/export/latexclasses/Vprasanja/HeatmapLatex.php index 8bd7f1ea1..97870f19e 100644 --- a/admin/survey/export/latexclasses/Vprasanja/HeatmapLatex.php +++ b/admin/survey/export/latexclasses/Vprasanja/HeatmapLatex.php @@ -9,9 +9,9 @@ * Datum: 09/2017 *****************************************/ //use enkaParameters; -define("PIC_SIZE", "\includegraphics[width=10cm]", true); //slika sirine 50mm -define("ICON_SIZE", "\includegraphics[width=0.5cm]", true); //za ikone @ slikovni tip -define("RADIO_BTN_SIZE", 0.13, true); +define("PIC_SIZE", "\includegraphics[width=10cm]"); //slika sirine 50mm +define("ICON_SIZE", "\includegraphics[width=0.5cm]"); //za ikone @ slikovni tip +define("RADIO_BTN_SIZE", 0.13); class HeatmapLatex extends LatexSurveyElement { diff --git a/admin/survey/export/latexclasses/Vprasanja/KalkulacijaLatex.php b/admin/survey/export/latexclasses/Vprasanja/KalkulacijaLatex.php index 77acc2d3f..a5368d848 100644 --- a/admin/survey/export/latexclasses/Vprasanja/KalkulacijaLatex.php +++ b/admin/survey/export/latexclasses/Vprasanja/KalkulacijaLatex.php @@ -9,7 +9,7 @@ * Datum: 05/2018 *****************************************/ - define("NAGOVOR_LINE_WIDTH", 0.5, true); + define("NAGOVOR_LINE_WIDTH", 0.5); class KalkulacijaLatex extends LatexSurveyElement { diff --git a/admin/survey/export/latexclasses/Vprasanja/KvotaLatex.php b/admin/survey/export/latexclasses/Vprasanja/KvotaLatex.php index 34e28e40b..5ef456e12 100644 --- a/admin/survey/export/latexclasses/Vprasanja/KvotaLatex.php +++ b/admin/survey/export/latexclasses/Vprasanja/KvotaLatex.php @@ -9,7 +9,7 @@ * Datum: 05/2018 *****************************************/ - define("NAGOVOR_LINE_WIDTH", 0.5, true); + define("NAGOVOR_LINE_WIDTH", 0.5); class KvotaLatex extends LatexSurveyElement { diff --git a/admin/survey/export/latexclasses/Vprasanja/MultiGridLatex.php b/admin/survey/export/latexclasses/Vprasanja/MultiGridLatex.php index 63f38140c..df47509a8 100644 --- a/admin/survey/export/latexclasses/Vprasanja/MultiGridLatex.php +++ b/admin/survey/export/latexclasses/Vprasanja/MultiGridLatex.php @@ -10,18 +10,15 @@ *****************************************/ -define("PIC_SIZE", "\includegraphics[width=10cm]", true); //slika sirine 50mm -define("ICON_SIZE", "\includegraphics[width=0.5cm]", true); //za ikone @ slikovni tip -define("RADIO_BTN_SIZE", 0.13, true); -//define("U_SHAPE_WIDTH", 4, true); -define("U_SHAPE_WIDTH_U", 4, true); -define("U_SHAPE_WIDTH_OKVIR", 3.62, true); -//define("U_SHAPE_WIDTH_TEXT_U", 2.1, true); -define("U_SHAPE_WIDTH_TEXT_U", 2.2, true); -define("U_SHAPE_WIDTH_TEXT_OKVIR", 1.81, true); -//define("U_SHAPE_WIDTH_TEXT_OKVIR", 2.1, true); -define("MAXSTEVILOSTOLPCEV", 21, true); //max Stevilo Stolpcev za prvo vrstico pod Drsnikom, zaradi tezav z izrisom, ce je teh vec kot toliko -define("VAS_SIZE", 0.04, true); //VAS_SIZE +define("PIC_SIZE", "\includegraphics[width=10cm]"); //slika sirine 50mm +define("ICON_SIZE", "\includegraphics[width=0.5cm]"); //za ikone @ slikovni tip +define("RADIO_BTN_SIZE", 0.13); +define("U_SHAPE_WIDTH_U", 4); +define("U_SHAPE_WIDTH_OKVIR", 3.62); +define("U_SHAPE_WIDTH_TEXT_U", 2.2); +define("U_SHAPE_WIDTH_TEXT_OKVIR", 1.81); +define("MAXSTEVILOSTOLPCEV", 21); //max Stevilo Stolpcev za prvo vrstico pod Drsnikom, zaradi tezav z izrisom, ce je teh vec kot toliko +define("VAS_SIZE", 0.04); //VAS_SIZE class MultiGridLatex extends LatexSurveyElement { @@ -115,7 +112,7 @@ class MultiGridLatex extends LatexSurveyElement $stringMissingOdgovor = $colVrednost['naslov']; array_push($missingOdgovori, $this->encodeText($stringMissingOdgovor) ); //filanje polja z missing odgovori }else{ - $stringTitleCol = $colVrednost['naslov']; + $stringTitleCol = $colVrednost['naslov']; array_push($vodoravniOdgovori, $this->encodeText($stringTitleCol) ); //filanje polja z vodoravnimi odgovori (po stolpcih) } } @@ -432,8 +429,9 @@ class MultiGridLatex extends LatexSurveyElement if (strip_tags($rowl['naslov']) != '') $colVrednost['naslov'] = $rowl['naslov']; #ce je respondent odgovarjal v drugem jeziku - konec ################ - $stringTitleCol = $colVrednost['naslov']; - array_push($vodoravniOdgovori, $this->encodeText($stringTitleCol) ); //filanje polja z vodoravnimi odgovori (po stolpcih) + $stringTitleCol = $colVrednost['naslov']; + $stringTitleCol = str_replace('
    ','',$stringTitleCol); //odstranitev odvecnih
    iz naslova stolpcev + array_push($vodoravniOdgovori, $this->encodeText($stringTitleCol) ); //filanje polja z vodoravnimi odgovori (po stolpcih) } } //pregled vseh odgovorov po stolpcih po $sqlStolpciVrednosti - konec @@ -470,10 +468,10 @@ class MultiGridLatex extends LatexSurveyElement $fillablePdf = 0; if((($spremenljivke['enota']==0)&&($spremenljivke['tip']==6||$spremenljivke['tip']==16))||($spremenljivke['tip']==19||$spremenljivke['tip']==20)){ //klasicna tabela ali multitext ali multinumber - if($export_data_type==1||($export_subtype=='q_empty'||$export_subtype=='q_comment')){//ce je dolg izvoz ali(prazen vprasalnik ali vpr. s komentarji) + if($export_data_type==1||($export_subtype=='q_empty'||$export_subtype=='q_comment')){//ce je dolg izvoz ali(prazen vprasalnik ali vpr. s komentarji) //izris tabel ustrezne postavitve if($spremenljivke['tip']==20){ //ce je tip vprasanja stevilo - if(($nacinVnosa == 0)){ //ce je nacin vnosa Stevilo + if(($nacinVnosa == 0)){ //ce je nacin vnosa Stevilo $tex .= $this->IzrisTabeleMultiGrid($spremenljivke, $numColSql, $numRowsSql, $vodoravniOdgovori, $navpicniOdgovori, 0, $symbol, $texNewLine, $texNewLineAfterTable, $export_format, 0, $missingOdgovori, $userAnswerDataText, $export_subtype); }else if($nacinVnosa == 1 && $export_format=='pdf'){ //ce so drsniki in je pdf $tex .= $this->IzrisGridDrsnikov($spremenljivke, $navpicniOdgovori, $export_format, $export_subtype, $missingOdgovori, $userAnswerDataText); diff --git a/admin/survey/export/latexclasses/Vprasanja/NagovorLatex.php b/admin/survey/export/latexclasses/Vprasanja/NagovorLatex.php index a2b86f49b..779487829 100644 --- a/admin/survey/export/latexclasses/Vprasanja/NagovorLatex.php +++ b/admin/survey/export/latexclasses/Vprasanja/NagovorLatex.php @@ -9,7 +9,7 @@ * Datum: 09/2017 *****************************************/ - define("NAGOVOR_LINE_WIDTH", 0.5, true); + define("NAGOVOR_LINE_WIDTH", 0.5); class NagovorLatex extends LatexSurveyElement { diff --git a/admin/survey/export/latexclasses/Vprasanja/RadioCheckboxSelectLatex.php b/admin/survey/export/latexclasses/Vprasanja/RadioCheckboxSelectLatex.php index 3dbe1f965..a8636e28e 100644 --- a/admin/survey/export/latexclasses/Vprasanja/RadioCheckboxSelectLatex.php +++ b/admin/survey/export/latexclasses/Vprasanja/RadioCheckboxSelectLatex.php @@ -11,8 +11,8 @@ //namespace Export\Latexclasses\Vprasanja; -define("PIC_SIZE", "\includegraphics[width=10cm]", true); //slika sirine 50mm -define("ICON_SIZE", "\includegraphics[width=0.5cm]", true); //za ikone @ slikovni tip +define("PIC_SIZE", "\includegraphics[width=10cm]"); //slika sirine 50mm +define("ICON_SIZE", "\includegraphics[width=0.5cm]"); //za ikone @ slikovni tip class RadioCheckboxSelectLatex extends LatexSurveyElement { @@ -29,6 +29,7 @@ class RadioCheckboxSelectLatex extends LatexSurveyElement protected $loop_id = null; // id trenutnega loopa ce jih imamo protected $path2ImagesRadio; protected $language; + protected $prevod; public static function getInstance() { @@ -43,6 +44,15 @@ class RadioCheckboxSelectLatex extends LatexSurveyElement $this->language = $language; $this->path2ImagesRadio = $site_path.'uploadi/editor/'; + + //preverjanje, ali je prevod + if(isset($_GET['language'])){ + $this->language = $_GET['language']; + $this->prevod = 1; + }else{ + $this->prevod = 0; + } + //preverjanje, ali je prevod - konec // Ce je spremenljivka v loopu $this->loop_id = $loop_id; @@ -54,6 +64,7 @@ class RadioCheckboxSelectLatex extends LatexSurveyElement $userAnswerData = array(); //belezi podatke respondenta $textRArray = array(); //belezi odgovore respondenta, ki se nahajajo v desnem delu vprasanja // iz baze preberemo vse moznosti - ko nimamo izpisa z odgovori respondenta + //echo "SELECT id, naslov, naslov2, variable, other FROM srv_vrednost WHERE spr_id='".$spremenljivke['id']."' AND hidden='0' ORDER BY vrstni_red"; $sqlVrednosti = sisplet_query("SELECT id, naslov, naslov2, variable, other FROM srv_vrednost WHERE spr_id='".$spremenljivke['id']."' AND hidden='0' ORDER BY vrstni_red"); $numRowsSql = mysqli_num_rows($sqlVrednosti); $tex = ''; @@ -66,6 +77,8 @@ class RadioCheckboxSelectLatex extends LatexSurveyElement if ($usr_id){ $userDataPresent = $this->GetUsersData($db_table, $spremenljivke['id'], $spremenljivke['tip'], $usr_id, $this->loop_id); //zgenerira podatke z odgovori respondenta v $this->userAnswer, zabelezi, ce so podatki prisotni } + + //echo "test: ".$userDataPresent."
    "; #izpis izvoza kratek ali zelo kratek ############################################################################### if($export_subtype=='q_data'||$export_subtype=='q_data_all'){ //ce je izvoz odgovorov respondenta/respodentov @@ -118,12 +131,10 @@ class RadioCheckboxSelectLatex extends LatexSurveyElement #izpis praznega vprasalnika ali dolgega izvoza (vprasalnika z odgovori respondenta) ################################################## if($export_subtype=='q_empty'||$export_data_type==1||$export_subtype=='q_comment'){ //ce je izpis praznega vprasalnika ali dolgega izvoza - + /* echo "orientacija: ".$spremenljivke['orientation']."
    "; + echo "tip: ".$spremenljivke['tip']."
    "; */ if($spremenljivke['orientation']==5){ //ce je postavitev Potrditev if($export_format == 'pdf'){ //ce je pdf - /* if($spremenljivke['orientation']==0 || $spremenljivke['orientation']==2){ //ce sta vodoravni orientaciji - $tex .= $texNewLine; //dodaj na koncu vprasanja prazno vrstico - } */ $tex .= $this->texBigSkip; $tex .= '\\end{absolutelynopagebreak}'; //zakljucimo environment, da med vprasanji ne bo prelomov strani }else{ //ce je rtf @@ -252,26 +263,30 @@ class RadioCheckboxSelectLatex extends LatexSurveyElement while ($rowVrednost = mysqli_fetch_assoc($sqlVrednosti)){ $prop['full'] = ( isset($userAnswer[$rowVrednost['id']]) ); - //if($this->language!=''){ //ce je prevod ankete - if($this->language>1){ //ce je prevod ankete + + //if($this->language>1){ //ce je prevod ankete + if($this->prevod){ //ce je prevod ankete $rowl = $this->srv_language_vrednost($rowVrednost['id']); //pridobi prevod naslova v ustreznem jeziku $stringTitle = ((( $rowl['naslov'] ) ? $rowl['naslov'] : ( ( $rowl['naslov2'] ) ? $rowl['naslov2'] : $rowl['variable'] ) )); //prevod naslova v ustreznem jeziku }else{ - $stringTitle = ((( $rowVrednost['naslov'] ) ? $rowVrednost['naslov'] : ( ( $rowVrednost['naslov2'] ) ? $rowVrednost['naslov2'] : $rowVrednost['variable'] ) )); + $stringTitle = ((( $rowVrednost['naslov'] ) ? $rowVrednost['naslov'] : ( ( $rowVrednost['naslov2'] ) ? $rowVrednost['naslov2'] : $rowVrednost['variable'] ) )); } + + //echo "naslov: $stringTitle
    "; //echo "jezik: ".$this->language."
    "; if ( $spremenljivke['tip'] == 1 || $spremenljivke['tip'] == 3 ){ $symbol = $this->getAnswerSymbol($export_format, $fillablePdf, $spremenljivke['tip'], $spremenljivke['grids'], 0, $this->userAnswer[$rowVrednost['id']], $spremenljivke['orientation'], $indeksZaWhile, $vizualnaSkalaNumber); //$tex .= '{\ChoiceMenu[radio,radiosymbol=\ding{108},name=myGroupOfRadiobuttons]{}{='.$stringTitle.'}}'.$stringTitle.' '.$this->texNewLine; $internalCellHeight = '0.3 cm'; //visina praznega okvirja @povleci-spusti - }else if ( $spremenljivke['tip'] == 2 ) - { + }else if ( $spremenljivke['tip'] == 2 ){ $symbol = $this->getAnswerSymbol($export_format, $fillablePdf, $spremenljivke['tip'], $spremenljivke['grids'], 0, $this->userAnswer[$rowVrednost['id']]); $internalCellHeight = '3 cm'; //visina praznega okvirja @povleci-spusti } if($spremenljivke['orientation']==1&&$spremenljivke['tip'] != 3){ //navpicno - $tex .= $symbol.' '.$this->encodeText($stringTitle, $rowVrednost['id']).' '.$texNewLine; + $tex .= $symbol.' '.$this->encodeText($stringTitle, $rowVrednost['id']).' '.$texNewLine; + //$test = $symbol.' '.$this->encodeText($stringTitle, $rowVrednost['id']).' '.$texNewLine; + //echo "tukaj! $test
    "; }elseif($spremenljivke['orientation']==7){ //navpicno - tekst levo $text = $this->encodeText($stringTitle, $rowVrednost['id']).' & '.$symbol.' '.$texNewLine; $textLength = strlen($text); diff --git a/admin/survey/export/latexclasses/Vprasanja/RazvrscanjeLatex.php b/admin/survey/export/latexclasses/Vprasanja/RazvrscanjeLatex.php index 7a7443493..9ef7df20c 100644 --- a/admin/survey/export/latexclasses/Vprasanja/RazvrscanjeLatex.php +++ b/admin/survey/export/latexclasses/Vprasanja/RazvrscanjeLatex.php @@ -10,9 +10,9 @@ *****************************************/ -define("PIC_SIZE", "\includegraphics[width=10cm]", true); //slika sirine 50mm -define("ICON_SIZE", "\includegraphics[width=0.5cm]", true); //za ikone @ slikovni tip -define("RADIO_BTN_SIZE", 0.13, true); +define("PIC_SIZE", "\includegraphics[width=10cm]"); //slika sirine 50mm +define("ICON_SIZE", "\includegraphics[width=0.5cm]"); //za ikone @ slikovni tip +define("RADIO_BTN_SIZE", 0.13); class RazvrscanjeLatex extends LatexSurveyElement { diff --git a/admin/survey/export/latexclasses/Vprasanja/SNImena.php b/admin/survey/export/latexclasses/Vprasanja/SNImena.php index 97b36f1f9..5ff63d990 100644 --- a/admin/survey/export/latexclasses/Vprasanja/SNImena.php +++ b/admin/survey/export/latexclasses/Vprasanja/SNImena.php @@ -9,7 +9,7 @@ * Datum: 05/2018 *****************************************/ - define("NAGOVOR_LINE_WIDTH", 0.5, true); + define("NAGOVOR_LINE_WIDTH", 0.5); class SNImenaLatex extends LatexSurveyElement { diff --git a/admin/survey/export/latexclasses/Vprasanja/SteviloLatex.php b/admin/survey/export/latexclasses/Vprasanja/SteviloLatex.php index afbd84e92..ade06a602 100644 --- a/admin/survey/export/latexclasses/Vprasanja/SteviloLatex.php +++ b/admin/survey/export/latexclasses/Vprasanja/SteviloLatex.php @@ -10,9 +10,9 @@ *****************************************/ -define("PIC_SIZE", "\includegraphics[width=10cm]", true); //slika sirine 50mm -define("ICON_SIZE", "\includegraphics[width=0.5cm]", true); //za ikone @ slikovni tip -define("MAXSTEVILOSTOLPCEV", 21, true); //max Stevilo Stolpcev za prvo vrstico pod Drsnikom, zaradi tezav z izrisom, ce je teh vec kot toliko +define("PIC_SIZE", "\includegraphics[width=10cm]"); //slika sirine 50mm +define("ICON_SIZE", "\includegraphics[width=0.5cm]"); //za ikone @ slikovni tip +define("MAXSTEVILOSTOLPCEV", 21); //max Stevilo Stolpcev za prvo vrstico pod Drsnikom, zaradi tezav z izrisom, ce je teh vec kot toliko class SteviloLatex extends LatexSurveyElement { diff --git a/admin/survey/export/latexclasses/Vprasanja/VsotaLatex.php b/admin/survey/export/latexclasses/Vprasanja/VsotaLatex.php index 857981a85..726d8fd4b 100644 --- a/admin/survey/export/latexclasses/Vprasanja/VsotaLatex.php +++ b/admin/survey/export/latexclasses/Vprasanja/VsotaLatex.php @@ -10,9 +10,9 @@ *****************************************/ -define("PIC_SIZE", "\includegraphics[width=10cm]", true); //slika sirine 50mm -define("ICON_SIZE", "\includegraphics[width=0.5cm]", true); //za ikone @ slikovni tip -define("RADIO_BTN_SIZE", 0.13, true); +define("PIC_SIZE", "\includegraphics[width=10cm]"); //slika sirine 50mm +define("ICON_SIZE", "\includegraphics[width=0.5cm]"); //za ikone @ slikovni tip +define("RADIO_BTN_SIZE", 0.13); class VsotaLatex extends LatexSurveyElement { diff --git a/admin/survey/export/latexclasses/class.LatexAnalysisElement.php b/admin/survey/export/latexclasses/class.LatexAnalysisElement.php index 2b6f4f5b7..408a87cc2 100644 --- a/admin/survey/export/latexclasses/class.LatexAnalysisElement.php +++ b/admin/survey/export/latexclasses/class.LatexAnalysisElement.php @@ -8,9 +8,8 @@ */ -//include('../../function.php'); include('../../vendor/autoload.php'); -define("MAX_STRING_LENGTH", 20, true); +define("MAX_STRING_LENGTH", 20); class LatexAnalysisElement{ @@ -925,7 +924,12 @@ class LatexAnalysisElement{ $text = str_replace('^','\textasciicircum{} ',$text); //$text = str_replace('_','\_ ',$text); $text = str_replace('_','\_',$text); - $text = str_replace('~','\textasciitilde{} ',$text); + $text = str_replace('~','\textasciitilde{} ',$text); + if(strpos($text, '&')){ //ce je prisotno v besedilu &' + $text = str_replace('&','\& ',$text); + }else{ + $text = str_replace('&','\& ',$text); + } $andSymbolPresent = 0; $posAndSymbolPresent = strpos($text,'&'); diff --git a/admin/survey/export/latexclasses/class.LatexDocument.php b/admin/survey/export/latexclasses/class.LatexDocument.php index 7dd3f0006..d5b021162 100644 --- a/admin/survey/export/latexclasses/class.LatexDocument.php +++ b/admin/survey/export/latexclasses/class.LatexDocument.php @@ -97,10 +97,10 @@ omenjeno kodo je potrebno deliti z 255, da dobimo stevilke, ki ustrezajo Latex = //namespace Export\Latexclasses; //include('../../function.php'); include('../../vendor/autoload.php'); -define("ENKA_LOGO_SIZE", 'width=3.51cm,height=2cm,keepaspectratio', true); -define("ENKA_LOGO_SIZE_HEADER", 'width=1.75cm,height=1cm,keepaspectratio', true); -define("SINGLE_TABLE_WIDTH", 3000, true); -define("PAGE_TEXT_WIDTH", 10200, true); //17 cm, 170 mm, je 10200 twips, 1 mm je 60 twips +define("ENKA_LOGO_SIZE", 'width=3.51cm,height=2cm,keepaspectratio'); +define("ENKA_LOGO_SIZE_HEADER", 'width=1.75cm,height=1cm,keepaspectratio'); +define("SINGLE_TABLE_WIDTH", 3000); +define("PAGE_TEXT_WIDTH", 10200); //17 cm, 170 mm, je 10200 twips, 1 mm je 60 twips #definicija za izris drsnika s kroglico define ("circleSlider", '\def\circleSLIDER#1#2{% 1: length, 2: position of the mark (0 to 1) @@ -111,7 +111,7 @@ define ("circleSlider", '\def\circleSLIDER#1#2{% 1: length, 2: position of the m \fill[rounded corners=0.1cm, draw=gray, fill=lightgray] (start) rectangle (end); \fill[draw=gray, rounded corners=0.2mm, fill=gray!20!gray] (mark) circle(.15) ; } - }', true); + }'); #definicija za izris drsnika brez kroglice define ("emptySlider", '\def\emptySLIDER#1{% 1: length @@ -120,25 +120,16 @@ define ("emptySlider", '\def\emptySLIDER#1{% 1: length \coordinate (end) at (#1,0.1cm); \fill[rounded corners=0.1cm, draw=gray, fill=lightgray] (start) rectangle (end); } - }', true); + }'); #definicija latex kode za dodajanje skripte za generiranje xls iz html -/* define ("headWithXlsScript", - '\ifdefined\HCode - \AtBeginDocument{% - \Configure{@HEAD}{\HCode{\Hnewline}} - \ConfigureEnv{quote}{\Tg}{\Tg}{}{} - } - \fi', -true); */ define ("headWithXlsScript", '\ifdefined\HCode \AtBeginDocument{% \Configure{@HEAD}{\HCode{\Hnewline}} \ConfigureEnv{quote}{\Tg}{\Tg}{}{} } - \fi', -true); + \fi'); class LatexDocument{ @@ -252,8 +243,23 @@ class LatexDocument{ echo 'SurveyId: '.SurveyInfo::getSurveyId().'
    '; */ #za pridobitev jezika respondenta + //pridobitev splosnega jezika ankete za respondenta nastavitev=> Osnovni jezik za respondente: + $sqlL = sisplet_query("SELECT lang_resp FROM srv_anketa WHERE id='$this->anketa' "); + $rowL = mysqli_fetch_array($sqlL); + $this->language = $rowL['lang_resp']; - if ($this->usr_id != '') { + ############testiranje za jezik + if(isset($_GET['language'])){ + $this->language = $_GET['language']; + //echo "jezik test: ".$this->language."
    "; + // Naložimo jezikovno datoteko + $file = '../../lang/'.$this->language.'.php'; + include($file); + $_SESSION['langX'] = $site_url .'lang/'.$this->language.'.php'; + } + ############testiranje za jezik - konec + + if ($this->usr_id != '') { //ce je izpis za dolocenega respondenta $sqlL = sisplet_query("SELECT language FROM srv_user WHERE id = '$this->usr_id ' AND ank_id='$this->anketa' "); $rowL = mysqli_fetch_array($sqlL); $this->language = $rowL['language']; @@ -1364,8 +1370,11 @@ class LatexDocument{ $text = str_replace('^','\textasciicircum{} ',$text); $text = str_replace('_','\_ ',$text); $text = str_replace('~','\textasciitilde{} ',$text); - $text = str_replace('&','\&',$text); - $text = str_replace('&','\&',$text); + if(strpos($text, '&')){ //ce je prisotno v besedilu &' + $text = str_replace('&','\& ',$text); + }else{ + $text = str_replace('&','\& ',$text); + } $text = str_replace(' ','~',$text); //$text = str_replace('<','\textless ',$text); $text = str_replace('<',' \textless ',$text); diff --git a/admin/survey/export/latexclasses/class.LatexEditsAnalysis.php b/admin/survey/export/latexclasses/class.LatexEditsAnalysis.php index de67c7d72..0b2dd4a45 100644 --- a/admin/survey/export/latexclasses/class.LatexEditsAnalysis.php +++ b/admin/survey/export/latexclasses/class.LatexEditsAnalysis.php @@ -9,15 +9,15 @@ define("ALLOW_HIDE_ZERRO_REGULAR", false); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za navadne odgovore define("ALLOW_HIDE_ZERRO_MISSING", true); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za missinge - define("NUM_DIGIT_AVERAGE", 2, true); // stevilo digitalnih mest za povprecje - define("NUM_DIGIT_DEVIATION", 2, true); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_AVERAGE", 2); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_DEVIATION", 2); // stevilo digitalnih mest za povprecje - define("M_ANALIZA_DESCRIPTOR", "descriptor", true); - define("M_ANALIZA_FREQUENCY", "frequency", true); + define("M_ANALIZA_DESCRIPTOR", "descriptor"); + define("M_ANALIZA_FREQUENCY", "frequency"); - define("RADIO_BTN_SIZE", 3, true); - define("CHCK_BTN_SIZE", 3, true); - define("LINE_BREAK", 6, true); + define("RADIO_BTN_SIZE", 3); + define("CHCK_BTN_SIZE", 3); + define("LINE_BREAK", 6); define ('FRAME_TEXT_WIDTH', 0.3); define ('FRAME_WIDTH', 480); diff --git a/admin/survey/export/latexclasses/class.LatexGDPR.php b/admin/survey/export/latexclasses/class.LatexGDPR.php index 6e225e3bd..d1aa83647 100644 --- a/admin/survey/export/latexclasses/class.LatexGDPR.php +++ b/admin/survey/export/latexclasses/class.LatexGDPR.php @@ -105,7 +105,7 @@ class LatexGDPR{ $url = $matches[1][$key]; $url_text = $matches[2][$key]; - $tex = str_replace($matches[0][$key], '\textcolor{crta}{ \underline{ \href{'.$url.'}'.'{'.$url_text.'} } }', $tex); + $tex = str_replace($matches[0][$key], '\textcolor{crta}{\underline{\href{'.$url.'}'.'{'.$url_text.'}}}', $tex); } diff --git a/admin/survey/export/latexclasses/class.LatexStatus.php b/admin/survey/export/latexclasses/class.LatexStatus.php index ae3a5467e..a4434a7de 100644 --- a/admin/survey/export/latexclasses/class.LatexStatus.php +++ b/admin/survey/export/latexclasses/class.LatexStatus.php @@ -9,27 +9,27 @@ define("ALLOW_HIDE_ZERRO_REGULAR", false); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za navadne odgovore define("ALLOW_HIDE_ZERRO_MISSING", true); // omogočimo delovanje prikazovanja/skrivanja ničelnih vnosti za missinge - define("NUM_DIGIT_AVERAGE", 2, true); // stevilo digitalnih mest za povprecje - define("NUM_DIGIT_DEVIATION", 2, true); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_AVERAGE", 2); // stevilo digitalnih mest za povprecje + define("NUM_DIGIT_DEVIATION", 2); // stevilo digitalnih mest za povprecje - define("M_ANALIZA_DESCRIPTOR", "descriptor", true); - define("M_ANALIZA_FREQUENCY", "frequency", true); + define("M_ANALIZA_DESCRIPTOR", "descriptor"); + define("M_ANALIZA_FREQUENCY", "frequency"); - define("FNT_FREESERIF", "freeserif", true); - define("FNT_FREESANS", "freesans", true); - define("FNT_HELVETICA", "helvetica", true); + define("FNT_FREESERIF", "freeserif"); + define("FNT_FREESANS", "freesans"); + define("FNT_HELVETICA", "helvetica"); - define("FNT_MAIN_TEXT", FNT_FREESANS, true); - define("FNT_QUESTION_TEXT", FNT_FREESANS, true); - define("FNT_HEADER_TEXT", FNT_FREESANS, true); + define("FNT_MAIN_TEXT", FNT_FREESANS); + define("FNT_QUESTION_TEXT", FNT_FREESANS); + define("FNT_HEADER_TEXT", FNT_FREESANS); - define("FNT_MAIN_SIZE", 10, true); - define("FNT_QUESTION_SIZE", 9, true); - define("FNT_HEADER_SIZE", 10, true); + define("FNT_MAIN_SIZE", 10); + define("FNT_QUESTION_SIZE", 9); + define("FNT_HEADER_SIZE", 10); - define("RADIO_BTN_SIZE", 3, true); - define("CHCK_BTN_SIZE", 3, true); - define("LINE_BREAK", 6, true); + define("RADIO_BTN_SIZE", 3); + define("CHCK_BTN_SIZE", 3); + define("LINE_BREAK", 6); define ('PDF_MARGIN_HEADER', 8); define ('PDF_MARGIN_FOOTER', 12); diff --git a/admin/survey/export/latexclasses/class.LatexSurvey.php b/admin/survey/export/latexclasses/class.LatexSurvey.php index 52b7d89eb..84ebb462b 100644 --- a/admin/survey/export/latexclasses/class.LatexSurvey.php +++ b/admin/survey/export/latexclasses/class.LatexSurvey.php @@ -8,9 +8,9 @@ */ //namespace Export\Latexclasses; -//include('../../function.php'); include('../../vendor/autoload.php'); -define("RADIO_BTN_SIZE", 0.13, true); + +define("RADIO_BTN_SIZE", 0.13); class LatexSurvey{ @@ -153,7 +153,7 @@ class LatexSurvey{ $tex .= $this->texNewLine; $tex .= $this->texNewLine; } - + //ce je potrebno izpisati GDPR besedilo v intro if($this->showGDPRIntro == 1){ //$GDPRintro = "gdpr INTRO"; @@ -207,18 +207,30 @@ class LatexSurvey{ if( ($surveyExpanded != 0 || $this->type != 1) && $this->showIntro == 1 ){ if ( SurveyInfo::getInstance()->getSurveyShowIntro() ) { - if($this->language!=-1){ //ce je prevod ankete + //preverjanje, ali je prevod + if(isset($_GET['language'])){ + $this->language = $_GET['language']; + $prevod = 1; + }else{ + $prevod = 0; + } + //preverjanje, ali je prevod - konec + + //if($this->language!=-1){ //ce je prevod ankete + if($prevod){ //ce je prevod ankete $spr_id_uvod = -1; $sqll = sisplet_query("SELECT naslov, info FROM srv_language_spremenljivka WHERE ank_id='".$this->anketa."' AND spr_id='".$spr_id_uvod."' AND lang_id='".$this->language."'"); $rowl = mysqli_fetch_array($sqll); //pridobi prevod uvoda v ustreznem jeziku $intro = $rowl['naslov']; //prevod uvoda v ustreznem jeziku }else{ $intro = (SurveyInfo::getInstance()->getSurveyIntro() == '') ? $lang['srv_intro'] : SurveyInfo::getInstance()->getSurveyIntro(); + } + $tex .= $this->encodeTextHere($intro); + if($intro){ + $tex .= $this->texNewLine; + $tex .= $this->texNewLine; } - $tex .= $this->encodeTextHere($intro); - $tex .= $this->texNewLine; - $tex .= $this->texNewLine; } } @@ -503,10 +515,9 @@ class LatexSurvey{ //$this->export_data_show_recnum = 1; #izpis statusa respondenta in anketiranja if($this->export_data_show_recnum == 1){ //ce je potrebno pokazati stevilko respondenta - //$tex .= '{\\Large Recnum '.$rowu['recnum'].' (status '.$rowu['last_status'].' - '.$status.')} '.$this->texNewLine.' \\par '; - $tex .= '{\\Large Status '.$rowu['last_status'].' - '.$status.' (Recnum '.$rowu['recnum'].')} '.$this->texNewLine.' \\par '; + $tex .= '{\\Large Status '.$rowu['last_status'].' - '.$status.' (Recnum '.$rowu['recnum'].')} '.$this->texNewLine.' \\par '; }else{ - $tex .= '{\\Large Status '.$rowu['last_status'].' - '.$status.$this->texNewLine.' \\par}'; + $tex .= '{\\Large Status '.$rowu['last_status'].' - '.$status.$this->texNewLine.' \\par}'; } #izpis statusa respondenta in anketiranja - konec diff --git a/admin/survey/export/latexclasses/class.LatexSurveyElement.php b/admin/survey/export/latexclasses/class.LatexSurveyElement.php index 1dc3493b8..7dea1e3b3 100644 --- a/admin/survey/export/latexclasses/class.LatexSurveyElement.php +++ b/admin/survey/export/latexclasses/class.LatexSurveyElement.php @@ -8,16 +8,15 @@ */ -//include('../../function.php'); include('../../vendor/autoload.php'); -define("MAX_STRING_LENGTH", 90, true); -define("LINE_BREAK_AT", '7 cm', true); -define("RADIO_BTN_SIZE", 0.13, true); -define("CHCK_BTN_SIZE", 0.13, true); -define("PIC_SIZE_ANS", "\includegraphics[width=3cm]", true); //slika dolocene sirine -define("DROPDOWN_SIZE", 0.8, true); -define("VAS_SIZE", 0.04, true); //VAS_SIZE +define("MAX_STRING_LENGTH", 90); +define("LINE_BREAK_AT", '7 cm'); +define("RADIO_BTN_SIZE", 0.13); +define("CHCK_BTN_SIZE", 0.13); +define("PIC_SIZE_ANS", "\includegraphics[width=3cm]"); //slika dolocene sirine +define("DROPDOWN_SIZE", 0.8); +define("VAS_SIZE", 0.04); //VAS_SIZE class LatexSurveyElement{ @@ -46,6 +45,7 @@ class LatexSurveyElement{ protected $path2Images; protected $path2UploadedImages; protected $language; + protected $prevod; protected $admin_type; protected $variableName; @@ -77,15 +77,25 @@ class LatexSurveyElement{ //$this->usr_id = $_GET['usr_id']; $this->usr_id = $usr_id; - + if ($this->usr_id != '') { $sqlL = sisplet_query("SELECT language FROM srv_user WHERE id = '$this->usr_id ' AND ank_id='$this->anketa' "); $rowL = mysqli_fetch_array($sqlL); $this->language = $rowL['language']; } - if($language!=-1){ //ce ni default jezik, ampak je prevod - $this->language = $language; + //preverjanje, ali je prevod + if(isset($_GET['language'])){ + $this->language = $_GET['language']; + $this->prevod = 1; + }else{ + $this->prevod = 0; + } + //preverjanje, ali je prevod - konec + + //if($language!=-1){ //ce ni default jezik, ampak je prevod + if($this->prevod){ //ce ni default jezik, ampak je prevod + $this->language = $language; } if ( SurveyInfo::getInstance()->SurveyInit($anketa)) @@ -192,7 +202,8 @@ class LatexSurveyElement{ ######################################### Pridobimo tekst vprasanja - konec #Stevilcenje vprasanj############################################################### - $numberingText = ($this->numbering == 1) ? $spremenljivke['variable'].' - ' : ''; + //$numberingText = ($this->numbering == 1) ? $spremenljivke['variable'].' - ' : ''; + $numberingText = ($this->numbering == 1) ? $this->encodeText($spremenljivke['variable']).' - ' : ''; ######################################### Stevilcenje vprasanj - konec //echo "goli naslov: ".$spremenljivke['naslov']."
    "; @@ -446,7 +457,8 @@ class LatexSurveyElement{ */ function srv_language_spremenljivka ($spremenljivka=null) { - if ($this->language != -1) { + // if ($this->language != -1) { + if ($this->prevod) { $sqll = sisplet_query("SELECT naslov, info FROM srv_language_spremenljivka WHERE ank_id='".$this->anketa."' AND spr_id='".$spremenljivka['id']."' AND lang_id='".$this->language."'"); $rowl = mysqli_fetch_array($sqll); @@ -509,8 +521,7 @@ class LatexSurveyElement{ } else $row1 = null; - $output .= $row1['variable']; - + $output .= $this->encodeText($row1['variable']); // radio, checkbox, dropdown in multigrid if (($row2['tip'] <= 3 || $row2['tip'] == 6) && ($row['spr_id'] || $row['vre_id'])) { @@ -578,8 +589,8 @@ class LatexSurveyElement{ $output .= ' ('; $output .= ' '.$row_if['label'].' '; $output .= ') '; - } - + } + return $output; } @@ -792,6 +803,8 @@ class LatexSurveyElement{ //echo "Encoding ".$text."
    "; //echo "vre_id: ".$vre_id."
    "; //echo "ime spremenljivke ".$this->variableName."
    "; + + $text = htmlspecialchars_decode($text); //vse html special chars kot je & spremeni v ustrezne simbole (npr. &=>&) //resevanje razbirajanja predolgih neprekinjenih besed in URL - spremenljivke za kasnejsi prilagojen izpis //$numOfWords = str_word_count($text, 0); @@ -898,9 +911,12 @@ class LatexSurveyElement{ $text = str_replace('€','\euro',$text); $text = str_replace('^','\textasciicircum{} ',$text); $text = str_replace('_','\_ ',$text); - $text = str_replace('~','\textasciitilde{} ',$text); - $text = str_replace('&','\&',$text); - $text = str_replace('&','\&',$text); + $text = str_replace('~','\textasciitilde{} ',$text); + if(strpos($text, '&')){ //ce je prisotno v besedilu &' + $text = str_replace('&','\& ',$text); + }else{ + $text = str_replace('&','\& ',$text); + } $text = str_replace(' ','~',$text); //$text = str_replace('<','\textless ',$text); $text = str_replace('<',' \textless ',$text); @@ -1000,6 +1016,35 @@ class LatexSurveyElement{ } //priprava izpisa zelo dolgega besedila brez presledkov - konec //echo "text potem: ".$text."
    "; + + //detekcija prisotnosti e-naslova v besedilu in primerna preureditev, da pride do pravilnega izpisa + $findAt = '@'; + $numOfAt = substr_count($text, $findAt); //stevilo '@' v besedilu + + $posAt = strpos($text, $findAt); + if($posAt){ //ce je prisotna afna + //echo "afna je: $posAt
    "; + //echo "Encoding: ".$text."
    "; + + //najdi prvi presledek po afni + //echo substr($text, $posAt) ."
    "; + $posSpace1Mail = strpos(substr($text, $posAt), $findSpace); //najdi pozicijo prvega presledka v besedilu po e-naslovu + $posSpace1Mail = $posSpace1Mail+$posAt; //koncna pozicija, ce se gleda celotno besedilo + //echo $posSpace1Mail."
    "; + + //najdi prvi presledek pred afno + $posSpace2Mail = strripos(substr($text, 0, $posAt), $findSpace); //najdi pozicijo zadnjega presledka v besedilu pred e-naslovom + //echo $posSpace2Mail."
    "; + + //dodaj po e-naslovu potrebno latex kodo za zakljucek url + $text = substr_replace($text, '}', $posSpace1Mail, 0); + + //dodaj pred e-naslovom potrebno latex kodo za url + //substr_replace(string_name, replacement_string, start_pos, length) + $text = substr_replace($text, ' \url{', $posSpace2Mail+1, 0); + //echo $text."
    "; + } + //detekcija prisotnosti e-naslova v besedilu in primerna preureditev, da pride do pravilnega izpisa - konec //RESEVANJE BESEDILA V CIRILICI @@ -1012,19 +1057,17 @@ class LatexSurveyElement{ //RESEVANJE odstranitve dodatnih style tag-ov po ul, ipd. ####################################################### - $findStyleTag = 'style="'; - $findStyleTagEnd = '">'; + $findStyleTag = 'style="'; + $findStyleTagEnd = '"'; $numOfStyleTags = substr_count($text, $findStyleTag); //stevilo 'style=" ' v tekstu - //echo "stevilo style: ".$numOfStyleTags."
    "; - - for($s=0; $s<$numOfStyleTags; $s++){ //za vsako najdeno 'style=" ' besedilo, uredi njeno odstranitev - //$posImg = strpos($text, $findImg); + //echo "stevilo style: ".$numOfStyleTags."
    "; + for($s=0; $s<$numOfStyleTags; $s++){ //za vsako najdeno 'style=" ' besedilo, uredi njeno odstranitev $posStyleTag = strpos($text, $findStyleTag); - $posStyleTagEnd = strpos($text, $findStyleTagEnd); + $posStyleTagEnd = strpos($text, $findStyleTagEnd, $posStyleTag); //strpos(string,find,start) najdi $findStyleTagEnd v $text, isci od $posStyleTag dalje $dolzinaOff = $posStyleTagEnd - $posStyleTag + 2; $text = substr_replace($text, "", $posStyleTag, $dolzinaOff); - } + } //RESEVANJE odstranitve dodatnih style tag-ov po ul, ipd. - konec ################################################# if($pos === false && $posImg === false) { //v tekstu ni br in img @@ -1311,7 +1354,8 @@ class LatexSurveyElement{ * @param mixed $vrednost */ function srv_language_vrednost ($vre_id=null) { - if ($this->language != -1) { + //if ($this->language != -1) { + if ($this->prevod) { $sqllString = "SELECT naslov, naslov2 FROM srv_language_vrednost WHERE vre_id='".$vre_id."' AND lang_id='".$this->language."'"; $sqll = sisplet_query($sqllString); $rowl = mysqli_fetch_array($sqll); @@ -1327,7 +1371,8 @@ class LatexSurveyElement{ */ function srv_language_grid ($grd_id=null, $spr_id=null) { - if ($this->language != -1) { + //if ($this->language != -1) { + if ($this->prevod) { $sqllString = "SELECT naslov FROM srv_language_grid WHERE spr_id = '".$spr_id."' AND grd_id='".$grd_id."' AND lang_id='".$this->language."'"; $sqll = sisplet_query($sqllString); $rowl = mysqli_fetch_array($sqll); @@ -2172,10 +2217,12 @@ class LatexSurveyElement{ $loop_id = $loop_id_raw; #za pridobitev stevila vrstic - //echo "SELECT id, naslov, naslov2, variable, other FROM srv_vrednost WHERE spr_id='".$spremenljivke['id']."' ORDER BY vrstni_red"; + //echo "SELECT id, naslov, naslov2, variable, other FROM srv_vrednost WHERE spr_id='".$spremenljivke['id']."' ORDER BY vrstni_red
    "; $sqlVrednostiKombo = sisplet_query("SELECT id, naslov, naslov2, variable, other FROM srv_vrednost WHERE spr_id='".$spremenljivke['id']."' ORDER BY vrstni_red"); $numRowsSql = mysqli_num_rows($sqlVrednostiKombo); //echo $numRowsSql."
    "; + //echo $spremenljivke['id']."
    "; + #za pridobitev stevila vrstic - konec #za pridobitev stevila stolpcev @@ -2184,6 +2231,7 @@ class LatexSurveyElement{ $numColSql = $rowStVrednost['count(*)']; //stevilo vseh stolpcev //echo "stevilo stolpcev: ".$numColSql."
    "; #za pridobitev stevila stolpcev - konec + //echo "presirokaTabela: ".$presirokaTabela."
    "; if($presirokaTabela==0){ //ce tabela ni presiroka $sqlSubGrid = sisplet_query("SELECT m.spr_id, s.tip FROM srv_grid_multiple m, srv_spremenljivka s WHERE m.parent='".$spremenljivke['id']."' AND m.spr_id=s.id ORDER BY m.vrstni_red"); //pridobimo spr_id in tip podvprasanj, ki sestavljajo kombinirano tabelo @@ -2217,9 +2265,12 @@ class LatexSurveyElement{ //echo $sqlVsehVrednostiString."
    "; //echo $rowVrednosti['tip']."
    "; + //echo $rowVrednosti['other']."
    "; //echo "Vrednost: ".$rowVrednosti['spr_id']."
    "; $sqlVsehVrednosti = sisplet_query($sqlVsehVrednostiString); //echo mysqli_num_rows($sqlVsehVrednosti)."
    "; + + $roletaZabelezena = 0; diff --git a/admin/survey/export/latexclasses/textemp/latexTemplatePdfSurvey.cls b/admin/survey/export/latexclasses/textemp/latexTemplatePdfSurvey.cls index eae55b0f1..0770fd126 100644 --- a/admin/survey/export/latexclasses/textemp/latexTemplatePdfSurvey.cls +++ b/admin/survey/export/latexclasses/textemp/latexTemplatePdfSurvey.cls @@ -37,7 +37,7 @@ \urlstyle{same} %nastavitev, da je font URL isti kot je font ostalega besedila (http://ctan.ijs.si/tex-archive/macros/latex/contrib/url/url.pdf) \usepackage{montserrat} % za uporabo Montserrat pisave v dokumentu \usepackage{multirow} % za spajanje vrstic v tabeli -\usepackage{hyperref} +\usepackage[hidelinks]{hyperref} \usepackage{tikz} % za risanje drsnikov \usetikzlibrary{calc} % za risanje drsnikov %definiranje uporabljenih barv diff --git a/admin/survey/export/xmlClasses/Vprasanja/BesediloXml.php b/admin/survey/export/xmlClasses/Vprasanja/BesediloXml.php index f19b92cff..70b0322a5 100644 --- a/admin/survey/export/xmlClasses/Vprasanja/BesediloXml.php +++ b/admin/survey/export/xmlClasses/Vprasanja/BesediloXml.php @@ -7,7 +7,7 @@ * Datum: 10/2018 *****************************************/ -define("VARFORMAT_ELEMENT_TYPE_BESEDILO", "character", true); +define("VARFORMAT_ELEMENT_TYPE_BESEDILO", "character"); class BesediloXml extends XmlSurveyElement { diff --git a/admin/survey/export/xmlClasses/Vprasanja/CheckboxXml.php b/admin/survey/export/xmlClasses/Vprasanja/CheckboxXml.php index 1f6ceba28..312912484 100644 --- a/admin/survey/export/xmlClasses/Vprasanja/CheckboxXml.php +++ b/admin/survey/export/xmlClasses/Vprasanja/CheckboxXml.php @@ -7,8 +7,8 @@ * Datum: 10/2018 *****************************************/ -define("VARGRP_ELEMENT_TYPE", "multipleResp", true); -define("VARFORMAT_ELEMENT_TYPE", "numeric", true); +define("VARGRP_ELEMENT_TYPE", "multipleResp"); +define("VARFORMAT_ELEMENT_TYPE", "numeric"); class CheckboxXml extends XmlSurveyElement { diff --git a/admin/survey/export/xmlClasses/Vprasanja/MultiGridXml.php b/admin/survey/export/xmlClasses/Vprasanja/MultiGridXml.php index b25683b3c..35e9298cb 100644 --- a/admin/survey/export/xmlClasses/Vprasanja/MultiGridXml.php +++ b/admin/survey/export/xmlClasses/Vprasanja/MultiGridXml.php @@ -7,9 +7,9 @@ * Datum: 10/2018 *****************************************/ -define("VARGRP_ELEMENT_TYPE_GRID", "Grid", true); -define("VARGRP_ELEMENT_TYPE_MULTIRESP", "multipleResp", true); -define("VARFORMAT_ELEMENT_TYPE_GRID", "numeric", true); +define("VARGRP_ELEMENT_TYPE_GRID", "Grid"); +define("VARGRP_ELEMENT_TYPE_MULTIRESP", "multipleResp"); +define("VARFORMAT_ELEMENT_TYPE_GRID", "numeric"); class MultiGridXml extends XmlSurveyElement { diff --git a/admin/survey/export/xmlClasses/Vprasanja/RadioXml.php b/admin/survey/export/xmlClasses/Vprasanja/RadioXml.php index e49600894..615cc4749 100644 --- a/admin/survey/export/xmlClasses/Vprasanja/RadioXml.php +++ b/admin/survey/export/xmlClasses/Vprasanja/RadioXml.php @@ -7,7 +7,7 @@ * Datum: 10/2018 *****************************************/ -define("VARFORMAT_ELEMENT_TYPE", "numeric", true); +define("VARFORMAT_ELEMENT_TYPE", "numeric"); class RadioXml extends XmlSurveyElement { diff --git a/admin/survey/export/xmlClasses/Vprasanja/SteviloXml.php b/admin/survey/export/xmlClasses/Vprasanja/SteviloXml.php index 6d5e752d4..cfe32fa66 100644 --- a/admin/survey/export/xmlClasses/Vprasanja/SteviloXml.php +++ b/admin/survey/export/xmlClasses/Vprasanja/SteviloXml.php @@ -7,7 +7,7 @@ * Datum: 10/2018 *****************************************/ -define("VARFORMAT_ELEMENT_TYPE_STEVILO", "numeric", true); +define("VARFORMAT_ELEMENT_TYPE_STEVILO", "numeric"); class SteviloXml extends XmlSurveyElement { diff --git a/admin/survey/export/xmlClasses/class.XmlDocument.php b/admin/survey/export/xmlClasses/class.XmlDocument.php index 931243e0f..3c6f1ba7e 100644 --- a/admin/survey/export/xmlClasses/class.XmlDocument.php +++ b/admin/survey/export/xmlClasses/class.XmlDocument.php @@ -12,7 +12,7 @@ ####################################konec include('../../vendor/autoload.php'); -define("CODEBOOK_VERSION", 2.1, true); +define("CODEBOOK_VERSION", 2.1); class XmlDocument{ diff --git a/admin/survey/export/xmlClasses/class.XmlSurveyElement.php b/admin/survey/export/xmlClasses/class.XmlSurveyElement.php index f903d7dc4..6b830becb 100644 --- a/admin/survey/export/xmlClasses/class.XmlSurveyElement.php +++ b/admin/survey/export/xmlClasses/class.XmlSurveyElement.php @@ -9,12 +9,12 @@ include('../../vendor/autoload.php'); -define("MAX_STRING_LENGTH", 60, true); -define("LINE_BREAK_AT", '7 cm', true); -define("RADIO_BTN_SIZE", 0.13, true); -define("CHCK_BTN_SIZE", 0.13, true); -define("PIC_SIZE_ANS", "\includegraphics[width=3cm]", true); //slika dolocene sirine -define("DROPDOWN_SIZE", 0.8, true); +define("MAX_STRING_LENGTH", 60); +define("LINE_BREAK_AT", '7 cm'); +define("RADIO_BTN_SIZE", 0.13); +define("CHCK_BTN_SIZE", 0.13); +define("PIC_SIZE_ANS", "\includegraphics[width=3cm]"); //slika dolocene sirine +define("DROPDOWN_SIZE", 0.8); class XmlSurveyElement{ diff --git a/admin/survey/index.php b/admin/survey/index.php index f2ad72dee..8ef62aea4 100644 --- a/admin/survey/index.php +++ b/admin/survey/index.php @@ -120,7 +120,7 @@ if(isset($_GET['a']) && ($_GET['a'] == 'hierarhija_superadmin' || $_GET['a'] == 'hierarhija')){ echo ''; } - elseif($_GET['a'] == 'narocila' || ($_GET['t'] == 'uporabniki' && in_array($_GET['m'], ['all', 'my', 'izbrisani', 'nepotrjeni', 'odjavljeni']))){ + elseif($_GET['a'] == 'narocila' || $_GET['t'] == 'uporabniki'){ echo ''; } else{ diff --git a/admin/survey/izvoz.php b/admin/survey/izvoz.php index b7c537827..78b95c71f 100644 --- a/admin/survey/izvoz.php +++ b/admin/survey/izvoz.php @@ -22,84 +22,84 @@ else{ /****** DEFINITIONS ******/ -define("M_ANALIZA_DESCRIPTOR", "descriptor", true); -define("M_ANALIZA_FREQUENCY", "frequency", true); -define("M_ANALIZA_CROSSTAB", "crosstabs", true); -define("M_ANALIZA_STATISTICS", "statistics", true); -define("M_ANALIZA_SUMS", "sums", true); +define("M_ANALIZA_DESCRIPTOR", "descriptor"); +define("M_ANALIZA_FREQUENCY", "frequency"); +define("M_ANALIZA_CROSSTAB", "crosstabs"); +define("M_ANALIZA_STATISTICS", "statistics"); +define("M_ANALIZA_SUMS", "sums"); /*PDF*/ -define("A_REPORT_VPRASALNIK_PDF", "vprasalnik_pdf", true); -define("A_REPORT_PDF_RESULTS","pdf_results",true); -define("A_REPORT_PDF_COMMENT","pdf_comment",true); -define("M_REPORT_ANALIZA_PDF_FREKVENCA","frequency",true); -define("M_REPORT_ANALIZA_PDF_CROSSTAB_IZPIS","crosstabs_izpis",true); -define("M_REPORT_ANALIZA_PDF_MULTICROSSTAB_IZPIS","multicrosstabs_izpis",true); -define("M_REPORT_ANALIZA_PDF_MEAN_IZPIS","mean_izpis",true); -define("M_REPORT_ANALIZA_PDF_TTEST_IZPIS","ttest_izpis",true); -define("M_REPORT_ANALIZA_PDF_BREAK_IZPIS","break_izpis",true); -define("M_REPORT_ANALIZA_PDF_STAT","statistics",true); -define("M_REPORT_ANALIZA_PDF_CHARTS","charts",true); -define("M_REPORT_ANALIZA_PDF_SUMS","sums",true); -define("M_REPORT_ANALIZA_PDF_CREPORT","creport_pdf",true); -define("A_REPORT_PDF_STATUS","status",true); -define("A_REPORT_PDF_EDITS_ANALYSIS","editsAnalysis",true); -define("A_REPORT_PDF_LIST","list_pdf",true); -define("M_REPORT_PDF_EVOLI","pdf_evoli",true); -define("M_REPORT_PDF_TEAMMETER","pdf_teammeter",true); -define("M_REPORT_PDF_EMPLOYMETER","pdf_employmeter",true); -define("M_REPORT_PDF_MFDPS","pdf_mfpds",true); -define("M_REPORT_PDF_MJU","pdf_mju",true); -define("M_REPORT_PDF_MJU2","pdf_mju2",true); -define("M_REPORT_BORZA","borza_chart",true); -define("M_REPORT_PDF_HEATMAP_IMAGE","heatmap_image_pdf",true); -define("M_REPORT_HIERARHIJA_PDF_IZPIS", "hierarhija_pdf_izpis", true); +define("A_REPORT_VPRASALNIK_PDF", "vprasalnik_pdf"); +define("A_REPORT_PDF_RESULTS","pdf_results"); +define("A_REPORT_PDF_COMMENT","pdf_comment"); +define("M_REPORT_ANALIZA_PDF_FREKVENCA","frequency"); +define("M_REPORT_ANALIZA_PDF_CROSSTAB_IZPIS","crosstabs_izpis"); +define("M_REPORT_ANALIZA_PDF_MULTICROSSTAB_IZPIS","multicrosstabs_izpis"); +define("M_REPORT_ANALIZA_PDF_MEAN_IZPIS","mean_izpis"); +define("M_REPORT_ANALIZA_PDF_TTEST_IZPIS","ttest_izpis"); +define("M_REPORT_ANALIZA_PDF_BREAK_IZPIS","break_izpis"); +define("M_REPORT_ANALIZA_PDF_STAT","statistics"); +define("M_REPORT_ANALIZA_PDF_CHARTS","charts"); +define("M_REPORT_ANALIZA_PDF_SUMS","sums"); +define("M_REPORT_ANALIZA_PDF_CREPORT","creport_pdf"); +define("A_REPORT_PDF_STATUS","status"); +define("A_REPORT_PDF_EDITS_ANALYSIS","editsAnalysis"); +define("A_REPORT_PDF_LIST","list_pdf"); +define("M_REPORT_PDF_EVOLI","pdf_evoli"); +define("M_REPORT_PDF_TEAMMETER","pdf_teammeter"); +define("M_REPORT_PDF_EMPLOYMETER","pdf_employmeter"); +define("M_REPORT_PDF_MFDPS","pdf_mfpds"); +define("M_REPORT_PDF_MJU","pdf_mju"); +define("M_REPORT_PDF_MJU2","pdf_mju2"); +define("M_REPORT_BORZA","borza_chart"); +define("M_REPORT_PDF_HEATMAP_IMAGE","heatmap_image_pdf"); +define("M_REPORT_HIERARHIJA_PDF_IZPIS", "hierarhija_pdf_izpis"); /*RTF*/ -define("A_REPORT_VPRASALNIK_RTF", "vprasalnik_rtf", true); -define("A_REPORT_RTF_RESULTS", "rtf_results", true); -define("A_REPORT_RTF_COMMENT","rtf_comment",true); -define("M_REPORT_ANALIZA_RTF_FREKVENCA", "frequency_rtf", true); -define("M_REPORT_ANALIZA_RTF_CROSSTAB_IZPIS", "crosstabs_izpis_rtf", true); -define("M_REPORT_ANALIZA_RTF_MULTICROSSTAB_IZPIS", "multicrosstabs_izpis_rtf", true); -define("M_REPORT_ANALIZA_RTF_MEAN_IZPIS", "mean_izpis_rtf", true); -define("M_REPORT_ANALIZA_RTF_TTEST_IZPIS", "ttest_izpis_rtf", true); -define("M_REPORT_ANALIZA_RTF_BREAK_IZPIS", "break_izpis_rtf", true); -define("M_REPORT_ANALIZA_RTF_STAT", "statistics_rtf", true); -define("M_REPORT_ANALIZA_RTF_SUMS", "sums_rtf", true); -define("M_REPORT_ANALIZA_RTF_CHARTS", "charts_rtf", true); -define("M_REPORT_ANALIZA_RTF_CREPORT", "creport_rtf", true); -define("A_REPORT_RTF_LIST", "list_rtf", true); -define("M_REPORT_ANALIZA_RTF_HEATMAP_IMAGE","heatmap_image_rtf",true); +define("A_REPORT_VPRASALNIK_RTF", "vprasalnik_rtf"); +define("A_REPORT_RTF_RESULTS", "rtf_results"); +define("A_REPORT_RTF_COMMENT","rtf_comment"); +define("M_REPORT_ANALIZA_RTF_FREKVENCA", "frequency_rtf"); +define("M_REPORT_ANALIZA_RTF_CROSSTAB_IZPIS", "crosstabs_izpis_rtf"); +define("M_REPORT_ANALIZA_RTF_MULTICROSSTAB_IZPIS", "multicrosstabs_izpis_rtf"); +define("M_REPORT_ANALIZA_RTF_MEAN_IZPIS", "mean_izpis_rtf"); +define("M_REPORT_ANALIZA_RTF_TTEST_IZPIS", "ttest_izpis_rtf"); +define("M_REPORT_ANALIZA_RTF_BREAK_IZPIS", "break_izpis_rtf"); +define("M_REPORT_ANALIZA_RTF_STAT", "statistics_rtf"); +define("M_REPORT_ANALIZA_RTF_SUMS", "sums_rtf"); +define("M_REPORT_ANALIZA_RTF_CHARTS", "charts_rtf"); +define("M_REPORT_ANALIZA_RTF_CREPORT", "creport_rtf"); +define("A_REPORT_RTF_LIST", "list_rtf"); +define("M_REPORT_ANALIZA_RTF_HEATMAP_IMAGE","heatmap_image_rtf"); /*XLS*/ -define("M_REPORT_ANALIZA_XLS_STAT", "statistics_xls", true); -define("M_REPORT_ANALIZA_XLS_FREKVENCA", "frequency_xls", true); -define("M_REPORT_ANALIZA_XLS_CROSSTAB_IZPIS", "crosstabs_izpis_xls", true); -define("M_REPORT_ANALIZA_XLS_MULTICROSSTAB_IZPIS", "multicrosstabs_izpis_xls", true); -define("M_REPORT_ANALIZA_XLS_SUMS", "sums_xls", true); -define("M_REPORT_ANALIZA_XLS_MEAN_IZPIS", "mean_izpis_xls", true); -define("M_REPORT_ANALIZA_XLS_TTEST_IZPIS", "ttest_izpis_xls", true); -define("M_REPORT_ANALIZA_XLS_BREAK_IZPIS", "break_izpis_xls", true); -define("A_REPORT_XLS_LIST", "list_xls", true); -define("A_REPORT_XLS_USABLE", "usable_xls", true); -define("A_REPORT_XLS_SPEEDER", "speeder_xls", true); -define("A_REPORT_XLS_TEXT_ANALYSIS", "text_analysis_xls", true); -define("A_REPORT_CSV_TEXT_ANALYSIS", "text_analysis_csv", true); -define("M_REPORT_CSV_MAZA_USERS", "maza_csv", true); -define("M_REPORT_CSV_ADVANCED_PARADATA", "advanced_paradata_csv", true); +define("M_REPORT_ANALIZA_XLS_STAT", "statistics_xls"); +define("M_REPORT_ANALIZA_XLS_FREKVENCA", "frequency_xls"); +define("M_REPORT_ANALIZA_XLS_CROSSTAB_IZPIS", "crosstabs_izpis_xls"); +define("M_REPORT_ANALIZA_XLS_MULTICROSSTAB_IZPIS", "multicrosstabs_izpis_xls"); +define("M_REPORT_ANALIZA_XLS_SUMS", "sums_xls"); +define("M_REPORT_ANALIZA_XLS_MEAN_IZPIS", "mean_izpis_xls"); +define("M_REPORT_ANALIZA_XLS_TTEST_IZPIS", "ttest_izpis_xls"); +define("M_REPORT_ANALIZA_XLS_BREAK_IZPIS", "break_izpis_xls"); +define("A_REPORT_XLS_LIST", "list_xls"); +define("A_REPORT_XLS_USABLE", "usable_xls"); +define("A_REPORT_XLS_SPEEDER", "speeder_xls"); +define("A_REPORT_XLS_TEXT_ANALYSIS", "text_analysis_xls"); +define("A_REPORT_CSV_TEXT_ANALYSIS", "text_analysis_csv"); +define("M_REPORT_CSV_MAZA_USERS", "maza_csv"); +define("M_REPORT_CSV_ADVANCED_PARADATA", "advanced_paradata_csv"); /*JSON*/ -define("M_REPORT_JSON_SURVEY_EXPORT", "json_survey", true); +define("M_REPORT_JSON_SURVEY_EXPORT", "json_survey"); -define("A_LANGUAGE_TECHNOLOGY_XLS", "lt_excel", true); +define("A_LANGUAGE_TECHNOLOGY_XLS", "lt_excel"); /*PPT*/ -define("M_REPORT_ANALIZA_PPT_CHARTS", "charts_ppt", true); -define("M_REPORT_ANALIZA_PPT_HEATMAP_IMAGE","heatmap_image_ppt",true); +define("M_REPORT_ANALIZA_PPT_CHARTS", "charts_ppt"); +define("M_REPORT_ANALIZA_PPT_HEATMAP_IMAGE","heatmap_image_ppt"); /*IMAGE*/ -define("M_REPORT_ANALIZA_HEATMAP_IMAGE", "heatmap_image", true); +define("M_REPORT_ANALIZA_HEATMAP_IMAGE", "heatmap_image"); diff --git a/admin/survey/modules/Evalvacija/class.Evalvacija.php b/admin/survey/modules/Evalvacija/class.Evalvacija.php index 282a11888..aaa217e69 100644 --- a/admin/survey/modules/Evalvacija/class.Evalvacija.php +++ b/admin/survey/modules/Evalvacija/class.Evalvacija.php @@ -8,10 +8,10 @@ ini_set('max_execution_time', 3600); // 1800 seconds = 30 minutes * */ -define("TEMP_FOLDER", "admin/survey/modules/Evalvacija/temp", true); -define("SCRIPT_FOLDER", "admin/survey/modules/Evalvacija/R", true); -define("RESULTS_FOLDER", "admin/survey/modules/Evalvacija/results", true); -define("PDF_FOLDER", "admin/survey/modules/Evalvacija/pdf", true); +define("TEMP_FOLDER", "admin/survey/modules/Evalvacija/temp"); +define("SCRIPT_FOLDER", "admin/survey/modules/Evalvacija/R"); +define("RESULTS_FOLDER", "admin/survey/modules/Evalvacija/results"); +define("PDF_FOLDER", "admin/survey/modules/Evalvacija/pdf"); class Evalvacija{ @@ -407,7 +407,7 @@ class Evalvacija{ global $lang; // Inicializiramo class za datoteko s podatki - $SDF = SurveyDataFile::get_instance(); + /*$SDF = SurveyDataFile::get_instance(); // Nastavimo ustrezno anketo za generiranje datoteke s podatki if($this->exportSettings['anketa_pred'] > 0){ @@ -430,7 +430,7 @@ class Evalvacija{ $SDF->prepareFiles(); $this->_headFileName = $SDF->getHeaderFileName(); - $this->_dataFileName = $SDF->getDataFileName(); + $this->_dataFileName = $SDF->getDataFileName();*/ // PRVI CSV - profesorji s predmeti @@ -598,7 +598,7 @@ class Evalvacija{ // Poskrbimo za datoteko s podatki - $SDF = SurveyDataFile::get_instance(); + $SDF = SurveyDataFile::get_instance($force_new=true); $SDF->init($anketa); $SDF->prepareFiles(); @@ -1390,6 +1390,9 @@ class Evalvacija{ if(move_uploaded_file($_FILES['import_csv']['tmp_name'], $target_file)){ //echo 'Datoteka '. basename( $_FILES["fileToUpload"]["name"]). ' je bila uspešno uvožena.'; + // Za odstranjevanje bom znakov + $bom = pack('H*','EFBBBF'); + $file = fopen($target_file, 'r'); while(!feof($file)){ @@ -1405,6 +1408,10 @@ class Evalvacija{ // Ce je stevilo studentov 0 ne uvazamo if($i == 8 && $val == '0') $skip = true; + + // za vsak slucaj odstranimo utf8 bom znake + if($i == 0) + $val = preg_replace("/^$bom/", '', $val); $values .= '\''.$val.'\','; diff --git a/admin/survey/modules/Evalvacija/class.GC.php b/admin/survey/modules/Evalvacija/class.GC.php index 2f3b189da..99db2c6e0 100644 --- a/admin/survey/modules/Evalvacija/class.GC.php +++ b/admin/survey/modules/Evalvacija/class.GC.php @@ -30,18 +30,18 @@ set_time_limit(7200); # 120 minut ini_set('default_socket_timeout', 1000); -define('CERT_FOLDER', "modules/Evalvacija/GC_cert", true); +define('CERT_FOLDER', "modules/Evalvacija/GC_cert"); // Produkcijski streznik -define('GC_URL', "https://gcwserac.uni-lj.si/IntegrationUL/Services/GcService.asmx", true); -//define(WSDL_URL, "https://gcwserac.uni-lj.si/IntegrationUL/Services/GcService.asmx?WSDL", true); +define('GC_URL', "https://gcwserac.uni-lj.si/IntegrationUL/Services/GcService.asmx"); +//define(WSDL_URL, "https://gcwserac.uni-lj.si/IntegrationUL/Services/GcService.asmx?WSDL"); // Direktno produkcijski strežnik za testiranje -//define(GC_URL, "https://193.2.64.32", true); +//define(GC_URL, "https://193.2.64.32"); // Testni streznik -//define(GC_URL, "https://gcwserac-test.uni-lj.si/IntegrationUL/Services/GcService.asmx", true); -//define(WSDL_URL, "https://gcwserac-test.uni-lj.si/IntegrationUL/Services/GcService.asmx?WSDL", true); +//define(GC_URL, "https://gcwserac-test.uni-lj.si/IntegrationUL/Services/GcService.asmx"); +//define(WSDL_URL, "https://gcwserac-test.uni-lj.si/IntegrationUL/Services/GcService.asmx?WSDL"); class GC{ @@ -53,7 +53,8 @@ class GC{ //var $year = '2017_2018'; // Letnica za porocilo //var $year = '2018_2019'; // Letnica za porocilo - var $year = '2019_2020'; // Letnica za porocilo + //var $year = '2019_2020'; // Letnica za porocilo + var $year = '2020_2021'; // Letnica za porocilo var $izvajalec_table = ''; // Katero tabelo izvajalcev uporabljamo - navadna (eval_izvajalec) ali testna (eval_izvajalec2) @@ -183,14 +184,14 @@ class GC{ '4_1' => 'predmeti' ); - $reports_id = '11112020'; - $report_type = '2_2'; - $fak_id = '3000027'; + $reports_id = '02032021'; + $report_type = '1_1'; + $fak_id = '3000001'; $zip_name = ''; // Nastavimo pot do pdf-jev - $this->pdf_path = 'modules/Evalvacija/pdf/unzipped/'; - //$this->pdf_path = 'modules/Evalvacija/pdf/unzipped/'.$fakultete[$fak_id]['kratica'].'/'; + //$this->pdf_path = 'modules/Evalvacija/pdf/unzipped/'; + $this->pdf_path = 'modules/Evalvacija/pdf/unzipped/'.$fakultete[$fak_id]['kratica'].'/'; //$this->pdf_path = 'modules/Evalvacija/pdf/unzipped/'.$fakultete[$fak_id]['kratica'].'/'.$report_type_array[$report_type].'/'; echo 'Parametri:'; @@ -206,7 +207,7 @@ class GC{ //$this->executeManualUpload($zip_name, $fak_id, $report_type, $reports_id, $unzip=false); // BRANJE POROCIL - IZVAJALEC - //$response = $this->readFolder($zadeva_id='RezultatiAnket_'.$fak_id.'_190', $fakultete[$fak_id]['kratica']); + //$response = $this->readFolder($zadeva_id='RezultatiAnket_'.$fak_id.'_321', $fakultete[$fak_id]['kratica']); // BRANJE POROCIL - FAKULTETA //$response = $this->readFolder($zadeva_id='RezultatiAnket_'.$fak_id.'_2019_2020', $fakultete[$fak_id]['kratica']); diff --git a/admin/survey/modules/mod_360/class.Survey360.php b/admin/survey/modules/mod_360/class.Survey360.php index e7ba93c04..6d8485606 100644 --- a/admin/survey/modules/mod_360/class.Survey360.php +++ b/admin/survey/modules/mod_360/class.Survey360.php @@ -1,8 +1,8 @@ 0) { +# install.packages(p_to_install) +# } + +# Load the packages +lapply(p_needed, require, character.only = TRUE) +#------------ //List packages we need// --------------# + + + +#----------------------------------------------------# +# Passing arguments to an R script from command lines +params <- commandArgs(trailingOnly=TRUE) +ID <- params[1] +## //Passing arguments// ## +#---------------------------------------------------# + + + +#---------------------------- CUSTOm FUNCTIONS -----------------------------# +source("modules/mod_EVOLI/R/Functions_QC/my_functions_QC_dan.R") +#---------------------------- CUSTOm FUNCTIONS -----------------------------# + + +#--------------- FOLDERS WHERE PDF WILL BE SAVED ---------------------# +# Tukaj bomo shranili končni PDF +dir.create('modules/mod_EVOLI/results', showWarnings = FALSE) +# Slike Grafa, ki jo bomo shranili s pomočjo funkcije pdf +# Ti sliko bomo nato s pomočjo latex funkcije "includegraphics" +# vstavili v PDF poročilo narejeno s pomočjo tools::texi2pdf +dir.create('modules/mod_EVOLI/results/slike', showWarnings = FALSE) +#--------------- FOLDERS WHERE PDF WILL BE SAVED ---------------------# + + + +#----------------------------- IMPORT DATA ----------------------------# +data <- + read.csv2( + "modules/mod_EVOLI/temp/quality_climate.csv", + sep = ";", + header = T, + fill = T, + encoding = 'UTF-8', + stringsAsFactors = FALSE + ) +if (data[1, 1] == ("Ustreznost") | + data[1, 1] == ("Relevance")) { + data <- data[2:nrow(data),] +} +data <- subset(data, skupina == ID) +# Če oddelek nima podatka oziroma je manjkajoča vrednost, +# ga odstranimo v izogib errorju pri izdelavi frekvenčne tabele +#data <- subset(data, oddelek_ime != -1) +# Izberemo samo koncane ankete +data <- subset(data, status == 6) +#--------------------------- //IMPORT DATA// --------------------------# + + +# TEAMS / ODDELKI # +#################### +# Skupine na podlagi katerih se bodo ra\u010Dunale vrednosti in izrisovale v grafih (glej SINTAX SPODAJ) + +# Pred računanjem odstranimo vrstice z "vrednostmi za neodgovor spremenljivke" +junk.data <- c("-1","-2", "-3", "-4", "-5") +data <- data[!apply(data[grep("var", names(data), value = T)], 1, function(x) {any(x %in% junk.data)}),] + +# Nato potrebujemo število vseh odgovorov, kar bomo v nadaljevanju zapisali generirano tabelo frekvenc in odstotkov +n.answers <- sum(data$XDEPT != "") + +# Oddelki (aggregate data by ime oddelka) +oddelek_length <- aggregate(data[,"oddelek_ime", drop=F], list(group=data$oddelek_ime), length) + +# Izra\u010Dunamo delež odgovorov za vsak oddelek +oddelek_length$percentage <- round(oddelek_length$oddelek_ime / sum(oddelek_length$oddelek_ime) * 100, 1) + +# Chech if the report should be as Single team EM or as Multiple team EM (the difference is that Multiple team Em has departments oddelek_length$group) +if(any(oddelek_length$group == "-1")) { + oddelek_length$group <- unique(data$skupina_ime) + data["oddelek_ime"] <- unique(data$skupina_ime) + +} + + +#-------------------------------- LATEX FREQUENCY TABLE --------------------------------------# + +# Generating table of frequencies and percentages for each area # +table <- cbind.data.frame( + freq=as.numeric(c(oddelek_length$oddelek_ime)), + perc=as.numeric(c(oddelek_length$percentage))) + +# Add TOTAl +table <- rbind(table, colSums(table, na.rm=TRUE)) +# Paste % simbol +table$perc <- round(table$perc, 0) +table$perc <- paste0(table$perc , "\\%", sep="") +# Name of rows +rownames(table) <- c(oddelek_length$group,"Total") +# Name of rows +colnames(table) <- c('Frekvens', 'Procent') +# Latex Table +table.tex <- capture.output(Hmisc::latex(table, + rowlabel="Kvalitetsklima", + file="", + where="H", + rowlabel.just="p{6.5cm}", + col.just=c("|c","|c"), + n.rgroup=rep_len(1, nrow(table)), # vertikalne \u010Drte pri vsaki vrstici + rowname=Hmisc::latexTranslate(rownames(table)))) + +#--------------------------------- //LATEX FREQUENCY TABLE// --------------------------------------# + + + +########################## +## //TEAMS / področja// ## +########################## + + +############################ +# QUALITY CLIMATE +############################ +# Izra\u010Dunamo vrednosti (glej excel datoteko: "Team EM syntax") SINTAX ENERGY METER +# Spremenljivke pretvorimo v številske zaradi ra\u010Dunanja aritmeti\u010Dne sredine +data[grep("var", names(data), value = TRUE)] <- sapply(data[grep("var", names(data), value = TRUE)], as.numeric) + +# SINTAX: ALL TEAMS +################### +### Goals ### +# Najprej izra\u010Dunamo število in deleže ocen vrednosti na lestvici od 1 do 5 +# Ra\u010Dunamo po navodilih datoteke "Team EM syntax": Gre za rekodiranje odgovorov iz lesvice 1-4 na lestvico 1-5 +goals <- prep.dat(data, c("var001", "var016", "var031", "var046")) + +### Organising ourselves/sharing responsibility ### +responsibility <- prep.dat( + data, + c( + "var002", + "var017", + "var032", + "var047", + "var061", + "var075", + "var089", + "var100", + "var105" + ) +) + +### Effectiveness/productivity ### +effectiveness <- prep.dat(data, + c( + "var003", + "var018", + "var033", + "var048", + "var062", + "var076", + "var090" + )) + +### Decisions ### +decisions <- prep.dat(data, + c( + "var004", + "var019", + "var034", + "var049", + "var063", + "var077", + "var091" + )) + +### Delegation ### +delegation <- prep.dat(data, + c("var005", "var020", "var035", "var050", "var064", "var078")) + + + +### Internal communication and coordination ### +intercomcord <- prep.dat(data, + c( + "var006", + "var021", + "var036", + "var051", + "var065", + "var079", + "var092" + )) + +### External communication and coordination ### +extercomcord <- prep.dat(data, + c( + "var007", + "var022", + "var037", + "var052", + "var066", + "var080", + "var093" + )) + + +### Physical environment ### +environment <- prep.dat(data, + c( + "var008", + "var023", + "var038", + "var053", + "var067", + "var081", + "var094", + "var101" + )) + + + +### Quality awareness ### +qAwarness <- prep.dat( + data, + c( + "var009", + "var024", + "var039", + "var054", + "var068", + "var082", + "var095", + "var102" + ) +) + + +### Creativity and innovation ### +innovation <- prep.dat(data, + c("var010", "var025", "var040", "var055", "var069", "var083")) + + + +### Commitment ### +commitment <- prep.dat(data, + c( + "var011", + "var026", + "var041", + "var056", + "var070", + "var084", + "var096" + )) + + + +### Recognition and rewards ### +recrew <- prep.dat(data, + c( + "var012", + "var027", + "var042", + "var057", + "var071", + "var085", + "var097" + )) + + +### Personal development ### +persondev <- prep.dat(data, + c("var013", "var028", "var043", "var058", "var072", "var086")) + + + +### Other psychological environmnet (relationships) ### +othr <- prep.dat(data, + c( + "var014", + "var029", + "var044", + "var059", + "var073", + "var087", + "var098", + "var103" + )) + + +### Implementation ### +implementation <- prep.dat( + data, + c( + "var015", + "var030", + "var045", + "var060", + "var074", + "var088", + "var099", + "var104" + ) +) + + +## //SINTAX ENERGY METER ALL TEAMS // ## + + +# Data preparation for ggplot ALL TEAMS +####################################### +# Dodamo labele frekvencam (1-5), ki se bodo izrisale v grafih +# Commitment + +goals <- labScore(goals, "M\u00E5l") +responsibility <- + labScore(responsibility, "Ansvarsfordeling/organisation") +effectiveness <- labScore(effectiveness, "Effektivitet/produktivitet") +decisions <- labScore(decisions, "Beslutninger") +delegation <- labScore(delegation, "Delegering") +intercomcord <- + labScore(intercomcord, "Intern kommunikation og koordination") +extercomcord <- + labScore(extercomcord, "Ekstern kommunikation og koordination") +environment <- labScore(environment, "Fysisk milj\u00F8") +qAwarness <- labScore(qAwarness, "Kvalitetsbevidsthed") +innovation <- labScore(innovation, "Kreativitet og innovation") +commitment <- labScore(commitment, "Engagement") +recrew <- labScore(recrew, "Anerkendelse og bel\u00F8nning") +persondev <- labScore(persondev, "Personlig udvikling") +othr <- labScore(othr, "\u00D8vrigt psykisk milj\u00F8 (relationer)") +implementation <- labScore(implementation, "Implementering") + +# Combine all variables and create data frame +df <- + rbind( + goals, + responsibility, + effectiveness, + decisions, + delegation, + intercomcord, + extercomcord, + environment, + qAwarness, + innovation, + commitment, + recrew, + persondev, + othr, + implementation + ) + +# Get the levels for type in the required order +df$label = factor( + df$label, + levels = c( + "Meget utilfredsstillende", + "Utilfredsstillende", + "Gennemsnitlig", + "Meget tilfredsstillende", + "S\u00E6rdeles tilfredsstillende" + ) +) +df = arrange(df, name, desc(label)) + +# Format the labels and calculate their positions +df = ddply(df, .(name), transform, pos = (cumsum(Prcentage) - 0.5 * Prcentage)) +df$label1 = paste0(sprintf("%.0f", df$Prcentage), "%") + +# User-defined order of names on axis +df$name <- + factor( + df$name , + levels = c( + rev(c("M\u00E5l", + "Ansvarsfordeling/organisation", + "Effektivitet/produktivitet", + "Beslutninger", + "Delegering", + "Intern kommunikation og koordination", + "Ekstern kommunikation og koordination", + "Fysisk milj\u00F8", + "Kvalitetsbevidsthed", + "Kreativitet og innovation", + "Engagement", + "Anerkendelse og bel\u00F8nning", + "Personlig udvikling", + "\u00D8vrigt psykisk milj\u00F8 (relationer)", + "Implementering" + ) + ) + ) + ) +df <- df[order(df$name), ] + + +## GGPLOT Employeeship for all teams ## +####################################### +# BEGIN: Save ggplot to pdf +cairo_pdf( + paste('modules/mod_EVOLI/results/slike/meter_all_teams.pdf', sep = ''), + pointsize = 12, + width = 9, + height = 6.5 +) + +p <- ggplot(df, aes(x = factor(name))) + + + # Vertikalne sive \u010Drte prikazana za stolpi\u010Dnim diagramom + geom_hline(yintercept = 0, col="gray",alpha=0.5, size=0.7) + + geom_hline(yintercept = 10, col="gray",alpha=0.5, size=0.7) + + geom_hline(yintercept = 30, col="gray",alpha=0.5, size=0.7) + + geom_hline(yintercept = 40, col="gray",alpha=0.5, size=0.7) + + geom_hline(yintercept = 60, col="gray",alpha=0.5, size=0.7) + + geom_hline(yintercept = 70, col="gray",alpha=0.5, size=0.7) + + geom_hline(yintercept = 80, col="gray",alpha=0.5, size=0.7) + + geom_hline(yintercept = 90, col="gray",alpha=0.5, size=0.7) + + geom_hline(yintercept = 100, col="gray",alpha=0.5, size=0.7) + + + # Dolo\u010Dimo položaj prikaza deležev v grafu + geom_col(aes(y = Prcentage, fill = label), + position = position_stack(reverse = TRUE), + width = .5) + + + # Vertikalne rde\u010De \u010Drte prikazana na rde\u010Di \u010Drti + geom_hline( + yintercept = 20, + colour = "#AA0000", + alpha = 1, + size = 0.8 + ) + + geom_hline( + yintercept = 50, + colour = "#AA0000", + alpha = 1, + size = 0.8 + ) + + + # Set the position to its complementary /izris deležev + geom_text(aes(y = 100 - pos, label = label1), size = 4) + + + # Rest of theme + coord_flip() + + scale_y_continuous( + position = "right", + # položaj osi je na vrgu grafa + expand = c(0, 0), + breaks = seq(min(0), max(0, 102), by = 10), + limits = c(0, 102), + labels = dollar_format(suffix = "%", prefix = "") + ) + + scale_fill_manual( + values = c("#ff0000", "#ffff00", "#b2b2b2", "#1baf05", "#007FFF"), + drop = FALSE + ) + + xlab("") + ylab("") + + theme_bw() + theme( + axis.line = element_blank(), + panel.grid.major = element_blank(), + panel.grid.minor = element_blank(), + panel.border = element_blank(), + panel.background = element_blank() + ) + + theme( + legend.position = "bottom", + legend.title = element_blank(), + legend.key.size = unit(0.7, "line"), + legend.text = element_text(size = 12) + ) + +# Add axis text colour, size and style +p1 <- p + theme(axis.text.x = element_text(colour="black",size=11,face="plain"), + axis.text.y = element_text(colour="black",size=11,face="plain"), + plot.margin=unit(c(1, 1, 1, -0.4), units="line"), + plot.background = element_rect(colour = 'gray', fill = 'NA', size = 0.5), + plot.title = element_text(hjust = 0.4,size = 15, face = "bold")) #+ + +p1 <- p1 + guides(fill = guide_legend(nrow = 2, byrow = TRUE)) +#ggtitle("Employeeship for all teams") + +print(p1 + theme(axis.ticks=element_blank())) + +dev.off() # END: Save ggplot to pdf +# Shranimo sliko in vklju\u010Dimo v pdf: LATEX +tex.meter_all_tems <- c(paste0( + "\\begin{figure}[H]", + # "\\caption{ \\textbf{\\large{Employeeship for all teams}}}", + paste0( + "\\centerline{\\includegraphics[width=1\\textwidth]{slike/meter_all_teams.pdf}}" + ), + "\\end{figure}" +)) +#################################### +## //Employeeship for all teams// ## +#################################### + + +################################################################################################ +########### Employeeship for seperate team: Management, services, infiormatics etc. ############ +################################################################################################ + + +################################### +# Team Employeeship Meter: Services +################################### +Oddeleki.tmp <- list() + +if (nrow(oddelek_length) > 0) { + for(oddelek in oddelek_length$group) { + + Oddelki_podatki <- subset(data, oddelek == oddelek_ime) + Oddelki_podatki[grep("var", names(Oddelki_podatki), value = TRUE)] <- + sapply(Oddelki_podatki[grep("var", names(Oddelki_podatki), value = TRUE)], as.numeric) + + + #---------------------------------- FILLABLE NOTES/FORMS-------------------------------------# + # Pod vsakim grafom "Team Employeeship Meter" naj bo za vnos komentarjev (fillable form) + # simbol svinčnika + simbol <- "\\ding{46} " + # Ime forme + label_Notes <- "Bem\u00E6rkninger:" + # Forma + form <- c("\\begin{Form} + \\noindent + \\TextField[name=",oddelek,", multiline=true, width=\\linewidth,height=9cm,bordercolor=0 0 0]{} + \\end{Form}") + # Concetinate + FillableFORM <- c(simbol, label_Notes, "\\\\[0.1cm]",form) + # Not needed right now + vspace <- "\\vspace*{18pt}" + #---------------------------------- //FILLABLE NOTES/FORMS// -------------------------------------# + + + ### GOALS ### + # Najprej izračunamo število in deleže ocen vrednosti na lestvici od 1 do 4 in jih pretvorimo na lestivo 1 do 5 + odd_goals <- prep.dat(Oddelki_podatki, c("var001", "var016", "var031", "var046")) + + + ### RESPONSIBILITY ### + odd_res <- prep.dat( + Oddelki_podatki, + c( + "var002", + "var017", + "var032", + "var047", + "var061", + "var075", + "var089", + "var100", + "var105" + ) + ) + + ### Effectiveness/productivity ### + odd_effect <- prep.dat(Oddelki_podatki, + c( + "var003", + "var018", + "var033", + "var048", + "var062", + "var076", + "var090" + )) + + ### Decisions ### + odd_dec <- prep.dat(Oddelki_podatki, + c( + "var004", + "var019", + "var034", + "var049", + "var063", + "var077", + "var091" + )) + + ### Delegation ### + odd_deleg <- prep.dat(Oddelki_podatki, + c("var005", "var020", "var035", "var050", "var064", "var078")) + + + + ### Internal communication and coordination ### + odd_intercomcord <- prep.dat(Oddelki_podatki, + c( + "var006", + "var021", + "var036", + "var051", + "var065", + "var079", + "var092" + )) + + ### External communication and coordination ### + odd_extercomcord <- prep.dat(Oddelki_podatki, + c( + "var007", + "var022", + "var037", + "var052", + "var066", + "var080", + "var093" + )) + + + ### Physical environment ### + odd_envir <- prep.dat(Oddelki_podatki, + c( + "var008", + "var023", + "var038", + "var053", + "var067", + "var081", + "var094", + "var101" + )) + + + + ### Quality awareness ### + odd_qAwarness <- prep.dat( + Oddelki_podatki, + c( + "var009", + "var024", + "var039", + "var054", + "var068", + "var082", + "var095", + "var102" + ) + ) + + + ### Creativity and innovation ### + odd_innov <- prep.dat(Oddelki_podatki, + c("var010", "var025", "var040", "var055", "var069", "var083")) + + + + ### Commitment ### + odd_commit <- prep.dat(Oddelki_podatki, + c( + "var011", + "var026", + "var041", + "var056", + "var070", + "var084", + "var096" + )) + + + + ### Recognition and rewards ### + odd_recrew <- prep.dat(Oddelki_podatki, + c( + "var012", + "var027", + "var042", + "var057", + "var071", + "var085", + "var097" + )) + + + ### Personal development ### + odd_persondev <- prep.dat(Oddelki_podatki, + c("var013", "var028", "var043", "var058", "var072", "var086")) + + + + ### Other psychological environmnet (relationships) ### + odd_othr <- prep.dat(Oddelki_podatki, + c( + "var014", + "var029", + "var044", + "var059", + "var073", + "var087", + "var098", + "var103" + )) + + + ### Implementation ### + odd_implem <- prep.dat( + Oddelki_podatki, + c( + "var015", + "var030", + "var045", + "var060", + "var074", + "var088", + "var099", + "var104" + ) + ) + + + + # Data preparation for ggplot Oddelki_podatki + ###################################### + # Commitment + odd_goals <- labScore(odd_goals, "M\u00E5l") + odd_res <- labScore(odd_res, "Ansvarsfordeling/organisation") + odd_effect <- labScore(odd_effect, "Effektivitet/produktivitet") + odd_dec <- labScore(odd_dec, "Beslutninger") + odd_deleg <- labScore(odd_deleg, "Delegering") + odd_intercomcord <- labScore(odd_intercomcord, "Intern kommunikation og koordination") + odd_extercomcord <- labScore(odd_extercomcord, "Ekstern kommunikation og koordination") + odd_envir <- labScore(odd_envir, "Fysisk milj\u00F8") + odd_qAwarness <- labScore(odd_qAwarness, "Kvalitetsbevidsthed") + odd_innov <- labScore(odd_innov, "Kreativitet og innovation") + odd_commit <- labScore(odd_commit, "Engagement") + odd_recrew <- labScore(odd_recrew, "Anerkendelse og bel\u00F8nning") + odd_persondev <- labScore(odd_persondev, "Personlig udvikling") + odd_othr <- labScore(odd_othr, "\u00D8vrigt psykisk milj\u00F8 (relationer)") + odd_implem <- labScore(odd_implem, "Implementering") + + # Combine all variables and create data frame + odd.df <- + rbind( + odd_goals, + odd_res, + odd_effect, + odd_dec, + odd_deleg, + odd_intercomcord, + odd_extercomcord, + odd_envir, + odd_qAwarness, + odd_innov, + odd_commit, + odd_recrew, + odd_persondev, + odd_othr, + odd_implem + ) + + # Get the levels for type in the required order + odd.df$label = factor( + odd.df$label, + levels = c( + "Meget utilfredsstillende", + "Utilfredsstillende", + "Gennemsnitlig", + "Meget tilfredsstillende", + "S\u00E6rdeles tilfredsstillende" + ) + ) + odd.df = arrange(odd.df, name, desc(label)) + + # Format the labels and calculate their positions + odd.df = ddply(odd.df, .(name), transform, pos = (cumsum(Prcentage) - 0.5 * Prcentage)) + odd.df$label1 = paste0(sprintf("%.0f", odd.df$Prcentage), "%") + + # User-defined order of names on axis + odd.df$name <- + factor( + odd.df$name , + levels = rev(c("M\u00E5l", + "Ansvarsfordeling/organisation", + "Effektivitet/produktivitet", + "Beslutninger", + "Delegering", + "Intern kommunikation og koordination", + "Ekstern kommunikation og koordination", + "Fysisk milj\u00F8", + "Kvalitetsbevidsthed", + "Kreativitet og innovation", + "Engagement", + "Anerkendelse og bel\u00F8nning", + "Personlig udvikling", + "\u00D8vrigt psykisk milj\u00F8 (relationer)", + "Implementering" + ) + ) + ) + odd.df <- odd.df[order(odd.df$name),] + + + ## GGPLOT Employeeship Oddelki_podatki ## + ################################## + + cairo_pdf( + paste( + 'modules/mod_EVOLI/results/slike/meter_', + gsub("\\.|\\_|\\-|\\&| ","",oddelek), + '.pdf', + sep = "" + ), + pointsize = 15, + width = 9, + height = 6.5 + ) + + S <- ggplot(odd.df, aes(x = factor(name))) + + + # Vertikalne sive črte prikazana za stolpičnim diagramom + geom_hline(yintercept = 0, col="gray",alpha=0.5, size=0.7) + + geom_hline(yintercept = 10, col="gray",alpha=0.5, size=0.7) + + geom_hline(yintercept = 30, col="gray",alpha=0.5, size=0.7) + + geom_hline(yintercept = 40, col="gray",alpha=0.5, size=0.7) + + geom_hline(yintercept = 60, col="gray",alpha=0.5, size=0.7) + + geom_hline(yintercept = 70, col="gray",alpha=0.5, size=0.7) + + geom_hline(yintercept = 80, col="gray",alpha=0.5, size=0.7) + + geom_hline(yintercept = 90, col="gray",alpha=0.5, size=0.7) + + geom_hline(yintercept = 100, col="gray",alpha=0.5, size=0.7) + + + # Določimo položaj prikaza deležev v grafu + geom_col(aes(y = Prcentage, fill = label), position = position_stack(reverse = TRUE), width = .5) + + + # Vertikalne rdeče črte prikazana na rdeči črti + geom_hline(yintercept = 20, colour="#AA0000", alpha=1, size=0.8) + + geom_hline(yintercept = 50, colour="#AA0000", alpha=1, size=0.8) + + + # Set the position to its complementary /izris deležev + geom_text(aes(y = 100 - pos, label = label1), size=4) + + + # Rest of theme + coord_flip() + + scale_y_continuous(position = "right", # položaj osi je na vrgu grafa + expand = c(0, 0), + breaks = seq(min(0), max(0,102), by = 10), + limits = c(0,102), + labels = dollar_format(suffix = "%", prefix = "")) + + scale_fill_manual(values = c("#ff0000","#ffff00","#b2b2b2","#1baf05","#007FFF"), drop = FALSE) + + xlab("") + ylab("") + + theme_bw() + theme(axis.line = element_blank(), + panel.grid.major = element_blank(), + panel.grid.minor = element_blank(), + panel.border = element_blank(), + panel.background = element_blank()) + + theme(legend.position="bottom",legend.title = element_blank(),legend.key.size = unit(0.7,"line"),legend.text=element_text(size=12)) + + # Add axis text colour, size and style + S1 <- S + theme(axis.text.x = element_text(colour="black",size=11,face="plain"), + axis.text.y = element_text(colour="black",size=11,face="plain"), + plot.margin=unit(c(1, 1, 1, -0.4), units="line"), + plot.background = element_rect(colour = 'gray', fill = 'NA', size = 0.5), + plot.title = element_text(hjust = 0.4,size = 15, face = "bold")) + + ggtitle(oddelek) # In case of leter č we need to add extra space because of encoding + + S1 <- S1 + guides(fill = guide_legend(nrow = 2, byrow = TRUE)) + + print(S1 + theme(axis.ticks=element_blank())) + + + dev.off() # Save ggplot to pdf + + Oddeleki.tmp[[oddelek]] <- c(paste0( + "\\begin{figure}[H]", + #"\\caption{ \\textbf{\\large{Oddelki_podatki}}}", + paste0( + "\\centerline{\\includegraphics[width=1\\textwidth]{slike/meter_", + gsub("\\.|\\_|\\-|\\&| ","",oddelek), + ".pdf}}" + ), + "\\end{figure}" + ), + FillableFORM) + + }} else { + Oddeleki.tmp[[oddelek]] <- NULL + fillableForm_Serv <- NULL + vspace <- NULL + } + + +## //Employeeship Oddelki_podatki// ## +############################### + + + +###################################################### +## Team scores for each of the 11 Employeeship factors +###################################################### + +#--------------------------------------- COMITMENT -------------------------------------------# + + +#------------------------ ORGANIZATION INFORMATION --------------------------# +# Ime organizacije +organisation <- ifelse( + all(unique(data$itime) %in% junk.data), + "", + unique(data$skupina_ime) +) +# Datum na prvi strani +date <- ifelse( + all(unique(data$itime) %in% junk.data), + "", + unique(data$itime) +) +# Ce ni imena izpise samo Spostovani +customer <- + ifelse( + all(unique(data$ime) %in% junk.data), + "K\u00E6re!", + paste0("K\u00E6re ", data$ime, "!") + ) + +# Mali č +organisation <- gsub("\u010D", "č", organisation, fixed = TRUE) +# Velik Č +organisation <- gsub("\u010C", "Č", organisation, fixed = TRUE) +# Mali ž +organisation <- gsub("\u017E", "ž", organisation, fixed = TRUE) +# Velik Ž +organisation <- gsub("\u017D", "Ž", organisation, fixed = TRUE) +# Mali š +organisation <- gsub("\u0161", "š", organisation, fixed = TRUE) +# Velik Š +organisation <- gsub("\u0160", "š", organisation, fixed = TRUE) +# Mali đ +organisation <- gsub("\u0111", "đ", organisation, fixed = TRUE) +# Velik đ +organisation <- gsub("\u0110", "Đ", organisation, fixed = TRUE) +#--------------------- //ORGANIZATION INFORMATION// ------------------------# + + + +################## +# Generiranje PDF +################## +# Opredelitev delov za koncni dokument +# Definiranje dokumenta +glava_tex <- + scan( + "modules/mod_EVOLI/latexkosi/glava-quality_clime_dan.tex", + character(0), + sep = "\n", + quiet = TRUE, + encoding = 'UTF-8' + ) +# Drugi del +drugi_del_tex <- + scan( + "modules/mod_EVOLI/latexkosi/drugi_del-quality_clime_dan.tex", + character(0), + sep = "\n", + quiet = TRUE, + encoding = 'UTF-8' + ) +# Zamenjava organizacije v glavi +glava_tex <- + gsub( + '!organisation!', + Hmisc::latexTranslate(organisation), + glava_tex, + fixed = TRUE + ) +# Datum +glava_tex <- + gsub( + '!date!', + Hmisc::latexTranslate(date), + glava_tex, + fixed = TRUE + ) +# Ime podjetja +glava_tex <- + gsub( + '!company name!', + Hmisc::latexTranslate(organisation), + glava_tex, + fixed = TRUE + ) +# Ime stranke +glava_tex <- + gsub( + '!name!', + Hmisc::latexTranslate(customer), + glava_tex, + fixed = TRUE + ) +Rdirektorij <- getwd() # Get working diretory + +# Compiling file +tex.izbor <- c( + glava_tex, + tex.meter_all_tems, + "\\vspace*{30px}", + "\\begin{center}", + organisation , + "\\end{center}", + table.tex, + "\\chapter{\\Large Kvalitetsklima}", + Oddeleki.tmp, + drugi_del_tex, + "\\end{document}" +) +# Compile PDF +setwd(paste(Rdirektorij, "modules/mod_EVOLI/results", sep="/")) # File folder +cat(unlist(tex.izbor), file=paste0("Kvalitetsklima.tex"), sep="\n") # Name of tex file +tools::texi2pdf(file=paste0("Kvalitetsklima.tex"), quiet=TRUE, clean=TRUE) # Pdf file +setwd(Rdirektorij) \ No newline at end of file diff --git a/admin/survey/modules/mod_EVOLI/R/Functions_QC/my_functions_QC_dan.R b/admin/survey/modules/mod_EVOLI/R/Functions_QC/my_functions_QC_dan.R new file mode 100644 index 000000000..2d9508e0b --- /dev/null +++ b/admin/survey/modules/mod_EVOLI/R/Functions_QC/my_functions_QC_dan.R @@ -0,0 +1,79 @@ + +#------------------------------------ Load some usefull functions ------------------------------------# +# Ustvarimo svojo funkcijo, ki vedno števila z 0.5 zaokrožila navzgor +# (glej "Variables and syntax Quality Climate 22072019 - FDV (1)".xlsx) +round2 = function(x) { + x <- round(x, 1) + # Najprej rekodiramo rezultate kot želi + # stranka: glej file + # "Variables and syntax Quality Climate 22072019 - FDV (1).xlsx" + x <- ifelse(x >= 4.9, 5, + ifelse(x >=4.1 & x <= 4.8, 4, ifelse( + x >= 3.1 & x <= 4.0, 3, ifelse( + x >= 2.1 & x <= 3.0, 2, ifelse( + x >= 1.3 & x <= 2.0, 1, NA + ) + ) + ) + ) + ) + x +} + + + +#prepare data for plot +prep.dat <- function(df, variable) { + df <- round2(rowMeans(df[, variable], na.rm = TRUE) / 4 * 5) + df <- data.frame(prop.table(table(df)) * 100) + names(df)[1] <- "Frequency" + names(df)[2] <- "Prcentage" + # Check if there is no labels + # We want to show values from 1 - 5 + # Therefore is some is missing we will + # create it and assign it 0 + # if (nrow(df) < 5) { + # miss <- 1:5 + # # Check diff + # dif <- setdiff(miss, df[,1]) + # # Check how many data we are missing + # miss.dummy <- df[1:length(dif),] + # # Clone data + # miss.dummy$Frekvens <- dif + # # # Add zeero + # miss.dummy$Procent <- 0 + # # Finally Rbind + # df <- rbind(miss.dummy, df) + # # And order + # df <- df[order(df$Frekvens),] + # } + return(df) +} + + +# name po katerih bomo razvrstili stolpce v grafu +labScore <- function(df, labelord) { + df$label <- ifelse(df$Frequency == 1, + "Meget utilfredsstillende", + ifelse( + df$Frequency == 2, + "Utilfredsstillende", + ifelse( + df$Frequency == 3, + "Gennemsnitlig", + ifelse( + df$Frequency == 4, + "Meget tilfredsstillende", + ifelse(df$Frequency == 5, "S\u00E6rdeles tilfredsstillende", NA) + ) + ) + )) + + # Imena po katerih bomo razvrstili stolpce v grafih + df$name <- labelord + + return(df) + +} + +#---------------------------------- //Load some usefull functions// ----------------------------------# \ No newline at end of file diff --git a/admin/survey/modules/mod_EVOLI/class.SurveyEmployMeter.php b/admin/survey/modules/mod_EVOLI/class.SurveyEmployMeter.php index 597d703c4..5b181885d 100644 --- a/admin/survey/modules/mod_EVOLI/class.SurveyEmployMeter.php +++ b/admin/survey/modules/mod_EVOLI/class.SurveyEmployMeter.php @@ -2,9 +2,9 @@ include_once 'definition.php'; -define("TEMP_FOLDER", "admin/survey/modules/mod_EVOLI/temp", true); -define("SCRIPT_FOLDER", "admin/survey/modules/mod_EVOLI/R", true); -define("RESULTS_FOLDER", "admin/survey/modules/mod_EVOLI/results", true); +define("TEMP_FOLDER", "admin/survey/modules/mod_EVOLI/temp"); +define("SCRIPT_FOLDER", "admin/survey/modules/mod_EVOLI/R"); +define("RESULTS_FOLDER", "admin/survey/modules/mod_EVOLI/results"); class SurveyEmployMeter{ diff --git a/admin/survey/modules/mod_EVOLI/class.SurveyEvoli.php b/admin/survey/modules/mod_EVOLI/class.SurveyEvoli.php index 904442d14..49b8f3f0e 100644 --- a/admin/survey/modules/mod_EVOLI/class.SurveyEvoli.php +++ b/admin/survey/modules/mod_EVOLI/class.SurveyEvoli.php @@ -2,9 +2,9 @@ include_once 'definition.php'; -define("TEMP_FOLDER", "admin/survey/modules/mod_EVOLI/temp", true); -define("SCRIPT_FOLDER", "admin/survey/modules/mod_EVOLI/R", true); -define("RESULTS_FOLDER", "admin/survey/modules/mod_EVOLI/results", true); +define("TEMP_FOLDER", "admin/survey/modules/mod_EVOLI/temp"); +define("SCRIPT_FOLDER", "admin/survey/modules/mod_EVOLI/R"); +define("RESULTS_FOLDER", "admin/survey/modules/mod_EVOLI/results"); class SurveyEvoli{ diff --git a/admin/survey/modules/mod_EVOLI/class.SurveyTeamMeter.php b/admin/survey/modules/mod_EVOLI/class.SurveyTeamMeter.php index 87bbb5035..5d7a36795 100644 --- a/admin/survey/modules/mod_EVOLI/class.SurveyTeamMeter.php +++ b/admin/survey/modules/mod_EVOLI/class.SurveyTeamMeter.php @@ -2,11 +2,11 @@ include_once 'definition.php'; -define("TEMP_FOLDER", "admin/survey/modules/mod_EVOLI/temp", true); -define("SCRIPT_FOLDER", "admin/survey/modules/mod_EVOLI/R", true); -define("RESULTS_FOLDER", "admin/survey/modules/mod_EVOLI/results", true); +define("TEMP_FOLDER", "admin/survey/modules/mod_EVOLI/temp"); +define("SCRIPT_FOLDER", "admin/survey/modules/mod_EVOLI/R"); +define("RESULTS_FOLDER", "admin/survey/modules/mod_EVOLI/results"); -define("EXPORT_FOLDER", "admin/survey/SurveyData", true); +define("EXPORT_FOLDER", "admin/survey/SurveyData"); class SurveyTeamMeter{ @@ -60,7 +60,7 @@ class SurveyTeamMeter{ // DANSCINA if(isset($_GET['lang_id']) && $_GET['lang_id'] == '29'){ $this->execute_params['script_name'] = 'Evoli_quality_clime_dan.R'; - $this->execute_params['pdf_name'] = 'Quality-climate-dan'; + $this->execute_params['pdf_name'] = 'Kvalitetsklima.pdf'; } // SLOVENSCINA elseif(isset($_GET['lang_id']) && $_GET['lang_id'] == '1'){ @@ -477,8 +477,8 @@ class SurveyTeamMeter{ } // Zaenkrat dopuscamo samo status 6 in brez lurkerjev - define('STATUS_FIELD', '$4', true); - define('LURKER_FIELD', '$5', true); + define('STATUS_FIELD', '$4'); + define('LURKER_FIELD', '$5'); $status_filter = '('.STATUS_FIELD.' ~ /6|5/)&&('.LURKER_FIELD.'==0)'; //$status_filter = '($4 ~ /6|5/)&&($5==0)'; //$status_filter = '('.STATUS_FIELD.'==6)&&('.LURKER_FIELD.'==0)'; diff --git a/admin/survey/modules/mod_EVOLI/latexkosi/drugi_del-quality_clime_ang.tex b/admin/survey/modules/mod_EVOLI/latexkosi/drugi_del-quality_clime_ang.tex index 9f92221b8..6c138d02e 100644 --- a/admin/survey/modules/mod_EVOLI/latexkosi/drugi_del-quality_clime_ang.tex +++ b/admin/survey/modules/mod_EVOLI/latexkosi/drugi_del-quality_clime_ang.tex @@ -114,7 +114,7 @@ role in contributing to society. \newpage % 3. STRAN PO GRAFIH -\chapter{\Large \textbf{Quality Climate recommendations}} +\chapter{\Large \textbf{Quality Climate Recommendation}} \begin{center} \begin{minipage}{0.8\linewidth} To create, maintain and develop the \textit{Quality Climate}, we strongly \\ @@ -126,8 +126,8 @@ recommend using the three other tools: \begin{itemize} \addtolength{\itemindent}{2.2cm} \item Star Quality -\item Team Energy Meter -\item Organisational Energy Meter +\item Team Employeeship Meter +\item Organisational Employeeship Meter \end{itemize} \end{minipage} \end{center} @@ -141,12 +141,12 @@ recommend using the three other tools: \ \\ \\ -"Star Quality" is a tool to monitor, evaluate and develop the quality \\ +\textit{'Star Quality'} is a tool to monitor, evaluate and develop the quality \\ of a team's collective performance so it constantly meets the \\ demands and expectations of other people. \\ \ \\ -This tool contains five steps: +This tool contains five elements: \\ \renewcommand\labelitemi{\large$\bullet$} \textbf{ @@ -206,10 +206,10 @@ contribute to the survival, growth, and long-term success of the \\ organisation. \\ \\ -The Team Energy Meter describes 11 factors which can form part \\ +The Team Employeeship Meter describes 11 factors which can form part \\ of evaluating whether the attitude and behaviour of an employee \\ demonstrate Employeeship. These 11 factors also form part of the \\ -tool "Personal Employeeship Meter". +tool \textit{Personal Employeeship Meter}. \end{minipage} \end{center} diff --git a/admin/survey/modules/mod_EVOLI/latexkosi/drugi_del-quality_clime_dan.tex b/admin/survey/modules/mod_EVOLI/latexkosi/drugi_del-quality_clime_dan.tex new file mode 100644 index 000000000..c436ebb6e --- /dev/null +++ b/admin/survey/modules/mod_EVOLI/latexkosi/drugi_del-quality_clime_dan.tex @@ -0,0 +1,401 @@ +% 1. STRAN PO GRAFIH +\chapter{\Large \textbf{17 kendetegn for en kvalitetsvirksomhed}} +\begin{center} +\begin{minipage}{0.8\linewidth} +\textbf{1. Kvalitetsudvikling i fokus} \\ +Kvalitet tages alvorligt. Kvalitetsudvikling er en lige så naturlig del af \\ +virksomhedens liv som budgetter og regnskaber. +\\ \\ + +\textbf{2. Ledelsens deltagelse i kvalitetsprocessen} \\ +Ledelsen deltager synligt I kvalitetsprocessen og lever selv op til de \\ +stiller til effektivitet og menneskelige relationer. +\\ \\ + +\textbf{3. Tilfredse kunder/brugere} \\ +Kunderne, brugerne og servicetagerne er tilfredse med virksomhedens \\ +og serviceydelser og bevarer en loyal tilknytning til virksomheden. +\\ \\ + +\textbf{4. Engagerede medarbejdere} \\ +Medarbejderne trives og er dybt engagerede. \\ +Personaleomsætningshastigheden og fraværsprocenten er lav. Interne \\ + funktioner understøtter kundeorienterede ansatte i at opnå succes. +\\ \\ + +\textbf{5. Langsigtet kvalitetsudvikling} \\ +Virksomheden satser mere på langsigtet kvalitetsudvikling end på \\ +omkostningsreduktion og fortjeneste. +\\ \\ + +\textbf{6. Klare og høje kvalitetsmål} \\ +Der findes klare og høje kvalitetsmål på alle områder. Resultaterne \\ +måles løbende, og nøgletallene gøres synlige for alle. +\\ \\ + +\textbf{7. Belønning af kvalitetspræstationer} \\ +Kvalitetspræstationer belønnes synligt og er en forudsætning for \\ +forfremmelse. +\\ \\ + +\textbf{8. Positiv opfattelse af kvalitetskontrol} \\ +Kvalitetskontrol opfattes ikke som et tegn på mistillid, men som et \\ +middel til at udvikle kvaliteten.\\ +Afvigelser fra aftalte kvalitetsmål accepteres ikke, men fører til \\ +ændringer af præstationerne eller af målene. +\\ \\ + +\textbf{9. Næste person i arbejdsprocessen er en vigtig kunde} \\ +I virksomheden betragtes den næste person i arbejdsprocessen som\\ +en vigtig kunde. Intet led/menneske i arbejdsprocessen bør lide \\ +under fejl begået af andre. Hver person forpligter sig til \\ +at optræde som leverandør af kvalitetsprodukter til sine kunder. +\end{minipage} +\end{center} + +% 2. STRAN PO GRAFIH +\begin{center} +\begin{minipage}{0.8\linewidth} +\textbf{10. Investering i medarbejderudvikling} \\ +Medarbejderne betragtes som virksomhedens vigtigste ressource. \\ +Der investeres i udvikling og uddannelse af alle medarbejdere.\\ +Lederne deltager i karriereplanlægning med et fokus på at udvide \\ +erfaringsbasen i form af viden og evner -- og derved højne \\ +individets værdi. \\ +Den enkelte udviser initiativ og tager ansvar for sin egen karriere. +\\ \\ + +\textbf{11. Forebyggelse og begrænsning af fejl} \\ +Der investeres meget i at forebygge og begrænse fejl. \\ +Virksomheden skelner mellem acceptable og uacceptable fejl. \\ +De acceptable fejl er kreative fejl, som er udtryk for udvikling, \\ +afprøvning af ny viden og eksperimenter. De uacceptable \\ +fejl er ''sjuskefejl'', som er unødvendige, dyre og skadelige. +\\ \\ + +\textbf{12. Rigtigt beslutningsniveau} \\ +Beslutningsniveauet er ikke placeret højere i organisationen, end det \\ +er nødvendigt, for at beslutninger kan træffes med indsigt, og \\ +kvalitetskravene kan indfries. +\\ \\ + +\textbf{13. Enkel og direkte vej til den endelige bruger} \\ +Produkter og serviceydelser producers og leveres til den endelige \\ +bruger så direkte og enkelt som muligt. +\\ \\ + +\textbf{14. Fokus på både teknisk og menneskelig kvalitet} \\ +Virksomheden lægger stor vægt på både teknisk og menneskelig kvalitet. +\\ \\ + +\textbf{15. Orientering mod kundebehov} \\ +Indfrielsen af kundens eller den endelige brugers behov afspejles \\ +i alle virksomhedens handlinger. Kvalitetsmålinger finder ikke \\ +alene sted internt i virksomheden, men også hos kunderne. +\\ \\ + +\textbf{16. Løbende værdianalyser} \\ +Der gennemføres løbende værdianalyser for at bedømme, om det \\ +er de rigtige ting, der gøres, og om udbyttet står i forhold til indsatsen. \\ +Arbejdsaktiviteter, som ikke tilfører ''værdi'' nedlægges. +\\ \\ + +\textbf{17. Virksomheden påtager sig sin samfundsroller} \\ +Virksomheden erkender og påtager sig sin samfundsrolle. +\end{minipage} +\end{center} + +\newpage + +% 3. STRAN PO GRAFIH +\chapter{\Large \textbf{Kvalitetsklima anbefalinger}} +\begin{center} +\begin{minipage}{0.8\linewidth} +For at skabe, vedligeholde og udvikle et \textit{Kvalitetsklima}, anbefaler \\ +vi at du lærer mere om de 15 kvalitetsområder i \textit{Kvalitetsklima } \\ +værktøjet og de 17 kendetegn for kvalitetsvirksomheder gennem \\ +anvendelsen af tre andre værktøjer: + +\renewcommand\labelitemi{\small$\bullet$} +\begin{itemize} +\addtolength{\itemindent}{2.2cm} +\item Stjernekvalitet +\item Team Employeeship måler +\item Organisationens Employeeship Måler +\end{itemize} +\end{minipage} +\end{center} + +\ \\ \\ \\ \\ \\ + +\begin{center} +{\Large \textbf{Stjernekvalitet værktøjet}} \\ +\textbf{Et værktøj til at skabe 3-stjernet Teamkvalitet} +\begin{minipage}{0.8\linewidth} + +\ \\ \\ + +\textit{'Stjernekvalitet'} er et værktøj til at overvåge, bedømme og udvikle \\ +kvaliteten af et teams kollektive præstationer så de konstant indfrier \\ +krav og forventninger fra andre.\\ +\ \\ + +Værktøjet har fem trin: +\\ +\renewcommand\labelitemi{\large$\bullet$} +\textbf{ +\begin{itemize} + +\item Udvælg kvalitetsområder og -faktorer +\item Bestem målemetoden for hver faktor +\item Definér det ideale kvalitetsniveau for hver faktor +\item Mål det faktiske præstationsniveau for hver faktor +\item Lav en udviklingsplan for kvalitet +\end{itemize} +} +\ \\ +Teamets kvalitetsområder er bestemt af prioriteringen i teamet \\ +med tilhørende kvalitetsfaktorer og målemetoden besluttet \\ + for hver faktor. Derefter udvikles \\ +hovedelementerne af kvalitetsudviklingsprocessen konsistent. +\\ \\ +Hele Stjernekvalitetsværktøjet findes på web sitet \href{https://clausmoller.com/en/reachingforthestars}{\underline{www.ClausMoller.com}}. + + +\end{minipage} +\end{center} + +\newpage + +% 4. STRAN PO GRAFIH +\begin{center} +{\Large \textbf{Team Employeeship Måler}} +\begin{minipage}{0.8\linewidth} + +\ \\ \\ +\textit{Team Employeeship Måler} er et værktøj til at analysere, vurdere \\ +og udvikle teamets og hele virksomhedens \textit{Employeeship} kultur. + +\\ \\ + +Værktøjet er en enkel og hurtig hjælp til ledelse og medarbejdere \\ +til at identificere områder, hvor en forandring eller en mere \\ +indgående analyse af kulturen er påkrævet. + +\\ \\ + + Når alle ansatte er dybt engagerede i virksomhedens overlevelse, \\ +udvikling og stræben efter "business excellence" så har virksomheden en \\ +\textit{Employeeship} kultur Den er karakteriseret ved at alle udviser \\ +engagement, ansvarlighed, loyalitet, initiativ og positive energi. + +\\ \\ + +\textit{Employeeship} er et unikt koncept udviklet af Claus Møller som handler \\ +om \textbf{ledelse for alle}. Det illustrerer hvad der kræves for at være en god \\ +medarbejder og hvordan man kan inspirere alle til at yde deres bedste og \\ +dermed medvirke til virksomhedens overlevelse, vækst og \\ +langsigtede succes. + + +\end{minipage} +\end{center} + +\newpage + +% 5. STRAN PO GRAFIH +\begin{center} +{\Large \textbf{Virksomhedens Employeeship Måler}} +\begin{minipage}{0.8\linewidth} + +\ \\ \\ +Et værktøj til at måle, hvorvidt virksomhedens kultur, systemer \\ + og politikker inspirerer medarbejderne til at udvise \\ +\textit{Employeeship}. +\\ \\ +Medarbejdernes Employeeship holdning og adfærd påvirkes af en \\ +lang række forhold i virksomheden, som vi, ''lidt forenklet'', kalder \\ +virksomhedens ''systemer og politikker''. For at få alle i virksomheden \\ +til at udvise Employeeship og dermed skabe en Employeeship kultur \\ + er det afgørende, at ledere og medarbejdere yder en indsats både \\ +på de \textbf{hårde} og de \textbf{bløde} områder. \\ + \hspace*{0.8\baselineskip} Det er også nødvendigt, at der i virksomheden findes \\ +politikker og systemer, der indeholder \textbf{både} hårde \textbf{og} \\ + \textbf{bløde} elementer. + +\end{minipage} +\end{center} +\ \\ \\ \\ + +\begin{minipage}[t]{0.54\textwidth} +{\textbf{Hårde områder}} \\ \\ +De hårde områder omfatter de konkrete og \\ +tekniske aspekter af virksomhedens liv: systemer, \\ +regler, procedure, kommandoveje, fysisk miljø etc. \\ \\ +De hårde områder er de rationelle og logiske \\ +aspekter i virksomheden. Dem som er lettest at \\ +forklare og beskrive. +\\ +\hspace*{0.8\baselineskip}På de hårde områder er det mest \\ +et spørgsmål om indhold: + +\renewcommand\labelitemi{\small$\bullet$} +\begin{itemize} +\item Hvad skal gøres? +\item Hvem skal gøre det? +\item Hvornår skal det gøres? +\item Hvordan skal det gøres? +\end{itemize} +\ \\ +I mange virksomheder udøves ledelse \\ +hovedsageligt ud fra de forudsætninger og \\ +regler, der gælder i den hårde verden. \\ +Det afspejler sig eksempelvis i \\ + virksomhedens hårde: +\renewcommand\labelitemi{\small$\bullet$} +\begin{itemize} +\item Personalepolitik +\item Ansættelseskontrakter +\item Belønningssystemer +\item Informationssystemer + +\end{itemize} +\end{minipage} + +% 5. STRAN PO GRAFIH drugi stolpec +\begin{minipage}[t]{0.54\textwidth} +{\large \textbf{Bløde områder}} \\ \\ +De bløde områder omfatter de \\ +følelsesmæssige aspekter af virksomhedens\\ + liv: omgangsform, kommunikationsform, \\ +psykisk miljø, ledelsesstil, menneskesyn, \\ +moral, traditioner, tryghed, udfordringer etc. \\ +\\ \\ + +De bløde områder beskæftiger sig med \\ +det, der kaldes virksomhedskultur. \\ +De bløde områder kan være vanskelige at \\ +konkretisere og beskrive. \\ +\hspace*{0.8\baselineskip} På de bløde områder er det mest \\ +et spørgsmål om relationer: +\renewcommand\labelitemi{\small$\bullet$} +\begin{itemize} +\item Hvordan skal vi inspirere og motivere \\ +hinanden? +\item Hvordan skal vi kommunikere for at \\ +forstå hinanden? +\item Hvordan skal vi skabe visioner og \\ +udvikle kreativitet? +\item Hvordan skal vi håndtere konflikter \\ +og tilspidsede situationer? +\item Hvordan opnår vi begejstring, \\ +arbejdsglæde, stolthed, tolerance \\ +og fleksibilitet? +\item Hvordan skaber vi sammenhold og \\ +teamfølelse? +\end{itemize} +\end{minipage} + +\newpage + +% 7. STRAN PO GRAFIH +\begin{center} +{\LARGE \textbf{Næste skridt \dots}} +\end{center} +\begin{minipage}[t]{0.54\textwidth} + +\ \\ +\textit{Kvalitetsklima testen } er et værktøj til at undersøge, \\ +bedømme og udvikle kvalitetskulturen \\ + i dit team og i din organisation. \\ +\hspace*{0.8\baselineskip} Resultaterne af Kvalitetsklima vil \\ + inspirere dig til at lære mere om, og \\ +udvikle, en kvalitetskultur. +\\ \\ +Claus Møller Consulting har udviklet metoder \\ + og værktøjer til at hjælpe individer, teams og \\ + organisationer udvikle sig indenfor de områder \\ + hvor Kvalitetsklima testen har påvist muligheder \\ +for forbedringer: Produktivitet, relationer, \\ + kvalitet, engagement, personlig udvikling, \\ + anerkendelse og belønning, implementering og \\ +andre områder af generel \\ + virksomhedskompetence. \\ + \\ +\hspace*{0.8\baselineskip} Hvis du ønsker at lære mere om din \\ +kvalitetskultur, og hvordan du udvikler \\ +områder hvor Kvalitetsklima værktøjet \\ +har påvist mulighed for forbedringer, \\ +har du følgende muligheder: +\\ \\ + +\textbf{1. \textit{\href{https://clausmoller.com/da/kontakt/}{ \underline {Kontakt Claus Møller Consulting}}}} \\ +for at modtage mere detaljeret verbal eller \\ +skriftlig feedback -- eller coaching og \\ +konsulentbistand. +\\ \\ +\textbf{2. \textit{\href{}{ \underline {Deltag i Personlig Kvalitet og På vej mod } \\ \underline {Stjernerne kurser } }}} \\ \\ +for at lære mere om kvalitetsprocessen \\ +og hvordan du, dit team og din virksomhed \\ +kan udvikle kvalitet. +\end{minipage} + +% 7. STRAN PO GRAFIH drugi stolpec +\begin{minipage}[t]{0.54\textwidth} +\ \\ \ +\textbf{3. \textit{\href{https://clausmoller.com/da/product/personal-quality/}{ \underline {Læs bogen Personlig Kvalitet }}}} \\ \\ +for at få en introduktion til konceptet om \\ +\textit{Personlig Kvalitet}, der er fokuseret på den \\ +\textbf{menneskelige side af kvalitet } og som \\ +danner grundlag for alle andre former for \\ + kvalitet: produkt-, service-, team- og \\ + virksomhedskvalitet. +\\ \\ + +\textbf{4. \textit{\href{https://clausmoller.com/da/produkt/heart-work/}{ \underline {Læs Heart Work}}}} \\ \\ +(En bog om følelsesmæssig intelligens) \\ \\ +for at opnå en dyb indsigt i følelsesmæssig \\ +intelligens og dens rolle i forhold til kvalitet. \\ +Lær hvorfor det er vigtigt, både privat og på \\ +arbejde, og hvordan følelsesmæssig intelligens \\ + kan udvikles af individer, teams og \\ +organisationer. +\\ \\ + +\textbf{5. \textit{\href{https://clausmoller.com/da/tests/}{ \underline {Brug Team EQ Måler}}}} \\ \\ +til præcist at vurdere og udvikle dit teams \\ + og din organisations følelsesmæssige intelligens. +\\ \\ + +\textbf{6. \textit{\href{https://clausmoller.com/da/tests/}{ \underline {Brug Team Employeeship Måler}}}} \\ \\ +for at præcist vurdere og udvikle Employeeship \\ + holdninger og adfærd i dit team \\ + og din organisation. +\\ \\ +\textbf{7. \textit{\href{https://clausmoller.com/da/tests/}{ \underline {Anvend Virksomhedens } \\ \underline{Employeeship Måler}}}} \\ \\ +for at virksomheden kan identificere dens \\ +styrker og svagheder indenfor 14 områder \\ + af organisatoriske systemer og politikker. + +\end{minipage} +\ \\ + +\begin{center} +{\small Claus Møller Consulting tilbyder lederuddannelse, skræddersyede kurser, executive coaching, \\ +diagnostiske værktøjer til virksomheder over hele verden for at gøre dem i stand til at \\ +opnå varige resultater for individer, teams og hele organisationen. } +\end{center} + +\begin{center} +{\small Claus Møller Consulting hjælper organisationer med at måle, forbedre og styre \\ +produktivitet, relationer, kvalitet, og ledelse.}. +\end{center} + +\begin{center} +\includegraphics[width=4.5cm]{../latexkosi/logo/CMC.png} +\end{center} + +\begin{center} +Kontakt os for yderligere information om konsulentbistand, kurser og værktøjer. \\ +\href{info@clausmoller.com}{ \underline {info@clausmoller.com}} \small$\bullet$ \href{http://www.clausmoller.com}{ \underline {http://www.clausmoller.com}} +\end{center} diff --git a/admin/survey/modules/mod_EVOLI/latexkosi/glava-evoli_ang.tex b/admin/survey/modules/mod_EVOLI/latexkosi/glava-evoli_ang.tex index 55755f9fe..6ffe585b5 100644 --- a/admin/survey/modules/mod_EVOLI/latexkosi/glava-evoli_ang.tex +++ b/admin/survey/modules/mod_EVOLI/latexkosi/glava-evoli_ang.tex @@ -192,7 +192,7 @@ \renewcommand{\footrulewidth}{0.4pt} \fancyhead[L]{!name! } \fancyfoot[L]{} - \fancyfoot[C]{\circled{c} 2001 - 2016 Claus M{\o}ller Consulting} + \fancyfoot[C]{\circled{c} 2001- Claus M{\o}ller Consulting} \fancyfoot[R]{ \thepage} \headsep 20pt \fancypagestyle{plain}{ diff --git a/admin/survey/modules/mod_EVOLI/latexkosi/glava-evoli_dan.tex b/admin/survey/modules/mod_EVOLI/latexkosi/glava-evoli_dan.tex index 959e70fd0..2b400194a 100644 --- a/admin/survey/modules/mod_EVOLI/latexkosi/glava-evoli_dan.tex +++ b/admin/survey/modules/mod_EVOLI/latexkosi/glava-evoli_dan.tex @@ -166,7 +166,7 @@ \renewcommand{\footrulewidth}{0.4pt} \fancyhead[L]{!name!} \fancyfoot[L]{} - \fancyfoot[C]{\circled{c} 2001 - 2016 Claus M{\o}ller Consulting} + \fancyfoot[C]{\circled{c} 2001- Claus M{\o}ller Consulting} \fancyfoot[R]{ \thepage} \headsep 20pt \fancypagestyle{plain}{ diff --git a/admin/survey/modules/mod_EVOLI/latexkosi/glava-evoli_slo.tex b/admin/survey/modules/mod_EVOLI/latexkosi/glava-evoli_slo.tex index e524bd363..b54bf9faf 100644 --- a/admin/survey/modules/mod_EVOLI/latexkosi/glava-evoli_slo.tex +++ b/admin/survey/modules/mod_EVOLI/latexkosi/glava-evoli_slo.tex @@ -172,7 +172,7 @@ \renewcommand{\footrulewidth}{0.4pt} \fancyhead[L]{!name! } \fancyfoot[L]{} - \fancyfoot[C]{\circled{c} 2001 - 2016 Claus M{\o}ller Consulting} + \fancyfoot[C]{\circled{c} 2001- Claus M{\o}ller Consulting} \fancyfoot[R]{ \thepage} \headsep 20pt \fancypagestyle{plain}{ diff --git a/admin/survey/modules/mod_EVOLI/latexkosi/glava-quality_clime_ang.tex b/admin/survey/modules/mod_EVOLI/latexkosi/glava-quality_clime_ang.tex index 618b2faaa..98aab934f 100644 --- a/admin/survey/modules/mod_EVOLI/latexkosi/glava-quality_clime_ang.tex +++ b/admin/survey/modules/mod_EVOLI/latexkosi/glava-quality_clime_ang.tex @@ -143,13 +143,13 @@ results of this test will inspire you to learn more about and develop \\ your quality culture. \\ \\ -Claus M{\o}ller's \textit{Quality Climate} tool is a ''thermomete'' to help determine \\ -the state of a team's ''healt'h' at any given moment. The thermometer \\ +Claus M{\o}ller's \textit{Quality Climate} tool is a ''thermometer'' to help determine \\ +the state of a team's ''health' at any given moment. The thermometer \\ can also indicate the state of health of an entire organisation. \\ \\ This report shows the state of quality awareness and attitude in your \\ -organisation's team(s). +organisation's teams. \\ \\ We recommend that you read Claus M{\o}ller's book \textit{\href{https://clausmoller.com/en/product/personal-quality/}{''Personal Quality''}} \\ which gives specific suggestions for developing and sustaining Personal \\ @@ -168,8 +168,8 @@ the concepts of \textit{Team Quality} and \textit{Quality Climate}. % STRAN 3 \chapter{\Large \textbf{About Quality Climate}} \smash{\begin{minipage}[t]{0.54\textwidth} -{\large \textbf{What is team quality?}} \\ -Team Quality can be defined as how well a \\ +{\large \textbf{What is Team Quality?}} \\ +\textit{Team Quality} can be defined as how well a \\ team as a whole meets its own and the \\ outside world's demands and expectations. \\ Teams and organisations need regular \\ @@ -237,7 +237,7 @@ stars would your team be awarded? All the \\ members of the team should be committed \\ to achieving 3-star quality. \\ \\ -\textit{''Quality climate''} is a tool for monitoring \\ +\textit{Quality Climate} is a tool for monitoring \\ and developing the relationships, culture \\ and ''climate'' in the team so it can keep \\ meeting the \textbf{team members' demands} \\ @@ -333,7 +333,7 @@ their Personal Quality} % STRAN 4 drugi stolpec \begin{minipage}[t]{0.5\textwidth} -{\large \textbf{Teams' advantages of developing \\ quality climate}} +{\large \textbf{Teams' advantages of developing \\ a Quality Climate}} \\ \\ The survival of the organisation is \\ determined by its ability to meet the \\ @@ -397,8 +397,8 @@ personal and team level for different \\ periods: day, week, month, year and \\ long-term visions. We adjust our long-\\ term goals at least once a year. \\ -\hspace*{0.8\baselineskip}Read more in Claus M{\o}ller's book \textit{''My \\ Life tree''}, -the chapter ''My personal goals''. +\hspace*{0.8\baselineskip}Read more in Claus M{\o}ller's book \textit{My \\ Life Tree}, +the chapter 'My personal goals'. \\ \\ {\large \textbf{2. Organisation/sharing \\ responsibility}} \\ Everyone has an overview and control \\ @@ -424,8 +424,8 @@ even across professional or team borders \\ and even if rules may need to be \\ discussed. \\ \hspace*{0.8\baselineskip} Read more in Claus M{\o}ller's book \\ -\textit{''Employeeship''}, in the chapters ''Responsibility'' \\ -and ''Multi-functional employees''. +\textit{Employeeship}, in the chapters 'Responsibility' \\ +and 'Multi-functional employees'. \end{minipage} % STRAN 5 drugi stolpec \begin{minipage}[t]{0.5\textwidth} @@ -445,8 +445,9 @@ their salary. Teams fulfil the effectiveness \\ and productivity demands placed upon \\ them by other people. \\ \hspace*{0.8\baselineskip} Read more in Claus M{\o}ller's book \\ -\textit{Employeeship}, chapters ''Productiviry'' \\ -and ''Heart Work'', the chapter ''Self-\\management''. +\textit{Employeeship}, in the chapter on \\ + 'Productivity' and \textit{Heart Work}, \\ + the chapter 'Self-management'. \\ \\ {\large \textbf{4. Decisions}} \\ Decisions are made in the team on an \\ @@ -461,7 +462,7 @@ involve risk. We do not procrastinate \\ decisions but make good decisions rapidly \\ when the situation demands it. \\ \hspace*{0.8\baselineskip} Read more in Claus M{\o}ller's book \textit{Heart \\ Work}, -section ''The EI Person''. +in the section 'The EI Person'. \\ \\ {\large \textbf{5. Delegation}} \\ Managers delegate enough. We make use \\ @@ -474,7 +475,7 @@ develops enough to be able to take still \\ greater responsibility. Delegation \\ technique is effective. \\ \hspace*{0.8\baselineskip} Read more in Claus M{\o}ller's book \\ -\textit{Employeeship}, the chapter ''Employeeship \\ delegation''. +\textit{Employeeship}, in the chapter 'Employeeship \\ delegation'. \end{minipage} \newpage @@ -497,9 +498,9 @@ available. We make use of each other's \\ knowledge and we learn from each other \\ -- across professional demarcations. \\ \hspace*{0.8\baselineskip} Read more in Claus M{\o}ller's book \\ -\textit{Employeeship}, the section ''Employeeship \\ -and communication'' and the chapter \\ -''Employeeship and 'we' culture''. +\textit{Employeeship}, the section 'Employeeship \\ +and communication' and the chapter \\ +'Employeeship and 'we' culture'. \\ \\ {\large \textbf{7. External communication and co-\\ordination}} \\ We have good co-operation with other \\ @@ -512,10 +513,10 @@ stakeholders is appropriate. We know our \\ competitors and their strong and weak \\ points. We adapt to the changes around \\ us. \\ -\hspace*{0.8\baselineskip} Read more in Claus M{\o}ller's book \\ -\textit{''A Complaint is a Gift''}, and \textit{''Employeeship''} in \\ -in the section ''New demands on \\ -companies''. +\hspace*{0.8\baselineskip} Read more in Claus M{\o}ller's books \\ +\textit{A Complaint is a Gift} and \textit{Employeeship} in \\ +in the section 'New demands on \\ +companies'. \\ \\ {\large \textbf{8. Physical environment}} \\ The physical environment helps to create \\ @@ -556,9 +557,9 @@ discover mistakes, we thank the people \\ who point them out to us and we correct \\ them and avoid repetition. \\ \hspace*{0.8\baselineskip} Read more in Claus M{\o}ller's book \\ -\textit{''Personal Quality''}, particularly the section \\ -\textit{''Personal Guarantee''} or read the \\ -\textit{''Personal Guarantee''} booklet. +\textit{Personal Quality}, particularly the section \\ +'Personal Guarantee' or read the \\ +\textit{Personal Guarantee} booklet. \\ \\ {\large \textbf{10. Creativity and innovation}} \\ We notice the developments going on \\ @@ -572,8 +573,8 @@ team performance: do things faster, at a \\ lower cost, more creatively and at a \\ higher quality level. \\ \hspace*{0.8\baselineskip} Read more in Claus M{\o}ller's book \\ -\textit{''Employeeship''}, the chapters ''Employeeship \\ -delegation'' and ''Initiative''. +\textit{Employeeship}, in the chapters 'Employeeship \\ +delegation' and 'Initiative'. \end{minipage} \newpage @@ -592,8 +593,8 @@ development. Everybody is prepared to \\ make an extra effort when necessary. \\ Everybody finds a challenge in every job \\ function and action. \\ -\hspace*{0.8\baselineskip} Read more in Claus M{\o}ller's book \\ -\textit{''Employeeship''} and \textit{''Heart Work''}. +\hspace*{0.8\baselineskip} Read more in Claus M{\o}ller's books \\ +\textit{Employeeship} and \textit{Heart Work}. \\ \\ {\large \textbf{12. Recognition and rewards}} \\ Recognition is given more frequently than \\ @@ -609,9 +610,9 @@ never receive attention or recognition. \\ People expect recognition rather than \\ criticism when a member is asked to go \\ and see the manager. \\ -\hspace*{0.8\baselineskip} Read more in Claus M{\o}ller's book \textit{''My \\ Life Tree''}, -the chapter ''Surroundings -- the \\ -soil''. +\hspace*{0.8\baselineskip} Read more in Claus M{\o}ller's book \textit{My \\ Life Tree}, +the chapter on 'Surroundings -- the \\ +soil'. \\ \\ {\large \textbf{13. Personal development}} \\ Everybody is encouraged to develop. \\ @@ -623,9 +624,9 @@ There are opportunities for job rotation, \\ job sharing, variation and promotion. Each \\ person is given reasonable challenges. \\ \hspace*{0.8\baselineskip} Read more in Claus M{\o}ller's book \\ -\textit{Employeeship}, the chapter ''The soft \\ -contract'' and ''Employeeship personnel \\ -policies''. +\textit{Employeeship}, the chapter 'The soft \\ +contract' and 'Employeeship personnel \\ +policies'. \end{minipage} % STRAN 7 drugi stolpec \begin{minipage}[t]{0.5\textwidth} @@ -638,7 +639,7 @@ openness and honesty. We trust each \\ other. We talk to each other -- not about \\ each other. We respect each other's skills, \\ wishes and differences. \\ -\hspace*{0.8\baselineskip} Read more in Claus M{\o}ller's book \textit{''My \\ Life Tree''}. +\hspace*{0.8\baselineskip} Read more in Claus M{\o}ller's book \textit{My \\ Life Tree}. \\ \\ {\large \textbf{15. Implementation}} \\ We can translate ideas and thoughts into \\ @@ -659,16 +660,16 @@ decisions on the way towards the goal. We \\ can remove any obstacles on the way \\ towards our goals. \\ \hspace*{0.8\baselineskip} Read more in Claus M{\o}ller's book \\ -\textit{''Employeeship''}, the chapter ''Implementation'' \\ -and the book \textit{''Personal Quality''}, \\ -the section ''Learn to finish what you start -- \\ -strengthen your self-discipline''. +\textit{Employeeship}, the chapter 'Implementation' \\ +and the book \textit{Personal Quality}, \\ +the section 'Learn to finish what you start -- \\ +strengthen your self-discipline'. \end{minipage} \newpage -\chapter{\Large \textbf{How to use the Quality Climate tool}} +\chapter{\Large \textbf{How to Use the Quality Climate tool}} \begin{center} \begin{minipage}{0.8\linewidth} \begin{center} @@ -700,7 +701,7 @@ organisation. Results from the different teams should be \\ compared to achieve improvements throughout the \\ organisation. \item Senior management can use the Quality Climate tool to \\ -identify those teams, which need additional help, or those \\ +identify those teams, which need additional help or those \\ teams from which the whole organisation can learn something. \item It is possible to get an idea of the strong and weak points of \\ the entire organisation by looking at those factors for which all \\ @@ -764,5 +765,5 @@ departmental meetings. \begingroup \renewcommand{\cleardoublepage}{} \renewcommand{\clearpage}{} -\chapter{\Large \textbf{Quality climate for all teams}} +\chapter{\Large \textbf{Quality Climate for All Teams}} \endgroup diff --git a/admin/survey/modules/mod_EVOLI/latexkosi/glava-quality_clime_dan.tex b/admin/survey/modules/mod_EVOLI/latexkosi/glava-quality_clime_dan.tex new file mode 100644 index 000000000..1d4c1f076 --- /dev/null +++ b/admin/survey/modules/mod_EVOLI/latexkosi/glava-quality_clime_dan.tex @@ -0,0 +1,715 @@ +% Opredelitev dokumenta +\documentclass[11pt, a4paper]{report} +\usepackage[cm]{fullpage} +\setlength{\headheight}{12pt} + +% Opredelitev pisave +\usepackage[default,scale=0.95]{opensans} +\usepackage{arev} +\usepackage{textcomp} +\usepackage[danish]{babel} +\usepackage[utf8]{inputenc} +\usepackage[T1]{fontenc} +\UseRawInputEncoding + +% Za sezname +\usepackage{enumitem} +% Brez deljenja besed +\usepackage[none]{hyphenat} +% Barve ozadja +\usepackage[table,xcdraw]{xcolor} + +% Za slike in grafiko +\usepackage{float} +\usepackage{graphicx} + +% Urejanje poglavij +\usepackage{titlesec} +\titleformat{\chapter}[block] + {\centering\Large\bfseries} % format + {}% label + {0pt} % sep + {\Large} + +\titlespacing*{\chapter}{0pt}{-13pt}{10pt} +\renewcommand{\thechapter}{} % ne želimo številčenja poglavij v kazalu +\usepackage{etoolbox} +\makeatletter +\patchcmd{\l@chapter} + {\hfil} + {\leaders\hbox{\normalfont$\m@th\mkern \@dotsep mu\hbox{.}\mkern \@dotsep mu$}\hfill} + {}{} +\makeatother + + +\definecolor{lightblue}{rgb}{0.68, 0.85, 0.9} + +% Klik na poglavja v kazalu +\usepackage{hyperref} +\hypersetup{ + colorlinks=true, + linkcolor=black, + urlcolor=black, %Url naslov bo obarvan s črno barvo + pdfstartview={XYZ null null 1}, + pdfborderstyle={/S/U/W 1}, + pdftitle={naslov!} +} +\urlstyle{same} +% Urejanje kazala +\usepackage{etoolbox} +\makeatletter + + +% Pod slikami ne zelimo oznake "Figure" +\usepackage{caption} +\captionsetup[figure]{labelformat=empty} + +% Pri novem odstavku ni indenta +\setlength{\parindent}{0cm} + +% Za urejanje prve strani +\usepackage[margin=0.85in]{geometry} +\setlist{nolistsep} + +% Urejanje stila strani in stila glave in noge +\usepackage{fancyhdr} +\pagestyle{fancyplain} +\renewcommand{\chaptermark}[1]{\markboth{#1}{}} +\fancyhf{} +\renewcommand{\headrulewidth}{0.4pt} +\renewcommand{\footrulewidth}{0.4pt} +\fancyhead[L]{Kvalitetsklima - !organisation!} +\fancyhead[R]{\color{red} {\textcopyright} Ophavsret 2020 - Claus Møller Consulting} +\headsep 20pt +\fancypagestyle{plain}{ + \renewcommand{\headrulewidth}{0.5pt} + \renewcommand{\footrulewidth}{0.5pt} + + +} +% Footer on title page +\fancypagestyle{firststyle} +{ +\renewcommand{\headrulewidth}{0pt} +\renewcommand{\footrulewidth}{0pt} + \fancyfoot[C]{\textcopyright Ophavsret 2020 - Claus Møller Consulting.} +} + +% Simbol svincnika +\usepackage{pifont} + +% STRAN 1 +\begin{document} +\begin{titlepage} +\begin{center} +% Odmik od vrha +\vspace*{-4.5\baselineskip} +\noindent\makebox[\textwidth]{\includegraphics[width=17cm,height=4.1cm]{../latexkosi/logo/klima_kakovosti_dan.png}}~\\[2cm] +% Odmik od roba +\hspace*{-5.3\baselineskip} \includegraphics[width=20cm]{../latexkosi/logo/klima_kakovosti_middle.png}~\\[5cm] +\end{center} +\thispagestyle{firststyle} +% Organizacija +\hspace*{-2.5\baselineskip} \noindent\underline{\makebox[7in][l]{Organisation: !organisation!}} ~\\[0.5cm] +% Datum +\hspace*{-2.5\baselineskip} \noindent\underline{\makebox[4in][l]{Dato: !date!} \makebox[3in][l] {Konsulent:}} ~\\[0.5cm] +\end{titlepage} + +\newpage + +% Sprememba v glavi in nogi dokumenta +\renewcommand{\headrulewidth}{0pt} +\renewcommand{\footrulewidth}{0pt} +\fancyhead[L]{\color{red} \textit{Kvalitetsklima - !organisation!}} +\fancyfoot[c]{\small{\thepage}} +\headsep 15pt +\fancypagestyle{plain}{ + \renewcommand{\headrulewidth}{0pt} + \renewcommand{\footrulewidth}{0pt} +} + +% Zagotovi da smo na lihi strani +\cleardoublepage + +% STRAN 2 +% Odmik od levega roba, brez dodatnega odmika prve vrstice +\noindent\hspace{0.12\linewidth} +\begin{minipage}{0.8\linewidth} +\ \\ \\ +!name! +\\ \\ +Tak for, at du har taget \textit{Kvalitetsklima} testen. +\\ \\ +\textit{Kvalitetsklima } testen er et værktøj til at overvåge og udvikle \\ +forholdene kulturen eller "klimaet'' i dit team og din organisation. \\ +Testens resultater vil inspirere dig til at lære mere om og forbedre \\ +din kvalitetskultur. +\\ \\ + +Claus M{\o}ller's \textit{Kvalitetsklima} er et "termometer'' der hjælper med at måle \\ +teamets "'helbred'' på et givent tidspunkt. Det kan også anvendes til at \\ +vurdere hele virksomhedens "helbred". +\\ \\ + +Denne rapport viser tilstanden på kvalitetsbevidsthed og -holdning i din \\ +virksomheds teams. +\\ \\ +Vi anbefaler at du læser Claus Møller's bog ''Personlig Kvalitet'', som \\ + giver specifikke forslag til udvikling og vedligeholdelse af Personlig \\ + Kvalitet, Team Kvalitet og Kvalitetsklimaet i et team eller en hel \\ +organisation. På de følgende sider får du en introduktion til \\ + koncepterne \textit{Teamkvalitet} og \textit{Kvalitetsklima}. +\end{minipage} + +\ \\ \\ \\ \\ +% Kazalo na isti strani +\begingroup +\let\clearpage\endgroup +% Kazalo +\tableofcontents + +% STRAN 3 +\chapter{\Large \textbf{Om Teamkvalitet og Kvalitetsklima}} +\smash{\begin{minipage}[t]{0.54\textwidth} +{\large \textbf{Hvad er Teamkvalitet?}} \\ + Med \textit{Teamkvalitet} menes: \textit{Et teams indfrielse af \\ +de krav og forventninger der stilles til teamets \\ +samlede præstationer -- af omgivelserne og af \\ +teamets medlemmer}. Teams og organisationer \\ +bør ligesom enkeltpersoner, gennemgå \\ +regelmæssige helbredsundersøgelser. \\ +\hspace*{0.8\baselineskip}Det er ikke altid nødvendigt at lave \\ +dybdegående og dyre undersøgelser. Enkle \\ +undersøgelser kan indikere de same resultater \\ +og medvirker til at den næste dybdegående \\ +undersøgelse foretages når og hvor der er \\ +behov for den. \\ +\hspace*{0.8\baselineskip} \textit{Kvalitetsklima} er en team indikator, eller et \\ +"termometer" , som klarlægger et teams helbred \\ +på et givent tidspunkt. \textit{Kvalitetsklima} kan også \\ +opridse helbredet for en hel organisation. \\ +of an entire organisation. \\ +\hspace*{0.8\baselineskip}Indikatoren er ikke et værktøj til en \\ +dybtgående analyse. Det er en hurtig, enkel \\ + og praktisk måde for ledelsen at identificere de \\ +områder, der skal ændres eller hvor der er behov \\ +for en mere detaljeret undersøgelse af de \\ +nuværende tilstande. \\ +\hspace*{0.8\baselineskip} \textit{Kvalitetsklima } giver organisationer et effektivt \\ +tidligt varslingssystem, som kan hjælpe med at \\ +spare en masse penge. +\\ \\ +Forudsætningen for at virksomheden og alle dens \\ +teams kan indfri omgivelsernes krav og \\ +forventninger til dem, er at de ansatte både \textbf{kan} \\ +og \textbf{vil} gøre deres bedste. \\ +\hspace*{0.8\baselineskip}For at få de ansatte til at engagere sig med \\ +\textbf{hjernen} og med \textbf{hjertet} i teamets success, er \\ +det ikke nok at teamet indfrier kravene og \\ +forventningerne fra omgivelserne. \\ +\hspace*{0.8\baselineskip}Forholdene i teamet skal også kunne indfri \\ +kravene og forventningerne fra medlemmerne. +\\ \\ +Det er ikke nok at ledelsen fokuserer på \\ +kvaliteten af et teams produkter, serviceydelser, \\ +systemer og procedure. Det er nødvendigt \\ + at fokusere på menneskene bag \\ + teamets præstationer. \\ +\hspace*{0.8\baselineskip}Det er ikke nok at overvåge \\ +kundetilfredsheden. Det er også nødvendigt at \\ +overvåge \textbf{medlemmernes} tilfredshed. +\end{minipage}} +% STRAN 3 drugi stolpec +\begin{minipage}[t]{0.65\textwidth} + +{\large \textbf{Kvalitetsklima}} \\ +Michelin udgiver årlige håndbøger (guides) over \\ +forskellige landes og regioners restauranter, \\ +hoteller og turistattraktioner med tilhørende \\ +kvalitetsvurdering og uddybende kommentarer. \\ + I Michelin guiden er det højeste man kan opnå \\ +tre stjerner. Prøv at forestille dig at dit team \\ blev +vurderet på samme måde som Michelin- \\ +inspektørerne vurderer restauranter. Hvor \\ + mange stjerner ville dit team få? Alle teamets \\ +medlemmer skal engagere sig i at \\ + opnå 3-stjernet kvalitet. +\\ \\ +\textit{Kvalitetsklima } er et værktøj til at overvåge og \\ +udvikle forholdene, kulturen eller ''klimaet'' i \\ +teamet, så det til stadighed kan indfri \\ +\textbf{medlemmernes krav} og forventninger til en ''3- \\ +stjernet'' arbejdsplads. Den interne kvalitet i \\ +teamet sætter en øvre grænse for den kvalitet \\ +teamet kan levere til omgivelserne. +\\ +\hspace*{0.8\baselineskip} Værktøjet indeholder 15 nøje udvalgte \\ +områder. Erfaring viser os at hvor godt teamet \\ +fungererer indenfor disse områder, er afgørende \\ +for om medlemmerne synes det er godt at være \\ +med i teamet, og er en del af evalueringen af \\ +team kvalitetskulturen lavet af medlemmerne. +\begin{enumerate}[leftmargin=*] +\item Mål +\item Ansvarsfordeling/organisation +\item Effektivitet/produktivitet +\item Beslutninger +\item Delegering +\item Intern kommunikation og +koordination +\item Ekstern kommunikation og +koordination +\item Fysisk miljø +\item Kvalitetsbevidsthed +\item Kreativitet og innovation +\item Engagement +\item Anerkendelse og belønning +\item Personlig udvikling +\item Øvrigt psykisk miljø +(relationer) +\item Implementering +\end{enumerate} +\ \\ +På de efterfølgende sider finder du forklaringer af \\ +de 15 områder i Kvalitetsklima værktøjet som du \\ +og dine kollegaer kan benytte jer af når I er ''på \\ +vej mod stjernerne''. +\end{minipage} + +\newpage + +% STRAN 4 +\begin{minipage}[t]{0.54\textwidth} +{\large \textbf{Hvad får du ud af at udvikle et \\ Kvalitetsklima?}} +\\ \\ +\textit{Personlig Kvalitet} er forudsætningen for al anden \\ +kvalitet. For at forstå kvalitet på det personlige \\ +niveau er det vigtigt at forstå dette udsagn. \\ +Dette er det første skridt i at udvikle din \\ +personlige kvalitet -- eller i at hjælpe andre med \\ +at udvikle deres. +\\ \\ +\hspace*{0.8\baselineskip} Du gavner dit team, din virksomhed eller \\ +organisation ved at præstere høj kvalitet. Din \\ +personlige kvalitet er altafgørende for både \\ +produkt- og servicekvalitet or er grundlaget for \\ +team- og virksomhedskvalitet. Det bedste sted \\ + at starte en kvalitetsudvikling i en virksomhed \\ +og organisation er ved det enkelte menneskes \\ +præstationer og holdning til kvalitet. +\\ \\ +Du glæder også din familie, dine venner og \\ +kollegaer med dine kvalitetsydelser. +\\ \\ +\textit{De allerstørste fordele opnår du dog selv \\ +-- bade privat og på arbejde} +\\ \\ +Alle ansatte skal konstant søge at udvikle og \\ +vedligeholde kvalitetsholdninger og -adfærd \\ + (f.eks. ideelle kvalitetsstandarder). +\\ \\ +\textbf{Dine fordele ved at præstere \\ +høj Personlig Kvalitet} +\renewcommand\labelitemi{\small$\bullet$} +\begin{itemize} +\item Større ansvar og indflydelse +\item Bedre karrieremuligheder +\item Bedre relationer med andre +\item Færre undgåelige fejl +\item Flere venner og støtter +\item Andre mennesker stoler på dig +\item Højere selvværd +\item Bedre livskvalitet +\end{itemize} +\end{minipage} + +% STRAN 4 drugi stolpec +\begin{minipage}[t]{0.5\textwidth} +{\large \textbf{Hvad får teams ud af at \\ udvikle et Kvalitetsklima?}} +\\ \\ +Virksomhedens overlevelse er bestemt af dens \\ +evne til at indfri de krav og forventninger som \\ +interessenterne -- interne såvel som eksterne -- \\ +har. \\ +\hspace*{0.8\baselineskip}For at beholde kunder er det nødvendigt at \\ +indfri deres forventninger til kvaliteten af \\ +virksomhedens produkter og serviceydelser. \\ +\hspace*{0.8\baselineskip} De bedste resultater opnås når organisation \\ +også fokuserer på de mennesker der leverer \\ +kvaliteten.\\ +\hspace*{0.8\baselineskip} Virksomhedens kvalitet er et resultat af \\ +individers og teams' præstationer (afdelinger, \\ +projektgrupper eller teams). \\ +\hspace*{0.8\baselineskip}Den samlede \textit{Teamkvalitet} er et resultat af \\ +præstationerne af de enkelte medlemmer -- og \\ +deres evne til at koordinere deres indsats og skabe \\ +et miljø, som inspirerer alle til at yde deres bedste.\\ +\\ +\textbf{Teamets fordele ved at forbedre \\ Teamkvalitet} \\ +Teams forbedrer deres evne til at: +\renewcommand\labelitemi{\small$\bullet$} +\begin{itemize}[leftmargin=*] +\item Definere teamets kvalitetsmål +\item Overvåge teamkvaliteten +\item Opnå de aftalte kvalitetsmål +\item Identificere de områder hvor \\ +teamkvalitet skal udvikles +\item Bedømme om teamets kultur \\ +inspirerer medlemmerne til at yde \\ +deres bedste +\item Forbedre kvaliteten af både \\ +individer og teams +\item Inspirere og engagere alle i \\ +kvalitetsprocessen +\item Opbygge og vedligeholde gode \\ +relationer med teamets \\ + interessenter +\item Forbedre \textit{Kvalitetsklimaet } i teamet og \\ +skabe en bedre holdånd +\item Sikre at teamets navn forbindes med \\ +kvalitet +\end{itemize} +\end{minipage} +% STRAN 5 +\chapter{\Large \textbf{15 Kvalitetsklima områder}} +\begin{minipage}[t]{0.54\textwidth} +\ \\ +{\large \textbf{1. Mål}} \\ +Vores mål er meningsfulde. De er klart \\ +definerede. De er realistiske, men også \\ +udfordrende. Vores mål har en tidsfrist. Vi har \\ +både små og store mål, kortsigtede og \\ +langsigtede mål, kvantitative og kvalitative mål. \\ +Vi sætter løbende mål på det personlige plan \\ + og for teamet for forskellige perioder: dage, \\ +uger, måneder, år og langsigtede visioner. Vi \\ +justerer vores langsigtede mål mindst en gang \\ +om året. \\ +\hspace*{0.8\baselineskip}Læs mere i Claus Møllers bog \textit{Mit \\ Life Livstræ}, +i kapitlet 'Mine personlige mål'. +\\ \\ +{\large \textbf{2. Ansvarsfordeling/organisation}} \\ +Alle har overblik og kontrol over de krav der \\ +bliver stillet til ham ellers hende, områderne \\ +hvor de er ansvarlige for at skabe resultater og \\ +opnå mål. Alle holder øje med de store opgaver \\ +og projekter som de løbende er involveret i \\ +og forstår deres autoritetsbeføjelser. +\\ \\ +Primære opgaver indeholder aktiviteter, som en \\ +person skal udføre for at nå et specifikt resultat. \\ +Det er en liste over alle opgaver og aktiviteter de \\ +bliver nødt til at udføre inden for hvert ansvars \\ +nøgleområde. Aktiviteter er de specifikke ting \\ +der skal udføres for at kunne løse en opgave. \\ +Hvis nye krav opstår er det nemt for alle at \\ +tilpasse sig disse og de er alle villige til at påtage \\ + sig nye ansvar, en ny type af arbejdsopgaver -- \\ +selv på tværs af professionelle eller team skel og \\ +der er behov for at diskutere spillereglerne. \\ +\hspace*{0.8\baselineskip} Læs mere i Claus Møllers bog \\ +\textit{Employeeship}, i kapitlet 'Ansvar' og afsnittet \\ +om 'Multifunktionelle ansatte'. +\end{minipage} +% STRAN 5 drugi stolpec +\begin{minipage}[t]{0.5\textwidth} +\ \\ +{\large \textbf{3. Effektivitet/produktivitet}} \\ +Alle prioriterer rigtigt. Vi gør de rigtige ting -- \\ +dem der fører til de ønskede resultater. Vi når \\ +vores mål med mindst mulig brug af ressourcer. \\ +Vi gennemfører ting til den aftalte tid. \\ + Udstyr, kontorer m.v. er pæne og rede. Alle har \\ +overblik og styr på tingene. Alle sørger for at deres \\ +bidrag til teamet og virksomheden er mere værd \\ +end deres løn. Teams indfrier omgivelsernes \\ +effektivitets- og produktivitetskrav. \\ +\hspace*{0.8\baselineskip} Læs mere i Claus Møllers bøger \\ +\textit{Employeeship}, i kapitlet om 'Produktivitet' \\ +og \textit{Heart Work}, i kapitlet 'At styre \\ + sine følelser'. +\\ \\ +{\large \textbf{4. Beslutninger}} \\ +Beslutninger træffes i teamet på et \\ +hensigtsmæssigt niveau. Beslutningshastigheden \\ +er tilfredsstillende -- beslutninger bliver ikke \\ +forsinkede eller udsat. De er truffet på et \\ +tilstrækkeligt grundlag. Vi involverer de rigtige \\ +mennesker i vores beslutninger. Vi træffer \\ +beslutninger der går ud over hvad vi plejer og \\ +hvad omgivelserne forventer, selv om de \\ +indebærer risiko. Vi er I stand til at træffe gode \\ +beslutninger hurtigt når situationen \\ +kræver det. \\ +\hspace*{0.8\baselineskip} Læs mere i Claus Møllers bog \textit{Heart \\ Work}, +specielt i sektionen om 'EI-personen'. +\\ \\ +{\large \textbf{5. Delegering}} \\ +Lederne delegerer tilstrækkeligt. Alles evner \\ +udnyttes. Alle får mulighed for at gøre det de kan \\ +og vil. Lederne er indstillet på at afgive ansvar og \\ +magt. Alle er indstillet på at påtage sig ansvar. \\ +Alle udvikles til at kunne påtage sig stadig større \\ +ansvar. Delegeringsteknikken er effektiv. \\ +\hspace*{0.8\baselineskip} Læs mere i Claus Møller bog \\ +\textit{Employeeship}, i kapitlet om 'Employeeship \\ +delegering'. +\end{minipage} + +\newpage + +% STRAN 6 +\begin{minipage}[t]{0.54\textwidth} +{\large \textbf{6. Intern kommunikation og \\ koordination}} \\ +Vi fungerer som et team. Alle trækker i samme \\ +retning. Vi informerer hinanden tilstrækkeligt. \\ +Vores kommunikationsform er hensigtsmæssig. \\ +Vores møder er effektive: velforberedte, god \\ +mødedisciplin, aktiv deltagelse af alle, \\ +handlingsplaner med navne og tidsfrister og \\ +konkrete resultater. Vi viser respekt for \\ +hinandens tid og vi udnytter hinandens viden og \\ +lærer fra hinanden -- på tværs af faggrænser. \\ +\hspace*{0.8\baselineskip} Læs mere i Claus Møllers bog \\ +\textit{Employeeship}, i afsnittet 'Employeeship \\ +og kommunikation' og i kapitlet \\ + 'Employeeship og 'vi-kultur'. +\\ \\ +{\large \textbf{7. Ekstern kommunikation og \\ koordination}} \\ +Vi har et godt samarbejde med andre teams I \\ +virksomheden. Vi fungerer godt med \\ +interessenter uden for virksomheden -- \\ +og kender dem (''vores kunder''). Vi kender hver \\ +interessents forventninger til teamet. Teamet \\ +informerer interessenterne hensigtsmæssigt. Vi \\ +kender vores konkurrenter og deres stærke og \\ +svage sider. Vi registrerer og tilpasser os \\ +forandringerne omkring os. \\ +\hspace*{0.8\baselineskip} Læs mere i Claus Møllers bøger \\ +\textit{En reklamation er en gave}, og \textit{Employeeship}, i \\ +afsnittet 'Nye krav til virksomheder'. +\\ \\ +{\large \textbf{8. Fysisk miljø}} \\ +Det fysiske miljø fremmer teamets trivsel og \\ +effektivitet. Kontorerne er lyse og har god plads. \\ +Møblerne er moderne, velholdte og ergonomisk \\ +gennemtænkte. Der er nok plads til alle også til \\ +gæster udefra. Belysningen er veltilpasset. Støj er \\ +under kontrol og alle kan undgå for meget af den. \\ +Der er nok frisk luft eller tilfredsstillende \\ +ventilation. Udstyr og materiel er i god stand. +\end{minipage} +% STRAN 6 drugi stolpec +\begin{minipage}[t]{0.5\textwidth} +{\large \textbf{9. Kvalitetsbevidsthed}} \\ +Der er klare kvalitetsmål for alle funktioner, \\ +produkter og aktiviteter. Alle team medlemmer \\ +kender teamets kvalitetsområder og -faktorer. \\ +Alle ved hvordan teamets kvalitet males. Vi \\ +kontrollerer løbende, om der er forskel på det vi \\ +gerne vil præstere og det vi faktisk præsterer. \\ +Alle i teamet arbejder med kvalitetsudvikling. Vi \\ +behandler andre mennesker og teams som \\ +''vigtige kunder''. Vi efterprøver løbende \\ +fornuften af vores handlinger (værdianalyse). \\ +Den enkelte garanterer kvaliteten af sit eget \\ + arbejde. Vi forlanger kvalitet af hinanden -- og \\ +af vores omgivelser. Vi gør noget aktivt for \\ + at forebygge fejl. Vi håndterer fejl effektivt, \\ + glæder os når vi konstaterer dem, takker de \\ +personer der gør os opmærksom på fejlene, \\ + retter dem og undgår at gentage dem. \\ +\hspace*{0.8\baselineskip} Læs mere i Claus Møllers bog \\ +\textit{Personlig kvalitet}, specielt afsnittet om \\ +'Personlig garanti' eller læs pjecen \\ +\textit{Personlig garanti}. +\\ \\ +{\large \textbf{10. Kreativitet og innovation}} \\ +Vi ser udviklingen omkring os. Alle indser \\ +nødvendigheden af forandring. Vi har let ved at \\ +omstille os. Vi er fleksible. Vi tager ny teknologi i \\ +anvendelse. Vi anvender kreativ tænkning og \\ +kreativitetsteknikker. Alle ager initiativ til at \\ +forbedre teamets indsats: gøre tingene hurtigere, \\ +med færre omkostninger, mere kreativt og med \\ +en højere kvalitet. \\ +\hspace*{0.8\baselineskip} Læs mere i Claus Møllers bog \\ +\textit{Employeeship}, i kapitlerne 'Employeeship \\ +delegering' og 'Initiativ'. +\end{minipage} + +\newpage + +% STRAN 7 +\begin{minipage}[t]{0.54\textwidth} +{\large \textbf{11. Engagement}} \\ +Alle i vores team er engagerede i deres arbejde -- \\ +både med hjernen og med hjertet. Alle føler \\ +medansvar for teamets succeser og fiaskoer. Vi \\ +stiller alle op og yder vores bedste. Vi holder \\ +vores aftaler. Vi tager alle initiativ til forbedring \\ +og udvikling. Alle er indstillet på at yde en ekstra \\ +indsats, når det er påkrævet. Alle ser en \\ +udfordring i enhver funktion og handling. \\ +\hspace*{0.8\baselineskip} Læs mere i Claus Møllers bøger \\ +\textit{Employeeship} og \textit{Heart Work}. +\\ \\ +{\large \textbf{12. Anerkendelse og belønning}} \\ +Anerkendelse forekommer hyppigere end kritik \\ +og irettesættelse. Gode resultater bliver \\ +synliggjort. Gode præstationer belønnes. Gode \\ +præstationer fremmer mulighederne for \\ +forfremmelse og udvikling. Ledelsen fokuserer \\ +mere på medlemmernes stærke sider end på \\ +deres svage. Vi sikrer os, at vi ikke har \\ +medlemmer som stort set aldrig får \\ +opmærksomhed og anerkendelse. Vi forventer \\ +anerkendelse snarere end kritik, når et medlem \\ +kaldes til lederen. \\ +\hspace*{0.8\baselineskip} Læs mere i Claus Møllers bog \textit{Mit \\ livstræ}, +i kapitlet 'Miljøet -- grobunden'. +\\ \\ +{\large \textbf{13. Personlig udvikling}} \\ +Alle inspireres til udvikling. Der findes planer for \\ +udviklingen af den enkelte. Der tilbydes gode \\ +uddannelsesmuligheder. Virksomheden betaler \\ +for uddannelsen af de ansatte. Der er \\ +muligheder for jobrotation, fleksible arbejdstider \\ +og -steder, jobdeling, variation, og forfremmelse. \\ +Hver enkelt stilles over for rimelige \\ +udfordringer. \\ +\hspace*{0.8\baselineskip} Læs mere i Claus Møllers bog \\ +\textit{Employeeship}, i afsnittet 'Den bløde \\ +kontrakt' og kapitlet \\ +'Employeeship personalepolitik'. +\end{minipage} +% STRAN 7 drugi stolpec +\begin{minipage}[t]{0.5\textwidth} +{\large \textbf{14. Øvrigt psykisk miljø (relationer)}} \\ +Vi har det sjovt sammen. Vi glæder os til at \\ +komme på arbejde -- hver dag. Vi føler os trygge i \\ +ansættelsen. Vi hjælper og opmuntrer hinanden. \\ +Vores kommunikation er baseret på åbenhed og \\ +ærlighed. Vi viser tillid til hinanden. Vi taler med \\ +hinanden -- og ikke om hinanden. Vi respekterer \\ +hinandens kunnen, ønsker og særpræg. \\ +\hspace*{0.8\baselineskip} Læs mere i Claus Møllers bog \textit{Mit \\ Life livstræ}. +\\ \\ +{\large \textbf{15. Implementering}} \\ +Vi kan omskrive ideer og tanker til handling. Vi får \\ +tingene gjort i stedet for kun at tale om dem. Vi \\ +færdiggør de ting, vi har sat i gang. Vi følger op pa \\ +at opgaver udføres som aftalt. Ledelsen følger op \\ +på og bevarer interessen for opgaver, som den \\ +har sat i gang. Vi koncentrerer os om få vigtige \\ +opgaver ad gangen, frem for at have en masse \\ +bolde i luften på en gang. Ansvaret for et projekt \\ +er entydigt placeret hos én projektleder. \\ +Projektlederen har beføjelser og myndighed til at \\ +træffe alle nødvendige beslutninger på vej mod \\ +målet. Vi kan fjerne forhindringerne på vej mod \\ +målet. \\ +\hspace*{0.8\baselineskip} Læs mere i Claus Møllers bog \\ +\textit{Employeeship}, i kapitlet 'Implementering \\ +af Employeeship' og i bogen \textit{Personlig kvalitet}, \\ +specifikt afsnittet 'Lær at fuldføre -- skab \\ + selvdisciplin'. +\end{minipage} + + +\newpage + +\chapter{\Large \textbf{Sådan anvendes Kvalitetsklima værktøjet}} +\begin{center} +\begin{minipage}{0.8\linewidth} +\begin{center} +{\large \textbf{Sådan anvender den enkelte værktøjet}} +\end{center} +\ \\ +\renewcommand\labelitemi{\large$\bullet$} +\begin{itemize} +\item Hver enkelt gennemgår sin egen besvarelse af \textit{Kvalitetsklima}. Derved \\ +opnås en bevidsthed om, på hvilke områder teamkvaliteten efter den \\ +enkeltes opfattelse skal udvikles. +\item Ved at sammenligne egen besvarelse med det samlede teamresultat \\ +kan hver enkelt se, hvordan deres vurdering er i forhold til kollegaernes \\ +vurdering. +\item Med den nye indsigt kan den enkelte bedre bidrage til at udvikle \\ +\textit{Teamkvalitet}. +\end{itemize} + +\ \\ \\ \\ +\renewcommand\labelitemi{\large$\bullet$} +\begin{center} +{\large \textbf{Sådan anvender virksomheden værktøjet}} \\ +\end{center} +\begin{itemize} + +\item \textit{Kvalitetsklima} værktøjet anvendes af alle teams i virksomheden. \\ +Resultaterne i de enkelte teams sammenlignes og diskuteres med \\ +henblik på at opnå forbedringer i hele virksomheden. +\item Den øverste ledelse kan anvende Kvalitetsklima til at identificere teams, \\ +der trænger til hjælp, eller teams, som resten af virksomheden kan lære \\ +noget af. +\item Man kan få et indtryk af hele virksomhedens stærke og svage sider ved \\ +at se på de områder, hvor alle teams stort set får samme vurdering. +\item Hvis et teams resultat for et eller flere områder afviger væsentligt fra \\ +alle andre teams resultater, får man et indtryk af teamets særpræg. +\item For at registrere forandringer og succeser anvendes Kvalitetsklima af \\ +alle teams mindst en gang om året, og når der sker strukturelle \\ +forandringer på markedet og internt I virksomheden. +\end{itemize} +\end{minipage} +\end{center} +\newpage + +% STRAN 8 +\chapter{\Large \textbf{Hvad viser graferne?}} +\begin{minipage}[t]{0.5\textwidth} +De ansatte har vurderet områderne på en skala \\ +fra 1 til 5.\\ + +\vspace*{-2.2\baselineskip} \hspace*{-0.2\baselineskip} \includegraphics[width=5.6cm]{../latexkosi/logo/legend_description_dan.png}~\\[1cm] + +\newline + +Graferne viser svarenes fordeling i procent. \\ +En god tommelfingerregel er, at der bør ske \\ +forbedringer for de faktorer, hvor: +\begin{itemize} +\item[--] \textbf{mere end 20 \%} af de ansatte har \\ +markeret 'Utilfredsstillende' eller \\ +'Meget utilfredsstillende' \\ +og/eller +\item[--] \textbf{mindre end 50 \%} af de ansatte har \\ +markeret 'Meget tilfredsstillende' eller \\ + 'Særdeles tilfredsstillende'. +\end{itemize} +\ \\ \\ \\ + \includegraphics[width=16cm]{../latexkosi/logo/klima_kakovosti_middle.png} % horizontal space +\end{minipage} +% STRAN 8 drugi stolpec +\begin{minipage}[t]{0.5\textwidth} +\renewcommand\labelitemi{\small$\bullet$} +\begin{itemize} +\item Det samlede resultat af \\ +\textbf{Kvalitetsklima} bør diskuteres \\ +grundigt på et møde for afdelingens \\ +ansatte.\\ +Mødet bør munde ud i en konkret plan for \\ +udvikling og forbedring af kvalitetskulturen. \\ +Denne plan bør med mellemrum justeres \\ +på afdelingsmøder. +\end{itemize} +\end{minipage} + +\newpage +\begin{center} +\LARGE\textbf{!company name!} +\end{center} +% Odstranimo razmik po poglavju +\begingroup +\renewcommand{\cleardoublepage}{} +\renewcommand{\clearpage}{} +\chapter{\Large \textbf{Kvalitetsklima for alle teams}} +\endgroup diff --git a/admin/survey/modules/mod_EVOLI/latexkosi/logo/klima_kakovosti_dan.png b/admin/survey/modules/mod_EVOLI/latexkosi/logo/klima_kakovosti_dan.png new file mode 100644 index 000000000..6ee2db14f Binary files /dev/null and b/admin/survey/modules/mod_EVOLI/latexkosi/logo/klima_kakovosti_dan.png differ diff --git a/admin/survey/modules/mod_EVOLI/latexkosi/pojasnilo.konec_ang.tex b/admin/survey/modules/mod_EVOLI/latexkosi/pojasnilo.konec_ang.tex index f8b18af1d..0a8e5b0c1 100644 --- a/admin/survey/modules/mod_EVOLI/latexkosi/pojasnilo.konec_ang.tex +++ b/admin/survey/modules/mod_EVOLI/latexkosi/pojasnilo.konec_ang.tex @@ -85,8 +85,8 @@ productivity, relationships, quality and leadership. \begin{center} -Batzkes Bakke 3, DK-3400 Hiller{\o}d, Denmark \\[0.3cm] - \href{http://info@clausmoller.com}{info@clausmoller.com} \hspace{15pt} \url{http://www.clausmoller.com } +Smledni\v{s}ka 140, SI-4000 Kranj, Slovenija \\[0.3cm] + \href{mailto:info@clausmoller.com}{info@clausmoller.com} \hspace{15pt} \href{www.clausmoller.com}{www.clausmoller.com} \end{center} diff --git a/admin/survey/modules/mod_EVOLI/latexkosi/pojasnilo.konec_dan.tex b/admin/survey/modules/mod_EVOLI/latexkosi/pojasnilo.konec_dan.tex index 26741df61..af90d1154 100644 --- a/admin/survey/modules/mod_EVOLI/latexkosi/pojasnilo.konec_dan.tex +++ b/admin/survey/modules/mod_EVOLI/latexkosi/pojasnilo.konec_dan.tex @@ -89,8 +89,8 @@ Claus Møller Consulting tilbyder rådgivning til virksomheder og organisationer \begin{center} -Batzkes Bakke 3, DK-3400 Hiller{\o}d, Denmark \\[0.3cm] - \href{http://info@clausmoller.com}{info@clausmoller.com} \hspace{15pt} \url{http://www.clausmoller.com } +Smledni\v{s}ka 140, SI-4000 Kranj, Slovenija \\[0.3cm] + \href{mailto:info@clausmoller.com}{info@clausmoller.com} \hspace{15pt} \href{www.clausmoller.com}{www.clausmoller.com} \end{center} diff --git a/admin/survey/modules/mod_EVOLI/latexkosi/pojasnilo.konec_slo.tex b/admin/survey/modules/mod_EVOLI/latexkosi/pojasnilo.konec_slo.tex index 09424abb6..09a517921 100644 --- a/admin/survey/modules/mod_EVOLI/latexkosi/pojasnilo.konec_slo.tex +++ b/admin/survey/modules/mod_EVOLI/latexkosi/pojasnilo.konec_slo.tex @@ -89,8 +89,8 @@ produktivnost, odnose, kakovost in voditeljstvo. \begin{center} -Maistrova 18, SI-1241 Kamnik, Slovenija \\[0.3cm] -http://info@evoli.si \hspace{15pt} \url{http://www.evoli.si/} +Smledniška 140, SI-4000 Kranj, Slovenija \\[0.3cm] + \href{mailto:info@clausmoller.com}{info@clausmoller.com} \hspace{15pt} \href{www.clausmoller.com}{www.clausmoller.com} \end{center} diff --git a/admin/survey/modules/mod_MFDPS/class.SurveyMFDPS.php b/admin/survey/modules/mod_MFDPS/class.SurveyMFDPS.php index 354f5ef82..b3d320fb3 100644 --- a/admin/survey/modules/mod_MFDPS/class.SurveyMFDPS.php +++ b/admin/survey/modules/mod_MFDPS/class.SurveyMFDPS.php @@ -1,8 +1,8 @@ createList($list_name='Testni seznam Xyz'); + +/*$result = $squalo->createNewsletter( + $list_id = '5', + $subject = 'Testek', + $body = 'Testno sporočilo...', + $body_alt = 'Testno sporočilo ALT...', + $from_email = 'peter.hrvatin@gmail.com', + $from_name = 'Peter', + $reply_to_email = 'peter.hrvatin@gmail.com', + $language = 'sl' +);*/ + +//$result = $squalo->addRecipient($email='peter.h1203@gmail.com', $list_id='5'); + +//$result = $squalo->sendEmails($newsletter_id='24'); + +//$result = $squalo->deleteRecipient($recipient_id='2'); + + + + +echo '
    '; print_r($result); echo '
    '; + + + \ No newline at end of file diff --git a/admin/survey/modules/mod_squalo/class.SqualoApi.php b/admin/survey/modules/mod_squalo/class.SqualoApi.php new file mode 100644 index 000000000..ce821357a --- /dev/null +++ b/admin/survey/modules/mod_squalo/class.SqualoApi.php @@ -0,0 +1,269 @@ +executeGET($action, $data); + } + // POST call + else{ + $response = $this->executePOST($action, $data); + } + + // Decode json response + $response_array = json_decode($response, true); + + // Error + if($response_array['errorCode'] != '0'){ + $result['error'] = $response_array["errorMessage"]. ' (code '.$response_array["errorCode"].')'; + $result['success'] = false; + } + else{ + $result = $response_array; + $result['success'] = true; + } + + return $result; + } + + // Izvedemo post klic + private function executePOST($action, $data){ + + // Nastavimo url + $url = $this->api_url.$action; + + + // Init curl + $ch = curl_init($url); + + // JSON string za POST + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); + + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + // for debug only! + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + + $headers = array( + "Content-Type: application/json", + ); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + + + // Izvedemo klic + $response = curl_exec($ch); + curl_close($ch); + + + return $response; + } + + // Izvedemo get klic + private function executeGET($action, $data){ + + // GET params + $params = '?'; + foreach($data as $name => $value){ + $params .= $name.'='.$value.'&'; + } + $params = substr($params, 0, -1); + + // Nastavimo celoten url s parametri + $url = $this->api_url.$action.$params; + + + // Init curl + $ch = curl_init($url); + + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET'); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + + // Izvedemo klic + $response = curl_exec($ch); + + return $response; + } + + + /* + Ustvarimo seznam uporabnikov za pošiljanje + create-list + + "name":"String content", + "description":"String content", + "listTag":"String content", + "color":"String content", + "ordering":2147483647, + "published":true + + {subtag:name} + {subtag:code} + {subtag:url} + + {date:4} + + {unsubscribe}{/unsubscribe} + */ + public function createList($list_name){ + + $action = 'create-list'; + $method = 'POST'; + + $data = array( + 'name' => $list_name, + 'ordering' => $list_number, + 'published' => true + ); + + $response = $this->executeCall($action, $method, $data); + + return $response; + } + + /* + Ustvarimo email,ki se bo poslal + + "altBody":"String content", + "body":"String content", + "fromEmail":"String content", + "fromName":"String content", + "language":"String content", + "listIds":[2147483647], + "published":2147483647, + "replyToEmail":"String content", + "replyToName":"String content", + "subject":"String content", + "visible":true + */ + public function createNewsletter($list_id, $subject, $body, $body_alt, $from_email, $from_name, $reply_to_email, $language){ + + $action = 'create-newsletter'; + $method = 'POST'; + + $data = array( + 'listIds' => array($list_id), + 'subject' => $subject, + 'body' => $body, + 'altBody' => $body_alt, + 'fromEmail' => $from_email, + 'fromName' => $from_name, + 'replyToEmail' => $reply_to_email, + 'language' => $language, + 'visible' => true + ); + + $response = $this->executeCall($action, $method, $data); + + return $response; + } + + /* + Dodamo prejemnika + + "accept": true, + "confirmed": true, + "customAttributes": [{ + "name": "firstname", + "value": "John" + }, + { + "name": "lastname", + "value": "Smith" + } + ], + "email": "String content", + "enabled": true, + "html": true, + "listIds": [2147483647], + "name": "String content", + "surname": "String content", + "gender": "null | male | female | other", + "gdprCanSend": true, + "gdprCanTrack": true + */ + public function addRecipient($email, $list_id, $custom_attributes=array()){ + + $action = 'create-recipient'; + $method = 'POST'; + + $data = array( + 'email' => $email, + 'listIds' => array($list_id), + 'accept' => true, + 'confirmed' => true, + 'enabled' => true, + 'gdprCanSend' => true, + 'gdprCanTrack' => true + ); + + $response = $this->executeCall($action, $method, $data); + + return $response; + } + + /* + Pošljemo emaile + + "newsletterId":2147483647, + "sendDate":2147483647 + */ + public function sendEmails($newsletter_id){ + + $action = 'send-newsletter'; + $method = 'GET'; + + $data = array( + 'newsletterId' => $newsletter_id, + 'sendDate' => time()+30 + ); + + $response = $this->executeCall($action, $method, $data); + + return $response; + } + + + // Pobrisemo prejemnika + public function deleteRecipient($recipient_id){ + + $action = 'delete-recipient'; + $method = 'GET'; + + $data = array( + 'recipientId' => $recipient_id + ); + + $response = $this->executeCall($action, $method, $data); + + return $response; + } + +} \ No newline at end of file diff --git a/admin/survey/modules/mod_uporabnost/class.SurveyUporabnost.php b/admin/survey/modules/mod_uporabnost/class.SurveyUporabnost.php index b4d01d02d..16b3f1dfa 100644 --- a/admin/survey/modules/mod_uporabnost/class.SurveyUporabnost.php +++ b/admin/survey/modules/mod_uporabnost/class.SurveyUporabnost.php @@ -1,8 +1,8 @@ 0) { - tabelaDataTables = $('#my_users_list').DataTable({ - "ajax": { - "url": siteUrl+"admin/survey/ajax.php?t=dostop&a=my_users_list", - "type": "post" - }, - serverSide: true, - lengthMenu: [[50, 500, 1000, 5000, 10000], [50, 500, 1000, 5000, 10000]], - dom: 'Blfrtip', - deferRender: true, - select: true, - buttons: [ - { - extend: 'copy', - exportOptions: { - columns: ':visible' - } - }, - { - extend: 'print', - exportOptions: { - columns: ':visible' - } - }, - { - extend: 'csv', - bom: true, - exportOptions: { - columns: ':visible' - } - }, - { - extend: 'excel', - bom: true, - exportOptions: { - columns: ':visible' - } - }, - { - extend: 'pdf', - orientation: 'landscape', - pageSize: 'LEGAL', - exportOptions: { - columns: ':visible' - } - }, - 'colvis' - ], - language: { - "url": siteUrl+"admin/survey/script/datatables/Slovenian.json" - } - }); + tabelaDataTables = $('#my_users_list').DataTable({ + "ajax": { + "url": siteUrl+"admin/survey/ajax.php?t=dostop&a=my_users_list", + "type": "post" + }, + serverSide: true, + lengthMenu: [[50, 500, 1000, 5000, 10000], [50, 500, 1000, 5000, 10000]], + dom: 'Blfrtip', + deferRender: true, + select: true, + buttons: [ + ], + language: { + "url": siteUrl+"admin/survey/script/datatables/Slovenian.json" + }, + fnInitComplete : function() { + if ($(this).find('tbody tr td').hasClass('dataTables_empty')) { + $(this).parent().parent().hide(); + } + } + }); } if ($('#deleted_users_list').length > 0) { @@ -564,7 +561,7 @@ function izbrisiNepotrjenegaUporabnika(id) { function vsiUporabnikiAkcija(id, action) { var action = action || 'delete'; - if(action == 'delete' && !confirm(lang['srv_survey_list_users_confirm_delete'])){ + if(action == 'delete' && !confirm(lang['srv_survey_list_users_confirm_delete_warning'])){ return false; } diff --git a/admin/survey/script/invitations.js b/admin/survey/script/invitations.js index e84fccc69..289b330d8 100644 --- a/admin/survey/script/invitations.js +++ b/admin/survey/script/invitations.js @@ -1530,11 +1530,19 @@ function create_inv_editor (id, focus) { id='inv_message_body'; if (!editor_init) { - CKEDITOR.replace( id ); + CKEDITOR.replace(id, { + fullPage: true, + allowedContent: true + }); + editor_init = true; - }else{ - CKEDITOR.replace(id); - } + } + else{ + CKEDITOR.replace(id, { + fullPage: true, + allowedContent: true + }); + } } function mailSourceMesageChange(what) { @@ -1700,4 +1708,40 @@ function noEmailingToggle(value){ function noEmailingType(value){ $.post('ajax.php?t=invitations&a=set_noEmailing_type', {anketa:srv_meta_anketa_id, value:value}); -} \ No newline at end of file +} + + +// AAI - popup pri vklopu ARNES smtp streznika pri vabilih +function smtpAAIPopupShow(){ + + $('#fade').fadeTo('slow', 1); + $('#popup_note').html('').fadeIn('slow'); + $("#popup_note").load('ajax.php?t=invitations&a=showAAISmtpPopup', {anketa: srv_meta_anketa_id, noNavi:'true'}); +} +function smtpAAIPopupClose(){ + + // Ni sprejel - vrnemo radio + $('input[name=SMTPMailMode][value=2]').prop('checked', true); + + $('#popup_note').fadeOut('slow').html(''); + $('#fade').fadeOut('slow'); +} +function smtpAAISet(){ + + // Shranimo formo + $("form[name='settingsanketa_"+srv_meta_anketa_id+"']").submit(); + + // Prikazemo nastavitve za Arnes smtp + /*$('#send_mail_mode1, #send_mail_mode2').hide(); + $('#send_mail_mode0').show(); + + // Zapremo popup + smtpAAIPopupClose();*/ +} +function smtpAAIAccept(){ + + if($('#aai_smtp_checkbox').is(':checked')) + $('#aai_smtp_button').show(); + else + $('#aai_smtp_button').hide(); +} diff --git a/admin/survey/script/js-lang.php b/admin/survey/script/js-lang.php index a5c3d3718..7b45bfa71 100644 --- a/admin/survey/script/js-lang.php +++ b/admin/survey/script/js-lang.php @@ -179,6 +179,7 @@ lang('change_account_pass_conformation'); lang('cms_error_password_incorrect'); lang('password_err_complex'); lang('srv_survey_list_users_confirm_delete'); +lang('srv_survey_list_users_confirm_delete_warning'); lang('login_alternative_emails_error'); lang('login_alternative_emails_success'); lang('srv_user_exist'); @@ -190,6 +191,7 @@ lang('srv_delete_testdata_warning'); lang('srv_alert_upload_size'); lang('srv_alert_upload_ext'); lang('srv_trans_lang'); +lang('srv_manager_remove_alert'); //LOKACIJA diff --git a/admin/survey/script/narocila.js b/admin/survey/script/narocila.js index c2a078f8d..103c8c253 100644 --- a/admin/survey/script/narocila.js +++ b/admin/survey/script/narocila.js @@ -230,6 +230,15 @@ function urediNarociloPay(narocilo_id){ $('#fade').fadeOut('slow'); }); } +// Urejanje narocila - placaj eracun +function urediNarociloPayEracun(narocilo_id){ + + $("#narocila").load('ajax.php?t=userNarocila&a=payNarociloEracun', {narocilo_id: narocilo_id, payment_method: '1'}, function () { + + $('#user_narocila_popup').hide().html(''); + $('#fade').fadeOut('slow'); + }); +} // Urejanje narocila - zapri function urediNarociloClose(){ diff --git a/admin/survey/script/script.js b/admin/survey/script/script.js index c8440ed43..1aea2fd86 100644 --- a/admin/survey/script/script.js +++ b/admin/survey/script/script.js @@ -3919,11 +3919,10 @@ function showSearchb() { function executeDrupalSearch() { - //var url = 'https://www.1ka.si/d/sl/search/node/'; var url = $('#drupal_search_url').val(); - var searchString = $('#searchSurvey').val(); - - window.location = url + encodeURIComponent(searchString); + var searchString = $('#searchSurvey').val(); + + window.open(url + encodeURIComponent(searchString), '_blank'); } function showAdvancedSearch(){ @@ -4229,10 +4228,6 @@ function add_to_library(anketa,where) { $.post('ajax.php?a=add_to_library', {anketa:anketa, where:where}); } -function refresh_user_diagnostic(field, type, show, limit) { - $('#survey_list').load('ajax.php?a=refreshUserDiagnostic', {field:field, type:type, show:show, limit:limit}); -} - function create_archive_survey(anketa, msg) { $('#fade').fadeTo('slow', 1); $('#fullscreen').html('').fadeIn('slow').draggable({delay:100, cancel: 'input, textarea, select, .buttonwrapper'}); @@ -5459,3 +5454,17 @@ $(document).ready(function(){ }); }); + + +// Popup za individualno svetovanje +function consultingPopupOpen(){ + + $('#fade').fadeTo('slow', 1); + $('#popup_note').html('').fadeIn('slow'); + $("#popup_note").load('ajax.php?a=consulting_popup_open', {anketa: srv_meta_anketa_id}); +} +function consultingPopupClose(){ + + $('#popup_note').fadeOut('slow').html(''); + $('#fade').fadeOut('slow'); +} diff --git a/composer.lock b/composer.lock index edfe49a15..60ae7033e 100644 --- a/composer.lock +++ b/composer.lock @@ -9,16 +9,16 @@ "packages": [ { "name": "composer/ca-bundle", - "version": "1.2.8", + "version": "1.2.9", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "8a7ecad675253e4654ea05505233285377405215" + "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/8a7ecad675253e4654ea05505233285377405215", - "reference": "8a7ecad675253e4654ea05505233285377405215", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/78a0e288fdcebf92aa2318a8d3656168da6ac1a5", + "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5", "shasum": "" }, "require": { @@ -27,14 +27,15 @@ "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8", + "phpstan/phpstan": "^0.12.55", "psr/log": "^1.0", + "symfony/phpunit-bridge": "^4.2 || ^5", "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-main": "1.x-dev" } }, "autoload": { @@ -61,7 +62,7 @@ "ssl", "tls" ], - "time": "2020-08-23 12:54:47" + "time": "2021-01-12 12:10:35" }, { "name": "fgrosse/phpasn1", @@ -378,27 +379,28 @@ }, { "name": "maxmind-db/reader", - "version": "v1.8.0", + "version": "v1.10.0", "source": { "type": "git", "url": "https://github.com/maxmind/MaxMind-DB-Reader-php.git", - "reference": "b566d429ac9aec10594b0935be8ff38302f8d5c8" + "reference": "07f84d969cfc527ce49388558a366ad376f1f35c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/b566d429ac9aec10594b0935be8ff38302f8d5c8", - "reference": "b566d429ac9aec10594b0935be8ff38302f8d5c8", + "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/07f84d969cfc527ce49388558a366ad376f1f35c", + "reference": "07f84d969cfc527ce49388558a366ad376f1f35c", "shasum": "" }, "require": { "php": ">=7.2" }, "conflict": { - "ext-maxminddb": "<1.8.0,>=2.0.0" + "ext-maxminddb": "<1.10.0,>=2.0.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "2.*", + "friendsofphp/php-cs-fixer": "*", "php-coveralls/php-coveralls": "^2.1", + "phpstan/phpstan": "*", "phpunit/phpcov": ">=6.0.0", "phpunit/phpunit": ">=8.0.0,<10.0.0", "squizlabs/php_codesniffer": "3.*" @@ -434,7 +436,7 @@ "geolocation", "maxmind" ], - "time": "2020-10-01 17:30:21" + "time": "2021-02-09 17:52:47" }, { "name": "maxmind/web-service-common", @@ -755,16 +757,16 @@ }, { "name": "phpmailer/phpmailer", - "version": "v6.2.0", + "version": "v6.3.0", "source": { "type": "git", "url": "https://github.com/PHPMailer/PHPMailer.git", - "reference": "e38888a75c070304ca5514197d4847a59a5c853f" + "reference": "4a08cf4cdd2c38d12ee2b9fa69e5d235f37a6dcb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/e38888a75c070304ca5514197d4847a59a5c853f", - "reference": "e38888a75c070304ca5514197d4847a59a5c853f", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/4a08cf4cdd2c38d12ee2b9fa69e5d235f37a6dcb", + "reference": "4a08cf4cdd2c38d12ee2b9fa69e5d235f37a6dcb", "shasum": "" }, "require": { @@ -817,7 +819,7 @@ } ], "description": "PHPMailer is a full-featured email creation and transfer class for PHP", - "time": "2020-11-25 15:24:57" + "time": "2021-02-19 15:28:08" }, { "name": "psr/http-message", @@ -1019,16 +1021,16 @@ }, { "name": "stripe/stripe-php", - "version": "v7.66.1", + "version": "v7.75.0", "source": { "type": "git", "url": "https://github.com/stripe/stripe-php.git", - "reference": "a2ebaa272a8797b21e81afaf8d5ba0953ff15e13" + "reference": "d377a667cd789b99ccab768441a5a2160cc4ea80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/stripe/stripe-php/zipball/a2ebaa272a8797b21e81afaf8d5ba0953ff15e13", - "reference": "a2ebaa272a8797b21e81afaf8d5ba0953ff15e13", + "url": "https://api.github.com/repos/stripe/stripe-php/zipball/d377a667cd789b99ccab768441a5a2160cc4ea80", + "reference": "d377a667cd789b99ccab768441a5a2160cc4ea80", "shasum": "" }, "require": { @@ -1038,7 +1040,7 @@ "php": ">=5.6.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "2.16.5", + "friendsofphp/php-cs-fixer": "2.17.1", "php-coveralls/php-coveralls": "^2.1", "phpunit/phpunit": "^5.7", "squizlabs/php_codesniffer": "^3.3", @@ -1072,20 +1074,20 @@ "payment processing", "stripe" ], - "time": "2020-12-01 18:44:12" + "time": "2021-02-22 14:31:21" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.20.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "3b75acd829741c768bc8b1f84eb33265e7cc5117" + "reference": "2d63434d922daf7da8dd863e7907e67ee3031483" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/3b75acd829741c768bc8b1f84eb33265e7cc5117", - "reference": "3b75acd829741c768bc8b1f84eb33265e7cc5117", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/2d63434d922daf7da8dd863e7907e67ee3031483", + "reference": "2d63434d922daf7da8dd863e7907e67ee3031483", "shasum": "" }, "require": { @@ -1099,7 +1101,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.20-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1142,20 +1144,20 @@ "portable", "shim" ], - "time": "2020-10-23 14:02:19" + "time": "2021-01-22 09:19:47" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.20.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "727d1096295d807c309fb01a851577302394c897" + "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/727d1096295d807c309fb01a851577302394c897", - "reference": "727d1096295d807c309fb01a851577302394c897", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/43a0283138253ed1d48d352ab6d0bdb3f809f248", + "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248", "shasum": "" }, "require": { @@ -1167,7 +1169,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.20-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1209,20 +1211,20 @@ "portable", "shim" ], - "time": "2020-10-23 14:02:19" + "time": "2021-01-22 09:19:47" }, { "name": "symfony/polyfill-php72", - "version": "v1.20.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "cede45fcdfabdd6043b3592e83678e42ec69e930" + "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cede45fcdfabdd6043b3592e83678e42ec69e930", - "reference": "cede45fcdfabdd6043b3592e83678e42ec69e930", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", + "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", "shasum": "" }, "require": { @@ -1231,7 +1233,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.20-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1268,7 +1270,7 @@ "portable", "shim" ], - "time": "2020-10-23 14:02:19" + "time": "2021-01-07 16:49:33" }, { "name": "web-token/jwt-core", @@ -1910,16 +1912,16 @@ "packages-dev": [ { "name": "filp/whoops", - "version": "2.9.1", + "version": "2.9.2", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "307fb34a5ab697461ec4c9db865b20ff2fd40771" + "reference": "df7933820090489623ce0be5e85c7e693638e536" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/307fb34a5ab697461ec4c9db865b20ff2fd40771", - "reference": "307fb34a5ab697461ec4c9db865b20ff2fd40771", + "url": "https://api.github.com/repos/filp/whoops/zipball/df7933820090489623ce0be5e85c7e693638e536", + "reference": "df7933820090489623ce0be5e85c7e693638e536", "shasum": "" }, "require": { @@ -1967,7 +1969,7 @@ "throwable", "whoops" ], - "time": "2020-11-01 12:00:00" + "time": "2021-01-24 12:00:00" }, { "name": "kint-php/kint", @@ -2022,25 +2024,25 @@ }, { "name": "maximebf/debugbar", - "version": "v1.16.3", + "version": "v1.16.5", "source": { "type": "git", "url": "https://github.com/maximebf/php-debugbar.git", - "reference": "1a1605b8e9bacb34cc0c6278206d699772e1d372" + "reference": "6d51ee9e94cff14412783785e79a4e7ef97b9d62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/1a1605b8e9bacb34cc0c6278206d699772e1d372", - "reference": "1a1605b8e9bacb34cc0c6278206d699772e1d372", + "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/6d51ee9e94cff14412783785e79a4e7ef97b9d62", + "reference": "6d51ee9e94cff14412783785e79a4e7ef97b9d62", "shasum": "" }, "require": { - "php": "^7.1", + "php": "^7.1|^8", "psr/log": "^1.0", "symfony/var-dumper": "^2.6|^3|^4|^5" }, "require-dev": { - "phpunit/phpunit": "^5" + "phpunit/phpunit": "^7.5.20 || ^9.4.2" }, "suggest": { "kriswallsmith/assetic": "The best way to manage assets", @@ -2079,7 +2081,7 @@ "debug", "debugbar" ], - "time": "2020-05-06 07:06:27" + "time": "2020-12-07 11:07:24" }, { "name": "psr/log", @@ -2130,16 +2132,16 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.20.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "39d483bdf39be819deabf04ec872eb0b2410b531" + "reference": "5232de97ee3b75b0360528dae24e73db49566ab1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/39d483bdf39be819deabf04ec872eb0b2410b531", - "reference": "39d483bdf39be819deabf04ec872eb0b2410b531", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/5232de97ee3b75b0360528dae24e73db49566ab1", + "reference": "5232de97ee3b75b0360528dae24e73db49566ab1", "shasum": "" }, "require": { @@ -2151,7 +2153,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.20-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -2189,20 +2191,20 @@ "portable", "shim" ], - "time": "2020-10-23 14:02:19" + "time": "2021-01-22 09:19:47" }, { "name": "symfony/polyfill-php80", - "version": "v1.20.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "e70aa8b064c5b72d3df2abd5ab1e90464ad009de" + "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/e70aa8b064c5b72d3df2abd5ab1e90464ad009de", - "reference": "e70aa8b064c5b72d3df2abd5ab1e90464ad009de", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dc3063ba22c2a1fd2f45ed856374d79114998f91", + "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91", "shasum": "" }, "require": { @@ -2211,7 +2213,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.20-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -2255,20 +2257,20 @@ "portable", "shim" ], - "time": "2020-10-23 14:02:19" + "time": "2021-01-07 16:49:33" }, { "name": "symfony/var-dumper", - "version": "v4.4.17", + "version": "v4.4.19", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "65c6f1e848cda840ef7278686c8e30a7cc353c93" + "reference": "a1eab2f69906dc83c5ddba4632180260d0ab4f7f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/65c6f1e848cda840ef7278686c8e30a7cc353c93", - "reference": "65c6f1e848cda840ef7278686c8e30a7cc353c93", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/a1eab2f69906dc83c5ddba4632180260d0ab4f7f", + "reference": "a1eab2f69906dc83c5ddba4632180260d0ab4f7f", "shasum": "" }, "require": { @@ -2285,7 +2287,7 @@ "ext-iconv": "*", "symfony/console": "^3.4|^4.0|^5.0", "symfony/process": "^4.4|^5.0", - "twig/twig": "^1.34|^2.4|^3.0" + "twig/twig": "^1.43|^2.13|^3.0.4" }, "suggest": { "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", @@ -2321,13 +2323,13 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony mechanism for exploring and dumping PHP variables", + "description": "Provides mechanisms for walking through any arbitrary PHP variable", "homepage": "https://symfony.com", "keywords": [ "debug", "dump" ], - "time": "2020-11-24 09:55:37" + "time": "2021-01-27 09:09:26" } ], "aliases": [], diff --git a/editors/ckeditor_4_4/config.js b/editors/ckeditor_4_4/config.js index 57e36727c..fe40437af 100644 --- a/editors/ckeditor_4_4/config.js +++ b/editors/ckeditor_4_4/config.js @@ -6,11 +6,15 @@ //spremenljivka za ID elementa od txtUrl var urlsrc = ''; +// Jezik za image uploader +var lang = 'sl'; CKEDITOR.editorConfig = function (config) { //config.language = 'sl'; config.skin = 'moonocolor'; + lang = config.language; + config.toolbar = [ {name: 'document', items: ['Source', '-']}, {name: 'clipboard', items: ['PasteText','RemoveFormat', 'Undo', 'Redo', 'Scayt']}, @@ -93,6 +97,9 @@ CKEDITOR.editorConfig = function (config) { }; config.disallowedContent = 'h1, h2, h3, h4, h5, h6'; + // Full page mode (allow html, body...) + //config.fullPage = true; + //DEV TOOLS //config.extraPlugins = 'devtools'; @@ -111,6 +118,13 @@ CKEDITOR.editorConfig = function (config) { config. shiftEnterMode = CKEDITOR.ENTER_P; config.pasteFromWordRemoveStyles = true; config.keystrokes = [[CKEDITOR.ALT + 84 /*T*/, 'abbr' ]]; + + // Ne vem kje se to drugace lahko nastavi, potem naredimo kar tako:) + if(lang == 'en') + config.image_previewText = "Image preview."; + else + config.image_previewText = "Predogled slike."; + } CKEDITOR.on('instanceReady', function() { @@ -146,7 +160,7 @@ CKEDITOR.on('dialogDefinition', function (ev) { type: 'html', id: 'uploadSlikeEnka', label: 'Naloži sliko', - html: '
    ' + html: '
    ' }, 'txtAlt' ); @@ -165,7 +179,7 @@ CKEDITOR.on('dialogDefinition', function (ev) { type: 'html', id: 'uploadDatotekeEnka', label: 'Naloži datoteko', - html: '
    ' + html: '
    ' } ); } diff --git a/editors/ckeditor_4_4/uploader/EnkaUploader.php b/editors/ckeditor_4_4/uploader/EnkaUploader.php index 1f1881efe..685096081 100644 --- a/editors/ckeditor_4_4/uploader/EnkaUploader.php +++ b/editors/ckeditor_4_4/uploader/EnkaUploader.php @@ -5,9 +5,21 @@ " . $lang['upload_img_exe'] . ""; ?> @@ -26,7 +38,6 @@ if (!isset ($_POST['posted']) && (isset ($_GET['image']) && $_GET['image'] == 1) page_urls['page_login'.$this->prijava]); die(); } @@ -1014,13 +1016,6 @@ class ApiLogin setcookie("SL", $p, time() - 3600 * 24 * 365, "/", $nd); } - // Ce gre za AAI odjavo moramo odjavit tudi iz AAI - if (isset($_COOKIE['aai']) && !empty ($_COOKIE['aai']) && $_COOKIE['aai'] == "1") { - setcookie("aai", '', time() - 3600, '/', $cookie_domain); - header('location: https://aai.1ka.si/Shibboleth.sso/Logout?return=https://1ka.arnes.si'); - die(); - } - // Ce gre za arnes aai odjavo odjavimo posebej if ($aai_instalacija){ setcookie("aai", '', time() - 3600, '/', $cookie_domain); @@ -1373,9 +1368,15 @@ class ApiLogin if(isset($confirm_registration) && $confirm_registration == 1){ global $confirm_registration_admin; - // Mail posljemo vsem nastavljenim adminom - foreach($confirm_registration_admin as $admin_email){ - $MA->addRecipients($admin_email); + if(is_array($confirm_registration_admin)){ + // Mail posljemo vsem nastavljenim adminom + foreach($confirm_registration_admin as $admin_email){ + $MA->addRecipients($admin_email); + $result = $MA->sendMail($ZaMail, $Subject); + } + } + else{ + $MA->addRecipients($confirm_registration_admin); $result = $MA->sendMail($ZaMail, $Subject); } } @@ -1450,19 +1451,19 @@ class ApiLogin $Content = $lang['confirm_user_content']; $Subject = $lang['confirm_user_subject']; - // Ce je ga moramo po registraciji odobriti dobi drugacno sporocilo - if (isset($confirm_registration) && $confirm_registration == 1){ + // Ce je ga moramo po registraciji odobriti dobi drugacno sporocilo + if (isset($confirm_registration) && $confirm_registration == 1){ $UserContent = $lang['register_user_banned_content']; } - else{ + else{ $UserContent = $lang['register_user_content']; - - // Podpis - $signature = Common::getEmailSignature(); - $UserContent .= $signature; - - $UserContent .= $lang['register_user_content_edit']; } + + // Podpis + $signature = Common::getEmailSignature(); + $UserContent .= $signature; + + $UserContent .= $lang['register_user_content_edit']; $change = ''; $out = ''; @@ -1601,7 +1602,6 @@ class ApiLogin global $site_path; global $lang; global $global_user_id; - global $user_db; global $cookie_domain; global $app_settings; @@ -1611,7 +1611,7 @@ class ApiLogin $email = strtolower($_GET['email']); if (is_numeric($email)) { - $result = sisplet_query("SELECT email FROM $user_db.users WHERE id='$email'"); + $result = sisplet_query("SELECT email FROM users WHERE id='$email'"); $r = mysqli_fetch_row($result); $email = $r[0]; @@ -1622,7 +1622,7 @@ class ApiLogin list ($ByeEmail) = mysqli_fetch_row($result); $result = sisplet_query("SELECT value FROM misc WHERE what='ByeEmailSubject'"); list ($ByeEmailSubject) = mysqli_fetch_row($result); - $result = sisplet_query("SELECT name FROM $user_db.users WHERE email='$email'"); + $result = sisplet_query("SELECT name FROM users WHERE email='$email'"); list ($ime) = mysqli_fetch_row($result); $PageName = $app_settings['app_name']; @@ -1645,7 +1645,7 @@ class ApiLogin } - $result = sisplet_query("UPDATE $user_db.users SET email=CONCAT('UNSU8MD-', UNIX_TIMESTAMP(), email) WHERE email='$email'"); + $result = sisplet_query("UPDATE users SET email=CONCAT('UNSU8MD-', UNIX_TIMESTAMP(), email) WHERE email='$email'"); setcookie('uid', '', time() - 3600, '/', $cookie_domain); setcookie('secret', '', time() - 3600, '/', $cookie_domain); @@ -1841,7 +1841,6 @@ class ApiLogin global $lang; global $site_url; global $pass_salt; - global $user_db; global $cookie_domain; $ajaxKlic = (!empty($_POST['ajax']) ? true : false); diff --git a/frontend/drupal/CHANGELOG.txt b/frontend/drupal/CHANGELOG.txt index f2b2dd257..f9b010c58 100644 --- a/frontend/drupal/CHANGELOG.txt +++ b/frontend/drupal/CHANGELOG.txt @@ -1,3 +1,18 @@ +Drupal 7.78, 2021-01-19 +----------------------- +- Fixed security issues: + - SA-CORE-2021-001 + +Drupal 7.77, 2020-12-03 +----------------------- +- Hotfix for schema.prefixed tables + +Drupal 7.76, 2020-12-02 +----------------------- +- Support for MySQL 8 +- Core tests pass in SQLite +- Better user flood control logging + Drupal 7.75, 2020-11-26 ----------------------- - Fixed security issues: diff --git a/frontend/drupal/MAINTAINERS.txt b/frontend/drupal/MAINTAINERS.txt index 4ea5572a7..cbc9f51a8 100644 --- a/frontend/drupal/MAINTAINERS.txt +++ b/frontend/drupal/MAINTAINERS.txt @@ -12,7 +12,7 @@ The branch maintainers for Drupal 7 are: - Dries Buytaert 'dries' https://www.drupal.org/u/dries - Fabian Franz 'Fabianx' https://www.drupal.org/u/fabianx -- (provisional) Drew Webber 'mcdruid' https://www.drupal.org/u/mcdruid +- Drew Webber 'mcdruid' https://www.drupal.org/u/mcdruid Component maintainers diff --git a/frontend/drupal/includes/bootstrap.inc b/frontend/drupal/includes/bootstrap.inc index 29b0e1cf5..2b6d7ff48 100644 --- a/frontend/drupal/includes/bootstrap.inc +++ b/frontend/drupal/includes/bootstrap.inc @@ -8,7 +8,7 @@ /** * The current system version. */ -define('VERSION', '7.75'); +define('VERSION', '7.78'); /** * Core API compatibility. @@ -1189,19 +1189,21 @@ function variable_initialize($conf = array()) { $variables = $cached->data; } else { - // Cache miss. Avoid a stampede. + // Cache miss. Avoid a stampede by acquiring a lock. If the lock fails to + // acquire, optionally just continue with uncached processing. $name = 'variable_init'; - if (!lock_acquire($name, 1)) { - // Another request is building the variable cache. - // Wait, then re-run this function. + $lock_acquired = lock_acquire($name, 1); + if (!$lock_acquired && variable_get('variable_initialize_wait_for_lock', FALSE)) { lock_wait($name); return variable_initialize($conf); } else { - // Proceed with variable rebuild. + // Load the variables from the table. $variables = array_map('unserialize', db_query('SELECT name, value FROM {variable}')->fetchAllKeyed()); - cache_set('variables', $variables, 'cache_bootstrap'); - lock_release($name); + if ($lock_acquired) { + cache_set('variables', $variables, 'cache_bootstrap'); + lock_release($name); + } } } diff --git a/frontend/drupal/includes/common.inc b/frontend/drupal/includes/common.inc index 07373ac47..7b7955855 100644 --- a/frontend/drupal/includes/common.inc +++ b/frontend/drupal/includes/common.inc @@ -6653,30 +6653,41 @@ function element_children(&$elements, $sort = FALSE) { $sort = isset($elements['#sorted']) ? !$elements['#sorted'] : $sort; // Filter out properties from the element, leaving only children. - $children = array(); + $count = count($elements); + $child_weights = array(); + $i = 0; $sortable = FALSE; foreach ($elements as $key => $value) { if (is_int($key) || $key === '' || $key[0] !== '#') { - $children[$key] = $value; if (is_array($value) && isset($value['#weight'])) { + $weight = $value['#weight']; $sortable = TRUE; } + else { + $weight = 0; + } + // Support weights with up to three digit precision and conserve the + // insertion order. + $child_weights[$key] = floor($weight * 1000) + $i / $count; } + $i++; } + // Sort the children if necessary. if ($sort && $sortable) { - uasort($children, 'element_sort'); + asort($child_weights); // Put the sorted children back into $elements in the correct order, to // preserve sorting if the same element is passed through // element_children() twice. - foreach ($children as $key => $child) { + foreach ($child_weights as $key => $weight) { + $value = $elements[$key]; unset($elements[$key]); - $elements[$key] = $child; + $elements[$key] = $value; } $elements['#sorted'] = TRUE; } - return array_keys($children); + return array_keys($child_weights); } /** diff --git a/frontend/drupal/includes/database/database.inc b/frontend/drupal/includes/database/database.inc index 6879f6991..d4d2d8f02 100644 --- a/frontend/drupal/includes/database/database.inc +++ b/frontend/drupal/includes/database/database.inc @@ -310,6 +310,13 @@ abstract class DatabaseConnection extends PDO { */ protected $escapedAliases = array(); + /** + * List of un-prefixed table names, keyed by prefixed table names. + * + * @var array + */ + protected $unprefixedTablesMap = array(); + function __construct($dsn, $username, $password, $driver_options = array()) { // Initialize and prepare the connection prefix. $this->setPrefix(isset($this->connectionOptions['prefix']) ? $this->connectionOptions['prefix'] : ''); @@ -338,7 +345,9 @@ abstract class DatabaseConnection extends PDO { // Destroy all references to this connection by setting them to NULL. // The Statement class attribute only accepts a new value that presents a // proper callable, so we reset it to PDOStatement. - $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('PDOStatement', array())); + if (!empty($this->statementClass)) { + $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('PDOStatement', array())); + } $this->schema = NULL; } @@ -442,6 +451,13 @@ abstract class DatabaseConnection extends PDO { $this->prefixReplace[] = $this->prefixes['default']; $this->prefixSearch[] = '}'; $this->prefixReplace[] = ''; + + // Set up a map of prefixed => un-prefixed tables. + foreach ($this->prefixes as $table_name => $prefix) { + if ($table_name !== 'default') { + $this->unprefixedTablesMap[$prefix . $table_name] = $table_name; + } + } } /** @@ -477,6 +493,17 @@ abstract class DatabaseConnection extends PDO { } } + /** + * Gets a list of individually prefixed table names. + * + * @return array + * An array of un-prefixed table names, keyed by their fully qualified table + * names (i.e. prefix + table_name). + */ + public function getUnprefixedTablesMap() { + return $this->unprefixedTablesMap; + } + /** * Prepares a query string and returns the prepared statement. * @@ -2840,7 +2867,6 @@ function db_field_exists($table, $field) { * * @param $table_expression * An SQL expression, for example "simpletest%" (without the quotes). - * BEWARE: this is not prefixed, the caller should take care of that. * * @return * Array, both the keys and the values are the matching tables. @@ -2849,6 +2875,23 @@ function db_find_tables($table_expression) { return Database::getConnection()->schema()->findTables($table_expression); } +/** + * Finds all tables that are like the specified base table name. This is a + * backport of the change made to db_find_tables in Drupal 8 to work with + * virtual, un-prefixed table names. The original function is retained for + * Backwards Compatibility. + * @see https://www.drupal.org/node/2552435 + * + * @param $table_expression + * An SQL expression, for example "simpletest%" (without the quotes). + * + * @return + * Array, both the keys and the values are the matching tables. + */ +function db_find_tables_d8($table_expression) { + return Database::getConnection()->schema()->findTablesD8($table_expression); +} + function _db_create_keys_sql($spec) { return Database::getConnection()->schema()->createKeysSql($spec); } diff --git a/frontend/drupal/includes/database/mysql/database.inc b/frontend/drupal/includes/database/mysql/database.inc index 356e039f7..00df3c13e 100644 --- a/frontend/drupal/includes/database/mysql/database.inc +++ b/frontend/drupal/includes/database/mysql/database.inc @@ -5,6 +5,11 @@ * Database interface code for MySQL database servers. */ +/** + * The default character for quoting identifiers in MySQL. + */ +define('MYSQL_IDENTIFIER_QUOTE_CHARACTER_DEFAULT', '`'); + /** * @addtogroup database * @{ @@ -19,6 +24,277 @@ class DatabaseConnection_mysql extends DatabaseConnection { */ protected $needsCleanup = FALSE; + /** + * The list of MySQL reserved key words. + * + * @link https://dev.mysql.com/doc/refman/8.0/en/keywords.html + */ + private $reservedKeyWords = array( + 'accessible', + 'add', + 'admin', + 'all', + 'alter', + 'analyze', + 'and', + 'as', + 'asc', + 'asensitive', + 'before', + 'between', + 'bigint', + 'binary', + 'blob', + 'both', + 'by', + 'call', + 'cascade', + 'case', + 'change', + 'char', + 'character', + 'check', + 'collate', + 'column', + 'condition', + 'constraint', + 'continue', + 'convert', + 'create', + 'cross', + 'cube', + 'cume_dist', + 'current_date', + 'current_time', + 'current_timestamp', + 'current_user', + 'cursor', + 'database', + 'databases', + 'day_hour', + 'day_microsecond', + 'day_minute', + 'day_second', + 'dec', + 'decimal', + 'declare', + 'default', + 'delayed', + 'delete', + 'dense_rank', + 'desc', + 'describe', + 'deterministic', + 'distinct', + 'distinctrow', + 'div', + 'double', + 'drop', + 'dual', + 'each', + 'else', + 'elseif', + 'empty', + 'enclosed', + 'escaped', + 'except', + 'exists', + 'exit', + 'explain', + 'false', + 'fetch', + 'first_value', + 'float', + 'float4', + 'float8', + 'for', + 'force', + 'foreign', + 'from', + 'fulltext', + 'function', + 'generated', + 'get', + 'grant', + 'group', + 'grouping', + 'groups', + 'having', + 'high_priority', + 'hour_microsecond', + 'hour_minute', + 'hour_second', + 'if', + 'ignore', + 'in', + 'index', + 'infile', + 'inner', + 'inout', + 'insensitive', + 'insert', + 'int', + 'int1', + 'int2', + 'int3', + 'int4', + 'int8', + 'integer', + 'interval', + 'into', + 'io_after_gtids', + 'io_before_gtids', + 'is', + 'iterate', + 'join', + 'json_table', + 'key', + 'keys', + 'kill', + 'lag', + 'last_value', + 'lead', + 'leading', + 'leave', + 'left', + 'like', + 'limit', + 'linear', + 'lines', + 'load', + 'localtime', + 'localtimestamp', + 'lock', + 'long', + 'longblob', + 'longtext', + 'loop', + 'low_priority', + 'master_bind', + 'master_ssl_verify_server_cert', + 'match', + 'maxvalue', + 'mediumblob', + 'mediumint', + 'mediumtext', + 'middleint', + 'minute_microsecond', + 'minute_second', + 'mod', + 'modifies', + 'natural', + 'not', + 'no_write_to_binlog', + 'nth_value', + 'ntile', + 'null', + 'numeric', + 'of', + 'on', + 'optimize', + 'optimizer_costs', + 'option', + 'optionally', + 'or', + 'order', + 'out', + 'outer', + 'outfile', + 'over', + 'partition', + 'percent_rank', + 'persist', + 'persist_only', + 'precision', + 'primary', + 'procedure', + 'purge', + 'range', + 'rank', + 'read', + 'reads', + 'read_write', + 'real', + 'recursive', + 'references', + 'regexp', + 'release', + 'rename', + 'repeat', + 'replace', + 'require', + 'resignal', + 'restrict', + 'return', + 'revoke', + 'right', + 'rlike', + 'row', + 'rows', + 'row_number', + 'schema', + 'schemas', + 'second_microsecond', + 'select', + 'sensitive', + 'separator', + 'set', + 'show', + 'signal', + 'smallint', + 'spatial', + 'specific', + 'sql', + 'sqlexception', + 'sqlstate', + 'sqlwarning', + 'sql_big_result', + 'sql_calc_found_rows', + 'sql_small_result', + 'ssl', + 'starting', + 'stored', + 'straight_join', + 'system', + 'table', + 'terminated', + 'then', + 'tinyblob', + 'tinyint', + 'tinytext', + 'to', + 'trailing', + 'trigger', + 'true', + 'undo', + 'union', + 'unique', + 'unlock', + 'unsigned', + 'update', + 'usage', + 'use', + 'using', + 'utc_date', + 'utc_time', + 'utc_timestamp', + 'values', + 'varbinary', + 'varchar', + 'varcharacter', + 'varying', + 'virtual', + 'when', + 'where', + 'while', + 'window', + 'with', + 'write', + 'xor', + 'year_month', + 'zerofill', + ); + public function __construct(array $connection_options = array()) { // This driver defaults to transaction support, except if explicitly passed FALSE. $this->transactionSupport = !isset($connection_options['transactions']) || ($connection_options['transactions'] !== FALSE); @@ -86,15 +362,95 @@ class DatabaseConnection_mysql extends DatabaseConnection { $connection_options += array( 'init_commands' => array(), ); + + $sql_mode = 'REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO'; + // NO_AUTO_CREATE_USER was removed in MySQL 8.0.11 + // https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-11.html#mysqld-8-0-11-deprecation-removal + if (version_compare($this->getAttribute(PDO::ATTR_SERVER_VERSION), '8.0.11', '<')) { + $sql_mode .= ',NO_AUTO_CREATE_USER'; + } $connection_options['init_commands'] += array( - 'sql_mode' => "SET sql_mode = 'REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER'", + 'sql_mode' => "SET sql_mode = '$sql_mode'", ); + // Execute initial commands. foreach ($connection_options['init_commands'] as $sql) { $this->exec($sql); } } + /** + * {@inheritdoc}} + */ + protected function setPrefix($prefix) { + parent::setPrefix($prefix); + // Successive versions of MySQL have become increasingly strict about the + // use of reserved keywords as table names. Drupal 7 uses at least one such + // table (system). Therefore we surround all table names with quotes. + $quote_char = variable_get('mysql_identifier_quote_character', MYSQL_IDENTIFIER_QUOTE_CHARACTER_DEFAULT); + foreach ($this->prefixSearch as $i => $prefixSearch) { + if (substr($prefixSearch, 0, 1) === '{') { + // If the prefix already contains one or more quotes remove them. + // This can happen when - for example - DrupalUnitTestCase sets up a + // "temporary prefixed database". Also if there's a dot in the prefix, + // wrap it in quotes to cater for schema names in prefixes. + $search = array($quote_char, '.'); + $replace = array('', $quote_char . '.' . $quote_char); + $this->prefixReplace[$i] = $quote_char . str_replace($search, $replace, $this->prefixReplace[$i]); + } + if (substr($prefixSearch, -1) === '}') { + $this->prefixReplace[$i] .= $quote_char; + } + } + } + + /** + * {@inheritdoc} + */ + public function escapeField($field) { + $field = parent::escapeField($field); + return $this->quoteIdentifier($field); + } + + public function escapeFields(array $fields) { + foreach ($fields as &$field) { + $field = $this->escapeField($field); + } + return $fields; + } + + /** + * {@inheritdoc} + */ + public function escapeAlias($field) { + $field = parent::escapeAlias($field); + return $this->quoteIdentifier($field); + } + + /** + * Quotes an identifier if it matches a MySQL reserved keyword. + * + * @param string $identifier + * The field to check. + * + * @return string + * The identifier, quoted if it matches a MySQL reserved keyword. + */ + private function quoteIdentifier($identifier) { + // Quote identifiers so that MySQL reserved words like 'function' can be + // used as column names. Sometimes the 'table.column_name' format is passed + // in. For example, menu_load_links() adds a condition on "ml.menu_name". + if (strpos($identifier, '.') !== FALSE) { + list($table, $identifier) = explode('.', $identifier, 2); + } + if (in_array(strtolower($identifier), $this->reservedKeyWords, TRUE)) { + // Quote the string for MySQL reserved keywords. + $quote_char = variable_get('mysql_identifier_quote_character', MYSQL_IDENTIFIER_QUOTE_CHARACTER_DEFAULT); + $identifier = $quote_char . $identifier . $quote_char; + } + return isset($table) ? $table . '.' . $identifier : $identifier; + } + public function __destruct() { if ($this->needsCleanup) { $this->nextIdDelete(); diff --git a/frontend/drupal/includes/database/mysql/query.inc b/frontend/drupal/includes/database/mysql/query.inc index d3d2d9eec..3f0bcb796 100644 --- a/frontend/drupal/includes/database/mysql/query.inc +++ b/frontend/drupal/includes/database/mysql/query.inc @@ -48,6 +48,10 @@ class InsertQuery_mysql extends InsertQuery { // Default fields are always placed first for consistency. $insert_fields = array_merge($this->defaultFields, $this->insertFields); + if (method_exists($this->connection, 'escapeFields')) { + $insert_fields = $this->connection->escapeFields($insert_fields); + } + // If we're selecting from a SelectQuery, finish building the query and // pass it back, as any remaining options are irrelevant. if (!empty($this->fromQuery)) { @@ -89,6 +93,20 @@ class InsertQuery_mysql extends InsertQuery { class TruncateQuery_mysql extends TruncateQuery { } +class UpdateQuery_mysql extends UpdateQuery { + public function __toString() { + if (method_exists($this->connection, 'escapeField')) { + $escapedFields = array(); + foreach ($this->fields as $field => $data) { + $field = $this->connection->escapeField($field); + $escapedFields[$field] = $data; + } + $this->fields = $escapedFields; + } + return parent::__toString(); + } +} + /** * @} End of "addtogroup database". */ diff --git a/frontend/drupal/includes/database/mysql/schema.inc b/frontend/drupal/includes/database/mysql/schema.inc index 9ba1c7339..7d6e33395 100644 --- a/frontend/drupal/includes/database/mysql/schema.inc +++ b/frontend/drupal/includes/database/mysql/schema.inc @@ -57,6 +57,11 @@ class DatabaseSchema_mysql extends DatabaseSchema { protected function buildTableNameCondition($table_name, $operator = '=', $add_prefix = TRUE) { $info = $this->connection->getConnectionOptions(); + // Ensure the table name is not surrounded with quotes as that is not + // appropriate for schema queries. + $quote_char = variable_get('mysql_identifier_quote_character', MYSQL_IDENTIFIER_QUOTE_CHARACTER_DEFAULT); + $table_name = str_replace($quote_char, '', $table_name); + $table_info = $this->getPrefixInfo($table_name, $add_prefix); $condition = new DatabaseCondition('AND'); @@ -494,11 +499,11 @@ class DatabaseSchema_mysql extends DatabaseSchema { $condition->condition('column_name', $column); $condition->compile($this->connection, $this); // Don't use {} around information_schema.columns table. - return $this->connection->query("SELECT column_comment FROM information_schema.columns WHERE " . (string) $condition, $condition->arguments())->fetchField(); + return $this->connection->query("SELECT column_comment AS column_comment FROM information_schema.columns WHERE " . (string) $condition, $condition->arguments())->fetchField(); } $condition->compile($this->connection, $this); // Don't use {} around information_schema.tables table. - $comment = $this->connection->query("SELECT table_comment FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments())->fetchField(); + $comment = $this->connection->query("SELECT table_comment AS table_comment FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments())->fetchField(); // Work-around for MySQL 5.0 bug http://bugs.mysql.com/bug.php?id=11379 return preg_replace('/; InnoDB free:.*$/', '', $comment); } diff --git a/frontend/drupal/includes/database/schema.inc b/frontend/drupal/includes/database/schema.inc index 31862db39..faa521623 100644 --- a/frontend/drupal/includes/database/schema.inc +++ b/frontend/drupal/includes/database/schema.inc @@ -169,6 +169,11 @@ require_once dirname(__FILE__) . '/query.inc'; */ abstract class DatabaseSchema implements QueryPlaceholderInterface { + /** + * The database connection. + * + * @var DatabaseConnection + */ protected $connection; /** @@ -343,7 +348,70 @@ abstract class DatabaseSchema implements QueryPlaceholderInterface { // couldn't use db_select() here because it would prefix // information_schema.tables and the query would fail. // Don't use {} around information_schema.tables table. - return $this->connection->query("SELECT table_name FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments())->fetchAllKeyed(0, 0); + return $this->connection->query("SELECT table_name AS table_name FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments())->fetchAllKeyed(0, 0); + } + + /** + * Finds all tables that are like the specified base table name. This is a + * backport of the change made to findTables in Drupal 8 to work with virtual, + * un-prefixed table names. The original function is retained for Backwards + * Compatibility. + * @see https://www.drupal.org/node/2552435 + * + * @param string $table_expression + * An SQL expression, for example "cache_%" (without the quotes). + * + * @return array + * Both the keys and the values are the matching tables. + */ + public function findTablesD8($table_expression) { + // Load all the tables up front in order to take into account per-table + // prefixes. The actual matching is done at the bottom of the method. + $condition = $this->buildTableNameCondition('%', 'LIKE'); + $condition->compile($this->connection, $this); + + $individually_prefixed_tables = $this->connection->getUnprefixedTablesMap(); + $default_prefix = $this->connection->tablePrefix(); + $default_prefix_length = strlen($default_prefix); + $tables = array(); + // Normally, we would heartily discourage the use of string + // concatenation for conditionals like this however, we + // couldn't use db_select() here because it would prefix + // information_schema.tables and the query would fail. + // Don't use {} around information_schema.tables table. + $results = $this->connection->query("SELECT table_name AS table_name FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments()); + foreach ($results as $table) { + // Take into account tables that have an individual prefix. + if (isset($individually_prefixed_tables[$table->table_name])) { + $prefix_length = strlen($this->connection->tablePrefix($individually_prefixed_tables[$table->table_name])); + } + elseif ($default_prefix && substr($table->table_name, 0, $default_prefix_length) !== $default_prefix) { + // This table name does not start the default prefix, which means that + // it is not managed by Drupal so it should be excluded from the result. + continue; + } + else { + $prefix_length = $default_prefix_length; + } + + // Remove the prefix from the returned tables. + $unprefixed_table_name = substr($table->table_name, $prefix_length); + + // The pattern can match a table which is the same as the prefix. That + // will become an empty string when we remove the prefix, which will + // probably surprise the caller, besides not being a prefixed table. So + // remove it. + if (!empty($unprefixed_table_name)) { + $tables[$unprefixed_table_name] = $unprefixed_table_name; + } + } + + // Convert the table expression from its SQL LIKE syntax to a regular + // expression and escape the delimiter that will be used for matching. + $table_expression = str_replace(array('%', '_'), array('.*?', '.'), preg_quote($table_expression, '/')); + $tables = preg_grep('/^' . $table_expression . '$/i', $tables); + + return $tables; } /** diff --git a/frontend/drupal/includes/database/select.inc b/frontend/drupal/includes/database/select.inc index 8d84460e8..84098bdf7 100644 --- a/frontend/drupal/includes/database/select.inc +++ b/frontend/drupal/includes/database/select.inc @@ -1520,13 +1520,16 @@ class SelectQuery extends Query implements SelectQueryInterface { $fields = array(); foreach ($this->tables as $alias => $table) { if (!empty($table['all_fields'])) { - $fields[] = $this->connection->escapeTable($alias) . '.*'; + $fields[] = $this->connection->escapeAlias($alias) . '.*'; } } foreach ($this->fields as $alias => $field) { + // Note that $field['table'] holds the table alias. + // @see \SelectQuery::addField + $table = isset($field['table']) ? $this->connection->escapeAlias($field['table']) . '.' : ''; // Always use the AS keyword for field aliases, as some // databases require it (e.g., PostgreSQL). - $fields[] = (isset($field['table']) ? $this->connection->escapeTable($field['table']) . '.' : '') . $this->connection->escapeField($field['field']) . ' AS ' . $this->connection->escapeAlias($field['alias']); + $fields[] = $table . $this->connection->escapeField($field['field']) . ' AS ' . $this->connection->escapeAlias($field['alias']); } foreach ($this->expressions as $alias => $expression) { $fields[] = $expression['expression'] . ' AS ' . $this->connection->escapeAlias($expression['alias']); @@ -1555,7 +1558,7 @@ class SelectQuery extends Query implements SelectQueryInterface { // Don't use the AS keyword for table aliases, as some // databases don't support it (e.g., Oracle). - $query .= $table_string . ' ' . $this->connection->escapeTable($table['alias']); + $query .= $table_string . ' ' . $this->connection->escapeAlias($table['alias']); if (!empty($table['condition'])) { $query .= ' ON ' . $table['condition']; diff --git a/frontend/drupal/includes/database/sqlite/database.inc b/frontend/drupal/includes/database/sqlite/database.inc index 589a17287..c50f08ec5 100644 --- a/frontend/drupal/includes/database/sqlite/database.inc +++ b/frontend/drupal/includes/database/sqlite/database.inc @@ -107,6 +107,18 @@ class DatabaseConnection_sqlite extends DatabaseConnection { $this->sqliteCreateFunction('substring_index', array($this, 'sqlFunctionSubstringIndex'), 3); $this->sqliteCreateFunction('rand', array($this, 'sqlFunctionRand')); + // Enable the Write-Ahead Logging (WAL) option for SQLite if supported. + // @see https://www.drupal.org/node/2348137 + // @see https://sqlite.org/wal.html + if (version_compare($version, '3.7') >= 0) { + $connection_options += array( + 'init_commands' => array(), + ); + $connection_options['init_commands'] += array( + 'wal' => "PRAGMA journal_mode=WAL", + ); + } + // Execute sqlite init_commands. if (isset($connection_options['init_commands'])) { $this->exec(implode('; ', $connection_options['init_commands'])); @@ -128,10 +140,10 @@ class DatabaseConnection_sqlite extends DatabaseConnection { $count = $this->query('SELECT COUNT(*) FROM ' . $prefix . '.sqlite_master WHERE type = :type AND name NOT LIKE :pattern', array(':type' => 'table', ':pattern' => 'sqlite_%'))->fetchField(); // We can prune the database file if it doesn't have any tables. - if ($count == 0) { - // Detach the database. - $this->query('DETACH DATABASE :schema', array(':schema' => $prefix)); - // Destroy the database file. + if ($count == 0 && $this->connectionOptions['database'] != ':memory:') { + // Detaching the database fails at this point, but no other queries + // are executed after the connection is destructed so we can simply + // remove the database file. unlink($this->connectionOptions['database'] . '-' . $prefix); } } @@ -143,6 +155,18 @@ class DatabaseConnection_sqlite extends DatabaseConnection { } } + /** + * Gets all the attached databases. + * + * @return array + * An array of attached database names. + * + * @see DatabaseConnection_sqlite::__construct(). + */ + public function getAttachedDatabases() { + return $this->attachedDatabases; + } + /** * SQLite compatibility implementation for the IF() SQL function. */ diff --git a/frontend/drupal/includes/database/sqlite/query.inc b/frontend/drupal/includes/database/sqlite/query.inc index c9c028bb0..45c6a3024 100644 --- a/frontend/drupal/includes/database/sqlite/query.inc +++ b/frontend/drupal/includes/database/sqlite/query.inc @@ -23,7 +23,7 @@ class InsertQuery_sqlite extends InsertQuery { if (!$this->preExecute()) { return NULL; } - if (count($this->insertFields)) { + if (count($this->insertFields) || !empty($this->fromQuery)) { return parent::execute(); } else { @@ -36,7 +36,10 @@ class InsertQuery_sqlite extends InsertQuery { $comments = $this->connection->makeComment($this->comments); // Produce as many generic placeholders as necessary. - $placeholders = array_fill(0, count($this->insertFields), '?'); + $placeholders = array(); + if (!empty($this->insertFields)) { + $placeholders = array_fill(0, count($this->insertFields), '?'); + } // If we're selecting from a SelectQuery, finish building the query and // pass it back, as any remaining options are irrelevant. diff --git a/frontend/drupal/includes/database/sqlite/schema.inc b/frontend/drupal/includes/database/sqlite/schema.inc index 281d8fc6b..43ea6d61c 100644 --- a/frontend/drupal/includes/database/sqlite/schema.inc +++ b/frontend/drupal/includes/database/sqlite/schema.inc @@ -668,6 +668,9 @@ class DatabaseSchema_sqlite extends DatabaseSchema { $this->alterTable($table, $old_schema, $new_schema); } + /** + * {@inheritdoc} + */ public function findTables($table_expression) { // Don't add the prefix, $table_expression already includes the prefix. $info = $this->getPrefixInfo($table_expression, FALSE); @@ -680,4 +683,32 @@ class DatabaseSchema_sqlite extends DatabaseSchema { )); return $result->fetchAllKeyed(0, 0); } + + /** + * {@inheritdoc} + */ + public function findTablesD8($table_expression) { + $tables = array(); + + // The SQLite implementation doesn't need to use the same filtering strategy + // as the parent one because individually prefixed tables live in their own + // schema (database), which means that neither the main database nor any + // attached one will contain a prefixed table name, so we just need to loop + // over all known schemas and filter by the user-supplied table expression. + $attached_dbs = $this->connection->getAttachedDatabases(); + foreach ($attached_dbs as $schema) { + // Can't use query placeholders for the schema because the query would + // have to be :prefixsqlite_master, which does not work. We also need to + // ignore the internal SQLite tables. + $result = db_query("SELECT name FROM " . $schema . ".sqlite_master WHERE type = :type AND name LIKE :table_name AND name NOT LIKE :pattern", array( + ':type' => 'table', + ':table_name' => $table_expression, + ':pattern' => 'sqlite_%', + )); + $tables += $result->fetchAllKeyed(0, 0); + } + + return $tables; + } + } diff --git a/frontend/drupal/includes/form.inc b/frontend/drupal/includes/form.inc index 1158fd031..f2557e832 100644 --- a/frontend/drupal/includes/form.inc +++ b/frontend/drupal/includes/form.inc @@ -1361,7 +1361,10 @@ function _form_validate(&$elements, &$form_state, $form_id = NULL) { // The following errors are always shown. if (isset($elements['#needs_validation'])) { // Verify that the value is not longer than #maxlength. - if (isset($elements['#maxlength']) && drupal_strlen($elements['#value']) > $elements['#maxlength']) { + if (isset($elements['#maxlength']) && (isset($elements['#value']) && !is_scalar($elements['#value']))) { + form_error($elements, $t('An illegal value has been detected. Please contact the site administrator.')); + } + elseif (isset($elements['#maxlength']) && drupal_strlen($elements['#value']) > $elements['#maxlength']) { form_error($elements, $t('!name cannot be longer than %max characters but is currently %length characters long.', array('!name' => empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title'], '%max' => $elements['#maxlength'], '%length' => drupal_strlen($elements['#value'])))); } @@ -4124,9 +4127,17 @@ function form_process_weight($element) { $max_elements = variable_get('drupal_weight_select_max', DRUPAL_WEIGHT_SELECT_MAX); if ($element['#delta'] <= $max_elements) { $element['#type'] = 'select'; + $weights = array(); for ($n = (-1 * $element['#delta']); $n <= $element['#delta']; $n++) { $weights[$n] = $n; } + if (isset($element['#default_value'])) { + $default_value = (int) $element['#default_value']; + if (!isset($weights[$default_value])) { + $weights[$default_value] = $default_value; + ksort($weights); + } + } $element['#options'] = $weights; $element += element_info('select'); } diff --git a/frontend/drupal/includes/mail.inc b/frontend/drupal/includes/mail.inc index 0e5c17804..a97c788f0 100644 --- a/frontend/drupal/includes/mail.inc +++ b/frontend/drupal/includes/mail.inc @@ -12,6 +12,12 @@ */ define('MAIL_LINE_ENDINGS', isset($_SERVER['WINDIR']) || (isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'Win32') !== FALSE) ? "\r\n" : "\n"); + +/** + * Special characters, defined in RFC_2822. + */ +define('MAIL_RFC_2822_SPECIALS', '()<>[]:;@\,."'); + /** * Composes and optionally sends an e-mail message. * @@ -148,8 +154,13 @@ function drupal_mail($module, $key, $to, $language, $params = array(), $from = N // Return-Path headers should have a domain authorized to use the originating // SMTP server. $headers['From'] = $headers['Sender'] = $headers['Return-Path'] = $default_from; + + if (variable_get('mail_display_name_site_name', FALSE)) { + $display_name = variable_get('site_name', 'Drupal'); + $headers['From'] = drupal_mail_format_display_name($display_name) . ' <' . $default_from . '>'; + } } - if ($from) { + if ($from && $from != $default_from) { $headers['From'] = $from; } $message['headers'] = $headers; @@ -557,10 +568,59 @@ function drupal_html_to_text($string, $allowed_tags = NULL) { return $output . $footnotes; } +/** + * Return a RFC-2822 compliant "display-name" component. + * + * The "display-name" component is used in mail header "Originator" fields + * (From, Sender, Reply-to) to give a human-friendly description of the + * address, i.e. From: My Display Name . RFC-822 and + * RFC-2822 define its syntax and rules. This method gets as input a string + * to be used as "display-name" and formats it to be RFC compliant. + * + * @param string $string + * A string to be used as "display-name". + * + * @return string + * A RFC compliant version of the string, ready to be used as + * "display-name" in mail originator header fields. + */ +function drupal_mail_format_display_name($string) { + // Make sure we don't process html-encoded characters. They may create + // unneeded trouble if left encoded, besides they will be correctly + // processed if decoded. + $string = decode_entities($string); + + // If string contains non-ASCII characters it must be (short) encoded + // according to RFC-2047. The output of a "B" (Base64) encoded-word is + // always safe to be used as display-name. + $safe_display_name = mime_header_encode($string, TRUE); + + // Encoded-words are always safe to be used as display-name because don't + // contain any RFC 2822 "specials" characters. However + // mimeHeaderEncode() encodes a string only if it contains any + // non-ASCII characters, and leaves its value untouched (un-encoded) if + // ASCII only. For this reason in order to produce a valid display-name we + // still need to make sure there are no "specials" characters left. + if (preg_match('/[' . preg_quote(MAIL_RFC_2822_SPECIALS) . ']/', $safe_display_name)) { + + // If string is already quoted, it may or may not be escaped properly, so + // don't trust it and reset. + if (preg_match('/^"(.+)"$/', $safe_display_name, $matches)) { + $safe_display_name = str_replace(array('\\\\', '\\"'), array('\\', '"'), $matches[1]); + } + + // Transform the string in a RFC-2822 "quoted-string" by wrapping it in + // double-quotes. Also make sure '"' and '\' occurrences are escaped. + $safe_display_name = '"' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $safe_display_name) . '"'; + } + + return $safe_display_name; +} + /** * Wraps words on a single line. * - * Callback for array_walk() winthin drupal_wrap_mail(). + * Callback for array_walk() within drupal_wrap_mail(). */ function _drupal_wrap_mail_line(&$line, $key, $values) { // Use soft-breaks only for purely quoted or unindented text. diff --git a/frontend/drupal/includes/menu.inc b/frontend/drupal/includes/menu.inc index 2b489d886..22e6dba97 100644 --- a/frontend/drupal/includes/menu.inc +++ b/frontend/drupal/includes/menu.inc @@ -1067,7 +1067,7 @@ function menu_tree_output($tree) { // the active class accordingly. But local tasks do not appear in menu // trees, so if the current path is a local task, and this link is its // tab root, then we have to set the class manually. - if ($data['link']['href'] == $router_item['tab_root_href'] && $data['link']['href'] != $_GET['q']) { + if ($router_item && $data['link']['href'] == $router_item['tab_root_href'] && $data['link']['href'] != $_GET['q']) { $data['link']['localized_options']['attributes']['class'][] = 'active'; } diff --git a/frontend/drupal/misc/jquery.js b/frontend/drupal/misc/jquery.js index e900c19a3..8f3ca2e2d 100644 --- a/frontend/drupal/misc/jquery.js +++ b/frontend/drupal/misc/jquery.js @@ -1,4 +1,3 @@ - /*! * jQuery JavaScript Library v1.4.4 * http://jquery.com/ diff --git a/frontend/drupal/modules/aggregator/aggregator.info b/frontend/drupal/modules/aggregator/aggregator.info index 6d839422b..9fe93e0c4 100644 --- a/frontend/drupal/modules/aggregator/aggregator.info +++ b/frontend/drupal/modules/aggregator/aggregator.info @@ -7,7 +7,7 @@ files[] = aggregator.test configure = admin/config/services/aggregator/settings stylesheets[all][] = aggregator.css -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/aggregator/tests/aggregator_test.info b/frontend/drupal/modules/aggregator/tests/aggregator_test.info index 66f9ca742..1fc2daa31 100644 --- a/frontend/drupal/modules/aggregator/tests/aggregator_test.info +++ b/frontend/drupal/modules/aggregator/tests/aggregator_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/block/block.info b/frontend/drupal/modules/block/block.info index 936dd1913..484a4a0f2 100644 --- a/frontend/drupal/modules/block/block.info +++ b/frontend/drupal/modules/block/block.info @@ -6,7 +6,7 @@ core = 7.x files[] = block.test configure = admin/structure/block -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/block/tests/block_test.info b/frontend/drupal/modules/block/tests/block_test.info index ae8427771..5b1b0d2d6 100644 --- a/frontend/drupal/modules/block/tests/block_test.info +++ b/frontend/drupal/modules/block/tests/block_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/block/tests/themes/block_test_theme/block_test_theme.info b/frontend/drupal/modules/block/tests/themes/block_test_theme/block_test_theme.info index 20c612cfb..a10950ad4 100644 --- a/frontend/drupal/modules/block/tests/themes/block_test_theme/block_test_theme.info +++ b/frontend/drupal/modules/block/tests/themes/block_test_theme/block_test_theme.info @@ -13,7 +13,7 @@ regions[footer] = Footer regions[highlighted] = Highlighted regions[help] = Help -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/blog/blog.info b/frontend/drupal/modules/blog/blog.info index 5c94afd45..9f626f82a 100644 --- a/frontend/drupal/modules/blog/blog.info +++ b/frontend/drupal/modules/blog/blog.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x files[] = blog.test -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/book/book.info b/frontend/drupal/modules/book/book.info index 046f73ae2..3a611bc4f 100644 --- a/frontend/drupal/modules/book/book.info +++ b/frontend/drupal/modules/book/book.info @@ -7,7 +7,7 @@ files[] = book.test configure = admin/content/book/settings stylesheets[all][] = book.css -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/color/color.info b/frontend/drupal/modules/color/color.info index c2fc98df7..23be4ace9 100644 --- a/frontend/drupal/modules/color/color.info +++ b/frontend/drupal/modules/color/color.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x files[] = color.test -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/comment/comment.info b/frontend/drupal/modules/comment/comment.info index 2395a9bfc..68c6c2393 100644 --- a/frontend/drupal/modules/comment/comment.info +++ b/frontend/drupal/modules/comment/comment.info @@ -9,7 +9,7 @@ files[] = comment.test configure = admin/content/comment stylesheets[all][] = comment.css -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/contact/contact.info b/frontend/drupal/modules/contact/contact.info index 9513c3c1e..b6d67dd50 100644 --- a/frontend/drupal/modules/contact/contact.info +++ b/frontend/drupal/modules/contact/contact.info @@ -6,7 +6,7 @@ core = 7.x files[] = contact.test configure = admin/structure/contact -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/contextual/contextual.info b/frontend/drupal/modules/contextual/contextual.info index f06a778f7..c881710cf 100644 --- a/frontend/drupal/modules/contextual/contextual.info +++ b/frontend/drupal/modules/contextual/contextual.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x files[] = contextual.test -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/dashboard/dashboard.info b/frontend/drupal/modules/dashboard/dashboard.info index 844ec9e95..f4c2db68a 100644 --- a/frontend/drupal/modules/dashboard/dashboard.info +++ b/frontend/drupal/modules/dashboard/dashboard.info @@ -7,7 +7,7 @@ files[] = dashboard.test dependencies[] = block configure = admin/dashboard/customize -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/dblog/dblog.info b/frontend/drupal/modules/dblog/dblog.info index 14df4538d..da068eb78 100644 --- a/frontend/drupal/modules/dblog/dblog.info +++ b/frontend/drupal/modules/dblog/dblog.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x files[] = dblog.test -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/field/field.info b/frontend/drupal/modules/field/field.info index 9c35204dd..c8c4585e7 100644 --- a/frontend/drupal/modules/field/field.info +++ b/frontend/drupal/modules/field/field.info @@ -11,7 +11,7 @@ dependencies[] = field_sql_storage required = TRUE stylesheets[all][] = theme/field.css -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/field/modules/field_sql_storage/field_sql_storage.info b/frontend/drupal/modules/field/modules/field_sql_storage/field_sql_storage.info index e9cb84746..ed407fe88 100644 --- a/frontend/drupal/modules/field/modules/field_sql_storage/field_sql_storage.info +++ b/frontend/drupal/modules/field/modules/field_sql_storage/field_sql_storage.info @@ -7,7 +7,7 @@ dependencies[] = field files[] = field_sql_storage.test required = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/field/modules/field_sql_storage/field_sql_storage.test b/frontend/drupal/modules/field/modules/field_sql_storage/field_sql_storage.test index 7c88ac776..b2eb50652 100644 --- a/frontend/drupal/modules/field/modules/field_sql_storage/field_sql_storage.test +++ b/frontend/drupal/modules/field/modules/field_sql_storage/field_sql_storage.test @@ -313,9 +313,13 @@ class FieldSqlStorageTestCase extends DrupalWebTestCase { $field = array('field_name' => 'test_text', 'type' => 'text', 'settings' => array('max_length' => 255)); $field = field_create_field($field); - // Attempt to update the field in a way that would break the storage. + // Attempt to update the field in a way that would break the storage. The + // parenthesis suffix is needed because SQLite has *very* relaxed rules for + // data types, so we actually need to provide an invalid SQL syntax in order + // to break it. + // @see https://www.sqlite.org/datatype3.html $prior_field = $field; - $field['settings']['max_length'] = -1; + $field['settings']['max_length'] = '-1)'; try { field_update_field($field); $this->fail(t('Update succeeded.')); diff --git a/frontend/drupal/modules/field/modules/list/list.info b/frontend/drupal/modules/field/modules/list/list.info index 0a6bd1c9a..bc867c0ba 100644 --- a/frontend/drupal/modules/field/modules/list/list.info +++ b/frontend/drupal/modules/field/modules/list/list.info @@ -7,7 +7,7 @@ dependencies[] = field dependencies[] = options files[] = tests/list.test -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/field/modules/list/tests/list_test.info b/frontend/drupal/modules/field/modules/list/tests/list_test.info index 8b8caf365..f344a39f9 100644 --- a/frontend/drupal/modules/field/modules/list/tests/list_test.info +++ b/frontend/drupal/modules/field/modules/list/tests/list_test.info @@ -5,7 +5,7 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/field/modules/number/number.info b/frontend/drupal/modules/field/modules/number/number.info index 7a2b57b00..545ccb105 100644 --- a/frontend/drupal/modules/field/modules/number/number.info +++ b/frontend/drupal/modules/field/modules/number/number.info @@ -6,7 +6,7 @@ core = 7.x dependencies[] = field files[] = number.test -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/field/modules/options/options.info b/frontend/drupal/modules/field/modules/options/options.info index cb52bcf0d..8e42a49a4 100644 --- a/frontend/drupal/modules/field/modules/options/options.info +++ b/frontend/drupal/modules/field/modules/options/options.info @@ -6,7 +6,7 @@ core = 7.x dependencies[] = field files[] = options.test -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/field/modules/text/text.info b/frontend/drupal/modules/field/modules/text/text.info index 825927e5d..a1145184b 100644 --- a/frontend/drupal/modules/field/modules/text/text.info +++ b/frontend/drupal/modules/field/modules/text/text.info @@ -7,7 +7,7 @@ dependencies[] = field files[] = text.test required = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/field/tests/field_test.info b/frontend/drupal/modules/field/tests/field_test.info index 08a751152..242fe55a5 100644 --- a/frontend/drupal/modules/field/tests/field_test.info +++ b/frontend/drupal/modules/field/tests/field_test.info @@ -6,7 +6,7 @@ files[] = field_test.entity.inc version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/field_ui/field_ui.info b/frontend/drupal/modules/field_ui/field_ui.info index 0070f7890..e66bd97a7 100644 --- a/frontend/drupal/modules/field_ui/field_ui.info +++ b/frontend/drupal/modules/field_ui/field_ui.info @@ -6,7 +6,7 @@ core = 7.x dependencies[] = field files[] = field_ui.test -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/file/file.info b/frontend/drupal/modules/file/file.info index cf0beafd6..fe0ae6dd2 100644 --- a/frontend/drupal/modules/file/file.info +++ b/frontend/drupal/modules/file/file.info @@ -6,7 +6,7 @@ core = 7.x dependencies[] = field files[] = tests/file.test -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/file/file.module b/frontend/drupal/modules/file/file.module index eea58470f..1f1d59447 100644 --- a/frontend/drupal/modules/file/file.module +++ b/frontend/drupal/modules/file/file.module @@ -281,10 +281,11 @@ function file_ajax_upload() { } // Otherwise just add the new content class on a placeholder. else { - $form['#suffix'] .= ''; + $form['#suffix'] = (isset($form['#suffix']) ? $form['#suffix'] : '') . ''; } - $form['#prefix'] .= theme('status_messages'); + $form['#prefix'] = (isset($form['#prefix']) ? $form['#prefix'] : '') . theme('status_messages'); + $output = drupal_render($form); $js = drupal_add_js(); $settings = drupal_array_merge_deep_array($js['settings']['data']); diff --git a/frontend/drupal/modules/file/tests/file_module_test.info b/frontend/drupal/modules/file/tests/file_module_test.info index 32e7d4cc9..040561e7d 100644 --- a/frontend/drupal/modules/file/tests/file_module_test.info +++ b/frontend/drupal/modules/file/tests/file_module_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/filter/filter.info b/frontend/drupal/modules/filter/filter.info index 540f3edd2..bcd85882c 100644 --- a/frontend/drupal/modules/filter/filter.info +++ b/frontend/drupal/modules/filter/filter.info @@ -7,7 +7,7 @@ files[] = filter.test required = TRUE configure = admin/config/content/formats -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/forum/forum.info b/frontend/drupal/modules/forum/forum.info index f58a5d062..99253aa64 100644 --- a/frontend/drupal/modules/forum/forum.info +++ b/frontend/drupal/modules/forum/forum.info @@ -9,7 +9,7 @@ files[] = forum.test configure = admin/structure/forum stylesheets[all][] = forum.css -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/help/help.info b/frontend/drupal/modules/help/help.info index 448f73816..c410c63ea 100644 --- a/frontend/drupal/modules/help/help.info +++ b/frontend/drupal/modules/help/help.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x files[] = help.test -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/image/image.info b/frontend/drupal/modules/image/image.info index 768e02022..f427a74b8 100644 --- a/frontend/drupal/modules/image/image.info +++ b/frontend/drupal/modules/image/image.info @@ -7,7 +7,7 @@ dependencies[] = file files[] = image.test configure = admin/config/media/image-styles -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/image/tests/image_module_test.info b/frontend/drupal/modules/image/tests/image_module_test.info index 82860f0a4..300bfec19 100644 --- a/frontend/drupal/modules/image/tests/image_module_test.info +++ b/frontend/drupal/modules/image/tests/image_module_test.info @@ -6,7 +6,7 @@ core = 7.x files[] = image_module_test.module hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/locale/locale.info b/frontend/drupal/modules/locale/locale.info index 35bcc4296..aeec19f6d 100644 --- a/frontend/drupal/modules/locale/locale.info +++ b/frontend/drupal/modules/locale/locale.info @@ -6,7 +6,7 @@ core = 7.x files[] = locale.test configure = admin/config/regional/language -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/locale/locale.module b/frontend/drupal/modules/locale/locale.module index 768fead67..93a4657f0 100644 --- a/frontend/drupal/modules/locale/locale.module +++ b/frontend/drupal/modules/locale/locale.module @@ -564,6 +564,7 @@ function locale_language_types_info() { * Implements hook_language_negotiation_info(). */ function locale_language_negotiation_info() { + require_once DRUPAL_ROOT . '/includes/locale.inc'; $file = 'includes/locale.inc'; $providers = array(); diff --git a/frontend/drupal/modules/locale/tests/locale_test.info b/frontend/drupal/modules/locale/tests/locale_test.info index 42d71e557..1337147f6 100644 --- a/frontend/drupal/modules/locale/tests/locale_test.info +++ b/frontend/drupal/modules/locale/tests/locale_test.info @@ -5,7 +5,7 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/menu/menu.info b/frontend/drupal/modules/menu/menu.info index 079804f88..af1c1cdb0 100644 --- a/frontend/drupal/modules/menu/menu.info +++ b/frontend/drupal/modules/menu/menu.info @@ -6,7 +6,7 @@ core = 7.x files[] = menu.test configure = admin/structure/menu -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/node/node.info b/frontend/drupal/modules/node/node.info index 4e3e6acd8..58746503a 100644 --- a/frontend/drupal/modules/node/node.info +++ b/frontend/drupal/modules/node/node.info @@ -9,7 +9,7 @@ required = TRUE configure = admin/structure/types stylesheets[all][] = node.css -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/node/tests/node_access_test.info b/frontend/drupal/modules/node/tests/node_access_test.info index 833a5bb3f..06ecbee92 100644 --- a/frontend/drupal/modules/node/tests/node_access_test.info +++ b/frontend/drupal/modules/node/tests/node_access_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/node/tests/node_test.info b/frontend/drupal/modules/node/tests/node_test.info index debcb6af0..ef4f350e2 100644 --- a/frontend/drupal/modules/node/tests/node_test.info +++ b/frontend/drupal/modules/node/tests/node_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/node/tests/node_test_exception.info b/frontend/drupal/modules/node/tests/node_test_exception.info index 42a72a285..be07e9821 100644 --- a/frontend/drupal/modules/node/tests/node_test_exception.info +++ b/frontend/drupal/modules/node/tests/node_test_exception.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/official_facebook_pixel/CODE_OF_CONDUCT.md b/frontend/drupal/modules/official_facebook_pixel/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..0f7ad8bfc --- /dev/null +++ b/frontend/drupal/modules/official_facebook_pixel/CODE_OF_CONDUCT.md @@ -0,0 +1,5 @@ +# Code of Conduct + +Facebook has adopted a Code of Conduct that we expect project participants to adhere to. +Please read the [full text](https://code.fb.com/codeofconduct/) +so that you can understand what actions will and will not be tolerated. diff --git a/frontend/drupal/modules/official_facebook_pixel/CONTRIBUTING.md b/frontend/drupal/modules/official_facebook_pixel/CONTRIBUTING.md new file mode 100644 index 000000000..38f830111 --- /dev/null +++ b/frontend/drupal/modules/official_facebook_pixel/CONTRIBUTING.md @@ -0,0 +1,35 @@ +# Contributing to Official Facebook Pixel +We want to make contributing to this project as easy and transparent as +possible. + +## Pull Requests +We actively welcome your pull requests. + +1. Fork the repo and create your branch from `master`. +2. If you've added code that should be tested, add tests. +3. If you've changed APIs, update the documentation. +4. Make sure your code lints. +5. If you haven't already, complete the Contributor License Agreement ("CLA"). + +## Contributor License Agreement ("CLA") +In order to accept your pull request, we need you to submit a CLA. You only need +to do this once to work on any of Facebook's open source projects. + +Complete your CLA here: + +## Issues +We use GitHub issues to track public bugs. Please ensure your description is +clear and has sufficient instructions to be able to reproduce the issue. + +Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe +disclosure of security bugs. In those cases, please go through the process +outlined on that page and do not file a public issue. + +## Coding Style +* 4 spaces for indentation rather than tabs +* 80 character line length + +## License +By contributing to Official Facebook Pixel, you agree that your contributions +will be licensed under the LICENSE file in the root directory of +this source tree. diff --git a/frontend/drupal/modules/official_facebook_pixel/LICENSE b/frontend/drupal/modules/official_facebook_pixel/LICENSE new file mode 100644 index 000000000..9bd56be5c --- /dev/null +++ b/frontend/drupal/modules/official_facebook_pixel/LICENSE @@ -0,0 +1,339 @@ +GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + + Preamble + +The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + +To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + +We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + +Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and +modification follow. + +GNU GENERAL PUBLIC LICENSE +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + +a) You must cause the modified files to carry prominent notices +stating that you changed the files and the date of any change. + +b) You must cause any work that you distribute or publish, that in +whole or in part contains or is derived from the Program or any +part thereof, to be licensed as a whole at no charge to all third +parties under the terms of this License. + +c) If the modified program normally reads commands interactively +when run, you must cause it, when started running for such +interactive use in the most ordinary way, to print or display an +announcement including an appropriate copyright notice and a +notice that there is no warranty (or else, saying that you provide +a warranty) and that users may redistribute the program under +these conditions, and telling the user how to view a copy of this +License. (Exception: if the Program itself is interactive but +does not normally print such an announcement, your work based on +the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + +3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + +a) Accompany it with the complete corresponding machine-readable +source code, which must be distributed under the terms of Sections +1 and 2 above on a medium customarily used for software interchange; or, + +b) Accompany it with a written offer, valid for at least three +years, to give any third party, for a charge no more than your +cost of physically performing source distribution, a complete +machine-readable copy of the corresponding source code, to be +distributed under the terms of Sections 1 and 2 above on a medium +customarily used for software interchange; or, + +c) Accompany it with the information you received as to the offer +to distribute corresponding source code. (This alternative is +allowed only for noncommercial distribution and only if you +received the program in object code or executable form with such +an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + +5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + +7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + +9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + +10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + +Copyright (C) + +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 2 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, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + +Gnomovision version 69, Copyright (C) year name of author +Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. +This is free software, and you are welcome to redistribute it +under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in the program +`Gnomovision' (which makes passes at compilers) written by James Hacker. + +, 1 April 1989 +Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/frontend/drupal/modules/official_facebook_pixel/README.md b/frontend/drupal/modules/official_facebook_pixel/README.md new file mode 100644 index 000000000..7e938cfa5 --- /dev/null +++ b/frontend/drupal/modules/official_facebook_pixel/README.md @@ -0,0 +1,19 @@ + +# Official Facebook Pixel + +Grow your business with Official Facebook Pixel! This plugin will +install a Facebook Pixel on your Drupal site, detect and fire pixel events automatically! + +## Get started + +Download the zip file marked 'official-facebook-pixel-7.x-[version number].zip' attached to the current release. + +## Requirements + +Official Facebook Pixel requires +* Drupal 7.x +* PHP 5.6 or greater + +## License + +Official Facebook Pixel is GPLv2-licensed. diff --git a/frontend/drupal/modules/official_facebook_pixel/README.txt b/frontend/drupal/modules/official_facebook_pixel/README.txt new file mode 100644 index 000000000..1761f9d68 --- /dev/null +++ b/frontend/drupal/modules/official_facebook_pixel/README.txt @@ -0,0 +1,53 @@ +CONTENTS OF THIS FILE +--------------------- + + * Introduction + * Requirements + * Installation + * FAQ + * Maintainers + + +INTRODUCTION +------------ + +This plugin will install a Facebook Pixel on your Drupal page. The Official Facebook Pixel allows +you to fire PageView events when people visit your website. Tracking pixel events can help you +understand the actions people are taking on your website. You can then use this information to +make adjustments accordingly in your advertising campaigns. + + +REQUIREMENTS +------------ + * Drupal 7.x + * PHP 5.6 or greater + +INSTALLATION +------------ + + 1. Download the zip file attached to the current release. + 2. Go to your Drupal 7.x site, sign in and enter the "Modules" tab. + 3. Click "+ Install new module" and choose the zip file. + 4. Enable the "Official Facebook Pixel" module by check the checkbox and click "Save configuration". + 5. Go to the "Configuration" tab and click the "Official Facebook Pixel Settings". + 6. Paste your Facebook pixel ID into the text input box and click "Save configuration". + + +FAQ +--- + + Q: Where can I find more information about Facebook Pixel? + A: https://www.facebook.com/business/learn/facebook-ads-pixel + + Q: Where can I find more information about Official Facebook Pixel module? + A: https://www.facebook.com/business/help/1946768672286771 + + Q: I am a developer. Can I help improve the module? + A: Of course! This module is an open source project on GitHub. You can find the code and contribution instructions in: https://github.com/facebookincubator/Facebook-Pixel-for-Drupal. + + +MAINTAINERS +----------- + +Current maintainers: + * Facebook Inc. - https://www.drupal.org/u/facebook diff --git a/frontend/drupal/modules/official_facebook_pixel/official_facebook_pixel.admin.inc b/frontend/drupal/modules/official_facebook_pixel/official_facebook_pixel.admin.inc new file mode 100644 index 000000000..522b0a7db --- /dev/null +++ b/frontend/drupal/modules/official_facebook_pixel/official_facebook_pixel.admin.inc @@ -0,0 +1,49 @@ + 'textfield', + '#title' => t(OfficialFacebookPixelConfig::FORM_PIXEL_TITLE), + '#description' => t(OfficialFacebookPixelConfig::FORM_PIXEL_DESCRIPTION), + '#required' => TRUE, + '#default_value' => $options->getPixelId(), + ); + + $form[OfficialFacebookPixelConfig::FORM_PII_KEY] = array( + '#type' => 'checkbox', + '#title' => t(OfficialFacebookPixelConfig::FORM_PII_TITLE), + '#description' => t(sprintf( + OfficialFacebookPixelConfig::FORM_PII_DESCRIPTION, + OfficialFacebookPixelConfig::FORM_PII_DESCRIPTION_LINK)), + '#default_value' => $options->getUsePii(), + ); + + return system_settings_form($form); +} diff --git a/frontend/drupal/modules/official_facebook_pixel/official_facebook_pixel.info b/frontend/drupal/modules/official_facebook_pixel/official_facebook_pixel.info new file mode 100644 index 000000000..62f1b0a7a --- /dev/null +++ b/frontend/drupal/modules/official_facebook_pixel/official_facebook_pixel.info @@ -0,0 +1,15 @@ +name = Official Facebook Pixel +description = Official plugin provided by Facebook that will install a Facebook Pixel on your Drupal site. +package = Statistics +core = 7.x + +dependencies[] = xautoload + +configure = admin/config/system/official_facebook_pixel + +; Information added by Drupal.org packaging script on 2018-12-07 +version = "7.x-1.1" +core = "7.x" +project = "officialfacebookpixel" +datestamp = "1544223783" + diff --git a/frontend/drupal/modules/official_facebook_pixel/official_facebook_pixel.module b/frontend/drupal/modules/official_facebook_pixel/official_facebook_pixel.module new file mode 100644 index 000000000..f5d7fe754 --- /dev/null +++ b/frontend/drupal/modules/official_facebook_pixel/official_facebook_pixel.module @@ -0,0 +1,82 @@ + array( + 'title' => t('Official Facebook Pixel Plugin Admin'), + 'description' => t('Official Facebook Pixel plugin admin.'), + ), + ); +} + +/** + * Implements hook_menu(). + */ +function official_facebook_pixel_menu() { + $items = array(); + + $items['admin/config/system/official_facebook_pixel'] = array( + 'title' => t('Official Facebook Pixel Settings'), + 'description' => t('Configure Official Facebook Pixel.'), + 'page callback' => 'drupal_get_form', + 'page arguments' => array('official_facebook_pixel_settings_form'), + 'access arguments' => array('admin'), + 'type' => MENU_NORMAL_ITEM, + 'file' => 'official_facebook_pixel.admin.inc', + ); + + return $items; +} + +/** + * Implements hook_page_build(). + */ +function official_facebook_pixel_page_build(&$page) { + if (!should_render()) { + return; + } + + $options = OfficialFacebookPixelOptions::getInstance(); + // Return if pixel_id is not positive integer + if (!OfficialFacebookPixelUtils::isPositiveInteger($options->getPixelId())) { + return; + } + + OfficialFacebookPixelInjection::injectPixelCode(); +} + +/** + * Check if pixel code should be rendered + * + * @return boolean True is should render pixel code, otherwise false. + */ +function should_render() { + global $user; + $roles = $user->roles; + return !(is_array($roles) && in_array("administrator", $roles)); +} diff --git a/frontend/drupal/modules/official_facebook_pixel/src/OfficialFacebookPixelConfig.php b/frontend/drupal/modules/official_facebook_pixel/src/OfficialFacebookPixelConfig.php new file mode 100644 index 000000000..47c03a2e4 --- /dev/null +++ b/frontend/drupal/modules/official_facebook_pixel/src/OfficialFacebookPixelConfig.php @@ -0,0 +1,52 @@ +For businesses that operate in the European Union, you may need to take additional action. Read the Cookie Consent Guide for Sites and Apps for suggestions on complying with EU privacy requirements. the Facebook Pixel ID'; + const FORM_PII_DESCRIPTION_LINK = 'https://developers.facebook.com/docs/privacy/'; + const FORM_PIXEL_KEY = 'pixel_id'; + const FORM_PIXEL_TITLE = 'Pixel ID'; + const FORM_PIXEL_DESCRIPTION = 'Enter the Facebook Pixel ID'; + const SOURCE_7 = 'pldrupal-7'; + const SOURCE_8 = 'pldrupal-8'; + + // integration config for Drupal7: INTEGRATION_KEY => PLUGIN_CLASS + public static function integrationConfigFor7() { + return array( + ); + } + + // integration config for Drupal8: INTEGRATION_KEY => PLUGIN_CLASS + public static function integrationConfigFor8() { + return array( + ); + } +} diff --git a/frontend/drupal/modules/official_facebook_pixel/src/OfficialFacebookPixelInjection.php b/frontend/drupal/modules/official_facebook_pixel/src/OfficialFacebookPixelInjection.php new file mode 100644 index 000000000..7a986f4a0 --- /dev/null +++ b/frontend/drupal/modules/official_facebook_pixel/src/OfficialFacebookPixelInjection.php @@ -0,0 +1,72 @@ +getPixelId()); + + self::injectScriptCode($options); + self::injectNoScriptCode(); + + foreach (OfficialFacebookPixelConfig::integrationConfigFor7() as $key => $value) { + $class_name = 'Drupal\\official_facebook_pixel\\integration\\'.$value; + $class_name::injectPixelCode(); + } + } + + public static function injectScriptCode($options) { + // Inject inline script code to head + $pixel_script_code = PixelScriptBuilder::getPixelBaseCode(); + $pixel_script_code .= PixelScriptBuilder::getPixelInitCode( + $options->getAgentString(), + $options->getUserInfo()); + $pixel_script_code .= PixelScriptBuilder::getPixelPageViewCode(); + drupal_add_html_head( + [ + '#type' => 'markup', + '#markup' => $pixel_script_code, + '#weight' => 1000, + ], + 'facebook_pixel_script_code'); + } + + public static function injectNoScriptCode() { + // Inject inline noscript code to head + $pixel_noscript_code = PixelScriptBuilder::getPixelNoscriptCode(); + drupal_add_html_head( + [ + '#type' => 'markup', + '#markup' => $pixel_noscript_code, + '#weight' => 1000, + ], + 'facebook_pixel_noscript_code'); + } +} diff --git a/frontend/drupal/modules/official_facebook_pixel/src/OfficialFacebookPixelOptions.php b/frontend/drupal/modules/official_facebook_pixel/src/OfficialFacebookPixelOptions.php new file mode 100644 index 000000000..3f1738f8c --- /dev/null +++ b/frontend/drupal/modules/official_facebook_pixel/src/OfficialFacebookPixelOptions.php @@ -0,0 +1,109 @@ +setOptions(); + $this->setUserInfo(); + $this->setVersionInfo(); + } + + public function getOptions() { + return $this->options; + } + + private function setOptions() { + $this->options = array( + OfficialFacebookPixelConfig::FORM_PIXEL_KEY => + variable_get(OfficialFacebookPixelConfig::FORM_PIXEL_KEY, '3580569621997173'), + OfficialFacebookPixelConfig::FORM_PII_KEY => + variable_get(OfficialFacebookPixelConfig::FORM_PII_KEY, 1), + ); + } + + public function getPixelId() { + return $this->options[OfficialFacebookPixelConfig::FORM_PIXEL_KEY]; + } + + public function getUsePii() { + return $this->options[OfficialFacebookPixelConfig::FORM_PII_KEY]; + } + + public function getUserInfo() { + return $this->userInfo; + } + + public function setUserInfo() { + global $user; + $use_pii = $this->getUsePii(); + if (0 === $user->uid || $use_pii !== 1) { + // User not logged in or admin chose not to send PII. + $this->userInfo = array(); + } else { + $this->userInfo = array_filter( + array( + // Keys documented in + // https://developers.facebook.com/docs/facebook-pixel/pixel-with-ads/conversion-tracking#advanced_match + 'em' => $user->mail, + ), + function ($value) { return $value !== null && $value !== ''; }); + } + } + + public function getVersionInfo() { + return $this->versionInfo; + } + + public function setVersionInfo() { + $this->versionInfo = array( + 'source' => OfficialFacebookPixelConfig::SOURCE_7, + 'version' => VERSION, + ); + } + + public function getAgentString() { + return sprintf( + '%s-%s', + $this->versionInfo['source'], + $this->versionInfo['version']); + } +} diff --git a/frontend/drupal/modules/official_facebook_pixel/src/OfficialFacebookPixelUtils.php b/frontend/drupal/modules/official_facebook_pixel/src/OfficialFacebookPixelUtils.php new file mode 100644 index 000000000..e93f41cb6 --- /dev/null +++ b/frontend/drupal/modules/official_facebook_pixel/src/OfficialFacebookPixelUtils.php @@ -0,0 +1,39 @@ + + + +"; + + private static $pixelFbqCodeWithoutScript = " + fbq('%s', '%s'%s%s); +"; + + private static $pixelNoscriptCode = " + + + +"; + + public static function initialize($pixel_id = '') { + self::$pixelId = $pixel_id; + } + + /** + * Gets FB pixel ID + */ + public static function getPixelId() { + return self::$pixelId; + } + + /** + * Sets FB pixel ID + */ + public static function setPixelId($pixel_id) { + self::$pixelId = $pixel_id; + } + + /** + * Gets FB pixel base code + */ + public static function getPixelBaseCode() { + return self::$pixelBaseCode; + } + + /** + * Gets FB pixel init code + */ + public static function getPixelInitCode($agent_string, $param = array(), $with_script_tag = true) { + if (empty(self::$pixelId)) { + return; + } + + $code = $with_script_tag + ? "" + : self::$pixelFbqCodeWithoutScript; + $param_str = $param; + if (is_array($param)) { + $param_str = json_encode($param, JSON_PRETTY_PRINT); + } + $agent_param = array('agent' => $agent_string); + return sprintf( + $code, + 'init', + self::$pixelId, + ', ' . $param_str, + ', ' . json_encode($agent_param, JSON_PRETTY_PRINT)); + } + + /** + * Gets FB pixel track code + * $param is the parameter for the pixel event. + * If it is an array, FB_INTEGRATION_TRACKING_KEY parameter with $tracking_name value will automatically + * be added into the $param. If it is a string, please append the FB_INTEGRATION_TRACKING_KEY parameter + * with its tracking name into the JS Parameter block + */ + public static function getPixelTrackCode($event, $param = array(), $tracking_name = '', $with_script_tag = true) { + if (empty(self::$pixelId)) { + return; + } + + $code = $with_script_tag + ? "" + : self::$pixelFbqCodeWithoutScript; + $param_str = $param; + if (is_array($param)) { + if (!empty($tracking_name)) { + $param[self::FB_INTEGRATION_TRACKING_KEY] = $tracking_name; + } + $param_str = json_encode($param, JSON_PRETTY_PRINT); + } + $class = new \ReflectionClass(__CLASS__); + return sprintf( + $code, + $class->getConstant(strtoupper($event)) !== false ? 'track' : 'trackCustom', + $event, + ', ' . $param_str, + ''); + } + + /** + * Gets FB pixel noscript code + */ + public static function getPixelNoscriptCode($event = 'PageView', $cd = array(), $tracking_name = '') { + if (empty(self::$pixelId)) { + return; + } + + $data = ''; + foreach ($cd as $k => $v) { + $data .= '&cd[' . $k . ']=' . $v; + } + if (!empty($tracking_name)) { + $data .= '&cd[' . self::FB_INTEGRATION_TRACKING_KEY . ']=' . $tracking_name; + } + return sprintf( + self::$pixelNoscriptCode, + self::$pixelId, + $event, + $data); + } + + /** + * Gets FB pixel AddToCart code + */ + public static function getPixelAddToCartCode($param = array(), $tracking_name = '', $with_script_tag = true) { + return self::getPixelTrackCode( + self::ADDTOCART, + $param, + $tracking_name, + $with_script_tag); + } + + /** + * Gets FB pixel InitiateCheckout code + */ + public static function getPixelInitiateCheckoutCode($param = array(), $tracking_name = '', $with_script_tag = true) { + return self::getPixelTrackCode( + self::INITIATECHECKOUT, + $param, + $tracking_name, + $with_script_tag); + } + + /** + * Gets FB pixel Lead code + */ + public static function getPixelLeadCode($param = array(), $tracking_name = '', $with_script_tag = true) { + return self::getPixelTrackCode( + self::LEAD, + $param, + $tracking_name, + $with_script_tag); + } + + /** + * Gets FB pixel PageView code + */ + public static function getPixelPageViewCode($param = array(), $tracking_name = '', $with_script_tag = true) { + return self::getPixelTrackCode( + self::PAGEVIEW, + $param, + $tracking_name, + $with_script_tag); + } + + /** + * Gets FB pixel Purchase code + */ + public static function getPixelPurchaseCode($param = array(), $tracking_name = '', $with_script_tag = true) { + return self::getPixelTrackCode( + self::PURCHASE, + $param, + $tracking_name, + $with_script_tag); + } + + /** + * Gets FB pixel ViewContent code + */ + public static function getPixelViewContentCode($param = array(), $tracking_name = '', $with_script_tag = true) { + return self::getPixelTrackCode( + self::VIEWCONTENT, + $param, + $tracking_name, + $with_script_tag); + } +} diff --git a/frontend/drupal/modules/official_facebook_pixel/src/integration/FacebookDrupalExample.php b/frontend/drupal/modules/official_facebook_pixel/src/integration/FacebookDrupalExample.php new file mode 100644 index 000000000..c9e12d958 --- /dev/null +++ b/frontend/drupal/modules/official_facebook_pixel/src/integration/FacebookDrupalExample.php @@ -0,0 +1,34 @@ +originalFileDirectory . '/simpletest/' . substr($this->databasePrefix, 10)); // Remove all prefixed tables. - $tables = db_find_tables($this->databasePrefix . '%'); - $connection_info = Database::getConnectionInfo('default'); - $tables = db_find_tables($connection_info['default']['prefix']['default'] . '%'); + $tables = db_find_tables_d8('%'); if (empty($tables)) { $this->fail('Failed to find test tables to drop.'); } - $prefix_length = strlen($connection_info['default']['prefix']['default']); foreach ($tables as $table) { - if (db_drop_table(substr($table, $prefix_length))) { + if (db_drop_table($table)) { unset($tables[$table]); } } diff --git a/frontend/drupal/modules/simpletest/simpletest.info b/frontend/drupal/modules/simpletest/simpletest.info index 8203c36e7..b8576f271 100644 --- a/frontend/drupal/modules/simpletest/simpletest.info +++ b/frontend/drupal/modules/simpletest/simpletest.info @@ -58,7 +58,7 @@ files[] = tests/upgrade/update.trigger.test files[] = tests/upgrade/update.field.test files[] = tests/upgrade/update.user.test -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/simpletest.module b/frontend/drupal/modules/simpletest/simpletest.module index cf8304781..6a60d5949 100644 --- a/frontend/drupal/modules/simpletest/simpletest.module +++ b/frontend/drupal/modules/simpletest/simpletest.module @@ -563,7 +563,7 @@ function simpletest_clean_environment() { * Removed prefixed tables from the database that are left over from crashed tests. */ function simpletest_clean_database() { - $tables = db_find_tables(Database::getConnection()->prefixTables('{simpletest}') . '%'); + $tables = db_find_tables_d8(Database::getConnection()->prefixTables('{simpletest}') . '%'); $schema = drupal_get_schema_unprocessed('simpletest'); $count = 0; foreach (array_diff_key($tables, $schema) as $table) { diff --git a/frontend/drupal/modules/simpletest/tests/actions_loop_test.info b/frontend/drupal/modules/simpletest/tests/actions_loop_test.info index 7186b266c..81783afea 100644 --- a/frontend/drupal/modules/simpletest/tests/actions_loop_test.info +++ b/frontend/drupal/modules/simpletest/tests/actions_loop_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/ajax_forms_test.info b/frontend/drupal/modules/simpletest/tests/ajax_forms_test.info index 1364408ef..944f31c1e 100644 --- a/frontend/drupal/modules/simpletest/tests/ajax_forms_test.info +++ b/frontend/drupal/modules/simpletest/tests/ajax_forms_test.info @@ -5,7 +5,7 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/ajax_test.info b/frontend/drupal/modules/simpletest/tests/ajax_test.info index ed2f6ccb5..860f681b3 100644 --- a/frontend/drupal/modules/simpletest/tests/ajax_test.info +++ b/frontend/drupal/modules/simpletest/tests/ajax_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/batch_test.info b/frontend/drupal/modules/simpletest/tests/batch_test.info index 442785a22..a8e87a5ce 100644 --- a/frontend/drupal/modules/simpletest/tests/batch_test.info +++ b/frontend/drupal/modules/simpletest/tests/batch_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/boot_test_1.info b/frontend/drupal/modules/simpletest/tests/boot_test_1.info index 5e4f8b924..41c56572d 100644 --- a/frontend/drupal/modules/simpletest/tests/boot_test_1.info +++ b/frontend/drupal/modules/simpletest/tests/boot_test_1.info @@ -5,7 +5,7 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/boot_test_2.info b/frontend/drupal/modules/simpletest/tests/boot_test_2.info index 10a1e32f0..10b332413 100644 --- a/frontend/drupal/modules/simpletest/tests/boot_test_2.info +++ b/frontend/drupal/modules/simpletest/tests/boot_test_2.info @@ -5,7 +5,7 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/common.test b/frontend/drupal/modules/simpletest/tests/common.test index bd774dc19..6145546f7 100644 --- a/frontend/drupal/modules/simpletest/tests/common.test +++ b/frontend/drupal/modules/simpletest/tests/common.test @@ -2051,6 +2051,32 @@ class DrupalRenderTestCase extends DrupalWebTestCase { // The elements should appear in output in the same order as the array. $this->assertTrue(strpos($output, $second) < strpos($output, $first), 'Elements were not sorted.'); + + // The order of children with same weight should be preserved. + $element_mixed_weight = array( + 'child5' => array('#weight' => 10), + 'child3' => array('#weight' => -10), + 'child1' => array(), + 'child4' => array('#weight' => 10), + 'child2' => array(), + 'child6' => array('#weight' => 10), + 'child9' => array(), + 'child8' => array('#weight' => 10), + 'child7' => array(), + ); + + $expected = array( + 'child3', + 'child1', + 'child2', + 'child9', + 'child7', + 'child5', + 'child4', + 'child6', + 'child8', + ); + $this->assertEqual($expected, element_children($element_mixed_weight, TRUE), 'Order of elements with the same weight is preserved.'); } /** diff --git a/frontend/drupal/modules/simpletest/tests/common_test.info b/frontend/drupal/modules/simpletest/tests/common_test.info index 72050ce1b..b22b08328 100644 --- a/frontend/drupal/modules/simpletest/tests/common_test.info +++ b/frontend/drupal/modules/simpletest/tests/common_test.info @@ -7,7 +7,7 @@ stylesheets[all][] = common_test.css stylesheets[print][] = common_test.print.css hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/common_test_cron_helper.info b/frontend/drupal/modules/simpletest/tests/common_test_cron_helper.info index cb17b4d7d..79cb6dbeb 100644 --- a/frontend/drupal/modules/simpletest/tests/common_test_cron_helper.info +++ b/frontend/drupal/modules/simpletest/tests/common_test_cron_helper.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/database_test.info b/frontend/drupal/modules/simpletest/tests/database_test.info index c9e3f8a7c..758aeb72e 100644 --- a/frontend/drupal/modules/simpletest/tests/database_test.info +++ b/frontend/drupal/modules/simpletest/tests/database_test.info @@ -5,7 +5,7 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/database_test.install b/frontend/drupal/modules/simpletest/tests/database_test.install index 11361151f..44ed5ee0a 100644 --- a/frontend/drupal/modules/simpletest/tests/database_test.install +++ b/frontend/drupal/modules/simpletest/tests/database_test.install @@ -217,5 +217,24 @@ function database_test_schema() { ), ); + $schema['virtual'] = array( + 'description' => 'Basic test table with a reserved name.', + 'fields' => array( + 'id' => array( + 'type' => 'serial', + 'unsigned' => TRUE, + 'not null' => TRUE, + ), + 'function' => array( + 'description' => "A column with a reserved name.", + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'default' => '', + ), + ), + 'primary key' => array('id'), + ); + return $schema; } diff --git a/frontend/drupal/modules/simpletest/tests/database_test.test b/frontend/drupal/modules/simpletest/tests/database_test.test index 59d2e5d62..04be5c85b 100644 --- a/frontend/drupal/modules/simpletest/tests/database_test.test +++ b/frontend/drupal/modules/simpletest/tests/database_test.test @@ -163,6 +163,12 @@ class DatabaseTestCase extends DrupalWebTestCase { 'priority' => 3, )) ->execute(); + + db_insert('virtual') + ->fields(array( + 'function' => 'Function value 1', + )) + ->execute(); } } @@ -3457,7 +3463,6 @@ class DatabaseQueryTestCase extends DatabaseTestCase { ->fetchField(); $this->assertFalse($result, 'SQL injection attempt did not result in a row being inserted in the database table.'); } - } /** @@ -4033,6 +4038,8 @@ class ConnectionUnitTest extends DrupalUnitTestCase { protected $monitor; protected $originalCount; + protected $skipTest; + public static function getInfo() { return array( 'name' => 'Connection unit tests', @@ -4053,7 +4060,7 @@ class ConnectionUnitTest extends DrupalUnitTestCase { // @todo Make this test driver-agnostic, or find a proper way to skip it. // @see http://drupal.org/node/1273478 $connection_info = Database::getConnectionInfo('default'); - $this->skipTest = (bool) $connection_info['default']['driver'] != 'mysql'; + $this->skipTest = (bool) ($connection_info['default']['driver'] != 'mysql'); if ($this->skipTest) { // Insert an assertion to prevent Simpletest from interpreting the test // as failure. @@ -4238,5 +4245,178 @@ class ConnectionUnitTest extends DrupalUnitTestCase { // Verify that we are back to the original connection count. $this->assertNoConnection($id); } - +} + +/** + * Test reserved keyword handling (introduced for MySQL 8+) +*/ +class DatabaseReservedKeywordTestCase extends DatabaseTestCase { + public static function getInfo() { + return array( + 'name' => 'Reserved Keywords', + 'description' => 'Test handling of reserved keywords.', + 'group' => 'Database', + ); + } + + function setUp() { + parent::setUp('database_test'); + } + + public function testTableNameQuoting() { + // Test db_query with {table} pattern. + $record = db_query('SELECT * FROM {system} LIMIT 1')->fetchObject(); + $this->assertTrue(isset($record->filename), 'Successfully queried the {system} table.'); + + $connection = Database::getConnection()->getConnectionOptions(); + if ($connection['driver'] === 'sqlite') { + // In SQLite simpletest's prefixed db tables exist in their own schema + // (e.g. simpletest124904.system), so we cannot test the schema.{table} + // syntax here as the table name will have the schema name prepended to it + // when prefixes are processed. + $this->assert(TRUE, 'Skipping schema.{system} test for SQLite.'); + } + else { + $database = $connection['database']; + // Test db_query with schema.{table} pattern + db_query('SELECT * FROM ' . $database . '.{system} LIMIT 1')->fetchObject(); + $this->assertTrue(isset($record->filename), 'Successfully queried the schema.{system} table.'); + } + } + + public function testSelectReservedWordTableCount() { + $rows = db_select('virtual') + ->countQuery() + ->execute() + ->fetchField(); + $this->assertEqual($rows, 1, 'Successful count query on a table with a reserved name.'); + } + + public function testSelectReservedWordTableSpecificField() { + $record = db_select('virtual') + ->fields('virtual', array('function')) + ->execute() + ->fetchAssoc(); + $this->assertEqual($record['function'], 'Function value 1', 'Successfully read a field from a table with a name and column which are reserved words.'); + } + + public function testSelectReservedWordTableAllFields() { + $record = db_select('virtual') + ->fields('virtual') + ->execute() + ->fetchAssoc(); + $this->assertEqual($record['function'], 'Function value 1', 'Successful all_fields query from a table with a name and column which are reserved words.'); + } + + public function testSelectReservedWordAliasCount() { + $rows = db_select('test', 'character') + ->countQuery() + ->execute() + ->fetchField(); + $this->assertEqual($rows, 4, 'Successful count query using an alias which is a reserved word.'); + } + + public function testSelectReservedWordAliasSpecificFields() { + $record = db_select('test', 'high_priority') + ->fields('high_priority', array('name')) + ->condition('age', 27) + ->execute()->fetchAssoc(); + $this->assertEqual($record['name'], 'George', 'Successful query using an alias which is a reserved word.'); + } + + public function testSelectReservedWordAliasAllFields() { + $record = db_select('test', 'high_priority') + ->fields('high_priority') + ->condition('age', 27) + ->execute()->fetchAssoc(); + $this->assertEqual($record['name'], 'George', 'Successful all_fields query using an alias which is a reserved word.'); + } + + public function testInsertReservedWordTable() { + $num_records_before = db_query('SELECT COUNT(*) FROM {virtual}')->fetchField(); + db_insert('virtual') + ->fields(array( + 'function' => 'Inserted function', + )) + ->execute(); + $num_records_after = db_query('SELECT COUNT(*) FROM {virtual}')->fetchField(); + $this->assertIdentical($num_records_before + 1, (int) $num_records_after, 'Successful insert into a table with a name and column which are reserved words.'); + } + + public function testDeleteReservedWordTable() { + $delete = db_delete('virtual') + ->condition('function', 'Function value 1'); + $num_deleted = $delete->execute(); + $this->assertEqual($num_deleted, 1, "Deleted 1 record from a table with a name and column which are reserved words.."); + } + + function testTruncateReservedWordTable() { + db_truncate('virtual')->execute(); + $num_records_after = db_query("SELECT COUNT(*) FROM {virtual}")->fetchField(); + $this->assertEqual(0, $num_records_after, 'Truncated a table with a reserved name.'); + } + + function testUpdateReservedWordTable() { + $num_updated = db_update('virtual') + ->fields(array('function' => 'Updated function')) + ->execute(); + $this->assertIdentical($num_updated, 1, 'Updated 1 record in a table with a name and column which are reserved words.'); + } + + function testMergeReservedWordTable() { + $key = db_query('SELECT id FROM {virtual} LIMIT 1')->fetchField(); + $num_records_before = db_query('SELECT COUNT(*) FROM {virtual}')->fetchField(); + db_merge('virtual') + ->key(array('id' => $key)) + ->fields(array('function' => 'Merged function')) + ->execute(); + $num_records_after = db_query('SELECT COUNT(*) FROM {virtual}')->fetchField(); + $this->assertIdentical($num_records_before, $num_records_after, 'Successful merge query on a table with a name and column which are reserved words.'); + } +} + +/** + * Test table prefix handling. +*/ +class DatabaseTablePrefixTestCase extends DatabaseTestCase { + public static function getInfo() { + return array( + 'name' => 'Table prefixes', + 'description' => 'Test handling of table prefixes.', + 'group' => 'Database', + ); + } + + public function testSchemaDotTablePrefixes() { + // Get a copy of the default connection options. + $db = Database::getConnection('default', 'default'); + $connection_options = $db->getConnectionOptions(); + + if ($connection_options['driver'] === 'sqlite') { + // In SQLite simpletest's prefixed db tables exist in their own schema + // (e.g. simpletest124904.system), so we cannot test the schema.table + // prefix syntax here. + $this->assert(TRUE, 'Skipping schema.table prefixed tables test for SQLite.'); + return; + } + + $db_name = $connection_options['database']; + // This prefix is usually something like simpletest12345 + $test_prefix = $connection_options['prefix']['default']; + + // Set up a new connection with table prefixes in the form "schema.table" + $prefixed = $connection_options; + $prefixed['prefix'] = array( + 'default' => $test_prefix, + 'users' => $db_name . '.' . $test_prefix, + 'role' => $db_name . '.' . $test_prefix, + ); + Database::addConnectionInfo('default', 'prefixed', $prefixed); + + // Test that the prefixed database connection can query the prefixed tables. + $num_users_prefixed = Database::getConnection('prefixed', 'default')->query('SELECT COUNT(1) FROM {users}')->fetchField(); + $this->assertTrue((int) $num_users_prefixed > 0, 'Successfully queried the users table using a schema.table prefix'); + $num_users_default = Database::getConnection('default', 'default')->query('SELECT COUNT(1) FROM {users}')->fetchField(); + $this->assertEqual($num_users_default, $num_users_prefixed, 'Verified results of query using a connection with schema.table prefixed tables'); + } } diff --git a/frontend/drupal/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test.info b/frontend/drupal/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test.info index c06d04d27..6820a3517 100644 --- a/frontend/drupal/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test.info +++ b/frontend/drupal/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test.info @@ -7,7 +7,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info b/frontend/drupal/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info index 8a4d01156..0fb3d57b1 100644 --- a/frontend/drupal/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info +++ b/frontend/drupal/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info b/frontend/drupal/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info index 70221dc93..d015d3fb0 100644 --- a/frontend/drupal/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info +++ b/frontend/drupal/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/entity_cache_test.info b/frontend/drupal/modules/simpletest/tests/entity_cache_test.info index 10ca8d9ff..a95eaf5f2 100644 --- a/frontend/drupal/modules/simpletest/tests/entity_cache_test.info +++ b/frontend/drupal/modules/simpletest/tests/entity_cache_test.info @@ -6,7 +6,7 @@ core = 7.x dependencies[] = entity_cache_test_dependency hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/entity_cache_test_dependency.info b/frontend/drupal/modules/simpletest/tests/entity_cache_test_dependency.info index bbf00b395..35ea7039d 100644 --- a/frontend/drupal/modules/simpletest/tests/entity_cache_test_dependency.info +++ b/frontend/drupal/modules/simpletest/tests/entity_cache_test_dependency.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/entity_crud_hook_test.info b/frontend/drupal/modules/simpletest/tests/entity_crud_hook_test.info index e4e547415..17198cd0c 100644 --- a/frontend/drupal/modules/simpletest/tests/entity_crud_hook_test.info +++ b/frontend/drupal/modules/simpletest/tests/entity_crud_hook_test.info @@ -5,7 +5,7 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/entity_query_access_test.info b/frontend/drupal/modules/simpletest/tests/entity_query_access_test.info index 03adb93e8..9a5d7249a 100644 --- a/frontend/drupal/modules/simpletest/tests/entity_query_access_test.info +++ b/frontend/drupal/modules/simpletest/tests/entity_query_access_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/error_test.info b/frontend/drupal/modules/simpletest/tests/error_test.info index 6cc11bfd4..37425c3c8 100644 --- a/frontend/drupal/modules/simpletest/tests/error_test.info +++ b/frontend/drupal/modules/simpletest/tests/error_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/file_test.info b/frontend/drupal/modules/simpletest/tests/file_test.info index fd10f7c0f..0bb6d1db6 100644 --- a/frontend/drupal/modules/simpletest/tests/file_test.info +++ b/frontend/drupal/modules/simpletest/tests/file_test.info @@ -6,7 +6,7 @@ core = 7.x files[] = file_test.module hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/filter_test.info b/frontend/drupal/modules/simpletest/tests/filter_test.info index 8803d2723..96d316805 100644 --- a/frontend/drupal/modules/simpletest/tests/filter_test.info +++ b/frontend/drupal/modules/simpletest/tests/filter_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/form.test b/frontend/drupal/modules/simpletest/tests/form.test index d1be69d72..49b561a63 100644 --- a/frontend/drupal/modules/simpletest/tests/form.test +++ b/frontend/drupal/modules/simpletest/tests/form.test @@ -591,6 +591,19 @@ class FormElementTestCase extends DrupalWebTestCase { ))); } } + + /** + * Tests Weight form element #default_value behavior. + */ + public function testWeightDefaultValue() { + $element = array( + '#type' => 'weight', + '#delta' => 10, + '#default_value' => 15, + ); + $element = form_process_weight($element); + $this->assertTrue(isset($element['#options'][$element['#default_value']]), 'Default value exists in #options list'); + } } /** diff --git a/frontend/drupal/modules/simpletest/tests/form_test.info b/frontend/drupal/modules/simpletest/tests/form_test.info index fe14a8845..346acca29 100644 --- a/frontend/drupal/modules/simpletest/tests/form_test.info +++ b/frontend/drupal/modules/simpletest/tests/form_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/image_test.info b/frontend/drupal/modules/simpletest/tests/image_test.info index 340810cf3..b3e168036 100644 --- a/frontend/drupal/modules/simpletest/tests/image_test.info +++ b/frontend/drupal/modules/simpletest/tests/image_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/mail.test b/frontend/drupal/modules/simpletest/tests/mail.test index 3e40e13a8..307c77b29 100644 --- a/frontend/drupal/modules/simpletest/tests/mail.test +++ b/frontend/drupal/modules/simpletest/tests/mail.test @@ -59,6 +59,81 @@ class MailTestCase extends DrupalWebTestCase implements MailSystemInterface { $this->assertNull(self::$sent_message, 'Message was canceled.'); } + /** + * Checks for the site name in an auto-generated From: header. + */ + function testFromHeader() { + global $language; + $default_from = variable_get('site_mail', ini_get('sendmail_from')); + $site_name = variable_get('site_name', 'Drupal'); + + // Reset the class variable holding a copy of the last sent message. + self::$sent_message = NULL; + // Send an e-mail with a sender address specified. + $from_email = 'someone_else@example.com'; + $message = drupal_mail('simpletest', 'from_test', 'from_test@example.com', $language, array(), $from_email); + // Test that the from e-mail is just the e-mail and not the site name and + // default sender e-mail. + $this->assertEqual($from_email, self::$sent_message['headers']['From']); + + // Check default behavior is only email in FROM header. + self::$sent_message = NULL; + // Send an e-mail and check that the From-header contains only default mail address. + variable_del('mail_display_name_site_name'); + $message = drupal_mail('simpletest', 'from_test', 'from_test@example.com', $language); + $this->assertEqual($default_from, self::$sent_message['headers']['From']); + + self::$sent_message = NULL; + // Send an e-mail and check that the From-header contains the site name. + variable_set('mail_display_name_site_name', TRUE); + $message = drupal_mail('simpletest', 'from_test', 'from_test@example.com', $language); + $this->assertEqual($site_name . ' <' . $default_from . '>', self::$sent_message['headers']['From']); + } + + /** + * Checks for the site name in an auto-generated From: header. + */ + function testFromHeaderRfc2822Compliant() { + global $language; + $default_from = variable_get('site_mail', ini_get('sendmail_from')); + + // Enable adding a site name to From. + variable_set('mail_display_name_site_name', TRUE); + + $site_names = array( + // Simple ASCII characters. + 'Test site' => 'Test site', + // ASCII with html entity. + 'Test & site' => 'Test & site', + // Non-ASCII characters. + 'Tést site' => '=?UTF-8?B?VMOpc3Qgc2l0ZQ==?=', + // Non-ASCII with special characters. + 'Tést; site' => '=?UTF-8?B?VMOpc3Q7IHNpdGU=?=', + // Non-ASCII with html entity. + 'Tést; site' => '=?UTF-8?B?VMOpc3Q7IHNpdGU=?=', + // ASCII with special characters. + 'Test; site' => '"Test; site"', + // ASCII with special characters as html entity. + 'Test < site' => '"Test < site"', + // ASCII with special characters and '\'. + 'Test; \ "site"' => '"Test; \\\\ \"site\""', + // String already RFC-2822 compliant. + '"Test; site"' => '"Test; site"', + // String already RFC-2822 compliant. + '"Test; \\\\ \"site\""' => '"Test; \\\\ \"site\""', + ); + + foreach ($site_names as $original_name => $safe_string) { + variable_set('site_name', $original_name); + + // Reset the class variable holding a copy of the last sent message. + self::$sent_message = NULL; + // Send an e-mail and check that the From-header contains is RFC-2822 compliant. + drupal_mail('simpletest', 'from_test', 'from_test@example.com', $language); + $this->assertEqual($safe_string . ' <' . $default_from . '>', self::$sent_message['headers']['From']); + } + } + /** * Concatenate and wrap the e-mail body for plain-text mails. * diff --git a/frontend/drupal/modules/simpletest/tests/menu_test.info b/frontend/drupal/modules/simpletest/tests/menu_test.info index 87b72dbbf..4973c75b7 100644 --- a/frontend/drupal/modules/simpletest/tests/menu_test.info +++ b/frontend/drupal/modules/simpletest/tests/menu_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/module_test.info b/frontend/drupal/modules/simpletest/tests/module_test.info index 68725dabf..8c1eb098d 100644 --- a/frontend/drupal/modules/simpletest/tests/module_test.info +++ b/frontend/drupal/modules/simpletest/tests/module_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/path_test.info b/frontend/drupal/modules/simpletest/tests/path_test.info index 552f6e245..ab1a36b56 100644 --- a/frontend/drupal/modules/simpletest/tests/path_test.info +++ b/frontend/drupal/modules/simpletest/tests/path_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/psr_0_test/psr_0_test.info b/frontend/drupal/modules/simpletest/tests/psr_0_test/psr_0_test.info index f9bbc3dfb..2e2e8e508 100644 --- a/frontend/drupal/modules/simpletest/tests/psr_0_test/psr_0_test.info +++ b/frontend/drupal/modules/simpletest/tests/psr_0_test/psr_0_test.info @@ -5,7 +5,7 @@ core = 7.x hidden = TRUE package = Testing -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/psr_4_test/psr_4_test.info b/frontend/drupal/modules/simpletest/tests/psr_4_test/psr_4_test.info index 4fef41f37..a5270a7f7 100644 --- a/frontend/drupal/modules/simpletest/tests/psr_4_test/psr_4_test.info +++ b/frontend/drupal/modules/simpletest/tests/psr_4_test/psr_4_test.info @@ -5,7 +5,7 @@ core = 7.x hidden = TRUE package = Testing -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/requirements1_test.info b/frontend/drupal/modules/simpletest/tests/requirements1_test.info index cd1ffab80..bc85ee845 100644 --- a/frontend/drupal/modules/simpletest/tests/requirements1_test.info +++ b/frontend/drupal/modules/simpletest/tests/requirements1_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/requirements2_test.info b/frontend/drupal/modules/simpletest/tests/requirements2_test.info index ad1926d05..b023c44e9 100644 --- a/frontend/drupal/modules/simpletest/tests/requirements2_test.info +++ b/frontend/drupal/modules/simpletest/tests/requirements2_test.info @@ -7,7 +7,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/schema.test b/frontend/drupal/modules/simpletest/tests/schema.test index 41994284e..070b2911e 100644 --- a/frontend/drupal/modules/simpletest/tests/schema.test +++ b/frontend/drupal/modules/simpletest/tests/schema.test @@ -381,4 +381,60 @@ class SchemaTestCase extends DrupalWebTestCase { db_drop_field($table_name, $field_name); } + + /** + * Tests the findTables() method. + */ + public function testFindTables() { + // We will be testing with three tables, two of them using the default + // prefix and the third one with an individually specified prefix. + + // Set up a new connection with different connection info. + $connection_info = Database::getConnectionInfo(); + + // Add per-table prefix to the second table. + $new_connection_info = $connection_info['default']; + $new_connection_info['prefix']['test_2_table'] = $new_connection_info['prefix']['default'] . '_shared_'; + Database::addConnectionInfo('test', 'default', $new_connection_info); + + Database::setActiveConnection('test'); + + // Create the tables. + $table_specification = array( + 'description' => 'Test table.', + 'fields' => array( + 'id' => array( + 'type' => 'int', + 'default' => NULL, + ), + ), + ); + Database::getConnection()->schema()->createTable('test_1_table', $table_specification); + Database::getConnection()->schema()->createTable('test_2_table', $table_specification); + Database::getConnection()->schema()->createTable('the_third_table', $table_specification); + + // Check the "all tables" syntax. + $tables = Database::getConnection()->schema()->findTablesD8('%'); + sort($tables); + $expected = array( + 'test_1_table', + // This table uses a per-table prefix, yet it is returned as un-prefixed. + 'test_2_table', + 'the_third_table', + ); + + $this->assertTrue(!array_diff($expected, $tables), 'All tables were found.'); + + // Check the restrictive syntax. + $tables = Database::getConnection()->schema()->findTablesD8('test_%'); + sort($tables); + $expected = array( + 'test_1_table', + 'test_2_table', + ); + $this->assertEqual($tables, $expected, 'Two tables were found.'); + + // Go back to the initial connection. + Database::setActiveConnection('default'); + } } diff --git a/frontend/drupal/modules/simpletest/tests/session_test.info b/frontend/drupal/modules/simpletest/tests/session_test.info index 29a4e2d38..4a04c5b8c 100644 --- a/frontend/drupal/modules/simpletest/tests/session_test.info +++ b/frontend/drupal/modules/simpletest/tests/session_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/system_dependencies_test.info b/frontend/drupal/modules/simpletest/tests/system_dependencies_test.info index b55bb4844..d7242e282 100644 --- a/frontend/drupal/modules/simpletest/tests/system_dependencies_test.info +++ b/frontend/drupal/modules/simpletest/tests/system_dependencies_test.info @@ -6,7 +6,7 @@ core = 7.x hidden = TRUE dependencies[] = _missing_dependency -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.info b/frontend/drupal/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.info index c2968cc70..1680c1ade 100644 --- a/frontend/drupal/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.info +++ b/frontend/drupal/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.info @@ -6,7 +6,7 @@ core = 7.x hidden = TRUE dependencies[] = system_incompatible_core_version_test -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/system_incompatible_core_version_test.info b/frontend/drupal/modules/simpletest/tests/system_incompatible_core_version_test.info index eed2f3bde..1f70929de 100644 --- a/frontend/drupal/modules/simpletest/tests/system_incompatible_core_version_test.info +++ b/frontend/drupal/modules/simpletest/tests/system_incompatible_core_version_test.info @@ -5,7 +5,7 @@ version = VERSION core = 5.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info b/frontend/drupal/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info index 826fcd361..94721cbc5 100644 --- a/frontend/drupal/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info +++ b/frontend/drupal/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info @@ -7,7 +7,7 @@ hidden = TRUE ; system_incompatible_module_version_test declares version 1.0 dependencies[] = system_incompatible_module_version_test (>2.0) -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/system_incompatible_module_version_test.info b/frontend/drupal/modules/simpletest/tests/system_incompatible_module_version_test.info index 79027b705..ce11959b5 100644 --- a/frontend/drupal/modules/simpletest/tests/system_incompatible_module_version_test.info +++ b/frontend/drupal/modules/simpletest/tests/system_incompatible_module_version_test.info @@ -5,7 +5,7 @@ version = 1.0 core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/system_project_namespace_test.info b/frontend/drupal/modules/simpletest/tests/system_project_namespace_test.info index 6e426e318..371999d87 100644 --- a/frontend/drupal/modules/simpletest/tests/system_project_namespace_test.info +++ b/frontend/drupal/modules/simpletest/tests/system_project_namespace_test.info @@ -6,7 +6,7 @@ core = 7.x hidden = TRUE dependencies[] = drupal:filter -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/system_test.info b/frontend/drupal/modules/simpletest/tests/system_test.info index 632c51f41..3e6f87f82 100644 --- a/frontend/drupal/modules/simpletest/tests/system_test.info +++ b/frontend/drupal/modules/simpletest/tests/system_test.info @@ -6,7 +6,7 @@ core = 7.x files[] = system_test.module hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/taxonomy_test.info b/frontend/drupal/modules/simpletest/tests/taxonomy_test.info index d09eba609..f3a4a4bd8 100644 --- a/frontend/drupal/modules/simpletest/tests/taxonomy_test.info +++ b/frontend/drupal/modules/simpletest/tests/taxonomy_test.info @@ -6,7 +6,7 @@ core = 7.x hidden = TRUE dependencies[] = taxonomy -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/theme_test.info b/frontend/drupal/modules/simpletest/tests/theme_test.info index c0a7c07f3..4a929db16 100644 --- a/frontend/drupal/modules/simpletest/tests/theme_test.info +++ b/frontend/drupal/modules/simpletest/tests/theme_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info b/frontend/drupal/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info index a273dd04c..62d1a72dc 100644 --- a/frontend/drupal/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info +++ b/frontend/drupal/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info @@ -6,7 +6,7 @@ hidden = TRUE settings[basetheme_only] = base theme value settings[subtheme_override] = base theme value -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info b/frontend/drupal/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info index f7c5fe4a5..d3fd66caa 100644 --- a/frontend/drupal/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info +++ b/frontend/drupal/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info @@ -6,7 +6,7 @@ hidden = TRUE settings[subtheme_override] = subtheme value -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/themes/test_theme/test_theme.info b/frontend/drupal/modules/simpletest/tests/themes/test_theme/test_theme.info index 4d0f9e333..a09c4f190 100644 --- a/frontend/drupal/modules/simpletest/tests/themes/test_theme/test_theme.info +++ b/frontend/drupal/modules/simpletest/tests/themes/test_theme/test_theme.info @@ -17,7 +17,7 @@ stylesheets[all][] = system.base.css settings[theme_test_setting] = default value -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/themes/test_theme_nyan_cat/test_theme_nyan_cat.info b/frontend/drupal/modules/simpletest/tests/themes/test_theme_nyan_cat/test_theme_nyan_cat.info index 5ccb810f1..758c9b553 100644 --- a/frontend/drupal/modules/simpletest/tests/themes/test_theme_nyan_cat/test_theme_nyan_cat.info +++ b/frontend/drupal/modules/simpletest/tests/themes/test_theme_nyan_cat/test_theme_nyan_cat.info @@ -4,7 +4,7 @@ core = 7.x hidden = TRUE engine = nyan_cat -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/update_script_test.info b/frontend/drupal/modules/simpletest/tests/update_script_test.info index 1595423f1..6ecea7912 100644 --- a/frontend/drupal/modules/simpletest/tests/update_script_test.info +++ b/frontend/drupal/modules/simpletest/tests/update_script_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/update_test_1.info b/frontend/drupal/modules/simpletest/tests/update_test_1.info index 0ddcd6944..a9cc0c0f9 100644 --- a/frontend/drupal/modules/simpletest/tests/update_test_1.info +++ b/frontend/drupal/modules/simpletest/tests/update_test_1.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/update_test_2.info b/frontend/drupal/modules/simpletest/tests/update_test_2.info index 0ddcd6944..a9cc0c0f9 100644 --- a/frontend/drupal/modules/simpletest/tests/update_test_2.info +++ b/frontend/drupal/modules/simpletest/tests/update_test_2.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/update_test_3.info b/frontend/drupal/modules/simpletest/tests/update_test_3.info index 0ddcd6944..a9cc0c0f9 100644 --- a/frontend/drupal/modules/simpletest/tests/update_test_3.info +++ b/frontend/drupal/modules/simpletest/tests/update_test_3.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/url_alter_test.info b/frontend/drupal/modules/simpletest/tests/url_alter_test.info index 3db76997c..3adee0fad 100644 --- a/frontend/drupal/modules/simpletest/tests/url_alter_test.info +++ b/frontend/drupal/modules/simpletest/tests/url_alter_test.info @@ -5,7 +5,7 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/simpletest/tests/xmlrpc_test.info b/frontend/drupal/modules/simpletest/tests/xmlrpc_test.info index 8a93f3b3c..326b82dd1 100644 --- a/frontend/drupal/modules/simpletest/tests/xmlrpc_test.info +++ b/frontend/drupal/modules/simpletest/tests/xmlrpc_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/statistics/statistics.info b/frontend/drupal/modules/statistics/statistics.info index b9e3cd23a..0ad418980 100644 --- a/frontend/drupal/modules/statistics/statistics.info +++ b/frontend/drupal/modules/statistics/statistics.info @@ -6,7 +6,7 @@ core = 7.x files[] = statistics.test configure = admin/config/system/statistics -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/syslog/syslog.info b/frontend/drupal/modules/syslog/syslog.info index a25b179d6..4ee8581dd 100644 --- a/frontend/drupal/modules/syslog/syslog.info +++ b/frontend/drupal/modules/syslog/syslog.info @@ -6,7 +6,7 @@ core = 7.x files[] = syslog.test configure = admin/config/development/logging -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/system/system.info b/frontend/drupal/modules/system/system.info index b54295daf..8b4ba3a38 100644 --- a/frontend/drupal/modules/system/system.info +++ b/frontend/drupal/modules/system/system.info @@ -12,7 +12,7 @@ files[] = system.test required = TRUE configure = admin/config/system -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/system/system.tar.inc b/frontend/drupal/modules/system/system.tar.inc index 92fa52908..0af6275b4 100644 --- a/frontend/drupal/modules/system/system.tar.inc +++ b/frontend/drupal/modules/system/system.tar.inc @@ -2178,6 +2178,14 @@ class Archive_Tar } } } elseif ($v_header['typeflag'] == "2") { + if (strpos(realpath(dirname($v_header['link'])), realpath($p_path)) !== 0) { + $this->_error( + 'Out-of-path file extraction {' + . $v_header['filename'] . ' --> ' . + $v_header['link'] . '}' + ); + return false; + } if (!$p_symlinks) { $this->_warning('Symbolic links are not allowed. ' . 'Unable to extract {' diff --git a/frontend/drupal/modules/system/system.test b/frontend/drupal/modules/system/system.test index 270311ecb..45c6648c4 100644 --- a/frontend/drupal/modules/system/system.test +++ b/frontend/drupal/modules/system/system.test @@ -28,7 +28,7 @@ class ModuleTestCase extends DrupalWebTestCase { * specified base table. Defaults to TRUE. */ function assertTableCount($base_table, $count = TRUE) { - $tables = db_find_tables(Database::getConnection()->prefixTables('{' . $base_table . '}') . '%'); + $tables = db_find_tables_d8($base_table . '%'); if ($count) { return $this->assertTrue($tables, format_string('Tables matching "@base_table" found.', array('@base_table' => $base_table))); @@ -779,14 +779,14 @@ class IPAddressBlockingTestCase extends DrupalWebTestCase { $submit_ip = $_SERVER['REMOTE_ADDR'] = '192.168.1.1'; system_block_ip_action(); system_block_ip_action(); - $ip_count = db_query("SELECT iid from {blocked_ips} WHERE ip = :ip", array(':ip' => $submit_ip))->rowCount(); + $ip_count = db_query("SELECT COUNT(*) from {blocked_ips} WHERE ip = :ip", array(':ip' => $submit_ip))->fetchColumn(); $this->assertEqual('1', $ip_count); drupal_static_reset('ip_address'); $submit_ip = $_SERVER['REMOTE_ADDR'] = ' '; system_block_ip_action(); system_block_ip_action(); system_block_ip_action(); - $ip_count = db_query("SELECT iid from {blocked_ips} WHERE ip = :ip", array(':ip' => $submit_ip))->rowCount(); + $ip_count = db_query("SELECT COUNT(*) from {blocked_ips} WHERE ip = :ip", array(':ip' => $submit_ip))->fetchColumn(); $this->assertEqual('1', $ip_count); } } diff --git a/frontend/drupal/modules/system/tests/cron_queue_test.info b/frontend/drupal/modules/system/tests/cron_queue_test.info index 15ea6dbbc..4c33802bc 100644 --- a/frontend/drupal/modules/system/tests/cron_queue_test.info +++ b/frontend/drupal/modules/system/tests/cron_queue_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/system/tests/system_cron_test.info b/frontend/drupal/modules/system/tests/system_cron_test.info index d8261eb30..4a79c5461 100644 --- a/frontend/drupal/modules/system/tests/system_cron_test.info +++ b/frontend/drupal/modules/system/tests/system_cron_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/taxonomy/taxonomy.info b/frontend/drupal/modules/taxonomy/taxonomy.info index 37c3d022d..16b3b361d 100644 --- a/frontend/drupal/modules/taxonomy/taxonomy.info +++ b/frontend/drupal/modules/taxonomy/taxonomy.info @@ -8,7 +8,7 @@ files[] = taxonomy.module files[] = taxonomy.test configure = admin/structure/taxonomy -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/toolbar/toolbar.info b/frontend/drupal/modules/toolbar/toolbar.info index ef0640c07..f847f2a0a 100644 --- a/frontend/drupal/modules/toolbar/toolbar.info +++ b/frontend/drupal/modules/toolbar/toolbar.info @@ -4,7 +4,7 @@ core = 7.x package = Core version = VERSION -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/tracker/tracker.info b/frontend/drupal/modules/tracker/tracker.info index 9950027b0..02fdaab62 100644 --- a/frontend/drupal/modules/tracker/tracker.info +++ b/frontend/drupal/modules/tracker/tracker.info @@ -6,7 +6,7 @@ version = VERSION core = 7.x files[] = tracker.test -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/translation/tests/translation_test.info b/frontend/drupal/modules/translation/tests/translation_test.info index 2d8d7bf3d..af85ecc89 100644 --- a/frontend/drupal/modules/translation/tests/translation_test.info +++ b/frontend/drupal/modules/translation/tests/translation_test.info @@ -5,7 +5,7 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/translation/translation.info b/frontend/drupal/modules/translation/translation.info index 6f8f5e7a7..8b81011da 100644 --- a/frontend/drupal/modules/translation/translation.info +++ b/frontend/drupal/modules/translation/translation.info @@ -6,7 +6,7 @@ version = VERSION core = 7.x files[] = translation.test -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/trigger/tests/trigger_test.info b/frontend/drupal/modules/trigger/tests/trigger_test.info index 49c2b124d..4af57113d 100644 --- a/frontend/drupal/modules/trigger/tests/trigger_test.info +++ b/frontend/drupal/modules/trigger/tests/trigger_test.info @@ -4,7 +4,7 @@ package = Testing core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/trigger/trigger.info b/frontend/drupal/modules/trigger/trigger.info index 80477ae72..dccfe4a68 100644 --- a/frontend/drupal/modules/trigger/trigger.info +++ b/frontend/drupal/modules/trigger/trigger.info @@ -6,7 +6,7 @@ core = 7.x files[] = trigger.test configure = admin/structure/trigger -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/update/tests/aaa_update_test.info b/frontend/drupal/modules/update/tests/aaa_update_test.info index 65d45dd13..1e591277f 100644 --- a/frontend/drupal/modules/update/tests/aaa_update_test.info +++ b/frontend/drupal/modules/update/tests/aaa_update_test.info @@ -4,7 +4,7 @@ package = Testing core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/update/tests/bbb_update_test.info b/frontend/drupal/modules/update/tests/bbb_update_test.info index b974fac11..ca8c12c72 100644 --- a/frontend/drupal/modules/update/tests/bbb_update_test.info +++ b/frontend/drupal/modules/update/tests/bbb_update_test.info @@ -4,7 +4,7 @@ package = Testing core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/update/tests/ccc_update_test.info b/frontend/drupal/modules/update/tests/ccc_update_test.info index 078edb232..30b134133 100644 --- a/frontend/drupal/modules/update/tests/ccc_update_test.info +++ b/frontend/drupal/modules/update/tests/ccc_update_test.info @@ -4,7 +4,7 @@ package = Testing core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/update/tests/themes/update_test_admintheme/update_test_admintheme.info b/frontend/drupal/modules/update/tests/themes/update_test_admintheme/update_test_admintheme.info index aa5801970..db08879db 100644 --- a/frontend/drupal/modules/update/tests/themes/update_test_admintheme/update_test_admintheme.info +++ b/frontend/drupal/modules/update/tests/themes/update_test_admintheme/update_test_admintheme.info @@ -3,7 +3,7 @@ description = Test theme which is used as admin theme. core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info b/frontend/drupal/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info index abf9f95e0..409ab59cf 100644 --- a/frontend/drupal/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info +++ b/frontend/drupal/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info @@ -3,7 +3,7 @@ description = Test theme which acts as a base theme for other test subthemes. core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info b/frontend/drupal/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info index fa16d9882..757210739 100644 --- a/frontend/drupal/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info +++ b/frontend/drupal/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info @@ -4,7 +4,7 @@ core = 7.x base theme = update_test_basetheme hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/update/tests/update_test.info b/frontend/drupal/modules/update/tests/update_test.info index f0841a54f..bbd89205a 100644 --- a/frontend/drupal/modules/update/tests/update_test.info +++ b/frontend/drupal/modules/update/tests/update_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/update/update.info b/frontend/drupal/modules/update/update.info index 8543e3432..2799f33a3 100644 --- a/frontend/drupal/modules/update/update.info +++ b/frontend/drupal/modules/update/update.info @@ -6,7 +6,7 @@ core = 7.x files[] = update.test configure = admin/reports/updates/settings -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/user/tests/user_flood_test.info b/frontend/drupal/modules/user/tests/user_flood_test.info new file mode 100644 index 000000000..4500f0882 --- /dev/null +++ b/frontend/drupal/modules/user/tests/user_flood_test.info @@ -0,0 +1,11 @@ +name = "User module flood control tests" +description = "Support module for user flood control testing." +package = Testing +version = VERSION +core = 7.x +hidden = TRUE + +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" +project = "drupal" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/user/tests/user_flood_test.module b/frontend/drupal/modules/user/tests/user_flood_test.module new file mode 100644 index 000000000..f7388690f --- /dev/null +++ b/frontend/drupal/modules/user/tests/user_flood_test.module @@ -0,0 +1,18 @@ + $username, '%ip' => $ip)); + } + else { + watchdog('user_flood_test', 'hook_user_flood_control was passed IP %ip.', array('%ip' => $ip)); + } +} diff --git a/frontend/drupal/modules/user/tests/user_form_test.info b/frontend/drupal/modules/user/tests/user_form_test.info index 2f9952694..3ee56197b 100644 --- a/frontend/drupal/modules/user/tests/user_form_test.info +++ b/frontend/drupal/modules/user/tests/user_form_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/user/tests/user_form_test.module b/frontend/drupal/modules/user/tests/user_form_test.module index 382bc57b8..2af15cb83 100644 --- a/frontend/drupal/modules/user/tests/user_form_test.module +++ b/frontend/drupal/modules/user/tests/user_form_test.module @@ -35,7 +35,7 @@ function user_form_test_current_password($form, &$form_state, $account) { '#description' => t('A field that would require a correct password to change.'), '#required' => TRUE, ); - + $form['current_pass'] = array( '#type' => 'password', '#title' => t('Current password'), diff --git a/frontend/drupal/modules/user/tests/user_session_test.info b/frontend/drupal/modules/user/tests/user_session_test.info index 1ae2e6e34..4a9152602 100644 --- a/frontend/drupal/modules/user/tests/user_session_test.info +++ b/frontend/drupal/modules/user/tests/user_session_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/user/user.api.php b/frontend/drupal/modules/user/user.api.php index f205a85b5..b9dc95f15 100644 --- a/frontend/drupal/modules/user/user.api.php +++ b/frontend/drupal/modules/user/user.api.php @@ -472,6 +472,36 @@ function hook_user_role_delete($role) { ->execute(); } +/** + * Respond to user flood control events. + * + * This hook allows you act when an unsuccessful user login has triggered + * flood control. This means that either an IP address or a specific user + * account has been temporarily blocked from logging in. + * + * @param $ip + * The IP address that triggered flood control. + * @param $username + * The username that has been temporarily blocked. + * + * @see user_login_final_validate() + */ +function hook_user_flood_control($ip, $username = FALSE) { + if (!empty($username)) { + // Do something with the blocked $username and $ip. For example, send an + // e-mail to the user and/or site administrator. + + // Drupal core uses this hook to log the event: + watchdog('user', 'Flood control blocked login attempt for %user from %ip.', array('%user' => $username, '%ip' => $ip)); + } + else { + // Do something with the blocked $ip. For example, add it to a block-list. + + // Drupal core uses this hook to log the event: + watchdog('user', 'Flood control blocked login attempt from %ip.', array('%ip' => $ip)); + } +} + /** * @} End of "addtogroup hooks". */ diff --git a/frontend/drupal/modules/user/user.info b/frontend/drupal/modules/user/user.info index b5a0cdcf5..01b772a10 100644 --- a/frontend/drupal/modules/user/user.info +++ b/frontend/drupal/modules/user/user.info @@ -9,7 +9,7 @@ required = TRUE configure = admin/config/people stylesheets[all][] = user.css -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/modules/user/user.module b/frontend/drupal/modules/user/user.module index 2309aa929..dfa05978c 100644 --- a/frontend/drupal/modules/user/user.module +++ b/frontend/drupal/modules/user/user.module @@ -2225,11 +2225,17 @@ function user_login_final_validate($form, &$form_state) { if (isset($form_state['flood_control_triggered'])) { if ($form_state['flood_control_triggered'] == 'user') { form_set_error('name', format_plural(variable_get('user_failed_login_user_limit', 5), 'Sorry, there has been more than one failed login attempt for this account. It is temporarily blocked. Try again later or request a new password.', 'Sorry, there have been more than @count failed login attempts for this account. It is temporarily blocked. Try again later or request a new password.', array('@url' => url('user/password')))); + module_invoke_all('user_flood_control', ip_address(), $form_state['values']['name']); } else { // We did not find a uid, so the limit is IP-based. form_set_error('name', t('Sorry, too many failed login attempts from your IP address. This IP address is temporarily blocked. Try again later or request a new password.', array('@url' => url('user/password')))); + module_invoke_all('user_flood_control', ip_address()); } + // We cannot call drupal_access_denied() here as that can result in an + // infinite loop if the login form is rendered on the 403 page (e.g. in a + // block). So add the 403 header and allow form processing to finish. + drupal_add_http_header('Status', '403 Forbidden'); } else { // Use $form_state['input']['name'] here to guarantee that we send @@ -2247,6 +2253,23 @@ function user_login_final_validate($form, &$form_state) { } } +/** + * Implements hook_user_flood_control(). + */ +function user_user_flood_control($ip, $username = FALSE) { + if (variable_get('log_user_flood_control', TRUE)) { + if (!empty($username)) { + watchdog('user', 'Flood control blocked login attempt for %user from %ip.', array( + '%user' => $username, + '%ip' => $ip + )); + } + else { + watchdog('user', 'Flood control blocked login attempt from %ip.', array('%ip' => $ip)); + } + } +} + /** * Try to validate the user's login credentials locally. * diff --git a/frontend/drupal/modules/user/user.pages.inc b/frontend/drupal/modules/user/user.pages.inc index 2a1b291b1..6f997a62e 100644 --- a/frontend/drupal/modules/user/user.pages.inc +++ b/frontend/drupal/modules/user/user.pages.inc @@ -66,6 +66,22 @@ function user_pass() { * @see user_pass_submit() */ function user_pass_validate($form, &$form_state) { + if (isset($form_state['values']['name']) && !is_scalar($form_state['values']['name'])) { + form_set_error('name', t('An illegal value has been detected. Please contact the site administrator.')); + return; + } + $user_pass_reset_ip_window = variable_get('user_pass_reset_ip_window', 3600); + // Do not allow any password reset from the current user's IP if the limit + // has been reached. Default is 50 attempts allowed in one hour. This is + // independent of the per-user limit to catch attempts from one IP to request + // resets for many different user accounts. We have a reasonably high limit + // since there may be only one apparent IP for all users at an institution. + if (!flood_is_allowed('pass_reset_ip', variable_get('user_pass_reset_ip_limit', 50), $user_pass_reset_ip_window)) { + form_set_error('name', t('Sorry, too many password reset attempts from your IP address. This IP address is temporarily blocked. Try again later or request a new password.', array('@url' => url('user/password')))); + return; + } + // Always register an per-IP event. + flood_register_event('pass_reset_ip', $user_pass_reset_ip_window); $name = trim($form_state['values']['name']); // Try to load by email. $users = user_load_multiple(array(), array('mail' => $name, 'status' => '1')); @@ -76,6 +92,19 @@ function user_pass_validate($form, &$form_state) { $account = reset($users); } if (isset($account->uid)) { + // Register user flood events based on the uid only, so they can be cleared + // when a password is reset successfully. + $identifier = $account->uid; + $user_pass_reset_user_window = variable_get('user_pass_reset_user_window', 21600); + $user_pass_reset_user_limit = variable_get('user_pass_reset_user_limit', 5); + // Don't allow password reset if the limit for this user has been reached. + // Default is to allow 5 passwords resets every 6 hours. + if (!flood_is_allowed('pass_reset_user', $user_pass_reset_user_limit, $user_pass_reset_user_window, $identifier)) { + form_set_error('name', format_plural($user_pass_reset_user_limit, 'Sorry, there has been more than one password reset attempt for this account. It is temporarily blocked. Try again later or login with your password.', 'Sorry, there have been more than @count password reset attempts for this account. It is temporarily blocked. Try again later or login with your password.', array('@url' => url('user/login')))); + return; + } + // Register a per-user event. + flood_register_event('pass_reset_user', $user_pass_reset_user_window, $identifier); form_set_value(array('#parents' => array('account')), $account, $form_state); } else { @@ -161,6 +190,8 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a // user_login_finalize() also updates the login timestamp of the // user, which invalidates further use of the one-time login link. user_login_finalize(); + // Clear any password reset flood events for this user. + flood_clear_event('pass_reset_user', $account->uid); watchdog('user', 'User %name used one-time login link at time %timestamp.', array('%name' => $account->name, '%timestamp' => $timestamp)); drupal_set_message(t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.')); // Let the user's password be changed without the current password check. diff --git a/frontend/drupal/modules/user/user.test b/frontend/drupal/modules/user/user.test index 835154b25..4c16b531c 100644 --- a/frontend/drupal/modules/user/user.test +++ b/frontend/drupal/modules/user/user.test @@ -322,7 +322,7 @@ class UserLoginTestCase extends DrupalWebTestCase { } function setUp() { - parent::setUp('user_session_test'); + parent::setUp('user_session_test', 'user_flood_test'); } /** @@ -453,12 +453,19 @@ class UserLoginTestCase extends DrupalWebTestCase { $this->drupalPost('user', $edit, t('Log in')); $this->assertNoFieldByXPath("//input[@name='pass' and @value!='']", NULL, 'Password value attribute is blank.'); if (isset($flood_trigger)) { + $this->assertResponse(403); + $user_log = db_query_range('SELECT message FROM {watchdog} WHERE type = :type ORDER BY wid DESC', 0, 1, array(':type' => 'user'))->fetchField(); + $user_flood_test_log = db_query_range('SELECT message FROM {watchdog} WHERE type = :type ORDER BY wid DESC', 0, 1, array(':type' => 'user_flood_test'))->fetchField(); if ($flood_trigger == 'user') { - $this->assertRaw(format_plural(variable_get('user_failed_login_user_limit', 5), 'Sorry, there has been more than one failed login attempt for this account. It is temporarily blocked. Try again later or request a new password.', 'Sorry, there have been more than @count failed login attempts for this account. It is temporarily blocked. Try again later or request a new password.', array('@url' => url('user/password')))); + $this->assertRaw(t('Sorry, there have been more than @count failed login attempts for this account. It is temporarily blocked. Try again later or request a new password.', array('@url' => url('user/password'), '@count' => variable_get('user_failed_login_user_limit', 5)))); + $this->assertEqual('Flood control blocked login attempt for %user from %ip.', $user_log, 'A watchdog message was logged for the login attempt blocked by flood control per user'); + $this->assertEqual('hook_user_flood_control was passed username %username and IP %ip.', $user_flood_test_log, 'hook_user_flood_control was invoked by flood control per user'); } else { // No uid, so the limit is IP-based. $this->assertRaw(t('Sorry, too many failed login attempts from your IP address. This IP address is temporarily blocked. Try again later or request a new password.', array('@url' => url('user/password')))); + $this->assertEqual('Flood control blocked login attempt from %ip.', $user_log, 'A watchdog message was logged for the login attempt blocked by flood control per IP'); + $this->assertEqual('hook_user_flood_control was passed IP %ip.', $user_flood_test_log, 'hook_user_flood_control was invoked by flood control per IP'); } } else { @@ -507,6 +514,8 @@ class UserPasswordResetTestCase extends DrupalWebTestCase { $this->drupalPost('user/password', $edit, t('E-mail new password')); // Confirm the password reset. $this->assertText(t('Further instructions have been sent to your e-mail address.'), 'Password reset instructions mailed message displayed.'); + // Ensure that flood control was not triggered. + $this->assertNoText(t('is temporarily blocked. Try again later'), 'Flood control was not triggered by single password reset.'); // Create an image field to enable an Ajax request on the user profile page. $field = array( @@ -552,6 +561,84 @@ class UserPasswordResetTestCase extends DrupalWebTestCase { $this->assertText(t('The changes have been saved.'), 'Forgotten password changed.'); } + /** + * Test user-based flood control on password reset. + */ + function testPasswordResetFloodControlPerUser() { + // Set a very low limit for testing. + variable_set('user_pass_reset_user_limit', 2); + + // Create a user. + $account = $this->drupalCreateUser(); + $this->drupalLogin($account); + $this->drupalLogout(); + + $edit = array('name' => $account->name); + + // Try 2 requests that should not trigger flood control. + for ($i = 0; $i < 2; $i++) { + $this->drupalPost('user/password', $edit, t('E-mail new password')); + // Confirm the password reset. + $this->assertText(t('Further instructions have been sent to your e-mail address.'), 'Password reset instructions mailed message displayed.'); + // Ensure that flood control was not triggered. + $this->assertNoText(t('is temporarily blocked. Try again later'), 'Flood control was not triggered by password reset.'); + } + + // A successful password reset should clear flood events. + $resetURL = $this->getResetURL(); + $this->drupalGet($resetURL); + + // Check successful login. + $this->drupalPost(NULL, NULL, t('Log in')); + $this->drupalLogout(); + + // Try 2 requests that should not trigger flood control. + for ($i = 0; $i < 2; $i++) { + $this->drupalPost('user/password', $edit, t('E-mail new password')); + // Confirm the password reset. + $this->assertText(t('Further instructions have been sent to your e-mail address.'), 'Password reset instructions mailed message displayed.'); + // Ensure that flood control was not triggered. + $this->assertNoText(t('is temporarily blocked. Try again later'), 'Flood control was not triggered by password reset.'); + } + + // The next request should trigger flood control + $this->drupalPost('user/password', $edit, t('E-mail new password')); + // Confirm the password reset was blocked. + $this->assertNoText(t('Further instructions have been sent to your e-mail address.'), 'Password reset instructions mailed message not displayed for excessive password resets.'); + // Ensure that flood control was triggered. + $this->assertText(t('Sorry, there have been more than 2 password reset attempts for this account. It is temporarily blocked.'), 'Flood control was triggered by excessive password resets for one user.'); + } + + /** + * Test IP-based flood control on password reset. + */ + function testPasswordResetFloodControlPerIp() { + // Set a very low limit for testing. + variable_set('user_pass_reset_ip_limit', 2); + + // Try 2 requests that should not trigger flood control. + for ($i = 0; $i < 2; $i++) { + $name = $this->randomName(); + $edit = array('name' => $name); + $this->drupalPost('user/password', $edit, t('E-mail new password')); + // Confirm the password reset was not blocked. Note that @name is used + // instead of %name as assertText() works with plain text not HTML. + $this->assertText(t('Sorry, @name is not recognized as a user name or an e-mail address.', array('@name' => $name)), 'User name not recognized message displayed.'); + // Ensure that flood control was not triggered. + $this->assertNoText(t('is temporarily blocked. Try again later'), 'Flood control was not triggered by password reset.'); + } + + // The next request should trigger flood control + $name = $this->randomName(); + $edit = array('name' => $name); + $this->drupalPost('user/password', $edit, t('E-mail new password')); + // Confirm the password reset was blocked early. Note that @name is used + // instead of %name as assertText() works with plain text not HTML. + $this->assertNoText(t('Sorry, @name is not recognized as a user name or an e-mail address.', array('@name' => $name)), 'User name not recognized message not displayed.'); + // Ensure that flood control was triggered. + $this->assertText(t('Sorry, too many password reset attempts from your IP address. This IP address is temporarily blocked.'), 'Flood control was triggered by excessive password resets from one IP.'); + } + /** * Test user password reset while logged in. */ diff --git a/frontend/drupal/modules/xautoload/.travis.yml b/frontend/drupal/modules/xautoload/.travis.yml new file mode 100644 index 000000000..23902b4d6 --- /dev/null +++ b/frontend/drupal/modules/xautoload/.travis.yml @@ -0,0 +1,5 @@ +language: php +php: + - 5.5 + - 5.4 + - 5.3 diff --git a/frontend/drupal/modules/xautoload/LICENSE.txt b/frontend/drupal/modules/xautoload/LICENSE.txt new file mode 100644 index 000000000..d159169d1 --- /dev/null +++ b/frontend/drupal/modules/xautoload/LICENSE.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 2 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, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/frontend/drupal/modules/xautoload/README.md b/frontend/drupal/modules/xautoload/README.md new file mode 100644 index 000000000..732a04d2a --- /dev/null +++ b/frontend/drupal/modules/xautoload/README.md @@ -0,0 +1,3 @@ + + +[![Build Status](https://travis-ci.org/donquixote/drupal-xautoload.png)](https://travis-ci.org/donquixote/drupal-xautoload) diff --git a/frontend/drupal/modules/xautoload/legacy/lib/FinderPlugin/CheckIncludePath.php b/frontend/drupal/modules/xautoload/legacy/lib/FinderPlugin/CheckIncludePath.php new file mode 100644 index 000000000..8b3e1dcb8 --- /dev/null +++ b/frontend/drupal/modules/xautoload/legacy/lib/FinderPlugin/CheckIncludePath.php @@ -0,0 +1,17 @@ +suggestFile_checkIncludePath($path); + } +} diff --git a/frontend/drupal/modules/xautoload/legacy/lib/FinderPlugin/Interface.php b/frontend/drupal/modules/xautoload/legacy/lib/FinderPlugin/Interface.php new file mode 100644 index 000000000..6890b97d2 --- /dev/null +++ b/frontend/drupal/modules/xautoload/legacy/lib/FinderPlugin/Interface.php @@ -0,0 +1,51 @@ + The class finder will transform the class name to + * "Some/Namespace/Some/Class.php" + * - The plugin was registered for the namespace "Some\Namespace". This is + * because all those exotic classes all begin with Some\Namespace\ + * -> The arguments will be: + * ($api = the API object, see below) + * $logical_base_path = "Some/Namespace/" + * $relative_path = "Some/Class.php" + * $api->getClass() gives the original class name, if we still need it. + * -> We are supposed to: + * if ($api->suggestFile('exotic/location.php')) { + * return TRUE; + * } + * + * @param InjectedApiInterface $api + * An object with a suggestFile() method. + * We are supposed to suggest files until suggestFile() returns TRUE, or we + * have no more suggestions. + * @param string $logical_base_path + * The key that this plugin was registered with. + * With trailing '/'. + * @param string $relative_path + * Second part of the canonical path, ending with '.php'. + * + * @return bool|null + * TRUE, if the file was found. + * FALSE or NULL, otherwise. + */ + function findFile($api, $logical_base_path, $relative_path); +} diff --git a/frontend/drupal/modules/xautoload/legacy/lib/InjectedAPI/hookXautoload.php b/frontend/drupal/modules/xautoload/legacy/lib/InjectedAPI/hookXautoload.php new file mode 100644 index 000000000..eb9586416 --- /dev/null +++ b/frontend/drupal/modules/xautoload/legacy/lib/InjectedAPI/hookXautoload.php @@ -0,0 +1,248 @@ +finder = $adapter->getFinder(); + } + + // Prefix stuff + // --------------------------------------------------------------------------- + + /** + * Register an additional prefix for this module. + * Note: Drupal\\ is already registered for /lib. + * + * @deprecated + * + * @param string $prefix + * The prefix. + * @param string $prefix_root_dir + * Prefix root dir. + * If $relative is TRUE, this is relative to the extension module dir. + * If $relative is FALSE, this is an absolute path. + * @param boolean $relative + * Whether or not the path is relative to the current extension dir. + */ + function prefixRoot($prefix, $prefix_root_dir = NULL, $relative = TRUE) { + $prefix_root_dir = $this->processDir($prefix_root_dir, $relative); + $this->finder->registerPrefixRoot($prefix, $prefix_root_dir); + } + + /** + * Register an additional namespace for this module. + * Note: Drupal\\ is already registered for /lib. + * + * @deprecated + * + * @param string $prefix + * The namespace + * @param string $prefix_deep_dir + * PSR-0 root dir. + * If $relative is TRUE, this is relative to the current extension dir. + * If $relative is FALSE, this is an absolute path. + * @param boolean $relative + * Whether or not the path is relative to the current extension dir. + */ + function prefixDeep($prefix, $prefix_deep_dir = NULL, $relative = TRUE) { + $prefix_deep_dir = $this->processDir($prefix_deep_dir, $relative); + $this->finder->registerPrefixDeep($prefix, $prefix_deep_dir); + } + + /** + * Legacy: Plugins were called "Handler" before. + * + * @deprecated + * + * @param string $prefix + * @param xautoload_FinderPlugin_Interface $plugin + * + * @return string + * The key under which the plugin was registered. This can later be used to + * unregister the plugin again. + */ + function prefixHandler($prefix, $plugin) { + $key = Util::randomString(); + $this->finder->registerPrefixDeep($prefix, $key, $plugin); + + return $key; + } + + /** + * Register a prefix plugin object + * + * @deprecated + * + * @param string $prefix + * @param xautoload_FinderPlugin_Interface $plugin + * + * @return string + * The key under which the plugin was registered. This can later be used to + * unregister the plugin again. + */ + function prefixPlugin($prefix, $plugin) { + $key = Util::randomString(); + $this->finder->registerPrefixDeep($prefix, $key, $plugin); + + return $key; + } + + // Namespace stuff + // --------------------------------------------------------------------------- + + /** + * Register an additional namespace for this module. + * Note: Drupal\\ is already registered for /lib. + * + * @deprecated + * + * @param string $namespace + * The namespace + * @param string $psr_0_root_dir + * PSR-0 root dir. + * If $relative is TRUE, this is relative to the current module dir. + * If $relative is FALSE, this is an absolute path. + * @param boolean $relative + * Whether or not the path is relative to the current extension dir. + */ + function namespaceRoot($namespace, $psr_0_root_dir = NULL, $relative = TRUE) { + $psr_0_root_dir = $this->processDir($psr_0_root_dir, $relative); + $this->finder->registerNamespaceRoot($namespace, $psr_0_root_dir); + } + + /** + * Register an additional namespace for this module. + * Note: Drupal\\ is already registered for /lib. + * + * @deprecated + * + * @param string $namespace + * The namespace + * @param string $namespace_deep_dir + * PSR-0 root dir. + * If $relative is TRUE, this is relative to the current extension dir. + * If $relative is FALSE, this is an absolute path. + * @param boolean $relative + * Whether or not the path is relative to the current extension dir. + */ + function namespaceDeep($namespace, $namespace_deep_dir = NULL, $relative = TRUE) { + $namespace_deep_dir = $this->processDir($namespace_deep_dir, $relative); + $this->finder->registerNamespaceDeep($namespace, $namespace_deep_dir); + } + + /** + * Register a namespace plugin object + * + * @deprecated + * + * @param string $namespace + * @param xautoload_FinderPlugin_Interface $plugin + * + * @return string + * The key under which the plugin was registered. This can later be used to + * unregister the plugin again. + */ + function namespacePlugin($namespace, $plugin) { + $key = Util::randomString(); + $this->finder->registerNamespaceDeep($namespace, $key, $plugin); + + return $key; + } + + /** + * Legacy: Plugins were called "Handler" before. + * + * @deprecated + * + * @param string $namespace + * @param xautoload_FinderPlugin_Interface $plugin + * + * @return string + * The key under which the plugin was registered. This can later be used to + * unregister the plugin again. + */ + function namespaceHandler($namespace, $plugin) { + $key = Util::randomString(); + $this->finder->registerNamespaceDeep($namespace, $key, $plugin); + + return $key; + } + + /** + * Process a given directory to make it relative to Drupal root, + * instead of relative to the current extension dir. + * + * @deprecated + * + * @param string $dir + * The directory path that we want to make absolute. + * @param boolean $relative + * If TRUE, the $dir will be transformed from relative to absolute. + * If FALSE, the $dir is assumed to already be absolute, and remain unchanged. + * + * @return string + * The modified (absolute) directory path. + */ + protected function processDir($dir, $relative) { + if (!isset($dir)) { + return $this->localDirectory . 'lib/'; + } + $dir = strlen($dir) + ? rtrim($dir, '/') . '/' + : ''; + + return $relative + ? $this->localDirectory . $dir + : $dir; + } + + /** + * Explicitly set the base for relative paths. + * + * Alias for LocalDirectoryAdapter::setLocalDirectory() + * + * @param string $dir + * New relative base path. + */ + function setExtensionDir($dir) { + $this->localDirectory = strlen($dir) + ? rtrim($dir, '/') . '/' + : ''; + } +} diff --git a/frontend/drupal/modules/xautoload/lib/Drupal/xautoload/Tests/EnvironmentSnapshotMaker.php b/frontend/drupal/modules/xautoload/lib/Drupal/xautoload/Tests/EnvironmentSnapshotMaker.php new file mode 100644 index 000000000..4355028e5 --- /dev/null +++ b/frontend/drupal/modules/xautoload/lib/Drupal/xautoload/Tests/EnvironmentSnapshotMaker.php @@ -0,0 +1,62 @@ + 'X Autoload unit test', + 'description' => 'Test the xautoload class finder.', + 'group' => 'X Autoload', + ); + } + + function setUp() { + + // drupal_load('module', 'xautoload') would register namespaces for all + // enabled modules, which is not intended for this unit test. + // Instead, we just include xautoload.early.inc. + require_once __DIR__ . '/../../../../xautoload.early.inc'; + + // Make sure we use the regular loader, not the APC one. + // Also make sure to prepend this one. Otherwise, the core class loader will + // try to load xautoload-related stuff, e.g. xautoload_Mock_* stuff, and + // will fail due to the database. + foreach (spl_autoload_functions() as $callback) { + if (is_array($callback) + && ($loader = $callback[0]) + && $loader instanceof ClassLoaderInterface + ) { + $loader->unregister(); + } + } + xautoload()->finder->register(TRUE); + + // Do the regular setUp(). + parent::setUp(); + } + + function testAutoloadStackOrder() { + $expected = array( + 'Drupal\\xautoload\\ClassFinder\\ClassFinder->loadClass()', + /* @see _drupal_bootstrap_database() */ + 'drupal_autoload_class', + 'drupal_autoload_interface', + /* @see simpletest_classloader_register() */ + '_simpletest_autoload_psr4_psr0', + ); + + $actual = array(); + foreach (spl_autoload_functions() as $callback) { + $actual[] = Util::callbackToString($callback); + } + + $this->assertEqualBlock($expected, $actual, "SPL autoload stack:"); + } + + function testNamespaces() { + + // Prepare the class finder. + $finder = new ClassFinder(); + $finder->add('Drupal\\ex_ample', 'sites/all/modules/contrib/ex_ample/lib-psr0'); + $finder->addPsr4('Drupal\\ex_ample', 'sites/all/modules/contrib/ex_ample/lib-psr4'); + + // Test class finding for 'Drupal\\ex_ample\\Abc_Def'. + $this->assertFinderSuggestions($finder, 'Drupal\\ex_ample\\Abc_Def', array( + // Class finder is expected to suggest these files, in the exact order, + // until one of them is accepted. + array('suggestFile', 'sites/all/modules/contrib/ex_ample/lib-psr0/Drupal/ex_ample/Abc/Def.php'), + array('suggestFile', 'sites/all/modules/contrib/ex_ample/lib-psr4/Abc_Def.php'), + )); + } + + function testPrefixes() { + + // Prepare the class finder. + $finder = new ClassFinder(); + $finder->registerPrefixDeep('ex_ample', 'sites/all/modules/contrib/ex_ample/lib'); + $finder->registerPrefixRoot('ex_ample', 'sites/all/modules/contrib/ex_ample/vendor'); + + // Test class finding for 'ex_ample_Abc_Def'. + $this->assertFinderSuggestions($finder, 'ex_ample_Abc_Def', array( + // Class finder is expected to suggest these files, in the exact order, + // until one of them is accepted. + array('suggestFile', 'sites/all/modules/contrib/ex_ample/lib/Abc/Def.php'), + array('suggestFile', 'sites/all/modules/contrib/ex_ample/vendor/ex/ample/Abc/Def.php'), + )); + } + + /** + * @param ClassFinder $finder + * @param string $class + * @param array $expectedSuggestions + * + * @return bool + * Result of the assertion + */ + protected function assertFinderSuggestions($finder, $class, array $expectedSuggestions) { + $success = TRUE; + for ($iAccept = 0; $iAccept < count($expectedSuggestions); ++$iAccept) { + list($method_name, $file) = $expectedSuggestions[$iAccept]; + $api = new CollectFilesInjectedApi($class, $method_name, $file); + $finder->apiFindFile($api, $class); + $suggestions = $api->getSuggestions(); + $expected = array_slice($expectedSuggestions, 0, $iAccept + 1); + $success = $success && $this->assertEqualBlock($expected, $suggestions, "Finder suggestions for class $class:"); + } + return $success; + } + + /** + * @param mixed $expected + * @param mixed $actual + * @param string $label + * + * @return bool + * Result of the assertion + */ + protected function assertEqualBlock($expected, $actual, $label) { + $label .= '
    ' . + 'Expected:
    ' . var_export($expected, TRUE) . '
    ' . + 'Actual:
    ' . var_export($actual, TRUE) . '
    '; + return $this->assertEqual($expected, $actual, $label); + } +} diff --git a/frontend/drupal/modules/xautoload/lib/Drupal/xautoload/Tests/XAutoloadWebTestCase.php b/frontend/drupal/modules/xautoload/lib/Drupal/xautoload/Tests/XAutoloadWebTestCase.php new file mode 100644 index 000000000..3d80f4bd4 --- /dev/null +++ b/frontend/drupal/modules/xautoload/lib/Drupal/xautoload/Tests/XAutoloadWebTestCase.php @@ -0,0 +1,264 @@ + 'X Autoload web test', + 'description' => 'Test xautoload class loading for an example module.', + 'group' => 'X Autoload', + ); + } + + /** + * {@inheritdoc} + */ + function setUp() { + parent::setUp(); + } + + /** + * + */ + function testNoCache() { + $this->xautoloadTestWithCacheTypes(array(), TRUE); + } + + /** + * + */ + function testApcCache() { + $cache_types = array( + 'apc' => 'apc', + 'xcache' => 'xcache', + 'wincache' => 'wincache', + ); + $this->xautoloadTestWithCacheTypes($cache_types, TRUE); + } + + /** + * @param array $cache_types + * The autoloader modes that are enabled, e.g. + * array('apc' => 'apc', 'xcache' => 'xcache') + * @param bool $cache_lazy + * Whether the "lazy" mode is enabled. + */ + protected function xautoloadTestWithCacheTypes($cache_types, $cache_lazy) { + + variable_set(XAUTOLOAD_VARNAME_CACHE_TYPES, $cache_types); + $this->pass("Set cache types: " . var_export($cache_types, TRUE)); + + variable_set(XAUTOLOAD_VARNAME_CACHE_LAZY, $cache_lazy); + $this->pass("Set cache lazy mode: " . var_export($cache_lazy, TRUE)); + + // Enable xautoload. + module_enable(array('xautoload'), FALSE); + + // At this time the xautoload_cache_mode setting is not in effect yet, + // so we have to clear old cached values from APC cache. + xautoload()->cacheManager->renewCachePrefix(); + + module_enable(array( + 'xautoload_test_1', + 'xautoload_test_2', + 'xautoload_test_3', + 'xautoload_test_4', + 'xautoload_test_5', + ), FALSE); + menu_rebuild(); + + foreach (array( + 'xautoload_test_1' => array('Drupal\xautoload_test_1\ExampleClass'), + 'xautoload_test_2' => array('xautoload_test_2_ExampleClass'), + 'xautoload_test_3' => array('Drupal\xautoload_test_3\ExampleClass'), + ) as $module => $classes) { + $classes_on_include = in_array($module, array('xautoload_test_2', 'xautoload_test_3')); + $this->xautoloadModuleEnabled($module, $classes, $classes_on_include); + $this->xautoloadModuleCheckJson($module, $cache_types, $cache_lazy, $classes); + } + } + + /** + * @param string $module + * @param string[] $classes + * @param bool $classes_on_include + */ + protected function xautoloadModuleEnabled($module, $classes, $classes_on_include) { + + EnvironmentSnapshotMaker::takeSnapshot($module, 'later', $classes); + + $all = EnvironmentSnapshotMaker::getSnapshots($module); + + foreach ($all as $phase => $observations) { + $when = ($phase === 'early') + ? 'on drupal_load() during module_enable()' + : (($phase === 'later') + ? 'after hook_modules_enabled()' + : 'at an undefined time' + ); + + // Test the classes of the example module. + foreach ($classes as $class) { + // Test that the class was already found in $phase. + $this->assertTrue(isset($observations['class_exists'][$class]), "Class $class was checked $when."); + if ($classes_on_include || $phase !== 'early') { + $this->assertTrue($observations['class_exists'][$class], "Class $class was found $when."); + } + else { + $this->assertFalse($observations['class_exists'][$class], "Class $class cannot be found $when."); + } + } + } + } + + /** + * @param string $module + * @param array $cache_types + * The autoloader modes that are enabled, e.g. + * array('apc' => 'apc', 'xcache' => 'xcache') + * @param bool $cache_lazy + * Whether the "lazy" mode is enabled. + * @param string[] $classes + */ + protected function xautoloadModuleCheckJson($module, $cache_types, $cache_lazy, $classes) { + + $path = "$module.json"; + $json = $this->drupalGet($path); + $all = json_decode($json, TRUE); + + if (!is_array($all) || empty($all)) { + $this->fail("$path must return a non-empty json array."); + return; + } + + foreach ($all as $phase => $observations) { + + $when = ($phase === 'early') + ? 'on early bootstrap' + : (($phase === 'boot') + ? 'during hook_boot()' + : 'at an undefined time' + ); + + $this->xautoloadCheckTestEnvironment($observations, $cache_types, $cache_lazy, $when); + + // Test the classes of the example module. + foreach ($classes as $class) { + // Test that the class was already found in $phase. + $this->assertTrue($observations['class_exists'][$class], "Class $class was found $when."); + } + } + } + + /** + * @param array $observations + * @param array $cache_types + * The autoloader modes that are enabled, e.g. + * array('apc' => 'apc', 'xcache' => 'xcache') + * @param bool $lazy + * Whether the "lazy" mode is enabled. + * @param $when + */ + protected function xautoloadCheckTestEnvironment($observations, $cache_types, $lazy, $when) { + + // Check early-bootstrap variables. + $label = "$when: xautoload_cache_types:"; + $this->assertEqualBlock($cache_types, $observations[XAUTOLOAD_VARNAME_CACHE_TYPES], $label); + + $label = "$when: xautoload_cache_lazy:"; + $this->assertEqualInline($lazy, $observations[XAUTOLOAD_VARNAME_CACHE_LAZY], $label); + + // Check registered class loaders. + $expected = $this->expectedAutoloadStackOrder($cache_types); + $actual = $observations['spl_autoload_functions']; + $label = "$when: spl autoload stack:"; + $this->assertEqualBlock($expected, $actual, $label); + } + + /** + * @param string $cache_types + * The autoloader modes that are enabled, e.g. + * array('apc' => 'apc', 'xcache' => 'xcache') + * + * @return string[] + * Expected order of class loaders on the spl autoload stack for the given + * autoloader mode. Each represented by a string. + */ + protected function expectedAutoloadStackOrder($cache_types) { + + if (!empty($cache_types['apc']) && extension_loaded('apc') && function_exists('apc_store')) { + $loader = 'Drupal\xautoload\ClassLoader\ApcClassLoader->loadClass()'; + } + elseif (!empty($cache_types['wincache']) && extension_loaded('wincache') && function_exists('wincache_ucache_get')) { + $loader = 'Drupal\xautoload\ClassLoader\WinCacheClassLoader->loadClass()'; + } + elseif (!empty($cache_types['xcache']) && extension_loaded('Xcache') && function_exists('xcache_get')) { + $loader = 'Drupal\xautoload\ClassLoader\XCacheClassLoader->loadClass()'; + } + else { + $loader = 'Drupal\xautoload\ClassFinder\ClassFinder->loadClass()'; + } + + return array( + 'drupal_autoload_class', + 'drupal_autoload_interface', + $loader, + ); + } + + /** + * Assert that a module is disabled. + * + * @param string $module + */ + protected function assertModuleDisabled($module) { + $this->assertFalse(module_exists($module), "Module $module is disabled."); + } + + /** + * Assert that a module is enabled. + * + * @param string $module + */ + protected function assertModuleEnabled($module) { + $this->assertTrue(module_exists($module), "Module $module is enabled."); + } + + /** + * Assert that a class is defined. + * + * @param string $class + */ + protected function assertClassExists($class) { + $this->assertTrue(class_exists($class), "Class '$class' must exist."); + } + + /** + * @param mixed $expected + * @param mixed $actual + * @param string $label + */ + protected function assertEqualBlock($expected, $actual, $label) { + $label .= + 'Expected:
    ' . var_export($expected, TRUE) . '
    ' . + 'Actual:
    ' . var_export($actual, TRUE) . '
    '; + $this->assertEqual($expected, $actual, $label); + } + + /** + * @param mixed $expected + * @param mixed $actual + * @param string $label + */ + protected function assertEqualInline($expected, $actual, $label) { + $label .= '
    ' . + 'Expected: ' . var_export($expected, TRUE) . '
    ' . + 'Actual: ' . var_export($actual, TRUE) . ''; + $this->assertEqual($expected, $actual, $label); + } +} diff --git a/frontend/drupal/modules/xautoload/phpunit.xml.dist b/frontend/drupal/modules/xautoload/phpunit.xml.dist new file mode 100644 index 000000000..4acf8cc6d --- /dev/null +++ b/frontend/drupal/modules/xautoload/phpunit.xml.dist @@ -0,0 +1,19 @@ + + + + + + ./tests/src + + + diff --git a/frontend/drupal/modules/xautoload/src/Adapter/ClassFinderAdapter.php b/frontend/drupal/modules/xautoload/src/Adapter/ClassFinderAdapter.php new file mode 100644 index 000000000..e2904337d --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/Adapter/ClassFinderAdapter.php @@ -0,0 +1,287 @@ +finder = $finder; + $this->prefixMap = $finder->getPrefixMap(); + $this->namespaceMap = $finder->getNamespaceMap(); + $this->defaultBehavior = new DefaultDirectoryBehavior(); + $this->psr0Behavior = new Psr0DirectoryBehavior(); + $this->classMapGenerator = $classmap_generator; + } + + /** + * @return \Drupal\xautoload\ClassFinder\GenericPrefixMap + */ + function getNamespaceMap() { + return $this->namespaceMap; + } + + /** + * @return GenericPrefixMap + */ + function getPrefixMap() { + return $this->prefixMap; + } + + /** + * @return ClassMapGeneratorInterface + */ + function getClassmapGenerator() { + return $this->classMapGenerator; + } + + /** + * @return ClassMapGeneratorInterface + */ + function getFinder() { + return $this->finder; + } + + // Discovery + // --------------------------------------------------------------------------- + + /** + * {@inheritdoc} + */ + function addClassmapSources($paths) { + $map = $this->classMapGenerator->wildcardPathsToClassmap($paths); + $this->addClassMap($map); + } + + // Composer tools + // --------------------------------------------------------------------------- + + /** + * {@inheritdoc} + */ + function composerJson($file) { + $json = ComposerJson::createFromFile($file); + $json->writeToAdapter($this); + } + + /** + * {@inheritdoc} + */ + function composerDir($dir) { + $dir = ComposerDir::create($dir); + $dir->writeToAdapter($this); + } + + // multiple PSR-0 / PSR-4 + // --------------------------------------------------------------------------- + + /** + * {@inheritdoc} + */ + function addMultiplePsr0(array $prefixes) { + $namespace_map = array(); + $prefix_map = array(); + foreach ($prefixes as $prefix => $paths) { + if (FALSE === strpos($prefix, '\\')) { + $logical_base_path = Util::prefixLogicalPath($prefix); + foreach ((array) $paths as $root_path) { + $deep_path = strlen($root_path) + ? rtrim($root_path, '/') . '/' . $logical_base_path + : $logical_base_path; + $prefix_map[$logical_base_path][$deep_path] = $this->defaultBehavior; + } + } + $logical_base_path = Util::namespaceLogicalPath($prefix); + foreach ((array) $paths as $root_path) { + $deep_path = strlen($root_path) + ? rtrim($root_path, '/') . '/' . $logical_base_path + : $logical_base_path; + $namespace_map[$logical_base_path][$deep_path] = $this->psr0Behavior; + } + } + if (!empty($prefix_map)) { + $this->prefixMap->registerDeepPaths($prefix_map); + } + $this->namespaceMap->registerDeepPaths($namespace_map); + } + + /** + * {@inheritdoc} + */ + function addMultiplePsr4(array $map) { + $namespace_map = array(); + foreach ($map as $namespace => $paths) { + $logical_base_path = Util::namespaceLogicalPath($namespace); + foreach ($paths as $root_path) { + $deep_path = strlen($root_path) + ? rtrim($root_path, '/') . '/' + : ''; + $namespace_map[$logical_base_path][$deep_path] = $this->defaultBehavior; + } + } + $this->namespaceMap->registerDeepPaths($namespace_map); + } + + // Composer ClassLoader + // --------------------------------------------------------------------------- + + /** + * {@inheritdoc} + */ + function addClassMap(array $classMap) { + $this->finder->registerClasses($classMap); + } + + /** + * {@inheritdoc} + */ + function add($prefix, $paths) { + if (FALSE === strpos($prefix, '\\')) { + // Due to the ambiguity of PSR-0, this could be either PEAR-like or namespaced. + $logical_base_path = Util::prefixLogicalPath($prefix); + foreach ((array) $paths as $root_path) { + $deep_path = strlen($root_path) + ? rtrim($root_path, '/') . '/' . $logical_base_path + : $logical_base_path; + $this->prefixMap->registerDeepPath( + $logical_base_path, + $deep_path, + $this->defaultBehavior); + } + } + // Namespaced PSR-0 + $logical_base_path = Util::namespaceLogicalPath($prefix); + foreach ((array) $paths as $root_path) { + $deep_path = strlen($root_path) + ? rtrim($root_path, '/') . '/' . $logical_base_path + : $logical_base_path; + $this->namespaceMap->registerDeepPath( + $logical_base_path, + $deep_path, + $this->psr0Behavior); + } + } + + /** + * {@inheritdoc} + */ + function addPsr0($prefix, $paths) { + $this->add($prefix, $paths); + } + + /** + * {@inheritdoc} + */ + function addPsr4($prefix, $paths) { + // Namespaced PSR-4 + $logical_base_path = Util::namespaceLogicalPath($prefix); + foreach ((array) $paths as $deep_path) { + $deep_path = strlen($deep_path) + ? rtrim($deep_path, '/') . '/' + : ''; + $this->namespaceMap->registerDeepPath( + $logical_base_path, + $deep_path, + $this->defaultBehavior); + } + } + + // More convenience stuff + // --------------------------------------------------------------------------- + + /** + * {@inheritdoc} + */ + function addNamespacePsr0($prefix, $paths) { + $logical_base_path = Util::namespaceLogicalPath($prefix); + foreach ((array) $paths as $root_path) { + $deep_path = strlen($root_path) + ? rtrim($root_path, '/') . '/' . $logical_base_path + : $logical_base_path; + $this->namespaceMap->registerDeepPath( + $logical_base_path, + $deep_path, + $this->psr0Behavior); + } + } + + /** + * {@inheritdoc} + */ + function addPear($prefix, $paths) { + $logical_base_path = Util::prefixLogicalPath($prefix); + foreach ((array) $paths as $root_path) { + $deep_path = strlen($root_path) + ? rtrim($root_path, '/') . '/' . $logical_base_path + : $logical_base_path; + $this->prefixMap->registerDeepPath( + $logical_base_path, + $deep_path, + $this->defaultBehavior); + } + } + + /** + * {@inheritdoc} + */ + function addPearFlat($prefix, $paths) { + $logical_base_path = Util::prefixLogicalPath($prefix); + foreach ((array) $paths as $deep_path) { + $deep_path = strlen($deep_path) ? (rtrim($deep_path, '/') . '/') : ''; + $this->prefixMap->registerDeepPath( + $logical_base_path, + $deep_path, + $this->defaultBehavior + ); + } + } +} diff --git a/frontend/drupal/modules/xautoload/src/Adapter/ClassFinderAdapterInterface.php b/frontend/drupal/modules/xautoload/src/Adapter/ClassFinderAdapterInterface.php new file mode 100644 index 000000000..0fdd0d025 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/Adapter/ClassFinderAdapterInterface.php @@ -0,0 +1,56 @@ +system = $system; + $this->finder = $finder; + $this->namespaceMap = $finder->getNamespaceMap(); + $this->prefixMap = $finder->getPrefixMap(); + foreach (array('module', 'theme') as $extension_type) { + $this->namespaceBehaviors[$extension_type] = new DrupalExtensionNamespaceFinderPlugin( + $extension_type, + $this->namespaceMap, + $this->prefixMap, + $this->system); + $this->prefixBehaviors[$extension_type] = new DrupalExtensionUnderscoreFinderPlugin( + $extension_type, + $this->namespaceMap, + $this->prefixMap, + $this->system); + } + $this->defaultBehavior = new DefaultDirectoryBehavior(); + } + + /** + * Register lazy plugins for enabled Drupal modules and themes, assuming that + * we don't know yet whether they use PSR-0, PEAR-Flat, or none of these. + * + * @param string[] $extensions + * An array where the keys are extension names, and the values are extension + * types like 'module' or 'theme'. + */ + function registerExtensions(array $extensions) { + + $prefix_map = array(); + $namespace_map = array(); + foreach ($extensions as $name => $type) { + if (empty($this->namespaceBehaviors[$type])) { + // Unsupported extension type, e.g. "theme_engine". + // This can happen if a site was upgraded from Drupal 6. + // See https://drupal.org/comment/8503979#comment-8503979 + continue; + } + if (!empty($this->registered[$name])) { + // The extension has already been processed. + continue; + } + $namespace_map['Drupal/' . $name . '/'][$name] = $this->namespaceBehaviors[$type]; + $prefix_map[str_replace('_', '/', $name) . '/'][$name] = $this->prefixBehaviors[$type]; + $this->registered[$name] = TRUE; + } + $this->namespaceMap->registerDeepPaths($namespace_map); + $this->prefixMap->registerDeepPaths($prefix_map); + } + + /** + * Register lazy plugins for a given extension, assuming that we don't know + * yet whether it uses PSR-0, PEAR-Flat, or none of these. + * + * @param string $name + * @param string $type + */ + function registerExtension($name, $type) { + if (!empty($this->registered[$name])) { + // The extension has already been processed. + return; + } + $this->namespaceMap->registerDeepPath('Drupal/' . $name . '/', $name, $this->namespaceBehaviors[$type]); + $this->prefixMap->registerDeepPath(str_replace('_', '/', $name) . '/', $name, $this->prefixBehaviors[$type]); + $this->registered[$name] = TRUE; + } + + /** + * Register PSR-4 directory for an extension. + * Override previous settings for this extension. + * + * @param string $name + * The extension name. + * @param string $extension_dir + * The directory of the extension. + * @param string $subdir + * The PSR-4 base directory, relative to the extension directory. + * E.g. 'lib' or 'src'. + */ + function registerExtensionPsr4($name, $extension_dir, $subdir) { + if (!empty($this->registered[$name])) { + if ('psr-4' === $this->registered[$name]) { + // It already happened. + return; + } + // Unregister the lazy plugins. + $this->namespaceMap->unregisterDeepPath('Drupal/' . $name . '/', $name); + $this->prefixMap->unregisterDeepPath(str_replace('_', '/', $name) . '/', $name); + } + + $dir = strlen($subdir) + ? $extension_dir . '/' . trim($subdir, '/') . '/' + : $extension_dir . '/'; + $this->namespaceMap->registerDeepPath('Drupal/' . $name . '/', $dir, $this->defaultBehavior); + + // Re-add the PSR-0 test directory, for consistency's sake. + if (is_dir($psr0_tests_dir = $extension_dir . '/lib/Drupal/' . $name . '/Tests')) { + $this->namespaceMap->registerDeepPath('Drupal/' . $name . '/Tests/', $psr0_tests_dir, $this->defaultBehavior); + } + } +} diff --git a/frontend/drupal/modules/xautoload/src/Adapter/LocalDirectoryAdapter.php b/frontend/drupal/modules/xautoload/src/Adapter/LocalDirectoryAdapter.php new file mode 100644 index 000000000..6949214c4 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/Adapter/LocalDirectoryAdapter.php @@ -0,0 +1,278 @@ +finder, $adapter->getClassmapGenerator()); + $this->master = $adapter; + $this->localDirectory = strlen($localDirectory) + ? rtrim($localDirectory, '/') . '/' + : ''; + } + + /** + * Returns an adapter object that is not relative to a local directory. + * + * @return ClassFinderAdapter + */ + function absolute() { + return $this->master; + } + + // Discovery + // --------------------------------------------------------------------------- + + /** + * Adds source paths for classmap discovery. + * + * The classmap for each source will be cached between requests. + * A "clear all caches" will trigger a rescan. + * + * @param string[] $paths + * File paths or wildcard paths for class discovery. + * @param bool $relative + * If TRUE, the paths will be relative to $this->localDirectory. + */ + function addClassmapSources($paths, $relative = TRUE) { + $relative && $this->prependToPaths($paths); + $this->master->addClassmapSources($paths); + } + + // Composer tools + // --------------------------------------------------------------------------- + + /** + * Scans a composer.json file provided by a Composer package. + * + * @param string $file + * @param bool $relative + * If TRUE, the paths will be relative to $this->localDirectory. + * + * @throws \Exception + */ + function composerJson($file, $relative = TRUE) { + $relative && $file = $this->localDirectory . $file; + $json = ComposerJson::createFromFile($file); + $json->writeToAdapter($this->master); + } + + /** + * Scans a directory containing Composer-generated autoload files. + * + * @param string $dir + * Directory to look for Composer-generated files. Typically this is the + * ../vendor/composer dir. + * @param bool $relative + * If TRUE, the paths will be relative to $this->localDirectory. + */ + function composerDir($dir, $relative = TRUE) { + $relative && $dir = $this->localDirectory . $dir; + $dir = ComposerDir::create($dir); + $dir->writeToAdapter($this->master); + } + + // multiple PSR-0 / PSR-4 + // --------------------------------------------------------------------------- + + /** + * Adds multiple PSR-0 prefixes. + * + * @param array $prefixes + * Each array key is a PSR-0 prefix, e.g. "Acme\\FooPackage\\". + * Each array value is either a PSR-0 base directory or an array of PSR-0 + * base directories. + * @param bool $relative + * If TRUE, the paths will be relative to $this->localDirectory. + */ + function addMultiplePsr0(array $prefixes, $relative = TRUE) { + $relative && $this->prependMultiple($prefixes); + $this->master->addMultiplePsr0($prefixes); + } + + /** + * Adds multiple PSR-4 namespaces. + * + * @param array $map + * Each array key is a namespace, e.g. "Acme\\FooPackage\\". + * Each array value is either a PSR-4 base directory or an array of PSR-4 + * base directories. + * @param bool $relative + * If TRUE, the paths will be relative to $this->localDirectory. + */ + function addMultiplePsr4(array $map, $relative = TRUE) { + $relative && $this->prependMultiple($map); + $this->master->addMultiplePsr4($map); + } + + // Composer ClassLoader + // --------------------------------------------------------------------------- + + /** + * Registers an array ("map") of classes to file paths. + * + * @param array $classMap + * The map of classes to file paths. + * @param bool $relative + * If TRUE, the paths will be relative to $this->localDirectory. + */ + function addClassMap(array $classMap, $relative = TRUE) { + $relative && $this->prependToPaths($classMap); + $this->master->addClassMap($classMap); + } + + /** + * Adds a PSR-0 style prefix. Alias for ->addPsr0(). + * + * @param string $prefix + * @param string|\string[] $paths + * @param bool $relative + * If TRUE, the paths will be relative to $this->localDirectory. + */ + function add($prefix, $paths, $relative = TRUE) { + $relative && $this->prependToPaths($paths); + $this->master->add($prefix, $paths); + } + + /** + * Adds a PSR-0 style prefix. Alias for ->add(). + * + * @param string $prefix + * @param string|\string[] $paths + * @param bool $relative + * If TRUE, the paths will be relative to $this->localDirectory. + */ + function addPsr0($prefix, $paths, $relative = TRUE) { + $relative && $this->prependToPaths($paths); + $this->master->add($prefix, $paths); + } + + /** + * Adds a PSR-4 style namespace. + * + * @param string $prefix + * @param string|\string[] $paths + * @param bool $relative + * If TRUE, the paths will be relative to $this->localDirectory. + */ + function addPsr4($prefix, $paths, $relative = TRUE) { + $relative && $this->prependToPaths($paths); + $this->master->addPsr4($prefix, $paths); + } + + // More convenience stuff + // --------------------------------------------------------------------------- + + /** + * Adds a PSR-0 style namespace. + * + * This will assume that we are really dealing with a namespace, even if it + * has no '\\' included. + * + * @param string $prefix + * @param string|\string[] $paths + * @param bool $relative + * If TRUE, the paths will be relative to $this->localDirectory. + */ + function addNamespacePsr0($prefix, $paths, $relative = TRUE) { + $relative && $this->prependToPaths($paths); + $this->master->addNamespacePsr0($prefix, $paths); + } + + /** + * Adds a PEAR-like prefix. + * + * This will assume with no further checks that $prefix contains no namespace + * separator. + * + * @param string $prefix + * The prefix, e.g. 'Acme_FooPackage_' + * @param string|string[] $paths + * An array of paths, or one specific path. + * E.g. 'lib' for $relative = TRUE, + * or 'sites/all/libraries/AcmeFooPackage/lib' for $relative = FALSE. + * @param bool $relative + * If TRUE, the paths will be relative to $this->localDirectory. + */ + function addPear($prefix, $paths, $relative = TRUE) { + $relative && $this->prependToPaths($paths); + $this->master->addPear($prefix, $paths); + } + + /** + * Adds a prefix similar to PEAR, but with flat directories. + * + * This will assume with no further checks that $prefix contains no namespace + * separator. + * + * @param string $prefix + * The prefix, e.g. 'Acme_FooPackage_' + * @param string|string[] $paths + * An array of paths, or one specific path. + * E.g. 'lib' for $relative = TRUE, + * or 'sites/all/libraries/AcmeFooPackage/lib' for $relative = FALSE. + * @param bool $relative + * If TRUE, the paths will be relative to $this->localDirectory. + */ + function addPearFlat($prefix, $paths, $relative = TRUE) { + $relative && $this->prependToPaths($paths); + $this->master->addPearFlat($prefix, $paths); + } + + // Relative path handling + // --------------------------------------------------------------------------- + + /** + * Prepends $this->localDirectory to a number of paths. + * + * @param array $map + */ + protected function prependMultiple(array &$map) { + foreach ($map as &$paths) { + $paths = (array) $paths; + foreach ($paths as &$path) { + $path = $this->localDirectory . $path; + } + } + } + + /** + * Prepends $this->localDirectory to a number of paths. + * + * @param string|string[] &$paths + */ + protected function prependToPaths(&$paths) { + if (!is_array($paths)) { + $paths = $this->localDirectory . $paths; + } + else { + foreach ($paths as &$path) { + $path = $this->localDirectory . $path; + } + } + } +} diff --git a/frontend/drupal/modules/xautoload/src/CacheManager/CacheManager.php b/frontend/drupal/modules/xautoload/src/CacheManager/CacheManager.php new file mode 100644 index 000000000..633adb827 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/CacheManager/CacheManager.php @@ -0,0 +1,68 @@ +prefix = $prefix; + $this->system = $system; + } + + /** + * This method has side effects, so it is not the constructor. + * + * @param \Drupal\xautoload\DrupalSystem\DrupalSystemInterface $system + * + * @return CacheManager + */ + static function create(DrupalSystemInterface $system) { + $prefix = $system->variableGet(XAUTOLOAD_VARNAME_CACHE_PREFIX, NULL); + $manager = new self($prefix, $system); + if (empty($prefix)) { + $manager->renewCachePrefix(); + } + return $manager; + } + + /** + * @param CacheManagerObserverInterface $observer + */ + function observeCachePrefix($observer) { + $observer->setCachePrefix($this->prefix); + $this->observers[] = $observer; + } + + /** + * Renew the cache prefix, save it, and notify all observers. + */ + function renewCachePrefix() { + $this->prefix = Util::randomString(); + $this->system->variableSet(XAUTOLOAD_VARNAME_CACHE_PREFIX, $this->prefix); + foreach ($this->observers as $observer) { + $observer->setCachePrefix($this->prefix); + } + } +} diff --git a/frontend/drupal/modules/xautoload/src/CacheManager/CacheManagerObserverInterface.php b/frontend/drupal/modules/xautoload/src/CacheManager/CacheManagerObserverInterface.php new file mode 100644 index 000000000..4d13554e0 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/CacheManager/CacheManagerObserverInterface.php @@ -0,0 +1,14 @@ +loader = $loader; + } + + /** + * {@inheritdoc} + */ + function cacheMiss($finder) { + $this->loader->setFinder($finder); + } + +} diff --git a/frontend/drupal/modules/xautoload/src/CacheMissObserver/CacheMissObserverInterface.php b/frontend/drupal/modules/xautoload/src/CacheMissObserver/CacheMissObserverInterface.php new file mode 100644 index 000000000..bd1d21973 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/CacheMissObserver/CacheMissObserverInterface.php @@ -0,0 +1,29 @@ +prefixMap = new GenericPrefixMap('_'); + $this->namespaceMap = new GenericPrefixMap('\\'); + $this->defaultBehavior = new DefaultDirectoryBehavior(); + $this->psr0Behavior = new Psr0DirectoryBehavior(); + } + + /** + * {@inheritdoc} + */ + function getPrefixMap() { + return $this->prefixMap; + } + + /** + * {@inheritdoc} + */ + function getNamespaceMap() { + return $this->namespaceMap; + } + + // Composer compatibility + // --------------------------------------------------------------------------- + + /** + * {@inheritdoc} + */ + function addClassMap(array $classMap) { + $this->registerClasses($classMap); + } + + /** + * {@inheritdoc} + */ + function add($prefix, $paths) { + if (FALSE === strpos($prefix, '\\')) { + // Due to the ambiguity of PSR-0, this could be either PEAR-like or namespaced. + $logical_base_path = Util::prefixLogicalPath($prefix); + foreach ((array) $paths as $root_path) { + $deep_path = strlen($root_path) + ? rtrim($root_path, '/') . '/' . $logical_base_path + : $logical_base_path; + $this->prefixMap->registerDeepPath( + $logical_base_path, + $deep_path, + $this->defaultBehavior); + } + } + // Namespaced PSR-0 + $logical_base_path = Util::namespaceLogicalPath($prefix); + foreach ((array) $paths as $root_path) { + $deep_path = strlen($root_path) + ? rtrim($root_path, '/') . '/' . $logical_base_path + : $logical_base_path; + $this->namespaceMap->registerDeepPath( + $logical_base_path, + $deep_path, + $this->psr0Behavior); + } + } + + /** + * {@inheritdoc} + */ + function addPsr0($prefix, $paths) { + $this->add($prefix, $paths); + } + + /** + * {@inheritdoc} + */ + function addPsr4($prefix, $paths) { + // Namespaced PSR-4 + $logical_base_path = Util::namespaceLogicalPath($prefix); + foreach ((array) $paths as $deep_path) { + $deep_path = strlen($deep_path) + ? rtrim($deep_path, '/') . '/' + : ''; + $this->namespaceMap->registerDeepPath( + $logical_base_path, + $deep_path, + $this->defaultBehavior); + } + } + + // More convenience stuff + // --------------------------------------------------------------------------- + + /** + * {@inheritdoc} + */ + function addNamespacePsr0($prefix, $paths) { + $logical_base_path = Util::namespaceLogicalPath($prefix); + foreach ((array) $paths as $root_path) { + $deep_path = strlen($root_path) + ? rtrim($root_path, '/') . '/' . $logical_base_path + : $logical_base_path; + $this->namespaceMap->registerDeepPath( + $logical_base_path, + $deep_path, + $this->psr0Behavior); + } + } + + /** + * {@inheritdoc} + */ + function addPear($prefix, $paths) { + $logical_base_path = Util::prefixLogicalPath($prefix); + foreach ((array) $paths as $root_path) { + $deep_path = strlen($root_path) + ? rtrim($root_path, '/') . '/' . $logical_base_path + : $logical_base_path; + $this->prefixMap->registerDeepPath( + $logical_base_path, + $deep_path, + $this->defaultBehavior); + } + } + + /** + * {@inheritdoc} + */ + function addPearFlat($prefix, $paths) { + $logical_base_path = Util::prefixLogicalPath($prefix); + foreach ((array) $paths as $deep_path) { + $deep_path = strlen($deep_path) + ? (rtrim($deep_path, '/') . '/') + : ''; + $this->prefixMap->registerDeepPath( + $logical_base_path, + $deep_path, + $this->defaultBehavior + ); + } + } + + // Class map stuff + // --------------------------------------------------------------------------- + + /** + * {@inheritdoc} + */ + function registerClass($class, $file_path) { + $this->classes[$class][$file_path] = TRUE; + } + + /** + * {@inheritdoc} + */ + function registerClasses($classes) { + foreach ($classes as $class => $file_path) { + $this->classes[$class][$file_path] = TRUE; + } + } + + // Prefix stuff + // --------------------------------------------------------------------------- + + /** + * {@inheritdoc} + */ + function registerPrefixRoot($prefix, $root_path, $behavior = NULL) { + if (!isset($behavior)) { + $behavior = $this->defaultBehavior; + } + $logical_base_path = Util::prefixLogicalPath($prefix); + $deep_path = strlen($root_path) + ? rtrim($root_path, '/') . '/' . $logical_base_path + : $logical_base_path; + $this->prefixMap->registerDeepPath( + $logical_base_path, + $deep_path, + $behavior); + + if (strlen($prefix)) { + // We assume that the class named $prefix is also found at this path. + $filepath = substr($deep_path, 0, -1) . '.php'; + $this->registerClass($prefix, $filepath); + } + } + + /** + * {@inheritdoc} + */ + function registerPrefixesRoot($map, $behavior = NULL) { + if (!isset($behavior)) { + $behavior = $this->defaultBehavior; + } + $deep_map = array(); + foreach ($map as $prefix => $root_path) { + $logical_base_path = Util::prefixLogicalPath($prefix); + $deep_path = strlen($root_path) + ? rtrim($root_path, '/') . '/' . $logical_base_path + : $logical_base_path; + $deep_map[$logical_base_path][$deep_path] = $behavior; + + // Register the class with name $prefix. + if (strlen($prefix)) { + $filepath = substr($deep_path, 0, -1) . '.php'; + $this->classes[$prefix][$filepath] = TRUE; + } + } + $this->prefixMap->registerDeepPaths($deep_map); + } + + /** + * {@inheritdoc} + */ + function registerPrefixDeep($prefix, $deep_path, $behavior = NULL) { + if (!isset($behavior)) { + $behavior = $this->defaultBehavior; + } + $this->registerPrefixDeepLocation($prefix, $deep_path, $behavior); + } + + /** + * {@inheritdoc} + */ + function registerPrefixesDeep($map, $behavior = NULL) { + if (!isset($behavior)) { + $behavior = $this->defaultBehavior; + } + $deep_map = array(); + foreach ($map as $prefix => $deep_path) { + $logical_base_path = Util::prefixLogicalPath($prefix); + $deep_path = strlen($deep_path) + ? rtrim($deep_path, '/') . '/' + : ''; + $deep_map[$logical_base_path][$deep_path] = $behavior; + } + $this->prefixMap->registerDeepPaths($deep_map); + } + + /** + * {@inheritdoc} + */ + function registerPrefixDeepLocation($prefix, $deep_path, $behavior = NULL) { + if (!isset($behavior)) { + $behavior = $this->defaultBehavior; + } + $logical_base_path = Util::prefixLogicalPath($prefix); + $deep_path = strlen($deep_path) + ? rtrim($deep_path, '/') . '/' + : ''; + $this->prefixMap->registerDeepPath( + $logical_base_path, + $deep_path, + $behavior); + } + + // Namespace stuff + // --------------------------------------------------------------------------- + + /** + * {@inheritdoc} + */ + function registerNamespaceRoot($namespace, $root_path, $behavior = NULL) { + if (!isset($behavior)) { + $behavior = $this->defaultBehavior; + } + $logical_base_path = Util::namespaceLogicalPath($namespace); + $deep_path = strlen($root_path) + ? rtrim($root_path, '/') . '/' . $logical_base_path + : $logical_base_path; + $this->namespaceMap->registerDeepPath( + $logical_base_path, + $deep_path, + $behavior); + } + + /** + * {@inheritdoc} + */ + function registerNamespacesRoot($map, $behavior = NULL) { + if (!isset($behavior)) { + $behavior = $this->defaultBehavior; + } + $deep_map = array(); + foreach ($map as $namespace => $root_path) { + $logical_base_path = Util::namespaceLogicalPath($namespace); + $deep_path = strlen($root_path) + ? rtrim($root_path, '/') . '/' . $logical_base_path + : $logical_base_path; + $deep_map[$logical_base_path][$deep_path] = $behavior; + } + $this->namespaceMap->registerDeepPaths($deep_map); + } + + /** + * {@inheritdoc} + */ + function registerNamespaceDeep($namespace, $path, $behavior = NULL) { + if (!isset($behavior)) { + $behavior = $this->defaultBehavior; + } + $logical_base_path = Util::namespaceLogicalPath($namespace); + $deep_path = strlen($path) + ? $path . '/' + : ''; + $this->namespaceMap->registerDeepPath( + $logical_base_path, + $deep_path, + $behavior); + } + + /** + * {@inheritdoc} + */ + function registerNamespacesDeep($map, $behavior = NULL) { + if (!isset($behavior)) { + $behavior = $this->defaultBehavior; + } + $deep_map = array(); + foreach ($map as $namespace => $deep_path) { + $logical_base_path = Util::namespaceLogicalPath($namespace); + $deep_path = strlen($deep_path) + ? rtrim($deep_path, '/') . '/' + : ''; + $deep_map[$logical_base_path][$deep_path] = $behavior; + } + $this->namespaceMap->registerDeepPaths($deep_map); + } + + /** + * {@inheritdoc} + */ + function registerNamespaceDeepLocation($namespace, $path, $behavior = NULL) { + if (!isset($behavior)) { + $behavior = $this->defaultBehavior; + } + $namespace_path_fragment = Util::namespaceLogicalPath($namespace); + $deep_path = strlen($path) + ? $path . '/' + : ''; + $this->namespaceMap->registerDeepPath( + $namespace_path_fragment, + $deep_path, + $behavior); + } + + // --------------------------------------------------------------------------- + + /** + * {@inheritdoc} + */ + function loadClass($class) { + + // Fix the behavior of some PHP versions that prepend '\\' to the class name. + if ('\\' === $class[0]) { + $class = substr($class, 1); + } + + // First check if the literal class name is registered. + if (!empty($this->classes[$class])) { + foreach ($this->classes[$class] as $filepath => $true) { + if (file_exists($filepath)) { + require $filepath; + + return TRUE; + } + } + } + + // Check if the class has a namespace. + if (FALSE !== $pos = strrpos($class, '\\')) { + + // Build the "logical path" based on PSR-4 replacement rules. + $logical_path = str_replace('\\', '/', $class) . '.php'; + + return $this->namespaceMap->loadClass($class, $logical_path, $pos); + } + + // Build the "logical path" based on PEAR replacement rules. + $pear_logical_path = str_replace('_', '/', $class) . '.php'; + + // Clean up surplus '/' resulting from duplicate underscores, or an + // underscore at the beginning of the class. + while (FALSE !== $pos = strrpos('/' . $pear_logical_path, '//')) { + $pear_logical_path[$pos] = '_'; + } + + // Check if the class has any underscore. + $pos = strrpos($pear_logical_path, '/'); + + return $this->prefixMap->loadClass($class, $pear_logical_path, $pos); + } + + /** + * {@inheritdoc} + */ + function apiFindFile($api, $class) { + + // Fix the behavior of some PHP versions that prepend '\\' to the class name. + if ('\\' === $class[0]) { + $class = substr($class, 1); + } + + // First check if the literal class name is registered. + if (!empty($this->classes[$class])) { + foreach ($this->classes[$class] as $filepath => $true) { + if ($api->suggestFile($filepath)) { + return TRUE; + } + } + } + + // Check if the class has a namespace. + if (FALSE !== $pos = strrpos($class, '\\')) { + + // Build the "logical path" based on PSR-4 replacement rules. + $logical_path = str_replace('\\', '/', $class) . '.php'; + + return $this->namespaceMap->apiFindFile($api, $logical_path, $pos); + } + + // Build the "logical path" based on PEAR replacement rules. + $pear_logical_path = str_replace('_', '/', $class) . '.php'; + + // Clean up surplus '/' resulting from duplicate underscores, or an + // underscore at the beginning of the class. + while (FALSE !== $pos = strrpos('/' . $pear_logical_path, '//')) { + $pear_logical_path[$pos] = '_'; + } + + // Check if the class has any underscore. + $pos = strrpos($pear_logical_path, '/'); + + return $this->prefixMap->apiFindFile($api, $pear_logical_path, $pos); + } +} diff --git a/frontend/drupal/modules/xautoload/src/ClassFinder/ClassFinderInterface.php b/frontend/drupal/modules/xautoload/src/ClassFinder/ClassFinderInterface.php new file mode 100644 index 000000000..bb421d3bb --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassFinder/ClassFinderInterface.php @@ -0,0 +1,30 @@ +suggestFile($file) with all suggestions we + * can find, until it returns TRUE. Once suggestFile() returns TRUE, we stop + * and return TRUE as well. The $file will be in the $api object, so we + * don't need to return it. + * @param string $class + * The name of the class, with all namespaces prepended. + * E.g. Some\Namespace\Some\Class + * + * @return TRUE|NULL + * TRUE, if we found the file for the class. + * That is, if the $api->suggestFile($file) method returned TRUE one time. + * NULL, if we have no more suggestions. + */ + function apiFindFile($api, $class); + +} diff --git a/frontend/drupal/modules/xautoload/src/ClassFinder/CommonRegistrationInterface.php b/frontend/drupal/modules/xautoload/src/ClassFinder/CommonRegistrationInterface.php new file mode 100644 index 000000000..6582738dd --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassFinder/CommonRegistrationInterface.php @@ -0,0 +1,81 @@ +addPsr0(). + * + * @param string $prefix + * @param string[]|string $paths + */ + function add($prefix, $paths); + + /** + * Adds a PSR-0 style prefix. Alias for ->add(). + * + * @param string $prefix + * @param string[]|string $paths + */ + function addPsr0($prefix, $paths); + + /** + * Adds a PSR-4 style namespace. + * + * @param string $prefix + * @param string[]|string $paths + */ + function addPsr4($prefix, $paths); + + // More convenience stuff + // --------------------------------------------------------------------------- + + /** + * Adds a PSR-0 style namespace. + * + * This will assume that we are really dealing with a namespace, even if it + * has no '\\' included. + * + * @param string $prefix + * @param string[]|string $paths + */ + function addNamespacePsr0($prefix, $paths); + + /** + * Adds a PEAR-like prefix. + * + * This will assume with no further checks that $prefix contains no namespace + * separator. + * + * @param string $prefix + * @param string[]|string $paths + */ + function addPear($prefix, $paths); + + /** + * Adds a prefix similar to PEAR, but with flat directories. + * + * This will assume with no further checks that $prefix contains no namespace + * separator. + * + * @param string $prefix + * @param string[]|string $paths + */ + function addPearFlat($prefix, $paths); + +} diff --git a/frontend/drupal/modules/xautoload/src/ClassFinder/ExtendedClassFinderInterface.php b/frontend/drupal/modules/xautoload/src/ClassFinder/ExtendedClassFinderInterface.php new file mode 100644 index 000000000..c5a8b4913 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassFinder/ExtendedClassFinderInterface.php @@ -0,0 +1,215 @@ + ../lib/My/Prefix/SomeClass.php + * My_Prefix -> ../lib/My/Prefix.php + * @param DirectoryBehaviorInterface $behavior + * If TRUE, then we are not sure if the directory at $path actually exists. + * If during the process we find the directory to be nonexistent, we + * unregister the path. + */ + function registerPrefixRoot($prefix, $root_path, $behavior = NULL); + + /** + * Register an array of PEAR-style deep paths for given class prefixes. + * + * Note: + * This actually goes beyond PEAR style, because it also allows "shallow" + * PEAR-like structures like + * my_library_Some_Class -> (library dir)/src/Some/Class.php + * instead of + * my_library_Some_Class -> (library dir)/src/my/library/Some/Class.php + * via + * $finder->registerPrefixDeep('my_library', "$library_dir/src"); + * + * @param string[] $map + * Associative array, the keys are the prefixes, the values are the + * directories. + * This does NOT cover the class named $prefix itself. + * @param DirectoryBehaviorInterface $behavior + * If TRUE, then we are not sure if the directory at $path actually exists. + * If during the process we find the directory to be nonexistent, we + * unregister the path. + */ + function registerPrefixesRoot($map, $behavior = NULL); + + /** + * Register a PEAR-style deep path for a given class prefix. + * + * Note: + * This actually goes beyond PEAR style, because it also allows things like + * my_library_Some_Class -> (library dir)/src/Some/Class.php + * instead of + * my_library_Some_Class -> (library dir)/src/my/library/Some/Class.php + * via + * $finder->registerPrefixDeep('my_library', "$library_dir/src"); + * + * @param string $prefix + * Prefix, e.g. "My_Prefix", for classes like "My_Prefix_SomeClass". + * This does NOT cover the class named "My_Prefix" itself. + * @param string $deep_path + * The deep path, e.g. "../lib/My/Prefix", for classes placed in + * My_Prefix_SomeClass -> ../lib/My/Prefix/SomeClass.php + * @param DirectoryBehaviorInterface $behavior + * If TRUE, then we are not sure if the directory at $path actually exists. + * If during the process we find the directory to be nonexistent, we + * unregister the path. + */ + function registerPrefixDeep($prefix, $deep_path, $behavior = NULL); + + /** + * Register an array of PEAR-style deep paths for given class prefixes. + * + * Note: + * This actually goes beyond PEAR style, because it also allows "shallow" + * PEAR-like structures like + * my_library_Some_Class -> (library dir)/src/Some/Class.php + * instead of + * my_library_Some_Class -> (library dir)/src/my/library/Some/Class.php + * via + * $finder->registerPrefixDeep('my_library', "$library_dir/src"); + * + * @param string[] $map + * Associative array, the keys are the prefixes, the values are the + * directories. + * This does NOT cover the class named $prefix itself. + * @param \Drupal\xautoload\DirectoryBehavior\DirectoryBehaviorInterface $behavior + * If TRUE, then we are not sure if the directory at $path actually exists. + * If during the process we find the directory to be nonexistent, we + * unregister the path. + */ + function registerPrefixesDeep($map, $behavior = NULL); + + /** + * Register a filesystem location for a given class prefix. + * + * @param string $prefix + * The prefix, e.g. "My_Prefix" + * @param string $deep_path + * The deep filesystem location, e.g. "../lib/My/Prefix". + * @param DirectoryBehaviorInterface $behavior + * If TRUE, then we are not sure if the directory at $path actually exists. + * If during the process we find the directory to be nonexistent, we + * unregister the path. + */ + function registerPrefixDeepLocation($prefix, $deep_path, $behavior = NULL); + + // Namespace stuff + // --------------------------------------------------------------------------- + + /** + * Register a PSR-0 root folder for a given namespace. + * + * @param string $namespace + * The namespace, e.g. "My\Namespace", to cover all classes within that, + * e.g. My\Namespace\SomeClass, or My\Namespace\Xyz\SomeClass. This does not + * cover the root-level class, e.g. My\Namespace + * @param string $root_path + * The deep path, e.g. "../lib", if classes reside in e.g. + * My\Namespace\SomeClass -> ../lib/My/Namespace/SomeClass.php + * @param \Drupal\xautoload\DirectoryBehavior\DirectoryBehaviorInterface $behavior + * If TRUE, then we are not sure if the directory at $path actually exists. + * If during the process we find the directory to be nonexistent, we + * unregister the path. + */ + function registerNamespaceRoot($namespace, $root_path, $behavior = NULL); + + /** + * Register PSR-0 root folders for given namespaces. + * + * @param string[] $map + * Associative array, the keys are the namespaces, the values are the + * directories. + * @param \Drupal\xautoload\DirectoryBehavior\DirectoryBehaviorInterface $behavior + * If TRUE, then we are not sure if the directory at $path actually exists. + * If during the process we find the directory to be nonexistent, we + * unregister the path. + */ + function registerNamespacesRoot($map, $behavior = NULL); + + /** + * Alias for registerNamespaceDeepLocation() + * + * @param string $namespace + * The namespace, e.g. "My\Namespace" + * @param string $path + * The deep path, e.g. "../lib/My/Namespace" + * @param \Drupal\xautoload\DirectoryBehavior\DirectoryBehaviorInterface $behavior + * If TRUE, then we are not sure if the directory at $path actually exists. + * If during the process we find the directory to be nonexistent, we + * unregister the path. + */ + function registerNamespaceDeep($namespace, $path, $behavior = NULL); + + /** + * Register a number of "deep" namespace directories at once. + * + * @param string[] $map + * @param DirectoryBehaviorInterface $behavior + */ + function registerNamespacesDeep($map, $behavior = NULL); + + /** + * Register a deep filesystem location for a given namespace. + * + * @param string $namespace + * The namespace, e.g. "My\Namespace" + * @param string $path + * The deep path, e.g. "../lib/My/Namespace" + * @param DirectoryBehaviorInterface $behavior + * If TRUE, then we are not sure if the directory at $path actually exists. + * If during the process we find the directory to be nonexistent, we + * unregister the path. + */ + function registerNamespaceDeepLocation($namespace, $path, $behavior = NULL); +} diff --git a/frontend/drupal/modules/xautoload/src/ClassFinder/GenericPrefixMap.php b/frontend/drupal/modules/xautoload/src/ClassFinder/GenericPrefixMap.php new file mode 100644 index 000000000..9f2e5f604 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassFinder/GenericPrefixMap.php @@ -0,0 +1,242 @@ +separator = $separator; + } + + /** + * If a class file would be in + * $psr0_root . '/' . $path_fragment . $path_suffix + * then instead, we look in + * $deep_path . $path_suffix + * + * @param string $logical_base_path + * The would-be namespace path relative to PSR-0 root. + * That is, the namespace with '\\' replaced by '/'. + * @param string $deep_path + * The filesystem location of the (PSR-0) subfolder for the given namespace. + * @param DirectoryBehaviorInterface $behavior + * Behavior in this directory. + */ + function registerDeepPath($logical_base_path, $deep_path, $behavior) { + $this->paths[$logical_base_path][$deep_path] = $behavior; + } + + /** + * @param string $logical_base_path + * The would-be namespace path relative to PSR-0 root. + * That is, the namespace with '\\' replaced by '/'. + * @param string $deep_path + * The filesystem location of the (PSR-0) subfolder for the given namespace. + * @param DirectoryBehaviorInterface $behavior + * Behavior in this directory. + */ + function prependDeepPath($logical_base_path, $deep_path, $behavior) { + $this->paths[$logical_base_path] + = isset($this->paths[$logical_base_path]) + ? array($deep_path => $behavior) + $this->paths[$logical_base_path] + : array($deep_path => $behavior); + } + + /** + * Register a bunch of those paths .. + * + * @param array[] $map + * + * @throws \Exception + */ + function registerDeepPaths(array $map) { + foreach ($map as $key => $paths) { + if (isset($this->paths[$key])) { + $paths += $this->paths[$key]; + } + $this->paths[$key] = $paths; + } + } + + /** + * Delete a registered path mapping. + * + * @param string $logical_base_path + * @param string $deep_path + */ + function unregisterDeepPath($logical_base_path, $deep_path) { + unset($this->paths[$logical_base_path][$deep_path]); + } + + + /** + * @param string $class + * @param string $logical_path + * Class name translated into a logical path, either with PSR-4 or with PEAR + * translation rules. + * @param int|bool $lastpos + * Position of the last directory separator in $logical_path. + * FALSE, if there is no directory separator in $logical_path. + * + * @return bool|NULL + * TRUE, if the class was found. + */ + function loadClass($class, $logical_path, $lastpos) { + $pos = $lastpos; + while (TRUE) { + $logical_base_path = (FALSE === $pos) + ? '' + : substr($logical_path, 0, $pos + 1); + + if (isset($this->paths[$logical_base_path])) { + foreach ($this->paths[$logical_base_path] as $dir => $behavior) { + if ($behavior instanceof DefaultDirectoryBehavior) { + // PSR-4 and PEAR + if (file_exists($file = $dir . substr($logical_path, $pos + 1))) { + require $file; + + return TRUE; + } + } + elseif ($behavior instanceof Psr0DirectoryBehavior) { + // PSR-0 + if (file_exists( + $file = $dir + . substr($logical_path, $pos + 1, $lastpos - $pos) + . str_replace('_', '/', substr($logical_path, $lastpos + 1)) + )) { + require $file; + + return TRUE; + } + } + elseif ($behavior instanceof xautoload_FinderPlugin_Interface) { + // Legacy "FinderPlugin". + $api = new LoadClassInjectedAPI($class); + if ($behavior->findFile($api, $logical_base_path, substr($logical_path, $pos + 1), $dir)) { + return TRUE; + } + } + } + } + + // Continue with parent fragment. + if (FALSE === $pos) { + return NULL; + } + + $pos = strrpos($logical_base_path, '/', -2); + } + + return NULL; + } + + /** + * Find the file for a class that in PSR-0 or PEAR would be in + * $psr_0_root . '/' . $path_fragment . $path_suffix + * + * @param InjectedApiInterface $api + * @param string $logical_path + * Class name translated into a logical path, either with PSR-4 or with PEAR + * translation rules. + * @param int|bool $lastpos + * Position of the last directory separator in $logical_path. + * FALSE, if there is no directory separator in $logical_path. + * + * @return bool|NULL + * TRUE, if the class was found. + */ + function apiFindFile($api, $logical_path, $lastpos) { + $pos = $lastpos; + while (TRUE) { + $logical_base_path = (FALSE === $pos) + ? '' + : substr($logical_path, 0, $pos + 1); + + if (isset($this->paths[$logical_base_path])) { + foreach ($this->paths[$logical_base_path] as $dir => $behavior) { + if ($behavior instanceof DefaultDirectoryBehavior) { + // PSR-4 and PEAR + if ($api->suggestFile($dir . substr($logical_path, $pos + 1))) { + return TRUE; + } + } + elseif ($behavior instanceof Psr0DirectoryBehavior) { + // PSR-0 + if ($api->suggestFile( + $dir + . substr($logical_path, $pos + 1, $lastpos - $pos) + . str_replace('_', '/', substr($logical_path, $lastpos + 1)) + )) { + return TRUE; + } + } + elseif ($behavior instanceof xautoload_FinderPlugin_Interface) { + // Legacy "FinderPlugin". + if ($behavior->findFile($api, $logical_base_path, substr($logical_path, $pos + 1), $dir)) { + return TRUE; + } + } + } + } + + // Continue with parent fragment. + if (FALSE === $pos) { + return NULL; + } + + $pos = strrpos($logical_base_path, '/', -2); + } + + return NULL; + } +} diff --git a/frontend/drupal/modules/xautoload/src/ClassFinder/InjectedApi/AbstractInjectedApi.php b/frontend/drupal/modules/xautoload/src/ClassFinder/InjectedApi/AbstractInjectedApi.php new file mode 100644 index 000000000..f4aba9643 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassFinder/InjectedApi/AbstractInjectedApi.php @@ -0,0 +1,50 @@ +className = $class_name; + } + + /** + * This is done in the injected api object, so we can easily provide a mock + * implementation. + */ + function is_dir($dir) { + return is_dir($dir); + } + + /** + * Get the name of the class we are looking for. + * + * @return string + * The class we are looking for. + */ + function getClass() { + return $this->className; + } + + /** + * Dummy method to force autoloading this class (or an ancestor). + */ + static function forceAutoload() { + // Do nothing. + } +} diff --git a/frontend/drupal/modules/xautoload/src/ClassFinder/InjectedApi/CollectFilesInjectedApi.php b/frontend/drupal/modules/xautoload/src/ClassFinder/InjectedApi/CollectFilesInjectedApi.php new file mode 100644 index 000000000..b62ef29b1 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassFinder/InjectedApi/CollectFilesInjectedApi.php @@ -0,0 +1,147 @@ +file, will return TRUE. + */ + protected $methodName; + + /** + * @var string + * The file where $this->$method($this->file) will return TRUE. + */ + protected $file; + + /** + * @var array[] + * All files that were suggested. + */ + protected $suggestions; + + /** + * @param string $class_name + * @var string $method + * The method that, if called with $this->file, will return TRUE. + * @param string $file + * The file where $this->$method($this->file) will return TRUE. + */ + function __construct($class_name, $method_name, $file) { + $this->methodName = $method_name; + $this->file = $file; + parent::__construct($class_name); + } + + /** + * When the process has finished, use this to return the result. + * + * @return string + * The file that is supposed to declare the class. + */ + function getSuggestions() { + return $this->suggestions; + } + + /** + * Suggest a file that, if the file exists, + * has to declare the class we are looking for. + * Only keep the class on success. + * + * @param string $file + * The file that is supposed to declare the class. + * + * @return bool + * TRUE, if the file exists. + * FALSE, otherwise. + */ + function suggestFile($file) { + $this->suggestions[] = array(__FUNCTION__, $file); + return __FUNCTION__ === $this->methodName && $file === $this->file; + } + + /** + * Same as suggestFile(), but skip the file_exists(), + * assuming that we already know the file exists. + * + * This could make sense if a plugin already did the file_exists() check. + * + * @param string $file + * The file that is supposed to declare the class. + * + * @return bool + * TRUE, if the file was found - which is always. + */ + function suggestFile_skipFileExists($file) { + $this->suggestions[] = array(__FUNCTION__, $file); + return TRUE; + } + + /** + * Same as suggestFile(), but assume that file_exists() returns TRUE. + * + * @param string $file + * The file that is supposed to declare the class. + * + * @return bool + * TRUE, if the file was found - which is always. + */ + function suggestFile_checkNothing($file) { + $this->suggestions[] = array(__FUNCTION__, $file); + return TRUE; + } + + /** + * Same as suggestFile(), but check the full PHP include path. + * + * @param string $file + * The file that is supposed to declare the class. + * + * @return bool + * TRUE, if the file exists. + * FALSE, otherwise. + */ + function suggestFile_checkIncludePath($file) { + $this->suggestions[] = array(__FUNCTION__, $file); + return __FUNCTION__ == $this->methodName && $file === $this->file; + } + + /** + * {@inheritdoc} + */ + function guessFile($file) { + $this->suggestions[] = array(__FUNCTION__, $file); + return __FUNCTION__ == $this->methodName && $file === $this->file; + } + + /** + * {@inheritdoc} + */ + function guessPath($file) { + $this->suggestions[] = array(__FUNCTION__, $file); + return __FUNCTION__ == $this->methodName && $file === $this->file; + } + + /** + * {@inheritdoc} + */ + function claimFile($file) { + $this->suggestions[] = array(__FUNCTION__, $file); + return TRUE; + } + + /** + * {@inheritdoc} + */ + function claimPath($file) { + $this->suggestions[] = array(__FUNCTION__, $file); + return __FUNCTION__ == $this->methodName && $file === $this->file; + } +} diff --git a/frontend/drupal/modules/xautoload/src/ClassFinder/InjectedApi/FindFileInjectedApi.php b/frontend/drupal/modules/xautoload/src/ClassFinder/InjectedApi/FindFileInjectedApi.php new file mode 100644 index 000000000..67107cd3e --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassFinder/InjectedApi/FindFileInjectedApi.php @@ -0,0 +1,145 @@ +file; + } + + /** + * Suggest a file that, if the file exists, + * has to declare the class we are looking for. + * Only keep the class on success. + * + * @param string $file + * The file that is supposed to declare the class. + * + * @return bool + * TRUE, if the file exists. + * FALSE, otherwise. + */ + function suggestFile($file) { + if (file_exists($file)) { + $this->file = $file; + return TRUE; + } + return FALSE; + } + + /** + * Same as suggestFile(), but skip the file_exists(), + * assuming that we already know the file exists. + * + * This could make sense if a plugin already did the file_exists() check. + * + * @param string $file + * The file that is supposed to declare the class. + * + * @return bool + * TRUE, if the file was found - which is always. + */ + function suggestFile_skipFileExists($file) { + $this->file = $file; + return TRUE; + } + + /** + * Same as suggestFile(), but assume that file_exists() returns TRUE. + * + * @param string $file + * The file that is supposed to declare the class. + * + * @return bool + * TRUE, if the file was found - which is always. + */ + function suggestFile_checkNothing($file) { + $this->file = $file; + return TRUE; + } + + /** + * Same as suggestFile(), but check the full PHP include path. + * + * @param string $file + * The file that is supposed to declare the class. + * + * @return bool + * TRUE, if the file exists. + * FALSE, otherwise. + */ + function suggestFile_checkIncludePath($file) { + if (FALSE !== $file = Util::findFileInIncludePath($file)) { + $this->file = $file; + return TRUE; + } + return FALSE; + } + + /** + * {@inheritdoc} + */ + function guessFile($file) { + // The file must be included, or else we can't know if it defines the class. + require_once $file; + if (Util::classIsDefined($this->className)) { + $this->file = $file; + return TRUE; + } + return FALSE; + } + + /** + * {@inheritdoc} + */ + function guessPath($file) { + if (file_exists($file)) { + // The file must be included, or else we can't know if it defines the class. + require_once $file; + if (Util::classIsDefined($this->className)) { + $this->file = $file; + return TRUE; + } + } + return FALSE; + } + + /** + * {@inheritdoc} + */ + function claimFile($file) { + $this->file = $file; + return TRUE; + } + + /** + * {@inheritdoc} + */ + function claimPath($file) { + if (file_exists($file)) { + $this->file = $file; + return TRUE; + } + return FALSE; + } +} diff --git a/frontend/drupal/modules/xautoload/src/ClassFinder/InjectedApi/InjectedApiInterface.php b/frontend/drupal/modules/xautoload/src/ClassFinder/InjectedApi/InjectedApiInterface.php new file mode 100644 index 000000000..6e836e90e --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassFinder/InjectedApi/InjectedApiInterface.php @@ -0,0 +1,138 @@ +file = $file; + require $file; + return TRUE; + } + else { + return FALSE; + } + } + + /** + * Same as suggestFile(), but skip the file_exists(), + * assuming that we already know the file exists. + * + * This could make sense if a plugin already did the file_exists() check. + * + * @param string $file + * The file that is supposed to declare the class. + * + * @return bool + * TRUE, if the file was found - which is always. + */ + function suggestFile_skipFileExists($file) { + $this->file = $file; + require $file; + return TRUE; + } + + /** + * Same as suggestFile(), but assume that file_exists() returns TRUE. + * + * @param string $file + * The file that is supposed to declare the class. + * + * @return bool + * TRUE, if the file was found - which is always. + */ + function suggestFile_checkNothing($file) { + $this->file = $file; + require $file; + return TRUE; + } + + /** + * Same as suggestFile(), but check the full PHP include path. + * + * @param string $file + * The file that is supposed to declare the class. + * + * @return bool + * TRUE, if the file exists. + * FALSE, otherwise. + */ + function suggestFile_checkIncludePath($file) { + if (FALSE !== $file = Util::findFileInIncludePath($file)) { + $this->file = $file; + require $file; + return TRUE; + } + return FALSE; + } + + /** + * {@inheritdoc} + */ + function guessFile($file) { + require_once $file; + if (Util::classIsDefined($this->className)) { + $this->file = $file; + return TRUE; + } + return FALSE; + } + + /** + * {@inheritdoc} + */ + function guessPath($file) { + if (file_exists($file)) { + require_once $file; + if (Util::classIsDefined($this->className)) { + $this->file = $file; + return TRUE; + } + } + return FALSE; + } + + /** + * {@inheritdoc} + */ + function claimFile($file) { + require $file; + $this->file = $file; + return TRUE; + } + + /** + * {@inheritdoc} + */ + function claimPath($file) { + if (file_exists($file)) { + require $file; + $this->file = $file; + return TRUE; + } + return FALSE; + } +} diff --git a/frontend/drupal/modules/xautoload/src/ClassFinder/InjectedApi/LoadClassInjectedAPI.php b/frontend/drupal/modules/xautoload/src/ClassFinder/InjectedApi/LoadClassInjectedAPI.php new file mode 100644 index 000000000..a233628cb --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassFinder/InjectedApi/LoadClassInjectedAPI.php @@ -0,0 +1,105 @@ +className); + } + + /** + * {@inheritdoc} + */ + function guessPath($file) { + if (file_exists($file)) { + require_once $file; + + return Util::classIsDefined($this->className); + } + else { + return FALSE; + } + } + + /** + * {@inheritdoc} + */ + function claimFile($file) { + require $file; + + return TRUE; + } + + /** + * {@inheritdoc} + */ + function claimPath($file) { + if (file_exists($file)) { + require $file; + + return TRUE; + } + else { + return FALSE; + } + } +} diff --git a/frontend/drupal/modules/xautoload/src/ClassFinder/Plugin/DrupalCoreRegistryPlugin.php b/frontend/drupal/modules/xautoload/src/ClassFinder/Plugin/DrupalCoreRegistryPlugin.php new file mode 100644 index 000000000..50b45f033 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassFinder/Plugin/DrupalCoreRegistryPlugin.php @@ -0,0 +1,79 @@ +baseDir = $baseDir; + } + + /** + * Find the file for a class that in PSR-0 or PEAR would be in + * $psr_0_root . '/' . $path_fragment . $path_suffix + * + * E.g.: + * - The class we look for is Some\Namespace\Some\Class + * - The file is actually in "exotic/location.php". This is not following + * PSR-0 or PEAR standard, so we need a plugin. + * -> The class finder will transform the class name to + * "Some/Namespace/Some/Class.php" + * - The plugin was registered for the namespace "Some\Namespace". This is + * because all those exotic classes all begin with Some\Namespace\ + * -> The arguments will be: + * ($api = the API object, see below) + * $logical_base_path = "Some/Namespace/" + * $relative_path = "Some/Class.php" + * $api->getClass() gives the original class name, if we still need it. + * -> We are supposed to: + * if ($api->suggestFile('exotic/location.php')) { + * return TRUE; + * } + * + * @param InjectedApiInterface $api + * An object with a suggestFile() method. + * We are supposed to suggest files until suggestFile() returns TRUE, or we + * have no more suggestions. + * @param string $logical_base_path_empty + * The key that this plugin was registered with. + * With trailing '/'. + * @param string $relative_path_irrelevant + * Second part of the canonical path, ending with '.php'. + * + * @return bool|null + * TRUE, if the file was found. + * FALSE or NULL, otherwise. + */ + function findFile($api, $logical_base_path_empty, $relative_path_irrelevant) { + $q = db_select('registry'); + // Use LIKE here to make the query case-insensitive. + $q->condition('name', db_like($api->getClass()), 'LIKE'); + $q->addField('registry', 'filename'); + $stmt = $q->execute(); + while ($relative_path = $stmt->fetchField()) { + $file = $this->baseDir . $relative_path; + // Attention: The db_select() above can trigger the class loader for + // classes and interfaces of the database layer. This can cause some files + // to be included twice, if the file defines more than one class. + // So we need to use require_once here, instead of require. That is, use + // guessFile() instead of claimFile(). + if ($api->guessFile($file)) { + return TRUE; + } + } + return FALSE; + } +} diff --git a/frontend/drupal/modules/xautoload/src/ClassFinder/Plugin/DrupalExtensionNamespaceFinderPlugin.php b/frontend/drupal/modules/xautoload/src/ClassFinder/Plugin/DrupalExtensionNamespaceFinderPlugin.php new file mode 100644 index 000000000..0902673be --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassFinder/Plugin/DrupalExtensionNamespaceFinderPlugin.php @@ -0,0 +1,219 @@ +type = $type; + $this->prefixMap = $prefix_map; + $this->namespaceMap = $namespace_map; + $this->defaultBehavior = new DefaultDirectoryBehavior(); + $this->psr0Behavior = new Psr0DirectoryBehavior(); + $this->system = $system; + } + + /** + * Looks up a class starting with "Drupal\$extension_name\\". + * + * This plugin method will be called for every class beginning with + * "Drupal\\$extension_name\\", as long as the plugin is registered for + * $logical_base_path = 'Drupal/$extension_name/'. + * + * A similar plugin will is registered along with this one for the PEAR-FLAT + * pattern, called for every class beginning with $modulename . '_'. + * + * The plugin will eventually unregister itself and its cousin, once it has + * - determined the correct path for the module, and + * - determined that the module is using either PSR-0 or PSR-4. + * It does that by including the file candidate for PSR-0 and/or PSR-4 and + * checking whether the class is now defined. + * + * The plugin will instead register a direct + * + * @param \Drupal\xautoload\ClassFinder\InjectedApi\InjectedApiInterface $api + * An object with methods like suggestFile() and guessFile(). + * @param string $logical_base_path + * The logical base path determined from the registered namespace. + * E.g. 'Drupal/menupoly/'. + * @param string $relative_path + * Remaining part of the logical path following $logical_base_path. + * E.g. 'FooNamespace/BarClass.php'. + * @param string|null $extension_name + * Second key that the plugin was registered with. Usually this would be the + * physical base directory where we prepend the relative path to get the + * file path. But in this case it is simply the extensions name. + * E.g. 'menupoly'. + * + * @return bool|null + * TRUE, if the file was found. + * FALSE or NULL, otherwise. + */ + function findFile($api, $logical_base_path, $relative_path, $extension_name = NULL) { + + $extension_file = $this->system->drupalGetFilename($this->type, $extension_name); + if (empty($extension_file)) { + // Extension does not exist, or is not installed. + return FALSE; + } + + $nspath = 'Drupal/' . $extension_name . '/'; + $testpath = $nspath . 'Tests/'; + $uspath = $extension_name . '/'; + $extension_dir = dirname($extension_file); + $src = $extension_dir . '/src/'; + $lib_psr0 = $extension_dir . '/lib/Drupal/' . $extension_name . '/'; + $is_test_class = (0 === strpos($relative_path, 'Tests/')); + + // Try PSR-4. + if ($api->guessPath($src . $relative_path)) { + if ($is_test_class) { + // Register PSR-0 directory for "Drupal\\$modulename\\Tests\\" + // This generally happens only once per module, because for subsequent + // test classes the class will be found before this plugin is triggered. + // However, for class_exists() with nonexistent test files, this line + // will occur more than once. + $this->namespaceMap->registerDeepPath($testpath, $src . 'Tests/', $this->defaultBehavior); + // We found the class, but it is a test class, so it does not tell us + // anything about whether non-test classes are in PSR-0 or PSR-4. + return TRUE; + } + + // Register PSR-4 directory for "Drupal\\$modulename\\". + $this->namespaceMap->registerDeepPath($nspath, $src, $this->defaultBehavior); + + // Unregister the lazy plugins, including this one, for + // "Drupal\\$modulename\\" and for $modulename . '_'. + $this->namespaceMap->unregisterDeepPath($nspath, $extension_name); + $this->prefixMap->unregisterDeepPath($uspath, $extension_name); + + // Test classes in PSR-4 are already covered by the PSR-4 plugin we just + // registered. But test classes in PSR-0 would slip through. So we check + // if a separate behavior needs to be registered for those. + if (is_dir($lib_psr0 . 'Tests/')) { + $this->namespaceMap->registerDeepPath($testpath, $lib_psr0 . 'Tests/', $this->psr0Behavior); + } + + // The class was found, so return TRUE. + return TRUE; + } + + // Build PSR-0 relative path. + if (FALSE === $nspos = strrpos($relative_path, '/')) { + // No namespace separators in $relative_path, so all underscores must be + // replaced. + $relative_path = str_replace('_', '/', $relative_path); + } + else { + // Replace only those underscores in $relative_path after the last + // namespace separator, from right to left. On average there is no or very + // few of them, so this loop rarely iterates even once. + while ($nspos < $uspos = strrpos($relative_path, '_')) { + $relative_path[$uspos] = '/'; + } + } + + // Try PSR-0 + if ($api->guessPath($lib_psr0 . $relative_path)) { + if ($is_test_class) { + // We know now that there are test classes using PSR-0. + $this->namespaceMap->registerDeepPath($testpath, $lib_psr0 . 'Tests/', $this->psr0Behavior); + // We found the class, but it is a test class, so it does not tell us + // anything about whether non-test classes are in PSR-0 or PSR-4. + return TRUE; + } + + // Unregister the lazy plugins, including this one. + $this->namespaceMap->unregisterDeepPath($nspath, $extension_name); + $this->prefixMap->unregisterDeepPath($uspath, $extension_name); + + // Register PSR-0 for regular namespaced classes. + $this->namespaceMap->registerDeepPath($nspath, $lib_psr0, $this->psr0Behavior); + + // Test classes in PSR-0 are already covered by the PSR-0 plugin we just + // registered. But test classes in PSR-4 would slip through. So we check + // if a separate behavior needs to be registered for those. + # if (is_dir($src . 'Tests/')) { + # $this->namespaceMap->registerDeepPath($testpath, $src . 'Tests/', $this->psr0Behavior); + # } + + // The class was found, so return TRUE. + return TRUE; + } + + return FALSE; + } +} diff --git a/frontend/drupal/modules/xautoload/src/ClassFinder/Plugin/DrupalExtensionUnderscoreFinderPlugin.php b/frontend/drupal/modules/xautoload/src/ClassFinder/Plugin/DrupalExtensionUnderscoreFinderPlugin.php new file mode 100644 index 000000000..794653658 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassFinder/Plugin/DrupalExtensionUnderscoreFinderPlugin.php @@ -0,0 +1,53 @@ +system->drupalGetFilename($this->type, $extension_name); + + if (empty($extension_file)) { + // Extension does not exist, or is not installed. + return FALSE; + } + + $nspath = 'Drupal/' . $extension_name . '/'; + $testpath = $nspath . 'Tests/'; + $uspath = $extension_name . '/'; + $lib = dirname($extension_file) . '/lib/'; + $lib_psr0 = $lib . 'Drupal/' . $extension_name . '/'; + + // Try PEAR-Flat. + if ($api->guessPath($lib . $relative_path)) { + // Register PEAR-Flat. + $this->prefixMap->registerDeepPath($uspath, $lib, $this->defaultBehavior); + // Unregister the lazy plugins. + $this->namespaceMap->unregisterDeepPath($nspath, $extension_name); + $this->prefixMap->unregisterDeepPath($uspath, $extension_name); + // See if there are PSR-0 or PSR-4 test classes. + if (is_dir($lib_psr0 . 'Tests/')) { + $this->namespaceMap->registerDeepPath( + $testpath, + $lib_psr0 . 'Tests/', + $this->psr0Behavior); + } + if (is_dir($lib . 'Tests/')) { + $this->namespaceMap->registerDeepPath( + $testpath, + $lib . 'Tests/', + $this->defaultBehavior); + } + + // The class was found, so return TRUE. + return TRUE; + } + + // The class was not found, so return FALSE. + return FALSE; + } +} diff --git a/frontend/drupal/modules/xautoload/src/ClassFinder/Plugin/FinderPluginInterface.php b/frontend/drupal/modules/xautoload/src/ClassFinder/Plugin/FinderPluginInterface.php new file mode 100644 index 000000000..4803d0997 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassFinder/Plugin/FinderPluginInterface.php @@ -0,0 +1,65 @@ + The class finder will transform the class name to + * "Some/Namespace/Some/Class.php" + * - The plugin was registered for the namespace "Some\Namespace". This is + * because all those exotic classes all begin with Some\Namespace\ + * -> The arguments will be: + * ($api = the API object, see below) + * $path_fragment = "Some/Namespace/" + * $path_suffix = "Some/Class.php" + * $api->getClass() gives the original class name, if we still need it. + * -> We are supposed to: + * if ($api->suggestFile('exotic/location.php')) { + * return TRUE; + * } + * + * @param InjectedApiInterface $api + * An object with a suggestFile() method. + * We are supposed to suggest files until suggestFile() returns TRUE, or we + * have no more suggestions. + * @param string $path_fragment + * The key that this plugin was registered with. + * With trailing '/'. + * @param string $path_suffix + * Second part of the canonical path, ending with '.php'. + * @param int|string $id + * Id under which the plugin was registered. + * This may be a numeric id, or a string key. + * + * @return bool|null + * TRUE, if the file was found. + * FALSE, otherwise. + * + * NOTE: + * The signature of this method has changed since the legacy base interface, + * with a new optional parameter being added. + * Due to a bug in PHP 5.3.0 - 5.3.8, redeclaring the method with the + * modified signature would result in a fatal error in these PHP versions. + * This is why the method is commented out. + * The additional optional parameter can still be added in implementations. + */ + # function findFile($api, $path_fragment, $path_suffix, $id = NULL); +} diff --git a/frontend/drupal/modules/xautoload/src/ClassFinder/Plugin/Psr4FinderPlugin.php b/frontend/drupal/modules/xautoload/src/ClassFinder/Plugin/Psr4FinderPlugin.php new file mode 100644 index 000000000..8ecd8b7ea --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassFinder/Plugin/Psr4FinderPlugin.php @@ -0,0 +1,34 @@ +getClass(), strlen($logical_base_path)); + $relative_path = str_replace('\\', '/', $relative_classname) . '.php'; + return $api->suggestFile($base_dir . '/' . $relative_path); + } +} diff --git a/frontend/drupal/modules/xautoload/src/ClassFinder/ProxyClassFinder.php b/frontend/drupal/modules/xautoload/src/ClassFinder/ProxyClassFinder.php new file mode 100644 index 000000000..97ce40681 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassFinder/ProxyClassFinder.php @@ -0,0 +1,90 @@ +finder = $finder; + } + + /** + * {@inheritdoc} + */ + function loadClass($class) { + $this->initFinder(); + $this->finder->loadClass($class); + } + + /** + * {@inheritdoc} + */ + function apiFindFile($api, $class) { + $this->initFinder(); + + return $this->finder->apiFindFile($api, $class); + } + + /** + * @param CacheMissObserverInterface $observer + */ + function observeFirstCacheMiss($observer) { + if (!$this->initialized) { + $this->cacheMissObservers[] = $observer; + } + else { + $observer->cacheMiss($this->finder); + } + } + + /** + * @return ClassFinderInterface + */ + function getFinder() { + $this->initFinder(); + + return $this->finder; + } + + /** + * Initialize the finder and notify cache miss observers. + */ + protected function initFinder() { + if (!$this->initialized) { + $this->initialized = TRUE; + foreach ($this->cacheMissObservers as $operation) { + $operation->cacheMiss($this->finder); + } + } + } + +} diff --git a/frontend/drupal/modules/xautoload/src/ClassLoader/AbstractCachedClassLoader.php b/frontend/drupal/modules/xautoload/src/ClassLoader/AbstractCachedClassLoader.php new file mode 100644 index 000000000..a8cd44a43 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassLoader/AbstractCachedClassLoader.php @@ -0,0 +1,51 @@ +checkRequirements()) { + $class = get_class($loader); + throw new CacheNotSupportedException("Unable to use $class, because the respetive PHP extension is not enabled."); + } + $cacheManager->observeCachePrefix($loader); + + return $loader; + } + + /** + * @return bool + */ + protected abstract function checkRequirements(); + + /** + * {@inheritdoc} + */ + function setCachePrefix($prefix) { + $this->prefix = $prefix; + } +} diff --git a/frontend/drupal/modules/xautoload/src/ClassLoader/AbstractClassLoader.php b/frontend/drupal/modules/xautoload/src/ClassLoader/AbstractClassLoader.php new file mode 100644 index 000000000..f5b7ca828 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassLoader/AbstractClassLoader.php @@ -0,0 +1,41 @@ += 0) { + spl_autoload_register(array($this, 'loadClass'), TRUE, $prepend); + } + elseif ($prepend) { + $loaders = spl_autoload_functions(); + spl_autoload_register(array($this, 'loadClass')); + foreach ($loaders as $loader) { + spl_autoload_unregister($loader); + spl_autoload_register($loader); + } + } + else { + spl_autoload_register(array($this, 'loadClass')); + } + } + + /** + * Unregister from the spl autoload stack. + */ + function unregister() { + spl_autoload_unregister(array($this, 'loadClass')); + } +} diff --git a/frontend/drupal/modules/xautoload/src/ClassLoader/AbstractClassLoaderDecorator.php b/frontend/drupal/modules/xautoload/src/ClassLoader/AbstractClassLoaderDecorator.php new file mode 100644 index 000000000..f37741225 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassLoader/AbstractClassLoaderDecorator.php @@ -0,0 +1,41 @@ +finder = $finder; + } + + /** + * Replace the finder with another one. + * + * @param ClassFinderInterface $finder + * The object that does the actual class finding. + */ + function setFinder($finder) { + $this->finder = $finder; + } + + /** + * {@inheritdoc} + */ + function loadClass($class) { + $this->finder->loadClass($class); + } +} diff --git a/frontend/drupal/modules/xautoload/src/ClassLoader/AbstractQueuedCachedClassLoader.php b/frontend/drupal/modules/xautoload/src/ClassLoader/AbstractQueuedCachedClassLoader.php new file mode 100644 index 000000000..004c0a331 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassLoader/AbstractQueuedCachedClassLoader.php @@ -0,0 +1,137 @@ +observeCachePrefix($loader); + + return $loader; + } + + /** + * {@inheritdoc} + */ + function loadClass($class) { + + // Look if the cache has anything for this class. + if (isset($this->classFiles[$class])) { + $file = $this->classFiles[$class]; + // The is_file() check may cost around 0.0045 ms per class file, but this + // depends on your system of course. + if (is_file($file)) { + require $file; + + return; + } + $this->toBeDeleted[$class] = $file; + unset($this->classFiles[$class]); + ++$this->n; + } + + // Resolve cache miss. + $api = new LoadClassGetFileInjectedApi($class); + if ($this->finder->apiFindFile($api, $class)) { + // Queue the result for the cache. + $this->toBeAdded[$class] + = $this->classFiles[$class] + = $api->getFile(); + ++$this->n; + } + + // Save the cache if enough has been queued up. + if ($this->n >= $this->nMax) { + $this->classFiles = $this->updateClassFiles($this->toBeAdded, $this->toBeDeleted); + $this->toBeDeleted = array(); + $this->toBeAdded = array(); + $this->nMax *= 2; + $this->n = 0; + } + } + + /** + * Set the new cache prefix after a flush cache. + * + * @param string $prefix + * A prefix for the storage key in APC. + */ + function setCachePrefix($prefix) { + $this->classFiles = $this->loadClassFiles($prefix); + } + + /** + * @param string $prefix + * + * @return string[] + */ + abstract protected function loadClassFiles($prefix); + + /** + * @param string[] $toBeAdded + * @param string[] $toBeRemoved + * + * @return string[] + */ + abstract protected function updateClassFiles($toBeAdded, $toBeRemoved); + +} diff --git a/frontend/drupal/modules/xautoload/src/ClassLoader/ApcClassLoader.php b/frontend/drupal/modules/xautoload/src/ClassLoader/ApcClassLoader.php new file mode 100644 index 000000000..ebf57b6c4 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassLoader/ApcClassLoader.php @@ -0,0 +1,39 @@ +prefix . $class)) { + if (is_file($file)) { + require $file; + + return; + } + apc_delete($this->prefix . $class); + } + + // Resolve cache miss. + $api = new LoadClassGetFileInjectedApi($class); + if ($this->finder->apiFindFile($api, $class)) { + apc_store($this->prefix . $class, $api->getFile()); + } + } + +} diff --git a/frontend/drupal/modules/xautoload/src/ClassLoader/ApcuClassLoader.php b/frontend/drupal/modules/xautoload/src/ClassLoader/ApcuClassLoader.php new file mode 100644 index 000000000..53753e6f5 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassLoader/ApcuClassLoader.php @@ -0,0 +1,38 @@ +prefix . $class)) { + if (is_file($file)) { + require $file; + + return; + } + \apcu_delete($this->prefix . $class); + } + + // Resolve cache miss. + $api = new LoadClassGetFileInjectedApi($class); + if ($this->finder->apiFindFile($api, $class)) { + \apcu_store($this->prefix . $class, $api->getFile()); + } + } +} diff --git a/frontend/drupal/modules/xautoload/src/ClassLoader/ApcuQueuedCachedClassLoader.php b/frontend/drupal/modules/xautoload/src/ClassLoader/ApcuQueuedCachedClassLoader.php new file mode 100644 index 000000000..dc7cf7145 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassLoader/ApcuQueuedCachedClassLoader.php @@ -0,0 +1,52 @@ +prefix = $prefix; + $cached = \apcu_fetch($this->prefix); + + return !empty($cached) + ? $cached + : array(); + } + + /** + * @param string[] $toBeAdded + * @param string[] $toBeRemoved + * + * @return string[] + */ + protected function updateClassFiles($toBeAdded, $toBeRemoved) { + + $class_files = $toBeAdded; + // Other requests may have already written to the cache, so we get an up to + // date version. + $cached = \apcu_fetch($this->prefix); + if (!empty($cached)) { + $class_files += $cached; + foreach ($toBeRemoved as $class => $file) { + if (isset($class_files[$class]) && $class_files[$class] === $file) { + unset($class_files[$class]); + } + } + } + + \apcu_store($this->prefix, $class_files); + + return $class_files; + } + +} diff --git a/frontend/drupal/modules/xautoload/src/ClassLoader/CacheNotSupportedException.php b/frontend/drupal/modules/xautoload/src/ClassLoader/CacheNotSupportedException.php new file mode 100644 index 000000000..b7623bd42 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassLoader/CacheNotSupportedException.php @@ -0,0 +1,5 @@ +cacheName = 'xautoload_db_cache:' . $prefix; + $cached = cache_get($this->cacheName); + return isset($cached->data) + ? $cached->data + : array(); + } + + /** + * @param string[] $toBeAdded + * @param string[] $toBeRemoved + * + * @return string[] + */ + protected function updateClassFiles($toBeAdded, $toBeRemoved) { + + $class_files = $toBeAdded; + // Other requests may have already written to the cache, so we get an up to + // date version. + $cached = cache_get($this->cacheName); + if (isset($cached->data)) { + $class_files += $cached->data; + foreach ($toBeRemoved as $class => $file) { + if (isset($class_files[$class]) && $class_files[$class] === $file) { + unset($class_files[$class]); + } + } + } + + cache_set($this->cacheName, $class_files); + + return $class_files; + } + +} diff --git a/frontend/drupal/modules/xautoload/src/ClassLoader/WinCacheClassLoader.php b/frontend/drupal/modules/xautoload/src/ClassLoader/WinCacheClassLoader.php new file mode 100644 index 000000000..ee8376d5d --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassLoader/WinCacheClassLoader.php @@ -0,0 +1,39 @@ +prefix . $class)) { + if (is_file($file)) { + require $file; + + return; + } + wincache_ucache_delete($this->prefix . $class); + } + + // Resolve cache miss. + $api = new LoadClassGetFileInjectedApi($class); + if ($this->finder->apiFindFile($api, $class)) { + wincache_ucache_set($this->prefix . $class, $api->getFile()); + } + } +} diff --git a/frontend/drupal/modules/xautoload/src/ClassLoader/XCacheClassLoader.php b/frontend/drupal/modules/xautoload/src/ClassLoader/XCacheClassLoader.php new file mode 100644 index 000000000..a61cb9170 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/ClassLoader/XCacheClassLoader.php @@ -0,0 +1,40 @@ +prefix . $class) + && $file = xcache_get($this->prefix . $class) + ) { + if (is_file($file)) { + require $file; + + return; + } + xcache_unset($this->prefix . $class); + } + + // Resolve cache miss. + $api = new LoadClassGetFileInjectedApi($class); + if ($this->finder->apiFindFile($api, $class)) { + xcache_set($this->prefix . $class, $api->getFile()); + } + } +} diff --git a/frontend/drupal/modules/xautoload/src/DIC/ServiceContainer.php b/frontend/drupal/modules/xautoload/src/DIC/ServiceContainer.php new file mode 100644 index 000000000..83fd0ebee --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/DIC/ServiceContainer.php @@ -0,0 +1,76 @@ +services[$key]) + ? $this->services[$key] + : $this->services[$key] = $this->factory->$key($this) ? : FALSE; + } + + /** + * Unset the service for a specific key. + * + * @param string $key + */ + function reset($key) { + $this->services[$key] = NULL; + } + + /** + * Register a new service under the given key. + * + * @param string $key + * @param mixed $service + */ + function set($key, $service) { + $this->services[$key] = $service; + } + + /** + * Magic getter for a service. + * + * @param string $key + * + * @return mixed + * + * @throws \Exception + */ + function __get($key) { + if (isset($this->services[$key])) { + return $this->services[$key]; + } + if (!method_exists($this->factory, $key)) { + throw new \Exception("Unsupported key '$key' for service factory."); + } + + return $this->services[$key] = $this->factory->$key($this) ? : FALSE; + } + + /** + * @param ServiceFactory $factory + */ + function __construct($factory) { + $this->factory = $factory; + } +} diff --git a/frontend/drupal/modules/xautoload/src/DIC/ServiceContainerInterface.php b/frontend/drupal/modules/xautoload/src/DIC/ServiceContainerInterface.php new file mode 100644 index 000000000..312c4f124 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/DIC/ServiceContainerInterface.php @@ -0,0 +1,47 @@ +classFinder + * @property DrupalSystemInterface $system + * @property DrupalPhaseControl $phaseControl + * @property DrupalExtensionAdapter $extensionRegistrationService + * @property ExtensionNamespaces extensionNamespaces + * @property LibrariesInfoAlter librariesInfoAlter + * + * @see \Drupal\xautoload\DIC\ServiceContainer + * @see \Drupal\xautoload\DIC\ServiceFactory + */ +interface ServiceContainerInterface { + + /** + * Retrieves a lazy-instantiated service. + * + * @param string $key + * A key to specify a service. + * @return mixed + * The service for the given key. Usually an object. + */ + function __get($key); +} diff --git a/frontend/drupal/modules/xautoload/src/DIC/ServiceFactory.php b/frontend/drupal/modules/xautoload/src/DIC/ServiceFactory.php new file mode 100644 index 000000000..8c21899b6 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/DIC/ServiceFactory.php @@ -0,0 +1,174 @@ +finder, $services->classMapGenerator); + } + + /** + * @param ServiceContainer $services + * + * @return ClassMapGenerator + */ + function classMapGenerator($services) { + return new CachedClassMapGenerator($services->classMapGeneratorRaw, $services->system); + } + + /** + * @param ServiceContainer $services + * + * @return ClassMapGenerator + */ + function classMapGeneratorRaw($services) { + return new ClassMapGenerator(); + } + + /** + * @param ServiceContainer $services + * + * @return DrupalExtensionAdapter + */ + function extensionRegistrationService($services) { + return new DrupalExtensionAdapter($services->system, $services->finder); + } + + /** + * @param ServiceContainer $services + * + * @return CacheManager + */ + function cacheManager($services) { + return CacheManager::create($services->system); + } + + /** + * Proxy class finder. + * + * @param ServiceContainer $services + * + * @return ClassFinderInterface + * Proxy object wrapping the class finder. + * This is used to delay namespace registration until the first time the + * finder is actually used. + * (which might never happen thanks to the APC cache) + */ + function proxyFinder($services) { + // The class finder is cheap to create, so it can use an identity proxy. + return new ProxyClassFinder($services->finder); + } + + /** + * The class finder (alias for 'finder'). + * + * @param ServiceContainer $services + * + * @return ClassFinderInterface + * Object that can find classes, + * and provides methods to register namespaces and prefixes. + * Note: The findClass() method expects an InjectedAPI argument. + */ + function classFinder($services) { + return $services->finder; + } + + /** + * The class finder (alias for 'classFinder'). + * + * @param ServiceContainer $services + * + * @return ClassFinderInterface + * Object that can find classes, + * and provides methods to register namespaces and prefixes. + * Notes: + * - The findClass() method expects an InjectedAPI argument. + * - namespaces are only supported since PHP 5.3 + */ + function finder($services) { + return new ClassFinder(); + } + + /** + * @param ServiceContainer $services + * + * @return DrupalSystemInterface + */ + function system($services) { + return new DrupalSystem(); + } + + /** + * @param ServiceContainer $services + * + * @return DrupalPhaseControl + */ + function phaseControl($services) { + $observers = array( + $services->extensionNamespaces, + new HookXautoload($services->system), + new LibrariesOnInit($services->system), + ); + if ($services->system->variableGet(XAUTOLOAD_VARNAME_REPLACE_CORE, FALSE)) { + $observers[] = new DrupalCoreRegistryRegistrator(); + } + return new DrupalPhaseControl($services->system, $observers); + } + + /** + * @param ServiceContainer $services + * + * @return ExtensionNamespaces + */ + function extensionNamespaces($services) { + return new ExtensionNamespaces($services->system); + } + + /** + * @param ServiceContainer $services + * + * @return LibrariesInfoAlter + */ + function librariesInfoAlter($services) { + return new LibrariesInfoAlter(); + } + +} + diff --git a/frontend/drupal/modules/xautoload/src/DirectoryBehavior/DefaultDirectoryBehavior.php b/frontend/drupal/modules/xautoload/src/DirectoryBehavior/DefaultDirectoryBehavior.php new file mode 100644 index 000000000..4d089b82e --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/DirectoryBehavior/DefaultDirectoryBehavior.php @@ -0,0 +1,13 @@ +decorated = $decorated; + $this->system = $system; + } + + /** + * @param string[] $paths + * + * @return string[] + */ + function wildcardPathsToClassmap($paths) { + // Attempt to load from cache. + $cid = 'xautoload:wildcardPathsToClassmap:' . md5(serialize($paths)); + $cache = $this->system->cacheGet($cid); + if ($cache && isset($cache->data)) { + return $cache->data; + } + // Resolve cache miss and save. + $map = $this->decorated->wildcardPathsToClassmap($paths); + $this->system->cacheSet($cid, $map); + + return $map; + } +} diff --git a/frontend/drupal/modules/xautoload/src/Discovery/ClassMapGenerator.php b/frontend/drupal/modules/xautoload/src/Discovery/ClassMapGenerator.php new file mode 100644 index 000000000..213b3e965 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/Discovery/ClassMapGenerator.php @@ -0,0 +1,47 @@ +wildcardPathsToFiles($paths); + + return $this->filesToClassmap($files); + } + + /** + * @param string[] $files + * + * @return string[] + */ + protected function filesToClassmap($files) { + $map = array(); + foreach ($files as $file) { + $classes = FileInspector::inspectPhpFile($file); + foreach ($classes as $class) { + $map[$class] = $file; + } + } + + return $map; + } + + /** + * @param string[] $paths + * + * @return string[] + */ + protected function wildcardPathsToFiles($paths) { + $wildcardFinder = new WildcardFileFinder(); + $wildcardFinder->addPaths($paths); + + return $wildcardFinder->getFiles(); + } +} \ No newline at end of file diff --git a/frontend/drupal/modules/xautoload/src/Discovery/ClassMapGeneratorInterface.php b/frontend/drupal/modules/xautoload/src/Discovery/ClassMapGeneratorInterface.php new file mode 100644 index 000000000..d3547a399 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/Discovery/ClassMapGeneratorInterface.php @@ -0,0 +1,14 @@ +dir = $dir; + } + + /** + * @param ClassFinderAdapter $adapter + */ + function writeToAdapter($adapter) { + + // PSR-0 namespaces / prefixes + if (is_file($this->dir . '/autoload_namespaces.php')) { + $prefixes = require $this->dir . '/autoload_namespaces.php'; + if (!empty($prefixes)) { + $adapter->addMultiplePsr0($prefixes); + } + } + + // PSR-4 namespaces + if (is_file($this->dir . '/autoload_psr4.php')) { + $map = require $this->dir . '/autoload_psr4.php'; + if (!empty($map)) { + $adapter->addMultiplePsr4($map); + } + } + + // Class map + if (is_file($this->dir . '/autoload_classmap.php')) { + $class_map = require $this->dir . '/autoload_classmap.php'; + if (!empty($class_map)) { + $adapter->addClassMap($class_map); + } + } + + // Include path + if (is_file($this->dir . '/include_paths.php')) { + $include_paths = require $this->dir . '/include_paths.php'; + if (!empty($include_paths)) { + array_push($include_paths, get_include_path()); + set_include_path(join(PATH_SEPARATOR, $include_paths)); + } + } + + // Include files + if (is_file($this->dir . '/autoload_files.php')) { + $include_files = require $this->dir . '/autoload_files.php'; + foreach ($include_files as $file) { + require $file; + } + } + } +} \ No newline at end of file diff --git a/frontend/drupal/modules/xautoload/src/Discovery/ComposerJson.php b/frontend/drupal/modules/xautoload/src/Discovery/ComposerJson.php new file mode 100644 index 000000000..a95f722d3 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/Discovery/ComposerJson.php @@ -0,0 +1,132 @@ +data = $data; + $this->pathPrefix = $path_prefix; + } + + /** + * @param ClassFinderAdapter $adapter + */ + function writeToAdapter(ClassFinderAdapter $adapter) { + + $data = $this->data; + + if (!empty($data['include-path'])) { + $this->addIncludePaths((array)$data['include-path']); + } + + if (!empty($data['autoload']['psr-0'])) { + $map = $this->transformMultiple($data['autoload']['psr-0']); + $adapter->addMultiplePsr0($map); + } + + if (!empty($data['autoload']['psr-4'])) { + $map = $this->transformMultiple($data['autoload']['psr-4']); + $adapter->addMultiplePsr4($map); + } + + if (!empty($data['autoload']['classmap'])) { + $this->addClassmapSources($adapter, (array)$data['autoload']['classmap']); + } + + if (!empty($data['autoload']['files'])) { + foreach ($data['autoload']['files'] as $file) { + require $this->pathPrefix . $file; + } + } + } + + /** + * @param array $multiple + * + * @return array[] + */ + protected function transformMultiple(array $multiple) { + foreach ($multiple as &$paths) { + $paths = (array)$paths; + foreach ($paths as &$path) { + if ('' === $path || '/' !== $path[0]) { + $path = $this->pathPrefix . $path; + } + } + } + return $multiple; + } + + /** + * @param string[] $include_paths + */ + protected function addIncludePaths(array $include_paths) { + foreach ($include_paths as &$path) { + $path = $this->pathPrefix . $path; + } + array_push($include_paths, get_include_path()); + set_include_path(join(PATH_SEPARATOR, $include_paths)); + } + + /** + * @param ClassFinderAdapter $adapter + * @param string[] $sources_raw + * Array of files and folders to scan for class implementations. + */ + protected function addClassmapSources($adapter, array $sources_raw) { + foreach ($sources_raw as &$path) { + $path = $this->pathPrefix . $path; + } + $adapter->addClassmapSources($sources_raw); + } +} diff --git a/frontend/drupal/modules/xautoload/src/Discovery/ComposerJsonTargetDir.php b/frontend/drupal/modules/xautoload/src/Discovery/ComposerJsonTargetDir.php new file mode 100644 index 000000000..26a452807 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/Discovery/ComposerJsonTargetDir.php @@ -0,0 +1,118 @@ +targetDir = rtrim($data['target-dir'], '/') . '/'; + } + + /** + * @param ClassFinderAdapter $adapter + * + * @throws \Exception + */ + function writeToAdapter(ClassFinderAdapter $adapter) { + + $data = $this->data; + + if (!empty($data['include-path'])) { + $paths = $this->pathsResolveTargetDir((array) $data['include-path']); + $this->addIncludePaths($paths, $this->pathPrefix); + } + + if (!empty($data['autoload']['psr-0'])) { + $this->addMultipleWithTargetDir($adapter, $data['autoload']['psr-0']); + } + + if (!empty($data['autoload']['psr-4'])) { + throw new \Exception("PSR-4 is incompatible with target-dir."); + } + + if (!empty($data['autoload']['classmap'])) { + $paths = $this->pathsResolveTargetDir($data['autoload']['classmap']); + $this->addClassmapSources($adapter, $paths); + } + + if (!empty($data['autoload']['files'])) { + $paths = $this->pathsResolveTargetDir($data['autoload']['files']); + foreach ($paths as $file) { + require $this->pathPrefix . $file; + } + } + } + + /** + * @param string[] $paths + * + * @return string[] + */ + protected function pathsResolveTargetDir(array $paths) { + $strlen = strlen($this->targetDir); + foreach ($paths as &$path) { + if (0 === strpos($path, $this->targetDir)) { + $path = substr($path, $strlen); + } + } + + return $paths; + } + + /** + * @param ClassFinderAdapter $adapter + * @param array $prefixes + */ + protected function addMultipleWithTargetDir(ClassFinderAdapter $adapter, array $prefixes) { + $default_behavior = new DefaultDirectoryBehavior(); + $psr0_behavior = new Psr0DirectoryBehavior(); + $namespace_map = array(); + $prefix_map = array(); + $target_dir_strlen = strlen($this->targetDir); + foreach ($prefixes as $prefix => $paths) { + if (FALSE === strpos($prefix, '\\')) { + $logical_base_path = Util::prefixLogicalPath($prefix); + foreach ((array) $paths as $root_path) { + $deep_path = strlen($root_path) + ? rtrim($root_path, '/') . '/' . $logical_base_path + : $logical_base_path; + if (0 !== strpos($deep_path, $this->targetDir)) { + continue; + } + $deep_path = $this->pathPrefix . substr($deep_path, $target_dir_strlen); + $prefix_map[$logical_base_path][$deep_path] = $default_behavior; + } + } + $logical_base_path = Util::namespaceLogicalPath($prefix); + foreach ((array) $paths as $root_path) { + $deep_path = strlen($root_path) + ? rtrim($root_path, '/') . '/' . $logical_base_path + : $logical_base_path; + if (0 !== strpos($deep_path, $this->targetDir)) { + continue; + } + $deep_path = $this->pathPrefix . substr($deep_path, $target_dir_strlen); + $namespace_map[$logical_base_path][$deep_path] = $psr0_behavior; + } + } + if (!empty($prefix_map)) { + $adapter->getPrefixMap()->registerDeepPaths($prefix_map); + } + $adapter->getNamespaceMap()->registerDeepPaths($namespace_map); + } +} diff --git a/frontend/drupal/modules/xautoload/src/Discovery/FileInspector.php b/frontend/drupal/modules/xautoload/src/Discovery/FileInspector.php new file mode 100644 index 000000000..f2df02589 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/Discovery/FileInspector.php @@ -0,0 +1,98 @@ +getMessage(), + // The Exception code. Defaults to 0. + 0, + // The previous exception used for exception chaining. + $e); + } + + return self::inspectFileContents($contents); + } + + /** + * @param string $contents + * The PHP file contents obtained with php_strip_whitespace($path). + * + * @return string[] + * Classes discovered in the file. + */ + protected static function inspectFileContents($contents) { + $traits = version_compare(PHP_VERSION, '5.4', '<') + ? '' + : '|trait'; + + // return early if there is no chance of matching anything in this file + if (!preg_match('{\b(?:class|interface' . $traits . ')\s}i', $contents)) { + return array(); + } + + // strip heredocs/nowdocs + $contents = preg_replace( + '{<<<\'?(\w+)\'?(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)\\1(?=\r\n|\n|\r|;)}s', + 'null', + $contents); + + // strip strings + $contents = preg_replace( + '{"[^"\\\\]*(\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(\\\\.[^\'\\\\]*)*\'}s', + 'null', + $contents); + + // strip leading non-php code if needed + if (substr($contents, 0, 2) !== '.+<\?}s', '?>'); + if (FALSE !== $pos && FALSE === strpos(substr($contents, $pos), '])(?Pclass|interface' . $traits . ') \s+ (?P[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*) + | \b(?])(?Pnamespace) (?P\s+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(?:\s*\\\\\s*[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*)? \s*[\{;] + ) + }ix', + $contents, + $matches + ); + + $classes = array(); + $namespace = ''; + + for ($i = 0, $len = count($matches['type']); $i < $len; $i++) { + if (!empty($matches['ns'][$i])) { + $namespace = str_replace(array(' ', "\t", "\r", "\n"), '', $matches['nsname'][$i]) + . '\\'; + } + else { + $classes[] = ltrim($namespace . $matches['name'][$i], '\\'); + } + } + + return $classes; + } +} diff --git a/frontend/drupal/modules/xautoload/src/Discovery/WildcardFileFinder.php b/frontend/drupal/modules/xautoload/src/Discovery/WildcardFileFinder.php new file mode 100644 index 000000000..436386824 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/Discovery/WildcardFileFinder.php @@ -0,0 +1,211 @@ + $value) { + if (1 + && FALSE !== strpos($path, '*') + && preg_match('#^([^\*]*)/(.*\*.*)$#', $path, $m) + ) { + // Resolve wildcards. + $this->value = $value; + list(, $base, $wildcard) = $m; + $this->scanDirectory($base, $wildcard); + } + else { + // Register the file directly. + $this->files[$path] = $value; + } + } + } + + /** + * @param string[] $paths + * Array keys are file paths or wildcard file paths. + * @param mixed $value + */ + function addPaths(array $paths, $value = TRUE) { + foreach ($paths as $path) { + if (1 + && FALSE !== strpos($path, '*') + && preg_match('#^([^\*]*)/(.*\*.*)$#', $path, $m) + ) { + // Resolve wildcards. + $this->value = $value; + list(, $base, $wildcard) = $m; + $this->scanDirectory($base, $wildcard); + } + elseif (is_dir($path)) { + // Resolve wildcards. + $this->value = $value; + $this->scanDirectory($path . '/', '**/*.inc'); + $this->scanDirectory($path . '/', '**/*.php'); + } + elseif (is_file($path)) { + // Register the file directly. + $this->files[$path] = $value; + } + } + } + + /** + * @return string[] + */ + function getFiles() { + return array_keys($this->files); + } + + /** + * @return mixed[] + */ + function getDrupalFiles() { + return $this->files; + } + + /** + * @param string $dir + * Base folder, e.g. "sites/all/modules/foo/includes", which does NOT + * contain any asterisk ("*"). + * @param string $wildcard + * Suffix which may contain asterisks. + */ + protected function scanDirectory($dir, $wildcard) { + if (!is_dir($dir)) { + return; + } + if (FALSE === strpos($wildcard, '*')) { + // $wildcard is a fixed string, not a wildcard. + $this->suggestFile($dir . '/' . $wildcard); + } + elseif ('**' === $wildcard) { + // Trick: "$a/**" == union of "$a/*" and "$a/*/**" + $this->scanDirectoryLevel($dir, '*'); + $this->scanDirectoryLevel($dir, '*', '**'); + } + elseif ('**/' === substr($wildcard, 0, 3)) { + // Trick: "$a/**/$b" == union of "$a/$b" and "$a/*/**/$b" + $remaining = substr($wildcard, 3); + $this->scanDirectory($dir, $remaining); + $this->scanDirectoryLevel($dir, '*', $wildcard); + } + elseif (FALSE !== ($slashpos = strpos($wildcard, '/'))) { + // $wildcard consists of more than one fragment. + $fragment = substr($wildcard, 0, $slashpos); + $remaining = substr($wildcard, $slashpos + 1); + if (FALSE === strpos($fragment, '*')) { + $this->scanDirectory($dir . '/' . $fragment, $remaining); + } + else { + $this->scanDirectoryLevel($dir, $fragment, $remaining); + } + } + else { + // $wildcard represents a file name. + $this->scanDirectoryLevel($dir, $wildcard); + } + } + + /** + * @param string $dir + * Base directory, not containing any wildcard. + * @param string $fragment + * Wildcard path fragment to be processed now. This is never '**', but it + * always contains at least one asterisk. + * @param null $remaining + * Optional rest of the wildcard string, that may contain path fragments to + * be processed later. + * + * @throws \Exception + */ + protected function scanDirectoryLevel($dir, $fragment, $remaining = NULL) { + + if (!is_dir($dir)) { + return; + } + + if ('**' === $fragment) { + throw new \Exception("Fragment must not be '**'."); + } + + foreach (scandir($dir) as $candidate) { + if (!$this->validateCandidate($candidate, $fragment)) { + continue; + } + + if (!isset($remaining)) { + $this->suggestFile($dir . '/' . $candidate); + } + else { + $this->scanDirectory($dir . '/' . $candidate, $remaining); + } + } + } + + /** + * @param $candidate + * String to be checked against the wildcard. + * @param $wildcard + * Wildcard string like '*', '*.*' or '*.inc'. + * + * @return bool + * TRUE, if $candidate matches $wildcard. + */ + protected function validateCandidate($candidate, $wildcard) { + + if ($candidate == '.' || $candidate == '..') { + return FALSE; + } + if (strpos($candidate, '*') !== FALSE) { + return FALSE; + } + if ($wildcard == '*' || $wildcard == '**') { + return TRUE; + } + + // More complex wildcard string. + $fragments = array(); + foreach (explode('*', $wildcard) as $fragment) { + $fragments[] = preg_quote($fragment); + } + $regex = implode('.*', $fragments); + + return preg_match("/^$regex$/", $candidate); + } + + /** + * @param string $path + * Add a new file path to $this->filesInRegistry(). + */ + protected function suggestFile($path) { + if (is_file($path)) { + $this->files[$path] = $this->value; + } + } +} diff --git a/frontend/drupal/modules/xautoload/src/DrupalSystem/DrupalSystem.php b/frontend/drupal/modules/xautoload/src/DrupalSystem/DrupalSystem.php new file mode 100644 index 000000000..9b8ea60a8 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/DrupalSystem/DrupalSystem.php @@ -0,0 +1,178 @@ +condition('name', $extension_names); + $q->fields('system', array('name', 'type')); + + return $q->execute()->fetchAllKeyed(); + } + + /** + * {@inheritdoc} + */ + function getActiveExtensions() { + try { + // Doing this directly tends to be a lot faster than system_list(). + return db_query("SELECT name, type from {system} WHERE status = 1") + ->fetchAllKeyed(); + } + catch (\DatabaseConnectionNotDefinedException $e) { + // During install, the database is not available. + // At this time only the system module is "installed". + /** See https://www.drupal.org/node/2393205 */ + return array('system' => 'module'); + } + catch (\PDOException $e) { + // Some time later during install, there is a database but not yet a system table. + // At this time only the system module is "installed". + // @todo Check if this is really a "Table 'system' doesn't exist'" exception. + return array('system' => 'module'); + } + } + + /** + * {@inheritdoc} + */ + function moduleImplements($hook) { + return module_implements($hook); + } + + /** + * Wrapper for module_list() + * + * @return array + */ + function moduleList() { + return module_list(); + } + + /** + * @see libraries_info() + * + * @throws \Exception + * @return mixed + */ + function getLibrariesInfo() { + if (!function_exists('libraries_info')) { + // Libraries is at a lower version, which does not have this function. + return array(); + } + # drupal_static_reset('libraries_info'); + return libraries_info(); + } + + /** + * @see libraries_get_path() + * + * @param string $name + * Name of the library. + * + * @throws \Exception + * @return string|false + */ + function librariesGetPath($name) { + if (!function_exists('libraries_get_path')) { + throw new \Exception('Function libraries_get_path() does not exist.'); + } + return libraries_get_path($name); + } + + /** + * Called from xautoload_install() to set the module weight. + * + * @param int $weight + * New module weight for xautoload. + */ + public function installSetModuleWeight($weight) { + db_update('system') + ->fields(array('weight' => $weight)) + ->condition('name', 'xautoload') + ->condition('type', 'module') + ->execute(); + system_list_reset(); + } + + /** + * @param string $cid + * @param string $bin + * + * @return mixed + * + * @see cache_get() + */ + public function cacheGet($cid, $bin = 'cache') { + return cache_get($cid, $bin); + } + + /** + * @param string $cid + * @param mixed $data + * @param string $bin + * + * @return mixed + * + * @see cache_set() + */ + public function cacheSet($cid, $data, $bin = 'cache') { + cache_set($cid, $data, $bin); + } + + /** + * @param string|null $cid + * @param string|null $bin + * + * @see cache_clear_all() + */ + public function cacheClearAll($cid = NULL, $bin = NULL) { + cache_clear_all($cid, $bin); + } + + /** + * @param string $key + */ + public function drupalStaticReset($key) { + \drupal_static_reset($key); + } +} diff --git a/frontend/drupal/modules/xautoload/src/DrupalSystem/DrupalSystemInterface.php b/frontend/drupal/modules/xautoload/src/DrupalSystem/DrupalSystemInterface.php new file mode 100644 index 000000000..6a76143a3 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/DrupalSystem/DrupalSystemInterface.php @@ -0,0 +1,145 @@ +finder = $finder; + $this->system = $system; + } + + /** + * Find the file for a class that in PSR-0 or PEAR would be in + * $psr_0_root . '/' . $path_fragment . $path_suffix + * + * @param InjectedApiInterface $api + * @param string $logical_base_path + * @param string $relative_path + * + * @return bool|null + * TRUE, if the file was found. + * FALSE or NULL, otherwise. + */ + function findFile($api, $logical_base_path, $relative_path) { + + // Prevent recursion if this is called from libraries_info(). + // @todo Find a better way to do this? + $backtrace = defined('DEBUG_BACKTRACE_IGNORE_ARGS') + ? debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS) + : debug_backtrace(FALSE); + foreach ($backtrace as $call) { + if ('libraries_info' === $call['function']) { + return FALSE; + } + } + + $this->finder->getNamespaceMap()->unregisterDeepPath('', ''); + $this->finder->getPrefixMap()->unregisterDeepPath('', ''); + $this->registerAllLibraries(); + return $this->finder->apiFindFile($api, $api->getClass()); + } + + /** + * Registers all libraries that have an "xautoload" setting. + */ + private function registerAllLibraries() { + $adapter = \xautoload_InjectedAPI_hookXautoload::create($this->finder, ''); + foreach ($info = $this->getLibrariesXautoloadInfo() as $name => $pathAndCallback) { + list($path, $callback) = $pathAndCallback; + if (!is_callable($callback)) { + continue; + } + if (!is_dir($path)) { + continue; + } + $adapter->setExtensionDir($path); + call_user_func($callback, $adapter, $path); + } + } + + /** + * @return array[] + */ + private function getLibrariesXautoloadInfo() { + $cached = $this->system->cacheGet(XAUTOLOAD_CACHENAME_LIBRARIES_INFO); + if (FALSE !== $cached) { + return $cached->data; + } + $info = $this->buildLibrariesXautoloadInfo(); + $this->system->cacheSet(XAUTOLOAD_CACHENAME_LIBRARIES_INFO, $info); + return $info; + } + + /** + * @return array[] + */ + private function buildLibrariesXautoloadInfo() { + // @todo Reset drupal_static('libraries') ? + $all = array(); + foreach ($this->system->getLibrariesInfo() as $name => $info) { + if (!isset($info['xautoload'])) { + continue; + } + $callback = $info['xautoload']; + if (!is_callable($callback)) { + continue; + } + /** See https://www.drupal.org/node/2473901 */ + $path = isset($info['library path']) + ? $info['library path'] + : $this->system->librariesGetPath($name); + if (FALSE === $path) { + continue; + } + $all[$name] = array($path, $callback); + } + return $all; + } + +} diff --git a/frontend/drupal/modules/xautoload/src/Libraries/LibrariesInfoAlter.php b/frontend/drupal/modules/xautoload/src/Libraries/LibrariesInfoAlter.php new file mode 100644 index 000000000..dc3340adc --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/Libraries/LibrariesInfoAlter.php @@ -0,0 +1,55 @@ + &$library_info) { + if (1 + && isset($library_info['xautoload']) + && is_callable($library_info['xautoload']) + ) { + $this->alterLibraryInfo($library_info, $library_name); + } + } + } + + /** + * @param array $library_info + * @param string $library_name + */ + private function alterLibraryInfo(&$library_info, $library_name) { + $callable = $library_info['xautoload']; + if ($callable instanceof \Closure) { + // Wrap the closure so it can be serialized. + $callable = new SerializableClosureWrapper( + $library_info['xautoload'], + // The module name and library name allow the closure to be recovered on + // unserialize. + $library_info['module'], + $library_name); + $library_info['xautoload'] = $callable; + } + # $library_info['callbacks']['pre-load'][] = new LibrariesPreLoadCallback($callable); + } + +} diff --git a/frontend/drupal/modules/xautoload/src/Libraries/LibrariesOnInit.php b/frontend/drupal/modules/xautoload/src/Libraries/LibrariesOnInit.php new file mode 100644 index 000000000..a2c3dce1b --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/Libraries/LibrariesOnInit.php @@ -0,0 +1,91 @@ +system = $system; + } + + /** + * Wake up after a cache fail. + * + * @param ExtendedClassFinderInterface $finder + * @param string[] $extensions + * Extension type by extension name. + */ + public function wakeUp(ExtendedClassFinderInterface $finder, array $extensions) { + $this->finder = $finder; + } + + /** + * Enter the boot phase of the request, where all bootstrap module files are included. + */ + public function enterBootPhase() { + // Nothing. + } + + /** + * Enter the main phase of the request, where all module files are included. + */ + public function enterMainPhase() { + $this->registerLibrariesFinderPlugin(); + } + + /** + * React to new extensions that were just enabled. + * + * @param string $name + * @param string $type + */ + public function welcomeNewExtension($name, $type) { + // Nothing. + } + + /** + * React to xautoload_modules_enabled() + * + * @param string[] $modules + * New module names. + */ + public function modulesEnabled($modules) { + $this->system->drupalStaticReset('libraries_info'); + $this->system->cacheClearAll(XAUTOLOAD_CACHENAME_LIBRARIES_INFO, 'cache'); + $this->registerLibrariesFinderPlugin(); + } + + /** + * Registers all libraries that have an "xautoload" setting. + */ + private function registerLibrariesFinderPlugin() { + $plugin = new LibrariesFinderPlugin($this->finder, $this->system); + $this->finder->getPrefixMap()->registerDeepPath('', '', $plugin); + $this->finder->getNamespaceMap()->registerDeepPath('', '', $plugin); + } + +} diff --git a/frontend/drupal/modules/xautoload/src/Libraries/LibrariesPreLoadCallback.php b/frontend/drupal/modules/xautoload/src/Libraries/LibrariesPreLoadCallback.php new file mode 100644 index 000000000..8048bfd60 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/Libraries/LibrariesPreLoadCallback.php @@ -0,0 +1,51 @@ +callable = $callable; + } + + /** + * Callback that is applied directly before the library is loaded. At this + * point the library contains variant-specific information, if specified. Note + * that in this group the 'variants' property is no longer available. + * + * @param array $library + * An array of library information belonging to the top-level library, a + * specific version, a specific variant or a specific variant of a specific + * version. Because library information such as the 'files' property (see + * above) can be declared in all these different locations of the library + * array, but a callback may have to act on all these different parts of the + * library, it is called recursively for each library with a certain part of + * the libraries array passed as $library each time. + * @param string|null $version + * If the $library array belongs to a certain version (see above), a string + * containing the version. This argument may be empty, so NULL should be + * specified as the default value. + * @param string|null $variant + * If the $library array belongs to a certain variant (see above), a string + * containing the variant name. This argument may be empty, so NULL should + * be specified as the default value. + */ + function __invoke($library, $version, $variant) { + if (!empty($library['installed'])) { + xautoload()->proxyFinder->observeFirstCacheMiss( + new LibraryCacheMissObserver($this->callable, $library['library path'])); + } + } + +} diff --git a/frontend/drupal/modules/xautoload/src/Libraries/LibraryCacheMissObserver.php b/frontend/drupal/modules/xautoload/src/Libraries/LibraryCacheMissObserver.php new file mode 100644 index 000000000..bda0df719 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/Libraries/LibraryCacheMissObserver.php @@ -0,0 +1,45 @@ +callable = $callable; + $this->path = $path; + } + + /** + * Executes the operation. + * + * This method will only be called if and when the "real" class finder is + * initialized. + * + * @param ExtendedClassFinderInterface $finder + * The class finder. + */ + function cacheMiss($finder) { + $adapter = \xautoload_InjectedAPI_hookXautoload::create($finder, $this->path); + call_user_func($this->callable, $adapter, $this->path); + } + +} diff --git a/frontend/drupal/modules/xautoload/src/Libraries/SerializableClosureWrapper.php b/frontend/drupal/modules/xautoload/src/Libraries/SerializableClosureWrapper.php new file mode 100644 index 000000000..90f8982b9 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/Libraries/SerializableClosureWrapper.php @@ -0,0 +1,85 @@ +closure = $closure; + $this->moduleName = $moduleName; + $this->libraryName = $libraryName; + } + + public function __sleep() { + return array('moduleName', 'libraryName'); + } + + /** + * @param \Drupal\xautoload\Adapter\LocalDirectoryAdapter $adapter + */ + public function __invoke($adapter) { + $closure = $this->lazyGetClosure(); + if ($closure instanceof \Closure) { + $closure($adapter); + } + } + + /** + * @return \Closure|FALSE + */ + private function lazyGetClosure() { + return isset($this->closure) + ? $this->closure + : $this->closure = $this->loadClosure(); + } + + /** + * @return \Closure|FALSE + */ + private function loadClosure() { + $source_function = $this->moduleName . '_libraries_info'; + if (!function_exists($source_function)) { + return FALSE; + } + $module_libraries = $source_function(); + if (!isset($module_libraries[$this->libraryName]['xautoload'])) { + return FALSE; + } + $closure_candidate = $module_libraries[$this->libraryName]['xautoload']; + if (!$closure_candidate instanceof \Closure) { + return FALSE; + } + return $closure_candidate; + } + +} diff --git a/frontend/drupal/modules/xautoload/src/Main.php b/frontend/drupal/modules/xautoload/src/Main.php new file mode 100644 index 000000000..7d9204a08 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/Main.php @@ -0,0 +1,110 @@ +services = $services; + } + + /** + * @return ServiceContainer + */ + function getServiceContainer() { + return $this->services; + } + + /** + * Invalidate all values stored in APC. + */ + function flushCache() { + $this->services->cacheManager->renewCachePrefix(); + } + + /** + * Register a module in early bootstrap, or from modulename.install. + * + * This is only needed for modules that need autoloading very early in the + * request, or e.g. during uninstall, or any situation that xautoload cannot + * catch up with. + * + * The method will register all autoloading schemes for this module that are + * supported by default: + * - PSR-0: "Drupal\\$module\\Foo" => "$module_dir/lib/Drupal/$module/Foo.php" + * - PEAR-FLAT: $module . "_Foo_Bar" => "$module_dir/lib/Foo/Bar.php" + * + * It will not register anything for PSR-4, since it is not clear whether this + * will be in "/lib/" or "/src/" or elsewhere. + * + * Suggested usage: (in your $modulename.module, or $modulename.install): + * + * xautoload()->registerModule(__FILE__); + * + * @param string $__FILE__ + * File path to a *.module or *.install file. + * The basename of the file MUST be the module name. + * It is recommended to call this from the respective file itself, using the + * __FILE__ constant for this argument. + */ + function registerModule($__FILE__) { + $this->services->extensionNamespaces->registerExtension($__FILE__); + } + + /** + * Register a module as PSR-4, in early bootstrap or from modulename.install + * + * This can be used while Drupal 8 is still undecided whether PSR-4 class + * files should live in "lib" or in "src" by default. + * + * Suggested usage: (in your $modulename.module, or $modulename.install): + * + * // E.g. "Drupal\\$module\\Foo" => "$module_dir/lib/Foo.php" + * xautoload()->registerModulePsr4(__FILE__, 'lib'); + * + * or + * + * // E.g. "Drupal\\$module\\Foo" => "$module_dir/src/Foo.php" + * xautoload()->registerModulePsr4(__FILE__, 'src'); + * + * or + * + * // E.g. "Drupal\\$module\\Foo" => "$module_dir/psr4/Foo.php" + * xautoload()->registerModulePsr4(__FILE__, 'psr4'); + * + * @param string $__FILE__ + * File path to a *.module or *.install file. + * The basename of the file MUST be the module name. + * It is recommended to call this from the respective file itself, using the + * __FILE__ constant for this argument. + * @param string $subdir + * The PSR-4 base directory for the module namespace, relative to the module + * directory. E.g. "src" or "lib". + */ + function registerModulePsr4($__FILE__, $subdir) { + $this->services->extensionNamespaces->registerExtensionPsr4($__FILE__, $subdir); + } + + /** + * Magic getter for service objects. This lets this class act as a proxy for + * the service container. + * + * @param string $key + * @return mixed + */ + function __get($key) { + return $this->services->__get($key); + } +} diff --git a/frontend/drupal/modules/xautoload/src/Phases/DrupalCoreRegistryRegistrator.php b/frontend/drupal/modules/xautoload/src/Phases/DrupalCoreRegistryRegistrator.php new file mode 100644 index 000000000..73200f5a1 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/Phases/DrupalCoreRegistryRegistrator.php @@ -0,0 +1,57 @@ +getNamespaceMap()->registerDeepPath('', 'registry', $plugin); + $finder->getPrefixMap()->registerDeepPath('', 'registry', $plugin); + } + + /** + * Enter the boot phase of the request, where all bootstrap module files are included. + */ + public function enterBootPhase() { + // Nothing. + } + + /** + * Enter the main phase of the request, where all module files are included. + */ + public function enterMainPhase() { + // Nothing. + } + + /** + * React to new extensions that were just enabled. + * + * @param string $name + * @param string $type + */ + public function welcomeNewExtension($name, $type) { + // Nothing. + } + + /** + * React to xautoload_modules_enabled() + * + * @param string[] $modules + * New module names. + */ + public function modulesEnabled($modules) { + // Nothing. + } +} diff --git a/frontend/drupal/modules/xautoload/src/Phases/DrupalPhaseControl.php b/frontend/drupal/modules/xautoload/src/Phases/DrupalPhaseControl.php new file mode 100644 index 000000000..40bc209fa --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/Phases/DrupalPhaseControl.php @@ -0,0 +1,171 @@ +system = $system; + $this->observers = $observers; + } + + /** + * {@inheritdoc} + */ + public function cacheMiss($finder) { + $this->extensions = $this->system->getActiveExtensions(); + foreach ($this->observers as $observer) { + $observer->wakeUp($finder, $this->extensions); + } + $this->awake = TRUE; + if ($this->bootPhase) { + // We slipped into boot phase while asleep. Need to catch up. + foreach ($this->observers as $observer) { + $observer->enterBootPhase(); + } + } + if ($this->mainPhase) { + // We slipped into main phase while asleep. Need to catch up. + foreach ($this->observers as $observer) { + $observer->enterMainPhase(); + } + } + } + + public function enterBootPhase() { + if ($this->bootPhase) { + // We are already in the main phase. Nothing changes. + return; + } + $this->bootPhase = TRUE; + if (!$this->awake) { + // The entire thing is not initialized yet. + // Postpone until operateOnFinder() + return; + } + foreach ($this->observers as $observer) { + $observer->enterBootPhase(); + } + } + + /** + * Initiate the main phase. + * + * Called from + * @see xautoload_custom_theme() + * @see xautolaod_init() + */ + public function enterMainPhase() { + // Main phase implies boot phase. + $this->enterBootPhase(); + if ($this->mainPhase) { + // We are already in the main phase. Nothing changes. + return; + } + $this->mainPhase = TRUE; + if (!$this->awake) { + // The entire thing is not initialized yet. + // Postpone until operateOnFinder() + return; + } + foreach ($this->observers as $observer) { + $observer->enterMainPhase(); + } + } + + /** + * Checks if new extensions have been enabled, and registers them. + * + * This is called from xautoload_module_implements_alter(), which is called + * whenever a new module is enabled, but also some calls we need to ignore. + */ + public function checkNewExtensions() { + if (!$this->awake) { + // The entire thing is not initialized yet. + // Postpone until operateOnFinder() + return; + } + $activeExtensions = $this->system->getActiveExtensions(); + if ($activeExtensions === $this->extensions) { + // Nothing actually changed. False alarm. + return; + } + // Now check all extensions to find out if any of them is new. + foreach ($activeExtensions as $name => $type) { + if (!isset($this->extensions[$name])) { + // This extension was freshly enabled. + if ('xautoload' === $name) { + // If xautoload is enabled in this request, then boot phase and main + // phase are not properly initialized yet. + $this->enterMainPhase(); + } + // Notify observers about the new extension. + foreach ($this->observers as $observer) { + $observer->welcomeNewExtension($name, $type); + } + } + } + } + + /** + * Called from @see xautoload_modules_enabled() + * + * @param $modules + */ + public function modulesEnabled($modules) { + if (!$this->awake) { + // No need to postpone. + // initMainPhase() will have these modules included. + return; + } + foreach ($this->observers as $observer) { + $observer->modulesEnabled($modules); + } + } +} diff --git a/frontend/drupal/modules/xautoload/src/Phases/ExtensionNamespaces.php b/frontend/drupal/modules/xautoload/src/Phases/ExtensionNamespaces.php new file mode 100644 index 000000000..a9a4a1894 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/Phases/ExtensionNamespaces.php @@ -0,0 +1,253 @@ +system = $system; + } + + /** + * Registers the namespaces for a module even though it might be currently + * disabled, or even though it might be early in the request. + * + * @param string $__FILE__ + */ + public function registerExtension($__FILE__) { + if (NULL === $this->finder) { + // Sleeping.. + $this->queue[$__FILE__] = FALSE; + + return; + } + + $info = pathinfo($__FILE__); + $name = $info['filename']; + + // Check if something was registered before. + if (isset($this->registered[$name])) { + // Already registered. + return; + } + + $this->_registerExtension($name, $info['dirname']); + } + + /** + * Registers the namespace with PSR-4 for a module even though it might be + * currently disabled, or even though it might be early in the request. + * + * @param string $__FILE__ + * @param string $subdir + */ + public function registerExtensionPsr4($__FILE__, $subdir) { + if (NULL === $this->finder) { + // Sleeping.. + $this->queue[$__FILE__] = $subdir; + + return; + } + + $info = pathinfo($__FILE__); + $name = $info['filename']; + + // Check if something was registered before. + if (isset($this->registered[$name])) { + if ('psr-4' === $this->registered[$name]) { + // It already happened. + return; + } + // Unregister the lazy plugins. + $this->finder->getNamespaceMap()->unregisterDeepPath( + 'Drupal/' . $name . '/', + $name + ); + $this->finder->getPrefixMap()->unregisterDeepPath( + str_replace('_', '/', $name) . '/', + $name + ); + } + $this->_registerExtensionPsr4($name, $info['dirname'], $subdir); + } + + /** + * Wake up after a cache fail. + * + * @param ExtendedClassFinderInterface $finder + * @param string[] $extensions + * Extension type by extension name. + */ + public function wakeUp(ExtendedClassFinderInterface $finder, array $extensions) { + $this->finder = $finder; + + // Register queued extensions. + foreach ($this->queue as $__FILE__ => $subdir) { + $info = pathinfo($__FILE__); + $name = $info['filename']; + $dir = $info['dirname']; + if (FALSE === $subdir) { + // This is not PSR-4. + $this->_registerExtension($name, $dir); + } + else { + // This is PSR-4. + $this->_registerExtensionPsr4($name, $dir, $subdir); + } + } + + $extensions = array_diff_key($extensions, $this->registered); + + // Register remaining extensions, using the lazy plugins. + $this->_registerLazyExtensionPlugins($extensions); + } + + /** + * Enter the boot phase of the request, where all bootstrap module files are included. + */ + public function enterBootPhase() { + // Nothing. + } + + /** + * Enter the main phase of the request, where all module files are included. + */ + public function enterMainPhase() { + // Nothing. + } + + /** + * React to new extensions that were just enabled. + * + * @param string $name + * @param string $type + */ + public function welcomeNewExtension($name, $type) { + if (isset($this->registered[$name])) { + // Already registered. + return; + } + $dir = $this->system->drupalGetPath($type, $name); + $this->_registerExtension($name, $dir); + } + + /** + * React to xautoload_modules_enabled() + * + * @param string[] $modules + * New module names. + */ + public function modulesEnabled($modules) { + // Nothing. + } + + /** + * @param string $name + * @param string $dir + */ + private function _registerExtension($name, $dir) { + if (is_dir($lib = $dir . '/lib')) { + $this->finder->addPsr0('Drupal\\' . $name . '\\', $lib); + $this->finder->addPearFlat($name . '_', $lib); + } + if (is_dir($src = $dir . '/src')) { + $this->finder->addPsr4('Drupal\\' . $name . '\\', $src); + } + + $this->registered[$name] = TRUE; + } + + /** + * @param string $name + * @param string $dir + * @param string $subdir + */ + private function _registerExtensionPsr4($name, $dir, $subdir) { + $this->finder->addPsr4('Drupal\\' . $name . '\\', $dir . '/' . $subdir); + + // Re-add the PSR-0 test directory, for consistency's sake. + if (is_dir($lib_tests = $dir . '/lib/Drupal/' . $name . '/Tests')) { + $this->finder->addPsr0('Drupal\\' . $name . '\\Tests\\', $lib_tests); + } + $this->registered[$name] = 'psr-4'; + } + + /** + * Register lazy plugins for enabled Drupal modules and themes, assuming that + * we don't know yet whether they use PSR-0, PEAR-Flat, or none of these. + * + * @param string[] $extensions + * An array where the keys are extension names, and the values are extension + * types like 'module' or 'theme'. + */ + private function _registerLazyExtensionPlugins(array $extensions) { + + $namespaceBehaviors = array(); + $prefixBehaviors = array(); + foreach (array('module', 'theme') as $extension_type) { + $namespaceBehaviors[$extension_type] = new DrupalExtensionNamespaceFinderPlugin( + $extension_type, + $this->finder->getNamespaceMap(), + $this->finder->getPrefixMap(), + $this->system); + $prefixBehaviors[$extension_type] = new DrupalExtensionUnderscoreFinderPlugin( + $extension_type, + $this->finder->getNamespaceMap(), + $this->finder->getPrefixMap(), + $this->system); + } + + $prefix_map = array(); + $namespace_map = array(); + foreach ($extensions as $name => $type) { + if (empty($namespaceBehaviors[$type])) { + // Unsupported extension type, e.g. "theme_engine". + // This can happen if a site was upgraded from Drupal 6. + // See https://drupal.org/comment/8503979#comment-8503979 + continue; + } + if (!empty($this->registered[$name])) { + // The extension has already been processed. + continue; + } + $namespace_map['Drupal/' . $name . '/'][$name] = $namespaceBehaviors[$type]; + $prefix_map[str_replace('_', '/', $name) . '/'][$name] = $prefixBehaviors[$type]; + $this->registered[$name] = TRUE; + } + + $this->finder->getNamespaceMap()->registerDeepPaths($namespace_map); + $this->finder->getPrefixMap()->registerDeepPaths($prefix_map); + } +} diff --git a/frontend/drupal/modules/xautoload/src/Phases/HookXautoload.php b/frontend/drupal/modules/xautoload/src/Phases/HookXautoload.php new file mode 100644 index 000000000..2f6215645 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/Phases/HookXautoload.php @@ -0,0 +1,111 @@ +system = $system; + } + + /** + * Wake up after a cache fail. + * + * @param ExtendedClassFinderInterface $finder + * @param string[] $extensions + * Extension type by extension name. + */ + public function wakeUp(ExtendedClassFinderInterface $finder, array $extensions) { + $this->finder = $finder; + $this->extensions = $extensions; + } + + /** + * Enter the boot phase of the request, where all bootstrap module files are included. + */ + public function enterBootPhase() { + // Nothing. + } + + /** + * Enter the main phase of the request, where all module files are included. + */ + public function enterMainPhase() { + $modules = $this->system->moduleImplements('xautoload'); + $this->runHookXautoload($modules); + } + + /** + * New extensions were enabled/installed. + * + * @param string $name + * Extension type by name. + * @param string $type + */ + public function welcomeNewExtension($name, $type) { + // Nothing. + } + + /** + * React to xautoload_modules_enabled() + * + * @param string[] $modules + * New module names. + */ + public function modulesEnabled($modules) { + $modules = $this->system->moduleImplements('xautoload'); + $this->runHookXautoload($modules); + } + + /** + * Runs hook_xautoload() on all enabled modules. + * + * This may occur multiple times in a request, if new modules are enabled. + * + * @param array $modules + */ + private function runHookXautoload(array $modules) { + // Let other modules register stuff to the finder via hook_xautoload(). + $adapter = \xautoload_InjectedAPI_hookXautoload::create($this->finder, ''); + foreach ($modules as $module) { + $adapter->setExtensionDir($dir = $this->system->drupalGetPath('module', $module)); + $function = $module . '_xautoload'; + $function($adapter, $dir); + } + } + +} diff --git a/frontend/drupal/modules/xautoload/src/Phases/HookXautoloadEarly.php b/frontend/drupal/modules/xautoload/src/Phases/HookXautoloadEarly.php new file mode 100644 index 000000000..1306cfbf4 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/Phases/HookXautoloadEarly.php @@ -0,0 +1,110 @@ +system = $system; + } + + /** + * Wake up after a cache fail. + * + * @param ExtendedClassFinderInterface $finder + * @param string[] $extensions + * Extension type by extension name. + */ + public function wakeUp(ExtendedClassFinderInterface $finder, array $extensions) { + $this->finder = $finder; + $this->extensions = $extensions; + } + + /** + * Enter the boot phase of the request, where all bootstrap module files are included. + */ + public function enterBootPhase() { + // @todo Call hook_xautoload() on bootstrap modules, if in bootstrap phase. + } + + /** + * Enter the main phase of the request, where all module files are included. + */ + public function enterMainPhase() { + // @todo Don't use moduleImplements(), to prevent hook_module_implements_alter() + $modules = $this->system->moduleImplements('xautoload'); + // @todo Remove boot modules from the list. + $this->runHookXautoload($modules); + } + + /** + * New extensions were enabled/installed. + * + * @param string $name + * Extension type by name. + * @param string $type + */ + public function welcomeNewExtension($name, $type) { + $function = $name . '_xautoload'; + if (!function_exists($function)) { + return; + } + $dir = $this->system->drupalGetPath($type, $name); + $adapter = \xautoload_InjectedAPI_hookXautoload::create($this->finder, $dir); + $function($adapter, $dir); + } + + /** + * React to xautoload_modules_enabled() + * + * @param string[] $modules + * New module names. + */ + public function modulesEnabled($modules) { + // Nothing. + } + + /** + * Runs hook_xautoload() on all enabled modules. + * + * This may occur multiple times in a request, if new modules are enabled. + * + * @param array $modules + */ + private function runHookXautoload(array $modules) { + // Let other modules register stuff to the finder via hook_xautoload(). + $adapter = \xautoload_InjectedAPI_hookXautoload::create($this->finder, ''); + foreach ($modules as $module) { + $adapter->setExtensionDir($dir = $this->system->drupalGetPath('module', $module)); + $function = $module . '_xautoload'; + $function($adapter, $dir); + } + } +} diff --git a/frontend/drupal/modules/xautoload/src/Phases/PhaseObserverInterface.php b/frontend/drupal/modules/xautoload/src/Phases/PhaseObserverInterface.php new file mode 100644 index 000000000..976fc5b59 --- /dev/null +++ b/frontend/drupal/modules/xautoload/src/Phases/PhaseObserverInterface.php @@ -0,0 +1,63 @@ +bar()" + */ + static function callbackToString($callback) { + if (is_array($callback)) { + list($obj, $method) = $callback; + if (is_object($obj)) { + $str = get_class($obj) . '->' . $method . '()'; + } + else { + $str = $obj . '::'; + $str .= $method . '()'; + } + } + else { + $str = $callback; + } + + return $str; + } + + /** + * Convert the underscores of a prefix into directory separators. + * + * @param string $prefix + * Prefix, without trailing underscore. + * + * @return string + * Path fragment representing the prefix, with trailing '/'. + */ + static function prefixLogicalPath($prefix) { + if (!strlen($prefix)) { + return ''; + } + $pear_logical_path = str_replace('_', '/', rtrim($prefix, '_') . '_'); + // Clean up surplus '/' resulting from duplicate underscores, or an + // underscore at the beginning of the class. + while (FALSE !== $pos = strrpos('/' . $pear_logical_path, '//')) { + $pear_logical_path[$pos] = '_'; + } + + return $pear_logical_path; + } + + /** + * Replace the namespace separator with directory separator. + * + * @param string $namespace + * Namespace without trailing namespace separator. + * + * @return string + * Path fragment representing the namespace, with trailing '/'. + */ + static function namespaceLogicalPath($namespace) { + return + strlen($namespace) + ? str_replace('\\', '/', rtrim($namespace, '\\') . '\\') + : ''; + } + + /** + * Check if a file exists, considering the full include path. + * Return the resolved path to that file. + * + * @param string $file + * The filepath + * @return boolean|string + * The resolved file path, if the file exists in the include path. + * FALSE, otherwise. + */ + static function findFileInIncludePath($file) { + if (function_exists('stream_resolve_include_path')) { + // Use the PHP 5.3.1+ way of doing this. + return stream_resolve_include_path($file); + } + elseif ($file[0] === '/') { + // That's an absolute path already. + return file_exists($file) + ? $file + : FALSE; + } + else { + // Manually loop all candidate paths. + foreach (explode(PATH_SEPARATOR, get_include_path()) as $base_dir) { + if (file_exists($base_dir . '/' . $file)) { + return $base_dir . '/' . $file; + } + } + + return FALSE; + } + } + + /** + * Checks whether an identifier is defined as either a class, interface or + * trait. Does not trigger autoloading. + * + * @param string $class + * @return bool + */ + static function classIsDefined($class) { + return class_exists($class, FALSE) + || interface_exists($class, FALSE) + || (PHP_VERSION_ID >= 50400 && trait_exists($class, FALSE)); + } + + /** + * Dummy method to force autoloading this class (or an ancestor). + */ + static function forceAutoload() { + // Do nothing. + } +} + diff --git a/frontend/drupal/modules/xautoload/tests/bootstrap.php b/frontend/drupal/modules/xautoload/tests/bootstrap.php new file mode 100644 index 000000000..7f4770260 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/bootstrap.php @@ -0,0 +1,37 @@ +finder->addPsr4('Drupal\xautoload\Tests\\', __DIR__ . '/src/'); + +// Use a non-cached class map generator. +xautoload()->getServiceContainer()->set('classMapGenerator', new ClassMapGenerator()); + +// Register a one-off class loader for the test PSR-4 classes. +/* +call_user_func( + function() { + $addPsr4 = function($namespace, $src) { + $strlen = strlen($namespace); + spl_autoload_register( + function ($class) use ($src, $namespace, $strlen) { + if (0 === strpos($class, $namespace)) { + $file = $src . '/' . str_replace('\\', '/', substr($class, $strlen)) . '.php'; + if (file_exists($file)) { + require_once $file; + return TRUE; + } + } + return FALSE; + } + ); + }; + $addPsr4('Drupal\xautoload\Tests\\', __DIR__ . '/src'); + $addPsr4('Drupal\xautoload\\', dirname(__DIR__) . '/src'); + } +); +*/ diff --git a/frontend/drupal/modules/xautoload/tests/fixtures/.libraries/ComposerTargetDirTestLib/Foo.php b/frontend/drupal/modules/xautoload/tests/fixtures/.libraries/ComposerTargetDirTestLib/Foo.php new file mode 100644 index 000000000..2b8fedacf --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/fixtures/.libraries/ComposerTargetDirTestLib/Foo.php @@ -0,0 +1,8 @@ +librariesLoad($name); +} diff --git a/frontend/drupal/modules/xautoload/tests/fixtures/.modules/system/system.module b/frontend/drupal/modules/xautoload/tests/fixtures/.modules/system/system.module new file mode 100644 index 000000000..b3d9bbc7f --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/fixtures/.modules/system/system.module @@ -0,0 +1 @@ +addPsr4('Drupal\testmod\\', 'psr4'); + new \Drupal\testmod\Foo(); +} + +/** + * Implements hook_libraries_info() + */ +function testmod_libraries_info() { + StaticCallLog::addCall(); + new \Drupal\testmod\Foo(); + return array( + 'testlib' => array( + 'name' => 'Test library', + 'xautoload' => '_testmod_libraries_testlib_xautoload', + ), + 'ComposerTestLib' => array( + 'xautoload' => '_testmod_libraries_ComposerTestLib_xautoload', + ), + 'ComposerTargetDirTestLib' => array( + 'xautoload' => '_testmod_libraries_ComposerTargetDirTestLib_xautoload', + ), + ); +} + +/** + * @param LocalDirectoryAdapter $adapter + */ +function _testmod_libraries_testlib_xautoload($adapter) { + StaticCallLog::addCall(); + $adapter->addPsr4('Acme\TestLib\\', 'src'); +} + +/** + * @param LocalDirectoryAdapter $adapter + */ +function _testmod_libraries_ComposerTestLib_xautoload($adapter) { + $adapter->composerJson('composer.json'); +} + +/** + * @param LocalDirectoryAdapter $adapter + */ +function _testmod_libraries_ComposerTargetDirTestLib_xautoload($adapter) { + $adapter->composerJson('composer.json'); +} diff --git a/frontend/drupal/modules/xautoload/tests/fixtures/.modules/testmod_pearflat/lib/Foo.php b/frontend/drupal/modules/xautoload/tests/fixtures/.modules/testmod_pearflat/lib/Foo.php new file mode 100644 index 000000000..9890a23ef --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/fixtures/.modules/testmod_pearflat/lib/Foo.php @@ -0,0 +1,3 @@ +main->registerModulePsr4(__FILE__, 'psr4'); + +function testmod_psr4_custom_init() { + StaticCallLog::addCall(); + new Foo; +} + +function testmod_psr4_custom_modules_enabled() { + StaticCallLog::addCall(); + new Foo; +} + +function testmod_psr4_custom_watchdog() { + StaticCallLog::addCall(); + new Foo; +} diff --git a/frontend/drupal/modules/xautoload/tests/fixtures/.modules/testmod_psr4_src/src/Foo.php b/frontend/drupal/modules/xautoload/tests/fixtures/.modules/testmod_psr4_src/src/Foo.php new file mode 100644 index 000000000..35e1e6a81 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/fixtures/.modules/testmod_psr4_src/src/Foo.php @@ -0,0 +1,5 @@ +includeAllRecursivePsr4($lib, 'Drupal\xautoload', $skip); + } + + /** + * @param string $dir + * @param string $namespace + * @param array $skip + * + * @throws \Exception + */ + private function includeAllRecursivePsr4($dir, $namespace, array $skip) { + foreach (scandir($dir) as $candidate) { + if ('.' === $candidate || '..' === $candidate) { + continue; + } + $path = $dir . '/' . $candidate; + if (in_array($path, $skip)) { + continue; + } + if (is_dir($path)) { + $this->includeAllRecursivePsr4($dir . '/' . $candidate, $namespace . '\\' . $candidate, $skip); + } + elseif (is_file($path)) { + if ('.php' === substr($candidate, -4)) { + $class = $namespace . '\\' . substr($candidate, 0, -4); + if (class_exists($class)) { + continue; + } + if (interface_exists($class)) { + continue; + } + if (function_exists('trait_exists') && trait_exists($class)) { + continue; + } + throw new \Exception("Non-existing class, trait or interface '$class'."); + } + } + } + } +} diff --git a/frontend/drupal/modules/xautoload/tests/src/ClassFinderAdapterTest.php b/frontend/drupal/modules/xautoload/tests/src/ClassFinderAdapterTest.php new file mode 100644 index 000000000..cbb2c1ee3 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/ClassFinderAdapterTest.php @@ -0,0 +1,35 @@ +filesystem = StreamWrapper::register('test'); + } + + function tearDown() { + stream_wrapper_unregister('test'); + parent::tearDown(); + } + + /** + * Test hook_registry_files_alter() wildcard replacement. + */ + public function testWildcardClassmap() { + $this->filesystem->addClass('test://lib/xy/z.php', 'Foo\Bar'); + + $this->assertFalse(class_exists('Foo\Bar', FALSE), 'Class Foo\Bar must not exist yet.'); + xautoload()->adapter->addClassmapSources(array('test://lib/**/*.php')); + $this->assertTrue(class_exists('Foo\Bar'), 'Class Foo\Bar must exist.'); + } +} diff --git a/frontend/drupal/modules/xautoload/tests/src/ClassLoaderTest.php b/frontend/drupal/modules/xautoload/tests/src/ClassLoaderTest.php new file mode 100644 index 000000000..b1b88c211 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/ClassLoaderTest.php @@ -0,0 +1,210 @@ +filesystem = StreamWrapper::register('test'); + } + + function tearDown() { + stream_wrapper_unregister('test'); + parent::tearDown(); + } + + // Test methods + // --------------------------------------------------------------------------- + + /** + * Test PSR-4-like namespaces. + */ + function testPsr4() { + + // Prepare the class finder. + $finder = new ClassFinder(); + + $finder->addPsr4('Drupal\ex_ample\\', 'test://base/lib/'); + + $this->assertCandidateOrder( + $finder, + 'Drupal\ex_ample\Psr4_%\Foo_Bar', + array('test://base/lib/Psr4_%/Foo_Bar.php')); + } + + /** + * Test PSR-0-like namespaces. + */ + function testNamespaces() { + + // Prepare the class finder. + $finder = new ClassFinder(); + $psr0 = new Psr0DirectoryBehavior(); + + $finder->registerNamespaceDeep('Drupal\\ex_ample', 'test://base/lib', $psr0); + $finder->registerNamespaceRoot('Drupal\\ex_ample', 'test://base/vendor', $psr0); + + $this->assertCandidateOrder( + $finder, + 'Drupal\ex_ample\Sub_%\Foo_Bar', + array( + 'test://base/lib/Sub_%/Foo/Bar.php', + 'test://base/vendor/Drupal/ex_ample/Sub_%/Foo/Bar.php', + )); + } + + /** + * Test PEAR-like prefixes. + */ + function testPrefixes() { + + // Prepare the class finder. + $finder = new ClassFinder(); + + $finder->registerPrefixDeep('ex_ample', 'test://base/lib'); + $finder->registerPrefixRoot('ex_ample', 'test://base/vendor'); + + $this->assertCandidateOrder( + $finder, + 'ex_ample_Sub%_Foo', + array( + 'test://base/lib/Sub%/Foo.php', + 'test://base/vendor/ex/ample/Sub%/Foo.php', + )); + } + + /** + * Tests PEAR-like class names beginning with underscore, or with a double + * underscore in between. + */ + function testSpecialUnderscores() { + + // Prepare the class finder. + $finder = new ClassFinder(); + + $finder->registerPrefixDeep('_ex_ample', 'test://lib'); + $finder->registerPrefixRoot('_ex_ample', 'test://vendor'); + + // Verify that underscores are not a problem.. + $this->assertCandidateOrder( + $finder, + '_ex_ample_Abc%_Def', array( + 'test://lib/Abc%/Def.php', + 'test://vendor/_ex/ample/Abc%/Def.php', + )); + $this->assertCandidateOrder($finder, '_abc_Foo%', array()); + $this->assertCandidateOrder($finder, 'abc__Foo%', array()); + } + + // Assertion helpers + // --------------------------------------------------------------------------- + + /** + * @param \Drupal\xautoload\ClassLoader\ClassLoaderInterface $loader + * @param string $class + * @param string $file + */ + protected function assertLoadClass($loader, $class, $file) { + + // Register the class file in the virtual filesystem. + $this->filesystem->addClass($file, $class); + + // Check that the class is not already defined. + $this->assertFalse(class_exists($class, FALSE)); + + // Trigger the class loader. + $loader->loadClass($class); + + // Check that the class is defined after the class loader has done its job. + $this->assertTrue(class_exists($class, FALSE)); + } + + /** + * @param \Drupal\xautoload\ClassLoader\ClassLoaderInterface $loader + * @param string $classTemplate + * @param string[] $expectedCandidateTemplates + */ + protected function assertCandidateOrder($loader, $classTemplate, array $expectedCandidateTemplates) { + for ($i = 0; $i < count($expectedCandidateTemplates); ++$i) { + $class = $this->replaceWildcard($classTemplate, "n$i"); + // If str_replace() is called with an array as 3rd parameter, it will do + // the replacement on all array elements. + $expectedCandidates = $this->replaceWildcardMultiple(array_slice($expectedCandidateTemplates, 0, $i + 1), "n$i"); + $this->assertFileInclusions($loader, $class, $expectedCandidates); + } + } + + /** + * Assert that inclusions are done in the expected order. + * + * @param \Drupal\xautoload\ClassLoader\ClassLoaderInterface $loader + * @param string $class + * @param string[] $expectedCandidates + */ + protected function assertFileInclusions($loader, $class, array $expectedCandidates) { + + // Register the class file in the virtual filesystem. + $this->filesystem->addClass(end($expectedCandidates), $class); + + $this->filesystem->resetReportedOperations(); + + // Check that the class is not already defined. + $this->assertFalse(class_exists($class, FALSE), "Class '$class' is not defined before loadClass()."); + + // Trigger the class loader. + $loader->loadClass($class); + + $expectedOperations = array(); + foreach ($expectedCandidates as $file) { + $expectedOperations[] = $file . ' - stat'; + } + $expectedOperations[] = end($expectedCandidates) . ' - include'; + $this->assertSame($expectedOperations, $this->filesystem->getReportedOperations()); + + // Check that the class is defined after the class loader has done its job. + $this->assertTrue(class_exists($class, FALSE), "Class is defined after loadClass()."); + } + + /** + * @param string[] $strings + * @param string $replacement + * + * @return string[] + */ + protected function replaceWildcardMultiple(array $strings, $replacement) { + foreach ($strings as &$str) { + $str = $this->replaceWildcard($str, $replacement); + } + return $strings; + } + + /** + * @param string $str + * @param string $replacement + * + * @return string + * + * @throws \Exception + */ + protected function replaceWildcard($str, $replacement) { + $fragments = explode('%', $str); + if (count($fragments) < 2) { + throw new \Exception("String '$str' does not contain a '%' wildcard."); + } + if (count($fragments) > 2) { + throw new \Exception("String '$str' has more than one '%' wildcard."); + } + return str_replace('%', $replacement, $str); + } +} diff --git a/frontend/drupal/modules/xautoload/tests/src/ComposerJsonTest.php b/frontend/drupal/modules/xautoload/tests/src/ComposerJsonTest.php new file mode 100644 index 000000000..688a04964 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/ComposerJsonTest.php @@ -0,0 +1,35 @@ + array( + 'ComposerTestLib\Foo', + 'ComposerTestLib\Other\Foo', + ), + dirname(__DIR__) . '/fixtures/.libraries/ComposerTargetDirTestLib' => array( + 'Acme\ComposerTargetDirTestLib\Foo', + ), + ) as $dir => $classes) { + $localDirectoryAdapter = new LocalDirectoryAdapter($masterAdapter, $dir); + $localDirectoryAdapter->composerJson('composer.json'); + foreach ($classes as $class) { + $this->assertFalse(class_exists($class, FALSE), "Class $class not defined yet."); + $finder->loadClass($class); + $this->assertTrue(class_exists($class, FALSE), "Class $class is defined."); + } + } + } + +} diff --git a/frontend/drupal/modules/xautoload/tests/src/DiscoveryTest.php b/frontend/drupal/modules/xautoload/tests/src/DiscoveryTest.php new file mode 100644 index 000000000..9ea0e08ef --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/DiscoveryTest.php @@ -0,0 +1,63 @@ + 'views', 'weight' => 0); + } + + // The class file is loaded using the regular uncached xautoload autoload. + $file_finder = new WildcardFileFinder(); + $file_finder->addDrupalPaths($files, TRUE); + $files = $file_finder->getDrupalFiles(); + + // The order of scandir() cannot be predicted, therefore only the sorted + // list of files is being compared here. + ksort($files); + + $expected = array ( + dirname(__DIR__) . '/fixtures/WildcardFileFinder/foo/bar.inc', + dirname(__DIR__) . '/fixtures/WildcardFileFinder/handlers/bar.inc', + dirname(__DIR__) . '/fixtures/WildcardFileFinder/handlers/foo.inc', + dirname(__DIR__) . '/fixtures/WildcardFileFinder/misc/abc', + dirname(__DIR__) . '/fixtures/WildcardFileFinder/misc/foo.bar', + dirname(__DIR__) . '/fixtures/WildcardFileFinder/misc/sub/xyz', + dirname(__DIR__) . '/fixtures/WildcardFileFinder/modules/sub/foo.inc', + dirname(__DIR__) . '/fixtures/WildcardFileFinder/modules/sub/sub/foo.inc', + dirname(__DIR__) . '/fixtures/WildcardFileFinder/modules/sub/sub/sub/foo.inc', + dirname(__DIR__) . '/fixtures/WildcardFileFinder/tests/foo.test', + dirname(__DIR__) . '/fixtures/WildcardFileFinder/tests/sub/foo.test', + dirname(__DIR__) . '/fixtures/WildcardFileFinder/tests/sub/sub/foo.test', + dirname(__DIR__) . '/fixtures/WildcardFileFinder/tests/sub/sub/sub/foo.test', + ); + + $expected = array_fill_keys( + $expected, + array ( + 'module' => 'views', + 'weight' => 0, + )); + + $this->assertEquals($expected, $files); + } + +} diff --git a/frontend/drupal/modules/xautoload/tests/src/DrupalBootTest/AbstractDrupalBootTest.php b/frontend/drupal/modules/xautoload/tests/src/DrupalBootTest/AbstractDrupalBootTest.php new file mode 100644 index 000000000..e3552e92c --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/DrupalBootTest/AbstractDrupalBootTest.php @@ -0,0 +1,221 @@ +prepare(); + + $this->prepareAllEnabled(); + + $this->exampleDrupal->boot(); + + $expectedCalls = $this->getExpectedCallsForNormalRequest(); + + $this->callLog->assertCalls($this, $expectedCalls); + + // Now we want all classes to be available. + foreach ($this->exampleModules->getExampleClasses() as $classes) { + foreach ((array)$classes as $class) { + $this->assertClassExists($class); + } + } + + $this->unprepare(); + } + + /** + * Tests a request where modules are enabled, but xautoload is already + * enabled. + * + * @dataProvider providerModuleEnable + * + * @param mixed[] $initialModules + * Initial modules being installed / enabled. + * @param array $expectedCalls + * + * @throws \Exception + */ + function testModuleEnable(array $initialModules, array $expectedCalls) { + + $this->prepare(); + + $this->prepareInitialModules($initialModules); + + foreach ($this->exampleModules->getExampleClasses() as $classes) { + foreach ((array)$classes as $class) { + $this->assertClassIsUndefined($class); + } + } + + $this->exampleDrupal->boot(); + + $new_modules = array_keys($this->exampleModules->getExampleClasses()); + $this->exampleDrupal->moduleEnable($new_modules); + + # HackyLog::log($this->callLog->getCalls()); + + $this->callLog->assertCalls($this, $expectedCalls); + + // Now we want all classes to be available. + foreach ($this->exampleModules->getExampleClasses() as $classes) { + foreach ((array)$classes as $class) { + $this->assertClassExists($class); + } + } + + $this->unprepare(); + } + + /** + * @return array[] + */ + abstract public function providerModuleEnable(); + + /** + * Start with all available modules enabled. + */ + private function prepareAllEnabled() { + foreach (array('system', 'xautoload', 'libraries') as $name) { + $this->exampleDrupal->getSystemTable()->moduleSetEnabled($name); + } + foreach ($this->exampleModules->getExampleClasses() as $name => $classes) { + $this->exampleDrupal->getSystemTable()->moduleSetEnabled($name); + } + $this->exampleDrupal->getSystemTable()->moduleSetWeight('xautoload', -90); + } + + /** + * @param mixed[] $initialModules + * Initial modules being installed / enabled. + * + * @throws \Exception + */ + private function prepareInitialModules($initialModules) { + foreach ($initialModules as $name => $state) { + if (TRUE === $state) { + // Module is installed and enabled. + $this->exampleDrupal->getSystemTable()->moduleSetEnabled($name); + $this->exampleDrupal->getSystemTable()->moduleSetSchemaVersion($name, 7000); + } + elseif (FALSE === $state) { + // Module is installed, but disabled. + $this->exampleDrupal->getSystemTable()->moduleSetSchemaVersion($name, 7000); + } + elseif (NULL === $state) { + // Module is neither installed nor enabled. + } + else { + throw new \Exception("Unexpected state."); + } + } + if (isset($initialModules['xautoload'])) { + // xautoload is installed or enabled, so the module weight must be in the database. + $this->exampleDrupal->getSystemTable()->moduleSetWeight('xautoload', -90); + } + } + + /** + * setUp() does not help us because of the process sharing problem. + * So we use this instead. + * + * @throws \Exception + */ + abstract protected function prepare(); + + /** + * Runs after a test is finished. + */ + private function unprepare() { + stream_wrapper_unregister('test'); + StaticCallLog::unsetCallLog(); + } + + /** + * @param string $class + */ + public function assertLoadClass($class) { + $this->assertFalse(class_exists($class, FALSE), "Class '$class' is not defined yet."); + $this->assertTrue(class_exists($class), "Class '$class' successfully loaded."); + } + + /** + * @param string $class + */ + public function assertClassExists($class) { + $this->assertTrue(class_exists($class), "Class '$class' exists."); + } + + /** + * @param string $class + */ + public function assertClassIsDefined($class) { + $this->assertTrue(class_exists($class, FALSE), "Class '$class' is defined."); + } + + /** + * @param string $class + */ + public function assertClassIsUndefined($class) { + $this->assertFalse(class_exists($class, FALSE), "Class '$class' is undefined."); + } + + /** + * @return array[] + */ + abstract protected function getExpectedCallsForNormalRequest(); + +} diff --git a/frontend/drupal/modules/xautoload/tests/src/DrupalBootTest/DrupalBootHookTest.php b/frontend/drupal/modules/xautoload/tests/src/DrupalBootTest/DrupalBootHookTest.php new file mode 100644 index 000000000..5b57b696b --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/DrupalBootTest/DrupalBootHookTest.php @@ -0,0 +1,172 @@ + TRUE)); + foreach (array( + 'xautoload' => array(FALSE, TRUE), + 'libraries' => array(FALSE, TRUE), + 'testmod' => array(FALSE, NULL), + ) as $module => $states) { + $initialModuleVariations = $this->providerArrayKeyVariations($initialModuleVariations, $module, $states); + } + $variations = array(); + foreach ($initialModuleVariations as $initialModuleVariation) { + $expectedCalls = array(); + + if ($hookXautoloadEarly) { + $expectedCalls[] = array( + 'function' => 'testmod_xautoload', + 'args' => array( + '(xautoload_InjectedAPI_hookXautoload)', + dirname(dirname(__DIR__)) . '/fixtures/.modules/testmod', + ), + ); + } + + if (NULL === $initialModuleVariation['testmod']) { + $expectedCalls[] = array( + 'function' => 'testmod_schema', + 'args' => array(), + ); + $expectedCalls[] = array( + 'function' => 'testmod_install', + 'args' => array(), + ); + $expectedCalls[] = array( + 'function' => 'testmod_watchdog', + 'args' => array(), + ); + } + + $expectedCalls[] = array( + 'function' => 'testmod_enable', + 'args' => array(), + ); + $expectedCalls[] = array( + 'function' => 'testmod_watchdog', + 'args' => array(), + ); + + if ($hookXautoloadLate) { + $expectedCalls[] = array( + 'function' => 'testmod_xautoload', + 'args' => array( + '(xautoload_InjectedAPI_hookXautoload)', + dirname(dirname(__DIR__)) . '/fixtures/.modules/testmod', + ), + ); + } + $expectedCalls[] = array( + 'function' => 'testmod_modules_enabled', + 'args' => array( + '(array)' + ), + ); + $expectedCalls[] = array( + 'function' => 'testmod_libraries_info', + 'args' => array(), + ); + $expectedCalls[] = array( + 'function' => '_testmod_libraries_testlib_xautoload', + 'args' => array( + '(xautoload_InjectedAPI_hookXautoload)', + dirname(dirname(__DIR__)) . '/fixtures/.libraries/testlib', + ), + ); + + $variations[] = array($initialModuleVariation, $expectedCalls); + } + return $variations; + } + + function initOnce() { + if (isset($this->exampleDrupal)) { + return; + } + $this->exampleModules = new HookTestExampleModules(); + $this->exampleDrupal = new DrupalEnvironment($this->exampleModules); + $this->exampleDrupal->setStaticInstance(); + } + + /** + * setUp() does not help us because of the process sharing problem. + * So we use this instead. + * + * @throws \Exception + */ + protected function prepare() { + $this->initOnce(); + $filesystem = StreamWrapper::register('test'); + foreach ($this->exampleModules->discoverModuleFilenames('module') as $name => $filename) { + $this->exampleDrupal->getSystemTable()->addModuleWithFilename($name, $filename); + } + $this->exampleDrupal->getSystemTable()->moduleSetEnabled('system'); + $this->exampleDrupal->initBootstrapStatus(); + # $this->exampleDrupal->getCache()->cacheSet('module_implements', $data, 'cache_bootstrap'); + xautoload()->getServiceContainer()->set('system', $this->exampleDrupal->getMockDrupalSystem()); + $this->callLog = new CallLog(); + StaticCallLog::setCallLog($this->callLog); + } + + /** + * @return array[] + */ + protected function getExpectedCallsForNormalRequest() { + $expectedCalls = array( + array( + 'function' => 'testmod_xautoload', + 'args' => array( + '(xautoload_InjectedAPI_hookXautoload)', + dirname(dirname(__DIR__)) . '/fixtures/.modules/testmod', + # 'test://modules/testmod', + ), + ), + array( + 'function' => 'testmod_init', + 'args' => array(), + ), + array( + 'function' => 'testmod_libraries_info', + 'args' => array(), + ), + array( + 'function' => '_testmod_libraries_testlib_xautoload', + 'args' => array( + '(xautoload_InjectedAPI_hookXautoload)', + dirname(dirname(__DIR__)) . '/fixtures/.libraries/testlib', + # 'test://libraries/testlib', + ), + ), + ); + return $expectedCalls; + } +} diff --git a/frontend/drupal/modules/xautoload/tests/src/DrupalBootTest/DrupalBootTest.php b/frontend/drupal/modules/xautoload/tests/src/DrupalBootTest/DrupalBootTest.php new file mode 100644 index 000000000..80b5fe6ed --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/DrupalBootTest/DrupalBootTest.php @@ -0,0 +1,157 @@ + TRUE, + * 'xautoload' => FALSE, + * 'libraries' => NULL), ...) + */ + private function initialModulesVariations($install) { + $variations = array(); + $state = $install ? NULL : FALSE; + $variation = array('system' => TRUE); + $variation += array_fill_keys(array_keys($this->exampleModules->getExampleClasses()), $state); + $variations[] = $variation; + foreach (array('xautoload') as $module) { + $variations = $this->providerArrayKeyVariations($variations, $module, array(TRUE, FALSE, NULL)); + } + return $variations; + } + + /** + * @return array[] + */ + public function providerModuleEnable() { + $this->initOnce(); + $variations = array(); + foreach (array(TRUE, FALSE) as $install) { + $expectedCalls = array(); + $enabledModulesSoFar = array(); + foreach ($this->exampleModules->getExampleClasses() as $module => $classes) { + $enabledModulesSoFar[] = $module; + if ($install) { + $expectedCalls[] = array( + 'function' => $module . '_schema', + 'args' => array(), + ); + $expectedCalls[] = array( + 'function' => $module . '_install', + 'args' => array(), + ); + foreach ($enabledModulesSoFar as $module) { + $expectedCalls[] = array( + 'function' => $module . '_watchdog', + 'args' => array(), + ); + } + } + $expectedCalls[] = array( + 'function' => $module . '_enable', + 'args' => array(), + ); + foreach ($enabledModulesSoFar as $module) { + $expectedCalls[] = array( + 'function' => $module . '_watchdog', + 'args' => array(), + ); + } + } + foreach ($this->initialModulesVariations($install) as $moduleStates) { + /* + $enabledModules = array(); + foreach ($moduleStates as $module => $state) { + if (TRUE !== $state) { + $enabledModules[$module] = TRUE; + } + } + foreach ($enabledModulesSoFar as $module) { + if (isset($enabledModules[$module])) { + unset($enabledModules[$module]); + $enabledModules[$module] = TRUE; + } + } + $enabledModules = array_keys($enabledModules); + */ + $variationExpectedCalls = $expectedCalls; + foreach (array_keys($this->exampleModules->getExampleClasses()) as $module) { + $variationExpectedCalls[] = array( + 'function' => $module . '_modules_enabled', + 'args' => array('(array)'), + ); + } + $variations[] = array($moduleStates, $variationExpectedCalls); + } + } + + return $variations; + } + + function initOnce() { + if (isset($this->exampleDrupal)) { + return; + } + $this->exampleModules = new ExampleModules(); + $this->exampleDrupal = new DrupalEnvironment($this->exampleModules); + $this->exampleDrupal->setStaticInstance(); + } + + /** + * setUp() does not help us because of the process sharing problem. + * So we use this instead. + * + * @throws \Exception + */ + protected function prepare() { + $this->initOnce(); + $filesystem = StreamWrapper::register('test'); + foreach ($this->exampleModules->discoverModuleFilenames('module') as $name => $filename) { + $this->exampleDrupal->getSystemTable()->addModuleWithFilename($name, $filename); + } + $this->exampleDrupal->getSystemTable()->moduleSetEnabled('system'); + $this->exampleDrupal->initBootstrapStatus(); + # $this->exampleDrupal->getCache()->cacheSet('module_implements', $data, 'cache_bootstrap'); + xautoload()->getServiceContainer()->set('system', $this->exampleDrupal->getMockDrupalSystem()); + $this->callLog = new CallLog(); + StaticCallLog::setCallLog($this->callLog); + } + + /** + * @return array[] + */ + protected function getExpectedCallsForNormalRequest() { + $expectedCalls = array(); + foreach ($this->exampleModules->getExampleClasses() as $module => $classes) { + $expectedCalls[] = array( + 'function' => $module . '_init', + 'args' => array(), + ); + } + return $expectedCalls; + } +} diff --git a/frontend/drupal/modules/xautoload/tests/src/Example/AbstractExampleModules.php b/frontend/drupal/modules/xautoload/tests/src/Example/AbstractExampleModules.php new file mode 100644 index 000000000..172a740cd --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/Example/AbstractExampleModules.php @@ -0,0 +1,106 @@ +getAvailableExtensions() as $name => $type) { + if ('module' !== $type) { + continue; + } + $modules[$name] = (object)array( + 'uri' => $this->getExtensionFilename($type, $name), + 'filename' => $name . '.module', + 'name' => $name, + ); + } + return $modules; + } + + /** + * @return string[] + * Extension types by name. + */ + abstract protected function getAvailableExtensions(); + + /** + * @return true[] + */ + public function getBootstrapModules() { + $bootstrap_modules = array(); + foreach ($this->discoverModuleFilenames('module') as $name => $filename) { + $php = file_get_contents($filename); + foreach (PureFunctions::bootstrapHooks() as $hook) { + if (FALSE !== strpos($php, 'function ' . $name . '_' . $hook)) { + $bootstrap_modules[$name] = TRUE; + break; + } + } + } + return $bootstrap_modules; + } + + /** + * @param \Drupal\xautoload\Tests\DrupalBootTest\AbstractDrupalBootTest $testCase + */ + public function assertLoadExampleClasses(AbstractDrupalBootTest $testCase) { + foreach ($this->getExampleClasses() as $class) { + $testCase->assertLoadClass($class); + } + } + + /** + * @return array[] + */ + abstract public function getExampleClasses(); + + /** + * @param string $type + * E.g. 'module' + * + * @return string[] + */ + function discoverModuleFilenames($type) { + $filenames = array(); + foreach ($this->getAvailableExtensions() as $name => $itemType) { + if ($type !== $itemType) { + continue; + } + $filenames[$name] = $this->getExtensionFilename($type, $name); + } + return $filenames; + } + + /** + * @param string $type + * @param string $name + * + * @return string + */ + public function getExtensionFilename($type, $name) { + if ('xautoload' === $name) { + return dirname(dirname(dirname(__DIR__))) . '/xautoload.module'; + } + $file = dirname(dirname(__DIR__)) . '/fixtures/.modules/' . $name . '/' . $name . '.module'; + if (is_file($file)) { + return $file; + } + } + +} diff --git a/frontend/drupal/modules/xautoload/tests/src/Example/ExampleModules.php b/frontend/drupal/modules/xautoload/tests/src/Example/ExampleModules.php new file mode 100644 index 000000000..647a19bc4 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/Example/ExampleModules.php @@ -0,0 +1,52 @@ + 'testmod_pearflat_Foo', + 'testmod_psr0_lib' => 'Drupal\testmod_psr0_lib\Foo', + 'testmod_psr4_custom' => 'Drupal\testmod_psr4_custom\Foo', + 'testmod_psr4_src' => 'Drupal\testmod_psr4_src\Foo', + ); + } + + /** + * Replicates drupal_parse_info_file(dirname($module->uri) . '/' . $module->name . '.info') + * + * @see drupal_parse_info_file() + * + * @param string $name + * + * @return array + * Parsed info file contents. + */ + public function drupalParseInfoFile($name) { + $info = array('core' => '7.x'); + if (0 === strpos($name, 'testmod')) { + $info['dependencies'][] = 'xautoload'; + } + return $info; + } + +} diff --git a/frontend/drupal/modules/xautoload/tests/src/Example/HookTestExampleModules.php b/frontend/drupal/modules/xautoload/tests/src/Example/HookTestExampleModules.php new file mode 100644 index 000000000..59871d244 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/Example/HookTestExampleModules.php @@ -0,0 +1,56 @@ + array( + 'Drupal\\testmod\\Foo', + 'Acme\\TestLib\\Foo', + ), + ); + } + + /** + * Replicates drupal_parse_info_file(dirname($module->uri) . '/' . $module->name . '.info') + * + * @see drupal_parse_info_file() + * + * @param string $name + * + * @return array + * Parsed info file contents. + */ + public function drupalParseInfoFile($name) { + $info = array('core' => '7.x'); + if ('testmod' === $name) { + $info['dependencies'][] = 'xautoload'; + $info['dependencies'][] = 'libraries'; + } + return $info; + } + +} diff --git a/frontend/drupal/modules/xautoload/tests/src/Filesystem/StreamWrapper.php b/frontend/drupal/modules/xautoload/tests/src/Filesystem/StreamWrapper.php new file mode 100644 index 000000000..6eb23e802 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/Filesystem/StreamWrapper.php @@ -0,0 +1,159 @@ +getStat($path); + } + + /** + * @param $path + * @param $mode + * @param $options + * @param $opened_path + * + * @return bool + * + * @throws \Exception + */ + function stream_open($path, $mode, $options, &$opened_path) { + + $this->contents = self::$filesystem->getFileContents($path); + + $this->path = $path; + $this->position = 0; + + return TRUE; + } + + /** + * @return array + * Stat for the currently open stream. + * @throws \Exception + */ + function stream_stat() { + if (!isset($this->path)) { + throw new \Exception("No file currently open."); + } + return self::$filesystem->getStat($this->path, FALSE); + } + + /** + * @param int $count + * Number of characters to read. + * + * @return string + * Snippet read from the file. + */ + function stream_read($count) { + $ret = substr($this->contents, $this->position, $count); + $this->position += strlen($ret); + + return $ret; + } + + /** + * @return bool + */ + function stream_eof() { + return $this->position >= strlen($this->contents); + } + + /** + * @param string $path + * @param int $options + * + * @return bool + */ + function dir_opendir($path, $options) { + $contents = self::$filesystem->getDirContents($path); + if (FALSE === $contents) { + return FALSE; + } + $this->path = $path; + $this->dirContents = $contents; + return TRUE; + } + + /** + * @return string + */ + function dir_readdir() { + $name = current($this->dirContents); + next($this->dirContents); + return $name; + } +} \ No newline at end of file diff --git a/frontend/drupal/modules/xautoload/tests/src/Filesystem/VirtualFilesystem.php b/frontend/drupal/modules/xautoload/tests/src/Filesystem/VirtualFilesystem.php new file mode 100644 index 000000000..ca8787dc1 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/Filesystem/VirtualFilesystem.php @@ -0,0 +1,273 @@ +reportedOperations[] = $file . ' - include'; + } + + /** + * @var string + */ + protected $instanceKey; + + /** + * @var string[] + */ + protected $knownPaths = array(); + + /** + * @var string[] + */ + protected $reportedOperations = array(); + + const NOTHING = FALSE; + const DIR = '(dir)'; + const FILE = '(file)'; + + function __construct() { + $this->instanceKey = Util::randomString(); + self::$instances[$this->instanceKey] = $this; + } + + /** + * @return array[] + */ + function getReportedOperations() { + return $this->reportedOperations; + } + + /** + * Delete all reported operations and start fresh. + */ + function resetReportedOperations() { + $this->reportedOperations = array(); + } + + /** + * @param string $file + * @param string $class + * @throws \Exception + */ + function addClass($file, $class) { + $this->addKnownFile($file); + if (self::FILE !== ($existing = $this->knownPaths[$file])) { + throw new \Exception("A non-empty file already exists at '$file'. Cannot overwrite with class '$class'."); + } + $this->knownPaths[$file] = $class; + } + + /** + * @param string $file + * @param string $php + * File contents starting with 'addKnownFile($file); + if (!$overwrite && self::FILE !== ($existing = $this->knownPaths[$file])) { + throw new \Exception("A non-empty file already exists at '$file'. Cannot overwrite with PHP code."); + } + if (0 !== strpos($php, 'knownPaths[$file] = $php; + } + + /** + * @param string[] $files + */ + function addKnownFiles(array $files) { + foreach ($files as $file) { + $this->addKnownFile($file); + } + } + + /** + * @param string $file + * + * @throws \Exception + */ + function addKnownFile($file) { + if (!isset($this->knownPaths[$file])) { + $this->knownPaths[$file] = self::FILE; + $this->addKnownDir(dirname($file)); + } + elseif (self::DIR === $this->knownPaths[$file]) { + throw new \Exception("A directory already exists at '$file', cannot overwrite with a file."); + } + } + + /** + * @param string $dir + */ + function addKnownDir($dir) { + if (FALSE === strpos($dir, '://')) { + return; + } + if (!isset($this->knownPaths[$dir])) { + // Need to set parents first. + $this->addKnownDir(dirname($dir)); + } + $this->knownPaths[$dir] = self::DIR; + } + + /** + * @param string $path + * @return string|bool + * One of self::NOTHING, self::DIR, self::FILE, or a class name for a class + * that is supposed to be defined in the file. + */ + function resolvePath($path) { + if (isset($this->knownPaths[$path])) { + return $this->knownPaths[$path]; + } + else { + return self::NOTHING; + } + } + + /** + * @param string $dir + * @return array|bool + */ + function getDirContents($dir) { + if (empty($this->knownPaths[$dir]) || self::DIR !== $this->knownPaths[$dir]) { + return FALSE; + } + $pos = strlen($dir . '/'); + $contents = array('.', '..'); + foreach ($this->knownPaths as $path => $type) { + if ($dir . '/' !== substr($path, 0, $pos)) { + continue; + } + $name = substr($path, $pos); + if (FALSE !== strpos($name, '/')) { + // This is a deeper subdirectory. + continue; + } + if ('' === $name) { + continue; + } + $contents[] = $name; + } + return $contents; + } + + /** + * @param string $path + * @param bool $report + * + * @return array + */ + function getStat($path, $report = TRUE) { + if ($report) { + $this->reportedOperations[] = $path . ' - stat'; + } + if (!isset($this->knownPaths[$path])) { + // File does not exist. + return FALSE; + } + elseif (self::DIR === $this->knownPaths[$path]) { + return stat(__DIR__); + } + else { + // Create a tmp file with the contents and get its stats. + $contents = $this->getFileContents($path); + $resource = tmpfile(); + fwrite($resource, $contents); + $stat = fstat($resource); + fclose($resource); + return $stat; + } + } + + /** + * @param $path + * The file path. + * + * @return string + * The file contents. + * + * @throws \Exception + * Exception thrown if there is no file at $path. + */ + function getFileContents($path) { + if (!isset($this->knownPaths[$path])) { + // File does not exist. + throw new \Exception("Assumed file '$path' does not exist."); + } + elseif (self::DIR === $this->knownPaths[$path]) { + throw new \Exception("Assumed file '$path' is a directory."); + } + + $instance_key_export = var_export($this->instanceKey, TRUE); + $path_export = var_export($path, TRUE); + if (self::FILE === $this->knownPaths[$path]) { + // Empty PHP file.. + return <<knownPaths[$path], 'knownPaths[$path], 5); + return <<knownPaths[$path])) { + // File with arbitrary contents. + return $this->knownPaths[$path]; + } + + // PHP file with class definition. + $class = $this->knownPaths[$path]; + + if (FALSE === ($pos = strrpos($class, '\\'))) { + // Class without namespace. + return <<components = $components; + } + + /** + * {@inheritdoc} + */ + function variableSet($name, $value) { + $this->variables[$name] = $value; + } + + /** + * {@inheritdoc} + */ + function variableGet($name, $default = NULL) { + return isset($this->variables[$name]) + ? $this->variables[$name] + : $default; + } + + /** + * {@inheritdoc} + */ + function drupalGetFilename($type, $name) { + return $this->components->DrupalGetFilename->drupalGetFilename($type, $name); + } + + /** + * {@inheritdoc} + */ + function drupalGetPath($type, $name) { + return $this->components->DrupalGetFilename->drupalGetPath($type, $name); + } + + /** + * {@inheritdoc} + */ + function getExtensionTypes($extension_names) { + // Simply assume that everything is a module. + return array_fill_keys($extension_names, 'module'); + } + + /** + * {@inheritdoc} + */ + function getActiveExtensions() { + return $this->components->SystemTable->getActiveExtensions(); + } + + /** + * Replicates module_list() + * + * @param bool $refresh + * @param bool $bootstrap_refresh + * @param bool $sort + * + * @return string[] + */ + function moduleList($refresh = FALSE, $bootstrap_refresh = FALSE, $sort = FALSE) { + return $this->components->ModuleList->moduleList($refresh, $bootstrap_refresh, $sort); + } + + /** + * @see module_invoke() + * + * @param string $module + * @param string $hook + * + * @return mixed + * + * @throws \Exception + */ + function moduleInvoke($module, $hook) { + $args = func_get_args(); + switch (count($args)) { + case 2: + return PureFunctions::moduleInvoke($module, $hook); + case 3: + return PureFunctions::moduleInvoke($module, $hook, $args[2]); + case 4: + return PureFunctions::moduleInvoke($module, $hook, $args[2], $args[3]); + default: + throw new \Exception("More arguments than expected."); + } + } + + /** + * @param string $hook + */ + function moduleInvokeAll($hook) { + $args = func_get_args(); + call_user_func_array(array($this->components->HookSystem, 'moduleInvokeAll'), $args); + } + + /** + * @param string $hook + * + * @throws \Exception + * @return array + */ + function moduleImplements($hook) { + return $this->components->HookSystem->moduleImplements($hook); + } + + /** + * @param string $hook + * @param mixed $data + */ + function drupalAlter($hook, &$data) { + $args = func_get_args(); + assert($hook === array_shift($args)); + assert($data === array_shift($args)); + while (count($args) < 3) { + $args[] = NULL; + } + $this->components->HookSystem->drupalAlter($hook, $data, $args[0], $args[1], $args[2]); + } + + /** + * Replicates module_load_include() + * + * @param string $type + * @param string $module + * @param string|null $name + * + * @return bool|string + */ + function moduleLoadInclude($type, $module, $name = NULL) { + if (!isset($name)) { + $name = $module; + } + $file = $this->drupalGetPath('module', $module) . "/$name.$type"; + if (is_file($file)) { + require_once $file; + return $file; + } + return FALSE; + } + + /** + * Resets the module_implements() cache. + */ + public function resetModuleImplementsCache() { + $this->components->HookSystem->moduleImplementsReset(); + } + + /** + * @see libraries_info() + * + * @return mixed + */ + function getLibrariesInfo() { + $this->components->LibrariesInfo->resetLibrariesInfo(); + return $this->components->LibrariesInfo->getLibrariesInfo(); + } + + /** + * @see libraries_get_path() + * + * @param string $name + * Name of the library. + * + * @return string|false + */ + function librariesGetPath($name) { + return $this->components->LibrariesInfo->librariesGetPath($name); + } + + /** + * Called from xautoload_install() to set the module weight. + * + * @param int $weight + * New module weight for xautoload. + */ + public function installSetModuleWeight($weight) { + $this->components->SystemTable->moduleSetWeight('xautoload', $weight); + $this->components->SystemListReset->systemListReset(); + } + + /** + * @param string $cid + * @param string $bin + * + * @return object|false + * The cache or FALSE on failure. + * + * @see cache_get() + */ + public function cacheGet($cid, $bin = 'cache') { + return $this->components->Cache->cacheGet($cid, $bin); + } + + /** + * @param string $cid + * @param mixed $data + * @param string $bin + * + * @return mixed + * + * @see cache_set() + */ + public function cacheSet($cid, $data, $bin = 'cache') { + $this->components->Cache->cacheSet($cid, $data, $bin); + } + + /** + * @param string|null $cid + * @param string|null $bin + * + * @see cache_clear_all() + */ + public function cacheClearAll($cid = NULL, $bin = NULL) { + $this->components->Cache->cacheClearAll($cid, $bin); + } + + /** + * @param string $key + */ + public function drupalStaticReset($key) { + $this->components->DrupalStatic->resetKey($key); + } + +} diff --git a/frontend/drupal/modules/xautoload/tests/src/Util/CallLog.php b/frontend/drupal/modules/xautoload/tests/src/Util/CallLog.php new file mode 100644 index 000000000..72911a7e0 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/Util/CallLog.php @@ -0,0 +1,75 @@ +calls[] = $call; + } + + /** + * @return array[] + */ + function getCalls() { + return $this->calls; + } + + /** + * @param \PHPUnit_Framework_TestCase $testCase + * @param array[] $expectedCalls + */ + function assertCalls(\PHPUnit_Framework_TestCase $testCase, array $expectedCalls) { + if (array_values($expectedCalls) !== $expectedCalls) { + throw new \InvalidArgumentException('$expectedCalls must be a numeric array with no keys missing.'); + } + $extractFunction = array($this, 'callGetFunction'); + $testCase->assertEquals( + "\n" . implode("\n", array_map($extractFunction, $expectedCalls)) . "\n", + "\n" . implode("\n", array_map($extractFunction, $this->calls)) . "\n"); + $testCase->assertEquals($expectedCalls, $this->calls); + for ($i = 0; TRUE; ++$i) { + $actualCall = isset($this->calls[$i]) ? $this->calls[$i] : NULL; + $expectedCall = isset($expectedCalls[$i]) ? $expectedCalls[$i] : NULL; + if (NULL === $actualCall && NULL === $expectedCall) { + break; + } + if (NULL === $actualCall) { + $testCase->fail("Call $i missing.\nExpected: " . var_export($expectedCall, TRUE)); + break; + } + if (NULL === $expectedCall) { + $testCase->fail("Call $i was not expected.\nActual: " . var_export($actualCall, TRUE)); + break; + } + if ($actualCall !== $expectedCall) { + $testCase->fail("Call $i mismatch.\nExpected: " . var_export($expectedCall, TRUE) . "\nActual: " . var_export($this->calls[$i], TRUE)); + break; + } + } + $testCase->assertEquals($expectedCalls, $this->calls); + } + + function callGetFunction($call) { + if (!isset($call['function'])) { + return NULL; + } + if (!isset($call['class'])) { + return $call['function']; + } + return $call['class'] . '::' . $call['function']; + } + +} diff --git a/frontend/drupal/modules/xautoload/tests/src/Util/HackyLog.php b/frontend/drupal/modules/xautoload/tests/src/Util/HackyLog.php new file mode 100644 index 000000000..63452fbfe --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/Util/HackyLog.php @@ -0,0 +1,23 @@ +=') + ? debug_backtrace(0, 2) + // Second parameter not supported in PHP < 5.4.0. It would cause a + // "Warning: debug_backtrace() expects at most 1 parameter, 2 given". + : debug_backtrace(0); + + $call = $trace[1]; + $callFiltered = array(); + foreach (array('function', 'class', 'type') as $key) { + if (isset($call[$key])) { + $callFiltered[$key] = $call[$key]; + } + } + $callFiltered['args'] = array(); + foreach ($call['args'] as $arg) { + if (is_array($arg)) { + $arg = '(array)'; + } + elseif (is_object($arg)) { + $arg = '(' . get_class($arg) . ')'; + } + $callFiltered['args'][] = $arg; + } + self::$callLog->addCall($callFiltered); + } +} diff --git a/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/Cache.php b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/Cache.php new file mode 100644 index 000000000..5254d7eb7 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/Cache.php @@ -0,0 +1,68 @@ +cache[$bin][$cid])) { + return FALSE; + } + return $this->cache[$bin][$cid]; + } + + /** + * @param string $cid + * @param mixed $data + * @param string $bin + * + * @see cache_set() + */ + function cacheSet($cid, $data, $bin = 'cache') { + $this->cache[$bin][$cid] = (object)array( + 'data' => $data, + ); + } + + /** + * @param null $cid + * @param null $bin + * + * @return mixed + * + * @see cache_clear_all() + */ + function cacheClearAll($cid = NULL, $bin = NULL) { + if (!isset($cid) && !isset($bin)) { + $this->cacheClearAll(NULL, 'cache_page'); + return NULL; + } + elseif (!isset($cid)) { + unset($this->cache[$bin]); + } + elseif (!isset($bin)) { + throw new \InvalidArgumentException("No cache \$bin argument given."); + } + else { + unset($this->cache[$bin][$cid]); + } + } + +} diff --git a/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/DrupalBootstrap.php b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/DrupalBootstrap.php new file mode 100644 index 000000000..38932f86f --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/DrupalBootstrap.php @@ -0,0 +1,120 @@ +drupalLoad = $drupalLoad; + $this->hookSystem = $hookSystem; + $this->moduleList = $moduleList; + } + + /** + * @see drupal_bootstrap() + */ + function boot() { + $this->drupalBootstrapVariables(); + $this->drupalBootstrapPageHeader(); + $this->drupalBootstrapFull(); + } + + /** + * @see _drupal_bootstrap_variables() + */ + private function drupalBootstrapVariables() { + $this->moduleLoadAll(TRUE); + } + + /** + * @see _drupal_bootstrap_page_header() + */ + private function drupalBootstrapPageHeader() { + $this->bootstrapInvokeAll('boot'); + } + + /** + * @see _drupal_bootstrap_full() + */ + private function drupalBootstrapFull() { + $this->moduleLoadAll(); + $this->menuSetCustomTheme(); + $this->hookSystem->moduleInvokeAll('init'); + } + + /** + * @see menu_set_custom_theme() + */ + private function menuSetCustomTheme() { + $this->hookSystem->moduleInvokeAll('custom_theme'); + } + + /** + * Replicates module_load_all() + * + * @see module_load_all() + * + * @param bool|null $bootstrap + * + * @return bool + */ + private function moduleLoadAll($bootstrap = FALSE) { + if (isset($bootstrap)) { + foreach ($this->moduleList->moduleList(TRUE, $bootstrap) as $module) { + $this->drupalLoad->drupalLoad('module', $module); + } + // $has_run will be TRUE if $bootstrap is FALSE. + $this->moduleLoadAllHasRun = !$bootstrap; + } + return $this->moduleLoadAllHasRun; + } + + /** + * @see bootstrap_invoke_all() + * + * @param string $hook + */ + private function bootstrapInvokeAll($hook) { + // Bootstrap modules should have been loaded when this function is called, so + // we don't need to tell module_list() to reset its internal list (and we + // therefore leave the first parameter at its default value of FALSE). We + // still pass in TRUE for the second parameter, though; in case this is the + // first time during the bootstrap that module_list() is called, we want to + // make sure that its internal cache is primed with the bootstrap modules + // only. + foreach ($this->moduleList->moduleList(FALSE, TRUE) as $module) { + $this->drupalLoad->drupalLoad('module', $module); + PureFunctions::moduleInvoke($module, $hook); + } + } +} diff --git a/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/DrupalComponentContainer.php b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/DrupalComponentContainer.php new file mode 100644 index 000000000..e0d7f6d7a --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/DrupalComponentContainer.php @@ -0,0 +1,268 @@ +exampleModules = $exampleModules; + } + + /** + * Magic getter for a Drupal component. + * + * @param string $key + * + * @return object + * + * @throws \Exception + */ + function __get($key) { + if (array_key_exists($key, $this->components)) { + return $this->components[$key]; + } + $method = 'get' . $key; + if (!method_exists($this, $method)) { + throw new \Exception("Unsupported key '$key' for DrupalComponentContainer."); + } + return $this->components[$key] = $this->$method($this); + } + + /** + * @return SystemTable + * + * @see DrupalComponentContainer::SystemTable + */ + protected function getSystemTable() { + return new SystemTable(); + } + + /** + * @return Cache + * + * @see DrupalComponentContainer::Cache + */ + protected function getCache() { + return new Cache(); + } + + /** + * @return DrupalStatic + * + * @see DrupalComponentContainer::DrupalStatic + */ + protected function getDrupalStatic() { + return new DrupalStatic(); + } + + /** + * @return DrupalGetFilename + * + * @see DrupalComponentContainer::DrupalGetFilename + */ + protected function getDrupalGetFilename() { + return new DrupalGetFilename($this->SystemTable, $this->exampleModules); + } + + /** + * @return HookSystem + * + * @see DrupalComponentContainer::HookSystem + */ + protected function getHookSystem() { + return new HookSystem( + $this->DrupalStatic, + $this->Cache, + $this->ModuleList); + } + + /** + * @return ModuleEnable + * + * @see DrupalComponentContainer::ModuleEnable + */ + protected function getModuleEnable() { + return new ModuleEnable( + $this->DrupalGetFilename, + $this->HookSystem, + $this->ModuleList, + $this->SystemTable, + $this->SystemListReset, + $this->SystemRebuildModuleData, + $this->SystemUpdateBootstrapStatus); + } + + /** + * @return ModuleList + * + * @see DrupalComponentContainer::ModuleList + */ + protected function getModuleList() { + return new ModuleList( + $this->DrupalGetFilename, + $this->SystemList, + $this->DrupalStatic); + } + + /** + * @return SystemListReset + * + * @see DrupalComponentContainer::SystemListReset + */ + protected function getSystemListReset() { + return new SystemListReset( + $this->Cache, + $this->DrupalStatic); + } + + /** + * @return ModuleBuildDependencies + * + * @see DrupalComponentContainer::ModuleBuildDependencies + */ + protected function getModuleBuildDependencies() { + return new ModuleBuildDependencies(); + } + + /** + * @return SystemBuildModuleData + * + * @see DrupalComponentContainer::SystemBuildModuleData + */ + protected function getSystemBuildModuleData() { + return new SystemBuildModuleData( + $this->exampleModules, + $this->HookSystem); + } + + /** + * @return SystemRebuildModuleData + * + * @see DrupalComponentContainer::SystemRebuildModuleData + */ + protected function getSystemRebuildModuleData() { + return new SystemRebuildModuleData( + $this->DrupalStatic, + $this->ModuleBuildDependencies, + $this->SystemTable, + $this->SystemBuildModuleData, + $this->SystemListReset); + } + + /** + * @return SystemUpdateBootstrapStatus + * + * @see DrupalComponentContainer::SystemUpdateBootstrapStatus + */ + protected function getSystemUpdateBootstrapStatus() { + return new SystemUpdateBootstrapStatus( + $this->HookSystem, + $this->SystemTable, + $this->SystemListReset); + } + + /** + * @return SystemList + * + * @see DrupalComponentContainer::SystemList + */ + protected function getSystemList() { + return new SystemList( + $this->Cache, + $this->SystemTable, + $this->DrupalGetFilename, + $this->DrupalStatic); + } + + /** + * @return LibrariesInfo + * + * @see DrupalComponentContainer::LibrariesInfo + */ + protected function getLibrariesInfo() { + return new LibrariesInfo( + $this->DrupalStatic, + $this->HookSystem); + } + + /** + * @return LibrariesLoad + * + * @see DrupalComponentContainer::LibrariesLoad + */ + protected function getLibrariesLoad() { + return new LibrariesLoad( + $this->DrupalStatic, + $this->Cache, + $this->LibrariesInfo); + } + + /** + * @return DrupalBootstrap + * + * @see DrupalComponentContainer::DrupalBoot + */ + protected function getDrupalBoot() { + return new DrupalBootstrap( + $this->DrupalLoad, + $this->HookSystem, + $this->ModuleList); + } + + /** + * @return MockDrupalSystem + * + * @see DrupalComponentContainer::MockDrupalSystem + */ + protected function getMockDrupalSystem() { + return new MockDrupalSystem($this); + } + + /** + * @return DrupalLoad + * + * @see DrupalComponentContainer::DrupalLoad + */ + protected function getDrupalLoad() { + return new DrupalLoad( + $this->DrupalGetFilename); + } + +} diff --git a/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/DrupalEnvironment.php b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/DrupalEnvironment.php new file mode 100644 index 000000000..bafef37a2 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/DrupalEnvironment.php @@ -0,0 +1,106 @@ +components = new DrupalComponentContainer($exampleModules); + $this->exampleModules = $exampleModules; + } + + function setStaticInstance() { + self::$staticInstance = $this; + } + + /** + * @return DrupalEnvironment + */ + static function getInstance() { + return self::$staticInstance; + } + + /** + * @return MockDrupalSystem + */ + function getMockDrupalSystem() { + return $this->components->MockDrupalSystem; + } + + /** + * @return Cache + */ + function getCache() { + return $this->components->Cache; + } + + /** + * @return SystemTable + */ + function getSystemTable() { + return $this->components->SystemTable; + } + + /** + * Simulates Drupal's \module_enable() + * + * @param string[] $module_list + * Array of module names. + * @param bool $enable_dependencies + * TRUE, if dependencies should be enabled too. + * + * @return bool + */ + function moduleEnable(array $module_list, $enable_dependencies = TRUE) { + $this->components->ModuleEnable->moduleEnable($module_list, $enable_dependencies); + } + + /** + * Replicates the Drupal bootstrap. + */ + public function boot() { + $this->components->DrupalBoot->boot(); + } + + /** + * Version of systemUpdateBootstrapStatus() with no side effects. + * + * @see _system_update_bootstrap_status() + */ + public function initBootstrapStatus() { + $bootstrap_modules = $this->exampleModules->getBootstrapModules(); + $this->components->SystemTable->setBootstrapModules($bootstrap_modules); + } + + /** + * @param string $name + * + * @return mixed + */ + public function librariesLoad($name) { + return $this->components->LibrariesLoad->librariesLoad($name); + } + +} diff --git a/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/DrupalGetFilename.php b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/DrupalGetFilename.php new file mode 100644 index 000000000..d50039a27 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/DrupalGetFilename.php @@ -0,0 +1,97 @@ +systemTable = $systemTable; + $this->exampleModules = $exampleModules; + } + + /** + * Replicates drupal_get_filename(*, *, $filename) + * + * @param string $type + * @param string $name + * @param string $filename + */ + function drupalSetFilename($type, $name, $filename) { + if (file_exists($filename)) { + $this->files[$type][$name] = $filename; + } + } + + /** + * Replicates drupal_get_filename(*, *, NULL) + * + * @param string $type + * @param string $name + * + * @return string|null + */ + function drupalGetFilename($type, $name) { + + // Profiles are a special case: they have a fixed location and naming. + if ($type == 'profile') { + $profile_filename = "profiles/$name/$name.profile"; + $this->files[$type][$name] = file_exists($profile_filename) + ? $profile_filename + : FALSE; + } + + // Look in runtime cache. + if (isset($this->files[$type][$name])) { + return $this->files[$type][$name]; + } + + // Load from the database. + $file = $this->systemTable->moduleGetFilename($name); + if (isset($file) && file_exists($file)) { + $this->files[$type][$name] = $file; + return $file; + } + + // Fallback: Search the filesystem. + $this->files[$type] = $this->exampleModules->discoverModuleFilenames($type); + + if (isset($this->files[$type][$name])) { + return $this->files[$type][$name]; + } + + return NULL; + } + + /** + * @see drupal_get_path() + * + * @param string $type + * @param string $name + * + * @return string|null + */ + function drupalGetPath($type, $name) { + return dirname($this->drupalGetFilename($type, $name)); + } +} diff --git a/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/DrupalLoad.php b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/DrupalLoad.php new file mode 100644 index 000000000..f6e857bc2 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/DrupalLoad.php @@ -0,0 +1,46 @@ +drupalGetFilename = $drupalGetFilename; + } + + /** + * @see drupal_load() + */ + function drupalLoad($type, $name) { + + if (isset($this->files[$type][$name])) { + return TRUE; + } + + $filename = $this->drupalGetFilename->drupalGetFilename($type, $name); + + if ($filename) { + include_once $filename; + $this->files[$type][$name] = TRUE; + + return TRUE; + } + + return FALSE; + } +} diff --git a/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/DrupalStatic.php b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/DrupalStatic.php new file mode 100644 index 000000000..1747d7a0f --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/DrupalStatic.php @@ -0,0 +1,88 @@ +data[$name]) || array_key_exists($name, $this->data)) { + // Non-NULL $name and both $this->data[$name] and $this->default[$name] statics exist. + return $this->data[$name]; + } + // Neither $this->data[$name] nor $this->default[$name] static variables exist. + // First call with new non-NULL $name. Initialize a new static variable. + $this->default[$name] = $this->data[$name] = $default_value; + return $this->data[$name]; + } + + /** + * Replicates drupal_static($name, NULL, TRUE). + * + * @see drupal_static() + * + * @param string $name + * + * @return array + */ + public function &resetKey($name) { + if (!isset($name)) { + throw new \InvalidArgumentException('$name cannot be NULL.'); + } + // First check if dealing with a previously defined static variable. + if (isset($this->data[$name]) || array_key_exists($name, $this->data)) { + // Non-NULL $name and both $this->data[$name] and $this->default[$name] statics exist. + // Reset pre-existing static variable to its default value. + $this->data[$name] = $this->default[$name]; + return $this->data[$name]; + } + // Neither $this->data[$name] nor $this->default[$name] static variables exist. + // Reset was called before a default is set and yet a variable must be + // returned. + return $this->data; + } + + /** + * Replicates drupal_static(NULL, NULL, TRUE). + * + * @see drupal_static() + * + * @return array + */ + public function &resetAll() { + // Reset all: ($name == NULL). This needs to be done one at a time so that + // references returned by earlier invocations of drupal_static() also get + // reset. + foreach ($this->default as $name => $value) { + $this->data[$name] = $value; + } + // As the function returns a reference, the return should always be a + // variable. + return $this->data; + } +} diff --git a/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/ExampleModulesInterface.php b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/ExampleModulesInterface.php new file mode 100644 index 000000000..21b2b9e67 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/ExampleModulesInterface.php @@ -0,0 +1,48 @@ + (object)array( + * 'uri' => 'sites/all/modules/contrib/devel/devel.module', + * 'filename' => 'devel.module', + * 'name' => 'devel', + * )); + */ + public function drupalSystemListingModules(); + + /** + * Replicates drupal_parse_info_file(dirname($module->uri) . '/' . $module->name . '.info') + * + * @see drupal_parse_info_file() + * + * @param string $name + * + * @return array + * Parsed info file contents. + */ + public function drupalParseInfoFile($name); + + /** + * @return true[] + */ + public function getBootstrapModules(); +} diff --git a/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/HookSystem.php b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/HookSystem.php new file mode 100644 index 000000000..7a0d74097 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/HookSystem.php @@ -0,0 +1,71 @@ +moduleImplements = new ModuleImplements($drupalStatic, $cache, $moduleList, $this); + } + + /** + * @param string $hook + */ + function moduleInvokeAll($hook) { + $args = func_get_args(); + assert($hook === array_shift($args)); + foreach ($this->moduleImplements($hook) as $extension) { + $function = $extension . '_' . $hook; + if (function_exists($function)) { + call_user_func_array($function, $args); + } + } + } + + /** + * @param string $hook + * @param mixed $data + */ + function drupalAlter($hook, &$data) { + $args = func_get_args(); + assert($hook === array_shift($args)); + assert($data === array_shift($args)); + while (count($args) < 3) { + $args[] = NULL; + } + foreach ($this->moduleImplements($hook . '_alter') as $extension) { + $function = $extension . '_' . $hook . '_alter'; + $function($data, $args[0], $args[1], $args[2]); + } + } + + /** + * @param string $hook + * + * @throws \Exception + * @return array + */ + function moduleImplements($hook) { + return $this->moduleImplements->moduleImplements($hook); + } + + /** + * Resets the module_implements() cache. + */ + public function moduleImplementsReset() { + $this->moduleImplements->reset(); + } +} diff --git a/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/LibrariesInfo.php b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/LibrariesInfo.php new file mode 100644 index 000000000..9aa0d6100 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/LibrariesInfo.php @@ -0,0 +1,198 @@ +drupalStatic = $drupalStatic; + $this->hookSystem = $hookSystem; + } + + /** + * @see libraries_info() + * + * @param string|null $name + * + * @return mixed + */ + function &getLibrariesInfo($name = NULL) { + // This static cache is re-used by libraries_detect() to save memory. + $libraries = &$this->drupalStatic->get('libraries_info'); + + if (!isset($libraries)) { + $libraries = array(); + // Gather information from hook_libraries_info(). + foreach ($this->hookSystem->moduleImplements('libraries_info') as $module) { + foreach (PureFunctions::moduleInvoke($module, 'libraries_info') as $machine_name => $properties) { + $properties['module'] = $module; + $libraries[$machine_name] = $properties; + } + } + + // Gather information from hook_libraries_info() in enabled themes. + // @see drupal_alter() + // SKIPPED + + // Gather information from .info files. + // .info files override module definitions. + // SKIPPED + + // Provide defaults. + foreach ($libraries as $machine_name => &$properties) { + $this->librariesInfoDefaults($properties, $machine_name); + } + + // Allow modules to alter the registered libraries. + $this->hookSystem->drupalAlter('libraries_info', $libraries); + + // Invoke callbacks in the 'info' group. + // SKIPPED + } + + if (isset($name)) { + if (!empty($libraries[$name])) { + return $libraries[$name]; + } + else { + $false = FALSE; + return $false; + } + } + + return $libraries; + } + + /** + * @see libraries_info_defaults() + * + * @param array $library + * @param string $name + * + * @return array + */ + private function librariesInfoDefaults(&$library, $name) { + $library += array( + 'machine name' => $name, + 'name' => $name, + 'vendor url' => '', + 'download url' => '', + 'path' => '', + 'library path' => NULL, + 'version callback' => 'libraries_get_version', + 'version arguments' => array(), + 'files' => array(), + 'dependencies' => array(), + 'variants' => array(), + 'versions' => array(), + 'integration files' => array(), + 'callbacks' => array(), + ); + $library['callbacks'] += array( + 'info' => array(), + 'pre-detect' => array(), + 'post-detect' => array(), + 'pre-dependencies-load' => array(), + 'pre-load' => array(), + 'post-load' => array(), + ); + + // Add our own callbacks before any others. + array_unshift($library['callbacks']['info'], 'libraries_prepare_files'); + array_unshift($library['callbacks']['post-detect'], 'libraries_detect_dependencies'); + + return $library; + } + + /** + * @see libraries_get_path() + * + * @param string $name + * @param string|bool $base_path + * + * @return string|bool + */ + public function librariesGetPath($name, $base_path = FALSE) { + $libraries = &$this->drupalStatic->get('libraries_get_path'); + + if (!isset($libraries)) { + $libraries = $this->librariesGetLibraries(); + } + + $path = ($base_path ? base_path() : ''); + if (!isset($libraries[$name])) { + return FALSE; + } + else { + $path .= $libraries[$name]; + } + + return $path; + } + + /** + * @see libraries_get_libraries() + */ + private function librariesGetLibraries() { + $searchdir = array(); + # $profile = drupal_get_path('profile', drupal_get_profile()); + # $config = conf_path(); + + // Similar to 'modules' and 'themes' directories in the root directory, + // certain distributions may want to place libraries into a 'libraries' + // directory in Drupal's root directory. + # $searchdir[] = 'libraries'; + + // Similar to 'modules' and 'themes' directories inside an installation + // profile, installation profiles may want to place libraries into a + // 'libraries' directory. + # $searchdir[] = "$profile/libraries"; + + // Always search sites/all/libraries. + # $searchdir[] = 'sites/all/libraries'; + + // Also search sites//*. + # $searchdir[] = "$config/libraries"; + + // Custom location to search + $searchdir[] = dirname(dirname(__DIR__)) . '/fixtures/.libraries'; + + // Retrieve list of directories. + $directories = array(); + $nomask = array('CVS'); + foreach ($searchdir as $dir) { + if (is_dir($dir) && $handle = opendir($dir)) { + while (FALSE !== ($file = readdir($handle))) { + if (!in_array($file, $nomask) && $file[0] != '.') { + if (is_dir("$dir/$file")) { + $directories[$file] = "$dir/$file"; + } + } + } + closedir($handle); + } + } + + return $directories; + } + + public function resetLibrariesInfo() { + $this->drupalStatic->resetKey('libraries_info'); + } +} diff --git a/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/LibrariesLoad.php b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/LibrariesLoad.php new file mode 100644 index 000000000..d4a5ee891 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/LibrariesLoad.php @@ -0,0 +1,337 @@ +drupalStatic = $drupalStatic; + $this->cache = $cache; + $this->librariesInfo = $librariesInfo; + } + + /** + * @param string $name + * + * @see libraries_load() + */ + function librariesLoad($name) { + $loaded = &$this->drupalStatic->get('libraries_load', array()); + + if (!isset($loaded[$name])) { + $library = $this->cache->cacheGet($name, 'cache_libraries'); + if ($library) { + $library = $library->data; + } + else { + $library = $this->librariesDetect($name); + $this->cache->cacheSet($name, $library, 'cache_libraries'); + } + + // If a variant was specified, override the top-level properties with the + // variant properties. + if (isset($variant)) { + // Ensure that the $variant key exists, and if it does not, set its + // 'installed' property to FALSE by default. This will prevent the loading + // of the library files below. + $library['variants'] += array($variant => array('installed' => FALSE)); + $library = array_merge($library, $library['variants'][$variant]); + } + // Regardless of whether a specific variant was requested or not, there can + // only be one variant of a library within a single request. + unset($library['variants']); + + // Invoke callbacks in the 'pre-dependencies-load' group. + $this->librariesInvoke('pre-dependencies-load', $library); + + // If the library (variant) is installed, load it. + $library['loaded'] = FALSE; + if ($library['installed']) { + // Load library dependencies. + if (isset($library['dependencies'])) { + foreach ($library['dependencies'] as $dependency) { + $this->librariesLoad($dependency); + } + } + + // Invoke callbacks in the 'pre-load' group. + $this->librariesInvoke('pre-load', $library); + + // Load all the files associated with the library. + $library['loaded'] = $this->librariesLoadFiles($library); + + // Invoke callbacks in the 'post-load' group. + $this->librariesInvoke('post-load', $library); + } + $loaded[$name] = $library; + } + + return $loaded[$name]; + } + + /** + * Tries to detect a library and its installed version. + * + * @param $name + * The machine name of a library to return registered information for. + * + * @return array|false + * An associative array containing registered information for the library + * specified by $name, or FALSE if the library $name is not registered. + * In addition to the keys returned by libraries_info(), the following keys + * are contained: + * - installed: A boolean indicating whether the library is installed. Note + * that not only the top-level library, but also each variant contains this + * key. + * - version: If the version could be detected, the full version string. + * - error: If an error occurred during library detection, one of the + * following error statuses: "not found", "not detected", "not supported". + * - error message: If an error occurred during library detection, a detailed + * error message. + * + * @see libraries_info() + * @see libraries_detect() + */ + private function librariesDetect($name) { + // Re-use the statically cached value of libraries_info() to save memory. + $library = & $this->librariesInfo->getLibrariesInfo($name); + + if ($library === FALSE) { + return $library; + } + // If 'installed' is set, library detection ran already. + if (isset($library['installed'])) { + return $library; + } + + $library['installed'] = FALSE; + + // Check whether the library exists. + if (!isset($library['library path'])) { + $library['library path'] = $this->librariesInfo->librariesGetPath($library['machine name']); + } + if ($library['library path'] === FALSE || !file_exists($library['library path'])) { + $library['error'] = 'not found'; + $library['error message'] = t( + 'The %library library could not be found.', array( + '%library' => $library['name'], + ) + ); + + return $library; + } + + // Invoke callbacks in the 'pre-detect' group. + $this->librariesInvoke('pre-detect', $library); + + // Detect library version, if not hardcoded. + if (!isset($library['version'])) { + // We support both a single parameter, which is an associative array, and an + // indexed array of multiple parameters. + if (isset($library['version arguments'][0])) { + // Add the library as the first argument. + $library['version'] = call_user_func_array($library['version callback'], array_merge(array($library), $library['version arguments'])); + } + elseif ('libraries_get_version' === $library['version callback']) { + $library['version'] = $this->librariesGetVersion($library, $library['version arguments']); + } + else { + $library['version'] = $library['version callback']($library, $library['version arguments']); + } + if (empty($library['version'])) { + $library['error'] = 'not detected'; + $library['error message'] = t( + 'The version of the %library library could not be detected.', array( + '%library' => $library['name'], + ) + ); + + return $library; + } + } + + // Determine to which supported version the installed version maps. + if (!empty($library['versions'])) { + ksort($library['versions']); + $version = 0; + foreach ($library['versions'] as $supported_version => $version_properties) { + if (version_compare($library['version'], $supported_version, '>=')) { + $version = $supported_version; + } + } + if (!$version) { + $library['error'] = 'not supported'; + $library['error message'] = t( + 'The installed version %version of the %library library is not supported.', array( + '%version' => $library['version'], + '%library' => $library['name'], + ) + ); + + return $library; + } + + // Apply version specific definitions and overrides. + $library = array_merge($library, $library['versions'][$version]); + unset($library['versions']); + } + + // Check each variant if it is installed. + if (!empty($library['variants'])) { + foreach ($library['variants'] as $variant_name => &$variant) { + // If no variant callback has been set, assume the variant to be + // installed. + if (!isset($variant['variant callback'])) { + $variant['installed'] = TRUE; + } + else { + // We support both a single parameter, which is an associative array, + // and an indexed array of multiple parameters. + if (isset($variant['variant arguments'][0])) { + // Add the library as the first argument, and the variant name as the second. + $variant['installed'] = call_user_func_array( + $variant['variant callback'], array_merge( + array( + $library, + $variant_name + ), $variant['variant arguments'] + ) + ); + } + else { + $variant['installed'] = $variant['variant callback']($library, $variant_name, $variant['variant arguments']); + } + if (!$variant['installed']) { + $variant['error'] = 'not found'; + $variant['error message'] = t( + 'The %variant variant of the %library library could not be found.', array( + '%variant' => $variant_name, + '%library' => $library['name'], + ) + ); + } + } + } + } + + // If we end up here, the library should be usable. + $library['installed'] = TRUE; + + // Invoke callbacks in the 'post-detect' group. + $this->librariesInvoke('post-detect', $library); + + return $library; + } + + /** + * Invokes library callbacks. + * + * @param string $group + * A string containing the group of callbacks that is to be applied. Should be + * either 'info', 'pre-detect', 'post-detect', or 'load'. + * @param array $library + * An array of library information, passed by reference. + * + * @see libraries_invoke() + */ + private function librariesInvoke($group, &$library) { + foreach ($library['callbacks'][$group] as $callback) { + if ('libraries_detect_dependencies' === $callback) { + continue; + } + $this->librariesTraverseLibrary($library, $callback); + } + } + + /** + * Helper function to apply a callback to all parts of a library. + * + * Because library declarations can include variants and versions, and those + * version declarations can in turn include variants, modifying e.g. the 'files' + * property everywhere it is declared can be quite cumbersome, in which case + * this helper function is useful. + * + * @param array $library + * An array of library information, passed by reference. + * @param callback $callback + * A string containing the callback to apply to all parts of a library. + * + * @see libraries_traverse_library() + */ + private function librariesTraverseLibrary(&$library, $callback) { + // Always apply the callback to the top-level library. + $callback($library, NULL, NULL); + + // Apply the callback to versions. + if (isset($library['versions'])) { + foreach ($library['versions'] as $version_string => &$version) { + $callback($version, $version_string, NULL); + // Versions can include variants as well. + if (isset($version['variants'])) { + foreach ($version['variants'] as $version_variant_name => &$version_variant) { + $callback($version_variant, $version_string, $version_variant_name); + } + } + } + } + + // Apply the callback to variants. + if (isset($library['variants'])) { + foreach ($library['variants'] as $variant_name => &$variant) { + $callback($variant, NULL, $variant_name); + } + } + } + + /** + * Loads a library's files. + * + * @param array $library + * An array of library information as returned by libraries_info(). + * + * @return int + * The number of loaded files. + * + * @see libraries_load_files() + */ + private function librariesLoadFiles($library) { + // Not doing anything here, since library files are not relevant for + // xautoload. + return 0; + } + + /** + * @param $library + * @param $options + * + * @return string + * + * @see libraries_get_version() + */ + private function librariesGetVersion($library, $options) { + return '1.0.0'; + } + +} diff --git a/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/ModuleBuildDependencies.php b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/ModuleBuildDependencies.php new file mode 100644 index 000000000..9510d3ea2 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/ModuleBuildDependencies.php @@ -0,0 +1,190 @@ +name]['edges'] = array(); + if (isset($file->info['dependencies']) && is_array($file->info['dependencies'])) { + foreach ($file->info['dependencies'] as $dependency) { + $dependency_data = $this->drupalParseDependency($dependency); + $graph[$file->name]['edges'][$dependency_data['name']] = $dependency_data; + } + } + } + $this->drupalDepthFirstSearch($graph); + foreach ($graph as $module => $data) { + $files[$module]->required_by = isset($data['reverse_paths']) + ? $data['reverse_paths'] + : array(); + $files[$module]->requires = isset($data['paths']) + ? $data['paths'] + : array(); + $files[$module]->sort = $data['weight']; + } + return $files; + } + + /** + * @see drupal_depth_first_search() + * + * @param $graph + */ + private function drupalDepthFirstSearch(&$graph) { + $state = array( + // The order of last visit of the depth first search. This is the reverse + // of the topological order if the graph is acyclic. + 'last_visit_order' => array(), + // The components of the graph. + 'components' => array(), + ); + // Perform the actual search. + foreach ($graph as $start => $data) { + $this->drupalDepthFirstSearchRec($graph, $state, $start); + } + + // We do such a numbering that every component starts with 0. This is useful + // for module installs as we can install every 0 weighted module in one + // request, and then every 1 weighted etc. + $component_weights = array(); + + foreach ($state['last_visit_order'] as $vertex) { + $component = $graph[$vertex]['component']; + if (!isset($component_weights[$component])) { + $component_weights[$component] = 0; + } + $graph[$vertex]['weight'] = $component_weights[$component]--; + } + } + + /** + * Performs a depth-first search on a graph. + * + * @see _drupal_depth_first_search() + * + * @param array $graph + * A three dimensional associated graph array. + * @param array $state + * An associative array. The key 'last_visit_order' stores a list of the + * vertices visited. The key components stores list of vertices belonging + * to the same the component. + * @param string $start + * An arbitrary vertex where we started traversing the graph. + * @param $component + * The component of the last vertex. + */ + function drupalDepthFirstSearchRec(&$graph, &$state, $start, &$component = NULL) { + // Assign new component for each new vertex, i.e. when not called recursively. + if (!isset($component)) { + $component = $start; + } + // Nothing to do, if we already visited this vertex. + if (isset($graph[$start]['paths'])) { + return; + } + // Mark $start as visited. + $graph[$start]['paths'] = array(); + + // Assign $start to the current component. + $graph[$start]['component'] = $component; + $state['components'][$component][] = $start; + + // Visit edges of $start. + if (isset($graph[$start]['edges'])) { + foreach ($graph[$start]['edges'] as $end => $v) { + // Mark that $start can reach $end. + $graph[$start]['paths'][$end] = $v; + + if (isset($graph[$end]['component']) && $component != $graph[$end]['component']) { + // This vertex already has a component, use that from now on and + // reassign all the previously explored vertices. + $new_component = $graph[$end]['component']; + foreach ($state['components'][$component] as $vertex) { + $graph[$vertex]['component'] = $new_component; + $state['components'][$new_component][] = $vertex; + } + unset($state['components'][$component]); + $component = $new_component; + } + // Only visit existing vertices. + if (isset($graph[$end])) { + // Visit the connected vertex. + $this->drupalDepthFirstSearchRec($graph, $state, $end, $component); + + // All vertices reachable by $end are also reachable by $start. + $graph[$start]['paths'] += $graph[$end]['paths']; + } + } + } + + // Now that any other subgraph has been explored, add $start to all reverse + // paths. + foreach ($graph[$start]['paths'] as $end => $v) { + if (isset($graph[$end])) { + $graph[$end]['reverse_paths'][$start] = $v; + } + } + + // Record the order of the last visit. This is the reverse of the + // topological order if the graph is acyclic. + $state['last_visit_order'][] = $start; + } + + /** + * @see drupal_parse_dependency() + * + * @param $dependency + * + * @return array + */ + private function drupalParseDependency($dependency) { + // We use named subpatterns and support every op that version_compare + // supports. Also, op is optional and defaults to equals. + $p_op = '(?P!=|==|=|<|<=|>|>=|<>)?'; + // Core version is always optional: 7.x-2.x and 2.x is treated the same. + $p_core = '(?:' . preg_quote('7.x') . '-)?'; + $p_major = '(?P\d+)'; + // By setting the minor version to x, branches can be matched. + $p_minor = '(?P(?:\d+|x)(?:-[A-Za-z]+\d+)?)'; + $value = array(); + $parts = explode('(', $dependency, 2); + $value['name'] = trim($parts[0]); + if (isset($parts[1])) { + $value['original_version'] = ' (' . $parts[1]; + foreach (explode(',', $parts[1]) as $version) { + if (preg_match("/^\s*$p_op\s*$p_core$p_major\.$p_minor/", $version, $matches)) { + $op = !empty($matches['operation']) ? $matches['operation'] : '='; + if ($matches['minor'] == 'x') { + // Drupal considers "2.x" to mean any version that begins with + // "2" (e.g. 2.0, 2.9 are all "2.x"). PHP's version_compare(), + // on the other hand, treats "x" as a string; so to + // version_compare(), "2.x" is considered less than 2.0. This + // means that >=2.x and <2.x are handled by version_compare() + // as we need, but > and <= are not. + if ($op == '>' || $op == '<=') { + $matches['major']++; + } + // Equivalence can be checked by adding two restrictions. + if ($op == '=' || $op == '==') { + $value['versions'][] = array('op' => '<', 'version' => ($matches['major'] + 1) . '.x'); + $op = '>='; + } + } + $value['versions'][] = array('op' => $op, 'version' => $matches['major'] . '.' . $matches['minor']); + } + } + } + return $value; + } +} diff --git a/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/ModuleEnable.php b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/ModuleEnable.php new file mode 100644 index 000000000..ba7e4cbc4 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/ModuleEnable.php @@ -0,0 +1,225 @@ +drupalGetFilename = $drupalGetFilename; + $this->hookSystem = $hookSystem; + $this->moduleList = $moduleList; + $this->systemTable = $systemTable; + $this->systemListReset = $systemListReset; + $this->systemRebuildModuleData = $systemRebuildModuleData; + $this->systemUpdateBootstrapStatus = $systemUpdateBootstrapStatus; + } + + /** + * Simulates Drupal's module_enable() + * + * @see module_enable() + * + * @param string[] $module_list + * Array of module names. + * @param bool $enable_dependencies + * TRUE, if dependencies should be enabled too. + * + * @return bool + */ + function moduleEnable(array $module_list, $enable_dependencies = TRUE) { + + if ($enable_dependencies) { + $module_list = $this->moduleEnableCheckDependencies($module_list); + } + + if (empty($module_list)) { + // Nothing to do. All modules already enabled. + return TRUE; + } + + $modules_installed = array(); + $modules_enabled = array(); + foreach ($module_list as $module) { + if (1 == $this->systemTable->moduleGetStatus($module)) { + // Already installed + enabled, do nothing. + continue; + } + if (-1 == $this->systemTable->moduleGetSchemaVersion($module)) { + // Install this module. + $this->enableModule($module, TRUE); + $modules_installed[] = $module; + $modules_enabled[] = $module; + } + else { + // Enable the module. + $this->enableModule($module, FALSE); + $modules_enabled[] = $module; + } + } + + // If any modules were newly installed, invoke hook_modules_installed(). + if (!empty($modules_installed)) { + $this->hookSystem->moduleInvokeAll('modules_installed', $modules_installed); + } + + // If any modules were newly enabled, invoke hook_modules_enabled(). + if (!empty($modules_enabled)) { + $this->hookSystem->moduleInvokeAll('modules_enabled', $modules_enabled); + } + + return TRUE; + } + + /** + * @param string[] $module_list + * + * @return string[] + * Module list with added dependencies, sorted by dependency. + * + * @throws \Exception + */ + protected function moduleEnableCheckDependencies(array $module_list) { + // Get all module data so we can find dependencies and sort. + $module_data = $this->systemRebuildModuleData->systemRebuildModuleData(); + // Create an associative array with weights as values. + $module_list = array_flip(array_values($module_list)); + + // The array is iterated over manually (instead of using a foreach) because + // modules may be added to the list within the loop and we need to process + // them. + while ($module = key($module_list)) { + next($module_list); + if (!isset($module_data[$module])) { + // This module is not found in the filesystem, abort. + throw new \Exception("Module '$module' not found."); + } + if ($module_data[$module]->status) { + // Skip already enabled modules. + unset($module_list[$module]); + continue; + } + $module_list[$module] = $module_data[$module]->sort; + + // Add dependencies to the list, with a placeholder weight. + // The new modules will be processed as the while loop continues. + foreach (array_keys($module_data[$module]->requires) as $dependency) { + if (!isset($module_list[$dependency])) { + $module_list[$dependency] = 0; + } + } + } + + if (!$module_list) { + // Nothing to do. All modules already enabled. + return array(); + } + + // Sort the module list by pre-calculated weights. + arsort($module_list); + return array_keys($module_list); + } + + /** + * @param string $extension + * @param bool $install + * + * @see module_enable() + */ + private function enableModule($extension, $install) { + + $filename = $this->drupalGetFilename->drupalGetFilename('module', $extension); + + // Include module files. + require_once $filename; + if (file_exists($install_file = dirname($filename) . '/' . $extension . '.install')) { + require_once $install_file; + } + + // Update status in system table + $this->systemTable->moduleSetEnabled($extension); + + // Clear various caches, especially hook_module_implements() + $this->systemListReset->systemListReset(); + $this->moduleList->moduleList(TRUE); + $this->hookSystem->moduleImplementsReset(); + $this->systemUpdateBootstrapStatus->systemUpdateBootstrapStatus(); + + // Update the registry to include it. + # registry_update(); + // Refresh the schema to include it. + # drupal_get_schema(NULL, TRUE); + // Update the theme registry to include it. + # drupal_theme_rebuild(); + // Clear entity cache. + # entity_info_cache_clear(); + + if ($install) { + PureFunctions::moduleInvoke($extension, 'schema'); + $this->systemTable->moduleSetSchemaVersion($extension, 7000); + PureFunctions::moduleInvoke($extension, 'update_last_removed'); + // Optional hook_install().. + PureFunctions::moduleInvoke($extension, 'install'); + // Optional watchdog() + $this->hookSystem->moduleInvokeAll('watchdog'); + } + // hook_enable() + PureFunctions::moduleInvoke($extension, 'enable'); + // watchdog() + $this->hookSystem->moduleInvokeAll('watchdog'); + } +} diff --git a/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/ModuleImplements.php b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/ModuleImplements.php new file mode 100644 index 000000000..861614f25 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/ModuleImplements.php @@ -0,0 +1,197 @@ +drupalStatic = $drupalStatic; + $this->cache = $cache; + $this->moduleList = $moduleList; + $this->hookSystem = $hookSystem; + } + + /** + * Replicates module_implements(*, *, TRUE) + * + * @see module_implements() + * + * @return null + */ + function reset() { + + // Use the advanced drupal_static() pattern, since this is called very often. + if (!isset($this->drupalStaticFast)) { + $this->drupalStaticFast['implementations'] = &$this->drupalStatic->get('module_implements'); + } + $implementations = &$this->drupalStaticFast['implementations']; + + $implementations = array(); + $this->cache->cacheSet('module_implements', array(), 'cache_bootstrap'); + $this->drupalStatic->resetKey('module_hook_info'); + $this->drupalStatic->resetKey('drupal_alter'); + $this->cache->cacheClearAll('hook_info', 'cache_bootstrap'); + return NULL; + } + + /** + * @see module_implements() + * + * @param string $hook + * @param bool $sort + * + * @return array + */ + function moduleImplements($hook, $sort = FALSE) { + + // Use the advanced drupal_static() pattern, since this is called very often. + if (!isset($this->drupalStaticFast)) { + $this->drupalStaticFast['implementations'] = &$this->drupalStatic->get('module_implements'); + } + $implementations = &$this->drupalStaticFast['implementations']; + + // Fetch implementations from cache. + if (empty($implementations)) { + $cache = $this->cache->cacheGet('module_implements', 'cache_bootstrap'); + if (FALSE === $cache) { + $implementations = array(); + } + else { + $implementations = $cache->data; + } + } + + if (!isset($implementations[$hook])) { + $implementations[$hook] = $this->discoverImplementations($hook, $sort); + } + else { + // @todo Change this when https://drupal.org/node/2263365 has landed in Drupal core. + $this->filterImplementations($implementations[$hook], $hook); + } + + return array_keys($implementations[$hook]); + } + + /** + * @param string $hook + * @param bool $sort + * + * @return array + */ + private function discoverImplementations($hook, $sort) { + + # StaticCallLog::addCall(); + + // The hook is not cached, so ensure that whether or not it has + // implementations, that the cache is updated at the end of the request. + $this->writeCache = TRUE; + $hook_info = $this->moduleHookInfo(); + $implementations = array(); + $list = $this->moduleList->moduleList(FALSE, FALSE, $sort); + + if ('modules_enabled' === $hook) { + # HackyLog::logx($list); + } + + foreach ($list as $module) { + $include_file = isset($hook_info[$hook]['group']) + && module_load_include('inc', $module, $module . '.' . $hook_info[$hook]['group']); + // Since module_hook() may needlessly try to load the include file again, + // function_exists() is used directly here. + if (function_exists($module . '_' . $hook)) { + $implementations[$module] = $include_file + ? $hook_info[$hook]['group'] + : FALSE; + } + } + + // Allow modules to change the weight of specific implementations but avoid + // an infinite loop. + if ($hook != 'module_implements_alter') { + $this->hookSystem->drupalAlter('module_implements', $implementations, $hook); + } + + return $implementations; + } + + /** + * @param array &$implementations + * @param string $hook + */ + private function filterImplementations(&$implementations, $hook) { + foreach ($implementations as $module => $group) { + // If this hook implementation is stored in a lazy-loaded file, so include + // that file first. + if ($group) { + module_load_include('inc', $module, "$module.$group"); + } + // It is possible that a module removed a hook implementation without the + // implementations cache being rebuilt yet, so we check whether the + // function exists on each request to avoid undefined function errors. + // Since module_hook() may needlessly try to load the include file again, + // function_exists() is used directly here. + if (!function_exists($module . '_' . $hook)) { + // Clear out the stale implementation from the cache and force a cache + // refresh to forget about no longer existing hook implementations. + unset($implementations[$module]); + $this->writeCache = TRUE; + } + } + } + + + /** + * Replicates module_hook_info() for some known hooks. + * + * @return array + * An associative array whose keys are hook names and whose values are an + * associative array containing a group name. The structure of the array + * is the same as the return value of hook_hook_info(). + * + * @see hook_hook_info() + */ + private function moduleHookInfo() { + // No core modules implement hook_hook_info(). + return array(); + } +} diff --git a/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/ModuleList.php b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/ModuleList.php new file mode 100644 index 000000000..b00e89af1 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/ModuleList.php @@ -0,0 +1,124 @@ +drupalGetFilename = $drupalGetFilename; + $this->systemList = $systemList; + $this->drupalStatic = $drupalStatic; + } + + /** + * Replicates module_list(FALSE, FALSE, $sort, $fixed_list) + * + * @param array $fixed_list + * @param bool $sort + * + * @return string[] + */ + function setModuleList($fixed_list, $sort = FALSE) { + + foreach ($fixed_list as $name => $module) { + $this->drupalGetFilename->drupalSetFilename('module', $name, $module['filename']); + $this->list[$name] = $name; + } + + if ($sort) { + return $this->moduleListSorted(); + } + + return $this->list; + } + + /** + * Replicates module_list($refresh, $bootstrap_refresh, $sort, NULL) + * + * @see module_list() + * + * @param bool $refresh + * @param bool $bootstrap_refresh + * @param bool $sort + * + * @return string[] + */ + function moduleList($refresh = FALSE, $bootstrap_refresh = FALSE, $sort = FALSE) { + + if (empty($this->list) || $refresh) { + $this->list = array(); + $sorted_list = NULL; + if ($refresh) { + // For the $refresh case, make sure that system_list() returns fresh + // data. + $this->drupalStatic->resetKey('system_list'); + } + if ($bootstrap_refresh) { + $this->list = $this->systemList->systemListBootstrap(); + } + else { + // Not using drupal_map_assoc() here as that requires common.inc. + $this->list = array_keys($this->systemList->systemListModuleEnabled()); + $this->list = !empty($this->list) + ? array_combine($this->list, $this->list) + : array(); + } + } + + if ($sort) { + return $this->moduleListSorted(); + } + + if (count($this->list)) { + # HackyLog::log($this->list); + } + + return $this->list; + } + + /** + * @return string[] + */ + private function moduleListSorted() { + if (!isset($this->moduleListSorted)) { + $this->moduleListSorted = $this->list; + ksort($this->moduleListSorted); + } + return $this->moduleListSorted; + } +} diff --git a/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/PureFunctions.php b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/PureFunctions.php new file mode 100644 index 000000000..bb07c8587 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/PureFunctions.php @@ -0,0 +1,39 @@ +exampleModules = $exampleModules; + $this->hookSystem = $hookSystem; + } + + /** + * Scans and collects module .info data. + * + * @see _system_rebuild_module_data() + * + * @return object[] + */ + public function systemBuildModuleData() { + // Find modules + $modules = $this->exampleModules->drupalSystemListingModules(); + + if (FALSE) { + // Include the installation profile in modules that are loaded. + $profile = 'minimal'; + $modules[$profile] = new \stdClass(); + $modules[$profile]->name = $profile; + $modules[$profile]->uri = 'profiles/' . $profile . '/' . $profile . '.profile'; + $modules[$profile]->filename = $profile . '.profile'; + + // Installation profile hooks are always executed last. + $modules[$profile]->weight = 1000; + } + else { + $profile = 'NO_PROFILE'; + } + + // Set defaults for module info. + $defaults = array( + 'dependencies' => array(), + 'description' => '', + 'package' => 'Other', + 'version' => NULL, + # 'php' => DRUPAL_MINIMUM_PHP, + 'files' => array(), + 'bootstrap' => 0, + ); + + // Read info files for each module. + foreach ($modules as $key => $module) { + // The module system uses the key 'filename' instead of 'uri' so copy the + // value so it will be used by the modules system. + $modules[$key]->filename = $module->uri; + + // Look for the info file. + $module->info = $this->exampleModules->drupalParseInfoFile($module->name); + + // Skip modules that don't provide info. + if (empty($module->info)) { + unset($modules[$key]); + continue; + } + + // Merge in defaults and save. + $modules[$key]->info = $module->info + $defaults; + + // Installation profiles are hidden by default, unless explicitly specified + // otherwise in the .info file. + if ($key == $profile && !isset($modules[$key]->info['hidden'])) { + $modules[$key]->info['hidden'] = TRUE; + } + + // Invoke hook_system_info_alter() to give installed modules a chance to + // modify the data in the .info files if necessary. + $type = 'module'; + $this->hookSystem->drupalAlter('system_info', $modules[$key]->info, $modules[$key], $type); + } + + if (isset($modules[$profile])) { + // The installation profile is required, if it's a valid module. + $modules[$profile]->info['required'] = TRUE; + // Add a default distribution name if the profile did not provide one. This + // matches the default value used in install_profile_info(). + if (!isset($modules[$profile]->info['distribution_name'])) { + $modules[$profile]->info['distribution_name'] = 'Drupal'; + } + } + + unset($modules['NO_PROFILE']); + + return $modules; + } + +} diff --git a/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/SystemList.php b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/SystemList.php new file mode 100644 index 000000000..1814f8eaf --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/SystemList.php @@ -0,0 +1,123 @@ +cache = $cache; + $this->drupalGetFilename = $drupalGetFilename; + $this->systemListLoader = new SystemListLoader($systemTable); + $this->drupalStatic = $drupalStatic; + } + + /** + * Replicates system_list('module_enabled'). + * + * @return object[] + */ + public function systemListModuleEnabled() { + return $this->systemList('module_enabled'); + } + + /** + * Replicates system_list($type), with $type !== 'bootstrap'. + * + * @see system_list() + * + * @param string $type + * Either 'module_enabled', 'theme' or 'filepaths'. + * + * @return object[]|array[] + */ + private function systemList($type) { + $lists = &$this->drupalStatic->get('system_list'); + + if (isset($lists['module_enabled'])) { + return $lists[$type]; + } + + // Otherwise build the list for enabled modules and themes. + if ($cached = $this->cache->cacheGet('system_list', 'cache_bootstrap')) { + $lists = $cached->data; + } + else { + $lists = $this->systemListLoader->loadSystemLists(); + $this->cache->cacheSet('system_list', $lists, 'cache_bootstrap'); + } + // To avoid a separate database lookup for the filepath, prime the + // drupal_get_filename() static cache with all enabled modules and themes. + foreach ($lists['filepaths'] as $item) { + $this->drupalGetFilename->drupalSetFilename($item['type'], $item['name'], $item['filepath']); + } + + return $lists[$type]; + } + + /** + * Replicates system_list('bootstrap') + * + * @see system_list() + * + * @return array|null + */ + function systemListBootstrap() { + $lists = &$this->drupalStatic->get('system_list'); + + // For bootstrap modules, attempt to fetch the list from cache if possible. + // if not fetch only the required information to fire bootstrap hooks + // in case we are going to serve the page from cache. + if (isset($lists['bootstrap'])) { + return $lists['bootstrap']; + } + + if ($cached = $this->cache->cacheGet('bootstrap_modules', 'cache_bootstrap')) { + $bootstrap_list = $cached->data; + } + else { + $bootstrap_list = $this->systemListLoader->fetchBootstrapSystemList(); + $this->cache->cacheSet('bootstrap_modules', $bootstrap_list, 'cache_bootstrap'); + } + + // To avoid a separate database lookup for the filepath, prime the + // drupal_get_filename() static cache for bootstrap modules only. + // The rest is stored separately to keep the bootstrap module cache small. + foreach ($bootstrap_list as $module) { + $this->drupalGetFilename->drupalSetFilename('module', $module->name, $module->filename); + } + + // We only return the module names here since module_list() doesn't need + // the filename itself. + return $lists['bootstrap'] = array_keys($bootstrap_list); + } + +} diff --git a/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/SystemListLoader.php b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/SystemListLoader.php new file mode 100644 index 000000000..21dead08e --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/SystemListLoader.php @@ -0,0 +1,156 @@ +systemTable = $systemTable; + } + + /** + * @return object[] + */ + public function fetchBootstrapSystemList() { + $bootstrapList = array(); + foreach ($this->systemTable->systemTableSortedObjects(NULL, 'module') as $name => $record) { + if (1 == $record->status && 1 == $record->bootstrap) { + $bootstrapList[$name] = (object)array( + 'name' => $record->name, + 'filename' => $record->filename, + ); + } + } + return $bootstrapList; + } + + /** + * @see system_list() + * + * @return array[] + */ + public function loadSystemLists() { + + $lists = array( + 'module_enabled' => array(), + 'theme' => array(), + 'filepaths' => array(), + ); + + // The module name (rather than the filename) is used as the fallback + // weighting in order to guarantee consistent behavior across different + // Drupal installations, which might have modules installed in different + // locations in the file system. The ordering here must also be + // consistent with the one used in module_implements(). + foreach ($this->systemTable->systemTableSortedObjects() as $record) { + // Build a list of all enabled modules. + if ($record->type == 'module') { + if (1 != $record->status) { + continue; + } + $lists['module_enabled'][$record->name] = $record; + } + // Build a list of themes. + elseif ($record->type == 'theme') { + $lists['theme'][$record->name] = $record; + } + else { + continue; + } + // Build a list of filenames so drupal_get_filename can use it. + if ($record->status) { + $lists['filepaths'][] = array( + 'type' => $record->type, + 'name' => $record->name, + 'filepath' => $record->filename + ); + } + } + + $this->themesAddHierarchy($lists['theme']); + + return $lists; + } + + /** + * @param array $themes + */ + private function themesAddHierarchy(array $themes) { + foreach ($themes as $key => $theme) { + if (!empty($theme->info['base theme'])) { + // Make a list of the theme's base themes. + $theme->base_themes = $this->drupalFindBaseThemes($themes, $key); + // Don't proceed if there was a problem with the root base theme. + if (!current($theme->base_themes)) { + continue; + } + // Determine the root base theme. + $base_key = key($theme->base_themes); + // Add to the list of sub-themes for each of the theme's base themes. + foreach (array_keys($theme->base_themes) as $base_theme) { + $themes[$base_theme]->sub_themes[$key] = $theme->info['name']; + } + // Add the base theme's theme engine info. + $theme->info['engine'] = isset($themes[$base_key]->info['engine']) + ? $themes[$base_key]->info['engine'] + : 'theme'; + } + else { + // A plain theme is its own engine. + $base_key = $key; + if (!isset($theme->info['engine'])) { + $theme->info['engine'] = 'theme'; + } + } + // Set the theme engine prefix. + $theme->prefix = ($theme->info['engine'] == 'theme') + ? $base_key + : $theme->info['engine']; + } + } + + /** + * Replicates drupal_find_base_themes() + * + * @param $themes + * @param $key + * @param array $used_keys + * + * @return array + */ + private function drupalFindBaseThemes($themes, $key, $used_keys = array()) { + $base_key = $themes[$key]->info['base theme']; + // Does the base theme exist? + if (!isset($themes[$base_key])) { + return array($base_key => NULL); + } + + $current_base_theme = array($base_key => $themes[$base_key]->info['name']); + + // Is the base theme itself a child of another theme? + if (isset($themes[$base_key]->info['base theme'])) { + // Do we already know the base themes of this theme? + if (isset($themes[$base_key]->base_themes)) { + return $themes[$base_key]->base_themes + $current_base_theme; + } + // Prevent loops. + if (!empty($used_keys[$base_key])) { + return array($base_key => NULL); + } + $used_keys[$base_key] = TRUE; + return $this->drupalFindBaseThemes($themes, $base_key, $used_keys) + $current_base_theme; + } + // If we get here, then this is our parent theme. + return $current_base_theme; + } +} diff --git a/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/SystemListReset.php b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/SystemListReset.php new file mode 100644 index 000000000..e84497475 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/SystemListReset.php @@ -0,0 +1,39 @@ +cache = $cache; + $this->drupalStatic = $drupalStatic; + } + + /** + * @see system_list_reset() + */ + function systemListReset() { + $this->drupalStatic->resetKey('system_list'); + $this->drupalStatic->resetKey('system_rebuild_module_data'); + $this->drupalStatic->resetKey('list_themes'); + $this->cache->cacheClearAll('bootstrap_modules', 'cache_bootstrap'); + $this->cache->cacheClearAll('system_list', 'cache_bootstrap'); + + } +} diff --git a/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/SystemRebuildModuleData.php b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/SystemRebuildModuleData.php new file mode 100644 index 000000000..b4633e64f --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/SystemRebuildModuleData.php @@ -0,0 +1,92 @@ +drupalStatic = $drupalStatic; + $this->moduleBuildDependencies = $moduleBuildDependencies; + $this->systemTable = $systemTable; + $this->systemBuildModuleData = $systemBuildModuleData; + $this->systemListReset = $systemListReset; + } + + /** + * Rebuild, save, and return data about all currently available modules. + * + * @see system_rebuild_module_data() + * + * @return array[] + */ + public function systemRebuildModuleData() { + $modules_cache = &$this->drupalStatic->get('system_rebuild_module_data'); + // Only rebuild once per request. $modules and $modules_cache cannot be + // combined into one variable, because the $modules_cache variable is reset by + // reference from system_list_reset() during the rebuild. + if (!isset($modules_cache)) { + $modules = $this->systemBuildModuleData->systemBuildModuleData(); + ksort($modules); + $this->systemTable->systemGetFilesDatabase($modules, 'module'); + $this->systemUpdateFilesDatabase($modules, 'module'); + $modules = $this->moduleBuildDependencies->moduleBuildDependencies($modules); + $modules_cache = $modules; + } + return $modules_cache; + } + + /** + * @see system_update_files_database() + * + * @param object[] $files + * @param string $type + */ + private function systemUpdateFilesDatabase($files, $type) { + $this->systemTable->systemUpdateFilesDatabase($files, $type); + + // If any module or theme was moved to a new location, we need to reset the + // system_list() cache or we will continue to load the old copy, look for + // schema updates in the wrong place, etc. + $this->systemListReset->systemListReset(); + } +} diff --git a/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/SystemTable.php b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/SystemTable.php new file mode 100644 index 000000000..713a0272a --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/SystemTable.php @@ -0,0 +1,330 @@ +addModule($module, array('filename' => $filename)); + } + + /** + * @param string $module + * @param mixed[] $data + * + * @throws \Exception + */ + function addModule($module, $data) { + if (!isset($data['filename'])) { + throw new \Exception("Missing filename in module data."); + } + if ($data['filename'] !== dirname($data['filename']) . '/' . $module . '.module') { + throw new \Exception("Unexpected filename for module."); + } + $this->systemTableData[$module] = $data + array( + 'status' => 0, + 'bootstrap' => 0, + 'schema_version' => -1, + 'weight' => 0, + 'info' => NULL, + 'type' => 'module', + 'name' => $module, + ); + } + + /** + * @param string $module + * @param string $dir + * + * @throws \Exception + */ + function moduleSetDir($module, $dir) { + if (!isset($this->systemTableData[$module])) { + throw new \Exception("Unknown module '$module'."); + } + $filename = $dir . '/' . $module . '.module'; + $this->systemTableData[$module]['filename'] = $filename; + } + + /** + * @param string $module + * @param string $filename + * + * @throws \Exception + */ + function moduleSetFilename($module, $filename) { + if (!isset($this->systemTableData[$module])) { + throw new \Exception("Unknown module '$module'."); + } + $this->systemTableData[$module]['filename'] = $filename; + } + + /** + * @param string $module + * + * @throws \Exception + */ + function moduleSetEnabled($module) { + if (!isset($this->systemTableData[$module])) { + throw new \Exception("Unknown module '$module'."); + } + $this->systemTableData[$module]['status'] = 1; + } + + /** + * @param string $module + * @param int $version + * + * @throws \Exception + */ + public function moduleSetSchemaVersion($module, $version) { + if (!isset($this->systemTableData[$module])) { + throw new \Exception("Unknown module '$module'."); + } + $this->systemTableData[$module]['schema_version'] = $version; + } + + /** + * @return string[] + * Extension type by extension name. + */ + function getActiveExtensions() { + $activeExtensions = array(); + foreach ($this->systemTableData as $module => $data) { + if (1 === $data['status']) { + $activeExtensions[$module] = $data['type']; + } + } + return $activeExtensions; + } + + /** + * Load module data/status from the system table. + * + * @param $module + * + * @return array|null + */ + function moduleGetData($module) { + if (!isset($this->systemTableData[$module])) { + return NULL; + } + return $this->systemTableData[$module]; + } + + /** + * @param string $module + * + * @return string|null + */ + function moduleGetFilename($module) { + if (!isset($this->systemTableData[$module])) { + return NULL; + } + return $this->systemTableData[$module]['filename']; + } + + /** + * @param string $module + * + * @return int + * @throws \Exception + */ + function moduleGetStatus($module) { + if (!isset($this->systemTableData[$module])) { + throw new \Exception("Unknown module '$module'."); + } + return $this->systemTableData[$module]['status']; + } + + /** + * @param string $module + * + * @return int + * @throws \Exception + */ + function moduleGetSchemaVersion($module) { + if (!isset($this->systemTableData[$module])) { + throw new \Exception("Unknown module '$module'."); + } + return $this->systemTableData[$module]['schema_version']; + } + + /** + * @param string[]|null $fields + * @param string|null $type + * + * @return array + */ + public function systemTableObjects(array $fields = NULL, $type = NULL) { + $objects = array(); + foreach ($this->systemTableData as $name => $record) { + if (NULL !== $type && $type !== $record['type']) { + continue; + } + $objects[$name] = $this->makeObject($record, $fields); + } + return $objects; + } + + /** + * @param string[] $fields + * @param string|null $type + * + * @return object[] + */ + public function systemTableSortedObjects(array $fields = NULL, $type = NULL) { + $byWeight = array(); + foreach ($this->systemTableData as $name => $record) { + if (NULL !== $type && $type !== $record['type']) { + continue; + } + $byWeight[$record['weight']][$name] = $this->makeObject($record, $fields); + } + ksort($byWeight); + $sorted = array(); + foreach ($byWeight as $records) { + ksort($records); + $sorted += $records; + } + return $sorted; + } + + /** + * @param $array + * @param array $fields + * + * @return \stdClass + */ + private function makeObject($array, array $fields = NULL) { + if (!isset($fields)) { + return (object)$array; + } + $object = new \stdClass; + foreach ($fields as $field) { + $object->$field = $array[$field]; + } + return $object; + } + + /** + * Retrieves the current status of an array of files in the system table. + * + * @see system_get_files_database() + * + * @param object[] $files + * @param string $type + * E.g. 'module' + */ + public function systemGetFilesDatabase($files, $type) { + $fields = array('filename', 'name', 'type', 'status', 'schema_version', 'weight'); + foreach ($this->systemTableObjects($fields) as $file) { + if ($type !== $file->type) { + continue; + } + if (!isset($files[$file->name]) || !is_object($files[$file->name])) { + continue; + } + $file->uri = $file->filename; + foreach ($file as $key => $value) { + if (!isset($files[$file->name]->$key)) { + $files[$file->name]->$key = $value; + } + } + } + } + + /** + * @see system_update_files_database() + * + * @param object[] $files + * @param string $type + */ + public function systemUpdateFilesDatabase(&$files, $type) { + + // Add all files that need to be deleted to a DatabaseCondition. + foreach ($this->systemTableObjects(NULL, $type) as $record) { + if (isset($files[$record->name]) && is_object($files[$record->name])) { + $file = $files[$record->name]; + // Scan remaining fields to find only the updated values. + foreach ($record as $key => $oldvalue) { + if (isset($file->$key)) { + $this->systemTableData[$record->name][$key] = $file->$key; + } + } + // Indicate that the file exists already. + $file->exists = TRUE; + } + else { + // File is not found in file system, so delete record from the system table. + unset($this->systemTableData[$record->name]); + } + } + + // All remaining files are not in the system table, so we need to add them. + foreach ($files as $name => $file) { + if (isset($file->exists)) { + unset($file->exists); + } + else { + $this->systemTableData[$name] = array( + 'filename' => $file->uri, + 'name' => $file->name, + 'type' => $type, + 'owner' => isset($file->owner) ? $file->owner : '', + 'info' => $file->info, + 'status' => 0, + 'bootstrap' => 0, + 'schema_version' => -1, + 'weight' => 0, + ); + $file->type = $type; + $file->status = 0; + $file->schema_version = -1; + } + } + } + + /** + * @param true[] $bootstrap_modules + */ + public function setBootstrapModules($bootstrap_modules) { + foreach ($this->systemTableData as $name => $record) { + $record['bootstrap'] = empty($bootstrap_modules[$name]) ? 0 : 1; + } + } + + /** + * @param string $name + * @param int $weight + * + * @throws \Exception + */ + public function moduleSetWeight($name, $weight) { + if (!isset($this->systemTableData[$name])) { + throw new \Exception("Unknown module '$name'."); + } + $this->systemTableData[$name]['weight'] = $weight; + } +} diff --git a/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/SystemUpdateBootstrapStatus.php b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/SystemUpdateBootstrapStatus.php new file mode 100644 index 000000000..84dc6d067 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/src/VirtualDrupal/SystemUpdateBootstrapStatus.php @@ -0,0 +1,49 @@ +hookSystem = $hookSystem; + $this->systemTable = $systemTable; + $this->systemListReset = $systemListReset; + } + + /** + * @see _system_update_bootstrap_status() + */ + function systemUpdateBootstrapStatus() { + $bootstrap_modules = array(); + foreach (PureFunctions::bootstrapHooks() as $hook) { + foreach ($this->hookSystem->moduleImplements($hook) as $module) { + $bootstrap_modules[$module] = TRUE; + } + } + $this->systemTable->setBootstrapModules($bootstrap_modules); + // Reset the cached list of bootstrap modules. + $this->systemListReset->systemListReset(); + } +} diff --git a/frontend/drupal/modules/xautoload/tests/test_1/lib/Drupal/xautoload_test_1/ExampleClass.php b/frontend/drupal/modules/xautoload/tests/test_1/lib/Drupal/xautoload_test_1/ExampleClass.php new file mode 100644 index 000000000..3ff9602fd --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/test_1/lib/Drupal/xautoload_test_1/ExampleClass.php @@ -0,0 +1,5 @@ + array( + 'page callback' => '_xautoload_test_1_json', + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ), + ); +} + +/** + * Page callback for "xautoload-example/json" + */ +function _xautoload_test_1_json() { + $all = EnvironmentSnapshotMaker::getSnapshots('xautoload_test_1'); + drupal_json_output($all); + exit(); +} diff --git a/frontend/drupal/modules/xautoload/tests/test_2/lib/ExampleClass.php b/frontend/drupal/modules/xautoload/tests/test_2/lib/ExampleClass.php new file mode 100644 index 000000000..2f9ff893b --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/test_2/lib/ExampleClass.php @@ -0,0 +1,3 @@ +registerModule(__FILE__); + +/** + * Implements hook_boot() + * + * This turns xautoload_test_2 into a boot module. + */ +function xautoload_test_2_boot() { + _xautoload_test_2_early_boot_observations('boot'); +} + +_xautoload_test_2_early_boot_observations('early'); + +/** + * Test the current state, and remember it. + */ +function _xautoload_test_2_early_boot_observations($phase = NULL) { + EnvironmentSnapshotMaker::takeSnapshot('xautoload_test_2', $phase, array('xautoload_test_2_ExampleClass')); +} + +/** + * Implements hook_menu() + */ +function xautoload_test_2_menu() { + return array( + 'xautoload_test_2.json' => array( + 'page callback' => '_xautoload_test_2_json', + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ), + ); +} + +/** + * Page callback for "xautoload-example/json" + */ +function _xautoload_test_2_json() { + $all = EnvironmentSnapshotMaker::getSnapshots('xautoload_test_2'); + drupal_json_output($all); + exit(); +} diff --git a/frontend/drupal/modules/xautoload/tests/test_3/lib/ExampleClass.php b/frontend/drupal/modules/xautoload/tests/test_3/lib/ExampleClass.php new file mode 100644 index 000000000..d36ed25b3 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/test_3/lib/ExampleClass.php @@ -0,0 +1,5 @@ +registerModulePsr4(__FILE__, 'lib'); + +/** + * Implements hook_boot() + * + * This turns xautoload_test_2 into a boot module. + */ +function xautoload_test_3_boot() { + _xautoload_test_3_early_boot_observations('boot'); +} + +_xautoload_test_3_early_boot_observations('early'); + +/** + * Test the current state, and remember it. + */ +function _xautoload_test_3_early_boot_observations($phase = NULL) { + EnvironmentSnapshotMaker::takeSnapshot( + 'xautoload_test_3', + $phase, + array('Drupal\xautoload_test_3\ExampleClass')); +} + +/** + * Implements hook_menu() + */ +function xautoload_test_3_menu() { + return array( + 'xautoload_test_3.json' => array( + 'page callback' => '_xautoload_test_3_json', + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ), + ); +} + +/** + * Page callback for "xautoload-example/json" + */ +function _xautoload_test_3_json() { + $all = EnvironmentSnapshotMaker::getSnapshots('xautoload_test_3'); + drupal_json_output($all); + exit(); +} diff --git a/frontend/drupal/modules/xautoload/tests/test_4/testlib/src/TestClass.php b/frontend/drupal/modules/xautoload/tests/test_4/testlib/src/TestClass.php new file mode 100644 index 000000000..9acaeec8a --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/test_4/testlib/src/TestClass.php @@ -0,0 +1,7 @@ +addPsr4('Drupal\xautoload_test_4\testlib\\', 'testlib/src'); +} + +/** + * Implements hook_menu() + */ +function xautoload_test_4_menu() { + // Let's see if this breaks. + new \Drupal\xautoload_test_4\testlib\TestClass(); +} + +/** + * Implements hook_theme() + */ +function xautoload_test_4_theme() { + new \Drupal\xautoload_test_4\testlib\TestClass(); +} diff --git a/frontend/drupal/modules/xautoload/tests/test_5/src/FooNamespace/Foo_Class.php b/frontend/drupal/modules/xautoload/tests/test_5/src/FooNamespace/Foo_Class.php new file mode 100644 index 000000000..6c6394005 --- /dev/null +++ b/frontend/drupal/modules/xautoload/tests/test_5/src/FooNamespace/Foo_Class.php @@ -0,0 +1,9 @@ +finder->addPsr4('Aaa\Bbb\\', 'sites/all/libraries/aaa-bbb/src'); + + // Or use an adapter with more powerful methods. + xautoload()->adapter->composerDir('sites/all/vendor/composer'); +} + +/** + * Implements hook_xautoload() + * + * Register additional classes, namespaces, autoload patterns, that are not + * already registered by default. + * + * @param \Drupal\xautoload\Adapter\LocalDirectoryAdapter $adapter + * An adapter object that can register stuff into the class loader. + */ +function hook_xautoload($adapter) { + + // Register a namespace with PSR-0. + $adapter->add( + // Namespace of a 3rd party package included in the module directory. + 'Acme\GardenKit\\', + // Path to the 3rd party package, relative to the module directory. + 'shrubbery/lib'); + + // Register a namespace with PSR-4. + $adapter->absolute()->addPsr4( + // The namespace. + 'Acme\ShrubGardens\\', + // Absolute path to the PSR-4 base directory. + '/home/karnouffle/php/shrub-gardens/src'); + + // Scan sites/all/vendor/composer for Composer-generated autoload files, e.g. + // 'sites/all/vendor/composer/autoload_namespaces.php', etc. + $adapter->absolute()->composerDir('sites/all/vendor/composer'); +} + + +/** + * Implements hook_libraries_info() + * + * Allows to register PSR-0 (or other) class folders for your libraries. + * (those things living in sites/all/libraries) + * + * The original documentation for this hook is at libraries module, + * libraries.api.php + * + * X Autoload extends the capabilities of this hook, by adding an "xautoload" + * key. This key takes a callback or closure function, which has the same + * signature as hook_xautoload($adapter). + * This means, you can use the same methods on the $api object. + * + * @return array[] + * Same as explained in libraries module, but with added key 'xautoload'. + */ +function mymodule_libraries_info() { + + return array( + 'ruebenkraut' => array( + 'name' => 'Rübenkraut library', + 'vendor url' => 'http://www.example.com', + 'download url' => 'http://github.com/example/ruebenkraut', + 'version' => '1.0', + 'xautoload' => function($adapter) { + /** + * @var \Drupal\xautoload\Adapter\LocalDirectoryAdapter $adapter + * An adapter object that can register stuff into the class loader. + */ + // Register a namespace with PSR-0 root in + // 'sites/all/libraries/ruebenkraut/src'. + $adapter->add('Rueben\Kraut\\', 'src'); + }, + ), + 'gurkentraum' => array( + 'name' => 'Gurkentraum library', + 'xautoload' => function($adapter) { + /** @var \Drupal\xautoload\Adapter\LocalDirectoryAdapter $adapter */ + // Scan sites/all/libraries/ruebenkraut/composer.json to look for + // autoload information. + $adapter->composerJson('composer.json'); + } + ) + ); +} diff --git a/frontend/drupal/modules/xautoload/xautoload.early.inc b/frontend/drupal/modules/xautoload/xautoload.early.inc new file mode 100644 index 000000000..4882e8b20 --- /dev/null +++ b/frontend/drupal/modules/xautoload/xautoload.early.inc @@ -0,0 +1,14 @@ +classFinder; +} + +/** + * Get a service object from the registry. + * Services are lazy-created first time you need them. + * + * @param string $key + * Identifier of the service within the registry. + * The xautoload_ServiceFactory should have a method with the same name. + * The recommended way (esp if you ask your IDE) is to omit this parameter and + * use xautoload()->$key instead. + * + * @return Main|object + */ +function xautoload($key = 'main') { + static $service_registry; + static $main; + if (!isset($service_registry)) { + $service_factory = new ServiceFactory(); + $service_registry = new ServiceContainer($service_factory); + $main = $service_registry->main; + } + switch ($key) { + case 'main': + return $main; + default: + // Legacy.. + return $service_registry->get($key); + } +} + + +// "Private" functions. +// ----------------------------------------------------------------------------- + +/** + * Creates and registers the xautoload class loader. + * + * Registers the xautoload_ prefix and the Drupal\xautoload\\ namespace, but + * does not register any other Drupal-specific stuff yet. This is because this + * might be called from settings.php, while some parts of Drupal are not fully + * initialized yet. + */ +function _xautoload_register() { + + // Check that this runs only once. + static $_first_run = TRUE; + if (!$_first_run) { + return; + } + $_first_run = FALSE; + + // Register a temporary loader. + spl_autoload_register('_xautoload_autoload_temp', TRUE, TRUE); + + // Some classes need to be loaded manually. Believe it! + LoadClassInjectedAPI::forceAutoload(); + LoadClassGetFileInjectedApi::forceAutoload(); + \Drupal\xautoload\Util::forceAutoload(); + + $finder = xautoload()->finder; + $finder->register(); + + // Register the 'Drupal\xautoload\\' namespace. + $finder->addPsr4('Drupal\xautoload\\', XAUTOLOAD_SRC_DIR . '/'); + + // Register the "xautoload_" prefix for legacy classes. + $finder->addPearFlat('xautoload_', __DIR__ . '/legacy/lib/'); + + // Unregister the temporary loader. + spl_autoload_unregister('_xautoload_autoload_temp'); +} + +/** + * Temporary loader callback, to avoid any module_load_include() + * while building the real autoloader. + * + * @param string $name + * Name of the class or interface we want to load. + * + * @throws \Exception + */ +function _xautoload_autoload_temp($name) { + + if ('Drupal\xautoload\\' === substr($name, 0, 17)) { + // PSR-4 case + $file = XAUTOLOAD_SRC_DIR . '/' . str_replace('\\', '/', substr($name, 17)) . '.php'; + require_once $file; + } + elseif ('xautoload_' === substr($name, 0, 10) && FALSE === strpos($name, '\\')) { + // Legacy case + $file = XAUTOLOAD_LIB_DIR . '/' . str_replace('_', '/', substr($name, 10)) . '.php'; + require_once $file; + } +} diff --git a/frontend/drupal/modules/xautoload/xautoload.emulate.inc b/frontend/drupal/modules/xautoload/xautoload.emulate.inc new file mode 100644 index 000000000..4843968b2 --- /dev/null +++ b/frontend/drupal/modules/xautoload/xautoload.emulate.inc @@ -0,0 +1,71 @@ +system->installSetModuleWeight(-90); +} + +/** + * Implements hook_uninstall() + */ +function xautoload_uninstall() { + variable_del(XAUTOLOAD_VARNAME_CACHE_TYPES); + variable_del(XAUTOLOAD_VARNAME_CACHE_LAZY); + variable_del(XAUTOLOAD_VARNAME_REPLACE_CORE); + variable_del(XAUTOLOAD_VARNAME_CACHE_PREFIX); + + // The following variable is a leftover from previous versions. + variable_del('xautoload_cache_mode'); +} + +/** + * Implements hook_update_N() + */ +function xautoload_update_7000() { + // Set module weight for xautoload to run before other modules. + db_query("UPDATE {system} SET weight = -90 WHERE name = 'xautoload' AND type = 'module'"); +} diff --git a/frontend/drupal/modules/xautoload/xautoload.libraries.inc b/frontend/drupal/modules/xautoload/xautoload.libraries.inc new file mode 100644 index 000000000..f6a97fb68 --- /dev/null +++ b/frontend/drupal/modules/xautoload/xautoload.libraries.inc @@ -0,0 +1,15 @@ +librariesInfoAlter->librariesInfoAlter($info); +} diff --git a/frontend/drupal/modules/xautoload/xautoload.module b/frontend/drupal/modules/xautoload/xautoload.module new file mode 100644 index 000000000..c20584408 --- /dev/null +++ b/frontend/drupal/modules/xautoload/xautoload.module @@ -0,0 +1,198 @@ +phaseControl->enterMainPhase(); +} + +/** + * Implements hook_init() + * + * Note: + * This is a first step to allow modules to register foreign namespaces. + * We will probably change this, to allow bootstrap modules to register their + * namespaces earlier in the request. + * We might also find a solution to cache the result of this hook between + * requests. This would require a different implementation of the InjectedAPI, + * which would no longer have a direct reference to the finder object. + */ +function xautoload_init() { + xautoload()->phaseControl->enterMainPhase(); +} + +/** + * Implements hook_system_theme_info(). + * + * This is the first hook to fire on update.php. + * + * Unfortunately, hook_custom_theme() and hook_init() are not called on + * update.php in _drupal_bootstrap_full(). + * + * But in list_themes(), _system_rebuild_theme_data() is always called in + * maintenance mode. And from there, hook_system_theme_info(). + * + * @see _drupal_bootstrap_full() + * @see list_themes() + */ +function xautoload_system_theme_info() { + xautoload()->phaseControl->enterMainPhase(); +} + +/** + * Implements hook_module_implements_alter() + * + * @param array &$implementations + * @param string $hook + */ +function xautoload_module_implements_alter(&$implementations, $hook) { + + // Check if new modules have been enabled. + if ('boot' === $hook) { + + # \Drupal\xautoload\Tests\HackyLog::log($hook); + // hook_module_implements_alter('boot') gets called (indirectly) from + // _system_update_bootstrap_status(), which happens each time a new module + // is enabled. + xautoload()->phaseControl->checkNewExtensions(); + } + + // Most hook implementations are in dedicated files. + switch ($hook) { + case 'init': + case 'custom_theme': + case 'system_theme_info': + // Move xautoload_$hook() to the start. + $implementations = array('xautoload' => FALSE) + $implementations; + break; + case 'form_system_performance_settings_alter': + // Specify that the implementation lives in xautoload.ui.inc. + $implementations['xautoload'] = 'ui'; + require_once __DIR__ . '/xautoload.ui.inc'; + break; + case 'modules_enabled': + case 'registry_files_alter': + // Move xautoload_$hook() to the start, and specify that the + // implementation lives in xautoload.system.inc. + $implementations = array('xautoload' => 'system') + $implementations; + require_once __DIR__ . '/xautoload.system.inc'; + break; + case 'libraries_info_alter': + $implementations['xautoload'] = 'libraries'; + require_once __DIR__ . '/xautoload.libraries.inc'; + break; + default: + return; + } +} + + +// "Private" functions. +// ----------------------------------------------------------------------------- + +/** + * Registers Drupal-related namespaces and prefixes in the xautoload loader, and + * activates the APC (or similar) cache, if enabled. + */ +function _xautoload_register_drupal() { + + // Check that this runs only once. + static $_first_run = TRUE; + if (!$_first_run) { + return; + } + $_first_run = FALSE; + + // Register the class loader itself. + require_once __DIR__ . '/xautoload.early.lib.inc'; + _xautoload_register(); + + $services = xautoload()->getServiceContainer(); + + if ($services->system->variableGet(XAUTOLOAD_VARNAME_REPLACE_CORE)) { + /** + * Completely take over. + * + * @see _drupal_bootstrap_database() + * @see drupal_autoload_class() + * @see drupal_autoload_interface() + */ + spl_autoload_unregister('drupal_autoload_class'); + spl_autoload_unregister('drupal_autoload_interface'); + } + + $lazy = $services->system->variableGet(XAUTOLOAD_VARNAME_CACHE_LAZY, FALSE); + $decorated = $lazy + ? $services->proxyFinder + : $services->proxyFinder->getFinder() + ; + + // Activate a cache, if available and enabled. + $cache_types = $services->system->variableGet(XAUTOLOAD_VARNAME_CACHE_TYPES, array()); + if (!empty($cache_types['apcu_q']) && extension_loaded('apcu') && function_exists('apcu_store')) { + $cached_loader = ApcuQueuedCachedClassLoader::create($decorated, $services->cacheManager); + } + elseif (!empty($cache_types['apc']) && extension_loaded('apc') && function_exists('apc_store')) { + $cached_loader = ApcClassLoader::create($decorated, $services->cacheManager); + } + /** @noinspection NotOptimalIfConditionsInspection */ + elseif (!empty($cache_types['apcu']) && extension_loaded('apcu') && function_exists('apcu_store')) { + $cached_loader = ApcuClassLoader::create($decorated, $services->cacheManager); + } + elseif (!empty($cache_types['wincache']) && extension_loaded('wincache') && function_exists('wincache_ucache_get')) { + $cached_loader = WinCacheClassLoader::create($decorated, $services->cacheManager); + } + elseif (!empty($cache_types['xcache']) && extension_loaded('Xcache') && function_exists('xcache_get')) { + $cached_loader = XCacheClassLoader::create($decorated, $services->cacheManager); + } + elseif (!empty($cache_types['dbcache'])) { + $cached_loader = DbCacheClassLoader::create($decorated, $services->cacheManager); + } + + if (isset($cached_loader)) { + if ($lazy) { + $decorated->observeFirstCacheMiss(new CacheMissLoaderSetFinder($cached_loader)); + } + $cached_loader->register(); + $services->finder->unregister(); + } + else { + // No cache is active. + // Initialize the finder, to fire scheduled operations. + $services->proxyFinder->getFinder(); + } + + // Register prefixes and namespaces for enabled extensions. + $services->proxyFinder->observeFirstCacheMiss($services->phaseControl); +} diff --git a/frontend/drupal/modules/xautoload/xautoload.system.inc b/frontend/drupal/modules/xautoload/xautoload.system.inc new file mode 100644 index 000000000..b37df33c5 --- /dev/null +++ b/frontend/drupal/modules/xautoload/xautoload.system.inc @@ -0,0 +1,41 @@ +phaseControl->modulesEnabled($modules); +} + +/** + * Implements hook_registry_files_alter() + * + * Support wildcard syntax in the files[] setting in your module's info file. + * See https://drupal.org/node/1976198 + * + * This function will remove entries like foo/inc/**, and instead add all the + * individual class files found in the foo/inc/ folder. + * + * @param array[] &$files + * List of files specified in files[] array in module info files. + * Format: + * + * $files['modules/field/field.attach.inc'] = array( + * 'module' => 'field', + * 'weight' => 0, + * ); + * // Wildcard syntax. + * $files['sites/all/modules/foo/inc/**'] = array( + * 'module' => 'foo', + * 'weight' => 0, + * ); + */ +function xautoload_registry_files_alter(&$files) { + $file_finder = new WildcardFileFinder(); + $file_finder->addDrupalPaths($files); + $files = $file_finder->getDrupalFiles(); +} diff --git a/frontend/drupal/modules/xautoload/xautoload.ui.inc b/frontend/drupal/modules/xautoload/xautoload.ui.inc new file mode 100644 index 000000000..5f9aca833 --- /dev/null +++ b/frontend/drupal/modules/xautoload/xautoload.ui.inc @@ -0,0 +1,89 @@ + 'fieldset', + '#title' => t('X Autoload'), + ); + + $cache_default_value = variable_get(XAUTOLOAD_VARNAME_CACHE_TYPES, array()); + + $cache_status = array( + 'apcu_q' => $apcu_status = (extension_loaded('apcu') && function_exists('apcu_store')), + 'apc' => (extension_loaded('apc') && function_exists('apc_store')), + 'apcu' => $apcu_status, + 'wincache' => (extension_loaded('WinCache') && function_exists('wincache_ucache_get')), + 'xcache' => (extension_loaded('Xcache') && function_exists('xcache_get')), + 'dbcache' => TRUE, + ); + $cache_names = array( + 'apcu_q' => t('Self-updating APCu classmap (*)'), + 'apc' => 'APC', + 'apcu' => 'APCu', + 'wincache' => 'WinCache', + 'xcache' => 'XCache', + 'dbcache' => t('Self-updating database classmap (*)'), + ); + $options = $cache_names; + $options_descriptions = array(); + $options['dbcache'] = l($options['dbcache'], 'https://www.drupal.org/node/2451261'); + $active_cache_key = NULL; + $active_cache_name = t('No cache.'); + foreach ($cache_names as $key => $title) { + $status = $cache_status[$key]; + if (!isset($active_cache_key) && $status && !empty($cache_default_value[$key])) { + $active_cache_key = $key; + $active_cache_name = $title; + } + } + foreach ($options as $key => $title) { + if ($cache_status[$key]) { + $options[$key] .= ' (' . t('Running and available') . ')'; + } + else { + $options[$key] .= ' (' . t('Not currently available') . ')'; + $options[$key] = '' . $options[$key] . ''; + } + } + + $form['xautoload'][XAUTOLOAD_VARNAME_CACHE_TYPES] = array( + /* @see system_element_info() */ + '#type' => 'checkboxes', + '#title' => t('Cache mode'), + '#default_value' => $cache_default_value, + '#options' => $options, + '#options_descriptions' => $options_descriptions, + '#description' => '' + . '

    ' . t('X Autoload will pick the first cache mode that is available and enabled.') + . '
    ' . t('Currently, this is:') . ' ' . $active_cache_name . '.' + . '

    ' . t('It is usually safe to enable all these checkboxes, so xautoload can always use the best cache mode available on your system.') + . '
    ' . t('This also makes it easier to sync these settings between environments, where different PHP extensions might be installed.') + . '

    ' + . '

    (*) ' . t('The "Self-updating [_] classmap" cache types require more than one request until they are "hot", but may bring higher performance.') + . '

    ', + ); + + $form['xautoload'][XAUTOLOAD_VARNAME_CACHE_LAZY] = array( + '#type' => 'checkbox', + '#title' => t('Postpone registration of module namespaces until the first cache miss (recommended).'), + '#default_value' => variable_get(XAUTOLOAD_VARNAME_CACHE_LAZY, FALSE), + '#description' => t('This should speed up the bootstrap of xautoload.'), + ); + + $form['xautoload'][XAUTOLOAD_VARNAME_REPLACE_CORE] = array( + '#type' => 'checkbox', + '#title' => t('Replace core class loader.'), + '#default_value' => variable_get(XAUTOLOAD_VARNAME_REPLACE_CORE, FALSE), + '#description' => t('Lets xautoload replace Drupal\'s drupal_autoload_class() and drupal_autoload_interface().') + . '
    ' . t('Improves performance, if at least one of the cache options is active and enabled.') + . '
    ' . t('This features is quite new. Please report any problems in the xautoload issue queue on drupal.org.'), + ); +} diff --git a/frontend/drupal/profiles/minimal/minimal.info b/frontend/drupal/profiles/minimal/minimal.info index ce71979ec..c9a70a1db 100644 --- a/frontend/drupal/profiles/minimal/minimal.info +++ b/frontend/drupal/profiles/minimal/minimal.info @@ -5,7 +5,7 @@ core = 7.x dependencies[] = block dependencies[] = dblog -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/profiles/standard/standard.info b/frontend/drupal/profiles/standard/standard.info index 053da174d..bcda8923e 100644 --- a/frontend/drupal/profiles/standard/standard.info +++ b/frontend/drupal/profiles/standard/standard.info @@ -24,7 +24,7 @@ dependencies[] = field_ui dependencies[] = file dependencies[] = rdf -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info b/frontend/drupal/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info index 990173f9a..6ef5373c4 100644 --- a/frontend/drupal/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info +++ b/frontend/drupal/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info @@ -6,7 +6,7 @@ core = 7.x hidden = TRUE files[] = drupal_system_listing_compatible_test.test -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info b/frontend/drupal/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info index 6d4111616..fb319ecb0 100644 --- a/frontend/drupal/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info +++ b/frontend/drupal/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info @@ -8,7 +8,7 @@ version = VERSION core = 6.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/profiles/testing/testing.info b/frontend/drupal/profiles/testing/testing.info index 220c0b5f4..fe1a2e863 100644 --- a/frontend/drupal/profiles/testing/testing.info +++ b/frontend/drupal/profiles/testing/testing.info @@ -4,7 +4,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2020-11-26 -version = "7.75" +; Information added by Drupal.org packaging script on 2021-01-20 +version = "7.78" project = "drupal" -datestamp = "1606357834" +datestamp = "1611162699" diff --git a/frontend/drupal/scripts/run-tests.sh b/frontend/drupal/scripts/run-tests.sh index 8c0be40ef..f5c4a144f 100755 --- a/frontend/drupal/scripts/run-tests.sh +++ b/frontend/drupal/scripts/run-tests.sh @@ -264,6 +264,10 @@ function simpletest_script_init($server_software) { // '_' is an environment variable set by the shell. It contains the command that was executed. $php = $php_env; } + elseif (defined('PHP_BINARY') && $php_env = PHP_BINARY) { + // 'PHP_BINARY' specifies the PHP binary path during script execution. Available since PHP 5.4. + $php = $php_env; + } elseif ($sudo = getenv('SUDO_COMMAND')) { // 'SUDO_COMMAND' is an environment variable set by the sudo program. // Extract only the PHP interpreter, not the rest of the command. diff --git a/frontend/drupal/sites/all/libraries/modernizr/modernizr-custom.js b/frontend/drupal/sites/all/libraries/modernizr/modernizr-custom.js new file mode 100644 index 000000000..daaeab5cb --- /dev/null +++ b/frontend/drupal/sites/all/libraries/modernizr/modernizr-custom.js @@ -0,0 +1,3 @@ +/*! modernizr 3.6.0 (Custom Build) | MIT * + * https://modernizr.com/download/?-webp-setclasses !*/ +!function(e,n,A){function o(e){var n=u.className,A=Modernizr._config.classPrefix||"";if(c&&(n=n.baseVal),Modernizr._config.enableJSClass){var o=new RegExp("(^|\\s)"+A+"no-js(\\s|$)");n=n.replace(o,"$1"+A+"js$2")}Modernizr._config.enableClasses&&(n+=" "+A+e.join(" "+A),c?u.className.baseVal=n:u.className=n)}function t(e,n){return typeof e===n}function a(){var e,n,A,o,a,i,l;for(var f in r)if(r.hasOwnProperty(f)){if(e=[],n=r[f],n.name&&(e.push(n.name.toLowerCase()),n.options&&n.options.aliases&&n.options.aliases.length))for(A=0;A $plugin_name)); } - else { + + $handler = ctools_export_ui_get_handler($plugin); + if (!$handler) { return t('Configuration error. No handler found.'); } + + $method = $op . '_page'; + if (method_exists($handler, $method)) { + // Replace the first two arguments: + $args[0] = $js; + $args[1] = $_POST; + return call_user_func_array(array($handler, $method), $args); + } } diff --git a/frontend/drupal/sites/all/modules/ctools/includes/export.inc b/frontend/drupal/sites/all/modules/ctools/includes/export.inc index d2fff2fdc..efc356efb 100644 --- a/frontend/drupal/sites/all/modules/ctools/includes/export.inc +++ b/frontend/drupal/sites/all/modules/ctools/includes/export.inc @@ -637,11 +637,19 @@ function ctools_get_default_object($table, $name) { } /** + * Get export object defaults. + * * Call the hook to get all default objects of the given type from the * export. If configured properly, this could include loading up an API * to get default objects. + * + * @param string $table + * The name of the table to be loaded. Data is expected to be in the + * schema to make all this work. + * @param array $export + * The export definition from the table's hook_schema() definition. */ -function _ctools_export_get_defaults($table, $export) { +function _ctools_export_get_defaults($table, array $export) { $cache = &drupal_static(__FUNCTION__, array()); // If defaults may be cached, first see if we can load from cache. @@ -684,7 +692,8 @@ function _ctools_export_get_defaults($table, $export) { $cache[$table][$name] = $object; } else { - // If version checking is enabled, ensure that the object can be used. + // If version checking is enabled, ensure that the object can be + // used. if (isset($object->api_version) && version_compare($object->api_version, $export['api']['minimum_version']) >= 0 && version_compare($object->api_version, $export['api']['current_version']) <= 0) { @@ -866,6 +875,7 @@ function ctools_var_export($var, $prefix = '') { } else { $output = "array(\n"; + ksort($var); foreach ($var as $key => $value) { $output .= $prefix . " " . ctools_var_export($key) . " => " . ctools_var_export($value, $prefix . ' ') . ",\n"; } diff --git a/frontend/drupal/sites/all/modules/ctools/includes/fields.inc b/frontend/drupal/sites/all/modules/ctools/includes/fields.inc index 0d3256f2d..75e964f1d 100644 --- a/frontend/drupal/sites/all/modules/ctools/includes/fields.inc +++ b/frontend/drupal/sites/all/modules/ctools/includes/fields.inc @@ -238,8 +238,6 @@ function ctools_field_label($field_name) { function ctools_field_invoke_field($field_name, $op, $entity_type, $entity, &$a = NULL, &$b = NULL, $options = array()) { if (is_array($field_name)) { $instance = $field_name; - $field = empty($field_name['field']) ? field_info_field($instance['field_name']) : $field_name['field']; - $field_name = $instance['field_name']; } else { list(, , $bundle) = entity_extract_ids($entity_type, $entity); @@ -250,6 +248,11 @@ function ctools_field_invoke_field($field_name, $op, $entity_type, $entity, &$a return; } + // Keep the variables consistent regardless if we retrieve the field instance + // ourself, or if one is provided to us via the $field_name variable. + $field = field_info_field($instance['field_name']); + $field_name = $instance['field_name']; + // Merge default options. $default_options = array( 'default' => FALSE, diff --git a/frontend/drupal/sites/all/modules/ctools/includes/page-wizard.inc b/frontend/drupal/sites/all/modules/ctools/includes/page-wizard.inc index 9690aae07..d45d80421 100644 --- a/frontend/drupal/sites/all/modules/ctools/includes/page-wizard.inc +++ b/frontend/drupal/sites/all/modules/ctools/includes/page-wizard.inc @@ -97,7 +97,7 @@ function page_manager_page_wizard($name, $step = NULL) { } // Check for possibly more complex access callback on plugin. - if ($function = ctools_plugin_get_function($plugin, 'access callback') && !$function($plugin)) { + if (($function = ctools_plugin_get_function($plugin, 'access callback')) && !$function($plugin)) { return MENU_ACCESS_DENIED; } diff --git a/frontend/drupal/sites/all/modules/ctools/js/ajax-responder.js b/frontend/drupal/sites/all/modules/ctools/js/ajax-responder.js index 6c30b26df..116d4744f 100644 --- a/frontend/drupal/sites/all/modules/ctools/js/ajax-responder.js +++ b/frontend/drupal/sites/all/modules/ctools/js/ajax-responder.js @@ -26,7 +26,7 @@ // Grab all the links that match this url and add the fetching class. // This allows the caching system to grab each url once and only once // instead of grabbing the url once per . - var $objects = $('a[href="' + old_url + '"]') + var $objects = $('a[href="' + old_url + '"]'); $objects.addClass('ctools-fetching'); try { url = old_url.replace(/\/nojs(\/|$)/g, '/ajax$1'); diff --git a/frontend/drupal/sites/all/modules/ctools/js/auto-submit.js b/frontend/drupal/sites/all/modules/ctools/js/auto-submit.js index b658577a4..0e97e2eb5 100644 --- a/frontend/drupal/sites/all/modules/ctools/js/auto-submit.js +++ b/frontend/drupal/sites/all/modules/ctools/js/auto-submit.js @@ -98,5 +98,5 @@ Drupal.behaviors.CToolsAutoSubmit = { }); }); } -} +}; })(jQuery); diff --git a/frontend/drupal/sites/all/modules/ctools/js/collapsible-div.js b/frontend/drupal/sites/all/modules/ctools/js/collapsible-div.js index 4e21a2259..4719d7cc4 100644 --- a/frontend/drupal/sites/all/modules/ctools/js/collapsible-div.js +++ b/frontend/drupal/sites/all/modules/ctools/js/collapsible-div.js @@ -194,7 +194,7 @@ Drupal.CTools.CollapsibleCallbacksAfterToggle[i]($container, handle, content, toggle); } } - } + }; var clickMe = function () { if (Drupal.CTools.CollapsibleCallbacks) { @@ -222,7 +222,7 @@ } return false; - } + }; // Let both the toggle and the handle be clickable. toggle.click(clickMe); @@ -237,5 +237,5 @@ attach: function(context) { $('.ctools-collapsible-container', context).once('ctools-collapsible', Drupal.CTools.bindCollapsible); } - } + }; })(jQuery); diff --git a/frontend/drupal/sites/all/modules/ctools/js/dependent.js b/frontend/drupal/sites/all/modules/ctools/js/dependent.js index 77777e38e..6e4b79670 100644 --- a/frontend/drupal/sites/all/modules/ctools/js/dependent.js +++ b/frontend/drupal/sites/all/modules/ctools/js/dependent.js @@ -14,7 +14,7 @@ * - Checkboxes don't have their own id, so you need to add one in a div * around the checkboxes via #prefix and #suffix. You actually need to add TWO * divs because it's the parent that gets hidden. Also be sure to retain the - * 'expand_checkboxes' in the #process array, because the CTools process will + * 'form_process_checkboxes' in the #process array, because the CTools process will * override it. */ @@ -34,7 +34,7 @@ } } return false; - } + }; Drupal.CTools.dependent.autoAttach = function() { @@ -118,7 +118,7 @@ } } return val; - } + }; var setChangeTrigger = function(trigger_id, bind_id) { // Triggered when change() is clicked. @@ -205,7 +205,7 @@ } } } - } + }; $(trigger_id).bind('change.ctools-dependent', function() { // Trigger the internal change function @@ -214,11 +214,11 @@ }); // Trigger initial reaction changeTrigger(trigger_id, bind_id); - } + }; setChangeTrigger(trigger_id, bind_id); } } - } + }; Drupal.behaviors.CToolsDependent = { attach: function (context) { @@ -240,5 +240,5 @@ }) .trigger('change.ctools-dependent'); } - } + }; })(jQuery); diff --git a/frontend/drupal/sites/all/modules/ctools/js/dropbutton.js b/frontend/drupal/sites/all/modules/ctools/js/dropbutton.js index f505550b6..6d08d05a5 100644 --- a/frontend/drupal/sites/all/modules/ctools/js/dropbutton.js +++ b/frontend/drupal/sites/all/modules/ctools/js/dropbutton.js @@ -69,7 +69,7 @@ $secondaryActions.animate({height: "show", opacity: "show"}, 100); $dropbutton.addClass('open'); } - } + }; // Hide the secondary actions initially. $secondaryActions.hide(); @@ -90,5 +90,5 @@ ); }); } - } + }; })(jQuery); diff --git a/frontend/drupal/sites/all/modules/ctools/js/dropdown.js b/frontend/drupal/sites/all/modules/ctools/js/dropdown.js index c829ae2fe..e2488b1ea 100644 --- a/frontend/drupal/sites/all/modules/ctools/js/dropdown.js +++ b/frontend/drupal/sites/all/modules/ctools/js/dropdown.js @@ -61,7 +61,7 @@ $("div.ctools-dropdown-container", $dropdown) .animate({height: "show", opacity: "show"}, 100); } - } + }; $("a.ctools-dropdown-link", $dropdown).click(function() { toggle(); return false; @@ -83,5 +83,5 @@ ); }); } - } + }; })(jQuery); diff --git a/frontend/drupal/sites/all/modules/ctools/js/jump-menu.js b/frontend/drupal/sites/all/modules/ctools/js/jump-menu.js index 7b0928a68..14852d5ad 100644 --- a/frontend/drupal/sites/all/modules/ctools/js/jump-menu.js +++ b/frontend/drupal/sites/all/modules/ctools/js/jump-menu.js @@ -38,5 +38,5 @@ return false; }); } - } + }; })(jQuery); diff --git a/frontend/drupal/sites/all/modules/ctools/js/modal.js b/frontend/drupal/sites/all/modules/ctools/js/modal.js index 71b4b6aa0..92f8d7860 100644 --- a/frontend/drupal/sites/all/modules/ctools/js/modal.js +++ b/frontend/drupal/sites/all/modules/ctools/js/modal.js @@ -86,7 +86,7 @@ 'width': (width - Drupal.CTools.Modal.currentSettings.modalSize.contentRight) + 'px', 'height': (height - Drupal.CTools.Modal.currentSettings.modalSize.contentBottom) + 'px' }); - } + }; if (!Drupal.CTools.Modal.modal) { Drupal.CTools.Modal.modal = $(Drupal.theme(settings.modalTheme)); @@ -120,9 +120,9 @@ * Provide the HTML to create the modal dialog. */ Drupal.theme.prototype.CToolsModalDialog = function () { - var html = '' - html += '
    ' - html += '
    ' // panels-modal-content + var html = ''; + html += '
    '; + html += '
    '; // panels-modal-content html += ' '; return html; - } + }; /** * Provide the HTML to create the throbber. @@ -159,7 +159,7 @@ if (match) { return match[1]; } - } + }; /** * Click function for modals that can be cached. @@ -186,7 +186,7 @@ setTimeout(function() { Drupal.CTools.AJAX.ajaxSubmit($form, url); }, 1); return false; - } + }; /** * Bind links that will open modals to the appropriate function. @@ -250,7 +250,7 @@ element_settings.url = $this.attr('action'); element_settings.event = 'submit'; - element_settings.progress = { 'type': 'throbber' } + element_settings.progress = { 'type': 'throbber' }; var base = $this.attr('id'); Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings); @@ -291,9 +291,15 @@ * AJAX responder command to place HTML within the modal. */ Drupal.CTools.Modal.modal_display = function(ajax, response, status) { + var settings = response.settings || ajax.settings || Drupal.settings; + // If the modal does not exist yet, create it. if ($('#modalContent').length == 0) { Drupal.CTools.Modal.show(Drupal.CTools.Modal.getSettings(ajax.element)); } + // If the modal exists run detachBehaviors before removing existing content. + else { + Drupal.detachBehaviors($('#modalContent'), settings, 'unload'); + } $('#modal-title').html(response.title); // Simulate an actual page load by scrolling to the top after adding the // content. This is helpful for allowing users to see error messages at the @@ -302,7 +308,6 @@ $(document).trigger('CToolsAttachBehaviors', $('#modalContent')); // Attach behaviors within a modal dialog. - var settings = response.settings || ajax.settings || Drupal.settings; Drupal.attachBehaviors($('#modalContent'), settings); if ($('#modal-content').hasClass('ctools-modal-loading')) { @@ -315,7 +320,7 @@ // button by the show() function called above.) $('#modal-content :focusable:first').focus(); } - } + }; /** * AJAX responder command to dismiss the modal. @@ -323,7 +328,7 @@ Drupal.CTools.Modal.modal_dismiss = function(command) { Drupal.CTools.Modal.dismiss(); $('link.ctools-temporary-css').remove(); - } + }; /** * Display loading @@ -334,7 +339,7 @@ output: Drupal.theme(Drupal.CTools.Modal.currentSettings.throbberTheme), title: Drupal.CTools.Modal.currentSettings.loadingText }); - } + }; /** * Find a URL for an AJAX button. @@ -590,6 +595,7 @@ $('body').unbind( 'keydown', modalTabTrapHandler ); $('.close', $modalHeader).unbind('click', modalContentClose); $(document).unbind('keydown', modalEventEscapeCloseHandler); + $(document).trigger('CToolsCloseModalBehaviors', $('#modalContent')); $(document).trigger('CToolsDetachBehaviors', $('#modalContent')); // Closing animation. @@ -675,7 +681,7 @@ var $modalContent = $('#modalContent'); var $modalHeader = $modalContent.find('.modal-header'); $('.close', $modalHeader).unbind('click', modalContentClose); - $('body').unbind('keypress', modalEventEscapeCloseHandler); + $(document).unbind('keydown', modalEventEscapeCloseHandler); $(document).trigger('CToolsDetachBehaviors', $modalContent); // jQuery magic loop through the instances and run the animations or removal. diff --git a/frontend/drupal/sites/all/modules/ctools/js/stylizer.js b/frontend/drupal/sites/all/modules/ctools/js/stylizer.js index d48f64541..227d4f4be 100644 --- a/frontend/drupal/sites/all/modules/ctools/js/stylizer.js +++ b/frontend/drupal/sites/all/modules/ctools/js/stylizer.js @@ -180,7 +180,7 @@ ); $(this).after(lock); locks.push(lock); - }; + } // Add hook var $this = $(this); @@ -216,5 +216,5 @@ $widget.attr('checked', !$widget.attr('checked') || $widget.is('input[type=radio]')); }); } - } + }; })(jQuery); diff --git a/frontend/drupal/sites/all/modules/ctools/page_manager/page_manager.info b/frontend/drupal/sites/all/modules/ctools/page_manager/page_manager.info index 77c9815bc..06720486a 100644 --- a/frontend/drupal/sites/all/modules/ctools/page_manager/page_manager.info +++ b/frontend/drupal/sites/all/modules/ctools/page_manager/page_manager.info @@ -6,8 +6,8 @@ package = Chaos tool suite files[] = tests/head_links.test -; Information added by Drupal.org packaging script on 2020-10-23 -version = "7.x-1.17" +; Information added by Drupal.org packaging script on 2021-01-30 +version = "7.x-1.19" core = "7.x" project = "ctools" -datestamp = "1603490551" +datestamp = "1611988843" diff --git a/frontend/drupal/sites/all/modules/ctools/plugins/access/node_status.inc b/frontend/drupal/sites/all/modules/ctools/plugins/access/node_status.inc index 137f2826c..519619bec 100644 --- a/frontend/drupal/sites/all/modules/ctools/plugins/access/node_status.inc +++ b/frontend/drupal/sites/all/modules/ctools/plugins/access/node_status.inc @@ -21,7 +21,7 @@ $plugin = array( * Check for access. */ function ctools_node_status_ctools_access_check($conf, $context) { - return (!empty($context->data) && $context->data->status); + return (!empty($context->data->status) && $context->data->status); } /** diff --git a/frontend/drupal/sites/all/modules/ctools/plugins/content_types/form/entity_form_field.inc b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/form/entity_form_field.inc index b4d833813..f2f1e7bd6 100644 --- a/frontend/drupal/sites/all/modules/ctools/plugins/content_types/form/entity_form_field.inc +++ b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/form/entity_form_field.inc @@ -152,6 +152,12 @@ function ctools_entity_form_field_content_type_render($subtype, $conf, $panel_ar * Returns the administrative title for a type. */ function ctools_entity_form_field_content_type_admin_title($subtype, $conf, $context) { + // Return early because we don't have context to build this field from. + if (!$context || !isset($context->identifier)) { + watchdog('ctools_entity_form_field_content_type_admin_title', 'Context is missing for field: @name', array('@name' => $subtype), WATCHDOG_NOTICE); + return t('Deleted/missing field @name', array('@name' => $subtype)); + } + list($entity_type, $field_name) = explode(':', $subtype, 2); if (!empty($context->restrictions)) { diff --git a/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/icon_user_form.png b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/icon_user_form.png new file mode 100644 index 000000000..f0417cb65 Binary files /dev/null and b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/icon_user_form.png differ diff --git a/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_actions.inc b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_actions.inc new file mode 100644 index 000000000..e11587d81 --- /dev/null +++ b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_actions.inc @@ -0,0 +1,65 @@ + TRUE, + 'icon' => 'icon_user_form.png', + 'title' => t('User form actions / buttons'), + 'description' => t('The user form actions / buttons.'), + 'required context' => new ctools_context_required(t('Form'), 'form'), + 'category' => t('Form'), +); + +/** + * Ctools plugin content type render for the picture form field. + */ +function ctools_user_form_actions_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + $block->module = t('user-form'); + + $block->delta = 'title-options'; + + if (isset($context->form)) { + if (!empty($context->form['actions'])) { + $block->content['actions'] = $context->form['actions']; + unset($context->form['actions']); + } + // Because we are adding the submit buttons outside the General form + // we can assume the necessary hidden components should be added as well. + if (!empty($context->form['form_build_id'])) { + $block->content['form_build_id'] = $context->form['form_build_id']; + unset($context->form['form_build_id']); + } + if (!empty($context->form['form_token'])) { + $block->content['form_token'] = $context->form['form_token']; + unset($context->form['form_token']); + } + if (!empty($context->form['form_id'])) { + $block->content['form_id'] = $context->form['form_id']; + unset($context->form['form_id']); + } + } + else { + $block->content = t('User actions / buttons form components.'); + } + return $block; +} + +/** + * Ctools plugin admin title function for the actions form field. + */ +function ctools_user_form_actions_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" user form actions / buttons field', array('@s' => $context->identifier)); +} + +/** + * Ctools plugin configuration edit form for the actions form field. + * + * Provide a blank form so we have a place to have context setting. + */ +function ctools_user_form_actions_content_type_edit_form($form, &$form_state) { + return $form; +} diff --git a/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_component.inc b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_component.inc new file mode 100644 index 000000000..b4963f99b --- /dev/null +++ b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_component.inc @@ -0,0 +1,72 @@ + TRUE, + 'icon' => 'icon_user_form.png', + 'title' => t('User form: add a specific component'), + 'description' => t('The user form component by selection.'), + 'required context' => new ctools_context_required(t('Form'), 'form'), + 'category' => t('Form'), +); + +/** + * Ctools plugin content type render for the picture form field. + */ +function ctools_user_form_component_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + $block->module = t('user-form'); + + $block->delta = 'title-options'; + + if (isset($context->form)) { + if (!empty($context->form[$conf['field']])) { + $block->content[$conf['field']] = $context->form[$conf['field']]; + unset($context->form[$conf['field']]); + } + } + else { + $block->content = t('User form edit components.'); + } + return $block; +} + +/** + * Ctools plugin admin title function for the a selectable form field. + */ +function ctools_user_form_component_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" user form @field field', array('@s' => $context->identifier, '@field' => $conf['field'])); +} + +/** + * Ctools plugin configuration edit form for the selectable form field. + * + * Provide the list of fields in the user profile edit form to select from the + * plugin configuration. + */ +function ctools_user_form_component_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + $user_form = drupal_get_form('user_profile_form'); + + $field_keys = element_children($user_form); + $options = array_combine($field_keys, $field_keys); + + $form['field'] = array( + '#type' => 'select', + '#title' => t('User form field'), + '#options' => $options, + '#description' => t('Select a form field from the current user form to display in this pane.'), + '#default_value' => !empty($conf['field']) ? $conf['field'] : '', + ); + return $form; +} + +/** + * Ctools plugin configuration edit form submit handler. + */ +function ctools_user_form_component_content_type_edit_form_submit($form, &$form_state) { + $form_state['conf']['field'] = $form_state['values']['field']; +} diff --git a/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_email.inc b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_email.inc new file mode 100644 index 000000000..346555d09 --- /dev/null +++ b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_email.inc @@ -0,0 +1,56 @@ + TRUE, + 'icon' => 'icon_user_form.png', + 'title' => t('User form email field'), + 'description' => t('The user email form.'), + 'required context' => new ctools_context_required(t('Form'), 'form'), + 'category' => t('Form'), +); + +/** + * Ctools plugin content type render for the email form field. + */ +function ctools_user_form_email_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + $block->module = t('user-form'); + + $block->delta = 'title-options'; + + if (isset($context->form)) { + // The current password is required to change the email. + if (!empty($context->form['account']['current_pass'])) { + $block->content['current_pass'] = $context->form['account']['current_pass']; + unset($context->form['account']['current_pass']); + } + if (!empty($context->form['account']['mail'])) { + $block->content['mail'] = $context->form['account']['mail']; + unset($context->form['account']['mail']); + } + } + else { + $block->content = t('User email form.'); + } + return $block; +} + +/** + * Ctools plugin admin title function for the email form field. + */ +function ctools_user_form_email_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" user form email field', array('@s' => $context->identifier)); +} + +/** + * Ctools plugin configuration edit form for the email form field. + * + * Provide a blank form so we have a place to have context setting. + */ +function ctools_user_form_email_content_type_edit_form($form, &$form_state) { + return $form; +} diff --git a/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_notify.inc b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_notify.inc new file mode 100644 index 000000000..bb74963c1 --- /dev/null +++ b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_notify.inc @@ -0,0 +1,51 @@ + TRUE, + 'icon' => 'icon_user_form.png', + 'title' => t('User form notify field'), + 'description' => t('The user notify form.'), + 'required context' => new ctools_context_required(t('Form'), 'form'), + 'category' => t('Form'), +); + +/** + * Ctools plugin content type render for the notify form field. + */ +function ctools_user_form_notify_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + $block->module = t('user-form'); + + $block->delta = 'title-options'; + + if (isset($context->form)) { + if (!empty($context->form['account']['notify'])) { + $block->content['notify'] = $context->form['account']['notify']; + unset($context->form['account']['notify']); + } + } + else { + $block->content = t('User notify form.'); + } + return $block; +} + +/** + * Ctools plugin admin title function for the notify form field. + */ +function ctools_user_form_notify_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" user form notify field', array('@s' => $context->identifier)); +} + +/** + * Ctools plugin configuration edit form for the notify form field. + * + * Provide a blank form so we have a place to have context setting. + */ +function ctools_user_form_notify_content_type_edit_form($form, &$form_state) { + return $form; +} diff --git a/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_password.inc b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_password.inc new file mode 100644 index 000000000..89bab949c --- /dev/null +++ b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_password.inc @@ -0,0 +1,56 @@ + TRUE, + 'icon' => 'icon_user_form.png', + 'title' => t('User form password field'), + 'description' => t('The user password form.'), + 'required context' => new ctools_context_required(t('Form'), 'form'), + 'category' => t('Form'), +); + +/** + * Ctools plugin content type render for the password form field. + */ +function ctools_user_form_password_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + $block->module = t('user-form'); + + $block->delta = 'title-options'; + + if (isset($context->form)) { + // The current password is required to change the password. + if (!empty($context->form['account']['current_pass'])) { + $block->content['current_pass'] = $context->form['account']['current_pass']; + unset($context->form['account']['current_pass']); + } + if (!empty($context->form['account']['pass'])) { + $block->content['pass'] = $context->form['account']['pass']; + unset($context->form['account']['pass']); + } + } + else { + $block->content = t('User password form.'); + } + return $block; +} + +/** + * Ctools plugin admin title function for the password form field. + */ +function ctools_user_form_password_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" user form password field', array('@s' => $context->identifier)); +} + +/** + * Ctools plugin configuration edit form for the password form field. + * + * Provide a blank form so we have a place to have context setting. + */ +function ctools_user_form_password_content_type_edit_form($form, &$form_state) { + return $form; +} diff --git a/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_picture.inc b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_picture.inc new file mode 100644 index 000000000..ac310bed7 --- /dev/null +++ b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_picture.inc @@ -0,0 +1,51 @@ + TRUE, + 'icon' => 'icon_user_form.png', + 'title' => t('User form picture field'), + 'description' => t('The user picture form.'), + 'required context' => new ctools_context_required(t('Form'), 'form'), + 'category' => t('Form'), +); + +/** + * Ctools plugin content type render for the picture form field. + */ +function ctools_user_form_picture_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + $block->module = t('user-form'); + + $block->delta = 'title-options'; + + if (isset($context->form)) { + if (!empty($context->form['picture'])) { + $block->content['picture'] = $context->form['picture']; + unset($context->form['picture']); + } + } + else { + $block->content = t('User picture form.'); + } + return $block; +} + +/** + * Ctools plugin admin title function for the picture form field. + */ +function ctools_user_form_picture_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" user form picture field', array('@s' => $context->identifier)); +} + +/** + * Ctools plugin configuration edit form for the picture form field. + * + * Provide a blank form so we have a place to have context setting. + */ +function ctools_user_form_picture_content_type_edit_form($form, &$form_state) { + return $form; +} diff --git a/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_roles.inc b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_roles.inc new file mode 100644 index 000000000..47a169f7f --- /dev/null +++ b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_roles.inc @@ -0,0 +1,51 @@ + TRUE, + 'icon' => 'icon_user_form.png', + 'title' => t('User form roles field'), + 'description' => t('The user roles form.'), + 'required context' => new ctools_context_required(t('Form'), 'form'), + 'category' => t('Form'), +); + +/** + * Ctools plugin content type render for the roles form field. + */ +function ctools_user_form_roles_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + $block->module = t('user-form'); + + $block->delta = 'title-options'; + + if (isset($context->form)) { + if (!empty($context->form['account']['roles'])) { + $block->content['roles'] = $context->form['account']['roles']; + unset($context->form['account']['roles']); + } + } + else { + $block->content = t('User roles form.'); + } + return $block; +} + +/** + * Ctools plugin admin title function for the roles form field. + */ +function ctools_user_form_roles_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" user form roles field', array('@s' => $context->identifier)); +} + +/** + * Ctools plugin configuration edit form for the roles form field. + * + * Provide a blank form so we have a place to have context setting. + */ +function ctools_user_form_roles_content_type_edit_form($form, &$form_state) { + return $form; +} diff --git a/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_signature_settings.inc b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_signature_settings.inc new file mode 100644 index 000000000..2a69ea09e --- /dev/null +++ b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_signature_settings.inc @@ -0,0 +1,51 @@ + TRUE, + 'icon' => 'icon_user_form.png', + 'title' => t('User form signature settings field'), + 'description' => t('The user signature settings form.'), + 'required context' => new ctools_context_required(t('Form'), 'form'), + 'category' => t('Form'), +); + +/** + * Ctools plugin content type render for the signature settings form field. + */ +function ctools_user_form_signature_settings_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + $block->module = t('user-form'); + + $block->delta = 'title-options'; + + if (isset($context->form)) { + if (!empty($context->form['signature_settings'])) { + $block->content['signature_settings'] = $context->form['signature_settings']; + unset($context->form['signature_settings']); + } + } + else { + $block->content = t('User signature settings form.'); + } + return $block; +} + +/** + * Ctools plugin admin title function for the signature settings form field. + */ +function ctools_user_form_signature_settings_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" user form signature settings field', array('@s' => $context->identifier)); +} + +/** + * Ctools plugin configuration edit form for the signature settings form field. + * + * Provide a blank form so we have a place to have context setting. + */ +function ctools_user_form_signature_settings_content_type_edit_form($form, &$form_state) { + return $form; +} diff --git a/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_status.inc b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_status.inc new file mode 100644 index 000000000..7c7f87247 --- /dev/null +++ b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_status.inc @@ -0,0 +1,51 @@ + TRUE, + 'icon' => 'icon_user_form.png', + 'title' => t('User form status field'), + 'description' => t('The user status form.'), + 'required context' => new ctools_context_required(t('Form'), 'form'), + 'category' => t('Form'), +); + +/** + * Ctools plugin content type render for the status form field. + */ +function ctools_user_form_status_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + $block->module = t('user-form'); + + $block->delta = 'title-options'; + + if (isset($context->form)) { + if (!empty($context->form['account']['status'])) { + $block->content['status'] = $context->form['account']['status']; + unset($context->form['account']['status']); + } + } + else { + $block->content = t('User status form.'); + } + return $block; +} + +/** + * Ctools plugin admin title function for the status form field. + */ +function ctools_user_form_status_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" user form status field', array('@s' => $context->identifier)); +} + +/** + * Ctools plugin configuration edit form for the status form field. + * + * Provide a blank form so we have a place to have context setting. + */ +function ctools_user_form_status_content_type_edit_form($form, &$form_state) { + return $form; +} diff --git a/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_timezone.inc b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_timezone.inc new file mode 100644 index 000000000..1a0066488 --- /dev/null +++ b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_timezone.inc @@ -0,0 +1,51 @@ + TRUE, + 'icon' => 'icon_user_form.png', + 'title' => t('User form timezone field'), + 'description' => t('The user timezone form.'), + 'required context' => new ctools_context_required(t('Form'), 'form'), + 'category' => t('Form'), +); + +/** + * Ctools plugin content type render for the timezone form field. + */ +function ctools_user_form_timezone_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + $block->module = t('user-form'); + + $block->delta = 'title-options'; + + if (isset($context->form)) { + if (!empty($context->form['timezone'])) { + $block->content['timezone'] = $context->form['timezone']; + unset($context->form['timezone']); + } + } + else { + $block->content = t('User timezone form.'); + } + return $block; +} + +/** + * Ctools plugin admin title function for the timezone form field. + */ +function ctools_user_form_timezone_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" user form timezone field', array('@s' => $context->identifier)); +} + +/** + * Ctools plugin configuration edit form for the timezone form field. + * + * Provide a blank form so we have a place to have context setting. + */ +function ctools_user_form_timezone_content_type_edit_form($form, &$form_state) { + return $form; +} diff --git a/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_username.inc b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_username.inc new file mode 100644 index 000000000..d64953085 --- /dev/null +++ b/frontend/drupal/sites/all/modules/ctools/plugins/content_types/user_form/user_form_username.inc @@ -0,0 +1,51 @@ + TRUE, + 'icon' => 'icon_user_form.png', + 'title' => t('User form username field'), + 'description' => t('The user username form.'), + 'required context' => new ctools_context_required(t('Form'), 'form'), + 'category' => t('Form'), +); + +/** + * Ctools plugin content type render for the username form field. + */ +function ctools_user_form_username_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + $block->module = t('user-form'); + + $block->delta = 'title-options'; + + if (isset($context->form)) { + if (!empty($context->form['account']['name'])) { + $block->content['name'] = $context->form['account']['name']; + unset($context->form['account']['name']); + } + } + else { + $block->content = t('User username form.'); + } + return $block; +} + +/** + * Ctools plugin admin title function for the username form field. + */ +function ctools_user_form_username_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" user form username field', array('@s' => $context->identifier)); +} + +/** + * Ctools plugin configuration edit form for the username form field. + * + * Provide a blank form so we have a place to have context setting. + */ +function ctools_user_form_username_content_type_edit_form($form, &$form_state) { + return $form; +} diff --git a/frontend/drupal/sites/all/modules/ctools/plugins/contexts/user.inc b/frontend/drupal/sites/all/modules/ctools/plugins/contexts/user.inc index bbdbd1a27..9cd73085e 100644 --- a/frontend/drupal/sites/all/modules/ctools/plugins/contexts/user.inc +++ b/frontend/drupal/sites/all/modules/ctools/plugins/contexts/user.inc @@ -41,10 +41,13 @@ function ctools_context_create_user($empty, $data = NULL, $conf = FALSE) { if ($conf) { if ($data['type'] == 'current') { global $user; - $data = user_load($user->uid); if (user_is_logged_in()) { + $data = user_load($user->uid); $data->logged_in_user = TRUE; } + else { + $data = drupal_anonymous_user(); + } } else { $data = user_load($data['uid']); diff --git a/frontend/drupal/sites/all/modules/ctools/plugins/export_ui/ctools_export_ui.class.php b/frontend/drupal/sites/all/modules/ctools/plugins/export_ui/ctools_export_ui.class.php index 0c8145e4b..f78795aad 100644 --- a/frontend/drupal/sites/all/modules/ctools/plugins/export_ui/ctools_export_ui.class.php +++ b/frontend/drupal/sites/all/modules/ctools/plugins/export_ui/ctools_export_ui.class.php @@ -310,7 +310,7 @@ class ctools_export_ui { $form['bottom row']['reset'] = array( '#type' => 'submit', - '#id' => 'ctools-export-ui-list-items-apply', + '#id' => 'ctools-export-ui-list-items-reset', '#value' => t('Reset'), '#attributes' => array('class' => array('use-ajax-submit')), ); diff --git a/frontend/drupal/sites/all/modules/ctools/plugins/relationships/comment_parent.inc b/frontend/drupal/sites/all/modules/ctools/plugins/relationships/comment_parent.inc new file mode 100644 index 000000000..ae29a08ce --- /dev/null +++ b/frontend/drupal/sites/all/modules/ctools/plugins/relationships/comment_parent.inc @@ -0,0 +1,32 @@ + t('Parent comment'), + 'keyword' => 'parent_comment', + 'description' => t('Adds a parent comment from a comment context.'), + 'required context' => new ctools_context_required(t('Comment'), 'entity:comment'), + 'context' => 'ctools_comment_parent_context', +); + +/** + * Return a new context based on an existing context. + */ +function ctools_comment_parent_context($context, $conf) { + if (empty($context->data)) { + return ctools_context_create_empty('entity:comment'); + } + + if (isset($context->data->pid) && ($context->data->pid !== 0)) { + $parent_comment = comment_load($context->data->pid); + return ctools_context_create('entity:comment', $parent_comment); + } +} diff --git a/frontend/drupal/sites/all/modules/ctools/stylizer/stylizer.info b/frontend/drupal/sites/all/modules/ctools/stylizer/stylizer.info index a86ada601..6b7f70f5e 100644 --- a/frontend/drupal/sites/all/modules/ctools/stylizer/stylizer.info +++ b/frontend/drupal/sites/all/modules/ctools/stylizer/stylizer.info @@ -5,8 +5,8 @@ package = Chaos tool suite dependencies[] = ctools dependencies[] = color -; Information added by Drupal.org packaging script on 2020-10-23 -version = "7.x-1.17" +; Information added by Drupal.org packaging script on 2021-01-30 +version = "7.x-1.19" core = "7.x" project = "ctools" -datestamp = "1603490551" +datestamp = "1611988843" diff --git a/frontend/drupal/sites/all/modules/ctools/term_depth/term_depth.info b/frontend/drupal/sites/all/modules/ctools/term_depth/term_depth.info index 4f05954df..5cceeda7a 100644 --- a/frontend/drupal/sites/all/modules/ctools/term_depth/term_depth.info +++ b/frontend/drupal/sites/all/modules/ctools/term_depth/term_depth.info @@ -4,8 +4,8 @@ core = 7.x dependencies[] = ctools package = Chaos tool suite -; Information added by Drupal.org packaging script on 2020-10-23 -version = "7.x-1.17" +; Information added by Drupal.org packaging script on 2021-01-30 +version = "7.x-1.19" core = "7.x" project = "ctools" -datestamp = "1603490551" +datestamp = "1611988843" diff --git a/frontend/drupal/sites/all/modules/ctools/tests/ctools_export_test/ctools_export_test.info b/frontend/drupal/sites/all/modules/ctools/tests/ctools_export_test/ctools_export_test.info index bc231dbf1..6bb6063a3 100644 --- a/frontend/drupal/sites/all/modules/ctools/tests/ctools_export_test/ctools_export_test.info +++ b/frontend/drupal/sites/all/modules/ctools/tests/ctools_export_test/ctools_export_test.info @@ -7,8 +7,8 @@ hidden = TRUE files[] = ctools_export.test -; Information added by Drupal.org packaging script on 2020-10-23 -version = "7.x-1.17" +; Information added by Drupal.org packaging script on 2021-01-30 +version = "7.x-1.19" core = "7.x" project = "ctools" -datestamp = "1603490551" +datestamp = "1611988843" diff --git a/frontend/drupal/sites/all/modules/ctools/tests/ctools_plugin_test.info b/frontend/drupal/sites/all/modules/ctools/tests/ctools_plugin_test.info index bdb624c7b..5c955bb41 100644 --- a/frontend/drupal/sites/all/modules/ctools/tests/ctools_plugin_test.info +++ b/frontend/drupal/sites/all/modules/ctools/tests/ctools_plugin_test.info @@ -5,8 +5,8 @@ core = 7.x dependencies[] = ctools hidden = TRUE -; Information added by Drupal.org packaging script on 2020-10-23 -version = "7.x-1.17" +; Information added by Drupal.org packaging script on 2021-01-30 +version = "7.x-1.19" core = "7.x" project = "ctools" -datestamp = "1603490551" +datestamp = "1611988843" diff --git a/frontend/drupal/sites/all/modules/ctools/views_content/plugins/views/views_content_plugin_display_panel_pane.inc b/frontend/drupal/sites/all/modules/ctools/views_content/plugins/views/views_content_plugin_display_panel_pane.inc index 801d3d61e..af0704f30 100644 --- a/frontend/drupal/sites/all/modules/ctools/views_content/plugins/views/views_content_plugin_display_panel_pane.inc +++ b/frontend/drupal/sites/all/modules/ctools/views_content/plugins/views/views_content_plugin_display_panel_pane.inc @@ -385,13 +385,6 @@ class views_content_plugin_display_panel_pane extends views_plugin_display { return (bool) $conf['more_link']; } - /** - * {@inheritdoc} - */ - public function has_path() { - return TRUE; - } - /** * {@inheritdoc} */ diff --git a/frontend/drupal/sites/all/modules/ctools/views_content/tests/modules/views_content_test.info b/frontend/drupal/sites/all/modules/ctools/views_content/tests/modules/views_content_test.info new file mode 100644 index 000000000..336876a85 --- /dev/null +++ b/frontend/drupal/sites/all/modules/ctools/views_content/tests/modules/views_content_test.info @@ -0,0 +1,11 @@ +name = Views content panes Test +description = Test module for Views content panes. +package = Views +core = 7.x +dependencies[] = views_content +hidden = TRUE +; Information added by Drupal.org packaging script on 2021-01-30 +version = "7.x-1.19" +core = "7.x" +project = "ctools" +datestamp = "1611988843" diff --git a/frontend/drupal/sites/all/modules/ctools/views_content/tests/modules/views_content_test.module b/frontend/drupal/sites/all/modules/ctools/views_content/tests/modules/views_content_test.module new file mode 100644 index 000000000..52998650a --- /dev/null +++ b/frontend/drupal/sites/all/modules/ctools/views_content/tests/modules/views_content_test.module @@ -0,0 +1,15 @@ + 3.0, + ); +} diff --git a/frontend/drupal/sites/all/modules/ctools/views_content/tests/modules/views_content_test.views_default.inc b/frontend/drupal/sites/all/modules/ctools/views_content/tests/modules/views_content_test.views_default.inc new file mode 100644 index 000000000..6dd08494c --- /dev/null +++ b/frontend/drupal/sites/all/modules/ctools/views_content/tests/modules/views_content_test.views_default.inc @@ -0,0 +1,82 @@ +name = 'views_content_more_link'; + $view->description = ''; + $view->tag = 'default'; + $view->base_table = 'node'; + $view->human_name = 'views_content_more_link'; + $view->core = 7; + $view->api_version = '3.0'; + $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */ + + /* Display: Master */ + $handler = $view->new_display('default', 'Master', 'default'); + $handler->display->display_options['title'] = 'views_content_more_link'; + $handler->display->display_options['use_more'] = TRUE; + $handler->display->display_options['use_more_always'] = FALSE; + $handler->display->display_options['access']['type'] = 'perm'; + $handler->display->display_options['cache']['type'] = 'none'; + $handler->display->display_options['query']['type'] = 'views_query'; + $handler->display->display_options['exposed_form']['type'] = 'basic'; + $handler->display->display_options['pager']['type'] = 'none'; + $handler->display->display_options['pager']['options']['offset'] = '0'; + $handler->display->display_options['style_plugin'] = 'table'; + $handler->display->display_options['style_options']['columns'] = array( + 'title' => 'title', + ); + $handler->display->display_options['style_options']['class'] = ''; + $handler->display->display_options['style_options']['default'] = '-1'; + $handler->display->display_options['style_options']['info'] = array( + 'title' => array( + 'sortable' => 0, + 'default_sort_order' => 'asc', + 'align' => '', + 'separator' => '', + 'empty_column' => 0, + ), + ); + /* Field: Content: Title */ + $handler->display->display_options['fields']['title']['id'] = 'title'; + $handler->display->display_options['fields']['title']['table'] = 'node'; + $handler->display->display_options['fields']['title']['field'] = 'title'; + $handler->display->display_options['fields']['title']['label'] = ''; + $handler->display->display_options['fields']['title']['alter']['word_boundary'] = FALSE; + $handler->display->display_options['fields']['title']['alter']['ellipsis'] = FALSE; + /* Sort criterion: Content: Post date */ + $handler->display->display_options['sorts']['created']['id'] = 'created'; + $handler->display->display_options['sorts']['created']['table'] = 'node'; + $handler->display->display_options['sorts']['created']['field'] = 'created'; + $handler->display->display_options['sorts']['created']['order'] = 'DESC'; + /* Filter criterion: Content: Published status */ + $handler->display->display_options['filters']['status']['id'] = 'status'; + $handler->display->display_options['filters']['status']['table'] = 'node'; + $handler->display->display_options['filters']['status']['field'] = 'status'; + $handler->display->display_options['filters']['status']['value'] = 1; + $handler->display->display_options['filters']['status']['group'] = 1; + $handler->display->display_options['filters']['status']['expose']['operator'] = FALSE; + + /* Display: Page */ + $handler = $view->new_display('page', 'Page', 'page'); + $handler->display->display_options['path'] = 'views-content-more-link'; + + /* Display: Content pane */ + $handler = $view->new_display('panel_pane', 'Content pane', 'panel_pane_1'); + $handler->display->display_options['defaults']['pager'] = FALSE; + $handler->display->display_options['pager']['type'] = 'some'; + $handler->display->display_options['pager']['options']['items_per_page'] = '3'; + $handler->display->display_options['pager']['options']['offset'] = '0'; + + $views[$view->name] = $view; + + return $views; +} diff --git a/frontend/drupal/sites/all/modules/ctools/views_content/tests/src/views_content.test b/frontend/drupal/sites/all/modules/ctools/views_content/tests/src/views_content.test new file mode 100644 index 000000000..25fee392b --- /dev/null +++ b/frontend/drupal/sites/all/modules/ctools/views_content/tests/src/views_content.test @@ -0,0 +1,79 @@ + 'Views content panes tests', + 'description' => 'Tests rendering views content pane displays.', + 'group' => 'ctools', + 'dependencies' => array('ctools', 'views'), + ); + } + + /** + * {@inheritdoc} + */ + public function setUp(array $modules = array()) { + $modules[] = 'ctools'; + $modules[] = 'views_content'; + $modules[] = 'views_content_test'; + parent::setUp($modules); + } + + /** + * Tests rendering a content pane with a more link. + */ + public function testViewMoreLink() { + // The view "views_content_more_link" has two displays: a content pane + // display and a page display. The content pane display displays 3 nodes, + // the page display displays all items. + // On the content pane display a "more" link is configured that should link + // to the page. + $view = views_get_view('views_content_more_link'); + + // Create four nodes that the view will display. The first three + // will get displayed on the content pane display and the remaining + // on the page display. + for ($i = 0; $i < 4; $i++) { + $this->drupalCreateNode(); + } + + // Render the content pane display and assert that a more link is shown. + $view->set_display('panel_pane_1'); + $rendered_output = $view->preview(); + $this->verbose($rendered_output); + $this->storeViewPreview($rendered_output); + + $this->assertLink('more'); + $this->assertLinkByHref('views-content-more-link'); + } + + /** + * Stores a view output in the elements. + * + * @param string $output + * The Views HTML output. + */ + protected function storeViewPreview($output) { + $html_dom = new DOMDocument(); + @$html_dom->loadHTML($output); + if ($html_dom) { + // It's much easier to work with simplexml than DOM, luckily enough + // we can just simply import our DOM tree. + $this->elements = simplexml_import_dom($html_dom); + } + } + +} diff --git a/frontend/drupal/sites/all/modules/ctools/views_content/views_content.info b/frontend/drupal/sites/all/modules/ctools/views_content/views_content.info index 9b348c52a..3ab45e665 100644 --- a/frontend/drupal/sites/all/modules/ctools/views_content/views_content.info +++ b/frontend/drupal/sites/all/modules/ctools/views_content/views_content.info @@ -8,9 +8,10 @@ package = Chaos tool suite files[] = plugins/views/views_content_plugin_display_ctools_context.inc files[] = plugins/views/views_content_plugin_display_panel_pane.inc files[] = plugins/views/views_content_plugin_style_ctools_context.inc +files[] = tests/src/views_content.test -; Information added by Drupal.org packaging script on 2020-10-23 -version = "7.x-1.17" +; Information added by Drupal.org packaging script on 2021-01-30 +version = "7.x-1.19" core = "7.x" project = "ctools" -datestamp = "1603490551" +datestamp = "1611988843" diff --git a/frontend/drupal/sites/all/modules/jquery_update/replace/ui/ui/.jshintrc b/frontend/drupal/sites/all/modules/jquery_update/replace/ui/ui/.jshintrc index c7589525f..3204017c9 100644 --- a/frontend/drupal/sites/all/modules/jquery_update/replace/ui/ui/.jshintrc +++ b/frontend/drupal/sites/all/modules/jquery_update/replace/ui/ui/.jshintrc @@ -8,7 +8,7 @@ "latedef": true, "noarg": true, "onevar": true, - "quotmark": "double", + "quotmark": "single", "trailing": true, "undef": true, "unused": true, diff --git a/frontend/drupal/sites/all/modules/modernizr/LICENSE.txt b/frontend/drupal/sites/all/modules/modernizr/LICENSE.txt new file mode 100644 index 000000000..d159169d1 --- /dev/null +++ b/frontend/drupal/sites/all/modules/modernizr/LICENSE.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 2 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, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/frontend/drupal/sites/all/modules/modernizr/README.txt b/frontend/drupal/sites/all/modules/modernizr/README.txt new file mode 100644 index 000000000..0f9e9950f --- /dev/null +++ b/frontend/drupal/sites/all/modules/modernizr/README.txt @@ -0,0 +1,57 @@ +Modernizr for Drupal +==================== + +This module implements Modernizr, the client-side feature detection +library. Modernizr allows you to avoid user-agent sniffing on the +server, and rely on the honesty of the browsers that visit your +website by detecting each individual feature that they support. + +Modernizr will inject yes/no classes into your tag for each +test, so that you can write conditional rules based on the results: + + .multiplebgs div p { + /* properties for browsers that + support multiple backgrounds */ + } + .no-multiplebgs div p { + /* optional fallback properties + for browsers that don't */ + } + +Modernizr v2 optionally includes a script loader which can load +additional resources based on the outcome of specific Modernizr +tests you're interested in: + + Modernizr.load({ + test : Modernizr.geolocation, + yep : 'normal.js', + nope : ['polyfill.js', 'wrapper.js'] + }); + +The 3.x branch of the Drupal module integrates Modernizr.load() +so it can be used by themes/modules that support HTML5/CSS3. + +Documentation +============= + +Read about Modernizr: http://www.modernizr.com/docs/ +Module documentation: http://drupal.org/node/1913744 + +Installation & Usage +==================== + +1. Install module +2. Build Modernizr at /admin/config/development/modernizr +3. Place your custom build inside sites/all/libraries/modernizr + +Credits +======= + +Project page: http://drupal.org/project/modernizr +Library page: http://modernizr.com + +Module originally written by: +Tams Demeter-Haludka - http://drupal.org/user/372872 + +Maintainers: +Chris Ruppel - http://drupal.org/user/411999 diff --git a/frontend/drupal/sites/all/modules/modernizr/css/modernizr.admin.css b/frontend/drupal/sites/all/modules/modernizr/css/modernizr.admin.css new file mode 100644 index 000000000..530a411e9 --- /dev/null +++ b/frontend/drupal/sites/all/modules/modernizr/css/modernizr.admin.css @@ -0,0 +1,41 @@ +/** + * @file + * Administrative CSS for Modernizr module. + */ + +body.page-admin-config-development-modernizr .modernizr-tests { + margin-left: 2em; +} + +body.page-admin-config-development-modernizr .modernizr-tests h3 { + float: left; + clear: left; + margin: 0 1em 1em 0; +} + +body.page-admin-config-development-modernizr .modernizr-tests p.desc { + float: left; + margin: 0; +} + +body.page-admin-config-development-modernizr div.download-modernizr { + float: none; + clear: both; + padding-top: 1em; +} + +/** + * Styles for Test API. Based on whether our current Modernizr lib is in sync + * with the latest Test API settings. + */ +body.page-admin-config-development-modernizr .modernizr-tests h3.not-included { + font-weight: bold; + color: #d02; +} +body.page-admin-config-development-modernizr .modernizr-tests h3.not-included::after { + content: " (missing)"; + font-size: .7em; + vertical-align: top; + position: relative; + top: -2px; +} diff --git a/frontend/drupal/sites/all/modules/modernizr/drush/modernizr.drush.inc b/frontend/drupal/sites/all/modules/modernizr/drush/modernizr.drush.inc new file mode 100644 index 000000000..bb4afb528 --- /dev/null +++ b/frontend/drupal/sites/all/modules/modernizr/drush/modernizr.drush.inc @@ -0,0 +1,99 @@ + '_modernizr_drush_download_dev', + 'description' => dt('This command used to download a development copy of Modernizr but it is no longer offered on modernizr.com as of v3'), + 'aliases' => array('mdl'), + ); + $items['modernizr-build'] = array( + 'callback' => '_modernizr_drush_custom_build', + 'description' => dt('Requests a custom build of Modernizr based on your Drupal module settings. Depends on node.js/npm.'), + 'aliases' => array('mcb'), + 'arguments' => array(), + ); + + return $items; +} + +/** + * Implements hook_drush_help(). + * + * This function is called whenever a drush user calls + * 'drush help ' + * + * @param + * A string with the help section (prepend with 'drush:') + * + * @return + * A string with the help text for your command. + */ +function modernizr_drush_help($section) { + switch ($section) { + case 'error:modernizr-dev': + case 'drush:modernizr-dev': + return dt('This command used to download a development copy of Modernizr but it is no longer offered on modernizr.com as of v3'); + case 'drush:modernizr-build': + return dt('Queries Drupal modules for any Modernizr tests they require, and creates a request for a node.js-powered CLI builder. You must install node.js, npm, and the CLI builder beforehand.'); + } +} + +/** + * Helper function downloads the uncompressed development copy of Modernizr. + */ +function _modernizr_drush_download_dev() { + return drush_set_error('modernizr-dev'); +} + +/** + * Helper function that generates a list of Modernizr tests + * from other modules and sends them to the node.js CLI builder. + */ +function _modernizr_drush_custom_build() { + $output_args = array(); + $args = modernizr_api_list(); + $output = ''; + + // Get the map of Modernizr args. + include_once(drupal_get_path('module', 'modernizr') . '/modernizr.args.inc'); + + // Fetch all the tests, and record which modules supplied them. + foreach ($args as $key => $test) { + $meta = _modernizr_args_return($key); + $type = $meta['type']; + $output_args[$type][] = $key; + } + + // Collapse tests into the format accepted by the node builder. + $tests = (isset($output_args['tests'])) ? ' -t ' . implode(' ', $output_args['tests']) : ''; + $extras = (isset($output_args['extras'])) ? ' -e ' . implode(' ', $output_args['extras']) : ''; + $groups = (isset($output_args['groups'])) ? ' -g ' . implode(' ', $output_args['groups']) : ''; + $not = (isset($output_args['not'])) ? ' -n ' . implode(' ', $output_args['not']) : ''; + + $output = $tests . $extras . $groups . $not; + + return $output; +} diff --git a/frontend/drupal/sites/all/modules/modernizr/js/yepnope.js b/frontend/drupal/sites/all/modules/modernizr/js/yepnope.js new file mode 100644 index 000000000..38e3f9033 --- /dev/null +++ b/frontend/drupal/sites/all/modules/modernizr/js/yepnope.js @@ -0,0 +1,5 @@ +/*! + * yepnope1.5.4 + * (c) WTFPL, GPLv2 + */ +(function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f 'fieldset', + '#title' => t('Placement and Performance'), + ); + + // Option to set the scope of Modernizr. + $form['js']['modernizr_scope'] = array( + '#type' => 'select', + '#title' => t('Where should Modernizr be loaded?'), + '#options' => array( + 'header' => t('header'), + 'footer' => t('footer'), + ), + '#default_value' => variable_get('modernizr_scope', MODERNIZR_SCOPE_DEFAULT), + '#description' => t('When possible, it is recommended to print all JavaScript in the footer unless you are using a specific set of features which require blocking execution in the <head>. Read more on GitHub. Important: you should not move Modernizr to the bottom of the page unless ALL dependent scripts are also after Modernizr (higher weight in drupal_add_js() settings).', array('@url' => 'https://github.com/Modernizr/Modernizr/issues/878#issuecomment-41448059')), + ); + + // Options to determine how Modernizr is included. Although these options are + // presented as one group, they control two settings within drupal_add_js() + // because an inline file cannot be deferred. If inline is set, it precludes + // us from setting `defer` to TRUE. Conversely if `defer` is chosen, we must + // set the type to `file` when invoking drupal_add_js(). + $form['js']['modernizr_type'] = array( + '#type' => 'select', + '#title' => t('How should Modernizr be loaded?'), + '#options' => array( + 'defer' => t('Defer'), + 'inline' => t('Inline'), + 'sync' => t('Synchronous'), + ), + '#default_value' => variable_get('modernizr_type', MODERNIZR_TYPE_DEFAULT), + '#description' => t('When possible, it is recommended to defer this JavaScript unless you are using a specific set of features which require blocking execution in the <head>. Important: you should not defer Modernizr unless any dependent scripts are also deferred.

    In some cases, it might be beneficial to inline this JavaScript file. Make sure that you can confirm that this works better for your site by measuring performance! Read more on GitHub.', array('@url' => 'https://github.com/Modernizr/Modernizr/issues/878#issuecomment-41448059')), + ); + + // Fieldset for custom build options. + $form['build_options'] = array( + '#type' => 'fieldset', + '#title' => t('Custom Build Options'), + ); + + // Custom builds no longer require printshiv by default. + $form['build_options']['modernizr_cb_printshiv'] = array( + '#type' => 'checkbox', + '#title' => t('Require printshiv when custom builds are created.'), + '#default_value' => variable_get('modernizr_cb_printshiv', FALSE), + ); + + // Modernizr v3 deprecated direct inclusion of Modernizr.load(). In order to + // continue using Modernizr.load(), we have to include yepnope.js ourselves. + $form['build_options']['modernizr_cb_load'] = array( + '#type' => 'checkbox', + '#title' => t('Include Modernizr.load() functionality. Modernizr v3 no longer includes this script itself. Read more on GitHub.', array('@url' => 'https://github.com/Modernizr/Modernizr/issues/1182')), + '#default_value' => variable_get('modernizr_cb_load', MODERNIZR_YEPNOPE_DEFAULT), + ); + + // Fieldset for reporting options. + $form['reporting'] = array( + '#type' => 'fieldset', + '#title' => t('Error reporting'), + ); + + // Reduce severity of requirements errors. Admin can use this option to avoid + // seeing the red boxes when Modernizr requirements are not met. + $form['reporting']['modernizr_quiet'] = array( + '#type' => 'checkbox', + '#title' => t('Decrease severity of Modernizr Test API errors.'), + '#description' => t('Check this box if you\'d rather not see the red warning about missing Modernizr tests (or lack of a custom build). Enabling this option will not make Modernizr function properly if things are missing, but it will suppress the error message.'), + '#default_value' => variable_get('modernizr_quiet', MODERNIZR_QUIET_DEFAULT), + ); + + return system_settings_form($form); +} + + +/** + * Generates new Modernizr URL for admin interface + * Callback for 'admin/config/development/modernizr'. + */ +function modernizr_generate_url() { + // Reset our lists of needed Modernizr tests in drupal_static. + drupal_static_reset('modernizr_api_list'); + + // Get latest tests from modules and themes + $tests = modernizr_api_list(); + + // Begin assembling link to re-download Modernizr + $link = 'https://modernizr.com/download/?'; + + // Pull tests that are currently set. + $current_tests = _modernizr_current_build(); + + if (is_null($current_tests)) { + // We can't find a custom build of modernizr. + // Decide how severe this warning is based on admin settings. + $modernizr_severity = (variable_get('modernizr_quiet', MODERNIZR_QUIET_DEFAULT)) ? 'warning' : 'error'; + + // Set error/warning message. + drupal_set_message(t("You don't seem to have a custom build of Modernizr installed yet, or we are detecting the wrong version. Remove any existing modernizr-latest.js or modernizr custom builds from !path and replace it with a new copy. This page will help generate one for you.", array( + '!path' => module_exists('libraries') ? libraries_get_path('modernizr') : 'sites/all/libraries/modernizr' + )), $modernizr_severity); + } + else { + // Generate the list of tests that are being requested by the Test API, but + // are NOT in the Modernizr JS file. + $missing_tests = array_diff_key($tests, array_flip($current_tests)); + + foreach ($current_tests as $current_test) { + // Adds all current tests to the array of tests. + if (!isset($tests[$current_test])) { + $tests[$current_test] = array( + 'name' => $current_test, + 'source' => array(modernizr_get_filename()), + 'desc' => _modernizr_get_desc($current_test), + 'docs' => '', + 'caniuse' => '', + ); + } + } + } + + // Create indexes for first download link/desc to place them + // above everything. They will be populated later. + $elements['download_modernizr1']['link'] = array(); + $elements['download_modernizr1']['description'] = array(); + + // Give a hint about which file is currently in use and in which directories + // we have searched for the file. + $file_path = modernizr_get_path(); + $file_markup = $file_path ? l($file_path, $file_path) : t('No file found'); + $elements['modernizr_file']['title'] = array( + '#type' => 'html_tag', + '#value' => t('Currently loaded file'), + '#tag' => 'h2', + ); + $elements['modernizr_file']['file'] = array( + '#type' => 'markup', + '#markup' => $file_markup, + ); + if (!$file_path) { + $elements['modernizr_file']['paths'] = array( + '#theme' => 'item_list', + '#title' => t('Scanned directories'), + '#items' => _modernizr_get_paths(), + ); + } + + // Create the tests heading render element. + $elements['tests']['heading-tests'] = array( + '#theme' => 'html_tag', + '#value' => t('Current Modernizr Tests'), + '#tag' => 'h2', + ); + + // Create the tests description render element. + $elements['tests']['description'] = array( + '#theme' => 'html_tag', + '#value' => t('Currently enabled Drupal modules and themes have requested the following Modernizr tests:'), + '#tag' => 'p', + ); + + // Create a container to indent everything + $elements['tests']['list'] = array( + '#prefix' => '
    ', + '#suffix' => '
    ', + ); + + // Check to see if there are any registered tests. + if (!empty($tests)) { + // Loop through each registered test. + foreach ($tests as $key => $test) { + // API was changed between 7.x-3.0 and 7.x-3.1. We originally specified + // `module` but since themes can also specify tests the attribute was + // changed to `source`. + $source = (isset($test['source'])) ? $test['source'] : $test['module']; + + // Check to see if this test has been set. If not, add it. + if (!isset($elements['tests']['list'][$key])) { + // Check if this test is missing, and apply a special class only when it + // is missing from the current build of Modernizr JS file. + $not_included = (isset($missing_tests[$key])) ? 'not-included' : ''; + + // Build the element for this Modernizr test. + $elements['tests']['list'][$key]['name'] = array( + '#theme' => 'html_tag', + '#value' => $key, + '#tag' => 'h3', + '#attributes' => array('class' => $not_included), + ); + } + + // Create the description for this test. + $elements['tests']['list'][$key]['tests'][] = array( + 'description' => array( + '#markup' => _modernizr_get_desc($key), + '#prefix' => '

    ', + '#suffix' => '

    ', + ), + ); + + // @TODO: Check to see if this test has already been added by another module. + $link .= $key . '-'; + } + } + else { + $elements['tests']['list']['#markup'] = '

    There are no Modernizr tests registered

    '; + } + + // Create the download link render element. + $download_link = array( + '#prefix' => '
    ', + '#theme' => 'link', + '#text' => t('Download your Modernizr production build'), + '#path' => substr($link, 0, -1), // Truncate the last hyphen. + '#options' => array( + 'attributes' => array( + 'class' => array( + 'button', + ), + 'target' => '_blank', + ), + 'html' => FALSE, + ), + '#suffix' => '
    ', + ); + + // Create the download description render element. + $download_desc = array( + '#theme' => 'html_tag', + '#value' => t('The button links to a custom Modernizr build based on the tests listed above.
    Once you download the script, place it inside !path and !cc.', array( + '!path' => module_exists('libraries') ? libraries_get_path('modernizr') : 'sites/all/libraries/modernizr', + '!cc' => l(t('clear your cache'), 'admin/config/development/performance'), + )), + '#tag' => 'p', + ); + + // Print the Download link above and below the tests. + $elements['download_modernizr1']['link'] = $download_link; + $elements['download_modernizr2']['link'] = $download_link; + + // Print the Download description above and below the tests. + $elements['download_modernizr1']['description'] = $download_desc; + $elements['download_modernizr2']['description'] = $download_desc; + + // Load admin CSS + drupal_add_css(drupal_get_path('module', 'modernizr') . '/css/modernizr.admin.css'); + + return $elements; +} diff --git a/frontend/drupal/sites/all/modules/modernizr/modernizr.api.php b/frontend/drupal/sites/all/modules/modernizr/modernizr.api.php new file mode 100644 index 000000000..ebd802cda --- /dev/null +++ b/frontend/drupal/sites/all/modules/modernizr/modernizr.api.php @@ -0,0 +1,114 @@ + 'Modernizr.borderradius', + + // If the test PASSES load these files. Example shows a hardcoded path. + 'yep' => array('/css/radius.css'), + + // If the test FAILS load these files. Example shows a Drupal path (don't + // forget opening slash, or it won't work except at your site root) + 'nope' => array('/' . drupal_get_path('module', 'modernizr') . '/fake/path/to/radius.css'), + + // These resources will always load regardless of the test results. + // 'load' and 'both' offer the exact same functionality. + 'both' => array('/always/loaded.js'), + 'load' => array('/always/loaded.js'), + + // Each JavaScript callback should be enclosed inside an anonymous function. + // Take care to format correctly. You can provide an array of functions that + // should match the number of items in your yep or nope properties. + 'callback' => array('function(){console.log("If you can see this, a Modernizr.load() individual callback was fired.")}'), + + // The final 'complete' callback requires an anonymous JavaScript function. + // Take care to format correctly. Despite being inside an array, you should + // only add one function. + 'complete' => array('function(){console.log("If you can see this, the Modernizr.load() complete callback was fired.")}'), + ); + + return $load; +} + +/** + * @} End of "addtogroup hooks". + */ diff --git a/frontend/drupal/sites/all/modules/modernizr/modernizr.args.inc b/frontend/drupal/sites/all/modules/modernizr/modernizr.args.inc new file mode 100644 index 000000000..bc6a2d63b --- /dev/null +++ b/frontend/drupal/sites/all/modules/modernizr/modernizr.args.inc @@ -0,0 +1,263 @@ + array( + 'type' => 'tests', + 'desc' => 'Browser cache layer that allows for offline usage of web applications.', + ), + 'audio' => array( + 'type' => 'tests', + 'desc' => 'Built-in audio support using <audio>.', + ), + 'borderradius' => array( + 'type' => 'tests', + 'desc' => 'CSS property that allows for rounded corners.', + ), + 'boxshadow' => array( + 'type' => 'tests', + 'desc' => 'CSS property that allows for drop-shadows around an element.', + ), + 'backgroundsize' => array( + 'type' => 'tests', + 'desc' => 'CSS property that allows a background image to resize based on its container.', + ), + 'borderimage' => array( + 'type' => 'tests', + 'desc' => 'CSS property that allows for image-based borders around elements.', + ), + 'canvas' => array( + 'type' => 'tests', + 'desc' => 'JavaScript API that allows for dynamic, scriptable rendering of 2D shapes and bitmap images.', + ), + 'canvastext' => array( + 'type' => 'tests', + 'desc' => 'JavaScript API that allows for text effects within <canvas>.', + ), + 'cssanimations' => array( + 'type' => 'tests', + 'desc' => 'CSS property that allows for keyframe-based animations.', + ), + 'csscolumns' => array( + 'type' => 'tests', + 'desc' => 'CSS property that allows elements to be formatted in columns.', + ), + 'cssgradients' => array( + 'type' => 'tests', + 'desc' => 'CSS property that creates vector-based background gradients.', + ), + 'cssreflections' => array( + 'type' => 'tests', + 'desc' => 'CSS property that creates a "reflection" below the element.', + ), + 'csstransforms' => array( + 'type' => 'tests', + 'desc' => 'CSS properties that allow elements to be moved or rotated in 2D space.', + ), + 'csstransforms3d' => array( + 'type' => 'tests', + 'desc' => 'CSS properties that allow elements to be moved or rotated in 3D space.', + ), + 'csstransitions' => array( + 'type' => 'tests', + 'desc' => 'CSS property that allow other CSS properties to smoothly tween between two values.', + ), + 'draganddrop' => array( + 'type' => 'tests', + 'desc' => 'JavaScript API that allows elements to be moved with the user\'s cursor.', + ), + 'flexbox' => array( + 'type' => 'tests', + 'desc' => 'CSS properties that allow for advanced, content-independent layouts.', + ), + 'flexboxlegacy' => array( + 'type' => 'tests', + 'desc' => 'An old version of the CSS properties that allow for advanced, content-independent layouts.', + ), + 'fontface' => array( + 'type' => 'tests', + 'desc' => 'CSS properties that allow use of web fonts.', + ), + 'generatedcontent' => array( + 'type' => 'tests', + 'desc' => 'CSS properties that allow CSS to generate presentational content.', + ), + 'geolocation' => array( + 'type' => 'tests', + 'desc' => 'JavaScript API that allows the browser to determine its physical location.', + ), + 'hashchange' => array( + 'type' => 'tests', + 'desc' => 'JavaScript API that provides an event listener for changes to window.location.hash.', + ), + 'history' => array( + 'type' => 'tests', + 'desc' => 'JavaScript API that allows window.location to be updated dynamically.', + ), + 'hsla' => array( + 'type' => 'tests', + 'desc' => 'CSS value that allows colors to be specified in terms of hue, saturation, lightness, and alpha.', + ), + 'indexeddb' => array( + 'type' => 'tests', + 'desc' => 'JavaScript API that allows access to a local database which supports indexing.', + ), + 'inlinesvg' => array( + 'type' => 'tests', + 'desc' => 'Browser support for inline SVG images.', + ), + 'input' => array( + 'type' => 'tests', + 'desc' => 'Browser support for new <input> attributes such as placeholder, autocomplete, required...', + ), + 'inputtypes' => array( + 'type' => 'tests', + 'desc' => 'Browser support for new <input> types such as color, date, number, tel...', + ), + 'localstorage' => array( + 'type' => 'tests', + 'desc' => 'JavaScript API that allows access to a simple key/value store that persists across sessions.', + ), + 'multiplebgs' => array( + 'type' => 'tests', + 'desc' => 'CSS value that allows multiple background images to be specified on a single element.', + ), + 'opacity' => array( + 'type' => 'tests', + 'desc' => 'CSS property that allows for alpha transparency.', + ), + 'pointerevents' => array( + 'type' => 'tests', + 'desc' => 'JavaScript API for pointer events.', + ), + 'postmessage' => array( + 'type' => 'tests', + 'desc' => 'JavaScript API for cross-domain communication.', + ), + 'rgba' => array( + 'type' => 'tests', + 'desc' => 'CSS value that allows colors to be specified in terms of red, green, blue, and alpha.', + ), + 'sessionstorage' => array( + 'type' => 'tests', + 'desc' => 'JavaScript API that allows access to a simple key/value store. Cannot persist across sessions.', + ), + 'smil' => array( + 'type' => 'tests', + 'desc' => 'Synchronized Multimedia Integration Language.', + ), + 'svg' => array( + 'type' => 'tests', + 'desc' => 'Browser support for SVG images.', + ), + 'svgclippaths' => array( + 'type' => 'tests', + 'desc' => 'Browser support for non-rectangular element shapes.', + ), + 'textshadow' => array( + 'type' => 'tests', + 'desc' => 'CSS property that allows for drop-shadows behind text.', + ), + 'touchevents' => array( + 'type' => 'tests', + 'desc' => 'JavaScript API for touch events.', + ), + 'video' => array( + 'type' => 'tests', + 'desc' => 'Built-in video support using <video>.', + ), + 'webgl' => array( + 'type' => 'tests', + 'desc' => 'JavaScript API for WebGL, the 3D graphics layer.', + ), + 'websockets' => array( + 'type' => 'tests', + 'desc' => 'JavaScript API for asynchronous browser communication.', + ), + 'websqldatabase' => array( + 'type' => 'tests', + 'desc' => 'JavaScript API that allows access to a local database which supports a SQL-type language.', + ), + 'webworkers' => array( + 'type' => 'tests', + 'desc' => 'JavaScript API that allows execution of background processes.', + ), + + // Extensibility + 'addtest' => array( + 'type' => 'extensibility', + 'desc' => 'An internal Modernizr function that allows the user to define their own feature tests.', + ), + 'domprefixes' => array( + 'type' => 'extensibility', + 'desc' => 'An internal Modernizr function that supplies DOM-style vendor prefixes.', + ), + 'hasevent' => array( + 'type' => 'extensibility', + 'desc' => 'An internal Modernizr function that detects support for a given event.', + ), + 'prefixed' => array( + 'type' => 'extensibility', + 'desc' => 'An internal Modernizr function that returns the prefixed or nonprefixed property name variant of its input.', + ), + 'prefixes' => array( + 'type' => 'extensibility', + 'desc' => 'An internal Modernizr function that supplies CSS-style vendor prefixes.', + ), + 'teststyles' => array( + 'type' => 'extensibility', + 'desc' => 'An internal Modernizr function that tests support for a specific CSS property.', + ), + 'testprop' => array( + 'type' => 'extensibility', + 'desc' => 'An internal Modernizr function investigates whether a given style property is recognized.', + ), + 'testallprops' => array( + 'type' => 'extensibility', + 'desc' => 'An internal Modernizr function that tests a list of DOM properties.', + ), + + // Extras + 'load' => array( + 'type' => 'extras', + 'desc' => 'Provides yepnope.js, a conditional CSS/JS loader.', + ), + 'setclasses' => array( + 'type' => 'extras', + 'desc' => 'Allows Modernizr to inject CSS classes into <html>.', + ), + 'mq' => array( + 'type' => 'extras', + 'desc' => 'Allows Modernizr to evaluate CSS media queries.', + ), + 'printshiv' => array( + 'type' => 'extras', + 'desc' => 'Provides html5shiv (for browsers that do not support HTML5 tags). Support for printing.', + ), + 'shiv' => array( + 'type' => 'extras', + 'desc' => 'Provides html5shiv (for browsers that do not support HTML5 tags). No support for printing.', + ), + + // CSS Prefix + 'cssclassprefix' => array( + 'type' => 'extras', + 'desc' => 'Allows the user to prefix injected Modernizr classes.', + ), + ); + + if (isset($modernizr_args[$name])) { + return $modernizr_args[$name]; + } + + return FALSE; +} diff --git a/frontend/drupal/sites/all/modules/modernizr/modernizr.info b/frontend/drupal/sites/all/modules/modernizr/modernizr.info new file mode 100644 index 000000000..02568093b --- /dev/null +++ b/frontend/drupal/sites/all/modules/modernizr/modernizr.info @@ -0,0 +1,17 @@ +name = Modernizr +description = Modernizr integration for Drupal. Extends the library by providing two APIs: (1) for test management (2) for exposing Modernizr.load() to Drupal +core = 7.x +package = Frontend +configure = admin/config/development/modernizr + +files[] = modernizr.module +files[] = modernizr.install +files[] = modernizr.admin.inc +files[] = modernizr.args.inc +files[] = tests/modernizr.test + +; Information added by Drupal.org packaging script on 2018-06-28 +version = "7.x-3.11" +core = "7.x" +project = "modernizr" +datestamp = "1530180227" diff --git a/frontend/drupal/sites/all/modules/modernizr/modernizr.install b/frontend/drupal/sites/all/modules/modernizr/modernizr.install new file mode 100644 index 000000000..1e80e0b7c --- /dev/null +++ b/frontend/drupal/sites/all/modules/modernizr/modernizr.install @@ -0,0 +1,222 @@ + l(t('Libraries API'), 'http://drupal.org/project/libraries'), + ) + ); + $severity = REQUIREMENT_WARNING; + } + // Modernizr not installed, Libraries API is installed. + // Supply instructions recommending Libraries module. + elseif (!$path && module_exists('libraries')) { + $description = t('Modernizr JS library cannot be found. Download it from !modernizr-site, copy it into !path and rename it to modernizr.min.js.', + array( + '!modernizr-site' => l(t('modernizr.com'), 'http://modernizr.com/download/'), + // !path has a hardcoded default because the libraries_get_path() function might not return + // the correct path when conditions lead to this block of code being executed + '!path' => (libraries_get_path('modernizr')) ? libraries_get_path('modernizr') : 'sites/all/libraries/modernizr', + ) + ); + $severity = REQUIREMENT_ERROR; + } + // Modernizr not installed, Libraries API not installed. + // Supply generic instructions + else { + $description = t('Modernizr and Libraries API cannot be found. Download Modernizr from !modernizr-site, copy it into !path and rename it to modernizr.min.js. You should also use the !libraries-api by installing from drupal.org.', + array( + '!modernizr-site' => l(t('modernizr.com'), 'http://modernizr.com/download/'), + '!path' => 'sites/all/libraries/modernizr', + '!libraries-api' => l(t('Libraries API'), 'http://drupal.org/project/libraries'), + ) + ); + $severity = REQUIREMENT_ERROR; + } + + + /** + * We need a secondary set of requirements in case all modernizr tests + * requested are not added to the current modernizr build. This will only + * run if modernizr is available. + */ + if ($path) { + $missing_tests = _modernizr_info_missing_tests(); + + if (empty($missing_tests)) { + // There are no missing tests! We are awesome! + $tests_value = t('All required tests are present in current Modernizr build.'); + $tests_description = FALSE; + $tests_severity = REQUIREMENT_OK; + } + else { + // Pull tests that are currently set. + $current_tests = _modernizr_current_build(); + + // If the custom build hasn't been created yet, we should report that + // instead of saying that they're missing altogether. The development + // copy has all the tests, so none are missing. However, dev does NOT + // have Modernizr.load(), so it still registers as a full-blown error + // by default. + if (is_null($current_tests)) { + $tests_value = t('You haven\'t created a custom build yet.'); + $tests_description = t('Modernizr only works with a custom build. Visit the !modernizr-settings to create one.', array('!modernizr-settings' => l(t('Modernizr settings page'), 'admin/config/development/modernizr'))); + $tests_severity = variable_get('modernizr_quiet', MODERNIZR_QUIET_DEFAULT) ? REQUIREMENT_WARNING : REQUIREMENT_ERROR; + } + else { + // Custom build exists, and tests are missing, we need to fix that. + $tests_value = t('Tests are missing in current Modernizr build.'); + $tests_description = t('Certain tests requested by currently enabled modules and themes are not within the current Modernizr build. Go to the !link to download a new version of Modernizr. The tests that are missing are: ', array('!link' => l(t('Modernizr settings page'), 'admin/config/development/modernizr'))) . '' . implode(', ', array_keys($missing_tests)) . ''; + $tests_severity = variable_get('modernizr_quiet', MODERNIZR_QUIET_DEFAULT) ? REQUIREMENT_WARNING : REQUIREMENT_ERROR; + } + } + + /** + * Declare requirement to Drupal + */ + $requirements[] = array( + 'title' => t('Modernizr Tests'), + 'value' => $tests_value, + 'description' => $tests_description, + 'severity' => $tests_severity, + ); + } + + /* + * Declare requirement to Drupal + */ + $requirements[] = array( + 'title' => t('Modernizr'), + 'value' => $version ? $version : t('Not installed'), + 'description' => $description, + 'severity' => $severity, + ); + break; + } + + return $requirements; +} + +/** + * Set module weight. + */ +function modernizr_set_module_weight() { + db_update('system') + ->fields(array('weight' => 10)) + ->condition('name', 'modernizr', '=') + ->execute(); +} + +/** + * Implements hook_install(). + */ +function modernizr_install() { + modernizr_set_module_weight(); +} + +/** + * Implements hook_uninstall(). + */ +function modernizr_uninstall() { + // Delete drupal_add_js() options. + variable_del('modernizr_load'); + variable_del('modernizr_scope'); + variable_del('modernizr_type'); + + // Delete Drupal admin UI options. + variable_del('modernizr_quiet'); + + // Delete custom build options. + variable_del('modernizr_cb_printshiv'); + variable_del('modernizr_cb_load'); +} + +/** + * Delete the deprecated 'modernizr_serverside' variable. + */ +function modernizr_update_7300() { + variable_del('modernizr_serverside'); + + return t("Deleted 'modernizr_serverside' variable"); +} + +/** + * Revert the introduction of 'defer' as the default method of including script. + */ +function modernizr_update_7301() { + // Setting `defer` as default was a bad idea, because: + // 1. The deferred script almost always gets executed after any inlined + // Modernizr.load() commands. + // + // @see https://www.drupal.org/node/2252899#comment-9228009 + // + // 2. Setting `defer` by default is bad for backwards-compatibility. + // + // @see https://www.drupal.org/node/2252899#comment-9383221 + if (variable_get('modernizr_type', MODERNIZR_TYPE_DEFAULT) == 'defer') { + variable_set('modernizr_type', MODERNIZR_TYPE_DEFAULT); + } +} + +/** + * Increase module weight to override other modules library definitions. + */ +function modernizr_update_7302() { + modernizr_set_module_weight(); + return t('Increased Modernizr module weight.'); +} + +/** + * Automatically enable yepnope.js for backwards compatibility. + */ +function modernizr_update_7303() { + variable_set('modernizr_cb_load', 1); + return t('Enabled yepnope.js for backwards compatibility.'); +} diff --git a/frontend/drupal/sites/all/modules/modernizr/modernizr.module b/frontend/drupal/sites/all/modules/modernizr/modernizr.module new file mode 100644 index 000000000..c3ddf3ae5 --- /dev/null +++ b/frontend/drupal/sites/all/modules/modernizr/modernizr.module @@ -0,0 +1,838 @@ + (variable_get('modernizr_type', MODERNIZR_TYPE_DEFAULT) != 'inline') ? 'file' : 'inline', + 'scope' => variable_get('modernizr_scope', MODERNIZR_SCOPE_DEFAULT), + 'group' => MODERNIZR_SCRIPT_GROUP, + 'weight' => MODERNIZR_SCRIPT_WEIGHT, + 'every_page' => TRUE, + 'preprocess' => 0, + 'defer' => (variable_get('modernizr_type', MODERNIZR_TYPE_DEFAULT) == 'defer') ? TRUE : FALSE, + ); +} + +/** + * Implements hook_page_build(). + * + * We used to use hook_init(), but that loads the JS files needlessly + * on AJAX requests, private file requests, etc. + */ +function modernizr_page_build(&$page) { + global $base_url; + $modernizr_js_settings = _modernizr_js_settings(); + + // Load Modernizr on the page by invoking our implementation of + // hook_libraries_info(). + // + // We can only use this method when Libraries API 2.0 is installed. Since Libraries 1.0 + // did not contain a function called libraries_load(), we must explicitly check for a + // valid function to avoid fatal errors. + // + // @see http://drupal.org/node/1919796 + if (module_exists('libraries') && function_exists('libraries_load')) { + libraries_load('modernizr'); + } + else { + // First, figure out if we're inlining. + if (in_array(variable_get('modernizr_type', MODERNIZR_TYPE_DEFAULT), array('sync', 'defer'))) { + // We are loading external script. Load file path. + $modernizr_file = modernizr_get_path(); + } + else { + // We are inlining. Load contents of file instead of path. + $modernizr_file = file_get_contents(modernizr_get_path()); + } + + // With no Libraries API, load the regular way. + drupal_add_js( + $modernizr_file, + $modernizr_js_settings + ); + } + + // We want yepnope() commands to be issued immediately after the call + // to Modernizr so that they download while the page renders. The overrides + // to $inline_js_settings will format the output as inline JS. + if ($output = _modernizr_load_generate()) { + + // Modernizr v3 removed the ability to include yepnope.js directly in the + // custom builds. To ensure that previous users of this module can continue + // without breaking changes, we need to load a copy of yepnope manually, + // which Modernizr detects and aliases to yepnope(). + if ($output && variable_get('modernizr_cb_load', MODERNIZR_YEPNOPE_DEFAULT)) { + $yepnope_settings = $modernizr_js_settings; + $yepnope_settings['type'] = 'inline'; + $yepnope_settings['weight'] = MODERNIZR_SCRIPT_WEIGHT - 1; + + // yepnope.js + drupal_add_js( + file_get_contents(drupal_get_path('module', 'modernizr') . '/js/yepnope.js'), + $yepnope_settings + ); + + $inline_js_settings = $modernizr_js_settings; + $inline_js_settings['type'] = 'inline'; + $inline_js_settings['weight'] = MODERNIZR_SCRIPT_WEIGHT + 1; + + // yepnope() statements + drupal_add_js( + $output, + $inline_js_settings + ); + } + // If there are yepnope commands being requested, but the module does not + // have yepnope enabled, warn the user in the console. + else if ($output && !variable_get('modernizr_cb_load', MODERNIZR_YEPNOPE_DEFAULT)) { + drupal_add_js('console.warn("The Modernizr module is receiving requests to use yepnope.js but that option is currently disabled. Please enable yepnope.js by loading ' . $base_url . '/admin/config/development/modernizr/settings' . '");', array('type' => 'inline')); + } + } +} + +/** + * Implements hook_permission(). + */ +function modernizr_permission() { + return array( + 'administer modernizr' => array( + 'title' => t('Administer Modernizr'), + 'description' => t('Perform administration tasks for Modernizr.'), + ), + ); +} + +/** + * Implements hook_menu(). + */ +function modernizr_menu() { + $items = array(); + + // Rebuild Modernizr + $items['admin/config/development/modernizr/rebuild'] = array( + 'title' => 'Rebuild Modernizr', + 'description' => 'Queries Drupal for Modernizr dependencies and generates a custom link to the Modernizr builder.', + 'page callback' => 'modernizr_generate_url', + 'file' => 'modernizr.admin.inc', + 'type' => MENU_DEFAULT_LOCAL_TASK, + 'access arguments' => array('administer modernizr'), + ); + + // Module settings + $items['admin/config/development/modernizr/settings'] = array( + 'title' => 'Modernizr settings', + 'description' => 'Administrative settings for Modernizr module.', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('modernizr_admin'), + 'file' => 'modernizr.admin.inc', + 'type' => MENU_LOCAL_TASK, + 'access arguments' => array('administer modernizr'), + ); + + // Admin menu item (duplicate of "Rebuild Modernizr") + $items['admin/config/development/modernizr'] = array( + 'title' => 'Modernizr', + 'description' => 'Queries Drupal for Modernizr dependencies and generates a custom link to the Modernizr builder.', + 'page callback' => 'modernizr_generate_url', + 'file' => 'modernizr.admin.inc', + 'type' => MENU_NORMAL_ITEM, + 'access arguments' => array('administer modernizr'), + ); + + + return $items; +} + +/** + * Implements hook_libraries_info(). + * + * @return array + */ +function modernizr_libraries_info() { + $modernizr_js_settings = _modernizr_js_settings(); + $libraries = array(); + $file_name = modernizr_get_filename(); + + // Define Modernizr within Libraries API + $libraries['modernizr'] = array( + 'name' => t('Modernizr'), + 'vendor url' => 'http://modernizr.com', + 'download url' => 'http://modernizr.com/download/', + 'version arguments' => array( + 'file' => $file_name, + 'pattern' => MODERNIZR_VERSION_REGEX, + ), + 'files' => array( + 'js' => array( + $file_name => $modernizr_js_settings, + ), + ), + ); + + return $libraries; +} + +/** + * Returns the full path of modernizr, along with the filename. + * + * @return string + */ +function modernizr_get_path() { + $path = &drupal_static(__FUNCTION__); + + if ($path === NULL) { + // Get possible paths for the file. + $paths = _modernizr_get_paths(); + + // Scan directories for files + $path = _modernizr_scan_for_library($paths); + } + + return $path; +} + +/** + * Helper function to scan for acceptably named libraries + */ +function _modernizr_get_paths() { + $paths = &drupal_static(__FUNCTION__); + + if ($paths === NULL) { + $paths = array(); + foreach (_modernizr_library_search_paths() as $search_path) { + $library_path = $search_path . '/modernizr'; + if (file_exists($library_path)) { + $paths[] = $library_path; + } + } + } + + return $paths; +} + +/** + * Get library search paths. + * + * Original logic was taken from Libraries 7.x-2.3 since it doesn't provide a + * way to look up its search paths. + * + * @see libraries_get_libraries() + */ +function _modernizr_library_search_paths() { + $searchdir = array(); + $profile = drupal_get_path('profile', drupal_get_profile()); + $config = conf_path(); + + // Similar to 'modules' and 'themes' directories in the root directory, + // certain distributions may want to place libraries into a 'libraries' + // directory in Drupal's root directory. + $searchdir[] = 'libraries'; + + // Always search sites/all/libraries. + $searchdir[] = 'sites/all/libraries'; + + // $profile should never be empty in a proper Drupal setup. Check to make sure + // it exists before adding path. + if ($profile) { + // Similar to 'modules' and 'themes' directories inside an installation + // profile, installation profiles may want to place libraries into a + // 'libraries' directory. + $searchdir[] = $profile . '/libraries'; + } + + // $config should never be empty in a proper Drupal setup. Check to make sure + // it exists before adding path. + if ($config) { + // Also search sites//*. + $searchdir[] = $config . '/libraries'; + } + + return $searchdir; +} + +/** + * Helper function to scan for acceptably named libraries + */ +function _modernizr_scan_for_library($paths) { + $path = ''; + + if (is_array($paths) && !empty($paths)) { + foreach ($paths as $p) { + if ($files = file_scan_directory($p, MODERNIZR_FILENAME_REGEX)) { + $path = reset($files)->uri; + break; + } + } + } + + return $path; +} + +/** + * Helper function to fetch the active Modernizr library. + */ +function modernizr_get_filename() { + // Get the full path to the library, + $full_path = modernizr_get_path(); + // Break it up into its directories and file + $file_parts = explode('/', $full_path); + // Isolate the filename + $file_name = $file_parts[count($file_parts)-1]; + + return $file_name; +} + + +/** + * Guesses the modernizr library version. + * + * This function is using a regex, which assumes that the format of the version + * string won't change. If it changes, feel free to submit a bug report. + * + * @return mixed The version number if exists, or a boolean FALSE if it can't be + * determined. + */ +function modernizr_get_version($reset = FALSE) { + $version = &drupal_static(__FUNCTION__); + + if ($version === NULL || $reset == TRUE) { + if ($cached = cache_get('modernizr_version') && isset($cached->data) && $reset != TRUE) { + $version = $cached->data; + } + else { + $version = FALSE; + $modernizr_path = modernizr_get_path(); + if (file_exists($modernizr_path)) { + $modernizr = file_get_contents($modernizr_path); + + $matches = array(); + preg_match(MODERNIZR_VERSION_REGEX, $modernizr, $matches); + + if (isset($matches[0])) { + $version = $matches[0]; + if ($version) { + cache_set('modernizr_version', $version); + } + } + + unset($modernizr); + } + } + } + + return $version; +} + + +/** + * Implements MODULE_preprocess_html(). + */ +function modernizr_preprocess_html(&$vars, $hook) { + // This will set up all of our tests for Modernizr. + modernizr_load_data(); +} + +/** + * A function to generate the load data from the current themes. + * + * Reads async-loaded CSS/JS from theme .info files. Stores info in variable. + * Prints yepnope() calls into drupal_add_js() as inline settings. + * + * @return array + */ +function modernizr_load_data() { + $load = &drupal_static(__FUNCTION__); + + if (!isset($load)) { + // This is the first time this is called. + global $base_url, $base_theme_info, $theme_info; + $load = array(); + $num_tests = 0; + + // Make a list of base themes and the current theme. + $themes = $base_theme_info; + $themes[] = $theme_info; + + foreach (array_keys($themes) as $key) { + $theme_path = dirname($themes[$key]->filename) . '/'; + if (isset($themes[$key]->info['modernizr'])) { + // Loop through Modernizr calls and assemble Load variable. + foreach (array_keys($themes[$key]->info['modernizr']) as $test_key => $test) { + // If no tests are defined, simply add them as resources for loading them unconditionally. + if (is_numeric($test)) { + $load[] = array(_modernizr_sanitize_resource($themes[$key]->info['modernizr'][$test_key], $theme_path)); + } + // Skip the ['tests'] variable because it is reserved for selecting + // specific tests that Modernizr must include. + elseif ($test != 'tests') { + // All other entries inside a theme's modernizr[] settings should be scanned + $load[$num_tests]['test'] = $test; + foreach (array_keys($themes[$key]->info['modernizr'][$test]) as $action) { + foreach ($themes[$key]->info['modernizr'][$test][$action] as $asset) { + + // First figure out which property we're reading. + // callback/complete need different processing than yep/nope/both/load + $functions = array('callback', 'complete'); + + // Is this a function or a resource? + if (in_array($action, $functions)) { + // It's a function + $load[$num_tests][$action][] = _modernizr_sanitize_callback($asset); + } + else { + // It's a resource + $load[$num_tests][$action][] = _modernizr_sanitize_resource($asset, $theme_path); + } + } + } + + $num_tests++; + } + } + } + } + } + + return $load; +} + +/** + * Helper function to render the yepnope() calls. + */ +function _modernizr_load_generate() { + $output = FALSE; + + // Get yepnope() calls from the active theme. + $theme = modernizr_load_data(); + + // Collect data from modules that implement hook_modernizr_load(). + $modules = modernizr_load_list(); + + // Combine the data from the .info file and the Drupal modules. + // Themes go first because they are more visual and in most cases + // it's probably best to load them first. Modules whose assets + // truly need to be loaded first have hook_modernizr_load_alter() + // at their disposal. + $test_objects = array_merge($theme, $modules); + + // Build the yepnope() commands. + if (count($test_objects)) { + $num_tests = 0; + $items = array(); + + foreach ($test_objects as $load) { + // If test is defined, this entry will be an object. + if (isset($load['test'])) { + $item = '{' . "\n"; + $item .= ' test: ' . $load['test'] . ',' . "\n"; + + // Print each action and its resources + $actions = array('yep', 'nope', 'both', 'load'); + foreach ($actions as $action) { + if (isset($load[$action])) { + + // Begin output for this action + $item .= ' ' . sprintf('%-4s', $action) . ': '; + + // How many resources for this action? + if (count($load[$action]) == 1) { + // Single resource + $item .= "'" . $load[$action][0] . "',\n"; + } + else { + // Multiple resources + $item .= '['; + foreach ($load[$action] as $resource) { + $item .= "'" . $resource . "',"; + } + // Truncate last comma + $item = substr($item, 0, -1); + $item .= "],\n"; + } + } + } + + // Output these two properties without quotes around the output + $callbacks = array('callback', 'complete'); + foreach ($callbacks as $action) { + if (isset($load[$action])) { + + // Begin output for this action + $item .= ' ' . sprintf('%-4s', $action) . ': '; + + // How many callbacks for this action? + if (count($load[$action]) == 1) { + // Single resource + $item .= $load[$action][0] . ",\n"; + } + else { + // Multiple resources + $item .= '['; + foreach ($load[$action] as $callback) { + $item .= $callback . ","; + } + // Truncate last comma + $item = substr($item, 0, -1); + $item .= "],\n"; + } + } + } + // Truncate last comma and newline + $item = substr($item, 0, -2); + $item .= "\n}"; + $num_tests++; + } + // No test is defined, add the resource(s) to the loader unconditionally. + else { + $resources = array(); + foreach ($load as $resource) { + $resources[] = "'" . $resource . "'"; + } + $item = implode(",\n", $resources); + $num_tests++; + } + + $items[] = $item; + } + + $output .= 'yepnope('; + // Issue commands as array if there is more than resource to load. + $output .= ($num_tests > 1) ? '[' : ''; + // Add commands. + $output .= implode(",\n", $items); + // Finally, close the yepnope() function parenthesis. + $output .= ($num_tests > 1) ? ']' : ''; + $output .= ');'; + } + + return $output; +} + +/** + * Implements MODULE_preprocess_maintenance_page(). + */ +function modernizr_preprocess_maintenance_page(&$vars, $hook) { + modernizr_preprocess_html($vars, $hook); +} + +/** + * Helper function to sanitize yepnope() callbacks + */ +function _modernizr_sanitize_callback($callback) { + global $base_url; + $output = ''; + $function_regex = '/^function(\s)*\(\)(\s)*\{(.*)\}$/'; + + // Save the people who don't wrap their code in anonymous functions. + // Yes, an extra semi-colon has been added for safety :) + $output = (preg_match($function_regex, $callback)) ? $callback : 'function(){' . $callback . ';}'; + + return $output; +} + +/** + * Helper function to sanitize yepnope() assets + */ +function _modernizr_sanitize_resource($resource, $theme_path) { + global $base_path, $base_url; + $output = ''; + + // If a path starts with 'sites/' or 'profiles/' we assume they know exactly + // where they're going. Otherwise, they seem like relative URLs so append + // theme path. + $output = (strpos($resource, 'sites/') === 0 || strpos($resource, 'profiles/') === 0) ? $base_path . $resource : $base_url . '/' . $theme_path . $resource; + + return $output; +} + +/** + * Helper function for hook_modernizr_info(). + * Returns a Modernizr argument's type. + */ +function _modernizr_get_type($arg) { + $data = _modernizr_get_arg_info($arg, 'type'); + + // Since community-created detects are by far the most likely unknown entry, + // we assume that a value not found in modernizr.args.inc is a community detect. + // Note: 'tests' does NOT need t() because it is a machine value. + return $data ? $data : 'tests'; +} + +/** + * Helper function for hook_modernizr_info(). + * Returns a Modernizr argument's description. + */ +function _modernizr_get_desc($arg) { + $data = _modernizr_get_arg_info($arg, 'desc'); + + // If we can't find a description, just admit it. + return $data ? $data : '' . t('No description available.') . ''; +} + + +/** + * A helper function to get the information stored in modernizr.args.inc. + * + * @param string $arg + * The test machine name. + * @param string $type (default: 'desc') + * The data wanted, currently just 'desc' or 'type'. + * @return + * The data in the field, or FALSE if it doesn't exist. + */ +function _modernizr_get_arg_info($arg, $type = 'desc') { + static $loaded = FALSE; + + if (!$loaded) { + $loaded = module_load_include('inc', 'modernizr', 'modernizr.args'); + } + + $data = _modernizr_args_return($arg); + + // This data doesnt exist. + return ($data && isset($data[$type])) ? $data[$type] : FALSE; +} + + + +/** + * Helper function to pulls all tests from the current modernizr.js + */ +function _modernizr_current_build() { + $tests = &drupal_static(__FUNCTION__); + + if (!isset($tests)) { + + $path = modernizr_get_path(); + $path_parts = explode('/', $path); + $file = ($path) ? file_get_contents($path) : NULL; + $filename = $path_parts[count($path_parts)-1]; + $tests = array(); + + // $matches holds two items: + // - [0] the full URL + // - [1] a string containing the args captured in the parens vvvv + $build_url = preg_match('/https?:\/\/modernizr.com\/download\/[#?]-(.*) /', $file, $matches); + + // Turn URL args into test entries for Drupal module + if (isset($matches[1])) { + $args_and_prefix = explode(':', $matches[1]); + $build_args = explode('-', $args_and_prefix[0]); + + foreach ($build_args as $arg) { + $tests[] = $arg; + } + } + else { + // Modernizr must not be downloaded, return null. + return NULL; + } + } + + return $tests; +} + +/** + * Asks other Drupal modules which Modernizr tests they need. + * + * @return array + */ +function modernizr_api_list() { + $tests = &drupal_static(__FUNCTION__); + + if (!isset($tests)) { + // Grab all module implementations + // Note: this is a slightly augmented version of module_invoke_all(), so + // that we can know which module is providing which test. + $hook = 'modernizr_info'; + + foreach (module_implements($hook) as $module) { + $function = $module . '_' . $hook; + if (function_exists($function)) { + $result = call_user_func($function); + if (isset($result) && is_array($result)) { + $tests[$module] = $result; + } + } + } + + // Grabbing the information with an hook_alter is not enough for themes + // because they will not all be active, nor their code added into the session. + $themes = list_themes(); + $active_themes = array(); + foreach ($themes as $theme_name => $theme) { + if ($theme->status == 1) { + $active_themes[$theme_name] = $theme; + if (isset($theme->base_themes)) { + foreach ($theme->base_themes as $base_theme_name => $base_theme) { + $active_themes[$base_theme_name] = $themes[$base_theme_name]; + } + } + } + } + + // We now go into every active theme and pull from the .info file the tests. + foreach ($active_themes as $active_theme) { + $data = drupal_parse_info_file($active_theme->filename); + + if (isset($data['modernizr']) && isset($data['modernizr']['tests'])) { + // There are modernizr tests within this theme. + $theme_name = $data['name']; + $tests[$theme_name] = $data['modernizr']['tests']; + } + } + + // The last thing we do is send it to have its data cleaned and organized. + $tests = _modernizr_api_list_clean($tests); + } + + return $tests; +} + + + +/** + * Cleans up the array of tests to be unified. + * + * @param $raw_tests array + * An array of tests provided by hook_modernizr_info. + * @return array + */ +function _modernizr_api_list_clean($raw_tests) { + $clean_tests = array(); + + foreach ($raw_tests as $module => $tests) { + + foreach ($tests as $name => $data) { + // First, we check and correct if the tests have been added using indexed + // arrays, fixing the name variable. + if (is_int($name) && !is_array($data)) { + // The test is stored as a simple array, therefore the data is the name. + $name = $data; + $data = array(); + } + elseif (is_int($name) && is_array($data)) { + // Still stored as a indexed array, but the data is an array. + $name = $data['name']; + } + + // Now, we add these tests to our array of cleaned up data. + if (isset($clean_tests[$name])) { + // We already have the test, we are just going to add our module name. + $clean_tests[$name]['source'][] = $module; + } + else { + // The test has not been marked, we are adding it to the array. + $clean_tests[$name] = $data; + $clean_tests[$name]['source'] = array($module); + } + } + } + + // Cleaning up the data to ensure all data we need is present. + foreach ($clean_tests as $name => $clean_test) { + $data = array( + 'name' => $name, + 'desc' => _modernizr_get_desc($name), + 'docs' => '', + 'camiuse' => '', + ); + + $clean_tests[$name] = array_merge($data, $clean_test); + } + + return $clean_tests; +} + +/** + * Implements hook_modernizr_info(). + * + * This function implements our own hook to ensure that any custom Modernizr + * builds downloaded from either the settings screen or drush commands contain + * the essential components needed to support the module's functionality. + * + * html5shiv w/ printshiv + * - Includes some utility JS that allows IE to recognize HTML5 elements. + */ +function modernizr_modernizr_info() { + $items = array(); + + // If a site admin has chosen to require printshiv, add it to dependencies. + if (variable_get('modernizr_cb_printshiv', FALSE)) { + $items[] = 'printshiv'; + } + + return $items; +} + +/** + * Asks other Drupal modules for yepnope() commands. + * + * @return array + */ +function modernizr_load_list($reset = FALSE) { + $load = &drupal_static(__FUNCTION__); + if (!isset($load) || $reset) { + $load = module_invoke_all('modernizr_load'); + drupal_alter('modernizr_load', $load); + } + + return $load; +} + +/** + * Private function to look for missing Modernizr tests. + */ +function _modernizr_info_missing_tests() { + $requested_tests = modernizr_api_list(); + $current_build = _modernizr_current_build(); + $missing_tests = array(); + + if (is_null($current_build)) { + // There is no installed version of Modernizr. Return all tests. + return $requested_tests; + } + + foreach($requested_tests as $test => $test_info) { + if (!in_array($test, $current_build)) { + $missing_tests[$test] = $test_info; + } + } + + return $missing_tests; +} diff --git a/frontend/drupal/sites/all/modules/modernizr/tests/modernizr.test b/frontend/drupal/sites/all/modules/modernizr/tests/modernizr.test new file mode 100644 index 000000000..7cdba2641 --- /dev/null +++ b/frontend/drupal/sites/all/modules/modernizr/tests/modernizr.test @@ -0,0 +1,57 @@ + 'Modernizr module unit tests', + 'description' => 'Tests basic api functions provided by Modernizr module.', + 'group' => 'Modernizr', + ); + } + + /** + * Basic setup for Modernizr module tests. + */ + function setUp() { + drupal_load('module', 'modernizr'); + parent::setUp(); + } + + /** + * Tests that Modernizr is implementing hook_modernizr_info() correctly. + */ + function testModernizrInfo() { + global $conf; + + // By default there are no tests + $tests = modernizr_modernizr_info(); + if (is_array($tests)) { + $this->assertEqual(count($tests), 0, 'No tests by default'); + } + else { + $this->fail('modernizr_modernizr_info returns an array'); + } + // Now we require the printshiv test. + $conf['modernizr_cb_printshiv'] = TRUE; + $tests = modernizr_modernizr_info(); + + if (is_array($tests)) { + $test = array_shift($tests); + $this->assertEqual($test, 'printshiv', 'printshiv test enabled'); + } + else { + $this->fail('modernizr_modernizr_info returns an array'); + } + } +} diff --git a/frontend/drupal/sites/all/modules/nakupovanje_1ka/nakupovanje_1ka_script.js b/frontend/drupal/sites/all/modules/nakupovanje_1ka/nakupovanje_1ka_script.js index 4ad1fe955..b257627d2 100644 --- a/frontend/drupal/sites/all/modules/nakupovanje_1ka/nakupovanje_1ka_script.js +++ b/frontend/drupal/sites/all/modules/nakupovanje_1ka/nakupovanje_1ka_script.js @@ -20,8 +20,8 @@ function CookieAlert(link, jezik, url) { var url = url || false; if (link == 'fb') { - //link = '/frontend/api/api.php?action=login_facebook'; - link = 'https://www.1ka.si/fb_login.php'; + link = '/frontend/api/api.php?action=login_facebook'; + // link = 'https://www.1ka.si/fb_login.php'; } // if (link == 'google') { diff --git a/frontend/drupal/sites/all/modules/prijava_1ka/prijava_1ka.module b/frontend/drupal/sites/all/modules/prijava_1ka/prijava_1ka.module index 5ec89499c..d8b81ab19 100644 --- a/frontend/drupal/sites/all/modules/prijava_1ka/prijava_1ka.module +++ b/frontend/drupal/sites/all/modules/prijava_1ka/prijava_1ka.module @@ -5,6 +5,10 @@ function prijava_1ka_block_info() { + $blocks['prijava_1ka_izbira'] = [ + 'info' => t('Izbira pred prijavo v 1ka - modal'), + ]; + $blocks['prijava_1ka'] = [ 'info' => t('Prijavni obrazec 1ka - modal'), ]; @@ -29,6 +33,10 @@ function prijava_1ka_block_info() 'info' => t('ArnesAAI popup - modal'), ]; + $blocks['prijava_telefonska_pomoc'] = [ + 'info' => t('Telefonska pomoč -moodal'), + ]; + return $blocks; } @@ -44,6 +52,95 @@ function prijava_1ka_block_view($delta = '') $block = []; switch ($delta) { + case 'prijava_1ka_izbira': + + $html = ''; + // Modul izpišemo samo če uporabnik ni prijavljen + + if(empty($_COOKIE['unam'])) { + $html = ''; + + } + + $block['content'] = $html; + break; + case 'prijava_1ka' : $parametri = drupal_get_query_parameters(); @@ -122,6 +219,18 @@ function prijava_1ka_block_view($delta = '') }else{ + if(nalozi_ustrezen_jezik(TRUE) == 'sl') { + $html .= ''; + } + + $html .= '
    +
    + www.1ka.si +
    +
    '; + $html .= '

    ' . $lang['cms_login_title_block'] . '

    @@ -373,7 +482,7 @@ function prijava_1ka_block_view($delta = '') $url_google .= '&openid.realm=https://www.1ka.si'; $html .= ''; - $html .= ''; + $html .= ''; $html .= ''; @@ -446,10 +555,16 @@ function prijava_1ka_block_view($delta = '') $html = ''; @@ -489,6 +603,47 @@ function prijava_1ka_block_view($delta = '') $block['content'] = $html; break; + case 'prijava_telefonska_pomoc': + + // Modul izpišemo samo če uporabnik ni prijavljen + + $html = '
    ' . $lang['date'] . 'UserIPPodstranGETPOST
    ' . datetime($row['datetime']) . '' . $rowu['name'] . ' ' . $rowu['surname'] . '' . $row['ip'] . '' . $statuses[$row['status']] . '' . $row['get'] . '' . $row['post'] . '