Ext.namespace("B");

(function() {

    function StringUtils() {
    }

    StringUtils.prototype = {
        /**
         * @return string with only digits, e.g. "target15" -> "15".
         */
        removeNonDigits : function(s) {
            return s.replace(/[^0-9]*([0-9]+)/, "$1");
        }
    };

    B.StringUtils = new StringUtils();

})();
Ext.namespace("se.pictosys");

(function() {
    var Dom = YAHOO.util.Dom;
    var Y = YAHOO.lang;

    se.pictosys.PictoSlider = function(name, options) {
        this.init(name, options);
    };

    se.pictosys.PictoSlider.prototype = {

        init : function(name, options) {

            this.initOptions(options);

            /* Pixels per millimeter for slider. */
            this.pixelsPerMillimeter = 2;

            if (!name) {
                throw "Slider name must be specified";
            }

            var sliderBg = name + "-slider";
            var sliderThumb = name + "-thumb";

            if (!Dom.get(sliderBg)) {
                throw "Could not find slider background";
            }

            if (!Dom.get(sliderThumb)) {
                throw "Could not find slider thumb";
            }

            this.template = new Ext.Template(this.options.template, {
                compiled : true,
                disableFormats : true
            });

            this.slider = YAHOO.widget.Slider.getHorizSlider(sliderBg,
                    sliderThumb, this.options.min, this.options.max,
                    this.options.step);
            this.slider.subscribe("change", function(offset, target) {
                        /*
                         * note: "this" will point to the slider in this event
                         * listener
                         */
                        Ext.fly(name + "-info").update(target.getFormattedText());
                    }, this);
        },

        initOptions : function(options) {
            options = options || {};

            if (!Y.isNumber(options.min)) {
                options.min = 0;
            }

            if (!Y.isNumber(options.max)) {
                options.max = 100;
            }

            if (!Y.isNumber(options.step)) {
                options.step = 1;
            }

            if (!Y.isNumber(options.minPixelValue)) {
                options.minPixelValue = 0;
            }

            options.template = options.template || "{value} mm";

            this.options = options;
        },

        getSliderValue : function() {
            return this.slider.getValue();
        },

        setSliderValue : function(value, options) {
            options = options || {};
            var skipAnim = !options.animated;
            var skipFireEvents = false;
            var force = true;

            this.slider.setValue(value, skipAnim, force, skipFireEvents);
        },
        getRealValue : function() {
            return Math.floor(this.getAdjustedSliderValue() / this.pixelsPerMillimeter);
        },

        setRealValue : function(mm, options) {
            var pixels = Math.max(0, mm * this.pixelsPerMillimeter
                            - this.options.minPixelValue);
            this.setSliderValue(pixels, options);
        },

        getFormattedText : function() {
            return this.template.apply({
                        value : this.getRealValue()
                    });
        },
        getAdjustedSliderValue : function() {
            return this.getSliderValue() + this.options.minPixelValue;
        },

        /* Pixels for preview slots in web GUI. */
        getPixelValue : function() {
            return this.getRealValue() * 2;

        }

    };

    /**
     * Size slider
     */
    se.pictosys.SizeSlider = function(name, options) {
        options = options || {};
        options.template = options.template || "{value}x{value} mm";
        if (!Y.isNumber(options.step)) {
            options.step = 1;
        }

        if (!Y.isNumber(options.minPixelValue)) {
            options.minPixelValue = 60;
        }

        se.pictosys.SizeSlider.superclass.constructor.call(this, name, options);

        var that = this;

        /**
         * Fire when dragging the thumb in the slider.
         */
        this.slider.subscribe("change", function(offsetFromStart, target) {
                    YAHOO.Bubbling.fire('previewSizeSlider', {
                                realValue : target.getRealValue(),
                                pixelValue : target.getPixelValue()
                            });

                }, this);

        /**
         * Fired when dragging ends.
         */
        this.slider.subscribe("slideEnd", function() {
                    YAHOO.Bubbling.fire('changeSizeSlider', {
                                realValue : that.getRealValue(),
                                pixelValue : that.getPixelValue()
                            });
                });

    };

    YAHOO.lang.extend(se.pictosys.SizeSlider, se.pictosys.PictoSlider, {});


})();
/* Window metrics functions adapted from
 * http://www.humanized.com/reader/static/javascript/utils.js
 * http://www.quirksmode.org/viewport/compatibility.html
 */

var Metrics = function() {
	return {
	
	    getPageHeight: function() {
	        var y;
	        var test1 = document.body.scrollHeight;
	        var test2 = document.body.offsetHeight;
	        if (test1 > test2) {
                // all but Explorer Mac
	            y = document.body.scrollHeight;
	        } else  {
	        // Explorer Mac;
	        //would also work in Explorer 6 Strict, Mozilla and Safari
	            y = document.body.offsetHeight;
	        }
	        return parseInt(y, 10);
	    },
	
	     getWindowHeight: function() {
	        if (self.innerWidth) {
	            frameWidth = self.innerWidth;
	            frameHeight = self.innerHeight;
	        } else if (document.documentElement && document.documentElement.clientWidth) {
	            frameWidth = document.documentElement.clientWidth;
	            frameHeight = document.documentElement.clientHeight;
	        } else if (document.body) {
	            frameWidth = document.body.clientWidth;
	            frameHeight = document.body.clientHeight;
	        }
	        return parseInt(frameHeight, 10);
	    },
	
	
	    getScrollHeight: function() {
	        var y;
	        // all except Explorer
	        if (self.pageYOffset) {
	            y = self.pageYOffset;
	        } else if (document.documentElement && document.documentElement.scrollTop) {
	            y = document.documentElement.scrollTop;
	        } else if (document.body) {
	            // all other Explorers
	            y = document.body.scrollTop;
	        }
	        return parseInt(y, 10) + Metrics.getWindowHeight();
	    }
    };
 } ();
(function() {
    Ext.BLANK_IMAGE_URL = 'http://static.pictosys.se/1x1.gif';

    /* Turn off loading indicator to reduce flicker. */
    Ext.Updater.defaults.showLoadIndicator = false;
    
    Ext.onReady(function() {
        Ext.QuickTips.init();
    }); 
    
})();
/*
 * Ext JS Library 2.1 Copyright(c) 2006-2008, Ext JS, LLC. licensing@extjs.com
 * 
 * http://extjs.com/license
 * 
 * 
 * Adapted from http://extjs.com/deploy/dev/examples/shared/examples.js
 * 
 */
Ext.namespace("B");

(function() {
    
    function QuickNotification()  {
    }
    
    var animConfig = {
            easing : 'easeOut',
            duration: 0.5
        };

    
    var msgCt;

    function createBox(t, s) {
        return [
                '<div class="msg">',
                '<div class="x-box-tl"><div class="x-box-tr"><div class="x-box-tc"></div></div></div>',
                '<div class="x-box-ml"><div class="x-box-mr"><div class="x-box-mc"><h3>',
                t,
                '</h3><p>',
                s,
                '</p></div></div></div>',
                '<div class="x-box-bl"><div class="x-box-br"><div class="x-box-bc"></div></div></div>',
                '</div>'].join('');
    }
    
    
    QuickNotification.prototype = {
        /**
         * Usage QuickNotification("Note header", "Message with {0}",
         * "parameter0")
         */
        formatMessage : function(title, format) {
        

            if (!msgCt) {
                msgCt = Ext.DomHelper.insertFirst(document.body, {
                    id : 'msg-div'
                }, true);
            }
            msgCt.alignTo(document, 't-t');
            var s = String.format.apply(String, Array.prototype.slice.call(
                    arguments, 1));
            var m = Ext.DomHelper.append(msgCt, {
                html : createBox(title, s)
            }, true);
            m.slideIn('t', animConfig).pause(4).ghost("t", {
                remove : true
            });
        }

    };
    
    
    B.QuickNotification = new QuickNotification();

})();
Ext.namespace("B");

(function() {

    function TestMode() {
    }

    TestMode.prototype = {

        isTestMode : function() {
            return !this.isLoggedIn();
        },

        isLoggedIn : function() {
            if (Ext.fly("username").getValue()) {
                return true;
            } else {
                return false;
            }
        },

        showTestModeMessage : function() {
            B.QuickNotification.formatMessage(TestModeTranslations.testModeHeader, TestModeTranslations.testModeText);
        },

        showNotAllowedInTestModeMessage : function() {
            B.QuickNotification.formatMessage(TestModeTranslations.notAllowedInTestModeHeader, TestModeTranslations.notAllowedInTestModeText);
        }

    };

    B.TestMode = new TestMode();

})();
Ext.namespace("B");

(function() {

    function Page() {
    }

    Page.prototype = {
        isChartPage : function() {
            return "chart" === document.body.id;
        }
    };

    B.Page = new Page();

})();
Ext.namespace("P");

(function() {

    /*
     * If the user doesn't provide a function to determine if more content is needed, then this function will be used.
     */
    function checkScrollHeight(iThreshold) {
        /* Check how close to the end of the page we are. */
        var diff = Metrics.getPageHeight() - Metrics.getScrollHeight();
        return diff < iThreshold;
    }

    /*
     * sUrl is the (possibly relative) url to send request to.
     *
     * sCcontainerId is the html id of the container to add content to.
     *
     * The options parameter is a map (a simple Object):
     *
     *  - chunk is the next chunk to load, beginning from zero, so if you've
     * already loaded one batch when the page first loaded, then chunk would be
     * 1.
     *
     *  - form is the html id of a form whose values will be serialized and sent
     * with the request for content.
     *
     *  - areWeThereYet is a function(sResponse) which determines if updating
     * should stop.
     *
     *  - needsMoreContent is a function which determines if more content is
     * needed.
     *
     * - callback is a function(sId) which is called after the content has been added.
     *
     * - addParameters(oParams) is called after the form has been serialized, so that
     * additional parameters can be added.
     *
     * -beforeParameters() is called before serializing form and adding other parameters
     * to give a change to modify the form if needed.
     */
    function EndlessScrolling(sUrl, sContainerId, options) {
        this.sUrl = sUrl;
        this.sContainerId = sContainerId;

        this.chunk = options.chunk !== undefined ? options.chunk : 0;

        this.limit = options.limit !== undefined ? options.limit : 10;
        this.offset = options.offset !== undefined ? options.offset : this.chunk * this.limit;

        this.formId = options.form;
        this.isUpdating = false;
        this.isFinished = options.areWeThereYet || function(s) {
            return s.length < 500;
        };
        this.needsMoreContent = options.needsMoreContent || checkScrollHeight.createDelegate(this, [ 1000 ]);

        this.callback = options.callback || function(id) {
        };

        this.beforeParameters = options.beforeParameters || function() {
        };
        this.addParameters = options.addParameters || function(oParams) {
        };
    }

    EndlessScrolling.prototype = {
        start : function() {

            if (!this.task) {
                this.task = {
                    run : this.update.createDelegate(this),
                    interval : 5000
                };

            }

            Ext.TaskMgr.start(this.task);
        },

        restartAt : function(chunk) {
            Ext.TaskMgr.stop(this.task);
            this.chunk = chunk;

            this.offset = this.chunk * this.limit;

            this.start();
        },

        update : function() {
            if (this.needsMoreContent()) {
                this.loadContent();
            }
        },

        stop : function() {
            if (!this.task) {
                return;
            }
            Ext.TaskMgr.stop(this.task);
        },

        loadContent : function() {
            this.beforeParameters();

            var params = Ext.fly(this.formId) ? Ext.urlDecode(Ext.Ajax.serializeForm(this.formId)) : {};

            this.removeSubmitButtons(params);

            this.addParameters(params);

            params.chunk = this.chunk;
            params.offset = this.offset;
            params.limit = this.limit;
            if (!this.isUpdating) {
                this.isUpdating = true;
                Ext.Ajax.request( {
                    url : this.sUrl,
                    method : "post",
                    params : params,
                    success : this.handleResponse.createDelegate(this)
                });
            }
        },

        /**
         * Removes submit buttons from serialized form.
         */
        removeSubmitButtons : function(params) {
            if (!Ext.fly(this.formId)) {
                return params;
            }

            var i;
            var filterFields = Ext.select("#" + this.formId + " input[type=submit]").pluck("name");

            for (i = 0; i < filterFields.length; i++) {
                if (filterFields[i].length) {
                    delete params[filterFields[i]];
                }
            }

        },

        nextChunk : function() {
            this.chunk++;

            this.offset += this.limit;
        },

        decreaseOffset : function() {
            this.offset = Math.max(0, this.offset - 1);
        },

        handleResponse : function(transport) {
            var html = transport.responseText;
            var id = "chunk" + this.chunk;
            var div = Ext.DomHelper.createDom( {
                tag : "div",
                id : id,
                html : html
            });

            Ext.fly(this.sContainerId).appendChild(div);

            this.isUpdating = false;
            this.nextChunk();

            if (this.isFinished(html)) {
                this.stop();
            }

            this.callback(id);
        }
    };

    P.EndlessScrolling = EndlessScrolling;
})();
Ext.namespace("B");

