YUI Library Home

YUI Library Examples: Rich Text Editor: Flickr Image Search

Rich Text Editor: Flickr Image Search

This example provides a new button () in the toolbar that opens a custom panel.

This custom panel contains an AutoComplete Control that queries Flickr for tags and displays the images.

A selected image will be inserted into the Editor for ease of use.

This text field can contain stylized text and graphics. To cycle through all formatting options, use the keyboard shortcut Control + Shift + T to place focus on the toolbar and navigate between option heading names.

Common formatting keyboard shortcuts:

  • Control Shift B sets text to bold
  • Control Shift I sets text to italic
  • Control Shift U underlines text
  • Control Shift [ aligns text left
  • Control Shift | centers text
  • Control Shift ] aligns text right
  • Control Shift L adds an HTML link
  • To exit this text editor use the keyboard shortcut Control + Shift + ESC.
body

You have left the Rich Text Editor.

Setting up the Editor's HTML

Setting up the Editor's HTML is done by creating a textarea control on the page.

1<form method="post" action="#" id="form1"
2<textarea id="editor" name="editor" rows="20" cols="75"
3This is some more test text. <font face="Times New Roman">This is some more test text. 
4This is some more <b>test <i>text</i></b></font>
5This is some more test text. This is some more test text. 
6This is some more test text. This is some more test text. This is some more test text. 
7This is some more test text.  
8</textarea> 
9</form> 
view plain | print | ?

Setting up the Editor's Javascript

Once the textarea is on the page, then initialize the Editor like this:

1//The Editor config 
2var myConfig = { 
3    height: '300px'
4    width: '600px'
5    animate: true
6    dompath: true
7    focusAtStart: true 
8}; 
9 
10//Now let's load the Editor. 
11var myEditor = new YAHOO.widget.Editor('editor', myConfig); 
view plain | print | ?

Adding and Controlling the New Button

Here we subscribe to the toolbarLoaded Custom Event and create the new Button (flickr). After adding it to the group called insertitem, we subscribe to it's flickrClick Custom Event.

Inside this Custom Event, we set the STOP_EXEC_COMMAND var to true, which will keep the Editor from trying to run execCommand('flickr', '')

Then we call gutter.toggle() which will either hide or show our custom panel.

1var myEditor = new YAHOO.widget.Editor('editor', myConfig); 
2 
3//Wait for the editor's toolbar to load 
4myEditor.on('toolbarLoaded'function() { 
5    //create the new gutter object 
6    gutter = new YAHOO.gutter(); 
7 
8    //The Toolbar buttons config 
9    var flickrConfig = { 
10            type: 'push'
11            label: 'Insert Flickr Image'
12            value: 'flickr' 
13    } 
14     
15    //Add the button to the "insertitem" group 
16    myEditor.toolbar.addButtonToGroup(flickrConfig, 'insertitem'); 
17 
18    //Handle the button's click 
19    myEditor.toolbar.on('flickrClick'function(ev) { 
20        this._focusWindow(); 
21        if (ev && ev.img) { 
22            //To abide by the Flickr TOS, we need to link back to the image that we just inserted 
23            var html = '<a href="' + ev.url + '"><img src="' + ev.img + '" title="' + ev.title + '"></a>'
24            this.execCommand('inserthtml', html); 
25        } 
26        //Toggle the gutter, so that it opens and closes based on this click. 
27        gutter.toggle(); 
28    }); 
29    //Create the gutter control 
30    gutter.createGutter(); 
31}); 
32myEditor.render(); 
view plain | print | ?

Styling the New Button

There are 2 important states to style a button in the toolbar.

First is the default state, that can be accessed via this CSS rule: .yui-toolbar-container .yui-toolbar-flickr span.yui-toolbar-icon

Second is the selected state, that can be accessed via this CSS rule: .yui-toolbar-container .yui-toolbar-flickr-selected span.yui-toolbar-icon

.yui-toolbar-container is the class applied to the top-most container of the toolbar.

.yui-toolbar-icon is an extra SPAN injected into the button for spriting an image.

.yui-toolbar-VALUE is a dynamic class added to the button based on the value passed into the button's config. It is used for specific styling of a button that may appear in several places on the page.

The Style Rules to Create the Flickr Button in This Example

1.yui-skin-sam .yui-toolbar-container .yui-toolbar-flickr span.yui-toolbar-icon { 
2    background-imageurl( assets/flickr_default.gif ); 
3    background-position1px 0px
4} 
5.yui-skin-sam .yui-toolbar-container .yui-toolbar-flickr-selected span.yui-toolbar-icon { 
6    background-imageurl( assets/flickr_active.gif ); 
7    background-position1px 0px
8} 
view plain | print | ?

