Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added possibility to use custom icons in buttons #1531

Merged
merged 13 commits into from
Feb 6, 2018
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Fixed Issues:
API Changes:

* [#1346](https://github.com/ckeditor/ckeditor-dev/issues/1346): [Balloon Toolbar](https://ckeditor.com/cke4/addon/balloontoolbar) [context manager API](https://docs.ckeditor.com/ckeditor4/docs/#!/api/CKEDITOR.plugins.balloontoolbar.contextManager) is now available in [pluginDefinition.init](https://docs.ckeditor.com/ckeditor4/docs/#!/api/CKEDITOR.pluginDefinition-method-init) method of a [requiring](https://docs.ckeditor.com/ckeditor4/docs/#!/api/CKEDITOR.pluginDefinition-property-requires) plugin.
* [#1530](https://github.com/ckeditor/ckeditor-dev/issues/1530): Added possibility to use custom icons for [buttons](CKEDITOR.ui.button).

Other Changes:

Expand Down
56 changes: 53 additions & 3 deletions plugins/button/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@
btnTpl = CKEDITOR.addTemplate( 'button', template );

CKEDITOR.plugins.add( 'button', {
// jscs:disable maximumLineLength
lang: 'af,ar,az,bg,ca,cs,da,de,de-ch,el,en,en-au,en-gb,eo,es,es-mx,eu,fa,fi,fr,gl,he,hr,hu,id,it,ja,km,ko,ku,lt,nb,nl,no,oc,pl,pt,pt-br,ro,ru,sk,sl,sq,sv,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
// jscs:enable maximumLineLength
beforeInit: function( editor ) {
editor.ui.addHandler( CKEDITOR.UI_BUTTON, CKEDITOR.ui.button.handler );
}
Expand Down Expand Up @@ -117,6 +119,8 @@
* this button should be appended.
*/
render: function( editor, output ) {
var modeStates = null;

function updateState() {
// "this" is a CKEDITOR.ui.button instance.
var mode = editor.mode;
Expand Down Expand Up @@ -198,7 +202,7 @@

// Indicate a mode sensitive button.
if ( this.modes ) {
var modeStates = {};
modeStates = {};

editor.on( 'beforeModeUnload', function() {
if ( editor.mode && this._.state != CKEDITOR.TRISTATE_DISABLED )
Expand All @@ -224,6 +228,8 @@
}
}

var iconName;

// For button that has text-direction awareness on selection path.
if ( this.directional ) {
editor.on( 'contentDirChanged', function( evt ) {
Expand Down Expand Up @@ -254,12 +260,30 @@
}

var name = this.name || this.command,
iconName = name;
iconPath = null;

iconName = name;

// Check if we're pointing to an icon defined by another command. (https://dev.ckeditor.com/ticket/9555)
if ( this.icon && !( /\./ ).test( this.icon ) ) {
iconName = this.icon;
this.icon = null;

} else {
// Register and use custom icon for button (#1530).
if ( this.icon ) {
iconPath = this.icon;
}
if ( CKEDITOR.env.hidpi && this.iconHiDpi ) {
iconPath = this.iconHiDpi;
}
}

if ( iconPath ) {
CKEDITOR.skin.addIcon( iconPath, iconPath );
this.icon = null;
} else {
iconPath = iconName;
}

var params = {
Expand All @@ -277,7 +301,7 @@
keydownFn: keydownFn,
focusFn: focusFn,
clickFn: clickFn,
style: CKEDITOR.skin.getIconStyle( iconName, ( editor.lang.dir == 'rtl' ), this.icon, this.iconOffset ),
style: CKEDITOR.skin.getIconStyle( iconPath, ( editor.lang.dir == 'rtl' ), this.icon, this.iconOffset ),
arrowHtml: this.hasArrow ? btnArrowTpl.output() : ''
};

Expand Down Expand Up @@ -381,6 +405,32 @@
* @param {String} definition.command The command to be executed once the button is activated.
* @param {String} definition.toolbar The {@link CKEDITOR.config#toolbarGroups toolbar group} into which
* the button will be added. An optional index value (separated by a comma) determines the button position within the group.
* @param {String} definition.icon Path to custom icon or icon name registered by another plugin. Custom icon paths
* are supported since **4.9.0** version.
*
* To use icon registered by another plugin, icon parameter should be used like:
*
* editor.ui.addButton( 'my_button', {
* icon: 'Link' // Uses link icon from Link plugin.
* } );
*
* If the plugin provides HiDPI version of an icon it will be used for HiDPI displays (so defining `iconHiDpi` is not needed
* in this case).
*
* To use custom icon, path to icon should be provided like:
*
* editor.ui.addButton( 'my_button', {
* icon: 'assets/icons/my_button.png'
* } )
*
* This icon will be used for both standard and HiDPI displays unless `iconHiDpi` is explicitly defined.
* **Important**: CKEditor will resolve relative paths based on {@link CKEDITOR#basePath}.
* @param {String} definition.iconHiDpi Path to custom HiDPI icon version. Supported since **4.9.0** version.
* It will be used only in HiDPI environments. Usage is similar to `icon` parameter:
*
* editor.ui.addButton( 'my_button', {
* iconHiDpi: 'assets/icons/my_button.hidpi.png'
* } )
*/
CKEDITOR.ui.prototype.addButton = function( name, definition ) {
this.add( name, CKEDITOR.UI_BUTTON, definition );
Expand Down
Binary file added tests/_assets/sample_icon.hidpi.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/_assets/sample_icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
264 changes: 264 additions & 0 deletions tests/plugins/button/buttonicon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
/* bender-tags: editor */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no test for adding custom icon for standard buttons (e.g. Bold). It should be possible by overwriting button.icon property before rendering.

/* bender-ckeditor-plugins: button,toolbar */

( function() {
'use strict';

var editorCounter = 0,
originalBasePath = null,
isDev = CKEDITOR.version === '%VERSION%',
isHidpi,
tests;

function createIconTests( testsObj, tests ) {
CKEDITOR.tools.array.forEach( tests, function( test ) {
testsObj[ test.name ] = function() {
if ( test.ignore ) {
// On a build version icons sprite image is loaded before any test code is execute so we are not able
// to emulate `CKEDITOR.env.hidpi` to force different icons loading. Due to this behaviour some tests
// needs to be ignored in build version.
assert.ignore();
} else {
CKEDITOR.env.hidpi = test.name.indexOf( 'hidpi' ) !== -1;
assertIcon( test.config, test.button, test.iconPath, test.iconName );
}
};
} );
}

function assertIcon( editorConfig, btnName, iconPath, iconName ) {
editorCounter++;
bender.editorBot.create( {
name: 'editor' + editorCounter,
config: editorConfig
}, function( bot ) {
var btn = bot.editor.ui.get( btnName ),
btnEl = CKEDITOR.document.getById( btn._.id ),
btnCss = CKEDITOR.tools.parseCssText( btnEl.findOne( '.cke_button_icon' ).getAttribute( 'style' ), true );

if ( iconPath === undefined ) {
// Standard icon should be checked.
if ( isDev ) {
var iconFileName = ( iconName || btnName ).toLowerCase(),
hidpi = CKEDITOR.env.hidpi ? 'hidpi\\/' : '';

iconPath = new RegExp( 'plugins\\/' + iconFileName + '\\/icons\\/' + hidpi + iconFileName + '\\.png', 'gi' );
} else {
// In build version all standard icons are inside 'icons.png' sprite.
iconPath = CKEDITOR.env.hidpi ? /plugins\/icons_hidpi\.png/gi : /plugins\/icons\.png/gi;
}
}

assert.isMatching( iconPath, btnCss[ 'background-image' ] );
} );
}

tests = {
init: function() {
isHidpi = CKEDITOR.env.hidpi;
},

tearDown: function() {
// Restore global values modified by tests.
CKEDITOR.env.hidpi = isHidpi;
if ( originalBasePath ) {
CKEDITOR.basePath = originalBasePath;
originalBasePath = null;
}
}
};

createIconTests( tests, [
{
name: 'test default button icon',
button: 'Link',
config: {
extraPlugins: 'link'
},
ignore: !isDev && CKEDITOR.env.hidpi
}, {
name: 'test default button icon (hidpi)',
button: 'Find',
config: {
extraPlugins: 'find'
},
ignore: !isDev && !CKEDITOR.env.hidpi
}, {
name: 'test overwriting default button icon',
button: 'Replace',
iconPath: /tests\/_assets\/sample_icon\.png/gi,
config: {
extraPlugins: 'find',
toolbar: [ [ 'Replace' ] ],
on: {
pluginsLoaded: function( evt ) {
var editor = evt.editor;
editor.ui.addButton( 'Replace', {
label: editor.lang.find.replace,
command: 'replace',
icon: 'tests/_assets/sample_icon.png'
} );
}
}
}
}, {
name: 'test overwriting default button icon (hidpi)',
button: 'Replace',
iconPath: /tests\/_assets\/sample_icon\.hidpi\.png/gi,
config: {
extraPlugins: 'find',
toolbar: [ [ 'Replace' ] ],
on: {
pluginsLoaded: function( evt ) {
var editor = evt.editor;
editor.ui.addButton( 'Replace', {
label: editor.lang.find.replace,
command: 'replace',
iconHiDpi: 'tests/_assets/sample_icon.hidpi.png'
} );
}
}
}
}, {
name: 'test button icon from different plugin',
button: 'custom_btn1',
iconName: 'about',
config: {
extraPlugins: 'about',
toolbar: [ [ 'custom_btn1' ] ],
on: {
pluginsLoaded: function( evt ) {
evt.editor.ui.addButton( 'custom_btn1', {
icon: 'about'
} );
}
}
},
ignore: !isDev && CKEDITOR.env.hidpi
}, {
name: 'test button icon from different plugin (hidpi)',
button: 'custom_btn2',
iconName: 'blockquote',
config: {
extraPlugins: 'blockquote',
toolbar: [ [ 'custom_btn2' ] ],
on: {
pluginsLoaded: function( evt ) {
evt.editor.ui.addButton( 'custom_btn2', {
icon: 'blockquote'
} );
}
}
},
ignore: !isDev && !CKEDITOR.env.hidpi
}, {
name: 'test custom button icon',
button: 'custom_btn3',
iconPath: /tests\/_assets\/sample_icon\.png/gi,
config: {
toolbar: [ [ 'custom_btn3' ] ],
on: {
pluginsLoaded: function( evt ) {
evt.editor.ui.addButton( 'custom_btn3', {
icon: 'tests/_assets/sample_icon.png'
} );
}
}
}
}, {
name: 'test custom button icon (hidpi)',
button: 'custom_btn4',
iconPath: /tests\/_assets\/sample_icon\.hidpi\.png/gi,
config: {
toolbar: [ [ 'custom_btn4' ] ],
on: {
pluginsLoaded: function( evt ) {
evt.editor.ui.addButton( 'custom_btn4', {
iconHiDpi: 'tests/_assets/sample_icon.hidpi.png'
} );
}
}
}
}, {
name: 'test custom button icon-only (hidpi)',
button: 'custom_btn5',
iconPath: /tests\/_assets\/sample_icon\.png/gi,
config: {
toolbar: [ [ 'custom_btn5' ] ],
on: {
pluginsLoaded: function( evt ) {
evt.editor.ui.addButton( 'custom_btn5', {
icon: 'tests/_assets/sample_icon.png'
} );
}
}
}
}, {
name: 'test custom button icon with different basepath',
button: 'custom_btn6',
iconPath: /different\/basepath\/assets\/icons\.sample\.png/gi,
config: {
toolbar: [ [ 'custom_btn6' ] ],
on: {
pluginsLoaded: function( evt ) {
originalBasePath = CKEDITOR.basePath;
CKEDITOR.basePath = '/different/basepath/';
evt.editor.ui.addButton( 'custom_btn6', {
icon: 'assets/icons.sample.png'
} );
}
}
}
}, {
name: 'test custom button icon with different basepath (hidpi)',
button: 'custom_btn7',
iconPath: /different\/basepath\/assets\/hidpi\/icons\.sample\.png/gi,
config: {
toolbar: [ [ 'custom_btn7' ] ],
on: {
pluginsLoaded: function( evt ) {
originalBasePath = CKEDITOR.basePath;
CKEDITOR.basePath = '/different/basepath/';
evt.editor.ui.addButton( 'custom_btn7', {
icon: 'assets/hidpi/icons.sample.png'
} );
}
}
}
}, {
name: 'test custom button icon with different basepath trailing slash',
button: 'custom_btn8',
iconPath: /['|(]\/assets\/icons\.sample\.png/gi,
config: {
toolbar: [ [ 'custom_btn8' ] ],
on: {
pluginsLoaded: function( evt ) {
originalBasePath = CKEDITOR.basePath;
CKEDITOR.basePath = '/different/basepath/';
evt.editor.ui.addButton( 'custom_btn8', {
icon: '/assets/icons.sample.png'
} );
}
}
}
}, {
name: 'test custom button icon with different basepath trailing slash (hidpi)',
button: 'custom_btn9',
iconPath: /['|(]\/assets\/hidpi\/icons\.sample\.png/gi,
config: {
toolbar: [ [ 'custom_btn9' ] ],
on: {
pluginsLoaded: function( evt ) {
originalBasePath = CKEDITOR.basePath;
CKEDITOR.basePath = '/different/basepath/';
evt.editor.ui.addButton( 'custom_btn9', {
icon: '/assets/hidpi/icons.sample.png'
} );
}
}
}
}
] );

bender.test( tests );
} )();
Loading