Index: typo3/sysext/rtehtmlarea/extensions/DefaultLink/class.tx_rtehtmlarea_defaultlink.php =================================================================== --- typo3/sysext/rtehtmlarea/extensions/DefaultLink/class.tx_rtehtmlarea_defaultlink.php (révision 7101) +++ typo3/sysext/rtehtmlarea/extensions/DefaultLink/class.tx_rtehtmlarea_defaultlink.php (copie de travail) @@ -2,7 +2,7 @@ /*************************************************************** * Copyright notice * -* (c) 2008-2009 Stanislas Rolland +* (c) 2008-2010 Stanislas Rolland * All rights reserved * * This script is part of the Typo3 project. The Typo3 project is @@ -24,7 +24,7 @@ /** * Default Link extension for htmlArea RTE * - * @author Stanislas Rolland + * @author Stanislas Rolland * * TYPO3 SVN ID: $Id$ * @@ -43,9 +43,10 @@ protected $toolbar; // Reference to RTE toolbar array protected $LOCAL_LANG; // Frontend language array - protected $pluginButtons = 'link'; + protected $pluginButtons = 'link, unlink'; protected $convertToolbarForHtmlAreaArray = array ( - 'link' => 'CreateLink', + 'link' => 'CreateLink', + 'unlink' => 'UnLink', ); /** Index: typo3/sysext/rtehtmlarea/htmlarea/plugins/DefaultLink/default-link.js =================================================================== --- typo3/sysext/rtehtmlarea/htmlarea/plugins/DefaultLink/default-link.js (révision 7101) +++ typo3/sysext/rtehtmlarea/htmlarea/plugins/DefaultLink/default-link.js (copie de travail) @@ -1,7 +1,7 @@ /*************************************************************** * Copyright notice * -* (c) 2008-2009 Stanislas Rolland +* (c) 2008-2010 Stanislas Rolland * All rights reserved * * This script is part of the TYPO3 project. The TYPO3 project is @@ -32,54 +32,74 @@ * TYPO3 SVN ID: $Id$ */ DefaultLink = HTMLArea.Plugin.extend({ - - constructor : function(editor, pluginName) { + constructor: function(editor, pluginName) { this.base(editor, pluginName); }, - /* * This function gets called by the class constructor */ - configurePlugin : function(editor) { - + configurePlugin: function(editor) { this.baseURL = this.editorConfiguration.baseURL; this.pageTSConfiguration = this.editorConfiguration.buttons.link; this.stripBaseUrl = this.pageTSConfiguration && this.pageTSConfiguration.stripBaseUrl && this.pageTSConfiguration.stripBaseUrl; this.showTarget = !(this.pageTSConfiguration && this.pageTSConfiguration.targetSelector && this.pageTSConfiguration.targetSelector.disabled); - /* * Registering plugin "About" information */ var pluginInformation = { - version : "1.0", - developer : "Stanislas Rolland", - developerUrl : "http://www.sjbr.ca/", - copyrightOwner : "Stanislas Rolland", - sponsor : "SJBR", - sponsorUrl : "http://www.sjbr.ca/", - license : "GPL" + version : '2.0', + developer : 'Stanislas Rolland', + developerUrl : 'http://www.sjbr.ca/', + copyrightOwner : 'Stanislas Rolland', + sponsor : 'SJBR', + sponsorUrl : 'http://www.sjbr.ca/', + license : 'GPL' }; this.registerPluginInformation(pluginInformation); - /* - * Registering the button + * Registering the buttons */ - var buttonId = "CreateLink"; - var buttonConfiguration = { - id : buttonId, - tooltip : this.localize("createlink"), - action : "onButtonPress", - hotKey : (this.pageTSConfiguration ? this.pageTSConfiguration.hotKey : null), - context : "a", - selection : true, - dialog : true - }; - this.registerButton(buttonConfiguration); - + var buttonList = this.buttonList, buttonId; + for (var i = 0; i < buttonList.length; ++i) { + var button = buttonList[i]; + buttonId = button[0]; + var buttonConfiguration = { + id : buttonId, + tooltip : this.localize(buttonId.toLowerCase()), + action : "onButtonPress", + hotKey : (this.pageTSConfiguration ? this.pageTSConfiguration.hotKey : null), + context : button[1], + selection : button[2], + dialog : button[3] + }; + this.registerButton(buttonConfiguration); + } return true; - }, - + }, /* + * The list of buttons added by this plugin + */ + buttonList: [ + ['CreateLink', 'a,img', false, true], + ['UnLink', 'a', false, false] + ], + /* + * Sets of default configuration values for dialogue form fields + */ + configDefaults: { + combo: { + editable: true, + typeAhead: true, + triggerAction: 'all', + forceSelection: true, + mode: 'local', + valueField: 'value', + displayField: 'text', + helpIcon: true, + tpl: '
{text}
' + } + }, + /* * This function gets called when the button was pressed. * * @param object editor: the editor instance @@ -88,123 +108,279 @@ * * @return boolean false if action is completed */ - onButtonPress : function(editor, id, target) { - + onButtonPress: function(editor, id, target) { // Could be a button or its hotkey var buttonId = this.translateHotKey(id); buttonId = buttonId ? buttonId : id; - - if (buttonId === "UnLink") { - this.unLink(); - return false; + this.editor.focus(); + this.link = this.editor.getParentElement(); + var el = HTMLArea.getElementObject(this.link, 'a'); + if (el && /^a$/i.test(el.nodeName)) { + this.link = el; } - - var paramameters = null; - this.editor.focusEditor(); - var link = this.editor.getParentElement(); - var el = HTMLArea.getElementObject(link, "a"); - if (el != null && /^a$/i.test(el.nodeName)) link = el; - if (!link || !/^a$/i.test(link.nodeName)) { - link = null; - var selection = this.editor._getSelection(); - if (this.editor._selectionEmpty(selection)) { - alert(this.localize("Select some text")); - return; - } - paramameters = { - f_href : "", - f_title : "", - f_target : "" - }; - } else { - paramameters = { - f_href : (HTMLArea.is_ie && this.stripBaseUrl) ? this.stripBaseURL(link.href) : link.getAttribute("href"), - f_title : link.title, - f_target : link.target - }; + if (!this.link || !/^a$/i.test(this.link.nodeName)) { + this.link = null; } - - this.link = link; - this.dialog = this.openDialog("CreateLink", this.makeUrlFromPopupName("link"), "createLink", paramameters, {width:570, height:150}); + switch (buttonId) { + case 'UnLink': + this.unLink(); + break; + case 'CreateLink': + if (!this.link) { + var selection = this.editor._getSelection(); + if (this.editor._selectionEmpty(selection)) { + Ext.MessageBox.alert('', this.localize('Select some text')); + break; + } + this.parameters = { + href: 'http://', + title: '', + target: '' + }; + } else { + this.parameters = { + href: (Ext.isIE && this.stripBaseUrl) ? this.stripBaseURL(this.link.href) : this.link.getAttribute('href'), + title: this.link.title, + target: this.link.target + }; + } + // Open dialogue window + this.openDialogue( + buttonId, + 'Insert/Modify Link', + this.getWindowDimensions( + { + width: 470, + height:150 + }, + buttonId + ) + ); + break; + } return false; }, - /* - * Create the link + * Open the dialogue window * - * @param object param: the returned values + * @param string buttonId: the button id + * @param string title: the window title + * @param integer dimensions: the opening width of the window * - * @return boolean false + * @return void */ - createLink : function(param) { - if (typeof(param) != "undefined" && typeof(param.f_href) != "undefined") { - var a = this.link; - if(!a) { - this.editor._doc.execCommand("CreateLink", false, param.f_href); - a = this.editor.getParentElement(); - if (HTMLArea.is_gecko && !/^a$/i.test(a.nodeName)) { - var selection = this.editor._getSelection(); - var range = this.editor._createRange(selection); - try { - a = range.startContainer.childNodes[range.startOffset]; - } catch(e) {} + openDialogue: function (buttonId, title, dimensions) { + this.dialog = new Ext.Window({ + title: this.localize(title), + cls: 'htmlarea-window', + border: false, + width: dimensions.width, + height: 'auto', + // As of ExtJS 3.1, JS error with IE when the window is resizable + resizable: !Ext.isIE, + iconCls: buttonId, + listeners: { + afterrender: { + fn: this.onAfterRender, + scope: this + }, + close: { + fn: this.onClose, + scope: this } + }, + items: [{ + xtype: 'fieldset', + defaultType: 'textfield', + labelWidth: 100, + defaults: { + helpIcon: true, + width: 250, + labelSeparator: '' + }, + items: [{ + itemId: 'href', + name: 'href', + fieldLabel: this.localize('URL:'), + value: this.parameters.href, + helpTitle: this.localize('link_href_tooltip') + },{ + itemId: 'title', + name: 'title', + fieldLabel: this.localize('Title (tooltip):'), + value: this.parameters.title, + helpTitle: this.localize('link_title_tooltip') + }, Ext.apply({ + xtype: 'combo', + fieldLabel: this.localize('Target:'), + itemId: 'target', + helpTitle: this.localize('link_target_tooltip'), + store: new Ext.data.ArrayStore({ + autoDestroy: true, + fields: [ { name: 'text'}, { name: 'value'}], + data: [ + [this.localize('target_none'), ''], + [this.localize('target_blank'), '_blank'], + [this.localize('target_self'), '_self'], + [this.localize('target_top'), '_top'], + [this.localize('target_other'), '_other'] + ] + }), + listeners: { + select: { + fn: this.onTargetSelect + } + }, + hidden: !this.showTarget + }, this.configDefaults['combo']) + ,{ + itemId: 'frame', + name: 'frame', + fieldLabel: this.localize('frame'), + helpTitle: this.localize('frame_help'), + hideLabel: true, + hidden: true + } + ] + } + ], + buttons: [ + this.buildButtonConfig('OK', this.onOK), + this.buildButtonConfig('Cancel', this.onCancel) + ] + }); + this.show(); + }, + /* + * Handler invoked after the dialogue window is rendered + * If the current target is not in the available options, show frame field + */ + onAfterRender: function (dialog) { + var targetCombo = dialog.find('itemId', 'target')[0]; + if (!targetCombo.hidden && this.parameters.target) { + var frameField = dialog.find('itemId', 'frame')[0]; + var index = targetCombo.getStore().find('value', this.parameters.target); + if (index == -1) { + // The target is a specific frame name + targetCombo.setValue('_other'); + frameField.setValue(this.parameters.target); + frameField.show(); + frameField.label.show(); } else { - var href = param.f_href.trim(); - this.editor.selectNodeContents(a); - if (href == "") { - this.editor._doc.execCommand("Unlink", false, null); - this.dialog.close(); - return false; - } else { - a.href = href; - } + targetCombo.setValue(this.parameters.target); } - if (!(a && /^a$/i.test(a.nodeName))) { - this.dialog.close(); - return false; - } - if (typeof(param.f_target) != "undefined") a.target = param.f_target.trim(); - if (typeof(param.f_title) != "undefined") a.title = param.f_title.trim(); - this.editor.selectNodeContents(a); - this.dialog.close(); } + }, + /* + * Handler invoked when a target is selected + */ + onTargetSelect: function (combo, record) { + var frameField = combo.ownerCt.getComponent('frame'); + if (record.get('value') == '_other') { + frameField.show(); + frameField.label.show(); + frameField.focus(); + } else if (!frameField.hidden) { + frameField.hide(); + frameField.label.hide(); + } + }, + /* + * Handler invoked when the OK button is clicked + */ + onOK: function () { + var href = this.dialog.find('itemId', 'href')[0].getValue().trim(); + if (!href) { + Ext.MessageBox.alert('', this.localize('link_url_required')); + this.dialog.find('itemId', 'href').focus(); + return false; + } + var title = this.dialog.find('itemId', 'title')[0].getValue(); + var target = this.dialog.find('itemId', 'target')[0].getValue(); + if (target == '_other') { + target = this.dialog.find('itemId', 'frame')[0].getValue().trim(); + } + this.createLink(href, title, target); + this.close(); return false; }, - /* - * Unlink the selection. + * Create the link * - * @param object link: the link element to unlink + * @param string href: the value of href attribute + * @param string title: the value of title attribute + * @param string target: the value of target attribute * - * @return boolean false + * @return void */ - unLink : function () { - this.editor.focusEditor(); - var node = this.editor.getParentElement(); - var el = HTMLArea.getElementObject(node, "a"); - if (el != null && /^a$/i.test(el.nodeName)) node = el; - if (node != null && /^a$/i.test(node.nodeName)) this.editor.selectNode(node); - this.editor._doc.execCommand("Unlink", false, ""); + createLink: function (href, title, target) { + var a = this.link; + if (!a) { + this.editor.focus(); + this.restoreSelection(); + this.editor.document.execCommand('CreateLink', false, href); + a = this.editor.getParentElement(); + if (!Ext.isIE && !/^a$/i.test(a.nodeName)) { + var range = this.editor._createRange(this.editor._getSelection()); + if (range.startContainer.nodeType != 3) { + a = range.startContainer.childNodes[range.startOffset]; + } else { + a = range.startContainer.nextSibling; + } + this.editor.selectNode(a); + } + var el = HTMLArea.getElementObject(a, 'a'); + if (el != null && /^a$/i.test(el.nodeName)) { + a = el; + } + } else { + a.href = href; + } + if (a && /^a$/i.test(a.nodeName)) { + a.title = title; + a.target = target; + if (Ext.isOpera) { + this.editor.selectNodeContents(a, false); + } else { + this.editor.selectNodeContents(a); + } + } }, - /* + * Unlink the selection + */ + unLink: function () { + this.editor.focus(); + this.restoreSelection(); + if (this.link) { + this.editor.selectNode(this.link); + } + this.editor.document.execCommand('Unlink', false, ''); + }, + /* * IE makes relative links absolute. This function reverts this conversion. * * @param string url: the url * * @return string the url stripped out of the baseurl */ - stripBaseURL : function(url) { + stripBaseURL: function (url) { var baseurl = this.baseURL; // strip to last directory in case baseurl points to a file baseurl = baseurl.replace(/[^\/]+$/, ''); var basere = new RegExp(baseurl); - url = url.replace(basere, ""); + url = url.replace(basere, ''); // strip host-part of URL which is added by MSIE to links relative to server root - baseurl = baseurl.replace(/^(https?:\/\/[^\/]+)(.*)$/, '$1'); + baseurl = baseurl.replace(/^(https?:\/\/[^\/]+)(.*)$/, "$1"); basere = new RegExp(baseurl); - return url.replace(basere, ""); + return url.replace(basere, ''); + }, + /* + * This function gets called when the toolbar is updated + */ + onUpdateToolbar: function (button, mode, selectionEmpty, ancestors) { + if (mode === 'wysiwyg' && this.editor.isEditable() && button.itemId === 'CreateLink') { + button.setDisabled(selectionEmpty && !button.isInContext(mode, selectionEmpty, ancestors)); + } } }); - Index: typo3/sysext/rtehtmlarea/htmlarea/plugins/DefaultLink/locallang.xml =================================================================== --- typo3/sysext/rtehtmlarea/htmlarea/plugins/DefaultLink/locallang.xml (révision 7101) +++ typo3/sysext/rtehtmlarea/htmlarea/plugins/DefaultLink/locallang.xml (copie de travail) @@ -8,6 +8,8 @@ + + Index: typo3/sysext/rtehtmlarea/htmlarea/plugins/DefaultLink/popups/link.html =================================================================== --- typo3/sysext/rtehtmlarea/htmlarea/plugins/DefaultLink/popups/link.html (révision 7101) +++ typo3/sysext/rtehtmlarea/htmlarea/plugins/DefaultLink/popups/link.html (copie de travail) @@ -1,155 +0,0 @@ - - - - - Insert Image - - - - -
-
Insert/Modify Link
-
-
- - -
-
-
- - -
-
-
- - - -
-
- - -
-
-
-
- - Index: typo3/sysext/rtehtmlarea/htmlarea/skins/default/htmlarea.css =================================================================== --- typo3/sysext/rtehtmlarea/htmlarea/skins/default/htmlarea.css (révision 7138) +++ typo3/sysext/rtehtmlarea/htmlarea/skins/default/htmlarea.css (copie de travail) @@ -451,10 +451,6 @@ width:300px;height:200px; border:1px solid gray;margin:5px 0px; } -/* Selectors for the Default Link dialogue */ -.htmlarea-default-link #url, .htmlarea-default-link #title { - white-space:nowrap; -} /* Selectors for the InsertSmiley plugin */ .htmlarea-window .emoticon-array { padding: 10px; Index: typo3/sysext/t3skin/rtehtmlarea/htmlarea.css =================================================================== --- typo3/sysext/t3skin/rtehtmlarea/htmlarea.css (révision 7138) +++ typo3/sysext/t3skin/rtehtmlarea/htmlarea.css (copie de travail) @@ -458,10 +458,6 @@ width:300px;height:200px; border:1px solid gray;margin:5px 0px; } -/* Selectors for the Default Link dialogue */ -.htmlarea-default-link #url, .htmlarea-default-link #title { - white-space:nowrap; -} /* Selectors for the InsertSmiley plugin */ .htmlarea-window .emoticon-array { padding: 10px;