The Gutter Panel Full Javascript Source

The gutter in this example is not part of the Editor, but could easily be modified to do other things.

1(function() { 
2    //Some private vars 
3    var Dom = YAHOO.util.Dom, 
4        Event = YAHOO.util.Event; 
5 
6    YAHOO.gutter = function() { 
7        return { 
8            //The current status of the gutter (true is open) 
9            status: false
10            //Placeholder for the Overlay control 
11            gutter: null
12            /*
13            * This method will create the Overlay and
14            * attach some animations to the show and hide events
15            */ 
16            createGutter: function() { 
17                //Creating the Overlay 
18                this.gutter = new YAHOO.widget.Overlay('gutter1', { 
19                    height: '425px'
20                    width: '300px'
21                    //Setting it the context of the Editor's container 
22                    context: [ 
23                        myEditor.get('element'), 
24                        'tl'
25                        'tr' 
26                    ], 
27                    //Set the position 
28                    position: 'absolute'
29                    //Hide by default 
30                    visible: false 
31                }); 
32                /*
33                * The hideEvent will control the status of the toolbar button as well
34                * as fire the animation off to close the gutter
35                */ 
36                this.gutter.hideEvent.subscribe(function() { 
37                    //Deselect the flickr button in the toolbar 
38                    myEditor.toolbar.deselectButton('flickr'); 
39                    Dom.setStyle('gutter1''visibility''visible');                 
40                    var anim = new YAHOO.util.Anim('gutter1', { 
41                        width: { 
42                            from: 300, 
43                            to: 0 
44                        }, 
45                        opacity: { 
46                            from: 1, 
47                            to: 0 
48                        } 
49                    }, 1); 
50                    //When the animation is done, hide the element. 
51                    anim.onComplete.subscribe(function() {   
52                        Dom.setStyle('gutter1''visibility''hidden'); 
53                    }); 
54                    //Animate it 
55                    anim.animate(); 
56                }, thistrue); 
57                /*
58                * The showEvent will control the status of the toolbar button as well
59                * as fire the animation off to open the gutter
60                */ 
61                this.gutter.showEvent.subscribe(function() { 
62                    //Select the flickr button in the toolbar 
63                    myEditor.toolbar.selectButton('flickr'); 
64                    //Set the context of the panel (in case it was lost in the animation) 
65                    this.gutter.cfg.setProperty('context',[ 
66                        myEditor.get('element'), 
67                        'tl'
68                        'tr' 
69                    ]); 
70                    //Set the width to 0 pixels. 
71                    Dom.setStyle(this.gutter.element, 'width''0px'); 
72                    var anim = new YAHOO.util.Anim('gutter1', { 
73                        width: { 
74                            from: 0, 
75                            to: 300 
76                        }, 
77                        opacity: { 
78                            from: 0, 
79                            to: 1 
80                        } 
81                    }, 1); 
82                    //Animate it 
83                    anim.animate(); 
84                }, thistrue); 
85 
86                var warn = ''
87                //Check if we are using Safari or Opera, if we are show the warning that you can't drag and drop images 
88                if (myEditor.browser.webkit || myEditor.browser.opera) { 
89                    warn = myEditor.STR_IMAGE_COPY; 
90                } 
91                //Set the body of the gutter to hold the HTML needed to render the autocomplete 
92                this.gutter.setBody('<h2>Flickr Image Search</h2><label for="flikr_search">Tag:</label>' + 
93                    '<input type="text" value="" id="flickr_search"><div id="flickr_results">' +  
94                    '<p>Enter flickr tags into the box above, separated by commas. Be patient, ' +  
95                    'this example may take a few seconds to get the images.<p></div>' + warn); 
96                this.gutter.render(document.body); 
97            }, 
98            /*
99            * Open the gutter using Overlay's show method
100            */ 
101            open: function() { 
102                Dom.get('flickr_search').value = ''
103                this.gutter.show(); 
104                this.status = true
105            }, 
106            /*
107            * Close the gutter using Overlay's close method
108            */ 
109            close: function() { 
110                this.gutter.hide(); 
111                this.status = false
112            }, 
113            /*
114            * Check the state of the gutter and close it if it's open
115            * or open it if it's closed.
116            */ 
117            toggle: function() { 
118                if (this.status) { 
119                    this.close(); 
120                } else { 
121                    this.open(); 
122                } 
123            } 
124        } 
125    } 
126     
127})(); 
view plain | print | ?