(function() {
    var timer = null;
    var symbolSectionUpdater = null;
    var symbolSearchButtonId = "symbol-search";
    var searchInputId = "q";

    var searchTask = null;

    /* Private constructor. */
    function Search() {
    }

    Search.prototype = {
        init : function() {

            if (!this.isPageSearchAware()) {
                return;
            }

            this.registerEventListeners();

            Ext.fly("q").focus();
        },

        registerEventListeners : function() {
            if (Ext.get(searchInputId)) {
                Ext.get(searchInputId).on("keyup", this.filter, this);
            }

            if (Ext.get(symbolSearchButtonId)) {
                Ext.get(symbolSearchButtonId).on("click", this.filter, this);
            }

            if (Ext.get("partOfSpeech")) {
                Ext.get("partOfSpeech").on("change", this.filter, this);
            }

            searchTask = new Ext.util.DelayedTask(this.doFilter, this);

        },

        isPageSearchAware : function() {
            return !!Ext.get(searchInputId);
        },

        getSearchUrl : function() {
            if (this.isChartPage()) {
                return "/search/common/filter-chart/";
            } else if (this.isDictionaryPage()) {
                return "/search/dictionary/filter/";
            }

            return "/search/common/filter-download/";
        },

        isChartPage : function() {
            return "chart" === document.body.id;
        },

        isDictionaryPage : function() {
            return "dictionary" === document.body.id;
        },

        getUpdater : function() {
             if (symbolSectionUpdater) {
                 return symbolSectionUpdater;
             }

             var fireAfterFilter = this.fireAfterFilter.createDelegate(this);

             symbolSectionUpdater = Ext.get("symbol-section").getUpdater();
             symbolSectionUpdater.on("update", fireAfterFilter);
             symbolSectionUpdater.on("failure", function(el, oResponseObject) {
                 Ext.get("symbol-section").update(oResponseObject.responseText);
             });

             return symbolSectionUpdater;
        },

        doFilter : function() {
            var url = this.getSearchUrl();

            this.fireBeforeFilter();

            var updater = this.getUpdater();

            updater.abort();

            updater.update( {
                url: url,
                method : "GET",
                text :"",
                params : {
                    l : Ext.get("site-language").getValue(),
                    q : Ext.get("q").getValue(),
                    partOfSpeech : Ext.get("partOfSpeech") && Ext.get("partOfSpeech").getValue()
                }
            });
        },

        fireBeforeFilter : function() {
            YAHOO.Bubbling.fire('search/filter/before');
        },

        fireAfterFilter : function() {
            YAHOO.Bubbling.fire('search/filter/after');
        },

        filter : function(evt) {
            evt.stopEvent();

            searchTask.delay(150);
        }

    };

    /* Expose singleton. */
    B.Search = new Search();

    Ext.onReady(B.Search.init, B.Search);

})();
Ext.namespace("B");

/**
 * Handles state saved in the hash of the URL.
 *
 * Since ideally there should be only one YUI history manager, all state is
 * managed in this class and bubbling events are used to decouple the state from
 * the actual handlers.
 */
(function() {

    var searchStateName = "q";
    var entryStateName = "entry";

    function HashHistory() {
    }

    HashHistory.prototype = {
        init : function() {

            this.registerEventListeners();

            // this.searchStateInit();
            this.entryStateInit();

            YAHOO.util.History.initialize("yui-history-field",
                    "yui-history-iframe");

        },

        registerEventListeners : function() {
            YAHOO.Bubbling.on("dictionary/entry/changed",
                    this.dictionaryEntryChanged, this);

            var self = this;
            YAHOO.Bubbling.on('search/filter/before', function() {
                self.entryChanged("");
            });
        },

        dictionaryEntryChanged : function(name, args) {
            var entryId = args[1].entryId;
            this.entryChanged(entryId);
        },

        searchStateInit : function() {
            var stateName = searchStateName;
            var bookmarkedState = YAHOO.util.History
                    .getBookmarkedState(stateName);

            // If there is no bookmarked state, assign the default state:
            var initialState = bookmarkedState || "";

            function stateChangeHandler(state) {
                var currentSearch = decodeURIComponent(state);
            }

            YAHOO.util.History.register(stateName, initialState,
                    stateChangeHandler);

            YAHOO.util.History.onReady(function() {
                var currentState = YAHOO.util.History
                        .getCurrentState(stateName);
                stateChangeHandler(currentState);
            });

        },

        entryStateInit : function() {
            var stateName = entryStateName;
            var bookmarkedState = YAHOO.util.History
                    .getBookmarkedState(stateName);

            // If there is no bookmarked state, assign the default state:
            var initialState = bookmarkedState || "";

            function stateChangeHandler(state) {
                if (state) {
                    YAHOO.Bubbling.fire("history/dictionary/entry/changed", {
                        entryId : state
                    });
                }
            }
            YAHOO.util.History.register(stateName, initialState,
                    stateChangeHandler);

            YAHOO.util.History.onReady(function() {
                var currentState = YAHOO.util.History
                        .getCurrentState(stateName);

                stateChangeHandler(currentState);
            });

        },

        entryChanged : function(state) {
            if (state) {
                YAHOO.util.History.navigate(entryStateName, state);
            } else {
                var currentState = YAHOO.util.History.getCurrentState(entryStateName);
                if (currentState) {
                    YAHOO.util.History.navigate(entryStateName, "");
                }
            }
        },

        search : function(state) {
            /* State must be uri encoded. */
            state = encodeURIComponent(state);
            YAHOO.util.History.navigate(searchStateName, state);
        }
    };

    B.HashHistory = new HashHistory();




})();
Ext.namespace("B");

/**
 * Support class to augment other classes.
 *
 * Other classes must implement: getSingleSymbolUrl():String
 *
 *
 * and add a call to this.initBrowseListSupport(); in the init method.
 */
(function() {

    function BrowseListSupport() {
    }

    BrowseListSupport.prototype = {
        initBrowseListSupport : function() {

            if (!Ext.fly("symbol-list")) {
                return;
            }

            this._registerBrowseListEventListeners();

            this.showInitialSymbol();

        },

        _registerBrowseListEventListeners : function() {
            Ext.get("symbol-list").on("change", this._changeDisplaySymbol, this);
        },

        _changeDisplaySymbol : function(e) {
            var selection = this.getSelection();
            this._fireDisplaySymbolChanged(selection);
            this._loadSymbol(selection);
        },

        displaySymbol : function(glossKeyName, gloss) {
            this._loadSymbol(this.createMessagePayload(glossKeyName, gloss));
        },

        _loadSymbol : function(payload) {

            this._fireBeforeDisplaySymbol(payload);

            Ext.get("symbol-section").load({
                url : this.getSingleSymbolUrl(),
                params : {
                    glossKeyName : payload.glossKeyName
                },
                success : this._fireAfterDisplaySymbol.createDelegate(this, payload)
            });

        },

        _getList : function() {
            return Ext.get("symbol-list").dom;
        },

        getSelectedSymbolId : function() {
            var list = this._getList();
            var symbolId = Ext.get(list).getValue();
            return symbolId;
        },

        getSelectedGloss : function() {
            var list = this._getList();
            var i = list.selectedIndex;
            gloss = list.options[i].text;
            return gloss;
        },

        getSelection : function() {
            var symbolId = this.getSelectedSymbolId();
            var selectedGloss = this.getSelectedGloss();
            return this.createMessagePayload(symbolId, selectedGloss);
        },

        createMessagePayload : function(glossKeyName, gloss) {
            return {
                glossKeyName : glossKeyName,
                gloss : gloss
            };
        },

        showInitialSymbol : function() {
            var list = this._getList();
            if (list.length > 0 && list.selectedIndex < 0) {
                list.selectedIndex = 0;
            }

            var payload = this.getSelection();
            this._loadSymbol(payload);
        },

        _fireDisplaySymbolChanged : function(payload) {
        YAHOO.Bubbling.fire("browselist/symbol/changed", payload);
    },

    _fireBeforeDisplaySymbol : function(payload) {
        YAHOO.Bubbling.fire("browselist/symbol/display/before", payload);
    },

    _fireAfterDisplaySymbol : function(payload) {
        YAHOO.Bubbling.fire("browselist/symbol/display/after", payload);
    }

    };

    B.BrowseListSupport = BrowseListSupport;

})();
Ext.namespace("B");

