Merge branch 'wip-MDL-39824-m26' of http://github.com/samhemelryk/moodle

This commit is contained in:
Dan Poltawski 2013-06-10 10:54:22 +08:00
commit 07bac478b6
32 changed files with 3183 additions and 485 deletions

View File

@ -341,7 +341,7 @@ class block_manager {
* output the blocks anyway, so we are not doing wasted effort.)
*
* @param string $region a block region that exists on this page.
* @param object $output a core_renderer. normally the global $OUTPUT.
* @param core_renderer $output a core_renderer. normally the global $OUTPUT.
* @return boolean Whether there is anything in this region.
*/
public function region_has_content($region, $output) {

View File

@ -325,6 +325,14 @@ class theme_config {
*/
public $yuicssmodules = array('cssreset', 'cssfonts', 'cssgrids', 'cssbase');
/**
* An associative array of block manipulations that should be made if the user is using an rtl language.
* The key is the original block region, and the value is the block region to change to.
* This is used when displaying blocks for regions only.
* @var array
*/
public $blockrtlmanipulations = array();
/**
* @var renderer_factory Instance of the renderer_factory implementation
* we are using. Implementation detail.
@ -418,7 +426,7 @@ class theme_config {
$configurable = array('parents', 'sheets', 'parents_exclude_sheets', 'plugins_exclude_sheets', 'javascripts', 'javascripts_footer',
'parents_exclude_javascripts', 'layouts', 'enable_dock', 'enablecourseajax', 'supportscssoptimisation',
'rendererfactory', 'csspostprocess', 'editor_sheets', 'rarrow', 'larrow', 'hidefromselector', 'doctype',
'yuicssmodules');
'yuicssmodules', 'blockrtlmanipulations');
foreach ($config as $key=>$value) {
if (in_array($key, $configurable)) {

View File

@ -921,7 +921,7 @@ class core_renderer extends renderer_base {
$functioncalled = true;
$courseformat = course_get_format($this->page->course);
if (($obj = $courseformat->course_content_header()) !== null) {
return $courseformat->get_renderer($this->page)->render($obj);
return html_writer::div($courseformat->get_renderer($this->page)->render($obj), 'course-content-header');
}
return '';
}
@ -948,7 +948,7 @@ class core_renderer extends renderer_base {
require_once($CFG->dirroot.'/course/lib.php');
$courseformat = course_get_format($this->page->course);
if (($obj = $courseformat->course_content_footer()) !== null) {
return $courseformat->get_renderer($this->page)->render($obj);
return html_writer::div($courseformat->get_renderer($this->page)->render($obj), 'course-content-footer');
}
return '';
}
@ -1228,6 +1228,7 @@ class core_renderer extends renderer_base {
* @return string the HTML to be output.
*/
public function blocks_for_region($region) {
$region = $this->page->apply_theme_region_manipulations($region);
$blockcontents = $this->page->blocks->get_content_for_region($region, $this);
$blocks = $this->page->blocks->get_blocks_for_region($region);
$lastblock = null;
@ -2675,10 +2676,13 @@ EOD;
*/
public function navbar() {
$items = $this->page->navbar->get_items();
$itemcount = count($items);
if ($itemcount === 0) {
return '';
}
$htmlblocks = array();
// Iterate the navarray and display each node
$itemcount = count($items);
$separator = get_separator();
for ($i=0;$i < $itemcount;$i++) {
$item = $items[$i];
@ -2827,7 +2831,7 @@ EOD;
$jscode = "(function(){{$jscode}})";
$this->page->requires->yui_module('node-menunav', $jscode);
// Build the root nodes as required by YUI
$content = html_writer::start_tag('div', array('id'=>'custom_menu_'.$menucount, 'class'=>'yui3-menu yui3-menu-horizontal javascript-disabled'));
$content = html_writer::start_tag('div', array('id'=>'custom_menu_'.$menucount, 'class'=>'yui3-menu yui3-menu-horizontal javascript-disabled custom-menu'));
$content .= html_writer::start_tag('div', array('class'=>'yui3-menu-content'));
$content .= html_writer::start_tag('ul');
// Render each child
@ -3028,6 +3032,146 @@ EOD;
return $str;
}
/**
* Get the HTML for blocks in the given region.
*
* @since 2.5.1 2.6
* @param string $region The region to get HTML for.
* @return string HTML.
*/
public function blocks($region, $classes = array(), $tag = 'aside') {
$displayregion = $this->page->apply_theme_region_manipulations($region);
$classes = (array)$classes;
$classes[] = 'block-region';
$attributes = array(
'id' => 'block-region-'.preg_replace('#[^a-zA-Z0-9_\-]+#', '-', $displayregion),
'class' => join(' ', $classes),
'data-blockregion' => $displayregion,
'data-droptarget' => '1'
);
return html_writer::tag($tag, $this->blocks_for_region($region), $attributes);
}
/**
* Returns the CSS classes to apply to the body tag.
*
* @since 2.5.1 2.6
* @param array $additionalclasses Any additional classes to apply.
* @return string
*/
public function body_css_classes(array $additionalclasses = array()) {
// Add a class for each block region on the page.
// We use the block manager here because the theme object makes get_string calls.
foreach ($this->page->blocks->get_regions() as $region) {
$additionalclasses[] = 'has-region-'.$region;
if ($this->page->blocks->region_has_content($region, $this)) {
$additionalclasses[] = 'used-region-'.$region;
} else {
$additionalclasses[] = 'empty-region-'.$region;
}
}
foreach ($this->page->layout_options as $option => $value) {
if ($value) {
$additionalclasses[] = 'layout-option-'.$option;
}
}
$css = $this->page->bodyclasses .' '. join(' ', $additionalclasses);
return $css;
}
/**
* The ID attribute to apply to the body tag.
*
* @since 2.5.1 2.6
* @return string
*/
public function body_id() {
return $this->page->bodyid;
}
/**
* Returns HTML attributes to use within the body tag. This includes an ID and classes.
*
* @since 2.5.1 2.6
* @param string|array $additionalclasses Any additional classes to give the body tag,
* @return string
*/
public function body_attributes($additionalclasses = array()) {
if (!is_array($additionalclasses)) {
$additionalclasses = explode(' ', $additionalclasses);
}
return ' id="'. $this->body_id().'" class="'.$this->body_css_classes($additionalclasses).'"';
}
/**
* Gets HTML for the page heading.
*
* @since 2.5.1 2.6
* @param string $tag The tag to encase the heading in. h1 by default.
* @return string HTML.
*/
public function page_heading($tag = 'h1') {
return html_writer::tag($tag, $this->page->heading);
}
/**
* Gets the HTML for the page heading button.
*
* @since 2.5.1 2.6
* @return string HTML.
*/
public function page_heading_button() {
return $this->page->button;
}
/**
* Returns the Moodle docs link to use for this page.
*
* @since 2.5.1 2.6
* @param string $text
* @return string
*/
public function page_doc_link($text = null) {
if ($text === null) {
$text = get_string('moodledocslink');
}
$path = page_get_doc_link_path($this->page);
if (!$path) {
return '';
}
return $this->doc_link($path, $text);
}
/**
* Returns the page heading menu.
*
* @since 2.5.1 2.6
* @return string HTML.
*/
public function page_heading_menu() {
return $this->page->headingmenu;
}
/**
* Returns the title to use on the page.
*
* @since 2.5.1 2.6
* @return string
*/
public function page_title() {
return $this->page->title;
}
/**
* Returns the URL for the favicon.
*
* @since 2.5.1 2.6
* @return string The favicon URL
*/
public function favicon() {
return $this->pix_url('favicon', 'theme');
}
}
/**

View File

@ -51,7 +51,8 @@ defined('MOODLE_INTERNAL') || die();
* the forum or quiz table) that this page belongs to. Will be null
* if this page is not within a module.
* @property-read array $alternativeversions Mime type => object with ->url and ->title.
* @property-read blocks_manager $blocks The blocks manager object for this page.
* @property-read block_manager $blocks The blocks manager object for this page.
* @property-read array $blockmanipulations
* @property-read string $bodyclasses A string to use within the class attribute on the body tag.
* @property-read string $bodyid A string to use as the id of the body tag.
* @property-read string $button The HTML to go where the Turn editing on button normally goes.
@ -637,6 +638,22 @@ class moodle_page {
return $this->_theme;
}
/**
* Returns an array of minipulations or false if there are none to make.
*
* @since 2.5.1 2.6
* @return bool|array
*/
protected function magic_get_blockmanipulations() {
if (!right_to_left()) {
return false;
}
if (is_null($this->_theme)) {
$this->initialise_theme_and_output();
}
return $this->_theme->blockrtlmanipulations;
}
/**
* Please do not call this method directly, use the ->devicetypeinuse syntax. {@link moodle_page::__get()}.
* @return string The device type being used.
@ -1825,4 +1842,18 @@ class moodle_page {
public function set_popup_notification_allowed($allowed) {
$this->_popup_notification_allowed = $allowed;
}
/**
* Returns the block region having made any required theme manipulations.
*
* @since 2.5.1 2.6
* @param string $region
* @return string
*/
public function apply_theme_region_manipulations($region) {
if ($this->blockmanipulations && isset($this->blockmanipulations[$region])) {
return $this->blockmanipulations[$region];
}
return $region;
}
}

View File

@ -909,22 +909,39 @@ function close_window($delay = 0, $reloadopener = false) {
* @return string The link to user documentation for this current page
*/
function page_doc_link($text='') {
global $CFG, $PAGE, $OUTPUT;
if (empty($CFG->docroot) || during_initial_install()) {
return '';
}
if (!has_capability('moodle/site:doclinks', $PAGE->context)) {
return '';
}
$path = $PAGE->docspath;
global $OUTPUT, $PAGE;
$path = page_get_doc_link_path($PAGE);
if (!$path) {
return '';
}
return $OUTPUT->doc_link($path, $text);
}
/**
* Returns the path to use when constructing a link to the docs.
*
* @since 2.5.1 2.6
* @global stdClass $CFG
* @param moodle_page $page
* @return string
*/
function page_get_doc_link_path(moodle_page $page) {
global $CFG;
if (empty($CFG->docroot) || during_initial_install()) {
return '';
}
if (!has_capability('moodle/site:doclinks', $page->context)) {
return '';
}
$path = $page->docspath;
if (!$path) {
return '';
}
return $path;
}
/**
* Validates an email to make sure it makes sense.

View File

@ -1,5 +1,11 @@
YUI.add('moodle-core-blocks', function (Y, NAME) {
/**
* Provides drag and drop functionality for blocks.
*
* @module moodle-core-blockdraganddrop
*/
var AJAXURL = '/lib/ajax/blocks.php',
CSS = {
BLOCK : 'block',
@ -15,6 +21,16 @@ CSS = {
REGIONMAIN : 'region-main'
};
/**
* Legacy drag and drop manager.
* This drag and drop manager is specifically designed for themes using side-pre and side-post
* that do not make use of the block output methods introduced by MDL-39824.
*
* @namespace M.core.blockdraganddrop
* @class LegacyManager
* @constructor
* @extends M.core.dragdrop
*/
var DRAGBLOCK = function() {
DRAGBLOCK.superclass.constructor.apply(this, arguments);
};
@ -301,11 +317,676 @@ Y.extend(DRAGBLOCK, M.core.dragdrop, {
}
});
M.core_blocks = M.core_blocks || {};
M.core_blocks.init_dragdrop = function(params) {
new DRAGBLOCK(params);
/**
* Core namespace.
* @static
* @class core
*/
M.core = M.core || {};
/**
* Block drag and drop static class.
* @namespace M.core
* @class blockdraganddrop
* @static
*/
M.core.blockdraganddrop = M.core.blockdraganddrop || {};
/**
* True if the page is using the new blocks methods.
* @private
* @static
* @property _isusingnewblocksmethod
* @type Boolean
* @default null
*/
M.core.blockdraganddrop._isusingnewblocksmethod = null;
/**
* Returns true if the page is using the new blocks methods.
* @static
* @method is_using_blocks_render_method
* @return Boolean
*/
M.core.blockdraganddrop.is_using_blocks_render_method = function() {
if (this._isusingnewblocksmethod === null) {
var goodregions = Y.all('.block-region[data-blockregion]').size();
var allregions = Y.all('.block-region').size();
this._isusingnewblocksmethod = (allregions === goodregions);
}
return this._isusingnewblocksmethod;
};
/**
* Initialises a drag and drop manager.
* This should only ever be called once for a page.
* @static
* @method init
* @param {Object} params
* @return Manager
*/
M.core.blockdraganddrop.init = function(params) {
if (this.is_using_blocks_render_method()) {
new MANAGER(params);
} else {
new DRAGBLOCK(params);
}
};
/**
* Legacy code to keep things working.
*/
M.core_blocks = M.core_blocks || {};
M.core_blocks.init_dragdrop = function(params) {
M.core.blockdraganddrop.init(params);
};/**
* This file contains the drag and drop manager class.
*
* Provides drag and drop functionality for blocks.
*
* @module moodle-core-blockdraganddrop
*/
/**
* Constructs a new Block drag and drop manager.
*
* @namespace M.core.blockdraganddrop
* @class Manager
* @constructor
* @extends M.core.dragdrop
*/
var MANAGER = function() {
MANAGER.superclass.constructor.apply(this, arguments);
};
MANAGER.prototype = {
/**
* The skip block link from above the block being dragged while a drag is in progress.
* Required by the M.core.dragdrop from whom this class extends.
* @private
* @property skipnodetop
* @type Node
* @default null
*/
skipnodetop : null,
/**
* The skip block link from below the block being dragged while a drag is in progress.
* Required by the M.core.dragdrop from whom this class extends.
* @private
* @property skipnodebottom
* @type Node
* @default null
*/
skipnodebottom : null,
/**
* An associative object of regions and the
* @property regionobjects
* @type {Object} Primitive object mocking an associative array.
* @type {BLOCKREGION} [regionname]* Each item uses the region name as the key with the value being
* an instance of the BLOCKREGION class.
*/
regionobjects : {},
/**
* Called during the initialisation process of the object.
* @method initializer
*/
initializer : function() {
Y.log('Initialising drag and drop for blocks.', 'info');
var regionnames = this.get('regions'),
i = 0,
region,
regionname,
droptarget,
dragdelegation;
// Evil required by M.core.dragdrop.
this.groups = ['block'];
this.samenodeclass = CSS.BLOCK;
this.parentnodeclass = CSS.BLOCKREGION;
// Add relevant classes and ID to 'content' block region on My Home page.
var myhomecontent = Y.Node.all('body#'+CSS.MYINDEX+' #'+CSS.REGIONMAIN+' > .'+CSS.REGIONCONTENT);
if (myhomecontent.size() > 0) {
var contentregion = myhomecontent.item(0);
contentregion.addClass(CSS.BLOCKREGION);
contentregion.set('id', CSS.REGIONCONTENT);
contentregion.one('div').addClass(CSS.REGIONCONTENT);
}
for (i in regionnames) {
regionname = regionnames[i];
region = new BLOCKREGION({
manager : this,
region : regionname,
node : Y.one('#block-region-'+regionname)
});
this.regionobjects[regionname] = region;
// Setting blockregion as droptarget (the case when it is empty)
// The region-post (the right one)
// is very narrow, so add extra padding on the left to drop block on it.
droptarget = new Y.DD.Drop({
node: region.get_droptarget(),
groups: this.groups,
padding: '40 240 40 240'
});
// Make each div element in the list of blocks draggable
dragdelegation = new Y.DD.Delegate({
container: region.get_droptarget(),
nodes: '.'+CSS.BLOCK,
target: true,
handles: ['.'+CSS.HEADER],
invalid: '.block-hider-hide, .block-hider-show, .moveto',
dragConfig: {groups: this.groups}
});
dragdelegation.dd.plug(Y.Plugin.DDProxy, {
// Don't move the node at the end of the drag
moveOnEnd: false
});
dragdelegation.dd.plug(Y.Plugin.DDWinScroll);
// On the mouse down event we will enable all block regions so that they can be dragged to.
// This is VERY important as without it dnd won't work for empty block regions.
dragdelegation.on('drag:mouseDown', this.enable_all_regions, this);
region.remove_block_move_icons();
}
Y.log('Initialisation of drag and drop for blocks complete.', 'info');
},
/**
* Returns the ID of the block the given node represents.
* @method get_block_id
* @param {Node} node
* @returns {int} The blocks ID in the database.
*/
get_block_id : function(node) {
return Number(node.get('id').replace(/inst/i, ''));
},
/**
* Returns the block region that the node is part of or belonging to.
* @method get_block_region
* @param {Y.Node} node
* @returns {string} The region name.
*/
get_block_region : function(node) {
if (!node.test('[data-blockregion]')) {
node = node.ancestor('[data-blockregion]');
}
return node.getData('blockregion');
},
/**
* Returns the BLOCKREGION instance that represents the block region the given node is part of.
* @method get_region_object
* @param {Y.Node} node
* @returns {BLOCKREGION}
*/
get_region_object : function(node) {
return this.regionobjects[this.get_block_region(node)];
},
/**
* Enables all fo the regions so that they are all visible while dragging is occuring.
* @method enable_all_regions
* @returns {undefined}
*/
enable_all_regions : function() {
var i = 0;
for (i in this.regionobjects) {
this.regionobjects[i].enable();
}
},
/**
* Disables enabled regions if they contain no blocks.
* @method disable_regions_if_required
* @returns {undefined}
*/
disable_regions_if_required : function() {
var i = 0;
for (i in this.regionobjects) {
this.regionobjects[i].disable_if_required();
}
},
/**
* Called by M.core.dragdrop.global_drag_start when dragging starts.
* @method drag_start
* @param {Event} e
* @returns {undefined}
*/
drag_start : function(e) {
// Get our drag object
var drag = e.target;
// Store the parent node of original drag node (block)
// we will need it later for show/hide empty regions
// Determine skipnodes and store them
if (drag.get('node').previous() && drag.get('node').previous().hasClass(CSS.SKIPBLOCK)) {
this.skipnodetop = drag.get('node').previous();
}
if (drag.get('node').next() && drag.get('node').next().hasClass(CSS.SKIPBLOCKTO)) {
this.skipnodebottom = drag.get('node').next();
}
},
/**
* Called by M.core.dragdrop.global_drop_over when something is dragged over a drop target.
* @method drop_over
* @param {Event} e
* @returns {undefined}
*/
drop_over : function(e) {
// Get a reference to our drag and drop nodes
var drag = e.drag.get('node');
var drop = e.drop.get('node');
// We need to fix the case when parent drop over event has determined
// 'goingup' and appended the drag node after admin-block.
if (drop.hasClass(CSS.REGIONCONTENT) && drop.one('.'+CSS.BLOCKADMINBLOCK) && drop.one('.'+CSS.BLOCKADMINBLOCK).next('.'+CSS.BLOCK)) {
drop.prepend(drag);
}
},
/**
* Called by M.core.dragdrop.global_drop_end when a drop has been completed.
* @method drop_end
* @returns {undefined}
*/
drop_end : function() {
// Clear variables.
this.skipnodetop = null;
this.skipnodebottom = null;
this.disable_regions_if_required();
},
/**
* Called by M.core.dragdrop.global_drag_dropmiss when something has been dropped on a node that isn't contained by a drop target.
* @method drag_dropmiss
* @param {Event} e
* @returns {undefined}
*/
drag_dropmiss : function(e) {
// Missed the target, but we assume the user intended to drop it
// on the last ghost node location, e.drag and e.drop should be
// prepared by global_drag_dropmiss parent so simulate drop_hit(e).
this.drop_hit(e);
},
/**
* Called by M.core.dragdrop.global_drag_hit when something has been dropped on a drop target.
* @method drop_hit
* @param {Event} e
* @returns {undefined}
*/
drop_hit : function(e) {
// Get a reference to our drag node
var dragnode = e.drag.get('node');
var dropnode = e.drop.get('node');
// Amend existing skipnodes
if (dragnode.previous() && dragnode.previous().hasClass(CSS.SKIPBLOCK)) {
// the one that belongs to block below move below
dragnode.insert(dragnode.previous(), 'after');
}
// Move original skipnodes
if (this.skipnodetop) {
dragnode.insert(this.skipnodetop, 'before');
}
if (this.skipnodebottom) {
dragnode.insert(this.skipnodebottom, 'after');
}
// Add lightbox if it not there
var lightbox = M.util.add_lightbox(Y, dragnode);
// Prepare request parameters
var params = {
sesskey : M.cfg.sesskey,
courseid : this.get('courseid'),
pagelayout : this.get('pagelayout'),
pagetype : this.get('pagetype'),
subpage : this.get('subpage'),
contextid : this.get('contextid'),
action : 'move',
bui_moveid : this.get_block_id(dragnode),
bui_newregion : this.get_block_region(dropnode)
};
if (this.get('cmid')) {
params.cmid = this.get('cmid');
}
if (dragnode.next('.'+CSS.BLOCK) && !dragnode.next('.'+CSS.BLOCK).hasClass(CSS.BLOCKADMINBLOCK)) {
params.bui_beforeid = this.get_block_id(dragnode.next('.'+CSS.BLOCK));
}
// Do AJAX request
Y.io(M.cfg.wwwroot+AJAXURL, {
method: 'POST',
data: params,
on: {
start : function() {
lightbox.show();
},
success: function(tid, response) {
window.setTimeout(function() {
lightbox.hide();
}, 250);
try {
var responsetext = Y.JSON.parse(response.responseText);
if (responsetext.error) {
new M.core.ajaxException(responsetext);
}
} catch (e) {}
},
failure: function(tid, response) {
this.ajax_failure(response);
lightbox.hide();
},
complete : function() {
this.disable_regions_if_required();
}
},
context:this
});
}
};
Y.extend(MANAGER, M.core.dragdrop, MANAGER.prototype, {
NAME : 'core-blocks-dragdrop-manager',
ATTRS : {
/**
* The Course ID if there is one.
* @attribute courseid
* @type int|null
* @default null
*/
courseid : {
value : null
},
/**
* The Course Module ID if there is one.
* @attribute cmid
* @type int|null
* @default null
*/
cmid : {
value : null
},
/**
* The Context ID.
* @attribute contextid
* @type int|null
* @default null
*/
contextid : {
value : null
},
/**
* The current page layout.
* @attribute pagelayout
* @type string|null
* @default null
*/
pagelayout : {
value : null
},
/**
* The page type string, should be used as the id for the body tag in the theme.
* @attribute pagetype
* @type string|null
* @default null
*/
pagetype : {
value : null
},
/**
* The subpage identifier, if any.
* @attribute subpage
* @type string|null
* @default null
*/
subpage : {
value : null
},
/**
* An array of block regions that are present on the page.
* @attribute regions
* @type array|null
* @default Array[]
*/
regions : {
value : []
}
}
});/**
* This file contains the Block Region class used by the drag and drop manager.
*
* Provides drag and drop functionality for blocks.
*
* @module moodle-core-blockdraganddrop
*/
/**
* Constructs a new block region object.
*
* @namespace M.core.blockdraganddrop
* @class BlockRegion
* @constructor
* @extends Y.Base
*/
var BLOCKREGION = function() {
BLOCKREGION.superclass.constructor.apply(this, arguments);
};
BLOCKREGION.prototype = {
/**
* Called during the initialisation process of the object.
* @method initializer
*/
initializer : function() {
var node = this.get('node');
Y.log('Block region `'+this.get('region')+'` initialising', 'info');
if (!node) {
Y.log('block region known about but no HTML structure found for it. Guessing structure.', 'warn');
this.create_and_add_node();
}
var body = Y.one('body'),
hasblocks = node.all('.'+CSS.BLOCK).size() > 0,
hasregionclass = this.get_has_region_class();
this.set('hasblocks', hasblocks);
if (!body.hasClass(hasregionclass)) {
body.addClass(hasregionclass);
}
body.addClass((hasblocks) ? this.get_used_region_class() : this.get_empty_region_class());
body.removeClass((hasblocks) ? this.get_empty_region_class() : this.get_used_region_class());
},
/**
* Creates a generic block region node and adds it to the DOM at the best guess location.
* Any calling of this method is an unfortunate circumstance.
* @method create_and_add_node
*/
create_and_add_node : function() {
var c = Y.Node.create,
region = this.get('region'),
node = c('<div id="block-region-'+region+'" data-droptarget="1"></div>')
.addClass(CSS.BLOCKREGION)
.setData('blockregion', region),
regions = this.get('manager').get('regions'),
i,
haspre = false,
haspost = false,
added = false,
pre,
post;
for (i in regions) {
if (regions[i].match(/(pre|left)/)) {
haspre = regions[i];
} else if (regions[i].match(/(post|right)/)) {
haspost = regions[i];
}
}
if (haspre !== false && haspost !== false) {
if (region === haspre) {
post = Y.one('#block-region-'+haspost);
if (post) {
post.insert(node, 'before');
added = true;
}
} else {
pre = Y.one('#block-region-'+haspre);
if (pre) {
pre.insert(node, 'after');
added = true;
}
}
}
if (added === false) {
Y.one('body').append(node);
}
this.set('node', node);
},
/**
* Removes the move icons and changes the cursor to a move icon when over the header.
* @method remove_block_move_icons
*/
remove_block_move_icons : function() {
this.get('node').all('.'+CSS.BLOCK+' a.'+CSS.EDITINGMOVE).each(function(moveicon){
moveicon.ancestor('.'+CSS.BLOCK).one('.'+CSS.HEADER).setStyle('cursor', 'move');
moveicon.remove();
});
},
/**
* Returns the class name on the body that signifies the document knows about this region.
* @method get_has_region_class
* @return String
*/
get_has_region_class : function() {
return 'has-region-'+this.get('region');
},
/**
* Returns the class name to use on the body if the region contains no blocks.
* @method get_empty_region_class
* @return String
*/
get_empty_region_class : function() {
return 'empty-region-'+this.get('region');
},
/**
* Returns the class name to use on the body if the region contains blocks.
* @method get_used_region_class
* @return String
*/
get_used_region_class : function() {
return 'used-region-'+this.get('region');
},
/**
* Returns the node to use as the drop target for this region.
* @method get_droptarget
* @return Node
*/
get_droptarget : function() {
var node = this.get('node');
if (node.test('[data-droptarget="1"]')) {
return node;
}
return node.one('[data-droptarget="1"]');
},
/**
* Enables the block region so that we can be sure the user can see it.
* This is done even if it is empty.
* @method enable
*/
enable : function() {
Y.one('body').addClass(this.get_used_region_class()).removeClass(this.get_empty_region_class());
},
/**
* Disables the region if it contains no blocks, essentially hiding it from the user.
* @method disable_if_required
*/
disable_if_required : function() {
if (this.get('node').all('.'+CSS.BLOCK).size() === 0) {
Y.one('body').addClass(this.get_empty_region_class()).removeClass(this.get_used_region_class());
}
}
};
Y.extend(BLOCKREGION, Y.Base, BLOCKREGION.prototype, {
NAME : 'core-blocks-dragdrop-blockregion',
ATTRS : {
/**
* The drag and drop manager that created this block region instance.
* @attribute manager
* @type M.core.blockdraganddrop.Manager
* @writeOnce
*/
manager : {
// Can only be set during initialisation and must be set then.
writeOnce : 'initOnly',
validator : function (value) {
return Y.Lang.isObject(value) && value instanceof MANAGER;
}
},
/**
* The name of the block region this object represents.
* @attribute region
* @type String
* @writeOnce
*/
region : {
// Can only be set during initialisation and must be set then.
writeOnce : 'initOnly',
validator : function (value) {
return Y.Lang.isString(value);
}
},
/**
* The node the block region HTML starts at.s
* @attribute region
* @type Y.Node
*/
node : {
validator : function (value) {
return Y.Lang.isObject(value) || Y.Lang.isNull(value);
}
},
/**
* True if the block region currently contains blocks.
* @attribute hasblocks
* @type Boolean
* @default false
*/
hasblocks : {
value : false,
validator : function (value) {
return Y.Lang.isBoolean(value);
}
}
}
});
}, '@VERSION@', {
"requires": [

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,11 @@
YUI.add('moodle-core-blocks', function (Y, NAME) {
/**
* Provides drag and drop functionality for blocks.
*
* @module moodle-core-blockdraganddrop
*/
var AJAXURL = '/lib/ajax/blocks.php',
CSS = {
BLOCK : 'block',
@ -15,6 +21,16 @@ CSS = {
REGIONMAIN : 'region-main'
};
/**
* Legacy drag and drop manager.
* This drag and drop manager is specifically designed for themes using side-pre and side-post
* that do not make use of the block output methods introduced by MDL-39824.
*
* @namespace M.core.blockdraganddrop
* @class LegacyManager
* @constructor
* @extends M.core.dragdrop
*/
var DRAGBLOCK = function() {
DRAGBLOCK.superclass.constructor.apply(this, arguments);
};
@ -301,11 +317,672 @@ Y.extend(DRAGBLOCK, M.core.dragdrop, {
}
});
M.core_blocks = M.core_blocks || {};
M.core_blocks.init_dragdrop = function(params) {
new DRAGBLOCK(params);
/**
* Core namespace.
* @static
* @class core
*/
M.core = M.core || {};
/**
* Block drag and drop static class.
* @namespace M.core
* @class blockdraganddrop
* @static
*/
M.core.blockdraganddrop = M.core.blockdraganddrop || {};
/**
* True if the page is using the new blocks methods.
* @private
* @static
* @property _isusingnewblocksmethod
* @type Boolean
* @default null
*/
M.core.blockdraganddrop._isusingnewblocksmethod = null;
/**
* Returns true if the page is using the new blocks methods.
* @static
* @method is_using_blocks_render_method
* @return Boolean
*/
M.core.blockdraganddrop.is_using_blocks_render_method = function() {
if (this._isusingnewblocksmethod === null) {
var goodregions = Y.all('.block-region[data-blockregion]').size();
var allregions = Y.all('.block-region').size();
this._isusingnewblocksmethod = (allregions === goodregions);
}
return this._isusingnewblocksmethod;
};
/**
* Initialises a drag and drop manager.
* This should only ever be called once for a page.
* @static
* @method init
* @param {Object} params
* @return Manager
*/
M.core.blockdraganddrop.init = function(params) {
if (this.is_using_blocks_render_method()) {
new MANAGER(params);
} else {
new DRAGBLOCK(params);
}
};
/**
* Legacy code to keep things working.
*/
M.core_blocks = M.core_blocks || {};
M.core_blocks.init_dragdrop = function(params) {
M.core.blockdraganddrop.init(params);
};/**
* This file contains the drag and drop manager class.
*
* Provides drag and drop functionality for blocks.
*
* @module moodle-core-blockdraganddrop
*/
/**
* Constructs a new Block drag and drop manager.
*
* @namespace M.core.blockdraganddrop
* @class Manager
* @constructor
* @extends M.core.dragdrop
*/
var MANAGER = function() {
MANAGER.superclass.constructor.apply(this, arguments);
};
MANAGER.prototype = {
/**
* The skip block link from above the block being dragged while a drag is in progress.
* Required by the M.core.dragdrop from whom this class extends.
* @private
* @property skipnodetop
* @type Node
* @default null
*/
skipnodetop : null,
/**
* The skip block link from below the block being dragged while a drag is in progress.
* Required by the M.core.dragdrop from whom this class extends.
* @private
* @property skipnodebottom
* @type Node
* @default null
*/
skipnodebottom : null,
/**
* An associative object of regions and the
* @property regionobjects
* @type {Object} Primitive object mocking an associative array.
* @type {BLOCKREGION} [regionname]* Each item uses the region name as the key with the value being
* an instance of the BLOCKREGION class.
*/
regionobjects : {},
/**
* Called during the initialisation process of the object.
* @method initializer
*/
initializer : function() {
var regionnames = this.get('regions'),
i = 0,
region,
regionname,
droptarget,
dragdelegation;
// Evil required by M.core.dragdrop.
this.groups = ['block'];
this.samenodeclass = CSS.BLOCK;
this.parentnodeclass = CSS.BLOCKREGION;
// Add relevant classes and ID to 'content' block region on My Home page.
var myhomecontent = Y.Node.all('body#'+CSS.MYINDEX+' #'+CSS.REGIONMAIN+' > .'+CSS.REGIONCONTENT);
if (myhomecontent.size() > 0) {
var contentregion = myhomecontent.item(0);
contentregion.addClass(CSS.BLOCKREGION);
contentregion.set('id', CSS.REGIONCONTENT);
contentregion.one('div').addClass(CSS.REGIONCONTENT);
}
for (i in regionnames) {
regionname = regionnames[i];
region = new BLOCKREGION({
manager : this,
region : regionname,
node : Y.one('#block-region-'+regionname)
});
this.regionobjects[regionname] = region;
// Setting blockregion as droptarget (the case when it is empty)
// The region-post (the right one)
// is very narrow, so add extra padding on the left to drop block on it.
droptarget = new Y.DD.Drop({
node: region.get_droptarget(),
groups: this.groups,
padding: '40 240 40 240'
});
// Make each div element in the list of blocks draggable
dragdelegation = new Y.DD.Delegate({
container: region.get_droptarget(),
nodes: '.'+CSS.BLOCK,
target: true,
handles: ['.'+CSS.HEADER],
invalid: '.block-hider-hide, .block-hider-show, .moveto',
dragConfig: {groups: this.groups}
});
dragdelegation.dd.plug(Y.Plugin.DDProxy, {
// Don't move the node at the end of the drag
moveOnEnd: false
});
dragdelegation.dd.plug(Y.Plugin.DDWinScroll);
// On the mouse down event we will enable all block regions so that they can be dragged to.
// This is VERY important as without it dnd won't work for empty block regions.
dragdelegation.on('drag:mouseDown', this.enable_all_regions, this);
region.remove_block_move_icons();
}
},
/**
* Returns the ID of the block the given node represents.
* @method get_block_id
* @param {Node} node
* @returns {int} The blocks ID in the database.
*/
get_block_id : function(node) {
return Number(node.get('id').replace(/inst/i, ''));
},
/**
* Returns the block region that the node is part of or belonging to.
* @method get_block_region
* @param {Y.Node} node
* @returns {string} The region name.
*/
get_block_region : function(node) {
if (!node.test('[data-blockregion]')) {
node = node.ancestor('[data-blockregion]');
}
return node.getData('blockregion');
},
/**
* Returns the BLOCKREGION instance that represents the block region the given node is part of.
* @method get_region_object
* @param {Y.Node} node
* @returns {BLOCKREGION}
*/
get_region_object : function(node) {
return this.regionobjects[this.get_block_region(node)];
},
/**
* Enables all fo the regions so that they are all visible while dragging is occuring.
* @method enable_all_regions
* @returns {undefined}
*/
enable_all_regions : function() {
var i = 0;
for (i in this.regionobjects) {
this.regionobjects[i].enable();
}
},
/**
* Disables enabled regions if they contain no blocks.
* @method disable_regions_if_required
* @returns {undefined}
*/
disable_regions_if_required : function() {
var i = 0;
for (i in this.regionobjects) {
this.regionobjects[i].disable_if_required();
}
},
/**
* Called by M.core.dragdrop.global_drag_start when dragging starts.
* @method drag_start
* @param {Event} e
* @returns {undefined}
*/
drag_start : function(e) {
// Get our drag object
var drag = e.target;
// Store the parent node of original drag node (block)
// we will need it later for show/hide empty regions
// Determine skipnodes and store them
if (drag.get('node').previous() && drag.get('node').previous().hasClass(CSS.SKIPBLOCK)) {
this.skipnodetop = drag.get('node').previous();
}
if (drag.get('node').next() && drag.get('node').next().hasClass(CSS.SKIPBLOCKTO)) {
this.skipnodebottom = drag.get('node').next();
}
},
/**
* Called by M.core.dragdrop.global_drop_over when something is dragged over a drop target.
* @method drop_over
* @param {Event} e
* @returns {undefined}
*/
drop_over : function(e) {
// Get a reference to our drag and drop nodes
var drag = e.drag.get('node');
var drop = e.drop.get('node');
// We need to fix the case when parent drop over event has determined
// 'goingup' and appended the drag node after admin-block.
if (drop.hasClass(CSS.REGIONCONTENT) && drop.one('.'+CSS.BLOCKADMINBLOCK) && drop.one('.'+CSS.BLOCKADMINBLOCK).next('.'+CSS.BLOCK)) {
drop.prepend(drag);
}
},
/**
* Called by M.core.dragdrop.global_drop_end when a drop has been completed.
* @method drop_end
* @returns {undefined}
*/
drop_end : function() {
// Clear variables.
this.skipnodetop = null;
this.skipnodebottom = null;
this.disable_regions_if_required();
},
/**
* Called by M.core.dragdrop.global_drag_dropmiss when something has been dropped on a node that isn't contained by a drop target.
* @method drag_dropmiss
* @param {Event} e
* @returns {undefined}
*/
drag_dropmiss : function(e) {
// Missed the target, but we assume the user intended to drop it
// on the last ghost node location, e.drag and e.drop should be
// prepared by global_drag_dropmiss parent so simulate drop_hit(e).
this.drop_hit(e);
},
/**
* Called by M.core.dragdrop.global_drag_hit when something has been dropped on a drop target.
* @method drop_hit
* @param {Event} e
* @returns {undefined}
*/
drop_hit : function(e) {
// Get a reference to our drag node
var dragnode = e.drag.get('node');
var dropnode = e.drop.get('node');
// Amend existing skipnodes
if (dragnode.previous() && dragnode.previous().hasClass(CSS.SKIPBLOCK)) {
// the one that belongs to block below move below
dragnode.insert(dragnode.previous(), 'after');
}
// Move original skipnodes
if (this.skipnodetop) {
dragnode.insert(this.skipnodetop, 'before');
}
if (this.skipnodebottom) {
dragnode.insert(this.skipnodebottom, 'after');
}
// Add lightbox if it not there
var lightbox = M.util.add_lightbox(Y, dragnode);
// Prepare request parameters
var params = {
sesskey : M.cfg.sesskey,
courseid : this.get('courseid'),
pagelayout : this.get('pagelayout'),
pagetype : this.get('pagetype'),
subpage : this.get('subpage'),
contextid : this.get('contextid'),
action : 'move',
bui_moveid : this.get_block_id(dragnode),
bui_newregion : this.get_block_region(dropnode)
};
if (this.get('cmid')) {
params.cmid = this.get('cmid');
}
if (dragnode.next('.'+CSS.BLOCK) && !dragnode.next('.'+CSS.BLOCK).hasClass(CSS.BLOCKADMINBLOCK)) {
params.bui_beforeid = this.get_block_id(dragnode.next('.'+CSS.BLOCK));
}
// Do AJAX request
Y.io(M.cfg.wwwroot+AJAXURL, {
method: 'POST',
data: params,
on: {
start : function() {
lightbox.show();
},
success: function(tid, response) {
window.setTimeout(function() {
lightbox.hide();
}, 250);
try {
var responsetext = Y.JSON.parse(response.responseText);
if (responsetext.error) {
new M.core.ajaxException(responsetext);
}
} catch (e) {}
},
failure: function(tid, response) {
this.ajax_failure(response);
lightbox.hide();
},
complete : function() {
this.disable_regions_if_required();
}
},
context:this
});
}
};
Y.extend(MANAGER, M.core.dragdrop, MANAGER.prototype, {
NAME : 'core-blocks-dragdrop-manager',
ATTRS : {
/**
* The Course ID if there is one.
* @attribute courseid
* @type int|null
* @default null
*/
courseid : {
value : null
},
/**
* The Course Module ID if there is one.
* @attribute cmid
* @type int|null
* @default null
*/
cmid : {
value : null
},
/**
* The Context ID.
* @attribute contextid
* @type int|null
* @default null
*/
contextid : {
value : null
},
/**
* The current page layout.
* @attribute pagelayout
* @type string|null
* @default null
*/
pagelayout : {
value : null
},
/**
* The page type string, should be used as the id for the body tag in the theme.
* @attribute pagetype
* @type string|null
* @default null
*/
pagetype : {
value : null
},
/**
* The subpage identifier, if any.
* @attribute subpage
* @type string|null
* @default null
*/
subpage : {
value : null
},
/**
* An array of block regions that are present on the page.
* @attribute regions
* @type array|null
* @default Array[]
*/
regions : {
value : []
}
}
});/**
* This file contains the Block Region class used by the drag and drop manager.
*
* Provides drag and drop functionality for blocks.
*
* @module moodle-core-blockdraganddrop
*/
/**
* Constructs a new block region object.
*
* @namespace M.core.blockdraganddrop
* @class BlockRegion
* @constructor
* @extends Y.Base
*/
var BLOCKREGION = function() {
BLOCKREGION.superclass.constructor.apply(this, arguments);
};
BLOCKREGION.prototype = {
/**
* Called during the initialisation process of the object.
* @method initializer
*/
initializer : function() {
var node = this.get('node');
if (!node) {
this.create_and_add_node();
}
var body = Y.one('body'),
hasblocks = node.all('.'+CSS.BLOCK).size() > 0,
hasregionclass = this.get_has_region_class();
this.set('hasblocks', hasblocks);
if (!body.hasClass(hasregionclass)) {
body.addClass(hasregionclass);
}
body.addClass((hasblocks) ? this.get_used_region_class() : this.get_empty_region_class());
body.removeClass((hasblocks) ? this.get_empty_region_class() : this.get_used_region_class());
},
/**
* Creates a generic block region node and adds it to the DOM at the best guess location.
* Any calling of this method is an unfortunate circumstance.
* @method create_and_add_node
*/
create_and_add_node : function() {
var c = Y.Node.create,
region = this.get('region'),
node = c('<div id="block-region-'+region+'" data-droptarget="1"></div>')
.addClass(CSS.BLOCKREGION)
.setData('blockregion', region),
regions = this.get('manager').get('regions'),
i,
haspre = false,
haspost = false,
added = false,
pre,
post;
for (i in regions) {
if (regions[i].match(/(pre|left)/)) {
haspre = regions[i];
} else if (regions[i].match(/(post|right)/)) {
haspost = regions[i];
}
}
if (haspre !== false && haspost !== false) {
if (region === haspre) {
post = Y.one('#block-region-'+haspost);
if (post) {
post.insert(node, 'before');
added = true;
}
} else {
pre = Y.one('#block-region-'+haspre);
if (pre) {
pre.insert(node, 'after');
added = true;
}
}
}
if (added === false) {
Y.one('body').append(node);
}
this.set('node', node);
},
/**
* Removes the move icons and changes the cursor to a move icon when over the header.
* @method remove_block_move_icons
*/
remove_block_move_icons : function() {
this.get('node').all('.'+CSS.BLOCK+' a.'+CSS.EDITINGMOVE).each(function(moveicon){
moveicon.ancestor('.'+CSS.BLOCK).one('.'+CSS.HEADER).setStyle('cursor', 'move');
moveicon.remove();
});
},
/**
* Returns the class name on the body that signifies the document knows about this region.
* @method get_has_region_class
* @return String
*/
get_has_region_class : function() {
return 'has-region-'+this.get('region');
},
/**
* Returns the class name to use on the body if the region contains no blocks.
* @method get_empty_region_class
* @return String
*/
get_empty_region_class : function() {
return 'empty-region-'+this.get('region');
},
/**
* Returns the class name to use on the body if the region contains blocks.
* @method get_used_region_class
* @return String
*/
get_used_region_class : function() {
return 'used-region-'+this.get('region');
},
/**
* Returns the node to use as the drop target for this region.
* @method get_droptarget
* @return Node
*/
get_droptarget : function() {
var node = this.get('node');
if (node.test('[data-droptarget="1"]')) {
return node;
}
return node.one('[data-droptarget="1"]');
},
/**
* Enables the block region so that we can be sure the user can see it.
* This is done even if it is empty.
* @method enable
*/
enable : function() {
Y.one('body').addClass(this.get_used_region_class()).removeClass(this.get_empty_region_class());
},
/**
* Disables the region if it contains no blocks, essentially hiding it from the user.
* @method disable_if_required
*/
disable_if_required : function() {
if (this.get('node').all('.'+CSS.BLOCK).size() === 0) {
Y.one('body').addClass(this.get_empty_region_class()).removeClass(this.get_used_region_class());
}
}
};
Y.extend(BLOCKREGION, Y.Base, BLOCKREGION.prototype, {
NAME : 'core-blocks-dragdrop-blockregion',
ATTRS : {
/**
* The drag and drop manager that created this block region instance.
* @attribute manager
* @type M.core.blockdraganddrop.Manager
* @writeOnce
*/
manager : {
// Can only be set during initialisation and must be set then.
writeOnce : 'initOnly',
validator : function (value) {
return Y.Lang.isObject(value) && value instanceof MANAGER;
}
},
/**
* The name of the block region this object represents.
* @attribute region
* @type String
* @writeOnce
*/
region : {
// Can only be set during initialisation and must be set then.
writeOnce : 'initOnly',
validator : function (value) {
return Y.Lang.isString(value);
}
},
/**
* The node the block region HTML starts at.s
* @attribute region
* @type Y.Node
*/
node : {
validator : function (value) {
return Y.Lang.isObject(value) || Y.Lang.isNull(value);
}
},
/**
* True if the block region currently contains blocks.
* @attribute hasblocks
* @type Boolean
* @default false
*/
hasblocks : {
value : false,
validator : function (value) {
return Y.Lang.isBoolean(value);
}
}
}
});
}, '@VERSION@', {
"requires": [

View File

@ -158,7 +158,7 @@ YUI.add('moodle-core-dragdrop', function(Y) {
}
//Add the node
e.drop.get('node').ancestor().insertBefore(drag, drop);
} else if (drop.hasClass(this.parentnodeclass) && !drop.contains(drag)) {
} else if ((drop.hasClass(this.parentnodeclass) || drop.test('[data-droptarget="1"]')) && !drop.contains(drag)) {
// We are dropping on parent node and it is empty
if (this.goingup) {
drop.append(drag);

View File

@ -3,7 +3,9 @@
"builds": {
"moodle-core-blocks": {
"jsfiles": [
"blocks.js"
"blocks.js",
"manager.js",
"blockregion.js"
]
}
}

216
lib/yui/src/blocks/js/blockregion.js vendored Normal file
View File

@ -0,0 +1,216 @@
/**
* This file contains the Block Region class used by the drag and drop manager.
*
* Provides drag and drop functionality for blocks.
*
* @module moodle-core-blockdraganddrop
*/
/**
* Constructs a new block region object.
*
* @namespace M.core.blockdraganddrop
* @class BlockRegion
* @constructor
* @extends Y.Base
*/
var BLOCKREGION = function() {
BLOCKREGION.superclass.constructor.apply(this, arguments);
};
BLOCKREGION.prototype = {
/**
* Called during the initialisation process of the object.
* @method initializer
*/
initializer : function() {
var node = this.get('node');
Y.log('Block region `'+this.get('region')+'` initialising', 'info');
if (!node) {
Y.log('block region known about but no HTML structure found for it. Guessing structure.', 'warn');
this.create_and_add_node();
}
var body = Y.one('body'),
hasblocks = node.all('.'+CSS.BLOCK).size() > 0,
hasregionclass = this.get_has_region_class();
this.set('hasblocks', hasblocks);
if (!body.hasClass(hasregionclass)) {
body.addClass(hasregionclass);
}
body.addClass((hasblocks) ? this.get_used_region_class() : this.get_empty_region_class());
body.removeClass((hasblocks) ? this.get_empty_region_class() : this.get_used_region_class());
},
/**
* Creates a generic block region node and adds it to the DOM at the best guess location.
* Any calling of this method is an unfortunate circumstance.
* @method create_and_add_node
*/
create_and_add_node : function() {
var c = Y.Node.create,
region = this.get('region'),
node = c('<div id="block-region-'+region+'" data-droptarget="1"></div>')
.addClass(CSS.BLOCKREGION)
.setData('blockregion', region),
regions = this.get('manager').get('regions'),
i,
haspre = false,
haspost = false,
added = false,
pre,
post;
for (i in regions) {
if (regions[i].match(/(pre|left)/)) {
haspre = regions[i];
} else if (regions[i].match(/(post|right)/)) {
haspost = regions[i];
}
}
if (haspre !== false && haspost !== false) {
if (region === haspre) {
post = Y.one('#block-region-'+haspost);
if (post) {
post.insert(node, 'before');
added = true;
}
} else {
pre = Y.one('#block-region-'+haspre);
if (pre) {
pre.insert(node, 'after');
added = true;
}
}
}
if (added === false) {
Y.one('body').append(node);
}
this.set('node', node);
},
/**
* Removes the move icons and changes the cursor to a move icon when over the header.
* @method remove_block_move_icons
*/
remove_block_move_icons : function() {
this.get('node').all('.'+CSS.BLOCK+' a.'+CSS.EDITINGMOVE).each(function(moveicon){
moveicon.ancestor('.'+CSS.BLOCK).one('.'+CSS.HEADER).setStyle('cursor', 'move');
moveicon.remove();
});
},
/**
* Returns the class name on the body that signifies the document knows about this region.
* @method get_has_region_class
* @return String
*/
get_has_region_class : function() {
return 'has-region-'+this.get('region');
},
/**
* Returns the class name to use on the body if the region contains no blocks.
* @method get_empty_region_class
* @return String
*/
get_empty_region_class : function() {
return 'empty-region-'+this.get('region');
},
/**
* Returns the class name to use on the body if the region contains blocks.
* @method get_used_region_class
* @return String
*/
get_used_region_class : function() {
return 'used-region-'+this.get('region');
},
/**
* Returns the node to use as the drop target for this region.
* @method get_droptarget
* @return Node
*/
get_droptarget : function() {
var node = this.get('node');
if (node.test('[data-droptarget="1"]')) {
return node;
}
return node.one('[data-droptarget="1"]');
},
/**
* Enables the block region so that we can be sure the user can see it.
* This is done even if it is empty.
* @method enable
*/
enable : function() {
Y.one('body').addClass(this.get_used_region_class()).removeClass(this.get_empty_region_class());
},
/**
* Disables the region if it contains no blocks, essentially hiding it from the user.
* @method disable_if_required
*/
disable_if_required : function() {
if (this.get('node').all('.'+CSS.BLOCK).size() === 0) {
Y.one('body').addClass(this.get_empty_region_class()).removeClass(this.get_used_region_class());
}
}
};
Y.extend(BLOCKREGION, Y.Base, BLOCKREGION.prototype, {
NAME : 'core-blocks-dragdrop-blockregion',
ATTRS : {
/**
* The drag and drop manager that created this block region instance.
* @attribute manager
* @type M.core.blockdraganddrop.Manager
* @writeOnce
*/
manager : {
// Can only be set during initialisation and must be set then.
writeOnce : 'initOnly',
validator : function (value) {
return Y.Lang.isObject(value) && value instanceof MANAGER;
}
},
/**
* The name of the block region this object represents.
* @attribute region
* @type String
* @writeOnce
*/
region : {
// Can only be set during initialisation and must be set then.
writeOnce : 'initOnly',
validator : function (value) {
return Y.Lang.isString(value);
}
},
/**
* The node the block region HTML starts at.s
* @attribute region
* @type Y.Node
*/
node : {
validator : function (value) {
return Y.Lang.isObject(value) || Y.Lang.isNull(value);
}
},
/**
* True if the block region currently contains blocks.
* @attribute hasblocks
* @type Boolean
* @default false
*/
hasblocks : {
value : false,
validator : function (value) {
return Y.Lang.isBoolean(value);
}
}
}
});

View File

@ -1,3 +1,9 @@
/**
* Provides drag and drop functionality for blocks.
*
* @module moodle-core-blockdraganddrop
*/
var AJAXURL = '/lib/ajax/blocks.php',
CSS = {
BLOCK : 'block',
@ -13,6 +19,16 @@ CSS = {
REGIONMAIN : 'region-main'
};
/**
* Legacy drag and drop manager.
* This drag and drop manager is specifically designed for themes using side-pre and side-post
* that do not make use of the block output methods introduced by MDL-39824.
*
* @namespace M.core.blockdraganddrop
* @class LegacyManager
* @constructor
* @extends M.core.dragdrop
*/
var DRAGBLOCK = function() {
DRAGBLOCK.superclass.constructor.apply(this, arguments);
};
@ -299,7 +315,66 @@ Y.extend(DRAGBLOCK, M.core.dragdrop, {
}
});
/**
* Core namespace.
* @static
* @class core
*/
M.core = M.core || {};
/**
* Block drag and drop static class.
* @namespace M.core
* @class blockdraganddrop
* @static
*/
M.core.blockdraganddrop = M.core.blockdraganddrop || {};
/**
* True if the page is using the new blocks methods.
* @private
* @static
* @property _isusingnewblocksmethod
* @type Boolean
* @default null
*/
M.core.blockdraganddrop._isusingnewblocksmethod = null;
/**
* Returns true if the page is using the new blocks methods.
* @static
* @method is_using_blocks_render_method
* @return Boolean
*/
M.core.blockdraganddrop.is_using_blocks_render_method = function() {
if (this._isusingnewblocksmethod === null) {
var goodregions = Y.all('.block-region[data-blockregion]').size();
var allregions = Y.all('.block-region').size();
this._isusingnewblocksmethod = (allregions === goodregions);
}
return this._isusingnewblocksmethod;
};
/**
* Initialises a drag and drop manager.
* This should only ever be called once for a page.
* @static
* @method init
* @param {Object} params
* @return Manager
*/
M.core.blockdraganddrop.init = function(params) {
if (this.is_using_blocks_render_method()) {
new MANAGER(params);
} else {
new DRAGBLOCK(params);
}
};
/**
* Legacy code to keep things working.
*/
M.core_blocks = M.core_blocks || {};
M.core_blocks.init_dragdrop = function(params) {
new DRAGBLOCK(params);
};
M.core.blockdraganddrop.init(params);
};

393
lib/yui/src/blocks/js/manager.js vendored Normal file
View File

@ -0,0 +1,393 @@
/**
* This file contains the drag and drop manager class.
*
* Provides drag and drop functionality for blocks.
*
* @module moodle-core-blockdraganddrop
*/
/**
* Constructs a new Block drag and drop manager.
*
* @namespace M.core.blockdraganddrop
* @class Manager
* @constructor
* @extends M.core.dragdrop
*/
var MANAGER = function() {
MANAGER.superclass.constructor.apply(this, arguments);
};
MANAGER.prototype = {
/**
* The skip block link from above the block being dragged while a drag is in progress.
* Required by the M.core.dragdrop from whom this class extends.
* @private
* @property skipnodetop
* @type Node
* @default null
*/
skipnodetop : null,
/**
* The skip block link from below the block being dragged while a drag is in progress.
* Required by the M.core.dragdrop from whom this class extends.
* @private
* @property skipnodebottom
* @type Node
* @default null
*/
skipnodebottom : null,
/**
* An associative object of regions and the
* @property regionobjects
* @type {Object} Primitive object mocking an associative array.
* @type {BLOCKREGION} [regionname]* Each item uses the region name as the key with the value being
* an instance of the BLOCKREGION class.
*/
regionobjects : {},
/**
* Called during the initialisation process of the object.
* @method initializer
*/
initializer : function() {
Y.log('Initialising drag and drop for blocks.', 'info');
var regionnames = this.get('regions'),
i = 0,
region,
regionname,
droptarget,
dragdelegation;
// Evil required by M.core.dragdrop.
this.groups = ['block'];
this.samenodeclass = CSS.BLOCK;
this.parentnodeclass = CSS.BLOCKREGION;
// Add relevant classes and ID to 'content' block region on My Home page.
var myhomecontent = Y.Node.all('body#'+CSS.MYINDEX+' #'+CSS.REGIONMAIN+' > .'+CSS.REGIONCONTENT);
if (myhomecontent.size() > 0) {
var contentregion = myhomecontent.item(0);
contentregion.addClass(CSS.BLOCKREGION);
contentregion.set('id', CSS.REGIONCONTENT);
contentregion.one('div').addClass(CSS.REGIONCONTENT);
}
for (i in regionnames) {
regionname = regionnames[i];
region = new BLOCKREGION({
manager : this,
region : regionname,
node : Y.one('#block-region-'+regionname)
});
this.regionobjects[regionname] = region;
// Setting blockregion as droptarget (the case when it is empty)
// The region-post (the right one)
// is very narrow, so add extra padding on the left to drop block on it.
droptarget = new Y.DD.Drop({
node: region.get_droptarget(),
groups: this.groups,
padding: '40 240 40 240'
});
// Make each div element in the list of blocks draggable
dragdelegation = new Y.DD.Delegate({
container: region.get_droptarget(),
nodes: '.'+CSS.BLOCK,
target: true,
handles: ['.'+CSS.HEADER],
invalid: '.block-hider-hide, .block-hider-show, .moveto',
dragConfig: {groups: this.groups}
});
dragdelegation.dd.plug(Y.Plugin.DDProxy, {
// Don't move the node at the end of the drag
moveOnEnd: false
});
dragdelegation.dd.plug(Y.Plugin.DDWinScroll);
// On the mouse down event we will enable all block regions so that they can be dragged to.
// This is VERY important as without it dnd won't work for empty block regions.
dragdelegation.on('drag:mouseDown', this.enable_all_regions, this);
region.remove_block_move_icons();
}
Y.log('Initialisation of drag and drop for blocks complete.', 'info');
},
/**
* Returns the ID of the block the given node represents.
* @method get_block_id
* @param {Node} node
* @returns {int} The blocks ID in the database.
*/
get_block_id : function(node) {
return Number(node.get('id').replace(/inst/i, ''));
},
/**
* Returns the block region that the node is part of or belonging to.
* @method get_block_region
* @param {Y.Node} node
* @returns {string} The region name.
*/
get_block_region : function(node) {
if (!node.test('[data-blockregion]')) {
node = node.ancestor('[data-blockregion]');
}
return node.getData('blockregion');
},
/**
* Returns the BLOCKREGION instance that represents the block region the given node is part of.
* @method get_region_object
* @param {Y.Node} node
* @returns {BLOCKREGION}
*/
get_region_object : function(node) {
return this.regionobjects[this.get_block_region(node)];
},
/**
* Enables all fo the regions so that they are all visible while dragging is occuring.
* @method enable_all_regions
* @returns {undefined}
*/
enable_all_regions : function() {
var i = 0;
for (i in this.regionobjects) {
this.regionobjects[i].enable();
}
},
/**
* Disables enabled regions if they contain no blocks.
* @method disable_regions_if_required
* @returns {undefined}
*/
disable_regions_if_required : function() {
var i = 0;
for (i in this.regionobjects) {
this.regionobjects[i].disable_if_required();
}
},
/**
* Called by M.core.dragdrop.global_drag_start when dragging starts.
* @method drag_start
* @param {Event} e
* @returns {undefined}
*/
drag_start : function(e) {
// Get our drag object
var drag = e.target;
// Store the parent node of original drag node (block)
// we will need it later for show/hide empty regions
// Determine skipnodes and store them
if (drag.get('node').previous() && drag.get('node').previous().hasClass(CSS.SKIPBLOCK)) {
this.skipnodetop = drag.get('node').previous();
}
if (drag.get('node').next() && drag.get('node').next().hasClass(CSS.SKIPBLOCKTO)) {
this.skipnodebottom = drag.get('node').next();
}
},
/**
* Called by M.core.dragdrop.global_drop_over when something is dragged over a drop target.
* @method drop_over
* @param {Event} e
* @returns {undefined}
*/
drop_over : function(e) {
// Get a reference to our drag and drop nodes
var drag = e.drag.get('node');
var drop = e.drop.get('node');
// We need to fix the case when parent drop over event has determined
// 'goingup' and appended the drag node after admin-block.
if (drop.hasClass(CSS.REGIONCONTENT) && drop.one('.'+CSS.BLOCKADMINBLOCK) && drop.one('.'+CSS.BLOCKADMINBLOCK).next('.'+CSS.BLOCK)) {
drop.prepend(drag);
}
},
/**
* Called by M.core.dragdrop.global_drop_end when a drop has been completed.
* @method drop_end
* @returns {undefined}
*/
drop_end : function() {
// Clear variables.
this.skipnodetop = null;
this.skipnodebottom = null;
this.disable_regions_if_required();
},
/**
* Called by M.core.dragdrop.global_drag_dropmiss when something has been dropped on a node that isn't contained by a drop target.
* @method drag_dropmiss
* @param {Event} e
* @returns {undefined}
*/
drag_dropmiss : function(e) {
// Missed the target, but we assume the user intended to drop it
// on the last ghost node location, e.drag and e.drop should be
// prepared by global_drag_dropmiss parent so simulate drop_hit(e).
this.drop_hit(e);
},
/**
* Called by M.core.dragdrop.global_drag_hit when something has been dropped on a drop target.
* @method drop_hit
* @param {Event} e
* @returns {undefined}
*/
drop_hit : function(e) {
// Get a reference to our drag node
var dragnode = e.drag.get('node');
var dropnode = e.drop.get('node');
// Amend existing skipnodes
if (dragnode.previous() && dragnode.previous().hasClass(CSS.SKIPBLOCK)) {
// the one that belongs to block below move below
dragnode.insert(dragnode.previous(), 'after');
}
// Move original skipnodes
if (this.skipnodetop) {
dragnode.insert(this.skipnodetop, 'before');
}
if (this.skipnodebottom) {
dragnode.insert(this.skipnodebottom, 'after');
}
// Add lightbox if it not there
var lightbox = M.util.add_lightbox(Y, dragnode);
// Prepare request parameters
var params = {
sesskey : M.cfg.sesskey,
courseid : this.get('courseid'),
pagelayout : this.get('pagelayout'),
pagetype : this.get('pagetype'),
subpage : this.get('subpage'),
contextid : this.get('contextid'),
action : 'move',
bui_moveid : this.get_block_id(dragnode),
bui_newregion : this.get_block_region(dropnode)
};
if (this.get('cmid')) {
params.cmid = this.get('cmid');
}
if (dragnode.next('.'+CSS.BLOCK) && !dragnode.next('.'+CSS.BLOCK).hasClass(CSS.BLOCKADMINBLOCK)) {
params.bui_beforeid = this.get_block_id(dragnode.next('.'+CSS.BLOCK));
}
// Do AJAX request
Y.io(M.cfg.wwwroot+AJAXURL, {
method: 'POST',
data: params,
on: {
start : function() {
lightbox.show();
},
success: function(tid, response) {
window.setTimeout(function() {
lightbox.hide();
}, 250);
try {
var responsetext = Y.JSON.parse(response.responseText);
if (responsetext.error) {
new M.core.ajaxException(responsetext);
}
} catch (e) {}
},
failure: function(tid, response) {
this.ajax_failure(response);
lightbox.hide();
},
complete : function() {
this.disable_regions_if_required();
}
},
context:this
});
}
};
Y.extend(MANAGER, M.core.dragdrop, MANAGER.prototype, {
NAME : 'core-blocks-dragdrop-manager',
ATTRS : {
/**
* The Course ID if there is one.
* @attribute courseid
* @type int|null
* @default null
*/
courseid : {
value : null
},
/**
* The Course Module ID if there is one.
* @attribute cmid
* @type int|null
* @default null
*/
cmid : {
value : null
},
/**
* The Context ID.
* @attribute contextid
* @type int|null
* @default null
*/
contextid : {
value : null
},
/**
* The current page layout.
* @attribute pagelayout
* @type string|null
* @default null
*/
pagelayout : {
value : null
},
/**
* The page type string, should be used as the id for the body tag in the theme.
* @attribute pagetype
* @type string|null
* @default null
*/
pagetype : {
value : null
},
/**
* The subpage identifier, if any.
* @attribute subpage
* @type string|null
* @default null
*/
subpage : {
value : null
},
/**
* An array of block regions that are present on the page.
* @attribute regions
* @type array|null
* @default Array[]
*/
regions : {
value : []
}
}
});

View File

@ -32,7 +32,7 @@
$THEME->doctype = 'html5';
$THEME->yuicssmodules = array();
$THEME->name = 'bootstrapbase';
$THEME->parents = array('');
$THEME->parents = array();
$THEME->sheets = array('moodle');
$THEME->supportscssoptimisation = false;
@ -52,115 +52,112 @@ $THEME->rendererfactory = 'theme_overridden_renderer_factory';
$THEME->layouts = array(
// Most backwards compatible layout without the blocks - this is the layout used by default.
'base' => array(
'file' => 'general.php',
'file' => 'columns1.php',
'regions' => array(),
),
// Standard layout with blocks, this is recommended for most pages with general information.
'standard' => array(
'file' => 'general.php',
'file' => 'columns3.php',
'regions' => array('side-pre', 'side-post'),
'defaultregion' => 'side-pre',
),
// Main course page.
'course' => array(
'file' => 'general.php',
'file' => 'columns3.php',
'regions' => array('side-pre', 'side-post'),
'defaultregion' => 'side-pre',
'options' => array('langmenu'=>true),
),
'coursecategory' => array(
'file' => 'general.php',
'file' => 'columns3.php',
'regions' => array('side-pre', 'side-post'),
'defaultregion' => 'side-pre',
),
// part of course, typical for modules - default page layout if $cm specified in require_login()
'incourse' => array(
'file' => 'general.php',
'file' => 'columns3.php',
'regions' => array('side-pre', 'side-post'),
'defaultregion' => 'side-pre',
),
// The site home page.
'frontpage' => array(
'file' => 'general.php',
'file' => 'columns3.php',
'regions' => array('side-pre', 'side-post'),
'defaultregion' => 'side-pre',
'options' => array('nonavbar'=>true),
),
// Server administration scripts.
'admin' => array(
'file' => 'general.php',
'file' => 'columns2.php',
'regions' => array('side-pre'),
'defaultregion' => 'side-pre',
),
// My dashboard page.
'mydashboard' => array(
'file' => 'general.php',
'file' => 'columns3.php',
'regions' => array('side-pre', 'side-post'),
'defaultregion' => 'side-pre',
'options' => array('langmenu'=>true),
),
// My public page.
'mypublic' => array(
'file' => 'general.php',
'file' => 'columns3.php',
'regions' => array('side-pre', 'side-post'),
'defaultregion' => 'side-pre',
),
'login' => array(
'file' => 'general.php',
'file' => 'columns1.php',
'regions' => array(),
'options' => array('langmenu'=>true),
),
// Pages that appear in pop-up windows - no navigation, no blocks, no header.
'popup' => array(
'file' => 'general.php',
'file' => 'columns1.php',
'regions' => array(),
'options' => array('nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true, 'nologininfo'=>true, 'nocourseheaderfooter'=>true),
'options' => array('nofooter'=>true, 'nonavbar'=>true),
),
// No blocks and minimal footer - used for legacy frame layouts only!
'frametop' => array(
'file' => 'general.php',
'file' => 'columns1.php',
'regions' => array(),
'options' => array('nofooter'=>true, 'nocoursefooter'=>true),
),
// Embeded pages, like iframe/object embeded in moodleform - it needs as much space as possible
'embedded' => array(
'file' => 'embedded.php',
'regions' => array(),
'options' => array('nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true, 'nocourseheaderfooter'=>true),
'regions' => array()
),
// Used during upgrade and install, and for the 'This site is undergoing maintenance' message.
// This must not have any blocks, and it is good idea if it does not have links to
// other places - for example there should not be a home link in the footer...
'maintenance' => array(
'file' => 'general.php',
'file' => 'columns1.php',
'regions' => array(),
'options' => array('noblocks'=>true, 'nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true, 'nocourseheaderfooter'=>true),
'options' => array('nofooter'=>true, 'nonavbar'=>true, 'nocoursefooter'=>true, 'nocourseheader'=>true),
),
// Should display the content and basic headers only.
'print' => array(
'file' => 'general.php',
'file' => 'columns1.php',
'regions' => array(),
'options' => array('noblocks'=>true, 'nofooter'=>true, 'nonavbar'=>false, 'nocustommenu'=>true, 'nocourseheaderfooter'=>true),
'options' => array('nofooter'=>true, 'nonavbar'=>false),
),
// The pagelayout used when a redirection is occuring.
'redirect' => array(
'file' => 'embedded.php',
'regions' => array(),
'options' => array('nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true, 'nocourseheaderfooter'=>true),
),
// The pagelayout used for reports.
'report' => array(
'file' => 'general.php',
'file' => 'columns2.php',
'regions' => array('side-pre'),
'defaultregion' => 'side-pre',
),
// The pagelayout used for safebrowser and securewindow.
'secure' => array(
'file' => 'general.php',
'file' => 'secure.php',
'regions' => array('side-pre', 'side-post'),
'defaultregion' => 'side-pre',
'options' => array('nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true, 'nologinlinks'=>true, 'nocourseheaderfooter'=>true),
'defaultregion' => 'side-pre'
),
);
@ -175,3 +172,8 @@ if (check_browser_version('MSIE') && !check_browser_version('MSIE', '9.0')) {
}
$THEME->hidefromselector = true;
$THEME->blockrtlmanipulations = array(
'side-pre' => 'side-post',
'side-post' => 'side-pre'
);

View File

@ -0,0 +1,85 @@
<?php
// 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/>.
echo $OUTPUT->doctype() ?>
<html <?php echo $OUTPUT->htmlattributes(); ?>>
<head>
<title><?php echo $OUTPUT->page_title(); ?></title>
<link rel="shortcut icon" href="<?php echo $OUTPUT->favicon(); ?>" />
<?php echo $OUTPUT->standard_head_html() ?>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body <?php echo $OUTPUT->body_attributes(); ?>>
<?php echo $OUTPUT->standard_top_of_body_html() ?>
<header role="banner" class="navbar navbar-fixed-top">
<nav role="navigation" class="navbar-inner">
<div class="container-fluid">
<a class="brand" href="<?php echo $CFG->wwwroot;?>"><?php echo $SITE->shortname; ?></a>
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<div class="nav-collapse collapse">
<?php echo $OUTPUT->custom_menu(); ?>
<ul class="nav pull-right">
<li><?php echo $OUTPUT->page_heading_menu(); ?></li>
<li class="navbar-text"><?php echo $OUTPUT->login_info() ?></li>
</ul>
</div>
</div>
</nav>
</header>
<div id="page" class="container-fluid">
<header id="page-header" class="clearfix">
<div id="page-navbar">
<nav class="breadcrumb-button"><?php echo $OUTPUT->page_heading_button(); ?></nav>
<?php echo $OUTPUT->navbar(); ?>
</div>
<?php echo $OUTPUT->page_heading(); ?>
<div id="course-header">
<?php echo $OUTPUT->course_header(); ?>
</div>
</header>
<div id="page-content">
<div id="region-bs-main-and-pre">
<section id="region-main">
<?php
echo $OUTPUT->course_content_header();
echo $OUTPUT->main_content();
echo $OUTPUT->course_content_footer();
?>
</section>
</div>
</div>
<footer id="page-footer">
<div id="course-footer"><?php echo $OUTPUT->course_footer(); ?></div>
<p class="helplink"><?php echo $OUTPUT->page_doc_link(); ?></p>
<?php echo $OUTPUT->standard_footer_html(); ?>
</footer>
<?php echo $OUTPUT->standard_end_of_body_html() ?>
</div>
</body>
</html>

View File

@ -0,0 +1,96 @@
<?php
// 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/>.
echo $OUTPUT->doctype() ?>
<html <?php echo $OUTPUT->htmlattributes(); ?>>
<head>
<title><?php echo $OUTPUT->page_title(); ?></title>
<link rel="shortcut icon" href="<?php echo $OUTPUT->favicon(); ?>" />
<?php echo $OUTPUT->standard_head_html() ?>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body <?php echo $OUTPUT->body_attributes('two-column'); ?>>
<?php echo $OUTPUT->standard_top_of_body_html() ?>
<header role="banner" class="navbar navbar-fixed-top">
<nav role="navigation" class="navbar-inner">
<div class="container-fluid">
<a class="brand" href="<?php echo $CFG->wwwroot;?>"><?php echo $SITE->shortname; ?></a>
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<div class="nav-collapse collapse">
<?php echo $OUTPUT->custom_menu(); ?>
<ul class="nav pull-right">
<li><?php echo $OUTPUT->page_heading_menu(); ?></li>
<li class="navbar-text"><?php echo $OUTPUT->login_info() ?></li>
</ul>
</div>
</div>
</nav>
</header>
<div id="page" class="container-fluid">
<header id="page-header" class="clearfix">
<div id="page-navbar">
<nav class="breadcrumb-button"><?php echo $OUTPUT->page_heading_button(); ?></nav>
<?php echo $OUTPUT->navbar(); ?>
</div>
<?php echo $OUTPUT->page_heading(); ?>
<div id="course-header">
<?php echo $OUTPUT->course_header(); ?>
</div>
</header>
<div id="page-content" class="row-fluid">
<div id="region-bs-main-and-pre" class="span9">
<div class="row-fluid">
<section id="region-main" class="span9 pull-right">
<?php
echo $OUTPUT->course_content_header();
echo $OUTPUT->main_content();
echo $OUTPUT->course_content_footer();
?>
</section>
<?php
if (!right_to_left()) {
echo $OUTPUT->blocks('side-pre', 'span3 desktop-first-column');
} ?>
</div>
</div>
<?php
if (right_to_left()) {
echo $OUTPUT->blocks('side-post', 'span3');
}
?>
</div>
<footer id="page-footer">
<div id="course-footer"><?php echo $OUTPUT->course_footer(); ?></div>
<p class="helplink"><?php echo $OUTPUT->page_doc_link(); ?></p>
<?php echo $OUTPUT->standard_footer_html(); ?>
</footer>
<?php echo $OUTPUT->standard_end_of_body_html() ?>
</div>
</body>
</html>

View File

@ -0,0 +1,89 @@
<?php
// 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/>.
echo $OUTPUT->doctype() ?>
<html <?php echo $OUTPUT->htmlattributes(); ?>>
<head>
<title><?php echo $OUTPUT->page_title(); ?></title>
<link rel="shortcut icon" href="<?php echo $OUTPUT->favicon(); ?>" />
<?php echo $OUTPUT->standard_head_html() ?>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body <?php echo $OUTPUT->body_attributes(); ?>>
<?php echo $OUTPUT->standard_top_of_body_html() ?>
<header role="banner" class="navbar navbar-fixed-top">
<nav role="navigation" class="navbar-inner">
<div class="container-fluid">
<a class="brand" href="<?php echo $CFG->wwwroot;?>"><?php echo $SITE->shortname; ?></a>
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<div class="nav-collapse collapse">
<?php echo $OUTPUT->custom_menu(); ?>
<ul class="nav pull-right">
<li><?php echo $OUTPUT->page_heading_menu(); ?></li>
<li class="navbar-text"><?php echo $OUTPUT->login_info() ?></li>
</ul>
</div>
</div>
</nav>
</header>
<div id="page" class="container-fluid">
<header id="page-header" class="clearfix">
<div id="page-navbar">
<nav class="breadcrumb-button"><?php echo $OUTPUT->page_heading_button(); ?></nav>
<?php echo $OUTPUT->navbar(); ?>
</div>
<?php echo $OUTPUT->page_heading(); ?>
<div id="course-header">
<?php echo $OUTPUT->course_header(); ?>
</div>
</header>
<div id="page-content" class="row-fluid">
<div id="region-bs-main-and-pre" class="span9">
<div class="row-fluid">
<section id="region-main" class="span8 pull-right">
<?php
echo $OUTPUT->course_content_header();
echo $OUTPUT->main_content();
echo $OUTPUT->course_content_footer();
?>
</section>
<?php echo $OUTPUT->blocks('side-pre', 'span4 desktop-first-column'); ?>
</div>
</div>
<?php echo $OUTPUT->blocks('side-post', 'span3'); ?>
</div>
<footer id="page-footer">
<div id="course-footer"><?php echo $OUTPUT->course_footer(); ?></div>
<p class="helplink"><?php echo $OUTPUT->page_doc_link(); ?></p>
<?php echo $OUTPUT->standard_footer_html(); ?>
</footer>
<?php echo $OUTPUT->standard_end_of_body_html() ?>
</div>
</body>
</html>

View File

@ -1,23 +1,35 @@
<?php echo $OUTPUT->doctype() ?>
<html <?php echo $OUTPUT->htmlattributes() ?>>
<?php
// 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/>.
echo $OUTPUT->doctype() ?>
<html <?php echo $OUTPUT->htmlattributes(); ?>>
<head>
<title><?php echo $PAGE->title ?></title>
<link rel="shortcut icon" href="<?php echo $OUTPUT->pix_url('favicon', 'theme')?>" />
<title><?php echo $OUTPUT->page_title(); ?></title>
<link rel="shortcut icon" href="<?php echo $OUTPUT->favicon(); ?>" />
<?php echo $OUTPUT->standard_head_html() ?>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body id="<?php p($PAGE->bodyid) ?>" class="<?php p($PAGE->bodyclasses) ?>">
<body <?php echo $OUTPUT->body_attributes(); ?>>
<?php echo $OUTPUT->standard_top_of_body_html() ?>
<div id="page">
<!-- END OF HEADER -->
<div id="content" class="clearfix">
<?php echo $OUTPUT->main_content() ?>
<div id="page-content" class="clearfix">
<?php echo $OUTPUT->main_content(); ?>
</div>
<!-- START OF FOOTER -->
</div>
<?php echo $OUTPUT->standard_end_of_body_html() ?>
</body>
</html>
</html>

View File

@ -1,189 +0,0 @@
<?php
// 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/>.
$hasheading = ($PAGE->heading);
$hasnavbar = (empty($PAGE->layout_options['nonavbar']) && $PAGE->has_navbar());
$hasfooter = (empty($PAGE->layout_options['nofooter']));
$hasheader = (empty($PAGE->layout_options['noheader']));
$hassidepre = (empty($PAGE->layout_options['noblocks']) && $PAGE->blocks->region_has_content('side-pre', $OUTPUT));
$hassidepost = (empty($PAGE->layout_options['noblocks']) && $PAGE->blocks->region_has_content('side-post', $OUTPUT));
$showsidepre = ($hassidepre && !$PAGE->blocks->region_completely_docked('side-pre', $OUTPUT));
$showsidepost = ($hassidepost && !$PAGE->blocks->region_completely_docked('side-post', $OUTPUT));
// If there can be a sidepost region on this page and we are editing, always
// show it so blocks can be dragged into it.
if ($PAGE->user_is_editing()) {
if ($PAGE->blocks->is_known_region('side-pre')) {
$showsidepre = true;
}
if ($PAGE->blocks->is_known_region('side-post')) {
$showsidepost = true;
}
}
$custommenu = $OUTPUT->custom_menu();
$hascustommenu = (empty($PAGE->layout_options['nocustommenu']) && !empty($custommenu));
$courseheader = $coursecontentheader = $coursecontentfooter = $coursefooter = '';
if (empty($PAGE->layout_options['nocourseheaderfooter'])) {
$courseheader = $OUTPUT->course_header();
$coursecontentheader = $OUTPUT->course_content_header();
if (empty($PAGE->layout_options['nocoursefooter'])) {
$coursecontentfooter = $OUTPUT->course_content_footer();
$coursefooter = $OUTPUT->course_footer();
}
}
$layout = 'pre-and-post';
if ($showsidepre && !$showsidepost) {
if (!right_to_left()) {
$layout = 'side-pre-only';
} else {
$layout = 'side-post-only';
}
} else if ($showsidepost && !$showsidepre) {
if (!right_to_left()) {
$layout = 'side-post-only';
} else {
$layout = 'side-pre-only';
}
} else if (!$showsidepost && !$showsidepre) {
$layout = 'content-only';
}
$bodyclasses[] = $layout;
echo $OUTPUT->doctype() ?>
<html <?php echo $OUTPUT->htmlattributes() ?>>
<head>
<title><?php echo $PAGE->title ?></title>
<link rel="shortcut icon" href="<?php echo $OUTPUT->pix_url('favicon', 'theme')?>" />
<?php echo $OUTPUT->standard_head_html() ?>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body id="<?php p($PAGE->bodyid) ?>" class="<?php p($PAGE->bodyclasses.' '.join($bodyclasses)) ?>">
<?php echo $OUTPUT->standard_top_of_body_html() ?>
<header role="banner" class="navbar navbar-fixed-top">
<nav role="navigation" class="navbar-inner">
<div class="container-fluid">
<a class="brand" href="<?php echo $CFG->wwwroot;?>"><?php echo $SITE->shortname; ?></a>
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<div class="nav-collapse collapse">
<?php if ($hascustommenu) {
echo $custommenu;
} ?>
<ul class="nav pull-right">
<li><?php echo $PAGE->headingmenu ?></li>
<li class="navbar-text"><?php echo $OUTPUT->login_info() ?></li>
</ul>
</div>
</div>
</nav>
</header>
<div id="page" class="container-fluid">
<?php if ($hasheader) { ?>
<header id="page-header" class="clearfix">
<?php if ($hasnavbar) { ?>
<nav class="breadcrumb-button"><?php echo $PAGE->button; ?></nav>
<?php echo $OUTPUT->navbar(); ?>
<?php } ?>
<h1><?php echo $PAGE->heading ?></h1>
<?php if (!empty($courseheader)) { ?>
<div id="course-header"><?php echo $courseheader; ?></div>
<?php } ?>
</header>
<?php } ?>
<div id="page-content" class="row-fluid">
<?php if ($layout === 'pre-and-post') { ?>
<div id="region-bs-main-and-pre" class="span9">
<div class="row-fluid">
<section id="region-main" class="span8 pull-right">
<?php } else if ($layout === 'side-post-only') { ?>
<section id="region-main" class="span9">
<?php } else if ($layout === 'side-pre-only') { ?>
<section id="region-main" class="span9 pull-right">
<?php } else if ($layout === 'content-only') { ?>
<section id="region-main" class="span12">
<?php } ?>
<?php echo $coursecontentheader; ?>
<?php echo $OUTPUT->main_content() ?>
<?php echo $coursecontentfooter; ?>
</section>
<?php if ($layout !== 'content-only') {
if ($layout === 'pre-and-post') { ?>
<aside class="span4 desktop-first-column">
<?php } else if ($layout === 'side-pre-only') { ?>
<aside class="span3 desktop-first-column">
<?php } ?>
<div id="region-pre" class="block-region">
<div class="region-content">
<?php
if (!right_to_left()) {
echo $OUTPUT->blocks_for_region('side-pre');
} else if ($hassidepost) {
echo $OUTPUT->blocks_for_region('side-post');
} ?>
</div>
</div>
</aside>
<?php if ($layout === 'pre-and-post') {
?></div></div><?php // Close row-fluid and span9.
}
if ($layout === 'side-post-only' OR $layout === 'pre-and-post') { ?>
<aside class="span3">
<div id="region-post" class="block-region">
<div class="region-content">
<?php if (!right_to_left()) {
echo $OUTPUT->blocks_for_region('side-post');
} else {
echo $OUTPUT->blocks_for_region('side-pre');
} ?>
</div>
</div>
</aside>
<?php } ?>
<?php } ?>
</div>
<footer id="page-footer">
<p class="helplink"><?php echo page_doc_link(get_string('moodledocslink')) ?></p>
<?php echo $OUTPUT->standard_footer_html(); ?>
</footer>
<?php echo $OUTPUT->standard_end_of_body_html() ?>
</div>
</body>
</html>

View File

@ -0,0 +1,70 @@
<?php
// 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/>.
echo $OUTPUT->doctype() ?>
<html <?php echo $OUTPUT->htmlattributes(); ?>>
<head>
<title><?php echo $OUTPUT->page_title(); ?></title>
<link rel="shortcut icon" href="<?php echo $OUTPUT->favicon(); ?>" />
<?php echo $OUTPUT->standard_head_html() ?>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body <?php echo $OUTPUT->body_attributes(); ?>>
<?php echo $OUTPUT->standard_top_of_body_html() ?>
<header role="banner" class="navbar navbar-fixed-top">
<nav role="navigation" class="navbar-inner">
<div class="container-fluid">
<a class="brand" href="<?php echo $CFG->wwwroot;?>"><?php echo $SITE->shortname; ?></a>
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<div class="nav-collapse collapse">
<ul class="nav pull-right">
<li><?php echo $OUTPUT->page_heading_menu(); ?></li>
</ul>
</div>
</div>
</nav>
</header>
<div id="page" class="container-fluid">
<header id="page-header" class="clearfix">
<?php echo $OUTPUT->page_heading(); ?>
</header>
<div id="page-content" class="row-fluid">
<div id="region-bs-main-and-pre" class="span9">
<div class="row-fluid">
<section id="region-main" class="span8 pull-right">
<?php echo $OUTPUT->main_content(); ?>
</section>
<?php echo $OUTPUT->blocks('side-pre', 'span4 desktop-first-column'); ?>
</div>
</div>
<?php echo $OUTPUT->blocks('side-post', 'span3'); ?>
</div>
<?php echo $OUTPUT->standard_end_of_body_html() ?>
</div>
</body>
</html>

View File

@ -1,3 +1,6 @@
// Import the bootstrap variables.
@import "bootstrap/variables.less";
// Old Moodle stuff from base theme.
// Massive, needs broken up.
@import "moodle/core";

View File

@ -1,4 +1,45 @@
/* core.less */
/** Page layout CSS starts **/
.layout-option-noheader #page-header,
.layout-option-nonavbar #page-navbar,
.layout-option-nofooter #page-footer,
.layout-option-nocourseheader .course-content-header,
.layout-option-nocoursefooter .course-content-footer {
display:none;
}
.empty-region-side-pre #block-region-side-pre,
.empty-region-side-post #block-region-side-post {
display:none;
}
.dir-ltr.two-column #region-bs-main-and-pre.span9,
.dir-rtl.two-column #region-main.span9,
.empty-region-side-post #region-bs-main-and-pre.span9 {
width:100%;
}
.empty-region-side-pre #region-main {
float:none;
width:100%;
}
.fluid-span (@columns) {
width: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1));
*width: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%);
}
.empty-region-side-post.used-region-side-pre #region-main.span8 {
/** increase the span size by 1 **/
.fluid-span(9);
}
.empty-region-side-post.used-region-side-pre #block-region-side-pre.span4 {
/** decrease the span size by 1 **/
.fluid-span(3);
}
/** Page layout CSS ends **/
.dir-ltr,
.mdl-left,
.dir-rtl .mdl-right {

File diff suppressed because one or more lines are too long

View File

@ -55,3 +55,8 @@ $THEME->plugins_exclude_sheets = array(
$THEME->rendererfactory = 'theme_overridden_renderer_factory';
$THEME->csspostprocess = 'clean_process_css';
$THEME->blockrtlmanipulations = array(
'side-pre' => 'side-post',
'side-post' => 'side-pre'
);

View File

@ -0,0 +1,91 @@
<?php
// 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/>.
// Get the HTML for the settings bits.
$html = theme_clean_get_html_for_settings($OUTPUT, $PAGE);
echo $OUTPUT->doctype() ?>
<html <?php echo $OUTPUT->htmlattributes(); ?>>
<head>
<title><?php echo $OUTPUT->page_title(); ?></title>
<link rel="shortcut icon" href="<?php echo $OUTPUT->favicon(); ?>" />
<?php echo $OUTPUT->standard_head_html() ?>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body <?php echo $OUTPUT->body_attributes(); ?>>
<?php echo $OUTPUT->standard_top_of_body_html() ?>
<header role="banner" class="navbar navbar-fixed-top<?php echo $html->navbarclass ?>">
<nav role="navigation" class="navbar-inner">
<div class="container-fluid">
<a class="brand" href="<?php echo $CFG->wwwroot;?>"><?php echo $SITE->shortname; ?></a>
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<div class="nav-collapse collapse">
<?php echo $OUTPUT->custom_menu(); ?>
<ul class="nav pull-right">
<li><?php echo $OUTPUT->page_heading_menu(); ?></li>
<li class="navbar-text"><?php echo $OUTPUT->login_info() ?></li>
</ul>
</div>
</div>
</nav>
</header>
<div id="page" class="container-fluid">
<header id="page-header" class="clearfix">
<div id="page-navbar">
<nav class="breadcrumb-button"><?php echo $OUTPUT->page_heading_button(); ?></nav>
<?php echo $OUTPUT->navbar(); ?>
</div>
<?php echo $html->heading; ?>
<div id="course-header">
<?php echo $OUTPUT->course_header(); ?>
</div>
</header>
<div id="page-content">
<div id="region-bs-main-and-pre">
<section id="region-main">
<?php
echo $OUTPUT->course_content_header();
echo $OUTPUT->main_content();
echo $OUTPUT->course_content_footer();
?>
</section>
</div>
</div>
<footer id="page-footer">
<div id="course-footer"><?php echo $OUTPUT->course_footer(); ?></div>
<p class="helplink"><?php echo $OUTPUT->page_doc_link(); ?></p>
<?php
echo $html->footnote;
echo $OUTPUT->standard_footer_html();
?>
</footer>
<?php echo $OUTPUT->standard_end_of_body_html() ?>
</div>
</body>
</html>

View File

@ -0,0 +1,102 @@
<?php
// 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/>.
// Get the HTML for the settings bits.
$html = theme_clean_get_html_for_settings($OUTPUT, $PAGE);
echo $OUTPUT->doctype() ?>
<html <?php echo $OUTPUT->htmlattributes(); ?>>
<head>
<title><?php echo $OUTPUT->page_title(); ?></title>
<link rel="shortcut icon" href="<?php echo $OUTPUT->favicon(); ?>" />
<?php echo $OUTPUT->standard_head_html() ?>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body <?php echo $OUTPUT->body_attributes('two-column'); ?>>
<?php echo $OUTPUT->standard_top_of_body_html() ?>
<header role="banner" class="navbar navbar-fixed-top<?php echo $html->navbarclass ?>">
<nav role="navigation" class="navbar-inner">
<div class="container-fluid">
<a class="brand" href="<?php echo $CFG->wwwroot;?>"><?php echo $SITE->shortname; ?></a>
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<div class="nav-collapse collapse">
<?php echo $OUTPUT->custom_menu(); ?>
<ul class="nav pull-right">
<li><?php echo $OUTPUT->page_heading_menu(); ?></li>
<li class="navbar-text"><?php echo $OUTPUT->login_info() ?></li>
</ul>
</div>
</div>
</nav>
</header>
<div id="page" class="container-fluid">
<header id="page-header" class="clearfix">
<div id="page-navbar">
<nav class="breadcrumb-button"><?php echo $OUTPUT->page_heading_button(); ?></nav>
<?php echo $OUTPUT->navbar(); ?>
</div>
<?php echo $html->heading; ?>
<div id="course-header">
<?php echo $OUTPUT->course_header(); ?>
</div>
</header>
<div id="page-content" class="row-fluid">
<div id="region-bs-main-and-pre" class="span9">
<div class="row-fluid">
<section id="region-main" class="span9 pull-right">
<?php
echo $OUTPUT->course_content_header();
echo $OUTPUT->main_content();
echo $OUTPUT->course_content_footer();
?>
</section>
<?php
if (!right_to_left()) {
echo $OUTPUT->blocks('side-pre', 'span3 desktop-first-column');
} ?>
</div>
</div>
<?php
if (right_to_left()) {
echo $OUTPUT->blocks('side-post', 'span3');
}
?>
</div>
<footer id="page-footer">
<div id="course-footer"><?php echo $OUTPUT->course_footer(); ?></div>
<p class="helplink"><?php echo $OUTPUT->page_doc_link(); ?></p>
<?php
echo $html->footnote;
echo $OUTPUT->standard_footer_html();
?>
</footer>
<?php echo $OUTPUT->standard_end_of_body_html() ?>
</div>
</body>
</html>

View File

@ -0,0 +1,109 @@
<?php
// 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/>.
/**
* Moodle's Clean theme, an example of how to make a Bootstrap theme
*
* DO NOT MODIFY THIS THEME!
* COPY IT FIRST, THEN RENAME THE COPY AND MODIFY IT INSTEAD.
*
* For full information about creating Moodle themes, see:
* http://docs.moodle.org/dev/Themes_2.0
*
* @package theme_clean
* @copyright 2013 Moodle, moodle.org
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
// Get the HTML for the settings bits.
$html = theme_clean_get_html_for_settings($OUTPUT, $PAGE);
echo $OUTPUT->doctype() ?>
<html <?php echo $OUTPUT->htmlattributes(); ?>>
<head>
<title><?php echo $OUTPUT->page_title(); ?></title>
<link rel="shortcut icon" href="<?php echo $OUTPUT->favicon(); ?>" />
<?php echo $OUTPUT->standard_head_html() ?>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body <?php echo $OUTPUT->body_attributes(); ?>>
<?php echo $OUTPUT->standard_top_of_body_html() ?>
<header role="banner" class="navbar navbar-fixed-top<?php echo $html->navbarclass ?>">
<nav role="navigation" class="navbar-inner">
<div class="container-fluid">
<a class="brand" href="<?php echo $CFG->wwwroot;?>"><?php echo $SITE->shortname; ?></a>
<a class="btn btn-navbar" data-toggle="workaround-collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<div class="nav-collapse collapse">
<?php echo $OUTPUT->custom_menu(); ?>
<ul class="nav pull-right">
<li><?php echo $OUTPUT->page_heading_menu(); ?></li>
<li class="navbar-text"><?php echo $OUTPUT->login_info() ?></li>
</ul>
</div>
</div>
</nav>
</header>
<div id="page" class="container-fluid">
<header id="page-header" class="clearfix">
<div id="page-navbar">
<nav class="breadcrumb-button"><?php echo $OUTPUT->page_heading_button(); ?></nav>
<?php echo $OUTPUT->navbar(); ?>
</div>
<?php echo $html->heading; ?>
<div id="course-header">
<?php echo $OUTPUT->course_header(); ?>
</div>
</header>
<div id="page-content" class="row-fluid">
<div id="region-bs-main-and-pre" class="span9">
<div class="row-fluid">
<section id="region-main" class="span8 pull-right">
<?php
echo $OUTPUT->course_content_header();
echo $OUTPUT->main_content();
echo $OUTPUT->course_content_footer();
?>
</section>
<?php echo $OUTPUT->blocks('side-pre', 'span4 desktop-first-column'); ?>
</div>
</div>
<?php echo $OUTPUT->blocks('side-post', 'span3'); ?>
</div>
<footer id="page-footer">
<div id="course-footer"><?php echo $OUTPUT->course_footer(); ?></div>
<p class="helplink"><?php echo $OUTPUT->page_doc_link(); ?></p>
<?php
echo $html->footnote;
echo $OUTPUT->standard_footer_html();
?>
</footer>
<?php echo $OUTPUT->standard_end_of_body_html() ?>
</div>
</body>
</html>

View File

@ -0,0 +1,35 @@
<?php
// 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/>.
echo $OUTPUT->doctype() ?>
<html <?php echo $OUTPUT->htmlattributes(); ?>>
<head>
<title><?php echo $OUTPUT->page_title(); ?></title>
<link rel="shortcut icon" href="<?php echo $OUTPUT->favicon(); ?>" />
<?php echo $OUTPUT->standard_head_html() ?>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body <?php echo $OUTPUT->body_attributes(); ?>>
<?php echo $OUTPUT->standard_top_of_body_html() ?>
<div id="page">
<div id="page-content" class="clearfix">
<?php echo $OUTPUT->main_content(); ?>
</div>
</div>
<?php echo $OUTPUT->standard_end_of_body_html() ?>
</body>
</html>

View File

@ -1,228 +0,0 @@
<?php
// 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/>.
/**
* Moodle's Clean theme, an example of how to make a Bootstrap theme
*
* DO NOT MODIFY THIS THEME!
* COPY IT FIRST, THEN RENAME THE COPY AND MODIFY IT INSTEAD.
*
* For full information about creating Moodle themes, see:
* http://docs.moodle.org/dev/Themes_2.0
*
* @package theme_clean
* @copyright 2013 Moodle, moodle.org
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$hasheading = ($PAGE->heading);
$hasnavbar = (empty($PAGE->layout_options['nonavbar']) && $PAGE->has_navbar());
$hasfooter = (empty($PAGE->layout_options['nofooter']));
$hasheader = (empty($PAGE->layout_options['noheader']));
$hassidepre = (empty($PAGE->layout_options['noblocks']) && $PAGE->blocks->region_has_content('side-pre', $OUTPUT));
$hassidepost = (empty($PAGE->layout_options['noblocks']) && $PAGE->blocks->region_has_content('side-post', $OUTPUT));
$showsidepre = ($hassidepre && !$PAGE->blocks->region_completely_docked('side-pre', $OUTPUT));
$showsidepost = ($hassidepost && !$PAGE->blocks->region_completely_docked('side-post', $OUTPUT));
// If there can be a sidepost region on this page and we are editing, always
// show it so blocks can be dragged into it.
if ($PAGE->user_is_editing()) {
if ($PAGE->blocks->is_known_region('side-pre')) {
$showsidepre = true;
}
if ($PAGE->blocks->is_known_region('side-post')) {
$showsidepost = true;
}
}
$haslogo = (!empty($PAGE->theme->settings->logo));
$hasfootnote = (!empty($PAGE->theme->settings->footnote));
$navbar_inverse = '';
if (!empty($PAGE->theme->settings->invert)) {
$navbar_inverse = 'navbar-inverse';
}
$custommenu = $OUTPUT->custom_menu();
$hascustommenu = (empty($PAGE->layout_options['nocustommenu']) && !empty($custommenu));
$courseheader = $coursecontentheader = $coursecontentfooter = $coursefooter = '';
if (empty($PAGE->layout_options['nocourseheaderfooter'])) {
$courseheader = $OUTPUT->course_header();
$coursecontentheader = $OUTPUT->course_content_header();
if (empty($PAGE->layout_options['nocoursefooter'])) {
$coursecontentfooter = $OUTPUT->course_content_footer();
$coursefooter = $OUTPUT->course_footer();
}
}
$layout = 'pre-and-post';
if ($showsidepre && !$showsidepost) {
if (!right_to_left()) {
$layout = 'side-pre-only';
} else {
$layout = 'side-post-only';
}
} else if ($showsidepost && !$showsidepre) {
if (!right_to_left()) {
$layout = 'side-post-only';
} else {
$layout = 'side-pre-only';
}
} else if (!$showsidepost && !$showsidepre) {
$layout = 'content-only';
}
$bodyclasses[] = $layout;
echo $OUTPUT->doctype() ?>
<html <?php echo $OUTPUT->htmlattributes() ?>>
<head>
<title><?php echo $PAGE->title ?></title>
<link rel="shortcut icon" href="<?php echo $OUTPUT->pix_url('favicon', 'theme')?>" />
<?php echo $OUTPUT->standard_head_html() ?>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body id="<?php p($PAGE->bodyid) ?>" class="<?php p($PAGE->bodyclasses.' '.join(' ', $bodyclasses)) ?>">
<?php echo $OUTPUT->standard_top_of_body_html() ?>
<header role="banner" class="navbar <?php echo $navbar_inverse ?> navbar-fixed-top">
<nav role="navigation" class="navbar-inner">
<div class="container-fluid">
<a class="brand" href="<?php echo $CFG->wwwroot;?>"><?php echo $SITE->shortname; ?></a>
<a class="btn btn-navbar" data-toggle="workaround-collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<div class="nav-collapse collapse">
<?php if ($hascustommenu) {
echo $custommenu;
} ?>
<ul class="nav pull-right">
<li><?php echo $PAGE->headingmenu ?></li>
<li class="navbar-text"><?php echo $OUTPUT->login_info() ?></li>
</ul>
</div>
</div>
</nav>
</header>
<div id="page" class="container-fluid">
<?php if ($hasheader) { ?>
<header id="page-header" class="clearfix">
<?php if ($hasnavbar) { ?>
<nav class="breadcrumb-button"><?php echo $PAGE->button; ?></nav>
<?php echo $OUTPUT->navbar(); ?>
<?php } ?>
<?php
if (!$haslogo) { ?>
<h1><?php echo $PAGE->heading ?></h1>
<?php
} else { ?>
<a class="logo" href="<?php echo $CFG->wwwroot; ?>" title="<?php print_string('home'); ?>"></a>
<?php
} ?>
<?php if (!empty($courseheader)) { ?>
<div id="course-header"><?php echo $courseheader; ?></div>
<?php } ?>
</header>
<?php } ?>
<div id="page-content" class="row-fluid">
<?php if ($layout === 'pre-and-post') { ?>
<div id="region-bs-main-and-pre" class="span9">
<div class="row-fluid">
<section id="region-main" class="span8 pull-right">
<?php } else if ($layout === 'side-post-only') { ?>
<section id="region-main" class="span9">
<?php } else if ($layout === 'side-pre-only') { ?>
<section id="region-main" class="span9 pull-right">
<?php } else if ($layout === 'content-only') { ?>
<section id="region-main" class="span12">
<?php } ?>
<?php echo $coursecontentheader; ?>
<?php echo $OUTPUT->main_content() ?>
<?php echo $coursecontentfooter; ?>
</section>
<?php if ($layout !== 'content-only') {
if ($layout === 'pre-and-post') { ?>
<aside class="span4 desktop-first-column">
<?php } else if ($layout === 'side-pre-only') { ?>
<aside class="span3 desktop-first-column">
<?php } ?>
<div id="region-pre" class="block-region">
<div class="region-content">
<?php
if (!right_to_left()) {
echo $OUTPUT->blocks_for_region('side-pre');
} else if ($hassidepost) {
echo $OUTPUT->blocks_for_region('side-post');
}
?>
</div>
</div>
</aside>
<?php if ($layout === 'pre-and-post') {
?></div></div><?php // Close row-fluid and span9.
}
if ($layout === 'side-post-only' OR $layout === 'pre-and-post') { ?>
<aside class="span3">
<div id="region-post" class="block-region">
<div class="region-content">
<?php if (!right_to_left()) {
echo $OUTPUT->blocks_for_region('side-post');
} else {
echo $OUTPUT->blocks_for_region('side-pre');
} ?>
</div>
</div>
</aside>
<?php } ?>
<?php } ?>
</div>
<footer id="page-footer">
<p class="helplink"><?php echo page_doc_link(get_string('moodledocslink')) ?></p>
<?php
if ($hasfootnote) { ?>
<div class="footnote text-center">
<?php echo $PAGE->theme->settings->footnote; ?>
</div>
<?php
} ?>
<?php echo $OUTPUT->standard_footer_html(); ?>
</footer>
<?php echo $OUTPUT->standard_end_of_body_html() ?>
</div>
</body>
</html>

View File

@ -0,0 +1,70 @@
<?php
// 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/>.
echo $OUTPUT->doctype() ?>
<html <?php echo $OUTPUT->htmlattributes(); ?>>
<head>
<title><?php echo $OUTPUT->page_title(); ?></title>
<link rel="shortcut icon" href="<?php echo $OUTPUT->favicon(); ?>" />
<?php echo $OUTPUT->standard_head_html() ?>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body <?php echo $OUTPUT->body_attributes(); ?>>
<?php echo $OUTPUT->standard_top_of_body_html() ?>
<header role="banner" class="navbar navbar-fixed-top">
<nav role="navigation" class="navbar-inner">
<div class="container-fluid">
<a class="brand" href="<?php echo $CFG->wwwroot;?>"><?php echo $SITE->shortname; ?></a>
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<div class="nav-collapse collapse">
<ul class="nav pull-right">
<li><?php echo $OUTPUT->page_heading_menu(); ?></li>
</ul>
</div>
</div>
</nav>
</header>
<div id="page" class="container-fluid">
<header id="page-header" class="clearfix">
<?php echo $html->heading; ?>
</header>
<div id="page-content" class="row-fluid">
<div id="region-bs-main-and-pre" class="span9">
<div class="row-fluid">
<section id="region-main" class="span8 pull-right">
<?php echo $OUTPUT->main_content(); ?>
</section>
<?php echo $OUTPUT->blocks('side-pre', 'span4 desktop-first-column'); ?>
</div>
</div>
<?php echo $OUTPUT->blocks('side-post', 'span3'); ?>
</div>
<?php echo $OUTPUT->standard_end_of_body_html() ?>
</div>
</body>
</html>

View File

@ -78,3 +78,36 @@ function clean_set_customcss($css, $customcss) {
return $css;
}
/**
* Returns an object containing HTML for the areas affected by settings.
*
* @param renderer_base $output Pass in $OUTPUT.
* @param moodle_page $page Pass in $PAGE.
* @return stdClass An object with the following properties:
* - navbarclass A CSS class to use on the navbar. By default ''.
* - heading HTML to use for the heading. A logo if one is selected or the default heading.
* - footnote HTML to use as a footnote. By default ''.
*/
function theme_clean_get_html_for_settings(renderer_base $output, moodle_page $page) {
global $CFG;
$return = new stdClass;
$return->navbarclass = '';
if (!empty($page->theme->settings->invert)) {
$return->navbarclass .= ' navbar-inverse';
}
if (!empty($page->theme->settings->logo)) {
$return->heading = html_writer::link($CFG->wwwroot, '', array('title' => get_string('home'), 'class' => 'logo'));
} else {
$return->heading = $output->page_heading();
}
$return->footnote = '';
if (!empty($page->theme->settings->footnote)) {
$return->footnote = '<div class="footnote text-center">'.$page->theme->settings->footnote.'</div>';
}
return $return;
}

View File

@ -1,6 +1,33 @@
This files describes API changes in /theme/* themes,
information provided here is intended especially for theme designer.
=== 2.5.1 ===
Notes:
* Block drag and drop functionality has been improved so that it works regardless of what block regions you use
or how many block regions you have. In order to benefit from this improvement you must convert your calls from
$OUTPUT->blocks_for_region() to $OUTPUT->blocks.
Optional changes:
* Theme config can nominate block regions to swap if the user is using a rtl languages such as Hebrew.
$THEME->blockrtlmanipulations should be an associative array, the key is the original block region, and the
value should be where the blocks in that region should be displayed.
* New $OUTPUT methods to replace code that was previously using $PAGE. Converting to these methods is optional
but highly recommended. Refer to the bootstrapbase layouts for examples.
- $OUTPUT->body_attributes() returns a string you can use for the body id and classes.
- $OUTPUT->blocks() returns HTML to display a block region and all of its blocks. This adds data attributes
that ensure drag and drop of blocks will work no matter what block regions or how many you have.
- $OUTPUT->page_heading() returns the page heading. Replaces $PAGE->heading.
- $OUTPUT->page_heading_button() returns the button to display with the heading. Replaces $page->button.
- $OUTPUT->page_doc_link() returns the link to moodle docs for the page. Replaces page_doc_link().
- $OUTPUT->page_heading_menu() returns the heading menu for the page. Replaces $PAGE->headingmenu.
- $OUTPUT->page_title() Returns the title to use for the head section.
- $OUTPUT->favicon() returns the URL to the favicon.
Renderer changes:
* core_renderer::navbar now returns an empty string if there are no navigation items to display.
* core_renderer::custom_menu now adds a class "custom_menu" to the div that contains the HTML for the custom menu.
=== 2.5 ===
required changes: