mirror of
https://github.com/moodle/moodle.git
synced 2025-01-19 06:18:28 +01:00
Merge branch 'MDL-58428-master' of git://github.com/sarjona/moodle
This commit is contained in:
commit
44d5c25469
@ -43,8 +43,11 @@
|
||||
"default": "Default value"
|
||||
}
|
||||
}}
|
||||
<div class="form-item clearfix" id="{{id}}">
|
||||
<div class="form-label">
|
||||
{{!
|
||||
Setting.
|
||||
}}
|
||||
<div class="form-item row" id="{{id}}">
|
||||
<div class="form-label col-sm-3 text-sm-right">
|
||||
<label {{#labelfor}}for="{{labelfor}}"{{/labelfor}}>
|
||||
{{{title}}}
|
||||
{{#override}}
|
||||
@ -54,16 +57,16 @@
|
||||
<div class="form-warning">{{warning}}</div>
|
||||
{{/warning}}
|
||||
</label>
|
||||
<span class="form-shortname">{{{name}}}</span>
|
||||
<span class="form-shortname d-block small text-muted">{{{name}}}</span>
|
||||
</div>
|
||||
<div class="form-setting">
|
||||
<div class="form-setting col-sm-9">
|
||||
{{#error}}
|
||||
<div><span class="error">{{error}}</span></div>
|
||||
{{/error}}
|
||||
{{{element}}}
|
||||
{{#default}}
|
||||
<div class="form-defaultinfo {{#forceltr}}text-ltr{{/forceltr}}">{{{default}}}</div>
|
||||
<div class="form-defaultinfo text-muted {{#forceltr}}text-ltr{{/forceltr}}">{{{default}}}</div>
|
||||
{{/default}}
|
||||
<div class="form-description mt-3">{{{description}}}</div>
|
||||
</div>
|
||||
<div class="form-description">{{{description}}}</div>
|
||||
</div>
|
||||
|
@ -35,13 +35,16 @@
|
||||
"haspreviewconfig": false
|
||||
}
|
||||
}}
|
||||
{{!
|
||||
Setting configcolourpicker.
|
||||
}}
|
||||
<div class="form-colourpicker defaultsnext">
|
||||
<div class="admin_colourpicker clearfix">
|
||||
{{#icon}}
|
||||
{{>core/pix_icon}}
|
||||
{{/icon}}
|
||||
</div>
|
||||
<input type="text" name="{{name}}" id="{{id}}" value="{{value}}" size="12" class="text-ltr">
|
||||
<input type="text" name="{{name}}" id="{{id}}" value="{{value}}" size="12" class="form-control text-ltr">
|
||||
{{#haspreviewconfig}}
|
||||
<input type="button" id="{{id}}_preview" value={{#quote}}{{#str}}preview{{/str}}{{/quote}} class="admin_colourpicker_preview">
|
||||
{{/haspreviewconfig}}
|
||||
|
@ -33,13 +33,18 @@
|
||||
"options": [ { "name": "Minutes", "value": "mins", "selected": true } ]
|
||||
}
|
||||
}}
|
||||
{{!
|
||||
Setting configduration.
|
||||
}}
|
||||
<div class="form-duration defaultsnext">
|
||||
<input type="text" size="5" id="{{id}}v" name="{{name}}[v]" value="{{value}}" class="text-ltr">
|
||||
<label class="accesshide" for="{{id}}u">{{#str}}durationunits, admin{{/str}}</label>
|
||||
<select id="{{id}}u" name="{{name}}[u]">
|
||||
{{#options}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/options}}
|
||||
</select>
|
||||
<div class="form-inline">
|
||||
<input type="text" size="5" id="{{id}}v" name="{{name}}[v]" value="{{value}}" class="form-control text-ltr">
|
||||
<label class="sr-only" for="{{id}}u">{{#str}}durationunits, admin{{/str}}</label>
|
||||
<select id="{{id}}u" name="{{name}}[u]" class="form-control">
|
||||
{{#options}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/options}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -38,15 +38,20 @@
|
||||
"valid": false
|
||||
}
|
||||
}}
|
||||
{{!
|
||||
Setting configfile.
|
||||
}}
|
||||
<div class="form-file defaultsnext">
|
||||
<input type="text" name="{{name}}" id="{{id}}" size="{{size}}" value="{{value}}" class="text-ltr" {{#readonly}}readonly{{/readonly}}>
|
||||
{{#showvalidity}}
|
||||
{{#valid}}
|
||||
<span class="pathok">✔</span>
|
||||
{{/valid}}
|
||||
{{^valid}}
|
||||
<span class="patherror">✘</span>
|
||||
{{/valid}}
|
||||
{{/showvalidity}}
|
||||
<div class="form-inline">
|
||||
<input type="text" name="{{name}}" id="{{id}}" size="{{size}}" value="{{value}}" class="form-control text-ltr" {{#readonly}}readonly{{/readonly}}>
|
||||
{{#showvalidity}}
|
||||
{{#valid}}
|
||||
<span class="text-success">✔</span>
|
||||
{{/valid}}
|
||||
{{^valid}}
|
||||
<span class="text-danger">✘</span>
|
||||
{{/valid}}
|
||||
{{/showvalidity}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -34,9 +34,12 @@
|
||||
{ "name": "Option 2", "value": "V", "selected": true } ]
|
||||
}
|
||||
}}
|
||||
{{!
|
||||
Setting configmultiselect.
|
||||
}}
|
||||
<div class="form-select">
|
||||
<input type="hidden" name="{{name}}[xxxxx]" value="1">
|
||||
<select id="{{id}}" name="{{name}}[]" size="{{size}}" multiple>
|
||||
<select id="{{id}}" name="{{name}}[]" size="{{size}}" class="form-control" multiple>
|
||||
{{#options}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/options}}
|
||||
|
@ -53,13 +53,16 @@
|
||||
]
|
||||
}
|
||||
}}
|
||||
{{!
|
||||
Setting configmultiselect with optgroup support.
|
||||
}}
|
||||
<div class="form-select">
|
||||
<input type="hidden" name="{{name}}[xxxxx]" value="1">
|
||||
<select id="{{id}}" name="{{name}}[]" size="{{size}}" multiple>
|
||||
{{#options}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/options}}
|
||||
{{#optgroups}}
|
||||
<select id="{{id}}" name="{{name}}[]" size="{{size}}" class="form-control" multiple>
|
||||
{{#options}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/options}}
|
||||
{{#optgroups}}
|
||||
<optgroup label="{{label}}">
|
||||
{{#options}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
|
@ -34,8 +34,11 @@
|
||||
]
|
||||
}
|
||||
}}
|
||||
{{!
|
||||
Setting configselect.
|
||||
}}
|
||||
<div class="form-select defaultsnext">
|
||||
<select id="{{id}}" name="{{name}}">
|
||||
<select id="{{id}}" name="{{name}}" class="custom-select">
|
||||
{{#options}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/options}}
|
||||
|
@ -51,8 +51,11 @@
|
||||
]
|
||||
}
|
||||
}}
|
||||
{{!
|
||||
Setting configselect with optgroup support.
|
||||
}}
|
||||
<div class="form-select defaultsnext">
|
||||
<select id="{{id}}" name="{{name}}">
|
||||
<select id="{{id}}" name="{{name}}" class="custom-select">
|
||||
{{#options}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/options}}
|
||||
@ -66,3 +69,4 @@
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -37,6 +37,9 @@
|
||||
"attributes": [ { "name": "readonly", "value": "readonly" } ]
|
||||
}
|
||||
}}
|
||||
{{!
|
||||
Setting configtext.
|
||||
}}
|
||||
<div class="form-text defaultsnext">
|
||||
<input type="text" name="{{name}}" value="{{value}}" size="{{size}}" id="{{id}}" class="{{#forceltr}}text-ltr{{/forceltr}}"{{#attributes}} {{name}}="{{value}}"{{/attributes}}>
|
||||
<input type="text" name="{{name}}" value="{{value}}" size="{{size}}" id="{{id}}" class="form-control {{#forceltr}}text-ltr{{/forceltr}}">
|
||||
</div>
|
||||
|
@ -36,6 +36,9 @@
|
||||
"id": "test0"
|
||||
}
|
||||
}}
|
||||
{{!
|
||||
Setting configtextarea.
|
||||
}}
|
||||
<div class="form-textarea">
|
||||
<textarea rows="{{rows}}" cols="{{cols}}" id="{{id}}" name="{{name}}" spellcheck="true" class="{{#forceltr}}text-ltr{{/forceltr}}">{{value}}</textarea>
|
||||
<textarea rows="{{rows}}" cols="{{cols}}" id="{{id}}" name="{{name}}" spellcheck="true" class="form-control {{#forceltr}}text-ltr{{/forceltr}}">{{value}}</textarea>
|
||||
</div>
|
||||
|
@ -39,18 +39,23 @@
|
||||
]
|
||||
}
|
||||
}}
|
||||
<div class="form-time defaultsnext text-ltr">
|
||||
<label class="accesshide" for="{{id}}h">{{#str}}hours{{/str}}</label>
|
||||
<select id="{{id}}h" name="{{name}}[h]">
|
||||
{{#hours}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/hours}}
|
||||
</select>:
|
||||
<label class="accesshide" for="{{id}}m">{{#str}}minutes{{/str}}</label>
|
||||
<select id="{{id}}m" name="{{name}}[m]">
|
||||
{{#minutes}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/minutes}}
|
||||
</select>
|
||||
{{!
|
||||
Setting configtime.
|
||||
}}
|
||||
<div class="form-time defaultsnext">
|
||||
<div class="form-inline text-ltr">
|
||||
<label class="sr-only" for="{{id}}h">{{#str}}hours{{/str}}</label>
|
||||
<select id="{{id}}h" name="{{name}}[h]" class="custom-select">
|
||||
{{#hours}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/hours}}
|
||||
</select>:
|
||||
<label class="sr-only" for="{{id}}m">{{#str}}minutes{{/str}}</label>
|
||||
<select id="{{id}}m" name="{{name}}[m]" class="custom-select">
|
||||
{{#minutes}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/minutes}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -37,9 +37,12 @@
|
||||
]
|
||||
}
|
||||
}}
|
||||
{{!
|
||||
Setting courselist_frontpage.
|
||||
}}
|
||||
<div class="form-group">
|
||||
{{#selects}}
|
||||
<select id="{{id}}{{key}}" name="{{name}}[]" class="form-select">
|
||||
<select id="{{id}}{{key}}" name="{{name}}[]" class="custom-select">
|
||||
{{#options}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/options}}
|
||||
|
@ -34,12 +34,13 @@
|
||||
{{!
|
||||
Setting description.
|
||||
}}
|
||||
<div class="form-item form-horizontal clearfix">
|
||||
<div class="form-label">
|
||||
<div class="form-item row">
|
||||
<div class="form-label col-sm-3 text-sm-right">
|
||||
<label>
|
||||
{{{title}}}
|
||||
</label>
|
||||
<span class="form-shortname ">{{{name}}}</span>
|
||||
</div>
|
||||
<div class="controls felement fstatic">{{{description}}}</div>
|
||||
</div>
|
||||
<div class="form-setting col-sm-9">
|
||||
<div class="form-description">{{{description}}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -29,7 +29,10 @@
|
||||
]
|
||||
}
|
||||
}}
|
||||
<table class="generaltable">
|
||||
{{!
|
||||
Setting devicedetectregex.
|
||||
}}
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{#str}}devicedetectregexexpression, admin{{/str}}</th>
|
||||
@ -40,10 +43,10 @@
|
||||
{{#expressions}}
|
||||
<tr>
|
||||
<td class="c{{index}}">
|
||||
<input type="text" name="{{name}}[expression{{index}}]" class="form-text text-ltr" value="{{expression}}">
|
||||
<input type="text" name="{{name}}[expression{{index}}]" class="form-control" value="{{expression}}">
|
||||
</td>
|
||||
<td class="c{{index}}">
|
||||
<input type="text" name="{{name}}[value{{index}}]" class="form-text text-ltr" value="{{value}}">
|
||||
<input type="text" name="{{name}}[value{{index}}]" class="form-control" value="{{value}}">
|
||||
</td>
|
||||
</tr>
|
||||
{{/expressions}}
|
||||
|
@ -32,6 +32,9 @@
|
||||
]
|
||||
}
|
||||
}}
|
||||
{{!
|
||||
Setting emoticons.
|
||||
}}
|
||||
<div class="form-group">
|
||||
<table id="emoticonsetting" class="admintable generaltable">
|
||||
<thead>
|
||||
@ -48,7 +51,7 @@
|
||||
<tr>
|
||||
{{#fields}}
|
||||
<td class="c{{index}}">
|
||||
<input type="text" name="{{name}}[{{field}}]" class="form-text text-ltr" value="{{value}}">
|
||||
<input type="text" name="{{name}}[{{field}}]" class="form-text form-control text-ltr" value="{{value}}">
|
||||
</td>
|
||||
{{/fields}}
|
||||
<td>
|
||||
|
@ -37,8 +37,11 @@
|
||||
"advanced": true
|
||||
}
|
||||
}}
|
||||
{{!
|
||||
Setting configselect.
|
||||
}}
|
||||
<div class="form-group">
|
||||
<select id="{{id}}" name="{{name}}[value]" class="form-select">
|
||||
<select id="{{id}}" name="{{name}}[value]" class="form-select custom-select">
|
||||
{{#options}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/options}}
|
||||
|
@ -36,8 +36,11 @@
|
||||
"showsave": true
|
||||
}
|
||||
}}
|
||||
{{!
|
||||
Settings.
|
||||
}}
|
||||
<form action="{{actionurl}}" method="post" id="adminsettings">
|
||||
<div class="settingsform clearfix">
|
||||
<div class="settingsform">
|
||||
{{#params}}
|
||||
<input type="hidden" name="{{name}}" value="{{value}}">
|
||||
<input type="hidden" name="action" value="save-settings">
|
||||
@ -49,8 +52,10 @@
|
||||
{{/title}}
|
||||
{{{settings}}}
|
||||
{{#showsave}}
|
||||
<div class="form-buttons">
|
||||
<input type="submit" class="form-submit" value={{#quote}}{{#str}}savechanges, admin{{/str}}{{/quote}}>
|
||||
<div class="row">
|
||||
<div class="offset-sm-3 col-sm-3">
|
||||
<button type="submit" class="btn btn-primary">{{#str}}savechanges, admin{{/str}}</button>
|
||||
</div>
|
||||
</div>
|
||||
{{/showsave}}
|
||||
</div>
|
||||
|
@ -58,8 +58,10 @@
|
||||
</fieldset>
|
||||
{{/results}}
|
||||
{{#showsave}}
|
||||
<div class="form-buttons">
|
||||
<input type="submit" class="form-submit" value={{#quote}}{{#str}}savechanges, admin{{/str}}{{/quote}}>
|
||||
<div class="row">
|
||||
<div class="offset-sm-3 col-sm-3">
|
||||
<button type="submit" class="btn btn-primary">{{#str}}savechanges, admin{{/str}}</button>
|
||||
</div>
|
||||
</div>
|
||||
{{/showsave}}
|
||||
{{/hasresults}}
|
||||
|
@ -55,16 +55,12 @@ class behat_admin extends behat_base {
|
||||
|
||||
foreach ($data as $label => $value) {
|
||||
|
||||
// We expect admin block to be visible, otherwise go to homepage.
|
||||
if (!$this->getSession()->getPage()->find('css', '.block_settings')) {
|
||||
$this->getSession()->visit($this->locate_path('/'));
|
||||
$this->wait(self::TIMEOUT * 1000, self::PAGE_READY_JS);
|
||||
}
|
||||
$this->execute('behat_navigation::i_select_from_flat_navigation_drawer', [get_string('administrationsite')]);
|
||||
|
||||
// Search by label.
|
||||
$searchbox = $this->find_field(get_string('searchinsettings', 'admin'));
|
||||
$searchbox = $this->find_field(get_string('query', 'admin'));
|
||||
$searchbox->setValue($label);
|
||||
$submitsearch = $this->find('css', 'form.adminsearchform input[type=submit]');
|
||||
$submitsearch = $this->find('css', 'form input[type=submit][name=search]');
|
||||
$submitsearch->press();
|
||||
|
||||
$this->wait(self::TIMEOUT * 1000, self::PAGE_READY_JS);
|
||||
@ -78,21 +74,24 @@ class behat_admin extends behat_base {
|
||||
|
||||
// Single element settings.
|
||||
try {
|
||||
$fieldxpath = "//*[self::input | self::textarea | self::select][not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]" .
|
||||
"[@id=//label[contains(normalize-space(.), $label)]/@for or " .
|
||||
"@id=//span[contains(normalize-space(.), $label)]/preceding-sibling::label[1]/@for]";
|
||||
$fieldxpath = "//*[self::input | self::textarea | self::select]" .
|
||||
"[not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]" .
|
||||
"[@id=//label[contains(normalize-space(.), $label)]/@for or " .
|
||||
"@id=//span[contains(normalize-space(.), $label)]/preceding-sibling::label[1]/@for]";
|
||||
$fieldnode = $this->find('xpath', $fieldxpath, $exception);
|
||||
|
||||
$formfieldtypenode = $this->find('xpath', $fieldxpath . "/ancestor::div[@class='form-setting']" .
|
||||
"/child::div[contains(concat(' ', @class, ' '), ' form-')]/child::*/parent::div");
|
||||
$formfieldtypenode = $this->find('xpath', $fieldxpath .
|
||||
"/ancestor::div[contains(concat(' ', @class, ' '), ' form-setting ')]" .
|
||||
"/child::div[contains(concat(' ', @class, ' '), ' form-')]/child::*/parent::div");
|
||||
|
||||
} catch (ElementNotFoundException $e) {
|
||||
|
||||
// Multi element settings, interacting only the first one.
|
||||
$fieldxpath = "//*[label[normalize-space(.)= $label]|span[normalize-space(.)= $label]]/" .
|
||||
"ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' form-item ')]" .
|
||||
"/descendant::div[@class='form-group']/descendant::*[self::input | self::textarea | self::select]" .
|
||||
"[not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]";
|
||||
$fieldxpath = "//*[label[contains(., $label)]|span[contains(., $label)]]" .
|
||||
"/ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' form-item ')]" .
|
||||
"/descendant::div[contains(concat(' ', @class, ' '), ' form-group ')]" .
|
||||
"/descendant::*[self::input | self::textarea | self::select]" .
|
||||
"[not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]";
|
||||
$fieldnode = $this->find('xpath', $fieldxpath);
|
||||
|
||||
// It is the same one that contains the type.
|
||||
@ -101,6 +100,7 @@ class behat_admin extends behat_base {
|
||||
|
||||
// Getting the class which contains the field type.
|
||||
$classes = explode(' ', $formfieldtypenode->getAttribute('class'));
|
||||
$type = false;
|
||||
foreach ($classes as $class) {
|
||||
if (substr($class, 0, 5) == 'form-') {
|
||||
$type = substr($class, 5);
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
|
||||
|
||||
require_once(__DIR__ . '/../../../../../lib/behat/behat_base.php');
|
||||
require_once(__DIR__ . '/../../../../../../lib/behat/behat_base.php');
|
||||
|
||||
/**
|
||||
* Test context 1
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
|
||||
|
||||
require_once(__DIR__ . '/../../../../../lib/behat/behat_base.php');
|
||||
require_once(__DIR__ . '/../../../../../../lib/behat/behat_base.php');
|
||||
|
||||
/**
|
||||
* Test context 2
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
|
||||
|
||||
require_once(__DIR__ . '/../../../../../lib/behat/behat_base.php');
|
||||
require_once(__DIR__ . '/../../../../../../../lib/behat/behat_base.php');
|
||||
|
||||
/**
|
||||
* Default Theme test context 1
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
|
||||
|
||||
require_once(__DIR__ . '/../behat_test_context_1.php');
|
||||
require_once(__DIR__ . '/../../core/behat_test_context_1.php');
|
||||
|
||||
/**
|
||||
* Theme test context 1
|
||||
@ -33,6 +33,6 @@ require_once(__DIR__ . '/../behat_test_context_1.php');
|
||||
* @copyright 2016 Rajesh Taneja <rajesh@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_theme_nofeatures_behat_test_context_1 extends behat_test_context_1 {
|
||||
class behat_theme_nofeatures_behat_test_context_2 extends behat_test_context_2 {
|
||||
|
||||
}
|
@ -24,7 +24,7 @@
|
||||
|
||||
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
|
||||
|
||||
require_once(__DIR__ . '/../../../../../lib/behat/behat_base.php');
|
||||
require_once(__DIR__ . '/../../../../../../../lib/behat/behat_base.php');
|
||||
|
||||
/**
|
||||
* Theme test context 2
|
||||
@ -33,6 +33,6 @@ require_once(__DIR__ . '/../../../../../lib/behat/behat_base.php');
|
||||
* @copyright 2016 Rajesh Taneja <rajesh@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_theme_nofeatures_test_context_2 extends behat_base {
|
||||
class behat_theme_nofeatures_test_context_1 extends behat_base {
|
||||
|
||||
}
|
@ -24,7 +24,7 @@
|
||||
|
||||
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
|
||||
|
||||
require_once(__DIR__ . '/../behat_test_context_1.php');
|
||||
require_once(__DIR__ . '/../../core/behat_test_context_1.php');
|
||||
|
||||
/**
|
||||
* Theme test context 1
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
|
||||
|
||||
require_once(__DIR__ . '/../../../../../lib/behat/behat_base.php');
|
||||
require_once(__DIR__ . '/../../../../../../../lib/behat/behat_base.php');
|
||||
|
||||
/**
|
||||
* Theme test context 2
|
||||
|
@ -108,7 +108,6 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
array('nofeatures', __DIR__.'/fixtures/theme/nofeatures'),
|
||||
array('defaulttheme', __DIR__.'/fixtures/theme/defaulttheme'),
|
||||
);
|
||||
|
||||
// List of themes is const for test.
|
||||
if ($notheme) {
|
||||
$themelist = array('defaulttheme');
|
||||
@ -116,6 +115,13 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
$themelist = array('withfeatures', 'nofeatures', 'defaulttheme');
|
||||
}
|
||||
|
||||
$thememap = [];
|
||||
foreach ($themelist as $themename) {
|
||||
$mock = $this->getMockBuilder('theme_config');
|
||||
$mock->disableOriginalConstructor();
|
||||
$thememap[] = [$themename, $mock->getMock()];
|
||||
}
|
||||
|
||||
$behatconfigutil->expects($this->any())
|
||||
->method('get_list_of_themes')
|
||||
->will($this->returnValue($themelist));
|
||||
@ -125,6 +131,11 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
->method('get_theme_test_directory')
|
||||
->will($this->returnValueMap($map));
|
||||
|
||||
// Theme directory for testing.
|
||||
$behatconfigutil->expects($this->any())
|
||||
->method('get_theme_config')
|
||||
->will($this->returnValueMap($thememap));
|
||||
|
||||
$behatconfigutil->expects($this->any())
|
||||
->method('get_default_theme')
|
||||
->will($this->returnValue('defaulttheme'));
|
||||
@ -138,7 +149,7 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
public function test_get_config_file_contents_with_single_run() {
|
||||
|
||||
$mockbuilder = $this->getMockBuilder('behat_config_util');
|
||||
$mockbuilder->setMethods(array('get_theme_test_directory', 'get_list_of_themes', 'get_default_theme'));
|
||||
$mockbuilder->setMethods(array('get_theme_test_directory', 'get_list_of_themes', 'get_default_theme', 'get_theme_config'));
|
||||
|
||||
$behatconfigutil = $mockbuilder->getMock();
|
||||
|
||||
@ -177,7 +188,7 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
public function test_get_config_file_contents_with_single_run_no_theme() {
|
||||
|
||||
$mockbuilder = $this->getMockBuilder('behat_config_util');
|
||||
$mockbuilder->setMethods(array('get_theme_test_directory', 'get_list_of_themes', 'get_default_theme'));
|
||||
$mockbuilder->setMethods(array('get_theme_test_directory', 'get_list_of_themes', 'get_default_theme', 'get_theme_config'));
|
||||
|
||||
$behatconfigutil = $mockbuilder->getMock();
|
||||
|
||||
@ -231,7 +242,7 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
public function test_get_config_file_contents_with_parallel_run() {
|
||||
|
||||
$mockbuilder = $this->getMockBuilder('behat_config_util');
|
||||
$mockbuilder->setMethods(array('get_theme_test_directory', 'get_list_of_themes', 'get_default_theme'));
|
||||
$mockbuilder->setMethods(array('get_theme_test_directory', 'get_list_of_themes', 'get_default_theme', 'get_theme_config'));
|
||||
|
||||
$behatconfigutil = $mockbuilder->getMock();
|
||||
|
||||
@ -334,7 +345,7 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
public function test_get_config_file_contents_with_parallel_run_optimize_tags() {
|
||||
|
||||
$mockbuilder = $this->getMockBuilder('behat_config_util');
|
||||
$mockbuilder->setMethods(array('get_theme_test_directory', 'get_list_of_themes', 'get_default_theme'));
|
||||
$mockbuilder->setMethods(array('get_theme_test_directory', 'get_list_of_themes', 'get_default_theme', 'get_theme_config'));
|
||||
|
||||
$behatconfigutil = $mockbuilder->getMock();
|
||||
|
||||
@ -479,7 +490,7 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
|
||||
$mockbuilder = $this->getMockBuilder('behat_config_util');
|
||||
$mockbuilder->setMethods(array('get_theme_test_directory', 'get_list_of_themes', 'get_blacklisted_tests_for_theme',
|
||||
'get_default_theme'));
|
||||
'get_default_theme', 'get_theme_config'));
|
||||
|
||||
$behatconfigutil = $mockbuilder->getMock();
|
||||
|
||||
@ -543,7 +554,7 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
|
||||
$mockbuilder = $this->getMockBuilder('behat_config_util');
|
||||
$mockbuilder->setMethods(array('get_theme_test_directory', 'get_list_of_themes', 'get_blacklisted_tests_for_theme',
|
||||
'get_default_theme'));
|
||||
'get_default_theme', 'get_theme_config'));
|
||||
|
||||
$behatconfigutil = $mockbuilder->getMock();
|
||||
|
||||
@ -621,7 +632,7 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
public function test_core_features_to_include_in_specified_theme() {
|
||||
|
||||
$mockbuilder = $this->getMockBuilder('behat_config_util');
|
||||
$mockbuilder->setMethods(array('get_theme_test_directory', 'get_list_of_themes', 'get_default_theme'));
|
||||
$mockbuilder->setMethods(array('get_theme_test_directory', 'get_list_of_themes', 'get_default_theme', 'get_theme_config'));
|
||||
|
||||
$behatconfigutil = $mockbuilder->getMock();
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
This files describes API changes in the tool_behat code.
|
||||
|
||||
=== 3.7 ===
|
||||
* Behat will now look for behat step definitions in the current
|
||||
theme and any parents the theme may have.
|
||||
=== 2.7 ===
|
||||
* Constants behat_base::cap_allow, behat_base::cap_prevent and
|
||||
behat_base::cap_prohibit have been removed in favour of the
|
||||
|
@ -20,7 +20,6 @@
|
||||
Moodle progress bar template for tool_lp.
|
||||
|
||||
The purpose of this template is to render a progress bar with a brief description.
|
||||
Inherits core/columns-1to2.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
@ -41,17 +40,8 @@
|
||||
}
|
||||
|
||||
}}
|
||||
<div class="row-fluid rtl-compatible">
|
||||
<div class="span4">
|
||||
<div class="progresstext">
|
||||
{{$progresstext}}{{progresstextvalue}}{{/progresstext}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="span8">
|
||||
<div class="progress">
|
||||
<div class="bar" style="width: {{$percentage}}{{percentagevalue}}{{/percentage}}%;" role="progressbar" aria-valuenow="{{$percentage}}{{percentagevalue}}{{/percentage}}" aria-valuemin="0" aria-valuemax="100">
|
||||
{{$percentlabel}}{{percentlabelvalue}}{{/percentlabel}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="progress-{{uniqid}}">
|
||||
{{$progresstext}}{{progresstextvalue}}{{/progresstext}}
|
||||
</div>
|
||||
<progress class="progress" aria-describedby="progress-{{uniqid}}"
|
||||
value="{{$percentage}}{{percentagevalue}}{{/percentage}}" max="100"></progress>
|
||||
|
@ -7,7 +7,7 @@ Feature: Clear scheduled task fail delay
|
||||
Background:
|
||||
Given the scheduled task "\core\task\send_new_user_passwords_task" has a fail delay of "60" seconds
|
||||
And I log in as "admin"
|
||||
And I navigate to "Server > Scheduled tasks" in site administration
|
||||
And I navigate to "Server > Tasks > Scheduled tasks" in site administration
|
||||
|
||||
Scenario: Clear fail delay
|
||||
When I click on "Clear" "text" in the "Send new user passwords" "table_row"
|
||||
|
@ -6,7 +6,7 @@ Feature: Manage scheduled tasks
|
||||
|
||||
Background:
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Server > Scheduled tasks" in site administration
|
||||
And I navigate to "Server > Tasks > Scheduled tasks" in site administration
|
||||
|
||||
Scenario: Disable scheduled task
|
||||
When I click on "Edit task schedule: Log table cleanup" "link" in the "Log table cleanup" "table_row"
|
||||
|
@ -45,18 +45,22 @@
|
||||
}
|
||||
|
||||
}}
|
||||
<div class="modal" data-role="flexitour-step">
|
||||
<div data-role="arrow"></div>
|
||||
<div class="modal-dialog" role="document" data-role="flexitour-step">
|
||||
<div class="modal-content">
|
||||
<div class="tooltip-arrow" data-role="arrow"></div>
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true" data-role="end">×</button>
|
||||
<h3 data-placeholder="title"></h3>
|
||||
<h5 class="modal-title" data-placeholder="title"></h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close" data-role="end">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
<div class="modal-body" data-placeholder="body">
|
||||
</div>
|
||||
<div class="modal-body" data-placeholder="body"></div>
|
||||
<div class="modal-footer">
|
||||
<div class="btn-group">
|
||||
<button href="#" class="btn" data-role="previous">{{# str }} previous, moodle {{/ str }}</button>
|
||||
<button href="#" class="btn btn-primary" data-role="next">{{# str }} next, moodle {{/ str }}</button>
|
||||
</div>
|
||||
<button class="btn" data-role="end"> {{# str }} endtour, tool_usertours {{/ str }} </button>
|
||||
<button type="button" class="btn btn-secondary" data-role="previous">{{# str }} previous, moodle {{/ str }}</button>
|
||||
<button type="button" class="btn btn-primary" data-role="next">{{# str }} next, moodle {{/ str }}</button>
|
||||
<button class="btn btn-secondary" data-role="end"> {{# str }} endtour, tool_usertours {{/ str }} </button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -6,7 +6,7 @@ Feature: Add a bookmarks to an admin pages
|
||||
|
||||
Background:
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Server > Scheduled tasks" in site administration
|
||||
And I navigate to "Server > Tasks > Scheduled tasks" in site administration
|
||||
And I click on "Bookmark this page" "link" in the "Admin bookmarks" "block"
|
||||
And I log out
|
||||
|
||||
|
@ -1,15 +1,18 @@
|
||||
<div class="searchform">
|
||||
<form action="{{actionurl}}" style="display: inline;">
|
||||
<fieldset class="invisiblefieldset">
|
||||
<legend class="accesshide">{{#str}}search{{/str}}</legend>
|
||||
<input type="hidden" name="id" value="{{courseid}}">
|
||||
<label class="accesshide" for="searchform_search">{{#str}}search{{/str}}</label>
|
||||
<input id="searchform_search" name="search" type="text" size="16">
|
||||
<button id="searchform_button" type="submit" title={{#quote}}{{#str}}search{{/str}}{{/quote}}>{{#str}}go{{/str}}</button><br>
|
||||
<a href="{{advancedsearchurl}}">{{#str}}advancedsearch, block_search_forums{{/str}}</a>
|
||||
{{#helpicon}}
|
||||
{{>core/help_icon}}
|
||||
{{/helpicon}}
|
||||
</fieldset>
|
||||
<form action="{{actionurl}}" class="form-inline">
|
||||
<input type="hidden" name="id" value="{{courseid}}">
|
||||
<div class="input-group w-100">
|
||||
<label class="sr-only" for="searchform_search">{{#str}}search{{/str}}</label>
|
||||
<input id="searchform_search" name="search" type="text" class="form-control" size="10">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-secondary" id="searchform_button" type="submit">{{#str}}go{{/str}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="mt-3">
|
||||
<a href="{{advancedsearchurl}}">{{#str}}advancedsearch, block_search_forums{{/str}}</a>
|
||||
{{#helpicon}}
|
||||
{{>core/help_icon}}
|
||||
{{/helpicon}}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -143,14 +143,12 @@ class block_settings_renderer extends plugin_renderer_base {
|
||||
}
|
||||
|
||||
public function search_form(moodle_url $formtarget, $searchvalue) {
|
||||
$content = html_writer::start_tag('form', array('class'=>'adminsearchform', 'method'=>'get', 'action'=>$formtarget, 'role' => 'search'));
|
||||
$content .= html_writer::start_tag('div');
|
||||
$content .= html_writer::tag('label', s(get_string('searchinsettings', 'admin')), array('for'=>'adminsearchquery', 'class'=>'accesshide'));
|
||||
$content .= html_writer::empty_tag('input', array('id'=>'adminsearchquery', 'type'=>'text', 'name'=>'query', 'value'=>s($searchvalue)));
|
||||
$content .= html_writer::empty_tag('input', array('type'=>'submit', 'value'=>s(get_string('search'))));
|
||||
$content .= html_writer::end_tag('div');
|
||||
$content .= html_writer::end_tag('form');
|
||||
return $content;
|
||||
$data = [
|
||||
'action' => $formtarget->out(false),
|
||||
'label' => get_string('searchinsettings', 'admin'),
|
||||
'searchvalue' => $searchvalue
|
||||
];
|
||||
return $this->render_from_template('block_settings/search_form', $data);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -46,15 +46,13 @@ class behat_blocks extends behat_base {
|
||||
* @param string $blockname
|
||||
*/
|
||||
public function i_add_the_block($blockname) {
|
||||
$this->execute('behat_forms::i_set_the_field_to',
|
||||
array("bui_addblock", $this->escape($blockname))
|
||||
);
|
||||
$addblock = get_string('addblock');
|
||||
$this->execute('behat_navigation::i_select_from_flat_navigation_drawer', $addblock);
|
||||
|
||||
// If we are running without javascript we need to submit the form.
|
||||
if (!$this->running_javascript()) {
|
||||
$this->execute('behat_general::i_click_on_in_the',
|
||||
array(get_string('go'), "button", "#add_block", "css_element")
|
||||
);
|
||||
$this->execute('behat_general::i_click_on_in_the', [$blockname, 'link_exact', '#region-main', 'css_element']);
|
||||
} else {
|
||||
$this->execute('behat_general::i_click_on_in_the', [$blockname, 'link_exact', $addblock, 'dialogue']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,7 +106,7 @@ class behat_blocks extends behat_base {
|
||||
}
|
||||
|
||||
$this->execute('behat_general::i_click_on_in_the',
|
||||
array(get_string('actions'), "link", $this->escape($blockname), "block")
|
||||
array("a[data-toggle='dropdown']", "css_element", $this->escape($blockname), "block")
|
||||
);
|
||||
}
|
||||
|
||||
@ -137,7 +135,17 @@ class behat_blocks extends behat_base {
|
||||
* @param string $blockname
|
||||
*/
|
||||
public function the_add_block_selector_should_contain_block($blockname) {
|
||||
$this->execute('behat_forms::the_select_box_should_contain', [get_string('addblock'), $blockname]);
|
||||
$addblock = get_string('addblock');
|
||||
$this->execute('behat_navigation::i_select_from_flat_navigation_drawer', $addblock);
|
||||
|
||||
$cancelstr = get_string('cancel');
|
||||
if (!$this->running_javascript()) {
|
||||
$this->execute('behat_general::should_exist_in_the', [$blockname, 'link_exact', '#region-main', 'css_element']);
|
||||
$this->execute('behat_general::i_click_on_in_the', [$cancelstr, 'link_exact', '#region-main', 'css_element']);
|
||||
} else {
|
||||
$this->execute('behat_general::should_exist_in_the', [$blockname, 'link_exact', $addblock, 'dialogue']);
|
||||
$this->execute('behat_general::i_click_on_in_the', [$cancelstr, 'button', $addblock, 'dialogue']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -147,6 +155,16 @@ class behat_blocks extends behat_base {
|
||||
* @param string $blockname
|
||||
*/
|
||||
public function the_add_block_selector_should_not_contain_block($blockname) {
|
||||
$this->execute('behat_forms::the_select_box_should_not_contain', [get_string('addblock'), $blockname]);
|
||||
$addblock = get_string('addblock');
|
||||
$this->execute('behat_navigation::i_select_from_flat_navigation_drawer', $addblock);
|
||||
|
||||
$cancelstr = get_string('cancel');
|
||||
if (!$this->running_javascript()) {
|
||||
$this->execute('behat_general::should_not_exist_in_the', [$blockname, 'link_exact', '#region-main', 'css_element']);
|
||||
$this->execute('behat_general::i_click_on_in_the', [$cancelstr, 'link_exact', '#region-main', 'css_element']);
|
||||
} else {
|
||||
$this->execute('behat_general::should_not_exist_in_the', [$blockname, 'link_exact', $addblock, 'dialogue']);
|
||||
$this->execute('behat_general::i_click_on_in_the', [$cancelstr, 'button', $addblock, 'dialogue']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,15 +24,41 @@
|
||||
"day": "Today",
|
||||
"url": "http://example.com/",
|
||||
"title": "Monday 2nd January",
|
||||
"content": "<img class='icon smallicon' alt='icon' src='../../../pix/i/siteevent.svg'>Test site event"
|
||||
"content": "<img class='icon smallicon' src='../../../pix/i/siteevent.svg'>Test site event"
|
||||
}
|
||||
}}
|
||||
{{< core/hover_tooltip }}
|
||||
{{$anchor}}
|
||||
<a href="{{url}}">{{$day}}{{day}}{{/day}}</a>
|
||||
{{/anchor}}
|
||||
{{$tooltip}}
|
||||
<b>{{$title}}{{title}}{{/title}}</b>
|
||||
{{$content}}{{{content}}}{{/content}}
|
||||
{{/tooltip}}
|
||||
{{/ core/hover_tooltip }}
|
||||
<a {{!
|
||||
}} id="calendar-day-popover-link-{{courseid}}-{{year}}-{{yday}}-{{uniqid}}"{{!
|
||||
}} href="{{$url}}{{url}}{{/url}}"{{!
|
||||
}} data-container="body"{{!
|
||||
}} data-toggle="popover"{{!
|
||||
}} data-html="true"{{!
|
||||
}} data-trigger="hover"{{!
|
||||
}} data-placement="top"{{!
|
||||
}} data-title="{{$title}}{{title}}{{/title}}"{{!
|
||||
}} data-alternate="{{$nocontent}}{{/nocontent}}"{{!
|
||||
}}>{{$day}}{{day}}{{/day}}</a>
|
||||
<div class="hidden">
|
||||
{{$content}}{{/content}}
|
||||
</div>
|
||||
{{#js}}
|
||||
require(['jquery'], function($) {
|
||||
require(['theme_boost/popover'], function() {
|
||||
var target = $("#calendar-day-popover-link-{{courseid}}-{{year}}-{{yday}}-{{uniqid}}");
|
||||
target.popover({
|
||||
content: function() {
|
||||
var source = target.next().find("> *:not('.hidden')");
|
||||
var content = $('<div>');
|
||||
|
||||
if (source.length) {
|
||||
content.html(source.clone(false));
|
||||
} else {
|
||||
content.html(target.data('alternate'));
|
||||
}
|
||||
|
||||
return content.html();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
{{/js}}
|
||||
|
@ -139,13 +139,15 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
$listing = core_course_category::get(0)->get_children();
|
||||
|
||||
$attributes = array(
|
||||
'class' => 'ml',
|
||||
'role' => 'tree',
|
||||
'aria-labelledby' => 'category-listing-title'
|
||||
'class' => 'ml-1 list-unstyled',
|
||||
'role' => 'tree',
|
||||
'aria-labelledby' => 'category-listing-title'
|
||||
);
|
||||
|
||||
$html = html_writer::start_div('category-listing');
|
||||
$html .= html_writer::tag('h3', get_string('categories'), array('id' => 'category-listing-title'));
|
||||
$html = html_writer::start_div('category-listing card w-100');
|
||||
$html .= html_writer::tag('h3', get_string('categories'),
|
||||
array('class' => 'card-header', 'id' => 'category-listing-title'));
|
||||
$html .= html_writer::start_div('card-body');
|
||||
$html .= $this->category_listing_actions($category);
|
||||
$html .= html_writer::start_tag('ul', $attributes);
|
||||
foreach ($listing as $listitem) {
|
||||
@ -155,16 +157,17 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
$subcategories = $listitem->get_children();
|
||||
}
|
||||
$html .= $this->category_listitem(
|
||||
$listitem,
|
||||
$subcategories,
|
||||
$listitem->get_children_count(),
|
||||
$selectedcategory,
|
||||
$selectedparents
|
||||
$listitem,
|
||||
$subcategories,
|
||||
$listitem->get_children_count(),
|
||||
$selectedcategory,
|
||||
$selectedparents
|
||||
);
|
||||
}
|
||||
$html .= html_writer::end_tag('ul');
|
||||
$html .= $this->category_bulk_actions($category);
|
||||
$html .= html_writer::end_div();
|
||||
$html .= html_writer::end_div();
|
||||
return $html;
|
||||
}
|
||||
|
||||
@ -181,20 +184,20 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
* @return string
|
||||
*/
|
||||
public function category_listitem(core_course_category $category, array $subcategories, $totalsubcategories,
|
||||
$selectedcategory = null, $selectedcategories = array()) {
|
||||
$selectedcategory = null, $selectedcategories = array()) {
|
||||
|
||||
$isexpandable = ($totalsubcategories > 0);
|
||||
$isexpanded = (!empty($subcategories));
|
||||
$activecategory = ($selectedcategory === $category->id);
|
||||
$attributes = array(
|
||||
'class' => 'listitem listitem-category',
|
||||
'data-id' => $category->id,
|
||||
'data-expandable' => $isexpandable ? '1' : '0',
|
||||
'data-expanded' => $isexpanded ? '1' : '0',
|
||||
'data-selected' => $activecategory ? '1' : '0',
|
||||
'data-visible' => $category->visible ? '1' : '0',
|
||||
'role' => 'treeitem',
|
||||
'aria-expanded' => $isexpanded ? 'true' : 'false'
|
||||
'class' => 'listitem listitem-category list-group-item list-group-item-action',
|
||||
'data-id' => $category->id,
|
||||
'data-expandable' => $isexpandable ? '1' : '0',
|
||||
'data-expanded' => $isexpanded ? '1' : '0',
|
||||
'data-selected' => $activecategory ? '1' : '0',
|
||||
'data-visible' => $category->visible ? '1' : '0',
|
||||
'role' => 'treeitem',
|
||||
'aria-expanded' => $isexpanded ? 'true' : 'false'
|
||||
);
|
||||
$text = $category->get_formatted_name();
|
||||
if ($category->parent) {
|
||||
@ -205,12 +208,12 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
}
|
||||
$courseicon = $this->output->pix_icon('i/course', get_string('courses'));
|
||||
$bcatinput = array(
|
||||
'type' => 'checkbox',
|
||||
'name' => 'bcat[]',
|
||||
'value' => $category->id,
|
||||
'class' => 'bulk-action-checkbox',
|
||||
'aria-label' => get_string('bulkactionselect', 'moodle', $text),
|
||||
'data-action' => 'select'
|
||||
'type' => 'checkbox',
|
||||
'name' => 'bcat[]',
|
||||
'value' => $category->id,
|
||||
'class' => 'bulk-action-checkbox',
|
||||
'aria-label' => get_string('bulkactionselect', 'moodle', $text),
|
||||
'data-action' => 'select'
|
||||
);
|
||||
|
||||
if (!$category->can_resort_subcategories() && !$category->has_manage_capability()) {
|
||||
@ -220,34 +223,36 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
|
||||
$viewcaturl = new moodle_url('/course/management.php', array('categoryid' => $category->id));
|
||||
if ($isexpanded) {
|
||||
$icon = $this->output->pix_icon('t/switch_minus', get_string('collapse'), 'moodle', array('class' => 'tree-icon', 'title' => ''));
|
||||
$icon = $this->output->pix_icon('t/switch_minus', get_string('collapse'),
|
||||
'moodle', array('class' => 'tree-icon', 'title' => ''));
|
||||
$icon = html_writer::link(
|
||||
$viewcaturl,
|
||||
$icon,
|
||||
array(
|
||||
'class' => 'float-left',
|
||||
'data-action' => 'collapse',
|
||||
'title' => get_string('collapsecategory', 'moodle', $text),
|
||||
'aria-controls' => 'subcategoryof'.$category->id
|
||||
)
|
||||
$viewcaturl,
|
||||
$icon,
|
||||
array(
|
||||
'class' => 'float-left',
|
||||
'data-action' => 'collapse',
|
||||
'title' => get_string('collapsecategory', 'moodle', $text),
|
||||
'aria-controls' => 'subcategoryof'.$category->id
|
||||
)
|
||||
);
|
||||
} else if ($isexpandable) {
|
||||
$icon = $this->output->pix_icon('t/switch_plus', get_string('expand'), 'moodle', array('class' => 'tree-icon', 'title' => ''));
|
||||
$icon = $this->output->pix_icon('t/switch_plus', get_string('expand'),
|
||||
'moodle', array('class' => 'tree-icon', 'title' => ''));
|
||||
$icon = html_writer::link(
|
||||
$viewcaturl,
|
||||
$icon,
|
||||
array(
|
||||
'class' => 'float-left',
|
||||
'data-action' => 'expand',
|
||||
'title' => get_string('expandcategory', 'moodle', $text)
|
||||
)
|
||||
$viewcaturl,
|
||||
$icon,
|
||||
array(
|
||||
'class' => 'float-left',
|
||||
'data-action' => 'expand',
|
||||
'title' => get_string('expandcategory', 'moodle', $text)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$icon = $this->output->pix_icon(
|
||||
'i/empty',
|
||||
'',
|
||||
'moodle',
|
||||
array('class' => 'tree-icon'));
|
||||
'i/empty',
|
||||
'',
|
||||
'moodle',
|
||||
array('class' => 'tree-icon'));
|
||||
$icon = html_writer::span($icon, 'float-left');
|
||||
}
|
||||
$actions = \core_course\management\helper::get_category_listitem_actions($category);
|
||||
@ -268,7 +273,7 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
$textattributes['aria-label'] = $textlabel;
|
||||
}
|
||||
$html .= html_writer::link($viewcaturl, $text, $textattributes);
|
||||
$html .= html_writer::start_div('float-right');
|
||||
$html .= html_writer::start_div('float-right d-flex');
|
||||
if ($category->idnumber) {
|
||||
$html .= html_writer::tag('span', s($category->idnumber), array('class' => 'dimmed idnumber'));
|
||||
}
|
||||
@ -277,28 +282,28 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
}
|
||||
$countid = 'course-count-'.$category->id;
|
||||
$html .= html_writer::span(
|
||||
html_writer::span($category->get_courses_count()) .
|
||||
html_writer::span(get_string('courses'), 'accesshide', array('id' => $countid)) .
|
||||
$courseicon,
|
||||
'course-count dimmed',
|
||||
array('aria-labelledby' => $countid)
|
||||
html_writer::span($category->get_courses_count()) .
|
||||
html_writer::span(get_string('courses'), 'accesshide', array('id' => $countid)) .
|
||||
$courseicon,
|
||||
'course-count dimmed',
|
||||
array('aria-labelledby' => $countid)
|
||||
);
|
||||
$html .= html_writer::end_div();
|
||||
$html .= html_writer::end_div();
|
||||
if ($isexpanded) {
|
||||
$html .= html_writer::start_tag('ul',
|
||||
array('class' => 'ml', 'role' => 'group', 'id' => 'subcategoryof'.$category->id));
|
||||
array('class' => 'ml', 'role' => 'group', 'id' => 'subcategoryof'.$category->id));
|
||||
$catatlevel = \core_course\management\helper::get_expanded_categories($category->path);
|
||||
$catatlevel[] = array_shift($selectedcategories);
|
||||
$catatlevel = array_unique($catatlevel);
|
||||
foreach ($subcategories as $listitem) {
|
||||
$childcategories = (in_array($listitem->id, $catatlevel)) ? $listitem->get_children() : array();
|
||||
$html .= $this->category_listitem(
|
||||
$listitem,
|
||||
$childcategories,
|
||||
$listitem->get_children_count(),
|
||||
$selectedcategory,
|
||||
$selectedcategories
|
||||
$listitem,
|
||||
$childcategories,
|
||||
$listitem->get_children_count(),
|
||||
$selectedcategory,
|
||||
$selectedcategories
|
||||
);
|
||||
}
|
||||
$html .= html_writer::end_tag('ul');
|
||||
@ -327,7 +332,7 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
|
||||
if ($cancreatecategory) {
|
||||
$url = new moodle_url('/course/editcategory.php', array('parent' => $category->id));
|
||||
$actions[] = html_writer::link($url, get_string('createnewcategory'));
|
||||
$actions[] = html_writer::link($url, get_string('createnewcategory'), array('class' => 'btn btn-default'));
|
||||
}
|
||||
if (core_course_category::can_approve_course_requests()) {
|
||||
$actions[] = html_writer::link(new moodle_url('/course/pending.php'), get_string('coursespending'));
|
||||
@ -335,7 +340,7 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
if (count($actions) === 0) {
|
||||
return '';
|
||||
}
|
||||
return html_writer::div(join(' | ', $actions), 'listing-actions category-listing-actions');
|
||||
return html_writer::div(join(' ', $actions), 'listing-actions category-listing-actions mb-3');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -480,20 +485,19 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
* Renders a course listing.
|
||||
*
|
||||
* @param core_course_category $category The currently selected category. This is what the listing is focused on.
|
||||
* @param core_course_list_element $course The currently selected course.
|
||||
* @param core_course_list_element $course The currently selected course.
|
||||
* @param int $page The page being displayed.
|
||||
* @param int $perpage The number of courses to display per page.
|
||||
* @param string|null $viewmode The view mode the page is in, one out of 'default', 'combined', 'courses' or 'categories'.
|
||||
* @return string
|
||||
*/
|
||||
public function course_listing(core_course_category $category = null, core_course_list_element $course = null,
|
||||
$page = 0, $perpage = 20,
|
||||
$viewmode = 'default') {
|
||||
$page = 0, $perpage = 20, $viewmode = 'default') {
|
||||
|
||||
if ($category === null) {
|
||||
$html = html_writer::start_div('select-a-category');
|
||||
$html .= html_writer::tag('h3', get_string('courses'),
|
||||
array('id' => 'course-listing-title', 'tabindex' => '0'));
|
||||
array('id' => 'course-listing-title', 'tabindex' => '0'));
|
||||
$html .= $this->output->notification(get_string('selectacategory'), 'notifymessage');
|
||||
$html .= html_writer::end_div();
|
||||
return $html;
|
||||
@ -507,8 +511,8 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
$page = $totalpages - 1;
|
||||
}
|
||||
$options = array(
|
||||
'offset' => $page * $perpage,
|
||||
'limit' => $perpage
|
||||
'offset' => $page * $perpage,
|
||||
'limit' => $perpage
|
||||
);
|
||||
$courseid = isset($course) ? $course->id : null;
|
||||
$class = '';
|
||||
@ -519,15 +523,16 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
$class .= ' lastpage';
|
||||
}
|
||||
|
||||
$html = html_writer::start_div('course-listing'.$class, array(
|
||||
'data-category' => $category->id,
|
||||
'data-page' => $page,
|
||||
'data-totalpages' => $totalpages,
|
||||
'data-totalcourses' => $totalcourses,
|
||||
'data-canmoveoutof' => $category->can_move_courses_out_of() && $category->can_move_courses_into()
|
||||
$html = html_writer::start_div('card course-listing w-100'.$class, array(
|
||||
'data-category' => $category->id,
|
||||
'data-page' => $page,
|
||||
'data-totalpages' => $totalpages,
|
||||
'data-totalcourses' => $totalcourses,
|
||||
'data-canmoveoutof' => $category->can_move_courses_out_of() && $category->can_move_courses_into()
|
||||
));
|
||||
$html .= html_writer::tag('h3', $category->get_formatted_name(),
|
||||
array('id' => 'course-listing-title', 'tabindex' => '0'));
|
||||
array('id' => 'course-listing-title', 'tabindex' => '0', 'class' => 'card-header'));
|
||||
$html .= html_writer::start_div('card-body');
|
||||
$html .= $this->course_listing_actions($category, $course, $perpage);
|
||||
$html .= $this->listing_pagination($category, $page, $perpage, false, $viewmode);
|
||||
$html .= html_writer::start_tag('ul', array('class' => 'ml course-list', 'role' => 'group'));
|
||||
@ -538,6 +543,7 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
$html .= $this->listing_pagination($category, $page, $perpage, true, $viewmode);
|
||||
$html .= $this->course_bulk_actions($category);
|
||||
$html .= html_writer::end_div();
|
||||
$html .= html_writer::end_div();
|
||||
return $html;
|
||||
}
|
||||
|
||||
@ -588,7 +594,7 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
* This function will be called for every course being displayed by course_listing.
|
||||
*
|
||||
* @param core_course_category $category The currently selected category and the category the course belongs to.
|
||||
* @param core_course_list_element $course The course to produce HTML for.
|
||||
* @param core_course_list_element $course The course to produce HTML for.
|
||||
* @param int $selectedcourse The id of the currently selected course.
|
||||
* @return string
|
||||
*/
|
||||
@ -596,19 +602,19 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
|
||||
$text = $course->get_formatted_name();
|
||||
$attributes = array(
|
||||
'class' => 'listitem listitem-course',
|
||||
'data-id' => $course->id,
|
||||
'data-selected' => ($selectedcourse == $course->id) ? '1' : '0',
|
||||
'data-visible' => $course->visible ? '1' : '0'
|
||||
'class' => 'listitem listitem-course list-group-item list-group-item-action',
|
||||
'data-id' => $course->id,
|
||||
'data-selected' => ($selectedcourse == $course->id) ? '1' : '0',
|
||||
'data-visible' => $course->visible ? '1' : '0'
|
||||
);
|
||||
|
||||
$bulkcourseinput = array(
|
||||
'type' => 'checkbox',
|
||||
'name' => 'bc[]',
|
||||
'value' => $course->id,
|
||||
'class' => 'bulk-action-checkbox',
|
||||
'aria-label' => get_string('bulkactionselect', 'moodle', $text),
|
||||
'data-action' => 'select'
|
||||
'type' => 'checkbox',
|
||||
'name' => 'bc[]',
|
||||
'value' => $course->id,
|
||||
'class' => 'bulk-action-checkbox',
|
||||
'aria-label' => get_string('bulkactionselect', 'moodle', $text),
|
||||
'data-action' => 'select'
|
||||
);
|
||||
if (!$category->has_manage_capability()) {
|
||||
// Very very hardcoded here.
|
||||
@ -654,7 +660,7 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
$actions = array();
|
||||
if ($category->can_create_course()) {
|
||||
$url = new moodle_url('/course/edit.php', array('category' => $category->id, 'returnto' => 'catmanage'));
|
||||
$actions[] = html_writer::link($url, get_string('createnewcourse'));
|
||||
$actions[] = html_writer::link($url, get_string('createnewcourse'), array('class' => 'btn btn-default'));
|
||||
}
|
||||
if ($category->can_request_course()) {
|
||||
// Request a new course.
|
||||
@ -675,42 +681,42 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
$timecreatedurl = new moodle_url($baseurl, array('resort' => 'timecreated'));
|
||||
$timecreateddescurl = new moodle_url($baseurl, array('resort' => 'timecreateddesc'));
|
||||
$menu = new action_menu(array(
|
||||
new action_menu_link_secondary($fullnameurl,
|
||||
null,
|
||||
get_string('sortbyx', 'moodle', get_string('fullnamecourse'))),
|
||||
new action_menu_link_secondary($fullnameurldesc,
|
||||
null,
|
||||
get_string('sortbyxreverse', 'moodle', get_string('fullnamecourse'))),
|
||||
new action_menu_link_secondary($shortnameurl,
|
||||
null,
|
||||
get_string('sortbyx', 'moodle', get_string('shortnamecourse'))),
|
||||
new action_menu_link_secondary($shortnameurldesc,
|
||||
null,
|
||||
get_string('sortbyxreverse', 'moodle', get_string('shortnamecourse'))),
|
||||
new action_menu_link_secondary($idnumberurl,
|
||||
null,
|
||||
get_string('sortbyx', 'moodle', get_string('idnumbercourse'))),
|
||||
new action_menu_link_secondary($idnumberdescurl,
|
||||
null,
|
||||
get_string('sortbyxreverse', 'moodle', get_string('idnumbercourse'))),
|
||||
new action_menu_link_secondary($timecreatedurl,
|
||||
null,
|
||||
get_string('sortbyx', 'moodle', get_string('timecreatedcourse'))),
|
||||
new action_menu_link_secondary($timecreateddescurl,
|
||||
null,
|
||||
get_string('sortbyxreverse', 'moodle', get_string('timecreatedcourse')))
|
||||
new action_menu_link_secondary($fullnameurl,
|
||||
null,
|
||||
get_string('sortbyx', 'moodle', get_string('fullnamecourse'))),
|
||||
new action_menu_link_secondary($fullnameurldesc,
|
||||
null,
|
||||
get_string('sortbyxreverse', 'moodle', get_string('fullnamecourse'))),
|
||||
new action_menu_link_secondary($shortnameurl,
|
||||
null,
|
||||
get_string('sortbyx', 'moodle', get_string('shortnamecourse'))),
|
||||
new action_menu_link_secondary($shortnameurldesc,
|
||||
null,
|
||||
get_string('sortbyxreverse', 'moodle', get_string('shortnamecourse'))),
|
||||
new action_menu_link_secondary($idnumberurl,
|
||||
null,
|
||||
get_string('sortbyx', 'moodle', get_string('idnumbercourse'))),
|
||||
new action_menu_link_secondary($idnumberdescurl,
|
||||
null,
|
||||
get_string('sortbyxreverse', 'moodle', get_string('idnumbercourse'))),
|
||||
new action_menu_link_secondary($timecreatedurl,
|
||||
null,
|
||||
get_string('sortbyx', 'moodle', get_string('timecreatedcourse'))),
|
||||
new action_menu_link_secondary($timecreateddescurl,
|
||||
null,
|
||||
get_string('sortbyxreverse', 'moodle', get_string('timecreatedcourse')))
|
||||
));
|
||||
$menu->set_menu_trigger(get_string('resortcourses'));
|
||||
$actions[] = $this->render($menu);
|
||||
}
|
||||
$strall = get_string('all');
|
||||
$menu = new action_menu(array(
|
||||
new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 5)), null, 5),
|
||||
new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 10)), null, 10),
|
||||
new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 20)), null, 20),
|
||||
new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 50)), null, 50),
|
||||
new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 100)), null, 100),
|
||||
new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 999)), null, $strall),
|
||||
new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 5)), null, 5),
|
||||
new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 10)), null, 10),
|
||||
new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 20)), null, 20),
|
||||
new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 50)), null, 50),
|
||||
new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 100)), null, 100),
|
||||
new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 999)), null, $strall),
|
||||
));
|
||||
if ((int)$perpage === 999) {
|
||||
$perpage = $strall;
|
||||
@ -718,7 +724,7 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
$menu->attributes['class'] .= ' courses-per-page';
|
||||
$menu->set_menu_trigger(get_string('perpagea', 'moodle', $perpage));
|
||||
$actions[] = $this->render($menu);
|
||||
return html_writer::div(join(' | ', $actions), 'listing-actions course-listing-actions');
|
||||
return html_writer::div(join(' ', $actions), 'listing-actions course-listing-actions');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -800,20 +806,25 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
/**
|
||||
* Renderers detailed course information.
|
||||
*
|
||||
* @param core_course_list_element $course The course to display details for.
|
||||
* @param core_course_list_element $course The course to display details for.
|
||||
* @return string
|
||||
*/
|
||||
public function course_detail(core_course_list_element $course) {
|
||||
$details = \core_course\management\helper::get_course_detail_array($course);
|
||||
$fullname = $details['fullname']['value'];
|
||||
|
||||
$html = html_writer::start_div('course-detail');
|
||||
$html .= html_writer::tag('h3', $fullname, array('id' => 'course-detail-title', 'tabindex' => '0'));
|
||||
$html = html_writer::start_div('course-detail card');
|
||||
$html .= html_writer::start_div('card-header');
|
||||
$html .= html_writer::tag('h3', $fullname, array('id' => 'course-detail-title',
|
||||
'class' => 'card-title', 'tabindex' => '0'));
|
||||
$html .= html_writer::end_div();
|
||||
$html .= html_writer::start_div('card-body');
|
||||
$html .= $this->course_detail_actions($course);
|
||||
foreach ($details as $class => $data) {
|
||||
$html .= $this->detail_pair($data['key'], $data['value'], $class);
|
||||
}
|
||||
$html .= html_writer::end_div();
|
||||
$html .= html_writer::end_div();
|
||||
return $html;
|
||||
}
|
||||
|
||||
@ -827,8 +838,8 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
*/
|
||||
protected function detail_pair($key, $value, $class ='') {
|
||||
$html = html_writer::start_div('detail-pair row yui3-g '.preg_replace('#[^a-zA-Z0-9_\-]#', '-', $class));
|
||||
$html .= html_writer::div(html_writer::span($key), 'pair-key span3 col-md-3 yui3-u-1-4');
|
||||
$html .= html_writer::div(html_writer::span($value), 'pair-value span9 col-md-9 m-b-1 yui3-u-3-4 form-inline');
|
||||
$html .= html_writer::div(html_writer::span($key), 'pair-key col-md-3 yui3-u-1-4 font-weight-bold');
|
||||
$html .= html_writer::div(html_writer::span($value), 'pair-value col-md-8 yui3-u-3-4');
|
||||
$html .= html_writer::end_div();
|
||||
return $html;
|
||||
}
|
||||
@ -836,7 +847,7 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
/**
|
||||
* A collection of actions for a course.
|
||||
*
|
||||
* @param core_course_list_element $course The course to display actions for.
|
||||
* @param core_course_list_element $course The course to display actions for.
|
||||
* @return string
|
||||
*/
|
||||
public function course_detail_actions(core_course_list_element $course) {
|
||||
@ -846,9 +857,10 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
}
|
||||
$options = array();
|
||||
foreach ($actions as $action) {
|
||||
$options[] = $this->action_link($action['url'], $action['string']);
|
||||
$options[] = $this->action_link($action['url'], $action['string'], null,
|
||||
array('class' => 'btn btn-sm btn-secondary mr-1 mb-3'));
|
||||
}
|
||||
return html_writer::div(join(' | ', $options), 'listing-actions course-detail-listing-actions');
|
||||
return html_writer::div(join('', $options), 'listing-actions course-detail-listing-actions');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -893,7 +905,7 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
* @return string
|
||||
*/
|
||||
public function grid_start($id = null, $class = null) {
|
||||
$gridclass = 'grid-row-r row-fluid';
|
||||
$gridclass = 'grid-start grid-row-r d-flex flex-wrap row';
|
||||
if (is_null($class)) {
|
||||
$class = $gridclass;
|
||||
} else {
|
||||
@ -925,29 +937,14 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
*/
|
||||
public function grid_column_start($size, $id = null, $class = null) {
|
||||
|
||||
// Calculate Bootstrap grid sizing.
|
||||
$bootstrapclass = 'span'.$size.' col-md-'.$size;
|
||||
if ($id == 'course-detail') {
|
||||
$size = 12;
|
||||
$bootstrapclass = 'col-md-'.$size;
|
||||
} else {
|
||||
$bootstrapclass = 'd-flex flex-wrap px-3 mb-3';
|
||||
}
|
||||
|
||||
// Calculate YUI grid sizing.
|
||||
if ($size === 12) {
|
||||
$maxsize = 1;
|
||||
$size = 1;
|
||||
} else {
|
||||
$maxsize = 12;
|
||||
$divisors = array(8, 6, 5, 4, 3, 2);
|
||||
foreach ($divisors as $divisor) {
|
||||
if (($maxsize % $divisor === 0) && ($size % $divisor === 0)) {
|
||||
$maxsize = $maxsize / $divisor;
|
||||
$size = $size / $divisor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($maxsize > 1) {
|
||||
$yuigridclass = "grid-col-{$size}-{$maxsize} grid-col";
|
||||
} else {
|
||||
$yuigridclass = "grid-col-1 grid-col";
|
||||
}
|
||||
$yuigridclass = "col-sm";
|
||||
|
||||
if (is_null($class)) {
|
||||
$class = $yuigridclass . ' ' . $bootstrapclass;
|
||||
@ -958,7 +955,7 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
if (!is_null($id)) {
|
||||
$attributes['id'] = $id;
|
||||
}
|
||||
return html_writer::start_div($class, $attributes);
|
||||
return html_writer::start_div($class . " grid_column_start", $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1058,14 +1055,14 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
*
|
||||
* @param array $courses The courses to display.
|
||||
* @param int $totalcourses The total number of courses to display.
|
||||
* @param core_course_list_element $course The currently selected course if there is one.
|
||||
* @param core_course_list_element $course The currently selected course if there is one.
|
||||
* @param int $page The current page, starting at 0.
|
||||
* @param int $perpage The number of courses to display per page.
|
||||
* @param string $search The string we are searching for.
|
||||
* @return string
|
||||
*/
|
||||
public function search_listing(array $courses, $totalcourses, core_course_list_element $course = null, $page = 0, $perpage = 20,
|
||||
$search = '') {
|
||||
$search = '') {
|
||||
$page = max($page, 0);
|
||||
$perpage = max($perpage, 2);
|
||||
$totalpages = ceil($totalcourses / $perpage);
|
||||
@ -1077,11 +1074,11 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
$last = false;
|
||||
$i = $page * $perpage;
|
||||
|
||||
$html = html_writer::start_div('course-listing', array(
|
||||
'data-category' => 'search',
|
||||
'data-page' => $page,
|
||||
'data-totalpages' => $totalpages,
|
||||
'data-totalcourses' => $totalcourses
|
||||
$html = html_writer::start_div('course-listing w-100', array(
|
||||
'data-category' => 'search',
|
||||
'data-page' => $page,
|
||||
'data-totalpages' => $totalpages,
|
||||
'data-totalcourses' => $totalcourses
|
||||
));
|
||||
$html .= html_writer::tag('h3', get_string('courses'));
|
||||
$html .= $this->search_pagination($totalcourses, $page, $perpage);
|
||||
@ -1172,7 +1169,7 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
*
|
||||
* This function will be called for every course being displayed by course_listing.
|
||||
*
|
||||
* @param core_course_list_element $course The course to produce HTML for.
|
||||
* @param core_course_list_element $course The course to produce HTML for.
|
||||
* @param int $selectedcourse The id of the currently selected course.
|
||||
* @return string
|
||||
*/
|
||||
@ -1180,20 +1177,20 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
|
||||
$text = $course->get_formatted_name();
|
||||
$attributes = array(
|
||||
'class' => 'listitem listitem-course',
|
||||
'data-id' => $course->id,
|
||||
'data-selected' => ($selectedcourse == $course->id) ? '1' : '0',
|
||||
'data-visible' => $course->visible ? '1' : '0'
|
||||
'class' => 'listitem listitem-course list-group-item list-group-item-action',
|
||||
'data-id' => $course->id,
|
||||
'data-selected' => ($selectedcourse == $course->id) ? '1' : '0',
|
||||
'data-visible' => $course->visible ? '1' : '0'
|
||||
);
|
||||
$bulkcourseinput = '';
|
||||
if (core_course_category::get($course->category)->can_move_courses_out_of()) {
|
||||
$bulkcourseinput = array(
|
||||
'type' => 'checkbox',
|
||||
'name' => 'bc[]',
|
||||
'value' => $course->id,
|
||||
'class' => 'bulk-action-checkbox',
|
||||
'aria-label' => get_string('bulkactionselect', 'moodle', $text),
|
||||
'data-action' => 'select'
|
||||
'type' => 'checkbox',
|
||||
'name' => 'bc[]',
|
||||
'value' => $course->id,
|
||||
'class' => 'bulk-action-checkbox',
|
||||
'aria-label' => get_string('bulkactionselect', 'moodle', $text),
|
||||
'data-action' => 'select'
|
||||
);
|
||||
}
|
||||
$viewcourseurl = new moodle_url($this->page->url, array('courseid' => $course->id));
|
||||
@ -1302,16 +1299,26 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
$strsearchcourses = get_string("searchcourses");
|
||||
$searchurl = new moodle_url('/course/management.php');
|
||||
|
||||
$output = html_writer::start_tag('form', array('id' => $formid, 'action' => $searchurl, 'method' => 'get',
|
||||
'class' => 'form-inline'));
|
||||
$output .= html_writer::start_tag('fieldset', array('class' => 'coursesearchbox invisiblefieldset m-y-1'));
|
||||
$output .= html_writer::tag('label', $strsearchcourses, array('for' => $inputid));
|
||||
$output .= html_writer::empty_tag('input', array('type' => 'text', 'id' => $inputid, 'size' => $inputsize,
|
||||
'name' => 'search', 'value' => s($value), 'class' => 'form-control m-x-1'));
|
||||
$output .= html_writer::empty_tag('input', array('type' => 'submit', 'value' => get_string('go'),
|
||||
'class' => 'btn btn-secondary'));
|
||||
$output = html_writer::start_div('row');
|
||||
$output .= html_writer::start_div('col-md-12');
|
||||
$output .= html_writer::start_tag('form', array('class' => 'card', 'id' => $formid,
|
||||
'action' => $searchurl, 'method' => 'get'));
|
||||
$output .= html_writer::start_tag('fieldset', array('class' => 'coursesearchbox invisiblefieldset'));
|
||||
$output .= html_writer::tag('div', $this->output->heading($strsearchcourses.': ', 2, 'm-0'),
|
||||
array('class' => 'card-header'));
|
||||
$output .= html_writer::start_div('card-body');
|
||||
$output .= html_writer::start_div('input-group col-sm-6 col-lg-4 m-auto');
|
||||
$output .= html_writer::empty_tag('input', array('class' => 'form-control', 'type' => 'text', 'id' => $inputid,
|
||||
'size' => $inputsize, 'name' => 'search', 'value' => s($value)));
|
||||
$output .= html_writer::start_tag('span', array('class' => 'input-group-btn'));
|
||||
$output .= html_writer::tag('button', get_string('go'), array('class' => 'btn btn-primary', 'type' => 'submit'));
|
||||
$output .= html_writer::end_tag('span');
|
||||
$output .= html_writer::end_div();
|
||||
$output .= html_writer::end_div();
|
||||
$output .= html_writer::end_tag('fieldset');
|
||||
$output .= html_writer::end_tag('form');
|
||||
$output .= html_writer::end_div();
|
||||
$output .= html_writer::end_div();
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
@ -344,13 +344,13 @@ class core_course_renderer extends plugin_renderer_base {
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders html to display a course search form
|
||||
* Renders html to display a course search form.
|
||||
*
|
||||
* @param string $value default value to populate the search field
|
||||
* @param string $format display format - 'plain' (default), 'short' or 'navbar'
|
||||
* @return string
|
||||
*/
|
||||
function course_search_form($value = '', $format = 'plain') {
|
||||
public function course_search_form($value = '', $format = 'plain') {
|
||||
static $count = 0;
|
||||
$formid = 'coursesearch';
|
||||
if ((++$count) > 1) {
|
||||
@ -372,23 +372,19 @@ class core_course_renderer extends plugin_renderer_base {
|
||||
$inputsize = 30;
|
||||
}
|
||||
|
||||
$strsearchcourses= get_string("searchcourses");
|
||||
$searchurl = new moodle_url('/course/search.php');
|
||||
|
||||
$output = html_writer::start_tag('form', array('id' => $formid, 'action' => $searchurl, 'method' => 'get'));
|
||||
$output .= html_writer::start_tag('fieldset', array('class' => 'coursesearchbox invisiblefieldset'));
|
||||
$output .= html_writer::tag('label', $strsearchcourses.': ', array('for' => $inputid));
|
||||
$output .= html_writer::empty_tag('input', array('type' => 'text', 'id' => $inputid,
|
||||
'size' => $inputsize, 'name' => 'search', 'value' => s($value)));
|
||||
$output .= html_writer::empty_tag('input', array('type' => 'submit',
|
||||
'value' => get_string('go')));
|
||||
$output .= html_writer::end_tag('fieldset');
|
||||
$data = (object) [
|
||||
'searchurl' => (new moodle_url('/course/search.php'))->out(false),
|
||||
'id' => $formid,
|
||||
'inputid' => $inputid,
|
||||
'inputsize' => $inputsize,
|
||||
'value' => $value
|
||||
];
|
||||
if ($format != 'navbar') {
|
||||
$output .= $this->output->help_icon("coursesearch", "core");
|
||||
$helpicon = new \help_icon('coursesearch', 'core');
|
||||
$data->helpicon = $helpicon->export_for_template($this);
|
||||
}
|
||||
$output .= html_writer::end_tag('form');
|
||||
|
||||
return $output;
|
||||
return $this->render_from_template('core_course/course_search_form', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -186,10 +186,11 @@ class behat_course extends behat_base {
|
||||
// We are on the frontpage.
|
||||
if ($section) {
|
||||
// Section 1 represents the contents on the frontpage.
|
||||
$sectionxpath = "//body[@id='page-site-index']/descendant::div[contains(concat(' ',normalize-space(@class),' '),' sitetopic ')]";
|
||||
$sectionxpath = "//body[@id='page-site-index']" .
|
||||
"/descendant::div[contains(concat(' ',normalize-space(@class),' '),' sitetopic ')]";
|
||||
} else {
|
||||
// Section 0 represents "Site main menu" block.
|
||||
$sectionxpath = "//div[contains(concat(' ',normalize-space(@class),' '),' block_site_main_menu ')]";
|
||||
$sectionxpath = "//*[contains(concat(' ',normalize-space(@class),' '),' block_site_main_menu ')]";
|
||||
}
|
||||
} else {
|
||||
// We are inside the course.
|
||||
@ -201,15 +202,16 @@ class behat_course extends behat_base {
|
||||
if ($this->running_javascript()) {
|
||||
|
||||
// Clicks add activity or resource section link.
|
||||
$sectionxpath = $sectionxpath . "/descendant::div[@class='section-modchooser']/span/a";
|
||||
$sectionxpath = $sectionxpath . "/descendant::div" .
|
||||
"[contains(concat(' ', normalize-space(@class) , ' '), ' section-modchooser ')]/span/a";
|
||||
$sectionnode = $this->find('xpath', $sectionxpath);
|
||||
$sectionnode->click();
|
||||
|
||||
// Clicks the selected activity if it exists.
|
||||
$activityxpath = "//div[@id='chooseform']/descendant::label" .
|
||||
"/descendant::span[contains(concat(' ', normalize-space(@class), ' '), ' typename ')]" .
|
||||
"[normalize-space(.)=$activityliteral]" .
|
||||
"/parent::label/child::input";
|
||||
"/descendant::span[contains(concat(' ', normalize-space(@class), ' '), ' typename ')]" .
|
||||
"[normalize-space(.)=$activityliteral]" .
|
||||
"/parent::label/child::input";
|
||||
$activitynode = $this->find('xpath', $activityxpath);
|
||||
$activitynode->doubleClick();
|
||||
|
||||
@ -217,8 +219,9 @@ class behat_course extends behat_base {
|
||||
// Without Javascript.
|
||||
|
||||
// Selecting the option from the select box which contains the option.
|
||||
$selectxpath = $sectionxpath . "/descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' section_add_menus ')]" .
|
||||
"/descendant::select[option[normalize-space(.)=$activityliteral]]";
|
||||
$selectxpath = $sectionxpath . "/descendant::div" .
|
||||
"[contains(concat(' ', normalize-space(@class), ' '), ' section_add_menus ')]" .
|
||||
"/descendant::select[option[normalize-space(.)=$activityliteral]]";
|
||||
$selectnode = $this->find('xpath', $selectxpath);
|
||||
$selectnode->selectOption($activity);
|
||||
|
||||
@ -230,7 +233,6 @@ class behat_course extends behat_base {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Opens a section edit menu if it is not already opened.
|
||||
*
|
||||
@ -248,7 +250,7 @@ class behat_course extends behat_base {
|
||||
|
||||
// If it is already opened we do nothing.
|
||||
$xpath = $this->section_exists($sectionnumber);
|
||||
$xpath .= "/descendant::div[contains(@class, 'section-actions')]/descendant::a[contains(@class, 'textmenu')]";
|
||||
$xpath .= "/descendant::div[contains(@class, 'section-actions')]/descendant::a[contains(@data-toggle, 'dropdown')]";
|
||||
|
||||
$exception = new ExpectationException('Section "' . $sectionnumber . '" was not found', $this->getSession());
|
||||
$menu = $this->find('xpath', $xpath, $exception);
|
||||
@ -550,8 +552,8 @@ class behat_course extends behat_base {
|
||||
// Edit menu should be visible.
|
||||
if ($this->is_course_editor()) {
|
||||
$xpath = $sectionxpath .
|
||||
"/descendant::div[contains(@class, 'section-actions')]" .
|
||||
"/descendant::a[contains(@class, 'textmenu')]";
|
||||
"/descendant::div[contains(@class, 'section-actions')]" .
|
||||
"/descendant::a[contains(@data-toggle, 'dropdown')]";
|
||||
if (!$this->getSession()->getPage()->find('xpath', $xpath)) {
|
||||
throw new ExpectationException('The section edit menu is not available', $this->getSession());
|
||||
}
|
||||
@ -843,15 +845,23 @@ class behat_course extends behat_base {
|
||||
|
||||
// If it is already opened we do nothing.
|
||||
$activitynode = $this->get_activity_node($activityname);
|
||||
$classes = array_flip(explode(' ', $activitynode->getAttribute('class')));
|
||||
if (!empty($classes['action-menu-shown'])) {
|
||||
|
||||
// Find the menu.
|
||||
$menunode = $activitynode->find('css', 'a[data-toggle=dropdown]');
|
||||
if (!$menunode) {
|
||||
throw new ExpectationException(sprintf('Could not find actions menu for the activity "%s"', $activityname),
|
||||
$this->getSession());
|
||||
}
|
||||
$expanded = $menunode->getAttribute('aria-expanded');
|
||||
if ($expanded == 'true') {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->execute('behat_course::i_click_on_in_the_activity',
|
||||
array("a[role='menuitem']", "css_element", $this->escape($activityname))
|
||||
array("a[data-toggle='dropdown']", "css_element", $this->escape($activityname))
|
||||
);
|
||||
|
||||
$this->actions_menu_should_be_open($activityname);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -869,13 +879,19 @@ class behat_course extends behat_base {
|
||||
|
||||
// If it is already closed we do nothing.
|
||||
$activitynode = $this->get_activity_node($activityname);
|
||||
$classes = array_flip(explode(' ', $activitynode->getAttribute('class')));
|
||||
if (empty($classes['action-menu-shown'])) {
|
||||
// Find the menu.
|
||||
$menunode = $activitynode->find('css', 'a[data-toggle=dropdown]');
|
||||
if (!$menunode) {
|
||||
throw new ExpectationException(sprintf('Could not find actions menu for the activity "%s"', $activityname),
|
||||
$this->getSession());
|
||||
}
|
||||
$expanded = $menunode->getAttribute('aria-expanded');
|
||||
if ($expanded != 'true') {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->execute('behat_course::i_click_on_in_the_activity',
|
||||
array("a[role='menuitem']", "css_element", $this->escape($activityname))
|
||||
array("a[data-toggle='dropdown']", "css_element", $this->escape($activityname))
|
||||
);
|
||||
}
|
||||
|
||||
@ -892,10 +908,15 @@ class behat_course extends behat_base {
|
||||
throw new DriverException('Activities actions menu not available when Javascript is disabled');
|
||||
}
|
||||
|
||||
// If it is already closed we do nothing.
|
||||
$activitynode = $this->get_activity_node($activityname);
|
||||
$classes = array_flip(explode(' ', $activitynode->getAttribute('class')));
|
||||
if (empty($classes['action-menu-shown'])) {
|
||||
// Find the menu.
|
||||
$menunode = $activitynode->find('css', 'a[data-toggle=dropdown]');
|
||||
if (!$menunode) {
|
||||
throw new ExpectationException(sprintf('Could not find actions menu for the activity "%s"', $activityname),
|
||||
$this->getSession());
|
||||
}
|
||||
$expanded = $menunode->getAttribute('aria-expanded');
|
||||
if ($expanded != 'true') {
|
||||
throw new ExpectationException(sprintf("The action menu for '%s' is not open", $activityname), $this->getSession());
|
||||
}
|
||||
}
|
||||
@ -1039,18 +1060,18 @@ class behat_course extends behat_base {
|
||||
|
||||
// Determine the future new activity xpath from the former one.
|
||||
$duplicatedxpath = "//li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')]" .
|
||||
"[contains(., $activityliteral)]/following-sibling::li";
|
||||
$duplicatedactionsmenuxpath = $duplicatedxpath . "/descendant::a[@role='menuitem']";
|
||||
"[contains(., $activityliteral)]/following-sibling::li";
|
||||
$duplicatedactionsmenuxpath = $duplicatedxpath . "/descendant::a[@data-toggle='dropdown']";
|
||||
|
||||
if ($this->running_javascript()) {
|
||||
// We wait until the AJAX request finishes and the section is visible again.
|
||||
$hiddenlightboxxpath = "//li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')]" .
|
||||
"[contains(., $activityliteral)]" .
|
||||
"/ancestor::li[contains(concat(' ', normalize-space(@class), ' '), ' section ')]" .
|
||||
"/descendant::div[contains(concat(' ', @class, ' '), ' lightbox ')][contains(@style, 'display: none')]";
|
||||
"[contains(., $activityliteral)]" .
|
||||
"/ancestor::li[contains(concat(' ', normalize-space(@class), ' '), ' section ')]" .
|
||||
"/descendant::div[contains(concat(' ', @class, ' '), ' lightbox ')][contains(@style, 'display: none')]";
|
||||
|
||||
$this->execute("behat_general::wait_until_exists",
|
||||
array($this->escape($hiddenlightboxxpath), "xpath_element")
|
||||
array($this->escape($hiddenlightboxxpath), "xpath_element")
|
||||
);
|
||||
|
||||
// Close the original activity actions menu.
|
||||
@ -1059,13 +1080,13 @@ class behat_course extends behat_base {
|
||||
// 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).
|
||||
$this->execute('behat_general::i_click_on',
|
||||
array($this->escape($duplicatedactionsmenuxpath), "xpath_element")
|
||||
array($this->escape($duplicatedactionsmenuxpath), "xpath_element")
|
||||
);
|
||||
}
|
||||
|
||||
// We force the xpath as otherwise mink tries to interact with the former one.
|
||||
$this->execute('behat_general::i_click_on_in_the',
|
||||
array(get_string('editsettings'), "link", $this->escape($duplicatedxpath), "xpath_element")
|
||||
array(get_string('editsettings'), "link", $this->escape($duplicatedxpath), "xpath_element")
|
||||
);
|
||||
|
||||
$this->execute("behat_forms::i_set_the_following_fields_to_these_values", $data);
|
||||
@ -1281,8 +1302,8 @@ class behat_course extends behat_base {
|
||||
protected function is_course_editor() {
|
||||
|
||||
// We don't need to behat_base::spin() here as all is already loaded.
|
||||
if (!$this->getSession()->getPage()->findButton(get_string('turneditingoff')) &&
|
||||
!$this->getSession()->getPage()->findButton(get_string('turneditingon'))) {
|
||||
if (!$this->getSession()->getPage()->findLink(get_string('turneditingoff')) &&
|
||||
!$this->getSession()->getPage()->findLink(get_string('turneditingon'))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1842,7 +1863,8 @@ class behat_course extends behat_base {
|
||||
* @throws Behat\Mink\Exception\ExpectationException
|
||||
*/
|
||||
protected function user_clicks_on_management_listing_action($listingtype, $listingnode, $action) {
|
||||
$actionsnode = $listingnode->find('xpath', "//*[contains(concat(' ', normalize-space(@class), ' '), '{$listingtype}-item-actions')]");
|
||||
$actionsnode = $listingnode->find('xpath', "//*" .
|
||||
"[contains(concat(' ', normalize-space(@class), ' '), '{$listingtype}-item-actions')]");
|
||||
if (!$actionsnode) {
|
||||
throw new ExpectationException("Could not find the actions for $listingtype", $this->getSession());
|
||||
}
|
||||
@ -1851,7 +1873,7 @@ class behat_course extends behat_base {
|
||||
throw new ExpectationException("Expected action was not available or not found ($action)", $this->getSession());
|
||||
}
|
||||
if ($this->running_javascript() && !$actionnode->isVisible()) {
|
||||
$actionsnode->find('css', 'a.toggle-display')->click();
|
||||
$actionsnode->find('css', 'a[data-toggle=dropdown]')->click();
|
||||
$actionnode = $actionsnode->find('css', '.action-'.$action);
|
||||
}
|
||||
$actionnode->click();
|
||||
@ -1874,10 +1896,7 @@ class behat_course extends behat_base {
|
||||
* @Given /^I navigate to course participants$/
|
||||
*/
|
||||
public function i_navigate_to_course_participants() {
|
||||
$coursestr = behat_context_helper::escape(get_string('courses'));
|
||||
$mycoursestr = behat_context_helper::escape(get_string('mycourses'));
|
||||
$xpath = "//div[contains(@class,'block')]//li[p/*[string(.)=$coursestr or string(.)=$mycoursestr]]";
|
||||
$this->execute('behat_general::i_click_on_in_the', [get_string('participants'), 'link', $xpath, 'xpath_element']);
|
||||
$this->execute('behat_navigation::i_select_from_flat_navigation_drawer', get_string('participants'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -602,8 +602,8 @@ class enrol_self_testcase extends advanced_testcase {
|
||||
$selfplugin->enrol_user($instance1, $user2->id, $editingteacherrole->id);
|
||||
|
||||
$this->setUser($guest);
|
||||
$noaccesshtml = get_string('noguestaccess', 'enrol') . $OUTPUT->continue_button(get_login_url());
|
||||
$this->assertSame($noaccesshtml, $selfplugin->can_self_enrol($instance1, true));
|
||||
$this->assertContains(get_string('noguestaccess', 'enrol'),
|
||||
$selfplugin->can_self_enrol($instance1, true));
|
||||
|
||||
$this->setUser($user1);
|
||||
$this->assertTrue($selfplugin->can_self_enrol($instance1, true));
|
||||
|
@ -134,124 +134,16 @@ class core_files_renderer extends plugin_renderer_base {
|
||||
/**
|
||||
* Returns html for displaying one file manager
|
||||
*
|
||||
* The main element in HTML must have id="filemanager-{$client_id}" and
|
||||
* class="filemanager fm-loading";
|
||||
* After all necessary code on the page (both html and javascript) is loaded,
|
||||
* the class fm-loading will be removed and added class fm-loaded;
|
||||
* The main element (class=filemanager) will be assigned the following classes:
|
||||
* 'fm-maxfiles' - when filemanager has maximum allowed number of files;
|
||||
* 'fm-nofiles' - when filemanager has no files at all (although there might be folders);
|
||||
* 'fm-noitems' - when current view (folder) has no items - neither files nor folders;
|
||||
* 'fm-updating' - when current view is being updated (usually means that loading icon is to be displayed);
|
||||
* 'fm-nomkdir' - when 'Make folder' action is unavailable (empty($fm->options->subdirs) == true)
|
||||
*
|
||||
* Element with class 'filemanager-container' will be holding evens for dnd upload (dragover, etc.).
|
||||
* It will have class:
|
||||
* 'dndupload-ready' - when a file is being dragged over the browser
|
||||
* 'dndupload-over' - when file is being dragged over this filepicker (additional to 'dndupload-ready')
|
||||
* 'dndupload-uploading' - during the upload process (note that after dnd upload process is
|
||||
* over, the file manager will refresh the files list and therefore will have for a while class
|
||||
* fm-updating. Both waiting processes should look similar so the images don't jump for user)
|
||||
*
|
||||
* If browser supports Drag-and-drop, the body element will have class 'dndsupported',
|
||||
* otherwise - 'dndnotsupported';
|
||||
*
|
||||
* Element with class 'fp-content' will be populated with files list;
|
||||
* Element with class 'fp-btn-add' will hold onclick event for adding a file (opening filepicker);
|
||||
* Element with class 'fp-btn-mkdir' will hold onclick event for adding new folder;
|
||||
* Element with class 'fp-btn-download' will hold onclick event for download action;
|
||||
*
|
||||
* Element with class 'fp-path-folder' is a template for one folder in path toolbar.
|
||||
* It will hold mouse click event and will be assigned classes first/last/even/odd respectfully.
|
||||
* Parent element will receive class 'empty' when there are no folders to be displayed;
|
||||
* The content of subelement with class 'fp-path-folder-name' will be substituted with folder name;
|
||||
*
|
||||
* Element with class 'fp-viewbar' will have the class 'enabled' or 'disabled' when view mode
|
||||
* can be changed or not;
|
||||
* Inside element with class 'fp-viewbar' there are expected elements with classes
|
||||
* 'fp-vb-icons', 'fp-vb-tree' and 'fp-vb-details'. They will handle onclick events to switch
|
||||
* between the view modes, the last clicked element will have the class 'checked';
|
||||
*
|
||||
* @param form_filemanager $fm
|
||||
* @return string
|
||||
*/
|
||||
protected function fm_print_generallayout($fm) {
|
||||
global $OUTPUT;
|
||||
$options = $fm->options;
|
||||
$client_id = $options->client_id;
|
||||
$straddfile = get_string('addfile', 'repository');
|
||||
$strmakedir = get_string('makeafolder', 'moodle');
|
||||
$strdownload = get_string('downloadfolder', 'repository');
|
||||
$strloading = get_string('loading', 'repository');
|
||||
$strdroptoupload = get_string('droptoupload', 'moodle');
|
||||
$icon_progress = $OUTPUT->pix_icon('i/loading_small', $strloading).'';
|
||||
$restrictions = $this->fm_print_restrictions($fm);
|
||||
$strdndnotsupported = get_string('dndnotsupported_insentence', 'moodle').$OUTPUT->help_icon('dndnotsupported');
|
||||
$strdndenabledinbox = get_string('dndenabled_inbox', 'moodle');
|
||||
$loading = get_string('loading', 'repository');
|
||||
$straddfiletext = get_string('addfiletext', 'repository');
|
||||
$strcreatefolder = get_string('createfolder', 'repository');
|
||||
$strdownloadallfiles = get_string('downloadallfiles', 'repository');
|
||||
|
||||
$html = '
|
||||
<div id="filemanager-'.$client_id.'" class="filemanager fm-loading">
|
||||
<div class="fp-restrictions">
|
||||
'.$restrictions.'
|
||||
<span class="dnduploadnotsupported-message"> - '.$strdndnotsupported.' </span>
|
||||
</div>
|
||||
<div class="fp-navbar">
|
||||
<div class="filemanager-toolbar">
|
||||
<div class="fp-toolbar">
|
||||
<div class="fp-btn-add">
|
||||
<a role="button" title="' . $straddfile . '" href="#">
|
||||
' . $this->pix_icon('a/add_file', $straddfiletext) . '
|
||||
</a>
|
||||
</div>
|
||||
<div class="fp-btn-mkdir">
|
||||
<a role="button" title="' . $strmakedir . '" href="#">
|
||||
' . $this->pix_icon('a/create_folder', $strcreatefolder) . '
|
||||
</a>
|
||||
</div>
|
||||
<div class="fp-btn-download">
|
||||
<a role="button" title="' . $strdownload . '" href="#">
|
||||
' . $this->pix_icon('a/download_all', $strdownloadallfiles) . '
|
||||
</a>
|
||||
</div>
|
||||
<span class="fp-img-downloading">
|
||||
' . $this->pix_icon('i/loading_small', '') . '
|
||||
</span>
|
||||
</div>
|
||||
<div class="fp-viewbar">
|
||||
<a title="'. get_string('displayicons', 'repository') .'" class="fp-vb-icons" href="#">
|
||||
' . $this->pix_icon('fp/view_icon_active', get_string('displayasicons', 'repository'), 'theme') . '
|
||||
</a>
|
||||
<a title="'. get_string('displaydetails', 'repository') .'" class="fp-vb-details" href="#">
|
||||
' . $this->pix_icon('fp/view_list_active', get_string('displayasdetails', 'repository'), 'theme') . '
|
||||
</a>
|
||||
<a title="'. get_string('displaytree', 'repository') .'" class="fp-vb-tree" href="#">
|
||||
' . $this->pix_icon('fp/view_tree_active', get_string('displayastree', 'repository'), 'theme') . '
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fp-pathbar">
|
||||
<span class="fp-path-folder"><a class="fp-path-folder-name" href="#"></a></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="filemanager-loading mdl-align">'.$icon_progress.'</div>
|
||||
<div class="filemanager-container" >
|
||||
<div class="fm-content-wrapper">
|
||||
<div class="fp-content"></div>
|
||||
<div class="fm-empty-container">
|
||||
<div class="dndupload-message">'.$strdndenabledinbox.'<br/><div class="dndupload-arrow"></div></div>
|
||||
</div>
|
||||
<div class="dndupload-target">'.$strdroptoupload.'<br/><div class="dndupload-arrow"></div></div>
|
||||
<div class="dndupload-progressbars"></div>
|
||||
<div class="dndupload-uploadinprogress">'.$icon_progress.'</div>
|
||||
</div>
|
||||
<div class="filemanager-updating">'.$icon_progress.'</div>
|
||||
</div>
|
||||
</div>';
|
||||
return $html;
|
||||
$context = [
|
||||
'client_id' => $fm->options->client_id,
|
||||
'helpicon' => $this->help_icon('setmainfile', 'repository'),
|
||||
'restrictions' => $this->fm_print_restrictions($fm)
|
||||
];
|
||||
return $this->render_from_template('core/filemanager_page_generallayout', $context);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -350,140 +242,21 @@ class core_files_renderer extends plugin_renderer_base {
|
||||
/**
|
||||
* FileManager JS template for window with file information/actions.
|
||||
*
|
||||
* All content must be enclosed in one element, CSS for this class must define width and
|
||||
* height of the window;
|
||||
*
|
||||
* Thumbnail image will be added as content to the element with class 'fp-thumbnail';
|
||||
*
|
||||
* Inside the window the elements with the following classnames must be present:
|
||||
* 'fp-saveas', 'fp-author', 'fp-license', 'fp-path'. Inside each of them must be
|
||||
* one input element (or select in case of fp-license and fp-path). They may also have labels.
|
||||
* The elements will be assign with class 'uneditable' and input/select element will become
|
||||
* disabled if they are not applicable for the particular file;
|
||||
*
|
||||
* There may be present elements with classes 'fp-original', 'fp-datemodified', 'fp-datecreated',
|
||||
* 'fp-size', 'fp-dimensions', 'fp-reflist'. They will receive additional class 'fp-unknown' if
|
||||
* information is unavailable. If there is information available, the content of embedded
|
||||
* element with class 'fp-value' will be substituted with the value;
|
||||
*
|
||||
* The value of Original ('fp-original') is loaded in separate request. When it is applicable
|
||||
* but not yet loaded the 'fp-original' element receives additional class 'fp-loading';
|
||||
*
|
||||
* The value of 'Aliases/Shortcuts' ('fp-reflist') is also loaded in separate request. When it
|
||||
* is applicable but not yet loaded the 'fp-original' element receives additional class
|
||||
* 'fp-loading'. The string explaining that XX references exist will replace content of element
|
||||
* 'fp-refcount'. Inside '.fp-reflist .fp-value' each reference will be enclosed in <li>;
|
||||
*
|
||||
* Elements with classes 'fp-file-update', 'fp-file-download', 'fp-file-delete', 'fp-file-zip',
|
||||
* 'fp-file-unzip', 'fp-file-setmain' and 'fp-file-cancel' will hold corresponding onclick
|
||||
* events (there may be several elements with class 'fp-file-cancel');
|
||||
*
|
||||
* When confirm button is pressed and file is being selected, the top element receives
|
||||
* additional class 'loading'. It is removed when response from server is received.
|
||||
*
|
||||
* When any of the input fields is changed, the top element receives class 'fp-changed';
|
||||
* When current file can be set as main - top element receives class 'fp-cansetmain';
|
||||
* When current file is folder/zip/file - top element receives respectfully class
|
||||
* 'fp-folder'/'fp-zip'/'fp-file';
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function fm_js_template_fileselectlayout() {
|
||||
global $OUTPUT;
|
||||
$strloading = get_string('loading', 'repository');
|
||||
$iconprogress = $this->pix_icon('i/loading_small', $strloading).'';
|
||||
$rv = '
|
||||
<div class="filemanager fp-select">
|
||||
<div class="fp-select-loading">
|
||||
' . $this->pix_icon('i/loading_small', '') . '
|
||||
</div>
|
||||
<form class="form-horizontal">
|
||||
<button class="fp-file-download">'.get_string('download').'</button>
|
||||
<button class="fp-file-delete">'.get_string('delete').'</button>
|
||||
<button class="fp-file-setmain">'.get_string('setmainfile', 'repository').'</button>
|
||||
<span class="fp-file-setmain-help">'.$OUTPUT->help_icon('setmainfile', 'repository').'</span>
|
||||
<button class="fp-file-zip">'.get_string('zip', 'editor').'</button>
|
||||
<button class="fp-file-unzip">'.get_string('unzip').'</button>
|
||||
<div class="fp-hr"></div>
|
||||
|
||||
<div class="fp-forminset">
|
||||
<div class="fp-saveas control-group clearfix">
|
||||
<label class="control-label">'.get_string('name', 'repository').'</label>
|
||||
<div class="controls">
|
||||
<input type="text"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fp-author control-group clearfix">
|
||||
<label class="control-label">'.get_string('author', 'repository').'</label>
|
||||
<div class="controls">
|
||||
<input type="text"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fp-license control-group clearfix">
|
||||
<label class="control-label">'.get_string('chooselicense', 'repository').'</label>
|
||||
<div class="controls">
|
||||
<select></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fp-path control-group clearfix">
|
||||
<label class="control-label">'.get_string('path', 'repository').'</label>
|
||||
<div class="controls">
|
||||
<select></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fp-original control-group clearfix">
|
||||
<label class="control-label">'.get_string('original', 'repository').'</label>
|
||||
<div class="controls">
|
||||
<span class="fp-originloading">'.$iconprogress.' '.$strloading.'</span><span class="fp-value"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fp-reflist control-group clearfix">
|
||||
<label class="control-label">'.get_string('referenceslist', 'repository').'</label>
|
||||
<div class="controls">
|
||||
<p class="fp-refcount"></p>
|
||||
<span class="fp-reflistloading">'.$iconprogress.' '.$strloading.'</span>
|
||||
<ul class="fp-value"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fp-select-buttons">
|
||||
<button class="fp-file-update btn-primary btn">'.get_string('update', 'moodle').'</button>
|
||||
<button class="fp-file-cancel btn-cancel btn">'.get_string('cancel').'</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="fp-info clearfix">
|
||||
<div class="fp-hr"></div>
|
||||
<p class="fp-thumbnail"></p>
|
||||
<div class="fp-fileinfo">
|
||||
<div class="fp-datemodified">'.get_string('lastmodified', 'repository').' <span class="fp-value"></span></div>
|
||||
<div class="fp-datecreated">'.get_string('datecreated', 'repository').' <span class="fp-value"></span></div>
|
||||
<div class="fp-size">'.get_string('size', 'repository').' <span class="fp-value"></span></div>
|
||||
<div class="fp-dimensions">'.get_string('dimensions', 'repository').' <span class="fp-value"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>';
|
||||
return $rv;
|
||||
$context = [
|
||||
'helpicon' => $this->help_icon('setmainfile', 'repository')
|
||||
];
|
||||
return $this->render_from_template('core/filemanager_fileselect', $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* FileManager JS template for popup confirm dialogue window.
|
||||
*
|
||||
* Must have one top element, CSS for this element must define width and height of the window;
|
||||
*
|
||||
* content of element with class 'fp-dlg-text' will be replaced with dialog text;
|
||||
* elements with classes 'fp-dlg-butconfirm' and 'fp-dlg-butcancel' will
|
||||
* hold onclick events;
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function fm_js_template_confirmdialog() {
|
||||
$rv = '
|
||||
<div class="filemanager fp-dlg">
|
||||
<div class="fp-dlg-text"></div>
|
||||
<button class="fp-dlg-butconfirm btn-primary btn">'.get_string('ok').'</button>
|
||||
<button class="fp-dlg-butcancel btn-cancel btn">'.get_string('cancel').'</button>
|
||||
</div>';
|
||||
return $rv;
|
||||
return $this->render_from_template('core/filemanager_confirmdialog', []);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -529,112 +302,11 @@ class core_files_renderer extends plugin_renderer_base {
|
||||
/**
|
||||
* Template for FilePicker with general layout (not QuickUpload).
|
||||
*
|
||||
* Must have one top element containing everything else (recommended <div class="file-picker">),
|
||||
* CSS for this element must define width and height of the filepicker window. Or CSS must
|
||||
* define min-width, max-width, min-height and max-height and in this case the filepicker
|
||||
* window will be resizeable;
|
||||
*
|
||||
* Element with class 'fp-viewbar' will have the class 'enabled' or 'disabled' when view mode
|
||||
* can be changed or not;
|
||||
* Inside element with class 'fp-viewbar' there are expected elements with classes
|
||||
* 'fp-vb-icons', 'fp-vb-tree' and 'fp-vb-details'. They will handle onclick events to switch
|
||||
* between the view modes, the last clicked element will have the class 'checked';
|
||||
*
|
||||
* Element with class 'fp-repo' is a template for displaying one repository. Other repositories
|
||||
* will be attached as siblings (classes first/last/even/odd will be added respectfully).
|
||||
* The currently selected repostory will have class 'active'. Contents of element with class
|
||||
* 'fp-repo-name' will be replaced with repository name, source of image with class
|
||||
* 'fp-repo-icon' will be replaced with repository icon;
|
||||
*
|
||||
* Element with class 'fp-content' is obligatory and will hold the current contents;
|
||||
*
|
||||
* Element with class 'fp-paging' will contain page navigation (will be deprecated soon);
|
||||
*
|
||||
* Element with class 'fp-path-folder' is a template for one folder in path toolbar.
|
||||
* It will hold mouse click event and will be assigned classes first/last/even/odd respectfully.
|
||||
* Parent element will receive class 'empty' when there are no folders to be displayed;
|
||||
* The content of subelement with class 'fp-path-folder-name' will be substituted with folder name;
|
||||
*
|
||||
* Element with class 'fp-toolbar' will have class 'empty' if all 'Back', 'Search', 'Refresh',
|
||||
* 'Logout', 'Manage' and 'Help' are unavailable for this repo;
|
||||
*
|
||||
* Inside fp-toolbar there are expected elements with classes fp-tb-back, fp-tb-search,
|
||||
* fp-tb-refresh, fp-tb-logout, fp-tb-manage and fp-tb-help. Each of them will have
|
||||
* class 'enabled' or 'disabled' if particular repository has this functionality.
|
||||
* Element with class 'fp-tb-search' must contain empty form inside, it's contents will
|
||||
* be substituted with the search form returned by repository (in the most cases it
|
||||
* is generated with template core_repository_renderer::repository_default_searchform);
|
||||
* Other elements must have either <a> or <button> element inside, it will hold onclick
|
||||
* event for corresponding action; labels for fp-tb-back and fp-tb-logout may be
|
||||
* replaced with those specified by repository;
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function fp_js_template_generallayout() {
|
||||
$rv = '
|
||||
<div tabindex="0" class="file-picker fp-generallayout" role="dialog" aria-live="assertive">
|
||||
<div class="fp-repo-area">
|
||||
<ul class="fp-list" role="tablist">
|
||||
<li class="fp-repo" role="tab" aria-selected="false" tabindex="-1">
|
||||
<a href="#" tabindex="-1"><img class="fp-repo-icon" alt=" " width="16" height="16" />
|
||||
<span class="fp-repo-name"></span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="fp-repo-items" tabindex="0">
|
||||
<div class="fp-navbar">
|
||||
<div>
|
||||
<div class="fp-toolbar">
|
||||
<div class="fp-tb-back">
|
||||
<a href="#">'.get_string('back', 'repository').'</a>
|
||||
</div>
|
||||
<div class="fp-tb-search">
|
||||
<form></form>
|
||||
</div>
|
||||
<div class="fp-tb-refresh">
|
||||
<a title="'. get_string('refresh', 'repository') .'" href="#">
|
||||
' . $this->pix_icon('a/refresh', '') . '
|
||||
</a>
|
||||
</div>
|
||||
<div class="fp-tb-logout">
|
||||
<a title="'. get_string('logout', 'repository') .'" href="#">
|
||||
' . $this->pix_icon('a/logout', '') . '
|
||||
</a>
|
||||
</div>
|
||||
<div class="fp-tb-manage">
|
||||
<a title="'. get_string('manageurl', 'repository') .'" href="#">
|
||||
' . $this->pix_icon('a/setting', '') . '
|
||||
</a>
|
||||
</div>
|
||||
<div class="fp-tb-help">
|
||||
<a title="'. get_string('help', 'repository') .'" href="#">
|
||||
' . $this->pix_icon('a/help', '') . '
|
||||
</a>
|
||||
</div>
|
||||
<div class="fp-tb-message"></div>
|
||||
</div>
|
||||
<div class="fp-viewbar">
|
||||
<a role="button" title="'. get_string('displayicons', 'repository') .'" class="fp-vb-icons" href="#">
|
||||
' . $this->pix_icon('fp/view_icon_active', '', 'theme') . '
|
||||
</a>
|
||||
<a role="button" title="'. get_string('displaydetails', 'repository') .'" class="fp-vb-details" href="#">
|
||||
' . $this->pix_icon('fp/view_list_active', '', 'theme') . '
|
||||
</a>
|
||||
<a role="button" title="'. get_string('displaytree', 'repository') .'" class="fp-vb-tree" href="#">
|
||||
' . $this->pix_icon('fp/view_tree_active', '', 'theme') . '
|
||||
</a>
|
||||
</div>
|
||||
<div class="fp-clear-left"></div>
|
||||
</div>
|
||||
<div class="fp-pathbar">
|
||||
<span class="fp-path-folder"><a class="fp-path-folder-name" href="#"></a></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fp-content"></div>
|
||||
</div>
|
||||
</div>';
|
||||
return $rv;
|
||||
return $this->render_from_template('core/filemanager_modal_generallayout', []);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -723,159 +395,19 @@ class core_files_renderer extends plugin_renderer_base {
|
||||
/**
|
||||
* FilePicker JS template for window appearing to select a file.
|
||||
*
|
||||
* All content must be enclosed in one element, CSS for this class must define width and
|
||||
* height of the window;
|
||||
*
|
||||
* Thumbnail image will be added as content to the element with class 'fp-thumbnail';
|
||||
*
|
||||
* Inside the window the elements with the following classnames must be present:
|
||||
* 'fp-saveas', 'fp-linktype-2', 'fp-linktype-1', 'fp-linktype-4', 'fp-setauthor',
|
||||
* 'fp-setlicense'. Inside each of them must have one input element (or select in case of
|
||||
* fp-setlicense). They may also have labels.
|
||||
* The elements will be assign with class 'uneditable' and input/select element will become
|
||||
* disabled if they are not applicable for the particular file;
|
||||
*
|
||||
* There may be present elements with classes 'fp-datemodified', 'fp-datecreated', 'fp-size',
|
||||
* 'fp-license', 'fp-author', 'fp-dimensions'. They will receive additional class 'fp-unknown'
|
||||
* if information is unavailable. If there is information available, the content of embedded
|
||||
* element with class 'fp-value' will be substituted with the value;
|
||||
*
|
||||
* Elements with classes 'fp-select-confirm' and 'fp-select-cancel' will hold corresponding
|
||||
* onclick events;
|
||||
*
|
||||
* When confirm button is pressed and file is being selected, the top element receives
|
||||
* additional class 'loading'. It is removed when response from server is received.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function fp_js_template_selectlayout() {
|
||||
$rv = '
|
||||
<div class="file-picker fp-select">
|
||||
<div class="fp-select-loading">
|
||||
' . $this->pix_icon('i/loading_small', '') . '
|
||||
</div>
|
||||
<form class="form-horizontal">
|
||||
<div class="fp-forminset">
|
||||
<div class="fp-linktype-2 control-group control-radio clearfix">
|
||||
<label class="control-label control-radio">'.get_string('makefileinternal', 'repository').'</label>
|
||||
<div class="controls control-radio">
|
||||
<input type="radio"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fp-linktype-1 control-group control-radio clearfix">
|
||||
<label class="control-label control-radio">'.get_string('makefilelink', 'repository').'</label>
|
||||
<div class="controls control-radio">
|
||||
<input type="radio"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fp-linktype-4 control-group control-radio clearfix">
|
||||
<label class="control-label control-radio">'.get_string('makefilereference', 'repository').'</label>
|
||||
<div class="controls control-radio">
|
||||
<input type="radio"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fp-linktype-8 control-group control-radio clearfix">
|
||||
<label class="control-label control-radio">'.get_string('makefilecontrolledlink', 'repository').'</label>
|
||||
<div class="controls control-radio">
|
||||
<input type="radio"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fp-saveas control-group clearfix">
|
||||
<label class="control-label">'.get_string('saveas', 'repository').'</label>
|
||||
<div class="controls">
|
||||
<input type="text"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fp-setauthor control-group clearfix">
|
||||
<label class="control-label">'.get_string('author', 'repository').'</label>
|
||||
<div class="controls">
|
||||
<input type="text"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fp-setlicense control-group clearfix">
|
||||
<label class="control-label">'.get_string('chooselicense', 'repository').'</label>
|
||||
<div class="controls">
|
||||
<select></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fp-select-buttons">
|
||||
<button class="fp-select-confirm btn-primary btn">'.get_string('getfile', 'repository').'</button>
|
||||
<button class="fp-select-cancel btn-cancel btn">'.get_string('cancel').'</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="fp-info clearfix">
|
||||
<div class="fp-hr"></div>
|
||||
<p class="fp-thumbnail"></p>
|
||||
<div class="fp-fileinfo">
|
||||
<div class="fp-datemodified">'.get_string('lastmodified', 'repository').'<span class="fp-value"></span></div>
|
||||
<div class="fp-datecreated">'.get_string('datecreated', 'repository').'<span class="fp-value"></span></div>
|
||||
<div class="fp-size">'.get_string('size', 'repository').'<span class="fp-value"></span></div>
|
||||
<div class="fp-license">'.get_string('license', 'repository').'<span class="fp-value"></span></div>
|
||||
<div class="fp-author">'.get_string('author', 'repository').'<span class="fp-value"></span></div>
|
||||
<div class="fp-dimensions">'.get_string('dimensions', 'repository').'<span class="fp-value"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>';
|
||||
return $rv;
|
||||
return $this->render_from_template('core/filemanager_selectlayout', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* FilePicker JS template for 'Upload file' repository
|
||||
*
|
||||
* Content to display when user chooses 'Upload file' repository (will be nested inside
|
||||
* element with class 'fp-content').
|
||||
*
|
||||
* Must contain form (enctype="multipart/form-data" method="POST")
|
||||
*
|
||||
* The elements with the following classnames must be present:
|
||||
* 'fp-file', 'fp-saveas', 'fp-setauthor', 'fp-setlicense'. Inside each of them must have
|
||||
* one input element (or select in case of fp-setlicense). They may also have labels.
|
||||
*
|
||||
* Element with class 'fp-upload-btn' will hold onclick event for uploading the file;
|
||||
*
|
||||
* Please note that some fields may be hidden using CSS if this is part of quickupload form
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function fp_js_template_uploadform() {
|
||||
$rv = '
|
||||
<div class="fp-upload-form">
|
||||
<div class="fp-content-center">
|
||||
<form enctype="multipart/form-data" method="POST" class="form-horizontal">
|
||||
<div class="fp-formset">
|
||||
<div class="fp-file control-group clearfix">
|
||||
<label class="control-label">'.get_string('attachment', 'repository').'</label>
|
||||
<div class="controls">
|
||||
<input type="file"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fp-saveas control-group clearfix">
|
||||
<label class="control-label">'.get_string('saveas', 'repository').'</label>
|
||||
<div class="controls">
|
||||
<input type="text"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fp-setauthor control-group clearfix">
|
||||
<label class="control-label">'.get_string('author', 'repository').'</label>
|
||||
<div class="controls">
|
||||
<input type="text"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fp-setlicense control-group clearfix">
|
||||
<label class="control-label">'.get_string('chooselicense', 'repository').'</label>
|
||||
<div class="controls">
|
||||
<select ></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="mdl-align">
|
||||
<button class="fp-upload-btn btn-primary btn">'.get_string('upload', 'repository').'</button>
|
||||
</div>
|
||||
</div>
|
||||
</div> ';
|
||||
return $rv;
|
||||
return $this->render_from_template('core/filemanager_uploadform', []);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -932,115 +464,29 @@ class core_files_renderer extends plugin_renderer_base {
|
||||
/**
|
||||
* FilePicker JS template for popup dialogue window asking for action when file with the same name already exists.
|
||||
*
|
||||
* Must have one top element, CSS for this element must define width and height of the window;
|
||||
*
|
||||
* content of element with class 'fp-dlg-text' will be replaced with dialog text;
|
||||
* elements with classes 'fp-dlg-butoverwrite', 'fp-dlg-butrename',
|
||||
* 'fp-dlg-butoverwriteall', 'fp-dlg-butrenameall' and 'fp-dlg-butcancel' will
|
||||
* hold onclick events;
|
||||
*
|
||||
* content of element with class 'fp-dlg-butrename' will be substituted with appropriate string
|
||||
* (Note that it may have long text)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function fp_js_template_processexistingfile() {
|
||||
$rv = '
|
||||
<div class="file-picker fp-dlg">
|
||||
<p class="fp-dlg-text"></p>
|
||||
<div class="fp-dlg-buttons">
|
||||
<button class="fp-dlg-butoverwrite btn">'.get_string('overwrite', 'repository').'</button>
|
||||
<button class="fp-dlg-butrename btn"></button>
|
||||
<button class="fp-dlg-butcancel btn btn-cancel">'.get_string('cancel').'</button>
|
||||
</div>
|
||||
</div>';
|
||||
return $rv;
|
||||
return $this->render_from_template('core/filemanager_processexistingfile', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* FilePicker JS template for popup dialogue window asking for action when file with the same name already exists (multiple-file version).
|
||||
*
|
||||
* Must have one top element, CSS for this element must define width and height of the window;
|
||||
*
|
||||
* content of element with class 'fp-dlg-text' will be replaced with dialog text;
|
||||
* elements with classes 'fp-dlg-butoverwrite', 'fp-dlg-butrename' and 'fp-dlg-butcancel' will
|
||||
* hold onclick events;
|
||||
*
|
||||
* content of element with class 'fp-dlg-butrename' will be substituted with appropriate string
|
||||
* (Note that it may have long text)
|
||||
* FilePicker JS template for popup dialogue window asking for action when file with the same name already exists
|
||||
* (multiple-file version).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function fp_js_template_processexistingfilemultiple() {
|
||||
$rv = '
|
||||
<div class="file-picker fp-dlg">
|
||||
<p class="fp-dlg-text"></p>
|
||||
<a class="fp-dlg-butoverwrite fp-panel-button" href="#">'.get_string('overwrite', 'repository').'</a>
|
||||
<a class="fp-dlg-butcancel fp-panel-button" href="#">'.get_string('cancel').'</a>
|
||||
<a class="fp-dlg-butrename fp-panel-button" href="#"></a>
|
||||
<br/>
|
||||
<a class="fp-dlg-butoverwriteall fp-panel-button" href="#">'.get_string('overwriteall', 'repository').'</a>
|
||||
<a class="fp-dlg-butrenameall fp-panel-button" href="#">'.get_string('renameall', 'repository').'</a>
|
||||
</div>';
|
||||
return $rv;
|
||||
return $this->render_from_template('core/filemanager_processexistingfilemultiple', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* FilePicker JS template for repository login form including templates for each element type
|
||||
*
|
||||
* Must contain one <form> element with templates for different input types inside:
|
||||
* Elements with classes 'fp-login-popup', 'fp-login-textarea', 'fp-login-select' and
|
||||
* 'fp-login-input' are templates for displaying respective login form elements. Inside
|
||||
* there must be exactly one element with type <button>, <textarea>, <select> or <input>
|
||||
* (i.e. fp-login-popup should have <button>, fp-login-textarea should have <textarea>, etc.);
|
||||
* They may also contain the <label> element and it's content will be substituted with
|
||||
* label;
|
||||
*
|
||||
* You can also define elements with classes 'fp-login-checkbox', 'fp-login-text'
|
||||
* but if they are not found, 'fp-login-input' will be used;
|
||||
*
|
||||
* Element with class 'fp-login-radiogroup' will be used for group of radio inputs. Inside
|
||||
* it should hava a template for one radio input (with class 'fp-login-radio');
|
||||
*
|
||||
* Element with class 'fp-login-submit' will hold on click mouse event (form submission). It
|
||||
* will be removed if at least one popup element is present;
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function fp_js_template_loginform() {
|
||||
$rv = '
|
||||
<div class="fp-login-form">
|
||||
<div class="fp-content-center">
|
||||
<form class="form-horizontal">
|
||||
<div class="fp-formset">
|
||||
<div class="fp-login-popup control-group clearfix">
|
||||
<div class="controls fp-popup">
|
||||
<button class="fp-login-popup-but btn-primary btn">'.get_string('login', 'repository').'</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fp-login-textarea control-group clearfix">
|
||||
<div class="controls"><textarea></textarea></div>
|
||||
</div>
|
||||
<div class="fp-login-select control-group clearfix">
|
||||
<label class="control-label"></label>
|
||||
|
||||
<div class="controls"><select></select></div>
|
||||
</div>';
|
||||
$rv .= '
|
||||
<div class="fp-login-input control-group clearfix">
|
||||
<label class="control-label"></label>
|
||||
<div class="controls"><input/></div>
|
||||
</div>
|
||||
<div class="fp-login-radiogroup control-group clearfix">
|
||||
<label class="control-label"></label>
|
||||
<div class="controls fp-login-radio"><input /> <label></label></div>
|
||||
</div>
|
||||
</div>
|
||||
<p><button class="fp-login-submit btn-primary btn">'.get_string('submit', 'repository').'</button></p>
|
||||
</form>
|
||||
</div>
|
||||
</div>';
|
||||
return $rv;
|
||||
return $this->render_from_template('core/filemanager_loginform', []);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1066,13 +512,7 @@ class core_files_renderer extends plugin_renderer_base {
|
||||
* Default contents is one text input field with name="s"
|
||||
*/
|
||||
public function repository_default_searchform() {
|
||||
$searchinput = html_writer::label(get_string('searchrepo', 'repository'),
|
||||
'reposearch', false, array('class' => 'accesshide'));
|
||||
$searchinput .= html_writer::empty_tag('input', array('type' => 'text',
|
||||
'id' => 'reposearch', 'name' => 's', 'value' => get_string('search', 'repository')));
|
||||
$str = html_writer::tag('div', $searchinput, array('class' => "fp-def-search"));
|
||||
|
||||
return $str;
|
||||
return $this->render_from_template('core/filemanager_default_searchform', []);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,13 +47,11 @@
|
||||
}
|
||||
}}
|
||||
<div class="gradingform_guide_comment_chooser" id="comment_chooser">
|
||||
<ul role="list">
|
||||
<div class="list-group">
|
||||
{{#comments}}
|
||||
<li role="listitem">
|
||||
<button id="comment-option-{{criterionId}}-{{id}}" class="btn btn-link" tabindex="0">
|
||||
{{description}}
|
||||
</button>
|
||||
</li>
|
||||
<button class="list-group-item list-group-item-action" id="comment-option-{{criterionId}}-{{id}}" tabindex="0">
|
||||
{{description}}
|
||||
</button>
|
||||
{{/comments}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -46,50 +46,8 @@ class renderer extends \plugin_renderer_base {
|
||||
* @return string HTML to display
|
||||
*/
|
||||
protected function render_user_button(user_button $button) {
|
||||
$attributes = array('type' => 'button',
|
||||
'class' => 'selectortrigger',
|
||||
'value' => $button->label,
|
||||
'disabled' => $button->disabled ? 'disabled' : null,
|
||||
'title' => $button->tooltip);
|
||||
|
||||
if ($button->actions) {
|
||||
$id = \html_writer::random_id('single_button');
|
||||
$attributes['id'] = $id;
|
||||
foreach ($button->actions as $action) {
|
||||
$this->add_action_handler($action, $id);
|
||||
}
|
||||
}
|
||||
// First the input element.
|
||||
$output = \html_writer::empty_tag('input', $attributes);
|
||||
|
||||
// Then hidden fields.
|
||||
$params = $button->url->params();
|
||||
if ($button->method === 'post') {
|
||||
$params['sesskey'] = sesskey();
|
||||
}
|
||||
foreach ($params as $var => $val) {
|
||||
$output .= \html_writer::empty_tag('input', array('type' => 'hidden', 'name' => $var, 'value' => $val));
|
||||
}
|
||||
|
||||
// Then div wrapper for xhtml strictness.
|
||||
$output = \html_writer::tag('div', $output);
|
||||
|
||||
// Now the form itself around it.
|
||||
if ($button->method === 'get') {
|
||||
$url = $button->url->out_omit_querystring(true); // Url without params, the anchor part allowed.
|
||||
} else {
|
||||
$url = $button->url->out_omit_querystring(); // Url without params, the anchor part not allowed.
|
||||
}
|
||||
if ($url === '') {
|
||||
$url = '#'; // There has to be always some action.
|
||||
}
|
||||
$attributes = array('method' => $button->method,
|
||||
'action' => $url,
|
||||
'id' => $button->formid);
|
||||
$output = \html_writer::tag('div', $output, $attributes);
|
||||
|
||||
// Finally one more wrapper with class.
|
||||
return \html_writer::tag('div', $output, array('class' => $button->class));
|
||||
$data = $button->export_for_template($this);
|
||||
return $this->render_from_template('gradereport_history/user_button', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21,10 +21,10 @@
|
||||
<input type="checkbox" name="{{applyname}}" value="1" id="{{applyname}}">
|
||||
<label for="{{applyname}}">{{applylabel}}</label>
|
||||
</div>
|
||||
<fieldset>
|
||||
<fieldset class="form-inline">
|
||||
<legend class="accesshide">{{label}}</legend>
|
||||
<label for="{{menuname}}">{{menulabel}}</label>
|
||||
<select name="{{menuname}}" id="{{menuname}}">
|
||||
<select name="{{menuname}}" id="{{menuname}}" class="form-control">
|
||||
{{#menuoptions}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/menuoptions}}
|
||||
|
@ -17,4 +17,4 @@
|
||||
{{!
|
||||
Button.
|
||||
}}
|
||||
<input type="{{type}}" value={{#quote}}{{value}}{{/quote}}>
|
||||
<input type="{{type}}" value={{#quote}}{{value}}{{/quote}} class="btn btn-secondary">
|
||||
|
@ -17,7 +17,7 @@
|
||||
{{!
|
||||
Dropdown attribute.
|
||||
}}
|
||||
<select id="{{name}}" name="{{name}}" tabindex="1" {{#disabled}}disabled{{/disabled}}>
|
||||
<select id="{{name}}" name="{{name}}" class="custom-select" tabindex="1" {{#disabled}}disabled{{/disabled}}>
|
||||
{{#options}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/options}}
|
||||
|
@ -18,5 +18,5 @@
|
||||
Text attribute.
|
||||
}}
|
||||
<label for="{{name}}" class="accesshide">{{label}}</label>
|
||||
<input id="{{name}}" name="{{name}}" type="text" value="{{value}}" {{#tabindex}}tabindex="{{.}}"{{/tabindex}} {{#disabled}}disabled{{/disabled}}>
|
||||
<input id="{{name}}" name="{{name}}" type="text" value="{{value}}" class="form-control" {{#tabindex}}tabindex="{{.}}"{{/tabindex}} {{#disabled}}disabled{{/disabled}}>
|
||||
<input type="hidden" name="old{{name}}" value="{{value}}">
|
||||
|
@ -76,15 +76,18 @@ class behat_grade extends behat_base {
|
||||
$gradeitem = behat_context_helper::escape($gradeitem);
|
||||
|
||||
if ($this->running_javascript()) {
|
||||
$xpath = "//tr[contains(.,$gradeitem)]//*[contains(@class,'moodle-actionmenu')]//a[contains(@class,'toggle-display')]";
|
||||
$xpath = "//tr[contains(.,$gradeitem)]//*[contains(@class,'moodle-actionmenu')]";
|
||||
if ($this->getSession()->getPage()->findAll('xpath', $xpath)) {
|
||||
$this->execute("behat_general::i_click_on", array($this->escape($xpath), "xpath_element"));
|
||||
$this->execute("behat_action_menu::i_open_the_action_menu_in",
|
||||
array("//tr[contains(.,$gradeitem)]",
|
||||
"xpath_element"));
|
||||
}
|
||||
}
|
||||
|
||||
$savechanges = get_string('savechanges', 'grades');
|
||||
$edit = behat_context_helper::escape(get_string('edit') . ' ');
|
||||
$linkxpath = "//a[./img[starts-with(@title,$edit) and contains(@title,$gradeitem)]]";
|
||||
$linkxpath = "//a[./*[contains(concat(' ', normalize-space(@class), ' '), ' icon ') " .
|
||||
"and starts-with(@title,$edit) and contains(@title,$gradeitem)]]";
|
||||
|
||||
$this->execute("behat_general::i_click_on", array($this->escape($linkxpath), "xpath_element"));
|
||||
$this->execute("behat_forms::i_set_the_following_fields_to_these_values", $data);
|
||||
@ -128,16 +131,19 @@ class behat_grade extends behat_base {
|
||||
$gradeitem = behat_context_helper::escape($gradeitem);
|
||||
|
||||
if ($this->running_javascript()) {
|
||||
$xpath = "//tr[contains(.,$gradeitem)]//*[contains(@class,'moodle-actionmenu')]//a[contains(@class,'toggle-display')]";
|
||||
$xpath = "//tr[contains(.,$gradeitem)]//*[contains(@class,'moodle-actionmenu')]";
|
||||
if ($this->getSession()->getPage()->findAll('xpath', $xpath)) {
|
||||
$this->execute("behat_general::i_click_on", array($this->escape($xpath), "xpath_element"));
|
||||
$this->execute("behat_action_menu::i_open_the_action_menu_in",
|
||||
array("//tr[contains(.,$gradeitem)]",
|
||||
"xpath_element"));
|
||||
}
|
||||
}
|
||||
|
||||
// Going to edit calculation.
|
||||
$savechanges = get_string('savechanges', 'grades');
|
||||
$edit = behat_context_helper::escape(get_string('editcalculation', 'grades'));
|
||||
$linkxpath = "//a[./img[starts-with(@title,$edit) and contains(@title,$gradeitem)]]";
|
||||
$linkxpath = "//a[./*[contains(concat(' ', normalize-space(@class), ' '), ' icon ') " .
|
||||
"and starts-with(@title,$edit) and contains(@title,$gradeitem)]]";
|
||||
$this->execute("behat_general::i_click_on", array($this->escape($linkxpath), "xpath_element"));
|
||||
|
||||
// Mapping names to idnumbers.
|
||||
@ -145,11 +151,12 @@ class behat_grade extends behat_base {
|
||||
foreach ($datahash as $gradeitem => $idnumber) {
|
||||
// This xpath looks for course, categories and items with the provided name.
|
||||
// Grrr, we can't equal in categoryitem and courseitem because there is a line jump...
|
||||
$inputxpath ="//input[@class='idnumber'][" .
|
||||
"parent::li[@class='item'][text()='" . $gradeitem . "']" .
|
||||
" or " .
|
||||
"parent::li[@class='categoryitem' or @class='courseitem']/parent::ul/parent::li[starts-with(text(),'" . $gradeitem . "')]" .
|
||||
"]";
|
||||
$inputxpath = "//input[@class='idnumber'][" .
|
||||
"parent::li[@class='item'][text()='" . $gradeitem . "']" .
|
||||
" or " .
|
||||
"parent::li[@class='categoryitem' or @class='courseitem']" .
|
||||
"/parent::ul/parent::li[starts-with(text(),'" . $gradeitem . "')]" .
|
||||
"]";
|
||||
$this->execute('behat_forms::i_set_the_field_with_xpath_to', array($inputxpath, $idnumber));
|
||||
}
|
||||
|
||||
@ -174,17 +181,18 @@ class behat_grade extends behat_base {
|
||||
$gradeitem = behat_context_helper::escape($gradeitem);
|
||||
|
||||
if ($this->running_javascript()) {
|
||||
$xpath = "//tr[contains(.,$gradecategorytotal)]//*[contains(@class,'moodle-actionmenu')]" .
|
||||
"//a[contains(@class,'toggle-display')]";
|
||||
$xpath = "//tr[contains(.,$gradecategorytotal)]//*[contains(@class,'moodle-actionmenu')]";
|
||||
if ($this->getSession()->getPage()->findAll('xpath', $xpath)) {
|
||||
$this->execute("behat_general::i_click_on", array($this->escape($xpath), "xpath_element"));
|
||||
$xpath = "//tr[contains(.,$gradecategorytotal)]";
|
||||
$this->execute("behat_action_menu::i_open_the_action_menu_in", array($xpath, "xpath_element"));
|
||||
}
|
||||
}
|
||||
|
||||
// Going to edit calculation.
|
||||
$savechanges = get_string('savechanges', 'grades');
|
||||
$edit = behat_context_helper::escape(get_string('editcalculation', 'grades'));
|
||||
$linkxpath = "//a[./img[starts-with(@title,$edit) and contains(@title,$gradeitem)]]";
|
||||
$linkxpath = "//a[./*[contains(concat(' ', normalize-space(@class), ' '), ' icon ') " .
|
||||
"and starts-with(@title,$edit) and contains(@title,$gradeitem)]]";
|
||||
$this->execute("behat_general::i_click_on", array($this->escape($linkxpath), "xpath_element"));
|
||||
|
||||
// Mapping names to idnumbers.
|
||||
@ -193,11 +201,11 @@ class behat_grade extends behat_base {
|
||||
// This xpath looks for course, categories and items with the provided name.
|
||||
// Grrr, we can't equal in categoryitem and courseitem because there is a line jump...
|
||||
$inputxpath = "//input[@class='idnumber'][" .
|
||||
"parent::li[@class='item'][text()='" . $gradeitem . "']" .
|
||||
" | " .
|
||||
"parent::li[@class='categoryitem' | @class='courseitem']" .
|
||||
"/parent::ul/parent::li[starts-with(text(),'" . $gradeitem . "')]" .
|
||||
"]";
|
||||
"parent::li[@class='item'][text()='" . $gradeitem . "']" .
|
||||
" | " .
|
||||
"parent::li[@class='categoryitem' | @class='courseitem']" .
|
||||
"/parent::ul/parent::li[starts-with(text(),'" . $gradeitem . "')]" .
|
||||
"]";
|
||||
$this->execute('behat_forms::i_set_the_field_with_xpath_to', array($inputxpath, $idnumber));
|
||||
}
|
||||
|
||||
@ -221,9 +229,10 @@ class behat_grade extends behat_base {
|
||||
|
||||
if ($this->running_javascript()) {
|
||||
$gradeitemliteral = behat_context_helper::escape($gradeitem);
|
||||
$xpath = "//tr[contains(.,$gradeitemliteral)]//*[contains(@class,'moodle-actionmenu')]//a[contains(@class,'toggle-display')]";
|
||||
$xpath = "//tr[contains(.,$gradeitemliteral)]//*[contains(@class,'moodle-actionmenu')]";
|
||||
if ($this->getSession()->getPage()->findAll('xpath', $xpath)) {
|
||||
$this->execute("behat_general::i_click_on", array($this->escape($xpath), "xpath_element"));
|
||||
$xpath = "//tr[contains(.,$gradeitemliteral)]";
|
||||
$this->execute("behat_action_menu::i_open_the_action_menu_in", array($xpath, "xpath_element"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -290,11 +299,10 @@ class behat_grade extends behat_base {
|
||||
* @param string $gradepath
|
||||
*/
|
||||
public function i_navigate_to_in_the_course_gradebook($gradepath) {
|
||||
// If we are not on one of the gradebook pages already, follow "Grades" link in the navigation block.
|
||||
// If we are not on one of the gradebook pages already, follow "Grades" link in the navigation drawer.
|
||||
$xpath = '//div[contains(@class,\'grade-navigation\')]';
|
||||
if (!$this->getSession()->getPage()->findAll('xpath', $xpath)) {
|
||||
$this->execute("behat_general::i_click_on_in_the", array(get_string('grades'), 'link',
|
||||
get_string('pluginname', 'block_navigation'), 'block'));
|
||||
$this->execute('behat_navigation::i_select_from_flat_navigation_drawer', get_string('grades'));
|
||||
}
|
||||
|
||||
$this->select_in_gradebook_tabs($gradepath);
|
||||
|
@ -194,15 +194,11 @@ class core_grade_import_lib_test extends advanced_testcase {
|
||||
'itemid' => $gradeitem->id
|
||||
));
|
||||
|
||||
$url = $CFG->wwwroot . '/grade/index.php';
|
||||
$expectedresponse = "++ Grade import success ++
|
||||
<div class=\"continuebutton\"><form method=\"get\" action=\"$url\"><div><input type=\"submit\" value=\"Continue\" /><input type=\"hidden\" name=\"id\" value=\"$course->id\" /></div></form></div>";
|
||||
|
||||
ob_start();
|
||||
$status = grade_import_commit($course->id, $importcode);
|
||||
$output = ob_get_contents();
|
||||
ob_end_clean();
|
||||
$this->assertTrue($status);
|
||||
$this->assertEquals($expectedresponse, $output);
|
||||
$this->assertContains("++ Grade import success ++", $output);
|
||||
}
|
||||
}
|
||||
|
@ -55,11 +55,6 @@ class behat_config_util {
|
||||
*/
|
||||
private $themecontexts;
|
||||
|
||||
/**
|
||||
* @var array list of all contexts in theme suite.
|
||||
*/
|
||||
private $themesuitecontexts;
|
||||
|
||||
/**
|
||||
* @var array list of overridden theme contexts.
|
||||
*/
|
||||
@ -314,13 +309,16 @@ class behat_config_util {
|
||||
|
||||
$this->contexts = array();
|
||||
foreach ($components as $componentname => $componentpath) {
|
||||
if (false !== strpos($componentname, 'theme_')) {
|
||||
continue;
|
||||
}
|
||||
$componentpath = self::clean_path($componentpath);
|
||||
|
||||
if (!file_exists($componentpath . self::get_behat_tests_path())) {
|
||||
continue;
|
||||
}
|
||||
$diriterator = new DirectoryIterator($componentpath . self::get_behat_tests_path());
|
||||
$regite = new RegexIterator($diriterator, '|behat_.*\.php$|');
|
||||
$regite = new RegexIterator($diriterator, '|^behat_.*\.php$|');
|
||||
|
||||
// All behat_*.php inside self::get_behat_tests_path() are added as steps definitions files.
|
||||
foreach ($regite as $file) {
|
||||
@ -493,24 +491,23 @@ class behat_config_util {
|
||||
|
||||
$suites = $this->get_behat_suites($parallelruns, $currentrun);
|
||||
|
||||
$overriddenthemescontexts = $this->get_overridden_theme_contexts();
|
||||
if (!empty($overriddenthemescontexts)) {
|
||||
$allcontexts = array_merge($this->contexts, $overriddenthemescontexts);
|
||||
} else {
|
||||
$allcontexts = $this->contexts;
|
||||
}
|
||||
|
||||
// Remove selectors from step definitions.
|
||||
$themes = $this->get_list_of_themes();
|
||||
$selectortypes = ['named_partial', 'named_exact'];
|
||||
foreach ($themes as $theme) {
|
||||
$allpaths = [];
|
||||
foreach (array_keys($suites) as $theme) {
|
||||
// Remove selectors from step definitions.
|
||||
foreach ($selectortypes as $selectortype) {
|
||||
// Don't include selector classes.
|
||||
$selectorclass = self::get_behat_theme_selector_override_classname($theme, $selectortype);
|
||||
if (isset($allcontexts[$selectorclass])) {
|
||||
unset($allcontexts[$selectorclass]);
|
||||
if (isset($suites[$theme]['contexts'][$selectorclass])) {
|
||||
unset($suites[$theme]['contexts'][$selectorclass]);
|
||||
}
|
||||
}
|
||||
|
||||
// Get a list of all step definition paths.
|
||||
$allpaths = array_merge($allpaths, $suites[$theme]['contexts']);
|
||||
|
||||
// Convert the contexts array to a list of names only.
|
||||
$suites[$theme]['contexts'] = array_keys($suites[$theme]['contexts']);
|
||||
}
|
||||
|
||||
// Comments use black color, so failure path is not visible. Using color other then black/white is safer.
|
||||
@ -532,7 +529,7 @@ class behat_config_util {
|
||||
),
|
||||
'Moodle\BehatExtension' => array(
|
||||
'moodledirroot' => $CFG->dirroot,
|
||||
'steps_definitions' => $allcontexts,
|
||||
'steps_definitions' => $allpaths,
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -1128,9 +1125,8 @@ class behat_config_util {
|
||||
|
||||
// Create list of theme suite features and contexts.
|
||||
foreach ($themes as $theme) {
|
||||
// Get theme features.
|
||||
// Get theme features and contexts.
|
||||
$themefeatures[$theme] = $this->get_behat_features_for_theme($theme);
|
||||
|
||||
$themecontexts[$theme] = $this->get_behat_contexts_for_theme($theme);
|
||||
}
|
||||
|
||||
@ -1141,20 +1137,6 @@ class behat_config_util {
|
||||
}
|
||||
}
|
||||
|
||||
// Remove list of theme contexts form other suite contexts, as suite don't require other theme specific contexts.
|
||||
foreach ($themecontexts as $themename => $themecontext) {
|
||||
if (!empty($themecontext['contexts'])) {
|
||||
foreach ($themecontext['contexts'] as $contextkey => $contextpath) {
|
||||
// Remove theme specific contexts from other themes.
|
||||
foreach ($themes as $currenttheme) {
|
||||
if (($currenttheme != $themename) && isset($themecontexts[$currenttheme]['suitecontexts'][$contextkey])) {
|
||||
unset($themecontexts[$currenttheme]['suitecontexts'][$contextkey]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set suite for each theme.
|
||||
$suites = array();
|
||||
foreach ($themes as $theme) {
|
||||
@ -1186,12 +1168,12 @@ class behat_config_util {
|
||||
$suitename = $theme;
|
||||
}
|
||||
|
||||
// Add suite no matter what. If there is no feature in suite then it will just exist successfully with no
|
||||
// scenarios. But if we don't set this then the user has to know which run doesn't have suite and which run do.
|
||||
// Add suite no matter what. If there is no feature in suite then it will just exist successfully with no scenarios.
|
||||
// But if we don't set this then the user has to know which run doesn't have suite and which run do.
|
||||
$suites = array_merge($suites, array(
|
||||
$suitename => array(
|
||||
'paths' => array_values($themesuitefeatures),
|
||||
'contexts' => array_keys($themecontexts[$theme]['suitecontexts']),
|
||||
'contexts' => $themecontexts[$theme],
|
||||
)
|
||||
));
|
||||
}
|
||||
@ -1223,7 +1205,7 @@ class behat_config_util {
|
||||
foreach ($themes as $themename => $themedir) {
|
||||
// Load the theme config.
|
||||
try {
|
||||
$theme = theme_config::load($themename);
|
||||
$theme = $this->get_theme_config($themename);
|
||||
} catch (Exception $e) {
|
||||
// Bad theme, just skip it for now.
|
||||
continue;
|
||||
@ -1243,10 +1225,21 @@ class behat_config_util {
|
||||
return $selectablethemes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the theme config for a given theme name.
|
||||
* This is done so we can mock it in PHPUnit.
|
||||
*
|
||||
* @param $themename name of theme
|
||||
* @return theme_config
|
||||
*/
|
||||
public function get_theme_config($themename) {
|
||||
return theme_config::load($themename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return theme directory.
|
||||
*
|
||||
* @param string $themename
|
||||
* @param string $themename name of theme
|
||||
* @return string theme directory
|
||||
*/
|
||||
protected function get_theme_test_directory($themename) {
|
||||
@ -1339,7 +1332,7 @@ class behat_config_util {
|
||||
|
||||
$tests = array();
|
||||
$testtypes = array(
|
||||
'contexts' => '|behat_.*\.php$|',
|
||||
'contexts' => '|^behat_.*\.php$|',
|
||||
'features' => '|.*\.feature$|',
|
||||
);
|
||||
|
||||
@ -1427,91 +1420,71 @@ class behat_config_util {
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of contexts overridden by themes.
|
||||
*
|
||||
* @return array.
|
||||
*/
|
||||
protected function get_overridden_theme_contexts() {
|
||||
if (empty($this->overriddenthemescontexts)) {
|
||||
$this->overriddenthemescontexts = array();
|
||||
}
|
||||
|
||||
return $this->overriddenthemescontexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of behat contexts for theme and update $this->stepdefinitions list.
|
||||
*
|
||||
* @param string $theme theme name.
|
||||
* @return array list($themecontexts, $themesuitecontexts)
|
||||
* @return List of contexts
|
||||
*/
|
||||
protected function get_behat_contexts_for_theme($theme) {
|
||||
|
||||
protected function get_behat_contexts_for_theme($theme) : array {
|
||||
// If we already have this list then just return. This will not change by run.
|
||||
if (!empty($this->themecontexts[$theme]) && !empty($this->themesuitecontexts)) {
|
||||
return array(
|
||||
'contexts' => $this->themecontexts[$theme],
|
||||
'suitecontexts' => $this->themesuitecontexts[$theme],
|
||||
);
|
||||
if (!empty($this->themecontexts[$theme])) {
|
||||
return $this->themecontexts[$theme];
|
||||
}
|
||||
|
||||
if (empty($this->overriddenthemescontexts)) {
|
||||
$this->overriddenthemescontexts = array();
|
||||
try {
|
||||
$themeconfig = $this->get_theme_config($theme);
|
||||
} catch (Exception $e) {
|
||||
// This theme has no theme config.
|
||||
return [];
|
||||
}
|
||||
|
||||
$contexts = $this->get_components_contexts();
|
||||
// The theme will use all core contexts, except the one overridden by theme or its parent.
|
||||
$parentcontexts = [];
|
||||
if (isset($themeconfig->parents)) {
|
||||
foreach ($themeconfig->parents as $parent) {
|
||||
if ($parentcontexts = $this->get_behat_contexts_for_theme($parent)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create list of contexts used by theme suite.
|
||||
$themecontexts = $this->get_tests_for_theme($theme, 'contexts');
|
||||
if (empty($parentcontexts)) {
|
||||
$parentcontexts = $this->get_components_contexts();
|
||||
}
|
||||
|
||||
// Remove contexts which have been actively blacklisted.
|
||||
$blacklistedcontexts = $this->get_blacklisted_tests_for_theme($theme, 'contexts');
|
||||
|
||||
// Theme suite will use all core contexts, except the one overridden by theme.
|
||||
$themesuitecontexts = $contexts;
|
||||
|
||||
foreach ($themecontexts as $context => $path) {
|
||||
|
||||
// If a context in theme starts with behat_theme_{themename}_behat_* then it's overriding core context.
|
||||
if (preg_match('/^behat_theme_'.$theme.'_(\w+)$/', $context, $match)) {
|
||||
|
||||
if (!empty($themesuitecontexts[$match[1]])) {
|
||||
unset($themesuitecontexts[$match[1]]);
|
||||
}
|
||||
|
||||
// Add this to the list of overridden paths, so it can be added to final contexts list for class resolver.
|
||||
$this->overriddenthemescontexts[$context] = $path;
|
||||
}
|
||||
|
||||
$selectortypes = ['named_partial', 'named_exact'];
|
||||
foreach ($selectortypes as $selectortype) {
|
||||
// Don't include selector classes.
|
||||
if ($context === self::get_behat_theme_selector_override_classname($theme, $selectortype)) {
|
||||
unset($this->contexts[$context]);
|
||||
unset($themesuitecontexts[$context]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Add theme specific contexts with suffix to steps definitions.
|
||||
$themesuitecontexts[$context] = $path;
|
||||
}
|
||||
|
||||
// Remove blacklisted contexts.
|
||||
foreach ($blacklistedcontexts as $blacklistpath) {
|
||||
$blacklistcontext = basename($blacklistpath, '.php');
|
||||
|
||||
unset($themesuitecontexts[$blacklistcontext]);
|
||||
unset($parentcontexts[$blacklistcontext]);
|
||||
}
|
||||
|
||||
// We are only interested in the class name of context.
|
||||
$this->themesuitecontexts[$theme] = $themesuitecontexts;
|
||||
$this->themecontexts[$theme] = $themecontexts;
|
||||
// Apply overrides.
|
||||
$contexts = array_merge($parentcontexts, $this->get_tests_for_theme($theme, 'contexts'));
|
||||
|
||||
$retval = array(
|
||||
'contexts' => $themecontexts,
|
||||
'suitecontexts' => $themesuitecontexts,
|
||||
);
|
||||
// Remove classes which are overridden.
|
||||
foreach ($contexts as $contextclass => $path) {
|
||||
require_once($path);
|
||||
if (!class_exists($contextclass)) {
|
||||
// This may be a Poorly named class.
|
||||
continue;
|
||||
}
|
||||
|
||||
return $retval;
|
||||
$rc = new \ReflectionClass($contextclass);
|
||||
while ($rc = $rc->getParentClass()) {
|
||||
if (isset($contexts[$rc->name])) {
|
||||
unset($contexts[$rc->name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the list of contexts.
|
||||
ksort($contexts);
|
||||
|
||||
$this->themecontexts[$theme] = $contexts;
|
||||
|
||||
return $contexts;
|
||||
}
|
||||
}
|
||||
|
@ -90,6 +90,13 @@ class behat_context_helper {
|
||||
* @return behat_base
|
||||
*/
|
||||
public static function get($classname) {
|
||||
$contexts = self::$environment->getContexts();
|
||||
|
||||
foreach ($contexts as $context) {
|
||||
if (is_a($context, $classname)) {
|
||||
return $context;
|
||||
}
|
||||
}
|
||||
|
||||
$suitename = self::$environment->getSuite()->getName();
|
||||
// If default suite, then get the default theme name.
|
||||
|
@ -17,9 +17,8 @@
|
||||
/**
|
||||
* Files interactions with behat.
|
||||
*
|
||||
* Note that steps definitions files can not extend other steps definitions files, so
|
||||
* steps definitions which makes use of file attachments or filepicker should
|
||||
* extend behat_files instead of behat_base.
|
||||
* Note that steps definitions files can not extend other steps definitions files, so steps definitions which makes use
|
||||
* of file attachments or filepicker should use this behat_file_helper trait.
|
||||
*
|
||||
* @package core
|
||||
* @category test
|
||||
@ -37,16 +36,15 @@ use Behat\Mink\Exception\ExpectationException as ExpectationException,
|
||||
/**
|
||||
* Files-related actions.
|
||||
*
|
||||
* Steps definitions related with filepicker or repositories should extend
|
||||
* this class instead of behat_base as it provides useful methods to deal
|
||||
* with the common filepicker issues.
|
||||
* Steps definitions related with filepicker or repositories should extend use this trait as it provides useful methods
|
||||
* to deal with the common filepicker issues.
|
||||
*
|
||||
* @package core
|
||||
* @category test
|
||||
* @copyright 2013 David Monllaó
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_files extends behat_base {
|
||||
trait core_behat_file_helper {
|
||||
|
||||
/**
|
||||
* Gets the NodeElement for filepicker of filemanager moodleform element.
|
||||
@ -58,6 +56,7 @@ class behat_files extends behat_base {
|
||||
* @param string $filepickerelement The filepicker form field label
|
||||
* @return NodeElement The hidden element node.
|
||||
*/
|
||||
|
||||
protected function get_filepicker_node($filepickerelement) {
|
||||
|
||||
// More info about the problem (in case there is a problem).
|
||||
@ -66,18 +65,18 @@ class behat_files extends behat_base {
|
||||
// If no file picker label is mentioned take the first file picker from the page.
|
||||
if (empty($filepickerelement)) {
|
||||
$filepickercontainer = $this->find(
|
||||
'xpath',
|
||||
"//*[@data-fieldtype=\"filemanager\"]",
|
||||
$exception
|
||||
'xpath',
|
||||
"//*[@data-fieldtype=\"filemanager\"]",
|
||||
$exception
|
||||
);
|
||||
} else {
|
||||
// Gets the ffilemanager node specified by the locator which contains the filepicker container.
|
||||
$filepickerelement = behat_context_helper::escape($filepickerelement);
|
||||
$filepickercontainer = $this->find(
|
||||
'xpath',
|
||||
"//input[./@id = //label[normalize-space(.)=$filepickerelement]/@for]" .
|
||||
'//ancestor::div[@data-fieldtype="filemanager" or @data-fieldtype="filepicker"]',
|
||||
$exception
|
||||
'xpath',
|
||||
"//input[./@id = //label[normalize-space(.)=$filepickerelement]/@for]" .
|
||||
"//ancestor::*[@data-fieldtype = 'filemanager' or @data-fieldtype = 'filepicker']",
|
||||
$exception
|
||||
);
|
||||
}
|
||||
|
||||
@ -275,5 +274,4 @@ class behat_files extends behat_base {
|
||||
$filepickernode
|
||||
);
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -30,31 +30,26 @@
|
||||
}
|
||||
}
|
||||
}}
|
||||
<div class="{{classes}}"{{#attributes}} {{name}}="{{value}}"{{/attributes}}>
|
||||
<div class="action-menu {{classes}} d-inline"{{#attributes}} {{name}}="{{value}}"{{/attributes}}>
|
||||
{{#primary}}
|
||||
|
||||
<ul class="{{classes}}"{{#attributes}} {{name}}="{{value}}"{{/attributes}}>
|
||||
<div class="{{classes}} d-flex "{{#attributes}} {{name}}="{{value}}"{{/attributes}}>
|
||||
|
||||
{{#prioritise}}<li role="presentation">{{> core/action_menu_trigger }}</li>{{/prioritise}}<!--
|
||||
{{#prioritise}}{{> core/action_menu_trigger }}{{/prioritise}}
|
||||
|
||||
-->{{#items}}<li role="presentation">{{> core/action_menu_item }}</li>{{/items}}<!--
|
||||
{{#items}}
|
||||
<div class="action-menu-item">
|
||||
{{> core/action_menu_item }}
|
||||
</div>
|
||||
{{/items}}
|
||||
|
||||
-->{{^prioritise}}<li role="presentation">{{> core/action_menu_trigger }}</li>{{/prioritise}}
|
||||
{{^prioritise}}
|
||||
<div class="action-menu-trigger">
|
||||
{{> core/action_menu_trigger }}
|
||||
</div>
|
||||
{{/prioritise}}
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{{/primary}}
|
||||
|
||||
{{#secondary}}
|
||||
<ul class="{{classes}}"{{#attributes}} {{name}}="{{value}}"{{/attributes}}>
|
||||
{{#items}}<li role="presentation">{{> core/action_menu_item }}</li>{{/items}}
|
||||
</ul>
|
||||
{{/secondary}}
|
||||
</div>
|
||||
{{#js}}
|
||||
require(['core/yui'], function(Y) {
|
||||
Y.use('moodle-core-actionmenu', function() {
|
||||
M.core.actionmenu.init();
|
||||
});
|
||||
});
|
||||
{{/js}}
|
||||
|
@ -23,14 +23,12 @@
|
||||
{
|
||||
"text": "Example link text",
|
||||
"showtext": true,
|
||||
"url": "http://example.com/link",
|
||||
"classes": "menu-action",
|
||||
"instance": "1"
|
||||
"url": "http://example.com/link"
|
||||
}
|
||||
}}
|
||||
{{^disabled}}
|
||||
<a href="{{url}}" class="{{classes}}" {{#attributes}}{{name}}={{#quote}}{{value}}{{/quote}} {{/attributes}}{{#showtext}}aria-labelledby="actionmenuaction-{{instance}}"{{/showtext}}>{{#icon}}{{#pix}}{{key}}, {{component}}, {{title}}{{/pix}}{{/icon}}{{#showtext}}<span class="menu-action-text" id="actionmenuaction-{{instance}}">{{{text}}}</span>{{/showtext}}</a>
|
||||
{{/disabled}}
|
||||
{{#disabled}}
|
||||
<span class="currentlink" role="menuitem">{{#icon}}{{#pix}}{{key}}, {{component}}, {{title}}{{/pix}}{{/icon}}{{{text}}}</span>
|
||||
<span class="currentlink" role="menuitem">{{#icon}}{{#pix}}{{key}},{{component}},{{title}}{{/pix}}{{/icon}}{{{text}}}</span>
|
||||
{{/disabled}}
|
||||
|
@ -21,10 +21,100 @@
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"text": "Example link text",
|
||||
"title": "Example link title",
|
||||
"url": "http://example.com/link",
|
||||
"classes": "icon menu-action",
|
||||
"instance": "1",
|
||||
"title": "Trigger me!",
|
||||
"menutrigger": true,
|
||||
"triggerextraclasses": ""
|
||||
"triggerextraclasses": "",
|
||||
"attributes": [
|
||||
{"name": "role", "value": "menuitem" },
|
||||
{"name": "data-title", "value": "mymoodle,admin" }
|
||||
],
|
||||
"secondary": {
|
||||
"classes": "menu align-tr-br",
|
||||
"attributes": [
|
||||
{"name": "id", "value": "action-menu-0-menu"},
|
||||
{"name": "data-rel", "value": "menu-content"},
|
||||
{"name": "role", "value": "menu"},
|
||||
{"name": "data-align", "value": "tr-br"}
|
||||
],
|
||||
"items": [
|
||||
{"actionmenulink":
|
||||
{
|
||||
"id": "action_link59ecf8394a68078",
|
||||
"disabled": false,
|
||||
"text": "Dashboard",
|
||||
"url": "http://example.com/link",
|
||||
"icon": {
|
||||
"key": "i/dashboard",
|
||||
"component": null,
|
||||
"title": "Dashboard"
|
||||
},
|
||||
"classes": "icon menu-action",
|
||||
"attributes": [
|
||||
{"name": "role", "value": "menuitem"},
|
||||
{"name": "data-title", "value": "mymoodle,admin"}
|
||||
],
|
||||
"instance": 1,
|
||||
"showtext": true
|
||||
}
|
||||
},
|
||||
{"actionmenufiller":
|
||||
{
|
||||
"id": "action_link59ecf8394a68079",
|
||||
"disabled": false,
|
||||
"text": "",
|
||||
"url": "",
|
||||
"icon": null,
|
||||
"classes": "",
|
||||
"attributes": [
|
||||
{"name": "role", "value": "menuitem"}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}}
|
||||
<a href="#" class="{{triggerextraclasses}} toggle-display {{#menutrigger}}textmenu{{/menutrigger}}" id="action-menu-toggle-{{instance}}" title="{{title}}" role="menuitem">{{{actiontext}}}{{{menutrigger}}}{{#icon}}{{#pix}}{{key}}, {{component}}, {{title}}{{/pix}}{{/icon}}{{#rawicon}}{{{.}}}{{/rawicon}}{{#menutrigger}}<b class="caret"></b>{{/menutrigger}}</a>
|
||||
<div class="dropdown">
|
||||
<a href="#" tabindex="0" class="{{triggerextraclasses}} dropdown-toggle icon-no-margin" id="dropdown-{{instance}}" aria-label="{{title}}" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" aria-controls="action-menu-{{instance}}-menu">
|
||||
{{{actiontext}}}
|
||||
{{{menutrigger}}}
|
||||
{{#icon}}
|
||||
{{#pix}}
|
||||
{{key}},{{component}},{{title}}
|
||||
{{/pix}}
|
||||
{{/icon}}
|
||||
{{#rawicon}}{{{.}}}{{/rawicon}}
|
||||
{{#menutrigger}}
|
||||
<b class="caret"></b>
|
||||
{{/menutrigger}}
|
||||
</a>
|
||||
{{#secondary}}
|
||||
<div class="dropdown-menu dropdown-menu-right {{classes}}"{{#attributes}} {{name}}="{{value}}"{{/attributes}} id="dropdown-menu-{{instance}}">
|
||||
{{#items}}
|
||||
{{#actionmenulink}}
|
||||
<a href="{{url}}" class="dropdown-item {{classes}}" {{#attributes}}{{name}}={{#quote}}{{value}}{{/quote}} {{/attributes}}{{#showtext}}aria-labelledby="actionmenuaction-{{instance}}"{{/showtext}}>
|
||||
{{#icon}}
|
||||
{{#pix}}{{key}},{{component}},{{title}}{{/pix}}
|
||||
{{/icon}}
|
||||
{{#showtext}}
|
||||
<span class="menu-action-text" id="actionmenuaction-{{instance}}">
|
||||
{{{text}}}
|
||||
</span>
|
||||
{{/showtext}}
|
||||
</a>
|
||||
{{/actionmenulink}}
|
||||
{{#actionmenufiller}}
|
||||
<div class="dropdown-divider" role="presentation"><span class="filler"> </span></div>
|
||||
{{/actionmenufiller}}
|
||||
{{^actionmenulink}}
|
||||
{{^actionmenufiller}}
|
||||
<div class="dropdown-item">{{> core/action_menu_item }}</div>
|
||||
{{/actionmenufiller}}
|
||||
{{/actionmenulink}}
|
||||
{{/items}}
|
||||
</div>
|
||||
{{/secondary}}
|
||||
</div>
|
||||
|
@ -26,12 +26,33 @@
|
||||
"homelink": "/"
|
||||
}
|
||||
}}
|
||||
<h3>{{#str}}considereddigitalminor{{/str}}</h3>
|
||||
<p class="m-b-0">{{#str}}digitalminor_desc{{/str}}</p>
|
||||
<div class="p-t-1 p-b-1">
|
||||
<p class="m-b-0">{{{supportname}}}</p>
|
||||
<p class="m-b-0">{{{supportemail}}}</p>
|
||||
</div>
|
||||
<div class="backlink">
|
||||
<a href="{{homelink}}">{{#str}}backtohome{{/str}}</a>
|
||||
<div class="container-fluid mt-1 mt-md-5">
|
||||
<div class="row justify-content-md-center">
|
||||
<div class="col-md-8 push-md-2 col-xl-6 push-xl-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="card-title text-xs-center">
|
||||
{{#logourl}}
|
||||
<h2><img src="{{logourl}}" title="{{sitename}}" alt="{{sitename}}"/></h2>
|
||||
{{/logourl}}
|
||||
{{^logourl}}
|
||||
<h2>{{sitename}}</h2>
|
||||
{{/logourl}}
|
||||
<hr>
|
||||
</div>
|
||||
<div class="card-title">
|
||||
<h3>{{#str}}considereddigitalminor{{/str}}</h3>
|
||||
</div>
|
||||
<div class="p-t-1 p-b-2">
|
||||
<p>{{#str}}digitalminor_desc{{/str}}</p>
|
||||
<p class="m-b-0">{{{supportname}}}</p>
|
||||
<p class="m-b-0">{{{supportemail}}}</p>
|
||||
</div>
|
||||
<div class="backlink">
|
||||
<a href="{{homelink}}">{{#str}}backtohome{{/str}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -25,13 +25,40 @@
|
||||
"formhtml": "(Form html would go here)"
|
||||
}
|
||||
}}
|
||||
{{#error}}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
{{{error}}}
|
||||
<div class="container-fluid mt-1 mt-md-5">
|
||||
<div class="row justify-content-md-center">
|
||||
<div class="col-md-8 push-md-2 col-xl-6 push-xl-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="card-title text-xs-center">
|
||||
{{#logourl}}
|
||||
<h2><img src="{{logourl}}" title="{{sitename}}" alt="{{sitename}}"/></h2>
|
||||
{{/logourl}}
|
||||
{{^logourl}}
|
||||
<h2>{{sitename}}</h2>
|
||||
{{/logourl}}
|
||||
<hr>
|
||||
</div>
|
||||
{{#error}}
|
||||
<div class="alert alert-danger" role="alert" data-aria-autofocus="true">
|
||||
{{{error}}}
|
||||
</div>
|
||||
{{/error}}
|
||||
<div class="card-title">
|
||||
<h3>{{#str}}agelocationverification{{/str}}</h3>
|
||||
</div>
|
||||
<div class="m-t-2 m-b-2">
|
||||
{{{formhtml}}}
|
||||
</div>
|
||||
<hr>
|
||||
<div class="card-title">
|
||||
<h3>{{#str}}whyisthisrequired{{/str}}</h3>
|
||||
</div>
|
||||
<div class="m-t-1">
|
||||
<p >{{#str}}explanationdigitalminor{{/str}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/error}}
|
||||
<h3>{{#str}}agelocationverification{{/str}}</h3>
|
||||
{{{formhtml}}}
|
||||
<hr>
|
||||
<h3>{{#str}}whyisthisrequired{{/str}}</h3>
|
||||
<p >{{#str}}explanationdigitalminor{{/str}}</p>
|
||||
</div>
|
||||
|
@ -17,7 +17,12 @@
|
||||
{{!
|
||||
@template core/availability_info
|
||||
|
||||
Moodle template for the course or section availability information.
|
||||
Renders the availability info on the course outline page.
|
||||
|
||||
Availability info can be displayed for activity modules or whole course
|
||||
sections. Activity modules can be either hidden from students, or available
|
||||
but not shown on course page (stealth), or the access can be restricted by
|
||||
configured conditions. Sections can be hidden.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
@ -25,9 +30,32 @@
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Context variables required for this template:
|
||||
* classes String list of CSS classes for the wrapping element
|
||||
* text HTML formatted text with the actual availability information
|
||||
* ishidden Boolean flag indiciating that the item is hidden from students
|
||||
* isstealth Boolean flag indicating that the item is in stealth mode
|
||||
* isrestricted Boolean flag indicating that restricted access conditions apply
|
||||
* isfullinfo Boolean flag indicating that the full list of restricted
|
||||
access conditions is displayed (aka teacher's view).
|
||||
|
||||
Example context (json):
|
||||
{ "classes": "", "text": "This activity is not available" }
|
||||
{
|
||||
"classes": "",
|
||||
"text": "Not available unless: <ul><li>It is on or after <strong>8 June 2012</strong></li></ul>",
|
||||
"ishidden": 0,
|
||||
"isstealth": 0,
|
||||
"isrestricted": 1,
|
||||
"isfullinfo": 1
|
||||
}
|
||||
}}
|
||||
{{#text}}
|
||||
<div class="availabilityinfo {{classes}}">{{{text}}}</div>
|
||||
<div class="availabilityinfo {{classes}}">
|
||||
{{^isrestricted}}
|
||||
<span class="tag tag-info">{{{text}}}</span>
|
||||
{{/isrestricted}}
|
||||
{{#isrestricted}}
|
||||
<span class="tag tag-info">{{#str}}restricted, core{{/str}}</span> {{{text}}}
|
||||
{{/isrestricted}}
|
||||
</div>
|
||||
{{/text}}
|
||||
|
@ -70,8 +70,8 @@
|
||||
</div>
|
||||
|
||||
<div class="submitbuttons">
|
||||
<input type="submit" name="submitbutton" class="submitbutton" value={{#quote}}{{#str}}add{{/str}}{{/quote}}>
|
||||
<input type="submit" name="addcancel" class="addcancel" value={{#quote}}{{#str}}cancel{{/str}}{{/quote}}>
|
||||
<input type="submit" name="submitbutton" class="submitbutton btn btn-primary" value={{#quote}}{{#str}}add{{/str}}{{/quote}}>
|
||||
<input type="submit" name="addcancel" class="addcancel btn btn-secondary" value={{#quote}}{{#str}}cancel{{/str}}{{/quote}}>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
@ -41,8 +41,8 @@
|
||||
}
|
||||
|
||||
}}
|
||||
<div class="row-fluid rtl-compatible">
|
||||
<div class="span4">{{$ column1 }}{{{ col1content }}}{{/ column1 }}</div>
|
||||
<div class="span4">{{$ column2 }}{{{ col2content }}}{{/ column2 }}</div>
|
||||
<div class="span4">{{$ column3 }}{{{ col3content }}}{{/ column3 }}</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4">{{$ column1 }}{{{ col1content }}}{{/ column1 }}</div>
|
||||
<div class="col-md-4">{{$ column2 }}{{{ col2content }}}{{/ column2 }}</div>
|
||||
<div class="col-md-4">{{$ column3 }}{{{ col3content }}}{{/ column3 }}</div>
|
||||
</div>
|
||||
|
@ -39,7 +39,7 @@
|
||||
}
|
||||
|
||||
}}
|
||||
<div class="row-fluid rtl-compatible">
|
||||
<div class="span4">{{$ column1 }}{{{ col1content }}}{{/ column1 }}</div>
|
||||
<div class="span8">{{$ column2 }}{{{ col2content }}}{{/ column2 }}</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4">{{$ column1 }}{{{ col1content }}}{{/ column1 }}</div>
|
||||
<div class="col-md-8">{{$ column2 }}{{{ col2content }}}{{/ column2 }}</div>
|
||||
</div>
|
||||
|
@ -38,7 +38,7 @@
|
||||
"col2content": "<div class='alert alert-success'>2. Vivamus ac orci in velit fringilla aliquam a a nisl. Cras luctus quam laoreet magna pulvinar aliquet.</div>"
|
||||
}
|
||||
}}
|
||||
<div class="row-fluid rtl-compatible">
|
||||
<div class="span8">{{$ column1 }}{{{ col1content }}}{{/ column1 }}</div>
|
||||
<div class="span4">{{$ column2 }}{{{ col2content }}}{{/ column2 }}</div>
|
||||
<div class="row">
|
||||
<div class="col-md-8">{{$ column1 }}{{{ col1content }}}{{/ column1 }}</div>
|
||||
<div class="col-md-4">{{$ column2 }}{{{ col2content }}}{{/ column2 }}</div>
|
||||
</div>
|
||||
|
@ -17,8 +17,6 @@
|
||||
{{!
|
||||
@template core/dataformat_selector
|
||||
|
||||
Template for dataformat selection and download form.
|
||||
|
||||
Context variables required for this template:
|
||||
* label
|
||||
* base
|
||||
@ -32,24 +30,26 @@
|
||||
{
|
||||
"base": "http://example.org/",
|
||||
"name": "test",
|
||||
"value": "test",
|
||||
"label": "Download table data as",
|
||||
"params": false,
|
||||
"options": [{"label": "CSV", "name": "csv"}, {"label": "Excel", "name": "excel"}],
|
||||
"submit": "Download"
|
||||
"submit": "Download",
|
||||
"sesskey": ""
|
||||
}
|
||||
}}
|
||||
<form method="get" action="{{base}}" class="dataformatselector">
|
||||
<div class="mdl-align">
|
||||
<form method="get" action="{{base}}" class="dataformatselector m-1">
|
||||
<div class="form-inline text-xs-right">
|
||||
<input type="hidden" name="sesskey" value="{{sesskey}}">
|
||||
<label for="downloadtype_{{name}}">{{label}}</label>
|
||||
<select name="{{name}}" id="downloadtype_{{name}}">
|
||||
{{#options}}
|
||||
<option value="{{value}}">{{label}}</option>
|
||||
{{/options}}
|
||||
<label for="downloadtype_{{name}}" class="mr-1">{{label}}</label>
|
||||
<select name="{{name}}" id="downloadtype_{{name}}" class="form-control">
|
||||
{{#options}}
|
||||
<option value="{{value}}">{{label}}</option>
|
||||
{{/options}}
|
||||
</select>
|
||||
<input type="submit" value="{{submit}}">
|
||||
<button type="submit" class="btn btn-secondary">{{submit}}</button>
|
||||
{{#params}}
|
||||
<input type="hidden" name="{{name}}" value="{{value}}" />
|
||||
<input type="hidden" name="{{name}}" value="{{value}}">
|
||||
{{/params}}
|
||||
</div>
|
||||
</form>
|
||||
|
@ -36,7 +36,7 @@
|
||||
{ "inputID": 1, "suggestionsId": 2, "selectionId": 3, "downArrowId": 4, "placeholder": "Select something" }
|
||||
}}
|
||||
{{#showSuggestions}}
|
||||
<input type="text" id="{{inputId}}" list="{{suggestionsId}}" placeholder="{{placeholder}}" role="combobox" aria-expanded="false" autocomplete="off" autocorrect="off" autocapitalize="off" aria-autocomplete="list" aria-owns="{{suggestionsId}} {{selectionId}}" {{#tags}}data-tags="1"{{/tags}}/><span class="form-autocomplete-downarrow" id="{{downArrowId}}">▼</span>
|
||||
<input type="text" id="{{inputId}}" class="form-control" list="{{suggestionsId}}" placeholder="{{placeholder}}" role="combobox" aria-expanded="false" autocomplete="off" autocorrect="off" autocapitalize="off" aria-autocomplete="list" aria-owns="{{suggestionsId}} {{selectionId}}" {{#tags}}data-tags="1"{{/tags}}/><span class="form-autocomplete-downarrow" id="{{downArrowId}}">▼</span>
|
||||
{{/showSuggestions}}
|
||||
{{^showSuggestions}}
|
||||
<input type="text" id="{{inputId}}" placeholder="{{placeholder}}" role="textbox" aria-owns="{{selectionId}}" {{#tags}}data-tags="1"{{/tags}}/>
|
||||
|
@ -37,15 +37,14 @@
|
||||
{ "label": "Another item label with <strong>tags</strong>", "value": "4" }
|
||||
], "noSelectionString": "No selection" }
|
||||
}}
|
||||
<div class="form-autocomplete-selection {{#multiple}}form-autocomplete-multiple{{/multiple}}" id="{{selectionId}}" role="list" aria-atomic="true" {{#multiple}}tabindex="0" aria-multiselectable="true"{{/multiple}}>
|
||||
<div class="form-autocomplete-selection w-100 {{#multiple}}form-autocomplete-multiple{{/multiple}}" id="{{selectionId}}" role="list" aria-atomic="true" {{#multiple}}tabindex="0" aria-multiselectable="true"{{/multiple}}>
|
||||
<span class="accesshide">{{#str}}selecteditems, form{{/str}}</span>
|
||||
{{#items}}
|
||||
<span role="listitem" data-value="{{value}}" aria-selected="true" class="label label-info" style="font-size: 100%; margin-bottom: 0.5rem;">
|
||||
<span role="listitem" data-value="{{value}}" aria-selected="true" class="tag tag-info mb-3 mr-1" style="font-size: 100%">
|
||||
{{#multiple}}<span aria-hidden="true">× </span>{{/multiple}}{{{label}}}
|
||||
</span>
|
||||
{{/items}}
|
||||
{{^items}}
|
||||
<span>{{noSelectionString}}</span>
|
||||
<span class="mb-3 mr-1">{{noSelectionString}}</span>
|
||||
{{/items}}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,19 +1,3 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template core/help_icon
|
||||
|
||||
@ -33,6 +17,9 @@
|
||||
}
|
||||
}
|
||||
}}
|
||||
<span class="helptooltip">
|
||||
<a href="{{url}}" title={{#quote}}{{title}}{{/quote}} aria-haspopup="true" target="_blank">{{#icon}}{{>core/pix_icon}}{{/icon}}{{#linktext}}{{.}}{{/linktext}}</a>
|
||||
</span>
|
||||
<a class="btn btn-link p-0" role="button"
|
||||
data-container="body" data-toggle="popover"
|
||||
data-placement="{{#ltr}}right{{/ltr}}{{^ltr}}left{{/ltr}}" data-content="{{text}} {{completedoclink}}"
|
||||
data-html="true" tabindex="0" data-trigger="focus">
|
||||
{{#pix}}help, core, {{{alt}}}{{/pix}}
|
||||
</a>
|
||||
|
@ -73,24 +73,30 @@
|
||||
]
|
||||
}
|
||||
}}
|
||||
<div class="initialbar {{class}}">
|
||||
<span class="initialbarlabel">{{title}}</span>
|
||||
{{#current}}
|
||||
<a class="initialbarall page-item letter" href="{{url}}">{{all}}</a>
|
||||
{{/current}}
|
||||
{{^current}}
|
||||
<div class="initialbarall letter page-item active">{{all}}</div>
|
||||
{{/current}}
|
||||
<div class="initialbar {{class}} d-flex flex-wrap justify-content-center justify-content-md-start">
|
||||
<span class="initialbarlabel mr-2">{{title}}</span>
|
||||
|
||||
<div class="initialbargroups">
|
||||
<div class="initialbargroups d-flex flex-wrap justify-content-center justify-content-md-start">
|
||||
<ul class="pagination pagination-sm">
|
||||
{{#current}}
|
||||
<li class="initialbarall page-item">
|
||||
<a class="page-link" href="{{url}}">{{all}}</a>
|
||||
</li>
|
||||
{{/current}}
|
||||
{{^current}}
|
||||
<li class="initialbarall page-item active">
|
||||
<a class="page-link">{{all}}</a>
|
||||
</li>
|
||||
{{/current}}
|
||||
</ul>
|
||||
{{#group}}
|
||||
<ul class="initialbargroup">
|
||||
<ul class="pagination pagination-sm">
|
||||
{{#letter}}
|
||||
{{#selected}}
|
||||
<li><span class="letter page-item active {{name}}">{{name}}</span></li>
|
||||
<li class="page-item active {{name}}"><span class="page-link">{{name}}</span></li>
|
||||
{{/selected}}
|
||||
{{^selected}}
|
||||
<li><a class="letter page-item {{name}}" href="{{url}}">{{name}}</a></li>
|
||||
<li class="page-item {{name}}"><a class="page-link" href="{{url}}">{{name}}</a></li>
|
||||
{{/selected}}
|
||||
{{/letter}}
|
||||
</ul>
|
||||
|
@ -19,149 +19,210 @@
|
||||
|
||||
Moodle template for the login page.
|
||||
|
||||
Context variables required for this template:
|
||||
* autofocusform: Auto focus on form ?,
|
||||
* canloginasguest - Is guest login allowed?,
|
||||
* canloginbyemail - Is login by email allowed?,
|
||||
* cansignup - Signup allowed?,
|
||||
* cookieshelpicon - cookies help icon details
|
||||
* error - Any errors in the form?,
|
||||
* forgotpasswordurl - Forgot password url,
|
||||
* hasidentityproviders - Flag, set to true to hide identity providers,
|
||||
* hasinstructions - Flag, set to true to show instructions,
|
||||
* identityproviders - List of identiy providers,
|
||||
* instructions - Instructions,
|
||||
* instructionsformat - Format of instructions,
|
||||
* loginurl - Login url,
|
||||
* rememberusername - Remeber username?,
|
||||
* signupurl - Signup url,
|
||||
* cookieshelpiconformatted - Formatted html of cookies help icon,
|
||||
* errorformatted - Formatted error,
|
||||
* logourl - Flag, logo url,
|
||||
* sitename - Name of site.
|
||||
* logintoken - Random token to protect login request.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"autofocusform": false,
|
||||
"canloginasguest": true,
|
||||
"canloginbyemail": true,
|
||||
"canloginasguest": "1",
|
||||
"canloginbyemail": false,
|
||||
"cansignup": true,
|
||||
"error": "testerror",
|
||||
"errorformatted": "Test error formatted",
|
||||
"forgotpasswordurl": "http://example.com/login/forgot_password.php",
|
||||
"cookieshelpicon": {
|
||||
"heading": "Cookies must be enabled in your browser",
|
||||
"text": "<div class=\"no-overflow\">Two cookies are used on this site. Both died..</div>",
|
||||
"icon": {
|
||||
"attributes": [
|
||||
{
|
||||
"name": "class",
|
||||
"value": "iconhelp"
|
||||
},
|
||||
{
|
||||
"name": "alt",
|
||||
"value": "Help with Cookies must be enabled in your browser"
|
||||
},
|
||||
{
|
||||
"name": "title",
|
||||
"value": "Help with Cookies must be enabled in your browser"
|
||||
},
|
||||
{
|
||||
"name": "src",
|
||||
"value": "http://localhost/stable_master/theme/image.php?theme=boost&component=core&image=help"
|
||||
}
|
||||
]
|
||||
},
|
||||
"linktext": null,
|
||||
"title": "Help with Cookies must be enabled in your browser",
|
||||
"url": "http://localhost/stable_master/help.php?component=core&identifier=cookiesenabled&lang=en",
|
||||
"ltr": true
|
||||
},
|
||||
"error": "",
|
||||
"forgotpasswordurl": "http://localhost/stable_master/login/forgot_password.php",
|
||||
"hasidentityproviders": false,
|
||||
"hasinstructions": true,
|
||||
"identityproviders": [],
|
||||
"instructions": "For full access to this site, you first need to create an account.",
|
||||
"loginurl": "http://example.com/stable_master/login/index.php",
|
||||
"instructionsformat": "1",
|
||||
"loginurl": "http://localhost/stable_master/login/index.php",
|
||||
"rememberusername": true,
|
||||
"signupurl": "http://localhost/stable_master/login/signup.php",
|
||||
"cookieshelpiconformatted": "",
|
||||
"username": "",
|
||||
"errorformatted": "",
|
||||
"logourl": false,
|
||||
"sitename": "Beer & Chips",
|
||||
"logintoken": "randomstring"
|
||||
}
|
||||
}}
|
||||
{{#hasinstructions}}
|
||||
<div class="loginbox clearfix twocolumns">
|
||||
{{/hasinstructions}}
|
||||
{{^hasinstructions}}
|
||||
<div class="loginbox clearfix onecolumn">
|
||||
{{/hasinstructions}}
|
||||
|
||||
<div class="loginpanel">
|
||||
{{#cansignup}}
|
||||
<div class="skiplinks">
|
||||
<a class="skip" href="{{signupurl}}">{{#str}} tocreatenewaccount {{/str}}</a>
|
||||
</div>
|
||||
{{/cansignup}}
|
||||
|
||||
<h2>{{#str}} login {{/str}}</h2>
|
||||
|
||||
<div class="subcontent loginsub">
|
||||
{{#error}}
|
||||
<div class="loginerrors" role="alert">
|
||||
<a href="#" id="loginerrormessage" class="accesshide">{{error}}</a>
|
||||
{{{errorformatted}}}
|
||||
</div>
|
||||
{{/error}}
|
||||
<form action="{{loginurl}}" method="post" id="login">
|
||||
<div class="loginform">
|
||||
<div class="form-label">
|
||||
<label for="username">
|
||||
{{^canloginbyemail}}
|
||||
{{#str}} username {{/str}}
|
||||
{{/canloginbyemail}}
|
||||
{{#canloginbyemail}}
|
||||
{{#str}} usernameemail {{/str}}
|
||||
{{/canloginbyemail}}
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-input">
|
||||
<input type="text" name="username" id="username" size="15" value="{{username}}" autocomplete="username">
|
||||
</div>
|
||||
<div class="clearer"><!-- --></div>
|
||||
<div class="form-label">
|
||||
<label for="password">{{#str}} password {{/str}}</label>
|
||||
</div>
|
||||
<div class="form-input">
|
||||
<input type="password" name="password" id="password" size="15" value="" autocomplete="current-password">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clearer"><!-- --></div>
|
||||
{{#rememberusername}}
|
||||
<div class="rememberpass">
|
||||
<input type="checkbox" name="rememberusername" id="rememberusername" value="1" {{#username}}checked="checked"{{/username}} />
|
||||
<label for="rememberusername">{{#str}} rememberusername, admin {{/str}}</label>
|
||||
</div>
|
||||
{{/rememberusername}}
|
||||
<div class="clearer"><!-- --></div>
|
||||
<input id="anchor" type="hidden" name="anchor" value="" />
|
||||
<script>document.getElementById('anchor').value = location.hash;</script>
|
||||
<input type="hidden" name="logintoken" value="{{logintoken}}">
|
||||
<input type="submit" id="loginbtn" value={{#quote}}{{#str}} login {{/str}}{{/quote}} />
|
||||
<div class="forgetpass">
|
||||
<a href="{{forgotpasswordurl}}">{{#str}} forgotten {{/str}}</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="desc">
|
||||
{{#str}} cookiesenabled {{/str}}
|
||||
{{{cookieshelpiconformatted}}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{{#canloginasguest}}
|
||||
<div class="subcontent guestsub">
|
||||
<div class="desc">{{#str}} someallowguest {{/str}}</div>
|
||||
<form action="{{loginurl}}" method="post" id="guestlogin">
|
||||
<div class="guestform">
|
||||
<input type="hidden" name="logintoken" value="{{logintoken}}">
|
||||
<input type="hidden" name="username" value="guest" />
|
||||
<input type="hidden" name="password" value="guest" />
|
||||
<input type="submit" value={{#quote}}{{#str}} loginguest {{/str}}{{/quote}} />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{/canloginasguest}}
|
||||
|
||||
</div>
|
||||
|
||||
<div class="signuppanel">
|
||||
{{#hasinstructions}}
|
||||
<h2>{{#str}} firsttime {{/str}}</h2>
|
||||
<div class="subcontent">
|
||||
{{{instructions}}}
|
||||
<div class="my-1 my-sm-5"></div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-xl-6 col-sm-8 ">
|
||||
<div class="card">
|
||||
<div class="card-block">
|
||||
{{#logourl}}
|
||||
<h2 class="card-header text-center" ><img src="{{logourl}}" title="{{sitename}}" alt="{{sitename}}"/></h2>
|
||||
{{/logourl}}
|
||||
{{^logourl}}
|
||||
<h2 class="card-header text-center">{{sitename}}</h2>
|
||||
{{/logourl}}
|
||||
<div class="card-body">
|
||||
{{#cansignup}}
|
||||
<div class="signupform">
|
||||
<form action="{{signupurl}}" method="get" id="signup">
|
||||
<div>
|
||||
<input type="submit" value={{#quote}}{{#str}} startsignup {{/str}}{{/quote}} />
|
||||
</div>
|
||||
</form>
|
||||
<div class="sr-only">
|
||||
<a href="{{signupurl}}">{{#str}} tocreatenewaccount {{/str}}</a>
|
||||
</div>
|
||||
{{/cansignup}}
|
||||
</div>
|
||||
{{/hasinstructions}}
|
||||
|
||||
{{#hasidentityproviders}}
|
||||
<div class="subcontent potentialidps">
|
||||
<h6>{{#str}} potentialidps, auth {{/str}}</h6>
|
||||
<div class="potentialidplist">
|
||||
{{#identityproviders}}
|
||||
<div class="potentialidp">
|
||||
<a href="{{url}}" title={{#quote}}{{name}}{{/quote}} class="btn">
|
||||
{{#iconurl}}
|
||||
<img src="{{iconurl}}" alt="" width="24" height="24"/>
|
||||
{{/iconurl}}
|
||||
{{name}}
|
||||
</a>
|
||||
{{#error}}
|
||||
<div class="loginerrors mt-3">
|
||||
<a href="#" id="loginerrormessage" class="accesshide">{{error}}</a>
|
||||
<div class="alert alert-danger" role="alert" data-aria-autofocus="true">{{error}}</div>
|
||||
</div>
|
||||
{{/error}}
|
||||
|
||||
<div class="row justify-content-md-center">
|
||||
<div class="col-md-5">
|
||||
<form class="mt-3" action="{{loginurl}}" method="post" id="login">
|
||||
<input id="anchor" type="hidden" name="anchor" value="">
|
||||
<script>document.getElementById('anchor').value = location.hash;</script>
|
||||
<input type="hidden" name="logintoken" value="{{logintoken}}">
|
||||
<div class="form-group">
|
||||
<label for="username" class="sr-only">
|
||||
{{^canloginbyemail}}
|
||||
{{#str}} username {{/str}}
|
||||
{{/canloginbyemail}}
|
||||
{{#canloginbyemail}}
|
||||
{{#str}} usernameemail {{/str}}
|
||||
{{/canloginbyemail}}
|
||||
</label>
|
||||
<input type="text" name="username" id="username"
|
||||
class="form-control"
|
||||
value="{{username}}"
|
||||
placeholder={{#quote}}{{^canloginbyemail}}{{#str}}username{{/str}}{{/canloginbyemail}}{{#canloginbyemail}}{{#str}}usernameemail{{/str}}{{/canloginbyemail}}{{/quote}}
|
||||
autocomplete="username">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password" class="sr-only">{{#str}} password {{/str}}</label>
|
||||
<input type="password" name="password" id="password" value=""
|
||||
class="form-control"
|
||||
placeholder={{#quote}}{{#str}}password{{/str}}{{/quote}}
|
||||
autocomplete="current-password">
|
||||
</div>
|
||||
{{#rememberusername}}
|
||||
<div class="rememberpass mt-3">
|
||||
<input type="checkbox" name="rememberusername" id="rememberusername" value="1" {{#username}}checked="checked"{{/username}} />
|
||||
<label for="rememberusername">{{#str}} rememberusername, admin {{/str}}</label>
|
||||
</div>
|
||||
{{/rememberusername}}
|
||||
|
||||
<button type="submit" class="btn btn-primary btn-block mt-3" id="loginbtn">{{#str}}login{{/str}}</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="col-md-5">
|
||||
<div class="forgetpass mt-3">
|
||||
<p><a href="{{forgotpasswordurl}}">{{#str}}forgotten{{/str}}</a></p>
|
||||
</div>
|
||||
{{/identityproviders}}
|
||||
|
||||
<div class="mt-3">
|
||||
{{#str}} cookiesenabled {{/str}}
|
||||
{{{cookieshelpiconformatted}}}
|
||||
</div>
|
||||
{{#canloginasguest}}
|
||||
<div class="mt-2">
|
||||
<p>{{#str}}someallowguest{{/str}}</p>
|
||||
<form action="{{loginurl}}" method="post" id="guestlogin">
|
||||
<input type="hidden" name="logintoken" value="{{logintoken}}">
|
||||
<input type="hidden" name="username" value="guest" />
|
||||
<input type="hidden" name="password" value="guest" />
|
||||
<button class="btn btn-secondary btn-block" type="submit">{{#str}}loginguest{{/str}}</button>
|
||||
</form>
|
||||
</div>
|
||||
{{/canloginasguest}}
|
||||
|
||||
{{#hasidentityproviders}}
|
||||
<h6 class="mt-2">{{#str}} potentialidps, auth {{/str}}</h6>
|
||||
<div class="potentialidplist" class="mt-3">
|
||||
{{#identityproviders}}
|
||||
<div class="potentialidp">
|
||||
<a href="{{url}}" title={{#quote}}{{name}}{{/quote}} class="btn btn-secondary btn-block">
|
||||
{{#iconurl}}
|
||||
<img src="{{iconurl}}" alt="" width="24" height="24"/>
|
||||
{{/iconurl}}
|
||||
{{name}}
|
||||
</a>
|
||||
</div>
|
||||
{{/identityproviders}}
|
||||
</div>
|
||||
{{/hasidentityproviders}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/hasidentityproviders}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{{#hasinstructions}}
|
||||
<div class="row justify-content-center mt-3">
|
||||
<div class="col-xl-6 col-sm-8">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="card-title">
|
||||
<h2>{{#str}}firsttime{{/str}}</h2>
|
||||
</div>
|
||||
<div>
|
||||
{{{instructions}}}
|
||||
{{#cansignup}}
|
||||
<form class="mt-3" action="{{signupurl}}" method="get" id="signup">
|
||||
<button type="submit" class="btn btn-secondary">{{#str}}startsignup{{/str}}</button>
|
||||
</form>
|
||||
{{/cansignup}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/hasinstructions}}
|
||||
|
||||
{{#js}}
|
||||
{{#error}}
|
||||
|
@ -40,28 +40,28 @@
|
||||
}
|
||||
}}
|
||||
|
||||
<div class="modal-container moodle-has-zindex hide" data-region="modal-container" aria-hidden="true" role="dialog">
|
||||
<div class="modal {{$classes}}{{/classes}}"
|
||||
data-region="modal"
|
||||
aria-labelledby="{{uniqid}}-modal-title"
|
||||
role="document" tabindex="0">
|
||||
<div class="modal-header {{$headerclasses}}{{headerclasses}}{{/headerclasses}}" data-region="header">
|
||||
<button type="button" class="close" data-action="hide" title="{{#str}} closebuttontitle {{/str}}"></button>
|
||||
{{$header}}
|
||||
<h3 id="{{uniqid}}-modal-title" class="modal-title" data-region="title">
|
||||
{{$title}}{{title}}{{/title}}
|
||||
</h3>
|
||||
{{/header}}
|
||||
</div>
|
||||
<div class="modal-body" data-region="body">
|
||||
{{$body}}
|
||||
{{{body}}}
|
||||
{{/body}}
|
||||
</div>
|
||||
<div class="modal-footer" data-region="footer">
|
||||
{{$footer}}
|
||||
{{{footer}}}
|
||||
{{/footer}}
|
||||
<div class="modal moodle-has-zindex" data-region="modal-container" aria-hidden="true" role="dialog">
|
||||
<div class="modal-dialog {{$classes}}{{/classes}}" role="document" data-region="modal" aria-labelledby="{{uniqid}}-modal-title" tabindex="0">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header {{$headerclasses}}{{headerclasses}}{{/headerclasses}}" data-region="header">
|
||||
|
||||
{{$header}}
|
||||
<h5 id="{{uniqid}}-modal-title" class="modal-title" data-region="title">{{$title}}{{title}}{{/title}}</h5>
|
||||
{{/header}}
|
||||
<button type="button" class="close" data-action="hide" aria-label={{#quote}}{{#str}}closebuttontitle{{/str}}{{/quote}}>
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body" data-region="body">
|
||||
{{$body}}
|
||||
{{{body}}}
|
||||
{{/body}}
|
||||
</div>
|
||||
<div class="modal-footer" data-region="footer">
|
||||
{{$footer}}
|
||||
{{{footer}}}
|
||||
{{/footer}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -33,4 +33,4 @@
|
||||
Example context (json):
|
||||
{}
|
||||
}}
|
||||
<div class="modal-backdrop hide" aria-hidden="true" data-region="modal-backdrop"></div>
|
||||
<div class="modal-backdrop in hide" aria-hidden="true" data-region="modal-backdrop"></div>
|
||||
|
@ -36,15 +36,9 @@
|
||||
Example context (json):
|
||||
{ "message": "Your pants are on fire!", "closebutton": 1, "announce": 1, "extraclasses": "foo bar"}
|
||||
}}
|
||||
<div class="alert alert-error alert-block fade in {{ extraclasses }}" {{!
|
||||
}}{{# announce }} role="alert"{{/ announce }}{{!
|
||||
<div class="alert alert-danger alert-block fade in {{ extraclasses }}" {{!
|
||||
}}{{# announce }} role="alert" data-aria-autofocus="true"{{/ announce }}{{!
|
||||
}}>
|
||||
{{# closebutton }}<button type="button" class="close" data-dismiss="alert">×</button>{{/ closebutton }}
|
||||
{{{ message }}}
|
||||
</div>
|
||||
{{# js }}
|
||||
require(['jquery', 'theme_bootstrapbase/bootstrap'], function($) {
|
||||
// Setup closing of bootstrap alerts.
|
||||
$().alert();
|
||||
});
|
||||
{{/ js }}
|
||||
|
@ -37,14 +37,9 @@
|
||||
{ "message": "Your pants are on fire!", "closebutton": 1, "announce": 1, "extraclasses": "foo bar"}
|
||||
}}
|
||||
<div class="alert alert-info alert-block fade in {{ extraclasses }}" {{!
|
||||
}}{{# announce }} role="alert"{{/ announce }}{{!
|
||||
}}{{# announce }} role="alert" data-aria-autofocus="true"{{/ announce }}{{!
|
||||
}}>
|
||||
{{# closebutton }}<button type="button" class="close" data-dismiss="alert">×</button>{{/ closebutton }}
|
||||
{{{ message }}}
|
||||
</div>
|
||||
{{# js }}
|
||||
require(['jquery', 'theme_bootstrapbase/bootstrap'], function($) {
|
||||
// Setup closing of bootstrap alerts.
|
||||
$().alert();
|
||||
});
|
||||
{{/ js }}
|
||||
|
||||
|
@ -37,14 +37,8 @@
|
||||
{ "message": "Your pants are on fire!", "closebutton": 1, "announce": 1, "extraclasses": "foo bar"}
|
||||
}}
|
||||
<div class="alert alert-success alert-block fade in {{ extraclasses }}" {{!
|
||||
}}{{# announce }} role="alert"{{/ announce }}{{!
|
||||
}}{{# announce }} role="alert" data-aria-autofocus="true"{{/ announce }}{{!
|
||||
}}>
|
||||
{{# closebutton }}<button type="button" class="close" data-dismiss="alert">×</button>{{/ closebutton }}
|
||||
{{{ message }}}
|
||||
</div>
|
||||
{{# js }}
|
||||
require(['jquery', 'theme_bootstrapbase/bootstrap'], function($) {
|
||||
// Setup closing of bootstrap alerts.
|
||||
$().alert();
|
||||
});
|
||||
{{/ js }}
|
||||
|
@ -37,14 +37,8 @@
|
||||
{ "message": "Your pants are on fire!", "closebutton": 1, "announce": 1, "extraclasses": "foo bar"}
|
||||
}}
|
||||
<div class="alert alert-warning alert-block fade in {{ extraclasses }}" {{!
|
||||
}}{{# announce }} role="alert"{{/ announce }}{{!
|
||||
}}{{# announce }} role="alert" data-aria-autofocus="true"{{/ announce }}{{!
|
||||
}}>
|
||||
{{# closebutton }}<button type="button" class="close" data-dismiss="alert">×</button>{{/ closebutton }}
|
||||
{{{ message }}}
|
||||
</div>
|
||||
{{# js }}
|
||||
require(['jquery', 'theme_bootstrapbase/bootstrap'], function($) {
|
||||
// Setup closing of bootstrap alerts.
|
||||
$().alert();
|
||||
});
|
||||
{{/ js }}
|
||||
|
@ -25,12 +25,12 @@
|
||||
"width": "500"
|
||||
}
|
||||
}}
|
||||
<div class="progressbar_container" style="width: {{width}}px;" id="{{id}}">
|
||||
<h2 id="{{id}}_status"></h2>
|
||||
<div class="progress progress-striped active">
|
||||
<div id="{{id}}_bar" class="bar" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"> </div>
|
||||
<div id="{{id}}" class="row progressbar_container">
|
||||
<div class="col-md-6 push-md-3">
|
||||
<p id="{{id}}_status" class="text-xs-center"></p>
|
||||
<progress id="{{id}}_bar" class="progress progress-striped progress-animated" value="0" max="100"></progress>
|
||||
<p id="{{id}}_estimate" class="text-xs-center"></p>
|
||||
</div>
|
||||
<p id="{{id}}_estimate"></p>
|
||||
</div>
|
||||
|
||||
{{! We must not use the JS helper otherwise this gets executed too late. }}
|
||||
@ -47,20 +47,18 @@
|
||||
estimate = e.detail.estimate;
|
||||
|
||||
statusIndicator.textContent = msg;
|
||||
progressBar.textContent = '' + percent + '%';
|
||||
progressBar.setAttribute('value', Math.round(percent));
|
||||
if (percent === 100) {
|
||||
el.classList.add('progress-success');
|
||||
estimateIndicator.textContent = '';
|
||||
progressBar.classList.add('progress-success');
|
||||
estimateIndicator.textContent = '100%';
|
||||
} else {
|
||||
if (estimate) {
|
||||
estimateIndicator.textContent = estimate;
|
||||
estimateIndicator.textContent = estimate + ' - ' + percent + '%';
|
||||
} else {
|
||||
estimateIndicator.textContent = '';
|
||||
estimateIndicator.textContent = '' + percent + '%';
|
||||
}
|
||||
el.classList.remove('progress-success');
|
||||
progressBar.classList.remove('progress-success');
|
||||
}
|
||||
progressBar.setAttribute('aria-valuenow', percent);
|
||||
progressBar.setAttribute('style', 'width: ' + percent + '%');
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
@ -30,8 +30,8 @@
|
||||
]
|
||||
}
|
||||
}}
|
||||
<label for="{{id}}" class="accesshide">{{label}}</label>
|
||||
<select name="{{name}}" id="{{id}}"{{#attributes}} {{name}}="{{value}}"{{/attributes}}>
|
||||
<label for="{{id}}" class="sr-only">{{label}}</label>
|
||||
<select name="{{name}}" id="{{id}}"{{#attributes}} {{name}}="{{value}}"{{/attributes}} class="form-control">
|
||||
{{#options}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/options}}
|
||||
|
@ -39,105 +39,107 @@
|
||||
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<!-- First the top most node and immediate children -->
|
||||
<li class="active"> <a href="#link{{node.key}}" data-toggle="tab" role="tab">{{node.text}}</a> </li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="#link{{node.key}}" data-toggle="tab" role="tab">{{node.text}}</a>
|
||||
</li>
|
||||
<!-- Now the first level children with sub nodes -->
|
||||
{{#node.children}}
|
||||
{{#children.count}}
|
||||
{{#display}}
|
||||
{{^is_short_branch}}
|
||||
<li> <a href="#link{{key}}" data-toggle="tab" role="tab">{{text}}</a> </li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#link{{key}}" data-toggle="tab" role="tab">{{text}}</a>
|
||||
</li>
|
||||
{{/is_short_branch}}
|
||||
{{/display}}
|
||||
{{/children.count}}
|
||||
{{/node.children}}
|
||||
</ul>
|
||||
|
||||
<div class="tab-content">
|
||||
<div class="tab-content mt-3">
|
||||
<div class="tab-pane active" id="link{{node.key}}" role="tabpanel">
|
||||
<div class="well">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="span9 offset3">
|
||||
<ul class="unstyled indented-list">
|
||||
{{#node.children}}
|
||||
{{^children.count}}
|
||||
{{#display}}
|
||||
<li><a href="{{{action}}}">{{text}}</a></li>
|
||||
{{/display}}
|
||||
{{/children.count}}
|
||||
{{/node.children}}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
</div>
|
||||
<div class="col">
|
||||
<ul class="list-unstyled">
|
||||
{{#node.children}}
|
||||
{{^children.count}}
|
||||
{{#display}}
|
||||
<li><a href="{{{action}}}">{{text}}</a></li>
|
||||
{{/display}}
|
||||
{{/children.count}}
|
||||
{{/node.children}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#node.children}}
|
||||
{{#display}}
|
||||
{{#children.count}}
|
||||
{{#is_short_branch}}
|
||||
{{#node.children}}
|
||||
{{#display}}
|
||||
{{#children.count}}
|
||||
{{#is_short_branch}}
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
{{#action}}<h4><a href="{{action}}">{{text}}</a><h4>{{/action}}
|
||||
{{^action}}<h4>{{text}}<h4>{{/action}}
|
||||
</div>
|
||||
<div class="col">
|
||||
<ul class="list-unstyled">
|
||||
{{#children}}
|
||||
{{> core/settings_link_page_single }}
|
||||
{{/children}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{/is_short_branch}}
|
||||
{{/children.count}}
|
||||
{{/display}}
|
||||
{{/node.children}}
|
||||
</div>
|
||||
</div>
|
||||
{{#node.children}}
|
||||
{{#children.count}}
|
||||
<div class="tab-pane" id="link{{key}}" role="tabpanel">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
{{#action}}<h4><a href="{{action}}">{{text}}</a><h4>{{/action}}
|
||||
{{^action}}<h4>{{text}}<h4>{{/action}}
|
||||
</div>
|
||||
<div class="col-sm-9">
|
||||
<ul class="list-unstyled">
|
||||
{{#children}}
|
||||
{{#display}}
|
||||
{{^children.count}}
|
||||
<li><a href="{{{action}}}">{{text}}</a></li>
|
||||
{{/children.count}}
|
||||
{{/display}}
|
||||
{{/children}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{#children}}
|
||||
{{#display}}
|
||||
{{#children.count}}
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="span3">
|
||||
<div class="col-sm-3">
|
||||
{{#action}}<h4><a href="{{action}}">{{text}}</a><h4>{{/action}}
|
||||
{{^action}}<h4>{{text}}<h4>{{/action}}
|
||||
</div>
|
||||
<div class="span9">
|
||||
<ul class="unstyled indented-list">
|
||||
<div class="col-sm-9">
|
||||
<ul class="list-unstyled">
|
||||
{{#children}}
|
||||
{{> core/settings_link_page_single }}
|
||||
{{/children}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{/is_short_branch}}
|
||||
{{/children.count}}
|
||||
{{/display}}
|
||||
{{/node.children}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{#node.children}}
|
||||
{{#children.count}}
|
||||
<div class="tab-pane" id="link{{key}}" role="tabpanel">
|
||||
<div class="well">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="span3">
|
||||
{{#action}}<h4><a href="{{action}}">{{text}}</a><h4>{{/action}}
|
||||
{{^action}}<h4>{{text}}<h4>{{/action}}
|
||||
</div>
|
||||
<div class="span9">
|
||||
<ul class="unstyled">
|
||||
{{#children}}
|
||||
{{#display}}
|
||||
{{^children.count}}
|
||||
<li><a href="{{{action}}}">{{text}}</a></li>
|
||||
{{/children.count}}
|
||||
{{/display}}
|
||||
{{/children}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{#children}}
|
||||
{{#display}}
|
||||
{{#children.count}}
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="span3">
|
||||
{{#action}}<h4><a href="{{action}}">{{text}}</a><h4>{{/action}}
|
||||
{{^action}}<h4>{{text}}<h4>{{/action}}
|
||||
</div>
|
||||
<div class="span9">
|
||||
<ul class="unstyled indented-list">
|
||||
{{#children}}
|
||||
{{> core/settings_link_page_single }}
|
||||
{{/children}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{/children.count}}
|
||||
{{/display}}
|
||||
{{/children}}
|
||||
</div>
|
||||
{{/children.count}}
|
||||
{{/display}}
|
||||
{{/children}}
|
||||
</div>
|
||||
</div>
|
||||
{{/children.count}}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user