(function() {

    function DownloadSymbols() {
    }

    var popup = null;

    function hidePopup() {
        if (popup) {
            popup.hide();
        }
    }

    function getSymbolId(source) {
        var setboxId = Ext.fly(source).up(".set").child(".setbox").id;
        var symbolId = setboxId.replace("symbol-", "");
        return symbolId;
    }

    function getSymbolName(source) {
        /* links below the symbols */
        var symbolName = Ext.fly(source).up(".set").child(".setbox").child("img").alt;
        return symbolName;
    }

    function listContains(list, itemId, itemValue) {
        for ( var i = list.length - 1; i >= 0; i--) {
            if (list.options[i].value === itemId) {
                return true;
            }
        }
        return false;
    }

    function getGloss(source) {
        var gloss;

        source = Ext.get(source);

        if (source.hasClass("multiple-glosses")) {
            Ext.select(".symbol-gloss").each( function(item) {
                if (item.hasClass("selected")) {
                    gloss = item.dom.innerHTML;
                }
            });
        } else {
            gloss = source.up(".set").child(".setbox").child("img").dom.alt;
        }

        return gloss;
    }

    function getGlossKey(source) {
        var glossKey;

        source = Ext.get(source);

        if (source.hasClass("multiple-glosses")) {
            Ext.select(".symbol-gloss").each( function(item) {
                if (item.hasClass("selected")) {
                    glossKey = item.up("li").child("input.gloss-key-name").getValue();
                }
            });
        } else {
            glossKey = source.up(".set").child(".setbox").child("input.gloss-key-name").getValue();
        }

        return glossKey;
    }


    DownloadSymbols.prototype = {
        init : function() {

            this.registerEventListeners();

			this.initBrowseListSupport();
            this.checkTestMode();
            this.initiateDownloadPopup();

        },

        initiateDownloadPopup : function() {
            if (!popup) {
                popup = new YAHOO.widget.Dialog("export-dialog", {
                    width : "200px",
                    fixedcenter : false,
                    visible : true,
                    constraintoviewport : true,
                    postmethod : "form"
                });

                popup.beforeHideEvent.subscribe( function() {
                    Ext.select(".set.selected").removeClass("selected");
                });

                popup.render();
            }
            popup.hide();
        },

        registerEventListeners : function() {

            YAHOO.Bubbling.on('search/filter/before', this.beforeFilter, this);
            YAHOO.Bubbling.on('search/filter/after', this.afterFilter, this);
            YAHOO.Bubbling.on("browselist/symbol/display/before", this.beforeLoadSymbol, this);

            Ext.fly("empty-list") && Ext.get("empty-list").on("click", this.emptyDownloadList, this);
            Ext.fly("remove-marked") && Ext.get("remove-marked").on("click", this.removeMarkedFromDownloadList, this);
            Ext.fly("show-list") && Ext.get("show-list").on("click", this.showDownloadList, this);
            Ext.fly("add-search-hits") && Ext.get("add-search-hits").on("click", this.addSearchHits, this);

            /* Observe add to list links */
            Ext.get("symbol-section").on("click", this.addToDownloadList, this, {
                delegate : ".add-to-list"
            });

            Ext.get("symbol-section").on("click", this.downloadSingleSymbol, this, {
                delegate : ".download-directly"
            });

            Ext.get("symbol-section").on("click", this.changeDisplaySymbol, this, {
                delegate : ".filtered-symbol"
            });

            /* Observe selection of different glosses */
            Ext.get("symbol-section").on("click", this.toggleGlossCheckBox, this, {
                delegate : ".symbol-gloss"
            });

        },


        checkTestMode : function() {
            if (B.TestMode.isTestMode()) {
                B.TestMode.showTestModeMessage();

                Ext.select(".disabled-in-test-mode").each( function(el) {
                    el.dom.disabled = "disabled";
                });
            }
        },

        /**
         * Used when clicking an image in search result.
         */
        changeDisplaySymbol : function(evt, target) {
            var glossKeyName = Ext.fly(target).child("input.gloss-key-name").getValue();
            var gloss = getSymbolName(target);

            this.displaySymbol(glossKeyName, gloss);
        },

        beforeFilter : function() {
            hidePopup();
        },

        afterFilter : function() {
        },

        beforeLoadSymbol : function() {
            hidePopup();
        },

        getSingleSymbolUrl : function() {
            return "/download/display-symbol";
        },


        downloadSingleSymbol : function(evt, source) {
            Ext.fly("symbolId").dom.value = getSymbolId(source);
            Ext.fly("symbolGloss").dom.value = getGloss(source);
            Ext.fly("glossKey").dom.value = getGlossKey(source);

            this.initiateDownloadPopup();
            popup.show();

            /*
             * Remove any previous selections (needed when clicking another
             * symbol without hiding panel)
             */
            Ext.select(".set.selected").removeClass("selected");

            /* Show panel next to the symbol */
            var symbolContainer = Ext.fly(source).up(".set");
            symbolContainer.addClass("selected");
            var panelContainer = Ext.get("export-dialog").up(".yui-panel-container");
            panelContainer.alignTo(symbolContainer, "tl", [40, 40]);
        },

        addToDownloadList : function(evt, source) {
            var list = Ext.fly("download-list").dom;
            var symbolId = getSymbolId(source);
            var gloss = getGloss(source);
            var glossKey = getGlossKey(source);

            if (B.TestMode.isTestMode() && list.length > 0) {
                B.TestMode.showNotAllowedInTestModeMessage();
                return false;
            }

            if (!listContains(list, symbolId, gloss)) {
                Ext.get("download-list-div").load({
                   url: "/download-list-management/add-download-row",
                   method : "post",
                   params : {
                       symbolId : symbolId,
                       symbolGloss : gloss,
                       glossKey : glossKey
                   },
                   callback : function() {
                       Ext.select("#download-list option").first().highlight();
                   }
                });
            }
        },

        emptyDownloadList : function(evt) {
            Ext.get("download-list").update("");

            Ext.Ajax.request({
                url : "/download-list-management/empty-download-list",
                method : "post"
            });
        },

        removeMarkedFromDownloadList : function(evt) {
            var list = Ext.get("download-list").dom;

            for ( var i = list.length - 1; i >= 0; i--) {
                if (list.options[i].selected) {
                    var glossKey = list.options[i].value;
                    Ext.Ajax.request({
                        url: "/download-list-management/delete-download-row",
                        params : {
                            glossKey : glossKey
                        }
                    });

                    list.remove(i);
                }
            }
        },

        showDownloadList : function(evt) {
            var afterFilter = this.afterFilter.createDelegate(this);

            Ext.get("symbol-section").load({
               url : "/download-list-management/show-download-list",
               method : "post", /* post so that response won't be cached */
               success : afterFilter
            });
        },

        addSearchHits : function(evt) {
            if (B.TestMode.isTestMode()) {
                B.TestMode.showNotAllowedInTestModeMessage();
                return false;
            }

            var filterText = Ext.fly("q").getValue();

            Ext.get("download-list-div").load({
                url: "/download-list-management/add-search-hits",
                method : "post",
                params : {
                    filterText : filterText
                }
            });
        },

        toggleGlossCheckBox : function(evt, source) {
            Ext.fly(source).up(".gloss-list").select("li span").removeClass("selected");
            Ext.fly(source).addClass("selected");

            var glossKeyName = Ext.fly(source).up("li").child("input.gloss-key-name").getValue();

            var img = Ext.fly(source).up(".set").child("img");
            (new B.BlissImage(img).withGlossKeyName(glossKeyName).updateInPlace());
        }

    };


    /* Add functions from BrowseListSupport. */
    YAHOO.lang.augmentProto(DownloadSymbols, B.BrowseListSupport);

    B.DownloadSymbols = new DownloadSymbols();

})();
var Customer = function() {

    return {
        init : function() {
            Ext.get("site-language").on("change", this.updateLanguage);
            if (Ext.fly("hide-menu") && Ext.fly("show-menu")) {
                Ext.select("#hide-menu,#show-menu").on("click", this.toggleMenu);
            }
        },

        updateLanguage : function() {
            Ext.Ajax.request( {
                url : "/login/siteLanguage",
                method : 'post',
                params : {
                    siteLanguage : Ext.fly("site-language").getValue()
                },
                success : function() {
                    window.location.reload();
                }
            });
        },

        toggleMenu : function() {
            Ext.select("#header,#hide-menu-option,#show-menu-option").setVisibilityMode(Ext.Element.DISPLAY).toggle();
        }
    };
}();
Ext.namespace("B");

(function() {

    var Lang = YAHOO.lang;

    var hostPattern = new RegExp("^http://[^:/]+:?[0-9]*");
    var srcPattern = new RegExp("\/images\/(merged|single)\/([^/]+)\/([^/]+)\/([^/]+)\/([^/]+)\/([0-9]+)\/([^/]+)\/([^?]*)[?]{0,1}(.*)$");

    function BlissImage(element) {
        if (!element) {
            return;
        }

        if (Lang.isString(element)) {
            this._parseSrc(element);
        } else {

            element = Ext.get(element);
            this.image = element.is("img") ? element.dom : element.child("img").dom;

            if (!this.image) {
                console.warn("Could not find img element for element %s",
                        element);
                return;
            }

            this.alt = this.image.alt;
            this._parseSrc(this.image.src);
        }

    }

    BlissImage.prototype = {
        _parseSrc : function(source) {

            var matcher = srcPattern.exec(source);

            this.imageType = matcher[1]; // merged or single
            this.event = matcher[2]; // e.g jpeg
            this.language = matcher[3]; // sv
            this.position = matcher[4]; // top
            this.background = matcher[5]; // grid
            this.size = matcher[6]; // 160
            this.imageId = matcher[7];
            this.glossKey = matcher[8];
            this.query = matcher[9]; // title=  (no leading "?")

            var hostMatcher = hostPattern.exec(source);

            if (hostMatcher) {
                this.host = hostMatcher[0];
            } else {
                this.host = "";
            }

        },

        _getSrc : function() {
            return this.host + "/images/" +
            this.imageType + "/" +
            this.event + "/" +
            this.language + "/" +
            this.position + "/" +
            this.background + "/" +
            this.size + "/" +
            this.imageId +  "/" +
            (this.isMerged() ? "" : this.glossKey) +
            (Ext.isEmpty(this.query) ? "" : "?" + this.query)
        },

        _parseQuery : function() {
            if (Ext.isEmpty(this.query)) {
                return {};
            }

            return Ext.urlDecode(this.query);
        },

        withSize : function(size) {
            this.size = size;
            return this;
        },

        isMerged: function() {
            return "merged" === this.imageType;
        },

        getImageUuid : function() {
            return this.imageId;
        },

        getSize : function() {
            return this.size;
        },

        withPosition : function(position) {
            this.position = position || "top";
            return this;
        },

        getCaption : function() {
            return this._parseQuery().title;
        },

        withGlossText : function(caption) {
            var queryParameters = this._parseQuery();
            queryParameters.title = caption;
            this.query = Ext.urlEncode(queryParameters);
            return this;
        },

        withBackground : function(useBackground) {
            this.background = useBackground || "white";
            return this;
        },

        checkBackground : function() {
            var useBackground = Ext.get("background-color").getValue();
            return this.withBackground(useBackground);
        },

        checkTextPosition : function() {
            var textPosition = Ext.get("text-position-select").getValue();
            return this.withPosition(textPosition);
        },

        mergeUuid : function(uuid) {
            this.imageType = "merged";
            this.imageId = this.imageId + "," + uuid;
            return this;
        },

        countUuid : function() {
            return this.imageId.split(",").length;
        },

        withImageId : function(imageUuid) {
            this.imageId = imageUuid;
            return this;
        },

        withGlossKeyName : function(key) {
            this.glossKey = key;
            return this;
        },

        getGlossKeyName : function() {
            return this.glossKey;
        },

        toggleGrid : function() {
            return this.withBackground("grid" === this.background ? "view" : "grid");
        },

        /**
         * Updates the current image element in place.
         */
        updateInPlace: function() {
            this.image.src = this._getSrc();
            return this;
        },

        toElement : function() {
            return Ext.DomHelper.createDom({
                tag : "img",
                src : this._getSrc(),
                alt : this.alt || ""
            });
        }

    };

    B.BlissImage = BlissImage;

})();
Ext.namespace("B");

(function() {

    var Motion = YAHOO.util.Motion, Dom = YAHOO.util.Dom;

    function AddSymbolToChartAnimation(source, target) {
        this.source = Ext.fly(source).dom;
        this.target = Ext.fly(target).dom;
    }

    AddSymbolToChartAnimation.prototype = {

        animate : function() {
            var img = new B.BlissImage(this.source).toElement();

            Ext.fly(img).setStyle({position: "absolute"});

            document.body.appendChild(img);

            var targetPos = Dom.getXY(this.target);
            var startPos = Dom.getXY(this.source);

            var targetSize = Dom.getRegion(this.target);
            var sourceSize = Dom.getRegion(this.source);

            var anim = new Motion(img, {
                points : {
                    "from" : startPos,
                    "to" : targetPos
                },
                width : {
                    from : sourceSize.width,
                    to : targetSize.width
                },
                height : {
                    from : sourceSize.width,
                    to : targetSize.height
                }
            }, 0.500, YAHOO.util.Easing.easeBothStrong);

            var targetImage = new B.BlissImage(this.source).checkBackground().withSize(
                    targetSize.height-1).toElement();
            Ext.fly(targetImage).hide();

            Ext.get(targetImage).on("load", function() {
                img.src = targetImage.src;
            });

            anim.onStart.subscribe(function() {

                /*
                 * Create a hidden image in the target slot while the animation
                 * is running so that the slot will be marked as taken.
                 */
                this.target.appendChild(targetImage);

            }.createDelegate(this));

            anim.onComplete.subscribe(function() {

                /* Remove moving image */
                Ext.fly(img).remove();
                /* Show properly sized image */
                Ext.fly(targetImage).show();

            }.createDelegate(this));


            /* Run animation. */
            anim.animate();

        }

    };

    B.AddSymbolToChartAnimation = AddSymbolToChartAnimation;

})();
Ext.namespace("B");

