Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Added Advanced tab to Link dialog, similar to Images' #234

Closed
wants to merge 1 commit into from

5 participants

@WebVeteran

Some additions to help with using SEO and light boxes, etc.
Set "link_advtab: true" in your tinyMCE.init({}) to turn on the advanced link tab.

GENERAL tab
• Text
• URL
• Anchors (pulldown menu)
• Links (pulldown menu)

ADVANCED tab
• Title
• Target
• Targets (pulldown menu)
• Rel
• Rels (pulldown menu)

screen shot 2013-08-19 at 11 33 20 am
screen shot 2013-08-19 at 11 33 35 am

@WebVeteran WebVeteran Added Advanced tab to Link dialog, similar to Images'
Some additions to help with using SEO and light boxes, etc.
Set "link_advtab: true" in your tinyMCE.init({}) to turn on the advanced link tab.

GENERAL tab
• Text
• URL
• Anchors (pulldown menu)
• Links (pulldown menu)

ADVANCED tab
• Title
• Target
• Targets (pulldown menu)
• Rel
• Rels (pulldown menu)
1cd929e
@WebVeteran

Forgot to mention... add RELs in the init({}) the same way you add Targets...

link_list: "/admin/main/tools/pagesJSON.cfm",
target_list: [
{title: 'Same Window/Tab', value: '_self'},
{title: 'New Window/Tab', value: '_blank'}
],
rel_list: [
{title: 'Rel Sample 1', value: 'rs1'},
{title: 'Rel Sample 2', value: 'rs2'}
],

@spocke
Owner

Need to pull this in when making 4.1 since it changes the current behavior. Also not sure about the rel input area. According to the specs rel a fixed list of tokens: http://www.w3.org/html/wg/drafts/html/master/links.html#attr-hyperlink-rel however the user should be able to select multiple ones. Might be better to add the advanced options like this to a separate plugin.

@WebVeteran

Hi Johan,
The rel inputs are for controlling popup modals such as Shadowbox:
http://www.shadowbox-js.com/usage.html
EX: [a href="mymovie.swf" rel="shadowbox;height=140;width=120"]My Movie[/a]

I know that usage is not HTML5 spec, but it is real world usage. Also someone might opt for tinymce to output xhtml rather than html5.

@rhetherington

Hi WebVeteran / Spocke, thanks for taking the time to create this pull request as I have been Google'ing everywhere to find out where the "title" attribute went in 4.0. Might I suggest moving the "title" attribute of the "link" "advanced tab" to the "general" tab. I expect my content editors to complete "url" and "title" as a minimum standard for both SEO and accessibility. I would generally not consider the "title" attribute to be an advanced config for a link. I also noticed that the "title" attribute is missing from the "image" plugin also. I generally expect images to have both "alt" and "title" attributes completed as a minimum standard of coding.

Many thanks again.

Richard Hetherington
Web Developer

@toxalot

The title attribute does not help with SEO or accessibility. The current trend is to remove the title attribute from legacy code and not use it at all on new code. I really would not want a set up that would encourage its use.

@rhetherington

Well, I disagree. I see nowhere on the internet where it states that title tags should be ommitted and in fact the w3c states that you can and should add title attributes to any html5 element if it provides additional data / benefit to the user. I for one use title attributes for backwards compatability and to create tooltips when space to display a title / heading is limited. "Of course" I could modify all of my websites to use some form of "data-" attribute, but until such times as the title attribute is "formally" deprecated from current standards, then I believe it's a viable element attribute that should be accessible within user interfaces.

Just my opinion.

@toxalot

We'll have to agree to disagree.

The title attribute will never be deprecated and does have valid uses. It's valid on just about every element in HTML5, but that doesn't mean it should be added to every element (or every anchor) by default.

I don't have time to find the links now, but I see everywhere on the Internet about how screen readers don't read the title attribute (except maybe for form fields with no label), keyboard users can't access the title attribute, touch screen users won't see the title attribute, search engines give no weight to the title attribute. If the content is important enough, it should be in the visible text.

