Merge branch 'w04_MDL-37726_m25_prevnext_int' of git://github.com/skodak/moodle
authorDan Poltawski <dan@moodle.com>
Wed, 30 Jan 2013 01:18:57 +0000 (09:18 +0800)
committerDan Poltawski <dan@moodle.com>
Wed, 30 Jan 2013 01:18:57 +0000 (09:18 +0800)
17 files changed:
enrol/database/lib.php
lib/dml/sqlsrv_native_moodle_database.php
lib/dml/sqlsrv_native_moodle_recordset.php
lib/dml/tests/dml_test.php
lib/yui/notification/notification.js
theme/anomaly/config.php
theme/anomaly/lang/en/theme_anomaly.php
theme/anomaly/layout/frontpage.php [new file with mode: 0644]
theme/anomaly/layout/general.php
theme/anomaly/layout/report.php
theme/anomaly/lib.php
theme/anomaly/settings.php [new file with mode: 0644]
theme/anomaly/style/base.css
theme/anomaly/style/general.css
theme/anomaly/style/menu.css
theme/anomaly/style/settings.css [new file with mode: 0644]
theme/anomaly/version.php

index 214c70a..5a88859 100644 (file)
@@ -42,7 +42,7 @@ class enrol_database_plugin extends enrol_plugin {
         if (!enrol_is_enabled('database')) {
             return true;
         }
-        if (!$this->get_config('dbtype') or !$this->get_config('dbhost') or !$this->get_config('remoteenroltable') or !$this->get_config('remotecoursefield') or !$this->get_config('remoteuserfield')) {
+        if (!$this->get_config('dbtype') or !$this->get_config('remoteenroltable') or !$this->get_config('remotecoursefield') or !$this->get_config('remoteuserfield')) {
             return true;
         }
 
@@ -98,7 +98,7 @@ class enrol_database_plugin extends enrol_plugin {
         global $CFG, $DB;
 
         // We do not create courses here intentionally because it requires full sync and is slow.
-        if (!$this->get_config('dbtype') or !$this->get_config('dbhost') or !$this->get_config('remoteenroltable') or !$this->get_config('remotecoursefield') or !$this->get_config('remoteuserfield')) {
+        if (!$this->get_config('dbtype') or !$this->get_config('remoteenroltable') or !$this->get_config('remotecoursefield') or !$this->get_config('remoteuserfield')) {
             return;
         }
 
@@ -292,7 +292,7 @@ class enrol_database_plugin extends enrol_plugin {
         global $CFG, $DB;
 
         // We do not create courses here intentionally because it requires full sync and is slow.
-        if (!$this->get_config('dbtype') or !$this->get_config('dbhost') or !$this->get_config('remoteenroltable') or !$this->get_config('remotecoursefield') or !$this->get_config('remoteuserfield')) {
+        if (!$this->get_config('dbtype') or !$this->get_config('remoteenroltable') or !$this->get_config('remotecoursefield') or !$this->get_config('remoteuserfield')) {
             $trace->output('User enrolment synchronisation skipped.');
             $trace->finished();
             return 0;
@@ -616,7 +616,7 @@ class enrol_database_plugin extends enrol_plugin {
         global $CFG, $DB;
 
         // Make sure we sync either enrolments or courses.
-        if (!$this->get_config('dbtype') or !$this->get_config('dbhost') or !$this->get_config('newcoursetable') or !$this->get_config('newcoursefullname') or !$this->get_config('newcourseshortname')) {
+        if (!$this->get_config('dbtype') or !$this->get_config('newcoursetable') or !$this->get_config('newcoursefullname') or !$this->get_config('newcourseshortname')) {
             $trace->output('Course synchronisation skipped.');
             $trace->finished();
             return 0;
index 30ceb2c..6fc935d 100644 (file)
@@ -41,6 +41,8 @@ class sqlsrv_native_moodle_database extends moodle_database {
     protected $last_error_reporting; // To handle SQL*Server-Native driver default verbosity
     protected $temptables; // Control existing temptables (sqlsrv_moodle_temptables object)
     protected $collation;  // current DB collation cache
+    /** @var array list of open recordsets */
+    protected $recordsets = array();
 
     /**
      * Constructor - instantiates the database, specifying if it's external (connect to other systems) or no (Moodle DB)
@@ -789,7 +791,20 @@ class sqlsrv_native_moodle_database extends moodle_database {
      * @return sqlsrv_native_moodle_recordset
      */
     protected function create_recordset($result) {
-        return new sqlsrv_native_moodle_recordset($result);
+        $rs = new sqlsrv_native_moodle_recordset($result, $this);
+        $this->recordsets[] = $rs;
+        return $rs;
+    }
+
+    /**
+     * Do not use outside of recordset class.
+     * @internal
+     * @param sqlsrv_native_moodle_recordset $rs
+     */
+    public function recordset_closed(sqlsrv_native_moodle_recordset $rs) {
+        if ($key = array_search($rs, $this->recordsets, true)) {
+            unset($this->recordsets[$key]);
+        }
     }
 
     /**
@@ -1367,6 +1382,12 @@ class sqlsrv_native_moodle_database extends moodle_database {
      * @return void
      */
     protected function begin_transaction() {
+        // Recordsets do not work well with transactions in SQL Server,
+        // let's prefetch the recordsets to memory to work around these problems.
+        foreach ($this->recordsets as $rs) {
+            $rs->transaction_starts();
+        }
+
         $this->query_start('native sqlsrv_begin_transaction', NULL, SQL_QUERY_AUX);
         $result = sqlsrv_begin_transaction($this->sqlsrv);
         $this->query_end($result);
index e397e2e..677c2d0 100644 (file)
@@ -31,9 +31,49 @@ class sqlsrv_native_moodle_recordset extends moodle_recordset {
     protected $rsrc;
     protected $current;
 
-    public function __construct($rsrc) {
-        $this->rsrc  = $rsrc;
+    /** @var array recordset buffer */
+    protected $buffer = null;
+
+    /** @var sqlsrv_native_moodle_database */
+    protected $db;
+
+    public function __construct($rsrc, sqlsrv_native_moodle_database $db) {
+        $this->rsrc    = $rsrc;
         $this->current = $this->fetch_next();
+        $this->db      = $db;
+    }
+
+    /**
+     * Inform existing open recordsets that transaction
+     * is starting, this works around MARS problem described
+     * in MDL-37734.
+     */
+    public function transaction_starts() {
+        if ($this->buffer !== null) {
+            $this->unregister();
+            return;
+        }
+        if (!$this->rsrc) {
+            $this->unregister();
+            return;
+        }
+        // This might eat memory pretty quickly...
+        raise_memory_limit('2G');
+        $this->buffer = array();
+
+        while($next = $this->fetch_next()) {
+            $this->buffer[] = $next;
+        }
+    }
+
+    /**
+     * Unregister recordset from the global list of open recordsets.
+     */
+    private function unregister() {
+        if ($this->db) {
+            $this->db->recordset_closed($this);
+            $this->db = null;
+        }
     }
 
     public function __destruct() {
@@ -47,6 +87,7 @@ class sqlsrv_native_moodle_recordset extends moodle_recordset {
         if (!$row = sqlsrv_fetch_array($this->rsrc, SQLSRV_FETCH_ASSOC)) {
             sqlsrv_free_stmt($this->rsrc);
             $this->rsrc = null;
+            $this->unregister();
             return false;
         }
 
@@ -69,7 +110,11 @@ class sqlsrv_native_moodle_recordset extends moodle_recordset {
     }
 
     public function next() {
-        $this->current = $this->fetch_next();
+        if ($this->buffer === null) {
+            $this->current = $this->fetch_next();
+        } else {
+            $this->current = array_shift($this->buffer);
+        }
     }
 
     public function valid() {
@@ -82,5 +127,7 @@ class sqlsrv_native_moodle_recordset extends moodle_recordset {
             $this->rsrc  = null;
         }
         $this->current = null;
+        $this->buffer  = null;
+        $this->unregister();
     }
 }
index 5010b72..1c93f9d 100644 (file)
@@ -4444,6 +4444,35 @@ class dml_testcase extends database_driver_testcase {
         }
         $rs1->close();
         $this->assertEquals(3, $i);
+
+        // Test nested recordsets isolation without transaction.
+        $DB->delete_records($tablename);
+        $DB->insert_record($tablename, array('course'=>1));
+        $DB->insert_record($tablename, array('course'=>2));
+        $DB->insert_record($tablename, array('course'=>3));
+
+        $DB->delete_records($tablename2);
+        $DB->insert_record($tablename2, array('course'=>5));
+        $DB->insert_record($tablename2, array('course'=>6));
+        $DB->insert_record($tablename2, array('course'=>7));
+        $DB->insert_record($tablename2, array('course'=>8));
+
+        $rs1 = $DB->get_recordset($tablename);
+        $i = 0;
+        foreach ($rs1 as $record1) {
+            $i++;
+            $rs2 = $DB->get_recordset($tablename2);
+            $j = 0;
+            foreach ($rs2 as $record2) {
+                $DB->set_field($tablename, 'course', $record1->course+1, array('id'=>$record1->id));
+                $DB->set_field($tablename2, 'course', $record2->course+1, array('id'=>$record2->id));
+                $j++;
+            }
+            $rs2->close();
+            $this->assertEquals(4, $j);
+        }
+        $rs1->close();
+        $this->assertEquals(3, $i);
     }
 
     function test_transactions_forbidden() {
index eca0664..8969f6a 100644 (file)
@@ -22,17 +22,22 @@ var DIALOGUE_NAME = 'Moodle dialogue',
         FOOTER : 'moodle-dialogue-ft',
         HIDDEN : 'hidden',
         LIGHTBOX : 'moodle-dialogue-lightbox'
-    };
+    },
+    EXCEPTION,
+    ALERT,
+    CONFIRM,
+    AJAXEXCEPTION,
+    DIALOGUE;
 
-var DIALOGUE = function(config) {
+DIALOGUE = function(config) {
     COUNT++;
     var id = 'moodle-dialogue-'+COUNT;
     config.notificationBase =
-        C('<div class="'+CSS.BASE+'">')
-            .append(C('<div id="'+id+'" role="dialog" aria-labelledby="'+id+'-header-text" class="'+CSS.WRAP+'"></div>')
-                .append(C('<div class="'+CSS.HEADER+' yui3-widget-hd"></div>'))
-                .append(C('<div class="'+CSS.BODY+' yui3-widget-bd"></div>'))
-                .append(C('<div class="'+CSS.FOOTER+' yui3-widget-ft"></div>')));
+        new C('<div class="'+CSS.BASE+'">')
+              .append(new C('<div id="'+id+'" role="dialog" aria-labelledby="'+id+'-header-text" class="'+CSS.WRAP+'"></div>')
+              .append(new C('<div class="'+CSS.HEADER+' yui3-widget-hd"></div>'))
+              .append(new C('<div class="'+CSS.BODY+' yui3-widget-bd"></div>'))
+              .append(new C('<div class="'+CSS.FOOTER+' yui3-widget-ft"></div>')));
     Y.one(document.body).append(config.notificationBase);
     config.srcNode =    '#'+id;
     config.width =      config.width || '400px';
@@ -74,27 +79,28 @@ Y.extend(DIALOGUE, Y.Panel, {
         this.show();
     },
     visibilityChanged : function(e) {
-        switch (e.attrName) {
-            case 'visible':
-                this.get('maskNode').addClass(CSS.LIGHTBOX);
-                if (this.get('center') && !e.prevVal && e.newVal) {
-                    this.centerDialogue();
-                }
-                if (this.get('draggable')) {
-                    var titlebar = '#' + this.get('id') + ' .' + CSS.HEADER;
-                    this.plug(Y.Plugin.Drag, {handles : [titlebar]});
-                    Y.one(titlebar).setStyle('cursor', 'move');
-                }
-                break;
+        var titlebar;
+        if (e.attrName === 'visible') {
+            this.get('maskNode').addClass(CSS.LIGHTBOX);
+            if (this.get('center') && !e.prevVal && e.newVal) {
+                this.centerDialogue();
+            }
+            if (this.get('draggable')) {
+                titlebar = '#' + this.get('id') + ' .' + CSS.HEADER;
+                this.plug(Y.Plugin.Drag, {handles : [titlebar]});
+                Y.one(titlebar).setStyle('cursor', 'move');
+            }
         }
     },
     centerDialogue : function() {
-        var bb = this.get('boundingBox'), hidden = bb.hasClass(DIALOGUE_PREFIX+'-hidden');
+        var bb = this.get('boundingBox'),
+            hidden = bb.hasClass(DIALOGUE_PREFIX+'-hidden'),
+            x, y;
         if (hidden) {
             bb.setStyle('top', '-1000px').removeClass(DIALOGUE_PREFIX+'-hidden');
         }
-        var x = Math.max(Math.round((bb.get('winWidth') - bb.get('offsetWidth'))/2), 15);
-        var y = Math.max(Math.round((bb.get('winHeight') - bb.get('offsetHeight'))/2), 15) + Y.one(window).get('scrollTop');
+        x = Math.max(Math.round((bb.get('winWidth') - bb.get('offsetWidth'))/2), 15);
+        y = Math.max(Math.round((bb.get('winHeight') - bb.get('offsetHeight'))/2), 15) + Y.one(window).get('scrollTop');
 
         if (hidden) {
             bb.addClass(DIALOGUE_PREFIX+'-hidden');
@@ -131,13 +137,13 @@ Y.extend(DIALOGUE, Y.Panel, {
     }
 });
 
-var ALERT = function(config) {
+ALERT = function(config) {
     config.closeButton = false;
     ALERT.superclass.constructor.apply(this, [config]);
 };
 Y.extend(ALERT, DIALOGUE, {
     _enterKeypress : null,
-    initializer : function(config) {
+    initializer : function() {
         this.publish('complete');
         var yes = C('<input type="button" id="id_yuialertconfirm-' + this.COUNT + '" value="'+this.get(CONFIRMYES)+'" />'),
             content = C('<div class="confirmation-dialogue"></div>')
@@ -151,7 +157,7 @@ Y.extend(ALERT, DIALOGUE, {
         this._enterKeypress = Y.on('key', this.submit, window, 'down:13', this);
         yes.on('click', this.submit, this);
     },
-    submit : function(e, outcome) {
+    submit : function() {
         this._enterKeypress.detach();
         this.fire('complete');
         this.hide();
@@ -182,13 +188,13 @@ Y.extend(ALERT, DIALOGUE, {
     }
 });
 
-var CONFIRM = function(config) {
+CONFIRM = function(config) {
     CONFIRM.superclass.constructor.apply(this, [config]);
 };
 Y.extend(CONFIRM, DIALOGUE, {
     _enterKeypress : null,
     _escKeypress : null,
-    initializer : function(config) {
+    initializer : function() {
         this.publish('complete');
         this.publish('complete-yes');
         this.publish('complete-no');
@@ -244,7 +250,7 @@ Y.extend(CONFIRM, DIALOGUE, {
 });
 Y.augment(CONFIRM, Y.EventTarget);
 
-var EXCEPTION = function(config) {
+EXCEPTION = function(config) {
     config.width = config.width || (M.cfg.developerdebug)?Math.floor(Y.one(document.body).get('winWidth')/3)+'px':null;
     config.closeButton = true;
     EXCEPTION.superclass.constructor.apply(this, [config]);
@@ -253,20 +259,21 @@ Y.extend(EXCEPTION, DIALOGUE, {
     _hideTimeout : null,
     _keypress : null,
     initializer : function(config) {
+        var content,
+            self = this,
+            delay = this.get('hideTimeoutDelay');
         this.get(BASE).addClass('moodle-dialogue-exception');
         this.setStdModContent(Y.WidgetStdMod.HEADER, '<h1 id="moodle-dialogue-'+COUNT+'-header-text">' + config.name + '</h1>', Y.WidgetStdMod.REPLACE);
-        var content = C('<div class="moodle-exception"></div>')
-                    .append(C('<div class="moodle-exception-message">'+this.get('message')+'</div>'))
-                    .append(C('<div class="moodle-exception-param hidden param-filename"><label>File:</label> '+this.get('fileName')+'</div>'))
-                    .append(C('<div class="moodle-exception-param hidden param-linenumber"><label>Line:</label> '+this.get('lineNumber')+'</div>'))
-                    .append(C('<div class="moodle-exception-param hidden param-stacktrace"><label>Stack trace:</label> <pre>'+this.get('stack')+'</pre></div>'));
+        content = C('<div class="moodle-exception"></div>')
+                .append(C('<div class="moodle-exception-message">'+this.get('message')+'</div>'))
+                .append(C('<div class="moodle-exception-param hidden param-filename"><label>File:</label> '+this.get('fileName')+'</div>'))
+                .append(C('<div class="moodle-exception-param hidden param-linenumber"><label>Line:</label> '+this.get('lineNumber')+'</div>'))
+                .append(C('<div class="moodle-exception-param hidden param-stacktrace"><label>Stack trace:</label> <pre>'+this.get('stack')+'</pre></div>'));
         if (M.cfg.developerdebug) {
             content.all('.moodle-exception-param').removeClass('hidden');
         }
         this.setStdModContent(Y.WidgetStdMod.BODY, content, Y.WidgetStdMod.REPLACE);
 
-        var self = this;
-        var delay = this.get('hideTimeoutDelay');
         if (delay) {
             this._hideTimeout = setTimeout(function(){self.hide();}, delay);
         }
@@ -276,8 +283,10 @@ Y.extend(EXCEPTION, DIALOGUE, {
         this.centerDialogue();
     },
     visibilityChanged : function(e) {
-        if (e.attrName == 'visible' && e.prevVal && !e.newVal) {
-            if (this._keypress) this._keypress.detach();
+        if (e.attrName === 'visible' && e.prevVal && !e.newVal) {
+            if (this._keypress) {
+                this._keypress.detach();
+            }
             var self = this;
             setTimeout(function(){self.destroy();}, 1000);
         }
@@ -300,10 +309,12 @@ Y.extend(EXCEPTION, DIALOGUE, {
         },
         stack : {
             setter : function(str) {
-                var lines = str.split("\n");
-                var pattern = new RegExp('^(.+)@('+M.cfg.wwwroot+')?(.{0,75}).*:(\\d+)$');
-                for (var i in lines) {
-                    lines[i] = lines[i].replace(pattern, "<div class='stacktrace-line'>ln: $4</div><div class='stacktrace-file'>$3</div><div class='stacktrace-call'>$1</div>");
+                var lines = str.split("\n"),
+                    pattern = new RegExp('^(.+)@('+M.cfg.wwwroot+')?(.{0,75}).*:(\\d+)$'),
+                    i;
+                for (i in lines) {
+                    lines[i] = lines[i].replace(pattern,
+                            "<div class='stacktrace-line'>ln: $4</div><div class='stacktrace-file'>$3</div><div class='stacktrace-call'>$1</div>");
                 }
                 return lines.join('');
             },
@@ -316,7 +327,7 @@ Y.extend(EXCEPTION, DIALOGUE, {
     }
 });
 
-var AJAXEXCEPTION = function(config) {
+AJAXEXCEPTION = function(config) {
     config.name = config.name || 'Error';
     config.closeButton = true;
     AJAXEXCEPTION.superclass.constructor.apply(this, [config]);
@@ -324,20 +335,21 @@ var AJAXEXCEPTION = function(config) {
 Y.extend(AJAXEXCEPTION, DIALOGUE, {
     _keypress : null,
     initializer : function(config) {
+        var content,
+            self = this,
+            delay = this.get('hideTimeoutDelay');
         this.get(BASE).addClass('moodle-dialogue-exception');
         this.setStdModContent(Y.WidgetStdMod.HEADER, '<h1 id="moodle-dialogue-'+COUNT+'-header-text">' + config.name + '</h1>', Y.WidgetStdMod.REPLACE);
-        var content = C('<div class="moodle-ajaxexception"></div>')
-                    .append(C('<div class="moodle-exception-message">'+this.get('error')+'</div>'))
-                    .append(C('<div class="moodle-exception-param hidden param-debuginfo"><label>URL:</label> '+this.get('reproductionlink')+'</div>'))
-                    .append(C('<div class="moodle-exception-param hidden param-debuginfo"><label>Debug info:</label> '+this.get('debuginfo')+'</div>'))
-                    .append(C('<div class="moodle-exception-param hidden param-stacktrace"><label>Stack trace:</label> <pre>'+this.get('stacktrace')+'</pre></div>'));
+        content = C('<div class="moodle-ajaxexception"></div>')
+                .append(C('<div class="moodle-exception-message">'+this.get('error')+'</div>'))
+                .append(C('<div class="moodle-exception-param hidden param-debuginfo"><label>URL:</label> '+this.get('reproductionlink')+'</div>'))
+                .append(C('<div class="moodle-exception-param hidden param-debuginfo"><label>Debug info:</label> '+this.get('debuginfo')+'</div>'))
+                .append(C('<div class="moodle-exception-param hidden param-stacktrace"><label>Stack trace:</label> <pre>'+this.get('stacktrace')+'</pre></div>'));
         if (M.cfg.developerdebug) {
             content.all('.moodle-exception-param').removeClass('hidden');
         }
         this.setStdModContent(Y.WidgetStdMod.BODY, content, Y.WidgetStdMod.REPLACE);
 
-        var self = this;
-        var delay = this.get('hideTimeoutDelay');
         if (delay) {
             this._hideTimeout = setTimeout(function(){self.hide();}, delay);
         }
@@ -346,7 +358,7 @@ Y.extend(AJAXEXCEPTION, DIALOGUE, {
         this.centerDialogue();
     },
     visibilityChanged : function(e) {
-        if (e.attrName == 'visible' && e.prevVal && !e.newVal) {
+        if (e.attrName === 'visible' && e.prevVal && !e.newVal) {
             var self = this;
             this._keypress.detach();
             setTimeout(function(){self.destroy();}, 1000);
index d94f108..9e840f3 100644 (file)
@@ -7,12 +7,19 @@
 
 $THEME->name = 'anomaly';
 
-$THEME->sheets = array('base', 'general', 'browser', 'dock', 'menu');
+$THEME->sheets = array(
+    'base',
+    'general',
+    'browser',
+    'dock',
+    'menu',
+    'settings'
+);
 /// This variable is an array containing the names of all the
 /// stylesheet files you want included in this theme, and in what order
 ////////////////////////////////////////////////////////////////////////////////
 
-$THEME->parents = array('base');  // TODO: new themes can not be based on standardold, instead use 'base' as the base
+$THEME->parents = array('base');
 /// This variable can be set to the name of a parent theme
 /// which you want to have included before the current theme.
 /// This can make it easy to make modifications to another
@@ -54,7 +61,7 @@ $THEME->layouts = array(
         'options' => array('langmenu' => true)
     ),
     'frontpage' => array(
-        'file' => 'general.php',
+        'file' => 'frontpage.php',
         'regions' => array('side-pre', 'side-post'),
         'defaultregion' => 'side-pre',
         'options' => array('langmenu' => true)
@@ -113,16 +120,32 @@ $THEME->layouts = array(
         'regions' => array(),
         'options' => array('nofooter'=>true, 'nonavbar'=>false, 'noblocks'=>true, 'nocourseheaderfooter'=>true),
     ),
+    // 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' => 'report.php',
         'regions' => array('side-pre'),
         'defaultregion' => 'side-pre',
-        'options' => array('langmenu' => true)
+        'options' => array('langmenu' => true),
+    ),
+    // The pagelayout used for safebrowser and securewindow.
+    'secure' => array(
+        'file' => 'general.php',
+        'regions' => array('side-pre', 'side-post'),
+        'defaultregion' => 'side-pre',
+        'options' => array('nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true, 'nologinlinks'=>true, 'nocourseheaderfooter'=>true),
     ),
 );
 
 $THEME->rendererfactory = 'theme_overridden_renderer_factory';
 
+$THEME->csspostprocess = 'anomaly_process_css';
+
 $THEME->enable_dock = true;
 
 $THEME->editor_sheets = array('editor');
index c38f679..18967aa 100644 (file)
  * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-
+$string['choosereadme'] = '<div class="clearfix"><div class="theme_screenshot"><h2>Anomaly</h2><img src="anomaly/pix/screenshot.jpg" /><h3>Theme Discussion Forum:</h3><p><a href="http://moodle.org/mod/forum/view.php?id=46">http://moodle.org/mod/forum/view.php?id=46</a></p><h3>Theme Credits</h3><p><a href="http://docs.moodle.org/en/Theme_credits">http://docs.moodle.org/en/Theme_credits</a></p><h3>Theme Documentation:</h3><p><a href="http://docs.moodle.org/en/Themes">http://docs.moodle.org/en/Themes</a></p><h3>Report a bug:</h3><p><a href="http://tracker.moodle.org">http://tracker.moodle.org</a></p></div><div class="theme_description"><h2>About</h2><p>Anomaly is a fluid-width, three-column Moodle 2.0 theme with rounded corners. <h2>Tweaks</h2><p>This theme is built upon the Base theme inside the Moodle core. If you want to modify this theme, we recommend that you first duplicate it, then rename it before making your changes. This will prevent your customized theme from being overwritten by future Moodle upgrades, and you\'ll still have the original files if you make a mess. More information on modifying themes can be found in the <a href="http://docs.moodle.org/en/Theme">MoodleDocs</a>.</p><h2>Credits</h2><p>This theme was originally designed for Moodle 1.9 by Patrick Malley. It was then coded for 2.0 and is maintained by Sam Hemelryk at Moodle HQ. He can be contacted at sam@moodle.com.</p><h2>License</h2><p>This, and all other themes included in the Moodle core, are licensed under the <a href="http://www.gnu.org/licenses/gpl.html">GNU General Public License</a>.</div></div>';
+$string['configtitle'] = 'Anomaly Theme';
+$string['customcss'] = 'Custom CSS';
+$string['customcssdesc'] = 'Whatever CSS rules you add to this Custom CSS box will be reflected in every page, making for easier customization of this theme.';
 $string['pluginname'] = 'Anomaly';
 $string['region-side-post'] = 'Right';
 $string['region-side-pre'] = 'Left';
-$string['choosereadme'] = '<div class="clearfix"><div class="theme_screenshot"><h2>Anomaly</h2><img src="anomaly/pix/screenshot.jpg" /><h3>Theme Discussion Forum:</h3><p><a href="http://moodle.org/mod/forum/view.php?id=46">http://moodle.org/mod/forum/view.php?id=46</a></p><h3>Theme Credits</h3><p><a href="http://docs.moodle.org/en/Theme_credits">http://docs.moodle.org/en/Theme_credits</a></p><h3>Theme Documentation:</h3><p><a href="http://docs.moodle.org/en/Themes">http://docs.moodle.org/en/Themes</a></p><h3>Report a bug:</h3><p><a href="http://tracker.moodle.org">http://tracker.moodle.org</a></p></div><div class="theme_description"><h2>About</h2><p>Anomaly is a fluid-width, three-column Moodle 2.0 theme with rounded corners. <h2>Tweaks</h2><p>This theme is built upon the Base theme inside the Moodle core. If you want to modify this theme, we recommend that you first duplicate it, then rename it before making your changes. This will prevent your customized theme from being overwritten by future Moodle upgrades, and you\'ll still have the original files if you make a mess. More information on modifying themes can be found in the <a href="http://docs.moodle.org/en/Theme">MoodleDocs</a>.</p><h2>Credits</h2><p>This theme was originally designed for Moodle 1.9 by Patrick Malley. It was then coded for 2.0 and is maintained by Sam Hemelryk at Moodle HQ. He can be contacted at sam@moodle.com.</p><h2>License</h2><p>This, and all other themes included in the Moodle core, are licensed under the <a href="http://www.gnu.org/licenses/gpl.html">GNU General Public License</a>.</div></div>';
\ No newline at end of file
+$string['tagline'] = 'Tagline';
+$string['taglinedesc'] = 'Whatever text you add to this Tagline text box will be displayed below the heading on the front page of your Moodle site only.';
diff --git a/theme/anomaly/layout/frontpage.php b/theme/anomaly/layout/frontpage.php
new file mode 100644 (file)
index 0000000..01292c5
--- /dev/null
@@ -0,0 +1,115 @@
+<?php
+
+$hassidepre = $PAGE->blocks->region_has_content('side-pre', $OUTPUT);
+$hassidepost = $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);
+
+$hastagline = (!empty($PAGE->theme->settings->tagline));
+
+$custommenu = $OUTPUT->custom_menu();
+$hascustommenu = (empty($PAGE->layout_options['nocustommenu']) && !empty($custommenu));
+
+$bodyclasses = array();
+if ($showsidepre && !$showsidepost) {
+    $bodyclasses[] = 'side-pre-only';
+} else if ($showsidepost && !$showsidepre) {
+    $bodyclasses[] = 'side-post-only';
+} else if (!$showsidepost && !$showsidepre) {
+    $bodyclasses[] = 'content-only';
+}
+if ($hascustommenu) {
+    $bodyclasses[] = 'has_custom_menu';
+}
+
+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')?>" />
+    <meta name="description" content="<?php p(strip_tags(format_text($SITE->summary, FORMAT_HTML))) ?>" />
+    <?php echo $OUTPUT->standard_head_html() ?>
+</head>
+<body id="<?php p($PAGE->bodyid) ?>" class="<?php p($PAGE->bodyclasses.' '.join(' ', $bodyclasses)) ?>">
+<?php echo $OUTPUT->standard_top_of_body_html() ?>
+
+<div id="page">
+
+<div id="page-header">
+
+        <div class="rounded-corner top-left"></div>
+        <div class="rounded-corner top-right"></div>
+
+            <div class="headermenu"><?php
+            echo $OUTPUT->login_info();
+            echo $OUTPUT->lang_menu();
+            echo $PAGE->headingmenu;
+        ?></div>
+
+        <h1 class="headermain"><?php echo $PAGE->heading ?></h1>
+
+        <?php if ($hastagline) { ?>
+            <h2 class="tagline"><?php echo $PAGE->theme->settings->tagline;?></h2>
+        <?php } ?>
+
+
+        <?php
+    if ($hascustommenu) { ?>
+        <div id="custommenu"><?php echo $custommenu; ?></div>
+        <?php
+    } ?>
+
+</div>
+<!-- END OF HEADER -->
+
+    <div id="page-content">
+        <div id="region-main-box">
+            <div id="region-post-box">
+
+                <div id="region-main-wrap">
+                    <div id="region-main">
+                        <div class="region-content">
+                            <?php echo $OUTPUT->main_content() ?>
+                        </div>
+                    </div>
+                </div>
+
+                <?php if ($hassidepre) { ?>
+                <div id="region-pre" class="block-region">
+                    <div class="region-content">
+                        <?php echo $OUTPUT->blocks_for_region('side-pre') ?>
+                    </div>
+                </div>
+                <?php } ?>
+
+                <?php if ($hassidepost) { ?>
+                <div id="region-post" class="block-region">
+                    <div class="region-content">
+                        <?php echo $OUTPUT->blocks_for_region('side-post') ?>
+                    </div>
+                </div>
+                <?php } ?>
+
+            </div>
+        </div>
+    </div>
+
+<!-- START OF FOOTER -->
+    <div id="page-footer">
+        <p class="helplink">
+        <?php echo page_doc_link(get_string('moodledocslink')) ?>
+        </p>
+
+        <?php
+        echo $OUTPUT->login_info();
+        echo $OUTPUT->home_link();
+        echo $OUTPUT->standard_footer_html();
+        ?>
+        <div class="rounded-corner bottom-left"></div>
+        <div class="rounded-corner bottom-right"></div>
+    </div>
+    <div class="clearfix"></div>
+</div>
+<?php echo $OUTPUT->standard_end_of_body_html() ?>
+</body>
+</html>
index 4037cce..d783101 100644 (file)
@@ -3,13 +3,26 @@
 $hasheading = ($PAGE->heading);
 $hasnavbar = (empty($PAGE->layout_options['nonavbar']) && $PAGE->has_navbar());
 $hasfooter = (empty($PAGE->layout_options['nofooter']));
-$hassidepre = $PAGE->blocks->region_has_content('side-pre', $OUTPUT);
-$hassidepost = $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);
+$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));
+$haslogininfo = (empty($PAGE->layout_options['nologininfo']));
+
+$showsidepre = ($hassidepre && !$PAGE->blocks->region_completely_docked('side-pre', $OUTPUT));
+$showsidepost = ($hassidepost && !$PAGE->blocks->region_completely_docked('side-post', $OUTPUT));
+
 $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();
+    }
+}
+
 $bodyclasses = array();
 if ($showsidepre && !$showsidepost) {
     $bodyclasses[] = 'side-pre-only';
@@ -25,16 +38,6 @@ if ($hasnavbar) {
     $bodyclasses[] = 'hasnavbar';
 }
 
-$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();
-    }
-}
-
 echo $OUTPUT->doctype() ?>
 <html <?php echo $OUTPUT->htmlattributes() ?>>
 <head>
@@ -65,7 +68,7 @@ echo $OUTPUT->doctype() ?>
         <?php } ?>
         <?php if ($hascustommenu) { ?>
             <div id="custommenu"><?php echo $custommenu; ?></div>
-               <?php } ?>
+        <?php } ?>
 
         <?php if ($hasnavbar) { ?>
             <div class="navbar clearfix">
@@ -131,4 +134,4 @@ echo $OUTPUT->doctype() ?>
 </div>
 <?php echo $OUTPUT->standard_end_of_body_html() ?>
 </body>
-</html>
\ No newline at end of file
+</html>
index ffb240d..d7207b3 100644 (file)
@@ -3,8 +3,13 @@
 $hasheading = ($PAGE->heading);
 $hasnavbar = (empty($PAGE->layout_options['nonavbar']) && $PAGE->has_navbar());
 $hasfooter = (empty($PAGE->layout_options['nofooter']));
-$hassidepre = $PAGE->blocks->region_has_content('side-pre', $OUTPUT);
-$showsidepre = $hassidepre && !$PAGE->blocks->region_completely_docked('side-pre', $OUTPUT);
+$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));
+$haslogininfo = (empty($PAGE->layout_options['nologininfo']));
+
+$showsidepre = ($hassidepre && !$PAGE->blocks->region_completely_docked('side-pre', $OUTPUT));
+$showsidepost = ($hassidepost && !$PAGE->blocks->region_completely_docked('side-post', $OUTPUT));
+
 $custommenu = $OUTPUT->custom_menu();
 $hascustommenu = (empty($PAGE->layout_options['nocustommenu']) && !empty($custommenu));
 
@@ -58,8 +63,8 @@ echo $OUTPUT->doctype() ?>
             <div id="course-header"><?php echo $courseheader; ?></div>
         <?php } ?>
         <?php if ($hascustommenu) { ?>
-       <div id="custommenu"><?php echo $custommenu; ?></div>
-               <?php } ?>
+    <div id="custommenu"><?php echo $custommenu; ?></div>
+        <?php } ?>
 
         <?php if ($hasnavbar) { ?>
             <div class="navbar clearfix">
@@ -110,4 +115,4 @@ echo $OUTPUT->doctype() ?>
 </div>
 <?php echo $OUTPUT->standard_end_of_body_html() ?>
 </body>
-</html>
\ No newline at end of file
+</html>
index dc33c81..42c3100 100644 (file)
@@ -1,8 +1,26 @@
 <?php
 
-/**
- * Functions needed by the anomaly theme should be put here.
- *
- * Any functions that get created here should ALWAYS contain the theme name
- * to reduce complications for other theme designers who may be copying this theme.
- */
\ No newline at end of file
+function anomaly_process_css($css, $theme) {
+
+    // Set custom CSS
+    if (!empty($theme->settings->customcss)) {
+        $customcss = $theme->settings->customcss;
+    } else {
+        $customcss = null;
+    }
+    $css = anomaly_set_customcss($css, $customcss);
+
+    return $css;
+}
+
+function anomaly_set_customcss($css, $customcss) {
+    $tag = '[[setting:customcss]]';
+    $replacement = $customcss;
+    if (is_null($replacement)) {
+        $replacement = '';
+    }
+
+    $css = str_replace($tag, $replacement, $css);
+
+    return $css;
+}
diff --git a/theme/anomaly/settings.php b/theme/anomaly/settings.php
new file mode 100644 (file)
index 0000000..73f5aa9
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+
+defined('MOODLE_INTERNAL') || die;
+
+if ($ADMIN->fulltree) {
+
+    // Tagline setting
+    $name = 'theme_anomaly/tagline';
+    $title = get_string('tagline','theme_anomaly');
+    $description = get_string('taglinedesc', 'theme_anomaly');
+    $default = '';
+    $setting = new admin_setting_configtext($name, $title, $description, $default);
+    $settings->add($setting);
+
+    // Custom CSS file
+    $name = 'theme_anomaly/customcss';
+    $title = get_string('customcss','theme_anomaly');
+    $description = get_string('customcssdesc', 'theme_anomaly');
+    $default = '';
+    $setting = new admin_setting_configtextarea($name, $title, $description, $default);
+    $settings->add($setting);
+
+}
index c7a4be1..35980ce 100644 (file)
@@ -2,7 +2,7 @@
  * Core
  */
 
-h1, h2, h3, h4, h5 {
+h1, h1.headermain, h2, h2.tagline, h3, h4, h5 {
     font-family: Georgia,Times,"Times New Roman",serif;
 }
 
index cfc2ecf..f1d7bff 100644 (file)
@@ -24,38 +24,49 @@ html, body {
 }
 /** Header **/
 
+.pagelayout-frontpage #page-header {
+    border-bottom: 5px solid #697F55;
+}
 #page-header {
     background-color: #222;
     color: #FFF;
-    border-bottom: 5px solid #697F55;
     margin: 0;
     padding: 0;
     width: 100%;
 }
 h1.headermain {
+    font-size: 30px;
+    margin: 20px;
+    font-weight: 400;
+}
+.pagelayout-frontpage h1.headermain,
+h2.tagline {
     float: left;
-    font-size: 2.3em;
-    margin: 15px;
     line-height: 1;
+    padding: 0;
+}
+.pagelayout-frontpage h1.headermain {
+    margin-bottom: 0;
 }
-#page-header .headermain span {
-    color: #C8C9C7;
+h2.tagline {
+    clear: left;
+    color: #bbb;
+    margin-top: 0;
+    margin-bottom: 20px;
+    margin-left: 20px;
+    font-size: 100%;
+    font-weight: normal;
 }
 
 /** Navbar **/
 
-.hasnavbar #page-header {
-    border-bottom-color: #3A4D28;
-    border-bottom-width: 3px;
-}
 #page-header .navbar {
     background-color: #697F55;
     width: 100%;
     margin: 0;
     padding: 0;
-}
-#page-header .navbar {
     color: #000;
+    height: 30px;
 }
 #page-header .navbar a:link,
 #page-header .navbar a:visited {
@@ -63,7 +74,16 @@ h1.headermain {
 }
 #page-header .navbar .breadcrumb,
 #page-header .navbar .navbutton {
-    margin: 5px 1em;
+    line-height: 1.5;
+}
+#page-header .navbar .breadcrumb {
+    margin: 5px 5px 0 20px;
+}
+#page-header .navbar .navbutton {
+    margin: 3px 5px 3px;
+}
+#page-header .navbar .navbutton .singlebutton {
+    margin: 0;
 }
 
 /** Footer **/
@@ -72,6 +92,9 @@ h1.headermain {
     background-color: #222;
     color: #FFF;
 }
+#page-footer .helplink {
+    margin-top: 10px;
+}
 
 /** General **/
 .generalbox {
@@ -678,4 +701,13 @@ h1.headermain {
 
 /* Add Block
 -------------------------*/
-.block .content .singleselect form#add_block .select.menubui_addblock { width: 160px;}
+.block .content .singleselect form#add_block .select.menubui_addblock {
+    width: 160px;
+}
+
+/* Admin settings
+-------------------------*/
+#adminsettings .form-buttons {
+    margin: 0;
+    text-align: center;
+}
\ No newline at end of file
index 09a8c14..58b1379 100644 (file)
@@ -6,9 +6,13 @@
     padding: 0;
     clear: both;
     height: 30px;
-    background: #222;
+    background: #333;
     margin:0;
 }
+#custommenu ul li {
+    border-right: 1px solid #444;
+    border-left: 1px solid #555
+}
 /*
 Dropdown Menu - CSS from DeCaf Theme by Lei Zhang
 -------------------------------------------------*/
diff --git a/theme/anomaly/style/settings.css b/theme/anomaly/style/settings.css
new file mode 100644 (file)
index 0000000..82955eb
--- /dev/null
@@ -0,0 +1,3 @@
+/* Custom CSS Settings
+-------------------------*/
+[[setting:customcss]]
\ No newline at end of file
index 2b6b85f..5936ea3 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die;
 
-$plugin->version   = 2012112900; // The current module version (Date: YYYYMMDDXX)
+$plugin->version   = 2013013000; // The current module version (Date: YYYYMMDDXX)
 $plugin->requires  = 2012112900; // Requires this Moodle version
 $plugin->component = 'theme_anomaly'; // Full name of the plugin (used for diagnostics)