(function() {

    var Dom = YAHOO.util.Dom, Lang = YAHOO.lang;
    var originalZIndex = 0;

    B.DraggableSymbol = function(id, sGroup, config) {
        if (id) {
            this.init(id, sGroup, config);
        }
    };

    YAHOO.lang.extend(B.DraggableSymbol, YAHOO.util.DD, {
        /*
         * Sets up config options specific to this class. Overrides
         * YAHOO.util.DD, but all versions of this method through the
         * inheritance chain are called
         */
        applyConfig : function() {
            B.DraggableSymbol.superclass.applyConfig.call(this);
            this.setDragElId("movable");
            this.isTarget = false;

            this.dropMode = "replace";
        },

        /** Add new or replace existing image */
        isReplace : function() {
            return "join" !== this.dropMode;
        },

        /**
         * Merge with existing image.
         */
        isJoin : function() {
            return !this.isReplace();
        },

        setSourceId : function(el) {
            /*
             * Primary key of source element, for example image primary key.
             */
            this.sourceId = B.StringUtils.removeNonDigits(el.id);
        },

        getSourceId : function() {
            return this.sourceId;
        },

        /* adjusts the drag element position relative to the pointer */
        adjustPointerPosition : function(x, y) {
            var dragEl = this.getDragEl();

            /* Must show before calculating dimensions. */
            var dim = Dom.getRegion(dragEl);

            /* Adjust position relative to pointer. */
            this.setDelta(dim.width / 2, dim.height / 2);

            /* Adjust starting position. */
            Ext.get(dragEl).setStyle( {
                left : x - dim.width / 2,
                top : y - dim.height / 2
            });

        },

        getTargetSize : function() {
            var height = B.BlissChart.getSize();
            return {
                width : height,
                height : height
            };
        },

        createDraggingImage : function() {
            var el = this.getEl(); // img element

            var clickedImage = Ext.get(el.parentNode).child("img").dom;
            var adjustedSize = this.getTargetSize().height - 1 /* border */;


            var draggingImage = new B.BlissImage(clickedImage).toElement();
            Ext.fly(draggingImage).setOpacity(0.75);

            var targetImage = new B.BlissImage(clickedImage).withSize(adjustedSize).checkBackground().toElement();
            this.targetImage = targetImage;

            Ext.get(this.targetImage).on("load", function() {
                draggingImage.src = targetImage.src;
            });

            return draggingImage;
        },

        getImageContainer : function() {
            return Ext.get(this.getDragEl()).child("div.image-container");
        },

        getSourceSize : function() {
            return Ext.get(this.getEl()).getSize();

        },

        getDraggingImage : function() {
            return Ext.get(this.getDragEl()).child("img").dom;
        },

        sizeToPixels : function(dimensions) {
            if (Lang.isNumber(dimensions.height)) {
                dimensions.height += "px";
            }

            if (Lang.isNumber(dimensions.width)) {
                dimensions.width += "px";
            }

            return dimensions;
        },

        resizeImageContainer : function() {
            var sourceSize = this.sizeToPixels(this.getTargetSize());
            this.getImageContainer().setStyle(sourceSize);
            Ext.get(this.getDragEl()).setStyle(sourceSize);
        },

        b4StartDrag : function(x, y) {

            this.setSourceId(this.getEl());

            Ext.get(this.getImageContainer()).select("img").remove();
            var draggingImage = this.createDraggingImage();
            this.getImageContainer().appendChild(draggingImage);
            Ext.get(this.getDragEl()).show();

            this.resizeImageContainer();

            this.adjustPointerPosition(x, y);
        },

        startDrag : function(x, y) {
            this.saveZIndex();
        },

        saveZIndex : function() {
            originalZIndex = Ext.get(this.getDragEl()).getStyle("zIndex");
        },

        restoreZIndex : function() {
            Ext.get(this.getDragEl()).setStyle("zIndex", originalZIndex);
        },

        endDrag : function(e) {
            this.restoreZIndex();

        },

        replaceTargetSlot : function(index) {

            var sourceId = this.getSourceId();

            /* Remove any existing images. */
            Ext.select("#target" + index + " img").remove();

            Ext.get("target" + index).appendChild(this.targetImage);

            Ext.fly("target" + index).setStyle( {
                width : B.BlissChart.getSize() - 1 + "px"
            });

            var addedImage = new B.BlissImage(this.targetImage);
            var imageUuid = addedImage.getImageUuid();
            var caption = addedImage.getCaption();
            var glossKeyName = addedImage.getGlossKeyName();


            YAHOO.Bubbling.fire("/chart/image/added", {
                position: index,
                imageUuid: imageUuid,
                caption : caption,
                glossKeyName : glossKeyName
            });
    },

    getIndexForId : function(id) {
        var index = id.replace("target", "");
        return index;
    },

    isTargetSlot : function(id) {
        return id.startsWith("target");
    },

    replaceTargetId : function(id) {
        var index = this.getIndexForId(id);
        this.replaceTargetSlot(index);
    },

    mergeTargetId : function(id) {
        var index = this.getIndexForId(id);
        this.mergeTargetSlot(index);
    },

    mergeTargetSlot : function(index) {
        var existingImage = Ext.fly("target" + index).child("img").dom;

        var img = Ext.get(this.getDraggingImage());
        img.setOpacity(1);

        var imageUuid = new B.BlissImage(img).getImageUuid();

        var mergedImage = new B.BlissImage(existingImage).mergeUuid(imageUuid).updateInPlace();
        var imageCount = mergedImage.countUuid();


        var width = B.BlissChart.getSize() * imageCount;

        Ext.fly("target" + index).setStyle( {
                width : width - 1 + "px"
            });

        YAHOO.Bubbling.fire("/chart/image/added", {
            position: index,
            imageUuid: mergedImage.getImageUuid(),
            caption : mergedImage.getCaption()
        });


    },

    onDragDrop : function(e, id) {

        Ext.get(id).setOpacity(1);

        // center it in the square
        Dom.setXY(this.getDragEl(), Dom.getXY(id));

        if (this.isReplace()) {
            this.replaceTargetId(id);
        } else {
            this.mergeTargetId(id);
        }

        Ext.fly(this.getDragEl()).hide();

        this.hideJoinIndicator();

    },

    onInvalidDrop : function(e) {
        /* return to the start position */
        var startPos = Dom.getXY(this.getEl());

        /* Adjust start pos for border. */
        startPos[0]++;
        startPos[1]++;

        var startSize = Dom.getRegion(this.getEl());
        var dragEl = Ext.get(this.getDragEl());
        var draggingImage = this.getDraggingImage();
        dragEl.addClass("animating");
        this.hideJoinIndicator();

        var animation = new YAHOO.util.Motion(draggingImage, {
            points : {
                "to" : startPos
            },
            width : {
                to : startSize.width
            },
            height : {
                to : startSize.height
            }
        }, 0.500, YAHOO.util.Easing.easeBothStrong);

        animation.onComplete.subscribe(function() {
            dragEl.removeClass("animating");
            dragEl.hide();
        });

        animation.animate();

    },

    onDragEnter : function(e, id) {
        this.updateJoinIndicatorPosition(id);
    },

    onDragOut : function(e, id) {
        this.hideJoinIndicator();
    },


    onDragOver : function(evt, id) {
        this.updateJoinIndicatorStatus(evt, id);
    },


    updateJoinIndicatorPosition : function(id) {
        if (Ext.get(id).child("img")) {
            Ext.get("join-indicator").setVisibilityMode(Ext.Element.DISPLAY).show().alignTo(id, "tl").setOpacity(0.2).setSize(Ext.get(id).getSize());

            this.cachedJoinIndicatorPosition = Dom.getXY("join-indicator");
        } else {
            this.hideJoinIndicator();
        }
    },

    hideJoinIndicator : function() {
        Ext.get("movable-header").removeClass("replace").removeClass("join");
        Ext.fly("join-indicator").setVisibilityMode(Ext.Element.DISPLAY).hide();
    },

    updateJoinIndicatorStatus : function(evt, id) {

        var target = Ext.get(id);

        if (target.child("img")) {

            Ext.fly("join-indicator").setVisibilityMode(Ext.Element.DISPLAY).show();

            var x = evt.clientX; // mouse position
            //var targetPosition = Dom.getXY(id);
            var targetPosition = this.cachedJoinIndicatorPosition;
            var targetX = targetPosition[0];

            if (0 < x - targetX && x < targetX + target.getWidth() * 0.65) {
                Ext.get("movable-header").addClass("replace").removeClass("join");
                this.dropMode = "replace";
            } else {
                Ext.get("movable-header").addClass("join").removeClass("replace");
                this.dropMode = "join";
            }
        } else {
            this.dropMode = "add";
            this.hideJoinIndicator();
        }
    }


    });

})();
Ext.namespace("B");

(function() {

    function Chart() {
    }

    Chart.prototype =  {
        init : function() {
            this.initBrowseListSupport();
            this.registerEventListeners();
            this.checkTestMode();
        },

        registerEventListeners : function() {
            /* Observe selection of different glosses */
            Ext.get("symbol-section").on("click", this.toggleGlossCheckBox, this, {
                delegate : ".symbol-gloss"
            });
        },

        checkTestMode : function() {
            if (B.TestMode.isTestMode()) {
                B.TestMode.showTestModeMessage();
            }
        },

        /**
         * @return the url to use to load a single symbol when browsing.
         */
        getSingleSymbolUrl : function() {
            return "/chart/display-symbol";
        },

        toggleGlossCheckBox : function(evt, source) {
            var glossKey = Ext.fly(source).up("li").dom.id;

            Ext.fly(source).up(".gloss-list").select(".symbol-gloss").removeClass("selected");
            Ext.fly(source).addClass("selected");

            var img = Ext.fly(source).up(".set").child(".symbol-box").child("img").dom;

            (new B.BlissImage(img).withGlossKeyName(glossKey).updateInPlace());

        }

    };

    /* Add functions from BrowseListSupport. */
    YAHOO.lang.augmentProto(Chart, B.BrowseListSupport);

    /* Make the singleton public. */
    B.Chart = new Chart();
}) ();
Ext.namespace("B");

(function() {

    var sizeSlider = null;

    function ChartSizeSelector() {
    }

    ChartSizeSelector.prototype = {
        /**
         * Will be called using YUI onDOMReady, so the arguments will be
         * "DOMReady", [], data.
         *
         * http://developer.yahoo.com/yui/docs/YAHOO.util.Event.html
         */
        init : function(event, emptyArgs, data) {
            sizeSlider = new se.pictosys.SizeSlider("size", {
                max : 120,
                step : 1
            });
            sizeSlider.setRealValue(data.realValue);
            this.bindEventListeners();

        },

        bindEventListeners : function() {

            function setRealValueForSheetSizes() {
                var size = Ext.fly("size-type-select").getValue();
                if (size) {
                    sizeSlider.setRealValue(size, {
                        animated : true
                    });

                    YAHOO.Bubbling.fire('chart/changeDocumentType', {
                        documentType : 'LABELS'
                    });
                } else {
                    YAHOO.Bubbling.fire('chart/changeDocumentType', {
                        documentType : 'CHART_A4'
                    });
                }
            }

            Ext.get("size-type-select").on("change", setRealValueForSheetSizes);
        },

        updateSizeDropDown : function(realValue) {
            var currentSize = Ext.fly("size-type-select").getValue(); // returns String

            if (currentSize !== realValue + "") {
                /* Set to custom size. */
                Ext.fly("size-type-select").dom.selectedIndex = 0;

                YAHOO.Bubbling.fire('chart/changeDocumentType', {
                    documentType : 'CHART_A4'
                });
            }
        }
    };

    B.ChartSizeSelector = new ChartSizeSelector();

    YAHOO.Bubbling.on('changeSizeSlider', function(name, array) {
        var param = array[1];
        this.updateSizeDropDown(param.realValue);
    }, B.ChartSizeSelector);


})();
Ext.namespace("B");

