Merge branch 'MDL-26250-final6' of github.com:mouneyrac/moodle
authorSam Hemelryk <sam@moodle.com>
Wed, 4 May 2011 10:04:10 +0000 (18:04 +0800)
committerSam Hemelryk <sam@moodle.com>
Wed, 4 May 2011 10:04:10 +0000 (18:04 +0800)
43 files changed:
admin/report/customlang/db/install.xml
admin/report/customlang/db/upgrade.php
admin/report/customlang/index.php
admin/report/customlang/lang/en/report_customlang.php
admin/report/customlang/locallib.php
admin/report/customlang/styles.css
admin/report/customlang/version.php
admin/settings/server.php
blog/locallib.php
course/report/completion/index.php
course/user.php
lang/en/admin.php
lang/en/repository.php
lib/filelib.php
lib/filestorage/file_storage.php
lib/form/filemanager.js
lib/moodlelib.php
lib/navigationlib.php
lib/outputlib.php
lib/outputrequirementslib.php
lib/tablelib.php
mod/forum/user.php
mod/lesson/essay.php
mod/lesson/locallib.php
mod/scorm/locallib.php
question/type/multianswer/questiontype.php
question/type/numerical/questiontype.php
repository/coursefiles/lib.php
repository/dropbox/lib.php
repository/filepicker.js
repository/lib.php
repository/local/lib.php
repository/recent/lib.php
repository/repository_ajax.php
repository/upload/lib.php
repository/user/lib.php
theme/anomaly/layout/general.php
theme/anomaly/layout/report.php
theme/anomaly/style/general.css
theme/serenity/layout/frontpage.php
theme/serenity/layout/general.php
theme/serenity/style/core.css
user/view.php

index 361616b..9392220 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
-<XMLDB PATH="admin/report/customlang/db" VERSION="20101115" COMMENT="XMLDB file for Moodle admin/report/customlang"
+<XMLDB PATH="admin/report/customlang/db" VERSION="20110419" COMMENT="XMLDB file for Moodle admin/report/customlang"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation="../../../../lib/xmldb/xmldb.xsd"
 >
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="The normalized name of the plugin" PREVIOUS="id" NEXT="version"/>
-        <FIELD NAME="version" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" COMMENT="The checked out version of the plugin, null of the version is unknown" PREVIOUS="name"/>
+        <FIELD NAME="version" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="The checked out version of the plugin, null if the version is unknown" PREVIOUS="name"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
       </KEYS>
     </TABLE>
   </TABLES>
-</XMLDB>
+</XMLDB>
\ No newline at end of file
index 0a947db..0b12553 100644 (file)
@@ -57,5 +57,18 @@ function xmldb_report_customlang_upgrade($oldversion) {
         upgrade_plugin_savepoint(true, 2010111500, 'report', 'customlang');
     }
 
+    /**
+     * Change the version field from integer to varchar
+     */
+    if ($oldversion < 2011041900) {
+        $table = new xmldb_table('report_customlang_components');
+        $field = new xmldb_field('version', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'name');
+
+        $dbman->change_field_type($table, $field);
+
+        upgrade_plugin_savepoint(true, 2011041900, 'report', 'customlang');
+    }
+
+
     return $result;
 }
index 621e15a..86ea785 100644 (file)
@@ -24,6 +24,8 @@
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+define('NO_OUTPUT_BUFFERING', true); // progress bar is used here
+
 require(dirname(dirname(dirname(dirname(__FILE__)))).'/config.php');
 require_once($CFG->dirroot.'/'.$CFG->admin.'/report/customlang/locallib.php');
 require_once($CFG->libdir.'/adminlib.php');
