<commit_before>/**
 * Arcadia is a full-width image gallery with a variety of control types,
 * including thumbnails, next and previous buttons, and a play/pause control to
 * make the gallery rotate without further user input.
 */
Arcadia = new JS.Class('Arcadia', {
    include: [JS.State, Ojay.Observable],

    initialize: function(container, json) {
        var x = 0, y = 0;

        this._container = Ojay(container);
        this._viewport  = Ojay(Ojay.HTML.div({className: 'viewport'}));

        this._container.children().remove()
        ._(this._container).insert(this._viewport, 'after')
        ._(this._viewport).setContent(this._container);

        this._centre = Math.floor((json.images.length - 1) / 2);
        this._left   = 0;

        this._items = new this.klass.ModNList(json.images.map(function(img, i) {
            var item = new this.klass.Item(this, img);

            if (i !== this._centre) {
                item.on('ready', function() {
                    item.hide({animate: false});
                });
            }

            this._container.insert(item.getHTML(), 'bottom');

            item.getHTML().on('click', function() {
                this.centreOn(item);
            }, this);

            x += img.width;

            if (img.height > y) {
                y = img.height;
            }

            return item;
        }, this));

        this._viewport.setStyle({
            position: 'relative',
            height:   y + 'px'
        });

        this._container.setStyle({
            width:    x + 'px',
            height:   y + 'px',
            position: 'absolute',
            top:      0,
            left:     this.getOffset() + 'px'
        });

        Ojay(window).on('resize', this.fitToViewport, this);

        this.setState('READY');
    },

    addControls: function(klass) {
        return new (klass || this.klass.Controls.Thumbnails)(this);
    },

    getItems: function() {
        return this._items;
    },

    getCentre: function() {
        return this._items.at(this._centre);
    },

    _balance: function(centre) {
        var oldLeft, newLeft, splicees, shiftRight, offset;

        oldLeft = this._left;
        newLeft = this._items.mod(oldLeft + centre - this._centre);

        if (oldLeft > this._centre) {
            shiftRight = centre < this._centre || centre >= oldLeft;
        } else {
            shiftRight = centre < this._centre && centre >= oldLeft;
        }

        if (shiftRight) {
            splicees = this._items.slice(newLeft, oldLeft);
            offset   = this._spliceLeft(splicees.reverse());
        } else {
            splicees = this._items.slice(oldLeft, newLeft);
            offset   = this._spliceRight(splicees);
        }

        this._container.setStyle({
            left: (this.getOffset() - offset) + 'px'
        });

        this._left = newLeft;
    },

    _spliceRight: function(items) {
        return items.reduce(function(offset, item) {
            this._container.insert(item.getHTML(), 'bottom');
            return offset - item.getWidth();
        }.bind(this), 0);
    },

    _spliceLeft: function(items) {
        return items.reduce(function(offset, item) {
            this._container.insert(item.getHTML(), 'top');
            return offset + item.getWidth();
        }.bind(this), 0);
    },

    getOffset: function() {
        var portWidth, leftWidth, currentWidth, offset;

        portWidth    = this._viewport.getWidth();
        leftWidth    = this.getLeftWidth();
        currentWidth = this.getCentre().getWidth();
        offset       = Math.floor(((portWidth - currentWidth) / 2) - leftWidth);

        return offset;
    },

    getLeftWidth: function() {
        return this._items.slice(this._left, this._centre).reduce(function(width, item) {
            return width + item.getWidth();
        }, 0);
    },

    getHTML: function() {
        return this._viewport;
    },

    states: {
        /**
         * In this state the gallery is able to accept user input and change
         * which item is centred.
         */
        READY: {
            centreOn: function(centre) {
                if (centre === this._centre || centre === this.getCentre()) return;

                if (typeof centre !== 'number') {
                    centre = this._items.indexOf(centre);

                    if (centre < 0) return;
                }

                this.setState('ANIMATING');
                this.notifyObservers('centreStart', this._items.at(centre));

                this._balance(centre);
                this.getCentre().hide();
                this._centre = centre;

                this._container.animate({
                    left: {
                        to: this.getOffset()
                    }
                }, 0.8)
                ._(this._items.at(centre)).show()
                ._(this).setState('READY')
                ._(this).notifyObservers('centreEnd', this.getCentre())
                ._(this).notifyObservers('centre', this.getCentre());
            },

            next: function() {
                this.centreOn(this._items.add(this._centre, 1));
            },

            previous: function() {
                this.centreOn(this._items.subtract(this._centre, 1));
            },

            fitToViewport: function() {
                this._container.setStyle({left: this.getOffset() + 'px'});
            }
        },

        /**
         * When the gallery is animating, it should respond only to requests
         * that don't affect the state of the gallery.
         */
        ANIMATING: {}
    },

    extend: {
        ModNList: new JS.Class('ModNList', {
            initialize: function(items) {
                this._store = items || [];
            },

            n: function() {
                return this._store.length;
            },

            at: function(i) {
                return this._store[this.mod(i)];
            },

            mod: function(a) {
                var n = this._store.length, m = a % n;
                return m < 0 ? n + m : m;
            },

            add: function(a, b) {
                return this.mod(a + b);
            },

            subtract: function(a, b) {
                return this.mod(a - b);
            },

            indexOf: function(element, from) {
                return this._store.indexOf(element, from);
            },

            slice: function(start, end) {
                var s1, s2, sliced;

                start = this.mod(start);
                end   = this.mod(end);

                if (start > end) {
                    s1     = this._store.slice(start);
                    s2     = this._store.slice(0, end);
                    sliced = s1.concat(s2);
                } else {
                    sliced = this._store.slice(start, end);
                }

                return sliced;
            },

            forEach: function(block, context) {
                return this._store.forEach(block, context);
            },

            map: function(block, context) {
                return this._store.map(block, context);
            },

            reduce: function(block, context) {
                return this._store.reduce(block, context);
            }
        }),

        Item: new JS.Class({
            include: Ojay.Observable,

            initialize: function(gallery, spec) {
                this._gallery = gallery;
                this._spec    = spec;
            },

            getHTML: function() {
                if (this._html) return this._html;

                var self = this;
                self._html = Ojay(Ojay.HTML.div({className: 'item'}, function(H) {
                    self._image = Ojay(H.img({
                        alt: self._spec.name,
                        src: self._spec.uri
                    }));

                    self._descWrapper = Ojay(H.div({className: 'description-wrapper'}, function(W) {
                        self._descToggle  = Ojay(W.div({className: 'description-toggle'}, 'More'));
                        self._description = Ojay(W.div({className: 'description'}, self._spec.description));
                    }));
                }));

                this._html.setStyle({
                    width:    this._spec.width  + 'px',
                    height:   this._spec.height + 'px',
                    overflow: 'hidden',
                    position: 'relative'
                });

                this._html.on('DOMNodeInserted', this.setup, this);

                return this._html;
            },

            getThumbnail: function() {
                if (this._thumbnail) return this._thumbnail;

                var self = this;
                self._thumbnail = Ojay(Ojay.HTML.div({className: 'thumbnail'}, function(H) {
                    H.img({
                        alt: self._name,
                        src: self._spec.thumbnail.uri
                    });
                }))
                .setStyle({
                    width:  self._spec.thumbnail.width  + 'px',
                    height: self._spec.thumbnail.height + 'px'
                });

                return this._thumbnail;
            },

            getWidth: function() {
                return this._spec.width;
            },

            collapseDescription: function() {
                this._toggleDescription(this._descMaxHeight, this._descMinHeight, 'More');
            },

            expandDescription: function() {
                this._toggleDescription(this._descMinHeight, this._descMaxHeight, 'Close');
            },

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

                this.getHTML().addClass('current');

                if (options.animate !== false) {
                    this._descWrapper.show().animate({
                        opacity: {
                            from: 0,
                            to:   1
                        }
                    }, 0.4);
                } else {
                    this._descWrapper.setStyle({opacity: 1}).show();
                }
            },

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

                this.getHTML().removeClass('current');

                if (options.animate !== false) {
                    this._descWrapper.animate({
                        opacity: {
                            from: 1,
                            to:   0
                        }
                    }, 0.4).hide();
                } else {
                    this._descWrapper.setStyle({opacity: 0}).hide();
                }
            },

            setup: function() {
                if (this._descriptionHeightFixed) return;

                setTimeout(function() {
                    this._descMaxHeight = this._descWrapper.getHeight();
                    this._description.hide();
                    this._descMinHeight = this._descWrapper.getHeight();

                    this._descWrapper.setStyle({
                        position: 'absolute',
                        left:     0,
                        bottom:   0,
                        width:    this._spec.width + 'px',
                        height:   this._descMinHeight + 'px',
                        overflow: 'hidden'
                    });

                    this._description.show();

                    this._descriptionCollapsed   = true;
                    this._descriptionHeightFixed = true;

                    this._descToggle.on('click', function(el, evnt) {
                        this[this._descriptionCollapsed ? 'expandDescription' : 'collapseDescription']();
                    }, this);

                    this.notifyObservers('ready', this);
                }.bind(this), 10);
            },

            _toggleDescription: function(startHeight, finishHeight, toggleText) {
                this._descWrapper.animate({
                    height: {
                        from: startHeight,
                        to:   finishHeight
                    }
                }, 0.3)
                ._(this._descToggle).setContent(toggleText)
                ._(function() {
                    this._descriptionCollapsed = !this._descriptionCollapsed;
                }.bind(this));
            }
        }),

        Controls: {
            Thumbnails: new JS.Class('Arcadia.Controls.Thumbnails', {
                initialize: function(gallery) {
                    this._gallery = gallery;
                },

                getHTML: function() {
                    if (this._html) return this._html;

                    this._html = Ojay(Ojay.HTML.div({className: 'arcadia-thumbnails'}));

                    this._gallery.getItems().forEach(function(item) {
                        var thumb = item.getThumbnail();

                        this._html.insert(thumb, 'bottom');

                        thumb.on('click', function() {
                            this._gallery.centreOn(item);
                        }, this);
                    }, this);

                    return this._html;
                }
            }),

            Play: new JS.Class('Arcadia.Controls.Play', {
                initialize: function(gallery) {
                    this._gallery = gallery;
                    this._playing = false;
                    this._timer   = null;
                },

                play: function() {
                    this._timer = setInterval(function() {
                        this._gallery.next();
                    }.bind(this), 3000);

                    this._gallery.next();

                    if (this._html) {
                        this._html.replaceClass('paused', 'playing').setContent('Pause');
                    }

                    this._playing = true;
                },

                pause: function() {
                    clearInterval(this._timer);

                    if (this._html) {
                        this._html.replaceClass('playing', 'paused').setContent('Play');
                    }

                    this._playing = false;
                },

                toggle: function() {
                    this[this._playing ? 'pause' : 'play']();
                },

                getHTML: function() {
                    if (this._html) return this._html;

                    this._html = Ojay(Ojay.HTML.div({
                        className: 'arcadia-play-button ' + (this._playing ? 'playing' : 'paused')
                    }, (this._playing ? 'Pause' : 'Play')));

                    this._html.on('click', this.toggle, this);

                    return this._html;
                }
            }),

            Next: new JS.Class('Arcadia.Controls.Next', {
                initialize: function(gallery) {
                    this._gallery = gallery;
                },

                previous: function() {
                    this._gallery.previous();
                },

                next: function() {
                    this._gallery.next();
                },

                getHTML: function() {
                    if (this._html) return this._html;

                    var self = this;
                    self._html = Ojay(Ojay.HTML.div({className: 'arcadia-next-previous'}, function(H) {
                        self._previous = Ojay(H.span({className: 'previous'}, 'Previous'));
                        self._next     = Ojay(H.span({className: 'next'}, 'Next'));
                    }));

                    this._previous.on('click', this.previous, this);
                    this._next.on('click', this.next, this);

                    return this._html;
                },

                getPrevious: function() {
                    return this._previous;
                },

                getNext: function() {
                    return this._next;
                },

                getGallery: function() {
                    return this._gallery;
                }
            })
        }
    }
});
<commit_msg>Better gallery width API: generic getWidth method which accepts a start and end point, getLeftWidth method which uses getWidth, and new getRightWidth method which also uses getWidth.<commit_after>/**
 * Arcadia is a full-width image gallery with a variety of control types,
 * including thumbnails, next and previous buttons, and a play/pause control to
 * make the gallery rotate without further user input.
 */
