lib.php 29.7 KB
Newer Older
1
2
3
4
5
<?php
/**
 *
 * @package    mahara
 * @subpackage blocktype-textbox
6
 * @author     Catalyst IT Ltd
7
8
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
 * @copyright  For copyright information on Mahara, please see the README file distributed with this software.
9
10
11
12
13
 *
 */

defined('INTERNAL') || die();

14
class PluginBlocktypeTextbox extends MaharaCoreBlocktype {
15
16

    public static function get_title() {
Ghada El-Zoghbi's avatar
Ghada El-Zoghbi committed
17
        return get_string('title', 'blocktype.internal/textbox');
18
19
20
    }

    public static function get_description() {
21
        return get_string('description', 'blocktype.internal/textbox');
22
23
24
    }

    public static function get_categories() {
25
        return array('general' => 24000);
26
27
    }

28
29
30
31
    public function can_have_attachments() {
        return true;
    }

32
    public static function render_instance(BlockInstance $instance, $editing=false, $versioning=false) {
33
        $configdata = $instance->get('configdata');
34
35
36
37
38
39
40
41
42
43
44
45

        if (!empty($configdata['artefactid'])) {
            safe_require('artefact', 'file');
            safe_require('artefact', 'comment');

            $artefact = $instance->get_artefact_instance($configdata['artefactid']);
            $viewid = $instance->get('view');
            $text = ArtefactTypeFolder::append_view_url($artefact->get('description'), $viewid);

            $smarty = smarty_core();
            $smarty->assign('text', $text);

46
47
48
49
50
51
52
            $attachments = $artefact->get_attachments();
            if ($attachments) {
                require_once(get_config('docroot') . 'artefact/lib.php');
                foreach ($attachments as &$attachment) {
                    $f = artefact_instance_from_id($attachment->id);
                    $attachment->size = $f->describe_size();
                    $attachment->iconpath = $f->get_icon(array('id' => $attachment->id, 'viewid' => isset($options['viewid']) ? $options['viewid'] : 0));
53
                    $attachment->viewpath = get_config('wwwroot') . 'artefact/artefact.php?artefact=' . $attachment->id . '&view=' . (isset($viewid) ? $viewid : 0);
54
55
56
57
58
59
60
                    $attachment->downloadpath = get_config('wwwroot') . 'artefact/file/download.php?file=' . $attachment->id;
                    if (isset($viewid)) {
                        $attachment->downloadpath .= '&view=' . $viewid;
                    }
                }
                $smarty->assign('count', count($attachments));
            }
61
            $smarty->assign('attachments', $attachments);
62
63
            require_once(get_config('docroot') . 'lib/view.php');
            $view = new View($viewid);
64
            list($commentcount, $comments) = ArtefactTypeComment::get_artefact_comments_for_view($artefact, $view, $instance->get('id'), true, $editing, $versioning);
65
66
            $smarty->assign('commentcount', $commentcount);
            $smarty->assign('comments', $comments);
67
            $smarty->assign('blockid', $instance->get('id'));
68
69
70
71
            return $smarty->fetch('blocktype:textbox:content.tpl');
        }

        return '';
72
73
    }

74
75
76
    /**
     * Returns a list of artefact IDs that are in this blockinstance.
     *
77
78
     * People may embed artefacts as images etc. They show up as links to the
     * download script, which isn't much to go on, but should be enough for us
79
80
81
82
     * to detect that the artefacts are therefore 'in' this blocktype.
     */
    public static function get_artefacts(BlockInstance $instance) {
        $configdata = $instance->get('configdata');
83
84
85
86
87
88
89
        $artefacts = array();
        if (isset($configdata['artefactid'])) {
            $artefacts[] = $configdata['artefactid'];

            // Add all artefacts found in the text
            $text = $instance->get_artefact_instance($configdata['artefactid'])->get('description');
            $artefacts = array_unique(array_merge($artefacts, artefact_get_references_in_html($text)));
90
91
92
93
        }
        return $artefacts;
    }

94
95
    public static function artefactchooser_element($default=null) {
        return array(
96
97
98
99
100
101
102
103
104
            'name'             => 'artefactid',
            'type'             => 'artefactchooser',
            'class'            => 'hidden',
            'defaultvalue'     => $default,
            'blocktype'        => 'textbox',
            'limit'            => 5,
            'selectone'        => true,
            'selectjscallback' => 'updateTextContent',
            'getblocks'        => true,
105
            'ownerinfo'        => true,
106
            'returnfields'     => array('id', 'title', 'description', 'tags', 'license', 'licensor', 'licensorurl', 'safedescription', 'safetags', 'safelicense', 'editable', 'attachments'),
107
108
            'artefacttypes'    => array('html'),
            'template'         => 'artefact:internal:html-artefactchooser-element.tpl',
109
            'lazyload'         => true,
110
111
112
        );
    }

113
114
115
116
117
    public static function artefactchooser_get_element_data($artefact) {

        require_once('license.php');
        $artefactobj = artefact_instance_from_id($artefact->id);
        $artefact->safelicense = render_license($artefactobj);
118
119
        $artefact->tags = ArtefactType::artefact_get_tags($artefact->id);
        $artefact->safetags = is_array($artefact->tags) ? hsc(join(', ', $artefact->tags)) : '';
120
121
122
123

        return $artefact;
    }

Son Nguyen's avatar
Son Nguyen committed
124
    public static function get_instance_config_javascript(BlockInstance $instance) {
125
126
127
128
129
        // When an artefact is selected in the artefactchooser, update the
        // contents of the wysiwyg editor and the message about the number
        // of blocks containing the new artefact.
        $blockid = $instance->get('id');
        return <<<EOF
130
formchangemanager.setFormStateById('instconf', FORM_CHANGED);
131
function updateTextContent(a) {
132
    jQuery('#instconf_title').prop('value', a.title);
133
134
135
    if (typeof(tinyMCE) != 'undefined') {
        tinyMCE.activeEditor.setContent(a.description);
    }
136
137
138
139
140
    jQuery('#instconf_license').prop('value', a.license);
    jQuery('#instconf_licensor').prop('value', a.licensor);
    jQuery('#instconf_licensorurl').prop('value', a.licensorurl);
    jQuery('#instconf_textreadonly_display').html(a.safedescription);
    jQuery('#instconf_licensereadonly_display').html(a.safelicense);
141
142
143
144
145
146
147
148
149
150
151
152
    if (a.tags && a.tags.length > 0) {
        for (var i = 0; i < a.tags.length; i++) {
            // Set the value, creating a new option if necessary
            if (!$('#instconf_tags').find("option[value='" + a.tags[i] + "']").length) {
                // Create a DOM Option and pre-select by default
                var newOption = new Option(a.tags[i], a.tags[i], true, true);
                // Append it to the select
                $('#instconf_tags').append(newOption);
            }
        }
        $('#instconf_tags').val(a.tags).trigger('change');
    }
153
154
    jQuery('#instconf_textreadonly_display').html(a.safedescription);
    jQuery('#instconf_tagsreadonly_display').html(a.safetags);
155
    jQuery('#instconf_makecopy').prop('checked', false);
156
    if (a.editable == 1) {
157
158
159
160
161
        jQuery('#instconf_textreadonly_container').addClass('hidden');
        jQuery('#instconf_readonlymsg_container').addClass('hidden');
        jQuery('#instconf_licensereadonly_container').addClass('hidden');
        jQuery('#instconf_tagsreadonly_container').addClass('hidden');
        jQuery('#instconf_text_container').removeClass('hidden');
162
        if (jQuery('#instconf_license_container').length) {
163
            // only deal with these if the license metadata is enabled
164
165
166
            jQuery('#instconf_license_container').removeClass('hidden');
            jQuery('#instconf_license_description').removeClass('hidden');
            jQuery('#instconf_license_advanced_fieldset').removeClass('hidden');
167
        }
168
169
        jQuery('#instconf_tags_container').removeClass('hidden');
        jQuery('#instconf_tags_description').removeClass('hidden');
170
171
        var blockcountmsg = jQuery('#instconf_otherblocksmsg_container');
        if (blockcountmsg && jQuery('#textbox_blockcount')) {
172
173
174
175
176
177
            var otherblockcount = 0;
            if (a.blocks && a.blocks.length > 0) {
                for (var i = 0; i < a.blocks.length; i++) {
                    if (a.blocks[i] != {$blockid}) {
                        otherblockcount++;
                    }
178
179
                }
            }
180
            if (otherblockcount) {
181
                jQuery('#textbox_blockcount').empty().append(otherblockcount);
182
                jQuery(blockcountmsg).removeClass('hidden');
183
184
            }
            else {
185
                jQuery(blockcountmsg).addClass('hidden');
186
            }
187
        }
188
189
190
191

        if (typeof a.attachments != 'undefined') {
            // remove any attached files
            for (var key in instconf_artefactids.selecteddata) {
192
              jQuery('#instconf_artefactids_unselect_' + key).triggerHandler('click', instconf_artefactids.unselect);
193
194
195
196
197
198
199
200
            }
            // add in ones we need
            if (a.attachments.length > 0) {
                for (var i = 0; i < a.attachments.length; i++) {
                    instconf_artefactids.add_to_selected_list(a.attachments[i]);
                }
            }
        }
201
202
    }
    else {
203
204
        jQuery('#instconf_text_container').addClass('hidden');
        jQuery('#instconf_otherblocksmsg_container').addClass('hidden');
205
        if (jQuery('#instconf_license_container').length) {
206
            // only deal with these if the license metadata is enabled
207
208
209
            jQuery('#instconf_license_container').addClass('hidden');
            jQuery('#instconf_license_description').addClass('hidden');
            jQuery('#instconf_license_advanced_fieldset').addClass('hidden');
210
        }
211
212
213
214
215
216
        jQuery('#instconf_tags_container').addClass('hidden');
        jQuery('#instconf_tags_description').addClass('hidden');
        jQuery('#instconf_textreadonly_container').removeClass('hidden');
        jQuery('#instconf_readonlymsg_container').removeClass('hidden');
        jQuery('#instconf_licensereadonly_container').removeClass('hidden');
        jQuery('#instconf_tagsreadonly_container').removeClass('hidden');
217
    }
218
}
219
220
jQuery('#chooseartefactlink').on('click', function(e) {
    e.preventDefault();
221
    // if the artefact chooser is hidden, use paginator p to populate it, then toggle its visibility
222
    if (jQuery('#instconf_artefactid_container').hasClass('hidden')) {
223
        var queryData = [];
224
        queryData.extradata = JSON.stringify(p.extraData);
225
226
        p.sendQuery(queryData, true);
    }
227
228
    jQuery('#instconf_artefactid_container').toggleClass('hidden');
    jQuery('#instconf_managenotes_container').toggleClass('hidden');
229
});
230
231
232
233
234
235
jQuery('#instconf a.copytextboxnote').each(function() {
    jQuery(this).on('click', function(e) {
        e.preventDefault();
        jQuery('#artefactid_data input.radio').each(function() {
            if (jQuery(this).prop('checked')) {
                jQuery(this).prop('checked', false);
236
237
            }
        });
238
        jQuery('#instconf_makecopy').prop('checked', true);
239
240
241
242
243
244
        jQuery('#instconf_textreadonly_container').addClass('hidden');
        jQuery('#instconf_readonlymsg_container').addClass('hidden');
        jQuery('#instconf_otherblocksmsg_container').addClass('hidden');
        jQuery('#instconf_licensereadonly_container').addClass('hidden');
        jQuery('#instconf_tagsreadonly_container').addClass('hidden');
        jQuery('#instconf_text_container').removeClass('hidden');
245
        if (jQuery('#instconf_license_container').length) {
246
            // only deal with these if the license metadata is enabled
247
248
249
            jQuery('#instconf_license_container').removeClass('hidden');
            jQuery('#instconf_license_description').removeClass('hidden');
            jQuery('#instconf_license_advanced_fieldset').removeClass('hidden');
250
        }
251
252
        jQuery('#instconf_tags_container').removeClass('hidden');
        jQuery('#instconf_tags_description').removeClass('hidden');
253
254
    });
});
255
if (jQuery('#instconf_license').length) {
256
    jQuery('#instconf_license').removeClass('hidden');
257
}
258
if (jQuery('#instconf_license_advanced_container').length) {
259
    jQuery('#instconf_license_advanced_container div').first().removeClass('hidden');
260
}
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
jQuery(function() {
    jQuery('#instconf_tags').on('change', function() {
        updatetagbuttons();
    });
    updatetagbuttons();

    function updatetagbuttons() {
        jQuery('#instconf_tags_container ul button').on('click', function(e) {
            e.stopPropagation();
            e.preventDefault();
            var li = jQuery(this).parent();
            var data = jQuery('#instconf_tags').select2('data');
            var value = null;
            for (var x in data) {
                if (li[0].title == data[x].text) {
                    value = data[x].id;
                    break;
                }
            }
            var val = jQuery('#instconf_tags').select2('val');
            var index = val.indexOf(value);
            if (index > -1) {
                val.splice(index, 1);
            }
            jQuery('#instconf_tags').select2('val', val);
        });
    }
});
289
290
291
EOF;
    }

292
293
294
295
    public static function has_instance_config() {
        return true;
    }

Son Nguyen's avatar
Son Nguyen committed
296
    public static function instance_config_form(BlockInstance $instance) {
297
        global $USER;
298
        require_once('license.php');
299
        safe_require('artefact', 'file');
300
        $instance->set('artefactplugin', 'internal');
301
        $configdata = $instance->get('configdata');
302
303
304
305
        if (!$height = get_config('blockeditorheight')) {
            $cfheight = param_integer('cfheight', 0);
            $height = $cfheight ? $cfheight * 0.7 : 150;
        }
306

307
        $otherblockcount = 0;
308
309
        $readonly = false;
        $text = '';
310
        $tags = '';
311
312
        $view = $instance->get_view();

313
314
        if (!empty($configdata['artefactid'])) {
            $artefactid = $configdata['artefactid'];
315
            try {
316
317
318
319
320
                $artefact = $instance->get_artefact_instance($artefactid);

                $readonly = $artefact->get('owner') !== $view->get('owner')
                    || $artefact->get('group') !== $view->get('group')
                    || $artefact->get('institution') !== $view->get('institution')
321
                    || $artefact->get('locked')
322
323
324
                    || !$USER->can_edit_artefact($artefact);

                $text = $artefact->get('description');
325
                $tags = $artefact->get('tags');
326
327
328
329
330

                if ($blocks = get_column('view_artefact', 'block', 'artefact', $artefactid)) {
                    $blocks = array_unique($blocks);
                    $otherblockcount = count($blocks) - 1;
                }
331
332
333
334
            }
            catch (ArtefactNotFoundException $e) {
                unset($artefactid);
            }
335
        }
336
337
338
339
340
341
342
343
344
345
346
347

        $otherblocksmsg = '<span id="textbox_blockcount">' . $otherblockcount . '</span>';
        $otherblocksmsg = get_string('textusedinotherblocks', 'blocktype.internal/textbox', $otherblocksmsg);

        $manageurl = get_config('wwwroot') . 'artefact/internal/notes.php';
        if ($group = $view->get('group')) {
            $manageurl .= '?group=' . $group;
        }
        else if ($institution = $view->get('institution')) {
            $manageurl .= '?institution=' . $institution;
        }

348
349
350
        // Update the attached files in block configdata as
        // it may change when attached files have been deleted
        $attachmentids = isset($artefact) ? $artefact->attachment_id_list() : false;
351
        if ($attachmentids !== false && isset($configdata['artefactids']) && $configdata['artefactids'] != $attachmentids) {
352
353
354
355
356
            $configdata['artefactids'] = $attachmentids;
            $instance->set('configdata', $configdata);
            $instance->commit();
        }

357
        $elements = array(
358
359
360
            // Add a message whenever this text appears in some other block
            'otherblocksmsg' => array(
                'type' => 'html',
361
                'class' => 'message info' . (($otherblockcount && !$readonly) ? '' : ' hidden'),
362
                'value' => '<p class="alert alert-warning">' . $otherblocksmsg
363
                    . ' <a class="copytextboxnote nojs-hidden-inline" href="">' . get_string('makeacopy', 'blocktype.internal/textbox') . '</a></p>',
364
365
366
367
368
369
                'help' => true,
            ),
            // Add a message whenever this text cannot be edited here
            'readonlymsg' => array(
                'type' => 'html',
                'class' => 'message info' . ($readonly ? '' : ' hidden'),
370
                'value' => '<p class="alert alert-warning">' . get_string('readonlymessage', 'blocktype.internal/textbox')
371
                    . ' <a class="copytextboxnote nojs-hidden-inline" href="">' . get_string('makeacopy', 'blocktype.internal/textbox') . '</a></p>',
372
                'help' => true,
373
            ),
374
            'text' => array(
375
                'type' => 'wysiwyg',
376
                'class' => $readonly ? 'hidden' : '',
377
                'title' => get_string('blockcontent', 'blocktype.internal/textbox'),
378
                'width' => '100%',
379
                'height' => $height . 'px',
380
                'defaultvalue' => $text,
381
                'rules' => array('maxlength' => 65536),
382
            ),
383
384
385
            'textreadonly' => array(
                'type' => 'html',
                'class' => $readonly ? '' : 'hidden',
386
                'title' => get_string('blockcontent', 'blocktype.internal/textbox'),
Pat Kira's avatar
Pat Kira committed
387
                'value' => '<div id="instconf_textreadonly_display" class="well text-midtone">' . $text . '</div>',
388
            ),
389
390
391
392
393
394
395
            'makecopy' => array(
                'type' => 'checkbox',
                'class' => 'hidden',
                'defaultvalue' => false,
            ),
            'chooseartefact' => array(
                'type'  => 'html',
396
                'value' => '<a id="chooseartefactlink" href="#" class="btn btn-default">'
397
                    . get_string('usecontentfromanothertextbox1', 'blocktype.internal/textbox') . '</a>',
398
399
400
            ),
            'managenotes' => array(
                'type'  => 'html',
401
                'class' => 'hidden text-right',
402
                'value' => '<a href="' . $manageurl . '" class="pull-right">'
403
                    . get_string('managealltextboxcontent1', 'blocktype.internal/textbox') . ' <span class="icon icon-arrow-right right" role="presentation"></span></a>',
404
            ),
405
406
407
408
409
410
411
            'artefactid' => self::artefactchooser_element(isset($artefactid) ? $artefactid : null),
            'license' => license_form_el_basic(isset($artefact) ? $artefact : null),
            'license_advanced' => license_form_el_advanced(isset($artefact) ? $artefact : null),
            'licensereadonly' => array(
                'type' => 'html',
                'class' => $readonly ? '' : 'hidden',
                'title' => get_string('license'),
412
                'value' => '<div id="instconf_licensereadonly_display">' . (isset($artefact) ? render_license($artefact) : get_string('licensenone1')) . '</div>',
413
            ),
414
            'allowcomments' => array(
415
                'type'         => 'switchbox',
416
417
418
                'title'        => get_string('allowcomments', 'artefact.comment'),
                'defaultvalue' => (!empty($artefact) ? $artefact->get('allowcomments') : 1),
            ),
419
420
421
422
423
424
425
426
427
428
429
430
431
            'tags' => array(
                'type' => 'tags',
                'class' => $readonly ? 'hidden' : '',
                'title' => get_string('tags'),
                'description' => get_string('tagsdescprofile'),
                'defaultvalue' => $tags,
            ),
            'tagsreadonly' => array(
                'type' => 'html',
                'class' => $readonly ? '' : 'hidden',
                'title' => get_string('tags'),
                'value' => '<div id="instconf_tagsreadonly_display">' . (is_array($tags) ? hsc(join(', ', $tags)) : '') . '</div>',
            ),
432
433
434
435
436
            'artefactfieldset' => array(
                'type'         => 'fieldset',
                'collapsible'  => true,
                'collapsed'    => true,
                'legend'       => get_string('attachments', 'artefact.blog'),
437
                'class'        => 'last with-formgroup',
438
                'elements'     => array(
439
                    'artefactids' => self::filebrowser_element($instance, (isset($configdata['artefactids'])) ? $configdata['artefactids'] : null),
440
441
                )
            )
442
        );
443
        if ($readonly) {
444
445
            $elements['license']['class'] = 'hidden';
            $elements['license_advanced']['class'] = 'hidden';
446
        }
447
448
449
        return $elements;
    }

450
    public static function delete_instance(BlockInstance $instance) {
451
452
453
454
455
456
457
458
459
460
        require_once('embeddedimage.php');
        $configdata = $instance->get('configdata');
        if (!empty($configdata)) {
            $artefactid = $configdata['artefactid'];
            if (!empty($artefactid)) {
                EmbeddedImage::delete_embedded_images($instance->get('blocktype'), $artefactid);
            }
        }
    }

461
    public static function instance_config_save($values, $instance) {
462
        global $USER;
463
        require_once('embeddedimage.php');
464
        $data = array();
465
466
467
468
        $view = $instance->get_view();
        foreach (array('owner', 'group', 'institution') as $f) {
            $data[$f] = $view->get($f);
        }
469

470
        if (empty($values['artefactid']) || $values['makecopy']) {
471
472
473
474
475
476
477
478
479
480
481
482
483
            // The artefact title will be the same as the block title when the
            // artefact is first created, or, if there's no block title, generate
            // 'Note (1)', 'Note (2)', etc.  After that, the artefact title can't
            // be edited inside the block, but can be changed in the Notes area.
            if (empty($values['title'])) {
                $title = artefact_new_title(
                    get_string('Note', 'artefact.internal'), 'html',
                    $data['owner'], $data['group'], $data['institution']
                );
            }
            else {
                $title = $values['title'];
            }
484
            safe_require('artefact', 'internal');
485
486
487
            $artefact = new ArtefactTypeHtml(0, $data);
            $artefact->set('title', $title);
            $artefact->set('description', $values['text']);
488
489
490
491
492
            if (get_config('licensemetadata')) {
                $artefact->set('license', $values['license']);
                $artefact->set('licensor', $values['licensor']);
                $artefact->set('licensorurl', $values['licensorurl']);
            }
493
            $artefact->set('allowcomments', (!empty($values['allowcomments']) ? $values['allowcomments'] : 0));
494
            $artefact->set('tags', $values['tags']);
495
        }
496
497
        else {
            $artefact = new ArtefactTypeHtml((int)$values['artefactid']);
498

499
500
501
            if (!$USER->can_publish_artefact($artefact)) {
                throw new AccessDeniedException(get_string('nopublishpermissiononartefact', 'mahara', hsc($artefact->get('title'))));
            }
502

503
            // Stop users from editing textbox artefacts whose owner is not the same as the
504
            // view owner, even if they would normally be allowed to edit the artefact.
505
            // It's too confusing.  Textbox artefacts with other owners *can* be included in
506
507
508
509
510
            // the view read-only, provided the artefact has the correct republish
            // permission.
            if ($artefact->get('owner') === $data['owner']
                && $artefact->get('group') === $data['group']
                && $artefact->get('institution') === $data['institution']
511
                && !$artefact->get('locked')
512
                && $USER->can_edit_artefact($artefact)) {
513
514
                $newdescription = EmbeddedImage::prepare_embedded_images($values['text'], 'textbox', (int)$values['artefactid'], $view->get('group'));
                $artefact->set('description', $newdescription);
515
516
517
518
519
                if (get_config('licensemetadata')) {
                    $artefact->set('license', $values['license']);
                    $artefact->set('licensor', $values['licensor']);
                    $artefact->set('licensorurl', $values['licensorurl']);
                }
520
                $artefact->set('tags', $values['tags']);
521
                $artefact->set('allowcomments', !empty($values['allowcomments']) ? 1 : 0);
522
            }
523
        }
524

525
526
        $artefact->commit();

527
528
529
530
531
532
533
534
535
        $newdescription = EmbeddedImage::prepare_embedded_images($values['text'], 'textbox', $artefact->get('id'), $view->get('group'));

        if ($newdescription !== $values['text']) {
            $updatedartefact = new stdClass();
            $updatedartefact->id = $artefact->get('id');
            $updatedartefact->description = $newdescription;
            update_record('artefact', $updatedartefact, 'id');
        }

536
537
538
        // Add attachments, if there are any...
        $old = $artefact->attachment_id_list();
        $new = is_array($values['artefactids']) ? $values['artefactids'] : array();
539
540
541
542
543
544
545
        // only allow the attaching of files that exist and are editable by user
        foreach ($new as $key => $fileid) {
            $file = artefact_instance_from_id($fileid);
            if (!($file instanceof ArtefactTypeFile) || !$USER->can_publish_artefact($file)) {
                unset($new[$key]);
            }
        }
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
        if (!empty($new) || !empty($old)) {
            foreach ($old as $o) {
                if (!in_array($o, $new)) {
                    try {
                        $artefact->detach($o);
                    }
                    catch (ArtefactNotFoundException $e) {}
                }
            }
            foreach ($new as $n) {
                if (!in_array($n, $old)) {
                    try {
                        $artefact->attach($n);
                    }
                    catch (ArtefactNotFoundException $e) {}
                }
            }
        }

565
566
567
568
        $values['artefactid'] = $artefact->get('id');
        $instance->save_artefact_instance($artefact);

        unset($values['text']);
569
        unset($values['otherblocksmsg']);
570
571
        unset($values['readonlymsg']);
        unset($values['textreadonly']);
572
        unset($values['makecopy']);
573
        unset($values['chooseartefact']);
574
        unset($values['managenotes']);
575
        unset($values['allowcomments']);
576
        unset($values['tags']); // We save the tags against the artefact so don't need to save again against the block
577
578
579
580
581
582
583
584
585

        // Pass back a list of any other blocks that need to be rendered
        // due to this change.
        $values['_redrawblocks'] = array_unique(get_column(
            'view_artefact', 'block',
            'artefact', $values['artefactid'],
            'view', $instance->get('view')
        ));

586
        return $values;
587
588
    }

589
590
591
592
    public static function filebrowser_element(&$instance, $default=array()) {
        $element = ArtefactTypeFileBase::blockconfig_filebrowser_element($instance, $default);
        $element['title'] = get_string('attachments', 'artefact.blog');
        $element['name'] = 'artefactids';
593
        $element['config']['select'] = true;
594
        $element['config']['selectone'] = false;
595
        $element['config']['selectmodal'] = true;
596
        $element['config']['alwaysopen'] = false;
597
598
599
        return $element;
    }

600
601
602
603
    public static function default_copy_type() {
        return 'full';
    }

604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
    /**
     * The content of this block is now stored as an html artefact, but older versions stored
     * the content directly in the 'text' property of the block config.  If this config has
     * 'text' but not 'artefactid', create an artefact.
     *
     * @param array $biconfig   The block instance config
     * @param array $viewconfig The view config
     * @return BlockInstance The newly made block instance
     */
    public static function import_create_blockinstance_leap(array $biconfig, array $viewconfig) {
        $configdata = $biconfig['config'];

        if (isset($configdata['text']) && !isset($configdata['artefactid'])) {
            $data = array(
                'title'       => $biconfig['title'],
                'description' => $configdata['text'],
620
621
622
                'license' => (!empty($configdata['license'])) ? $configdata['license'] : '',
                'licensor' => (!empty($configdata['licensor'])) ? $configdata['licensor'] : '',
                'licensorurl' => (!empty($configdata['licensorurl'])) ? $configdata['licensorurl'] : '',
623
                'tags'        => (!empty($configdata['tags'])) ? $configdata['tags'] : '',
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
                'owner'       => $viewconfig['owner'],
            );
            $artefact = new ArtefactTypeHtml(0, $data);
            $artefact->commit();
            $configdata['artefactid'] = $artefact->get('id');
            unset($configdata['text']);
        }

        $bi = new BlockInstance(0,
            array(
                'blocktype'  => $biconfig['type'],
                'configdata' => $configdata,
            )
        );

        return $bi;
    }

    /**
     * Set the text property of the block config so that exports can be imported
     * into older versions.
     *
     * @param BlockInstance $bi The blockinstance to export the config for.
     * @return array The config for the blockinstance
     */
    public static function export_blockinstance_config_leap(BlockInstance $bi) {
        $configdata = $bi->get('configdata');

        $result = array();

        $text = '';
655
656
657
        $license = '';
        $licensor = '';
        $licensorurl = '';
658
        $tags = '';
659
660
661

        if (!empty($configdata['artefactid'])) {
            $result['artefactid'] = json_encode(array($configdata['artefactid']));
662
663
            $note = $bi->get_artefact_instance($configdata['artefactid']);
            $text = $note->get('description');
664
            $tags = $note->get('tags');
665
666
667
            $license = $note->get('license');
            $licensor = $note->get('licensor');
            $licensorurl = $note->get('licensorurl');
668
669
670
        }

        $result['text'] = json_encode(array($text));
671
        $result['tags'] = json_encode(array($tags));
672
673
674
        $result['license '] = json_encode(array($license));
        $result['licensor'] = json_encode(array($licensor));
        $result['licensorurl'] = json_encode(array($licensorurl));
675
676
677

        return $result;
    }
678
}