Merge branch 'MDL-40975-master' of git://github.com/andrewnicols/moodle

Conflicts:
	theme/bootstrapbase/style/moodle.css
This commit is contained in:
Damyon Wiese
2013-11-06 13:06:01 +08:00
57 changed files with 1387 additions and 386 deletions
@@ -21,14 +21,18 @@ Feature: Duplicate activities
And I add a "Database" to section "1" and I fill the form with:
| Name | Test database name |
| Description | Test database description |
And I click on "Actions" "link" in the "Test database name" activity
And I open "Test database name" actions menu
When I click on "Duplicate" "link" in the "Test database name" activity
And I press "Continue"
And I press "Edit the new copy"
And I click on "Edit settings" "link" in the "Test database name" activity
And I fill the moodle form with:
| Name | Original database name |
And I press "Save and return to course"
And I open "Test database name" actions menu
And I click on "Edit settings" "link" in the "Test database name" activity
And I fill the moodle form with:
| Name | Duplicated database name |
| Description | Duplicated database description |
And I press "Save and return to course"
Then I should see "Test database name" in the "#section-1" "css_element"
Then I should see "Original database name" in the "#section-1" "css_element"
And I should see "Duplicated database name" in the "#section-1" "css_element"
And "Test database name" "link" should appear before "Duplicated database name" "link"
And "Original database name" "link" should appear before "Duplicated database name" "link"
@@ -40,7 +40,7 @@ Feature: Restore Moodle 2 course backups
Then I should see "Course 1 restored in a new course"
And I should see "Community finder" in the "Community finder" "block"
And I should see "Test forum name"
And I follow "Edit settings"
And I click on "Edit settings" "link" in the "Administration" "block"
And I expand all fieldsets
And the "id_format" field should match "Topics format" value
And the "Number of sections" field should match "15" value
@@ -85,7 +85,7 @@ Feature: Restore Moodle 2 course backups
When I restore "test_backup.mbz" backup into a new course using this options:
Then I should see "Topic 1"
And I should see "Test forum name"
And I follow "Edit settings"
And I click on "Edit settings" "link" in the "Administration" "block"
And I expand all fieldsets
And the "id_format" field should match "Topics format" value
And I fill the moodle form with:
@@ -96,14 +96,14 @@ Feature: Restore Moodle 2 course backups
And I press "Save changes"
And I should see "1 January - 7 January"
And I should see "Test forum name"
And I follow "Edit settings"
And I click on "Edit settings" "link" in the "Administration" "block"
And I expand all fieldsets
And the "id_format" field should match "Weekly format" value
And I fill the moodle form with:
| id_format | Social format |
And I press "Save changes"
And I should see "An open forum for chatting about anything you want to"
And I follow "Edit settings"
And I click on "Edit settings" "link" in the "Administration" "block"
And I expand all fieldsets
And the "id_format" field should match "Social format" value
And I press "Cancel"
@@ -120,7 +120,7 @@ Feature: Restore Moodle 2 course backups
| Filename | test_backup.mbz |
And I restore "test_backup.mbz" backup into "Course 2" course using this options:
| Overwrite course configuration | Yes |
And I follow "Edit settings"
And I click on "Edit settings" "link" in the "Administration" "block"
And I expand all fieldsets
Then the "id_format" field should match "Topics format" value
And the "Number of sections" field should match "15" value
@@ -18,6 +18,7 @@ Feature: Add and configure blocks throughout the site
And I log in as "manager1"
And I follow "Turn editing on"
And I add the "Comments" block
And I click on "Actions" "link" in the "Comments" "block"
And I follow "Configure Comments block"
And I fill the moodle form with:
| Page contexts | Display throughout the entire site |
@@ -26,6 +27,7 @@ Feature: Add and configure blocks throughout the site
Then I should see "Comments" in the "Comments" "block"
And I should see "Save comment" in the "Comments" "block"
And I am on homepage
And I click on "Actions" "link" in the "Comments" "block"
And I follow "Configure Comments block"
And I fill the moodle form with:
| Default weight | -10 (first) |
@@ -15,6 +15,7 @@ Feature: The context of a block can always be returned to it's original state.
And I add the "Tags" block
Then I should see "Tags" in the "Tags" "block"
And I click on "Participants" "link" in the "//li[p/span[contains(normalize-space(string(.)), 'Current course')]]" "xpath_element"
And I click on "Actions" "link" in the "Tags" "block"
And I follow "Configure Tags block"
And I fill the moodle form with:
| Display on page types | Any page |
@@ -24,6 +25,7 @@ Feature: The context of a block can always be returned to it's original state.
| Assignment name | Assignment1 |
| Description | Description |
And I follow "Assignment1"
And I click on "Actions" "link" in the "Tags" "block"
And I follow "Configure Tags block"
And I fill the moodle form with:
| Display on page types | Any assignment module page |
@@ -39,6 +41,7 @@ Feature: The context of a block can always be returned to it's original state.
| Description | Description |
And I follow "Assignment2"
And I should see "Tags" in the "Tags" "block"
And I click on "Actions" "link" in the "Tags" "block"
And I follow "Configure Tags block"
And I fill the moodle form with:
| Display on page types | Any page |
@@ -25,7 +25,7 @@ Feature: Allow students to manually mark an activity as complete
And I log in as "teacher1"
And I follow "Course 1"
And I turn editing mode on
And I follow "Edit settings"
And I click on "Edit settings" "link" in the "Administration" "block"
And I fill the moodle form with:
| Enable completion tracking | Yes |
And I press "Save changes"
@@ -27,7 +27,7 @@ Feature: Restrict sections availability through completion or grade conditions
Given I log in as "teacher1"
And I follow "Course 1"
And I turn editing mode on
And I follow "Edit settings"
And I click on "Edit settings" "link" in the "Administration" "block"
And I fill the moodle form with:
| Enable completion tracking | Yes |
And I press "Save changes"
@@ -93,4 +93,4 @@ Feature: Restrict sections availability through completion or grade conditions
And I log in as "student1"
And I follow "Course 1"
And "Test page name" activity should be visible
And I should not see "Not available until you achieve a required score in Grade assignment"
And I should not see "Not available until you achieve a required score in Grade assignment"
+3 -4
View File
@@ -611,8 +611,7 @@ class core_course_management_renderer extends plugin_renderer_base {
new action_menu_link_secondary($shortnameurl, null, get_string('resortbyshortname')),
new action_menu_link_secondary($idnumberurl, null, get_string('resortbyidnumber'))
));
$menu->actiontext = get_string('resortcourses');
$menu->actionicon = new pix_icon('t/contextmenu', ' ', 'moodle', array('class' => 'iconsmall', 'title' => ''));
$menu->set_menu_trigger(get_string('resortcourses'));
$actions[] = $this->render($menu);
}
$strall = get_string('all');
@@ -628,7 +627,7 @@ class core_course_management_renderer extends plugin_renderer_base {
$perpage = $strall;
}
$menu->attributes['class'] .= ' courses-per-page';
$menu->actiontext = get_string('perpagea', 'moodle', $perpage);
$menu->set_menu_trigger(get_string('perpagea', 'moodle', $perpage));
$actions[] = $this->render($menu);
return html_writer::div(join(' | ', $actions), 'listing-actions course-listing-actions');
}
@@ -922,7 +921,7 @@ class core_course_management_renderer extends plugin_renderer_base {
$menu->add(new action_menu_link_secondary($modeurl, null, $modestr, $attributes));
}
$menu->actiontext = get_string('viewing', 'moodle', $selected);
$menu->set_menu_trigger(get_string('viewing', 'moodle', $selected));
$html = html_writer::start_div('view-mode-selector vms');
$html .= $this->render($menu);
+273 -97
View File
@@ -1949,14 +1949,11 @@ function course_get_cm_edit_actions(cm_info $mod, $indent = -1, $sr = null) {
if (!isset($str)) {
$str = get_strings(array('delete', 'move', 'moveright', 'moveleft',
'update', 'duplicate', 'hide', 'show', 'edittitle'), 'moodle');
'editsettings', 'duplicate', 'hide', 'show'), 'moodle');
$str->assign = get_string('assignroles', 'role');
$str->groupsnone = get_string('clicktochangeinbrackets', 'moodle', get_string("groupsnone"));
$str->groupsseparate = get_string('clicktochangeinbrackets', 'moodle', get_string("groupsseparate"));
$str->groupsvisible = get_string('clicktochangeinbrackets', 'moodle', get_string("groupsvisible"));
$str->forcedgroupsnone = get_string('forcedmodeinbrackets', 'moodle', get_string("groupsnone"));
$str->forcedgroupsseparate = get_string('forcedmodeinbrackets', 'moodle', get_string("groupsseparate"));
$str->forcedgroupsvisible = get_string('forcedmodeinbrackets', 'moodle', get_string("groupsvisible"));
}
$baseurl = new moodle_url('/course/mod.php', array('sesskey' => sesskey()));
@@ -1966,21 +1963,21 @@ function course_get_cm_edit_actions(cm_info $mod, $indent = -1, $sr = null) {
}
$actions = array();
// AJAX edit title.
if ($mod->has_view() && $hasmanageactivities &&
(($mod->course == $COURSE->id && course_ajax_enabled($COURSE)) ||
($mod->course == SITEID && course_ajax_enabled($SITE)))) {
// we will not display link if we are on some other-course page (where we should not see this module anyway)
$actions['title'] = new action_menu_link_secondary(
// Update.
if ($hasmanageactivities) {
$actions['update'] = new action_menu_link_secondary(
new moodle_url($baseurl, array('update' => $mod->id)),
new pix_icon('t/editstring', $str->edittitle, 'moodle', array('class' => 'iconsmall visibleifjs', 'title' => '')),
$str->edittitle,
array('class' => 'editing_title', 'data-action' => 'edittitle')
new pix_icon('t/edit', $str->editsettings, 'moodle', array('class' => 'iconsmall', 'title' => '')),
$str->editsettings,
array('class' => 'editing_update', 'data-action' => 'update')
);
}
// Indent.
if ($hasmanageactivities) {
$indentlimits = new stdClass();
$indentlimits->min = 0;
$indentlimits->max = 16;
if (right_to_left()) { // Exchange arrows on RTL
$rightarrow = 't/left';
$leftarrow = 't/right';
@@ -1989,46 +1986,49 @@ function course_get_cm_edit_actions(cm_info $mod, $indent = -1, $sr = null) {
$leftarrow = 't/left';
}
$hiddenclass = 'hidden';
if ($indent > 0) {
$hiddenclass = '';
}
$actions['moveleft'] = new action_menu_link_secondary(
new moodle_url($baseurl, array('id' => $mod->id, 'indent' => '-1')),
new pix_icon($leftarrow, $str->moveleft, 'moodle', array('class' => 'iconsmall', 'title' => '')),
$str->moveleft,
array('class' => 'editing_moveleft ' . $hiddenclass, 'data-action' => 'moveleft')
);
$hiddenclass = 'hidden';
if ($indent >= 0) {
$hiddenclass = '';
if ($indent >= $indentlimits->max) {
$enabledclass = 'hidden';
} else {
$enabledclass = '';
}
$actions['moveright'] = new action_menu_link_secondary(
new moodle_url($baseurl, array('id' => $mod->id, 'indent' => '1')),
new pix_icon($rightarrow, $str->moveright, 'moodle', array('class' => 'iconsmall', 'title' => '')),
$str->moveright,
array('class' => 'editing_moveright ' . $hiddenclass, 'data-action' => 'moveright')
array('class' => 'editing_moveright ' . $enabledclass, 'data-action' => 'moveright')
);
if ($indent <= $indentlimits->min) {
$enabledclass = 'hidden';
} else {
$enabledclass = '';
}
$actions['moveleft'] = new action_menu_link_secondary(
new moodle_url($baseurl, array('id' => $mod->id, 'indent' => '-1')),
new pix_icon($leftarrow, $str->moveleft, 'moodle', array('class' => 'iconsmall', 'title' => '')),
$str->moveleft,
array('class' => 'editing_moveleft ' . $enabledclass, 'data-action' => 'moveleft')
);
}
// Move.
if ($hasmanageactivities) {
$actions['move'] = new action_menu_link_primary(
new moodle_url($baseurl, array('copy' => $mod->id)),
new pix_icon('t/move', $str->move, 'moodle', array('class' => 'iconsmall', 'title' => '')),
$str->move,
array('class' => 'editing_move status', 'data-action' => 'move')
);
}
// Update.
if ($hasmanageactivities) {
$actions['update'] = new action_menu_link_secondary(
new moodle_url($baseurl, array('update' => $mod->id)),
new pix_icon('t/edit', $str->update, 'moodle', array('class' => 'iconsmall', 'title' => '')),
$str->update,
array('class' => 'editing_update', 'data-action' => 'update')
);
// Hide/Show.
if (has_capability('moodle/course:activityvisibility', $modcontext)) {
if ($mod->visible) {
$actions['hide'] = new action_menu_link_secondary(
new moodle_url($baseurl, array('hide' => $mod->id)),
new pix_icon('t/hide', $str->hide, 'moodle', array('class' => 'iconsmall', 'title' => '')),
$str->hide,
array('class' => 'editing_hide', 'data-action' => 'hide')
);
} else {
$actions['show'] = new action_menu_link_secondary(
new moodle_url($baseurl, array('show' => $mod->id)),
new pix_icon('t/show', $str->show, 'moodle', array('class' => 'iconsmall', 'title' => '')),
$str->show,
array('class' => 'editing_show', 'data-action' => 'show')
);
}
}
// Duplicate (require both target import caps to be able to duplicate and backup2 support, see modduplicate.php)
@@ -2039,61 +2039,30 @@ function course_get_cm_edit_actions(cm_info $mod, $indent = -1, $sr = null) {
new moodle_url($baseurl, array('duplicate' => $mod->id)),
new pix_icon('t/copy', $str->duplicate, 'moodle', array('class' => 'iconsmall', 'title' => '')),
$str->duplicate,
array('class' => 'editing_duplicate', 'data-action' => 'duplicate')
array('class' => 'editing_duplicate', 'data-action' => 'duplicate', 'data-sr' => $sr)
);
}
// Delete.
if ($hasmanageactivities) {
$actions['delete'] = new action_menu_link_secondary(
new moodle_url($baseurl, array('delete' => $mod->id)),
new pix_icon('t/delete', $str->delete, 'moodle', array('class' => 'iconsmall', 'title' => '')),
$str->delete,
array('class' => 'editing_delete', 'data-action' => 'delete')
);
}
// Hide/Show.
if (has_capability('moodle/course:activityvisibility', $modcontext)) {
if ($mod->visible) {
$actions['hide'] = new action_menu_link_primary(
new moodle_url($baseurl, array('hide' => $mod->id)),
new pix_icon('t/hide', $str->hide, 'moodle', array('class' => 'iconsmall', 'title' => '')),
$str->hide,
array('class' => 'editing_hide', 'data-action' => 'hide')
);
} else {
$actions['show'] = new action_menu_link_primary(
new moodle_url($baseurl, array('show' => $mod->id)),
new pix_icon('t/show', $str->show, 'moodle', array('class' => 'iconsmall', 'title' => '')),
$str->show,
array('class' => 'editing_show', 'data-action' => 'show')
);
}
}
// Groupmode.
if ($hasmanageactivities and plugin_supports('mod', $mod->modname, FEATURE_GROUPS, 0)) {
if ($mod->effectivegroupmode == SEPARATEGROUPS) {
$nextgroupmode = VISIBLEGROUPS;
$grouptitle = $str->groupsseparate;
$forcedgrouptitle = $str->forcedgroupsseparate;
$actionname = 'groupsseparate';
$groupimage = 't/groups';
} else if ($mod->effectivegroupmode == VISIBLEGROUPS) {
$nextgroupmode = NOGROUPS;
$grouptitle = $str->groupsvisible;
$forcedgrouptitle = $str->forcedgroupsvisible;
$actionname = 'groupsvisible';
$groupimage = 't/groupv';
} else {
$nextgroupmode = SEPARATEGROUPS;
$grouptitle = $str->groupsnone;
$forcedgrouptitle = $str->forcedgroupsnone;
$actionname = 'groupsnone';
$groupimage = 't/groupn';
}
if (!$mod->coursegroupmodeforce) {
if ($hasmanageactivities && !$mod->coursegroupmodeforce) {
if (plugin_supports('mod', $mod->modname, FEATURE_GROUPS, 0)) {
if ($mod->effectivegroupmode == SEPARATEGROUPS) {
$nextgroupmode = VISIBLEGROUPS;
$grouptitle = $str->groupsseparate;
$actionname = 'groupsseparate';
$groupimage = 'i/groups';
} else if ($mod->effectivegroupmode == VISIBLEGROUPS) {
$nextgroupmode = NOGROUPS;
$grouptitle = $str->groupsvisible;
$actionname = 'groupsvisible';
$groupimage = 'i/groupv';
} else {
$nextgroupmode = SEPARATEGROUPS;
$grouptitle = $str->groupsnone;
$actionname = 'groupsnone';
$groupimage = 'i/groupn';
}
$actions[$actionname] = new action_menu_link_primary(
new moodle_url($baseurl, array('id' => $mod->id, 'groupmode' => $nextgroupmode)),
new pix_icon($groupimage, $grouptitle, 'moodle', array('class' => 'iconsmall', 'title' => '')),
@@ -2101,7 +2070,7 @@ function course_get_cm_edit_actions(cm_info $mod, $indent = -1, $sr = null) {
array('class' => 'editing_'. $actionname, 'data-action' => $actionname, 'data-nextgroupmode' => $nextgroupmode)
);
} else {
$actions[$actionname] = new pix_icon($groupimage, $forcedgrouptitle, 'moodle', array('class' => 'iconsmall'));
$actions['nogroupsupport'] = new action_menu_filler();
}
}
@@ -2115,9 +2084,111 @@ function course_get_cm_edit_actions(cm_info $mod, $indent = -1, $sr = null) {
);
}
// Delete.
if ($hasmanageactivities) {
$actions['delete'] = new action_menu_link_secondary(
new moodle_url($baseurl, array('delete' => $mod->id)),
new pix_icon('t/delete', $str->delete, 'moodle', array('class' => 'iconsmall', 'title' => '')),
$str->delete,
array('class' => 'editing_delete', 'data-action' => 'delete')
);
}
return $actions;
}
/**
* Returns the rename action.
*
* @param cm_info $mod The module to produce editing buttons for
* @param int $sr The section to link back to (used for creating the links)
* @return The markup for the rename action, or an empty string if not available.
*/
function course_get_cm_rename_action(cm_info $mod, $sr = null) {
global $COURSE, $OUTPUT;
static $str;
static $baseurl;
$modcontext = context_module::instance($mod->id);
$hasmanageactivities = has_capability('moodle/course:manageactivities', $modcontext);
if (!isset($str)) {
$str = get_strings(array('edittitle'));
}
if (!isset($baseurl)) {
$baseurl = new moodle_url('/course/mod.php', array('sesskey' => sesskey()));
}
if ($sr !== null) {
$baseurl->param('sr', $sr);
}
// AJAX edit title.
if ($mod->has_view() && $hasmanageactivities && course_ajax_enabled($COURSE) &&
(($mod->course == $COURSE->id) || ($mod->course == SITEID))) {
// we will not display link if we are on some other-course page (where we should not see this module anyway)
return html_writer::span(
html_writer::link(
new moodle_url($baseurl, array('update' => $mod->id)),
$OUTPUT->pix_icon('t/editstring', '', 'moodle', array('class' => 'iconsmall visibleifjs', 'title' => '')),
array(
'class' => 'editing_title',
'data-action' => 'edittitle',
'title' => $str->edittitle,
)
)
);
}
return '';
}
/**
* Returns the move action.
*
* @param cm_info $mod The module to produce a move button for
* @param int $sr The section to link back to (used for creating the links)
* @return The markup for the move action, or an empty string if not available.
*/
function course_get_cm_move(cm_info $mod, $sr = null) {
global $OUTPUT;
static $str;
static $baseurl;
$modcontext = context_module::instance($mod->id);
$hasmanageactivities = has_capability('moodle/course:manageactivities', $modcontext);
if (!isset($str)) {
$str = get_strings(array('move'));
}
if (!isset($baseurl)) {
$baseurl = new moodle_url('/course/mod.php', array('sesskey' => sesskey()));
if ($sr !== null) {
$baseurl->param('sr', $sr);
}
}
if ($hasmanageactivities) {
$pixicon = 'i/dragdrop';
if ($mod->course == SITEID) {
// Override for course frontpage until we get drag/drop working there.
$pixicon = 't/move';
}
return html_writer::link(
new moodle_url($baseurl, array('copy' => $mod->id)),
$OUTPUT->pix_icon($pixicon, $str->move, 'moodle', array('class' => 'iconsmall', 'title' => '')),
array('class' => 'editing_move', 'data-action' => 'move')
);
}
return '';
}
/**
* given a course object with shortname & fullname, this function will
* truncate the the number of chars allowed and add ... if it was too long
@@ -3309,6 +3380,111 @@ function update_module($moduleinfo) {
return $moduleinfo;
}
/**
* Duplicate a module on the course.
*
* @param object $course The course
* @param object $cm The course module to duplicate
* @throws moodle_exception if the plugin doesn't support duplication
* @return Object containing:
* - fullcontent: The HTML markup for the created CM
* - cmid: The CMID of the newly created CM
* - redirect: Whether to trigger a redirect following this change
*/
function mod_duplicate_activity($course, $cm, $sr = null) {
global $CFG, $USER, $PAGE, $DB;
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
require_once($CFG->libdir . '/filelib.php');
$a = new stdClass();
$a->modtype = get_string('modulename', $cm->modname);
$a->modname = format_string($cm->name);
if (!plugin_supports('mod', $cm->modname, FEATURE_BACKUP_MOODLE2)) {
throw new moodle_exception('duplicatenosupport', 'error');
}
// backup the activity
$bc = new backup_controller(backup::TYPE_1ACTIVITY, $cm->id, backup::FORMAT_MOODLE,
backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id);
$backupid = $bc->get_backupid();
$backupbasepath = $bc->get_plan()->get_basepath();
$bc->execute_plan();
$bc->destroy();
// restore the backup immediately
$rc = new restore_controller($backupid, $course->id,
backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id, backup::TARGET_CURRENT_ADDING);
$cmcontext = context_module::instance($cm->id);
if (!$rc->execute_precheck()) {
$precheckresults = $rc->get_precheck_results();
if (is_array($precheckresults) && !empty($precheckresults['errors'])) {
if (empty($CFG->keeptempdirectoriesonbackup)) {
fulldelete($backupbasepath);
}
}
}
$rc->execute_plan();
// now a bit hacky part follows - we try to get the cmid of the newly
// restored copy of the module
$newcmid = null;
$tasks = $rc->get_plan()->get_tasks();
foreach ($tasks as $task) {
error_log("Looking at a task");
if (is_subclass_of($task, 'restore_activity_task')) {
error_log("Looking at a restore_activity_task task");
if ($task->get_old_contextid() == $cmcontext->id) {
error_log("Contexts match");
$newcmid = $task->get_moduleid();
break;
}
}
}
// if we know the cmid of the new course module, let us move it
// right below the original one. otherwise it will stay at the
// end of the section
if ($newcmid) {
$info = get_fast_modinfo($course);
$newcm = $info->get_cm($newcmid);
$section = $DB->get_record('course_sections', array('id' => $cm->section, 'course' => $cm->course));
moveto_module($newcm, $section, $cm);
moveto_module($cm, $section, $newcm);
}
rebuild_course_cache($cm->course);
$rc->destroy();
if (empty($CFG->keeptempdirectoriesonbackup)) {
fulldelete($backupbasepath);
}
$resp = new stdClass();
if ($newcm) {
$courserenderer = $PAGE->get_renderer('core', 'course');
$completioninfo = new completion_info($course);
$modulehtml = $courserenderer->course_section_cm($course, $completioninfo,
$newcm, null, array());
$resp->fullcontent = $courserenderer->course_section_cm_list_item($course, $completioninfo, $newcm, $sr);
$resp->cmid = $newcm->id;
} else {
// Trigger a redirect
$resp->redirect = true;
}
return $resp;
}
/**
* Compare two objects to find out their correct order based on timestamp (to be used by usort).
* Sorts by descending order of time.
+66 -7
View File
@@ -364,9 +364,37 @@ class core_course_renderer extends plugin_renderer_base {
$menu = new action_menu();
$menu->set_owner_selector($ownerselector);
$menu->set_constraint($constraint);
$menu->set_alignment(action_menu::TL, action_menu::TR);
$menu->set_alignment(action_menu::TR, action_menu::BR);
$menu->set_menu_trigger(get_string('edit'));
if (isset($CFG->modeditingmenu) && !$CFG->modeditingmenu || !empty($displayoptions['donotenhance'])) {
$menu->do_not_enhance();
// Swap the left/right icons.
// Normally we have have right, then left but this does not
// make sense when modactionmenu is disabled.
$moveright = null;
$_actions = array();
foreach ($actions as $key => $value) {
if ($key === 'moveright') {
// Save moveright for later.
$moveright = $value;
} else if ($moveright) {
// This assumes that the order was moveright, moveleft.
// If we have a moveright, then we should place it immediately after the current value.
$_actions[$key] = $value;
$_actions['moveright'] = $moveright;
// Clear the value to prevent it being used multiple times.
$moveright = null;
} else {
$_actions[$key] = $value;
}
}
$actions = $_actions;
unset($_actions);
}
foreach ($actions as $action) {
if ($action instanceof action_menu_link) {
@@ -375,6 +403,10 @@ class core_course_renderer extends plugin_renderer_base {
$menu->add($action);
}
$menu->attributes['class'] .= ' section-cm-edit-actions commands';
// Prioritise the menu ahead of all other actions.
$menu->prioritise = true;
return $this->render($menu);
}
@@ -577,6 +609,9 @@ class core_course_renderer extends plugin_renderer_base {
}
$completion = $completioninfo->is_enabled($mod);
if ($completion == COMPLETION_TRACKING_NONE) {
if ($this->page->user_is_editing()) {
$output .= html_writer::span('&nbsp;', 'filler');
}
return $output;
}
@@ -612,7 +647,14 @@ class core_course_renderer extends plugin_renderer_base {
if ($completionicon) {
$formattedname = $mod->get_formatted_name();
$imgalt = get_string('completion-alt-' . $completionicon, 'completion', $formattedname);
if ($completion == COMPLETION_TRACKING_MANUAL && !$this->page->user_is_editing()) {
if ($this->page->user_is_editing()) {
// When editing, the icon is just an image.
$completionpixicon = new pix_icon('i/completion-'.$completionicon, $imgalt, '',
array('title' => $imgalt, 'class' => 'iconsmall'));
$output .= html_writer::tag('span', $this->output->render($completionpixicon),
array('class' => 'autocompletion'));
} else if ($completion == COMPLETION_TRACKING_MANUAL) {
$imgtitle = get_string('completion-title-' . $completionicon, 'completion', $formattedname);
$newstate =
$completiondata->completionstate == COMPLETION_COMPLETE
@@ -648,7 +690,7 @@ class core_course_renderer extends plugin_renderer_base {
$output .= html_writer::end_tag('div');
$output .= html_writer::end_tag('form');
} else {
// In auto mode, or when editing, the icon is just an image
// In auto mode, the icon is just an image.
$completionpixicon = new pix_icon('i/completion-'.$completionicon, $imgalt, '',
array('title' => $imgalt));
$output .= html_writer::tag('span', $this->output->render($completionpixicon),
@@ -933,6 +975,13 @@ class core_course_renderer extends plugin_renderer_base {
$indentclasses .= ' mod-indent-huge';
}
}
$output .= html_writer::start_tag('div');
if ($this->page->user_is_editing()) {
$output .= course_get_cm_move($mod, $sectionreturn);
}
$output .= html_writer::start_tag('div', array('class' => $indentclasses));
// Start the div for the activity title, excluding the edit icons.
@@ -940,6 +989,9 @@ class core_course_renderer extends plugin_renderer_base {
// Display the link to the module (or do nothing if module has no url)
$output .= $this->course_section_cm_name($mod, $displayoptions);
if ($this->page->user_is_editing()) {
$output .= ' ' . course_get_cm_rename_action($mod, $sectionreturn);
}
// Module can put text after the link (e.g. forum unread)
$output .= $mod->get_after_link();
@@ -959,13 +1011,18 @@ class core_course_renderer extends plugin_renderer_base {
$output .= $contentpart;
}
$modicons = '';
if ($this->page->user_is_editing()) {
$editactions = course_get_cm_edit_actions($mod, $mod->indent, $sectionreturn);
$output .= ' '. $this->course_section_cm_edit_actions($editactions, $mod, $displayoptions);
$output .= $mod->get_after_edit_icons();
$modicons .= ' '. $this->course_section_cm_edit_actions($editactions, $mod, $displayoptions);
$modicons .= $mod->get_after_edit_icons();
}
$output .= $this->course_section_cm_completion($course, $completioninfo, $mod, $displayoptions);
$modicons .= $this->course_section_cm_completion($course, $completioninfo, $mod, $displayoptions);
if (!empty($modicons)) {
$output .= html_writer::span($modicons, 'actions');
}
// If there is content AND a link, then display the content here
// (AFTER any icons). Otherwise it was displayed before
@@ -976,7 +1033,9 @@ class core_course_renderer extends plugin_renderer_base {
// show availability info (if module is not available)
$output .= $this->course_section_cm_availability($mod, $displayoptions);
$output .= html_writer::end_tag('div'); // $indentclasses
$output .= html_writer::end_tag('span'); // $indentclasses
$output .= html_writer::end_tag('div');
return $output;
}
+12
View File
@@ -106,6 +106,18 @@ switch($requestmethod) {
set_coursemodule_visible($cm->id, $value);
break;
case 'duplicate':
require_capability('moodle/course:manageactivities', $modcontext);
require_capability('moodle/backup:backuptargetimport', $modcontext);
require_capability('moodle/restore:restoretargetimport', $modcontext);
if (!course_allowed_module($course, $cm->modname)) {
throw new moodle_exception('No permission to create that activity');
}
$sr = optional_param('sr', null, PARAM_INT);
$result = mod_duplicate_activity($course, $cm, $sr);
echo json_encode($result);
break;
case 'groupmode':
require_capability('moodle/course:manageactivities', $modcontext);
set_coursemodule_groupmode($cm->id, $value);
@@ -21,7 +21,7 @@ Feature: Toggle activities groups mode from the course page
And I add a "Forum" to section "1" and I fill the form with:
| Forum name | Test forum name |
| Description | Test forum description |
And I follow "Edit settings"
And I click on "Edit settings" "link" in the "Administration" "block"
And I fill the moodle form with:
| Group mode | No groups |
| Force group mode | No |
@@ -24,7 +24,8 @@ Feature: Toggle activities visibility from the course page
| Forum name | Test forum name |
| Description | Test forum description |
| Visible | Show |
When I click on "Hide" "link" in the "Test forum name" activity
When I open "Test forum name" actions menu
And I click on "Hide" "link" in the "Test forum name" activity
Then "Test forum name" activity should be hidden
And I click on "Show" "link" in the "Test forum name" activity
And "Test forum name" activity should be visible
+1 -1
View File
@@ -30,7 +30,7 @@ Feature: Add activities to courses
And I turn editing mode off
Then I should not see "Adding a new"
And I follow "Test name"
And I follow "Edit settings"
And I click on "Edit settings" "link" in the "Administration" "block"
And I expand all fieldsets
And the "Name" field should match "Test name" value
And the "Entries required for completion" field should match "9" value
+34 -8
View File
@@ -327,6 +327,11 @@ class behat_course extends behat_base {
// Non-JS browsers can not click on img elements.
if ($this->running_javascript()) {
// Expanding the actions menu.
$actionsmenu = $this->find('css', "a[role='menuitem']", false, $activity);
$actionsmenu->click();
// To check that the visibility is not clickable we check the funcionality rather than the applied style.
$visibilityiconnode = $this->find('css', 'a.editing_show img', false, $activity);
$visibilityiconnode->click();
@@ -527,7 +532,6 @@ class behat_course extends behat_base {
// Adding chr(10) to save changes.
$activity = $this->escape($activityname);
return array(
new Given('I open "' . $activity . '" actions menu'),
new Given('I click on "' . get_string('edittitle') . '" "link" in the "' . $activity .'" activity'),
new Given('I fill in "title" with "' . $this->escape($newactivityname) . chr(10) . '"'),
new Given('I wait "2" seconds')
@@ -555,7 +559,7 @@ class behat_course extends behat_base {
return;
}
return new Given('I click on "' . get_string('actions', 'moodle') . '" "link" in the "' . $this->escape($activityname) . '" activity');
return new Given('I click on "a[role=\'menuitem\']" "css_element" in the "' . $this->escape($activityname) . '" activity');
}
/**
@@ -654,8 +658,13 @@ class behat_course extends behat_base {
$steps[] = new Given('I open "' . $activity . '" actions menu');
}
$steps[] = new Given('I click on "' . get_string('duplicate') . '" "link" in the "' . $activity . '" activity');
$steps[] = new Given('I press "' . get_string('continue') .'"');
$steps[] = new Given('I press "' . get_string('duplicatecontcourse') .'"');
if ($this->running_javascript()) {
// Temporary wait until MDL-41030 lands.
$steps[] = new Given('I wait "4" seconds');
} else {
$steps[] = new Given('I press "' . get_string('continue') .'"');
$steps[] = new Given('I press "' . get_string('duplicatecontcourse') .'"');
}
return $steps;
}
@@ -668,14 +677,31 @@ class behat_course extends behat_base {
* @return Given[]
*/
public function i_duplicate_activity_editing_the_new_copy_with($activityname, TableNode $data) {
$steps = array();
$activity = $this->escape($activityname);
if ($this->running_javascript()) {
$steps[] = new Given('I open "' . $activity . '" actions menu');
$steps[] = new Given('I duplicate "' . $activity . '" activity');
// Determine the future new activity xpath from the former one.
$activityliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($activityname);
$duplicatedxpath = "//li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')][contains(., $activityliteral)]" .
"/following-sibling::li";
$duplicatedactionsmenuxpath = $duplicatedxpath . "/descendant::a[@role='menuitem']";
// The next sibling of the former activity will be the duplicated one, so we click on it from it's xpath as, at
// this point, it don't even exists in the DOM (the steps are executed when we return them).
$steps[] = new Given('I click on "' . $this->escape($duplicatedactionsmenuxpath) . '" "xpath_element"');
// We force the xpath as otherwise mink tries to interact with the former one.
$steps[] = new Given('I click on "' . get_string('editsettings') . '" "link" in the "' . $this->escape($duplicatedxpath) . '" "xpath_element"');
} else {
$steps[] = new Given('I click on "' . get_string('duplicate') . '" "link" in the "' . $activity . '" activity');
$steps[] = new Given('I press "' . get_string('continue') .'"');
$steps[] = new Given('I press "' . get_string('duplicatecontedit') . '"');
}
$steps[] = new Given('I click on "' . get_string('duplicate') . '" "link" in the "' . $activity . '" activity');
$steps[] = new Given('I press "' . get_string('continue') .'"');
$steps[] = new Given('I press "' . get_string('duplicatecontedit') . '"');
$steps[] = new Given('I fill the moodle form with:', $data);
$steps[] = new Given('I press "' . get_string('savechangesandreturntocourse') . '"');
return $steps;
+2 -2
View File
@@ -56,7 +56,7 @@ Feature: Course activity controls works as expected
And I indent left "Test forum name 1" activity
And "#section-2" "css_element" <should_see_other_sections> exists
And I open "Test forum name 1" actions menu
And I click on "Update" "link" in the "Test forum name 1" activity
And I click on "Edit settings" "link" in the "Test forum name 1" activity
And I should see "Updating Forum"
And I should see "Display description on course page"
And I press "Save and return to course"
@@ -128,7 +128,7 @@ Feature: Course activity controls works as expected
And "#section-2" "css_element" <should_see_other_sections> exists
And I indent left "Test forum name 1" activity
And "#section-2" "css_element" <should_see_other_sections> exists
And I click on "Update" "link" in the "Test forum name 1" activity
And I click on "Edit settings" "link" in the "Test forum name 1" activity
And I should see "Updating Forum"
And I should see "Display description on course page"
And I press "Save and return to course"
+2 -2
View File
@@ -17,7 +17,7 @@ Feature: Edit course settings
| teacher1 | C1 | editingteacher |
And I log in as "teacher1"
And I follow "Course 1"
When I follow "Edit settings"
When I click on "Edit settings" "link" in the "Administration" "block"
And I fill the moodle form with:
| Course full name | Edited course fullname |
| Course short name | Edited course shortname |
@@ -28,7 +28,7 @@ Feature: Edit course settings
And I should not see "C1"
And I should see "Edited course fullname"
And I should see "Edited course shortname"
And I follow "Edit settings"
And I click on "Edit settings" "link" in the "Administration" "block"
And the "Course full name" field should match "Edited course fullname" value
And the "Course short name" field should match "Edited course shortname" value
And the "Course summary" field should match "Edited course summary" value
+4 -13
View File
@@ -20,7 +20,7 @@ Feature: Force group mode in a course
And I add a "Chat" to section "1" and I fill the form with:
| Name of this chat room | Chat room |
| Description | Chat description |
And I follow "Edit settings"
And I click on "Edit settings" "link" in the "Administration" "block"
@javascript
Scenario: Forced group mode using separate groups
@@ -29,10 +29,7 @@ Feature: Force group mode in a course
| Force group mode | Yes |
When I press "Save changes"
Then "//a/child::img[contains(@alt, 'Separate groups (forced mode)')]" "xpath_element" should not exists
And "//img[contains(@alt, 'Separate groups (forced mode)')]" "xpath_element" should exists
And I click on "//img[contains(@alt, 'Separate groups (forced mode)')]" "xpath_element" in the "li.activity.chat" "css_element"
And "//a/child::img[contains(@alt, 'Separate groups (forced mode)')]" "xpath_element" should not exists
And "//img[contains(@alt, 'Separate groups (forced mode)')]" "xpath_element" should exists
And "//img[contains(@alt, 'Separate groups (forced mode)')]" "xpath_element" should not exists
@javascript
Scenario: Forced group mode using visible groups
@@ -41,10 +38,7 @@ Feature: Force group mode in a course
| Force group mode | Yes |
And I press "Save changes"
Then "//a/child::img[contains(@alt, 'Visible groups (forced mode)')]" "xpath_element" should not exists
And "//img[contains(@alt, 'Visible groups (forced mode)')]" "xpath_element" should exists
And I click on "//img[contains(@alt, 'Visible groups (forced mode)')]" "xpath_element" in the "li.activity.chat" "css_element"
And "//a/child::img[contains(@alt, 'Visible groups (forced mode)')]" "xpath_element" should not exists
And "//img[contains(@alt, 'Visible groups (forced mode)')]" "xpath_element" should exists
And "//img[contains(@alt, 'Visible groups (forced mode)')]" "xpath_element" should not exists
@javascript
Scenario: Forced group mode without groups
@@ -53,8 +47,5 @@ Feature: Force group mode in a course
| Force group mode | Yes |
And I press "Save changes"
Then "//a/child::img[contains(@alt, 'No groups (forced mode)')]" "xpath_element" should not exists
And "//img[contains(@alt, 'No groups (forced mode)')]" "xpath_element" should exists
And I click on "//img[contains(@alt, 'No groups (forced mode)')]" "xpath_element" in the "li.activity.chat" "css_element"
And "//a/child::img[contains(@alt, 'No groups (forced mode)')]" "xpath_element" should not exists
And "//img[contains(@alt, 'No groups (forced mode)')]" "xpath_element" should exists
And "//img[contains(@alt, 'No groups (forced mode)')]" "xpath_element" should not exists
+2 -2
View File
@@ -33,7 +33,7 @@ Feature: Activities can be moved between sections
And I should not see "Test forum name" in the "#section-1" "css_element"
Scenario: Move activities in the course home with Javascript disabled using paged mode
Given I follow "Edit settings"
Given I click on "Edit settings" "link" in the "Administration" "block"
And I fill the moodle form with:
| Course layout | Show one section per page |
And I press "Save changes"
@@ -42,7 +42,7 @@ Feature: Activities can be moved between sections
And I should not see "Test forum name" in the "#section-1" "css_element"
Scenario: Move activities in a course section with Javascript disabled using paged mode
Given I follow "Edit settings"
Given I click on "Edit settings" "link" in the "Administration" "block"
And I fill the moodle form with:
| Course layout | Show one section per page |
And I press "Save changes"
+2 -2
View File
@@ -28,7 +28,7 @@ Feature: Sections can be moved
And I should see "Test forum name" in the "#section-1" "css_element"
Scenario: Move up and down a section with Javascript disabled in the course home of a course using paged mode
Given I follow "Edit settings"
Given I click on "Edit settings" "link" in the "Administration" "block"
And I fill the moodle form with:
| Course layout | Show one section per page |
And I press "Save changes"
@@ -41,7 +41,7 @@ Feature: Sections can be moved
And I should see "Test forum name" in the "#section-1" "css_element"
Scenario: Sections can not be moved with Javascript disabled in a section page of a course using paged mode
Given I follow "Edit settings"
Given I click on "Edit settings" "link" in the "Administration" "block"
And I fill the moodle form with:
| Course layout | Show one section per page |
And I press "Save changes"
+2 -2
View File
@@ -21,7 +21,7 @@ Feature: Rename roles within a course
| student1 | C1 | student |
And I log in as "teacher1"
And I follow "Course 1"
When I follow "Edit settings"
When I click on "Edit settings" "link" in the "Administration" "block"
And I fill the moodle form with:
| Your word for 'Non-editing teacher' | Tutor |
| Your word for 'Student' | Learner |
@@ -33,7 +33,7 @@ Feature: Rename roles within a course
And the "roleid" select box should contain "Tutor"
And the "roleid" select box should contain "Learner"
And the "roleid" select box should not contain "Student"
And I follow "Edit settings"
And I click on "Edit settings" "link" in the "Administration" "block"
And I fill the moodle form with:
| Your word for 'Non-editing teacher' | |
| Your word for 'Student' | |
+5 -2
View File
@@ -2,6 +2,7 @@ YUI.add('moodle-course-dragdrop', function(Y) {
var CSS = {
ACTIVITY : 'activity',
ACTIVITYINSTANCE : 'activityinstance',
COMMANDSPAN : '.commands',
CONTENT : 'content',
COURSECONTENT : 'course-content',
@@ -277,7 +278,7 @@ YUI.add('moodle-course-dragdrop', function(Y) {
this.groups = ['resource'];
this.samenodeclass = CSS.ACTIVITY;
this.parentnodeclass = CSS.SECTION;
this.resourcedraghandle = this.get_drag_handle(M.str.moodle.move, CSS.EDITINGMOVE, CSS.ICONCLASS);
this.resourcedraghandle = this.get_drag_handle(M.str.moodle.move, CSS.EDITINGMOVE, CSS.ICONCLASS, true);
// Go through all sections
var sectionlistselector = M.course.format.get_section_selector(Y);
@@ -374,12 +375,14 @@ YUI.add('moodle-course-dragdrop', function(Y) {
var dropnode = e.drop.get('node');
// Add spinner if it not there
var spinner = M.util.add_spinner(Y, dragnode.one(CSS.COMMANDSPAN));
var activityinstance = dragnode.one('.' + CSS.ACTIVITYINSTANCE);
var spinner = M.util.add_spinner(Y, activityinstance);
var params = {};
// Handle any variables which we must pass back through to
var pageparams = this.get('config').pageparams;
var varname;
for (varname in pageparams) {
params[varname] = pageparams[varname];
}
+190 -91
View File
@@ -13,6 +13,7 @@ YUI.add('moodle-course-toolboxes', function(Y) {
DIMCLASS : 'dimmed',
DIMMEDTEXT : 'dimmed_text',
EDITINSTRUCTIONS : 'editinstructions',
EDITINGTITLE: 'editor_displayed',
HIDE : 'hide',
MODINDENTCOUNT : 'mod-indent-',
MODINDENTHUGE : 'mod-indent-huge',
@@ -25,22 +26,29 @@ YUI.add('moodle-course-toolboxes', function(Y) {
// The CSS selectors we use.
SELECTOR = {
ACTIONLINKTEXT : '.actionlinktext',
ACTIVITYACTION : 'a.cm-edit-action[data-action]',
ACTIVITYFORM : 'form.'+CSS.ACTIVITYINSTANCE,
ACTIVITYACTION : 'a.cm-edit-action[data-action], a.editing_title',
ACTIVITYFORM : '.' + CSS.ACTIVITYINSTANCE + ' form',
ACTIVITYICON : 'img.activityicon',
ACTIVITYINSTANCE : '.' + CSS.ACTIVITYINSTANCE,
ACTIVITYLINK: '.' + CSS.ACTIVITYINSTANCE + ' > a',
ACTIVITYLI : 'li.activity',
ACTIVITYTITLE : 'input[name=title]',
COMMANDSPAN : '.commands',
CONTENTAFTERLINK : 'div.contentafterlink',
EDITTITLE: 'a.editing_title',
HIDE : 'a.editing_hide',
HIGHLIGHT : 'a.editing_highlight',
INSTANCENAME : 'span.instancename',
MODINDENTDIV : 'div.mod-indent',
MODINDENTDIV : '.mod-indent',
PAGECONTENT : 'div#page-content',
SECTIONLI : 'li.section',
SHOW : 'a.'+CSS.SHOW,
SHOWHIDE : 'a.editing_showhide'
},
INDENTLIMITS = {
MIN: 0,
MAX: 16
},
BODY = Y.one(document.body);
/**
@@ -52,24 +60,27 @@ YUI.add('moodle-course-toolboxes', function(Y) {
*/
var TOOLBOX = function() {
TOOLBOX.superclass.constructor.apply(this, arguments);
}
};
Y.extend(TOOLBOX, Y.Base, {
/**
* Send a request using the REST API
*
* @method send_request
* @param data The data to submit
* @param statusspinner (optional) A statusspinner which may contain a section loader
* @param {Function} success_callback The callback to use on success
* @param optionalconfig (optional) Any additional configuration to submit
* @return response responseText field from responce
* @return response responseText field from response - please use success_callback instead
*/
send_request : function(data, statusspinner, optionalconfig) {
send_request : function(data, statusspinner, success_callback, optionalconfig) {
// Default data structure
if (!data) {
data = {};
}
// Handle any variables which we must pass back through to
var pageparams = this.get('config').pageparams;
var pageparams = this.get('config').pageparams,
varname;
for (varname in pageparams) {
data[varname] = pageparams[varname];
}
@@ -92,8 +103,14 @@ YUI.add('moodle-course-toolboxes', function(Y) {
new M.core.ajaxException(responsetext);
}
} catch (e) {}
// Run the callback if we have one.
if (success_callback) {
Y.bind(success_callback, this, responsetext)();
}
if (statusspinner) {
window.setTimeout(function(e) {
window.setTimeout(function() {
statusspinner.hide();
}, 400);
}
@@ -105,9 +122,8 @@ YUI.add('moodle-course-toolboxes', function(Y) {
new M.core.ajaxException(response);
}
},
context: this,
sync: true
}
context: this
};
// Apply optional config
if (optionalconfig) {
@@ -249,6 +265,10 @@ YUI.add('moodle-course-toolboxes', function(Y) {
// The user is deleting the activity.
this.delete_with_confirmation(ev, node, activity, action);
break;
case 'duplicate' :
// The user is duplicating the activity.
this.duplicate(ev, node, activity, action);
break;
case 'hide' :
case 'show' :
// The user is changing the visibility of the activity.
@@ -270,6 +290,15 @@ YUI.add('moodle-course-toolboxes', function(Y) {
break;
}
},
add_spinner: function(activity) {
var instance = activity.one(SELECTOR.ACTIVITYINSTANCE);
if (instance) {
return M.util.add_spinner(Y, instance);
} else {
return M.util.add_spinner(Y, activity);
}
},
/**
* Change the indent of the activity or resource.
@@ -288,16 +317,22 @@ YUI.add('moodle-course-toolboxes', function(Y) {
var direction = (action === 'moveleft') ? -1 : 1;
// And we need to determine the current and new indent level
var indentdiv = activity.one(SELECTOR.MODINDENTDIV);
var indent = indentdiv.getAttribute('class').match(/mod-indent-(\d{1,})/);
var indentdiv = activity.one(SELECTOR.MODINDENTDIV),
indent = indentdiv.getAttribute('class').match(/mod-indent-(\d{1,})/),
oldindent = 0,
newindent;
if (indent) {
oldindent = parseInt(indent[1], 10);
}
newindent = oldindent + parseInt(direction, 10);
if (newindent < INDENTLIMITS.MIN || newindent > INDENTLIMITS.MAX) {
return;
}
if (indent) {
var oldindent = parseInt(indent[1]);
var newindent = Math.max(0, (oldindent + parseInt(direction)));
indentdiv.removeClass(indent[0]);
} else {
var oldindent = 0;
var newindent = 1;
}
// Perform the move
@@ -308,11 +343,7 @@ YUI.add('moodle-course-toolboxes', function(Y) {
'value' : newindent,
'id' : Y.Moodle.core_course.util.cm.getId(activity)
};
var commands = activity.one(SELECTOR.COMMANDSPAN);
var spinner = M.util.add_spinner(Y, commands).setStyles({
position: 'absolute',
top: 0
});
var spinner = this.add_spinner(activity);
if (BODY.hasClass('dir-ltr')) {
spinner.setStyle('left', '100%');
} else {
@@ -321,12 +352,18 @@ YUI.add('moodle-course-toolboxes', function(Y) {
this.send_request(data, spinner);
// Handle removal/addition of the moveleft button.
if (newindent == 0) {
if (newindent === INDENTLIMITS.MIN) {
button.addClass('hidden');
} else if (newindent == 1 && oldindent == 0) {
} else if (newindent > INDENTLIMITS.MIN && oldindent === INDENTLIMITS.MIN) {
button.ancestor('.menu').one('[data-action=moveleft]').removeClass('hidden');
}
if (newindent === INDENTLIMITS.MAX) {
button.addClass('hidden');
} else if (newindent < INDENTLIMITS.MAX && oldindent === INDENTLIMITS.MAX) {
button.ancestor('.menu').one('[data-action=moveright]').removeClass('hidden');
}
// Handle massive indentation to match non-ajax display
var hashugeclass = indentdiv.hasClass(CSS.MODINDENTHUGE);
if (newindent > 15 && !hashugeclass) {
@@ -383,6 +420,48 @@ YUI.add('moodle-course-toolboxes', function(Y) {
}
},
/**
* Duplicates the activity
*
* @protected
* @method duplicate
* @param {EventFacade} ev The event that was fired.
* @param {Node} button The button that triggered this action.
* @param {Node} activity The activity node that this action will be performed on.
* @return Boolean
*/
duplicate : function(ev, button, activity) {
// Prevent the default button action
ev.preventDefault();
// Get the element we're working on
var element = activity;
// Add the lightbox.
var section = activity.ancestor(M.course.format.get_section_selector(Y)),
lightbox = M.util.add_lightbox(Y, section).show();
// Build and send the request.
var data = {
'class' : 'resource',
'field' : 'duplicate',
'id' : Y.Moodle.core_course.util.cm.getId(element),
'sr' : button.getData('sr')
};
this.send_request(data, lightbox, function(response) {
var newcm = Y.Node.create(response.fullcontent);
// Append to the section?
activity.insert(newcm, 'after');
Y.use('moodle-course-coursebase', function() {
M.course.coursebase.invoke_function('setup_for_resource', newcm);
});
if (M.core.actionmenu && M.core.actionmenu.newDOMNode) {
M.core.actionmenu.newDOMNode(newcm);
}
});
},
/**
* Changes the visibility of this activity or resource.
*
@@ -415,7 +494,7 @@ YUI.add('moodle-course-toolboxes', function(Y) {
'value' : value,
'id' : Y.Moodle.core_course.util.cm.getId(element)
};
var spinner = M.util.add_spinner(Y, element.one(SELECTOR.COMMANDSPAN));
var spinner = this.add_spinner(element);
this.send_request(data, spinner);
return false; // Need to return false to stop the delegate for the new state firing
},
@@ -434,7 +513,8 @@ YUI.add('moodle-course-toolboxes', function(Y) {
var toggleclass = CSS.DIMCLASS,
dimarea = activity.one('a'),
availabilityinfo = activity.one(CSS.AVAILABILITYINFODIV),
nextaction = (action === 'hide') ? 'show' : 'hide';
nextaction = (action === 'hide') ? 'show' : 'hide',
buttontext = button.one('span'),
newstring = M.util.get_string(nextaction, 'moodle');
// Update button info.
@@ -445,9 +525,12 @@ YUI.add('moodle-course-toolboxes', function(Y) {
button.set('title', newstring);
button.replaceClass('editing_'+action, 'editing_'+nextaction);
button.setData('action', nextaction);
if (buttontext) {
buttontext.set('text', newstring);
}
// If activity is conditionally hidden, then don't toggle.
if (Y.Moodle.core_course.util.cm.getName(activity) == null) {
if (Y.Moodle.core_course.util.cm.getName(activity) === null) {
toggleclass = CSS.DIMMEDTEXT;
dimarea = activity.all(SELECTOR.MODINDENTDIV + ' > div').item(1);
}
@@ -494,13 +577,13 @@ YUI.add('moodle-course-toolboxes', function(Y) {
if (groupmode === this.GROUPS_NONE) {
newtitle = 'groupsnone';
iconsrc = M.util.image_url('t/groupn', 'moodle');
iconsrc = M.util.image_url('i/groupn', 'moodle');
} else if (groupmode === this.GROUPS_SEPARATE) {
newtitle = 'groupsseparate';
iconsrc = M.util.image_url('t/groups', 'moodle');
iconsrc = M.util.image_url('i/groups', 'moodle');
} else if (groupmode === this.GROUPS_VISIBLE) {
newtitle = 'groupsvisible';
iconsrc = M.util.image_url('t/groupv', 'moodle');
iconsrc = M.util.image_url('i/groupv', 'moodle');
}
newtitlestr = M.util.get_string(newtitle, 'moodle'),
newtitlestr = M.util.get_string('clicktochangeinbrackets', 'moodle', newtitlestr);
@@ -520,7 +603,7 @@ YUI.add('moodle-course-toolboxes', function(Y) {
'id' : Y.Moodle.core_course.util.cm.getId(activity)
};
spinner = M.util.add_spinner(Y, activity.one(SELECTOR.COMMANDSPAN));
spinner = this.add_spinner(activity);
this.send_request(data, spinner);
return false; // Need to return false to stop the delegate for the new state firing
},
@@ -549,49 +632,55 @@ YUI.add('moodle-course-toolboxes', function(Y) {
'class' : 'resource',
'field' : 'gettitle',
'id' : activityid
},
response = this.send_request(data);
};
if (M.core.actionmenu && M.core.actionmenu.instance) {
M.core.actionmenu.instance.hideMenu();
}
// Try to retrieve the existing string from the server
if (response.instancename) {
titletext = response.instancename;
}
// Create the editor and submit button
var editform = Y.Node.create('<form class="'+CSS.ACTIVITYINSTANCE+'" action="#" />');
var editinstructions = Y.Node.create('<span class="'+CSS.EDITINSTRUCTIONS+'" id="id_editinstructions" />')
.set('innerHTML', M.util.get_string('edittitleinstructions', 'moodle'));
var editor = Y.Node.create('<input name="title" type="text" class="'+CSS.TITLEEDITOR+'" />').setAttrs({
'value' : titletext,
'autocomplete' : 'off',
'aria-describedby' : 'id_editinstructions',
'maxLength' : '255'
})
// Clear the existing content and put the editor in
editform.appendChild(activity.one(SELECTOR.ACTIVITYICON).cloneNode());
editform.appendChild(editor);
editform.setData('anchor', anchor);
anchor.replace(editform);
activity.one('div').appendChild(editinstructions);
// Prevent the default actions.
ev.preventDefault();
// Focus and select the editor text
editor.focus().select();
this.send_request(data, null, function(response) {
if (M.core.actionmenu && M.core.actionmenu.instance) {
M.core.actionmenu.instance.hideMenu();
}
// Cancel the edit if we lose focus or the escape key is pressed.
thisevent = editor.on('blur', this.edit_title_cancel, this, activity, false);
this.edittitleevents.push(thisevent);
thisevent = editor.on('key', this.edit_title_cancel, 'esc', this, activity, true);
this.edittitleevents.push(thisevent);
// Try to retrieve the existing string from the server
if (response.instancename) {
titletext = response.instancename;
}
// Handle form submission.
thisevent = editform.on('submit', this.edit_title_submit, this, activity, oldtitle);
this.edittitleevents.push(thisevent);
// Create the editor and submit button
var editform = Y.Node.create('<form action="#" />');
var editinstructions = Y.Node.create('<span class="'+CSS.EDITINSTRUCTIONS+'" id="id_editinstructions" />')
.set('innerHTML', M.util.get_string('edittitleinstructions', 'moodle'));
var editor = Y.Node.create('<input name="title" type="text" class="'+CSS.TITLEEDITOR+'" />').setAttrs({
'value' : titletext,
'autocomplete' : 'off',
'aria-describedby' : 'id_editinstructions',
'maxLength' : '255'
});
// Clear the existing content and put the editor in
editform.appendChild(activity.one(SELECTOR.ACTIVITYICON).cloneNode());
editform.appendChild(editor);
editform.setData('anchor', anchor);
anchor.replace(editform);
activity.one('div').appendChild(editinstructions);
// We hide various components whilst editing:
activity.addClass(CSS.EDITINGTITLE);
// Focus and select the editor text
editor.focus().select();
// Cancel the edit if we lose focus or the escape key is pressed.
thisevent = editor.on('blur', this.edit_title_cancel, this, activity, false);
this.edittitleevents.push(thisevent);
thisevent = editor.on('key', this.edit_title_cancel, 'esc', this, activity, true);
this.edittitleevents.push(thisevent);
// Handle form submission.
thisevent = editform.on('submit', this.edit_title_submit, this, activity, oldtitle);
this.edittitleevents.push(thisevent);
});
},
/**
@@ -609,7 +698,7 @@ YUI.add('moodle-course-toolboxes', function(Y) {
var newtitle = Y.Lang.trim(activity.one(SELECTOR.ACTIVITYFORM + ' ' + SELECTOR.ACTIVITYTITLE).get('value'));
this.edit_title_clear(activity);
var spinner = M.util.add_spinner(Y, activity.one(SELECTOR.INSTANCENAME));
var spinner = this.add_spinner(activity);
if (newtitle != null && newtitle != "" && newtitle != originaltitle) {
var data = {
'class' : 'resource',
@@ -617,10 +706,11 @@ YUI.add('moodle-course-toolboxes', function(Y) {
'title' : newtitle,
'id' : Y.Moodle.core_course.util.cm.getId(activity)
};
var response = this.send_request(data, spinner);
if (response.instancename) {
activity.one(SELECTOR.INSTANCENAME).setContent(response.instancename);
}
this.send_request(data, spinner, function(response) {
if (response.instancename) {
activity.one(SELECTOR.INSTANCENAME).setContent(response.instancename);
}
});
}
},
@@ -661,6 +751,14 @@ YUI.add('moodle-course-toolboxes', function(Y) {
if (instructions) {
instructions.remove();
}
// Remove the editing class again to revert the display.
activity.removeClass(CSS.EDITINGTITLE);
// Refocus the link which was clicked originally so the user can continue using keyboard nav.
Y.later(100, this, function() {
activity.one(SELECTOR.EDITTITLE).focus();
});
},
/**
@@ -781,23 +879,24 @@ YUI.add('moodle-course-toolboxes', function(Y) {
var lightbox = M.util.add_lightbox(Y, section);
lightbox.show();
var response = this.send_request(data, lightbox);
this.send_request(data, lightbox, function(response) {
var activities = section.all(SELECTOR.ACTIVITYLI);
activities.each(function(node) {
var button;
if (node.one(SELECTOR.SHOW)) {
button = node.one(SELECTOR.SHOW);
} else {
button = node.one(SELECTOR.HIDE);
}
var activityid = Y.Moodle.core_course.util.cm.getId(node);
var activities = section.all(SELECTOR.ACTIVITYLI);
activities.each(function(node) {
if (node.one(SELECTOR.SHOW)) {
var button = node.one(SELECTOR.SHOW);
} else {
var button = node.one(SELECTOR.HIDE);
}
var activityid = Y.Moodle.core_course.util.cm.getId(node);
// NOTE: resourcestotoggle is returned as a string instead
// of a Number so we must cast our activityid to a String.
if (Y.Array.indexOf(response.resourcestotoggle, "" + activityid) != -1) {
M.course.resource_toolbox.handle_resource_dim(button, node, action);
}
}, this);
// NOTE: resourcestotoggle is returned as a string instead
// of a Number so we must cast our activityid to a String.
if (Y.Array.indexOf(response.resourcestotoggle, "" + activityid) !== -1) {
M.course.resource_toolbox.handle_resource_dim(button, node, action);
}
}, this);
});
},
toggle_highlight : function(e) {
// Prevent the default button action
+1 -1
View File
@@ -21,7 +21,7 @@ Feature: Guest users can auto-enrol themself in courses where guest access is al
And I add a "Forum" to section "1" and I fill the form with:
| Forum name | Test forum name |
| Description | Test forum description |
And I follow "Edit settings"
And I click on "Edit settings" "link" in the "Administration" "block"
@javascript
Scenario: Allow guest access without password
+1 -1
View File
@@ -529,6 +529,7 @@ $string['edita'] = 'Edit {$a}';
$string['editcategorysettings'] = 'Edit category settings';
$string['editcategorythis'] = 'Edit this category';
$string['editcoursesettings'] = 'Edit course settings';
$string['editsettings'] = 'Edit settings';
$string['editfiles'] = 'Edit files';
$string['editgroupprofile'] = 'Edit group profile';
$string['editinga'] = 'Editing {$a}';
@@ -763,7 +764,6 @@ $string['followingoptional'] = 'The following items are optional';
$string['followingrequired'] = 'The following items are required';
$string['for'] = 'For';
$string['force'] = 'Force';
$string['forcedmodeinbrackets'] = '{$a} (forced mode)';
$string['forcelanguage'] = 'Force language';
$string['forceno'] = 'Do not force';
$string['forcepasswordchange'] = 'Force password change';
+14 -13
View File
@@ -1050,7 +1050,7 @@ class block_manager {
if ($this->page->user_can_edit_blocks() || $block->user_can_edit()) {
// Edit config icon - always show - needed for positioning UI.
$str = new lang_string('configureblock', 'block', $blocktitle);
$controls[] = new action_menu_link_primary(
$controls[] = new action_menu_link_secondary(
new moodle_url($actionurl, array('bui_editid' => $block->instance->id)),
new pix_icon('t/edit', $str, 'moodle', array('class' => 'iconsmall', 'title' => '')),
$str,
@@ -1059,17 +1059,6 @@ class block_manager {
}
if ($this->user_can_delete_block($block)) {
// Delete icon.
$str = new lang_string('deleteblock', 'block', $blocktitle);
$controls[] = new action_menu_link_secondary(
new moodle_url($actionurl, array('bui_deleteid' => $block->instance->id)),
new pix_icon('t/delete', $str, 'moodle', array('class' => 'iconsmall', 'title' => '')),
$str,
array('class' => 'editing_delete')
);
}
if ($this->page->user_can_edit_blocks() && $block->instance_can_be_hidden()) {
// Show/hide icon.
if ($block->instance->visible) {
@@ -1083,7 +1072,7 @@ class block_manager {
$icon = new pix_icon('t/show', $str, 'moodle', array('class' => 'iconsmall', 'title' => ''));
$attributes = array('class' => 'editing_show');
}
$controls[] = new action_menu_link_primary($url, $icon, $str, $attributes);
$controls[] = new action_menu_link_secondary($url, $icon, $str, $attributes);
}
// Assign roles icon.
@@ -1105,6 +1094,18 @@ class block_manager {
array('class' => 'editing_roles')
);
}
if ($this->user_can_delete_block($block)) {
// Delete icon.
$str = new lang_string('deleteblock', 'block', $blocktitle);
$controls[] = new action_menu_link_secondary(
new moodle_url($actionurl, array('bui_deleteid' => $block->instance->id)),
new pix_icon('t/delete', $str, 'moodle', array('class' => 'iconsmall', 'title' => '')),
$str,
array('class' => 'editing_delete')
);
}
return $controls;
}
+64 -11
View File
@@ -3109,10 +3109,22 @@ class action_menu implements renderable {
/**
* An icon to use for the toggling the secondary menu (dropdown).
* @var pix_icon
* @var actionicon
*/
public $actionicon;
/**
* Any text to use for the toggling the secondary menu (dropdown).
* @var menutrigger
*/
public $menutrigger = '';
/**
* Place the action menu before all other actions.
* @var prioritise
*/
public $prioritise = false;
/**
* Constructs the action menu with the given items.
*
@@ -3140,18 +3152,16 @@ class action_menu implements renderable {
'aria-labelledby' => 'action-menu-toggle-'.$this->instance,
'role' => 'menu'
);
$this->actionicon = new pix_icon(
't/contextmenu',
new lang_string('actions', 'moodle'),
'moodle',
array('class' => 'iconsmall', 'title' => '')
);
$this->set_alignment(self::TR, self::BR);
foreach ($actions as $action) {
$this->add($action);
}
}
public function set_menu_trigger($trigger) {
$this->menutrigger = $trigger;
}
/**
* Initialises JS required fore the action menu.
* The JS is only required once as it manages all action menu's on the page.
@@ -3172,7 +3182,7 @@ class action_menu implements renderable {
* @param action_menu_link|pix_icon|string $action
*/
public function add($action) {
if ($action instanceof action_menu_link) {
if ($action instanceof action_link) {
if ($action->primary) {
$this->add_primary_action($action);
} else {
@@ -3227,7 +3237,22 @@ class action_menu implements renderable {
$output = $OUTPUT;
}
$pixicon = $this->actionicon;
$title = new lang_string('actions', 'moodle');
$linkclasses = array('toggle-display');
$title = '';
if (!empty($this->menutrigger)) {
$pixicon = '<b class="caret"></b>';
$linkclasses[] = 'textmenu';
} else {
$title = new lang_string('actions', 'moodle');
$this->actionicon = new pix_icon(
't/edit_menu',
'',
'moodle',
array('class' => 'iconsmall actionmenu', 'title' => '')
);
$pixicon = $this->actionicon;
}
if ($pixicon instanceof renderable) {
$pixicon = $output->render($pixicon);
if ($pixicon instanceof pix_icon && isset($pixicon->attributes['alt'])) {
@@ -3240,12 +3265,17 @@ class action_menu implements renderable {
}
$actions = $this->primaryactions;
$attributes = array(
'class' => 'toggle-display',
'class' => implode(' ', $linkclasses),
'title' => $title,
'id' => 'action-menu-toggle-'.$this->instance,
'role' => 'menuitem'
);
$actions[] = html_writer::link('#', $string.$pixicon, $attributes);
$link = html_writer::link('#', $string . $this->menutrigger . $pixicon, $attributes);
if ($this->prioritise) {
array_unshift($actions, $link);
} else {
$actions[] = $link;
}
return $actions;
}
@@ -3335,6 +3365,29 @@ class action_menu implements renderable {
}
}
/**
* An action menu filler
*
* @package core
* @category output
* @copyright 2013 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class action_menu_filler extends action_link implements renderable {
/**
* True if this is a primary action. False if not.
* @var bool
*/
public $primary = true;
/**
* Constructs the object.
*/
public function __construct() {
}
}
/**
* An action menu action
*
+11 -1
View File
@@ -1161,6 +1161,16 @@ class core_renderer extends renderer_base {
return html_writer::tag('a', $icon.$text, $attributes);
}
/**
* Renders a primary action_menu_filler item.
*
* @param action_menu_link_filler $action
* @return string HTML fragment
*/
protected function render_action_menu_filler(action_menu_filler $action) {
return html_writer::span('&nbsp;', 'filler');
}
/**
* Renders a primary action_menu_link item.
*
@@ -2064,7 +2074,7 @@ class core_renderer extends renderer_base {
public function heading_with_help($text, $helpidentifier, $component = 'moodle', $icon = '', $iconalt = '', $level = 2, $classnames = null) {
$image = '';
if ($icon) {
$image = $this->pix_icon($icon, $iconalt, $component, array('class'=>'icon'));
$image = $this->pix_icon($icon, $iconalt, $component, array('class'=>'icon iconlarge'));
}
$help = '';
@@ -11,8 +11,11 @@ var BODY = Y.one(Y.config.doc.body),
MENUSHOWN : 'action-menu-shown'
},
SELECTOR = {
CAN_RECEIVE_FOCUS_SELECTOR: 'input:not([type="hidden"]), a[href], button, textarea, select, [tabindex]',
MENU : '.moodle-actionmenu[data-enhance=moodle-core-actionmenu]',
MENUCONTENT : '.menu[data-rel=menu-content]',
MENUCONTENTCHILD: 'li a',
MENUCHILD: '.menu li a',
TOGGLE : '.toggle-display'
},
ACTIONMENU,
@@ -59,6 +62,15 @@ ACTIONMENU.prototype = {
*/
owner : null,
/**
* The menu button that toggles this open.
*
* @property menulink
* @type Node
* @protected
*/
menulink: null,
/**
* Called during the initialisation process of the object.
* @method initializer
@@ -104,16 +116,21 @@ ACTIONMENU.prototype = {
this.dialogue.one(SELECTOR.MENUCONTENT).set('aria-hidden', true);
this.dialogue = null;
}
if (this.owner) {
this.owner.removeClass(CSS.MENUSHOWN);
this.owner = null;
}
for (var i in this.events) {
if (this.events[i].detach) {
this.events[i].detach();
}
}
this.events = [];
if (this.owner) {
this.owner.removeClass(CSS.MENUSHOWN);
this.owner = null;
}
if (this.menulink) {
this.menulink.focus();
this.menulink = null;
}
},
/**
@@ -132,13 +149,49 @@ ACTIONMENU.prototype = {
// The menu was visible and the user has clicked to toggle it again.
return;
}
this.showMenu(menu);
this.showMenu(e, menu);
// Close the menu if the user presses escape.
this.events.push(BODY.on('key', this.hideMenu, 'esc', this));
// Close the menu if the user clicks outside the menu.
this.events.push(BODY.on('click', this.hideIfOutside, this));
// Close the menu if the user focuses outside the menu.
this.events.push(BODY.delegate('focus', this.hideIfOutside, '*', this));
// Check tabbing.
this.events.push(menu.delegate('key', this.checkFocus, 'down:9', SELECTOR.MENUCHILD, this));
},
/**
* Check current focus when moving around with the tab key.
* This will ensure that when the etreme menu items are reached, the
* menu is closed and the next DOM element is focused.
*
* @method checkFocus
* @param {EventFacade} e The key event
*/
checkFocus: function(e) {
var nodelist = this.dialogue.all(SELECTOR.MENUCHILD),
firstNode,
lastNode;
if (nodelist) {
firstNode = nodelist.item(0);
lastNode = nodelist.pop();
}
var menulink = this.menulink;
if (e.target === firstNode && e.shiftKey) {
this.hideMenu();
e.preventDefault();
} else if (e.target === lastNode && !e.shiftKey) {
var next;
if (this.hideMenu()) {
next = menulink.next(SELECTOR.CAN_RECEIVE_FOCUS_SELECTOR);
if (next) {
next.focus();
}
}
}
},
/**
@@ -156,21 +209,31 @@ ACTIONMENU.prototype = {
/**
* Displays the menu with the given content and alignment.
* @param {EventFacade} e
* @param {Node} menu
* @param Array align
* @returns {M.core.dialogue|dialogue}
*/
showMenu : function(menu) {
showMenu : function(e, menu) {
Y.log('Displaying an action menu', 'debug', ACTIONMENU.NAME);
var ownerselector = menu.getData('owner'),
menucontent = menu.one(SELECTOR.MENUCONTENT);
menucontent = menu.one(SELECTOR.MENUCONTENT),
menuchild;
this.owner = (ownerselector) ? menu.ancestor(ownerselector) : null;
this.dialogue = menu;
menu.addClass('show');
if (this.owner) {
this.owner.addClass(CSS.MENUSHOWN);
this.menulink = this.owner.one(SELECTOR.TOGGLE);
}
this.constrain(menucontent.set('aria-hidden', false));
if (e.type && e.type === 'key') {
menuchild = menucontent.one(SELECTOR.MENUCONTENTCHILD);
if (menuchild) {
menuchild.focus();
}
}
return true;
},
@@ -1 +1 @@
YUI.add("moodle-core-actionmenu",function(e,t){var n=e.one(e.config.doc.body),r={MENUSHOWN:"action-menu-shown"},i={MENU:".moodle-actionmenu[data-enhance=moodle-core-actionmenu]",MENUCONTENT:".menu[data-rel=menu-content]",TOGGLE:".toggle-display"},s,o={TL:"tl",TR:"tr",BL:"bl",BR:"br"};s=function(){s.superclass.constructor.apply(this,arguments)},s.prototype={dialogue:null,events:[],owner:null,initializer:function(){e.all(i.MENU).each(this.enhance,this),n.delegate("click",this.toggleMenu,i.MENU+" "+i.TOGGLE,this),n.delegate("key",this.toggleMenu,"enter,space",i.MENU+" "+i.TOGGLE,this)},enhance:function(e){var t=e.one(i.MENUCONTENT),n;if(!t)return!1;n=t.getData("align")||this.get("align").join("-"),e.one(i.TOGGLE).set("aria-haspopup",!0),t.set("aria-hidden",!0),t.hasClass("align-"+n)||t.addClass("align-"+n),t.hasChildNodes()&&e.setAttribute("data-enhanced","1")},hideMenu:function(){this.dialogue&&(this.dialogue.removeClass("show"),this.dialogue.one(i.MENUCONTENT).set("aria-hidden",!0),this.dialogue=null),this.owner&&(this.owner.removeClass(r.MENUSHOWN),this.owner=null);for(var e in this.events)this.events[e].detach&&this.events[e].detach();this.events=[]},toggleMenu:function(e){var t=e.target.ancestor(i.MENU),r=t.hasClass("show");e.halt(!0),this.hideMenu();if(r)return;this.showMenu(t),this.events.push(n.on("key",this.hideMenu,"esc",this)),this.events.push(n.on("click",this.hideIfOutside,this)),this.events.push(n.delegate("focus",this.hideIfOutside,"*",this))},hideIfOutside:function(e){!e.target.test(i.MENU)&&!e.target.ancestor(i.MENU)&&this.hideMenu()},showMenu:function(e){var t=e.getData("owner"),n=e.one(i.MENUCONTENT);return this.owner=t?e.ancestor(t):null,this.dialogue=e,e.addClass("show"),this.owner&&this.owner.addClass(r.MENUSHOWN),this.constrain(n.set("aria-hidden",!1)),!0},constrain:function(e){var t=e.getData("constraint"),n=e.getX(),r=e.getY(),i=e.get("offsetWidth"),s=e.get("offsetHeight"),o=0,u=0,a,f,l="auto",c=null,h=null,p=null,d=null,v=null;t&&(t=e.ancestor(t)),t?(a=t.get("offsetWidth"),f=t.get("offsetHeight"),o=t.getX(),u=t.getY(),l=t.getStyle("overflow")||"auto"):(a=e.get("docWidth"),f=e.get("docHeight")),i>a?(c=i=a,p=n=o):n<o?p=n=o:n+i>=o+a&&(p=o+a-i),s>f&&l.toLowerCase()==="hidden"&&(h=s=f,e.setStyle("overflow","auto"));if(r>=u&&r+s>u+f){d=u+f-s;try{v=e.getStyle("boxShadow").replace(/.*? (\d+)px \d+px$/,"$1"),(new RegExp(/^\d+$/)).test(v)&&d-u>v&&(d-=v)}catch(m){}}p!==null&&e.setX(p),d!==null&&e.setY(d),c!==null&&e.setStyle("width",c.toString()+"px"),h!==null&&e.setStyle("height",h.toString()+"px")}},e.extend(s,e.Base,s.prototype,{NAME:"moodle-core-actionmenu",ATTRS:{align:{value:[o.TR,o.BR]}}}),M.core=M.core||{},M.core.actionmenu=M.core.actionmenu||{},M.core.actionmenu.instance=null,M.core.actionmenu.init=M.core.actionmenu.init||function(e){M.core.actionmenu.instance=M.core.actionmenu.instance||new s(e)},M.core.actionmenu.newDOMNode=function(e){if(M.core.actionmenu.instance===null)return!0;e.all(i.MENU).each(M.core.actionmenu.instance.enhance,M.core.actionmenu.instance)}},"@VERSION@",{requires:["base","event"]});
YUI.add("moodle-core-actionmenu",function(e,t){var n=e.one(e.config.doc.body),r={MENUSHOWN:"action-menu-shown"},i={CAN_RECEIVE_FOCUS_SELECTOR:'input:not([type="hidden"]), a[href], button, textarea, select, [tabindex]',MENU:".moodle-actionmenu[data-enhance=moodle-core-actionmenu]",MENUCONTENT:".menu[data-rel=menu-content]",MENUCONTENTCHILD:"li a",MENUCHILD:".menu li a",TOGGLE:".toggle-display"},s,o={TL:"tl",TR:"tr",BL:"bl",BR:"br"};s=function(){s.superclass.constructor.apply(this,arguments)},s.prototype={dialogue:null,events:[],owner:null,menulink:null,initializer:function(){e.all(i.MENU).each(this.enhance,this),n.delegate("click",this.toggleMenu,i.MENU+" "+i.TOGGLE,this),n.delegate("key",this.toggleMenu,"enter,space",i.MENU+" "+i.TOGGLE,this)},enhance:function(e){var t=e.one(i.MENUCONTENT),n;if(!t)return!1;n=t.getData("align")||this.get("align").join("-"),e.one(i.TOGGLE).set("aria-haspopup",!0),t.set("aria-hidden",!0),t.hasClass("align-"+n)||t.addClass("align-"+n),t.hasChildNodes()&&e.setAttribute("data-enhanced","1")},hideMenu:function(){this.dialogue&&(this.dialogue.removeClass("show"),this.dialogue.one(i.MENUCONTENT).set("aria-hidden",!0),this.dialogue=null);for(var e in this.events)this.events[e].detach&&this.events[e].detach();this.events=[],this.owner&&(this.owner.removeClass(r.MENUSHOWN),this.owner=null),this.menulink&&(this.menulink.focus(),this.menulink=null)},toggleMenu:function(e){var t=e.target.ancestor(i.MENU),r=t.hasClass("show");e.halt(!0),this.hideMenu();if(r)return;this.showMenu(e,t),this.events.push(n.on("key",this.hideMenu,"esc",this)),this.events.push(n.on("click",this.hideIfOutside,this)),this.events.push(n.delegate("focus",this.hideIfOutside,"*",this)),this.events.push(t.delegate("key",this.checkFocus,"down:9",i.MENUCHILD,this))},checkFocus:function(e){var t=this.dialogue.all(i.MENUCHILD),n,r;t&&(n=t.item(0),r=t.pop());var s=this.menulink;if(e.target===n&&e.shiftKey)this.hideMenu(),e.preventDefault();else if(e.target===r&&!e.shiftKey){var o;this.hideMenu()&&(o=s.next(i.CAN_RECEIVE_FOCUS_SELECTOR),o&&o.focus())}},hideIfOutside:function(e){!e.target.test(i.MENU)&&!e.target.ancestor(i.MENU)&&this.hideMenu()},showMenu:function(e,t){var n=t.getData("owner"),s=t.one(i.MENUCONTENT),o;return this.owner=n?t.ancestor(n):null,this.dialogue=t,t.addClass("show"),this.owner&&(this.owner.addClass(r.MENUSHOWN),this.menulink=this.owner.one(i.TOGGLE)),this.constrain(s.set("aria-hidden",!1)),e.type&&e.type==="key"&&(o=s.one(i.MENUCONTENTCHILD),o&&o.focus()),!0},constrain:function(e){var t=e.getData("constraint"),n=e.getX(),r=e.getY(),i=e.get("offsetWidth"),s=e.get("offsetHeight"),o=0,u=0,a,f,l="auto",c=null,h=null,p=null,d=null,v=null;t&&(t=e.ancestor(t)),t?(a=t.get("offsetWidth"),f=t.get("offsetHeight"),o=t.getX(),u=t.getY(),l=t.getStyle("overflow")||"auto"):(a=e.get("docWidth"),f=e.get("docHeight")),i>a?(c=i=a,p=n=o):n<o?p=n=o:n+i>=o+a&&(p=o+a-i),s>f&&l.toLowerCase()==="hidden"&&(h=s=f,e.setStyle("overflow","auto"));if(r>=u&&r+s>u+f){d=u+f-s;try{v=e.getStyle("boxShadow").replace(/.*? (\d+)px \d+px$/,"$1"),(new RegExp(/^\d+$/)).test(v)&&d-u>v&&(d-=v)}catch(m){}}p!==null&&e.setX(p),d!==null&&e.setY(d),c!==null&&e.setStyle("width",c.toString()+"px"),h!==null&&e.setStyle("height",h.toString()+"px")}},e.extend(s,e.Base,s.prototype,{NAME:"moodle-core-actionmenu",ATTRS:{align:{value:[o.TR,o.BR]}}}),M.core=M.core||{},M.core.actionmenu=M.core.actionmenu||{},M.core.actionmenu.instance=null,M.core.actionmenu.init=M.core.actionmenu.init||function(e){M.core.actionmenu.instance=M.core.actionmenu.instance||new s(e)},M.core.actionmenu.newDOMNode=function(e){if(M.core.actionmenu.instance===null)return!0;e.all(i.MENU).each(M.core.actionmenu.instance.enhance,M.core.actionmenu.instance)}},"@VERSION@",{requires:["base","event"]});
@@ -11,8 +11,11 @@ var BODY = Y.one(Y.config.doc.body),
MENUSHOWN : 'action-menu-shown'
},
SELECTOR = {
CAN_RECEIVE_FOCUS_SELECTOR: 'input:not([type="hidden"]), a[href], button, textarea, select, [tabindex]',
MENU : '.moodle-actionmenu[data-enhance=moodle-core-actionmenu]',
MENUCONTENT : '.menu[data-rel=menu-content]',
MENUCONTENTCHILD: 'li a',
MENUCHILD: '.menu li a',
TOGGLE : '.toggle-display'
},
ACTIONMENU,
@@ -59,6 +62,15 @@ ACTIONMENU.prototype = {
*/
owner : null,
/**
* The menu button that toggles this open.
*
* @property menulink
* @type Node
* @protected
*/
menulink: null,
/**
* Called during the initialisation process of the object.
* @method initializer
@@ -102,16 +114,21 @@ ACTIONMENU.prototype = {
this.dialogue.one(SELECTOR.MENUCONTENT).set('aria-hidden', true);
this.dialogue = null;
}
if (this.owner) {
this.owner.removeClass(CSS.MENUSHOWN);
this.owner = null;
}
for (var i in this.events) {
if (this.events[i].detach) {
this.events[i].detach();
}
}
this.events = [];
if (this.owner) {
this.owner.removeClass(CSS.MENUSHOWN);
this.owner = null;
}
if (this.menulink) {
this.menulink.focus();
this.menulink = null;
}
},
/**
@@ -130,13 +147,49 @@ ACTIONMENU.prototype = {
// The menu was visible and the user has clicked to toggle it again.
return;
}
this.showMenu(menu);
this.showMenu(e, menu);
// Close the menu if the user presses escape.
this.events.push(BODY.on('key', this.hideMenu, 'esc', this));
// Close the menu if the user clicks outside the menu.
this.events.push(BODY.on('click', this.hideIfOutside, this));
// Close the menu if the user focuses outside the menu.
this.events.push(BODY.delegate('focus', this.hideIfOutside, '*', this));
// Check tabbing.
this.events.push(menu.delegate('key', this.checkFocus, 'down:9', SELECTOR.MENUCHILD, this));
},
/**
* Check current focus when moving around with the tab key.
* This will ensure that when the etreme menu items are reached, the
* menu is closed and the next DOM element is focused.
*
* @method checkFocus
* @param {EventFacade} e The key event
*/
checkFocus: function(e) {
var nodelist = this.dialogue.all(SELECTOR.MENUCHILD),
firstNode,
lastNode;
if (nodelist) {
firstNode = nodelist.item(0);
lastNode = nodelist.pop();
}
var menulink = this.menulink;
if (e.target === firstNode && e.shiftKey) {
this.hideMenu();
e.preventDefault();
} else if (e.target === lastNode && !e.shiftKey) {
var next;
if (this.hideMenu()) {
next = menulink.next(SELECTOR.CAN_RECEIVE_FOCUS_SELECTOR);
if (next) {
next.focus();
}
}
}
},
/**
@@ -154,20 +207,30 @@ ACTIONMENU.prototype = {
/**
* Displays the menu with the given content and alignment.
* @param {EventFacade} e
* @param {Node} menu
* @param Array align
* @returns {M.core.dialogue|dialogue}
*/
showMenu : function(menu) {
showMenu : function(e, menu) {
var ownerselector = menu.getData('owner'),
menucontent = menu.one(SELECTOR.MENUCONTENT);
menucontent = menu.one(SELECTOR.MENUCONTENT),
menuchild;
this.owner = (ownerselector) ? menu.ancestor(ownerselector) : null;
this.dialogue = menu;
menu.addClass('show');
if (this.owner) {
this.owner.addClass(CSS.MENUSHOWN);
this.menulink = this.owner.one(SELECTOR.TOGGLE);
}
this.constrain(menucontent.set('aria-hidden', false));
if (e.type && e.type === 'key') {
menuchild = menucontent.one(SELECTOR.MENUCONTENTCHILD);
if (menuchild) {
menuchild.focus();
}
}
return true;
},
+17 -8
View File
@@ -21,7 +21,7 @@ YUI.add('moodle-core-dragdrop', function(Y) {
parentnodeclass : null,
groups : [],
lastdroptarget : null,
initializer : function(params) {
initializer : function() {
// Listen for all drag:start events
Y.DD.DDM.on('drag:start', this.global_drag_start, this);
// Listen for all drag:end events
@@ -35,7 +35,8 @@ YUI.add('moodle-core-dragdrop', function(Y) {
// Listen for all drop:miss events
Y.DD.DDM.on('drag:dropmiss', this.global_drag_dropmiss, this);
Y.on('key', this.global_keydown, window, 'down:32,enter,esc', this);
Y.one(Y.config.doc.body).delegate('key', this.global_keydown, 'down:32, enter, esc', '.' + MOVEICON.cssclass, this);
Y.one(Y.config.doc.body).delegate('click', this.global_keydown, '.' + MOVEICON.cssclass , this);
},
get_drag_handle: function(title, classname, iconclass, large) {
@@ -57,7 +58,8 @@ YUI.add('moodle-core-dragdrop', function(Y) {
.addClass(classname)
.setAttribute('title', title)
.setAttribute('tabIndex', 0)
.setAttribute('data-draggroups', this.groups);
.setAttribute('data-draggroups', this.groups)
.setAttribute('aria-grabbed', 'false');
dragelement.appendChild(dragicon);
dragelement.addClass(MOVEICON.cssclass);
@@ -437,11 +439,16 @@ YUI.add('moodle-core-dragdrop', function(Y) {
* @param {Event} e The keydown / click event on the drag handle.
*/
global_keydown : function(e) {
var draghandle = e.target,
var draghandle = e.target.ancestor('.' + MOVEICON.cssclass, true),
dragcontainer,
draggroups;
if (e.keyCode == 27 ) {
if (draghandle === null) {
// The element clicked did not have a a draghandle in it's lineage.
return;
}
if (e.keyCode === 27 ) {
// Escape to cancel from anywhere.
this.global_cancel_keyboard_drag();
e.preventDefault();
@@ -452,17 +459,19 @@ YUI.add('moodle-core-dragdrop', function(Y) {
if (!draghandle.hasClass(MOVEICON.cssclass)) {
return;
}
// Do nothing if not space or enter.
if (e.keyCode != 13 && e.keyCode != 32) {
if (e.keyCode !== 13 && e.keyCode !== 32 && e.type !== 'click') {
return;
}
// Check the drag groups to see if we are the handler for this node.
draggroups = e.target.getAttribute('data-draggroups').split(' ');
draggroups = draghandle.getAttribute('data-draggroups').split(' ');
var i, j, validgroup = false;
for (i = 0; i < draggroups.length; i++) {
for (j = 0; j < this.groups.length; j++) {
if (draggroups[i] == this.groups[j]) {
if (draggroups[i] === this.groups[j]) {
validgroup = true;
break;
}
+71 -8
View File
@@ -9,8 +9,11 @@ var BODY = Y.one(Y.config.doc.body),
MENUSHOWN : 'action-menu-shown'
},
SELECTOR = {
CAN_RECEIVE_FOCUS_SELECTOR: 'input:not([type="hidden"]), a[href], button, textarea, select, [tabindex]',
MENU : '.moodle-actionmenu[data-enhance=moodle-core-actionmenu]',
MENUCONTENT : '.menu[data-rel=menu-content]',
MENUCONTENTCHILD: 'li a',
MENUCHILD: '.menu li a',
TOGGLE : '.toggle-display'
},
ACTIONMENU,
@@ -57,6 +60,15 @@ ACTIONMENU.prototype = {
*/
owner : null,
/**
* The menu button that toggles this open.
*
* @property menulink
* @type Node
* @protected
*/
menulink: null,
/**
* Called during the initialisation process of the object.
* @method initializer
@@ -102,16 +114,21 @@ ACTIONMENU.prototype = {
this.dialogue.one(SELECTOR.MENUCONTENT).set('aria-hidden', true);
this.dialogue = null;
}
if (this.owner) {
this.owner.removeClass(CSS.MENUSHOWN);
this.owner = null;
}
for (var i in this.events) {
if (this.events[i].detach) {
this.events[i].detach();
}
}
this.events = [];
if (this.owner) {
this.owner.removeClass(CSS.MENUSHOWN);
this.owner = null;
}
if (this.menulink) {
this.menulink.focus();
this.menulink = null;
}
},
/**
@@ -130,13 +147,49 @@ ACTIONMENU.prototype = {
// The menu was visible and the user has clicked to toggle it again.
return;
}
this.showMenu(menu);
this.showMenu(e, menu);
// Close the menu if the user presses escape.
this.events.push(BODY.on('key', this.hideMenu, 'esc', this));
// Close the menu if the user clicks outside the menu.
this.events.push(BODY.on('click', this.hideIfOutside, this));
// Close the menu if the user focuses outside the menu.
this.events.push(BODY.delegate('focus', this.hideIfOutside, '*', this));
// Check tabbing.
this.events.push(menu.delegate('key', this.checkFocus, 'down:9', SELECTOR.MENUCHILD, this));
},
/**
* Check current focus when moving around with the tab key.
* This will ensure that when the etreme menu items are reached, the
* menu is closed and the next DOM element is focused.
*
* @method checkFocus
* @param {EventFacade} e The key event
*/
checkFocus: function(e) {
var nodelist = this.dialogue.all(SELECTOR.MENUCHILD),
firstNode,
lastNode;
if (nodelist) {
firstNode = nodelist.item(0);
lastNode = nodelist.pop();
}
var menulink = this.menulink;
if (e.target === firstNode && e.shiftKey) {
this.hideMenu();
e.preventDefault();
} else if (e.target === lastNode && !e.shiftKey) {
var next;
if (this.hideMenu()) {
next = menulink.next(SELECTOR.CAN_RECEIVE_FOCUS_SELECTOR);
if (next) {
next.focus();
}
}
}
},
/**
@@ -154,21 +207,31 @@ ACTIONMENU.prototype = {
/**
* Displays the menu with the given content and alignment.
* @param {EventFacade} e
* @param {Node} menu
* @param Array align
* @returns {M.core.dialogue|dialogue}
*/
showMenu : function(menu) {
showMenu : function(e, menu) {
Y.log('Displaying an action menu', 'debug', ACTIONMENU.NAME);
var ownerselector = menu.getData('owner'),
menucontent = menu.one(SELECTOR.MENUCONTENT);
menucontent = menu.one(SELECTOR.MENUCONTENT),
menuchild;
this.owner = (ownerselector) ? menu.ancestor(ownerselector) : null;
this.dialogue = menu;
menu.addClass('show');
if (this.owner) {
this.owner.addClass(CSS.MENUSHOWN);
this.menulink = this.owner.one(SELECTOR.TOGGLE);
}
this.constrain(menucontent.set('aria-hidden', false));
if (e.type && e.type === 'key') {
menuchild = menucontent.one(SELECTOR.MENUCONTENTCHILD);
if (menuchild) {
menuchild.focus();
}
}
return true;
},
@@ -44,7 +44,7 @@ Feature: Group assignment submissions
And I fill the moodle form with:
| Group mode | Separate groups |
And I press "Save and return to course"
And I follow "Edit settings"
And I click on "Edit settings" "link" in the "Administration" "block"
And I fill the moodle form with:
| Group mode | Separate groups |
And I press "Save changes"
@@ -25,7 +25,7 @@ Feature: Set a certain number of discussions as a completion condition for a for
And I log in as "teacher1"
And I follow "Course 1"
And I turn editing mode on
And I follow "Edit settings"
And I click on "Edit settings" "link" in the "Administration" "block"
And I fill the moodle form with:
| Enable completion tracking | Yes |
And I press "Save changes"
Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 264 B

+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
]>
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="16px" height="16px" viewBox="0 0 16 16" style="overflow:visible;enable-background:new 0 0 16 16;"
xml:space="preserve" preserveAspectRatio="xMinYMid meet">
<defs>
</defs>
<path style="fill:#999999;" d="M5.2,10.3L0,13.1V16h16v-3l-5.2-2.7C10.3,10,10.2,9.4,10.6,9c0,0,1.4-1.8,1.4-3.8C12,2.3,10.2,0,8,0
S4,2.3,4,5.2C4,7.2,5.4,9,5.4,9C5.8,9.5,5.7,10,5.2,10.3z"/>
</svg>

After

Width:  |  Height:  |  Size: 827 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 345 B

+16
View File
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
]>
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="16px" height="16px" viewBox="0 0 16 16" style="overflow:visible;enable-background:new 0 0 16 16;"
xml:space="preserve">
<defs>
</defs>
<path style="fill:#999999;" d="M4.4,13H0V9.9l2.2-1.3C2.6,8.4,2.6,8,2.3,7.6c0,0-1.3-1.5-1.3-3.2C1,2,2.5,0,4.4,0s3.4,2,3.4,4.4
c0,1.7-1.2,3.2-1.2,3.2c-0.3,0.4-0.2,0.8,0.2,1l1.1,0.6c0.3,0.6,0.6,1.1,0.8,1.4L4.4,13L4.4,13z M16,12.2l-1.9-1
c-0.4-0.2-0.5-0.7-0.2-1c0,0,1.2-1.5,1.2-3.2c0-2.4-1.5-4.4-3.4-4.4S8.3,4.6,8.3,7c0,1.7,1.3,3.2,1.3,3.2c0.3,0.4,0.3,0.8-0.1,1.1
l-4.1,2.3V16H16V12.2z"/>
</svg>

After

Width:  |  Height:  |  Size: 993 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 327 B

+16
View File
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
]>
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="16px" height="16px" viewBox="0 0 16 16" style="overflow:visible;enable-background:new 0 0 16 16;"
xml:space="preserve" preserveAspectRatio="xMinYMid meet">
<defs>
</defs>
<path style="fill:#999999;" d="M3,16H0v-4l3.2-1.7C3.6,10,3.8,9.5,3.4,9C3.4,9,2,7.2,2,5.2C2,2.3,3.8,0,6,0c0.4,0,0.7,0.1,1.1,0.2
c-1.2,1.1-2,3-2,5c0,1.7,0.6,2.7,1,3.5c0.6,0.9,0.1,1-0.3,1.3C5.6,10.1,3,11.4,3,11.4V16z M16,11.9l-3.1-1.6
C12.4,10,12.3,9.4,12.6,9c0,0,1.4-1.8,1.4-3.8C14,2.3,12.2,0,10,0S6,2.3,6,5.2C6,7.2,7.5,9,7.5,9c0.3,0.4,0.2,1-0.3,1.3L4,12v4h12
V11.9z"/>
</svg>

After

Width:  |  Height:  |  Size: 1012 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
]>
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="16px" height="16px" viewBox="-2.1 -5 16 16"
style="overflow:visible;enable-background:new -2.1 -5 16 16;" xml:space="preserve" preserveAspectRatio="xMinYMid meet">
<defs>
</defs>
<path style="fill:#999999;" d="M0.5,0C0,0-0.2,0.3,0.2,0.7l5,5c0.4,0.4,1,0.4,1.4,0l5-5C12,0.3,11.9,0,11.3,0H0.5z"/>
</svg>

After

Width:  |  Height:  |  Size: 761 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 B

+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
]>
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="22px" height="12px" viewBox="0 0 22 12" style="overflow:visible;enable-background:new 0 0 22 12;"
xml:space="preserve">
<defs>
</defs>
<path style="fill:#999999;" d="M11.9,7C12,6.7,12,6.3,12,6s0-0.7-0.1-1l-1.6-0.3c-0.1-0.3-0.2-0.6-0.4-0.9l0.9-1.3
C10.5,2,10,1.5,9.5,1.1L8.1,2C7.9,1.9,7.6,1.8,7.3,1.7L7,0.1C6.7,0,6.3,0,6,0C5.7,0,5.3,0,5,0.1L4.7,1.7C4.4,1.8,4.1,1.9,3.9,2
L2.5,1.1C2,1.5,1.5,2,1.1,2.5L2,3.9C1.9,4.1,1.8,4.4,1.7,4.7L0.1,5C0,5.3,0,5.7,0,6c0,0.3,0,0.7,0.1,1l1.6,0.3
C1.8,7.6,1.9,7.9,2,8.1L1.1,9.5c0.4,0.5,0.9,1,1.4,1.4L3.9,10c0.3,0.1,0.6,0.3,0.9,0.4L5,11.9C5.3,12,5.7,12,6,12c0.3,0,0.7,0,1-0.1
l0.3-1.6c0.3-0.1,0.6-0.2,0.9-0.4l1.3,0.9c0.5-0.4,1-0.9,1.4-1.4L10,8.1c0.2-0.3,0.3-0.6,0.4-0.9L11.9,7z M6,7.5
C5.2,7.5,4.5,6.8,4.5,6S5.2,4.5,6,4.5S7.5,5.2,7.5,6S6.8,7.5,6,7.5z M15,4H22l-3.5,3.5L15,4L15,4z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@@ -169,6 +169,9 @@ img.iconsmall,
-moz-border-radius: 5px;
border-radius: 5px;
}
.block.block_with_controls div.header div.commands img.iconsmall.actionmenu {
width: auto;
}
.course-content ul.topics li.section .right img.spacer,
.course-content ul.topics li.section .left img.spacer {
height: 1px;
@@ -179,13 +182,6 @@ img.iconsmall,
padding: 0;
border-radius: 0;
}
.block .header .commands {
text-align: center;
}
.block-control-actions span.moodle-core-dragdrop-draghandle {
position: relative;
top: 5px;
}
.moodle-actionmenu.show[data-enhanced] .menu a {
color: #333333;
display: block;
@@ -193,4 +189,4 @@ img.iconsmall,
}
.moodle-actionmenu.show[data-enhanced] .menu {
left: 0;
}
}
@@ -486,3 +486,9 @@ body#page-course-view-topics.path-course div.moodle-dialogue-base div.yui3-widge
color: #cc3300;
text-decoration: underline;
}
/* Actionmenu
-------------*/
.jsenabled .moodle-actionmenu[data-enhance] .toggle-display.textmenu .iconsmall {
margin: 4px 4px 4px 2px;
}
+1
View File
@@ -6,6 +6,7 @@
.block .header .commands { text-align: right; clear: both;}
.block .header .commands > a { margin:0 3px; }
.block .header .commands .icon img {width:12px;height:12px;}
.block .header .commands img.actionmenu {width:auto;}
.block .content {padding:4px;}
.block.hidden .content {display: none;}
.block .content .userpicture {width:16px;height:16px;margin-right:6px;}
+45 -7
View File
@@ -102,7 +102,7 @@ img.resize {height: 1em;width: 1em;}
/* Icon styles */
img.icon {height:16px;vertical-align:text-bottom;width:16px;padding-right: 6px;}
.dir-rtl img.icon {padding-left: 6px; padding-right: 0; }
img.iconsmall {height:12px;margin-right:3px;vertical-align:middle;width:12px;}
img.iconsmall {height:12px;margin-right:3px; margin-left: 3px;vertical-align:middle;width:12px;}
img.iconhelp, .helplink img {height:16px; padding-left:3px;vertical-align:text-bottom;width:16px;}
.dir-rtl img.iconhelp, .dir-rtl .helplink img {padding-right: 3px; padding-left: 0; }
img.iconlarge {height: 24px; width: 24px; vertical-align:middle;}
@@ -149,7 +149,10 @@ h4 img.iconhelp,
h5 img.icon,
h5 img.iconhelp,
h6 img.icon,
h6 img.iconhelp {vertical-align: middle;}
h6 img.iconhelp {
vertical-align: middle;
padding: 4px;
}
/** The 1-pixel padding is there to avoid phantom scroll bars on OS X (FF, Safari and Chrome)**/
.no-overflow {overflow:auto;padding-bottom:1px;}
@@ -1475,22 +1478,46 @@ img#persona_signin { cursor: pointer; }
.jsenabled .moodle-actionmenu[data-enhance] {display: block;}
.jsenabled .moodle-actionmenu[data-enhance] .menu {display: none;}
.jsenabled .moodle-actionmenu[data-enhance] .toggle-display {display: inline;opacity: 0.5;filter: alpha(opacity=50);}
.jsenabled .moodle-actionmenu[data-enhance] .toggle-display.textmenu {
display: block;
margin-left: 4px;
padding-left: 4px;
}
.jsenabled .moodle-actionmenu[data-enhance] .toggle-display.textmenu .iconsmall {
margin: 8px 4px 0px 2px;
}
.jsenabled .moodle-actionmenu[data-enhance] .toggle-display.textmenu .caret {
margin-top: 4px;
margin-left: 2px;
}
.jsenabled .moodle-actionmenu[data-enhanced] .toggle-display {opacity: 1;filter: alpha(opacity=100);}
.jsenabled .moodle-actionmenu[data-enhanced] .menu-action-text {display: inline;}
.jsenabled .moodle-actionmenu[data-enhanced] .menu-action-text {
display: inline;
}
.moodle-actionmenu[data-enhanced].show {position: relative;}
.moodle-actionmenu[data-enhanced].show .menu {position: absolute;text-align:left;z-index: 1000;display: block;background-color: #fff;border: 1px solid #ccc;-webkit-border-radius: 5px;-moz-border-radius: 5px;border-radius: 5px;-webkit-box-shadow: 5px 5px 20px 0 #666666;-moz-box-shadow: 5px 5px 20px 0 #666666;box-shadow: 5px 5px 20px 0 #666666;}
.moodle-actionmenu[data-enhanced].show .menu a {display: block;padding: 2px 1em 2px 24px;color: #333333;}
.moodle-actionmenu[data-enhanced].show .menu a > img {margin-left:-20px;}
.moodle-actionmenu[data-enhanced].show .menu a {
display: block;
padding: 4px 1em 4px 28px;
color: #333333;
}
.moodle-actionmenu[data-enhanced].show .menu a > img {
margin: 4px 4px 4px -24px;
padding: 4px;
width: 12px;
height: 12px;
}
.moodle-actionmenu[data-enhanced].show .menu a:hover,
.moodle-actionmenu[data-enhanced].show .menu a:focus {color: #ffffff;background-color: #0088cc;}
.moodle-actionmenu[data-enhanced].show .menu a:first-child {-webkit-border-top-right-radius: 4px;border-top-right-radius: 4px;-webkit-border-top-left-radius: 4px;border-top-left-radius: 4px;-moz-border-radius-topright: 4px;-moz-border-radius-topleft: 4px;}
.moodle-actionmenu[data-enhanced].show .menu a:last-child {-webkit-border-bottom-right-radius: 4px;border-bottom-right-radius: 4px;-webkit-border-bottom-left-radius: 4px;border-bottom-left-radius: 4px;-moz-border-radius-bottomright: 4px;-moz-border-radius-bottomleft: 4px;}
.moodle-actionmenu[data-enhanced].show .menu a.hidden {display: none;}
.moodle-actionmenu[data-enhanced].show .menu img {vertical-align: middle;}
.moodle-actionmenu[data-enhanced].show .menu .iconsmall {margin-right: 8px;}
.moodle-actionmenu[data-enhanced].show .menu > li {display: block;}
.action-menu-shown .moodle-actionmenu[data-enhanced] .toggle-display {background-color: #FFF;}
.block .moodle-actionmenu {text-align: right;}
.dir-rtl .block .moodle-actionmenu {text-align: right;}
@@ -1562,3 +1589,14 @@ a.disabled {
font-style: italic;
color: #808080;
}
.caret {
display: inline-block;
width: 0;
height: 0;
vertical-align: top;
border-top: 4px solid #000;
border-right: 4px solid transparent;
border-left: 4px solid transparent;
content: "";
}
+103 -18
View File
@@ -16,25 +16,86 @@
.course-content ul.section { margin: 1em;}
.sitetopic .section .activity img.activityicon,
.course-content .section .activity img.activityicon {
vertical-align: middle;
vertical-align: text-bottom;
margin-right: 3px;
margin-left: 3px;
width: 24px;
height: 24px;
}
.section .activity .activityinstance .instancename {
vertical-align: bottom;
}
.sitetopic .section .activity .activityinstance,
.course-content .section .activity .activityinstance,
.section .activity .activityinstance {
display: inline-block;
}
.section .activity .editing_move {
position: absolute;
left: 0;
top: 0;
}
.dir-rtl .section .activity .editing_move {
left: auto;
right: 0;
}
.section .activity .mod-indent {
padding-left: 24px;
}
.dir-rtl .section .activity .mod-indent {
padding-left: auto;
padding-right: 24px;
}
.section .activity .actions {
position: absolute;
right: 0;
top: 0;
}
.dir-rtl .section .activity .actions {
left: 0;
right: auto;
}
.sitetopic .section .activity .activityinstance div,
.course-content .section .activity .activityinstance div { display: inline;}
.course-content .section .activity .activityinstance form { display: inline;}
.sitetopic .section .activity .activityinstance,
.course-content .section .activity .activityinstance { padding-right: 1em; }
.course-content .section .activity .activityinstance {
height: 2em;
}
.editing .sitetopic .section .activity .activityinstance,
.editing .course-content .section .activity .activityinstance {
padding-right: 200px;
height: 2em;
display: table-cell;
}
.dir-rtl.editing .sitetopic .section .activity .activityinstance,
.dir-rtl.editing .course-content .section .activity .activityinstance {
padding-left: 200px;
padding-right: auto;
}
.course-content .section .activity .filler {
width: 16px;
height: 16px;
margin: 4px;
display: inline-block;
vertical-align: text-bottom;
}
.dir-rtl .sitetopic .section .activity .activityinstance,
.dir-rtl .course-content .section .activity .activityinstance { padding-right: 0; padding-left: 3em;}
.sitetopic .section .activity .commands,
.course-content .section .activity .commands { white-space: nowrap; display: inline-block; padding: 0 3em 0 0;}
.course-content .section .activity .commands {
white-space: nowrap;
display: inline-block;
}
.dir-rtl .sitetopic .section .activity .commands,
.dir-rtl .course-content .section .activity .commands { padding: 0 0 0 3em;}
@@ -46,18 +107,24 @@
.section .activity .moodle-actionmenu[data-enhanced] .menu > li > * {
display: block;
}
.section .activity .moodle-actionmenu .menubar > li > img {
margin-right: 5px;
vertical-align: text-bottom;
padding:0 3px 0 0;
}
.section .activity .moodle-actionmenu[data-enhanced] .menu {margin-left: -2.8em;}
.section img.iconsmall {
vertical-align: middle;
vertical-align: text-bottom;
width: 16px;
height: 16px;
margin: 4px;
}
.section .editing_title img.iconsmall {
width: 12px;
height: 12px;
margin: 4px 8px 4px 0;
}
.section .activity.editor_displayed a.editing_title,
.section .activity.editor_displayed .moodle-actionmenu {
display: none;
}
.single-section h3.sectionname {text-align:center;clear:both;}
.sitetopic .section li.activity,
.course-content .section li.activity {padding: .2em;}
@@ -107,11 +174,7 @@
.path-site li.activity > div,
.path-course-view li.activity > div {position:relative;}
.path-course-view li.activity span.autocompletion,
.path-course-view li.activity form.togglecompletion {position: absolute; top: 0; right: .2em;}
.path-course-view li.activity span.autocompletion img,
.path-course-view li.activity form.togglecompletion input {position:absolute; top: .25em; right: 0px;}
.path-course-view li.activity form.togglecompletion .ajaxworking {position:absolute; right: 22px; top: 5px; width: 16px; height: 16px; background: url([[pix:i/ajaxloader]]) no-repeat;}
.path-course-view li.activity form.togglecompletion .ajaxworking {position:absolute; right: 22px; width: 16px; height: 16px; background: url([[pix:i/ajaxloader]]) no-repeat;}
.path-course-view li.activity form.togglecompletion div {display:inline;}
.dir-rtl.path-course-view li.activity form.togglecompletion,
.dir-rtl.path-course-view li.activity span.autocompletion {left:1.7em;right:auto;padding:0px;}
@@ -214,6 +277,14 @@ li.section.hidden span.commands a.editing_show {cursor:default;}
.path-course .clearfloat {float:none; clear:both;height:0px;}
.section .spinner {
height: 16px;
width: 16px;
}
.section .activity .spinner {
margin: 4px;
}
/* Quick edit of module name */
.sitetopic .section .activity form.activityinstance,
@@ -235,7 +306,10 @@ span.editinstructions {
border:1px solid #ddd;
}
.dir-rtl span.editinstructions { left: auto; right: 32px;}
input.titleeditor { width: 330px; vertical-align: text-bottom; }
input.titleeditor { vertical-align: text-bottom; }
.editing .course-content .section .activity.editor_displayed .activityinstance {
padding: initial;
}
/* Course drag and drop upload styles */
#dndupload-status {width:40%;margin:0 30%;padding:6px;border:1px solid #ddd;text-align:center;background:#ffc;position:absolute;z-index:9999;box-shadow:2px 2px 5px 1px #ccc;border-radius:0px 0px 8px 8px;z-index: 0;}
@@ -296,6 +370,17 @@ input.titleeditor { width: 330px; vertical-align: text-bottom; }
#course-category-listings .listing-actions .moodle-actionmenu:not([data-enhanced]) > .menubar a {color:inherit;}
#course-category-listings .listing-actions .moodle-actionmenu:not([data-enhanced]) > .menubar a > img {display:none;}
.jsenabled #course-category-listings .moodle-actionmenu[data-enhance] .toggle-display img {
width: auto;
}
.jsenabled #course-category-listings .moodle-actionmenu[data-enhance] .toggle-display.textmenu {
padding-right: 4px;
}
.jsenabled #course-category-listings .moodle-actionmenu[data-enhance] .toggle-display.textmenu .caret {
margin-top: 10px;
}
#course-category-listings .item-actions {margin-right:1em;display:inline-block;display:initial;}
#course-category-listings .item-actions img {margin: 0 4px;vertical-align:inherit;}
#course-category-listings .item-actions .menu img {max-width:none;width:12px;}
+1 -1
View File
@@ -104,7 +104,7 @@ fieldset#general {
}
.editing .block .header .commands {
padding: 2px 10px;
padding: 2px 0;
}
.block .header .block_action {
@@ -35,6 +35,10 @@
height: 12px;
}
.block .header .commands img.actionmenu {
width:auto;
}
.block .content {
padding: 4px 14px;
}
+20 -6
View File
@@ -225,6 +225,7 @@ h4 img.iconhelp, h4 img.icon,
h5 img.iconhelp, h5 img.icon,
h6 img.iconhelp, h6 img.icon {
vertical-align: middle;
padding: 4px;
}
.dir-rtl img.iconhelp, .dir-rtl .helplink img {
padding-right: 3px;
@@ -2030,6 +2031,22 @@ img#persona_signin {
display: inline; /** JS is enabled, we'll be using it so return display to normal **/
.opacity(50);
}
.toggle-display.textmenu {
display: block;
margin-left: 4px;
padding-left: 4px;
.iconsmall {
margin: 4px 4px 4px 0px;
padding: 8px 4px 0px 2px;
vertical-align: text-bottom;
}
.caret {
margin-top: 8px;
margin-left: 2px;
}
}
}
.moodle-actionmenu[data-enhanced] {
.toggle-display {
@@ -2037,6 +2054,7 @@ img#persona_signin {
}
.menu-action-text {
display:inline;
vertical-align: middle;
}
}
}
@@ -2059,7 +2077,7 @@ img#persona_signin {
a {
display: block;
color: @dropdownLinkColor;
padding:2px 1em 2px 24px;
padding:2px 1em 2px 28px;
&:hover,
&:focus {
color: @dropdownLinkColorHover;
@@ -2079,7 +2097,7 @@ img#persona_signin {
vertical-align: middle;
}
.iconsmall {
margin-left:-20px;
margin: 4px 4px 4px -24px;
}
> li {
display:block;
@@ -2108,10 +2126,6 @@ img#persona_signin {
}
}
.action-menu-shown .moodle-actionmenu[data-enhanced] .toggle-display {
background-color: #FFF;
}
.block .moodle-actionmenu {
text-align: right;
}
+176 -21
View File
@@ -38,8 +38,107 @@
.course-content ul.section {
margin: 1em;
}
.section .activity img.activityicon {
.section {
.spinner {
height: 16px;
width: 16px;
}
.activity {
.spinner {
margin: 4px;
left: 0;
position: absolute;
}
.editing_move {
/* Move the move icon to the start of the line */
position: absolute;
left: 0;
top: 0;
}
.mod-indent {
/**
* Add appropriate padding such that nothing overlaps the
* absolute positioned move icon.
*/
padding-left: 32px;
}
/* The command block for each activity */
.actions {
position: absolute;
right: 0;
top: 0;
}
.activityinstance {
.dimmed {
img.activityicon {
opacity: 0.5;
filter: alpha(opacity=50);
}
}
}
}
.filler {
width: 16px;
height: 16px;
padding: 0.3em;
display: inline-block;
}
.activity.editor_displayed {
a.editing_title,
.moodle-actionmenu {
display: none;
}
div.activityinstance {
padding: initial;
input {
margin-bottom: initial;
padding-top: initial;
padding-bottom: initial;
vertical-align: text-bottom;
}
}
}
}
.dir-rtl .section {
.activity {
.spinner {
left: 0;
}
.editing_move {
/* Move the move icon to the start of the line */
left: auto;
right: 0;
}
.mod-indent {
/**
* Add appropriate padding such that nothing overlaps the
* absolute positioned move icon.
*/
padding-left: auto;
padding-right: 32px;
}
/* The command block for each activity */
.actions {
left: 0;
right: auto;
}
}
}
.activity img.activityicon {
margin-right: 6px;
vertical-align: text-bottom;
}
.dir-rtl .section .activity img.activityicon {
margin-left: 6px;
@@ -49,12 +148,30 @@
.section .activity .activityinstance div {
display: inline-block;
}
.editing .section .activity .activityinstance {
min-width: 40%;
.editing {
.section {
.activity {
.activityinstance {
min-width: 40%;
display: table-cell;
padding-right: 200px;
min-height: 2em;
}
}
}
}
.section .activity .activityinstance > a {
display: block;
.dir-rtl.editing {
.section {
.activity {
.activityinstance {
padding-left: 200px;
padding-right: 0;
}
}
}
}
.editing_show + .editing_assign,
.editing_hide + .editing_assign {
// if roles icon missing, add space
@@ -246,24 +363,20 @@
position: relative;
padding: 0 0 0 16px;
}
.path-course-view li.activity span.autocompletion,
.path-course-view li.activity form.togglecompletion {
float: right;
width: 0; /* Reduce the width of the control to 0 and rely on natural overflow */
.path-course-view li.activity span.autocompletion img {
vertical-align: text-bottom;
}
.path-course-view li.activity span.autocompletion img,
.path-course-view li.activity form.togglecompletion img {
max-width: none; /* The width is 0 so ensure we don't end up with a relative max-width */
}
.path-course-view li.activity form.togglecompletion .ajaxworking {
width: 16px;
height: 16px;
position: absolute;
right: 22px;
top: 3px;
background: url([[pix:i/ajaxloader]]) no-repeat;
}
.dir-rtl.path-course-view li.activity form.togglecompletion,
.dir-rtl.path-course-view li.activity span.autocompletion {
float: left;
}
.dir-rtl.path-course-view .completionprogress {
float: none;
}
@@ -613,15 +726,41 @@ span.editinstructions {
margin: 10px 0 20px;
}
.section .activity .moodle-actionmenu .iconsmall {
max-width: none !important; /** reset sets 100% !important which breaks on IE8 without this !important */
width:16px;
height:16px;
padding:0.3em;
.section {
.activity {
.iconsmall {
width: 16px;
height: 16px;
}
}
.editing_title {
.iconsmall {
width: 12px;
height: 12px;
margin: 8px 8px 0px 0;
padding: 4px 8px 0px 0;
vertical-align: text-bottom;
}
}
.moodle-actionmenu {
.iconsmall {
max-width: none !important; /** reset sets 100% !important which breaks on IE8 without this !important */
width:16px;
height:16px;
padding: 4px;
vertical-align: text-bottom;
}
}
.moodle-actionmenu[data-enhanced] {
.menu {
img {
width: 12px;
height: 12px;
}
}
}
}
/**
* Course management page
* Palette
@@ -667,6 +806,22 @@ span.editinstructions {
.moodle-actionmenu {
white-space:nowrap;
}
.moodle-actionmenu[data-enhance] {
.toggle-display {
img {
width: auto;
}
&.textmenu {
padding-right: 4px;
.caret {
margin-top: 12px;
}
}
}
}
.listing-actions {
text-align:center;
padding:0.4rem 0.3rem 0.3rem;
@@ -230,7 +230,6 @@
border-bottom: thin solid #eee;
}
.course-content .section .activity .commands {
display: block;
text-align: right;
}
/** Handles display of the activity chooser on small screens **/
@@ -375,18 +374,6 @@
float: left;
}
// Hide broken drag'n'drop options on touch devices MDL-38371
// Not a great workaround, landscape iPads are wider than this,
// and a resized window on a netbook could be smaller, but best
// we can do with CSS. There might be a JS-based solution.
.section .side,
.editing_move {
display: none;
}
.activityinstance > a {
display: block;
}
// GRID & CONTAINERS
// -----------------
// Remove width from containers
File diff suppressed because one or more lines are too long
+1
View File
@@ -427,6 +427,7 @@ input[type=text],textarea,select,input[type=password]{
clear:both;
margin:0;
padding:5px 0 0 10px;
margin: 0 10px;
}
.block-region .block .content .commands{
border:0 none;