diff --git a/blocks/activity_results/edit_form.php b/blocks/activity_results/edit_form.php index 0342ee6d56726..def729c258caa 100644 --- a/blocks/activity_results/edit_form.php +++ b/blocks/activity_results/edit_form.php @@ -124,4 +124,13 @@ protected function specific_definition($mform) { $mform->freeze('config_decimalpoints'); } } + + /** + * Display the configuration form when block is being added to the page + * + * @return bool + */ + public static function display_form_when_adding(): bool { + return true; + } } \ No newline at end of file diff --git a/blocks/activity_results/tests/behat/addblockinactivity.feature b/blocks/activity_results/tests/behat/addblockinactivity.feature index c9d32db7c278f..f0c4e579e9d56 100644 --- a/blocks/activity_results/tests/behat/addblockinactivity.feature +++ b/blocks/activity_results/tests/behat/addblockinactivity.feature @@ -47,15 +47,12 @@ Feature: The activity results block displays student scores Scenario: Configure the block on a non-graded activity to show 3 high scores Given I am on the "Test page name" "page activity" page - And I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + And I add the "Activity results" block to the default region with: | config_activitygradeitemid | Test assignment 1 | | config_showbest | 3 | | config_showworst | 0 | | config_gradeformat | Absolute numbers | | config_nameformat | Display full names | - And I press "Save changes" Then I should see "Student 1" in the "Activity results" "block" And I should see "90.00" in the "Activity results" "block" And I should see "Student 2" in the "Activity results" "block" @@ -63,26 +60,24 @@ Feature: The activity results block displays student scores And I should see "Student 3" in the "Activity results" "block" And I should see "70.00" in the "Activity results" "block" + @javascript @addablocklink Scenario: Block should select current activity by default - Given I am on the "Test assignment 1" "assign activity" page - When I add the "Activity results" block - And I configure the "Activity results" block - Then the field "config_activitygradeitemid" matches value "Test assignment 1" - And I press "Cancel" + Given I click on "Test assignment 1" "link" in the "region-main" "region" + When I add the "Activity results..." block + Then the field "config_activitygradeitemid" in the "Add Activity results block" "dialogue" matches value "Test assignment 1" + And I click on "Save changes" "button" in the "Add Activity results block" "dialogue" And I am on "Course 1" course homepage - And I am on the "Test assignment 2" "assign activity" page - And I add the "Activity results" block - And I configure the "Activity results" block - And the field "config_activitygradeitemid" matches value "Test assignment 2" - And I press "Cancel" + And I click on "Test assignment 2" "link" in the "region-main" "region" + And I add the "Activity results..." block + And the field "config_activitygradeitemid" in the "Add Activity results block" "dialogue" matches value "Test assignment 2" + And I click on "Save changes" "button" in the "Add Activity results block" "dialogue" And I am on "Course 1" course homepage - And I am on the "Test assignment 3" "assign activity" page - And I add the "Activity results" block - And I configure the "Activity results" block - And the field "config_activitygradeitemid" matches value "Test assignment 3" - And I press "Cancel" + And I click on "Test assignment 3" "link" in the "region-main" "region" + And I add the "Activity results..." block + And the field "config_activitygradeitemid" in the "Add Activity results block" "dialogue" matches value "Test assignment 3" + And I click on "Save changes" "button" in the "Add Activity results block" "dialogue" And I am on "Course 1" course homepage - And I am on the "Test page name" "page activity" page - And I add the "Activity results" block - And I configure the "Activity results" block - And the field "config_activitygradeitemid" does not match value "Test page name" + And I click on "Test page name" "link" in the "region-main" "region" + And I add the "Activity results..." block + And the field "config_activitygradeitemid" in the "Add Activity results block" "dialogue" does not match value "Test page name" + And I click on "Save changes" "button" in the "Add Activity results block" "dialogue" diff --git a/blocks/activity_results/tests/behat/addunconfiguredblock.feature b/blocks/activity_results/tests/behat/addunconfiguredblock.feature index c2e5b140a3228..c10100512c2ae 100644 --- a/blocks/activity_results/tests/behat/addunconfiguredblock.feature +++ b/blocks/activity_results/tests/behat/addunconfiguredblock.feature @@ -17,10 +17,16 @@ Feature: The activity results block doesn't displays student scores for unconfig And I log in as "teacher1" And I am on "Course 1" course homepage with editing mode on - Scenario: Add the block to a the course + Scenario: Add the block to a the course with Javascript disabled Given I add the "Activity results" block Then I should see "Please configure this block and select which activity it should display results from." in the "Activity results" "block" + @javascript + Scenario: Add the block to a the course with Javascript enabled + Given I add the "Activity results" block to the default region with: + | config_showbest | 3 | + Then I should see "Please configure this block and select which activity it should display results from." in the "Activity results" "block" + Scenario: Try to configure the block on the course page in a course without activities Given I add the "Activity results" block When I configure the "Activity results" block diff --git a/blocks/activity_results/tests/behat/highscoreswithoutgroups.feature b/blocks/activity_results/tests/behat/highscoreswithoutgroups.feature index aba0c34c46e13..d16005a59a68a 100644 --- a/blocks/activity_results/tests/behat/highscoreswithoutgroups.feature +++ b/blocks/activity_results/tests/behat/highscoreswithoutgroups.feature @@ -39,63 +39,48 @@ Feature: The activity results block displays student high scores And I am on "Course 1" course homepage Scenario: Configure the block on the course page to show 0 high scores - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 0 | | config_gradeformat | Percentages | | config_nameformat | Display full names | - And I press "Save changes" Then I should see "This block's configuration currently does not allow it to show any results." in the "Activity results" "block" Scenario: Configure the block on the course page to show 1 high score - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 1 | | config_showworst | 0 | | config_gradeformat | Percentages | | config_nameformat | Display full names | | config_decimalpoints | 0 | - And I press "Save changes" Then I should see "Student 1" in the "Activity results" "block" And I should see "90%" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show 1 high score as a fraction - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 1 | | config_showworst | 0 | | config_gradeformat | Fractions | | config_nameformat | Display full names | - And I press "Save changes" Then I should see "Student 1" in the "Activity results" "block" And I should see "90.00/100.00" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show 1 high score as a absolute numbers - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 1 | | config_showworst | 0 | | config_gradeformat | Absolute numbers | | config_nameformat | Display full names | - And I press "Save changes" Then I should see "Student 1" in the "Activity results" "block" And I should see "90.00" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple high scores as percentages - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 3 | | config_showworst | 0 | | config_gradeformat | Percentages | | config_nameformat | Display full names | | config_decimalpoints | 0 | - And I press "Save changes" Then I should see "Student 1" in the "Activity results" "block" And I should see "90%" in the "Activity results" "block" And I should see "Student 2" in the "Activity results" "block" @@ -104,14 +89,11 @@ Feature: The activity results block displays student high scores And I should see "70%" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple high scores as fractions - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 3 | | config_showworst | 0 | | config_gradeformat | Fractions | | config_nameformat | Display full names | - And I press "Save changes" Then I should see "Student 1" in the "Activity results" "block" And I should see "90.00/100.00" in the "Activity results" "block" And I should see "Student 2" in the "Activity results" "block" @@ -120,14 +102,11 @@ Feature: The activity results block displays student high scores And I should see "70.00/100.00" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple high scores as absolute numbers - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 3 | | config_showworst | 0 | | config_gradeformat | Absolute numbers | | config_nameformat | Display full names | - And I press "Save changes" Then I should see "Student 1" in the "Activity results" "block" And I should see "90.00" in the "Activity results" "block" And I should see "Student 2" in the "Activity results" "block" @@ -138,14 +117,11 @@ Feature: The activity results block displays student high scores Scenario: Try to configure the block on the course page to show multiple high scores using ID numbers Given the following config values are set as admin: | showuseridentity | idnumber,email | - And I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + And I add the "Activity results" block to the default region with: | config_showbest | 3 | | config_showworst | 0 | | config_gradeformat | Percentages | | config_nameformat | Display only ID numbers | - And I press "Save changes" Then I should see "User S1" in the "Activity results" "block" And I should see "90.00%" in the "Activity results" "block" And I should see "User S2" in the "Activity results" "block" @@ -154,14 +130,11 @@ Feature: The activity results block displays student high scores And I should see "70.00%" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple high scores using anonymous names - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 3 | | config_showworst | 0 | | config_gradeformat | Percentages | | config_nameformat | Anonymous results | - And I press "Save changes" Then I should see "User" in the "Activity results" "block" And I should see "90.00%" in the "Activity results" "block" And I should see "80.00%" in the "Activity results" "block" diff --git a/blocks/activity_results/tests/behat/highscoreswithscales.feature b/blocks/activity_results/tests/behat/highscoreswithscales.feature index 0af28c4aee5e2..493ec00d2c98f 100644 --- a/blocks/activity_results/tests/behat/highscoreswithscales.feature +++ b/blocks/activity_results/tests/behat/highscoreswithscales.feature @@ -58,25 +58,19 @@ Feature: The activity results block displays students high scores in group as sc And I am on "Course 1" course homepage with editing mode on Scenario: Configure the block on the course page to show 1 high score - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 1 | | config_showworst | 0 | | config_nameformat | Display full names | | config_decimalpoints | 0 | - And I press "Save changes" Then I should see "Student 1" in the "Activity results" "block" And I should see "Excellent!" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple high scores using full names - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 3 | | config_showworst | 0 | | config_nameformat | Display full names | - And I press "Save changes" Then I should see "Student 1" in the "Activity results" "block" And I should see "Excellent!" in the "Activity results" "block" And I should see "Student 2" in the "Activity results" "block" @@ -87,13 +81,10 @@ Feature: The activity results block displays students high scores in group as sc Scenario: Try to configure the block on the course page to show multiple high scores using ID numbers Given the following config values are set as admin: | showuseridentity | idnumber,email | - And I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + And I add the "Activity results" block to the default region with: | config_showbest | 3 | | config_showworst | 0 | | config_nameformat | Display only ID numbers | - And I press "Save changes" Then I should see "User S1" in the "Activity results" "block" And I should see "Excellent!" in the "Activity results" "block" And I should see "User S2" in the "Activity results" "block" @@ -102,13 +93,10 @@ Feature: The activity results block displays students high scores in group as sc And I should see "Good" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple high scores using anonymous names - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 3 | | config_showworst | 0 | | config_nameformat | Anonymous results | - And I press "Save changes" Then I should see "User" in the "Activity results" "block" And I should not see "Student 1" in the "Activity results" "block" And I should see "Excellent!" in the "Activity results" "block" diff --git a/blocks/activity_results/tests/behat/highscoreswithscalesandgroups.feature b/blocks/activity_results/tests/behat/highscoreswithscalesandgroups.feature index d3b3b68634183..0713734e81745 100644 --- a/blocks/activity_results/tests/behat/highscoreswithscalesandgroups.feature +++ b/blocks/activity_results/tests/behat/highscoreswithscalesandgroups.feature @@ -44,6 +44,7 @@ Feature: The activity results block displays student in group high scores as sca And the following "activities" exist: | activity | name | intro | course | section | idnumber | | assign | Test assignment | Offline text | C1 | 1 | assign1 | + And I change window size to "large" And I log in as "teacher1" And I am on "Course 1" course homepage with editing mode on And I navigate to "Scales" in the course gradebook @@ -73,14 +74,11 @@ Feature: The activity results block displays student in group high scores as sca And I am on "Course 1" course homepage Scenario: Try to configure the block on the course page to show 1 high score - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 1 | | config_showworst | 0 | | config_nameformat | Display full names | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group 1" in the "Activity results" "block" And I should see "Excellent!" in the "Activity results" "block" And I log out @@ -90,14 +88,11 @@ Feature: The activity results block displays student in group high scores as sca And I should see "Excellent!" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple high scores using full names - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 3 | | config_showworst | 0 | | config_nameformat | Display full names | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group 1" in the "Activity results" "block" And I should see "Excellent!" in the "Activity results" "block" And I should see "Group 2" in the "Activity results" "block" @@ -115,14 +110,11 @@ Feature: The activity results block displays student in group high scores as sca Scenario: Try to configure the block on the course page to show multiple high scores using ID numbers Given the following config values are set as admin: | showuseridentity | idnumber,email | - And I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + And I add the "Activity results" block to the default region with: | config_showbest | 3 | | config_showworst | 0 | | config_nameformat | Display only ID numbers | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group" in the "Activity results" "block" And I should see "Excellent!" in the "Activity results" "block" And I should see "Very good" in the "Activity results" "block" @@ -138,14 +130,11 @@ Feature: The activity results block displays student in group high scores as sca And I should see "Very good" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple high scores using anonymous names - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 3 | | config_showworst | 0 | | config_nameformat | Anonymous results | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group" in the "Activity results" "block" And I should see "Excellent!" in the "Activity results" "block" And I should see "Very good" in the "Activity results" "block" diff --git a/blocks/activity_results/tests/behat/highscoreswithseperategroups.feature b/blocks/activity_results/tests/behat/highscoreswithseperategroups.feature index daa5d10a11d0d..a0c854d458f13 100644 --- a/blocks/activity_results/tests/behat/highscoreswithseperategroups.feature +++ b/blocks/activity_results/tests/behat/highscoreswithseperategroups.feature @@ -63,29 +63,23 @@ Feature: The activity results block displays student in separate groups scores And I am on "Course 1" course homepage Scenario: Configure the block on the course page to show 1 high score - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 1 | | config_showworst | 0 | | config_gradeformat | Percentages | | config_nameformat | Display full names | | config_decimalpoints | 0 | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group 1" in the "Activity results" "block" And I should see "95%" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show 1 high score as a fraction - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 1 | | config_showworst | 0 | | config_gradeformat | Fractions | | config_nameformat | Display full names | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group 1" in the "Activity results" "block" And I should see "95.00/100.00" in the "Activity results" "block" And I log out @@ -95,15 +89,12 @@ Feature: The activity results block displays student in separate groups scores And I should see "100.00/100.00" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show 1 high score as a absolute numbers - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 1 | | config_showworst | 0 | | config_gradeformat | Absolute numbers | | config_nameformat | Display full names | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group 1" in the "Activity results" "block" And I should see "95.00" in the "Activity results" "block" And I log out @@ -113,16 +104,13 @@ Feature: The activity results block displays student in separate groups scores And I should see "100.00" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple high scores as percentages - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 3 | | config_showworst | 0 | | config_gradeformat | Percentages | | config_nameformat | Display full names | | config_decimalpoints | 0 | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group 1" in the "Activity results" "block" And I should see "95%" in the "Activity results" "block" And I should see "Group 2" in the "Activity results" "block" @@ -138,15 +126,12 @@ Feature: The activity results block displays student in separate groups scores And I should see "90%" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple high scores as fractions - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 3 | | config_showworst | 0 | | config_gradeformat | Fractions | | config_nameformat | Display full names | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group 1" in the "Activity results" "block" And I should see "95.00/100.00" in the "Activity results" "block" And I should see "Group 2" in the "Activity results" "block" @@ -162,15 +147,12 @@ Feature: The activity results block displays student in separate groups scores And I should see "80.00/100.00" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple high scores as absolute numbers - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 3 | | config_showworst | 0 | | config_gradeformat | Absolute numbers | | config_nameformat | Display full names | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group 1" in the "Activity results" "block" And I should see "95.00" in the "Activity results" "block" And I should see "Group 2" in the "Activity results" "block" @@ -188,15 +170,12 @@ Feature: The activity results block displays student in separate groups scores Scenario: Try to configure the block on the course page to show multiple high scores using ID numbers Given the following config values are set as admin: | showuseridentity | idnumber,email | - And I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + And I add the "Activity results" block to the default region with: | config_showbest | 3 | | config_showworst | 0 | | config_gradeformat | Percentages | | config_nameformat | Display only ID numbers | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group" in the "Activity results" "block" And I should see "95.00%" in the "Activity results" "block" And I should see "85.00%" in the "Activity results" "block" @@ -212,15 +191,12 @@ Feature: The activity results block displays student in separate groups scores And I should see "90.00%" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple high scores using anonymous names - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 3 | | config_showworst | 0 | | config_gradeformat | Percentages | | config_nameformat | Anonymous results | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group" in the "Activity results" "block" And I should see "95.00%" in the "Activity results" "block" And I should see "85.00%" in the "Activity results" "block" diff --git a/blocks/activity_results/tests/behat/highscoreswithvisiblegroups.feature b/blocks/activity_results/tests/behat/highscoreswithvisiblegroups.feature index 6b3103b0af3d3..ee396e360fe93 100644 --- a/blocks/activity_results/tests/behat/highscoreswithvisiblegroups.feature +++ b/blocks/activity_results/tests/behat/highscoreswithvisiblegroups.feature @@ -64,29 +64,23 @@ Feature: The activity results block displays student in visible groups scores And I am on "Course 1" course homepage Scenario: Configure the block on the course page to show 1 high score - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 1 | | config_showworst | 0 | | config_gradeformat | Percentages | | config_nameformat | Display full names | | config_decimalpoints | 0 | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group 1" in the "Activity results" "block" And I should see "95%" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show 1 high score as a fraction - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 1 | | config_showworst | 0 | | config_gradeformat | Fractions | | config_nameformat | Display full names | | config_usegroups | Yes | - And I press "Save changes" And I log out Then I log in as "student1" And I am on "Course 1" course homepage @@ -94,15 +88,12 @@ Feature: The activity results block displays student in visible groups scores And I should see "95.00/100.00" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show 1 high score as a absolute numbers - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 1 | | config_showworst | 0 | | config_gradeformat | Absolute numbers | | config_nameformat | Display full names | | config_usegroups | Yes | - And I press "Save changes" And I log out Then I log in as "student1" And I am on "Course 1" course homepage @@ -110,16 +101,13 @@ Feature: The activity results block displays student in visible groups scores And I should see "95.00" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple high scores as percentages - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 3 | | config_showworst | 0 | | config_gradeformat | Percentages | | config_nameformat | Display full names | | config_decimalpoints | 0 | | config_usegroups | Yes | - And I press "Save changes" And I log out Then I log in as "student1" And I am on "Course 1" course homepage @@ -131,15 +119,12 @@ Feature: The activity results block displays student in visible groups scores And I should see "75%" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple high scores as fractions - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 3 | | config_showworst | 0 | | config_gradeformat | Fractions | | config_nameformat | Display full names | | config_usegroups | Yes | - And I press "Save changes" And I log out Then I log in as "student1" And I am on "Course 1" course homepage @@ -151,15 +136,12 @@ Feature: The activity results block displays student in visible groups scores And I should see "75.00/100.00" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple high scores as absolute numbers - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 3 | | config_showworst | 0 | | config_gradeformat | Absolute numbers | | config_nameformat | Display full names | | config_usegroups | Yes | - And I press "Save changes" And I log out Then I log in as "student1" And I am on "Course 1" course homepage @@ -173,15 +155,12 @@ Feature: The activity results block displays student in visible groups scores Scenario: Try to configure the block on the course page to show multiple high scores using ID numbers Given the following config values are set as admin: | showuseridentity | idnumber,email | - And I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + And I add the "Activity results" block to the default region with: | config_showbest | 3 | | config_showworst | 0 | | config_gradeformat | Percentages | | config_nameformat | Display only ID numbers | | config_usegroups | Yes | - And I press "Save changes" And I log out Then I log in as "student1" And I am on "Course 1" course homepage @@ -191,15 +170,12 @@ Feature: The activity results block displays student in visible groups scores And I should see "75.00%" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple high scores using anonymous names - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 3 | | config_showworst | 0 | | config_gradeformat | Percentages | | config_nameformat | Anonymous results | | config_usegroups | Yes | - And I press "Save changes" And I log out Then I log in as "student1" And I am on "Course 1" course homepage diff --git a/blocks/activity_results/tests/behat/lowscoreswithoutgroups.feature b/blocks/activity_results/tests/behat/lowscoreswithoutgroups.feature index 4ed74d718d67e..2b7a95d264691 100644 --- a/blocks/activity_results/tests/behat/lowscoreswithoutgroups.feature +++ b/blocks/activity_results/tests/behat/lowscoreswithoutgroups.feature @@ -44,52 +44,40 @@ Feature: The activity results block displays student low scores And I am on "Course 1" course homepage Scenario: Configure the block on the course page to show 1 low score - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 1 | | config_gradeformat | Percentages | | config_nameformat | Display full names | | config_decimalpoints | 0 | - And I press "Save changes" Then I should see "Student 5" in the "Activity results" "block" And I should see "50%" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show 1 low score as a fraction - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 1 | | config_gradeformat | Fractions | | config_nameformat | Display full names | - And I press "Save changes" Then I should see "Student 5" in the "Activity results" "block" And I should see "50.00/100.00" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show 1 low score as a absolute number - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 1 | | config_gradeformat | Absolute numbers | | config_nameformat | Display full names | - And I press "Save changes" Then I should see "Student 5" in the "Activity results" "block" And I should see "50.00" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple low scores as percentages - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 3 | | config_gradeformat | Percentages | | config_nameformat | Display full names | | config_decimalpoints | 0 | - And I press "Save changes" Then I should see "Student 5" in the "Activity results" "block" And I should see "50%" in the "Activity results" "block" And I should see "Student 4" in the "Activity results" "block" @@ -98,14 +86,11 @@ Feature: The activity results block displays student low scores And I should see "70%" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple low scores as fractions - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 3 | | config_gradeformat | Fractions | | config_nameformat | Display full names | - And I press "Save changes" Then I should see "Student 5" in the "Activity results" "block" And I should see "50.00/100.00" in the "Activity results" "block" And I should see "Student 4" in the "Activity results" "block" @@ -114,14 +99,11 @@ Feature: The activity results block displays student low scores And I should see "70.00/100.00" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple low scores as absolute numbers - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 3 | | config_gradeformat | Absolute numbers | | config_nameformat | Display full names | - And I press "Save changes" Then I should see "Student 5" in the "Activity results" "block" And I should see "50.00" in the "Activity results" "block" And I should see "Student 4" in the "Activity results" "block" @@ -132,14 +114,11 @@ Feature: The activity results block displays student low scores Scenario: Try to configure the block on the course page to show multiple low scores using ID numbers Given the following config values are set as admin: | showuseridentity | idnumber,email | - And I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + And I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 3 | | config_gradeformat | Percentages | | config_nameformat | Display only ID numbers | - And I press "Save changes" Then I should see "User S5" in the "Activity results" "block" And I should see "50.00%" in the "Activity results" "block" And I should see "User S4" in the "Activity results" "block" @@ -148,14 +127,11 @@ Feature: The activity results block displays student low scores And I should see "70.00%" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple low scores using anonymous names - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 3 | | config_gradeformat | Percentages | | config_nameformat | Anonymous results | - And I press "Save changes" Then I should see "User" in the "Activity results" "block" And I should see "50.00%" in the "Activity results" "block" And I should see "60.00%" in the "Activity results" "block" diff --git a/blocks/activity_results/tests/behat/lowscoreswithscales.feature b/blocks/activity_results/tests/behat/lowscoreswithscales.feature index 54b5654b23203..95efff20f6f05 100644 --- a/blocks/activity_results/tests/behat/lowscoreswithscales.feature +++ b/blocks/activity_results/tests/behat/lowscoreswithscales.feature @@ -58,26 +58,20 @@ Feature: The activity results block displays student low scores as scales And I am on "Course 1" course homepage Scenario: Configure the block on the course page to show 1 low score - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 1 | | config_gradeformat | Percentages | | config_nameformat | Display full names | | config_decimalpoints | 0 | - And I press "Save changes" Then I should see "Student 5" in the "Activity results" "block" And I should see "Not good enough" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple low scores using full names - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 3 | | config_nameformat | Display full names | - And I press "Save changes" Then I should see "Student 5" in the "Activity results" "block" And I should see "Not good enough" in the "Activity results" "block" And I should see "Student 4" in the "Activity results" "block" @@ -88,13 +82,10 @@ Feature: The activity results block displays student low scores as scales Scenario: Try to configure the block on the course page to show multiple low scores using ID numbers Given the following config values are set as admin: | showuseridentity | idnumber,email | - And I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + And I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 3 | | config_nameformat | Display only ID numbers | - And I press "Save changes" Then I should see "User S5" in the "Activity results" "block" And I should see "Not good enough" in the "Activity results" "block" And I should see "User S4" in the "Activity results" "block" @@ -103,13 +94,10 @@ Feature: The activity results block displays student low scores as scales And I should see "Good" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple low scores using anonymous names - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 3 | | config_nameformat | Anonymous results | - And I press "Save changes" Then I should see "User" in the "Activity results" "block" And I should not see "Student 5" in the "Activity results" "block" And I should see "Not good enough" in the "Activity results" "block" diff --git a/blocks/activity_results/tests/behat/lowscoreswithscalesandgroups.feature b/blocks/activity_results/tests/behat/lowscoreswithscalesandgroups.feature index f0f20b47f2cb9..67c711eda834e 100644 --- a/blocks/activity_results/tests/behat/lowscoreswithscalesandgroups.feature +++ b/blocks/activity_results/tests/behat/lowscoreswithscalesandgroups.feature @@ -49,6 +49,7 @@ Feature: The activity results block displays students in groups low scores as sc | description | Offline text | | assignsubmission_file_enabled | 0 | | groupmode | 1 | + And I change window size to "large" And I log in as "teacher1" And I am on "Course 1" course homepage And I navigate to "Scales" in the course gradebook @@ -77,14 +78,11 @@ Feature: The activity results block displays students in groups low scores as sc And I am on "Course 1" course homepage Scenario: Try to configure the block on the course page to show 1 low score - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 1 | | config_nameformat | Display full names | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group 3" in the "Activity results" "block" And I should see "Good" in the "Activity results" "block" And I log out @@ -94,14 +92,11 @@ Feature: The activity results block displays students in groups low scores as sc And I should see "Average" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple high scores using full names - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 2 | | config_nameformat | Display full names | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group 2" in the "Activity results" "block" And I should see "Very good" in the "Activity results" "block" And I should see "Group 3" in the "Activity results" "block" @@ -117,14 +112,11 @@ Feature: The activity results block displays students in groups low scores as sc Scenario: Try to configure the block on the course page to show multiple high scores using ID numbers Given the following config values are set as admin: | showuseridentity | idnumber,email | - And I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + And I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 2 | | config_nameformat | Display only ID numbers | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group" in the "Activity results" "block" And I should see "Very good" in the "Activity results" "block" And I should see "Good" in the "Activity results" "block" @@ -139,14 +131,11 @@ Feature: The activity results block displays students in groups low scores as sc And I should see "Average" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple high scores using anonymous names - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 2 | | config_nameformat | Anonymous results | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group" in the "Activity results" "block" And I should see "Very good" in the "Activity results" "block" And I should see "Good" in the "Activity results" "block" diff --git a/blocks/activity_results/tests/behat/lowscoreswithseperategroups.feature b/blocks/activity_results/tests/behat/lowscoreswithseperategroups.feature index 2214a8704aaff..b9f4ef7300dce 100644 --- a/blocks/activity_results/tests/behat/lowscoreswithseperategroups.feature +++ b/blocks/activity_results/tests/behat/lowscoreswithseperategroups.feature @@ -57,29 +57,23 @@ Feature: The activity results block displays students in separate groups scores And I am on "Course 1" course homepage Scenario: Configure the block on the course page to show 1 low score - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 1 | | config_gradeformat | Percentages | | config_nameformat | Display full names | | config_decimalpoints | 0 | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group 3" in the "Activity results" "block" And I should see "75%" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show 1 low score as a fraction - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 1 | | config_gradeformat | Fractions | | config_nameformat | Display full names | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group 3" in the "Activity results" "block" And I should see "75.00/100.00" in the "Activity results" "block" And I log out @@ -89,15 +83,12 @@ Feature: The activity results block displays students in separate groups scores And I should see "70.00/100.00" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show 1 low score as a absolute numbers - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 1 | | config_gradeformat | Absolute numbers | | config_nameformat | Display full names | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group 3" in the "Activity results" "block" And I should see "75.00" in the "Activity results" "block" And I log out @@ -107,16 +98,13 @@ Feature: The activity results block displays students in separate groups scores And I should see "70.00" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple low scores as percentages - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 2 | | config_gradeformat | Percentages | | config_nameformat | Display full names | | config_decimalpoints | 0 | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group 2" in the "Activity results" "block" And I should see "85%" in the "Activity results" "block" And I should see "Group 3" in the "Activity results" "block" @@ -130,15 +118,12 @@ Feature: The activity results block displays students in separate groups scores And I should see "80%" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple low scores as fractions - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 2 | | config_gradeformat | Fractions | | config_nameformat | Display full names | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group 2" in the "Activity results" "block" And I should see "85.00/100.00" in the "Activity results" "block" And I should see "Group 3" in the "Activity results" "block" @@ -152,15 +137,12 @@ Feature: The activity results block displays students in separate groups scores And I should see "80.00/100.00" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple low scores as absolute numbers - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 2 | | config_gradeformat | Absolute numbers | | config_nameformat | Display full names | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group 2" in the "Activity results" "block" And I should see "85.00" in the "Activity results" "block" And I should see "Group 3" in the "Activity results" "block" @@ -176,15 +158,12 @@ Feature: The activity results block displays students in separate groups scores Scenario: Try to configure the block on the course page to show multiple low scores using ID numbers Given the following config values are set as admin: | showuseridentity | idnumber,email | - And I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + And I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 2 | | config_gradeformat | Percentages | | config_nameformat | Display only ID numbers | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group" in the "Activity results" "block" And I should see "85.00%" in the "Activity results" "block" And I should see "75.00%" in the "Activity results" "block" @@ -199,15 +178,12 @@ Feature: The activity results block displays students in separate groups scores And I should see "90.00%" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple low scores using anonymous names - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 2 | | config_gradeformat | Percentages | | config_nameformat | Anonymous results | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group" in the "Activity results" "block" And I should see "85.00%" in the "Activity results" "block" And I should see "75.00%" in the "Activity results" "block" diff --git a/blocks/activity_results/tests/behat/lowscoreswithvisiblegroups.feature b/blocks/activity_results/tests/behat/lowscoreswithvisiblegroups.feature index 253f1c5b3d96d..cb9a3a5277282 100644 --- a/blocks/activity_results/tests/behat/lowscoreswithvisiblegroups.feature +++ b/blocks/activity_results/tests/behat/lowscoreswithvisiblegroups.feature @@ -63,29 +63,23 @@ Feature: The activity results block displays student in visible groups low score And I am on "Course 1" course homepage Scenario: Configure the block on the course page to show 1 low score - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 1 | | config_gradeformat | Percentages | | config_nameformat | Display full names | | config_decimalpoints | 0 | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group 3" in the "Activity results" "block" And I should see "75%" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show 1 low score as a fraction - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 1 | | config_gradeformat | Fractions | | config_nameformat | Display full names | | config_usegroups | Yes | - And I press "Save changes" And I log out Then I log in as "student1" And I am on "Course 1" course homepage @@ -93,15 +87,12 @@ Feature: The activity results block displays student in visible groups low score And I should see "75.00/100.00" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show 1 low score as a absolute numbers - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 1 | | config_gradeformat | Absolute numbers | | config_nameformat | Display full names | | config_usegroups | Yes | - And I press "Save changes" And I log out Then I log in as "student1" And I am on "Course 1" course homepage @@ -109,16 +100,13 @@ Feature: The activity results block displays student in visible groups low score And I should see "75.00" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple low scores as percentages - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 2 | | config_gradeformat | Percentages | | config_nameformat | Display full names | | config_decimalpoints | 0 | | config_usegroups | Yes | - And I press "Save changes" Then I should see "Group 2" in the "Activity results" "block" And I should see "85%" in the "Activity results" "block" And I should see "Group 3" in the "Activity results" "block" @@ -132,15 +120,12 @@ Feature: The activity results block displays student in visible groups low score And I should see "75%" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple low scores as fractions - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 2 | | config_gradeformat | Fractions | | config_nameformat | Display full names | | config_usegroups | Yes | - And I press "Save changes" And I log out Then I log in as "student1" And I am on "Course 1" course homepage @@ -150,15 +135,12 @@ Feature: The activity results block displays student in visible groups low score And I should see "75.00/100.00" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple low scores as absolute numbers - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 2 | | config_gradeformat | Absolute numbers | | config_nameformat | Display full names | | config_usegroups | Yes | - And I press "Save changes" And I log out Then I log in as "student1" And I am on "Course 1" course homepage @@ -170,15 +152,12 @@ Feature: The activity results block displays student in visible groups low score Scenario: Try to configure the block on the course page to show multiple low scores using ID numbers Given the following config values are set as admin: | showuseridentity | idnumber,email | - And I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + And I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 2 | | config_gradeformat | Percentages | | config_nameformat | Display only ID numbers | | config_usegroups | Yes | - And I press "Save changes" And I log out Then I log in as "student1" And I am on "Course 1" course homepage @@ -187,15 +166,12 @@ Feature: The activity results block displays student in visible groups low score And I should see "75.00%" in the "Activity results" "block" Scenario: Try to configure the block on the course page to show multiple low scores using anonymous names - Given I add the "Activity results" block - When I configure the "Activity results" block - And I set the following fields to these values: + Given I add the "Activity results" block to the default region with: | config_showbest | 0 | | config_showworst | 2 | | config_gradeformat | Percentages | | config_nameformat | Anonymous results | | config_usegroups | Yes | - And I press "Save changes" And I log out Then I log in as "student1" And I am on "Course 1" course homepage diff --git a/blocks/amd/build/add_modal.min.js b/blocks/amd/build/add_modal.min.js new file mode 100644 index 0000000000000..3f2d8e54cf239 --- /dev/null +++ b/blocks/amd/build/add_modal.min.js @@ -0,0 +1,10 @@ +define("core_block/add_modal",["exports","core/modal_factory","core/templates","core/str","core/ajax","core_form/modalform"],(function(_exports,_modal_factory,_templates,_str,_ajax,_modalform){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} +/** + * Show an add block modal instead of doing it on a separate page. + * + * @module core_block/add_modal + * @copyright 2016 Damyon Wiese + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_modal_factory=_interopRequireDefault(_modal_factory),_templates=_interopRequireDefault(_templates),_ajax=_interopRequireDefault(_ajax),_modalform=_interopRequireDefault(_modalform);const SELECTORS_ADD_BLOCK='[data-key="addblock"]',SELECTORS_SHOW_BLOCK_FORM='[data-action="showaddblockform"][data-blockname][data-blockform]';let listenerEventsRegistered=!1;const registerListenerEvents=(addBlockUrl,pagehash)=>{let addBlockModal=null;document.addEventListener("click",(e=>{const showAddBlockForm=e.target.closest(SELECTORS_SHOW_BLOCK_FORM);if(showAddBlockForm){e.preventDefault();const modalForm=new _modalform.default({modalConfig:{title:(0,_str.get_string)("addblock","core_block",showAddBlockForm.getAttribute("data-blocktitle"))},args:{blockname:showAddBlockForm.getAttribute("data-blockname"),pagehash:pagehash,blockregion:showAddBlockForm.getAttribute("data-blockregion")},formClass:showAddBlockForm.getAttribute("data-blockform"),returnFocus:showAddBlockForm});modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,(()=>{addBlockModal.destroy(),window.location.reload()})),modalForm.show()}const addBlock=e.target.closest(SELECTORS_ADD_BLOCK);if(addBlock){e.preventDefault();let addBlockModalUrl=null!=addBlockUrl?addBlockUrl:addBlock.dataset.url;buildAddBlockModal().then((modal=>{addBlockModal=modal;const modalBody=renderBlocks(addBlockModalUrl,pagehash,addBlock.getAttribute("data-blockregion"));return modal.setBody(modalBody),modal.show(),modalBody})).catch((()=>{addBlockModal.destroy()}))}}))},buildAddBlockModal=()=>_modal_factory.default.create({type:_modal_factory.default.types.CANCEL,title:(0,_str.get_string)("addblock")}),renderBlocks=async(addBlockUrl,pagehash,region)=>{const blocks=await getAddableBlocks(pagehash);return _templates.default.render("core/add_block_body",{blocks:blocks,url:addBlockUrl,blockregion:region,pagehash:pagehash})},getAddableBlocks=async pagehash=>{const request={methodname:"core_block_fetch_addable_blocks",args:{pagecontextid:0,pagetype:"",pagelayout:"",subpage:"",pagehash:pagehash}};return _ajax.default.call([request])[0]};_exports.init=function(){let addBlockUrl=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,pagehash=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";listenerEventsRegistered||(registerListenerEvents(addBlockUrl,pagehash),listenerEventsRegistered=!0)}})); + +//# sourceMappingURL=add_modal.min.js.map \ No newline at end of file diff --git a/blocks/amd/build/add_modal.min.js.map b/blocks/amd/build/add_modal.min.js.map new file mode 100644 index 0000000000000..32e068ba07a2c --- /dev/null +++ b/blocks/amd/build/add_modal.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"add_modal.min.js","sources":["../src/add_modal.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Show an add block modal instead of doing it on a separate page.\n *\n * @module core_block/add_modal\n * @copyright 2016 Damyon Wiese \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport ModalFactory from 'core/modal_factory';\nimport Templates from 'core/templates';\nimport {get_string as getString} from 'core/str';\nimport Ajax from 'core/ajax';\nimport ModalForm from \"core_form/modalform\";\n\nconst SELECTORS = {\n ADD_BLOCK: '[data-key=\"addblock\"]',\n SHOW_BLOCK_FORM: '[data-action=\"showaddblockform\"][data-blockname][data-blockform]'\n};\n\n// Ensure we only add our listeners once.\nlet listenerEventsRegistered = false;\n\n/**\n * Register related event listeners.\n *\n * @method registerListenerEvents\n * @param {String|null} addBlockUrl The add block URL\n * @param {String} pagehash\n */\nconst registerListenerEvents = (addBlockUrl, pagehash) => {\n let addBlockModal = null;\n document.addEventListener('click', e => {\n\n const showAddBlockForm = e.target.closest(SELECTORS.SHOW_BLOCK_FORM);\n if (showAddBlockForm) {\n e.preventDefault();\n\n const modalForm = new ModalForm({\n modalConfig: {\n title: getString('addblock', 'core_block',\n showAddBlockForm.getAttribute('data-blocktitle')),\n },\n args: {blockname: showAddBlockForm.getAttribute('data-blockname'), pagehash,\n blockregion: showAddBlockForm.getAttribute('data-blockregion')},\n formClass: showAddBlockForm.getAttribute('data-blockform'),\n returnFocus: showAddBlockForm,\n });\n\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, () => {\n addBlockModal.destroy();\n window.location.reload();\n });\n\n modalForm.show();\n }\n\n const addBlock = e.target.closest(SELECTORS.ADD_BLOCK);\n if (addBlock) {\n e.preventDefault();\n\n let addBlockModalUrl = addBlockUrl ?? addBlock.dataset.url;\n\n buildAddBlockModal()\n .then(modal => {\n addBlockModal = modal;\n const modalBody = renderBlocks(addBlockModalUrl, pagehash,\n addBlock.getAttribute('data-blockregion'));\n modal.setBody(modalBody);\n modal.show();\n\n return modalBody;\n })\n .catch(() => {\n addBlockModal.destroy();\n });\n }\n });\n};\n\n/**\n * Method that creates the 'add block' modal.\n *\n * @method buildAddBlockModal\n * @returns {Promise} The modal promise (modal's body will be rendered later).\n */\nconst buildAddBlockModal = () => {\n return ModalFactory.create({\n type: ModalFactory.types.CANCEL,\n title: getString('addblock')\n });\n};\n\n/**\n * Method that renders the list of available blocks.\n *\n * @method renderBlocks\n * @param {String} addBlockUrl The add block URL\n * @param {String} pagehash\n * @param {String} region\n * @return {Promise}\n */\nconst renderBlocks = async(addBlockUrl, pagehash, region) => {\n // Fetch all addable blocks in the given page.\n const blocks = await getAddableBlocks(pagehash);\n\n return Templates.render('core/add_block_body', {\n blocks: blocks,\n url: addBlockUrl,\n blockregion: region,\n pagehash\n });\n};\n\n/**\n * Method that fetches all addable blocks in a given page.\n *\n * @method getAddableBlocks\n * @param {String} pagehash\n * @return {Promise}\n */\nconst getAddableBlocks = async(pagehash) => {\n const request = {\n methodname: 'core_block_fetch_addable_blocks',\n args: {\n pagecontextid: 0,\n pagetype: '',\n pagelayout: '',\n subpage: '',\n pagehash: pagehash,\n },\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Set up the actions.\n *\n * @method init\n * @param {String} addBlockUrl The add block URL\n * @param {String} pagehash\n */\nexport const init = (addBlockUrl = null, pagehash = '') => {\n if (!listenerEventsRegistered) {\n registerListenerEvents(addBlockUrl, pagehash);\n listenerEventsRegistered = true;\n }\n};\n"],"names":["SELECTORS","listenerEventsRegistered","registerListenerEvents","addBlockUrl","pagehash","addBlockModal","document","addEventListener","e","showAddBlockForm","target","closest","preventDefault","modalForm","ModalForm","modalConfig","title","getAttribute","args","blockname","blockregion","formClass","returnFocus","events","FORM_SUBMITTED","destroy","window","location","reload","show","addBlock","addBlockModalUrl","dataset","url","buildAddBlockModal","then","modal","modalBody","renderBlocks","setBody","catch","ModalFactory","create","type","types","CANCEL","async","region","blocks","getAddableBlocks","Templates","render","request","methodname","pagecontextid","pagetype","pagelayout","subpage","Ajax","call"],"mappings":";;;;;;;8QA6BMA,oBACS,wBADTA,0BAEe,uEAIjBC,0BAA2B,QASzBC,uBAAyB,CAACC,YAAaC,gBACrCC,cAAgB,KACpBC,SAASC,iBAAiB,SAASC,UAEzBC,iBAAmBD,EAAEE,OAAOC,QAAQX,8BACtCS,iBAAkB,CAClBD,EAAEI,uBAEIC,UAAY,IAAIC,mBAAU,CAC5BC,YAAa,CACTC,OAAO,mBAAU,WAAY,aACzBP,iBAAiBQ,aAAa,qBAEtCC,KAAM,CAACC,UAAWV,iBAAiBQ,aAAa,kBAAmBb,SAAAA,SAC/DgB,YAAaX,iBAAiBQ,aAAa,qBAC/CI,UAAWZ,iBAAiBQ,aAAa,kBACzCK,YAAab,mBAGjBI,UAAUN,iBAAiBM,UAAUU,OAAOC,gBAAgB,KACxDnB,cAAcoB,UACdC,OAAOC,SAASC,YAGpBf,UAAUgB,aAGRC,SAAWtB,EAAEE,OAAOC,QAAQX,wBAC9B8B,SAAU,CACVtB,EAAEI,qBAEEmB,iBAAmB5B,MAAAA,YAAAA,YAAe2B,SAASE,QAAQC,IAEvDC,qBACKC,MAAKC,QACF/B,cAAgB+B,YACVC,UAAYC,aAAaP,iBAAkB3B,SAC7C0B,SAASb,aAAa,4BAC1BmB,MAAMG,QAAQF,WACdD,MAAMP,OAECQ,aAEVG,OAAM,KACHnC,cAAcoB,kBAY5BS,mBAAqB,IAChBO,uBAAaC,OAAO,CACvBC,KAAMF,uBAAaG,MAAMC,OACzB7B,OAAO,mBAAU,cAanBsB,aAAeQ,MAAM3C,YAAaC,SAAU2C,gBAExCC,aAAeC,iBAAiB7C,iBAE/B8C,mBAAUC,OAAO,sBAAuB,CAC3CH,OAAQA,OACRf,IAAK9B,YACLiB,YAAa2B,OACb3C,SAAAA,YAWF6C,iBAAmBH,MAAAA,iBACfM,QAAU,CACZC,WAAY,kCACZnC,KAAM,CACFoC,cAAe,EACfC,SAAU,GACVC,WAAY,GACZC,QAAS,GACTrD,SAAUA,kBAIXsD,cAAKC,KAAK,CAACP,UAAU,kBAUZ,eAACjD,mEAAc,KAAMC,gEAAW,GAC3CH,2BACDC,uBAAuBC,YAAaC,UACpCH,0BAA2B"} \ No newline at end of file diff --git a/blocks/amd/build/edit.min.js b/blocks/amd/build/edit.min.js new file mode 100644 index 0000000000000..c23b0eecc20bb --- /dev/null +++ b/blocks/amd/build/edit.min.js @@ -0,0 +1,10 @@ +define("core_block/edit",["exports","core_form/modalform"],(function(_exports,_modalform){var obj; +/** + * Javascript module for editing blocks + * + * @module core_block/edit + * @copyright 2022 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_modalform=(obj=_modalform)&&obj.__esModule?obj:{default:obj};const SELECTORS_EDITBLOCK='[data-action="editblock"][data-blockid][data-blockform]';_exports.init=pagehash=>{document.addEventListener("click",(e=>{const target=e.target.closest(SELECTORS_EDITBLOCK);if(!target||!target.getAttribute("data-blockform"))return;e.preventDefault();const modalForm=new _modalform.default({modalConfig:{title:target.getAttribute("data-header")},args:{blockid:target.getAttribute("data-blockid"),pagehash:pagehash},formClass:target.getAttribute("data-blockform"),returnFocus:target});modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,(()=>{location.reload()})),modalForm.show()}))}})); + +//# sourceMappingURL=edit.min.js.map \ No newline at end of file diff --git a/blocks/amd/build/edit.min.js.map b/blocks/amd/build/edit.min.js.map new file mode 100644 index 0000000000000..611791ff7c0d3 --- /dev/null +++ b/blocks/amd/build/edit.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"edit.min.js","sources":["../src/edit.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Javascript module for editing blocks\n *\n * @module core_block/edit\n * @copyright 2022 Marina Glancy\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport ModalForm from 'core_form/modalform';\n\nconst SELECTORS = {\n EDITBLOCK: '[data-action=\"editblock\"][data-blockid][data-blockform]',\n};\n\n/**\n * Initialize module\n * @param {String} pagehash\n */\nexport const init = (pagehash) => {\n document.addEventListener('click', e => {\n const target = e.target.closest(SELECTORS.EDITBLOCK);\n if (!target || !target.getAttribute('data-blockform')) {\n return;\n }\n e.preventDefault();\n\n const modalForm = new ModalForm({\n modalConfig: {\n title: target.getAttribute('data-header'),\n },\n args: {blockid: target.getAttribute('data-blockid'), pagehash},\n formClass: target.getAttribute('data-blockform'),\n returnFocus: target,\n });\n\n // Reload the page when the form is submitted, there is no possibility\n // currently to request contents update of just one block on the page.\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, () => {\n location.reload();\n });\n\n modalForm.show();\n });\n};\n"],"names":["SELECTORS","pagehash","document","addEventListener","e","target","closest","getAttribute","preventDefault","modalForm","ModalForm","modalConfig","title","args","blockid","formClass","returnFocus","events","FORM_SUBMITTED","location","reload","show"],"mappings":";;;;;;;sJAyBMA,oBACS,wEAOMC,WACjBC,SAASC,iBAAiB,SAASC,UACzBC,OAASD,EAAEC,OAAOC,QAAQN,yBAC3BK,SAAWA,OAAOE,aAAa,yBAGpCH,EAAEI,uBAEIC,UAAY,IAAIC,mBAAU,CAC5BC,YAAa,CACTC,MAAOP,OAAOE,aAAa,gBAE/BM,KAAM,CAACC,QAAST,OAAOE,aAAa,gBAAiBN,SAAAA,UACrDc,UAAWV,OAAOE,aAAa,kBAC/BS,YAAaX,SAKjBI,UAAUN,iBAAiBM,UAAUQ,OAAOC,gBAAgB,KACxDC,SAASC,YAGbX,UAAUY"} \ No newline at end of file diff --git a/blocks/amd/src/add_modal.js b/blocks/amd/src/add_modal.js new file mode 100644 index 0000000000000..a1d0f573ec838 --- /dev/null +++ b/blocks/amd/src/add_modal.js @@ -0,0 +1,163 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle 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 Moodle. If not, see . + +/** + * Show an add block modal instead of doing it on a separate page. + * + * @module core_block/add_modal + * @copyright 2016 Damyon Wiese + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +import ModalFactory from 'core/modal_factory'; +import Templates from 'core/templates'; +import {get_string as getString} from 'core/str'; +import Ajax from 'core/ajax'; +import ModalForm from "core_form/modalform"; + +const SELECTORS = { + ADD_BLOCK: '[data-key="addblock"]', + SHOW_BLOCK_FORM: '[data-action="showaddblockform"][data-blockname][data-blockform]' +}; + +// Ensure we only add our listeners once. +let listenerEventsRegistered = false; + +/** + * Register related event listeners. + * + * @method registerListenerEvents + * @param {String|null} addBlockUrl The add block URL + * @param {String} pagehash + */ +const registerListenerEvents = (addBlockUrl, pagehash) => { + let addBlockModal = null; + document.addEventListener('click', e => { + + const showAddBlockForm = e.target.closest(SELECTORS.SHOW_BLOCK_FORM); + if (showAddBlockForm) { + e.preventDefault(); + + const modalForm = new ModalForm({ + modalConfig: { + title: getString('addblock', 'core_block', + showAddBlockForm.getAttribute('data-blocktitle')), + }, + args: {blockname: showAddBlockForm.getAttribute('data-blockname'), pagehash, + blockregion: showAddBlockForm.getAttribute('data-blockregion')}, + formClass: showAddBlockForm.getAttribute('data-blockform'), + returnFocus: showAddBlockForm, + }); + + modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, () => { + addBlockModal.destroy(); + window.location.reload(); + }); + + modalForm.show(); + } + + const addBlock = e.target.closest(SELECTORS.ADD_BLOCK); + if (addBlock) { + e.preventDefault(); + + let addBlockModalUrl = addBlockUrl ?? addBlock.dataset.url; + + buildAddBlockModal() + .then(modal => { + addBlockModal = modal; + const modalBody = renderBlocks(addBlockModalUrl, pagehash, + addBlock.getAttribute('data-blockregion')); + modal.setBody(modalBody); + modal.show(); + + return modalBody; + }) + .catch(() => { + addBlockModal.destroy(); + }); + } + }); +}; + +/** + * Method that creates the 'add block' modal. + * + * @method buildAddBlockModal + * @returns {Promise} The modal promise (modal's body will be rendered later). + */ +const buildAddBlockModal = () => { + return ModalFactory.create({ + type: ModalFactory.types.CANCEL, + title: getString('addblock') + }); +}; + +/** + * Method that renders the list of available blocks. + * + * @method renderBlocks + * @param {String} addBlockUrl The add block URL + * @param {String} pagehash + * @param {String} region + * @return {Promise} + */ +const renderBlocks = async(addBlockUrl, pagehash, region) => { + // Fetch all addable blocks in the given page. + const blocks = await getAddableBlocks(pagehash); + + return Templates.render('core/add_block_body', { + blocks: blocks, + url: addBlockUrl, + blockregion: region, + pagehash + }); +}; + +/** + * Method that fetches all addable blocks in a given page. + * + * @method getAddableBlocks + * @param {String} pagehash + * @return {Promise} + */ +const getAddableBlocks = async(pagehash) => { + const request = { + methodname: 'core_block_fetch_addable_blocks', + args: { + pagecontextid: 0, + pagetype: '', + pagelayout: '', + subpage: '', + pagehash: pagehash, + }, + }; + + return Ajax.call([request])[0]; +}; + +/** + * Set up the actions. + * + * @method init + * @param {String} addBlockUrl The add block URL + * @param {String} pagehash + */ +export const init = (addBlockUrl = null, pagehash = '') => { + if (!listenerEventsRegistered) { + registerListenerEvents(addBlockUrl, pagehash); + listenerEventsRegistered = true; + } +}; diff --git a/blocks/amd/src/edit.js b/blocks/amd/src/edit.js new file mode 100644 index 0000000000000..0feac565e83f5 --- /dev/null +++ b/blocks/amd/src/edit.js @@ -0,0 +1,59 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle 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 Moodle. If not, see . + +/** + * Javascript module for editing blocks + * + * @module core_block/edit + * @copyright 2022 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +import ModalForm from 'core_form/modalform'; + +const SELECTORS = { + EDITBLOCK: '[data-action="editblock"][data-blockid][data-blockform]', +}; + +/** + * Initialize module + * @param {String} pagehash + */ +export const init = (pagehash) => { + document.addEventListener('click', e => { + const target = e.target.closest(SELECTORS.EDITBLOCK); + if (!target || !target.getAttribute('data-blockform')) { + return; + } + e.preventDefault(); + + const modalForm = new ModalForm({ + modalConfig: { + title: target.getAttribute('data-header'), + }, + args: {blockid: target.getAttribute('data-blockid'), pagehash}, + formClass: target.getAttribute('data-blockform'), + returnFocus: target, + }); + + // Reload the page when the form is submitted, there is no possibility + // currently to request contents update of just one block on the page. + modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, () => { + location.reload(); + }); + + modalForm.show(); + }); +}; diff --git a/blocks/classes/external/fetch_addable_blocks.php b/blocks/classes/external/fetch_addable_blocks.php index e58934e98f26b..addd65125cff6 100644 --- a/blocks/classes/external/fetch_addable_blocks.php +++ b/blocks/classes/external/fetch_addable_blocks.php @@ -44,6 +44,7 @@ public static function execute_parameters(): external_function_parameters { 'pagetype' => new external_value(PARAM_ALPHANUMEXT, 'The type of the page.'), 'pagelayout' => new external_value(PARAM_ALPHA, 'The layout of the page.'), 'subpage' => new external_value(PARAM_TEXT, 'The subpage identifier', VALUE_DEFAULT, ''), + 'pagehash' => new external_value(PARAM_ALPHANUMEXT, 'Page hash', VALUE_DEFAULT, ''), ] ); } @@ -55,9 +56,11 @@ public static function execute_parameters(): external_function_parameters { * @param string $pagetype The type of the page * @param string $pagelayout The layout of the page * @param string $subpage The subpage identifier + * @param string $pagehash Page hash that can be provided instead of all parameters above * @return array The blocks list */ - public static function execute(int $pagecontextid, string $pagetype, string $pagelayout, string $subpage = ''): array { + public static function execute(int $pagecontextid, string $pagetype, string $pagelayout, + string $subpage = '', string $pagehash = ''): array { global $PAGE; $params = self::validate_parameters(self::execute_parameters(), @@ -66,28 +69,43 @@ public static function execute(int $pagecontextid, string $pagetype, string $pag 'pagetype' => $pagetype, 'pagelayout' => $pagelayout, 'subpage' => $subpage, + 'pagehash' => $pagehash, ] ); - $context = \context::instance_by_id($params['pagecontextid']); - // Validate the context. This will also set the context in $PAGE. - self::validate_context($context); + if ($params['pagehash']) { + // If pagehash is specified, all other parameters are ignored, all information + // about the page is stored in the session. - // We need to manually set the page layout and page type. - $PAGE->set_pagelayout($params['pagelayout']); - $PAGE->set_pagetype($params['pagetype']); - $PAGE->set_subpage($params['subpage']); + $page = \moodle_page::retrieve_edited_page($params['pagehash'], MUST_EXIST); + self::validate_context($page->context); + } else { + // For backward-compatibility and Mobile App instead of pagehash + // we can specify context, pagelayout, pagetype and subtype. + + $context = \context::instance_by_id($params['pagecontextid']); + // Validate the context. This will also set the context in $PAGE. + self::validate_context($context); + + // We need to manually set the page layout and page type. + $PAGE->set_pagelayout($params['pagelayout']); + $PAGE->set_pagetype($params['pagetype']); + $PAGE->set_subpage($params['subpage']); + $page = $PAGE; + } // Firstly, we need to load all currently existing page blocks to later determine which blocks are addable. - $PAGE->blocks->load_blocks(false); - $PAGE->blocks->create_all_block_instances(); + $page->blocks->load_blocks(false); + $page->blocks->create_all_block_instances(); - $addableblocks = $PAGE->blocks->get_addable_blocks(); + $addableblocks = $page->blocks->get_addable_blocks(); - return array_map(function($block) { + return array_map(function($block) use ($page) { + $classname = \block_manager::get_block_edit_form_class($block->name); return [ 'name' => $block->name, - 'title' => get_string('pluginname', "block_{$block->name}") + 'title' => get_string('pluginname', "block_{$block->name}"), + 'blockform' => $classname::display_form_when_adding() ? $classname : null, ]; }, $addableblocks); } @@ -103,6 +121,8 @@ public static function execute_returns(): external_multiple_structure { [ 'name' => new external_value(PARAM_PLUGIN, 'The name of the block.'), 'title' => new external_value(PARAM_RAW, 'The title of the block.'), + 'blockform' => new external_value(PARAM_RAW, + 'If this block type has a form when it is being added then the classname of the form') ] ), 'List of addable blocks in a given page.' diff --git a/blocks/edit_form.php b/blocks/edit_form.php index fac55d4f05ccc..5dfec207253ef 100644 --- a/blocks/edit_form.php +++ b/blocks/edit_form.php @@ -17,7 +17,7 @@ /** * Defines the base class form used by blocks/edit.php to edit block instance configuration. * - * It works with the {@link block_edit_form} class, or rather the particular + * It works with the {@see block_edit_form} class, or rather the particular * subclass defined by this block, to do the editing. * * @package core_block @@ -25,30 +25,27 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -if (!defined('MOODLE_INTERNAL')) { - die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page -} - -require_once($CFG->libdir . '/formslib.php'); require_once($CFG->libdir . '/blocklib.php'); /** * The base class form used by blocks/edit.php to edit block instance configuration. * + * @property-read block_base $block + * @property-read moodle_page $page * @copyright 2009 Tim Hunt * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class block_edit_form extends moodleform { +class block_edit_form extends \core_form\dynamic_form { /** * The block instance we are editing. * @var block_base */ - public $block; + private $_block; /** * The page we are editing this block in association with. * @var moodle_page */ - public $page; + private $_page; /** * Defaults set in set_data() that need to be returned in get_data() if form elements were not created @@ -56,19 +53,95 @@ class block_edit_form extends moodleform { */ protected $defaults = []; - function __construct($actionurl, $block, $page) { - global $CFG; - $this->block = $block; - $this->page = $page; - parent::__construct($actionurl); + /** + * Magic getter for backward compatibility + * + * @param string $name + * @return block_base|moodle_page + */ + public function __get(string $name) { + if ($name === 'page') { + return $this->get_page(); + } else if ($name === 'block') { + return $this->get_block(); + } else { + throw new coding_exception('Property '.$name.' does not exist'); + } + } + + /** + * Page where we are adding or editing the block + * + * To access you can also use magic property $this->page + * + * @return moodle_page + * @throws moodle_exception + */ + protected function get_page(): moodle_page { + if (!$this->_page && !empty($this->_customdata['page'])) { + $this->_page = $this->_customdata['page']; + } else if (!$this->_page) { + if (!$pagehash = $this->optional_param('pagehash', '', PARAM_ALPHANUMEXT)) { + throw new \moodle_exception('missingparam', '', '', 'pagehash'); + } + $this->_page = moodle_page::retrieve_edited_page($pagehash, MUST_EXIST); + $this->_page->blocks->load_blocks(); + } + return $this->_page; + } + + /** + * Instance of the block that is being added or edited + * + * To access you can also use magic property $this->block + * + * If {{@see self::display_form_when_adding()}} returns true and the configuration + * form is displayed when adding block, the $this->block->id will be null. + * + * @return block_base + * @throws block_not_on_page_exception + * @throws moodle_exception + */ + protected function get_block(): block_base { + if (!$this->_block && !empty($this->_customdata['block'])) { + $this->_block = $this->_customdata['block']; + } else if (!$this->_block) { + $blockid = $this->optional_param('blockid', null, PARAM_INT); + $blockname = $this->optional_param('blockname', null, PARAM_PLUGIN); + if ($blockname && !$blockid) { + $this->_block = block_instance($blockname); + $this->_block->page = $this->page; + $this->_block->context = $this->page->context; + $this->_block->instance = (object)['parentcontextid' => $this->page->context->id, 'id' => null]; + } else { + $this->_block = $this->page->blocks->find_instance($blockid); + } + } + return $this->_block; } + /** + * Form definition + */ function definition() { $mform =& $this->_form; + $mform->addElement('hidden', 'blockid', $this->block->instance->id); + $mform->setType('blockid', PARAM_INT); + $mform->addElement('hidden', 'blockname', $this->optional_param('blockname', null, PARAM_PLUGIN)); + $mform->setType('blockname', PARAM_PLUGIN); + $mform->addElement('hidden', 'blockregion', $this->optional_param('blockregion', null, PARAM_TEXT)); + $mform->setType('blockregion', PARAM_TEXT); + $mform->addElement('hidden', 'pagehash', $this->optional_param('pagehash', null, PARAM_ALPHANUMEXT)); + $mform->setType('pagehash', PARAM_ALPHANUMEXT); + // First show fields specific to this type of block. $this->specific_definition($mform); + if (!$this->block->instance->id) { + return; + } + // Then show the fields about where this block appears. $mform->addElement('header', 'whereheader', get_string('wherethisblockappears', 'block')); @@ -110,10 +183,10 @@ function definition() { // First of all, check if we are editing blocks @ front-page or no and // make some dark magic if so (MDL-30340) because each page context // implies one (and only one) harcoded page-type that will be set later - // when processing the form data at {@link block_manager::process_url_edit()} + // when processing the form data at {@see block_manager::process_url_edit()}. // Front page, show the page-contexts element and set $pagetypelist to 'any page' (*) - // as unique option. Processign the form will do any change if needed + // as unique option. Processign the form will do any change if needed. if ($this->is_editing_the_frontpage()) { $contextoptions = array(); $contextoptions[BUI_CONTEXTS_FRONTPAGE_ONLY] = get_string('showonfrontpageonly', 'block'); @@ -232,7 +305,9 @@ function definition() { $mform->hardFreeze($pagefields); } - $this->add_action_buttons(); + if (!empty($this->_customdata['actionbuttons'])) { + $this->add_action_buttons(); + } } /** @@ -248,13 +323,19 @@ public function is_editing_the_frontpage() { return ($ctxconditions && $issiteindex); } - function set_data($defaults) { + /** + * Prepare block configuration data and add default values when needed + * + * @param stdClass $defaults + * @return stdClass + */ + protected function prepare_defaults(stdClass $defaults): stdClass { // Prefix bui_ on all the core field names. $blockfields = array('showinsubcontexts', 'pagetypepattern', 'subpagepattern', 'parentcontextid', 'defaultregion', 'defaultweight', 'visible', 'region', 'weight'); foreach ($blockfields as $field) { $newname = 'bui_' . $field; - $defaults->$newname = $defaults->$field; + $defaults->$newname = $defaults->$field ?? null; } // Copy block config into config_ fields. @@ -284,12 +365,22 @@ function set_data($defaults) { 'bui_pagetypepattern' => $defaults->bui_pagetypepattern, 'bui_subpagepattern' => $defaults->bui_subpagepattern, ]; - parent::set_data($defaults); + return $defaults; + } + + /** + * Load in existing data as form defaults + * + * @param stdClass $defaults + * @return void + */ + public function set_data($defaults) { + parent::set_data($this->prepare_defaults($defaults)); } /** * Override this to create any form fields specific to this type of block. - * @param object $mform the form being built. + * @param \MoodleQuickForm $mform the form being built. */ protected function specific_definition($mform) { // By default, do nothing. @@ -299,7 +390,7 @@ protected function specific_definition($mform) { * Return submitted data if properly submitted or returns NULL if validation fails or * if there is no submitted data. * - * @return object submitted data; NULL if not valid or not submitted or cancelled + * @return stdClass submitted data; NULL if not valid or not submitted or cancelled */ public function get_data() { if ($data = parent::get_data()) { @@ -310,4 +401,85 @@ public function get_data() { } return $data; } + + /** + * Returns context where this form is used + * + * @return context + */ + protected function get_context_for_dynamic_submission(): context { + return $this->page->context; + } + + /** + * Checks if current user has access to this form, otherwise throws exception + */ + protected function check_access_for_dynamic_submission(): void { + if ($this->block->instance->id) { + if (!$this->page->user_can_edit_blocks() && !$this->block->user_can_edit()) { + throw new moodle_exception('nopermissions', '', $this->page->url->out(), get_string('editblock')); + } + } else { + if (!$this->page->user_can_edit_blocks()) { + throw new moodle_exception('nopermissions', '', $this->page->url->out(), get_string('addblock')); + } + $addableblocks = $this->page->blocks->get_addable_blocks(); + $blocktype = $this->block->name(); + if (!array_key_exists($blocktype, $addableblocks)) { + throw new moodle_exception('cannotaddthisblocktype', '', $this->page->url->out(), $blocktype); + } + } + } + + /** + * Process the form submission, used if form was submitted via AJAX + */ + public function process_dynamic_submission() { + if ($this->block->instance->id) { + $this->page->blocks->save_block_data($this->block, $this->get_data()); + } else { + $blockregion = $this->optional_param('blockregion', null, PARAM_TEXT); + $newblock = $this->page->blocks->add_block_at_end_of_default_region($this->block->name(), + empty($blockregion) ? null : $blockregion); + $this->page->blocks->load_blocks(); + $newblock = $this->page->blocks->find_instance($newblock->instance->id); + $newdata = $this->prepare_defaults($newblock->instance); + foreach ($this->get_data() as $key => $value) { + $newdata->$key = $value; + } + $this->page->blocks->save_block_data($newblock, $newdata); + } + } + + /** + * Load in existing data as form defaults + */ + public function set_data_for_dynamic_submission(): void { + $this->set_data($this->block->instance); + } + + /** + * Returns url to set in $PAGE->set_url() when form is being rendered or submitted via AJAX + * + * @return moodle_url + */ + protected function get_page_url_for_dynamic_submission(): moodle_url { + return $this->page->url; + } + + /** + * Display the configuration form when block is being added to the page + * + * By default when block is added to the page it is added with the default configuration. + * Some block may require configuration, for example, "glossary random entry" block + * needs a glossary to be selected, "RSS feed" block needs an RSS feed to be selected, etc. + * + * Such blocks can override this function and return true. These blocks must + * ensure that the function specific_definition() will work if there is no current block id. + * + * @return bool + */ + public static function display_form_when_adding(): bool { + return false; + } } diff --git a/blocks/glossary_random/edit_form.php b/blocks/glossary_random/edit_form.php index ef1cf3440151b..9265a002bd2f5 100644 --- a/blocks/glossary_random/edit_form.php +++ b/blocks/glossary_random/edit_form.php @@ -40,7 +40,8 @@ protected function specific_definition($mform) { $mform->setType('config_title', PARAM_TEXT); // Select glossaries to put in dropdown box ... - $glossaries = $DB->get_records_select_menu('glossary', 'course = ? OR globalglossary = ?', array($this->block->course->id, 1), 'name', 'id,name'); + $glossaries = $DB->get_records_select_menu('glossary', 'course = ? OR globalglossary = ?', + [$this->get_course_id(), 1], 'name', 'id,name'); foreach($glossaries as $key => $value) { $glossaries[$key] = strip_tags(format_string($value, true)); } @@ -76,4 +77,28 @@ protected function specific_definition($mform) { $mform->setDefault('config_invisible', get_string('invisible', 'block_glossary_random')); $mform->setType('config_invisible', PARAM_NOTAGS); } + + /** + * Returns id of the course where this block is located (or siteid for the dashboard or non-course page) + * + * @return int + */ + protected function get_course_id(): int { + if ($this->block->instance->id) { + return $this->block->course->id; + } else if ($parentcontext = $this->block->context->get_course_context(false)) { + return $parentcontext->instanceid; + } else { + return get_site()->id; + } + } + + /** + * Display the configuration form when block is being added to the page + * + * @return bool + */ + public static function display_form_when_adding(): bool { + return true; + } } diff --git a/blocks/glossary_random/tests/behat/glossary_random_addblock_disabled.feature b/blocks/glossary_random/tests/behat/glossary_random_addblock_disabled.feature index ed5c01e6637f8..0daa939b7c3a5 100644 --- a/blocks/glossary_random/tests/behat/glossary_random_addblock_disabled.feature +++ b/blocks/glossary_random/tests/behat/glossary_random_addblock_disabled.feature @@ -12,7 +12,8 @@ Feature: Add the glossary random block when main feature is disabled Scenario: The glossary random block is displayed even when glossary module is disabled Given I turn editing mode on - And I add the "Random glossary entry" block + And I add the "Random glossary entry" block to the default region with: + | Title | Random glossary entry | When I navigate to "Plugins > Activity modules > Manage activities" in site administration And I click on "Disable the Glossary plugin" "icon" in the "Glossary" "table_row" And I am on "Course 1" course homepage with editing mode on @@ -20,7 +21,8 @@ Feature: Add the glossary random block when main feature is disabled Scenario: The glossary random block can be removed even when glossary module is disabled Given I turn editing mode on - And I add the "Random glossary entry" block + And I add the "Random glossary entry" block to the default region with: + | Title | Random glossary entry | And I open the "Random glossary entry" blocks action menu And I click on "Delete Random glossary entry block" "link" in the "Random glossary entry" "block" And "Delete block?" "dialogue" should exist diff --git a/blocks/html/edit_form.php b/blocks/html/edit_form.php index c92c8c5b50be1..e0f9921870d0b 100644 --- a/blocks/html/edit_form.php +++ b/blocks/html/edit_form.php @@ -88,4 +88,13 @@ function set_data($defaults) { $this->block->config->title = $title; } } + + /** + * Display the configuration form when block is being added to the page + * + * @return bool + */ + public static function display_form_when_adding(): bool { + return true; + } } diff --git a/blocks/html/tests/behat/configuring_html_block.feature b/blocks/html/tests/behat/configuring_html_block.feature index 11a4b1e413cc3..1b448abad3357 100644 --- a/blocks/html/tests/behat/configuring_html_block.feature +++ b/blocks/html/tests/behat/configuring_html_block.feature @@ -9,11 +9,9 @@ Feature: Adding and configuring Text blocks Given I log in as "admin" And I am on site homepage When I turn editing mode on - And I add the "Text" block - And I configure the "(new text block)" block - And I set the field "Content" to "Static text without a header" - Then I should see "Text block title" - And I press "Save changes" + And I add the "Text" block to the default region with: + | Text block title | | + | Content | Static text without a header | Then I should not see "(new text block)" And I configure the "block_html" block And I set the field "Text block title" to "The Text block header" diff --git a/blocks/moodleblock.class.php b/blocks/moodleblock.class.php index 742b93b3b0766..8ae2c1eff7e78 100644 --- a/blocks/moodleblock.class.php +++ b/blocks/moodleblock.class.php @@ -71,13 +71,13 @@ class block_base { /** * An object to contain the information to be displayed in the block. - * @var stdObject $content + * @var stdClass $content */ var $content = NULL; /** * The initialized instance of this block object. - * @var block $instance + * @var stdClass $instance */ var $instance = NULL; @@ -89,13 +89,13 @@ class block_base { /** * This blocks's context. - * @var stdClass + * @var context */ public $context = NULL; /** * An object containing the instance configuration information for the current instance of this block. - * @var stdObject $config + * @var stdClass $config */ var $config = NULL; @@ -462,7 +462,7 @@ function html_attributes() { * table and the current page. (See {@link block_manager::load_blocks()}.) * * @param stdClass $instance data from block_insances, block_positions, etc. - * @param moodle_page $the page this block is on. + * @param moodle_page $page the page this block is on. */ function _load_instance($instance, $page) { if (!empty($instance->configdata)) { diff --git a/blocks/recentlyaccesseditems/tests/behat/block_recentlyaccesseditems_dashboard.feature b/blocks/recentlyaccesseditems/tests/behat/block_recentlyaccesseditems_dashboard.feature index 73605ac4ab196..bdcec5ffc0510 100644 --- a/blocks/recentlyaccesseditems/tests/behat/block_recentlyaccesseditems_dashboard.feature +++ b/blocks/recentlyaccesseditems/tests/behat/block_recentlyaccesseditems_dashboard.feature @@ -52,6 +52,7 @@ Feature: The recently accessed items block allows users to easily access their m And I click on "Show more items" "button" in the "Recently accessed items" "block" And I should see "Test forum name" in the "Recently accessed items" "block" And I turn editing mode on + And I am on homepage And I configure the "Recently accessed items" block And I set the following fields to these values: | Region | content | diff --git a/blocks/rss_client/edit_form.php b/blocks/rss_client/edit_form.php index f232bcd4049d7..6f481abf83de2 100644 --- a/blocks/rss_client/edit_form.php +++ b/blocks/rss_client/edit_form.php @@ -89,4 +89,13 @@ protected function specific_definition($mform) { $mform->addElement('selectyesno', 'config_block_rss_client_show_channel_image', get_string('clientshowimagelabel', 'block_rss_client')); $mform->setDefault('config_block_rss_client_show_channel_image', 0); } + + /** + * Display the configuration form when block is being added to the page + * + * @return bool + */ + public static function display_form_when_adding(): bool { + return true; + } } diff --git a/blocks/tests/behat/behat_blocks.php b/blocks/tests/behat/behat_blocks.php index c8bf2146e3f2d..37142b10520c0 100644 --- a/blocks/tests/behat/behat_blocks.php +++ b/blocks/tests/behat/behat_blocks.php @@ -26,6 +26,7 @@ // NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php. use Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException; +use Behat\Gherkin\Node\TableNode as TableNode; require_once(__DIR__ . '/../../../lib/behat/behat_base.php'); @@ -56,6 +57,48 @@ public function i_add_the_block($blockname) { } } + /** + * Adds the selected block to the specified region + * + * Editing mode must be previously enabled. + * + * @Given /^I add the "(?P(?:[^"]|\\")*)" block to the "(?P(?:[^"]|\\")*)" region$/ + * @param string $blockname + * @param string $region + */ + public function i_add_the_block_to_the_region(string $blockname, string $region) { + if (!$this->running_javascript()) { + throw new coding_exception('Adding block to specific region is not possible with Javascript disabled'); + } + if ($region === "default") { + $region = ""; + } + $csselement = 'a[data-key="addblock"][data-blockregion='.behat_context_helper::escape($region).']'; + $addblock = get_string('addblock'); + $this->execute('behat_general::i_click_on', [$csselement, 'css_element']); + $this->execute('behat_general::i_click_on_in_the', [$blockname, 'link_exact', $addblock, 'dialogue']); + } + + /** + * Adds the selected block to the specified region and fills configuration form. + * + * Editing mode must be previously enabled. + * + * @Given /^I add the "(?P(?:[^"]|\\")*)" block to the (?P(?:[^"]|\\")*) region with:$/ + * @param string $blockname + * @param string $region + * @param TableNode $data + */ + public function i_add_the_block_to_the_region_with(string $blockname, string $region, TableNode $data) { + $blocklabel = get_string('textellipsis', 'moodle', $blockname); + $this->execute('behat_blocks::i_add_the_block_to_the_region', [$blocklabel, $region]); + $this->wait_for_pending_js(); + $dialogname = get_string('addblock', 'core_block', $blockname); + $this->execute('behat_forms::i_set_the_following_fields_in_container_to_these_values', + [$dialogname, "dialogue", $data]); + $this->execute('behat_general::i_click_on_in_the', ["Save changes", 'button', $dialogname, 'dialogue']); + } + /** * Adds the selected block if it is not already present. Editing mode must be previously enabled. * diff --git a/blocks/tests/behat/configure_block_throughout_site.feature b/blocks/tests/behat/configure_block_throughout_site.feature index 449c41298e997..71fc348dd0bf4 100644 --- a/blocks/tests/behat/configure_block_throughout_site.feature +++ b/blocks/tests/behat/configure_block_throughout_site.feature @@ -64,10 +64,8 @@ Feature: Add and configure blocks throughout the site Given I log in as "admin" And I am on homepage And I turn editing mode on - And I add the "Text" block - And I configure the "(new text block)" block - And I set the following fields to these values: + And I add the "Text" block to the default region with: | Text block title | Foo " onload="document.getElementsByTagName('body')[0].remove()" alt=" | | Content | Example | - When I press "Save changes" - Then I should see "Example" + Then I should see "Example" in the "block_html" "block" + Then I should see "document.getElementsByTagName" diff --git a/blocks/upgrade.txt b/blocks/upgrade.txt index 25fefc78a6ffb..63ca60645f2b2 100644 --- a/blocks/upgrade.txt +++ b/blocks/upgrade.txt @@ -1,6 +1,20 @@ This files describes API changes in /blocks/* - activity modules, information provided here is intended especially for developers. +=== 4.1 === +* Block configuration form is now displayed in a modal. Class 'block_edit_form' now extends + '\core_form\dynamic_form' and properties $block and $page are read-only. Normally + no changes should be necessary to keep the old behavior of configuration form. +* Block plugins can specify that they want to display configuration form when block is + added to the page by overriding static method block_edit_form::display_form_when_adding(). +* Web service 'core_block_fetch_addable_blocks' accepts new parameter 'pagehash' +* JS module 'core/addblockmodal' is deprecated, instead there is new module + 'core_block/add_modal' with similar functionality but different arguments. +* Functions in the JS modules 'moodle-core-blockdraganddrop' have changed their parameters. + File lib/ajax/blocks.php takes different arguments. + No backward-compatibility is provided since these files are not part of the blocks API + and not intended to be used by plugins. + === 4.0 === * Block block_quiz_results has been completely removed from core. diff --git a/filter/displayh5p/tests/behat/inline_editing_content.feature b/filter/displayh5p/tests/behat/inline_editing_content.feature index abf97c6c26661..49afc17e205de 100644 --- a/filter/displayh5p/tests/behat/inline_editing_content.feature +++ b/filter/displayh5p/tests/behat/inline_editing_content.feature @@ -221,16 +221,18 @@ Feature: Inline editing H5P content anywhere Given I am on the "C1" "Course" page logged in as "admin" # Add H5P content to the block. And I turn editing mode on - And I add the "Text" block - And I configure the "(new text block)" block - And I click on "Insert H5P" "button" in the "#fitem_id_config_text" "css_element" + And I add the "Text" block to the default region with: + | Text block title | H5PTest | + | Content | - | + And I configure the "H5PTest" block + And I click on "Insert H5P" "button" in the "//div[contains(@id,'fitem_id_config_text')]" "xpath_element" And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue" And I select "Content bank" repository in file picker And I click on "Greeting card" "file" in repository content area And I click on "Make a copy of the file" "radio" And I click on "Select this file" "button" And I click on "Insert H5P" "button" in the "Insert H5P" "dialogue" - And I press "Save changes" + And I click on "Save changes" "button" in the "Configure H5PTest block" "dialogue" And I switch to "h5p-iframe" class iframe And I switch to "h5p-iframe" class iframe And I should see "Hello world!" diff --git a/lang/en/block.php b/lang/en/block.php index 1d439228c68fc..4856cbec6131b 100644 --- a/lang/en/block.php +++ b/lang/en/block.php @@ -22,6 +22,7 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +$string['addblock'] = 'Add {$a} block'; $string['anypagematchingtheabove'] = 'Any page matching the above'; $string['appearsinsubcontexts'] = 'Appears in sub-contexts'; $string['assignrolesinblock'] = 'Assign roles in {$a} block'; diff --git a/lang/en/error.php b/lang/en/error.php index a7a587bfc8c32..73aa93130b4e1 100644 --- a/lang/en/error.php +++ b/lang/en/error.php @@ -240,6 +240,7 @@ $string['duplicaterolename'] = 'There is already a role with this name!'; $string['duplicateroleshortname'] = 'There is already a role with this short name!'; $string['duplicateusername'] = 'Duplicate username - skipping record'; +$string['editedpagenotfound'] = 'Could not determine the current page. Please try refreshing the page and repeating the operation.'; $string['emailfail'] = 'Emailing failed'; $string['encryption_encryptfailed'] = 'Encryption failed'; $string['encryption_decryptfailed'] = 'Decryption failed'; diff --git a/lib/ajax/blocks.php b/lib/ajax/blocks.php index 7d1a7625d90a2..d4aae2a82913b 100644 --- a/lib/ajax/blocks.php +++ b/lib/ajax/blocks.php @@ -26,52 +26,29 @@ require_once(__DIR__ . '/../../config.php'); // Initialise ALL common incoming parameters here, up front. -$courseid = required_param('courseid', PARAM_INT); -$pagelayout = required_param('pagelayout', PARAM_ALPHAEXT); -$pagetype = required_param('pagetype', PARAM_ALPHANUMEXT); -$contextid = required_param('contextid', PARAM_INT); -$subpage = optional_param('subpage', '', PARAM_ALPHANUMEXT); -$cmid = optional_param('cmid', null, PARAM_INT); +$pagehash = required_param('pagehash', PARAM_RAW); $action = optional_param('action', '', PARAM_ALPHA); // Params for blocks-move actions. $buimoveid = optional_param('bui_moveid', 0, PARAM_INT); $buinewregion = optional_param('bui_newregion', '', PARAM_ALPHAEXT); $buibeforeid = optional_param('bui_beforeid', 0, PARAM_INT); -// Setting pagetype and URL. -$PAGE->set_pagetype($pagetype); -$PAGE->set_url('/lib/ajax/blocks.php', array('courseid' => $courseid, 'pagelayout' => $pagelayout, 'pagetype' => $pagetype)); +$PAGE->set_url('/lib/ajax/blocks.php', ['pagehash' => $pagehash]); + +// Retrieve the edited page from the session hash. +$page = moodle_page::retrieve_edited_page($pagehash, MUST_EXIST); // Verifying login and session. $cm = null; -if (!is_null($cmid)) { - $cm = get_coursemodule_from_id(null, $cmid, $courseid, false, MUST_EXIST); +if (!is_null($page->cm)) { + $cm = get_coursemodule_from_id(null, $page->cm->id, $page->course->id, false, MUST_EXIST); } -require_login($courseid, false, $cm); +require_login($page->course, false, $cm); require_sesskey(); +$PAGE->set_context($page->context); -// Set context from ID, so we don't have to guess it from other info. -$PAGE->set_context(context::instance_by_id($contextid)); - -// Setting layout to replicate blocks configuration for the page we edit. -$PAGE->set_pagelayout($pagelayout); -$PAGE->set_subpage($subpage); -$PAGE->blocks->add_custom_regions_for_pagetype($pagetype); -$pagetype = explode('-', $pagetype); -switch ($pagetype[0]) { - case 'my': - case 'mycourses': - $PAGE->set_blocks_editing_capability('moodle/my:manageblocks'); - break; - case 'user': - if ($pagetype[1] === 'profile' && $PAGE->context->contextlevel == CONTEXT_USER - && $PAGE->context->instanceid == $USER->id) { - // A user can only move blocks on their own site profile. - $PAGE->set_blocks_editing_capability('moodle/user:manageownblocks'); - } else { - $PAGE->set_blocks_editing_capability('moodle/user:manageblocks'); - } - break; +if (!$page->user_can_edit_blocks() || !$page->user_is_editing()) { + throw new moodle_exception('nopermissions', '', $page->url->out(), get_string('editblock')); } // Send headers. @@ -80,8 +57,8 @@ switch ($action) { case 'move': // Loading blocks and instances for the region. - $PAGE->blocks->load_blocks(); - $instances = $PAGE->blocks->get_blocks_for_region($buinewregion); + $page->blocks->load_blocks(); + $instances = $page->blocks->get_blocks_for_region($buinewregion); $buinewweight = null; if ($buibeforeid == 0) { @@ -121,7 +98,7 @@ if (isset($buinewweight)) { // Nasty hack. $_POST['bui_newweight'] = $buinewweight; - $PAGE->blocks->process_url_move(); + $page->blocks->process_url_move(); } break; } diff --git a/lib/amd/build/addblockmodal.min.js b/lib/amd/build/addblockmodal.min.js index 22c77eb2d13ec..af43594d2236f 100644 --- a/lib/amd/build/addblockmodal.min.js +++ b/lib/amd/build/addblockmodal.min.js @@ -3,6 +3,7 @@ define("core/addblockmodal",["exports","core/modal_factory","core/templates","co * Show an add block modal instead of doing it on a separate page. * * @module core/addblockmodal + * @deprecated since Moodle 4.2 - please use core_block/add_modal instead. * @copyright 2016 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_modal_factory=_interopRequireDefault(_modal_factory),_templates=_interopRequireDefault(_templates),_ajax=_interopRequireDefault(_ajax);const SELECTORS_ADD_BLOCK='[data-key="addblock"]';let listenerEventsRegistered=!1;const registerListenerEvents=(pageType,pageLayout,addBlockUrl,subPage)=>{document.addEventListener("click",(e=>{const addBlock=e.target.closest(SELECTORS_ADD_BLOCK);if(addBlock){e.preventDefault();let addBlockModal=null,addBlockModalUrl=null!=addBlockUrl?addBlockUrl:addBlock.dataset.url;buildAddBlockModal().then((modal=>{addBlockModal=modal;const modalBody=renderBlocks(addBlockModalUrl,pageType,pageLayout,subPage);return modal.setBody(modalBody),modal.show(),modalBody})).catch((()=>{addBlockModal.destroy()}))}}))},buildAddBlockModal=()=>_modal_factory.default.create({type:_modal_factory.default.types.CANCEL,title:(0,_str.get_string)("addblock")}),renderBlocks=async(addBlockUrl,pageType,pageLayout,subPage)=>{const blocks=await getAddableBlocks(pageType,pageLayout,subPage);return _templates.default.render("core/add_block_body",{blocks:blocks,url:addBlockUrl})},getAddableBlocks=async(pageType,pageLayout,subPage)=>{const request={methodname:"core_block_fetch_addable_blocks",args:{pagecontextid:M.cfg.contextid,pagetype:pageType,pagelayout:pageLayout,subpage:subPage}};return _ajax.default.call([request])[0]};_exports.init=function(pageType,pageLayout){let addBlockUrl=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,subPage=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"";listenerEventsRegistered||(registerListenerEvents(pageType,pageLayout,addBlockUrl,subPage),listenerEventsRegistered=!0)}})); diff --git a/lib/amd/build/addblockmodal.min.js.map b/lib/amd/build/addblockmodal.min.js.map index 54422f1557359..b3316c79e774b 100644 --- a/lib/amd/build/addblockmodal.min.js.map +++ b/lib/amd/build/addblockmodal.min.js.map @@ -1 +1 @@ -{"version":3,"file":"addblockmodal.min.js","sources":["../src/addblockmodal.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Show an add block modal instead of doing it on a separate page.\n *\n * @module core/addblockmodal\n * @copyright 2016 Damyon Wiese \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport ModalFactory from 'core/modal_factory';\nimport Templates from 'core/templates';\nimport {get_string as getString} from 'core/str';\nimport Ajax from 'core/ajax';\n\nconst SELECTORS = {\n ADD_BLOCK: '[data-key=\"addblock\"]'\n};\n\n// Ensure we only add our listeners once.\nlet listenerEventsRegistered = false;\n\n/**\n * Register related event listeners.\n *\n * @method registerListenerEvents\n * @param {String} pageType The type of the page\n * @param {String} pageLayout The layout of the page\n * @param {String|null} addBlockUrl The add block URL\n * @param {String} subPage The subpage identifier\n */\nconst registerListenerEvents = (pageType, pageLayout, addBlockUrl, subPage) => {\n document.addEventListener('click', e => {\n\n const addBlock = e.target.closest(SELECTORS.ADD_BLOCK);\n if (addBlock) {\n e.preventDefault();\n\n let addBlockModal = null;\n let addBlockModalUrl = addBlockUrl ?? addBlock.dataset.url;\n\n buildAddBlockModal()\n .then(modal => {\n addBlockModal = modal;\n const modalBody = renderBlocks(addBlockModalUrl, pageType, pageLayout, subPage);\n modal.setBody(modalBody);\n modal.show();\n\n return modalBody;\n })\n .catch(() => {\n addBlockModal.destroy();\n });\n }\n });\n};\n\n/**\n * Method that creates the 'add block' modal.\n *\n * @method buildAddBlockModal\n * @returns {Promise} The modal promise (modal's body will be rendered later).\n */\nconst buildAddBlockModal = () => {\n return ModalFactory.create({\n type: ModalFactory.types.CANCEL,\n title: getString('addblock')\n });\n};\n\n/**\n * Method that renders the list of available blocks.\n *\n * @method renderBlocks\n * @param {String} addBlockUrl The add block URL\n * @param {String} pageType The type of the page\n * @param {String} pageLayout The layout of the page\n * @param {String} subPage The subpage identifier\n * @return {Promise}\n */\nconst renderBlocks = async(addBlockUrl, pageType, pageLayout, subPage) => {\n // Fetch all addable blocks in the given page.\n const blocks = await getAddableBlocks(pageType, pageLayout, subPage);\n\n return Templates.render('core/add_block_body', {\n blocks: blocks,\n url: addBlockUrl\n });\n};\n\n/**\n * Method that fetches all addable blocks in a given page.\n *\n * @method getAddableBlocks\n * @param {String} pageType The type of the page\n * @param {String} pageLayout The layout of the page\n * @param {String} subPage The subpage identifier\n * @return {Promise}\n */\nconst getAddableBlocks = async(pageType, pageLayout, subPage) => {\n const request = {\n methodname: 'core_block_fetch_addable_blocks',\n args: {\n pagecontextid: M.cfg.contextid,\n pagetype: pageType,\n pagelayout: pageLayout,\n subpage: subPage,\n },\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Set up the actions.\n *\n * @method init\n * @param {String} pageType The type of the page\n * @param {String} pageLayout The layout of the page\n * @param {String|null} addBlockUrl The add block URL\n * @param {String} subPage The subpage identifier\n */\nexport const init = (pageType, pageLayout, addBlockUrl = null, subPage = '') => {\n if (!listenerEventsRegistered) {\n registerListenerEvents(pageType, pageLayout, addBlockUrl, subPage);\n listenerEventsRegistered = true;\n }\n};\n"],"names":["SELECTORS","listenerEventsRegistered","registerListenerEvents","pageType","pageLayout","addBlockUrl","subPage","document","addEventListener","e","addBlock","target","closest","preventDefault","addBlockModal","addBlockModalUrl","dataset","url","buildAddBlockModal","then","modal","modalBody","renderBlocks","setBody","show","catch","destroy","ModalFactory","create","type","types","CANCEL","title","async","blocks","getAddableBlocks","Templates","render","request","methodname","args","pagecontextid","M","cfg","contextid","pagetype","pagelayout","subpage","Ajax","call"],"mappings":";;;;;;;gOA4BMA,oBACS,4BAIXC,0BAA2B,QAWzBC,uBAAyB,CAACC,SAAUC,WAAYC,YAAaC,WAC/DC,SAASC,iBAAiB,SAASC,UAEzBC,SAAWD,EAAEE,OAAOC,QAAQZ,wBAC9BU,SAAU,CACVD,EAAEI,qBAEEC,cAAgB,KAChBC,iBAAmBV,MAAAA,YAAAA,YAAeK,SAASM,QAAQC,IAEvDC,qBACKC,MAAKC,QACFN,cAAgBM,YACVC,UAAYC,aAAaP,iBAAkBZ,SAAUC,WAAYE,gBACvEc,MAAMG,QAAQF,WACdD,MAAMI,OAECH,aAEVI,OAAM,KACHX,cAAcY,kBAY5BR,mBAAqB,IAChBS,uBAAaC,OAAO,CACvBC,KAAMF,uBAAaG,MAAMC,OACzBC,OAAO,mBAAU,cAcnBV,aAAeW,MAAM5B,YAAaF,SAAUC,WAAYE,iBAEpD4B,aAAeC,iBAAiBhC,SAAUC,WAAYE,gBAErD8B,mBAAUC,OAAO,sBAAuB,CAC3CH,OAAQA,OACRjB,IAAKZ,eAaP8B,iBAAmBF,MAAM9B,SAAUC,WAAYE,iBAC3CgC,QAAU,CACZC,WAAY,kCACZC,KAAM,CACFC,cAAeC,EAAEC,IAAIC,UACrBC,SAAU1C,SACV2C,WAAY1C,WACZ2C,QAASzC,iBAIV0C,cAAKC,KAAK,CAACX,UAAU,kBAYZ,SAACnC,SAAUC,gBAAYC,mEAAc,KAAMC,+DAAU,GAChEL,2BACDC,uBAAuBC,SAAUC,WAAYC,YAAaC,SAC1DL,0BAA2B"} \ No newline at end of file +{"version":3,"file":"addblockmodal.min.js","sources":["../src/addblockmodal.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Show an add block modal instead of doing it on a separate page.\n *\n * @module core/addblockmodal\n * @deprecated since Moodle 4.2 - please use core_block/add_modal instead.\n * @copyright 2016 Damyon Wiese \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport ModalFactory from 'core/modal_factory';\nimport Templates from 'core/templates';\nimport {get_string as getString} from 'core/str';\nimport Ajax from 'core/ajax';\n\nconst SELECTORS = {\n ADD_BLOCK: '[data-key=\"addblock\"]'\n};\n\n// Ensure we only add our listeners once.\nlet listenerEventsRegistered = false;\n\n/**\n * Register related event listeners.\n *\n * @method registerListenerEvents\n * @param {String} pageType The type of the page\n * @param {String} pageLayout The layout of the page\n * @param {String|null} addBlockUrl The add block URL\n * @param {String} subPage The subpage identifier\n */\nconst registerListenerEvents = (pageType, pageLayout, addBlockUrl, subPage) => {\n document.addEventListener('click', e => {\n\n const addBlock = e.target.closest(SELECTORS.ADD_BLOCK);\n if (addBlock) {\n e.preventDefault();\n\n let addBlockModal = null;\n let addBlockModalUrl = addBlockUrl ?? addBlock.dataset.url;\n\n buildAddBlockModal()\n .then(modal => {\n addBlockModal = modal;\n const modalBody = renderBlocks(addBlockModalUrl, pageType, pageLayout, subPage);\n modal.setBody(modalBody);\n modal.show();\n\n return modalBody;\n })\n .catch(() => {\n addBlockModal.destroy();\n });\n }\n });\n};\n\n/**\n * Method that creates the 'add block' modal.\n *\n * @method buildAddBlockModal\n * @returns {Promise} The modal promise (modal's body will be rendered later).\n */\nconst buildAddBlockModal = () => {\n return ModalFactory.create({\n type: ModalFactory.types.CANCEL,\n title: getString('addblock')\n });\n};\n\n/**\n * Method that renders the list of available blocks.\n *\n * @method renderBlocks\n * @param {String} addBlockUrl The add block URL\n * @param {String} pageType The type of the page\n * @param {String} pageLayout The layout of the page\n * @param {String} subPage The subpage identifier\n * @return {Promise}\n */\nconst renderBlocks = async(addBlockUrl, pageType, pageLayout, subPage) => {\n // Fetch all addable blocks in the given page.\n const blocks = await getAddableBlocks(pageType, pageLayout, subPage);\n\n return Templates.render('core/add_block_body', {\n blocks: blocks,\n url: addBlockUrl\n });\n};\n\n/**\n * Method that fetches all addable blocks in a given page.\n *\n * @method getAddableBlocks\n * @param {String} pageType The type of the page\n * @param {String} pageLayout The layout of the page\n * @param {String} subPage The subpage identifier\n * @return {Promise}\n */\nconst getAddableBlocks = async(pageType, pageLayout, subPage) => {\n const request = {\n methodname: 'core_block_fetch_addable_blocks',\n args: {\n pagecontextid: M.cfg.contextid,\n pagetype: pageType,\n pagelayout: pageLayout,\n subpage: subPage,\n },\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Set up the actions.\n *\n * @method init\n * @param {String} pageType The type of the page\n * @param {String} pageLayout The layout of the page\n * @param {String|null} addBlockUrl The add block URL\n * @param {String} subPage The subpage identifier\n */\nexport const init = (pageType, pageLayout, addBlockUrl = null, subPage = '') => {\n if (!listenerEventsRegistered) {\n registerListenerEvents(pageType, pageLayout, addBlockUrl, subPage);\n listenerEventsRegistered = true;\n }\n};\n"],"names":["SELECTORS","listenerEventsRegistered","registerListenerEvents","pageType","pageLayout","addBlockUrl","subPage","document","addEventListener","e","addBlock","target","closest","preventDefault","addBlockModal","addBlockModalUrl","dataset","url","buildAddBlockModal","then","modal","modalBody","renderBlocks","setBody","show","catch","destroy","ModalFactory","create","type","types","CANCEL","title","async","blocks","getAddableBlocks","Templates","render","request","methodname","args","pagecontextid","M","cfg","contextid","pagetype","pagelayout","subpage","Ajax","call"],"mappings":";;;;;;;;gOA6BMA,oBACS,4BAIXC,0BAA2B,QAWzBC,uBAAyB,CAACC,SAAUC,WAAYC,YAAaC,WAC/DC,SAASC,iBAAiB,SAASC,UAEzBC,SAAWD,EAAEE,OAAOC,QAAQZ,wBAC9BU,SAAU,CACVD,EAAEI,qBAEEC,cAAgB,KAChBC,iBAAmBV,MAAAA,YAAAA,YAAeK,SAASM,QAAQC,IAEvDC,qBACKC,MAAKC,QACFN,cAAgBM,YACVC,UAAYC,aAAaP,iBAAkBZ,SAAUC,WAAYE,gBACvEc,MAAMG,QAAQF,WACdD,MAAMI,OAECH,aAEVI,OAAM,KACHX,cAAcY,kBAY5BR,mBAAqB,IAChBS,uBAAaC,OAAO,CACvBC,KAAMF,uBAAaG,MAAMC,OACzBC,OAAO,mBAAU,cAcnBV,aAAeW,MAAM5B,YAAaF,SAAUC,WAAYE,iBAEpD4B,aAAeC,iBAAiBhC,SAAUC,WAAYE,gBAErD8B,mBAAUC,OAAO,sBAAuB,CAC3CH,OAAQA,OACRjB,IAAKZ,eAaP8B,iBAAmBF,MAAM9B,SAAUC,WAAYE,iBAC3CgC,QAAU,CACZC,WAAY,kCACZC,KAAM,CACFC,cAAeC,EAAEC,IAAIC,UACrBC,SAAU1C,SACV2C,WAAY1C,WACZ2C,QAASzC,iBAIV0C,cAAKC,KAAK,CAACX,UAAU,kBAYZ,SAACnC,SAAUC,gBAAYC,mEAAc,KAAMC,+DAAU,GAChEL,2BACDC,uBAAuBC,SAAUC,WAAYC,YAAaC,SAC1DL,0BAA2B"} \ No newline at end of file diff --git a/lib/amd/src/addblockmodal.js b/lib/amd/src/addblockmodal.js index 42ebaf30ffe3a..829c7c39d338e 100644 --- a/lib/amd/src/addblockmodal.js +++ b/lib/amd/src/addblockmodal.js @@ -17,6 +17,7 @@ * Show an add block modal instead of doing it on a separate page. * * @module core/addblockmodal + * @deprecated since Moodle 4.2 - please use core_block/add_modal instead. * @copyright 2016 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ diff --git a/lib/blocklib.php b/lib/blocklib.php index f6fc929087de9..d24855600ede1 100644 --- a/lib/blocklib.php +++ b/lib/blocklib.php @@ -821,6 +821,7 @@ public function load_blocks($includeinvisible = null) { * @param boolean $showinsubcontexts whether this block appears in subcontexts, or just the current context. * @param string|null $pagetypepattern which page types this block should appear on. Defaults to just the current page type. * @param string|null $subpagepattern which subpage this block should appear on. NULL = any (the default), otherwise only the specified subpage. + * @return block_base */ public function add_block($blockname, $region, $weight, $showinsubcontexts, $pagetypepattern = NULL, $subpagepattern = NULL) { global $DB; @@ -853,6 +854,13 @@ public function add_block($blockname, $region, $weight, $showinsubcontexts, $pag if ($block = block_instance($blockname, $blockinstance)) { $block->instance_create(); } + + if (!is_null($this->birecordsbyregion)) { + // If blocks were already loaded on this page, reload them. + $this->birecordsbyregion = null; + $this->load_blocks(); + } + return $block; } /** @@ -860,11 +868,12 @@ public function add_block($blockname, $region, $weight, $showinsubcontexts, $pag * * @param string $blockname Name of the block to add. * @param null|string $blockregion If defined add the new block to the specified region. + * @return ?block_base */ public function add_block_at_end_of_default_region($blockname, $blockregion = null) { if (empty($this->birecordsbyregion)) { // No blocks or block regions exist yet. - return; + return null; } if ($blockregion === null) { @@ -911,7 +920,7 @@ public function add_block_at_end_of_default_region($blockname, $blockregion = nu // Surely other pages like course-report will need this too, they just are not important // enough now. This will be decided in the coming days. (MDL-27829, MDL-28150) - $this->add_block($blockname, $defaulregion, $weight, false, $pagetypepattern, $subpage); + return $this->add_block($blockname, $defaulregion, $weight, false, $pagetypepattern, $subpage); } /** @@ -1295,8 +1304,8 @@ public function ensure_content_created($region, $output) { * Get the appropriate list of editing icons for a block. This is used * to set {@link block_contents::$controls} in {@link block_base::get_contents_for_output()}. * - * @param $output The core_renderer to use when generating the output. (Need to get icon paths.) - * @return an array in the format for {@link block_contents::$controls} + * @param block_base $block + * @return array an array in the format for {@link block_contents::$controls} */ public function edit_controls($block) { global $CFG; @@ -1335,7 +1344,13 @@ public function edit_controls($block) { $editactionurl, new pix_icon('t/edit', $str, 'moodle', array('class' => 'iconsmall', 'title' => '')), $str, - array('class' => 'editing_edit') + [ + 'class' => 'editing_edit', + 'data-action' => 'editblock', + 'data-blockid' => $block->instance->id, + 'data-blockform' => self::get_block_edit_form_class($block->name()), + 'data-header' => $str, + ] ); } @@ -1648,6 +1663,31 @@ public function process_url_delete() { } } + /** + * Returns the name of the class for block editing and makes sure it is autoloaded + * + * @param string $blockname name of the block plugin (without block_ prefix) + * @return string + */ + public static function get_block_edit_form_class(string $blockname): string { + global $CFG; + require_once("$CFG->dirroot/blocks/moodleblock.class.php"); + $blockname = clean_param($blockname, PARAM_PLUGIN); + $formfile = $CFG->dirroot . '/blocks/' . $blockname . '/edit_form.php'; + if (is_readable($formfile)) { + require_once($CFG->dirroot . '/blocks/edit_form.php'); + require_once($formfile); + $classname = 'block_' . $blockname . '_edit_form'; + if (!class_exists($classname)) { + $classname = 'block_edit_form'; + } + } else { + require_once($CFG->dirroot . '/blocks/edit_form.php'); + $classname = 'block_edit_form'; + } + return $classname; + } + /** * Handle showing or hiding a block. * @return boolean true if anything was done. False if not. @@ -1749,140 +1789,17 @@ public function process_url_edit() { $output = $editpage->get_renderer('core'); $OUTPUT = $output; - $formfile = $CFG->dirroot . '/blocks/' . $block->name() . '/edit_form.php'; - if (is_readable($formfile)) { - require_once($formfile); - $classname = 'block_' . $block->name() . '_edit_form'; - if (!class_exists($classname)) { - $classname = 'block_edit_form'; - } - } else { - $classname = 'block_edit_form'; - } - - $mform = new $classname($editpage->url, $block, $this->page); + $classname = self::get_block_edit_form_class($block->name()); + /** @var block_edit_form $mform */ + $mform = new $classname($editpage->url->out(false), ['page' => $this->page, 'block' => $block, 'actionbuttons' => true]); $mform->set_data($block->instance); if ($mform->is_cancelled()) { redirect($this->page->url); } else if ($data = $mform->get_data()) { - $bi = new stdClass; - $bi->id = $block->instance->id; - - // This may get overwritten by the special case handling below. - $bi->pagetypepattern = $data->bui_pagetypepattern; - $bi->showinsubcontexts = (bool) $data->bui_contexts; - if (empty($data->bui_subpagepattern) || $data->bui_subpagepattern == '%@NULL@%') { - $bi->subpagepattern = null; - } else { - $bi->subpagepattern = $data->bui_subpagepattern; - } - - $systemcontext = context_system::instance(); - $frontpagecontext = context_course::instance(SITEID); - $parentcontext = context::instance_by_id($data->bui_parentcontextid); - - // Updating stickiness and contexts. See MDL-21375 for details. - if (has_capability('moodle/site:manageblocks', $parentcontext)) { // Check permissions in destination - - // Explicitly set the default context - $bi->parentcontextid = $parentcontext->id; - - if ($data->bui_editingatfrontpage) { // The block is being edited on the front page - - // The interface here is a special case because the pagetype pattern is - // totally derived from the context menu. Here are the excpetions. MDL-30340 - - switch ($data->bui_contexts) { - case BUI_CONTEXTS_ENTIRE_SITE: - // The user wants to show the block across the entire site - $bi->parentcontextid = $systemcontext->id; - $bi->showinsubcontexts = true; - $bi->pagetypepattern = '*'; - break; - case BUI_CONTEXTS_FRONTPAGE_SUBS: - // The user wants the block shown on the front page and all subcontexts - $bi->parentcontextid = $frontpagecontext->id; - $bi->showinsubcontexts = true; - $bi->pagetypepattern = '*'; - break; - case BUI_CONTEXTS_FRONTPAGE_ONLY: - // The user want to show the front page on the frontpage only - $bi->parentcontextid = $frontpagecontext->id; - $bi->showinsubcontexts = false; - $bi->pagetypepattern = 'site-index'; - // This is the only relevant page type anyway but we'll set it explicitly just - // in case the front page grows site-index-* subpages of its own later - break; - } - } - } - - $bits = explode('-', $bi->pagetypepattern); - // hacks for some contexts - if (($parentcontext->contextlevel == CONTEXT_COURSE) && ($parentcontext->instanceid != SITEID)) { - // For course context - // is page type pattern is mod-*, change showinsubcontext to 1 - if ($bits[0] == 'mod' || $bi->pagetypepattern == '*') { - $bi->showinsubcontexts = 1; - } else { - $bi->showinsubcontexts = 0; - } - } else if ($parentcontext->contextlevel == CONTEXT_USER) { - // for user context - // subpagepattern should be null - if ($bits[0] == 'user' or $bits[0] == 'my') { - // we don't need subpagepattern in usercontext - $bi->subpagepattern = null; - } - } - - $bi->defaultregion = $data->bui_defaultregion; - $bi->defaultweight = $data->bui_defaultweight; - $bi->timemodified = time(); - $DB->update_record('block_instances', $bi); - - if (!empty($block->config)) { - $config = clone($block->config); - } else { - $config = new stdClass; - } - foreach ($data as $configfield => $value) { - if (strpos($configfield, 'config_') !== 0) { - continue; - } - $field = substr($configfield, 7); - $config->$field = $value; - } - $block->instance_config_save($config); - - $bp = new stdClass; - $bp->visible = $data->bui_visible; - $bp->region = $data->bui_region; - $bp->weight = $data->bui_weight; - $needbprecord = !$data->bui_visible || $data->bui_region != $data->bui_defaultregion || - $data->bui_weight != $data->bui_defaultweight; - - if ($block->instance->blockpositionid && !$needbprecord) { - $DB->delete_records('block_positions', array('id' => $block->instance->blockpositionid)); - - } else if ($block->instance->blockpositionid && $needbprecord) { - $bp->id = $block->instance->blockpositionid; - $DB->update_record('block_positions', $bp); - - } else if ($needbprecord) { - $bp->blockinstanceid = $block->instance->id; - $bp->contextid = $this->page->context->id; - $bp->pagetype = $this->page->pagetype; - if ($this->page->subpage) { - $bp->subpage = $this->page->subpage; - } else { - $bp->subpage = ''; - } - $DB->insert_record('block_positions', $bp); - } + $this->save_block_data($block, $data); redirect($this->page->url); } else { @@ -1908,6 +1825,132 @@ public function process_url_edit() { } } + /** + * Updates block configuration in the database + * + * @param block_base $block + * @param stdClass $data data from the block edit form + * @return void + */ + public function save_block_data(block_base $block, stdClass $data): void { + global $DB; + + $bi = new stdClass; + $bi->id = $block->instance->id; + + // This may get overwritten by the special case handling below. + $bi->pagetypepattern = $data->bui_pagetypepattern; + $bi->showinsubcontexts = (bool) $data->bui_contexts; + if (empty($data->bui_subpagepattern) || $data->bui_subpagepattern == '%@NULL@%') { + $bi->subpagepattern = null; + } else { + $bi->subpagepattern = $data->bui_subpagepattern; + } + + $systemcontext = context_system::instance(); + $frontpagecontext = context_course::instance(SITEID); + $parentcontext = context::instance_by_id($data->bui_parentcontextid); + + // Updating stickiness and contexts. See MDL-21375 for details. + if (has_capability('moodle/site:manageblocks', $parentcontext)) { // Check permissions in destination. + + // Explicitly set the default context. + $bi->parentcontextid = $parentcontext->id; + + if ($data->bui_editingatfrontpage) { // The block is being edited on the front page. + + // The interface here is a special case because the pagetype pattern is + // totally derived from the context menu. Here are the excpetions. MDL-30340 . + + switch ($data->bui_contexts) { + case BUI_CONTEXTS_ENTIRE_SITE: + // The user wants to show the block across the entire site. + $bi->parentcontextid = $systemcontext->id; + $bi->showinsubcontexts = true; + $bi->pagetypepattern = '*'; + break; + case BUI_CONTEXTS_FRONTPAGE_SUBS: + // The user wants the block shown on the front page and all subcontexts. + $bi->parentcontextid = $frontpagecontext->id; + $bi->showinsubcontexts = true; + $bi->pagetypepattern = '*'; + break; + case BUI_CONTEXTS_FRONTPAGE_ONLY: + // The user want to show the front page on the frontpage only. + $bi->parentcontextid = $frontpagecontext->id; + $bi->showinsubcontexts = false; + $bi->pagetypepattern = 'site-index'; + // This is the only relevant page type anyway but we'll set it explicitly just + // in case the front page grows site-index-* subpages of its own later. + break; + } + } + } + + $bits = explode('-', $bi->pagetypepattern); + // Hacks for some contexts. + if (($parentcontext->contextlevel == CONTEXT_COURSE) && ($parentcontext->instanceid != SITEID)) { + // For course context + // is page type pattern is mod-*, change showinsubcontext to 1. + if ($bits[0] == 'mod' || $bi->pagetypepattern == '*') { + $bi->showinsubcontexts = 1; + } else { + $bi->showinsubcontexts = 0; + } + } else if ($parentcontext->contextlevel == CONTEXT_USER) { + // For user context subpagepattern should be null. + if ($bits[0] == 'user' || $bits[0] == 'my') { + // We don't need subpagepattern in usercontext. + $bi->subpagepattern = null; + } + } + + $bi->defaultregion = $data->bui_defaultregion; + $bi->defaultweight = $data->bui_defaultweight; + $bi->timemodified = time(); + $DB->update_record('block_instances', $bi); + + if (!empty($block->config)) { + $config = clone($block->config); + } else { + $config = new stdClass; + } + foreach ($data as $configfield => $value) { + if (strpos($configfield, 'config_') !== 0) { + continue; + } + $field = substr($configfield, 7); + $config->$field = $value; + } + $block->instance_config_save($config); + + $bp = new stdClass; + $bp->visible = $data->bui_visible; + $bp->region = $data->bui_region; + $bp->weight = $data->bui_weight; + $needbprecord = !$data->bui_visible || $data->bui_region != $data->bui_defaultregion || + $data->bui_weight != $data->bui_defaultweight; + + if ($block->instance->blockpositionid && !$needbprecord) { + $DB->delete_records('block_positions', array('id' => $block->instance->blockpositionid)); + + } else if ($block->instance->blockpositionid && $needbprecord) { + $bp->id = $block->instance->blockpositionid; + $DB->update_record('block_positions', $bp); + + } else if ($needbprecord) { + $bp->blockinstanceid = $block->instance->id; + $bp->contextid = $this->page->context->id; + $bp->pagetype = $this->page->pagetype; + if ($this->page->subpage) { + $bp->subpage = $this->page->subpage; + } else { + $bp->subpage = ''; + } + $DB->insert_record('block_positions', $bp); + } + } + /** * Handle showing/processing the submission from the block editing form. * @return boolean true if the form was submitted and the new config saved. Does not @@ -2081,7 +2124,7 @@ function block_instance_by_id($blockinstanceid) { * Creates a new instance of the specified block class. * * @param string $blockname the name of the block. - * @param $instance block_instances DB table row (optional). + * @param stdClass $instance block_instances DB table row (optional). * @param moodle_page $page the page this block is appearing on. * @return block_base the requested block instance. */ @@ -2090,6 +2133,7 @@ function block_instance($blockname, $instance = NULL, $page = NULL) { return false; } $classname = 'block_'.$blockname; + /** @var block_base $retval */ $retval = new $classname; if($instance !== NULL) { if (is_null($page)) { diff --git a/lib/form/classes/external/dynamic_form.php b/lib/form/classes/external/dynamic_form.php index 383f1fafd13a8..f430d2fe6220f 100644 --- a/lib/form/classes/external/dynamic_form.php +++ b/lib/form/classes/external/dynamic_form.php @@ -60,6 +60,8 @@ public static function execute(string $formclass, string $formdatastr): array { $formclass = $params['form']; parse_str($params['formdata'], $formdata); + self::autoload_block_edit_form($formclass); + if (!class_exists($formclass) || !is_subclass_of($formclass, \core_form\dynamic_form::class)) { // For security reason we don't throw exception "class does not exist" but rather an access exception. throw new \moodle_exception('nopermissionform', 'core_form'); @@ -85,6 +87,22 @@ public static function execute(string $formclass, string $formdatastr): array { return $output; } + /** + * Special autoloading for block forms. + * + * @param string $formclass + * @return void + */ + protected static function autoload_block_edit_form(string $formclass): void { + global $CFG; + if (preg_match('/^block_([\w_]+)_edit_form$/', $formclass, $matches)) { + \block_manager::get_block_edit_form_class($matches[1]); + } + if ($formclass === 'block_edit_form') { + require_once($CFG->dirroot . '/blocks/edit_form.php'); + } + } + /** * Return for modal * @return external_single_structure diff --git a/lib/navigationlib.php b/lib/navigationlib.php index eb5f5dcd7300e..f3547a6b94029 100644 --- a/lib/navigationlib.php +++ b/lib/navigationlib.php @@ -4229,8 +4229,8 @@ public function initialise() { $addblockurl = "?{$url->get_query_string(false)}"; - $PAGE->requires->js_call_amd('core/addblockmodal', 'init', - [$PAGE->pagetype, $PAGE->pagelayout, $addblockurl]); + $PAGE->requires->js_call_amd('core_block/add_modal', 'init', + [$addblockurl, $this->page->get_edited_page_hash()]); } } diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php index c19a8639d659f..77a83e3c26c91 100644 --- a/lib/outputrenderers.php +++ b/lib/outputrenderers.php @@ -5088,6 +5088,10 @@ public function addblockbutton($region = ''): string { [ 'link' => $url->out(false), 'escapedlink' => "?{$url->get_query_string(false)}", + 'pagehash' => $this->page->get_edited_page_hash(), + 'blockregion' => $region, + // The following parameters are not used since Moodle 4.2 but are + // still passed for backward-compatibility. 'pageType' => $this->page->pagetype, 'pageLayout' => $this->page->pagelayout, 'subPage' => $this->page->subpage, diff --git a/lib/outputrequirementslib.php b/lib/outputrequirementslib.php index e158b8cace46b..3ce54f98c286b 100644 --- a/lib/outputrequirementslib.php +++ b/lib/outputrequirementslib.php @@ -371,12 +371,8 @@ protected function init_requirements_data(moodle_page $page, core_renderer $rend // Include block drag/drop if editing is on if ($page->user_is_editing()) { $params = array( - 'courseid' => $page->course->id, - 'pagetype' => $page->pagetype, - 'pagelayout' => $page->pagelayout, - 'subpage' => $page->subpage, 'regions' => $page->blocks->get_regions(), - 'contextid' => $page->context->id, + 'pagehash' => $page->get_edited_page_hash(), ); if (!empty($page->cm->id)) { $params['cmid'] = $page->cm->id; @@ -387,6 +383,7 @@ protected function init_requirements_data(moodle_page $page, core_renderer $rend 'emptydragdropregion'), 'moodle'); $page->requires->yui_module('moodle-core-blocks', 'M.core_blocks.init_dragdrop', array($params), null, true); + $page->requires->js_call_amd('core_block/edit', 'init', ['pagehash' => $page->get_edited_page_hash()]); } // Include the YUI CSS Modules. diff --git a/lib/pagelib.php b/lib/pagelib.php index 4b9d7e81cacca..fc5b7ab32a6be 100644 --- a/lib/pagelib.php +++ b/lib/pagelib.php @@ -1637,6 +1637,120 @@ public function verify_https_required() { throw new coding_exception('verify_https_required() cannot be used anymore.'); } + /** + * Allows to 'serialize' the edited page information and store it in the session cache + * + * Due to Moodle architectural decision and non-SPA approach, a lot of page setup is + * happening in the actual page php file, for example, setting course/cm/context, + * setting layout and pagetype, requiring capabilities, setting specific block editing + * capabilities. + * + * When storing this information in the session cache we can pass the pagehash (cache key) + * as an argument to web services in AJAX requests and retrieve all data associated with + * the page without actually executing PHP code on that page. + * + * @return string|null + */ + public function get_edited_page_hash(): ?string { + global $SESSION; + if (!$this->user_is_editing()) { + return null; + } + $url = new moodle_url($this->url); + $url->set_anchor(null); + $data = [ + 'contextid' => $this->context->id, + 'url' => $url->out_as_local_url(false), + ]; + if (($cm = $this->cm) && $cm->id) { + $data['cmid'] = $cm->id; + } else if (($course = $this->course) && $course->id) { + $data['courseid'] = $course->id; + } + $keys = ['pagelayout', 'pagetype', 'subpage']; + foreach ($keys as $key) { + if ("{$this->$key}" !== "") { + $data[$key] = $this->$key; + } + } + if ($this->_blockseditingcap !== 'moodle/site:manageblocks') { + $data['bcap'] = $this->_blockseditingcap; + } + if (!empty($this->_othereditingcaps)) { + $data['caps'] = $this->_othereditingcaps; + } + if ($this->_forcelockallblocks) { + $data['forcelock'] = true; + } + $hash = md5(json_encode($data + ['sesskey' => sesskey()])); + $SESSION->editedpages = ($SESSION->editedpages ?? []); + $SESSION->editedpages[$hash] = $data; + return $hash; + } + + /** + * Retrieves a page that is being edited from the session cache + * + * {@see self::get_edited_page_hash()} + * + * @param string $hash + * @param int $strictness + * @return self|null + */ + public static function retrieve_edited_page(string $hash, $strictness = IGNORE_MISSING): ?self { + global $CFG, $SESSION; + $data = $SESSION->editedpages[$hash] ?? null; + if (!$data || !is_array($data) + || $hash !== md5(json_encode($data + ['sesskey' => sesskey()]))) { + // This can happen if the session cache becomes corrupt or the user logged out and back + // in in another window and changed their session. Refreshing the page will generate + // and store the correct page hash. + if ($strictness === MUST_EXIST) { + throw new moodle_exception('editedpagenotfound'); + } + return null; + } + + if (!empty($CFG->moodlepageclass)) { + if (!empty($CFG->moodlepageclassfile)) { + require_once($CFG->moodlepageclassfile); + } + $classname = $CFG->moodlepageclass; + } else { + $classname = self::class; + } + /** @var moodle_page $page */ + $page = new $classname(); + $page->set_context(context::instance_by_id($data['contextid'])); + if (array_key_exists('cmid', $data)) { + [$course, $cm] = get_course_and_cm_from_cmid($data['cmid']); + $page->set_cm($cm, $course); + } else if (array_key_exists('courseid', $data)) { + $page->set_course(get_course($data['courseid'])); + } + $page->set_url(new moodle_url($data['url'])); + $keys = ['pagelayout', 'pagetype', 'subpage']; + foreach ($keys as $key) { + if (array_key_exists($key, $data)) { + $func = "set_{$key}"; + $page->$func($data[$key]); + } + } + if (array_key_exists('bcap', $data)) { + $page->set_blocks_editing_capability($data['bcap']); + } + if (array_key_exists('caps', $data)) { + foreach ($data['caps'] as $cap) { + $page->set_other_editing_capability($cap); + } + } + if (array_key_exists('forcelock', $data)) { + $page->force_lock_all_blocks(); + } + $page->blocks->add_custom_regions_for_pagetype($page->pagetype); + return $page; + } + // Initialisation methods ===================================================== // These set various things up in a default way. diff --git a/lib/templates/add_block_body.mustache b/lib/templates/add_block_body.mustache index f6509511460ce..1d54e64801886 100644 --- a/lib/templates/add_block_body.mustache +++ b/lib/templates/add_block_body.mustache @@ -25,14 +25,20 @@ Example context (json): { - "blocks" : [ { "name": "test", "title": "Test block" } ], + "blocks" : [ + { "name": "test", "title": "Test block" }, + { "name": "html", "title": "Block with form", "blockform": "block_edit_form" } + ], "url" : "?a=b" } }}
{{#blocks}} - {{title}} + {{#blockform}}{{#str}}textellipsis, moodle, {{title}}{{/str}}{{/blockform}}{{^blockform}}{{title}}{{/blockform}} {{/blocks}} {{^blocks}} ').addClass(g).setData("blockregion",t),i=this.get("manager").get("regions"),n=!1,s=!1,r=!1;for(e in i)i[e].match(/(pre|left)/)?n=i[e]:i[e].match(/(post|right)/)&&(s=i[e]);return!1!==n&&!1!==s&&(t===n?(t=a.one("#block-region-"+s))&&(t.insert(o,"before"),r=!0):(t=a.one("#block-region-"+n))&&(t.insert(o,"after"),r=!0)),!1===r&&a.one("body").append(o),this.set("node",o),o},change_block_move_icons:function(o){var t;this.get("node").all("."+l+" a."+n).each(function(e){e.setStyle("cursor","move"),(t=o.get_drag_handle(e.getAttribute("title"),"","icon",!0)).setAttribute("role","menuitem"),e.replace(t)})},get_has_region_class:function(){return"has-region-"+this.get("region")},get_empty_region_class:function(){return"empty-region-"+this.get("region")},get_used_region_class:function(){return"used-region-"+this.get("region")},get_droptarget:function(){var e=this.get("node");return e.test('[data-droptarget="1"]')?e:e.one('[data-droptarget="1"]')},enable:function(){a.one("body").addClass(this.get_used_region_class()).removeClass(this.get_empty_region_class())},disable_if_required:function(){0===this.get("node").all("."+l).size()&&a.one("body").addClass(this.get_empty_region_class()).removeClass(this.get_used_region_class())}},a.extend(d,a.Base,d.prototype,{NAME:"core-blocks-dragdrop-blockregion",ATTRS:{manager:{writeOnce:"initOnly",validator:function(e){return a.Lang.isObject(e)&&e instanceof o}},region:{writeOnce:"initOnly",validator:function(e){return a.Lang.isString(e)}},node:{validator:function(e){return a.Lang.isObject(e)||a.Lang.isNull(e)}},hasblocks:{value:!1,validator:function(e){return a.Lang.isBoolean(e)}}}})},"@VERSION@",{requires:["base","node","io","dom","dd","dd-scroll","moodle-core-dragdrop","moodle-core-notification"]}); \ No newline at end of file +YUI.add("moodle-core-blocks",function(d,e){var o,a,r="/lib/ajax/blocks.php",g="block",l="block-region",s="block_adminblock",n="editing_move",h="header",c="region-content",t="skip-block",p="skip-block-to",_="page-my-index",b="region-main",f="blocks-moving",u={DRAGHANDLE:"."+h+" .commands .moodle-core-dragdrop-draghandle"},i=function(){i.superclass.constructor.apply(this,arguments)};d.extend(i,M.core.dragdrop,{skipnodetop:null,skipnodebottom:null,dragsourceregion:null,initializer:function(){var e,o,t,i;if(this.groups=["block"],this.samenodeclass=g,this.parentnodeclass=c,0<(e=d.Node.all("body#"+_+" #"+b+" > ."+c)).size()&&((e=e.item(0)).addClass(l),e.set("id",c),e.one("div").addClass(c)),0===(e=d.Node.all("div."+l)).size())return!1;e.size()!==this.get("regions").length&&(o=d.Node.create("
").addClass(l),t=d.Node.create("
").addClass(c),o.appendChild(t),t=e.filter("#region-pre"),i=e.filter("#region-post"),0===t.size()&&1===i.size()?(o.setAttrs({id:"region-pre"}),i.item(0).insert(o,"before"),e.unshift(o)):0===i.size()&&1===t.size()&&(o.setAttrs({id:"region-post"}),t.item(0).insert(o,"after"),e.push(o))),e.each(function(e){var o;new d.DD.Drop({node:e.one("div."+c),groups:this.groups,padding:"40 240 40 240"}),(o=new d.DD.Delegate({container:e,nodes:"."+g,target:!0,handles:[u.DRAGHANDLE],invalid:".block-hider-hide, .block-hider-show, .moveto",dragConfig:{groups:this.groups}})).dd.plug(d.Plugin.DDProxy,{moveOnEnd:!1}),o.dd.plug(d.Plugin.DDWinScroll),e.all("."+g).each(function(e){var o=e.one("a."+n);o&&(o.replace(this.get_drag_handle(o.getAttribute("title"),"","iconsmall",!0)),e.one(u.DRAGHANDLE).setStyle("cursor","move"))},this)},this)},get_block_id:function(e){return Number(e.get("id").replace(/inst/i,""))},get_block_region:function(e){e=e.ancestor("div."+l).get("id").replace(/region-/i,"");return-1===d.Array.indexOf(this.get("regions"),e)?(window.right_to_left()&&("post"===e?e="pre":"pre"===e&&(e="post")),"side-"+e):e},get_region_id:function(e){return e.get("id").replace(/region-/i,"")},drag_start:function(e){e=e.target;this.dragsourceregion=e.get("node").ancestor("div."+l),e.get("node").previous()&&e.get("node").previous().hasClass(t)&&(this.skipnodetop=e.get("node").previous()),e.get("node").next()&&e.get("node").next().hasClass(p)&&(this.skipnodebottom=e.get("node").next()),d.one("body").addClass(f)},drop_over:function(e){var o,t=e.drag.get("node"),e=e.drop.get("node");if(e.hasClass(this.parentnodeclass)&&e.one("."+s)&&e.one("."+s).next("."+g)&&e.prepend(t),this.dragsourceregion.contains(e))return!1;t=d.one("body"),o=this.get_region_id(this.dragsourceregion),t.hasClass("side-"+o+"-only")&&t.removeClass("side-"+o+"-only"),o=this.get_region_id(e.ancestor("div."+l)),0===this.dragsourceregion.all("."+g).size()&&this.dragsourceregion.get("id").match(/(region-pre|region-post)/i)&&(t.hasClass("side-"+o+"-only")||t.addClass("side-"+o+"-only"))},drag_end:function(){this.skipnodetop=null,this.skipnodebottom=null,this.dragsourceregion=null,d.one("body").removeClass(f)},drag_dropmiss:function(e){this.drop_hit(e)},drop_hit:function(i){var n,e=i.drag,e=e.get("node"),o=i.drop.get("node");e.previous()&&e.previous().hasClass(t)&&e.insert(e.previous(),"after"),this.skipnodetop&&e.insert(this.skipnodetop,"before"),this.skipnodebottom&&e.insert(this.skipnodebottom,"after"),n=M.util.add_lightbox(d,e),o={sesskey:M.cfg.sesskey,pagehash:this.get("pagehash"),action:"move",bui_moveid:this.get_block_id(e),bui_newregion:this.get_block_region(o)},this.get("cmid")&&(o.cmid=this.get("cmid")),e.next("."+this.samenodeclass)&&!e.next("."+this.samenodeclass).hasClass(s)&&(o.bui_beforeid=this.get_block_id(e.next("."+this.samenodeclass))),d.io(M.cfg.wwwroot+r,{method:"POST",data:o,on:{start:function(){n.show()},success:function(e,o){window.setTimeout(function(){n.hide()},250);try{var t=d.JSON.parse(o.responseText);t.error&&new M.core.ajaxException(t)}catch(i){}},failure:function(e,o){this.ajax_failure(o),n.hide()}},context:this})}},{NAME:"core-blocks-dragdrop",ATTRS:{pagehash:{value:null},regions:{value:null}}}),M.core=M.core||{},M.core.blockdraganddrop=M.core.blockdraganddrop||{},M.core.blockdraganddrop._isusingnewblocksmethod=null,M.core.blockdraganddrop.is_using_blocks_render_method=function(){var e,o;return null===this._isusingnewblocksmethod&&(e=d.all(".block-region[data-blockregion]").size(),o=d.all(".block-region").size(),this._isusingnewblocksmethod=o===e),this._isusingnewblocksmethod},M.core.blockdraganddrop.init=function(e){new(this.is_using_blocks_render_method()?o:i)(e)},M.core_blocks=M.core_blocks||{},M.core_blocks.init_dragdrop=function(e){M.core.blockdraganddrop.init(e)},(o=function(){o.superclass.constructor.apply(this,arguments)}).prototype={skipnodetop:null,skipnodebottom:null,regionobjects:{},initializer:function(){var e,o,t,i,n,s=this.get("regions"),r=0;for(r in this.groups=["block"],this.samenodeclass=g,this.parentnodeclass=l,this.detectkeyboarddirection=!0,0<(n=d.Node.all("body#"+_+" #"+b+" > ."+c)).size()&&((n=n.item(0)).addClass(l),n.set("id",c),n.one("div").addClass(c)),s)i=s[r],t=d.one("#block-region-"+i),o=new a({manager:this,region:i,node:t}),this.regionobjects[i]=o,new d.DD.Drop({node:o.get_droptarget(),groups:this.groups,padding:"40 240 40 240"}),(i=new d.DD.Delegate({container:o.get_droptarget(),nodes:"."+g,target:!0,handles:[u.DRAGHANDLE],invalid:".block-hider-hide, .block-hider-show, .moveto, .block_fake",dragConfig:{groups:this.groups}})).dd.plug(d.Plugin.DDProxy,{moveOnEnd:!1}),null!==t&&(e=t.ancestor(".drag-container",!0))?i.dd.plug(d.Plugin.DDNodeScroll,{node:e}):i.dd.plug(d.Plugin.DDWinScroll),d.DD.DDM.on("ddm:start",this.enable_all_regions,this),o.change_block_move_icons(this)},get_block_id:function(e){return Number(e.get("id").replace(/inst/i,""))},get_block_region:function(e){return(e=e.test("[data-blockregion]")?e:e.ancestor("[data-blockregion]")).getData("blockregion")},get_region_object:function(e){return this.regionobjects[this.get_block_region(e)]}, +enable_all_regions:function(){var e,o=d.DD.DDM.activeDrag.get("groups");if(o&&-1!==d.Array.indexOf(o,"block"))for(e in this.regionobjects)this.regionobjects.hasOwnProperty(e)&&this.regionobjects[e].enable()},disable_regions_if_required:function(){var e=0;for(e in this.regionobjects)this.regionobjects[e].disable_if_required()},drag_start:function(e){e=e.target;e.get("node").previous()&&e.get("node").previous().hasClass(t)&&(this.skipnodetop=e.get("node").previous()),e.get("node").next()&&e.get("node").next().hasClass(p)&&(this.skipnodebottom=e.get("node").next())},dragOver:function(e){var o=e.drop.get("node").ancestor(".drag-container",!0);if(o){if(e.drag[d.Plugin.DDNodeScroll]){if(e.drag[d.Plugin.DDNodeScroll].get("node")===o)return;e.drag.unplug(d.Plugin.DDNodeScroll)}e.drag.plug(d.Plugin.DDNodeScroll,{node:o})}},drop_over:function(e){var o=e.drag.get("node"),e=e.drop.get("node");e.hasClass(c)&&e.one("."+s)&&e.one("."+s).next("."+g)&&e.prepend(o)},drop_end:function(){this.skipnodetop=null,this.skipnodebottom=null,this.disable_regions_if_required()},drag_dropmiss:function(e){this.drop_hit(e)},drop_hit:function(i){var n,e=i.drag.get("node"),o=i.drop.get("node");e.previous()&&e.previous().hasClass(t)&&e.insert(e.previous(),"after"),this.skipnodetop&&e.insert(this.skipnodetop,"before"),this.skipnodebottom&&e.insert(this.skipnodebottom,"after"),n=M.util.add_lightbox(d,e),o={sesskey:M.cfg.sesskey,pagehash:this.get("pagehash"),action:"move",bui_moveid:this.get_block_id(e),bui_newregion:this.get_block_region(o)},this.get("cmid")&&(o.cmid=this.get("cmid")),e.next("."+g)&&!e.next("."+g).hasClass(s)&&(o.bui_beforeid=this.get_block_id(e.next("."+g))),d.io(M.cfg.wwwroot+r,{method:"POST",data:o,on:{start:function(){n.show()},success:function(e,o){window.setTimeout(function(){n.hide()},250);try{var t=d.JSON.parse(o.responseText);t.error&&new M.core.ajaxException(t)}catch(i){}},failure:function(e,o){this.ajax_failure(o),n.hide()},complete:function(){this.disable_regions_if_required()}},context:this})}},d.extend(o,M.core.dragdrop,o.prototype,{NAME:"core-blocks-dragdrop-manager",ATTRS:{pagehash:{value:null},regions:{value:[]}}}),(a=function(){a.superclass.constructor.apply(this,arguments)}).prototype={initializer:function(){var e=this.get("node"),e=e||this.create_and_add_node(),o=d.one("body"),e=0
').addClass(l).setData("blockregion",t),i=this.get("manager").get("regions"),n=!1,s=!1,r=!1;for(e in i)i[e].match(/(pre|left)/)?n=i[e]:i[e].match(/(post|right)/)&&(s=i[e]);return!1!==n&&!1!==s&&(t===n?(t=d.one("#block-region-"+s))&&(t.insert(o,"before"),r=!0):(t=d.one("#block-region-"+n))&&(t.insert(o,"after"),r=!0)),!1===r&&d.one("body").append(o),this.set("node",o),o},change_block_move_icons:function(o){var t;this.get("node").all("."+g+" a."+n).each(function(e){e.setStyle("cursor","move"),(t=o.get_drag_handle(e.getAttribute("title"),"","icon",!0)).setAttribute("role","menuitem"),e.replace(t)})},get_has_region_class:function(){return"has-region-"+this.get("region")},get_empty_region_class:function(){return"empty-region-"+this.get("region")},get_used_region_class:function(){return"used-region-"+this.get("region")},get_droptarget:function(){var e=this.get("node");return e.test('[data-droptarget="1"]')?e:e.one('[data-droptarget="1"]')},enable:function(){d.one("body").addClass(this.get_used_region_class()).removeClass(this.get_empty_region_class())},disable_if_required:function(){0===this.get("node").all("."+g).size()&&d.one("body").addClass(this.get_empty_region_class()).removeClass(this.get_used_region_class())}},d.extend(a,d.Base,a.prototype,{NAME:"core-blocks-dragdrop-blockregion",ATTRS:{manager:{writeOnce:"initOnly",validator:function(e){return d.Lang.isObject(e)&&e instanceof o}},region:{writeOnce:"initOnly",validator:function(e){return d.Lang.isString(e)}},node:{validator:function(e){return d.Lang.isObject(e)||d.Lang.isNull(e)}},hasblocks:{value:!1,validator:function(e){return d.Lang.isBoolean(e)}}}})},"@VERSION@",{requires:["base","node","io","dom","dd","dd-scroll","moodle-core-dragdrop","moodle-core-notification"]}); \ No newline at end of file diff --git a/lib/yui/build/moodle-core-blocks/moodle-core-blocks.js b/lib/yui/build/moodle-core-blocks/moodle-core-blocks.js index b3e1074614287..aec59a0747741 100644 --- a/lib/yui/build/moodle-core-blocks/moodle-core-blocks.js +++ b/lib/yui/build/moodle-core-blocks/moodle-core-blocks.js @@ -261,11 +261,7 @@ Y.extend(DRAGBLOCK, M.core.dragdrop, { // Prepare request parameters var params = { sesskey: M.cfg.sesskey, - courseid: this.get('courseid'), - pagelayout: this.get('pagelayout'), - pagetype: this.get('pagetype'), - subpage: this.get('subpage'), - contextid: this.get('contextid'), + pagehash: this.get('pagehash'), action: 'move', bui_moveid: this.get_block_id(dragnode), bui_newregion: this.get_block_region(dropnode) @@ -311,22 +307,7 @@ Y.extend(DRAGBLOCK, M.core.dragdrop, { }, { NAME: 'core-blocks-dragdrop', ATTRS: { - courseid: { - value: null - }, - cmid: { - value: null - }, - contextid: { - value: null - }, - pagelayout: { - value: null - }, - pagetype: { - value: null - }, - subpage: { + pagehash: { value: null }, regions: { @@ -701,11 +682,7 @@ MANAGER.prototype = { // Prepare request parameters var params = { sesskey: M.cfg.sesskey, - courseid: this.get('courseid'), - pagelayout: this.get('pagelayout'), - pagetype: this.get('pagetype'), - subpage: this.get('subpage'), - contextid: this.get('contextid'), + pagehash: this.get('pagehash'), action: 'move', bui_moveid: this.get_block_id(dragnode), bui_newregion: this.get_block_region(dropnode) @@ -756,62 +733,12 @@ Y.extend(MANAGER, M.core.dragdrop, MANAGER.prototype, { NAME: 'core-blocks-dragdrop-manager', ATTRS: { /** - * The Course ID if there is one. - * @attribute courseid - * @type int|null - * @default null - */ - courseid: { - value: null - }, - - /** - * The Course Module ID if there is one. - * @attribute cmid - * @type int|null - * @default null - */ - cmid: { - value: null - }, - - /** - * The Context ID. - * @attribute contextid - * @type int|null - * @default null - */ - contextid: { - value: null - }, - - /** - * The current page layout. - * @attribute pagelayout - * @type string|null - * @default null - */ - pagelayout: { - value: null - }, - - /** - * The page type string, should be used as the id for the body tag in the theme. - * @attribute pagetype - * @type string|null - * @default null - */ - pagetype: { - value: null - }, - - /** - * The subpage identifier, if any. - * @attribute subpage + * The page identifier. + * @attribute pagehash * @type string|null * @default null */ - subpage: { + pagehash: { value: null }, diff --git a/lib/yui/src/blocks/js/blocks.js b/lib/yui/src/blocks/js/blocks.js index 11c211430dff2..25a63f2329a88 100644 --- a/lib/yui/src/blocks/js/blocks.js +++ b/lib/yui/src/blocks/js/blocks.js @@ -256,11 +256,7 @@ Y.extend(DRAGBLOCK, M.core.dragdrop, { // Prepare request parameters var params = { sesskey: M.cfg.sesskey, - courseid: this.get('courseid'), - pagelayout: this.get('pagelayout'), - pagetype: this.get('pagetype'), - subpage: this.get('subpage'), - contextid: this.get('contextid'), + pagehash: this.get('pagehash'), action: 'move', bui_moveid: this.get_block_id(dragnode), bui_newregion: this.get_block_region(dropnode) @@ -306,22 +302,7 @@ Y.extend(DRAGBLOCK, M.core.dragdrop, { }, { NAME: 'core-blocks-dragdrop', ATTRS: { - courseid: { - value: null - }, - cmid: { - value: null - }, - contextid: { - value: null - }, - pagelayout: { - value: null - }, - pagetype: { - value: null - }, - subpage: { + pagehash: { value: null }, regions: { diff --git a/lib/yui/src/blocks/js/manager.js b/lib/yui/src/blocks/js/manager.js index f4cff7caa0b99..3a50b61afbc33 100644 --- a/lib/yui/src/blocks/js/manager.js +++ b/lib/yui/src/blocks/js/manager.js @@ -313,11 +313,7 @@ MANAGER.prototype = { // Prepare request parameters var params = { sesskey: M.cfg.sesskey, - courseid: this.get('courseid'), - pagelayout: this.get('pagelayout'), - pagetype: this.get('pagetype'), - subpage: this.get('subpage'), - contextid: this.get('contextid'), + pagehash: this.get('pagehash'), action: 'move', bui_moveid: this.get_block_id(dragnode), bui_newregion: this.get_block_region(dropnode) @@ -368,62 +364,12 @@ Y.extend(MANAGER, M.core.dragdrop, MANAGER.prototype, { NAME: 'core-blocks-dragdrop-manager', ATTRS: { /** - * The Course ID if there is one. - * @attribute courseid - * @type int|null - * @default null - */ - courseid: { - value: null - }, - - /** - * The Course Module ID if there is one. - * @attribute cmid - * @type int|null - * @default null - */ - cmid: { - value: null - }, - - /** - * The Context ID. - * @attribute contextid - * @type int|null - * @default null - */ - contextid: { - value: null - }, - - /** - * The current page layout. - * @attribute pagelayout - * @type string|null - * @default null - */ - pagelayout: { - value: null - }, - - /** - * The page type string, should be used as the id for the body tag in the theme. - * @attribute pagetype - * @type string|null - * @default null - */ - pagetype: { - value: null - }, - - /** - * The subpage identifier, if any. - * @attribute subpage + * The page identifier. + * @attribute pagehash * @type string|null * @default null */ - subpage: { + pagehash: { value: null }, diff --git a/my/tests/behat/my_courses.feature b/my/tests/behat/my_courses.feature index 5bae4d42c7b81..ef10341f7b109 100644 --- a/my/tests/behat/my_courses.feature +++ b/my/tests/behat/my_courses.feature @@ -92,14 +92,14 @@ Feature: Run tests over my courses. Given I log in as "admin" And I am on site homepage And I turn editing mode on - And I add the "Text" block - And I configure the "(new text block)" block - And I set the following fields to these values: - | Page contexts | Display throughout the entire site | + And I add the "Text" block to the default region with: | Text block title | Text on all pages | | Content | This is visible on all pages | + And I configure the "Text on all pages" block + And I set the following fields to these values: + | Page contexts | Display throughout the entire site | | Default region | Right | - And I press "Save changes" + And I click on "Save changes" "button" in the "Configure Text on all pages block" "dialogue" And I should see "This is visible on all pages" And "Move Text on all pages block" "menuitem" should exist in the "Text on all pages" "block" When I am on the "My courses" page diff --git a/theme/boost/tests/behat/mycoursesblocks.feature b/theme/boost/tests/behat/mycoursesblocks.feature index 6868cafb28ceb..b0f9adf9abb12 100644 --- a/theme/boost/tests/behat/mycoursesblocks.feature +++ b/theme/boost/tests/behat/mycoursesblocks.feature @@ -11,14 +11,14 @@ Feature: My courses page block layout in Boost theme And I log in as "admin" And I am on site homepage And I turn editing mode on - And I add the "Text" block - And I configure the "(new text block)" block - And I set the following fields to these values: - | Page contexts | Display throughout the entire site | + And I add the "Text" block to the default region with: | Text block title | Text on all pages | | Content | This is visible on all pages | + And I configure the "Text on all pages" block + And I set the following fields to these values: + | Page contexts | Display throughout the entire site | | Default region | Right | - And I press "Save changes" + And I click on "Save changes" "button" in the "Configure Text on all pages block" "dialogue" Scenario: Student can see relevant blocks with correct placement on my courses page When I log in as "student1" diff --git a/theme/classic/tests/behat/behat_theme_classic_behat_blocks.php b/theme/classic/tests/behat/behat_theme_classic_behat_blocks.php index 08a8543d71080..ecc95167f2a0d 100644 --- a/theme/classic/tests/behat/behat_theme_classic_behat_blocks.php +++ b/theme/classic/tests/behat/behat_theme_classic_behat_blocks.php @@ -1,4 +1,5 @@ execute('behat_blocks::i_add_the_block', [$blockname]); + } + + /** + * Adds the selected block to the specified region and fills configuration form. + * + * Editing mode must be previously enabled. + * + * @param string $blockname + * @param string $region + * @param TableNode $data + */ + public function i_add_the_block_to_the_region_with(string $blockname, string $region, TableNode $data) { + $this->execute('behat_blocks::i_add_the_block_to_the_region', [$blockname, $region]); + $this->wait_for_pending_js(); + $blocktitle = $blockname === 'Text' ? '(new text block)' : $blockname; + $this->execute('behat_blocks::i_configure_the_block', [$blocktitle]); + $dialogname = get_string('configureblock', 'core_block', $blocktitle); + $this->execute('behat_forms::i_set_the_following_fields_in_container_to_these_values', + [$dialogname, "dialogue", $data]); + $this->execute('behat_general::i_click_on_in_the', ["Save changes", 'button', $dialogname, 'dialogue']); + } + /** * Ensures that block can be added to the page, but does not add it. *