@@ -45,8 +47,22 @@ if ($action === 'checkout') {
     if (empty($lng)) {
         print_error('missingparameter');
     }
-    report_customlang_utils::checkout($lng);
-    redirect(new moodle_url('/admin/report/customlang/edit.php', array('lng' => $lng)));
+
+    $PAGE->set_cacheable(false);    // progress bar is used here
+    $output = $PAGE->get_renderer('report_customlang');
+    echo $output->header();
+    echo $output->heading(get_string('pluginname', 'report_customlang'));
+    $progressbar = new progress_bar();
+    $progressbar->create();         // prints the HTML code of the progress bar
+
+    // we may need a bit of extra execution time and memory here
+    @set_time_limit(HOURSECS);
+    raise_memory_limit(MEMORY_EXTRA);
+    report_customlang_utils::checkout($lng, $progressbar);
+
+    echo $output->continue_button(new moodle_url('/admin/report/customlang/edit.php', array('lng' => $lng)), 'get');
+    echo $output->footer();
+    exit;
 }
 
 if ($action === 'checkin') {
index d90acae..6e6c301 100644 (file)
@@ -27,7 +27,9 @@
 defined('MOODLE_INTERNAL') || die();
 
 $string['checkin'] = 'Check in strings into disk';
-$string['checkout'] = 'Check out strings into translator';
+$string['checkout'] = 'Check out strings into the translator';
+$string['checkoutdone'] = 'Strings checked out successfully into the translator';
+$string['checkoutinprogress'] = 'Checking out strings into the translator';
 $string['confirmcheckin'] = 'You are about to check in modified strings into your local language pack. This will export the customized strings from the translator into the data directory and Moodle will start using the modified strings. Press \'Continue\' button to proceed check in.';
 $string['customlang:edit'] = 'Edit local translation';
 $string['customlang:view'] = 'View local translation';
index 53ecee1..c3aa6ca 100644 (file)
@@ -16,7 +16,7 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * Definition of classes used by Langugae customization admin report
+ * Definition of classes used by language customization admin report
  *
  * @package    report
  * @subpackage customlang
@@ -33,6 +33,12 @@ defined('MOODLE_INTERNAL') || die();
  */
 class report_customlang_utils {
 
+    /**
+     * Rough number of strings that are being processed during a full checkout.
+     * This is used to estimate the progress of the checkout.
+     */
+    const ROUGH_NUMBER_OF_STRINGS = 16500;
+
     /** @var array cache of {@link self::list_components()} results */
     protected static $components = null;
 
@@ -83,8 +89,9 @@ class report_customlang_utils {
      * This should be executed each time before going to the translation page
      *
      * @param string $lang language code to checkout
+     * @param progress_bar $progressbar optionally, the given progress bar can be updated
      */
-    public static function checkout($lang) {
+    public static function checkout($lang, progress_bar $progressbar = null) {
         global $DB;
 
         // make sure that all components are registered
@@ -107,6 +114,10 @@ class report_customlang_utils {
         }
         unset($current);
 
+        // initialize the progress counter - stores the number of processed strings
+        $done = 0;
+        $strinprogress = get_string('checkoutinprogress', 'report_customlang');
+
         // reload components and fetch their strings
         $stringman  = get_string_manager();
         $components = $DB->get_records('report_customlang_components');
@@ -129,6 +140,12 @@ class report_customlang_utils {
                 $stringlocal = isset($local[$stringid]) ? $local[$stringid] : null;
                 $now = time();
 
+                if (!is_null($progressbar)) {
+                    $done++;
+                    $donepercent = floor(min($done, self::ROUGH_NUMBER_OF_STRINGS) / self::ROUGH_NUMBER_OF_STRINGS * 100);
+                    $progressbar->update_full($donepercent, $strinprogress);
+                }
+
                 if (isset($current[$stringid])) {
                     $needsupdate     = false;
                     $currentoriginal = $current[$stringid]->original;
@@ -175,6 +192,10 @@ class report_customlang_utils {
                 }
             }
         }
+
+        if (!is_null($progressbar)) {
+            $progressbar->update_full(100, get_string('checkoutdone', 'report_customlang'));
+        }
     }
 
     /**
index e75f412..e921972 100644 (file)
@@ -63,3 +63,7 @@
     background-color: #f6f6f6;
     margin-top: 0.5em;
 }
+
+#page-admin-report-customlang-index .continuebutton {
+    margin-top: 1em;
+}
index 78fa192..96b03d5 100644 (file)
@@ -24,5 +24,5 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version  = 2010120900;
+$plugin->version  = 2011041900;
 $plugin->requires = 2010120700;
index 807bf75..7334fec 100644 (file)
@@ -241,6 +241,8 @@ $temp->add(new admin_setting_configselect('extramemorylimit', get_string('extram
 $temp->add(new admin_setting_configtext('curlcache', get_string('curlcache', 'admin'),
                                         get_string('configcurlcache', 'admin'), 120, PARAM_INT));
 
+$temp->add(new admin_setting_configtext('curltimeoutkbitrate', get_string('curltimeoutkbitrate', 'admin'),
+                                        get_string('curltimeoutkbitrate_help', 'admin'), 56, PARAM_INT));
 /* //TODO: we need to fix code instead of relying on slow rcache, enable this once we have some code that is actually using it
 $temp->add(new admin_setting_special_selectsetup('cachetype', get_string('cachetype', 'admin'),
                                           get_string('configcachetype', 'admin'), '',
index 1cc4b0c..77d2ffd 100644 (file)
@@ -517,7 +517,7 @@ class blog_entry {
 
             } else {
                 if (in_array($type, array('image/gif', 'image/jpeg', 'image/png'))) {    // Image attachments don't get printed as links
-                    $imagereturn .= "<br />" . $OUTPUT->pix_icon($ffurl, $filename);
+                    $imagereturn .= '<br /><img src="'.$ffurl.'" alt="" />';
                 } else {
                     $imagereturn .= html_writer::link($ffurl, $image);
                     $imagereturn .= format_text(html_writer::link($ffurl, $filename), FORMAT_HTML, array('context'=>$syscontext));
index 470722d..2c222bf 100644 (file)
@@ -384,7 +384,7 @@ if(!$csv) {
                 // Try load a aggregation method
                 $method = $completion->get_aggregation_method($current_group->criteriatype);
 
-                $method = $method == 1 ? 'All' : 'Any';
+                $method = $method == 1 ? get_string('all') : get_string('any');
 
             } else {
                 $method = '-';
@@ -406,7 +406,7 @@ if(!$csv) {
     // Get course aggregation
     $method = $completion->get_aggregation_method();
 
-    print $method == 1 ? 'All' : 'Any';
+    print $method == 1 ? get_string('all') : get_string('any');
     print '</th>';
 
     print '</tr>';
@@ -515,7 +515,7 @@ if(!$csv) {
 
     // Overall course completion status
     print '<th class="criteriaicon">';
-    print '<img src="'.$OUTPUT->pix_url('i/course').'" class="icon" alt="Course" title="Course Complete" />'; //TODO: localize
+    print '<img src="'.$OUTPUT->pix_url('i/course').'" class="icon" alt="'.get_string('course').'" title="'.get_string('coursecomplete', 'completion').'" />';
     print '</th>';
 
     print '</tr>';
@@ -634,7 +634,7 @@ foreach ($progress as $user) {
                 print '<td class="completion-progresscell">'.
                     '<a href="'.$CFG->wwwroot.'/course/togglecompletion.php?user='.$user->id.'&amp;course='.$course->id.'&amp;rolec='.$allow_marking_criteria.'&amp;sesskey='.sesskey().'">'.
                     '<img src="'.$OUTPUT->pix_url('i/completion-manual-'.($is_complete ? 'y' : 'n')).
-                    '" alt="'.$describe.'" class="icon" title="Mark as complete" /></a></td>'; //TODO: localize
+                    '" alt="'.$describe.'" class="icon" title="'.get_string('markcomplete', 'completion').'" /></a></td>';
             } else {
                 print '<td class="completion-progresscell">'.
                     '<img src="'.$OUTPUT->pix_url('i/'.$completionicon).
index b5ab6cd..ee9db65 100644 (file)
@@ -152,6 +152,7 @@ if ($course->id != SITEID && has_capability('moodle/course:viewparticipants', $c
 }
 
 $PAGE->navigation->extend_for_user($user);
+$PAGE->navigation->set_userid_for_parent_checks($user->id); // see MDL-25805 for reasons and for full commit reference for reversal when fixed.
 $PAGE->set_title("$course->shortname: $stractivityreport ($mode)");
 $PAGE->set_heading($course->fullname);
 echo $OUTPUT->header();
index 427fa20..09817ef 100644 (file)
@@ -398,6 +398,8 @@ $string['ctyperequired'] = 'The ctype PHP extension is now required by Moodle, i
 $string['curlcache'] = 'cURL cache TTL';
 $string['curlrecommended'] = 'Installing the optional cURL library is highly recommended in order to enable Moodle Networking functionality.';
 $string['curlrequired'] = 'The cURL PHP extension is now required by Moodle, in order to communicate with Moodle repositories.';
+$string['curltimeoutkbitrate'] = 'Bitrate to use when calculating cURL timeouts (Kbps)';
+$string['curltimeoutkbitrate_help'] = 'This setting is used to calculate an appropriate timeout during large cURL requests. As part of this calculation an HTTP HEAD request is made to determine the size of the content. Setting this to 0 disables this request from being made.';
 $string['customcheck'] = 'Other checks';
 $string['custommenu'] = 'Custom menu';
 $string['custommenuitems'] = 'Custom menu items';
index 9ba7819..cc63fb0 100644 (file)
@@ -94,6 +94,9 @@ $string['errorpostmaxsize'] = 'The uploaded file may exceed max_post_size direct
 $string['existingrepository'] = 'This repository already exists';
 $string['federatedsearch'] = 'Federated search';
 $string['fileexists'] = 'File name already being used, please use another name';
+$string['fileexistsdialog_editor'] = 'A file with that name has already been attached to the text you are editing.';
+$string['fileexistsdialog_filemanager'] = 'A file with that name has already been attached';
+$string['fileexistsdialogheader'] = 'File exists';
 $string['filename'] = 'Filename';
 $string['filenotnull'] = 'You must select a file to upload.';
 $string['filesaved'] = 'The file has been saved';
@@ -138,6 +141,7 @@ $string['off'] = 'Enabled but hidden';
 $string['openpicker'] = 'Choose a file...';
 $string['operation'] = 'Operation';
 $string['on'] = 'Enabled and visible';
+$string['overwrite'] = 'Overwrite';
 $string['personalrepositories'] = 'Available repository instances';
 $string['plugin'] = 'Repository plug-ins';
 $string['pluginerror'] = 'Errors in repository plugin.';
@@ -148,9 +152,11 @@ $string['readonlyinstance'] = 'You cannot edit/delete a read-only instance';
 $string['refresh'] = 'Refresh';
 $string['refreshnonjsfilepicker'] = 'Please close this window and refresh non-javascript file picker';
 $string['removed'] = 'Repository removed';
+$string['renameto'] = 'Rename to';
 $string['repositories'] = 'Repositories';
 $string['repository'] = 'Repository';
 $string['repositorycourse'] = 'Course repositories';
+$string['repositoryerror'] = 'Remote repository returned error: {$a}';
 $string['save'] = 'Save';
 $string['saveas'] = 'Save as';
 $string['saved'] = 'Saved';
index 3e86263..0f879fc 100644 (file)
@@ -904,7 +904,6 @@ function format_postdata_for_curlcall($postdata) {
  * Fetches content of file from Internet (using proxy if defined). Uses cURL extension if present.
  * Due to security concerns only downloads from http(s) sources are supported.
  *
- * @global object
  * @param string $url file url starting with http(s)://
  * @param array $headers http headers, null if none. If set, should be an
  *   associative array of header name => value pairs.
@@ -916,11 +915,14 @@ function format_postdata_for_curlcall($postdata) {
  * @param int $connecttimeout timeout for connection to server; this is the timeout that
  *   usually happens if the remote server is completely down (default 20 seconds);
  *   may not work when using proxy
- * @param bool $skipcertverify If true, the peer's SSL certificate will not be checked. Only use this when already in a trusted location.
- * @param string $tofile store the downloaded content to file instead of returning it
- * @return mixed false if request failed or content of the file as string if ok. true if file downloaded into $tofile successfully.
+ * @param bool $skipcertverify If true, the peer's SSL certificate will not be checked. 
+ *   Only use this when already in a trusted location.
+ * @param string $tofile store the downloaded content to file instead of returning it.
+ * @param bool $calctimeout false by default, true enables an extra head request to try and determine 
+ *   filesize and appropriately larger timeout based on $CFG->curltimeoutkbitrate
+ * @return mixed false if request failed or content of the file as string if ok. True if file downloaded into $tofile successfully.
  */
-function download_file_content($url, $headers=null, $postdata=null, $fullresponse=false, $timeout=300, $connecttimeout=20, $skipcertverify=false, $tofile=NULL) {
+function download_file_content($url, $headers=null, $postdata=null, $fullresponse=false, $timeout=300, $connecttimeout=20, $skipcertverify=false, $tofile=NULL, $calctimeout=false) {
     global $CFG;
 
     // some extra security
@@ -962,7 +964,6 @@ function download_file_content($url, $headers=null, $postdata=null, $fullrespons
         curl_setopt($ch, CURLOPT_HTTPHEADER, $headers2);
     }
 
-
     if ($skipcertverify) {
         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
     }
@@ -977,7 +978,7 @@ function download_file_content($url, $headers=null, $postdata=null, $fullrespons
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
     curl_setopt($ch, CURLOPT_HEADER, false);
     curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connecttimeout);
-    curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
+
     if (!ini_get('open_basedir') and !ini_get('safe_mode')) {
         // TODO: add version test for '7.10.5'
         curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
@@ -1033,6 +1034,37 @@ function download_file_content($url, $headers=null, $postdata=null, $fullrespons
         curl_setopt($ch, CURLOPT_WRITEFUNCTION, partial('download_file_content_write_handler', $received));
     }
 
+    if (!isset($CFG->curltimeoutkbitrate)) {
+        //use very slow rate of 56kbps as a timeout speed when not set
+        $bitrate = 56;
+    } else {
+        $bitrate = $CFG->curltimeoutkbitrate;
+    }
+
+    // try to calculate the proper amount for timeout from remote file size.
+    // if disabled or zero, we won't do any checks nor head requests.
+    if ($calctimeout && $bitrate > 0) {
+        //setup header request only options
+        curl_setopt_array ($ch, array(
+            CURLOPT_RETURNTRANSFER => false,
+            CURLOPT_NOBODY         => true)
+        );
+
+        curl_exec($ch);
+        $info = curl_getinfo($ch);
+        $err = curl_error($ch);
+
+        if ($err === '' && $info['download_content_length'] > 0) { //no curl errors
+            $timeout = max($timeout, ceil($info['download_content_length'] * 8 / ($bitrate * 1024))); //adjust for large files only - take max timeout.
+        }
+        //reinstate affected curl options
+        curl_setopt_array ($ch, array(
+            CURLOPT_RETURNTRANSFER => true,
+            CURLOPT_NOBODY         => false)
+        );
+    }
+
+    curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
     $result = curl_exec($ch);
 
     // try to detect encoding problems
index 79f9770..d2e39bb 100644 (file)
@@ -702,6 +702,7 @@ class file_storage {
         $timeout        = isset($options['timeout'])        ? $options['timeout'] : 300;
         $connecttimeout = isset($options['connecttimeout']) ? $options['connecttimeout'] : 20;
         $skipcertverify = isset($options['skipcertverify']) ? $options['skipcertverify'] : false;
+        $calctimeout    = isset($options['calctimeout'])    ? $options['calctimeout'] : false;
 
         if (!isset($file_record->filename)) {
             $parts = explode('/', $url);
@@ -714,7 +715,7 @@ class file_storage {
         if ($usetempfile) {
             check_dir_exists($this->tempdir);
             $tmpfile = tempnam($this->tempdir, 'newfromurl');
-            $content = download_file_content($url, $headers, $postdata, $fullresponse, $timeout, $connecttimeout, $skipcertverify, $tmpfile);
+            $content = download_file_content($url, $headers, $postdata, $fullresponse, $timeout, $connecttimeout, $skipcertverify, $tmpfile, $calctimeout);
             if ($content === false) {
                 throw new file_exception('storedfileproblem', 'Can not fetch file form URL');
             }
@@ -728,7 +729,7 @@ class file_storage {
             }
 
         } else {
-            $content = download_file_content($url, $headers, $postdata, $fullresponse, $timeout, $connecttimeout, $skipcertverify);
+            $content = download_file_content($url, $headers, $postdata, $fullresponse, $timeout, $connecttimeout, $skipcertverify, NULL, $calctimeout);
             if ($content === false) {
                 throw new file_exception('storedfileproblem', 'Can not fetch file form URL');
             }
index 7cae695..cf6837b 100644 (file)
@@ -595,7 +595,11 @@ M.form_filemanager.init = function(Y, options) {
                         scope: scope,
                         params: params,
                         callback: function(id, obj, args) {
-                            scope.refresh(obj.filepath);
+                            if (obj == false) {
+                                alert(M.str.repository.fileexists);
+                            } else {
+                                scope.refresh(obj.filepath);
+                            }
                             Y.one('#fm-rename-input').set('value', '');
                             scope.rename_dialog.hide();
                         }
index bad7c45..bacdf72 100644 (file)
@@ -6873,6 +6873,8 @@ function endecrypt ($pwd, $data, $case) {
  * @return string full path to plugin directory; NULL if not found
  */
 function get_plugin_directory($plugintype, $name) {
+    global $CFG;
+
     if ($plugintype === '') {
         $plugintype = 'mod';
     }
@@ -6883,6 +6885,13 @@ function get_plugin_directory($plugintype, $name) {
     }
     $name = clean_param($name, PARAM_SAFEDIR); // just in case ;-)
 
+    if (!empty($CFG->themedir) and $plugintype === 'theme') {
+        if (!is_dir($types['theme'] . '/' . $name)) {
+            // ok, so the theme is supposed to be in the $CFG->themedir
+            return $CFG->themedir . '/' . $name;
+        }
+    }
+
     return $types[$plugintype].'/'.$name;
 }
 
@@ -7079,7 +7088,7 @@ function get_plugin_types($fullpaths=true) {
                       'qtype'         => 'question/type',
                       'qformat'       => 'question/format',
                       'plagiarism'    => 'plagiarism',
-                      'theme'         => 'theme'); // this is a bit hacky, themes may be in dataroot too
+                      'theme'         => 'theme'); // this is a bit hacky, themes may be in $CFG->themedir too
 
         $mods = get_plugin_list('mod');
         foreach ($mods as $mod => $moddir) {
index 4434d7c..1e4be90 100644 (file)
@@ -829,6 +829,8 @@ class global_navigation extends navigation_node {
     protected $addedcourses = array();
     /** @var int */
     protected $expansionlimit = 0;
+    /** @var int */
+    protected $useridtouseforparentchecks = 0;
 
     /**
      * Constructs a new global navigation
@@ -875,6 +877,19 @@ class global_navigation extends navigation_node {
         }
     }
 
+    /**
+     * Mutator to set userid to allow parent to see child's profile
+     * page navigation. See MDL-25805 for initial issue. Linked to it
+     * is an issue explaining why this is a REALLY UGLY HACK thats not
+     * for you to use!
+     *
+     * @param int $userid userid of profile page that parent wants to navigate around. 
+     */
+    public function set_userid_for_parent_checks($userid) {
+        $this->useridtouseforparentchecks = $userid;
+    }
+
+
     /**
      * Initialises the navigation object.
      *
@@ -986,12 +1001,28 @@ class global_navigation extends navigation_node {
                 // If the user is not enrolled then we only want to show the
                 // course node and not populate it.
                 $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
-                // Not enrolled, can't view, and hasn't switched roles
 
+                // Not enrolled, can't view, and hasn't switched roles
                 if (!can_access_course($coursecontext)) {
-                    $coursenode->make_active();
-                    $canviewcourseprofile = false;
-                    break;
+                    // TODO: very ugly hack - do not force "parents" to enrol into course their child is enrolled in,
+                    // this hack has been propagated from user/view.php to display the navigation node. (MDL-25805)
+                    $isparent = false;
+                    if ($this->useridtouseforparentchecks) {
+                        $currentuser = ($this->useridtouseforparentchecks == $USER->id);
+                        if (!$currentuser) {
+                            $usercontext   = get_context_instance(CONTEXT_USER, $this->useridtouseforparentchecks, MUST_EXIST);
+                            if ($DB->record_exists('role_assignments', array('userid'=>$USER->id, 'contextid'=>$usercontext->id))
+                                    and has_capability('moodle/user:viewdetails', $usercontext)) {
+                                $isparent = true;
+                            }
+                        }
+                    }
+
+                    if (!$isparent) {
+                        $coursenode->make_active();
+                        $canviewcourseprofile = false;
+                        break;
+                    }
                 }
                 // Add the essentials such as reports etc...
                 $this->add_course_essentials($coursenode, $course);
index 8a65f3e..304b744 100644 (file)
@@ -1035,6 +1035,9 @@ class theme_config {
         if (file_exists("$CFG->dirroot/theme/$themename/config.php")) {
             $dir = "$CFG->dirroot/theme/$themename";
 
+        } else if (!empty($CFG->themedir) and file_exists("$CFG->themedir/$themename/config.php")) {
+            $dir = "$CFG->themedir/$themename";
+
         } else {
             return null;
         }
index ef646e6..70f05e4 100644 (file)
@@ -415,7 +415,10 @@ class page_requirements_manager {
                                                         array('cancel'), array('chooselicense', 'repository'), array('author', 'repository'),
                                                         array('ok', 'moodle'), array('error', 'moodle'), array('info', 'moodle'), array('norepositoriesavailable', 'repository'), array('norepositoriesexternalavailable', 'repository'),
                                                         array('nofilesattached', 'repository'), array('filepicker', 'repository'),
-                                                        array('nofilesavailable', 'repository')
+                                                        array('nofilesavailable', 'repository'), array('overwrite', 'repository'),
+                                                        array('renameto', 'repository'), array('fileexists', 'repository'),
+                                                        array('fileexistsdialogheader', 'repository'), array('fileexistsdialog_editor', 'repository'),
+                                                        array('fileexistsdialog_filemanager', 'repository')
                                                     ));
                     break;
                 case 'core_comment':
index 07f5bf1..4039f9a 100644 (file)
@@ -1348,9 +1348,9 @@ class table_sql extends flexible_table {
                 $this->countsql = 'SELECT COUNT(1) FROM '.$this->sql->from.' WHERE '.$this->sql->where;
                 $this->countparams = $this->sql->params;
             }
+            $grandtotal = $DB->count_records_sql($this->countsql, $this->countparams);
             if ($useinitialsbar && !$this->is_downloading()) {
-                $totalinitials = $DB->count_records_sql($this->countsql, $this->countparams);
-                $this->initialbars($totalinitials>$pagesize);
+                $this->initialbars($grandtotal > $pagesize);
             }
 
             list($wsql, $wparams) = $this->get_sql_where();
@@ -1363,7 +1363,7 @@ class table_sql extends flexible_table {
 
                 $total  = $DB->count_records_sql($this->countsql, $this->countparams);
             } else {
-                $total = $totalinitials;
+                $total = $grandtotal;
             }
 
             $this->pagesize($pagesize, $total);
index 6576056..f333b22 100644 (file)
@@ -86,6 +86,7 @@ if (has_capability('moodle/course:viewparticipants', get_context_instance(CONTEX
 }
 
 $PAGE->navigation->extend_for_user($user);
+$PAGE->navigation->set_userid_for_parent_checks($id); // see MDL-25805 for reasons and for full commit reference for reversal when fixed.
 $PAGE->set_title("$course->shortname: $fullname: $strmode");
 $PAGE->set_heading($course->fullname);
 echo $OUTPUT->header();
index 04d3fad..981a833 100644 (file)
@@ -76,6 +76,8 @@ switch ($mode) {
             }
 
             $attemptid = required_param('attemptid', PARAM_INT);
+            $score = optional_param('score', 0, PARAM_INT);
+
             if (!$attempt = $DB->get_record('lesson_attempts', array('id' => $attemptid))) {
                 print_error('cannotfindattempt', 'lesson');
             }
@@ -87,7 +89,7 @@ switch ($mode) {
             $essayinfo = unserialize($attempt->useranswer);
 
             $essayinfo->graded = 1;
-            $essayinfo->score = clean_param($form->score, PARAM_INT);
+            $essayinfo->score = $score;
             $essayinfo->response = clean_param($form->response, PARAM_RAW);
             $essayinfo->sent = 0;
             if (!$lesson->custom && $essayinfo->score == 1) {
index 1791930..b4fb01e 100644 (file)
@@ -318,7 +318,10 @@ function lesson_grade($lesson, $ntries, $userid = 0) {
                 $attempt = end($attempts);
                 // If essay question, handle it, otherwise add to score
                 if ($page->requires_manual_grading()) {
-                    $earned += $page->earned_score($answers, $attempt);
+                    $useranswerobj = unserialize($attempt->useranswer);
+                    if (isset($useranswerobj->score)) {
+                        $earned += $useranswerobj->score;
+                    }
                     $nmanual++;
                     $manualpoints += $answers[$attempt->answerid]->score;
                 } else if (!empty($attempt->answerid)) {
index 627f17c..67b8987 100644 (file)
@@ -186,7 +186,7 @@ function scorm_parse($scorm, $full) {
             if ($scorm->reference !== '' and (!$full or $scorm->sha1hash !== sha1($scorm->reference))) {
                 $fs->delete_area_files($context->id, 'mod_scorm', 'package');
                 $file_record = array('contextid'=>$context->id, 'component'=>'mod_scorm', 'filearea'=>'package', 'itemid'=>0, 'filepath'=>'/');
-                if ($packagefile = $fs->create_file_from_url($file_record, $scorm->reference)) {
+                if ($packagefile = $fs->create_file_from_url($file_record, $scorm->reference, array('calctimeout' => true))) {
                     $newhash = sha1($scorm->reference);
                 } else {
                     $newhash = null;
index ff1b340..d673401 100644 (file)
@@ -617,9 +617,17 @@ class embedded_cloze_qtype extends default_questiontype {
                 $teststateforquestion->responses[''] = '';
             }
 
-            if (!$QTYPES[$wrapped->qtype]->compare_responses($wrapped,
-                    $stateforquestion, $teststateforquestion)) {
-                return false;
+            if ($wrapped->qtype == 'numerical') {
+                // Use shortanswer
+                if (!$QTYPES['shortanswer']->compare_responses($wrapped,
+                        $stateforquestion, $teststateforquestion)) {
+                    return false;
+                }
+            } else {
+                if (!$QTYPES[$wrapped->qtype]->compare_responses($wrapped,
+                        $stateforquestion, $teststateforquestion)) {
+                    return false;
+                }
             }
         }
 
index ef0b1f0..600811e 100644 (file)
@@ -299,9 +299,14 @@ class question_numerical_qtype extends question_shortanswer_qtype {
             $options->unitsleft = 0 ;
         }
 
-        $options->instructions = $this->import_or_save_files($question->instructions,
+        if (isset($question->instructions) && is_array($question->instructions)){
+            $options->instructions = $this->import_or_save_files($question->instructions,
                     $question->context, 'qtype_'.$question->qtype , 'instruction', $question->id);
-        $options->instructionsformat = $question->instructions['format'];
+            $options->instructionsformat = $question->instructions['format'];
+        } else {
+            $options->instructions = '' ;
+            $options->instructionsformat = editors_get_preferred_format();
+        }
 
         $DB->update_record('question_numerical_options', $options);
 
index 7242f6e..15381ae 100644 (file)
@@ -123,50 +123,6 @@ class repository_coursefiles extends repository {
         return $ret;
     }
 
-    /**
-     * Copy a file to file area
-     *
-     * @global object $USER
-     * @global object $DB
-     * @param string $encoded The metainfo of file, it is base64 encoded php serialized data
-     * @param string $draftitemid itemid
-     * @param string $new_filename The intended name of file
-     * @param string $new_filepath the new path in draft area
-     * @return array The information of file
-     */
-    public function copy_to_area($encoded, $draftitemid, $new_filepath, $new_filename) {
-        global $USER, $DB;
-        $info = array();
-
-        $browser = get_file_browser();
-        $fs = get_file_storage();
-        $user_context = get_context_instance(CONTEXT_USER, $USER->id);
-
-        // the final file
-        $params = unserialize(base64_decode($encoded));
-        $contextid  = clean_param($params['contextid'], PARAM_INT);
-        $fileitemid = clean_param($params['itemid'], PARAM_INT);
-        $filename = clean_param($params['filename'], PARAM_FILE);
-        $filepath = clean_param($params['filepath'], PARAM_PATH);;
-        $filearea = clean_param($params['filearea'], PARAM_ALPHAEXT);
-        $component = clean_param($params['component'], PARAM_ALPHAEXT);
-        $context = get_context_instance_by_id($contextid);
-
-        if ($existingfile = $fs->get_file($user_context->id, 'user', 'draft', $draftitemid, $new_filepath, $new_filename)) {
-            throw new moodle_exception('fileexists');
-        }
-
-        $file_info = $browser->get_file_info($context, $component, $filearea, $fileitemid, $filepath, $filename);
-        $file_info->copy_to_storage($user_context->id, 'user', 'draft', $draftitemid, $new_filepath, $new_filename);
-
-        $info['itemid'] = $draftitemid;
-        $info['title']  = $new_filename;
-        $info['contextid'] = $user_context->id;
-        $info['filesize'] = $file_info->get_filesize();
-
-        return $info;
-    }
-
     public function get_link($encoded) {
         $info = array();
 
@@ -216,4 +172,13 @@ class repository_coursefiles extends repository {
     public static function get_type_option_names() {
         return array();
     }
+
+    /**
+     * Does this repository used to browse moodle files?
+     *
+     * @return boolean
+     */
+    public function has_moodle_files() {
+        return true;
+    }
 }
index 68c8b9b..9086015 100644 (file)
@@ -66,7 +66,7 @@ class repository_dropbox extends repository {
             'oauth_consumer_key'=>$this->dropbox_key,
             'oauth_consumer_secret'=>$this->dropbox_secret,
             'oauth_callback' => $this->callback->out(false),
-            'api_root' => 'http://api.dropbox.com/0/oauth',
+            'api_root' => 'http://www.dropbox.com/0/oauth',
         );
 
         $this->dropbox = new dropbox($args);
@@ -163,10 +163,16 @@ class repository_dropbox extends repository {
             }
         }
 
-        $files = $result->contents;
-        if (!is_array($files) || empty($files)) {
+        if (!empty($result->error)) {
+            // reset access key
+            set_user_preference($this->setting.'_access_key', '');
+            set_user_preference($this->setting.'_access_secret', '');
+            throw new repository_exception('repositoryerror', 'repository', '', $result->error);
+        }
+        if (empty($result->contents) or !is_array($result->contents)) {
             return $list;
         }
+        $files = $result->contents;
         foreach ($files as $file) {
             if ($file->is_dir) {
                 $list['list'][] = array(
index 1be291a..a0f9052 100644 (file)
@@ -85,7 +85,11 @@ M.core_filepicker.init = function(Y, options) {
 
         request: function(args, redraw) {
             var client_id = args.client_id;
-            var api = this.api + '?action='+args.action;
+            if (!args.api) {
+                var api = this.api + '?action='+args.action;
+            } else {
+                var api = args.api + '?action='+args.action;
+            }
             var params = {};
             var scope = this;
             if (args['scope']) {
@@ -147,6 +151,14 @@ M.core_filepicker.init = function(Y, options) {
                             scope.print_msg(data.error, 'error');
                             scope.list();
                             return;
+                        } else if (data && data.event) {
+                            switch (data.event) {
+                                case 'fileexists':
+                                    scope.process_existing_file(data);
+                                    break;
+                                default:
+                                    break;
+                            }
                         } else {
                             if (data.msg) {
                                 scope.print_msg(data.msg, 'info');
@@ -172,6 +184,94 @@ M.core_filepicker.init = function(Y, options) {
                 this.wait('load');
             }
         },
+        process_existing_file: function(data) {
+            var scope = this;
+            var repository_id = scope.active_repo.id;
+            var client_id = scope.options.client_id;
+            var handleOverwrite = function() {
+                // overwrite
+                var dialog = this;
+                var params = {}
+                params['existingfilename'] = data.existingfile.filename;
+                params['existingfilepath'] = data.existingfile.filepath;
+                params['newfilename'] = data.newfile.filename;
+                params['newfilepath'] = data.newfile.filepath;
+                scope.request({
+                    'params': params,
+                    'scope': scope,
+                    'action':'overwrite',
+                    'path': '',
+                    'client_id': client_id,
+                    'repository_id': repository_id,
+                    'callback': function(id, o, args) {
+                        dialog.cancel();
+                        scope.hide();
+                        // editor needs to update url
+                        // filemanager do nothing
+                        if (scope.options.editor_target && scope.options.env == 'editor') {
+                            scope.options.editor_target.value = data.existingfile.url;
+                            scope.options.editor_target.onchange();
+                        }
+                    }
+                }, true);
+            }
+            var handleRename = function() {
+                if (scope.options.editor_target && scope.options.env == 'editor') {
+                    scope.options.editor_target.value = data.newfile.url;
+                    scope.options.editor_target.onchange();
+                }
+                this.cancel();
+                scope.hide();
+                data.client_id = client_id;
+                var formcallback_scope = null;
+                if (scope.options.magicscope) {
+                    formcallback_scope = scope.options.magicscope;
+                } else {
+                    formcallback_scope = scope;
+                }
+                scope.options.formcallback.apply(formcallback_scope, [data]);
+            }
+            var handleCancel = function() {
+                // Delete tmp file
+                var dialog = this;
+                var params = {};
+                params['newfilename'] = data.newfile.filename;
+                params['newfilepath'] = data.newfile.filepath;
+                scope.request({
+                    'params': params,
+                    'scope': scope,
+                    'action':'deletetmpfile',
+                    'path': '',
+                    'client_id': client_id,
+                    'repository_id': repository_id,
+                    'callback': function(id, o, args) {
+                        scope.hide();
+                        dialog.cancel();
+                    }
+                }, true);
+            }
+            var dialog = new YAHOO.widget.SimpleDialog("dlg", {
+                width: "50em",
+                fixedcenter: true,
+                modal: true,
+                close: false,
+                icon: YAHOO.widget.SimpleDialog.ICON_HELP,
+                visible: true,
+                draggable: true,
+                buttons: [{ text: M.str.repository.overwrite, handler: handleOverwrite },
+                { text: M.str.repository.renameto + ' "' + data.newfile.filename + '"', handler: handleRename },
+                { text: M.str.moodle.cancel, handler: handleCancel, isDefault: true}]
+            });
+            dialog.setHeader(M.str.repository.fileexistsdialogheader);
+            if (scope.options.env == 'editor') {
+                dialog.setBody(M.str.repository.fileexistsdialog_editor);
+            } else {
+                dialog.setBody(M.str.repository.fileexistsdialog_filemanager);
+            }
+
+            dialog.render(document.body);
+            dialog.show();
+        },
         print_msg: function(msg, type) {
             var client_id = this.options.client_id;
             var dlg_id = 'fp-msg-dlg-'+client_id;
@@ -1113,7 +1213,6 @@ M.core_filepicker.init = function(Y, options) {
                 this.print_paging('header');
             //}
 
-
             var toolbar = Y.one('#repo-tb-'+client_id);
 
             if(!r.nosearch) {
index 70c58d6..82a1b6a 100644 (file)
@@ -33,6 +33,7 @@ require_once($CFG->libdir . '/formslib.php');
 
 define('FILE_EXTERNAL', 1);
 define('FILE_INTERNAL', 2);
+define('RENAME_SUFFIX', '_2');
 
 /**
  * This class is used to manage repository plugins
@@ -586,6 +587,125 @@ abstract class repository {
         }
     }
 
+    /**
+     * Check if file already exists in draft area
+     *
+     * @param int $itemid
+     * @param string $filepath
+     * @param string $filename
+     * @return boolean
+     */
+    public static function draftfile_exists($itemid, $filepath, $filename) {
+        global $USER;
+        $fs = get_file_storage();
+        $usercontext = get_context_instance(CONTEXT_USER, $USER->id);
+        if ($fs->get_file($usercontext->id, 'user', 'draft', $itemid, $filepath, $filename)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Does this repository used to browse moodle files?
+     *
+     * @return boolean
+     */
+    public function has_moodle_files() {
+        return false;
+    }
+    /**
+     * This function is used to copy a moodle file to draft area
+     *
+     * @global object $USER
+     * @global object $DB
+     * @param string $encoded The metainfo of file, it is base64 encoded php serialized data
+     * @param string $draftitemid itemid
+     * @param string $new_filename The intended name of file
+     * @param string $new_filepath the new path in draft area
+     * @return array The information of file
+     */
+    public function copy_to_area($encoded, $draftitemid, $new_filepath, $new_filename) {
+        global $USER, $DB;
+
+        if ($this->has_moodle_files() == false) {
+            throw new coding_exception('Only repository used to browse moodle files can use copy_to_area');
+        }
+
+        $browser = get_file_browser();
+        $params = unserialize(base64_decode($encoded));
+        $user_context = get_context_instance(CONTEXT_USER, $USER->id);
+
+        $contextid  = clean_param($params['contextid'], PARAM_INT);
+        $fileitemid = clean_param($params['itemid'],    PARAM_INT);
+        $filename   = clean_param($params['filename'],  PARAM_FILE);
+        $filepath   = clean_param($params['filepath'],  PARAM_PATH);;
+        $filearea   = clean_param($params['filearea'],  PARAM_ALPHAEXT);
+        $component  = clean_param($params['component'], PARAM_ALPHAEXT);
+
+        $context    = get_context_instance_by_id($contextid);
+        // the file needs to copied to draft area
+        $file_info  = $browser->get_file_info($context, $component, $filearea, $fileitemid, $filepath, $filename);
+
+        if (repository::draftfile_exists($draftitemid, $new_filepath, $new_filename)) {
+            // create new file
+            $unused_filename = repository::get_unused_filename($draftitemid, $new_filepath, $new_filename);
+            $file_info->copy_to_storage($user_context->id, 'user', 'draft', $draftitemid, $new_filepath, $unused_filename);
+            $event = array();
+            $event['event'] = 'fileexists';
+            $event['newfile'] = new stdClass;
+            $event['newfile']->filepath = $new_filepath;
+            $event['newfile']->filename = $unused_filename;
+            $event['newfile']->url = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $unused_filename)->out();
+            $event['existingfile'] = new stdClass;
+            $event['existingfile']->filepath = $new_filepath;
+            $event['existingfile']->filename = $new_filename;
+            $event['existingfile']->url      = moodle_url::make_draftfile_url($draftitemid, $filepath, $filename)->out();;
+            return $event;
+        } else {
+            $file_info->copy_to_storage($user_context->id, 'user', 'draft', $draftitemid, $new_filepath, $new_filename);
+            $info = array();
+            $info['itemid'] = $draftitemid;
+            $info['title']  = $new_filename;
+            $info['contextid'] = $user_context->id;
+            $info['url'] = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out();;
+            $info['filesize'] = $file_info->get_filesize();
+            return $info;
+        }
+    }
+
+    /**
+     * Get unused filename by appending suffix
+     *
+     * @param int $itemid
+     * @param string $filepath
+     * @param string $filename
+     * @return string
+     */
+    public static function get_unused_filename($itemid, $filepath, $filename) {
+        global $USER;
+        $fs = get_file_storage();
+        while (repository::draftfile_exists($itemid, $filepath, $filename)) {
+            $filename = repository::append_suffix($filename);
+        }
+        return $filename;
+    }
+
+    /**
+     * Append a suffix to filename
+     *
+     * @param string $filename
+     * @return string
+     */
+    function append_suffix($filename) {
+        $pathinfo = pathinfo($filename);
+        if (empty($pathinfo['extension'])) {
+            return $filename . RENAME_SUFFIX;
+        } else {
+            return $pathinfo['filename'] . RENAME_SUFFIX . '.' . $pathinfo['extension'];
+        }
+    }
+
     /**
      * Return all types that you a user can create/edit and which are also visible
      * Note: Mostly used in order to know if at least one editable type can be set
@@ -861,7 +981,24 @@ abstract class repository {
         }
         $fs = get_file_storage();
         if ($existingfile = $fs->get_file($context->id, $record->component, $record->filearea, $record->itemid, $record->filepath, $record->filename)) {
-            throw new moodle_exception('fileexists');
+            $draftitemid = $record->itemid;
+            $new_filename = repository::get_unused_filename($draftitemid, $record->filepath, $record->filename);
+            $old_filename = $record->filename;
+            // create a tmp file
+            $record->filename = $new_filename;
+            $newfile = $fs->create_file_from_pathname($record, $thefile);
+            $event = array();
+            $event['event'] = 'fileexists';
+            $event['newfile'] = new stdClass;
+            $event['newfile']->filepath = $record->filepath;
+            $event['newfile']->filename = $new_filename;
+            $event['newfile']->url = moodle_url::make_draftfile_url($draftitemid, $record->filepath, $new_filename)->out();
+
+            $event['existingfile'] = new stdClass;
+            $event['existingfile']->filepath = $record->filepath;
+            $event['existingfile']->filename = $old_filename;
+            $event['existingfile']->url      = moodle_url::make_draftfile_url($draftitemid, $record->filepath, $old_filename)->out();;
+            return $event;
         }
         if ($file = $fs->create_file_from_pathname($record, $thefile)) {
             if (empty($CFG->repository_no_delete)) {
@@ -1552,6 +1689,54 @@ abstract class repository {
             return $str;
         }
     }
+
+    /**
+     * Overwrite an existing file
+     *
+     * @param int $itemid
+     * @param string $filepath
+     * @param string $filename
+     * @param string $newfilepath
+     * @param string $newfilename
+     * @return boolean
+     */
+    function overwrite_existing_draftfile($itemid, $filepath, $filename, $newfilepath, $newfilename) {
+        global $USER;
+        $fs = get_file_storage();
+        $user_context = get_context_instance(CONTEXT_USER, $USER->id);
+        if ($file = $fs->get_file($user_context->id, 'user', 'draft', $itemid, $filepath, $filename)) {
+            if ($tempfile = $fs->get_file($user_context->id, 'user', 'draft', $itemid, $newfilepath, $newfilename)) {
+                // delete existing file to release filename
+                $file->delete();
+                // create new file
+                $newfile = $fs->create_file_from_storedfile(array('filepath'=>$filepath, 'filename'=>$filename), $tempfile);
+                // remove temp file
+                $tempfile->delete();
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Delete a temp file from draft area
+     *
+     * @param int $draftitemid
+     * @param string $filepath
+     * @param string $filename
+     * @return boolean
+     */
+    function delete_tempfile_from_draft($draftitemid, $filepath, $filename) {
+        global $USER;
+        $fs = get_file_storage();
+        $user_context = get_context_instance(CONTEXT_USER, $USER->id);
+        if ($file = $fs->get_file($user_context->id, 'user', 'draft', $draftitemid, $filepath, $filename)) {
+            $file->delete();
+            return true;
+        } else {
+            return false;
+        }
+    }
 }
 
 /**
@@ -1835,3 +2020,12 @@ function initialise_filepicker($args) {
     }
     return $return;
 }
+/**
+ * Small function to walk an array to attach repository ID
+ * @param array $value
+ * @param string $key
+ * @param int $id
+ */
+function repository_attach_id(&$value, $key, $id){
+    $value['repo_id'] = $id;
+}
index 91b0d45..ab374d6 100644 (file)
@@ -162,49 +162,11 @@ class repository_local extends repository {
     }
 
     /**
-     * Copy a file to file area
+     * Does this repository used to browse moodle files?
      *
-     * @global object $USER
-     * @global object $DB
-     * @param string $encoded The metainfo of file, it is base64 encoded php serialized data
-     * @param string $draftitemid itemid
-     * @param string $new_filename The intended name of file
-     * @param string $new_filepath the new path in draft area
-     * @return array The information of file
+     * @return boolean
      */
-    public function copy_to_area($encoded, $draftitemid, $new_filepath, $new_filename) {
-        global $USER, $DB;
-        $info = array();
-
-        $browser = get_file_browser();
-        $fs = get_file_storage();
-        $user_context = get_context_instance(CONTEXT_USER, $USER->id);
-
-        // the final file
-        $params = unserialize(base64_decode($encoded));
-        $contextid  = clean_param($params['contextid'], PARAM_INT);
-        $fileitemid = clean_param($params['itemid'], PARAM_INT);
-        $filename = clean_param($params['filename'], PARAM_FILE);
-        $filepath = clean_param($params['filepath'], PARAM_PATH);;
-        $filearea = clean_param($params['filearea'], PARAM_ALPHAEXT);
-        $component = clean_param($params['component'], PARAM_ALPHAEXT);
-        $context = get_context_instance_by_id($contextid);
-
-        if ($existingfile = $fs->get_file($user_context->id, 'user', 'draft', $draftitemid, $new_filepath, $new_filename)) {
-            throw new moodle_exception('fileexists');
-        }
-
-        $file_info = $browser->get_file_info($context, $component, $filearea, $fileitemid, $filepath, $filename);
-        $file_info->copy_to_storage($user_context->id, 'user', 'draft', $draftitemid, $new_filepath, $new_filename);
-
-        $info['itemid'] = $draftitemid;
-        $info['title']  = $new_filename;
-        $info['contextid'] = $user_context->id;
-        $info['filesize'] = $file_info->get_filesize();
-
-        return $info;
-    }
-    function get_file_count($contextid) {
-        global $DB;
+    public function has_moodle_files() {
+        return true;
     }
 }
index 2176940..114a9a3 100644 (file)
@@ -137,7 +137,7 @@ class repository_recent extends repository {
         return FILE_INTERNAL;
     }
     /**
-     * Copy a file to file area
+     * This function overwrite the default implement to copying file using file_storage
      *
      * @global object $USER
      * @global object $DB
@@ -157,11 +157,11 @@ class repository_recent extends repository {
         $params = unserialize(base64_decode($encoded));
 
         $contextid  = clean_param($params['contextid'], PARAM_INT);
-        $fileitemid = clean_param($params['itemid'], PARAM_INT);
-        $filename = clean_param($params['filename'], PARAM_FILE);
-        $filepath = clean_param($params['filepath'], PARAM_PATH);;
-        $filearea = clean_param($params['filearea'], PARAM_ALPHAEXT);
-        $component = clean_param($params['component'], PARAM_ALPHAEXT);
+        $fileitemid = clean_param($params['itemid'],    PARAM_INT);
+        $filename   = clean_param($params['filename'],  PARAM_FILE);
+        $filepath   = clean_param($params['filepath'],  PARAM_PATH);;
+        $filearea   = clean_param($params['filearea'],  PARAM_ALPHAEXT);
+        $component  = clean_param($params['component'], PARAM_ALPHAEXT);
 
         // XXX:
         // When user try to pick a file from other filearea, normally file api will use file browse to
@@ -171,28 +171,52 @@ class repository_recent extends repository {
         // To get 'recent' plugin working, we need to use lower level file_stoarge class to bypass the
         // capability check, we will use a better workaround to improve it.
         if ($stored_file = $fs->get_file($contextid, $component, $filearea, $fileitemid, $filepath, $filename)) {
+            // verify user id
             if ($USER->id != $stored_file->get_userid()) {
                 throw new moodle_exception('errornotyourfile', 'repository');
             }
             $file_record = array('contextid'=>$user_context->id, 'component'=>'user', 'filearea'=>'draft',
                 'itemid'=>$draftitemid, 'filepath'=>$new_filepath, 'filename'=>$new_filename, 'sortorder'=>0);
-            if ($file = $fs->get_file($user_context->id, 'user', 'draft', $draftitemid, $new_filepath, $new_filename)) {
+
+            // test if file already exists
+            if (repository::draftfile_exists($draftitemid, $new_filepath, $new_filename)) {
+                // create new file
+                $unused_filename = repository::get_unused_filename($draftitemid, $new_filepath, $new_filename);
+                $file_record['filename'] = $unused_filename;
+                // create a tmp file
+                $fs->create_file_from_storedfile($file_record, $stored_file);
+                $event = array();
+                $event['event'] = 'fileexists';
+                $event['newfile'] = new stdClass;
+                $event['newfile']->filepath = $new_filepath;
+                $event['newfile']->filename = $unused_filename;
+                $event['newfile']->url = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $unused_filename)->out();
+                $event['existingfile'] = new stdClass;
+                $event['existingfile']->filepath = $new_filepath;
+                $event['existingfile']->filename = $new_filename;
+                $event['existingfile']->url      = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out();;
+                return $event;
+            } else {
+                $fs->create_file_from_storedfile($file_record, $stored_file);
                 $info = array();
-                $info['title']  = $file->get_filename();
-                $info['itemid'] = $file->get_itemid();
-                $info['filesize']  = $file->get_filesize();
-                $info['contextid'] = $file->get_contextid();
+                $info['title']  = $new_filename;
+                $info['itemid'] = $draftitemid;
+                $info['filesize']  = $stored_file->get_filesize();
+                $info['url'] = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out();;
+                $info['contextid'] = $user_context->id;
                 return $info;
             }
-            $fs->create_file_from_storedfile($file_record, $stored_file);
         }
+        return false;
 
-        $info = array();
-        $info['title']  = $new_filename;
-        $info['itemid'] = $draftitemid;
-        $info['filesize']  = $stored_file->get_filesize();
-        $info['contextid'] = $user_context->id;
+    }
 
-        return $info;
+    /**
+     * Does this repository used to browse moodle files?
+     *
+     * @return boolean
+     */
+    public function has_moodle_files() {
+        return true;
     }
 }
index a2d354c..7f0e127 100644 (file)
@@ -201,17 +201,12 @@ switch ($action) {
             echo json_encode($info);
             die;
         } else {
-            if (in_array($repo->options['type'], array('local', 'recent', 'user', 'coursefiles'))) { //TODO: this hardcoding is a really ugly hack (skodak)
+            // some repository plugins deal with moodle internal files, so we cannot use get_file
+            // method, so we use copy_to_area method
+            // (local, user, coursefiles, recent)
+            if ($repo->has_moodle_files()) {
                 $fileinfo = $repo->copy_to_area($source, $itemid, $saveas_path, $saveas_filename);
-                $info = array();
-                $info['file'] = $fileinfo['title'];
-                $info['id'] = $itemid;
-                $info['url'] = $CFG->httpswwwroot.'/draftfile.php/'.$fileinfo['contextid'].'/user/draft/'.$itemid.'/'.$fileinfo['title'];
-                $filesize = $fileinfo['filesize'];
-                if (($maxbytes!==-1) && ($filesize>$maxbytes)) {
-                    throw new file_exception('maxbytes');
-                }
-                echo json_encode($info);
+                echo json_encode($fileinfo);
                 die;
             }
             // Download file to moodle
@@ -266,14 +261,23 @@ switch ($action) {
             die;
         }
         break;
-}
 
-/**
- * Small function to walk an array to attach repository ID
- * @param array $value
- * @param string $key
- * @param int $id
- */
-function repository_attach_id(&$value, $key, $id){
-    $value['repo_id'] = $id;
+    case 'overwrite':
+        // existing file
+        $filepath    = required_param('existingfilepath', PARAM_PATH);
+        $filename    = required_param('existingfilename', PARAM_FILE);
+        // user added file which needs to replace the existing file
+        $newfilepath = required_param('newfilepath', PARAM_PATH);
+        $newfilename = required_param('newfilename', PARAM_FILE);
+
+        echo json_encode(repository::overwrite_existing_draftfile($itemid, $filepath, $filename, $newfilepath, $newfilename));
+        break;
+
+    case 'deletetmpfile':
+        // delete tmp file
+        $newfilepath = required_param('newfilepath', PARAM_PATH);
+        $newfilename = required_param('newfilename', PARAM_FILE);
+        echo json_encode(repository::delete_tempfile_from_draft($itemid, $newfilepath, $newfilename));
+
+        break;
 }
index 3619d4f..8285042 100644 (file)
@@ -140,21 +140,35 @@ class repository_upload extends repository {
         if (($maxbytes!==-1) && (filesize($_FILES[$elname]['tmp_name']) > $maxbytes)) {
             throw new file_exception('maxbytes');
         }
-
-        if ($file = $fs->get_file($context->id, $record->component, $record->filearea, $record->itemid, $record->filepath, $record->filename)) {
-            throw new moodle_exception('fileexists', 'repository');
-        }
-
         $record->contextid = $context->id;
         $record->userid    = $USER->id;
         $record->source    = '';
 
-        $stored_file = $fs->create_file_from_pathname($record, $_FILES[$elname]['tmp_name']);
+        if (repository::draftfile_exists($record->itemid, $record->filepath, $record->filename)) {
+            $existingfilename = $record->filename;
+            $unused_filename = repository::get_unused_filename($record->itemid, $record->filepath, $record->filename);
+            $record->filename = $unused_filename;
+            $stored_file = $fs->create_file_from_pathname($record, $_FILES[$elname]['tmp_name']);
+            $event = array();
+            $event['event'] = 'fileexists';
+            $event['newfile'] = new stdClass;
+            $event['newfile']->filepath = $record->filepath;
+            $event['newfile']->filename = $unused_filename;
+            $event['newfile']->url = moodle_url::make_draftfile_url($record->itemid, $record->filepath, $unused_filename)->out();
+
+            $event['existingfile'] = new stdClass;
+            $event['existingfile']->filepath = $record->filepath;
+            $event['existingfile']->filename = $existingfilename;
+            $event['existingfile']->url      = moodle_url::make_draftfile_url($record->itemid, $record->filepath, $existingfilename)->out();;
+            return $event;
+        } else {
+            $stored_file = $fs->create_file_from_pathname($record, $_FILES[$elname]['tmp_name']);
 
-        return array(
-            'url'=>moodle_url::make_draftfile_url($record->itemid, $record->filepath, $record->filename)->out(),
-            'id'=>$record->itemid,
-            'file'=>$record->filename);
+            return array(
+                'url'=>moodle_url::make_draftfile_url($record->itemid, $record->filepath, $record->filename)->out(),
+                'id'=>$record->itemid,
+                'file'=>$record->filename);
+        }
     }
 
     /**
@@ -180,16 +194,4 @@ class repository_upload extends repository {
     public function supported_returntypes() {
         return FILE_INTERNAL;
     }
-
-    /**
-     * Upload file to local filesystem pool
-     * @param string $elname name of element
-     * @param string $filearea
-     * @param string $filepath
-     * @param string $filename - use specified filename, if not specified name of uploaded file used
-     * @param bool $override override file if exists
-     * @return mixed stored_file object or false if error; may throw exception if duplicate found
-     */
-    public function upload_to_filepool($elname, $record, $override = true) {
-    }
 }
index 25e62f0..38d6d1b 100644 (file)
@@ -125,40 +125,11 @@ class repository_user extends repository {
     }
 
     /**
-     * Copy a file to file area
+     * Does this repository used to browse moodle files?
      *
-     * @global object $USER
-     * @global object $DB
-     * @param string $encoded The metainfo of file, it is base64 encoded php serialized data
-     * @param string $draftitemid itemid
-     * @param string $new_filename The intended name of file
-     * @param string $new_filepath the new path in draft area
-     * @return array The information of file
+     * @return boolean
      */
-    public function copy_to_area($encoded, $draftitemid, $new_filepath, $new_filename) {
-        global $USER, $DB;
-
-        $browser = get_file_browser();
-        $params = unserialize(base64_decode($encoded));
-        $user_context = get_context_instance(CONTEXT_USER, $USER->id);
-
-        $contextid  = clean_param($params['contextid'], PARAM_INT);
-        $fileitemid = clean_param($params['itemid'], PARAM_INT);
-        $filename = clean_param($params['filename'], PARAM_FILE);
-        $filepath = clean_param($params['filepath'], PARAM_PATH);;
-        $filearea = clean_param($params['filearea'], PARAM_ALPHAEXT);
-        $component = clean_param($params['component'], PARAM_ALPHAEXT);
-
-        $context    = get_context_instance_by_id($contextid);
-        $file_info = $browser->get_file_info($context, $component, $filearea, $fileitemid, $filepath, $filename);
-        $file_info->copy_to_storage($user_context->id, 'user', 'draft', $draftitemid, $new_filepath, $new_filename);
-
-        $info = array();
-        $info['itemid'] = $draftitemid;
-        $info['title']  = $new_filename;
-        $info['contextid'] = $user_context->id;
-        $info['filesize'] = $file_info->get_filesize();
-
-        return $info;
+    public function has_moodle_files() {
+        return true;
     }
 }
index 9048711..7c5fa8c 100644 (file)
@@ -7,7 +7,8 @@ $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);
-
+$custommenu = $OUTPUT->custom_menu();
+$hascustommenu = (empty($PAGE->layout_options['nocustommenu']) && !empty($custommenu));
 
 $bodyclasses = array();
 if ($showsidepre && !$showsidepost) {
@@ -17,6 +18,9 @@ if ($showsidepre && !$showsidepost) {
 } else if (!$showsidepost && !$showsidepre) {
     $bodyclasses[] = 'content-only';
 }
+if ($hascustommenu) {
+    $bodyclasses[] = 'has_custom_menu';
+}
 
 echo $OUTPUT->doctype() ?>
 <html <?php echo $OUTPUT->htmlattributes() ?>>
@@ -42,6 +46,11 @@ echo $OUTPUT->doctype() ?>
             }
             echo $PAGE->headingmenu
         ?></div><?php } ?>
+        
+        <?php if ($hascustommenu) { ?>
+       <div id="custommenu"><?php echo $custommenu; ?></div>
+               <?php } ?>
+        
         <?php if ($hasnavbar) { ?>
             <div class="navbar clearfix">
                 <div class="breadcrumb"><?php echo $OUTPUT->navbar(); ?></div>
index 53c368a..b7b3478 100644 (file)
@@ -5,12 +5,16 @@ $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);
-
+$custommenu = $OUTPUT->custom_menu();
+$hascustommenu = (empty($PAGE->layout_options['nocustommenu']) && !empty($custommenu));
 
 $bodyclasses = array();
 if (!$showsidepre) {
     $bodyclasses[] = 'content-only';
 }
+if ($hascustommenu) {
+    $bodyclasses[] = 'has_custom_menu';
+}
 
 echo $OUTPUT->doctype() ?>
 <html <?php echo $OUTPUT->htmlattributes() ?>>
@@ -36,6 +40,11 @@ echo $OUTPUT->doctype() ?>
             }
             echo $PAGE->headingmenu
         ?></div><?php } ?>
+        
+        <?php if ($hascustommenu) { ?>
+       <div id="custommenu"><?php echo $custommenu; ?></div>
+               <?php } ?>
+        
         <?php if ($hasnavbar) { ?>
             <div class="navbar clearfix">
                 <div class="breadcrumb"><?php echo $OUTPUT->navbar(); ?></div>
index b850a89..17a738e 100644 (file)
@@ -221,3 +221,31 @@ html, body {background-color:#C8C9C7;}
 /** Overide for RTL layout **/
 .dir-rtl #page-header .navbar .breadcrumb {float:right;}
 .dir-rtl #page-header .navbar .navbutton {float:left;}
+
+/** Custom menu **/
+/*YUI Reset */
+.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menu-content,
+.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menu-label,
+.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menu-label-active,
+.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menuitem-active .yui3-menuitem-content,
+.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menu-label-menuvisible {background-position: -10000px -10000px;}
+.yui3-skin-sam #page .yui3-menu-label,
+.yui3-skin-sam #page .yui3-menu .yui3-menu .yui3-menu-label,
+.yui3-skin-sam #page .yui3-menubuttonnav .yui3-menu-label em { background-position: right center; }
+.yui3-skin-sam #page .yui3-splitbuttonnav .yui3-menu-label .yui3-menu-toggle {background-position: 3px center;}
+.yui3-skin-sam #page .yui3-splitbuttonnav .yui3-menu-label-menuvisible .yui3-menu-toggle {background-position: 0% 50%;}
+#custommenu {clear: both;padding-left: 4px;margin-bottom: 0px;padding-bottom: 2px;}
+.yui3-skin-sam #page .yui3-menu-label,
+.yui3-skin-sam #page .yui3-menuitem-content  {color: #fff;font-weight: 800;line-height: 30px;}
+.yui3-skin-sam #page .custom_menu_submenu .yui3-menu-label,
+.yui3-skin-sam #page .custom_menu_submenu .yui3-menuitem-content {color: #000 !important;text-shadow: none !important;line-height: 25px;}
+.yui3-skin-sam #page .yui3-menu-label.yui3-menu-label-active,
+.yui3-skin-sam #page .yui3-menuitem-active .yui3-menuitem-content {color: #000;background-color: #697F55;}
+.yui3-skin-sam #page .yui3-menu-content,
+.yui3-skin-sam #page .yui3-menu .yui3-menu .yui3-menu-content,
+.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menu-label,
+.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menuitem-content  {border: none !important;}
+.yui3-skin-sam .yui3-menu-horizontal .yui3-menu-label,
+.yui3-skin-sam .yui3-menu-horizontal .yui3-menuitem-content {border-color:#808080;border-style:solid;border-width:0px 0;}
+
+#page .custom_menu_submenu {border: 1px solid #697F55 !important;-webkit-border-bottom-right-radius: 5px;-webkit-border-bottom-left-radius: 5px;-moz-border-radius-bottomright: 5px;-moz-border-radius-bottomleft: 5px;border-bottom-right-radius: 5px;border-bottom-left-radius: 5px;}
\ No newline at end of file
index 12e94f9..fc54123 100644 (file)
@@ -5,6 +5,8 @@ $hassidepost = (empty($PAGE->layout_options['noblocks']) && $PAGE->blocks->regio
 
 $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));
 
 $bodyclasses = array();
 if ($showsidepre && !$showsidepost) {
@@ -17,6 +19,9 @@ if ($showsidepre && !$showsidepost) {
 if ($hassidepre || $hassidepost) {
        $bodyclasses[] = 'background';
 }
+if ($hascustommenu) {
+    $bodyclasses[] = 'has_custom_menu';
+}
 
 echo $OUTPUT->doctype() ?>
 <html <?php echo $OUTPUT->htmlattributes() ?>>
@@ -46,7 +51,9 @@ echo $OUTPUT->doctype() ?>
                </div>
            </div>
     </div>
-
+<?php if ($hascustommenu) { ?>
+       <div id="custommenu"><?php echo $custommenu; ?></div>
+<?php } ?>
 <!-- END OF HEADER -->
 
 <!-- START OF CONTENT -->
index 367f4d9..11f205f 100644 (file)
@@ -8,6 +8,8 @@ $hassidepost = (empty($PAGE->layout_options['noblocks']) && $PAGE->blocks->regio
 
 $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));
 
 $bodyclasses = array();
 if ($showsidepre && !$showsidepost) {
@@ -17,7 +19,9 @@ if ($showsidepre && !$showsidepost) {
 } else if (!$showsidepost && !$showsidepre) {
     $bodyclasses[] = 'content-only';
 }
-
+if ($hascustommenu) {
+    $bodyclasses[] = 'has_custom_menu';
+}
 echo $OUTPUT->doctype() ?>
 <html <?php echo $OUTPUT->htmlattributes() ?>>
 <head>
@@ -48,6 +52,10 @@ echo $OUTPUT->doctype() ?>
                <?php } ?>
 
     </div>
+    
+       <?php if ($hascustommenu) { ?>
+       <div id="custommenu"><?php echo $custommenu; ?></div>
+       <?php } ?>
 
     <?php if ($hasnavbar) { ?>
            <div class="navbar clearfix">
index 0f1918a..f57325a 100644 (file)
@@ -48,11 +48,19 @@ a:hover {
     margin-bottom: 5px;
 }
 
+.has_custom_menu #page-header {
+    margin-bottom: 0px;
+}
+
 .headermain { 
     font-weight: normal;
     margin: 1em 0.5em 0.75em;
 }
 
+#page-content {
+    float: none;
+}
+
 /* Footer
 -------------------------*/
 #page-footer {
@@ -230,4 +238,70 @@ body.has_dock {
 #dockeditempanel .dockeditempanel_hd h2 { 
     font-size: 1em;
     color: #fff;
+}
+
+/*cutom menu */
+/*YUI Reset */
+.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menu-content,
+.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menu-label,
+.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menu-label-active,
+.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menuitem-active .yui3-menuitem-content,
+.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menu-label-menuvisible {background-position: -10000px -10000px;}
+.yui3-skin-sam #page .yui3-menu-label,
+.yui3-skin-sam #page .yui3-menu .yui3-menu .yui3-menu-label,
+.yui3-skin-sam #page .yui3-menubuttonnav .yui3-menu-label em {background-position: right center;}
+.yui3-skin-sam #page .yui3-splitbuttonnav .yui3-menu-label .yui3-menu-toggle {background-position: 3px center;}
+.yui3-skin-sam #page .yui3-splitbuttonnav .yui3-menu-label-menuvisible .yui3-menu-toggle {background-position: 0% 50%;}
+
+#custommenu {
+    clear: both;
+    background-image: url([[pix:theme|headingblock]]);
+    margin-bottom: 5px;
+}
+
+.yui3-skin-sam #page .yui3-menu-label,
+.yui3-skin-sam #page .yui3-menuitem-content  {
+    color: #fff;
+    font-weight: 800;
+    line-height: 30px;
+}
+
+.custom_menu_submenu .yui3-menu-label,
+.custom_menu_submenu .yui3-menuitem-content {
+    color: #000 !important;
+    text-shadow: none !important;
+    line-height: 25px;
+}
+
+.yui3-skin-sam #page .yui3-menu-label.yui3-menu-label-active,
+.yui3-skin-sam #page .yui3-menu-label.yui3-menu-label-menuvisible,
+.yui3-skin-sam #page .yui3-menuitem-active .yui3-menuitem-content {
+    color: #000;
+    background-color: #d8d2c6;
+}
+
+.yui3-skin-sam #page .yui3-menu-content,
+.yui3-skin-sam #page .yui3-menu-content,
+.yui3-skin-sam #page .yui3-menu .yui3-menu .yui3-menu-content,
+.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menu-label,
+.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menuitem-content  {
+    border: none !important;
+}
+
+.yui3-skin-sam .yui3-menu-horizontal .yui3-menu-label,
+.yui3-skin-sam .yui3-menu-horizontal .yui3-menuitem-content {
+    border-color:#808080;
+    border-style:solid;
+    border-width:0px 0;
+}
+
+#page .custom_menu_submenu {
+    border: 2px solid #d8d2c6 !important;
+    background: #fff;
+     -webkit-border-radius: 2px;
+    -moz-border-radius: 2px;
+    border-radius: 2px;
+    -webkit-box-shadow: 0px 1px 3px #ccc;
+    -moz-box-shadow: 0px 1px 3px #ccc;
+    box-shadow: 0px 1px 3px #ccc;
 }
\ No newline at end of file
index c77ba7c..40336b9 100644 (file)
@@ -80,6 +80,7 @@ if (!$currentuser
     //       please note this is just a guess!
     require_login();
     $isparent = true;
+    $PAGE->navigation->set_userid_for_parent_checks($id);
 } else {
     // normal course
     require_login($course);