(function() {

    var changeSlotSizeTask = null;
    var changeImageSizeTask = null;
    /**
     * Keeps track of all registered drag elements, so that they can be unregistered.
     */
    var draggables = [];


    /** Image size in pixels. */
    var size = 120;

    function isLabels50() {
        return Ext.fly("size-type-select").getValue() === "49";
    }

    function isLabels30() {
        return Ext.fly("size-type-select").getValue() === "30";;
    }

    function addDragProxy(element) {

        if (Ext.fly(element).hasClass("draggable-symbol")) {
            return;
        }

        var dd = new B.DraggableSymbol(element);
        draggables.push(dd);
        Ext.fly(element).addClass("draggable-symbol");
    }

    function unregisterAllDraggables() {
		while(draggables.length > 0) {
            try {
                var dd = draggables.shift();
                var image = dd.getEl();
                dd.unreg();
                Ext.fly(image).removeClass("draggable-symbol");
            } catch (e) {
                /* ignored - can't do anything anyway.*/
            }
        };
    }

    function isBoxEmpty(box) {
        return !(Ext.fly(box).child("img"));
    }

    /* Private constructor. */
    function BlissChart() {
    }

    BlissChart.prototype = {
        init : function() {
            if (!B.Page.isChartPage()) {
                return;
            }

        this.registerDropTargets();
        this.registerEventListeners();
    },


    registerEventListeners : function() {

        YAHOO.Bubbling.on("browselist/symbol/display/before", this.beforeFilter, this);
        YAHOO.Bubbling.on('search/filter/before', this.beforeFilter, this);

        // YAHOO.Bubbling.on('search/filter/after', this.afterFilter, this);
        // YAHOO.Bubbling.on("browselist/symbol/display/after", this.afterFilter, this);
        // YAHOO.Bubbling.on("symbol/image/reloaded", this.afterFilter, this);

        Ext.get("symbol-section").on("click", this.addImageToChart, this, {
                delegate : ".add-to-chart"
            });

        Ext.get("background-color").on("change", this.changeBackground.createDelegate(this));
        Ext.get("text-position-select").on("change", this.changeTextPosition.createDelegate(this));

        Ext.select(".toggle-chart-settings").on("click", this.toggleSettings, this, {delegate : "span"});

        reg.hover("span.filtered-symbol img", function() {
            addDragProxy(this);
        });

        reg.hover("div.symbol-box img", function() {
            addDragProxy(this);
        });
    },


    toggleSettings : function() {

        Ext.select('#chart-settings, .toggle-chart-settings span').setVisibilityMode(Ext.Element.DISPLAY);

        function toggleShowHideLinks() {
            Ext.select(".toggle-chart-settings span").toggle();
        }

        var animConfig = {
            callback : toggleShowHideLinks,
            duration : 0.3,
            easing : 'easeOut'
        };

        var chartSettings = Ext.get("chart-settings");


        if (chartSettings.isVisible()) {
            YAHOO.Bubbling.fire('/chart/settings/hide');
            chartSettings.slideOut("t", animConfig);
        } else {
            YAHOO.Bubbling.fire('/chart/settings/show');
            chartSettings.slideIn("t", animConfig);
        }
    },

    setSize : function(newSize) {
        size = newSize;
    },

    getSize : function() {
        return size;
    },

    scheduleChangeImageSize : function() {
        if (!changeImageSizeTask) {
            changeImageSizeTask = new Ext.util.DelayedTask(this.updateImageSizes, this);
        }

        changeImageSizeTask.delay(750);
    },

    schedulePreviewSymbolSize : function() {
        if (!changeSlotSizeTask) {
            changeSlotSizeTask = new Ext.util.DelayedTask(this.changeSlotSize, this);
        }
        changeSlotSizeTask.delay(50);
    },

    updateImageSizes : function() {
        function changeSize(img) {
            (new B.BlissImage(img)).withSize(size - 1).updateInPlace();
        }

        this.getTargetSlotImages().each(changeSize);
    },


    changeSlotSizeForMergedImage : function (img) {
        var count = new B.BlissImage(img).countUuid();
        Ext.get(img).parent().setStyle( {
                width : (size * count) - 1 + "px"
            });
    },


    getChartWidth : function() {
        if (isLabels50()) {
            return 400;
        } else if (isLabels30()) {
            return 360;
        }
        return 360;
    },

    getChartHeight : function() {
        return 540;
    },

    calculateImagesPerRow : function() {
         return Math.floor(this.getChartWidth() /size);
    },

    calculateImagesPerColumn : function() {
        return Math.floor(this.getChartHeight() / size);
    },

    changeSlotSize : function() {

        /* Change slot size and adjust for border width. */
        this.getTargetSlots().setStyle({
            width: size-1 +"px",
            height: size-1 + "px"
        });

        this.getMergedImages().each(this.changeSlotSizeForMergedImage);

        this.updateMargins();

        this.updateAppearanceForNonFittingSlots();

    },

    getMinimumLeftMargin : function() {
        if (isLabels50()) {
            return 25;
        }

        return 45;
    },

    getMinimumRightMargin :function() {
        if (isLabels50()) {
            return 25;
        }

        return 45;
    },

    updateMargins : function() {
        /* Make sure margins are integers. */
        var chartWidth = this.getChartWidth();
        var marginSpace = chartWidth % size;
        var width = chartWidth - marginSpace;
        var leftMargin = Math.ceil(marginSpace / 2);
        var rightMargin = marginSpace - leftMargin;


        var minLeftMargin = this.getMinimumLeftMargin();
        var minRightMargin = this.getMinimumRightMargin();

        var leftPadding = leftMargin + minLeftMargin + "px";
        var rightPadding = rightMargin + minRightMargin + "px";

        Ext.get("margins").setStyle( {
            "padding-left" : leftPadding,
            "padding-right" : rightPadding,
            width : width + "px"
        });

        Ext.get("rightbox").setStyle( {
            width : width + "px"
        });

    },


    updateAppearanceForNonFittingSlots: function() {
        Ext.select(".smallbox").setStyle({opacity:1});

        var numberOfElementsInside = this.calculateImagesPerRow() * this.calculateImagesPerColumn();

        function markOutside(el) {
            Ext.fly(el).setOpacity(0.2);
        }

        var elementsOutside = Ext.select(".smallbox").elements.splice(numberOfElementsInside);
        Ext.each(elementsOutside, markOutside);

    },

    changeTextPosition : function() {
        function updateTextPosition(img) {
            (new B.BlissImage(img)).checkTextPosition().updateInPlace();
        }

        this.getTargetSlotImages().each(updateTextPosition);

        this.fireSettingsChanged();
    },

    changeBackground : function() {
        function updateBackground(img) {
            (new B.BlissImage(img)).checkBackground().updateInPlace();
        }

        this.getTargetSlotImages().each(updateBackground);

        this.fireSettingsChanged();
    },

    changeDocumentType : function(documentType) {
        this.updateMargins();
    },

    fireSettingsChanged : function() {
        YAHOO.Bubbling.fire('/chart/settings/changed', {
            textPosition: Ext.fly("text-position-select").getValue(),
            imageBackground : Ext.fly("background-color").getValue()
        });
    },


    addImageFromUuidToChart : function(uuid, glossKeyName) {
        /* TODO language should not be hardcoded. */
        var addedImage = new B.BlissImage("/images/single/jpeg/sv/top/white/60/" + uuid + "/" + glossKeyName).withSize(this.getSize() -1);

        var slot = this.getFirstEmptySlot();
        if (slot) {
            slot.appendChild(addedImage.toElement());
            this.fireImageAdded(B.StringUtils.removeNonDigits(slot.id), addedImage.getImageUuid(), addedImage.getCaption(), addedImage.getGlossKeyName());
        }
    },

    addImageToChart : function(e, el) {
        var img = Ext.fly(el).up(".set").child("img").dom;
        this.addImageToFirstEmptySlot(img);
    },

    addImageToFirstEmptySlot : function(img) {
        var slot = this.getFirstEmptySlot();
        if (slot) {
            (new B.AddSymbolToChartAnimation(img, slot)).animate();
        }

        var addedImage = new B.BlissImage(img);
        this.fireImageAdded(B.StringUtils.removeNonDigits(slot.id), addedImage.getImageUuid(), addedImage.getCaption(), addedImage.getGlossKeyName());
    },

    createNewChart: function() {
        this.fireNewChartCreated();
    },

    onNewChartCreated : function() {
        this.getTargetSlotImages().remove();
        this.getTargetSlots().setStyle( {
                width : size - 1 + "px"
            });
    },

    fireNewChartCreated : function() {
        YAHOO.Bubbling.fire("/document/created");
    },

    fireImageAdded : function(position, imageUuid, caption, glossKeyName) {
        YAHOO.Bubbling.fire("/chart/image/added", {
            position: position,
            imageUuid: imageUuid,
            caption: caption,
            glossKeyName : glossKeyName
        });
    },

    getFirstEmptySlot : function() {
        var boxes = Ext.select(".smallbox").elements;

        function isBoxEmptyIterator(box) {
            if (isBoxEmpty(box)) {
                /* Breaks out of iteration. */
                return false;
            }
        }

        var index = Ext.each(boxes, isBoxEmptyIterator);

        return boxes[index];
    },

    registerDropTargets : function() {
        function addDropTarget(element) {
            (new YAHOO.util.DDTarget(element));
        }

        Ext.each(this.getSlots().elements, addDropTarget);
    },

    beforeFilter : function() {
    	unregisterAllDraggables();
    },

    afterFilter : function() {
    },

	/**
	 * Register drag handlers for all search results. Warning: this will be slow.
	 */
    registerDragElements : function() {
        this.getSearchResultImages().each(addDragProxy);
    },

    /**
     * @return img elements that are placed in the target slots of the chart.
     */
    getTargetSlotImages : function() {
        return Ext.select("#rightbox .smallbox img");
    },

    getMergedImages : function() {
        return Ext.get("rightbox").select("img[src*=merged]");
    },

    getTargetSlots : function() {
        return Ext.select("#rightbox .smallbox");
    },

    /**
     * @return all slots in the chart
     */
    getSlots : function() {
        return Ext.select(".smallbox");
    },

    getSearchResultImages : function() {
        return Ext.select("#symbol-section img");
    }

    };

    /* Expose singleton */
    B.BlissChart = new BlissChart();

    YAHOO.util.Event.onDOMReady(B.BlissChart.init, {}, B.BlissChart);



    YAHOO.Bubbling.on('previewSizeSlider', function(name, array) {
        var param = array[1];
        this.setSize(param.pixelValue);
        this.schedulePreviewSymbolSize();
        this.scheduleChangeImageSize();
    }, B.BlissChart);

    YAHOO.Bubbling.on('changeSizeSlider', function(name, array) {
        var param = array[1];
        this.setSize(param.pixelValue);
        this.updateImageSizes();
    }, B.BlissChart);

    YAHOO.Bubbling.on("/document/created", function(name, array) {
        this.onNewChartCreated();
    }, B.BlissChart);

    YAHOO.Bubbling.on('chart/changeDocumentType', function(name, array) {
        var params = array[1];
        this.changeDocumentType(params.documentType);
    }, B.BlissChart);




})();
Ext.namespace("B");

(function() {

    function QuickWrite() {
    }

    function onSelect(combo, record) {
        var glossKeyId = combo.getValue();
        B.BlissChart.addImageFromUuidToChart(record.json.uuid, record.json.glossKeyName);
        combo.clearValue();
        combo.focus();
    }

    function onSpecialKey(field, e) {
        if (e.getKey() === e.ESC) {
            field.clearValue();
        }
    }

    function addFirstSearchResult() {
        var firstSearchResultImage = Ext.select("#chart #filtered-symbols img").first().dom;
        B.BlissChart.addImageToFirstEmptySlot(firstSearchResultImage);
    }

    QuickWrite.prototype = {

        init : function() {
            this.initQuickwriteForSearchfield();
        },

        initQuickwriteForSearchfield : function() {

            var map = new Ext.KeyMap(document, [ {
                key : Ext.EventObject.ESC,
                handler : function() {
                    Ext.get("q").dom.value = "";
                    Ext.get("q").focus();
                }
            }, {
                key : Ext.EventObject.ENTER,
                shift : true,
                handler : addFirstSearchResult
            }, {
                key : Ext.EventObject.Enter,
                ctrl : true,
                handler : addFirstSearchResult
            } ]);
        },

        initAutocompleteWidget : function() {
            if (!Ext.get("gloss-key-autocomplete")) {
                return;
            }

            (new B.GlossKeyAutoComplete("gloss-key-autocomplete", {
                select : onSelect,
                specialkey : onSpecialKey
            }, {
                forceSelection : true
            }));

        }

    };

    B.QuickWrite = new QuickWrite();
})();
Ext.namespace("B");