Arcadia = new JS.Class('Arcadia', {
    include: [JS.State, Ojay.Observable],

    initialize: function(container, json) {
        var x = 0, y = 0;

        this._container = Ojay(container);
        this._viewport  = Ojay(Ojay.HTML.div({className: 'viewport'}));

        this._container.children().remove()
        ._(this._container).insert(this._viewport, 'after')
        ._(this._viewport).setContent(this._container);

        this._centre = Math.floor((json.images.length - 1) / 2);
        this._left   = 0;

        this._items = new this.klass.ModNList(json.images.map(function(img, i) {
            var item = new this.klass.Item(this, img);

            if (i !== this._centre) {
                item.on('ready', function() {
                    item.hide({animate: false});
                });
            }

            this._container.insert(item.getHTML(), 'bottom');

            item.getHTML().on('click', function() {
                this.centreOn(item);
            }, this);

            x += img.width;

            if (img.height > y) {
                y = img.height;
            }

            return item;
        }, this));

        this._viewport.setStyle({
            position: 'relative',
            height:   y + 'px'
        });

        this._container.setStyle({
            width:    x + 'px',
            height:   y + 'px',
            position: 'absolute',
            top:      0,
            left:     this.getOffset() + 'px'
        });

        Ojay(window).on('resize', this.fitToViewport, this);

        this.setState('READY');
    },

    addControls: function(klass) {
        return new (klass || this.klass.Controls.Thumbnails)(this);
    },

    getItems: function() {
        return this._items;
    },

    getCentre: function() {
        return this._items.at(this._centre);
    },

    _balance: function(centre) {
        var oldLeft, newLeft, splicees, shiftRight, offset;

        oldLeft = this._left;
        newLeft = this._items.mod(oldLeft + centre - this._centre);

        if (oldLeft > this._centre) {
            shiftRight = centre < this._centre || centre >= oldLeft;
        } else {
            shiftRight = centre < this._centre && centre >= oldLeft;
        }

        if (shiftRight) {
            splicees = this._items.slice(newLeft, oldLeft);
            offset   = this._spliceLeft(splicees.reverse());
        } else {
            splicees = this._items.slice(oldLeft, newLeft);
            offset   = this._spliceRight(splicees);
        }

        this._container.setStyle({
            left: (this.getOffset() - offset) + 'px'
        });

        this._left = newLeft;
    },

    _spliceRight: function(items) {
        return items.reduce(function(offset, item) {
            this._container.insert(item.getHTML(), 'bottom');
            return offset - item.getWidth();
        }.bind(this), 0);
    },

    _spliceLeft: function(items) {
        return items.reduce(function(offset, item) {
            this._container.insert(item.getHTML(), 'top');
            return offset + item.getWidth();
        }.bind(this), 0);
    },

    getOffset: function() {
        var portWidth, leftWidth, currentWidth, offset;

        portWidth    = this._viewport.getWidth();
        leftWidth    = this.getLeftWidth();
        currentWidth = this.getCentre().getWidth();
        offset       = Math.floor(((portWidth - currentWidth) / 2) - leftWidth);

        return offset;
    },

    getWidth: function(start, end) {
        return this._items.slice(start || 0, end).reduce(function(width, item) {
            return width + item.getWidth();
        }, 0);
    },

    getLeftWidth: function() {
        return this.getWidth(this._left, this._centre);
    },

    getRightWidth: function() {
        return this.getWidth(this._centre + 1, this._left);
    },

    getHTML: function() {
        return this._viewport;
    },

    states: {
        /**
         * In this state the gallery is able to accept user input and change
         * which item is centred.
         */
        READY: {
            centreOn: function(centre) {
                if (centre === this._centre || centre === this.getCentre()) return;

                if (typeof centre !== 'number') {
                    centre = this._items.indexOf(centre);

                    if (centre < 0) return;
                }

                this.setState('ANIMATING');
                this.notifyObservers('centreStart', this._items.at(centre));

                this._balance(centre);
                this.getCentre().hide();
                this._centre = centre;

                this._container.animate({
                    left: {
                        to: this.getOffset()
                    }
                }, 0.8)
                ._(this._items.at(centre)).show()
                ._(this).setState('READY')
                ._(this).notifyObservers('centreEnd', this.getCentre())
                ._(this).notifyObservers('centre', this.getCentre());
            },

            next: function() {
                this.centreOn(this._items.add(this._centre, 1));
            },

            previous: function() {
                this.centreOn(this._items.subtract(this._centre, 1));
            },

            fitToViewport: function() {
                this._container.setStyle({left: this.getOffset() + 'px'});
            }
        },

        /**
         * When the gallery is animating, it should respond only to requests
         * that don't affect the state of the gallery.
         */
        ANIMATING: {}
    },

    extend: {
        ModNList: new JS.Class('ModNList', {
            initialize: function(items) {
                this._store = items || [];
            },

            n: function() {
                return this._store.length;
            },

            at: function(i) {
                return this._store[this.mod(i)];
            },

            mod: function(a) {
                var n = this._store.length, m = a % n;
                return m < 0 ? n + m : m;
            },

            add: function(a, b) {
                return this.mod(a + b);
            },

            subtract: function(a, b) {
                return this.mod(a - b);
            },

            indexOf: function(element, from) {
                return this._store.indexOf(element, from);
            },

            slice: function(start, end) {
                var s1, s2, sliced;

                if (!(start || end)) return this._store;

                start = this.mod(start);
                end   = typeof end === 'number' && end !== this.n() ? this.mod(end) : this.n();

                if (start > end) {
                    s1     = this._store.slice(start);
                    s2     = this._store.slice(0, end);
                    sliced = s1.concat(s2);
                } else {
                    sliced = this._store.slice(start, end);
                }

                return sliced;
            },

            forEach: function(block, context) {
                return this._store.forEach(block, context);
            },

            map: function(block, context) {
                return this._store.map(block, context);
            },

            reduce: function(block, context) {
                return this._store.reduce(block, context);
            }
        }),

        Item: new JS.Class({
            include: Ojay.Observable,

            initialize: function(gallery, spec) {
                this._gallery = gallery;
                this._spec    = spec;
            },

            getHTML: function() {
                if (this._html) return this._html;

                var self = this;
                self._html = Ojay(Ojay.HTML.div({className: 'item'}, function(H) {
                    self._image = Ojay(H.img({
                        alt: self._spec.name,
                        src: self._spec.uri
                    }));

                    self._descWrapper = Ojay(H.div({className: 'description-wrapper'}, function(W) {
                        self._descToggle  = Ojay(W.div({className: 'description-toggle'}, 'More'));
                        self._description = Ojay(W.div({className: 'description'}, self._spec.description));
                    }));
                }));

                this._html.setStyle({
                    width:    this._spec.width  + 'px',
                    height:   this._spec.height + 'px',
                    overflow: 'hidden',
                    position: 'relative'
                });

                this._html.on('DOMNodeInserted', this.setup, this);

                return this._html;
            },

            getThumbnail: function() {
                if (this._thumbnail) return this._thumbnail;

                var self = this;
                self._thumbnail = Ojay(Ojay.HTML.div({className: 'thumbnail'}, function(H) {
                    H.img({
                        alt: self._name,
                        src: self._spec.thumbnail.uri
                    });
                }))
                .setStyle({
                    width:  self._spec.thumbnail.width  + 'px',
                    height: self._spec.thumbnail.height + 'px'
                });

                return this._thumbnail;
            },

            getWidth: function() {
                return this._spec.width;
            },

            collapseDescription: function() {
                this._toggleDescription(this._descMaxHeight, this._descMinHeight, 'More');
            },

            expandDescription: function() {
                this._toggleDescription(this._descMinHeight, this._descMaxHeight, 'Close');
            },

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

                this.getHTML().addClass('current');

                if (options.animate !== false) {
                    this._descWrapper.show().animate({
                        opacity: {
                            from: 0,
                            to:   1
                        }
                    }, 0.4);
                } else {
                    this._descWrapper.setStyle({opacity: 1}).show();
                }
            },

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

                this.getHTML().removeClass('current');

                if (options.animate !== false) {
                    this._descWrapper.animate({
                        opacity: {
                            from: 1,
                            to:   0
                        }
                    }, 0.4).hide();
                } else {
                    this._descWrapper.setStyle({opacity: 0}).hide();
                }
            },

            setup: function() {
                if (this._descriptionHeightFixed) return;

                setTimeout(function() {
                    this._descMaxHeight = this._descWrapper.getHeight();
                    this._description.hide();
                    this._descMinHeight = this._descWrapper.getHeight();

                    this._descWrapper.setStyle({
                        position: 'absolute',
                        left:     0,
                        bottom:   0,
                        width:    this._spec.width + 'px',
                        height:   this._descMinHeight + 'px',
                        overflow: 'hidden'
                    });

                    this._description.show();

                    this._descriptionCollapsed   = true;
                    this._descriptionHeightFixed = true;

                    this._descToggle.on('click', function(el, evnt) {
                        this[this._descriptionCollapsed ? 'expandDescription' : 'collapseDescription']();
                    }, this);

                    this.notifyObservers('ready', this);
                }.bind(this), 10);
            },

            _toggleDescription: function(startHeight, finishHeight, toggleText) {
                this._descWrapper.animate({
                    height: {
                        from: startHeight,
                        to:   finishHeight
                    }
                }, 0.3)
                ._(this._descToggle).setContent(toggleText)
                ._(function() {
                    this._descriptionCollapsed = !this._descriptionCollapsed;
                }.bind(this));
            }
        }),

        Controls: {
            Thumbnails: new JS.Class('Arcadia.Controls.Thumbnails', {
                initialize: function(gallery) {
                    this._gallery = gallery;
                },

                getHTML: function() {
                    if (this._html) return this._html;

                    this._html = Ojay(Ojay.HTML.div({className: 'arcadia-thumbnails'}));

                    this._gallery.getItems().forEach(function(item) {
                        var thumb = item.getThumbnail();

                        this._html.insert(thumb, 'bottom');

                        thumb.on('click', function() {
                            this._gallery.centreOn(item);
                        }, this);
                    }, this);

                    return this._html;
                }
            }),

            Play: new JS.Class('Arcadia.Controls.Play', {
                initialize: function(gallery) {
                    this._gallery = gallery;
                    this._playing = false;
                    this._timer   = null;
                },

                play: function() {
                    this._timer = setInterval(function() {
                        this._gallery.next();
                    }.bind(this), 3000);

                    this._gallery.next();

                    if (this._html) {
                        this._html.replaceClass('paused', 'playing').setContent('Pause');
                    }

                    this._playing = true;
                },

                pause: function() {
                    clearInterval(this._timer);

                    if (this._html) {
                        this._html.replaceClass('playing', 'paused').setContent('Play');
                    }

                    this._playing = false;
                },

                toggle: function() {
                    this[this._playing ? 'pause' : 'play']();
                },

                getHTML: function() {
                    if (this._html) return this._html;

                    this._html = Ojay(Ojay.HTML.div({
                        className: 'arcadia-play-button ' + (this._playing ? 'playing' : 'paused')
                    }, (this._playing ? 'Pause' : 'Play')));

                    this._html.on('click', this.toggle, this);

                    return this._html;
                }
            }),

            Next: new JS.Class('Arcadia.Controls.Next', {
                initialize: function(gallery) {
                    this._gallery = gallery;
                },

                previous: function() {
                    this._gallery.previous();
                },

                next: function() {
                    this._gallery.next();
                },

                getHTML: function() {
                    if (this._html) return this._html;

                    var self = this;
                    self._html = Ojay(Ojay.HTML.div({className: 'arcadia-next-previous'}, function(H) {
                        self._previous = Ojay(H.span({className: 'previous'}, 'Previous'));
                        self._next     = Ojay(H.span({className: 'next'}, 'Next'));
                    }));

                    this._previous.on('click', this.previous, this);
                    this._next.on('click', this.next, this);

                    return this._html;
                },

                getPrevious: function() {
                    return this._previous;
                },

                getNext: function() {
                    return this._next;
                },

                getGallery: function() {
                    return this._gallery;
                }
            })
        }
    }
});
<|endoftext|>