That being said, I still use the title attribute occasionally when I want additional info for mouse hover (or with JavaScript widgets). But, I don't want users to be encouraged to add a title attribute to all images / links.

Perhaps another config option is required to specify which tab it should appear on. Or make this a separate plugin altogether.

I like the current behaviour and would prefer to see this added as a separate plugin.

@rhetherington

Hi Jennifer (toxalot), I agree with you entirely and I have read up regarding various attributes and their usefulness across various media. Unfortunately for me my customer base is largely public sector and using dinosaur desktop boxes and not flashy ipads, iphones and similar.

I like your suggestion of possible plugin config. This could be a really nice feature, whereby you might provide a config for the attributes to display per plugin and also which ones must be completed before the plugin will allow updating of content. Therefore could it be that the current config remains as is, but allow it to be overriden ad hoc without having to hack the code to death?

@toxalot

As long as current behaviour remains unchanged, I'll be happy.

@WebVeteran
@toxalot

I am not interested in debating this further.

@WebVeteran

Richard - you're welcome! And thanks for the recognition.
I have a version of this as an External Plugin that you may be interested in. It has little more than spocke incorporated into the official built-in plugin.
rels
links
targets

@rhetherington

Hi Jules, I have already implemented your plugin across my websites.

Your plugin has inspired me to try making my own as I plan to make a new HTML Source editor which will work on the selected text within TinyMCE editor rather than the entire source. As most of the element classes, id's and CSS styling options have also disappeared in 4.0, I believe being able to edit an element's HTML source in a targeted fashion will be a massive optimisation. I have tried this loading the selected text into a jquery ui dialog, however I can't get this to update correctly. I think keeping it within TinyMCE will help. I'm more of a back end developer than front end, so this will be somewhat of a challenge :-) Maybe a future version of TinyMCE will make the source editor load "selected" text or "all" text an option??

@rhetherington

Here we go, a modified "code" plugin called htmleditor which allows fine tuning of a "selected" code rather than entire editor source. If anyone has any suggestions or improvements, please comment. I'll try and create this as a new plugin to allow comments separately from this thread, however it's my first time using github in this way :-)

Richard Hetherington

tinymce.PluginManager.add("htmleditor", function (e) {
e.addButton("htmleditor", {
text: "HTML Editor",
icon: !1,
onclick: function () {
e.windowManager.open({
title: "HTML Editor",
body: [{
type: "textbox",
name: "html_source",
label: "HTML",
value: e.selection.getContent( { format : 'html' } ),
multiline: !0,
minWidth: e.getParam("code_dialog_width", 600),
minHeight: e.getParam("code_dialog_height", Math.min(tinymce.DOM.getViewPort().h - 200, 500)),
spellcheck: !1,
style: "direction: ltr; text-align: left"
}],
onsubmit: function (t) {
// Set focus and set an undo point
e.focus(), e.undoManager.transact(function () {
// Update the selected text
e.execCommand('mceReplaceContent', false, t.data.html_source)
}), e.focus(), e.nodeChanged()
}
})
}
})
});

@rhetherington

Modified HTML / Code Editor - Works with Selected text rather than entire source!
#279

Richard Hetherington

@spocke
Owner

Started to poke around with this one. I think it would be nice if it was possible to dynamically configure in form control into the link dialog that alters attributes on the link.

My current idea is a config option like this:

tinymce.init({
    link_general_items: [
       {
          name: 'rel',
          type: 'combobox',
          label: 'Rel',
          values: [
                {text: 'My rel 1', value: 'my_rel1'},
                {text: 'My rel 2', value: 'my_rel2'}
          ]
        },
        {
            name: 'data-custom',
            type: 'text'
            label: 'My custom value'
        }
    ]
});

It basically enables you to add any field for any attribute and comboboxes, listboxes, textboxes etc. The drawback with this is that it's a bit heavy and complex to configure.

@WebVeteran

Spocke - It would be even nicer if tinyMCE could automatically read every attribute and populate by itself, and then allow us to add another right on the window. Rather than having to hard code the custom attributes in the config.