(function() {

    var listId = "symbol-list";
    var containerId = "symbol-section";

    function DictionaryBrowser() {
    }

    function fireEntryChanged(entryId) {
        YAHOO.Bubbling.fire("dictionary/entry/changed", {
            entryId : entryId
        });
    }

    function onBrowseListChanged() {
        var entryId = Ext.fly(listId).getValue();
        fireEntryChanged(entryId);
    }

    function reglib_navigateToEntry() {
        var entryId = Ext.get(this).up(".dictionary-composition-text").child(
                "input.hidden-input-entry").dom.value;
        fireEntryChanged(entryId);
    }

    function showImagePreview(id) {
        var uuid = Ext.get(id).child("input.hidden-input-uuid").dom.value;

        var preview = Ext.get("image-preview");
        if (!preview) {
            preview = Ext.DomHelper.append(document.body, {
                tag : 'img',
                id : "image-preview",
                style : "border: 1px solid #ccc"
            });

            preview = Ext.get(preview);
            preview.on("load", function() {
                preview.show();
            });
        }

        preview.hide();
        preview.dom.src = '/images/single/jpeg/sv/top/nordic/100/' + uuid;

        preview.alignTo(id, "bl", [ 0, 5 ]);
    }

    function reglib_showImagePreview() {
        var id = Ext.id(this);
        showImagePreview(id);
    }

    function hideImagePreview() {
        try {
            var preview = Ext.get("image-preview");
            if (preview) {
                preview.hide();
            }
        } catch (e) {
            /* Swallow exceptions so that other functions can continue. */
        }
    }

    DictionaryBrowser.prototype = {
        init : function() {
            this.registerEventListeners();
            this.showInitialEntry();
        },
        registerEventListeners : function() {
            Ext.fly(listId) && Ext.get(listId).on("change", onBrowseListChanged);

            YAHOO.Bubbling.on("history/dictionary/entry/changed", this.onEntryChanged, this);

            reg.hover(".dictionary-text-container div.composition .matched",
                    reglib_showImagePreview, hideImagePreview);
            reg.click(".dictionary-text-container div.composition .linkable",
                    reglib_navigateToEntry);

        },

        showInitialEntry : function() {
            if (!Ext.fly(listId)) {
                return;
            }

            var list = Ext.fly(listId).dom;
            if (list.length > 0 && list.selectedIndex < 0) {
                list.selectedIndex = 0;
                var entryId = list.value;
                this.loadEntry(entryId);
            }
        },

        onEntryChanged: function(name, args) {
            var entryId = args[1].entryId;
            this.loadEntry(entryId);
        },

        loadEntry : function(entryId) {
            hideImagePreview();

            Ext.get(containerId).load( {
                url : "/dictionary/entry",
                params : {
                    entryId : entryId
                }
            });
        }

    };

    B.DictionaryBrowser = new DictionaryBrowser();

})();
Ext.namespace("B");

(function() {

    function DocumentName() {
    }

    DocumentName.prototype = {

        setName : function(name) {
            Ext.fly("document-name").removeClass("unnamed").update(name);
        },

        setUnnamed : function() {
            Ext.fly("document-name").addClass("unnamed").update(
                    TreeTranslations.untitledSheet);
        }

    };

    B.DocumentName = new DocumentName();

    YAHOO.Bubbling.on("/document/saved", function(name, array) {
        var param = array[1];
        this.setName(param.name);
    }, B.DocumentName);

    YAHOO.Bubbling.on("/document/created", function(name, array) {
        var param = array[1];
        this.setUnnamed();
    }, B.DocumentName);

})();
Ext.namespace("B");

(function() {

    var msgCt;
    var messageTimer = null;

    function createBox(t, s) {
        return [
                '<div class="msg" style="text-align: center;">',
                // '<div class="x-box-tl"><div class="x-box-tr"><div
                // class="x-box-tc"></div></div></div>',
                '<div class="x-box-ml"><div class="x-box-mr"><div class="x-box-mc">' +
                // '<h3>',
                // t,
                // '</h3>',
                '<span>',
                s,
                '</span>',
                '</div></div></div>',
                '<div class="x-box-bl"><div class="x-box-br"><div class="x-box-bc"></div></div></div>',
                '</div>' ].join('');
    }

    function DocumentNotification() {
    }

    DocumentNotification.prototype = {

        /**
         * Usage QuickNotification("Note header", "Message with {0}",
         * "parameter0")
         */
        formatMessage : function(title, format) {
            if (!msgCt) {
                msgCt = Ext.DomHelper.insertFirst(document.body, {
                    id : 'msg-div'
                }, true);
            }

            /* Align twice or it won't work in IE6. */
            msgCt.alignTo("margins", 'tr-br');
            msgCt.alignTo("margins", 'tr-br');

            var s = String.format.apply(String, Array.prototype.slice.call(
                    arguments, 1));
            var m = Ext.DomHelper.append(msgCt, {
                html : createBox(title, s)
            }, true);
            m.slideIn('t').pause(3).slideOut("t", {
                remove : true
            });

        },

        cancelMessage : function() {
            if (messageTimer) {
                clearTimeout(messageTimer);
            }
        },

        scheduleSavedNotification : function() {
            this.cancelMessage();
            messageTimer = this.formatMessage.createDelegate(this, ["",
                    TreeTranslations.changesSaved]).defer(3000);
        }

    };

    B.DocumentNotification = new DocumentNotification();

    YAHOO.Bubbling.on('/document/userchart/changes/saved',
            function(name, array) {
                if (!Ext.fly("document-name").hasClass("unnamed")) {
                    this.scheduleSavedNotification();
                }
            }, B.DocumentNotification);

})();
Ext.namespace("B");

(function() {

    var hideTimer = null;
    var showTimer = null;
    var currentSlot = null;
    var animation = null;

    function clonePosition(overlay, target) {
        Ext.get(overlay).alignTo(target, "tl").setSize(Ext.get(target).getSize());
    }

    function getSlotPosition(slotId) {
        return B.StringUtils.removeNonDigits(slotId);
    }

    function getCurrentSlotId() {
        return B.StringUtils.removeNonDigits(currentSlot);
    }

    function BlissChartOverlayMenu() {
    }

    BlissChartOverlayMenu.prototype = {
        init : function() {
            if (!B.Page.isChartPage()) {
                return;
            }

            this.registerEventListeners();

            this.initialPositioningFixForIe6();
        },

        registerEventListeners : function() {
            reg.hover(".smallbox", this.hoverOverBox);
            reg.hover("#rightbox", null, this.hoverOut);
            reg.hover("#overlay-menu", this.showOverlayMenu);
            reg
                    .click(".remove-current-slot", this.removeCurrentSlot
                            .createDelegate(this));
            reg.click(".edit-gloss-text", this.editGlossTextForCurrentSlot
                    .createDelegate(this));

        },

        initialPositioningFixForIe6 : function() {
            /* Try to position the element once, to avoid problems with IE6. Not needed for any other browser. */
            try {
                var overlay = Ext.get("overlay-menu");
                overlay.setOpacity(0).show();
                clonePosition(overlay, "target0");
                overlay.hide();
            } catch (e) {
                /* Ignored. */
            }
        },

        editGlossTextForCurrentSlot : function() {

            var slot = Ext.get(currentSlot);

            function callback(btn, text) {

                if ("ok" !== btn) {
                    return;
                }

                if (!text) {
                    return;
                }

                var img = slot.child("img");
                (new B.BlissImage(img).withGlossText(text).updateInPlace());

                YAHOO.Bubbling.fire("/chart/image/caption/changed", {
                    position : getSlotPosition(slot.dom.id),
                    caption : text
                });
            }

            if (slot) {
                Ext.Msg.show({
                    title: 'Text',
                    msg: 'Valfri text:',
                    width: 300,
                    buttons: Ext.MessageBox.OKCANCEL,
                    modal: false,
                    prompt: true,
                    animEl: slot,
                    icon: Ext.MessageBox.INFO,
                    fn: callback
                 });
            }
        },

        removeCurrentSlot : function() {
            if (currentSlot) {
                Ext.get(currentSlot).update("");
                Ext.get("overlay-menu").hide();

                Ext.fly(currentSlot).setStyle( {
                    width : B.BlissChart.getSize() - 1 + "px"
                });

                YAHOO.Bubbling.fire('/chart/image/removed', {
                    position : getCurrentSlotId()
                });
            }
        },

        showOverlayMenu : function() {
            Ext.get("overlay-menu").show();
            clearTimeout(hideTimer);
            hideTimer = null;

        },

        hoverOverBox : function() {
            B.BlissChartOverlayMenu.clearShowHideTimers();

            currentSlot = this.id;

            if (!Ext.get(this).child("img")) {
                Ext.get("overlay-menu").hide();
                return;
            }

            try {
                var overlay = Ext.get("overlay-menu").setOpacity(0).show();
                clonePosition(overlay, this);
            } catch (e) {
                /* Prototype 1.6.1.0 in IE6 will throw errors complaining that style is null. */
            }

            var attributes = {
                opacity : {
                    from : 0,
                    to : 1
                }
            };
            animation = new YAHOO.util.Anim("overlay-menu", attributes, 0.3,
                    YAHOO.util.Easing.easeInStrong);
            animation.animate();
        },

        clearShowHideTimers : function() {
            if (hideTimer) {
                clearTimeout(hideTimer);
                hideTimer = null;
            }

            if (showTimer) {
                clearTimeout(showTimer);
                showTimer = null;
            }
        },

        hideOverlayMenu : function () {
            Ext.get("overlay-menu").setOpacity(0).hide();
        },

        hoverOut : function() {
            B.BlissChartOverlayMenu.clearShowHideTimers();
            hideTimer = B.BlissChartOverlayMenu.hideOverlayMenu.defer(0.2);
        }

    };

    B.BlissChartOverlayMenu = new BlissChartOverlayMenu();

    YAHOO.util.Event.onDOMReady(B.BlissChartOverlayMenu.init, {},
            B.BlissChartOverlayMenu);

    Ext.each(['previewSizeSlider', "/chart/settings/hide", "/chart/settings/show" ], function(event) {
        YAHOO.Bubbling.on(event, function(name, array) {
            this.hideOverlayMenu();
        }, B.BlissChartOverlayMenu);
    });

})();
Ext.namespace("B");