<commit_before>var volume;

function save(vol){
	chrome.storage.local.set({volume:vol});
}

function place(xhr, iframes, i){
	var iframe = iframes[i];
	var result = xhr.responseText;
	var alex = result.match(/source src\="([^"]+)/)[1]; //He asked me to put him in my code.

	var newVid = document.createElement("video");
	newVid.src = alex;
	newVid.volume = volume;
	newVid.className = "htmlVid";
	newVid.setAttribute("controls","controls");
	newVid.addEventListener("volumechange", function(){save(newVid.volume)});
	newVid.addEventListener("click", function(){if(newVid.paused){newVid.play();}else{newVid.pause();}});
	var cont = iframe.parentElement;
	cont.insertBefore(newVid, cont.childNodes[0]);
	iframes[i].remove();
}

function getSrc(iframes, i){
	var iframe = iframes[i];
	var xhr = new XMLHttpRequest();
	xhr.open("GET", iframe.src, true);
	xhr.onload = function (){place(this, iframes, i);};
	xhr.send(null);
}

function everything(){
	var iframes = document.querySelectorAll("iframe.tumblr_video_iframe");
	var numFrames = iframes.length;
	for (var i = 0; i < numFrames; i++) {
		getSrc(iframes, i);
	}

}

function repeat(items){
	volume = items.volume;
	everything();
	setInterval(everything, 100);
}

var hostname = location.hostname;
hostname = hostname.match(/tumblr\.com/)[0];
if(hostname == "tumblr.com"){
	chrome.storage.local.get({volume:.4}, repeat);
}<commit_msg>Added conditional code for video and audio replacement on dashboard.<commit_after>var volume;

function save(vol){
	chrome.storage.local.set({volume:vol});
}

function place(xhr, iframes, i){
	var iframe = iframes[i];
	var result = xhr.responseText;
	var alex = result.match(/source src\="([^"]+)/)[1]; //He asked me to put him in my code.

	var newVid = document.createElement("video");
	newVid.src = alex;
	newVid.volume = volume;
	newVid.className = "htmlVid";
	newVid.setAttribute("controls","controls");
	newVid.addEventListener("volumechange", function(){save(newVid.volume)});
	newVid.addEventListener("click", function(){if(newVid.paused){newVid.play();}else{newVid.pause();}});
	var cont = iframe.parentElement;
	cont.insertBefore(newVid, cont.childNodes[0]);
	iframes[i].remove();
}

function getSrc(iframes, i){
	var iframe = iframes[i];
	var xhr = new XMLHttpRequest();
	xhr.open("GET", iframe.src, true);
	xhr.onload = function (){place(this, iframes, i);};
	xhr.send(null);
}

function everything(){
	var iframes = document.querySelectorAll("iframe.tumblr_video_iframe");
	var numFrames = iframes.length;
	for (var i = 0; i < numFrames; i++) {
		getSrc(iframes, i);
	}

}

function repeat(items){
	volume = items.volume;
	everything();
	setInterval(everything, 100);
}

function dashReplace(items){
	volume = items.volume;
	setInterval(function(){
	var sources = document.querySelectorAll("source");
	for(var i = 0; i < sources.length; i++){
		var source = sources[i];
		if(source.className == "audio-source"){
			var newAud = document.createElement("audio");
			newAud.src = source.src;
			newAud.volume = volume;
			newAud.setAttribute("controls","controls");
			var cont = source.parentElement.parentElement.parentElement.parentElement;
			cont.insertBefore(newAud, cont.childNodes[0]);
			source.parentElement.parentElement.parentElement.remove();
		}else{
			var newVid = document.createElement("video");
			newVid.src = source.src;
			newVid.volume = volume;
			newVid.className = "htmlVid";
			newVid.setAttribute("controls","controls");
			newVid.addEventListener("volumechange", function(){save(newVid.volume)});
			newVid.addEventListener("click", function(){if(newVid.paused){newVid.play();}else{newVid.pause();}});
			var cont = source.parentElement.parentElement.parentElement;
			cont.insertBefore(newVid, cont.childNodes[0]);
			source.parentElement.parentElement.remove();
		}
	}}, 200);
}
var hostname = location.hostname;
hostname = hostname.match(/tumblr\.com/)[0];
if(location.href == "https://www.tumblr.com/dashboard"){
	chrome.storage.local.get({volume:.4}, dashReplace);
}
else if(hostname == "tumblr.com"){
	chrome.storage.local.get({volume:.4}, repeat);
}<|endoftext|>


<commit_before>import React from 'react';

import HIT_TYPES from 'game/HIT_TYPES';

import SpellLink from 'common/SpellLink';
import SPELLS from 'common/SPELLS';
import { formatPercentage } from 'common/format';

import Analyzer, { SELECTED_PLAYER } from 'parser/core/Analyzer';
import Events from 'parser/core/Events';
import calculateEffectiveHealing from 'parser/core/calculateEffectiveHealing';
import StatTracker from 'parser/shared/modules/StatTracker';
import CritEffectBonus from 'parser/shared/modules/helpers/CritEffectBonus';
import StatisticListBoxItem from 'interface/others/StatisticListBoxItem';

const HEAL_WINDOW_MS = 150;
const bounceReduction = 0.7;

/**
 * High Tide:
 * Every 40000 mana you spend brings a High Tide, making your next 2 Chain Heals heal for an additional 20% and not reduce with each jump.
 */

class HighTide extends Analyzer {
  static dependencies = {
    statTracker: StatTracker,
    critEffectBonus: CritEffectBonus,
  };
  healing = 0;
  chainHealTimestamp = 0;

  buffer = [];

  constructor(...args) {
    super(...args);
    this.active = this.selectedCombatant.hasTalent(SPELLS.HIGH_TIDE_TALENT.id);

    this.addEventListener(Events.heal.by(SELECTED_PLAYER).spell(SPELLS.CHAIN_HEAL), this.chainHeal);
    this.addEventListener(Events.fightend, this.onFightEnd);
  }

  chainHeal(event) {
    const hasHighTide = this.selectedCombatant.hasBuff(SPELLS.HIGH_TIDE_BUFF.id);
    if (!hasHighTide) {
      return;
    }

    // Detects new chain heal casts, can't use the cast event for this as its often somewhere in between its healing events
    if (!this.chainHealTimestamp || event.timestamp - this.chainHealTimestamp > HEAL_WINDOW_MS) {
      this.processBuffer();
      this.chainHealTimestamp = event.timestamp;
    }

    /**
     * Due to how Chain Heal interacts with the combatlog, we have to take a lot of extra steps here.
     * Issues:
     * 1. The healing events are backwards [4,3,2,1]
     * 2. If the Shaman heals himself, his healing event is always first [3,4,2,1] (3 = Shaman)
     * 3. If 2. happens, the heal on the shaman is also happening before the cast event, which the lines above already deal with.
     *
     * Calculating out High Tide requires us to know the exact jump order, as High Tide affects each jump differently.
     * https://ancestralguidance.com/hidden-spell-mechanics/
     * The solution is to reorder the events into the correct hit order, which could be done since each consecutive heal is weaker
     * than the one beforehand (by 30%), except, you have the Shaman mastery which will result in random healing numbers
     * as each hit has a different mastery effectiveness - the higher the Shamans mastery, the more rapidly different the numbers end up.
     * With traits like https://www.wowhead.com/spell=277942/ancestral-resonance existing, shamans mastery can randomly double or triple mid combat.
     *
     * So we take 1 cast of chain heal at a time (4 hits maximum), calculate out crits and the mastery bonus, reorder them according to the new values
     * (High healing to Low healing or [4,3,2,1] to [1,2,3,4]) and get the High Tide contribution by comparing the original heal values against
     * what a non-High Tide Chain Heal would have done each bounce.
     *
     * Things that are able to break the sorting: Deluge (Pls don't take it) as its undetectable, random player-based heal increases
     * (possibly encounter mechanics) if not accounted for.
     */
    let heal = event.amount + (event.absorbed || 0) + (event.overheal || 0);
    if (event.hitType === HIT_TYPES.CRIT) {
      const critMult = this.critEffectBonus.getBonus(event);
      heal /= critMult;
    }
    const currentMastery = this.statTracker.currentMasteryPercentage;
    const masteryEffectiveness = Math.max(0, 1 - (event.hitPoints - event.amount) / event.maxHitPoints);
    const baseHealingDone = heal / (1 + currentMastery * masteryEffectiveness);

    this.buffer.push({
      baseHealingDone: baseHealingDone,
      ...event,
    });
  }

