├── pix
└── icon.gif
├── tinymce
├── img
│ └── managefiles.png
└── editor_plugin.js
├── README.txt
├── styles.css
├── version.php
├── module.js
├── lang
└── en
│ └── tinymce_managefiles.php
├── lib.php
├── manage_form.php
└── manage.php
/pix/icon.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marinaglancy/moodle-tinymce_managefiles/master/pix/icon.gif
--------------------------------------------------------------------------------
/tinymce/img/managefiles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marinaglancy/moodle-tinymce_managefiles/master/tinymce/img/managefiles.png
--------------------------------------------------------------------------------
/README.txt:
--------------------------------------------------------------------------------
1 | This plugin will add a button to the TinyMCE text editor in Moodle that allows to
2 | manage files embedded in the current text area.
3 |
4 | To install copy files to lib/editor/tinymce/plugins/managefiles
5 | Please note that Moodle 2.6 already includes this plugin in the standard distribution.
6 |
7 | CHANGES LOG
8 | ===========
9 |
10 | Version 1.3
11 | -----------
12 |
13 | - Plugin now work correctly in quiz questions (for legacy reasons those textareas
14 | allows subfolders in the filearea attached to the editor).
15 | - Popup automatically opens fullscreen on small screens
16 | - Popup window correctly uses current environment (theme and language of the
17 | current course and/or user).
18 |
--------------------------------------------------------------------------------
/styles.css:
--------------------------------------------------------------------------------
1 | #tinymce_managefiles_manageform.hasunusedfiles .managefilesstatus {display:none;}
2 | #tinymce_managefiles_manageform.hasmissingfiles .managefilesstatus {display:inline;}
3 |
4 | #tinymce_managefiles_manageform #deletefiles,
5 | #tinymce_managefiles_manageform #id_deletefiles {display:none;}
6 | #tinymce_managefiles_manageform.hasunusedfiles #deletefiles,
7 | #tinymce_managefiles_manageform.hasunusedfiles #id_deletefiles {display:block;}
8 | #tinymce_managefiles_manageform #deletefiles .felement.fcheckbox,
9 | #tinymce_managefiles_manageform #id_deletefiles .felement.fcheckbox {display:none;}
10 | #tinymce_managefiles_manageform #deletefiles .felement.fcheckbox.isunused,
11 | #tinymce_managefiles_manageform #id_deletefiles .felement.fcheckbox.isunused {display:block;}
12 |
--------------------------------------------------------------------------------
/version.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * TinyMCE manage files plugin version details.
19 | *
20 | * @package tinymce_managefiles
21 | * @copyright 2013 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | defined('MOODLE_INTERNAL') || die();
26 |
27 | $plugin->version = 2013120200; // The current plugin version (Date: YYYYMMDDXX).
28 | $plugin->requires = 2012120300; // Required Moodle version.
29 | $plugin->release = '1.3';
30 | $plugin->maturity = MATURITY_STABLE;
31 | $plugin->component = 'tinymce_managefiles'; // Full name of the plugin (used for diagnostics).
32 |
--------------------------------------------------------------------------------
/module.js:
--------------------------------------------------------------------------------
1 | M.tinymce_managefiles = M.tinymce_managefiles || {}
2 | M.tinymce_managefiles.analysefiles = function(Y) {
3 | var form = Y.one('#tinymce_managefiles_manageform'),
4 | usedfiles, missingfiles = '', i;
5 | if (!form || !window.parent || !window.parent.tinyMCE.activeEditor) {
6 | return;
7 | }
8 | usedfiles = window.parent.tinyMCE.activeEditor.execCommand('mceManageFilesUsedFiles')
9 | var delfilesfieldset = form.one('#deletefiles,#id_deletefiles')
10 | for (i in usedfiles) {
11 | if (!delfilesfieldset.one('.felement.fcheckbox input[name="deletefile[' + usedfiles[i] + ']"]')) {
12 | missingfiles += '
' + usedfiles[i] + '';
13 | }
14 | }
15 | if (missingfiles !== '') {
16 | form.addClass('hasmissingfiles')
17 | form.one('.managefilesstatus').setContent(M.str.tinymce_managefiles.hasmissingfiles + ' ').addClass('error');
18 | }
19 | delfilesfieldset.all('.felement.fcheckbox').each(function(el) {
20 | var chb = el.one('input[type=checkbox]'),
21 | match = /^deletefile\[(.*)\]$/.exec(chb.get('name'));
22 | if (match && usedfiles.indexOf(match[1]) === -1) {
23 | el.addClass('isunused')
24 | form.addClass('hasunusedfiles')
25 | }
26 | });
27 | if (missingfiles === '' && !form.hasClass('hasunusedfiles')) {
28 | form.one('.managefilesstatus').setContent(M.str.tinymce_managefiles.allfilesok);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/lang/en/tinymce_managefiles.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * TinyMCE manage files plugin language file
19 | *
20 | * @package tinymce_managefiles
21 | * @copyright 2013 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | $string['pluginname'] = 'Manage embedded files';
26 | $string['manageareafiles'] = 'Manage files embedded in text editor';
27 | $string['managefiles:desc'] = 'Manage embedded files';
28 | $string['allfilesok'] = 'There are no missing or unused files';
29 | $string['hasmissingfiles'] = 'Warning! The following files that are referenced in the text area appear to be missing:';
30 | $string['refreshfiles'] = 'Refresh the lists of missing and unused files';
31 | $string['unusedfilesheader'] = 'Unused files';
32 | $string['unusedfilesdesc'] = 'The following embedded files are not used in the text area:';
33 | $string['deleteselected'] = 'Delete selected files';
--------------------------------------------------------------------------------
/lib.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | defined('MOODLE_INTERNAL') || die();
18 |
19 | /**
20 | * Plugin for managing files embedded in the text editor
21 | *
22 | * @package tinymce_managefiles
23 | * @copyright 2013 Marina Glancy
24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 | */
26 | class tinymce_managefiles extends editor_tinymce_plugin {
27 | /** @var array list of buttons defined by this plugin */
28 | protected $buttons = array('managefiles');
29 |
30 | /**
31 | * Adjusts TinyMCE init parameters for tinymce_managefiles
32 | *
33 | * Adds file area restrictions parameters and actual 'managefiles' button
34 | *
35 | * @param array $params TinyMCE init parameters array
36 | * @param context $context Context where editor is being shown
37 | * @param array $options Options for this editor
38 | */
39 | protected function update_init_params(array &$params, context $context,
40 | array $options = null) {
41 | global $USER;
42 |
43 | // Add parameters for filemanager
44 | $params['managefiles'] = array('usercontext' => context_user::instance($USER->id)->id);
45 | foreach (array('itemid', 'context', 'areamaxbytes', 'maxbytes', 'subdirs', 'return_types') as $key) {
46 | if (isset($options[$key])) {
47 | if ($key === 'context' && is_object($options[$key])) {
48 | // Just context id is enough
49 | $params['managefiles'][$key] = $options[$key]->id;
50 | } else {
51 | $params['managefiles'][$key] = $options[$key];
52 | }
53 | }
54 | }
55 |
56 | // Add button after moodlemedia button in advancedbuttons3.
57 | $added = $this->add_button_after($params, 3, 'managefiles', 'moodlemedia', false);
58 |
59 | // So, if no moodlemedia, add after 'image'.
60 | if (!$added) {
61 | $this->add_button_after($params, 3, 'managefiles', 'image');
62 | }
63 |
64 | // Add JS file, which uses default name.
65 | $this->add_js_plugin($params);
66 | }
67 |
68 | protected function get_sort_order() {
69 | return 310;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/manage_form.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Class tinymce_managefiles_manage_form
19 | *
20 | * @package tinymce_managefiles
21 | * @copyright 2013 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | defined('MOODLE_INTERNAL') || die();
26 |
27 | require_once($CFG->libdir."/formslib.php");
28 |
29 | /**
30 | * Form allowing to edit files in one draft area
31 | *
32 | * No buttons are necessary since the draft area files are saved immediately using AJAX
33 | *
34 | * @package tinymce_managefiles
35 | * @copyright 2013 Marina Glancy
36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37 | */
38 | class tinymce_managefiles_manage_form extends moodleform {
39 | function definition() {
40 | global $PAGE;
41 | $mform = $this->_form;
42 |
43 | $itemid = $this->_customdata['draftitemid'];
44 | $options = $this->_customdata['options'];
45 | $files = $this->_customdata['files'];
46 |
47 | $mform->addElement('hidden', 'itemid');
48 | $mform->setType('itemid', PARAM_INT);
49 | $mform->addElement('hidden', 'maxbytes');
50 | $mform->setType('maxbytes', PARAM_INT);
51 | $mform->addElement('hidden', 'subdirs');
52 | $mform->setType('subdirs', PARAM_INT);
53 | $mform->addElement('hidden', 'accepted_types');
54 | $mform->setType('accepted_types', PARAM_RAW);
55 | $mform->addElement('hidden', 'return_types');
56 | $mform->setType('return_types', PARAM_INT);
57 | $mform->addElement('hidden', 'context');
58 | $mform->setType('context', PARAM_INT);
59 | $mform->addElement('hidden', 'areamaxbytes');
60 | $mform->setType('areamaxbytes', PARAM_INT);
61 |
62 | $mform->addElement('filemanager', 'files_filemanager', '', null, $options);
63 |
64 | $mform->addElement('submit', 'refresh', get_string('refreshfiles', 'tinymce_managefiles'));
65 | $mform->registerNoSubmitButton('refresh');
66 |
67 | $mform->addElement('static', '', '',
68 | html_writer::tag('div', '', array('class' => 'managefilesstatus')));
69 |
70 | $mform->addElement('header', 'deletefiles', get_string('unusedfilesheader', 'tinymce_managefiles'));
71 | $mform->addElement('static', '', '',
72 | html_writer::tag('span', get_string('unusedfilesdesc', 'tinymce_managefiles'), array('class' => 'managefilesunuseddesc')));
73 | foreach ($files as $file) {
74 | $mform->addElement('checkbox', 'deletefile['.$file.']', '', $file);
75 | $mform->setType('deletefile['.$file.']', PARAM_INT);
76 | }
77 | $mform->addElement('submit', 'delete', get_string('deleteselected', 'tinymce_managefiles'));
78 |
79 | $PAGE->requires->js_init_call('M.tinymce_managefiles.analysefiles', array(), true);
80 | $PAGE->requires->strings_for_js(array('allfilesok', 'hasmissingfiles'), 'tinymce_managefiles');
81 |
82 | $this->set_data(array('files_filemanager' => $itemid,
83 | 'itemid' => $itemid,
84 | 'subdirs' => $options['subdirs'],
85 | 'maxbytes' => $options['maxbytes'],
86 | 'areamaxbytes' => $options['areamaxbytes'],
87 | 'accepted_types' => $options['accepted_types'],
88 | 'return_types' => $options['return_types'],
89 | 'context' => $options['context']->id,
90 | ));
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/manage.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Manage files in user draft area attached to texteditor
19 | *
20 | * @package tinymce_managefiles
21 | * @copyright 2013 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | require('../../../../../config.php');
26 | require_once('manage_form.php');
27 | require_once($CFG->libdir.'/filestorage/file_storage.php');
28 |
29 | $itemid = required_param('itemid', PARAM_INT);
30 | $maxbytes = optional_param('maxbytes', 0, PARAM_INT);
31 | $subdirs = optional_param('subdirs', 0, PARAM_INT);
32 | $accepted_types = optional_param('accepted_types', '*', PARAM_RAW); // TODO not yet passed to this script
33 | $return_types = optional_param('return_types', null, PARAM_INT);
34 | $areamaxbytes = optional_param('areamaxbytes', FILE_AREA_MAX_BYTES_UNLIMITED, PARAM_INT);
35 | $contextid = optional_param('context', SYSCONTEXTID, PARAM_INT);
36 |
37 | $context = context::instance_by_id($contextid);
38 | if ($context->contextlevel == CONTEXT_MODULE) {
39 | // Module context.
40 | $cm = $DB->get_record('course_modules', array('id' => $context->instanceid));
41 | require_login($cm->course, true, $cm);
42 | } else if (($coursecontext = $context->get_course_context(false)) && $coursecontext->id != SITEID) {
43 | // Course context or block inside the course.
44 | require_login($coursecontext->instanceid);
45 | $PAGE->set_context($context);
46 | } else {
47 | // Block that is not inside the course, user or system context.
48 | require_login();
49 | $PAGE->set_context($context);
50 | }
51 | if (isguestuser()) {
52 | // Guests can never manage files.
53 | print_error('noguest');
54 | }
55 |
56 | $title = get_string('manageareafiles', 'tinymce_managefiles');
57 |
58 | $PAGE->set_url('/lib/editor/tinymce/plugins/managefiles/manage.php');
59 | $PAGE->set_title($title);
60 | $PAGE->set_heading($title);
61 | $PAGE->set_pagelayout('popup');
62 |
63 | if ($return_types !== null) {
64 | $return_types = $return_types ^ 1; // links are allowed in textarea but never allowed in filemanager
65 | }
66 |
67 | $options = array(
68 | 'subdirs' => $subdirs,
69 | 'maxbytes' => $maxbytes,
70 | 'maxfiles' => -1,
71 | 'accepted_types' => $accepted_types,
72 | 'areamaxbytes' => $areamaxbytes,
73 | 'return_types' => $return_types,
74 | 'context' => $context
75 | );
76 |
77 | $usercontext = context_user::instance($USER->id);
78 | $fs = get_file_storage();
79 | $files = $fs->get_directory_files($usercontext->id, 'user', 'draft', $itemid, '/', !empty($subdirs), false);
80 | $filenames = array();
81 | foreach ($files as $file) {
82 | $filenames[] = ltrim($file->get_filepath(), '/'). $file->get_filename();
83 | }
84 |
85 | $mform = new tinymce_managefiles_manage_form(null,
86 | array('options' => $options, 'draftitemid' => $itemid, 'files' => $filenames),
87 | 'post', '', array('id' => 'tinymce_managefiles_manageform'));
88 |
89 | if ($data = $mform->get_data()) {
90 | if (!empty($data->deletefile)) {
91 | foreach (array_keys($data->deletefile) as $filename) {
92 | $filepath = '/';
93 | if (!empty($subdirs) && strlen(dirname($filename)) ) {
94 | $filepath = '/'. dirname($filename). '/';
95 | }
96 | if ($file = $fs->get_file($usercontext->id, 'user', 'draft', $itemid,
97 | $filepath, basename($filename))) {
98 | $file->delete();
99 | }
100 | }
101 | $filenames = array_diff($filenames, array_keys($data->deletefile));
102 | $mform = new tinymce_managefiles_manage_form(null,
103 | array('options' => $options, 'draftitemid' => $itemid, 'files' => $filenames),
104 | 'post', '', array('id' => 'tinymce_managefiles_manageform'));
105 | }
106 | }
107 |
108 | echo $OUTPUT->header();
109 | $mform->display();
110 | echo $OUTPUT->footer();
111 |
--------------------------------------------------------------------------------
/tinymce/editor_plugin.js:
--------------------------------------------------------------------------------
1 | /**
2 | * TinyMCE plugin ManageFiles - provides UI to edit files embedded in the text editor.
3 | *
4 | * @author Marina Glancy
5 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6 | */
7 |
8 | (function() {
9 | tinymce.create('tinymce.plugins.MoodleManageFiles', {
10 | /**
11 | * Initializes the plugin, this will be executed after the plugin has been created.
12 | * This call is done before the editor instance has finished it's initialization so use the onInit event
13 | * of the editor instance to intercept that event.
14 | *
15 | * @param {tinymce.Editor} ed Editor instance that the plugin is initialized in.
16 | * @param {string} url Absolute URL to where the plugin is located.
17 | */
18 | init : function(ed, url) {
19 | ed.addCommand('mceForceRepaint', function() {
20 | var root = ed.dom.getRoot();
21 | items = root.getElementsByTagName("img");
22 | for (var i = 0; i < items.length; i++) {
23 | src = items[i].getAttribute('src').replace(/\?\d+$/, '');
24 | items[i].setAttribute('src', src+'?'+(new Date().getTime()))
25 | }
26 | ed.execCommand('mceRepaint');
27 | ed.focus();
28 | });
29 |
30 | ed.addCommand('mceMaximizeWindow', function(w) {
31 | // This function duplicates the TinyMCE windowManager code when 'maximize' button is pressed.
32 | var vp = ed.dom.getViewPort(),
33 | id = w.id;
34 | // Reduce viewport size to avoid scrollbars
35 | vp.w -= 2;
36 | vp.h -= 2;
37 |
38 | w.oldPos = w.element.getXY();
39 | w.oldSize = w.element.getSize();
40 |
41 | w.element.moveTo(vp.x, vp.y);
42 | w.element.resizeTo(vp.w, vp.h);
43 | ed.dom.setStyles(id + '_ifr', {width : vp.w - w.deltaWidth, height : vp.h - w.deltaHeight});
44 | ed.dom.addClass(id + '_wrapper', 'mceMaximized');
45 | });
46 |
47 | ed.addCommand('mceManageFiles', function() {
48 | var managefiles = ed.getParam('managefiles', {}), key, cnt = 0,
49 | fileurl = ed.getParam("moodle_plugin_base") + 'managefiles/manage.php?';
50 | for (key in managefiles) {
51 | fileurl += (cnt++ ? '&' : '') + encodeURIComponent(key) + "=" + encodeURIComponent(managefiles[key]) + "&";
52 | }
53 | var onClose = function() {
54 | ed.windowManager.onClose.remove(onClose);
55 | ed.execCommand('mceForceRepaint');
56 | };
57 | ed.windowManager.onClose.add(onClose);
58 | var vp = ed.dom.getViewPort(),
59 | width = 900 + parseInt(ed.getLang('advimage.delta_width', 0)),
60 | height = 600 + parseInt(ed.getLang('advimage.delta_height', 0)),
61 | maximizedmode = (width >= vp.w - 2 || height >= vp.h - 2);
62 | if (maximizedmode) {
63 | width = vp.w;
64 | height = vp.h;
65 | }
66 | w = ed.windowManager.open({
67 | file : fileurl ,
68 | width : width,
69 | height : height,
70 | inline : 1
71 | }, {
72 | plugin_url : url // Plugin absolute URL
73 | });
74 | if (maximizedmode) {
75 | ed.execCommand('mceMaximizeWindow', w);
76 | }
77 | });
78 |
79 | ed.addCommand('mceManageFilesUsedFiles', function() {
80 | var managefiles = ed.getParam('managefiles', {}),
81 | text = ed.dom.getRoot().innerHTML,
82 | base = ed.getParam('document_base_url') + '/draftfile.php/' + managefiles['usercontext'] + '/user/draft/' + managefiles['itemid'] + '/',
83 | patt = new RegExp(base.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + "(.+?)[\\?\"']", 'gm'),
84 | arr = [], match, filename;
85 | while ((match = patt.exec(text)) !== null) {
86 | filename = unescape(match[1]);
87 | if (arr.indexOf(filename) === -1) {
88 | arr[arr.length] = filename;
89 | }
90 | }
91 | return arr;
92 | });
93 |
94 | var managefiles = ed.getParam('managefiles', {});
95 | // Get draft area id from filepicker options.
96 | if (!managefiles.itemid && M.editor_tinymce.filepicker_options
97 | && M.editor_tinymce.filepicker_options[ed.id]
98 | && M.editor_tinymce.filepicker_options[ed.id].image
99 | && M.editor_tinymce.filepicker_options[ed.id].image.itemid) {
100 | managefiles.itemid = M.editor_tinymce.filepicker_options[ed.id].image.itemid;
101 | ed.settings['managefiles'].itemid = managefiles.itemid;
102 | }
103 |
104 | // Register buttons
105 | if (managefiles.itemid) {
106 | ed.addButton('managefiles', {
107 | title : 'managefiles.desc',
108 | cmd : 'mceManageFiles',
109 | image : url + '/img/managefiles.png'
110 | });
111 | }
112 | },
113 | createControl : function(n, cm) {
114 | return null;
115 | },
116 |
117 | /**
118 | * Returns information about the plugin as a name/value array.
119 | * The current keys are longname, author, authorurl, infourl and version.
120 | *
121 | * @return {Object} Name/value array containing information about the plugin.
122 | */
123 | getInfo : function() {
124 | return {
125 | longname : 'Moodle Manage embedded files plugin',
126 | author : 'Marina Glancy',
127 | infourl : 'http://moodle.org',
128 | version : "1.0"
129 | };
130 | }
131 | });
132 |
133 | // Register plugin.
134 | tinymce.PluginManager.add('managefiles', tinymce.plugins.MoodleManageFiles);
135 | })();
136 |
--------------------------------------------------------------------------------