mirror of
https://github.com/moodle/moodle.git
synced 2025-03-14 04:30:15 +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['unlink'] = 'Unlink';
|
||||
$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',
|
||||
'enterurl',
|
||||
'browserepositories',
|
||||
'openinnewwindow'),
|
||||
'openinnewwindow',
|
||||
'texttodisplay'),
|
||||
'atto_link');
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ Feature: Add links to Atto
|
||||
And I set the field "Description" to "Super cool"
|
||||
And I select the text in the "Description" Atto editor
|
||||
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 "Private files" "link" in the ".fp-repo-area" "css_element"
|
||||
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 press "Save changes"
|
||||
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',
|
||||
CSS = {
|
||||
NEWWINDOW: 'atto_link_openinnewwindow',
|
||||
URLINPUT: 'atto_link_urlentry'
|
||||
URLINPUT: 'atto_link_urlentry',
|
||||
URLTEXT: 'atto_link_urltext'
|
||||
},
|
||||
SELECTORS = {
|
||||
URLINPUT: '.atto_link_urlentry'
|
||||
NEWWINDOW: '.atto_link_openinnewwindow',
|
||||
URLINPUT: '.atto_link_urlentry',
|
||||
URLTEXT: '.atto_link_urltext',
|
||||
SUBMIT: '.submit',
|
||||
LINKBROWSER: '.openlinkbrowser'
|
||||
},
|
||||
TEMPLATE = '' +
|
||||
'<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}}' +
|
||||
'<label for="{{elementid}}_atto_link_urlentry">{{get_string "enterurl" component}}</label>' +
|
||||
'<div class="input-group input-append w-100 mb-1">' +
|
||||
@ -61,7 +71,8 @@ var COMPONENTNAME = 'atto_link',
|
||||
'</div>' +
|
||||
'{{/if}}' +
|
||||
'<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}}">' +
|
||||
'{{get_string "openinnewwindow" component}}' +
|
||||
'</label>' +
|
||||
@ -92,6 +103,14 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
||||
*/
|
||||
_content: null,
|
||||
|
||||
/**
|
||||
* Text to display has value or not.
|
||||
* @property _hasTextToDisplay
|
||||
* @type Boolean
|
||||
* @private
|
||||
*/
|
||||
_hasTextToDisplay: false,
|
||||
|
||||
initializer: function() {
|
||||
// Add the link button first.
|
||||
this.addButton({
|
||||
@ -156,7 +175,8 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
||||
anchornodes,
|
||||
anchornode,
|
||||
url,
|
||||
target;
|
||||
target,
|
||||
textToDisplay;
|
||||
|
||||
// Note this is a document fragment and YUI doesn't like them.
|
||||
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);
|
||||
url = anchornode.getAttribute('href');
|
||||
target = anchornode.getAttribute('target');
|
||||
textToDisplay = anchornode.get('innerText');
|
||||
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') {
|
||||
this._content.one('.newwindow').setAttribute('checked', 'checked');
|
||||
this._content.one(SELECTORS.NEWWINDOW).setAttribute('checked', 'checked');
|
||||
} 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
|
||||
}).hide();
|
||||
|
||||
input = this._content.one('.url');
|
||||
input = this._content.one(SELECTORS.URLINPUT);
|
||||
|
||||
value = input.get('value');
|
||||
if (value !== '') {
|
||||
@ -250,14 +281,23 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
||||
link,
|
||||
selectednode,
|
||||
target,
|
||||
anchornodes;
|
||||
anchornodes,
|
||||
isUpdating,
|
||||
urlText,
|
||||
textToDisplay;
|
||||
|
||||
this.editor.focus();
|
||||
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.
|
||||
link = Y.Node.create('<a>' + url + '</a>');
|
||||
link = Y.Node.create('<a>' + textToDisplay + '</a>');
|
||||
link.setAttribute('href', url);
|
||||
|
||||
// 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));
|
||||
// Add new window attributes if requested.
|
||||
Y.Array.each(anchornodes, function(anchornode) {
|
||||
target = this._content.one('.newwindow');
|
||||
target = this._content.one(SELECTORS.NEWWINDOW);
|
||||
if (target.get('checked')) {
|
||||
anchornode.setAttribute('target', '_blank');
|
||||
} else {
|
||||
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);
|
||||
|
||||
return selectednode;
|
||||
@ -342,9 +386,11 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
||||
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) {
|
||||
this._content.one('.openlinkbrowser').on('click', function(e) {
|
||||
this._content.one(SELECTORS.LINKBROWSER).on('click', function(e) {
|
||||
e.preventDefault();
|
||||
this.get('host').showFilepicker('link', this._filepickerCallback, 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.
|
||||
nodes.each(function(node) {
|
||||
// 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);
|
||||
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));
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 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',
|
||||
CSS = {
|
||||
NEWWINDOW: 'atto_link_openinnewwindow',
|
||||
URLINPUT: 'atto_link_urlentry'
|
||||
URLINPUT: 'atto_link_urlentry',
|
||||
URLTEXT: 'atto_link_urltext'
|
||||
},
|
||||
SELECTORS = {
|
||||
URLINPUT: '.atto_link_urlentry'
|
||||
NEWWINDOW: '.atto_link_openinnewwindow',
|
||||
URLINPUT: '.atto_link_urlentry',
|
||||
URLTEXT: '.atto_link_urltext',
|
||||
SUBMIT: '.submit',
|
||||
LINKBROWSER: '.openlinkbrowser'
|
||||
},
|
||||
TEMPLATE = '' +
|
||||
'<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}}' +
|
||||
'<label for="{{elementid}}_atto_link_urlentry">{{get_string "enterurl" component}}</label>' +
|
||||
'<div class="input-group input-append w-100 mb-1">' +
|
||||
@ -61,7 +71,8 @@ var COMPONENTNAME = 'atto_link',
|
||||
'</div>' +
|
||||
'{{/if}}' +
|
||||
'<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}}">' +
|
||||
'{{get_string "openinnewwindow" component}}' +
|
||||
'</label>' +
|
||||
@ -92,6 +103,14 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
||||
*/
|
||||
_content: null,
|
||||
|
||||
/**
|
||||
* Text to display has value or not.
|
||||
* @property _hasTextToDisplay
|
||||
* @type Boolean
|
||||
* @private
|
||||
*/
|
||||
_hasTextToDisplay: false,
|
||||
|
||||
initializer: function() {
|
||||
// Add the link button first.
|
||||
this.addButton({
|
||||
@ -156,7 +175,8 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
||||
anchornodes,
|
||||
anchornode,
|
||||
url,
|
||||
target;
|
||||
target,
|
||||
textToDisplay;
|
||||
|
||||
// Note this is a document fragment and YUI doesn't like them.
|
||||
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);
|
||||
url = anchornode.getAttribute('href');
|
||||
target = anchornode.getAttribute('target');
|
||||
textToDisplay = anchornode.get('innerText');
|
||||
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') {
|
||||
this._content.one('.newwindow').setAttribute('checked', 'checked');
|
||||
this._content.one(SELECTORS.NEWWINDOW).setAttribute('checked', 'checked');
|
||||
} 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
|
||||
}).hide();
|
||||
|
||||
input = this._content.one('.url');
|
||||
input = this._content.one(SELECTORS.URLINPUT);
|
||||
|
||||
value = input.get('value');
|
||||
if (value !== '') {
|
||||
@ -250,14 +281,23 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
||||
link,
|
||||
selectednode,
|
||||
target,
|
||||
anchornodes;
|
||||
anchornodes,
|
||||
isUpdating,
|
||||
urlText,
|
||||
textToDisplay;
|
||||
|
||||
this.editor.focus();
|
||||
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.
|
||||
link = Y.Node.create('<a>' + url + '</a>');
|
||||
link = Y.Node.create('<a>' + textToDisplay + '</a>');
|
||||
link.setAttribute('href', url);
|
||||
|
||||
// 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));
|
||||
// Add new window attributes if requested.
|
||||
Y.Array.each(anchornodes, function(anchornode) {
|
||||
target = this._content.one('.newwindow');
|
||||
target = this._content.one(SELECTORS.NEWWINDOW);
|
||||
if (target.get('checked')) {
|
||||
anchornode.setAttribute('target', '_blank');
|
||||
} else {
|
||||
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);
|
||||
|
||||
return selectednode;
|
||||
@ -342,9 +386,11 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
||||
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) {
|
||||
this._content.one('.openlinkbrowser').on('click', function(e) {
|
||||
this._content.one(SELECTORS.LINKBROWSER).on('click', function(e) {
|
||||
e.preventDefault();
|
||||
this.get('host').showFilepicker('link', this._filepickerCallback, 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.
|
||||
nodes.each(function(node) {
|
||||
// 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);
|
||||
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));
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 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',
|
||||
CSS = {
|
||||
NEWWINDOW: 'atto_link_openinnewwindow',
|
||||
URLINPUT: 'atto_link_urlentry'
|
||||
URLINPUT: 'atto_link_urlentry',
|
||||
URLTEXT: 'atto_link_urltext'
|
||||
},
|
||||
SELECTORS = {
|
||||
URLINPUT: '.atto_link_urlentry'
|
||||
NEWWINDOW: '.atto_link_openinnewwindow',
|
||||
URLINPUT: '.atto_link_urlentry',
|
||||
URLTEXT: '.atto_link_urltext',
|
||||
SUBMIT: '.submit',
|
||||
LINKBROWSER: '.openlinkbrowser'
|
||||
},
|
||||
TEMPLATE = '' +
|
||||
'<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}}' +
|
||||
'<label for="{{elementid}}_atto_link_urlentry">{{get_string "enterurl" component}}</label>' +
|
||||
'<div class="input-group input-append w-100 mb-1">' +
|
||||
@ -59,7 +69,8 @@ var COMPONENTNAME = 'atto_link',
|
||||
'</div>' +
|
||||
'{{/if}}' +
|
||||
'<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}}">' +
|
||||
'{{get_string "openinnewwindow" component}}' +
|
||||
'</label>' +
|
||||
@ -90,6 +101,14 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
||||
*/
|
||||
_content: null,
|
||||
|
||||
/**
|
||||
* Text to display has value or not.
|
||||
* @property _hasTextToDisplay
|
||||
* @type Boolean
|
||||
* @private
|
||||
*/
|
||||
_hasTextToDisplay: false,
|
||||
|
||||
initializer: function() {
|
||||
// Add the link button first.
|
||||
this.addButton({
|
||||
@ -154,7 +173,8 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
||||
anchornodes,
|
||||
anchornode,
|
||||
url,
|
||||
target;
|
||||
target,
|
||||
textToDisplay;
|
||||
|
||||
// Note this is a document fragment and YUI doesn't like them.
|
||||
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);
|
||||
url = anchornode.getAttribute('href');
|
||||
target = anchornode.getAttribute('target');
|
||||
textToDisplay = anchornode.get('innerText');
|
||||
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') {
|
||||
this._content.one('.newwindow').setAttribute('checked', 'checked');
|
||||
this._content.one(SELECTORS.NEWWINDOW).setAttribute('checked', 'checked');
|
||||
} 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
|
||||
}).hide();
|
||||
|
||||
input = this._content.one('.url');
|
||||
input = this._content.one(SELECTORS.URLINPUT);
|
||||
|
||||
value = input.get('value');
|
||||
if (value !== '') {
|
||||
@ -248,14 +279,23 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
||||
link,
|
||||
selectednode,
|
||||
target,
|
||||
anchornodes;
|
||||
anchornodes,
|
||||
isUpdating,
|
||||
urlText,
|
||||
textToDisplay;
|
||||
|
||||
this.editor.focus();
|
||||
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.
|
||||
link = Y.Node.create('<a>' + url + '</a>');
|
||||
link = Y.Node.create('<a>' + textToDisplay + '</a>');
|
||||
link.setAttribute('href', url);
|
||||
|
||||
// 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));
|
||||
// Add new window attributes if requested.
|
||||
Y.Array.each(anchornodes, function(anchornode) {
|
||||
target = this._content.one('.newwindow');
|
||||
target = this._content.one(SELECTORS.NEWWINDOW);
|
||||
if (target.get('checked')) {
|
||||
anchornode.setAttribute('target', '_blank');
|
||||
} else {
|
||||
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);
|
||||
|
||||
return selectednode;
|
||||
@ -340,9 +384,11 @@ Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.Edit
|
||||
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) {
|
||||
this._content.one('.openlinkbrowser').on('click', function(e) {
|
||||
this._content.one(SELECTORS.LINKBROWSER).on('click', function(e) {
|
||||
e.preventDefault();
|
||||
this.get('host').showFilepicker('link', this._filepickerCallback, 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.
|
||||
nodes.each(function(node) {
|
||||
// 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);
|
||||
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));
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 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