  processBuffer() {
    this.buffer.sort((a, b) => parseFloat(b.baseHealingDone) - parseFloat(a.baseHealingDone));

    for (const [index, event] of Object.entries(this.buffer)) {
      // 20%, 71%, 145%, 250% increase per hit over not having High Tide
      const FACTOR_CONTRIBUTED_BY_HT_HIT = (SPELLS.HIGH_TIDE_BUFF.coefficient) / (SPELLS.CHAIN_HEAL.coefficient * bounceReduction ** index) - 1;

      this.healing += calculateEffectiveHealing(event, FACTOR_CONTRIBUTED_BY_HT_HIT);
    }
    this.buffer = [];
  }

  onFightEnd() {
    this.processBuffer();
  }

  subStatistic() {
    return (
      <StatisticListBoxItem
        title={<SpellLink id={SPELLS.HIGH_TIDE_TALENT.id} />}
        value={`${formatPercentage(this.owner.getPercentageOfTotalHealingDone(this.healing))} %`}
      />
    );
  }
}

export default HighTide;

<commit_msg>Update HighTide.js<commit_after>import React from 'react';

import HIT_TYPES from 'game/HIT_TYPES';

import SpellLink from 'common/SpellLink';
import SPELLS from 'common/SPELLS';
import { formatPercentage } from 'common/format';

import Analyzer, { SELECTED_PLAYER } from 'parser/core/Analyzer';
import Events from 'parser/core/Events';
import calculateEffectiveHealing from 'parser/core/calculateEffectiveHealing';
import StatTracker from 'parser/shared/modules/StatTracker';
import CritEffectBonus from 'parser/shared/modules/helpers/CritEffectBonus';
import StatisticListBoxItem from 'interface/others/StatisticListBoxItem';

const HEAL_WINDOW_MS = 150;
const bounceReduction = 0.7;

/**
 * High Tide:
 * Every 40000 mana you spend brings a High Tide, making your next 2 Chain Heals heal for an additional 20% and not reduce with each jump.
 */

class HighTide extends Analyzer {
  static dependencies = {
    statTracker: StatTracker,
    critEffectBonus: CritEffectBonus,
  };
  healing = 0;
  chainHealTimestamp = 0;
  buffer = [];

  // high tide efficiency trackers
  highTideEvents = [];
  usedHighTides = 0;
  wastedHighTides = 0;
  currentHighTideBuff = 0;

  /*
    Double stack log: https://www.warcraftlogs.com/reports/Qb91XvyqtNjaHRPr#fight=21&type=auras&source=11&pins=0%24Separate%24%23244F4B%24healing%240%240.0.0.Any%24137004809.0.0.Shaman%24true%240.0.0.Any%24false%241064&ability=288675
    Buff applied pre-fight: https://www.warcraftlogs.com/reports/R4JncHyajt8VQr9h#fight=48&type=auras&source=14&ability=288675

  */

  constructor(...args) {
    super(...args);
    this.active = this.selectedCombatant.hasTalent(SPELLS.HIGH_TIDE_TALENT.id);

    this.addEventListener(Events.heal.by(SELECTED_PLAYER).spell(SPELLS.CHAIN_HEAL), this.chainHeal);
    this.addEventListener(Events.fightend, this.onFightEnd);

    // these are for tracking high tide efficiency
    this.addEventListener(Events.cast.by(SELECTED_PLAYER).spell(SPELLS.CHAIN_HEAL), this.onChainHealCast);
    this.addEventListener(Events.applybuff, this.onHighTideBuff);
    this.addEventListener(Events.applybuffstack, this.onHighTideBuff);
    this.addEventListener(Events.removebuff, this.onHighTideRemoveBuff);
  }

  onHighTideBuff(event) {
    if(event.ability.guid === 288675) {
      this.highTideEvents.push(event);
      this.wastedHighTides += this.currentHighTideBuff; //not sure if this is possible
      this.currentHighTideBuff = 2;
    }
  }

  onHighTideRemoveBuff(event) {
    if(event.ability.guid === 288675) {
      this.highTideEvents.push(event);
      this.wastedHighTides += this.currentHighTideBuff; //if there were leftovers when buff expires
      this.currentHighTideBuff = 0;
    }
  }

  onChainHealCast(event) {
    if(event.ability.name === "Chain Heal" && this.currentHighTideBuff > 0) {
      this.highTideEvents.push(event);
      this.usedHighTides++;
      this.currentHighTideBuff -= 1;
    }
  }

  chainHeal(event) {
    const hasHighTide = this.selectedCombatant.hasBuff(SPELLS.HIGH_TIDE_BUFF.id);
    if (!hasHighTide) {
      return;
    }

    // Detects new chain heal casts, can't use the cast event for this as its often somewhere in between its healing events
    if (!this.chainHealTimestamp || event.timestamp - this.chainHealTimestamp > HEAL_WINDOW_MS) {
      this.processBuffer();
      this.chainHealTimestamp = event.timestamp;
    }

    /**
     * Due to how Chain Heal interacts with the combatlog, we have to take a lot of extra steps here.
     * Issues:
     * 1. The healing events are backwards [4,3,2,1]
     * 2. If the Shaman heals himself, his healing event is always first [3,4,2,1] (3 = Shaman)
     * 3. If 2. happens, the heal on the shaman is also happening before the cast event, which the lines above already deal with.
     *
     * Calculating out High Tide requires us to know the exact jump order, as High Tide affects each jump differently.
     * https://ancestralguidance.com/hidden-spell-mechanics/
     * The solution is to reorder the events into the correct hit order, which could be done since each consecutive heal is weaker
     * than the one beforehand (by 30%), except, you have the Shaman mastery which will result in random healing numbers
     * as each hit has a different mastery effectiveness - the higher the Shamans mastery, the more rapidly different the numbers end up.
     * With traits like https://www.wowhead.com/spell=277942/ancestral-resonance existing, shamans mastery can randomly double or triple mid combat.
     *
     * So we take 1 cast of chain heal at a time (4 hits maximum), calculate out crits and the mastery bonus, reorder them according to the new values
     * (High healing to Low healing or [4,3,2,1] to [1,2,3,4]) and get the High Tide contribution by comparing the original heal values against
     * what a non-High Tide Chain Heal would have done each bounce.
     *
     * Things that are able to break the sorting: Deluge (Pls don't take it) as its undetectable, random player-based heal increases
     * (possibly encounter mechanics) if not accounted for.
     */
    let heal = event.amount + (event.absorbed || 0) + (event.overheal || 0);
    if (event.hitType === HIT_TYPES.CRIT) {
      const critMult = this.critEffectBonus.getBonus(event);
      heal /= critMult;
    }
    const currentMastery = this.statTracker.currentMasteryPercentage;
    const masteryEffectiveness = Math.max(0, 1 - (event.hitPoints - event.amount) / event.maxHitPoints);
    const baseHealingDone = heal / (1 + currentMastery * masteryEffectiveness);

    this.buffer.push({
      baseHealingDone: baseHealingDone,
      ...event,
    });
  }

  processBuffer() {
    this.buffer.sort((a, b) => parseFloat(b.baseHealingDone) - parseFloat(a.baseHealingDone));

    for (const [index, event] of Object.entries(this.buffer)) {
      // 20%, 71%, 145%, 250% increase per hit over not having High Tide
      const FACTOR_CONTRIBUTED_BY_HT_HIT = (SPELLS.HIGH_TIDE_BUFF.coefficient) / (SPELLS.CHAIN_HEAL.coefficient * bounceReduction ** index) - 1;

      this.healing += calculateEffectiveHealing(event, FACTOR_CONTRIBUTED_BY_HT_HIT);
    }
    this.buffer = [];
  }

  onFightEnd() {
    this.processBuffer();
  }

  subStatistic() {
    console.log(this.highTideEvents,"this.usedHighTides,this.wastedHighTides,this.currentHighTideBuff",this.usedHighTides,this.wastedHighTides,this.currentHighTideBuff);
    const highTideToolTip = `
      ${this.usedHighTides} High Tide buffs used and
      ${(this.wastedHighTides+this.currentHighTideBuff)} High Tide buffs unused
    `;

    return (
      <div>
        <StatisticListBoxItem
          title={<SpellLink id={SPELLS.HIGH_TIDE_TALENT.id} />}
          value={`${formatPercentage(this.owner.getPercentageOfTotalHealingDone(this.healing))} %`}
          valueTooltip={highTideToolTip}
        />
      </div>

    );
  }
}

export default HighTide;

<|endoftext|>


<commit_before>import { warn, extend } from 'core/util/index'
import { transitionProps, extractTransitionData } from './transition'

const props = extend({
  tag: String,
  moveClass: String
}, transitionProps)

delete props.mode

export default {
  props,

  created () {
    const dom = this.$requireWeexModule('dom')
    this.getPosition = el => new Promise((resolve, reject) => {
      dom.getComponentRect(el.ref, res => {
        if (!res.result) {
          reject(new Error(`failed to get rect for element: ${el.tag}`))
        } else {
          resolve(res.size)
        }
      })
    })

    const animation = this.$requireWeexModule('animation')
    this.animate = (el, options) => new Promise(resolve => {
      animation.transition(el.ref, options, resolve)
    })
  },

  render (h) {
    const tag = this.tag || this.$vnode.data.tag || 'span'
    const map = Object.create(null)
    const prevChildren = this.prevChildren = this.children
    const rawChildren = this.$slots.default || []
    const children = this.children = []
    const transitionData = extractTransitionData(this)

    for (let i = 0; i < rawChildren.length; i++) {
      const c = rawChildren[i]
      if (c.tag) {
        if (c.key != null && String(c.key).indexOf('__vlist') !== 0) {
          children.push(c)
          map[c.key] = c
          ;(c.data || (c.data = {})).transition = transitionData
        } else if (process.env.NODE_ENV !== 'production') {
          const opts = c.componentOptions
          const name = opts
            ? (opts.Ctor.options.name || opts.tag)
            : c.tag
          warn(`<transition-group> children must be keyed: <${name}>`)
        }
      }
    }

    if (prevChildren) {
      const kept = []
      const removed = []
      prevChildren.forEach(c => {
        c.data.transition = transitionData

        // TODO: record before patch positions

        if (map[c.key]) {
          kept.push(c)
        } else {
          removed.push(c)
        }
      })
      this.kept = h(tag, null, kept)
      this.removed = removed
    }

    return h(tag, null, children)
  },

  beforeUpdate () {
    // force removing pass
    this.__patch__(
      this._vnode,
      this.kept,
      false, // hydrating
      true // removeOnly (!important, avoids unnecessary moves)
    )
    this._vnode = this.kept
  },

  updated () {
    const children = this.prevChildren
    const moveClass = this.moveClass || ((this.name || 'v') + '-move')
    const moveData = children.length && this.getMoveData(children[0].context, moveClass)
    if (!moveData) {
      return
    }

    // TODO: finish implementing move animations once
    // we have access to sync getComponentRect()

    // children.forEach(callPendingCbs)

    // Promise.all(children.map(c => {
    //   const oldPos = c.data.pos
    //   const newPos = c.data.newPos
    //   const dx = oldPos.left - newPos.left
    //   const dy = oldPos.top - newPos.top
    //   if (dx || dy) {
    //     c.data.moved = true
    //     return this.animate(c.elm, {
    //       styles: {
    //         transform: `translate(${dx}px,${dy}px)`
    //       }
    //     })
    //   }
    // })).then(() => {
    //   children.forEach(c => {
    //     if (c.data.moved) {
    //       this.animate(c.elm, {
    //         styles: {
    //           transform: ''
    //         },
    //         duration: moveData.duration || 0,
    //         delay: moveData.delay || 0,
    //         timingFunction: moveData.timingFunction || 'linear'
    //       })
    //     }
    //   })
    // })
  },

  methods: {
    getMoveData (context, moveClass) {
      const stylesheet = context.$options.style || {}
      return stylesheet['@TRANSITION'] && stylesheet['@TRANSITION'][moveClass]
    }
  }
}