Setting Up the Autocomplete Control

First we wait until flickr_search is available on the page. Then we set up a click handler on flickr_results to see if the user clicked an image.

If an image is clicked, we will call myEditor.execCommand('insertimage', IMG) to insert the image into the Editor.

This Autocomplete control uses a DataSource that points to Flickr Web Services; Flickr returns XML data via a simple PHP proxy. In order to return valid data from the Flickr application, scriptQueryParameter has been customized to be tags, and scriptQueryAppend is used to pass in additional required arguments. The cache has been disabled so that each query is forced to make a trip to the live application.

This instance of AutoComplete defines a robust custom formatResult function that parses result data into custom HTML markup that displays an actual image from the Flickr server. Automatic highlighting of the first result item in the container has been disabled by setting autoHighlight to false.

1YAHOO.util.Event.onAvailable('flickr_search'function() { 
2    YAHOO.util.Event.on('flickr_results''click'function(ev) { 
3        var tar = YAHOO.util.Event.getTarget(ev); 
4        if (tar.tagName.toLowerCase() == 'img') { 
5            if (tar.getAttribute('fullimage', 2)) { 
6                var img = tar.getAttribute('fullimage', 2), 
7                    title = tar.getAttribute('fulltitle'), 
8                    owner = tar.getAttribute('fullowner'), 
9                    url = tar.getAttribute('fullurl'); 
10                this.toolbar.fireEvent('flickrClick', { 
11                    type: 'flickrClick'
12                    img: img, 
13                    title: title, 
14                    owner: owner,  
15                    url: url 
16                }); 
17            } 
18        } 
19    }); 
20    oACDS = new YAHOO.widget.DS_XHR("assets/flickr_proxy.php"
21        ["photo""title""id""owner""secret""server"]); 
22    oACDS.scriptQueryParam = "tags"
23    oACDS.responseType = YAHOO.widget.DS_XHR.TYPE_XML; 
24    oACDS.maxCacheEntries = 0; 
25    oACDS.scriptQueryAppend = "method=flickr.photos.search"
26 
27    // Instantiate AutoComplete 
28    oAutoComp = new YAHOO.widget.AutoComplete('flickr_search','flickr_results', oACDS); 
29    oAutoComp.autoHighlight = false
30    oAutoComp.alwaysShowContainer = true;      
31    oAutoComp.formatResult = function(oResultItem, sQuery) { 
32        // This was defined by the schema array of the data source 
33        var sTitle = oResultItem[0]; 
34        var sId = oResultItem[1]; 
35        var sOwner = oResultItem[2]; 
36        var sSecret = oResultItem[3]; 
37        var sServer = oResultItem[4]; 
38        var urlPart = 'http:/'+'/static.flickr.com/' + sServer + '/' + sId + '_' + sSecret; 
39        var sUrl = urlPart + '_s.jpg'
40        var lUrl = urlPart + '_m.jpg'
41        var fUrl = 'http:/'+'/www.flickr.com/photos/' + sOwner + '/' + sId; 
42        var sMarkup = '<img src="' + sUrl + '" fullimage="' + lUrl + '" fulltitle="' + sTitle + '" fullid="' + 
43            sOwner + '" fullurl="' + fUrl + '" class="yui-ac-flickrImg" title="Click to add this image to the editor"><br>'
44        return (sMarkup); 
45    }; 
46}); 
view plain | print | ?

Configuration for This Example

You can load the necessary JavaScript and CSS for this example from Yahoo's servers. Click here to load the YUI Dependency Configurator with all of this example's dependencies preconfigured.

YUI Logger Output:

Logger Console

INFO 1532ms (+0) 5:14:56 PM:

example

Create the Auto Complete Control

INFO 1532ms (+19) 5:14:56 PM:

example

onAvailable: #flickr_search

INFO 1513ms (+1) 5:14:56 PM:

example

Creating gutter (#gutter1)

INFO 1512ms (+72) 5:14:56 PM:

example

Toolbar loaded, add button and create gutter

INFO 1440ms (+1440) 5:14:56 PM:

example

Editor loaded..

INFO 0ms (+0) 5:14:54 PM:

global

Logger initialized

Note: You are viewing this example in debug mode with logging enabled. This can significantly slow performance.

Reload with logging
and debugging disabled.

More Rich Text Editor Resources:

Copyright © 2009 Yahoo! Inc. All rights reserved.

Privacy Policy - Terms of Service - Copyright Policy - Job Openings