popovers.js - Ubuntu HTML5 API

# Ubuntu HTML5 API: popovers.js

API Docs for: HTML-14.04-dev~bzr202

#### popovers.js

    /*
     * Copyright (C) 2013 Adnane Belmadiaf <daker@ubuntu.com>
     * License granted by Canonical Limited
     *
     * This file is part of ubuntu-html5-ui-toolkit.
     *
     * This package is free software; you can redistribute it and/or modify
     * it under the terms of the GNU Lesser General Public License as
     * published by the Free Software Foundation; either version 3 of the
     * License, or
     * (at your option) any later version.

     * This package is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.

     * You should have received a copy of the GNU Lesser General Public
     * License along with this program. If not, see
     * <http://www.gnu.org/licenses/>.
     */

    /**
     * A Popover is a div containng markup that can pop up and disappear. (Unlike a Dialog, Popovers are not full screen.)

    A Popoves often contain a List whose items are connected to useful JavaScript functions.

    ######Popover Position
    The Popover's position is set relative to a specified base element with the <em>data-gravity="LETTER"</em> attribute. LETTER values:

     - 'n': the base element is above the Popover
     - 's': the base element is below the Popover
     - 'e': the base element is to the east of (to the right of) the Popover (in right-to-left locales)
     - 'w': the base element is to the west of (to the left of) the Popover (in right-to-left locale)

     * @class Popover
     * @constructor
     * @namespace UbuntuUI
     * @param {String} elem - The element to which the Popover's position is relative
     * @param {ID} id - The id attribute of the Popover in HTML
     * @example

          <p id="popoverBase">Text</p>
          <div class="popover active" data-gravity="n" id="popover">
            <ul class="list">
              <li class="active"><a href="#">Item1</a></li>
              <li><a href="#">Item2</a></li>
            </ul>
          </div>

          Javascript:
          var popBase = document.getElementById("popoverBase");
          var popover = UI.popover(popBase, "popover");
     */

    var Popover = function (elem, id) {
        this.id = id;
        this.popover = document.getElementById(id);
        this.elem = elem;
        this.parent = elem.parentNode.parentNode.parentNode.parentNode;
        this.is_parent_footer = (this.parent.nodeName.toLowerCase() === "footer");
    };

    Popover.prototype = {
        /**
         * Display a Popover
         * @method show
         */
        show: function () {
            if (this.popover === null) {
                console.error('The popover with the ID #' + this.id + ' doesn\'t exist');
                return;
            }
            var de = document.documentElement,
                w = (de&&de.clientWidth) || document.body.clientWidth,
                ot = 0,
                ol = 0,
                gravity = "s",
                pos_top = 0,
                pos_left = 0,
                pos_right = 0;

            this.popover.classList.add('active');
            popoverWidth = this.popover.offsetWidth;
            popoverHeight = this.popover.offsetHeight;

            gravity = this.popover.getAttribute("data-gravity");

            if (this.is_parent_footer) {
                ot = this.parent.offsetTop;
                ol = this.elem.offsetLeft;
            }
            else {
                ot = this.elem.offsetTop;
                ol = this.elem.offsetLeft;
            }

            switch (gravity) {
                case 'n':
                    pos_top = this.elem.offsetTop + this.elem.offsetHeight + 10;
                    pos_left = this.elem.offsetLeft + this.elem.offsetWidth / 2 - popoverWidth / 2;
                    break;
                case 's':
                    if (this.is_parent_footer) {
                        pos_top = ot - popoverHeight - 90;
                        pos_left = ol + this.elem.offsetWidth / 2 - popoverWidth / 2;
                        if (pos_left < 0)
                            pos_left = 5;
                        else {
                            if (pos_left + popoverWidth > w) {
                                pos_left = -1;
                                pos_right = 5;
                            }
                        }

                    }
                    else {
                        pos_top = ot - popoverHeight - 10;
                        pos_left = ol + this.elem.offsetWidth / 2 - popoverWidth / 2;
                    }
                    break;
                case 'e':
                    pos_top = this.elem.offsetTop + this.elem.offsetHeight / 2 - popoverHeight / 2;
                    pos_left = this.elem.offsetLeft - popoverWidth - 10;
                    break;
                case 'w':
                    pos_top = this.elem.offsetTop + this.elem.offsetHeight / 2 - popoverHeight / 2;
                    pos_left = this.elem.offsetLeft + this.elem.offsetWidth + 10;
                    break;
            }

            this.popover.style.top = pos_top + 'px';
            if (pos_left === -1) {
                this.popover.style.left = 'auto';
                this.popover.style.right = pos_right+ 'px';
            }
            else
                this.popover.style.left = pos_left+ 'px';

            return this.popover;
        },
        /**
         * Hide a Popover
         * @method hide
         */
        hide: function () {
            this.popover.classList.remove('active');
            this.popover.style.top = '0px';
            this.popover.style.left = '0px';
            return this.popover;
        },
        /**
         * Toggle show/hide status of a Popover
         * @method toggle
         */
        toggle: function () {
            if (this.popover === null) {
                console.error('The popover with the ID #' + this.id + ' doesn\'t exist');
                return;
            }
            var de = document.documentElement,
                w = (de&&de.clientWidth) || document.body.clientWidth,
                ot = 0,
                ol = 0,
                gravity = "s",
                pos_top = 0,
                pos_left = 0,
                pos_right = 0;

            this.popover.classList.toggle('active');
            popoverWidth = this.popover.offsetWidth;
            popoverHeight = this.popover.offsetHeight;

            gravity = this.popover.getAttribute("data-gravity");

            if (this.is_parent_footer) {
                ot = this.parent.offsetTop;
                ol = this.elem.offsetLeft;
            }
            else {
                ot = this.elem.offsetTop;
                ol = this.elem.offsetLeft;
            }

            switch (gravity) {
                case 'n':
                    pos_top = ot + this.elem.offsetHeight + 10;
                    pos_left = ol + this.elem.offsetWidth / 2 - popoverWidth / 2;
                    break;
                case 's':
                    if (this.is_parent_footer) {
                        pos_top = ot - popoverHeight - 90;
                        pos_left = ol + this.elem.offsetWidth / 2 - popoverWidth / 2;
                        if (pos_left < 0)
                            pos_left = 5;
                        else {
                            if (pos_left + popoverWidth > w) {
                                pos_left = -1;
                                pos_right = 5;
                            }
                        }

                    }
                    else {
                        pos_top = ot - popoverHeight - 10;
                        pos_left = ol + this.elem.offsetWidth / 2 - popoverWidth / 2;
                    }
                    break;
                case 'e':
                    pos_top = ot + this.elem.offsetHeight / 2 - popoverHeight / 2;
                    pos_left = ol - popoverWidth - 10;
                    break;
                case 'w':
                    pos_top = ot + this.elem.offsetHeight / 2 - popoverHeight / 2;
                    pos_left = ol + this.elem.offsetWidth + 10;
                    break;
            }

            this.popover.style.top = pos_top + 'px';
            if (pos_left === -1) {
                this.popover.style.left = 'auto';
                this.popover.style.right = pos_right+ 'px';
            }
            else
                this.popover.style.left = pos_left+ 'px';

            return this.popover;
        },
        /**
         * Returns the DOM element associated with the id this widget is bind to.
         * @method element
         * @example
            var mypopover = UI.popover("popoverid").element();
         */
        element: function () {
            return this.popover;
        }
    };