(function() {

    var saveChartSettingsTask = null;
    var millimeterHeight = null;
    var persistChartTask = null;

    function fireChangesSaved() {
        YAHOO.Bubbling.fire('/document/userchart/changes/saved');
    }

    function BlissChartAsyncPersistence() {
    }

    BlissChartAsyncPersistence.prototype = {

        scheduleSaveChartSettings : function() {
            if (!saveChartSettingsTask) {
                saveChartSettingsTask = new Ext.util.DelayedTask(
                        this.saveChartSettings, this);
            }

            saveChartSettingsTask.delay(1000);
        },

        setMillimeterSize : function(mm) {
            millimeterHeight = mm;
            this.scheduleSaveChartSettings();
        },

        saveChartSettings : function() {

            var params = {
                textPosition : Ext.fly("text-position-select").getValue(),
                imageBackground : Ext.fly("background-color").getValue(),
                height : millimeterHeight
            };

            Ext.Ajax.request( {
                url : "/chart/edit/changeChartSettings",
                params : params,
                success : this.schedulePersistChart.createDelegate(this)
            });
        },

        saveImageAdded : function(position, imageUuid, caption, glossKeyName) {

            var params = {
                position : position,
                imageUuid : imageUuid,
                caption : caption,
                glossKeyName : glossKeyName
            };

            Ext.Ajax.request( {
                url : "/chart/edit/addImage",
                params : params,
                success : this.schedulePersistChart.createDelegate(this)
            });
        },

        saveImageRemoved : function(position) {
            var params = {
                position : position
            };

            Ext.Ajax.request( {
                url : "/chart/edit/removeImage",
                params : params,
                success : this.schedulePersistChart.createDelegate(this)
            });
        },

        saveChangeCaption : function(position, caption) {
            var params = {
                position : position,
                caption : caption
            };

            Ext.Ajax.request( {
                url : "/chart/edit/changeCaption",
                params : params,
                success : this.schedulePersistChart.createDelegate(this)
            });
        },

        saveDocumentType : function(documentType) {

            var params = {
                documentType : documentType
            };

            Ext.Ajax.request( {
                url : "/chart/edit/changeDocumentType",
                params : params,
                success : this.schedulePersistChart.createDelegate(this)
            });
        },

        createNewChart : function() {
            Ext.Ajax.request( {
                url : "/chart/edit/create",
                success : this.scheduleSaveChartSettings.createDelegate(this)
            });
        },

        schedulePersistChart : function( ) {
            if (!persistChartTask) {
                persistChartTask= new Ext.util.DelayedTask(this.persistChart, this);
            }

            persistChartTask.delay(3000);
        },

        persistChart : function() {
            Ext.Ajax.request({
                url : "/chart/edit/save",
                success : function(response, options) {

                    var result = Ext.util.JSON.decode(response.responseText);
                    if (result.success) {
                        fireChangesSaved();
                    }
                }
            });
        }



    };

    B.BlissChartAsyncPersistence = new BlissChartAsyncPersistence();


    YAHOO.Bubbling.on('changeSizeSlider', function(name, array) {
        var param = array[1];
        this.setMillimeterSize(param.realValue);
    }, B.BlissChartAsyncPersistence);

    YAHOO.Bubbling.on('/chart/settings/changed', function(name, array) {
        var param = array[1];
        this.scheduleSaveChartSettings();
    }, B.BlissChartAsyncPersistence);

    YAHOO.Bubbling.on('/chart/image/removed', function(name, array) {
        var param = array[1];
        this.saveImageRemoved(param.position);
    }, B.BlissChartAsyncPersistence);

    YAHOO.Bubbling.on('/chart/image/added', function(name, array) {
        var param = array[1];
        this.saveImageAdded(param.position, param.imageUuid, param.caption, param.glossKeyName);
    }, B.BlissChartAsyncPersistence);

    YAHOO.Bubbling.on("/document/created", function(name, array) {
        var param = array[1];
        this.createNewChart();
    }, B.BlissChartAsyncPersistence);

    YAHOO.Bubbling.on("/chart/image/caption/changed", function(name, array) {
        var param = array[1];
        this.saveChangeCaption(param.position, param.caption);
    }, B.BlissChartAsyncPersistence);

    YAHOO.Bubbling.on('chart/changeDocumentType', function(name, array) {
        var params = array[1];
        this.saveDocumentType(params.documentType);
    }, B.BlissChartAsyncPersistence);


})();
var News = function() {

    var scroller = null;

    return {
        prepare : function() {
            this.startScroller();
            currSize = 450;
        },

        startScroller : function() {

            scroller = new P.EndlessScrolling("/news/list_page", "news-list", {
                chunk : 0
            });
            scroller.start();
        }
    };

}();
var TellAFriend = function() {
    var messageTemplate = null;

    return {
        init : function() {
            messageTemplate = Ext.Template.from("message-template", {
                compiled : true,
                disableFormats : true
            });

            Ext.select("#friendsName, #sendersName").on("keyup", this.updateMessage ,this);
            Ext.get("writeOwnMessage").on("click", this.writeOwnMessage, this);
            this.updateMessageWithParameters( {});
        },

        writeOwnMessage : function() {
            Ext.fly("referenceMessage").toggleClass("tell-a-friend-message-template");
            var checked = Ext.fly("writeOwnMessage").dom.checked;
            if (checked) {
                Ext.fly("referenceMessage").focus();
            } else {
                this.updateMessage();
            }
        },

        updateMessage : function() {
            var checked = Ext.fly("writeOwnMessage").dom.checked;
            if (!checked) {
                var parameters = {
                    friendsName : Ext.fly("friendsName").getValue(),
                    sendersName : Ext.fly("sendersName").getValue()
                };
                this.updateMessageWithParameters(parameters);
            }
        },

        updateMessageWithParameters : function(parameters) {
            if (Ext.fly("writeOwnMessage").dom.checked == false) {
                Ext.fly("referenceMessage").dom.value = messageTemplate.apply(parameters);
            }
        }
    };
}();
Ext.namespace("B");

(function() {

    function InvoicePage() {
    }

    var checkbox = "invoiceAddressSame";
    var panel = "invoiceAddressPanel";
    function toggleInvoiceAddress() {
        var show = !(Ext.fly(checkbox).dom.checked);
        if (show) {
            Ext.fly(panel).setOpacity(1.0);
            Ext.fly("invoiceFirstName").focus();
        } else {
            Ext.fly(panel).setOpacity(0.5);
        }
    }

    function setupInvoiceAddress() {
        var show = !(Ext.fly(checkbox).dom.checked);
        if (show) {
            Ext.fly(panel).setOpacity(1.0);
        } else {
            Ext.fly(panel).setOpacity(0.5);
        }
    }

    InvoicePage.prototype = {
        /* Init is expected to be called in an Ext.onReady() */
        init : function() {

            Ext.fly(checkbox).on( {
                change : toggleInvoiceAddress,
                /* click required for IE */
                click : toggleInvoiceAddress
            });

            setupInvoiceAddress();

            (new B.CountryCodeListener("countryCode", "state"));
            (new B.CountryCodeListener("invoiceCountryCode", "invoiceState"));

            Ext.fly("contactPerson").focus();
        }
    };

    B.InvoicePage = new InvoicePage();

})();
Ext.namespace("B");

(function() {

    /* source = country select id, target = state id */
    function CountryCodeListener(source, target) {

        this.source = Ext.fly(source).dom;
        this.target = Ext.fly(target).dom;

        Ext.fly(this.source).on("change", this.checkIfStateRequired, this);

        Ext.onReady(this.checkIfStateRequired, this);
    }

    CountryCodeListener.prototype = {

        checkIfStateRequired : function() {
            var country = Ext.fly(this.source).getValue();

            if (country === "CA" || country === "US") {
                Ext.fly(this.target).setVisibilityMode(Ext.Element.DISPLAY).show();
            } else {
                Ext.fly(this.target).setVisibilityMode(Ext.Element.DISPLAY).hide();
            }
        }

    };

    B.CountryCodeListener = CountryCodeListener;

})();
/**
 * Alternative solution which doesn't require ux?
 * 
 * http://extjs.com/forum/showthread.php?t=6153
 * 
 * Ext.get(Ext.get(tb.addSpacer().getEl()).dom.parentNode).setStyle('width', '100%');
 * 
 * Ext.fly(tb.addSpacer().getEl().parentNode).setStyle('width', '100%')
 */

Ext.ux.ToolbarFillingTextField = Ext.extend(Ext.form.TextField, {

	render : function(td) {
		td.style.width = '100%';
		Ext.form.TextField.superclass.render.call(this, td);
		this.el.applyStyles("width: 95%");
	}
});

Ext.reg('tbfilltextfield', Ext.ux.ToolbarFillingTextField);
Ext.namespace("P", "Ext", "Ext.app");

