mirror of
https://github.com/moodle/moodle.git
synced 2025-03-14 12:40:01 +01:00
MDL-66539 atto_link: Non-intuitive action for atto link button
This commit is contained in:
parent
30b8ad51f4
commit
6372d61f71
@ -29,3 +29,4 @@ $string['openinnewwindow'] = 'Open in new window';
|
|||||||
$string['pluginname'] = 'Link';
|
$string['pluginname'] = 'Link';
|
||||||
$string['unlink'] = 'Unlink';
|
$string['unlink'] = 'Unlink';
|
||||||
$string['privacy:metadata'] = 'The atto_link plugin does not store any personal data.';
|
$string['privacy:metadata'] = 'The atto_link plugin does not store any personal data.';
|
||||||
|
$string['texttodisplay'] = 'Text to display';
|
||||||
|
@ -35,7 +35,8 @@ function atto_link_strings_for_js() {
|
|||||||
'unlink',
|
'unlink',
|
||||||
'enterurl',
|
'enterurl',
|
||||||
'browserepositories',
|
'browserepositories',
|
||||||
'openinnewwindow'),
|
'openinnewwindow',
|
||||||
|
'texttodisplay'),
|
||||||
'atto_link');
|
'atto_link');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ Feature: Add links to Atto
|
|||||||
And I set the field "Description" to "Super cool"
|
And I set the field "Description" to "Super cool"
|
||||||
And I select the text in the "Description" Atto editor
|
And I select the text in the "Description" Atto editor
|
||||||
And I click on "Link" "button"
|
And I click on "Link" "button"
|
||||||
|
Then the field "Text to display" matches value "Super cool"
|
||||||
And I click on "Browse repositories..." "button"
|
And I click on "Browse repositories..." "button"
|
||||||
And I click on "Private files" "link" in the ".fp-repo-area" "css_element"
|
And I click on "Private files" "link" in the ".fp-repo-area" "css_element"
|
||||||
And I click on "moodle-logo.png" "link"
|
And I click on "moodle-logo.png" "link"
|
||||||
@ -22,4 +23,59 @@ Feature: Add links to Atto
|
|||||||
And I set the field "Text editor" to "Plain text area"
|
And I set the field "Text editor" to "Plain text area"
|
||||||
And I press "Save changes"
|
And I press "Save changes"
|
||||||
And I click on "Edit profile" "link" in the "region-main" "region"
|
And I click on "Edit profile" "link" in the "region-main" "region"
|
||||||
Then I should see "Super cool</a>"
|
And I should see "Super cool</a>"
|
||||||
|
|
||||||
|
@javascript
|
||||||
|
Scenario: Insert a link without providing text to display
|
||||||
|
Given I log in as "admin"
|
||||||
|
When I open my profile in edit mode
|
||||||
|
And I click on "Link" "button"
|
||||||
|
And I set the field "Enter a URL" to "https://moodle.org/"
|
||||||
|
Then the field "Text to display" matches value "https://moodle.org/"
|
||||||
|
And I click on "Create link" "button"
|
||||||
|
And I should see "https://moodle.org/"
|
||||||
|
And I click on "Link" "button"
|
||||||
|
And the field "Text to display" matches value "https://moodle.org/"
|
||||||
|
And the field "Enter a URL" matches value "https://moodle.org/"
|
||||||
|
And I click on "Close" "button" in the "Create link" "dialogue"
|
||||||
|
And I click on "Show more buttons" "button"
|
||||||
|
And I click on "HTML" "button"
|
||||||
|
And I should see "https://moodle.org/</a>"
|
||||||
|
|
||||||
|
@javascript
|
||||||
|
Scenario: Insert a link with providing text to display
|
||||||
|
Given I log in as "admin"
|
||||||
|
When I open my profile in edit mode
|
||||||
|
And I click on "Link" "button"
|
||||||
|
And I set the field "Text to display" to "Moodle - Open-source learning platform"
|
||||||
|
And I set the field "Enter a URL" to "https://moodle.org/"
|
||||||
|
And I click on "Create link" "button"
|
||||||
|
Then I should see "Moodle - Open-source learning platform"
|
||||||
|
And I click on "Link" "button"
|
||||||
|
And the field "Text to display" matches value "Moodle - Open-source learning platform"
|
||||||
|
And the field "Enter a URL" matches value "https://moodle.org/"
|
||||||
|
And I click on "Close" "button" in the "Create link" "dialogue"
|
||||||
|
And I click on "Show more buttons" "button"
|
||||||
|
And I click on "HTML" "button"
|
||||||
|
And I should see "Moodle - Open-source learning platform</a>"
|
||||||
|
And I should not see "https://moodle.org/</a>"
|
||||||
|
|
||||||
|
@javascript
|
||||||
|
Scenario: Edit a link that already had a custom text to display
|
||||||
|
Given I log in as "admin"
|
||||||
|
And I follow "Preferences" in the user menu
|
||||||
|
And I follow "Editor preferences"
|
||||||
|
And I set the field "Text editor" to "Plain text area"
|
||||||
|
And I press "Save changes"
|
||||||
|
And I click on "Edit profile" "link" in the "region-main" "region"
|
||||||
|
And I set the field "Description" to "<a href=\"https://moodle.org/\">Moodle - Open-source learning platform</a>"
|
||||||
|
And I click on "Update profile" "button"
|
||||||
|
And I follow "Preferences" in the user menu
|
||||||
|
And I follow "Editor preferences"
|
||||||
|
And I set the field "Text editor" to "Atto HTML editor"
|
||||||
|
And I press "Save changes"
|
||||||
|
When I click on "Edit profile" "link" in the "region-main" "region"
|
||||||
|
Then I should see "Moodle - Open-source learning platform"
|
||||||
|
And I click on "Link" "button"
|
||||||
|
And the field "Text to display" matches value "Moodle - Open-source learning platform"
|
||||||
|
And the field "Enter a URL" matches value "https://moodle.org/"
|
||||||
|
@ -36,13 +36,23 @@ YUI.add('moodle-atto_link-button', function (Y, NAME) {
|
|||||||
var COMPONENTNAME = 'atto_link',
|
var COMPONENTNAME = 'atto_link',
|
||||||
CSS = {
|
CSS = {
|
||||||
NEWWINDOW: 'atto_link_openinnewwindow',
|
NEWWINDOW: 'atto_link_openinnewwindow',
|
||||||
URLINPUT: 'atto_link_urlentry'
|
URLINPUT: 'atto_link_urlentry',
|
||||||
|
URLTEXT: 'atto_link_urltext'
|
||||||
},
|
},
|
||||||
SELECTORS = {
|
SELECTORS = {
|
||||||
URLINPUT: '.atto_link_urlentry'
|
NEWWINDOW: '.atto_link_openinnewwindow',
|
||||||
|
URLINPUT: '.atto_link_urlentry',
|
||||||
|
URLTEXT: '.atto_link_urltext',
|
||||||
|
SUBMIT: '.submit',
|
||||||
|
LINKBROWSER: '.openlinkbrowser'
|
||||||
},
|
},
|
||||||
TEMPLATE = '' +
|
TEMPLATE = '' +
|
||||||
'<form class="atto_form">' +
|
'<form class="atto_form">' +
|
||||||
|
'<div class="mb-1">' +
|
||||||
|
'<label for="{{elementid}}_atto_link_urltext">{{get_string "texttodisplay" component}}</label>' +
|
||||||
|
'<input class="form-control fullwidth {{CSS.URLTEXT}}" type="text" ' +
|
||||||
|
'id="{{elementid}}_atto_link_urltext" size="32"/>' +
|
||||||
|
'</div>' +
|
||||||
'{{#if showFilepicker}}' +
|
'{{#if showFilepicker}}' +
|
||||||
'<label for="{{elementid}}_atto_link_urlentry">{{get_string "enterurl" component}}</label>' +
|
'<label for="{{elementid}}_atto_link_urlentry">{{get_string "enterurl" component}}</label>' +
|
||||||
'<div class="input-group input-append w-100 mb-1">' +
|
'<div class="input-group input-append w-100 mb-1">' +
|
||||||
@ -61,7 +71,8 @@ var COMPONENTNAME = 'atto_link',
|
|||||||
'</div>' +
|
'</div>' +
|
||||||
'{{/if}}' +
|
'{{/if}}' +
|
||||||
'<div class="form-check">' +
|
'<div class="form-check">' +
|
||||||
'<input type="checkbox" class="form-check-input newwindow" id="{{elementid}}_{{CSS.NEWWINDOW}}"/>' +
|
'<input type="checkbox" class="form-check-input newwindow {{CSS.NEWWINDOW}}" ' +
|
||||||
|
'id="{{elementid}}_{{CSS.NEWWINDOW}}"/>' +
|
||||||
'<label class="form-check-label" for="{{elementid}}_{{CSS.NEWWINDOW}}">' +
|
'<label class="form-check-label" for="{{elementid}}_{{CSS.NEWWINDOW}}">' +
|
||||||
'{{get_string "openinnewwindow" component}}' +
|
'{{get_string "openinnewwindow" component}}' +
|
||||||
'</label>' +
|
'</label>' +
|
||||||
@ -92,6 +103,14 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
*/
|
*/
|
||||||
_content: null,
|
_content: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text to display has value or not.
|
||||||
|
* @property _hasTextToDisplay
|
||||||
|
* @type Boolean
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_hasTextToDisplay: false,
|
||||||
|
|
||||||
initializer: function() {
|
initializer: function() {
|
||||||
// Add the link button first.
|
// Add the link button first.
|
||||||
this.addButton({
|
this.addButton({
|
||||||
@ -156,7 +175,8 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
anchornodes,
|
anchornodes,
|
||||||
anchornode,
|
anchornode,
|
||||||
url,
|
url,
|
||||||
target;
|
target,
|
||||||
|
textToDisplay;
|
||||||
|
|
||||||
// Note this is a document fragment and YUI doesn't like them.
|
// Note this is a document fragment and YUI doesn't like them.
|
||||||
if (!selectednode) {
|
if (!selectednode) {
|
||||||
@ -169,13 +189,24 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
this._currentSelection = this.get('host').getSelectionFromNode(anchornode);
|
this._currentSelection = this.get('host').getSelectionFromNode(anchornode);
|
||||||
url = anchornode.getAttribute('href');
|
url = anchornode.getAttribute('href');
|
||||||
target = anchornode.getAttribute('target');
|
target = anchornode.getAttribute('target');
|
||||||
|
textToDisplay = anchornode.get('innerText');
|
||||||
if (url !== '') {
|
if (url !== '') {
|
||||||
this._content.one('.url').setAttribute('value', url);
|
this._content.one(SELECTORS.URLINPUT).setAttribute('value', url);
|
||||||
|
}
|
||||||
|
if (textToDisplay !== '') {
|
||||||
|
this._content.one(SELECTORS.URLTEXT).set('value', textToDisplay);
|
||||||
}
|
}
|
||||||
if (target === '_blank') {
|
if (target === '_blank') {
|
||||||
this._content.one('.newwindow').setAttribute('checked', 'checked');
|
this._content.one(SELECTORS.NEWWINDOW).setAttribute('checked', 'checked');
|
||||||
} else {
|
} else {
|
||||||
this._content.one('.newwindow').removeAttribute('checked');
|
this._content.one(SELECTORS.NEWWINDOW).removeAttribute('checked');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// User is selecting some text before clicking on the Link button.
|
||||||
|
textToDisplay = Y.one(selectednode).get('textContent');
|
||||||
|
if (textToDisplay !== '') {
|
||||||
|
this._hasTextToDisplay = true;
|
||||||
|
this._content.one(SELECTORS.URLTEXT).set('value', textToDisplay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -218,7 +249,7 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
focusAfterHide: null
|
focusAfterHide: null
|
||||||
}).hide();
|
}).hide();
|
||||||
|
|
||||||
input = this._content.one('.url');
|
input = this._content.one(SELECTORS.URLINPUT);
|
||||||
|
|
||||||
value = input.get('value');
|
value = input.get('value');
|
||||||
if (value !== '') {
|
if (value !== '') {
|
||||||
@ -250,14 +281,23 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
link,
|
link,
|
||||||
selectednode,
|
selectednode,
|
||||||
target,
|
target,
|
||||||
anchornodes;
|
anchornodes,
|
||||||
|
isUpdating,
|
||||||
|
urlText,
|
||||||
|
textToDisplay;
|
||||||
|
|
||||||
this.editor.focus();
|
this.editor.focus();
|
||||||
host.setSelection(this._currentSelection);
|
host.setSelection(this._currentSelection);
|
||||||
|
isUpdating = !this._currentSelection[0].collapsed;
|
||||||
|
urlText = this._content.one(SELECTORS.URLTEXT);
|
||||||
|
textToDisplay = urlText.get('value').replace(/(<([^>]+)>)/gi, "").trim();
|
||||||
|
if (textToDisplay === '') {
|
||||||
|
textToDisplay = url;
|
||||||
|
}
|
||||||
|
|
||||||
if (this._currentSelection[0].collapsed) {
|
if (!isUpdating) {
|
||||||
// Firefox cannot add links when the selection is empty so we will add it manually.
|
// Firefox cannot add links when the selection is empty so we will add it manually.
|
||||||
link = Y.Node.create('<a>' + url + '</a>');
|
link = Y.Node.create('<a>' + textToDisplay + '</a>');
|
||||||
link.setAttribute('href', url);
|
link.setAttribute('href', url);
|
||||||
|
|
||||||
// Add the node and select it to replicate the behaviour of execCommand.
|
// Add the node and select it to replicate the behaviour of execCommand.
|
||||||
@ -279,12 +319,16 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
anchornodes = this._findSelectedAnchors(Y.one(selectednode));
|
anchornodes = this._findSelectedAnchors(Y.one(selectednode));
|
||||||
// Add new window attributes if requested.
|
// Add new window attributes if requested.
|
||||||
Y.Array.each(anchornodes, function(anchornode) {
|
Y.Array.each(anchornodes, function(anchornode) {
|
||||||
target = this._content.one('.newwindow');
|
target = this._content.one(SELECTORS.NEWWINDOW);
|
||||||
if (target.get('checked')) {
|
if (target.get('checked')) {
|
||||||
anchornode.setAttribute('target', '_blank');
|
anchornode.setAttribute('target', '_blank');
|
||||||
} else {
|
} else {
|
||||||
anchornode.removeAttribute('target');
|
anchornode.removeAttribute('target');
|
||||||
}
|
}
|
||||||
|
if (isUpdating) {
|
||||||
|
// The 'createLink' command do not allow to set the custom text to display. So we need to do it here.
|
||||||
|
anchornode.set('innerText', textToDisplay);
|
||||||
|
}
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
return selectednode;
|
return selectednode;
|
||||||
@ -342,9 +386,11 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
CSS: CSS
|
CSS: CSS
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._content.one('.submit').on('click', this._setLink, this);
|
this._content.one(SELECTORS.URLINPUT).on('keyup', this._updateTextToDisplay, this);
|
||||||
|
this._content.one(SELECTORS.URLTEXT).on('keyup', this._setTextToDisplayState, this);
|
||||||
|
this._content.one(SELECTORS.SUBMIT).on('click', this._setLink, this);
|
||||||
if (canShowFilepicker) {
|
if (canShowFilepicker) {
|
||||||
this._content.one('.openlinkbrowser').on('click', function(e) {
|
this._content.one(SELECTORS.LINKBROWSER).on('click', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.get('host').showFilepicker('link', this._filepickerCallback, this);
|
this.get('host').showFilepicker('link', this._filepickerCallback, this);
|
||||||
}, this);
|
}, this);
|
||||||
@ -375,10 +421,10 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
// would then be unlinked too.
|
// would then be unlinked too.
|
||||||
nodes.each(function(node) {
|
nodes.each(function(node) {
|
||||||
// We need to select the whole anchor node for this to work in some browsers.
|
// We need to select the whole anchor node for this to work in some browsers.
|
||||||
// We only need to search up because getSeletedNodes returns all Nodes in the selection.
|
// We only need to search up because getSelectedNodes returns all Nodes in the selection.
|
||||||
var anchor = node.ancestor('a', true);
|
var anchor = node.ancestor('a', true);
|
||||||
if (anchor) {
|
if (anchor) {
|
||||||
// Set the selection to the whole of the first anchro.
|
// Set the selection to the whole of the first anchor.
|
||||||
host.setSelection(host.getSelectionFromNode(anchor));
|
host.setSelection(host.getSelectionFromNode(anchor));
|
||||||
|
|
||||||
// Call the browser unlink.
|
// Call the browser unlink.
|
||||||
@ -397,6 +443,42 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
this.markUpdated();
|
this.markUpdated();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current text to display state.
|
||||||
|
*
|
||||||
|
* @method _setTextToDisplayState
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_setTextToDisplayState: function() {
|
||||||
|
var urlText,
|
||||||
|
urlTextVal;
|
||||||
|
urlText = this._content.one(SELECTORS.URLTEXT);
|
||||||
|
urlTextVal = urlText.get('value');
|
||||||
|
if (urlTextVal !== '') {
|
||||||
|
this._hasTextToDisplay = true;
|
||||||
|
} else {
|
||||||
|
this._hasTextToDisplay = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the text to display if the user does not provide the custom text.
|
||||||
|
*
|
||||||
|
* @method _updateTextToDisplay
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_updateTextToDisplay: function() {
|
||||||
|
var urlEntry,
|
||||||
|
urlText,
|
||||||
|
urlEntryVal;
|
||||||
|
urlEntry = this._content.one(SELECTORS.URLINPUT);
|
||||||
|
urlText = this._content.one(SELECTORS.URLTEXT);
|
||||||
|
urlEntryVal = urlEntry.get('value');
|
||||||
|
if (!this._hasTextToDisplay) {
|
||||||
|
urlText.set('value', urlEntryVal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
@ -36,13 +36,23 @@ YUI.add('moodle-atto_link-button', function (Y, NAME) {
|
|||||||
var COMPONENTNAME = 'atto_link',
|
var COMPONENTNAME = 'atto_link',
|
||||||
CSS = {
|
CSS = {
|
||||||
NEWWINDOW: 'atto_link_openinnewwindow',
|
NEWWINDOW: 'atto_link_openinnewwindow',
|
||||||
URLINPUT: 'atto_link_urlentry'
|
URLINPUT: 'atto_link_urlentry',
|
||||||
|
URLTEXT: 'atto_link_urltext'
|
||||||
},
|
},
|
||||||
SELECTORS = {
|
SELECTORS = {
|
||||||
URLINPUT: '.atto_link_urlentry'
|
NEWWINDOW: '.atto_link_openinnewwindow',
|
||||||
|
URLINPUT: '.atto_link_urlentry',
|
||||||
|
URLTEXT: '.atto_link_urltext',
|
||||||
|
SUBMIT: '.submit',
|
||||||
|
LINKBROWSER: '.openlinkbrowser'
|
||||||
},
|
},
|
||||||
TEMPLATE = '' +
|
TEMPLATE = '' +
|
||||||
'<form class="atto_form">' +
|
'<form class="atto_form">' +
|
||||||
|
'<div class="mb-1">' +
|
||||||
|
'<label for="{{elementid}}_atto_link_urltext">{{get_string "texttodisplay" component}}</label>' +
|
||||||
|
'<input class="form-control fullwidth {{CSS.URLTEXT}}" type="text" ' +
|
||||||
|
'id="{{elementid}}_atto_link_urltext" size="32"/>' +
|
||||||
|
'</div>' +
|
||||||
'{{#if showFilepicker}}' +
|
'{{#if showFilepicker}}' +
|
||||||
'<label for="{{elementid}}_atto_link_urlentry">{{get_string "enterurl" component}}</label>' +
|
'<label for="{{elementid}}_atto_link_urlentry">{{get_string "enterurl" component}}</label>' +
|
||||||
'<div class="input-group input-append w-100 mb-1">' +
|
'<div class="input-group input-append w-100 mb-1">' +
|
||||||
@ -61,7 +71,8 @@ var COMPONENTNAME = 'atto_link',
|
|||||||
'</div>' +
|
'</div>' +
|
||||||
'{{/if}}' +
|
'{{/if}}' +
|
||||||
'<div class="form-check">' +
|
'<div class="form-check">' +
|
||||||
'<input type="checkbox" class="form-check-input newwindow" id="{{elementid}}_{{CSS.NEWWINDOW}}"/>' +
|
'<input type="checkbox" class="form-check-input newwindow {{CSS.NEWWINDOW}}" ' +
|
||||||
|
'id="{{elementid}}_{{CSS.NEWWINDOW}}"/>' +
|
||||||
'<label class="form-check-label" for="{{elementid}}_{{CSS.NEWWINDOW}}">' +
|
'<label class="form-check-label" for="{{elementid}}_{{CSS.NEWWINDOW}}">' +
|
||||||
'{{get_string "openinnewwindow" component}}' +
|
'{{get_string "openinnewwindow" component}}' +
|
||||||
'</label>' +
|
'</label>' +
|
||||||
@ -92,6 +103,14 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
*/
|
*/
|
||||||
_content: null,
|
_content: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text to display has value or not.
|
||||||
|
* @property _hasTextToDisplay
|
||||||
|
* @type Boolean
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_hasTextToDisplay: false,
|
||||||
|
|
||||||
initializer: function() {
|
initializer: function() {
|
||||||
// Add the link button first.
|
// Add the link button first.
|
||||||
this.addButton({
|
this.addButton({
|
||||||
@ -156,7 +175,8 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
anchornodes,
|
anchornodes,
|
||||||
anchornode,
|
anchornode,
|
||||||
url,
|
url,
|
||||||
target;
|
target,
|
||||||
|
textToDisplay;
|
||||||
|
|
||||||
// Note this is a document fragment and YUI doesn't like them.
|
// Note this is a document fragment and YUI doesn't like them.
|
||||||
if (!selectednode) {
|
if (!selectednode) {
|
||||||
@ -169,13 +189,24 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
this._currentSelection = this.get('host').getSelectionFromNode(anchornode);
|
this._currentSelection = this.get('host').getSelectionFromNode(anchornode);
|
||||||
url = anchornode.getAttribute('href');
|
url = anchornode.getAttribute('href');
|
||||||
target = anchornode.getAttribute('target');
|
target = anchornode.getAttribute('target');
|
||||||
|
textToDisplay = anchornode.get('innerText');
|
||||||
if (url !== '') {
|
if (url !== '') {
|
||||||
this._content.one('.url').setAttribute('value', url);
|
this._content.one(SELECTORS.URLINPUT).setAttribute('value', url);
|
||||||
|
}
|
||||||
|
if (textToDisplay !== '') {
|
||||||
|
this._content.one(SELECTORS.URLTEXT).set('value', textToDisplay);
|
||||||
}
|
}
|
||||||
if (target === '_blank') {
|
if (target === '_blank') {
|
||||||
this._content.one('.newwindow').setAttribute('checked', 'checked');
|
this._content.one(SELECTORS.NEWWINDOW).setAttribute('checked', 'checked');
|
||||||
} else {
|
} else {
|
||||||
this._content.one('.newwindow').removeAttribute('checked');
|
this._content.one(SELECTORS.NEWWINDOW).removeAttribute('checked');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// User is selecting some text before clicking on the Link button.
|
||||||
|
textToDisplay = Y.one(selectednode).get('textContent');
|
||||||
|
if (textToDisplay !== '') {
|
||||||
|
this._hasTextToDisplay = true;
|
||||||
|
this._content.one(SELECTORS.URLTEXT).set('value', textToDisplay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -218,7 +249,7 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
focusAfterHide: null
|
focusAfterHide: null
|
||||||
}).hide();
|
}).hide();
|
||||||
|
|
||||||
input = this._content.one('.url');
|
input = this._content.one(SELECTORS.URLINPUT);
|
||||||
|
|
||||||
value = input.get('value');
|
value = input.get('value');
|
||||||
if (value !== '') {
|
if (value !== '') {
|
||||||
@ -250,14 +281,23 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
link,
|
link,
|
||||||
selectednode,
|
selectednode,
|
||||||
target,
|
target,
|
||||||
anchornodes;
|
anchornodes,
|
||||||
|
isUpdating,
|
||||||
|
urlText,
|
||||||
|
textToDisplay;
|
||||||
|
|
||||||
this.editor.focus();
|
this.editor.focus();
|
||||||
host.setSelection(this._currentSelection);
|
host.setSelection(this._currentSelection);
|
||||||
|
isUpdating = !this._currentSelection[0].collapsed;
|
||||||
|
urlText = this._content.one(SELECTORS.URLTEXT);
|
||||||
|
textToDisplay = urlText.get('value').replace(/(<([^>]+)>)/gi, "").trim();
|
||||||
|
if (textToDisplay === '') {
|
||||||
|
textToDisplay = url;
|
||||||
|
}
|
||||||
|
|
||||||
if (this._currentSelection[0].collapsed) {
|
if (!isUpdating) {
|
||||||
// Firefox cannot add links when the selection is empty so we will add it manually.
|
// Firefox cannot add links when the selection is empty so we will add it manually.
|
||||||
link = Y.Node.create('<a>' + url + '</a>');
|
link = Y.Node.create('<a>' + textToDisplay + '</a>');
|
||||||
link.setAttribute('href', url);
|
link.setAttribute('href', url);
|
||||||
|
|
||||||
// Add the node and select it to replicate the behaviour of execCommand.
|
// Add the node and select it to replicate the behaviour of execCommand.
|
||||||
@ -279,12 +319,16 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
anchornodes = this._findSelectedAnchors(Y.one(selectednode));
|
anchornodes = this._findSelectedAnchors(Y.one(selectednode));
|
||||||
// Add new window attributes if requested.
|
// Add new window attributes if requested.
|
||||||
Y.Array.each(anchornodes, function(anchornode) {
|
Y.Array.each(anchornodes, function(anchornode) {
|
||||||
target = this._content.one('.newwindow');
|
target = this._content.one(SELECTORS.NEWWINDOW);
|
||||||
if (target.get('checked')) {
|
if (target.get('checked')) {
|
||||||
anchornode.setAttribute('target', '_blank');
|
anchornode.setAttribute('target', '_blank');
|
||||||
} else {
|
} else {
|
||||||
anchornode.removeAttribute('target');
|
anchornode.removeAttribute('target');
|
||||||
}
|
}
|
||||||
|
if (isUpdating) {
|
||||||
|
// The 'createLink' command do not allow to set the custom text to display. So we need to do it here.
|
||||||
|
anchornode.set('innerText', textToDisplay);
|
||||||
|
}
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
return selectednode;
|
return selectednode;
|
||||||
@ -342,9 +386,11 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
CSS: CSS
|
CSS: CSS
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._content.one('.submit').on('click', this._setLink, this);
|
this._content.one(SELECTORS.URLINPUT).on('keyup', this._updateTextToDisplay, this);
|
||||||
|
this._content.one(SELECTORS.URLTEXT).on('keyup', this._setTextToDisplayState, this);
|
||||||
|
this._content.one(SELECTORS.SUBMIT).on('click', this._setLink, this);
|
||||||
if (canShowFilepicker) {
|
if (canShowFilepicker) {
|
||||||
this._content.one('.openlinkbrowser').on('click', function(e) {
|
this._content.one(SELECTORS.LINKBROWSER).on('click', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.get('host').showFilepicker('link', this._filepickerCallback, this);
|
this.get('host').showFilepicker('link', this._filepickerCallback, this);
|
||||||
}, this);
|
}, this);
|
||||||
@ -375,10 +421,10 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
// would then be unlinked too.
|
// would then be unlinked too.
|
||||||
nodes.each(function(node) {
|
nodes.each(function(node) {
|
||||||
// We need to select the whole anchor node for this to work in some browsers.
|
// We need to select the whole anchor node for this to work in some browsers.
|
||||||
// We only need to search up because getSeletedNodes returns all Nodes in the selection.
|
// We only need to search up because getSelectedNodes returns all Nodes in the selection.
|
||||||
var anchor = node.ancestor('a', true);
|
var anchor = node.ancestor('a', true);
|
||||||
if (anchor) {
|
if (anchor) {
|
||||||
// Set the selection to the whole of the first anchro.
|
// Set the selection to the whole of the first anchor.
|
||||||
host.setSelection(host.getSelectionFromNode(anchor));
|
host.setSelection(host.getSelectionFromNode(anchor));
|
||||||
|
|
||||||
// Call the browser unlink.
|
// Call the browser unlink.
|
||||||
@ -397,6 +443,42 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
this.markUpdated();
|
this.markUpdated();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current text to display state.
|
||||||
|
*
|
||||||
|
* @method _setTextToDisplayState
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_setTextToDisplayState: function() {
|
||||||
|
var urlText,
|
||||||
|
urlTextVal;
|
||||||
|
urlText = this._content.one(SELECTORS.URLTEXT);
|
||||||
|
urlTextVal = urlText.get('value');
|
||||||
|
if (urlTextVal !== '') {
|
||||||
|
this._hasTextToDisplay = true;
|
||||||
|
} else {
|
||||||
|
this._hasTextToDisplay = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the text to display if the user does not provide the custom text.
|
||||||
|
*
|
||||||
|
* @method _updateTextToDisplay
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_updateTextToDisplay: function() {
|
||||||
|
var urlEntry,
|
||||||
|
urlText,
|
||||||
|
urlEntryVal;
|
||||||
|
urlEntry = this._content.one(SELECTORS.URLINPUT);
|
||||||
|
urlText = this._content.one(SELECTORS.URLTEXT);
|
||||||
|
urlEntryVal = urlEntry.get('value');
|
||||||
|
if (!this._hasTextToDisplay) {
|
||||||
|
urlText.set('value', urlEntryVal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -34,13 +34,23 @@
|
|||||||
var COMPONENTNAME = 'atto_link',
|
var COMPONENTNAME = 'atto_link',
|
||||||
CSS = {
|
CSS = {
|
||||||
NEWWINDOW: 'atto_link_openinnewwindow',
|
NEWWINDOW: 'atto_link_openinnewwindow',
|
||||||
URLINPUT: 'atto_link_urlentry'
|
URLINPUT: 'atto_link_urlentry',
|
||||||
|
URLTEXT: 'atto_link_urltext'
|
||||||
},
|
},
|
||||||
SELECTORS = {
|
SELECTORS = {
|
||||||
URLINPUT: '.atto_link_urlentry'
|
NEWWINDOW: '.atto_link_openinnewwindow',
|
||||||
|
URLINPUT: '.atto_link_urlentry',
|
||||||
|
URLTEXT: '.atto_link_urltext',
|
||||||
|
SUBMIT: '.submit',
|
||||||
|
LINKBROWSER: '.openlinkbrowser'
|
||||||
},
|
},
|
||||||
TEMPLATE = '' +
|
TEMPLATE = '' +
|
||||||
'<form class="atto_form">' +
|
'<form class="atto_form">' +
|
||||||
|
'<div class="mb-1">' +
|
||||||
|
'<label for="{{elementid}}_atto_link_urltext">{{get_string "texttodisplay" component}}</label>' +
|
||||||
|
'<input class="form-control fullwidth {{CSS.URLTEXT}}" type="text" ' +
|
||||||
|
'id="{{elementid}}_atto_link_urltext" size="32"/>' +
|
||||||
|
'</div>' +
|
||||||
'{{#if showFilepicker}}' +
|
'{{#if showFilepicker}}' +
|
||||||
'<label for="{{elementid}}_atto_link_urlentry">{{get_string "enterurl" component}}</label>' +
|
'<label for="{{elementid}}_atto_link_urlentry">{{get_string "enterurl" component}}</label>' +
|
||||||
'<div class="input-group input-append w-100 mb-1">' +
|
'<div class="input-group input-append w-100 mb-1">' +
|
||||||
@ -59,7 +69,8 @@ var COMPONENTNAME = 'atto_link',
|
|||||||
'</div>' +
|
'</div>' +
|
||||||
'{{/if}}' +
|
'{{/if}}' +
|
||||||
'<div class="form-check">' +
|
'<div class="form-check">' +
|
||||||
'<input type="checkbox" class="form-check-input newwindow" id="{{elementid}}_{{CSS.NEWWINDOW}}"/>' +
|
'<input type="checkbox" class="form-check-input newwindow {{CSS.NEWWINDOW}}" ' +
|
||||||
|
'id="{{elementid}}_{{CSS.NEWWINDOW}}"/>' +
|
||||||
'<label class="form-check-label" for="{{elementid}}_{{CSS.NEWWINDOW}}">' +
|
'<label class="form-check-label" for="{{elementid}}_{{CSS.NEWWINDOW}}">' +
|
||||||
'{{get_string "openinnewwindow" component}}' +
|
'{{get_string "openinnewwindow" component}}' +
|
||||||
'</label>' +
|
'</label>' +
|
||||||
@ -90,6 +101,14 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
*/
|
*/
|
||||||
_content: null,
|
_content: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text to display has value or not.
|
||||||
|
* @property _hasTextToDisplay
|
||||||
|
* @type Boolean
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_hasTextToDisplay: false,
|
||||||
|
|
||||||
initializer: function() {
|
initializer: function() {
|
||||||
// Add the link button first.
|
// Add the link button first.
|
||||||
this.addButton({
|
this.addButton({
|
||||||
@ -154,7 +173,8 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
anchornodes,
|
anchornodes,
|
||||||
anchornode,
|
anchornode,
|
||||||
url,
|
url,
|
||||||
target;
|
target,
|
||||||
|
textToDisplay;
|
||||||
|
|
||||||
// Note this is a document fragment and YUI doesn't like them.
|
// Note this is a document fragment and YUI doesn't like them.
|
||||||
if (!selectednode) {
|
if (!selectednode) {
|
||||||
@ -167,13 +187,24 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
this._currentSelection = this.get('host').getSelectionFromNode(anchornode);
|
this._currentSelection = this.get('host').getSelectionFromNode(anchornode);
|
||||||
url = anchornode.getAttribute('href');
|
url = anchornode.getAttribute('href');
|
||||||
target = anchornode.getAttribute('target');
|
target = anchornode.getAttribute('target');
|
||||||
|
textToDisplay = anchornode.get('innerText');
|
||||||
if (url !== '') {
|
if (url !== '') {
|
||||||
this._content.one('.url').setAttribute('value', url);
|
this._content.one(SELECTORS.URLINPUT).setAttribute('value', url);
|
||||||
|
}
|
||||||
|
if (textToDisplay !== '') {
|
||||||
|
this._content.one(SELECTORS.URLTEXT).set('value', textToDisplay);
|
||||||
}
|
}
|
||||||
if (target === '_blank') {
|
if (target === '_blank') {
|
||||||
this._content.one('.newwindow').setAttribute('checked', 'checked');
|
this._content.one(SELECTORS.NEWWINDOW).setAttribute('checked', 'checked');
|
||||||
} else {
|
} else {
|
||||||
this._content.one('.newwindow').removeAttribute('checked');
|
this._content.one(SELECTORS.NEWWINDOW).removeAttribute('checked');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// User is selecting some text before clicking on the Link button.
|
||||||
|
textToDisplay = Y.one(selectednode).get('textContent');
|
||||||
|
if (textToDisplay !== '') {
|
||||||
|
this._hasTextToDisplay = true;
|
||||||
|
this._content.one(SELECTORS.URLTEXT).set('value', textToDisplay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -216,7 +247,7 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
focusAfterHide: null
|
focusAfterHide: null
|
||||||
}).hide();
|
}).hide();
|
||||||
|
|
||||||
input = this._content.one('.url');
|
input = this._content.one(SELECTORS.URLINPUT);
|
||||||
|
|
||||||
value = input.get('value');
|
value = input.get('value');
|
||||||
if (value !== '') {
|
if (value !== '') {
|
||||||
@ -248,14 +279,23 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
link,
|
link,
|
||||||
selectednode,
|
selectednode,
|
||||||
target,
|
target,
|
||||||
anchornodes;
|
anchornodes,
|
||||||
|
isUpdating,
|
||||||
|
urlText,
|
||||||
|
textToDisplay;
|
||||||
|
|
||||||
this.editor.focus();
|
this.editor.focus();
|
||||||
host.setSelection(this._currentSelection);
|
host.setSelection(this._currentSelection);
|
||||||
|
isUpdating = !this._currentSelection[0].collapsed;
|
||||||
|
urlText = this._content.one(SELECTORS.URLTEXT);
|
||||||
|
textToDisplay = urlText.get('value').replace(/(<([^>]+)>)/gi, "").trim();
|
||||||
|
if (textToDisplay === '') {
|
||||||
|
textToDisplay = url;
|
||||||
|
}
|
||||||
|
|
||||||
if (this._currentSelection[0].collapsed) {
|
if (!isUpdating) {
|
||||||
// Firefox cannot add links when the selection is empty so we will add it manually.
|
// Firefox cannot add links when the selection is empty so we will add it manually.
|
||||||
link = Y.Node.create('<a>' + url + '</a>');
|
link = Y.Node.create('<a>' + textToDisplay + '</a>');
|
||||||
link.setAttribute('href', url);
|
link.setAttribute('href', url);
|
||||||
|
|
||||||
// Add the node and select it to replicate the behaviour of execCommand.
|
// Add the node and select it to replicate the behaviour of execCommand.
|
||||||
@ -277,12 +317,16 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
anchornodes = this._findSelectedAnchors(Y.one(selectednode));
|
anchornodes = this._findSelectedAnchors(Y.one(selectednode));
|
||||||
// Add new window attributes if requested.
|
// Add new window attributes if requested.
|
||||||
Y.Array.each(anchornodes, function(anchornode) {
|
Y.Array.each(anchornodes, function(anchornode) {
|
||||||
target = this._content.one('.newwindow');
|
target = this._content.one(SELECTORS.NEWWINDOW);
|
||||||
if (target.get('checked')) {
|
if (target.get('checked')) {
|
||||||
anchornode.setAttribute('target', '_blank');
|
anchornode.setAttribute('target', '_blank');
|
||||||
} else {
|
} else {
|
||||||
anchornode.removeAttribute('target');
|
anchornode.removeAttribute('target');
|
||||||
}
|
}
|
||||||
|
if (isUpdating) {
|
||||||
|
// The 'createLink' command do not allow to set the custom text to display. So we need to do it here.
|
||||||
|
anchornode.set('innerText', textToDisplay);
|
||||||
|
}
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
return selectednode;
|
return selectednode;
|
||||||
@ -340,9 +384,11 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
CSS: CSS
|
CSS: CSS
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._content.one('.submit').on('click', this._setLink, this);
|
this._content.one(SELECTORS.URLINPUT).on('keyup', this._updateTextToDisplay, this);
|
||||||
|
this._content.one(SELECTORS.URLTEXT).on('keyup', this._setTextToDisplayState, this);
|
||||||
|
this._content.one(SELECTORS.SUBMIT).on('click', this._setLink, this);
|
||||||
if (canShowFilepicker) {
|
if (canShowFilepicker) {
|
||||||
this._content.one('.openlinkbrowser').on('click', function(e) {
|
this._content.one(SELECTORS.LINKBROWSER).on('click', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.get('host').showFilepicker('link', this._filepickerCallback, this);
|
this.get('host').showFilepicker('link', this._filepickerCallback, this);
|
||||||
}, this);
|
}, this);
|
||||||
@ -373,10 +419,10 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
// would then be unlinked too.
|
// would then be unlinked too.
|
||||||
nodes.each(function(node) {
|
nodes.each(function(node) {
|
||||||
// We need to select the whole anchor node for this to work in some browsers.
|
// We need to select the whole anchor node for this to work in some browsers.
|
||||||
// We only need to search up because getSeletedNodes returns all Nodes in the selection.
|
// We only need to search up because getSelectedNodes returns all Nodes in the selection.
|
||||||
var anchor = node.ancestor('a', true);
|
var anchor = node.ancestor('a', true);
|
||||||
if (anchor) {
|
if (anchor) {
|
||||||
// Set the selection to the whole of the first anchro.
|
// Set the selection to the whole of the first anchor.
|
||||||
host.setSelection(host.getSelectionFromNode(anchor));
|
host.setSelection(host.getSelectionFromNode(anchor));
|
||||||
|
|
||||||
// Call the browser unlink.
|
// Call the browser unlink.
|
||||||
@ -395,5 +441,41 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
|||||||
this.markUpdated();
|
this.markUpdated();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current text to display state.
|
||||||
|
*
|
||||||
|
* @method _setTextToDisplayState
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_setTextToDisplayState: function() {
|
||||||
|
var urlText,
|
||||||
|
urlTextVal;
|
||||||
|
urlText = this._content.one(SELECTORS.URLTEXT);
|
||||||
|
urlTextVal = urlText.get('value');
|
||||||
|
if (urlTextVal !== '') {
|
||||||
|
this._hasTextToDisplay = true;
|
||||||
|
} else {
|
||||||
|
this._hasTextToDisplay = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the text to display if the user does not provide the custom text.
|
||||||
|
*
|
||||||
|
* @method _updateTextToDisplay
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_updateTextToDisplay: function() {
|
||||||
|
var urlEntry,
|
||||||
|
urlText,
|
||||||
|
urlEntryVal;
|
||||||
|
urlEntry = this._content.one(SELECTORS.URLINPUT);
|
||||||
|
urlText = this._content.one(SELECTORS.URLTEXT);
|
||||||
|
urlEntryVal = urlEntry.get('value');
|
||||||
|
if (!this._hasTextToDisplay) {
|
||||||
|
urlText.set('value', urlEntryVal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user