function callPendingCbs (c) {
  /* istanbul ignore if */
  if (c.elm._moveCb) {
    c.elm._moveCb()
  }
  /* istanbul ignore if */
  if (c.elm._enterCb) {
    c.elm._enterCb()
  }
}
<commit_msg>[weex] disable transition-group move animation for now<commit_after>import { warn, extend } from 'core/util/index'
import { transitionProps, extractTransitionData } from './transition'

const props = extend({
  tag: String,
  moveClass: String
}, transitionProps)

delete props.mode

export default {
  props,

  created () {
    const dom = this.$requireWeexModule('dom')
    this.getPosition = el => new Promise((resolve, reject) => {
      dom.getComponentRect(el.ref, res => {
        if (!res.result) {
          reject(new Error(`failed to get rect for element: ${el.tag}`))
        } else {
          resolve(res.size)
        }
      })
    })

    const animation = this.$requireWeexModule('animation')
    this.animate = (el, options) => new Promise(resolve => {
      animation.transition(el.ref, options, resolve)
    })
  },

  render (h) {
    const tag = this.tag || this.$vnode.data.tag || 'span'
    const map = Object.create(null)
    const prevChildren = this.prevChildren = this.children
    const rawChildren = this.$slots.default || []
    const children = this.children = []
    const transitionData = extractTransitionData(this)

    for (let i = 0; i < rawChildren.length; i++) {
      const c = rawChildren[i]
      if (c.tag) {
        if (c.key != null && String(c.key).indexOf('__vlist') !== 0) {
          children.push(c)
          map[c.key] = c
          ;(c.data || (c.data = {})).transition = transitionData
        } else if (process.env.NODE_ENV !== 'production') {
          const opts = c.componentOptions
          const name = opts
            ? (opts.Ctor.options.name || opts.tag)
            : c.tag
          warn(`<transition-group> children must be keyed: <${name}>`)
        }
      }
    }

    if (prevChildren) {
      const kept = []
      const removed = []
      prevChildren.forEach(c => {
        c.data.transition = transitionData

        // TODO: record before patch positions

        if (map[c.key]) {
          kept.push(c)
        } else {
          removed.push(c)
        }
      })
      this.kept = h(tag, null, kept)
      this.removed = removed
    }

    return h(tag, null, children)
  },

  beforeUpdate () {
    // force removing pass
    this.__patch__(
      this._vnode,
      this.kept,
      false, // hydrating
      true // removeOnly (!important, avoids unnecessary moves)
    )
    this._vnode = this.kept
  },

  updated () {
    const children = this.prevChildren
    const moveClass = this.moveClass || ((this.name || 'v') + '-move')
    const moveData = children.length && this.getMoveData(children[0].context, moveClass)
    if (!moveData) {
      return
    }

    // TODO: finish implementing move animations once
    // we have access to sync getComponentRect()

    // children.forEach(callPendingCbs)

    // Promise.all(children.map(c => {
    //   const oldPos = c.data.pos
    //   const newPos = c.data.newPos
    //   const dx = oldPos.left - newPos.left
    //   const dy = oldPos.top - newPos.top
    //   if (dx || dy) {
    //     c.data.moved = true
    //     return this.animate(c.elm, {
    //       styles: {
    //         transform: `translate(${dx}px,${dy}px)`
    //       }
    //     })
    //   }
    // })).then(() => {
    //   children.forEach(c => {
    //     if (c.data.moved) {
    //       this.animate(c.elm, {
    //         styles: {
    //           transform: ''
    //         },
    //         duration: moveData.duration || 0,
    //         delay: moveData.delay || 0,
    //         timingFunction: moveData.timingFunction || 'linear'
    //       })
    //     }
    //   })
    // })
  },

  methods: {
    getMoveData (context, moveClass) {
      const stylesheet = context.$options.style || {}
      return stylesheet['@TRANSITION'] && stylesheet['@TRANSITION'][moveClass]
    }
  }
}

// function callPendingCbs (c) {
//   /* istanbul ignore if */
//   if (c.elm._moveCb) {
//     c.elm._moveCb()
//   }
//   /* istanbul ignore if */
//   if (c.elm._enterCb) {
//     c.elm._enterCb()
//   }
// }
<|endoftext|>


<commit_before>/* Copyright 2009-2011 Hewlett-Packard Development Company, L.P. All rights reserved. */
var example = ""+
	"Typewriter\n"+
	"==========\n"+
	"\n"+
	"Welcome to *Typewriter*, a Markdown editor for the HP TouchPad.\n"+
	"\n"+
	"Markdown lets you create HTML documents by entering text in a simple format that's easy to read and write. No bells and whistles, just you and your text.\n"+
	"\n"+
	"To create a document simply do:\n"+
	"\n"+
	" 1. Type Markdown text [in the editor][editor]\n"+
	" 2. Preview the document after [dragging up the toolbar][preview]\n"+
	" \n"+
	"Markdown\n"+
	"--------\n"+
	"Markdown is a lightweight markup language based on the formatting conventions that people naturally use in email.  As [John Gruber] writes on the [Markdown site] [1]:\n"+
	"\n"+
	"> The overriding design goal for Markdown's\n"+
	"> formatting syntax is to make it as readable \n"+
	"> as possible. The idea is that a\n"+
	"> Markdown-formatted document should be\n"+
	"> publishable as-is, as plain text, without\n"+
	"> looking like it's been marked up with tags\n"+
	"> or formatting instructions.\n"+
	"\n"+
	"This document is written in Markdown; you are currently seeing the plaintext version. To get a feel for Markdown's syntax, type some text into the window and *pull up the toolbar*.\n"+
	"\n"+
	"What next?\n"+
	"----------\n"+
	"Go right ahead, [clear the editor][clear] and start typing.\n"+
	"\n"+
	"  [john gruber]: http://daringfireball.net/\n"+
	"  [1]: http://daringfireball.net/projects/markdown/\n"+
	"  [editor]: #editor\n"+
	"  [preview]: #preview\n"+
	"  [clear]: #clear";