@FlashJunior

@spocke sounds good for me. But the Title-Attribut should be standard, we need that for SEO and wcag 2.0 accessibility.

@FlashJunior

@spocke any update on this?

@FlashJunior

title attribute will be added in 4.0.21. You can test it http://www.tinymce.com/nightly/tinymce/tests/manual/development.html

@spocke
Owner

Maybe this could be added as an external plugin instead a more advanced link plugin for power users. Closing it now.

@spocke spocke closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Aug 19, 2013
  1. @WebVeteran

    Added Advanced tab to Link dialog, similar to Images'

    WebVeteran authored
    Some additions to help with using SEO and light boxes, etc.
    Set "link_advtab: true" in your tinyMCE.init({}) to turn on the advanced link tab.
    
    GENERAL tab
    • Text
    • URL
    • Anchors (pulldown menu)
    • Links (pulldown menu)
    
    ADVANCED tab
    • Title
    • Target
    • Targets (pulldown menu)
    • Rel
    • Rels (pulldown menu)
This page is out of date. Refresh to see the latest.
Showing with 198 additions and 114 deletions.
  1. +198 −114 js/tinymce/plugins/link/plugin.js
View
312 js/tinymce/plugins/link/plugin.js
@@ -32,6 +32,7 @@ tinymce.PluginManager.add('link', function(editor) {
var data = {}, selection = editor.selection, dom = editor.dom, selectedElm, anchorElm, initialText;
var win, linkListCtrl, relListCtrl, targetListCtrl;
+ // URLs
function linkListChangeHandler(e) {
var textCtrl = win.find('#text');
@@ -55,39 +56,67 @@ tinymce.PluginManager.add('link', function(editor) {
return linkListItems;
}
+
+
+ // RELs
+ function relListChangeHandler(e) {
+ var textCtrl = win.find('#text');
+
+ if (!textCtrl.value() || (e.lastControl && textCtrl.value() == e.lastControl.text())) {
+ textCtrl.value(e.control.text());
+ }
+
+ win.find('#rel').value(e.control.value());
+ }
- function buildRelList(relValue) {
+ function buildRelList(rel) {
var relListItems = [{text: 'None', value: ''}];
tinymce.each(editor.settings.rel_list, function(rel) {
relListItems.push({
text: rel.text || rel.title,
value: rel.value,
- selected: relValue === rel.value
+ selected: rel === rel.value
});
});
return relListItems;
}
- function buildTargetList(targetValue) {
- var targetListItems = [{text: 'None', value: ''}];
- if (!editor.settings.target_list) {
- targetListItems.push({text: 'New window', value: '_blank'});
+ // TARGETs
+ function targetListChangeHandler(e) {
+ var textCtrl = win.find('#text');
+
+ if (!textCtrl.value() || (e.lastControl && textCtrl.value() == e.lastControl.text())) {
+ textCtrl.value(e.control.text());
}
- tinymce.each(editor.settings.target_list, function(target) {
- targetListItems.push({
- text: target.text || target.title,
- value: target.value,
- selected: targetValue === target.value
+ win.find('#target').value(e.control.value());
+ }
+
+ function buildTargetList(target) {
+ var targetListItems = [{text: 'None', value: ''}];
+
+ if (!editor.settings.target_list) {
+ // DEFAULTs
+ targetListItems.push({text: 'Same Window/Tab', value: '_self'});
+ targetListItems.push({text: 'New Window/Tab', value: '_blank'});
+ } else {
+ tinymce.each(editor.settings.target_list, function(target) {
+ targetListItems.push({
+ text: target.text || target.title,
+ value: target.value,
+ selected: target === target.value
+ });
});
- });
+ }
return targetListItems;
}
-
+
+
+ // ANCHORs
function buildAnchorListControl(url) {
var anchorList = [];
@@ -115,6 +144,10 @@ tinymce.PluginManager.add('link', function(editor) {
};
}
}
+
+
+
+
function updateText() {
if (!initialText && data.text.length === 0) {
@@ -127,8 +160,9 @@ tinymce.PluginManager.add('link', function(editor) {
data.text = initialText = anchorElm ? (anchorElm.innerText || anchorElm.textContent) : selection.getContent({format: 'text'});
data.href = anchorElm ? dom.getAttrib(anchorElm, 'href') : '';
- data.target = anchorElm ? dom.getAttrib(anchorElm, 'target') : '';
+ data.title = anchorElm ? dom.getAttrib(anchorElm, 'title') : '';
data.rel = anchorElm ? dom.getAttrib(anchorElm, 'rel') : '';
+ data.target = anchorElm ? dom.getAttrib(anchorElm, 'target') : '';
if (selectedElm.nodeName == "IMG") {
data.text = initialText = " ";
@@ -137,133 +171,183 @@ tinymce.PluginManager.add('link', function(editor) {
if (linkList) {
linkListCtrl = {
type: 'listbox',
- label: 'Link list',
+ label: 'Links',
values: buildLinkList(),
onselect: linkListChangeHandler
};
}
- if (editor.settings.target_list !== false) {
- targetListCtrl = {
- name: 'target',
- type: 'listbox',
- label: 'Target',
- values: buildTargetList(data.target)
- };
- }
-
if (editor.settings.rel_list) {
relListCtrl = {
- name: 'rel',
+ name: 'rellist',
type: 'listbox',
- label: 'Rel',
- values: buildRelList(data.rel)
+ label: 'Rels',
+ values: buildRelList(data.rel),
+ onselect: relListChangeHandler
};
}
- win = editor.windowManager.open({
- title: 'Insert link',
- data: data,
- body: [
- {
- name: 'href',
- type: 'filepicker',
- filetype: 'file',
- size: 40,
- autofocus: true,
- label: 'Url',
- onchange: updateText,
- onkeyup: updateText
- },
- {name: 'text', type: 'textbox', size: 40, label: 'Text to display', onchange: function() {
- data.text = this.value();
- }},
- buildAnchorListControl(data.href),
- linkListCtrl,
- relListCtrl,
- targetListCtrl
- ],
- onSubmit: function(e) {
- var data = e.data, href = data.href;
-
- // Delay confirm since onSubmit will move focus
- function delayedConfirm(message, callback) {
- window.setTimeout(function() {
- editor.windowManager.confirm(message, callback);
- }, 0);
- }
+ targetListCtrl = {
+ name: 'targetlist',
+ type: 'listbox',
+ label: 'Targets',
+ values: buildTargetList(data.target),
+ onselect: targetListChangeHandler
+ };
- function insertLink() {
- if (data.text != initialText) {
- if (anchorElm) {
- editor.focus();
- anchorElm.innerHTML = data.text;
-
- dom.setAttribs(anchorElm, {
- href: href,
- target: data.target ? data.target : null,
- rel: data.rel ? data.rel : null
- });
-
- selection.select(anchorElm);
- } else {
- editor.insertContent(dom.createHTML('a', {
- href: href,
- target: data.target ? data.target : null,
- rel: data.rel ? data.rel : null
- }, data.text));
- }
- } else {
- editor.execCommand('mceInsertLink', false, {
+
+
+ function onSubmitForm() {
+ var data = win.toJSON();
+ var data = data, href = data.href, target = data.target;
+
+ // Delay confirm since onSubmit will move focus
+ function delayedConfirm(message, callback) {
+ window.setTimeout(function() {
+ editor.windowManager.confirm(message, callback);
+ }, 0);
+ }
+
+ function insertLink() {
+ if (data.text != initialText) {
+ if (anchorElm) {
+ editor.focus();
+ anchorElm.innerHTML = data.text;
+
+ dom.setAttribs(anchorElm, {
href: href,
- target: data.target,
+ title: data.title ? data.title : null,
+ target: data.target ? data.target : null,
rel: data.rel ? data.rel : null
});
- }
- }
- if (!href) {
- editor.execCommand('unlink');
- return;
+ selection.select(anchorElm);
+ } else {
+ editor.insertContent(dom.createHTML('a', {
+ href: href,
+ title: data.title ? data.title : null,
+ target: data.target ? data.target : null,
+ rel: data.rel ? data.rel : null
+ }, data.text));
+ }
+ } else {
+ editor.execCommand('mceInsertLink', false, {
+ href: href,
+ title: data.title,
+ target: data.target ? data.target : null,
+ rel: data.rel ? data.rel : null
+ });
}
+ }
- // Is email and not //user@domain.com
- if (href.indexOf('@') > 0 && href.indexOf('//') == -1 && href.indexOf('mailto:') == -1) {
- delayedConfirm(
- 'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?',
- function(state) {
- if (state) {
- href = 'mailto:' + href;
- }
+ if (!href) {
+ editor.execCommand('unlink');
+ return;
+ }
- insertLink();
+ // Is email and not //user@domain.com
+ if (href.indexOf('@') > 0 && href.indexOf('//') == -1 && href.indexOf('mailto:') == -1) {
+ delayedConfirm(
+ 'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?',
+ function(state) {
+ if (state) {
+ href = 'mailto:' + href;
}
- );
- return;
- }
+ insertLink();
+ }
+ );
- // Is www. prefixed
- if (/^\s*www\./i.test(href)) {
- delayedConfirm(
- 'The URL you entered seems to be an external link. Do you want to add the required http:// prefix?',
- function(state) {
- if (state) {
- href = 'http://' + href;
- }
+ return;
+ }
- insertLink();
+ // Is www. prefixed
+ if (/^\s*www\./i.test(href)) {
+ delayedConfirm(
+ 'The URL you entered seems to be an external link. Do you want to add the required http:// prefix?',
+ function(state) {
+ if (state) {
+ href = 'http://' + href;
}
- );
- return;
- }
+ insertLink();
+ }
+ );
- insertLink();
+ return;
}
- });
- }
+ insertLink();
+ }
+
+ // General settings shared between simple and advanced dialogs
+ var generalFormItems = [
+ {name: 'text', type: 'textbox', size: 40, label: 'Text', onchange: function() {
+ data.text = this.value();
+ }},
+ {
+ name: 'href',
+ type: 'filepicker',
+ filetype: 'file',
+ size: 40,
+ autofocus: true,
+ label: 'Url',
+ onchange: updateText,
+ onkeyup: updateText
+ },
+ buildAnchorListControl(data.href),
+ linkListCtrl
+ ];
+
+
+ if (editor.settings.link_advtab) {
+
+ // Advanced dialog shows general+advanced tabs
+ win = editor.windowManager.open({
+ title: 'Insert/edit link',
+ data: data,
+ bodyType: 'tabpanel',
+ body: [
+ {
+ title: 'General',
+ type: 'form',
+ items: generalFormItems
+ },
+
+ {
+ title: 'Advanced',
+ type: 'form',
+ pack: 'start',
+ items: [
+ {name: 'title', type: 'textbox', size: 40, label: 'Title', onchange: function() {
+ data.title = this.value();
+ }}
+ ,
+ {name: 'target', type: 'textbox', size: 40, label: 'Target', onchange: function() {
+ data.target = this.value();
+ }},
+ targetListCtrl,
+ {name: 'rel', type: 'textbox', size: 40, label: 'Rel', onchange: function() {
+ data.rel = this.value();
+ }},
+ relListCtrl
+ ]
+ }
+ ],
+ onSubmit: onSubmitForm
+ });
+ } else {
+ // Simple default dialog
+ win = editor.windowManager.open({
+ title: 'Insert/edit link',
+ data: data,
+ body: generalFormItems,
+ onSubmit: onSubmitForm
+ });
+ }
+
+
+ }
editor.addButton('link', {
icon: 'link',
tooltip: 'Insert/edit link',
@@ -292,4 +376,4 @@ tinymce.PluginManager.add('link', function(editor) {
context: 'insert',
prependToContext: true
});
-});
+});
Something went wrong with that request. Please try again.