~ubuntu-branches/ubuntu/trusty/ubuntu-html5-theme/trusty-proposed

« back to all changes in this revision

Viewing changes to 0.1/ambiance/js/pagestacks.js

  • Committer: Package Import Robot
  • Author(s): Ubuntu daily release, Adnane Belmadiaf, daker, Kyle Nitzsche, Colin Watson, Alexandre Abreu, Ubuntu daily release
  • Date: 2014-01-07 23:46:53 UTC
  • mfrom: (1.1.7)
  • Revision ID: package-import@ubuntu.com-20140107234653-oagvm6guom4h9dvh
Tags: 0.1+14.04.20140107-0ubuntu1
[ Adnane Belmadiaf ]
* s/parentNode/parendNode Spaces instead of tabs. (LP: #1241215)
* Add option selector widget. (LP: #1232533)

[ daker ]
* Passe the UI variable name so we will not lock the variable. (LP:
  #1222878)
* Made variable declaration locale. (LP: #1222881)
* Fixed z-index for the list items aside. (LP: #1223973)
* s/parentNode/parendNode Spaces instead of tabs. (LP: #1241215)
* Space instead of tab. (LP: #1240682)
* Made list items with headers differentes. (LP: #1246446)
* Updated the progressbar component to match the design.
* Move tabs closer to what they should be, Expand API to match the QML
  one (at least at the Tabs level), .
* Add option selector widget. (LP: #1232533)

[ Kyle Nitzsche ]
* Add button id to "Invalid button ID" error message .
* This MR does three main things: 1) Implements yuidoc comments in all
  js files to support API doc generation, and provides yuidoc assets
  (theme dir and json file) needed to build the API docs. Bug LP:
  #1241029 3) Provides JS classes for shape and page with
  corresponding UbuntuUI prototype constructor functions. Bug LP:
  #1243248 4) Adds a getEl(UbuntuUIObject) to return the element for
  any Ubuntu class. Also LP: #1243248. (LP: #1243248, #1241029)

[ Colin Watson ]
* Make ubuntu-html5-theme Multi-Arch: foreign.

[ Alexandre Abreu ]
* Fix exec path in app-gallery app desktop file. (LP: #1235321)
* Add convenient element() function to most widgets ... (we might want
  to factor those out in a second step).
* Move tabs closer to what they should be, Expand API to match the QML
  one (at least at the Tabs level), .
* Add HTML5 webapp container package.

[ Ubuntu daily release ]
* Automatic snapshot from revision 98

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
 * This file is part of ubuntu-html5-theme.
6
6
 *
7
7
 * This package is free software; you can redistribute it and/or modify
8
 
 * it under the terms of the GNU Lesser General Public License as 
9
 
 * published by the Free Software Foundation; either version 3 of the 
 
8
 * it under the terms of the GNU Lesser General Public License as
 
9
 * published by the Free Software Foundation; either version 3 of the
10
10
 * License, or
11
11
 * (at your option) any later version.
12
 
 
 
12
 
13
13
 * This package is distributed in the hope that it will be useful,
14
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
16
 * GNU General Public License for more details.
17
 
 
18
 
 * You should have received a copy of the GNU Lesser General Public 
19
 
 * License along with this program. If not, see 
 
17
 
 
18
 * You should have received a copy of the GNU Lesser General Public
 
19
 * License along with this program. If not, see
20
20
 * <http://www.gnu.org/licenses/>.
21
21
 */
22
22
 
23
 
/* Pagestack */
 
23
/**
 
24
 * The Pagestack manages all Pages in a stack data structure. Initially, the Pagestack contains no Pages. The <em>push()</em> method is normally executed on load to display the app starting page.
 
25
 
 
26
      UI.pagestack.push("pageID")
 
27
 
 
28
The topmost Page on the Pagestack is always displayed.
 
29
 
 
30
The Pagestack is declared as a direct child of the <em>content</em> div.
 
31
 
 
32
#####Default application wide footer
 
33
The Pagestack contains a default <em>footer</em> (represented in JavaScript as a Toolbar), even if you do not declare one in HTML. The <em>footer</em> has a single Back button.
 
34
#####Customized application wide footer
 
35
This application-wide <em>footer</em> can be customized (for example, you can add Buttons) by declaring a <em>footer</em> as a direct child of the <em>pagestack</em> div (see example).
 
36
######Page specific footers
 
37
A <em>page</em> may declare a page-specific <em>footer</em> as a child element.
 
38
 
 
39
 * @class Pagestack
 
40
 * @namespace UbuntuUI
 
41
 * @constructor
 
42
 * @example
 
43
 
 
44
     <div data-role="page">
 
45
        <header data-role="header">
 
46
          [...]
 
47
        </header>
 
48
        <div data-role="content">
 
49
          <div data-role="pagestack">
 
50
            <div data-role="page" id="main">
 
51
            </div>
 
52
            <div data-role="page" id="page2">
 
53
              [...]
 
54
              <footer data-role="footer" class="revealed" id="footerPage2">
 
55
                [...]
 
56
              </footer>
 
57
            </div>
 
58
            <footer data-role="footer" class="revealed" id="footerAppWide">
 
59
              [...]
 
60
            </footer>
 
61
          </div>  <!-- end of Pagestack div -->
 
62
        </div>
 
63
      </div>
 
64
 
 
65
      JavaScript:
 
66
      UI.pagestack.METHOD();
 
67
 
 
68
 */
24
69
var Pagestack = (function () {
25
 
    
 
70
 
26
71
    function __safeCall(f, args, errorfunc) {
27
 
        if (typeof(f) !== 'function')
28
 
            return;
29
 
        try {
30
 
            f.apply(null, args);
31
 
        }
32
 
        catch(e) { if (errorfunc && typeof(errorfunc) === 'function') errorfunc(e) }
 
72
        if (typeof (f) !== 'function')
 
73
            return;
 
74
        try {
 
75
            f.apply(null, args);
 
76
        } catch (e) {
 
77
            if (errorfunc && typeof (errorfunc) === 'function') errorfunc(e)
 
78
        }
33
79
    };
34
80
 
35
 
    function Pagestack () {
36
 
        this._pages = [];
 
81
    function Pagestack(pagestack) {
 
82
        this._pages = [];
 
83
        this._pagestack = pagestack;
37
84
    };
38
85
 
39
86
    Pagestack.prototype = {
40
 
        __setAllPagesVisibility: function (visible) {
41
 
            var visibility = visible ? "block" : "none";
42
 
            [].forEach.call(document.querySelectorAll("[data-role='pagestack'] [data-role='page']"), function(el) {
43
 
                el.style.display = visibility;
44
 
 
45
 
                // treat footers separately
46
 
                var footer = el.querySelector('footer');
47
 
                if (footer)
48
 
                    footer.style.display = visibility;
49
 
            });
50
 
        },
51
 
        __isPage: function (element) {
52
 
            return element.getAttribute('data-role') === 'page';
53
 
        },
54
 
        __deactivate: function (id) {
55
 
            if (!id || typeof(id) !== 'string')
56
 
                return;
57
 
            var page = document.getElementById(id);
58
 
            if ( ! this.__isPage(page)) {
59
 
                return;
60
 
            }
61
 
            page.style.display = "none";
62
 
            if (page.querySelector('footer')) {
63
 
                var footer = page.querySelector('footer');
64
 
                footer.style.display = 'none';
65
 
                footer.classList.remove('revealed');
66
 
            }
67
 
        },
68
 
        __activate: function (id) {
69
 
            if (!id || typeof(id) !== 'string')
70
 
                return;
71
 
            var page = document.getElementById(id);
72
 
            if ( ! this.__isPage(page)) {
73
 
                return;
74
 
            }
75
 
            page.style.display = "block";
76
 
            if (page.querySelector('footer')) {
77
 
                var footer = page.querySelector('footer');
78
 
                footer.style.display = 'block';
79
 
                footer.classList.add('revealed');
80
 
            }
81
 
        },
82
 
        push: function (id, properties) {
83
 
            try {
84
 
                __safeCall(this.__setAllPagesVisibility.bind(this), [false]);
85
 
 
86
 
                this.__activate(id);
87
 
                this._pages.push(id);
88
 
            }
89
 
            catch(e) {}
90
 
        },
91
 
        isEmpty: function () {
92
 
            return this._pages.length === 0;
93
 
        },
94
 
        currentPage: function () {
95
 
            return this.isEmpty() ? null : this._pages[this._pages.length-1];
96
 
        },
97
 
        depth: function() {
98
 
            return this._pages.length;
99
 
        },
100
 
        clear: function() {
101
 
            if (this.isEmpty())
102
 
                return;
103
 
            __safeCall(this.__deactivate.bind(this), [this.currentPage()]);
104
 
            this._pages = [];
105
 
        },
106
 
        pop: function() {
107
 
            if(this.isEmpty())
108
 
                return;
109
 
            __safeCall(this.__deactivate.bind(this), [this.currentPage()]);
110
 
            this._pages.pop();
111
 
            __safeCall(this.__activate.bind(this), [this.currentPage()]);
112
 
        }
113
 
    }
 
87
        /**
 
88
         * Push a page to the top of this pagestack
 
89
         * @method push
 
90
         * @param {String} id - The id attribute of the page element to be pushed
 
91
         * @param {Object} properties - This param is not currently used
 
92
         */
 
93
        push: function (id, properties) {
 
94
            try {
 
95
                __safeCall(this.__setAllPagesVisibility.bind(this), [false]);
 
96
                (new Page(id)).activate(id);
 
97
                this._pages.push(id);
 
98
 
 
99
                this.__dispatchPageChanged(this.currentPage());
 
100
            } catch (e) {}
 
101
        },
 
102
 
 
103
        /**
 
104
         * Checks for zero pages in this pagestack
 
105
         * @method isEmpty
 
106
         * @return {Boolean} - True when this pagestack has no pages, else false
 
107
         */
 
108
        isEmpty: function () {
 
109
            return this._pages.length === 0;
 
110
        },
 
111
 
 
112
        /**
 
113
         * Gets the id attribute of the page element on top of this pagestack
 
114
         * @method currentPage
 
115
         * @return {PageID|Null} - The topmost page's id attribute, else null when there are no pages on this pagestack
 
116
         */
 
117
        currentPage: function () {
 
118
            return this.isEmpty() ? null : this._pages[this._pages.length - 1];
 
119
        },
 
120
 
 
121
        /**
 
122
         * Gets the number of pages in this pagestack
 
123
         * @method depth
 
124
         * @return {Number} - The number of pages in this pagestack
 
125
         */
 
126
        depth: function () {
 
127
            return this._pages.length;
 
128
        },
 
129
 
 
130
        /**
 
131
         * Clears the whole page stack
 
132
         * @method clear
 
133
         */
 
134
        clear: function () {
 
135
            if (this.isEmpty())
 
136
                return;
 
137
            __safeCall(Page.prototype.deactivate.bind(new Page(this.currentPage())), []);
 
138
            this._pages = [];
 
139
        },
 
140
 
 
141
        /**
 
142
         * Pops the current page off this pagestack, which causes the next page to become the top page and to display
 
143
         * @method pop
 
144
         */
 
145
        pop: function () {
 
146
            if (this.isEmpty())
 
147
                return;
 
148
            __safeCall(Page.prototype.deactivate.bind(new Page(this.currentPage())), []);
 
149
            this._pages.pop();
 
150
            __safeCall(Page.prototype.activate.bind(new Page(this.currentPage())), []);
 
151
 
 
152
            this.__dispatchPageChanged(this.currentPage());
 
153
        },
 
154
 
 
155
        onPageChanged : function(callback){
 
156
            this._pagestack.addEventListener("pagechanged", callback);
 
157
        },
 
158
 
 
159
        /**
 
160
         * @private
 
161
         */
 
162
        __setAllPagesVisibility: function (visible) {
 
163
            var visibility = visible ? "block" : "none";
 
164
 
 
165
            var children = [].slice.call(this._pagestack.children);
 
166
            children.forEach(function(element) {
 
167
                var pageHelper = new Page();
 
168
                if (pageHelper.isPage(element)) {
 
169
                    el.style.display = visibility;
 
170
                    // treat footers separately
 
171
                    var footer = el.querySelector('footer');
 
172
                    if (footer)
 
173
                        footer.style.display = visibility;
 
174
                }
 
175
            });
 
176
        },
 
177
 
 
178
        /**
 
179
         * @private
 
180
         */
 
181
        __isPage: function (element) {
 
182
            return element.getAttribute('data-role') === 'page';
 
183
        },
 
184
 
 
185
        /**
 
186
         * @private
 
187
         */
 
188
        __dispatchPageChanged: function (page) {
 
189
            var event = document.createEvent('Event');
 
190
            event.initEvent('pagechanged',true,true);
 
191
            event.page = page;
 
192
            this._pagestack.dispatchEvent(event);
 
193
        },
 
194
    };
114
195
 
115
196
    return Pagestack;
116
197
})();
117