mirror of
https://github.com/moodle/moodle.git
synced 2025-04-16 14:02:32 +02:00
MDL-51802 core: new template for quick editing a title
convert editing tag name to use new template
This commit is contained in:
parent
2f45a11ac4
commit
cdc5f9785b
@ -277,6 +277,7 @@ $string['idnumbertaken'] = 'This ID number is already in use';
|
||||
$string['idnumbertoolong'] = 'ID number is too long';
|
||||
$string['importformatnotimplement'] = 'Sorry, importing this format is not yet implemented!';
|
||||
$string['incorrectext'] = 'File has an incorrect extension';
|
||||
$string['inplaceeditableerror'] = 'Error calling update processor';
|
||||
$string['installproblem'] = 'It is usually not possible to recover from errors triggered during installation, you may need to create a new database or use a different database prefix if you want to retry the installation.';
|
||||
$string['internalauthpassworderror'] = 'Missing password or invalid password policy for internal authentication';
|
||||
$string['invalidaccess'] = 'This page was not accessed correctly';
|
||||
|
1
lib/amd/build/inplace_editable.min.js
vendored
Normal file
1
lib/amd/build/inplace_editable.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
define(["jquery","core/ajax","core/templates","core/notification","core/str","core/config"],function(a,b,c,d,e,f){return a("body").on("click keypress","[data-inplaceeditable] [data-inplaceeditablelink]",function(g){if("keypress"!==g.type||13===g.keyCode){g.stopImmediatePropagation(),g.preventDefault();var h=a(this),i=h.closest("[data-inplaceeditable]"),j=function(e,f){var g=b.call([{methodname:"core_update_inplace_editable",args:{itemid:e.attr("data-itemid"),component:e.attr("data-component"),itemtype:e.attr("data-itemtype"),value:f}}],!0);a.when.apply(a,g).done(function(a){var b=e.attr("data-value");c.render("core/inplace_editable",a).done(function(a,b){c.replaceNode(e,a,b),e.find("[data-inplaceeditablelink]").focus()}),e.trigger({type:"updated",ajaxreturn:a,oldvalue:b})}).fail(function(b){var c=a.Event("updatefailed",{exception:b,newvalue:f});e.trigger(c),c.isDefaultPrevented()||d.exception(b)})},k=function(a){var b=a.find("input");b.off(),a.html(a.attr("data-oldcontent")),a.removeAttr("data-oldcontent"),a.removeClass("inplaceeditingon")},l=function(){a("span.inplaceeditable.inplaceeditingon").each(function(){k(a(this))})},m=function(b,c){for(var d=b,e=0;c>e;e++)d+=String(Math.floor(10*Math.random()));return 0===a("#"+d).length?d:m(b,c)},n=function(b){b.addClass("inplaceeditingon"),b.attr("data-oldcontent",b.html()),e.get_string("edittitleinstructions").done(function(c){var d=a('<span class="editinstructions">'+c+"</span>").attr("id",m("id_editinstructions_",20)),e=a('<input type="text"/>').attr("id",m("id_inplacevalue_",20)).attr("value",b.attr("data-value")).attr("aria-describedby",d.attr("id")),g=a('<label class="accesshide">'+i.attr("data-editlabel")+"</label>").attr("for",e.attr("id"));b.html("").append(d).append(g).append(e),e.focus(),e.select(),e.on("keyup keypress focusout",function(a){f.behatsiterunning&&"focusout"===a.type||("keypress"===a.type&&13===a.keyCode&&(j(b,e.val()),k(b)),("keyup"===a.type&&27===a.keyCode||"focusout"===a.type)&&k(b))})})};l(),n(i)}}),{}});
|
2
lib/amd/build/tag.min.js
vendored
2
lib/amd/build/tag.min.js
vendored
@ -1 +1 @@
|
||||
define(["jquery","core/ajax","core/templates","core/notification","core/str","core/config"],function(a,b,c,d,e,f){return{init_tagindex_page:function(){a("body").delegate(".tagarea[data-ta] a[data-quickload=1]","click",function(d){d.preventDefault();var e=a(this),f=e.context.search.replace(/^\?/,""),g=e.closest(".tagarea[data-ta]"),h=f.split("&").reduce(function(a,b){var c=b.split("=");return a[c[0]]=decodeURIComponent(c[1]),a},{}),i=b.call([{methodname:"core_tag_get_tagindex",args:{tagindex:h}}],!0);a.when.apply(a,i).done(function(a){c.render("core_tag/index",a).done(function(a){g.replaceWith(a)})})})},init_manage_page:function(){var g=function(b){var c=b.closest("tr").get(0);if(c){var d=a(c).find("td.col-timemodified").get(0);e.get_string("now").done(function(b){a(d).html(b)})}};a(".tag-management-table").delegate(".tagisstandard","click",function(d){d.preventDefault();var e=a(this),f=e.attr("data-id"),h=e.attr("data-value"),i="1"===h?0:1,j=b.call([{methodname:"core_tag_update_tags",args:{tags:[{id:f,isstandard:i}]}},{methodname:"core_tag_get_tags",args:{tags:[{id:f}]}}],!0);a.when.apply(a,j).done(function(a,b){void 0===a.warnings[0]&&void 0!==b.tags[0]&&c.render("core_tag/tagisstandard",b.tags[0]).done(function(a){g(e);var b=e.parent();e.replaceWith(a),b.find(".tagisstandard").get(0).focus()})})}),a(".tag-management-table").delegate(".tagflag","click",function(d){d.preventDefault();var e=a(this),f=e.attr("data-id"),h=e.attr("data-value"),i="0"===h?1:0,j=b.call([{methodname:"core_tag_update_tags",args:{tags:[{id:f,flag:i}]}},{methodname:"core_tag_get_tags",args:{tags:[{id:f}]}}],!0);a.when.apply(a,j).done(function(b,d){if(void 0===b.warnings[0]&&void 0!==d.tags[0]){var f=e.closest("tr").get(0);f&&(d.tags[0].flag?a(f).addClass("flagged-tag"):a(f).removeClass("flagged-tag")),c.render("core_tag/tagflag",d.tags[0]).done(function(a){g(e);var b=e.parent();e.replaceWith(a),b.find(".tagflag").get(0).focus()})}})}),a(".tag-management-table").delegate("a.tagdelete","click",function(b){b.preventDefault();var c=a(this).attr("href");e.get_strings([{key:"delete"},{key:"confirmdeletetag",component:"tag"},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){window.location.href=c})})}),a("#tag-management-delete").click(function(b){var c=a(this).closest("form").get(0),f=a(c).find("input[type=checkbox]:checked").length;return f?(b.preventDefault(),void e.get_strings([{key:"delete"},{key:"confirmdeletetags",component:"tag"},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){c.submit()})})):!1}),a(".tag-management-table").delegate(".tagnameedit","click keypress",function(h){if("keypress"!==h.type||13===h.keyCode){h.stopImmediatePropagation(),h.preventDefault();var i=a(this),j=a(i.closest("td").get(0)),k=a(j.find("input").get(0)),l=i.attr("data-id"),m=function(f,h){var i=b.call([{methodname:"core_tag_update_tags",args:{tags:[{id:f,rawname:h}]}},{methodname:"core_tag_get_tags",args:{tags:[{id:f}]}}],!0);a.when.apply(a,i).done(function(b,f){void 0!==b.warnings[0]?e.get_string("error").done(function(a){d.alert(a,b.warnings[0].message)}):void 0!==f.tags[0]&&c.render("core_tag/tagname",f.tags[0]).done(function(b){g(j),j.html(b),a(j.find(".tagnameedit").get(0)).focus()})})},n=function(){a(".tag-management-table td.tageditingon").each(function(){var b=a(this),c=a(b.find("input").get(0));c.off(),b.removeClass("tageditingon"),c.val(b.attr("data-value"))})};n(),j.addClass("tageditingon"),j.attr("data-value",k.val()),k.select(),k.on("keypress focusout",function(a){f.behatsiterunning&&"focusout"===a.type||("keypress"===a.type&&13===a.keyCode&&(m(l,k.val()),n()),("keypress"===a.type&&27===a.keyCode||"focusout"===a.type)&&n())})}})}}});
|
||||
define(["jquery","core/ajax","core/templates","core/notification","core/str"],function(a,b,c,d,e){return{init_tagindex_page:function(){a("body").delegate(".tagarea[data-ta] a[data-quickload=1]","click",function(d){d.preventDefault();var e=a(this),f=e.context.search.replace(/^\?/,""),g=e.closest(".tagarea[data-ta]"),h=f.split("&").reduce(function(a,b){var c=b.split("=");return a[c[0]]=decodeURIComponent(c[1]),a},{}),i=b.call([{methodname:"core_tag_get_tagindex",args:{tagindex:h}}],!0);a.when.apply(a,i).done(function(a){c.render("core_tag/index",a).done(function(a){g.replaceWith(a)})})})},init_manage_page:function(){var f=function(b){var c=b.closest("tr").get(0);if(c){var d=a(c).find("td.col-timemodified").get(0);e.get_string("now").done(function(b){a(d).html(b)})}};a(".tag-management-table").delegate(".tagisstandard","click",function(d){d.preventDefault();var e=a(this),g=e.attr("data-id"),h=e.attr("data-value"),i="1"===h?0:1,j=b.call([{methodname:"core_tag_update_tags",args:{tags:[{id:g,isstandard:i}]}},{methodname:"core_tag_get_tags",args:{tags:[{id:g}]}}],!0);a.when.apply(a,j).done(function(a,b){void 0===a.warnings[0]&&void 0!==b.tags[0]&&c.render("core_tag/tagisstandard",b.tags[0]).done(function(a){f(e);var b=e.parent();e.replaceWith(a),b.find(".tagisstandard").get(0).focus()})})}),a(".tag-management-table").delegate(".tagflag","click",function(d){d.preventDefault();var e=a(this),g=e.attr("data-id"),h=e.attr("data-value"),i="0"===h?1:0,j=b.call([{methodname:"core_tag_update_tags",args:{tags:[{id:g,flag:i}]}},{methodname:"core_tag_get_tags",args:{tags:[{id:g}]}}],!0);a.when.apply(a,j).done(function(b,d){if(void 0===b.warnings[0]&&void 0!==d.tags[0]){var g=e.closest("tr").get(0);g&&(d.tags[0].flag?a(g).addClass("flagged-tag"):a(g).removeClass("flagged-tag")),c.render("core_tag/tagflag",d.tags[0]).done(function(a){f(e);var b=e.parent();e.replaceWith(a),b.find(".tagflag").get(0).focus()})}})}),a(".tag-management-table").delegate("a.tagdelete","click",function(b){b.preventDefault();var c=a(this).attr("href");e.get_strings([{key:"delete"},{key:"confirmdeletetag",component:"tag"},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){window.location.href=c})})}),a("#tag-management-delete").click(function(b){var c=a(this).closest("form").get(0),f=a(c).find("input[type=checkbox]:checked").length;return f?(b.preventDefault(),void e.get_strings([{key:"delete"},{key:"confirmdeletetags",component:"tag"},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){c.submit()})})):!1})}}});
|
138
lib/amd/src/inplace_editable.js
Normal file
138
lib/amd/src/inplace_editable.js
Normal file
@ -0,0 +1,138 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* AJAX helper for the inline editing a value.
|
||||
*
|
||||
* This script is automatically included from template core/inplace_editable
|
||||
* It registers a click-listener on [data-inplaceeditablelink] link (the "inplace edit" icon),
|
||||
* then replaces the displayed value with an input field. On "Enter" it sends a request
|
||||
* to web service core_update_inplace_editable, which invokes the specified callback.
|
||||
* Any exception thrown by the web service (or callback) is displayed as an error popup.
|
||||
*
|
||||
* @module core/inplace_editable
|
||||
* @package core
|
||||
* @copyright 2016 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @since 3.1
|
||||
*/
|
||||
define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str', 'core/config'],
|
||||
function($, ajax, templates, notification, str, cfg) {
|
||||
|
||||
$('body').on('click keypress', '[data-inplaceeditable] [data-inplaceeditablelink]', function(e) {
|
||||
if (e.type === 'keypress' && e.keyCode !== 13) {
|
||||
return;
|
||||
}
|
||||
e.stopImmediatePropagation();
|
||||
e.preventDefault();
|
||||
var target = $(this),
|
||||
mainelement = target.closest('[data-inplaceeditable]');
|
||||
|
||||
var update_value = function(mainelement, value) {
|
||||
var promises = ajax.call([{
|
||||
methodname: 'core_update_inplace_editable',
|
||||
args: { itemid : mainelement.attr('data-itemid'),
|
||||
component : mainelement.attr('data-component') ,
|
||||
itemtype : mainelement.attr('data-itemtype') ,
|
||||
value : value }
|
||||
}], true);
|
||||
|
||||
$.when.apply($, promises)
|
||||
.done( function(data) {
|
||||
var oldvalue = mainelement.attr('data-value');
|
||||
templates.render('core/inplace_editable', data).done(function(html, js) {
|
||||
templates.replaceNode(mainelement, html, js);
|
||||
mainelement.find('[data-inplaceeditablelink]').focus();
|
||||
});
|
||||
mainelement.trigger({type: 'updated', ajaxreturn: data, oldvalue: oldvalue});
|
||||
}).fail(function(ex) {
|
||||
var e = $.Event('updatefailed', { exception: ex, newvalue: value });
|
||||
mainelement.trigger(e);
|
||||
if (!e.isDefaultPrevented()) {
|
||||
notification.exception(ex);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var turn_editing_off = function(el) {
|
||||
var input = el.find('input');
|
||||
input.off();
|
||||
el.html(el.attr('data-oldcontent'));
|
||||
el.removeAttr('data-oldcontent');
|
||||
el.removeClass('inplaceeditingon');
|
||||
};
|
||||
|
||||
var turn_editing_off_everywhere = function() {
|
||||
$('span.inplaceeditable.inplaceeditingon').each(function() {
|
||||
turn_editing_off($( this));
|
||||
});
|
||||
};
|
||||
|
||||
var unique_id = function(prefix, idlength) {
|
||||
var uniqid = prefix;
|
||||
for (var i = 0; i < idlength; i++) {
|
||||
uniqid += String(Math.floor(Math.random() * 10));
|
||||
}
|
||||
// Make sure this ID is not already taken by an existing element.
|
||||
if ($("#" + uniqid).length === 0) {
|
||||
return uniqid;
|
||||
}
|
||||
return unique_id(prefix, idlength);
|
||||
};
|
||||
|
||||
var turn_editing_on = function(el) {
|
||||
el.addClass('inplaceeditingon');
|
||||
el.attr('data-oldcontent', el.html());
|
||||
|
||||
str.get_string('edittitleinstructions').done(function(s) {
|
||||
var instr = $('<span class="editinstructions">' + s + '</span>').
|
||||
attr('id', unique_id('id_editinstructions_', 20)),
|
||||
inputelement = $('<input type="text"/>').
|
||||
attr('id', unique_id('id_inplacevalue_', 20)).
|
||||
attr('value', el.attr('data-value')).
|
||||
attr('aria-describedby', instr.attr('id')),
|
||||
lbl = $('<label class="accesshide">' + mainelement.attr('data-editlabel') + '</label>').
|
||||
attr('for', inputelement.attr('id'));
|
||||
el.html('').append(instr).append(lbl).append(inputelement);
|
||||
|
||||
inputelement.focus();
|
||||
inputelement.select();
|
||||
inputelement.on('keyup keypress focusout', function(e) {
|
||||
if (cfg.behatsiterunning && e.type === 'focusout') {
|
||||
// Behat triggers focusout too often.
|
||||
return;
|
||||
}
|
||||
if (e.type === 'keypress' && e.keyCode === 13) {
|
||||
// We need 'keypress' event for Enter because keyup/keydown would catch Enter that was
|
||||
// pressed in other fields.
|
||||
update_value(el, inputelement.val());
|
||||
turn_editing_off(el);
|
||||
}
|
||||
if ((e.type === 'keyup' && e.keyCode === 27) || e.type === 'focusout') {
|
||||
// We need 'keyup' event for Escape because keypress does not work with Escape.
|
||||
turn_editing_off(el);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Turn editing on for the current element and register handler for Enter/Esc keys.
|
||||
turn_editing_off_everywhere();
|
||||
turn_editing_on(mainelement);
|
||||
|
||||
});
|
||||
|
||||
return {};
|
||||
});
|
@ -22,8 +22,8 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @since 3.0
|
||||
*/
|
||||
define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str', 'core/config'],
|
||||
function($, ajax, templates, notification, str, cfg) {
|
||||
define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str'],
|
||||
function($, ajax, templates, notification, str) {
|
||||
return /** @alias module:core/tag */ {
|
||||
|
||||
/**
|
||||
@ -174,74 +174,6 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str'
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Edit tag name.
|
||||
$('.tag-management-table').delegate('.tagnameedit', 'click keypress', function(e) {
|
||||
if (e.type === 'keypress' && e.keyCode !== 13) {
|
||||
return;
|
||||
}
|
||||
e.stopImmediatePropagation();
|
||||
e.preventDefault();
|
||||
var target = $(this),
|
||||
tdelement = $( target.closest('td').get(0) ),
|
||||
inputelement = $( tdelement.find('input').get(0) ),
|
||||
tagid = target.attr('data-id');
|
||||
|
||||
var change_name = function(tagid, newname) {
|
||||
var promises = ajax.call([{
|
||||
methodname: 'core_tag_update_tags',
|
||||
args: { tags : [ { id : tagid , rawname : newname } ] }
|
||||
}, {
|
||||
methodname: 'core_tag_get_tags',
|
||||
args: { tags : [ { id : tagid } ] }
|
||||
}], true);
|
||||
|
||||
$.when.apply($, promises)
|
||||
.done( function(updateresult, data) {
|
||||
if (updateresult.warnings[0] !== undefined) {
|
||||
str.get_string('error').done(function(s) {
|
||||
notification.alert(s, updateresult.warnings[0].message);
|
||||
});
|
||||
} else if (data.tags[0] !== undefined) {
|
||||
templates.render('core_tag/tagname', data.tags[0]).done(function(html) {
|
||||
update_modified(tdelement);
|
||||
tdelement.html(html);
|
||||
$(tdelement.find('.tagnameedit').get(0)).focus();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var turn_editing_off = function() {
|
||||
$('.tag-management-table td.tageditingon').each(function() {
|
||||
var td = $( this ),
|
||||
input = $( td.find('input').get(0) );
|
||||
input.off();
|
||||
td.removeClass('tageditingon');
|
||||
// Reset input value to the one that was there before editing.
|
||||
input.val(td.attr('data-value'));
|
||||
});
|
||||
};
|
||||
|
||||
// Turn editing on for the current element and register handler for Enter/Esc keys.
|
||||
turn_editing_off();
|
||||
tdelement.addClass('tageditingon');
|
||||
tdelement.attr('data-value', inputelement.val());
|
||||
inputelement.select();
|
||||
inputelement.on('keypress focusout', function(e) {
|
||||
if (cfg.behatsiterunning && e.type === 'focusout') {
|
||||
// Behat triggers focusout too often.
|
||||
return;
|
||||
}
|
||||
if (e.type === 'keypress' && e.keyCode === 13) {
|
||||
change_name(tagid, inputelement.val());
|
||||
turn_editing_off();
|
||||
}
|
||||
if ((e.type === 'keypress' && e.keyCode === 27) || e.type === 'focusout') {
|
||||
turn_editing_off();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
@ -107,8 +107,14 @@ class behat_form_field {
|
||||
// dealing with a fgroup element.
|
||||
$instance = $this->guess_type();
|
||||
$instance->field->keyDown($char, $modifier);
|
||||
$instance->field->keyPress($char, $modifier);
|
||||
$instance->field->keyUp($char, $modifier);
|
||||
try {
|
||||
$instance->field->keyPress($char, $modifier);
|
||||
$instance->field->keyUp($char, $modifier);
|
||||
} catch (WebDriver\Exception $e) {
|
||||
// If the JS handler attached to keydown or keypress destroys the element
|
||||
// the later events may trigger errors because form element no longer exist
|
||||
// or is not visible. Ignore such exceptions here.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
146
lib/classes/output/inplace_editable.php
Normal file
146
lib/classes/output/inplace_editable.php
Normal file
@ -0,0 +1,146 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains class \core\output\inplace_editable
|
||||
*
|
||||
* @package core
|
||||
* @category output
|
||||
* @copyright 2016 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core\output;
|
||||
|
||||
use templatable;
|
||||
use renderable;
|
||||
use lang_string;
|
||||
|
||||
/**
|
||||
* Class allowing to quick edit a title inline
|
||||
*
|
||||
* This class is used for displaying an element that can be in-place edited by the user. To display call:
|
||||
* echo $OUTPUT->render($element);
|
||||
* or
|
||||
* echo $OUTPUT->render_from_template('core/inplace_editable', $element->export_for_template($OUTPUT));
|
||||
*
|
||||
* Template core/inplace_editable will automatically load javascript module with the same name
|
||||
* core/inplace_editable. Javascript module registers a click-listener on edit link and
|
||||
* then replaces the displayed value with an input field. On "Enter" it sends a request
|
||||
* to web service core_update_inplace_editable, which invokes the callback from the component.
|
||||
* Any exception thrown by the web service (or callback) is displayed as an error popup.
|
||||
*
|
||||
* Callback {$component}_inplace_editable($itemtype, $itemid, $newvalue) must be present in the lib.php file of
|
||||
* the component or plugin. It must return instance of this class.
|
||||
*
|
||||
* @package core
|
||||
* @category output
|
||||
* @copyright 2016 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class inplace_editable implements templatable, renderable {
|
||||
|
||||
/**
|
||||
* @var string component responsible for diplsying/updating
|
||||
*/
|
||||
protected $component = null;
|
||||
|
||||
/**
|
||||
* @var string itemtype inside the component
|
||||
*/
|
||||
protected $itemtype = null;
|
||||
|
||||
/**
|
||||
* @var int identifier of the editable element (usually database id)
|
||||
*/
|
||||
protected $itemid = null;
|
||||
|
||||
/**
|
||||
* @var string value of the editable element as it is present in the database
|
||||
*/
|
||||
protected $value = null;
|
||||
|
||||
/**
|
||||
* @var string value of the editable element as it should be displayed,
|
||||
* must be formatted and may contain links or other html tags
|
||||
*/
|
||||
protected $displayvalue = null;
|
||||
|
||||
/**
|
||||
* @var string label for the input element (for screenreaders)
|
||||
*/
|
||||
protected $editlabel = null;
|
||||
|
||||
/**
|
||||
* @var string hint for the input element (for screenreaders)
|
||||
*/
|
||||
protected $edithint = null;
|
||||
|
||||
/**
|
||||
* @var bool indicates if the current user is allowed to edit this element - set in constructor after permissions are checked
|
||||
*/
|
||||
protected $editable = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $component name of the component or plugin responsible for the updating of the value (must declare callback)
|
||||
* @param string $itemtype type of the item inside the component - each component/plugin may implement multiple inplace-editable elements
|
||||
* @param int $itemid identifier of the item that can be edited in-place
|
||||
* @param bool $editable whether this value is editable (check capabilities and editing mode), if false, only "displayvalue"
|
||||
* will be displayed without anything else
|
||||
* @param string $displayvalue what needs to be displayed to the user, it must be cleaned, with applied filters (call
|
||||
* {@link format_string()}). It may be wrapped in an html link, contain icons or other decorations
|
||||
* @param string $value what needs to be edited - usually raw value from the database, it may contain multilang tags
|
||||
* @param lang_string|string $edithint hint (title) that will be displayed under the edit link
|
||||
* @param lang_string|string $editlabel label for the input element in the editing mode (for screenreaders)
|
||||
*/
|
||||
public function __construct($component, $itemtype, $itemid, $editable,
|
||||
$displayvalue, $value = null, $edithint = null, $editlabel = null) {
|
||||
$this->component = $component;
|
||||
$this->itemtype = $itemtype;
|
||||
$this->itemid = $itemid;
|
||||
$this->editable = $editable;
|
||||
$this->displayvalue = $displayvalue;
|
||||
$this->value = $value;
|
||||
$this->edithint = $edithint;
|
||||
$this->editlabel = $editlabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export this data so it can be used as the context for a mustache template (core/inplace_editable).
|
||||
*
|
||||
* @param renderer_base $output typically, the renderer that's calling this function
|
||||
* @return array data context for a mustache template
|
||||
*/
|
||||
public function export_for_template(\renderer_base $output) {
|
||||
if (!$this->editable) {
|
||||
return array(
|
||||
'displayvalue' => (string)$this->displayvalue
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'component' => $this->component,
|
||||
'itemtype' => $this->itemtype,
|
||||
'itemid' => $this->itemid,
|
||||
'displayvalue' => (string)$this->displayvalue,
|
||||
'value' => (string)$this->value,
|
||||
'edithint' => (string)$this->edithint,
|
||||
'editlabel' => (string)$this->editlabel,
|
||||
);
|
||||
}
|
||||
}
|
@ -1060,6 +1060,15 @@ $functions = array(
|
||||
'ajax' => true,
|
||||
),
|
||||
|
||||
'core_update_inplace_editable' => array(
|
||||
'classname' => 'core_external',
|
||||
'methodname' => 'update_inplace_editable',
|
||||
'classpath' => 'lib/external/externallib.php',
|
||||
'description' => 'Generic service to update title',
|
||||
'type' => 'write',
|
||||
'loginrequired' => true,
|
||||
'ajax' => true
|
||||
),
|
||||
|
||||
// === Calendar related functions ===
|
||||
|
||||
|
61
lib/external/externallib.php
vendored
61
lib/external/externallib.php
vendored
@ -346,4 +346,65 @@ class core_external extends external_api {
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for function update_inplace_editable()
|
||||
*
|
||||
* @since Moodle 3.1
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function update_inplace_editable_parameters() {
|
||||
return new external_function_parameters(
|
||||
array(
|
||||
'component' => new external_value(PARAM_COMPONENT, 'component responsible for the update', VALUE_REQUIRED),
|
||||
'itemtype' => new external_value(PARAM_NOTAGS, 'type of the updated item inside the component', VALUE_REQUIRED),
|
||||
'itemid' => new external_value(PARAM_INT, 'identifier of the updated item', VALUE_REQUIRED),
|
||||
'value' => new external_value(PARAM_RAW, 'new value', VALUE_REQUIRED),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update any component's editable value assuming that component implements necessary callback
|
||||
*
|
||||
* @since Moodle 3.1
|
||||
* @param string $component
|
||||
* @param string $itemtype
|
||||
* @param string $itemid
|
||||
* @param string $value
|
||||
*/
|
||||
public static function update_inplace_editable($component, $itemtype, $itemid, $value) {
|
||||
global $PAGE;
|
||||
// Validate and normalize parameters.
|
||||
$params = self::validate_parameters(self::update_inplace_editable_parameters(),
|
||||
array('component' => $component, 'itemtype' => $itemtype, 'itemid' => $itemid, 'value' => $value));
|
||||
if (!$functionname = component_callback_exists($component, 'inplace_editable')) {
|
||||
throw new \moodle_exception('inplaceeditableerror');
|
||||
}
|
||||
$tmpl = component_callback($params['component'], 'inplace_editable',
|
||||
array($params['itemtype'], $params['itemid'], $params['value']));
|
||||
if (!$tmpl || !($tmpl instanceof \core\output\inplace_editable)) {
|
||||
throw new \moodle_exception('inplaceeditableerror');
|
||||
}
|
||||
return $tmpl->export_for_template($PAGE->get_renderer('core'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return structure for update_inplace_editable()
|
||||
*
|
||||
* @since Moodle 3.1
|
||||
* @return external_description
|
||||
*/
|
||||
public static function update_inplace_editable_returns() {
|
||||
return new external_single_structure(
|
||||
array(
|
||||
'displayvalue' => new external_value(PARAM_RAW, 'display value (may contain link or other html tags)'),
|
||||
'component' => new external_value(PARAM_NOTAGS, 'component responsible for the update', VALUE_OPTIONAL),
|
||||
'itemtype' => new external_value(PARAM_NOTAGS, 'itemtype', VALUE_OPTIONAL),
|
||||
'value' => new external_value(PARAM_RAW, 'value of the item as it is stored', VALUE_OPTIONAL),
|
||||
'itemid' => new external_value(PARAM_RAW, 'identifier of the updated item', VALUE_OPTIONAL),
|
||||
'edithint' => new external_value(PARAM_NOTAGS, 'hint for editing element', VALUE_OPTIONAL),
|
||||
'editlabel' => new external_value(PARAM_NOTAGS, 'label for editing element', VALUE_OPTIONAL),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
23
lib/external/tests/external_test.php
vendored
23
lib/external/tests/external_test.php
vendored
@ -135,4 +135,27 @@ class core_external_testcase extends externallib_advanced_testcase {
|
||||
$this->assertSame($string['string'], $wsstrings[$string['stringid']]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test update_inplace_editable()
|
||||
*/
|
||||
public function test_update_inplace_editable() {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
// Call service for component that does not have inplace_editable callback.
|
||||
try {
|
||||
core_external::update_inplace_editable('tool_log', 'itemtype', 1, 'newvalue');
|
||||
$this->fail('Exception expected');
|
||||
} catch (moodle_exception $e) {
|
||||
$this->assertEquals('Error calling update processor', $e->getMessage());
|
||||
}
|
||||
|
||||
// This is a very basic test for the return value of the external function.
|
||||
// More detailed test for tag updating can be found in core_tag component.
|
||||
$this->setAdminUser();
|
||||
$tag = $this->getDataGenerator()->create_tag();
|
||||
$res = core_external::update_inplace_editable('core_tag', 'tagname', $tag->id, 'new tag name');
|
||||
$res = external_api::clean_returnvalue(core_external::update_inplace_editable_returns(), $res);
|
||||
$this->assertEquals('new tag name', $res['value']);
|
||||
}
|
||||
}
|
||||
|
@ -4120,6 +4120,16 @@ EOD;
|
||||
$list = new \core_tag\output\taglist($tags, $label, $classes, $limit, $pagecontext);
|
||||
return $this->render_from_template('core_tag/taglist', $list->export_for_template($this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders element for inline editing of any value
|
||||
*
|
||||
* @param \core\output\inplace_editable $element
|
||||
* @return string
|
||||
*/
|
||||
public function render_inplace_editable(\core\output\inplace_editable $element) {
|
||||
return $this->render_from_template('core/inplace_editable', $element->export_for_template($this));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
60
lib/templates/inplace_editable.mustache
Normal file
60
lib/templates/inplace_editable.mustache
Normal file
@ -0,0 +1,60 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template core/inplace_editable
|
||||
|
||||
Displays the value that can be edited inline.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* data-inplaceeditable
|
||||
* data-inplaceeditablelink
|
||||
* data-identifier
|
||||
* data-callback
|
||||
|
||||
Context variables required for this template:
|
||||
* none
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"displayvalue" : "<a href=\"#\">Moodle</a>",
|
||||
"value" : "Moodle",
|
||||
"itemid" : "1",
|
||||
"component" : "core_tag",
|
||||
"itemtype" : "tagname",
|
||||
"edithint" : "Edit this",
|
||||
"editlabel" : "New name for this"
|
||||
}
|
||||
}}
|
||||
{{#component}}
|
||||
<span class="inplaceeditable" data-inplaceeditable="1" data-component="{{component}}" data-itemtype="{{itemtype}}" data-itemid="{{itemid}}"
|
||||
data-value="{{value}}" data-editlabel="{{editlabel}}">
|
||||
{{{displayvalue}}}
|
||||
<a href="#" class="quickeditlink visibleifjs" data-inplaceeditablelink="1" title="{{edithint}}">
|
||||
{{#pix}}t/editstring,core,{{edithint}}{{/pix}}
|
||||
</a>
|
||||
</span>
|
||||
{{#js}}
|
||||
require(['core/inplace_editable']);
|
||||
{{/js}}
|
||||
{{/component}}
|
||||
{{^component}}
|
||||
{{{displayvalue}}}
|
||||
{{/component}}
|
||||
|
@ -179,8 +179,8 @@ class core_tag_manage_table extends table_sql {
|
||||
*/
|
||||
public function col_name($tag) {
|
||||
global $OUTPUT;
|
||||
$tagoutput = new core_tag\output\tag($tag);
|
||||
return $OUTPUT->render_from_template('core_tag/tagname', $tagoutput->export_for_template($OUTPUT));
|
||||
$tagoutput = new core_tag\output\tagname($tag);
|
||||
return $OUTPUT->render_from_template('core/inplace_editable', $tagoutput->export_for_template($OUTPUT));
|
||||
}
|
||||
|
||||
/**
|
||||
|
55
tag/classes/output/tagname.php
Normal file
55
tag/classes/output/tagname.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains class core_tag\output\tagname
|
||||
*
|
||||
* @package core_tag
|
||||
* @copyright 2016 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_tag\output;
|
||||
|
||||
use context_system;
|
||||
use lang_string;
|
||||
use html_writer;
|
||||
use core_tag_tag;
|
||||
|
||||
/**
|
||||
* Class to preapare a tag name for display.
|
||||
*
|
||||
* @package core_tag
|
||||
* @copyright 2016 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tagname extends \core\output\inplace_editable {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param stdClass|core_tag $tag
|
||||
*/
|
||||
public function __construct($tag) {
|
||||
$editable = has_capability('moodle/tag:manage', context_system::instance());
|
||||
$edithint = new lang_string('editname', 'core_tag');
|
||||
$editlabel = new lang_string('newnamefor', 'core_tag', $tag->rawname);
|
||||
$value = $tag->rawname;
|
||||
$displayvalue = html_writer::link(core_tag_tag::make_url($tag->tagcollid, $tag->rawname),
|
||||
core_tag_tag::make_display_name($tag));
|
||||
parent::__construct('core_tag', 'tagname', $tag->id, $editable, $displayvalue, $value, $edithint, $editlabel);
|
||||
}
|
||||
}
|
@ -892,14 +892,12 @@ class core_tag_tag {
|
||||
$data['rawname'] = clean_param($data['rawname'], PARAM_TAG);
|
||||
$name = core_text::strtolower($data['rawname']);
|
||||
|
||||
if (!$name) {
|
||||
if (!$name || $data['rawname'] === $this->rawname) {
|
||||
unset($data['rawname']);
|
||||
} else if ($existing = static::get_by_name($this->tagcollid, $name, 'id')) {
|
||||
// Prevent the rename if a tag with that name already exists.
|
||||
if ($existing->id != $this->id) {
|
||||
debugging('New tag name already exists, you should check it before calling core_tag_tag::update()',
|
||||
DEBUG_DEVELOPER);
|
||||
unset($data['rawname']);
|
||||
throw new moodle_exception('namesalreadybeeingused', 'core_tag');
|
||||
}
|
||||
}
|
||||
if (isset($data['rawname'])) {
|
||||
|
17
tag/lib.php
17
tag/lib.php
@ -40,3 +40,20 @@ function tag_page_type_list($pagetype, $parentcontext, $currentcontext) {
|
||||
'tag-manage'=>get_string('page-tag-manage', 'tag')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements callback inplace_editable() allowing to edit values in-place
|
||||
*
|
||||
* @param string $itemtype
|
||||
* @param int $itemid
|
||||
* @param mixed $newvalue
|
||||
* @return \core\output\inplace_editable
|
||||
*/
|
||||
function core_tag_inplace_editable($itemtype, $itemid, $newvalue) {
|
||||
if ($itemtype === 'tagname') {
|
||||
require_capability('moodle/tag:manage', context_system::instance());
|
||||
$tag = core_tag_tag::get($itemid, '*', MUST_EXIST);
|
||||
$tag->update(array('rawname' => $newvalue));
|
||||
return new \core_tag\output\tagname($tag);
|
||||
}
|
||||
}
|
||||
|
@ -1,57 +0,0 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_tag/tagname
|
||||
|
||||
Displays the tag name in the tag management table.
|
||||
|
||||
For the Javascript handlers it is important that this template contains
|
||||
an element with .tagnameedit class (to switch on editing) and also
|
||||
an input element.
|
||||
When element with class .tagnameedit is clicked, JS will add class
|
||||
.tageditingon to the container td tag.
|
||||
|
||||
Classes required for JS:
|
||||
* tagnameedit
|
||||
|
||||
Data attributes required for JS:
|
||||
* data-id
|
||||
|
||||
Context variables required for this template:
|
||||
* none
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"id" : "1",
|
||||
"name" : "moodle",
|
||||
"rawname" : "Moodle",
|
||||
"viewurl" : "http://moodle.com/"
|
||||
}
|
||||
}}
|
||||
<span class="displaytagname">
|
||||
<a href="{{viewurl}}" data-id="{{id}}">
|
||||
{{rawname}}
|
||||
</a>
|
||||
<a href="#" class="tagnameedit visibleifjs" data-id="{{id}}" title="{{#str}}editname,core_tag{{/str}}">
|
||||
{{#pix}}t/editstring,core,{{#str}}editname,core_tag{{/str}}{{/pix}}
|
||||
</a>
|
||||
</span>
|
||||
<span class="edittagname">
|
||||
<span class="editinstructions" id="id_editinstructions_{{id}}">{{#str}}edittitleinstructions,core{{/str}}</span>
|
||||
<label class="accesshide" for="tagquickname{{id}}">{{#str}}newnamefor,core_tag,{{rawname}}{{/str}}</label>
|
||||
<input id="tagquickname{{id}}" type="text" value="{{rawname}}" data-id="{{id}}" aria-describedby="id_editinstructions_{{id}}"/>
|
||||
</span>
|
@ -153,7 +153,7 @@ Feature: Users can edit tags to add description or rename
|
||||
And I set the field "New name for tag Cat" to "Kitten"
|
||||
And I press key "13" in the field "New name for tag Cat"
|
||||
Then I should not see "Cat"
|
||||
And "New name for tag" "field" should not be visible
|
||||
And "New name for tag" "field" should not exist
|
||||
And I wait until "Kitten" "link" exists
|
||||
And I follow "Default collection"
|
||||
And I should see "Kitten"
|
||||
@ -163,8 +163,8 @@ Feature: Users can edit tags to add description or rename
|
||||
And I set the field "New name for tag Turtle" to "DOG"
|
||||
And I press key "13" in the field "New name for tag Turtle"
|
||||
And I should see "Tag names already being used"
|
||||
And I press "Ok"
|
||||
And "New name for tag" "field" should not be visible
|
||||
And I press "Close"
|
||||
And "New name for tag" "field" should not exist
|
||||
And I should see "Turtle"
|
||||
And I should see "Dog"
|
||||
And I should not see "DOG"
|
||||
@ -176,7 +176,7 @@ Feature: Users can edit tags to add description or rename
|
||||
And I click on "Edit tag name" "link" in the "Dog" "table_row"
|
||||
And I set the field "New name for tag Dog" to "Penguin"
|
||||
And I press key "27" in the field "New name for tag Dog"
|
||||
And "New name for tag" "field" should not be visible
|
||||
And "New name for tag" "field" should not exist
|
||||
And I should see "Turtle"
|
||||
And I should not see "Penguin"
|
||||
And I follow "Default collection"
|
||||
|
@ -147,4 +147,38 @@ class core_tag_external_testcase extends externallib_advanced_testcase {
|
||||
$this->assertEquals($tag->id, $result['warnings'][0]['item']);
|
||||
$this->assertEquals('namesalreadybeeingused', $result['warnings'][0]['warningcode']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test update_inplace_editable()
|
||||
*/
|
||||
public function test_update_inplace_editable() {
|
||||
global $CFG, $DB, $PAGE;
|
||||
require_once($CFG->dirroot . '/lib/external/externallib.php');
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
$tag = $this->getDataGenerator()->create_tag();
|
||||
|
||||
// Call service for core_tag component without necessary permissions.
|
||||
try {
|
||||
core_external::update_inplace_editable('core_tag', 'tagname', $tag->id, 'new tag name');
|
||||
$this->fail('Exception expected');
|
||||
} catch (moodle_exception $e) {
|
||||
$this->assertEquals('Sorry, but you do not currently have permissions to do that (Manage all tags)',
|
||||
$e->getMessage());
|
||||
}
|
||||
|
||||
// Change to admin user and make sure that tag name can be updated using web service update_inplace_editable().
|
||||
$this->setAdminUser();
|
||||
$res = core_external::update_inplace_editable('core_tag', 'tagname', $tag->id, 'New tag name');
|
||||
$res = external_api::clean_returnvalue(core_external::update_inplace_editable_returns(), $res);
|
||||
$this->assertEquals('New tag name', $res['value']);
|
||||
$this->assertEquals('New tag name', $DB->get_field('tag', 'rawname', array('id' => $tag->id)));
|
||||
|
||||
// Call callback core_tag_inplace_editable() directly.
|
||||
$tmpl = component_callback('core_tag', 'inplace_editable', array('tagname', $tag->id, 'Rename me again'));
|
||||
$this->assertInstanceOf('core\output\inplace_editable', $tmpl);
|
||||
$res = $tmpl->export_for_template($PAGE->get_renderer('core'));
|
||||
$this->assertEquals('Rename me again', $res['value']);
|
||||
$this->assertEquals('Rename me again', $DB->get_field('tag', 'rawname', array('id' => $tag->id)));
|
||||
}
|
||||
}
|
||||
|
@ -751,14 +751,7 @@ span.flagged-tag a,
|
||||
tr.flagged-tag a {color:#FF0000;}
|
||||
.tag-management-table td,
|
||||
.tag-management-table th {vertical-align: middle;padding: 4px;}
|
||||
.tag-management-table tr td.tageditingon .displaytagname,
|
||||
.tag-management-table td .edittagname {display: none;}
|
||||
.tag-management-table tr td.tageditingon .edittagname {display: inherit; position: relative;}
|
||||
.tag-management-table tr td.tageditingon .edittagname .editinstructions {margin-right: -300px; margin-left: 0;}
|
||||
.tag-management-table tr td .tagnameedit img {opacity: 0.2;}
|
||||
.tag-management-table tr:hover td .tagnameedit img,
|
||||
.tag-management-table tr td .tagnameedit:focus img {opacity: 1;}
|
||||
.tag-management-table tr:hover td.tageditingon .tagnameedit img {opacity: 0.2;}
|
||||
.tag-management-table span.inplaceeditable.inplaceeditingon input {width: 150px;}
|
||||
.tag_feed .media, .tag_feed .media-body {overflow: hidden;}
|
||||
.tag_feed.media-list .media .itemimage {float: left;}
|
||||
.dir-rtl .tag_feed.media-list .media .itemimage {float: right;}
|
||||
@ -2330,3 +2323,30 @@ body.lockscroll {
|
||||
.ie10 .yui3-calendar-header-label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
span.inplaceeditable.inplaceeditingon {
|
||||
position: relative;
|
||||
}
|
||||
span.inplaceeditable.inplaceeditingon span.editinstructions {
|
||||
margin-top: -30px;
|
||||
font-weight: normal;
|
||||
margin-right: -300px;
|
||||
margin-left: 0;
|
||||
}
|
||||
.dir-rtl span.inplaceeditable.inplaceeditingon span.editinstructions {
|
||||
margin-left: -300px;
|
||||
margin-right: 0;
|
||||
}
|
||||
span.inplaceeditable .quickeditlink img {
|
||||
opacity: 0.2;
|
||||
}
|
||||
span.inplaceeditable:hover .quickeditlink img,
|
||||
span.inplaceeditable .quickeditlink:focus img {
|
||||
opacity: 1;
|
||||
}
|
||||
span.inplaceeditable.inplaceeditingon input {
|
||||
width: 330px;
|
||||
height: 16px;
|
||||
vertical-align: text-bottom;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
@ -826,27 +826,8 @@ tr.flagged-tag a {
|
||||
vertical-align: middle;
|
||||
padding: 4px;
|
||||
}
|
||||
.tag-management-table tr td.tageditingon .displaytagname,
|
||||
.tag-management-table td .edittagname {
|
||||
display: none;
|
||||
}
|
||||
.tag-management-table tr td.tageditingon .edittagname {
|
||||
display: inherit;
|
||||
position: relative;
|
||||
}
|
||||
.tag-management-table tr td.tageditingon .edittagname .editinstructions {
|
||||
margin-right: -300px;
|
||||
margin-left: 0;
|
||||
}
|
||||
.tag-management-table tr td .tagnameedit img {
|
||||
opacity: 0.2;
|
||||
}
|
||||
.tag-management-table tr:hover td .tagnameedit img,
|
||||
.tag-management-table tr td .tagnameedit:focus img {
|
||||
opacity: 1;
|
||||
}
|
||||
.tag-management-table tr:hover td.tageditingon .tagnameedit img {
|
||||
opacity: 0.2;
|
||||
.tag-management-table span.inplaceeditable.inplaceeditingon input {
|
||||
width: 150px;
|
||||
}
|
||||
.path-tag .tag-relatedtags {
|
||||
padding-top: 10px;
|
||||
@ -2445,3 +2426,33 @@ dd:after {
|
||||
.nav-tabs > .active > a[href]:focus {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
span.inplaceeditable.inplaceeditingon {
|
||||
position: relative;
|
||||
}
|
||||
span.inplaceeditable.inplaceeditingon span.editinstructions {
|
||||
margin-top: -30px;
|
||||
font-weight: normal;
|
||||
margin-right: -300px;
|
||||
margin-left: 0;
|
||||
}
|
||||
.dir-rtl span.inplaceeditable.inplaceeditingon span.editinstructions {
|
||||
margin-left: -300px;
|
||||
margin-right: 0;
|
||||
}
|
||||
span.inplaceeditable .quickeditlink img {
|
||||
opacity: 0.2;
|
||||
}
|
||||
span.inplaceeditable:hover .quickeditlink img,
|
||||
span.inplaceeditable .quickeditlink:focus img {
|
||||
opacity: 1;
|
||||
}
|
||||
span.inplaceeditable.inplaceeditingon input {
|
||||
width: 330px;
|
||||
height: 16px;
|
||||
vertical-align: text-bottom;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
h3.sectionname span.inplaceeditable.inplaceeditingon span.editinstructions {
|
||||
margin-top: -20px;
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2016021100.00; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
$version = 2016021500.00; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user