enyo.kind({
	name: "EditorPanel",
	kind: enyo.HFlexBox,
	components: [
		{name: "slidingPane", kind: "HSlidingPane", flex: 1, multiViewMinHeight:1, components: [
			{name: "top", height: "100%", kind:"HSlidingView",
				components: [
					{kind: "Header", components: [
						{kind:"Image", "src":"images/icon.png"},
						{content: "Typewriter", "style": "padding-left: 10px;"},
						{kind: "Spacer", flex: 11},
						{kind: "ToolButtonGroup", components: [
							{caption: "Save File", onclick: "saveFile"},
							{caption: "Open File...", onclick: "openFile"}
						]},
						{kind: "Spacer"}
					]},
					{kind: "VFlexBox", flex: 1, components: [
						{kind: "HFlexBox", flex: 1, components: [
							{className: "desk-left", flex: 1},
							{kind: "BasicScroller",
								name:"editorScroller",
								flex: 10,
								autoHorizontal: false,
								horizontal: false,
								className: "output-scroller",
								components: [
									{kind: "BasicRichText",
										name: "editor",
										flex: 10,
										value: example,
										richContent: false,
										className: "editor-input",
										onblur: "generateMarkdown"
									}
								]
							},
							{className: "desk-right", flex: 1}
						]}
					]}
			]},
			{name: "bottom", kind:"HSlidingView", height: "62px", flex:0, //peekHeight: 54,
				onResize: "barMoved",
				components: [
					{kind: "Header", className: "enyo-toolbar fake-toolbar", components: [
						{kind: "GrabButton", className: "HGrabButton"},
						{kind: "Spacer"},
						{kind: "ToolButtonGroup", className: "enyo-toolbutton-dark", components: [
							{caption: "Headline", name:"markupheadline", className: "markuphelper"},
							{caption: "List", name:"markuplist", className: "markuphelper"},
							{caption: "Link", name:"markuplink", className: "markuphelper"},
							{caption: "Quote", name:"markupquote", className: "markuphelper"},
							{caption: "Image", name:"markupimage", className: "markuphelper"},
						]},
						{kind: "Spacer", flex: 10},
						{kind: "ToolButtonGroup", className: "enyo-toolbutton-dark", components: [
							{caption: "Print", name:"print", onclick: "printDocument"}
						]},
						{kind: "Spacer"},
						{kind: "GrabButton", className: "HGrabButton Right"},
					]},
					{kind: "VFlexBox", flex: 1, components: [
						{kind: "HFlexBox", flex: 1, components: [
							{className: "desk-left", flex: 1},
							{kind: "BasicScroller",
								name:"previewScroller",
								flex: 10,
								autoHorizontal: false,
								horizontal: false,
								className: "output-scroller",
								components: [
									{kind: "HtmlContent",
										name: "preview",
										className: "output-preview",
										onLinkClick: "htmlContentLinkClick"
									}
								]
							},
							{className: "desk-right", flex: 1}
						]}
					]}
			]}
		]},
		{name:'filePicker', kind: "FilePicker", fileType:["image"], allowMultiSelect:false, onPickFile: "handleFile"},
		{kind: "PrintDialog",
			duplexOption: true,
			frameToPrint: {name:"preview", landscape:false},
			appName: "Typewriter"
		}
	],
	generateMarkdown: function() {
		var converter = new Showdown.converter();

		var value = this.$.editor.getValue();
		this.$.preview.setContent(converter.makeHtml(value));
		//this.$.htmlContent.setContent(converter.makeHtml(example));
	},
	barMoved: function(event) {
		if(event.slidePosition == 0) { // down position
			this.position = "down";
			this.$.editorScroller.setScrollTop(this.$.previewScroller.scrollTop/this.$.previewScroller.getBoundaries().bottom*this.$.editorScroller.getBoundaries().bottom);
			//this.$.editor.forceFocus(); // buggy with on screen keyboard
			this.$.print.addClass("enyo-button-disabled");
			this.$.print.disabled = true;

			//this.$$.select(".markuphelper").each(function(item) {
			//	item.removeClass("enyo-button-disabled");
			//	item.disabled = false;
			//});

			this.$.markupheadline.removeClass("enyo-button-disabled");
			this.$.markuplist.removeClass("enyo-button-disabled");
			this.$.markuplink.removeClass("enyo-button-disabled");
			this.$.markupquote.removeClass("enyo-button-disabled");
			this.$.markupimage.removeClass("enyo-button-disabled");
			this.$.markupheadline.disabled = false;
			this.$.markuplist.disabled = false;
			this.$.markuplink.disabled = false;
			this.$.markupquote.disabled = false;
			this.$.markupimage.disabled = false;
		}
		else {  // up position
			this.position = "up";
			this.$.previewScroller.setScrollTop(this.$.editorScroller.scrollTop/this.$.editorScroller.getBoundaries().bottom*this.$.previewScroller.getBoundaries().bottom);
			this.$.print.removeClass("enyo-button-disabled");
			this.$.print.disabled = false;

			//this.$$.select(".markuphelper").each(function(item) {
			//	item.addClass("enyo-button-disabled");
			//	item.disabled = true;
			//});

			this.$.markupheadline.addClass("enyo-button-disabled");
			this.$.markuplist.addClass("enyo-button-disabled");
			this.$.markuplink.addClass("enyo-button-disabled");
			this.$.markupquote.addClass("enyo-button-disabled");
			this.$.markupimage.addClass("enyo-button-disabled");
			this.$.markupheadline.disabled = true;
			this.$.markuplist.disabled = true;
			this.$.markuplink.disabled = true;
			this.$.markupquote.disabled = true;
			this.$.markupimage.disabled = true;
		}

		this.generateMarkdown();
	},
	htmlContentLinkClick: function(sender, url) {
		var splits = url.split(/#/).slice(-1).pop();
		switch(splits) {
			case "clear":
				this.$.editor.setValue("");
			case "editor":
				this.$.slidingPane.selectView(this.$.top);
				return false;
				break;
			case "preview":
				this.$.slidingPane.selectView(this.$.bottom);
				return false;
				break;
			default:
				var r = new enyo.PalmService();
				r.service = "palm://com.palm.applicationManager/";
				r.method = "open";
				r.call({target: url});
		}
	},
	printDocument: function() {
		if(this.position == "down") {
			alert("Preview first!");
		}
		else {
			this.$.printDialog.openAtCenter();
		}
	},
	openFile: function() {
		this.$.filePicker.pickFile();
	},
	handleFile: function(inSender, msg) {
		this.$.editor.setValue(enyo.json.stringify(msg));
	},
	ready: function() {
		this.$.editor.forceFocus();
	}
});
<commit_msg>Button Callbacks<commit_after>/* Copyright 2009-2011 Hewlett-Packard Development Company, L.P. All rights reserved. */
var example = ""+
	"Typewriter\n"+
	"==========\n"+
	"\n"+
	"Welcome to *Typewriter*, a Markdown editor for the HP TouchPad.\n"+
	"\n"+
	"Markdown lets you create HTML documents by entering text in a simple format that's easy to read and write. No bells and whistles, just you and your text.\n"+
	"\n"+
	"To create a document simply do:\n"+
	"\n"+
	" 1. Type Markdown text [in the editor][editor]\n"+
	" 2. Preview the document after [dragging up the toolbar][preview]\n"+
	" \n"+
	"Markdown\n"+
	"--------\n"+
	"Markdown is a lightweight markup language based on the formatting conventions that people naturally use in email.  As [John Gruber] writes on the [Markdown site] [1]:\n"+
	"\n"+
	"> The overriding design goal for Markdown's\n"+
	"> formatting syntax is to make it as readable \n"+
	"> as possible. The idea is that a\n"+
	"> Markdown-formatted document should be\n"+
	"> publishable as-is, as plain text, without\n"+
	"> looking like it's been marked up with tags\n"+
	"> or formatting instructions.\n"+
	"\n"+
	"This document is written in Markdown; you are currently seeing the plaintext version. To get a feel for Markdown's syntax, type some text into the window and *pull up the toolbar*.\n"+
	"\n"+
	"What next?\n"+
	"----------\n"+
	"Go right ahead, [clear the editor][clear] and start typing.\n"+
	"\n"+
	"  [john gruber]: http://daringfireball.net/\n"+
	"  [1]: http://daringfireball.net/projects/markdown/\n"+
	"  [editor]: #editor\n"+
	"  [preview]: #preview\n"+
	"  [clear]: #clear";

enyo.kind({
	name: "EditorPanel",
	kind: enyo.HFlexBox,
	components: [
		{name: "slidingPane", kind: "HSlidingPane", flex: 1, multiViewMinHeight:1, components: [
			{name: "top", height: "100%", kind:"HSlidingView",
				components: [
					{kind: "Header", components: [
						{kind:"Image", "src":"images/icon.png"},
						{content: "Typewriter", "style": "padding-left: 10px;"},
						{kind: "Spacer", flex: 11},
						{kind: "ToolButtonGroup", components: [
							{caption: "Save File", onclick: "saveFile"},
							{caption: "Open File...", onclick: "openFile"}
						]},
						{kind: "Spacer"}
					]},
					{kind: "VFlexBox", flex: 1, components: [
						{kind: "HFlexBox", flex: 1, components: [
							{className: "desk-left", flex: 1},
							{kind: "BasicScroller",
								name:"editorScroller",
								flex: 10,
								autoHorizontal: false,
								horizontal: false,
								className: "output-scroller",
								components: [
									{kind: "BasicRichText",
										name: "editor",
										flex: 10,
										value: example,
										richContent: false,
										className: "editor-input",
										onblur: "generateMarkdown"
									}
								]
							},
							{className: "desk-right", flex: 1}
						]}
					]}
			]},
			{name: "bottom", kind:"HSlidingView", height: "62px", flex:0, //peekHeight: 54,
				onResize: "barMoved",
				components: [
					{kind: "Header", className: "enyo-toolbar fake-toolbar", components: [
						{kind: "GrabButton", className: "HGrabButton"},
						{kind: "Spacer"},
						{kind: "ToolButtonGroup", className: "enyo-toolbutton-dark", components: [
							{caption: "Headline", name:"markupheadline", className: "markuphelper", onclick:"markupHeadline" },
							{caption: "List", name:"markuplist", className: "markuphelper", onclick:"markupList" },
							{caption: "Link", name:"markuplink", className: "markuphelper", onclick:"markupLink" },
							{caption: "Quote", name:"markupquote", className: "markuphelper", onclick:"markupQuote" },
							{caption: "Code", name:"markupcode", className: "markuphelper", onclick:"markupCode" },
							{caption: "Image", name:"markupimage", className: "markuphelper", onclick:"markupImage" },
						]},
						{kind: "Spacer", flex: 10},
						{kind: "ToolButtonGroup", className: "enyo-toolbutton-dark", components: [
							{caption: "Print", name:"print", onclick: "printDocument"}
						]},
						{kind: "Spacer"},
						{kind: "GrabButton", className: "HGrabButton Right"},
					]},
					{kind: "VFlexBox", flex: 1, components: [
						{kind: "HFlexBox", flex: 1, components: [
							{className: "desk-left", flex: 1},
							{kind: "BasicScroller",
								name:"previewScroller",
								flex: 10,
								autoHorizontal: false,
								horizontal: false,
								className: "output-scroller",
								components: [
									{kind: "HtmlContent",
										name: "preview",
										className: "output-preview",
										onLinkClick: "htmlContentLinkClick"
									}
								]
							},
							{className: "desk-right", flex: 1}
						]}
					]}
			]}
		]},
		{name:'filePicker', kind: "FilePicker", fileType:["image"], allowMultiSelect:false, onPickFile: "handleFile"},
		{kind: "PrintDialog",
			duplexOption: true,
			frameToPrint: {name:"preview", landscape:false},
			appName: "Typewriter"
		}
	],

	/* PREVIEW HANDLING */

	barMoved: function(event) {
		if(event.slidePosition == 0) { // down position
			this.position = "down";
			this.$.editorScroller.setScrollTop(this.$.previewScroller.scrollTop/this.$.previewScroller.getBoundaries().bottom*this.$.editorScroller.getBoundaries().bottom);
			//this.$.editor.forceFocus(); // buggy with on screen keyboard
			this.$.print.addClass("enyo-button-disabled");
			this.$.print.disabled = true;

			//this.$$.select(".markuphelper").each(function(item) {
			//	item.removeClass("enyo-button-disabled");
			//	item.disabled = false;
			//});

			this.$.markupheadline.removeClass("enyo-button-disabled");
			this.$.markuplist.removeClass("enyo-button-disabled");
			this.$.markuplink.removeClass("enyo-button-disabled");
			this.$.markupquote.removeClass("enyo-button-disabled");
			this.$.markupcode.removeClass("enyo-button-disabled");
			this.$.markupimage.removeClass("enyo-button-disabled");
			this.$.markupheadline.disabled = false;
			this.$.markuplist.disabled = false;
			this.$.markuplink.disabled = false;
			this.$.markupquote.disabled = false;
			this.$.markupcode.disabled = false;
			this.$.markupimage.disabled = false;
		}
		else {  // up position
			this.position = "up";
			this.$.previewScroller.setScrollTop(this.$.editorScroller.scrollTop/this.$.editorScroller.getBoundaries().bottom*this.$.previewScroller.getBoundaries().bottom);
			this.$.print.removeClass("enyo-button-disabled");
			this.$.print.disabled = false;

			//this.$$.select(".markuphelper").each(function(item) {
			//	item.addClass("enyo-button-disabled");
			//	item.disabled = true;
			//});

			this.$.markupheadline.addClass("enyo-button-disabled");
			this.$.markuplist.addClass("enyo-button-disabled");
			this.$.markuplink.addClass("enyo-button-disabled");
			this.$.markupquote.addClass("enyo-button-disabled");
			this.$.markupcode.addClass("enyo-button-disabled");
			this.$.markupimage.addClass("enyo-button-disabled");
			this.$.markupheadline.disabled = true;
			this.$.markuplist.disabled = true;
			this.$.markuplink.disabled = true;
			this.$.markupquote.disabled = true;
			this.$.markupcode.disabled = true;
			this.$.markupimage.disabled = true;
		}

		this.generateMarkdown();
	},
	generateMarkdown: function() {
		var converter = new Showdown.converter();

		var value = this.$.editor.getValue();
		this.$.preview.setContent(converter.makeHtml(value));
		//this.$.htmlContent.setContent(converter.makeHtml(example));
	},
	htmlContentLinkClick: function(sender, url) {
		var splits = url.split(/#/).slice(-1).pop();
		switch(splits) {
			case "clear":
				this.$.editor.setValue("");
			case "editor":
				this.$.slidingPane.selectView(this.$.top);
				return false;
				break;
			case "preview":
				this.$.slidingPane.selectView(this.$.bottom);
				return false;
				break;
			default:
				var r = new enyo.PalmService();
				r.service = "palm://com.palm.applicationManager/";
				r.method = "open";
				r.call({target: url});
		}
	},

	/* PRINT HANDLING */

	printDocument: function() {
		if(this.position == "down") {
			alert("Preview first!");
		}
		else {
			this.$.printDialog.openAtCenter();
		}
	},

	/* FILE HANDLING */

	openFile: function() {
		this.$.filePicker.pickFile();
	},
	handleFile: function(inSender, msg) {
		this.$.editor.setValue(enyo.json.stringify(msg));
	},

	/* MARKUP CALLBACKS */

	markupHeadline: function() {
	},
	markupList: function() {
	},
	markupLink: function() {
	},
	markupQuote: function() {
	},
	markupCode: function() {
	},
	markupImage: function() {
	},

	/* CONSTRUCTOR */

	ready: function() {
		this.$.editor.forceFocus();
	}
});
<|endoftext|>


<commit_before>/*!
 * ${copyright}
 */

// Provides control sap.ui.commons.AccordionSection.
sap.ui.define(['jquery.sap.global', './library', 'sap/ui/core/Element'],
	function(jQuery, library, Element) {
	"use strict";

	/**
	 * Constructor for a new AccordionSection.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Represents a panel which is a container for other controls. The container does not have any layout function.
	 * @extends sap.ui.core.Element
	 *
	 * @author SAP SE
	 * @version ${version}
	 *
	 * @constructor
	 * @public
	 * @name sap.ui.commons.AccordionSection
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var AccordionSection = Element.extend("sap.ui.commons.AccordionSection", /** @lends sap.ui.commons.AccordionSection.prototype */ { metadata : {

		library : "sap.ui.commons",
		properties : {

			/**
			 * When the section content exceeds maxHeight, a vertical scroll bar appears.
			 */
			maxHeight : {type : "sap.ui.core.CSSSize", group : "Dimension", defaultValue : null},

			/**
			 * Requirement is that the used theme supports the control.
			 */
			enabled : {type : "boolean", group : "Behavior", defaultValue : true},

			/**
			 * It is recommended to make some settings for the width when the section is set to 'collapsed'.
			 */
			collapsed : {type : "boolean", group : "Behavior", defaultValue : false},

			/**
			 * Text for the section header
			 */
			title : {type : "string", group : "Misc", defaultValue : null}
		},
		defaultAggregation : "content",
		aggregations : {

			/**
			 * Aggregates the controls that are contained in the panel. Control layouting is browser-dependent. For a stable content layout, use a layout control as direct single child.
			 * When the panel dimensions are set, the child control may have width and height of 100%;
			 * when the panel dimensions are not set, the child defines the panel size.
			 */
			content : {type : "sap.ui.core.Control", multiple : true, singularName : "content"}
		},
		events : {

			/**
			 * Event is fired when the user scrolls the panel.
			 */
			scroll : {
				parameters : {

					/**
					 * Horizontal scroll position.
					 */
					left : {type : "int"},

					/**
					 * Vertical scroll position.
					 */
					top : {type : "int"}
				}
			}
		}
	}});

	/**
	 * AccordionSection Behavior Implementation
	 *
	 * Open:
	 * - HeaderDesign not implemented yet
	 */

	/**
	 * Do some initialization
	 * @private
	 */
	AccordionSection.prototype.init = function(){
	   this.bIgnoreScrollEvent = true; // do not fire a scroll event initially
	   this.oScrollDomRef = null;      // points to the content area
	};

	/**
	 * Set focus on the first control
	 * @private
	 */
	AccordionSection.prototype.focusFirstControl = function () {
		var aControls = this.getContent();
		if (aControls[0]) {
			aControls[0].focus();
		}
	};

	/**
	 * Set focus the arrow
	 * @private
	 */
	AccordionSection.prototype.focus = function () {

		var header = this.getDomRef("hdr");
		header.focus();
	};

	/**
	 * Called after the theme has been switched, required for adjustments
	 * @private
	 */
	AccordionSection.prototype.onThemeChanged = function () {
		var hdrLeft = this.getDomRef("hdrL");

		if (hdrLeft) {
			hdrLeft.style.width = "auto";
			var that = this;
			setTimeout(function() {that.onAfterRendering();}, 0); // TODO: there is a problem in IE8, depending on what the surrounding container is...
		}

	}

	/**
	 * Adapts size settings of the rendered HTML
	 * @private
	 */;
	AccordionSection.prototype.onAfterRendering = function () {

		this.oScrollDomRef = this.getDomRef("cont");
		var cont	  = this.oScrollDomRef;
		var root	  = this.getDomRef();
		var accordion = this.getParent().getDomRef();
		// if only height is set, the content area's height needs to be adapted  (should be a rare use-case)
		if (!AccordionSection._isSizeSet(this.getParent().getWidth()) && AccordionSection._isSizeSet(this.getMaxHeight())) {
			if (cont) {
				var contTop = cont.offsetTop;
				var targetHeight = (root.offsetHeight - contTop);
				cont.style.height = targetHeight + "px";

				var actualContHeight = cont.offsetHeight;
				if (actualContHeight > targetHeight) {
					cont.style.height = targetHeight - (actualContHeight - targetHeight) + "px";
				}
			}

		}

		var leftBorder	= jQuery(accordion).css("border-left-width");
		var rightBorder = jQuery(accordion).css("border-right-width");

		var borderTotal = parseFloat(leftBorder.substring(0, leftBorder.indexOf("px") )) + parseFloat(rightBorder.substring(0, rightBorder.indexOf("px") ));
		var oDomLabel = this.getDomRef("lbl");
		root.style.width = accordion.offsetWidth - borderTotal + "px";
		oDomLabel.style.width = accordion.offsetWidth - 30 + "px";

		//Bind the scroll event (does not bubble)
		var fnScrollProxy = this.__scrollproxy__;
		if (!fnScrollProxy) {
			fnScrollProxy = this.__scrollproxy__ = jQuery.proxy(this.onscroll, this);
		}
		this.$("cont").bind("scroll", fnScrollProxy);

	};

	AccordionSection.prototype.onBeforeRendering = function() {
		var fnScrollProxy = this.__scrollproxy__;
		if (fnScrollProxy) {
			this.$("cont").unbind("scroll", fnScrollProxy);
		}
	};

	/**
	 * Property setter for the "enabled" state
	 *
	 * @param {boolean} bEnabled Whether the AccordionSection should be enabled, or not
	 * @return {sap.ui.commons.AccordionSection} 'this' to allow method chaining
	 * @public
	 */
	AccordionSection.prototype.setEnabled = function(bEnabled) {
		this.setProperty("enabled", bEnabled, true); // no re-rendering!
		var root = this.getDomRef();
		if (root) {
			// if already rendered, adapt rendered control without complete re-rendering
			if (bEnabled) {
				jQuery(root).removeClass("sapUiAcdSectionDis");
			} else {
				jQuery(root).addClass("sapUiAcdSectionDis");
			}
		}
		return this;
	};

	/**
	 * Property setter for the "collapsed" state
	 *
	 * @param bCollapsed Whether the AccordionSection should be collapsed, or not
	 * @private
	 */
	AccordionSection.prototype._setCollapsed = function(bCollapsed) {
		this.setProperty("collapsed", bCollapsed, true); // no re-rendering!
		this._setCollapsedState(bCollapsed); // adapt rendered control without complete re-rendering
	};

	/**
	 * Property setter for the "collapsed" state
	 *
	 * @param {boolean} bCollapsed Whether the AccordionSection should be collapsed, or not
	 * @return {sap.ui.commons.AccordionSection} 'this' to allow method chaining
	 * @public
	 */
	AccordionSection.prototype.setCollapsed = function(bCollapsed) {
		if (this.getParent()) {

			if (!bCollapsed) {
				this.getParent().openSection(this.getId());
			} else {
				this.getParent().closeSection(this.getId());
			}
		} else {
			this._setCollapsed(bCollapsed);
		}
		return this;
	};

	/**
	 * Internal method for applying a "collapsed" state to the rendered HTML
	 *
	 * @param bCollapsed Whether the AccordionSection should be collapsed, or not
	 * @private
	 */
	AccordionSection.prototype._setCollapsedState = function(bCollapsed) {

		if (this.getDomRef()) {
			// after AccordionSection has been rendered
			if (bCollapsed) {
				var accessibility = sap.ui.getCore().getConfiguration().getAccessibility();

				// collapsing
				if (!this.getParent().getWidth()) {
					this.getDomRef().style.width = this.getDomRef().offsetWidth + "px"; // maintain the current width
				}
				jQuery(this.getDomRef()).addClass("sapUiAcdSectionColl");
				var tb = this.getDomRef("tb");
				if (tb) {
					tb.style.display = "none";
				}

				var cont = this.getDomRef("cont");
				cont.style.display = "none";
				if (accessibility) {
					cont.setAttribute("aria-expanded", "false");
					cont.setAttribute("aria-hidden", "true");
				}

				this.rerender();

			} else {
				// expanding
				if (!this.getDomRef("cont")) {
					// content has not been rendered yet, so render it now
					this.rerender(); // TODO: potentially restore focus to collapse icon/button
				} else {
					// content exists already, just make it visible again
					jQuery(this.getDomRef()).removeClass("sapUiAcdSectionColl");
					var tb = this.getDomRef("tb");
					if (tb) {
						tb.style.display = "block";
					}

					var cont = this.getDomRef("cont");
					cont.style.display = "block";
					if (accessibility) {
						cont.setAttribute("aria-expanded", "true");
					}

					if (this.getMaxHeight()) {
						this.getDomRef().style.height = this.getMaxHeight(); // restore the set height
					}
				}
			}
		}
	}

	/**
	 * Static method that finds out whether the given CSS size is actually set.
	 * Returns "true" for absolute and relative sizes, returns "false" if "null", "inherit" or "auto" is given.
	 *
	 * @static
	 * @param sCssSize A CSS size string which must be a valid CSS size, or null
	 * @private
	 */;
	AccordionSection._isSizeSet = function(sCssSize) {
		return (sCssSize && !(sCssSize == "auto") && !(sCssSize == "inherit"));
	}

	/*   Event Handling   */

	/**
	 * Handles any "triggering" actions like click and space
	 *
	 * @param {jQuery.Event} oEvent
	 * @private
	 */;
	AccordionSection.prototype._handleTrigger = function(oEvent) {
		// minimize button toggled
		if ((oEvent.target.id === this.getId() + "-minL") ||
				(oEvent.target.id === this.getId() + "-minR")) {
			var bCollapsed = !this.getProperty("collapsed");
			this._setCollapsed(bCollapsed);
			oEvent.preventDefault();
			oEvent.stopPropagation();
		}
	};

	/**
	 * Handles the scroll event of the browser
	 *
	 * @param {jQuery.Event} oEvent
	 * @private
	 */
	AccordionSection.prototype.onscroll = function (oEvent) {
		/**
		if (this.bIgnoreScrollEvent) { // bIgnoreScrollEvent is set to "true" if the scrollbar is moved via API calls
			this.bIgnoreScrollEvent = false;
			return;
		}
		var oDomRef = this.getDomRef();
		if (oDomRef) {
			this.fireScroll(oDomRef.scrollTop, oDomRef.scrollLeft);
		}
		 */
	};

	return AccordionSection;

}, /* bExport= */ true);
<commit_msg>[FEATURE] sap.ui.commons.Accordion: Introduce F6 handling<commit_after>/*!
 * ${copyright}
 */

// Provides control sap.ui.commons.AccordionSection.
sap.ui.define(['jquery.sap.global', './library', 'sap/ui/core/Element'],
	function(jQuery, library, Element) {
	"use strict";

	/**
	 * Constructor for a new AccordionSection.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Represents a panel which is a container for other controls. The container does not have any layout function.
	 * @extends sap.ui.core.Element
	 *
	 * @author SAP SE
	 * @version ${version}
	 *
	 * @constructor
	 * @public
	 * @name sap.ui.commons.AccordionSection
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var AccordionSection = Element.extend("sap.ui.commons.AccordionSection", /** @lends sap.ui.commons.AccordionSection.prototype */ { metadata : {

		library : "sap.ui.commons",
		properties : {

			/**
			 * When the section content exceeds maxHeight, a vertical scroll bar appears.
			 */
			maxHeight : {type : "sap.ui.core.CSSSize", group : "Dimension", defaultValue : null},

			/**
			 * Requirement is that the used theme supports the control.
			 */
			enabled : {type : "boolean", group : "Behavior", defaultValue : true},

			/**
			 * It is recommended to make some settings for the width when the section is set to 'collapsed'.
			 */
			collapsed : {type : "boolean", group : "Behavior", defaultValue : false},

			/**
			 * Text for the section header
			 */
			title : {type : "string", group : "Misc", defaultValue : null}
		},
		defaultAggregation : "content",
		aggregations : {

			/**
			 * Aggregates the controls that are contained in the panel. Control layouting is browser-dependent. For a stable content layout, use a layout control as direct single child.
			 * When the panel dimensions are set, the child control may have width and height of 100%;
			 * when the panel dimensions are not set, the child defines the panel size.
			 */
			content : {type : "sap.ui.core.Control", multiple : true, singularName : "content"}
		},
		events : {

			/**
			 * Event is fired when the user scrolls the panel.
			 */
			scroll : {
				parameters : {

					/**
					 * Horizontal scroll position.
					 */
					left : {type : "int"},

					/**
					 * Vertical scroll position.
					 */
					top : {type : "int"}
				}
			}
		}
	}});

	/**
	 * AccordionSection Behavior Implementation
	 *
	 * Open:
	 * - HeaderDesign not implemented yet
	 */

	/**
	 * Do some initialization
	 * @private
	 */
	AccordionSection.prototype.init = function(){
	   this.bIgnoreScrollEvent = true; // do not fire a scroll event initially
	   this.oScrollDomRef = null;      // points to the content area

	   this.data("sap-ui-fastnavgroup", "true", true); // Define group for F6 handling
	};

	/**
	 * Set focus on the first control
	 * @private
	 */
	AccordionSection.prototype.focusFirstControl = function () {
		var aControls = this.getContent();
		if (aControls[0]) {
			aControls[0].focus();
		}
	};

	/**
	 * Set focus the arrow
	 * @private
	 */
	AccordionSection.prototype.focus = function () {

		var header = this.getDomRef("hdr");
		header.focus();
	};

	/**
	 * Called after the theme has been switched, required for adjustments
	 * @private
	 */
	AccordionSection.prototype.onThemeChanged = function () {
		var hdrLeft = this.getDomRef("hdrL");

		if (hdrLeft) {
			hdrLeft.style.width = "auto";
			var that = this;
			setTimeout(function() {that.onAfterRendering();}, 0); // TODO: there is a problem in IE8, depending on what the surrounding container is...
		}

	}

	/**
	 * Adapts size settings of the rendered HTML
	 * @private
	 */;
	AccordionSection.prototype.onAfterRendering = function () {

		this.oScrollDomRef = this.getDomRef("cont");
		var cont	  = this.oScrollDomRef;
		var root	  = this.getDomRef();
		var accordion = this.getParent().getDomRef();
		// if only height is set, the content area's height needs to be adapted  (should be a rare use-case)
		if (!AccordionSection._isSizeSet(this.getParent().getWidth()) && AccordionSection._isSizeSet(this.getMaxHeight())) {
			if (cont) {
				var contTop = cont.offsetTop;
				var targetHeight = (root.offsetHeight - contTop);
				cont.style.height = targetHeight + "px";

				var actualContHeight = cont.offsetHeight;
				if (actualContHeight > targetHeight) {
					cont.style.height = targetHeight - (actualContHeight - targetHeight) + "px";
				}
			}

		}

		var leftBorder	= jQuery(accordion).css("border-left-width");
		var rightBorder = jQuery(accordion).css("border-right-width");

		var borderTotal = parseFloat(leftBorder.substring(0, leftBorder.indexOf("px") )) + parseFloat(rightBorder.substring(0, rightBorder.indexOf("px") ));
		var oDomLabel = this.getDomRef("lbl");
		root.style.width = accordion.offsetWidth - borderTotal + "px";
		oDomLabel.style.width = accordion.offsetWidth - 30 + "px";

		//Bind the scroll event (does not bubble)
		var fnScrollProxy = this.__scrollproxy__;
		if (!fnScrollProxy) {
			fnScrollProxy = this.__scrollproxy__ = jQuery.proxy(this.onscroll, this);
		}
		this.$("cont").bind("scroll", fnScrollProxy);

	};

	AccordionSection.prototype.onBeforeRendering = function() {
		var fnScrollProxy = this.__scrollproxy__;
		if (fnScrollProxy) {
			this.$("cont").unbind("scroll", fnScrollProxy);
		}
	};

	/**
	 * Property setter for the "enabled" state
	 *
	 * @param {boolean} bEnabled Whether the AccordionSection should be enabled, or not
	 * @return {sap.ui.commons.AccordionSection} 'this' to allow method chaining
	 * @public
	 */
	AccordionSection.prototype.setEnabled = function(bEnabled) {
		this.setProperty("enabled", bEnabled, true); // no re-rendering!
		var root = this.getDomRef();
		if (root) {
			// if already rendered, adapt rendered control without complete re-rendering
			if (bEnabled) {
				jQuery(root).removeClass("sapUiAcdSectionDis");
			} else {
				jQuery(root).addClass("sapUiAcdSectionDis");
			}
		}
		return this;
	};

	/**
	 * Property setter for the "collapsed" state
	 *
	 * @param bCollapsed Whether the AccordionSection should be collapsed, or not
	 * @private
	 */
	AccordionSection.prototype._setCollapsed = function(bCollapsed) {
		this.setProperty("collapsed", bCollapsed, true); // no re-rendering!
		this._setCollapsedState(bCollapsed); // adapt rendered control without complete re-rendering
	};

	/**
	 * Property setter for the "collapsed" state
	 *
	 * @param {boolean} bCollapsed Whether the AccordionSection should be collapsed, or not
	 * @return {sap.ui.commons.AccordionSection} 'this' to allow method chaining
	 * @public
	 */
	AccordionSection.prototype.setCollapsed = function(bCollapsed) {
		if (this.getParent()) {

			if (!bCollapsed) {
				this.getParent().openSection(this.getId());
			} else {
				this.getParent().closeSection(this.getId());
			}
		} else {
			this._setCollapsed(bCollapsed);
		}
		return this;
	};

	/**
	 * Internal method for applying a "collapsed" state to the rendered HTML
	 *
	 * @param bCollapsed Whether the AccordionSection should be collapsed, or not
	 * @private
	 */
	AccordionSection.prototype._setCollapsedState = function(bCollapsed) {

		if (this.getDomRef()) {
			// after AccordionSection has been rendered
			if (bCollapsed) {
				var accessibility = sap.ui.getCore().getConfiguration().getAccessibility();

				// collapsing
				if (!this.getParent().getWidth()) {
					this.getDomRef().style.width = this.getDomRef().offsetWidth + "px"; // maintain the current width
				}
				jQuery(this.getDomRef()).addClass("sapUiAcdSectionColl");
				var tb = this.getDomRef("tb");
				if (tb) {
					tb.style.display = "none";
				}

				var cont = this.getDomRef("cont");
				cont.style.display = "none";
				if (accessibility) {
					cont.setAttribute("aria-expanded", "false");
					cont.setAttribute("aria-hidden", "true");
				}

				this.rerender();

			} else {
				// expanding
				if (!this.getDomRef("cont")) {
					// content has not been rendered yet, so render it now
					this.rerender(); // TODO: potentially restore focus to collapse icon/button
				} else {
					// content exists already, just make it visible again
					jQuery(this.getDomRef()).removeClass("sapUiAcdSectionColl");
					var tb = this.getDomRef("tb");
					if (tb) {
						tb.style.display = "block";
					}

					var cont = this.getDomRef("cont");
					cont.style.display = "block";
					if (accessibility) {
						cont.setAttribute("aria-expanded", "true");
					}

					if (this.getMaxHeight()) {
						this.getDomRef().style.height = this.getMaxHeight(); // restore the set height
					}
				}
			}
		}
	}

	/**
	 * Static method that finds out whether the given CSS size is actually set.
	 * Returns "true" for absolute and relative sizes, returns "false" if "null", "inherit" or "auto" is given.
	 *
	 * @static
	 * @param sCssSize A CSS size string which must be a valid CSS size, or null
	 * @private
	 */;
	AccordionSection._isSizeSet = function(sCssSize) {
		return (sCssSize && !(sCssSize == "auto") && !(sCssSize == "inherit"));
	}

	/*   Event Handling   */

	/**
	 * Handles any "triggering" actions like click and space
	 *
	 * @param {jQuery.Event} oEvent
	 * @private
	 */;
	AccordionSection.prototype._handleTrigger = function(oEvent) {
		// minimize button toggled
		if ((oEvent.target.id === this.getId() + "-minL") ||
				(oEvent.target.id === this.getId() + "-minR")) {
			var bCollapsed = !this.getProperty("collapsed");
			this._setCollapsed(bCollapsed);
			oEvent.preventDefault();
			oEvent.stopPropagation();
		}
	};

	/**
	 * Handles the scroll event of the browser
	 *
	 * @param {jQuery.Event} oEvent
	 * @private
	 */
	AccordionSection.prototype.onscroll = function (oEvent) {
		/**
		if (this.bIgnoreScrollEvent) { // bIgnoreScrollEvent is set to "true" if the scrollbar is moved via API calls
			this.bIgnoreScrollEvent = false;
			return;
		}
		var oDomRef = this.getDomRef();
		if (oDomRef) {
			this.fireScroll(oDomRef.scrollTop, oDomRef.scrollLeft);
		}
		 */
	};

	return AccordionSection;

}, /* bExport= */ true);
<|endoftext|>