flickwriter

By 37to Last update Jul 2, 2009 — Installed 297 times. Daily Installs: 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 6, 1, 0, 0, 0, 0, 2, 3, 0, 0, 1, 3, 0, 2, 1, 1

There are 4 previous versions of this script.

Add Syntax Highlighting (this will take a few seconds, probably freezing your browser while it works)

// ==UserScript==
// @name           flickwriter
// @namespace      http://labs.37to.net/flickwriter/
// @description    Create Link as flickr image.
// @version        0.10 alpha
// @copyright      2009+, 37to (http://www.37to.net/)
// @licence        The MIT License Copyright (c) 2009 37to.
// @include        http://flickr.com/photos/*
// @include        http://www.flickr.com/photos/*
// ==/UserScript==
(function() {

    /**
     * Controller Object
     */
    var flickWriter = {
        photo      : {},
        template   : {},
        hasStorage : false,

        /*------------------------------------
         Main
        ------------------------------------*/

        init : function(){
            if(typeof GM_getValue == 'function'){
                this.hasStorage = true;
                //load saved data.
                this.loadTemplates();
            }
            
            if( view.insertTarget.get() ){
                //load image data
                this.requestPhotoData();
            }
        },

        requestPhotoData : function(){
            var self     = this;
            var photoId  = view.getPhotoId();
            var callback = {
                flickr_photos_getSizes_onLoad : function(success, responseXML, responseText, params){
                    self.loadPhoto(responseXML);
                }
            };
            unsafeWindow.F.API.callMethod('flickr.photos.getSizes', {
                photo_id: photoId
            }, callback);
        },

        loadPhoto : function(responseXML){
            var self = this;

            /*** photo data ***/
            this.photo = new FlickrPhoto(responseXML);
            this.setTemplate( this.photo );

            /*** generate html ***/
            //edit area
            var editArea = view.editArea.createElement();
            //select box
            var selectBox = view.selectBox.createElement( templateSets.getNames() );
            selectBox.addEventListener('change', function(event){
                self.changeTemplate(event.target);
                event.stopPropagation();
            }, false);
            editArea.appendChild( selectBox );
            
            //textarea
            var textArea = view.textArea.createElement();
            //textarea wrapper
            var p        = view.textAreaBox.createElement();

            //append html.
            if( this.hasStorage ){
                //this is bad code.rewrite later.
                var editMenuList = view.editMenuList.create({
                    code : {
                        id   : 'code',
                        text : 'code',
                        //"this" keyword in event handler indicates parent object
                        event : {
                            click : function(event){
                            },
                            active : function(){
                                view.editMenuButton.get(this.id).style.color = '#000';
                                var selectBox = view.selectBox.get();
                                self.showTemplate(selectBox);
                                view.editMenuArea.toggle(this.id);
                            },
                            nonActive : function(){
                                view.editMenuButton.get(this.id).style.color = '#0063DC';
                            }
                        }
                    },
                    format : {
                        id   : 'format',
                        text : 'edit',
                        //"this" keyword in event handler indicates parent object
                        event : {
                            click : function(event){
                            },
                            active : function(){
                                view.editMenuButton.get(this.id).style.color = '#000';
                                var selectBox = view.selectBox.get();
                                self.showTemplateFormat(selectBox);
                                view.editMenuArea.toggle(this.id);
                            },
                            nonActive : function(){
                                view.editMenuButton.get(this.id).style.color = '#0063DC';
                            }
                        },
                        editArea : function(elem){
                            var menuBody  = view.formatEditMenu.createElement();
                            menuBody.addEventListener('click', function(event){
                                var selectBox = view.selectBox.get();
                                var n = selectBox.selectedIndex;
                                if( selectBox.options[n].value !== '' ){
                                    var template = templateSets.templates[selectBox.options[n].value];
                                    template.code = view.textArea.get().value;
                                }
                                self.saveTemplate(templateSets);
                                alert('saved');
                                event.stopPropagation();
                            }, false);
                            elem.appendChild(menuBody);
                        }
                    }
                });
                editArea.appendChild(editMenuList);
            }
            p.appendChild(textArea);
            editArea.appendChild( p );
            view.insertTarget.append(editArea);
        },

        loadTemplates : function(){
            var templates = GM_getValue('templates');
            if( templates === undefined ){
                this.saveTemplate(templateSets);
            }else{
                templateSets.templates = eval(templates);
            }
        },

        setTemplate : function(photo){
            this.template = new Templater();

            //set default valiables
            for( var i in templateSets.valiables ){
                this.template.set( templateSets.valiables[i].name, '' );
            }

            //set photo info
            for( var i in photo.info ){
                this.template.set( i.toUpperCase(), photo.info[i] );
            }

            //set photo sizes
            for( var i in photo.sizes ){
                var label = this.getSizeLabel(i);
                var size  = photo.sizes[i];
                for( var j in size ){
                    name = label + '_' + j.toUpperCase();
                    this.template.set( name, size[j] );
                }
            }
        },

        saveTemplate : function( templateSets ){
            templates = templateSets.templates.toSource();
            GM_setValue('templates', templates);
        },

        /*------------------------------------
         Event Handler
        ------------------------------------*/

        changeTemplate : function(selectBox){
            var n = selectBox.selectedIndex;
            if( selectBox.options[n].value !== '' ){
                view.editMenuList.show();
                view.textAreaBox.show();
                this.showTemplate(selectBox);
                view.editMenuList.activate(document.getElementById('flickwriter_edit_menubar_code'));
            }else{
                view.editMenuList.hide();
                view.textAreaBox.hide();
            }
        },
        
        showTemplate : function(selectBox){
            var n = selectBox.selectedIndex;
            //This event is deleted once so that it is not called more than once. 
            view.textArea.get().removeEventListener('click', this.selectTextArea, false);
            if( selectBox.options[n].value !== '' ){
                var template = templateSets.templates[selectBox.options[n].value];
                view.textArea.get().value = this.template.fetch(template.code);
                view.textArea.get().addEventListener('click',this.selectTextArea, false);
                view.textAreaBox.show();
            }else{
                view.textAreaBox.hide();
            }
        },
        
        showTemplateFormat : function(selectBox){
            var n = selectBox.selectedIndex;
            //This event is deleted once so that it is not called more than once. 
            view.textArea.get().removeEventListener('click', this.selectTextArea, false);
            if( selectBox.options[n].value !== '' ){
                var template = templateSets.templates[selectBox.options[n].value];
                view.textArea.get().value = template.code;
                view.textArea.get().addEventListener('click',this.selectTextArea, false);
                view.textAreaBox.show();
            }else{
                view.textAreaBox.hide();
            }
        },

        selectTextArea : function(event){
            event.target.focus();
            event.target.select();
            //only first click
            event.target.removeEventListener(event.type, arguments.callee, false);
        },

        /*------------------------------------
         Utility
        ------------------------------------*/

        getSizeLabel : function( sizeName ){
            var label = 'SIZE_';
            switch( sizeName ){
              case 'large':
                label = label + 'O';
                break;
              case 'medium':
                label = label + 'M';
                break;
              case 'small':
                label = label + 'S';
                break;
              case 'thumbnail':
                label = label + 'T';
                break;
              case 'square':
                label = label + 'SQ';
                break;
            }
            return label;
        }
    };

    /**
     * HTML and more View Object
     */
    var view = {
        
        /*------------------------------------
         Manipulation HTML
        ------------------------------------*/

        selectBox : {
            createElement : function( names ){
                var selectBox    = document.createElement('select');
                selectBox.id     = 'flickwriter_selectbox';
                var option       = document.createElement('option');
                option.innerHTML = '... Please select';
                option.value     = '';
                selectBox.appendChild(option);
                for( var i in names ){
                    var option       = document.createElement('option');
                    option.innerHTML = names[i];
                    option.value     = i;
                    selectBox.appendChild(option);
                }
                return selectBox;
            },
            get : function(){
                return document.getElementById('flickwriter_selectbox');
            }
        },

        textArea : {
            createElement : function(){
                var textArea         = document.createElement('textarea');
                textArea.id          = 'flickwriter_textarea';
                textArea.rows        = 10;
                textArea.style.width = '90%';
                return textArea;
            },

            get : function(){
                return document.getElementById('flickwriter_textarea');
            }
        },

        textAreaBox : {
            createElement : function(){
                var p           = document.createElement('p');
                p.id            = 'flickwriter_textarea_box';
                p.style.display = 'none';
                return p;
            },

            get : function(){
                return document.getElementById('flickwriter_textarea_box');
            },

            show : function(){
                this.get().style.display = 'block';
            },

            hide : function(){
                this.get().style.display = 'none';
            }
        },

        editArea : {
            createElement : function(){
                var div = document.createElement('div');
                div.style.margin = '1em 0';
                return div;
            }
        },

        insertTarget : {
            get : function(){
                return document.getElementById('button_bar');;
            },
            append : function(elem){
                var buttonBar = this.get();
                buttonBar.parentNode.insertBefore( elem, buttonBar.nextSibling );
            }
        },

        editMenuList : {

            menus : {},

            create : function(menus){
                this.menus   = menus;
                var menubar  = this.createMenubar(menus);
                var editArea = this.createEditArea(menus);
                var menuList = this.createElement();
                menuList.appendChild(menubar);
                menuList.appendChild(editArea);
                return menuList;
            },
            
            createElement : function(){
                var div = document.createElement('div');
                div.id  = 'flickwriter_edit_menu';
                div.style.display = 'none';
                return div;
            },

            activate : function(target){
                var menus = this.menus;
                for( var key in menus ){
                    if(target.id != view.editMenuButton.getId( menus[key].id ) ){
                        if( menus[key].event.nonActive )
                          menus[key].event.nonActive.apply( menus[key], null );
                    }else{
                        if( menus[key].event.active )
                          menus[key].event.active.apply( menus[key], null );
                    }
                }
                
            },

            createMenubar : function(menus){
                var p = document.createElement('p');
                p.id  = 'flickwriter_edit_menubar';
                for( var i in menus ){
                    var elem = view.editMenuButton.createElement( menus[i].id, menus[i].text);
                    elem._flickWriter = {};
                    if( menus[i].event ){
                        for( var type in menus[i].event ){
                            if( type == 'active' || type == 'nonActive' ){
                                elem._flickWriter[type] = function(menus, key, type){
                                    return function(elem){
                                        menus[key].event[type](elem);
                                    };
                                }(menus, i, type);
                            }else{
                                var callback = function(menus, key, type){
                                    return function(event){
                                        menus[key].event[type].call( menus[key] ,event);
                                    }
                                }(menus, i, type);
                                elem.addEventListener( type, callback, false );
                            }
                        }
                    }
                    elem.addEventListener( 'click', function(event){
                        view.editMenuList.activate( event.currentTarget );
                    }, false );
                    p.appendChild( elem );
                    p.appendChild( document.createTextNode( ' | ' ) );
                }
                //remove last "|"
                p.removeChild( p.childNodes.item(p.childNodes.length-1) );
                return p;
            },

            createEditArea : function(menus){
                var div = document.createElement('div');
                div.id  = 'flickwriter_edit_menuarea';
                for( var i in menus ){
                    var elem = view.editMenuArea.createElement( menus[i].id, menus[i].text);
                    if( typeof menus[i].editArea === 'function' ){
                        menus[i].editArea(elem);
                    }
                    div.appendChild( elem );
                }
                return div;
            },

            get : function(){
                return document.getElementById('flickwriter_edit_menu');
            },

            show : function(){
                this.get().style.display = '';
            },

            hide : function(){
                this.get().style.display = 'none';
            }
        },
        
        editMenuButton : {

            getId : function(id){
                return 'flickwriter_edit_menubar_'+id;
            },
            
            createElement : function(id, text){
                var span          = document.createElement('span');
                span.id           = this.getId(id);
                span.style.color  = '#0063DC';
                span.style.cursor = 'pointer';
                span.innerHTML    = text;
                return span;
            },

            get : function(id){
                return document.getElementById(this.getId(id));
            },

            button : {
                
            },

            area : {
            }
        },

        editMenuArea : {

            getId : function(id){
                return 'flickwriter_edit_menuarea_'+id
            },
            
            createElement : function(id, text){
                var div           = document.createElement('div');
                div.id            = this.getId(id);
                div.style.display = 'none';
                return div;
            },

            get : function(id){
                return document.getElementById( this.getId(id) );
            },

            toggle : function(id, before, after){
                var elem = this.get(id);
                var areas = document.getElementById('flickwriter_edit_menuarea').childNodes;
                for( var i=0, l=areas.length; i<l; i++ ){
                    if(elem.id != areas[i].id){
                        areas[i].style.display = 'none';
                        //areas[i]._flickWriter.nonactive();
                    }
                }
                view.toggle(elem);
                //elem._flickWriter.nonactive();
            }
        },

        formatMenu : {
            createElement : function(){
                var div = document.createElement('div');
                div.id  = 'format_menu';
                div.innerHTML = 'edit';
                return div;
            },

            newTitle : function(){
            },

            newBody : function(){
            }
            
        },
        
        formatEditMenu : {
            createElement : function(name, code){
                var div = document.createElement('div');
                div.id  = 'format_edit_menu';
                div.innerHTML = '<span id="format_save_link" style="color:#0063DC;cursor:pointer;">save</span>';
                return div;
            },

            newTitle : function(){
            },

            newBody : function(){
            }
            
        },

        /*------------------------------------
         Getter of Photo into
        ------------------------------------*/

        getTitle : function(){
            var title   = '';
            var photoId = this.getPhotoId();
            var elem    = document.getElementById("title_div" + photoId);
            if( elem ) title = elem.innerHTML;
            return title;
        },

        getDescription : function(){
            var description = '';
            var photoId     = this.getPhotoId();
            var elem        = document.getElementById("description_div" + photoId);
            if( elem ) description = elem.innerHTML;
            return description;
        },

        getOwnerName : function(){
            var ownerName = '';
            var res = document.evaluate('//div[@class="Widget"]//a/b',
                                        document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null );
            if( res.snapshotLength ) ownerName = res.snapshotItem(0).innerHTML;
            return ownerName;
        },
        
        getOwnerIcon : function(){
            var ownerIcon = '';
            var res = document.evaluate('//div[@class="Widget"]//a/img',
                                        document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null );
            if( res.snapshotLength ) ownerIcon = res.snapshotItem(0).src;
            return ownerIcon;
            
        },

        getPhotoStream : function(){
            var photoStream = '';
            var res = document.evaluate('//div[@class="Widget"]//a/b',
                                        document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null );
            if( res.snapshotLength ) photoStream = res.snapshotItem(0).parentNode.href;
            return photoStream;
        },

        getUploadDate : function(){
            var uploadDate = '';
            var res = document.evaluate('//div[@class="Widget"]//a[@class="Plain"]',
                                        document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null );
            if( res.snapshotLength ) uploadDate = res.snapshotItem(0).innerHTML;
            return uploadDate;
            
        },

        getPhotoId : function(){
            return location.pathname.split('/')[3];
        },
        
        /*------------------------------------
         Utility
        ------------------------------------*/

        toggle : function(elem){
            if( elem.style.display == 'none' ){
                elem.style.display = '';
            }else{
                elem.style.display = 'none';
            }
        }
    }

    /**
     * flickr's photo Object
     */
    var FlickrPhoto = function(rsp){
        //parse xml and set to object
        this.rsp.status = rsp.getElementsByTagName('rsp')[0].getAttribute('stat');
        this.rsp.sizes  = rsp.getElementsByTagName('size');
        if( this.rsp.status != 'ok' ) return;

        //set sizes
        for( var i=0, l=this.rsp.sizes.length; i<l; i++ ){
            var size = this.rsp.sizes[i];
            if( size.getAttribute('media') === 'photo' ){
                this.sizes[size.getAttribute('label').toLowerCase()] = {
                    width    : size.getAttribute('width'),
                    height   : size.getAttribute('height'),
                    imageUrl : size.getAttribute('source'),
                    pageUrl  : size.getAttribute('url'),
                };
            }
        }
        
        //set page info
        this.info.pageUrl     = location;
        this.info.title       = view.getTitle();
        this.info.description = view.getDescription();
        this.info.uploadDate  = view.getUploadDate();
        this.info.ownerName   = view.getOwnerName();
        this.info.ownerIcon   = view.getOwnerIcon();
        this.info.photoStream = view.getPhotoStream();
    };
    FlickrPhoto.prototype = {
        sizes : {},
        info : {
            pageUrl     : '',
            title       : '',
            description : '',
            uploadDate  : '',
            ownerName   : '',
            ownerIcon   : '',
            photoStream : ''
        },
        rsp : {
            status : 'error',
            sizes  : []
        }
    };

    /**
     * Simple Template Engine Object
     **/
    var Templater = function(){};
    Templater.prototype ={
        valiables : {},
        set : function( name, value ){
            this.valiables[name] = value;
        },

        fetch : function( template ){
            var pattern = /(%.+?%)/;
            var splitTemplate = template.split(pattern);
            for( var i=0,l=splitTemplate.length; i<l; i++ ){
                if( splitTemplate[i].match(pattern) ){
                    var name = splitTemplate[i].replace( /%(.+)%/, '$1' );
                    if( this.valiables[name] !== undefined )
                      splitTemplate[i] = this.valiables[name];
                }
            }
            return splitTemplate.join('');
        }
    };

    /**
     * Template sets object
     **/
    var templateSets = {
        valiables : [
            {
                name : 'TITLE',
                desc : 'Photo title'
            },
            {
                name : 'PAGEURL',
                desc : 'Photo page url'
            },
            {
                name : 'DESCRIPTION',
                desc : 'Description of photo'
            },
            {
                name : 'UPLOADDATE',
                desc : 'Updaload date of photo'
            },
            {
                name : 'OWNERNAME',
                desc : 'Author in photo'
            },
            {
                name : 'OWNERICON',
                desc : 'Icon url of author in photo'
            },
            {
                name : 'PHOTOSTREAM',
                desc : 'Photo Stream url of author in photo'
            },
            {
                name : 'SIZE_O_IMAGEURL',
                desc : 'Url of original size photo'
            },
            {
                name : 'SIZE_O_PAGEURL',
                desc : 'Url of original size photo page'
            },
            {
                name : 'SIZE_O_WIDTH',
                desc : 'Width of original size photo'
            },
            {
                name : 'SIZE_O_HEIGHT',
                desc : 'Height of original size photo'
            },
            {
                name : 'SIZE_M_IMAGEURL',
                desc : 'Url of medium size photo'
            },
            {
                name : 'SIZE_M_PAGEURL',
                desc : 'Url of medium size photo page'
            },
            {
                name : 'SIZE_M_WIDTH',
                desc : 'Width of medium size photo'
            },
            {
                name : 'SIZE_M_HEIGHT',
                desc : 'Height of medium size photo'
            },
            {
                name : 'SIZE_T_IMAGEURL',
                desc : 'Url of thumbnail size photo'
            },
            {
                name : 'SIZE_T_PAGEURL',
                desc : 'Url of thumbnail size photo page'
            },
            {
                name : 'SIZE_T_WIDTH',
                desc : 'Width of thumbnail size photo'
            },
            {
                name : 'SIZE_T_HEIGHT',
                desc : 'Height of thumbnail size photo'
            },
            {
                name : 'SIZE_S_IMAGEURL',
                desc : 'Url of small size photo'
            },
            {
                name : 'SIZE_S_PAGEURL',
                desc : 'Url of small size photo page'
            },
            {
                name : 'SIZE_S_WIDTH',
                desc : 'Width of small size photo'
            },
            {
                name : 'SIZE_S_HEIGHT',
                desc : 'Height of small size photo'
            },
            {
                name : 'SIZE_SQ_IMAGEURL',
                desc : 'Url of square size photo'
            },
            {
                name : 'SIZE_SQ_PAGEURL',
                desc : 'Url of square size photo page'
            },
            {
                name : 'SIZE_SQ_WIDTH',
                desc : 'Width of square size photo'
            },
            {
                name : 'SIZE_SQ_HEIGHT',
                desc : 'Height of square size photo'
            }
        ],
        
        templates : [
            {
                name : 'Plane Text',
                code : '%TITLE%\n%PAGEURL%'
            },
            {
                name : 'Basic HTML(Original)',
                code : '<a title="%TITLE%" href="%PAGEURL%"><img src="%SIZE_O_IMAGEURL%" width="%SIZE_O_WIDTH%" height="%SIZE_O_HEIGHT%" alt="%TITLE%" /></a>'
            },
            {
                name : 'Basic HTML(Medium)',
                code : '<a title="%TITLE%" href="%PAGEURL%"><img src="%SIZE_M_IMAGEURL%" width="%SIZE_M_WIDTH%" height="%SIZE_M_HEIGHT%" alt="%TITLE%" /></a>'
            },
            {
                name : 'Basic HTML(Small)',
                code : '<a title="%TITLE%" href="%PAGEURL%"><img src="%SIZE_S_IMAGEURL%" width="%SIZE_S_WIDTH%" height="%SIZE_S_HEIGHT%" alt="%TITLE%" /></a>'
            },
            {
                name : 'Basic HTML(Thumbnail)',
                code : '<a title="%TITLE%" href="%PAGEURL%"><img src="%SIZE_T_IMAGEURL%" width="%SIZE_T_WIDTH%" height="%SIZE_T_HEIGHT%" alt="%TITLE%" /></a>'
            },
            {
                name : 'Basic HTML(Square)',
                code : '<a title="%TITLE%" href="%PAGEURL%"><img src="%SIZE_SQ_IMAGEURL%" width="%SIZE_SQ_WIDTH%" height="%SIZE_SQ_HEIGHT%" alt="%TITLE%" /></a>'
            },
            {
                name : 'LightBox HTML(Medium to Original)',
                code : '<a title="%TITLE%" href="%SIZE_O_IMAGEURL%" rel="lightbox"><img src="%SIZE_M_IMAGEURL%" width="%SIZE_M_WIDTH%" height="%SIZE_M_HEIGHT%" alt="%TITLE%" /></a><br /><a href="%PAGEURL%">%TITLE%"</a>'
            },
            {
                name : 'LightBox HTML(Small to Original)',
                code : '<a title="%TITLE%" href="%SIZE_O_IMAGEURL%" rel="lightbox"><img src="%SIZE_S_IMAGEURL%" width="%SIZE_S_WIDTH%" height="%SIZE_S_HEIGHT%" alt="%TITLE%" /></a><br /><a href="%PAGEURL%">%TITLE%"</a>'
            },
            {
                name : 'LightBox HTML(Thumbnail to original)',
                code : '<a title="%TITLE%" href="%SIZE_O_IMAGEURL%" rel="lightbox"><img src="%SIZE_T_IMAGEURL%" width="%SIZE_T_WIDTH%" height="%SIZE_T_HEIGHT%" alt="%TITLE%" /></a><br /><a href="%PAGEURL%">%TITLE%"</a>'
            },
            {
                name : 'LightBox HTML(Square to Original)',
                code : '<a title="%TITLE%" href="%SIZE_O_IMAGEURL%" rel="lightbox"><img src="%SIZE_SQ_IMAGEURL%" width="%SIZE_SQ_WIDTH%" height="%SIZE_SQ_HEIGHT%" alt="%TITLE%" /></a><br /><a href="%PAGEURL%">%TITLE%"</a>'
            }
        ],
        
        getNames : function(){
            var names = [];
            this.templates.forEach( function(v, i){
                names.push(v.name);
            });
            return names;
        }
    };
    

    //Execute
    //----------------------------------------
    //  Maybe, processing of flickr stopped bubbling event. 
    //  Therefore, the loading event is executed by the capture phase.
    document.body.addEventListener( 'load', function(event){
        flickWriter.init();
        //It executes only first and the event is deleted because it is called many times.
        event.currentTarget.removeEventListener( event.type, arguments.callee, true );
    }, true );

})();