Ext.app.SheetTreePanel = function() {

    function getUrlKey() {
        return "userchart";
    }

    var urls = {
        userchart : {
            save: "/chart/edit/saveAs",
            rootTranslation: TreeTranslations.userChartRootTitle
        }, nullObject : {
            save: "",
            rootTranslation : ""
        }
    };

    function getSaveUrl() {
        return urls[getUrlKey()].save;
    }

    function getRootNodeTitle() {
        return urls[getUrlKey()].rootTranslation;
    }

    function getExploreUrl() {
        return "/document/tree/explore";
    }

    function getLoadUrl(documentId) {
        return "/print/common/load/" + documentId;
    }


	// set the root node
	var saveRoot = new Ext.tree.AsyncTreeNode({
		text : getRootNodeTitle(),
		draggable : false,
		id : 'source'
	});

	var loadRoot = new Ext.tree.AsyncTreeNode({
		text : getRootNodeTitle(),
		draggable : false,
		id : 'source'
	});

	var saveWindow = null;
	var loadWindow = null;


	return {

		createWindow : function(save) {

			var getParentNode = function(node) {
				return node.isLeaf() ? node.parentNode : node;
			};

			var getSelectedNode = function() {
				var node = tree.getSelectionModel().getSelectedNode();
				return node || tree.getRootNode();
			};

			var buildParams = function(node) {
				var params = {
					node : node.attributes.id,
					parent : node.parentNode.attributes.id,
					leaf : node.isLeaf(),
					text : node.attributes.text
				};

                /* Add sheet size for fixed sheets. */
                if (Ext.getDom("sheetChangeSizeSelect")) {
                    params.sheetSize = Ext.getDom("sheetChangeSizeSelect").value;
                }

                return params;
			};

			var openFile = function() {
				var node = getSelectedNode();

				var sheetId = null;

				if (node.isLeaf()) {
					loadWindow.hide();

					sheetId = node.attributes.id;

					window.document.location.pathname = getLoadUrl(sheetId);

				} else {
					node.expand();
				}
			};

			var saveFile = function() {
				var input = Ext.getCmp("filename");
				var value = input.getValue();

				if (value.trim().length === 0) {
					return;
				}

				var node = getSelectedNode();
				var parentNode = getParentNode(node);
				var added = null;

				parentNode.expand(false, false, function(parentNode) {
					var i;
                    for (i = 0; i < parentNode.childNodes.length; i++) {
                        var node = parentNode.childNodes[i];

                        if (value === node.text && node.leaf) {
                            Ext.Msg.show({
		                        modal: false,
		                        msg: TreeTranslations.namingConflictMessage,
		                        buttons: Ext.MessageBox.OK,
                                icon: Ext.MessageBox.INFO
		                    });

                            return;
                        }
                    }

                    added = parentNode.appendChild(new Ext.tree.AsyncTreeNode({
						text : value,
						iconCls : 'file',
						leaf : true
					}));

					// added.ensureVisible();
					added.select();

					input.setValue("");

					Ext.Ajax.request({
						url : getSaveUrl(),
						params : buildParams(added),
						success : function(response, options) {

				            var result = Ext.util.JSON.decode(response.responseText);
							var newId = result.documentId;

							var node = tree.getNodeById(options.params.node);

							node.attributes.id = newId;

							// not necessary, but more consistent:
							node.id = newId;

                            YAHOO.Bubbling.fire("/document/saved", {name: value});

 					        saveWindow.hide();
						}
					});


				});

			};

			var onNewFolderComplete = function(editor, value, startValue) {

				Ext.Ajax.request({
					url : "/document/tree/addFolder",
					params : buildParams(editor.editNode),
					success : function(response, options) {

						var result = Ext.util.JSON
								.decode(response.responseText);

						if (result.success) {
							var node = tree.getNodeById(result.oldId);

							node.attributes.id = result.newId;

							// not necessary, but more consistent:
							node.id = result.newId;
						}
					}
				});
			};

			/*
			 * Adapted from
			 * http://filetree.extjs.eu/source.php?file=js/Ext.ux.FileTreePanel.js
			 */
			var createNewFolder = function(node) {
				var parentNode = getParentNode(node);

				var folder;

				parentNode.expand(false, false, function(parent) {
					folder = parent.appendChild(new Ext.tree.AsyncTreeNode({
						text : TreeTranslations.createFolder,
						iconCls : 'folder'
					}));

					treeEditor.on({
						complete : {
							scope : this,
							single : true,
							fn : onNewFolderComplete
						}
					});

					folder.ensureVisible();
					folder.select();

					(function() {
						treeEditor.triggerEdit(folder);
					}).defer(10);
				}.createDelegate(this));

			};

			var deleteNode = function(node) {
				if ("source" !== node.attributes.id && !node.hasChildNodes()) {

					Ext.Ajax.request({
						url : "/document/tree/delete",
						params : buildParams(node),
						success : function(response, options) {
							node.remove();

							var result = Ext.util.JSON.decode(response.responseText);
							// reload if we're deleting the currently loaded
							// document.
							if (result.reload) {
							    B.BlissChart.fireNewChartCreated();
							}
						}
					});

				} else {
				    /* node has children */
				}
			};

			var onRenameNodeComplete = function(editor, value, startValue) {
				Ext.Ajax.request({
					url : "/document/tree/move",
					params : buildParams(editor.editNode)
				});
			};

			var renameNode = function(node) {

				treeEditor.on({
					complete : {
						scope : this,
						single : true,
						fn : onRenameNodeComplete
					}
				});

				(function() {
					treeEditor.triggerEdit(node);
				}).defer(0);
			};

			var saveBbar = [{
				xtype : "tbtext",
				text : TreeTranslations.saveAs
			}, " ", {
				xtype : "tbfilltextfield",
				scope : this,
				id : "filename"
			}," ",  {
				cls : 'x-btn-text-icon',
				text : TreeTranslations.save,
				icon : 'http://static.pictosys.se/famfamfam/silk/icons/disk.png',
				handler : saveFile
			}];

			var loadBbar = ["->", {
				cls : 'x-btn-text-icon',
				text : TreeTranslations.open,
				icon : 'http://static.pictosys.se/famfamfam/silk/icons/accept.png',
				handler : openFile
			}];

            var treeLoader = new Ext.tree.TreeLoader({
                    dataUrl : getExploreUrl()
            });

            /* Pass extra parameters to loader. */
            treeLoader.on("beforeload", function(loader, node) {
                loader.baseParams.type = getUrlKey();
            });

			var tree = new Ext.tree.TreePanel({
				// el : 'tree-div',
				animate : true,
				autoScroll : true,
				enableDD : true,
				width : 300,
				height : 350,
				dropConfig : {
					appendOnly : true
				},
				containerScroll : true,
				rootVisible : true, // can't move folders to root otherwise
				loader : treeLoader,
				tbar : [{
					cls : 'x-btn-text-icon',
					handler : function() {
						var node = getSelectedNode();
						createNewFolder(node);
					},
					icon : 'http://static.pictosys.se/famfamfam/silk/icons/folder_add.png',
					scope : this,
					text : TreeTranslations.createFolder
				}, {
					xtype : "tbseparator"
				}, {
					cls : 'x-btn-text-icon',
					icon : 'http://static.pictosys.se/famfamfam/silk/icons/pencil.png',
					scope : this,
					text : TreeTranslations.rename,
					id : "tbarRenameButton",
					handler : function() {
						var node = getSelectedNode();
						renameNode(node);
					}
				},

				{
					xtype : 'tbseparator'
				}, {
					cls : 'x-btn-text-icon',
					icon : 'http://static.pictosys.se/famfamfam/silk/icons/cross.png',
					scope : this,
					text : TreeTranslations.remove,
					disabled : true,
					id : "tbarRemoveButton",
					handler : function() {
						var node = getSelectedNode();
						deleteNode(node);
					}
				}],
				bbar : save ? saveBbar : loadBbar,
				listeners : {
					nodedrop : function(dropEvent) {
						var targetNode = dropEvent.target;
						var dropNode = dropEvent.dropNode;
						var parentNode = dropNode.parentNode;

						Ext.Ajax.request({
							url : "/document/tree/move",
							params : buildParams(dropNode)
						});

						return true;
					},
					dblclick : function(node, eventObject) {

						var sheetId = node.attributes.id;

						if (!save && node.isLeaf()) {
							loadWindow.hide();
							window.document.location.pathname = getLoadUrl(sheetId);
						}
					},
					beforeclick : function(node, eventObject) {

						/* prevent edit mode */
						return !node.isSelected();

						/*
						 * If edit on selection is to be enabled then you need
						 * to add a complete-listener on treeEditor.
						 */
					},
					click : function(node, eventObject) {

						var renameButton = Ext.getCmp("tbarRenameButton");
						if (node.id !== "source") {
							renameButton.enable();
						} else {
							renameButton.disable();
						}

						var removeButton = Ext.getCmp("tbarRemoveButton");
						if (!node.hasChildNodes()) {
							removeButton.enable();
						} else {
							removeButton.disable();
						}

					}
				}
			});

			// add a tree sorter in folder mode
			var treeSorter = new Ext.tree.TreeSorter(tree, {
				folderSort : true
			});

			var treeEditor = new Ext.tree.TreeEditor(tree, {
				allowBlank : false,
				cancelOnEsc : true,
				completeOnEnter : true,
				ignoreNoChange : true,
				selectOnFocus : true

			});

			treeEditor.on({
				beforestartedit : {
					fn : function(editor, el, value) {
						/* Don't allow renaming root node. */
						return editor.editNode.id !== "source";
					}
				}

			});

			tree.setRootNode(save ? saveRoot : loadRoot);

			// render the tree
			// tree.render();

			var extWindow = new Ext.Window({
				title : 'BlissOnline',
				closable : true,
				id : save ? 'saveSheet' : "loadSheet",
				closeAction : 'hide', // allows re-opening window
				width : 370,
				// height : 360,
				autoHeight : true,
				border : true,
				plain : false,
				layout : 'fit',
				items : tree,
				modal : false,
				tools : [{
					id : "refresh",
					handler : function(event, toolEl, panel) {
						(save ? saveRoot : loadRoot).reload();
					}
				}]

			});

			if (save) {
				saveWindow = extWindow;
			} else {
				loadWindow = extWindow;
			}
		},

		save : function() {
			if (!saveWindow) {
				this.createWindow(true);
			}
			this.hideLoadWindow();
			saveWindow.show();

			// saveRoot.expand(false, false);
			saveRoot.reload();
			setTimeout(function() {
				Ext.getCmp("filename").focus();
			}, 0);

		},

		load : function() {
			if (!loadWindow) {
				this.createWindow(false);
			}

			this.hideSaveWindow();
			loadWindow.show();
			// loadRoot.expand(false, false);
			loadRoot.reload();

		},

		hideSaveWindow : function() {
			if (saveWindow) {
				saveWindow.hide();
			}
		},

		hideLoadWindow : function() {
			if (loadWindow) {
				loadWindow.hide();
			}
		}
	};
};


Ext.onReady(function() {
    P.SheetTreePanel = new Ext.app.SheetTreePanel();
});
Ext.namespace("B");

(function() {

    Ext.form.Field.prototype.msgTarget = 'side';

    var form = null;
    var window = null;

    function PrintSettings() {
    }

    PrintSettings.prototype = {
        init : function() {
            var fieldset30 = new Ext.form.FieldSet( {
                title : "3x3 cm",
                autoHeight : true,
                defaultType : 'textfield',
                items : [

                {
                    fieldLabel : PrintSettingsTranslations.topMargin,
                    name : "margin3cmtop"
                }, {
                    fieldLabel : PrintSettingsTranslations.leftMargin,
                    name : "margin3cmleft"
                }

                ]

            });

            var fieldset50 = new Ext.form.FieldSet( {
                title : "5x5 cm",
                autoHeight : true,
                defaultType : 'textfield',
                items : [

                {
                    fieldLabel : PrintSettingsTranslations.topMargin,
                    name : "margin5cmtop"
                },

                {
                    fieldLabel : PrintSettingsTranslations.leftMargin,
                    name : "margin5cmleft"
                }

                ]

            });

            var help = new Ext.Panel(
                    {
                        border : false,
                        html : ("<p>" + PrintSettingsTranslations.dialogText1
                                + "</p><p>"
                                + PrintSettingsTranslations.dialogText2 + "</p>")
                    });

            form = new Ext.FormPanel( {
                frame : false,
                labelAlign : "right",
                title : null,
                border : true,
                labelWidth : 140,
                defaults : {
                    xtype : 'textfield'
                },
                bodyStyle : 'padding: 10px',

                items : [ help, fieldset30, fieldset50 ]
            });

            window = new Ext.Window( {
                title : 'BlissOnline',
                closable : true,
                bodyCssClass : "label-print-settings",
                closeAction : 'hide', // allows re-opening window
                width : 280,
                // height : 360,
                // autoHeight : true,
                border : true,
                plain : false,
                // layout : 'fit',
                items : [ form ],
                modal : false

            });

            function loadValues() {
                form.getForm().load( {
                    url : "/chart/print-settings/load"
                });
            }

            function saveValues() {
                form.getForm().submit( {
                    url : "/chart/print-settings/save"
                });
            }

            form.addButton(PrintSettingsTranslations.saveButton, saveValues);

            form.on('actioncomplete', function(form, action) {
                if ('submit' === action.type) {
                    window.hide();
                }
            });

            window.on("show", loadValues);

        },

        show : function() {
            window.show();
        }
    };

    B.PrintSettings = new PrintSettings();

    YAHOO.Bubbling.on('chart/changeDocumentType', function(name, array) {
        var params = array[1];

        if (params.documentType === "LABELS") {
            Ext.fly("sheet-settings").setDisplayed(true);
        } else {
            Ext.fly("sheet-settings").setDisplayed(false);

        }

    }, B.PrintSettings);

})();
Ext.namespace("B");

(function() {

    var store = new Ext.data.JsonStore( {
        url : '/public/glosskey/list/autocompleteGloss',
        root : 'data',
        fields : [ 'text', 'id', 'uuid', "glossKeyName", "symbolName" ],
        totalProperty :'totalCount',
        remoteSort : true
    });

    
    function GlossKeyAutoComplete(inputId, listeners, overrideOptions) {
        var options = {
            store : store,
            displayField : 'text',
            valueField : 'glossKeyName',
            typeAhead : true,
            mode : 'remote',
            queryParam : 'autocomplete',
            hideTrigger : true,
            selectOnFocus : true,
            minChars: 1,
            pageSize: 10,
            applyTo : inputId,
            tpl : '<tpl for="."><div class="x-combo-list-item symbol-autocomplete-item"><img src="/images/single/jpeg/sv/none/white/60/{uuid}/{glossKeyName}/"></img>{text} <span class="symbol-name">({symbolName})</span></div></tpl>'
        };
        
        if (overrideOptions) {
            options = Ext.apply(options, overrideOptions);
        }
        
        var combo = new Ext.form.ComboBox(options);
        
        if (listeners) {
            for (key in listeners) {
                combo.on(key, listeners[key]);
            }
        }

    }

    B.GlossKeyAutoComplete = GlossKeyAutoComplete;
}());
Ext.namespace("B");

(function() {

    function Pinger() {
    }

    Pinger.prototype = {
        init : function() {
            var task = {
                run : B.Pinger.ping,
                interval : 20 * 60 * 1000,
                scope : B.Pinger
            };

            Ext.TaskMgr.start(task);
        },

        ping : function() {
            if (B.TestMode.isLoggedIn()) {
                this.checkSession();
            }
        },

        checkSession : function() {

            Ext.Ajax.request( {
                url : "/session/session",
                method : "POST",
                success : function(response, options) {

                    var json = Ext.decode(response.responseText);

                    if (!json.success) {
                        return;
                    }

                    if (B.TestMode.isLoggedIn() && !json.loggedIn) {

                        B.QuickNotification.formatMessage(
                                SessionTranslations.sessionExpiredHeader,
                                SessionTranslations.sessionExpiredText);

                        (function() {
                            window.location = "/";
                        }).defer(5000);

                    }

                }
            });

        }

    };

    B.Pinger = new Pinger();

    Ext.onReady(B.Pinger.init, B.Pinger);

})();
Ext.namespace("B");

(function() {

    function QuickSuggest() {
    }

    QuickSuggest.prototype = {
        init : function() {
            reg.click("input.missing-word-suggest", function() {

                var missingWordText = Ext.get(this).up("div").select(
                        "input.missing-word-text").elements.first();

                if (missingWordText.value.length > 0) {
                    Ext.Ajax.request( {
                        url : "/contact/suggest",
                        params : {
                            missingWord : missingWordText.value
                        },
                        success : function() {
                            Ext.fly("missing-word-complete").setDisplayed(true).highlight("#ffffff");
                            missingWordText.value = "";
                            missingWordText.focus();

                        }
                    });
                }

                return false;
            });
        }

    };

    B.QuickSuggest = new QuickSuggest();

})();