13 ported and 1 new for 1.4.0.
[webos-internals:justyns-modifications.git] / app-launcher / app-launcher-named-pages-in-the-launcher.patch
1 diff --git a/usr/lib/luna/system/luna-applauncher/app/controllers/app-info-assistant.js b/usr/lib/luna/system/luna-applauncher/app/controllers/app-info-assistant.js
2 index 6b3e351..e385497 100644
3 --- a/usr/lib/luna/system/luna-applauncher/app/controllers/app-info-assistant.js
4 +++ b/usr/lib/luna/system/luna-applauncher/app/controllers/app-info-assistant.js
5 @@ -1,8 +1,9 @@
6  /* Copyright 2009 Palm, Inc.  All rights reserved. */
7  
8  var AppInfoAssistant = Class.create({
9 -       initialize: function(appInfo, sceneController, closeCallback) {
10 +       initialize: function(appInfo, parent, sceneController, closeCallback) {
11                 this.sceneController = sceneController;
12 +        this.parent = parent;
13                 this.appInfo = appInfo;
14                 this.isDynamic = this.isDynamicLaunchPoint(this.appInfo);
15                 this.closeCallback = closeCallback;
16 @@ -43,6 +44,29 @@ var AppInfoAssistant = Class.create({
17                 if (!this.isDynamic) {
18                         this.appSizeRequest = ApplicationService.getAppSize(this.appInfo.id, this.onGetAppSize.bind(this));
19                 }
20 +
21 +        // Find the page for the app being inspected.
22 +        var app_page = this.parent.pagesModel
23 +            .findApplication(this.appInfo.launchPointId);
24 +
25 +        // Build the list selector for switching pages.
26 +        this.sceneController.setupWidget(
27 +            'page_name', 
28 +            {
29 +                label: $L('Page'),
30 +                choices: this.parent.pageDivs.map(function (alias, idx) {
31 +                    return { 
32 +                        value: idx, 
33 +                        label: this.parent.getPageName(idx)
34 +                    };
35 +                }, this)
36 +            }, 
37 +            this.page_name_model = { 
38 +                value: app_page.page, disabled: false 
39 +            }
40 +        );
41 +        this.sceneController.listen('page_name', Mojo.Event.propertyChange,
42 +            this.onPageNameChanged.bindAsEventListener(this));
43         },
44         
45         insertVersion: function() {
46 @@ -157,6 +181,10 @@ var AppInfoAssistant = Class.create({
47                         this.sceneController.get('app-size').update(sizeInKBytes + $L('K'));
48                 }
49         },
50 +
51 +    onPageNameChanged: function (event) {
52 +        this.parent.moveAppToPage(this.appInfo.launchPointId, event.value);
53 +    },
54         
55         cleanup: function() {
56                 if (this.appSizeRequest) {
57 diff --git a/usr/lib/luna/system/luna-applauncher/app/controllers/global-search-assistant.js b/usr/lib/luna/system/luna-applauncher/app/controllers/global-search-assistant.js
58 index 6f3368e..1d3ad74 100644
59 --- a/usr/lib/luna/system/luna-applauncher/app/controllers/global-search-assistant.js
60 +++ b/usr/lib/luna/system/luna-applauncher/app/controllers/global-search-assistant.js
61 @@ -263,6 +263,10 @@ GlobalSearchAssistant = Class.create({
62         },
63         
64         onKeyDown: function(event) {
65 +        if (!this.searchEnabled) {
66 +            // HACK: The event.stop() below disables text entry in dialogs
67 +            return;
68 +        }
69                 
70                 this.searchField.mojo.focus();
71  
72 @@ -279,6 +283,10 @@ GlobalSearchAssistant = Class.create({
73         },
74         
75         onKeyUp: function(event) {
76 +        if (!this.searchEnabled) {
77 +            // HACK: The event.stop() below disables text entry in dialogs
78 +            return;
79 +        }
80                 
81                 // block key events from global search
82                 if (!this.searchEnabled) {
83 @@ -296,6 +304,10 @@ GlobalSearchAssistant = Class.create({
84         },
85         
86         onKeyPress: function(event) {
87 +        if (!this.searchEnabled) {
88 +            // HACK: The event.stop() below disables text entry in dialogs
89 +            return;
90 +        }
91                 
92                 if(this.searchPressHoldTerm && this.searchPressHoldTerm.length > 0 && event.keyCode != this.searchPressHoldTerm.charCodeAt(0)) {
93                 // first key no longer being held
94 diff --git a/usr/lib/luna/system/luna-applauncher/app/controllers/launcher-assistant.js b/usr/lib/luna/system/luna-applauncher/app/controllers/launcher-assistant.js
95 index 9057138..33589a2 100644
96 --- a/usr/lib/luna/system/luna-applauncher/app/controllers/launcher-assistant.js
97 +++ b/usr/lib/luna/system/luna-applauncher/app/controllers/launcher-assistant.js
98 @@ -59,6 +59,14 @@ var LauncherAssistant = Class.create({
99                 
100                 this.dragStartHandler = this.onDragStart.bindAsEventListener(this);
101                 this.launchApp = this.launchApp.bind(this);
102 +
103 +        this.page_names_cookie = new Mojo.Model.Cookie('page_names');
104 +        this.page_names = this.page_names_cookie.get() || [];
105 +
106 +        // HACK: Doing a splice here rather than defining this item above so
107 +        // that the patch works with 'Enable Add / Delete' patch.
108 +        this.appMenuModel.items.splice(1, 0, 
109 +                       { label: $L('Rename page'), command: 'renamepage' });
110         },
111         
112         setup: function() {
113 @@ -74,6 +82,9 @@ var LauncherAssistant = Class.create({
114                         }
115                 );
116                 
117 +        Mojo.listen($('page-category'), Mojo.Event.tap, 
118 +            this.handlePageNameTap.bindAsEventListener(this));
119 +
120                 this.globalSearchAssistant = new GlobalSearchAssistant(this.controller, this);
121                 
122                 // HACK: The launcher starts out launched and deactive.
123 @@ -118,6 +129,9 @@ var LauncherAssistant = Class.create({
124                                 case 'listapps':
125                                         ApplicationService.launch(this.deviceInfo.id, this.deviceInfo.params);
126                                         break;
127 +                case 'renamepage':
128 +                    this.handleRenamePage(event);
129 +                    break;
130                                 case 'defaultapps':
131                                         ApplicationService.launch(this.deviceInfo.id, this.deviceInfo.defaultAppParams);
132                                         break;
133 @@ -236,6 +250,12 @@ var LauncherAssistant = Class.create({
134                 }
135                 
136                 this.pageDivs = $$('.launcher_page');
137 +
138 +        if (createPage) {
139 +            this.page_names.splice(newPageIndex, 0, []);
140 +            this.updatePageHeader();
141 +            this.savePageNames();
142 +        }
143                 
144                 // extend the horizontal scrollers internal width
145                 pagesContainer.style.width = (this.pageDivs.length*this.kPageWidth)+'px';
146 @@ -297,6 +317,11 @@ var LauncherAssistant = Class.create({
147                 
148                 // remove the pages indicator
149                 this.deletePageIndicator();
150 +
151 +        // Splice out the name for this page.
152 +        this.page_names.splice(pageIndex, 1);
153 +        this.updatePageHeader();
154 +        this.savePageNames();
155                 
156                 // snap to a valid location
157                 if (pageIndex >= this.pageDivs.length) {
158 @@ -582,6 +607,7 @@ var LauncherAssistant = Class.create({
159                 this.globalSearchAssistant.enable(false);
160                 
161                 var appInfoAssistant = new AppInfoAssistant(appInfo,
162 +                                                                                                       this,
163                                                                                                         this.controller,
164                                                                                                         function() {
165                                                                                                                 this.appDialog = undefined;
166 @@ -655,6 +681,9 @@ var LauncherAssistant = Class.create({
167         
168         /* Updates the positions of all page indicators. */
169         updatePageIndicators: function() {
170 +
171 +        // Ensure that the view menu tabs reflect the active page. (LMO)
172 +        this.updatePageHeader();
173                 
174                 if (this.indicators.length <= 0) {
175                         return;
176 @@ -763,6 +792,139 @@ var LauncherAssistant = Class.create({
177         onLaunchCompleted: function(response) {
178                 
179                 this.launchRequest = undefined;
180 -       }
181 -       
182 -});
183 +    },
184 +
185 +    /**
186 +     * Handle tap and meta-tap on the launcher page name header.
187 +     */
188 +    handlePageNameTap: function (event) {
189 +        if (event.up && ( event.up.altKey || event.up.metaKey )) {
190 +            // Handle alt-tap or meta-tap on page header to rename page.
191 +            this.handleRenamePage(event);
192 +        } else {
193 +            // Handle tap on page header to invoke page menu.
194 +            
195 +            // Hide the quick launch panel so there's room for the full menu.
196 +            SystemManagerService.showQuickLaunch(false);
197 +
198 +            // Invoke the page menu.
199 +            this.controller.popupSubmenu({
200 +                placeNear: event.target,
201 +                // Construct the menu based on the names for each page, placing
202 +                // the checkmark appropriately.
203 +                items: this.pageDivs.map(function (alias, idx) {
204 +                    return { 
205 +                        command: idx, 
206 +                        label: this.getPageName(idx), 
207 +                        chosen: (idx == this.activePageIndex) 
208 +                    };
209 +                }, this),
210 +                onChoose: function (command) {
211 +                    // Reveal the quick launch bar and jump to the chosen page.
212 +                    SystemManagerService.showQuickLaunch(true);
213 +                    this.gotoPage(command);
214 +                }.bind(this)
215 +            });
216 +
217 +       }
218 +    },
219 +
220 +    /**
221 +     * Handle request to rename page
222 +     */
223 +    handleRenamePage: function (event) {
224 +        // Hide the quick launch panel and disable the global search so
225 +        // that the dialog is fully visible and usable.
226 +        SystemManagerService.showQuickLaunch(false);
227 +        this.globalSearchAssistant.enable(false);
228 +
229 +        // Invoke the page rename dialog.
230 +        this.renamePageDialog = this.controller.showDialog({
231 +            template: 'launcher/dialogs/rename-page',
232 +            assistant: new RenamePageAssistant(
233 +                this, function () {
234 +                    delete this.renamePageDialog;
235 +                    SystemManagerService.showQuickLaunch(true);
236 +                    this.globalSearchAssistant.enable(true);
237 +                }.bind(this)
238 +            )
239 +        });
240 +    },
241 +
242 +    /**
243 +     * Get the name for a numbered page.
244 +     *
245 +     * @param {integer} idx Page number
246 +     */
247 +    getPageName: function (idx) {
248 +        if (Object.isUndefined(idx)) { idx = this.activePageIndex; }
249 +        return this.page_names[idx] || ('#'+(idx+1));
250 +    },
251 +
252 +    /**
253 +     * Set the name for a numbered page.
254 +     *
255 +     * @param {integer} idx  Page number
256 +     * @param {string}  name Page name
257 +     */
258 +    setPageName: function (idx, name) {
259 +        this.page_names[idx] = name;
260 +        this.savePageNames();
261 +    },
262 +
263 +    /**
264 +     * Save the current state of page names
265 +     */
266 +    savePageNames: function () {
267 +        this.page_names_cookie.put(this.page_names);
268 +    },
269 +
270 +    /**
271 +     * Update the view menu tabs to reflect a given page index. (LMO)
272 +     *
273 +     * @param {int} idx Page index.
274 +     */
275 +    updatePageHeader: function (idx) {
276 +        if (Object.isUndefined(idx)) { idx = this.activePageIndex; }
277 +        this.controller.get('page-category').update(this.getPageName(idx));
278 +    },
279 +
280 +    /**
281 +     * Switch directly to a page. (LMO)
282 +     *
283 +     * @param {int} idx Page index.
284 +     */
285 +    gotoPage: function (idx) {
286 +        var idx = parseInt(idx);
287 +        if (Object.isUndefined(this.pageDivs[idx])) {
288 +            // Bail if attempting to move to a nonexistent page.
289 +            return false;
290 +        }
291 +        // Move to the page, update the on-scene indicators.
292 +        $('launcher_root').mojo.setSnapIndex(idx, true);
293 +        this.activePageIndex = idx;
294 +        this.updatePageIndicators();
295 +        return true;
296 +    },
297 +
298 +    /**
299 +     * Move an app from its existing page to the first position of a new page.
300 +     * Launcher is also switched to that destination page to show the move.
301 +     *
302 +     * @param {string}  launchPointId  Launch point ID in the apps list
303 +     * @param {integer} page_idx       Destination page number
304 +     */
305 +    moveAppToPage: function (launchPointId, page_idx) {
306 +        var from = this.pagesModel.findApplication(launchPointId),
307 +            to = { page: parseInt(page_idx), position: 0 };
308 +        // Move the page in the launcher layout
309 +        this.moveApp(launchPointId, to);
310 +        // Move the page in the page model
311 +        this.pagesModel.moveApplication(from, to);
312 +        // Save the page model changes
313 +        this.pagesModel.save();
314 +        // Switch to the page to show the change
315 +        this.gotoPage(page_idx);
316 +    }
317 +       
318 + });
319 diff --git a/usr/lib/luna/system/luna-applauncher/app/controllers/rename-page-assistant.js b/usr/lib/luna/system/luna-applauncher/app/controllers/rename-page-assistant.js
320 new file mode 100644
321 index 0000000..5777194
322 --- /dev/null
323 +++ b/usr/lib/luna/system/luna-applauncher/app/controllers/rename-page-assistant.js
324 @@ -0,0 +1,76 @@
325 +/**
326 + * Assistant managing the page rename dialog.
327 + */
328 +RenamePageAssistant = Class.create({
329 +
330 +    initialize: function (parent, closeCallback) {
331 +        this.parent = parent;
332 +        this.closeCallback = closeCallback;
333 +    },
334 +
335 +    setup: function (widget) {
336 +        this.widget = widget;
337 +
338 +        var idx = this.parent.activePageIndex,
339 +        page_name = this.parent.getPageName(idx);
340 +
341 +        this.parent.controller.setupWidget(
342 +            'page_rename_field', 
343 +            {
344 +                textReplacement: false,
345 +                focus: true,
346 +                hintText: 'enter page name...',
347 +                changeOnKeyPress: true
348 +            }, 
349 +            this.page_name_model = {
350 +                value: page_name,
351 +                disabled: false
352 +            }
353 +        );
354 +        this.parent.controller.listen(
355 +            'page_rename_field', 
356 +            Mojo.Event.propertyChange, 
357 +            this.handleChange.bindAsEventListener(this)
358 +        );
359 +
360 +        setTimeout(function () {
361 +            // HACK: Auto-focus the rename field after setup is done.
362 +            this.parent.controller.get('page_rename_field').mojo.focus();
363 +        }.bind(this), 1);
364 +
365 +        this.parent.controller.setupWidget('rename_button', {}, 
366 +        { buttonLabel: $L('Rename') });
367 +        this.parent.controller.listen('rename_button', Mojo.Event.tap, 
368 +        this.handleRename.bindAsEventListener(this));
369 +
370 +        this.parent.controller.setupWidget('cancel_button', {}, 
371 +        { buttonLabel: $L('Cancel') });
372 +        this.parent.controller.listen('cancel_button', Mojo.Event.tap, 
373 +        this.handleCancel.bindAsEventListener(this));
374 +    },
375 +
376 +    handleChange: function (event) {
377 +        if (event && Mojo.Char.isEnterKey(event.originalEvent.keyCode)) {
378 +            this.handleRename(event);
379 +        }
380 +    },
381 +
382 +    handleRename: function (event) {
383 +        this.parent.setPageName(
384 +            this.parent.activePageIndex,
385 +            this.parent.controller.get('page_rename_field').mojo.getValue()
386 +        );
387 +        this.parent.updatePageHeader();
388 +        this.widget.mojo.close();
389 +    },
390 +
391 +    handleCancel: function (event) {
392 +        this.widget.mojo.close();
393 +    },
394 +
395 +    cleanup: function() {
396 +        this.closeCallback();
397 +    },
398 +
399 +    EOF:null
400 +});
401 diff --git a/usr/lib/luna/system/luna-applauncher/app/views/launcher/dialogs/app-info.html b/usr/lib/luna/system/luna-applauncher/app/views/launcher/dialogs/app-info.html
402 index bdf3824..bd0a90a 100644
403 --- a/usr/lib/luna/system/luna-applauncher/app/views/launcher/dialogs/app-info.html
404 +++ b/usr/lib/luna/system/luna-applauncher/app/views/launcher/dialogs/app-info.html
405 @@ -8,6 +8,16 @@
406  </div>
407  <div class="palm-dialog-separator"></div>
408  <div class="palm-dialog-buttons">
409 +    <div class="palm-group unlabeled">
410 +        <div class="palm-list">
411 +            <div class="palm-row single">
412 +                <div class="palm-row-wrapper">
413 +                    <div x-mojo-element="ListSelector" 
414 +                        id="page_name" name="page_name"></div>
415 +                </div>
416 +            </div>
417 +        </div>
418 +    </div>
419         <div id='delete-btn' x-mojo-element="Button"></div>     
420         <div id='done-btn' x-mojo-element="Button"></div>
421  </div>
422 diff --git a/usr/lib/luna/system/luna-applauncher/app/views/launcher/dialogs/rename-page.html b/usr/lib/luna/system/luna-applauncher/app/views/launcher/dialogs/rename-page.html
423 new file mode 100644
424 index 0000000..b26286a
425 --- /dev/null
426 +++ b/usr/lib/luna/system/luna-applauncher/app/views/launcher/dialogs/rename-page.html
427 @@ -0,0 +1,24 @@
428 +<div id="palm-dialog-content" class="palm-dialog-content">
429 +    <div class="palm-dialog-title">
430 +        Rename Page
431 +    </div>
432 +    <div class="palm-dialog-separator"></div>
433 +    <div class="textfield-group" x-mojo-focus-highlight="true">
434 +        <div class="title">
435 +            <div class="label">Name</div>
436 +            <div id="page_rename_field" name="page_rename_field" 
437 +                x-mojo-element="TextField"></div>
438 +        </div> 
439 +    </div>
440 +</div>
441 +
442 +<div class="palm-dialog-buttons">
443 +    <div id="rename_button" class="palm-button affirmative" 
444 +        x-mojo-touch-feedback="immediatePersistent">
445 +        <div class="palm-button-wrapper" x-mojo-loc="">Rename</div>
446 +    </div>
447 +    <div id="cancel_button" class="palm-button dismiss" 
448 +        x-mojo-touch-feedback="immediatePersistent">
449 +        <div class="palm-button-wrapper" x-mojo-loc="">Cancel</div>
450 +    </div>
451 +</div>
452 diff --git a/usr/lib/luna/system/luna-applauncher/app/views/launcher/launcher-scene.html b/usr/lib/luna/system/luna-applauncher/app/views/launcher/launcher-scene.html
453 index d34a6a5..61c2788 100644
454 --- a/usr/lib/luna/system/luna-applauncher/app/views/launcher/launcher-scene.html
455 +++ b/usr/lib/luna/system/luna-applauncher/app/views/launcher/launcher-scene.html
456 @@ -18,6 +18,7 @@
457         </div>\r
458         \r
459         <div id="launcher-main">\r
460 +        <div id="page-category" class="palm-header center" x-mojo-touch-feedback="immediate">...</div>\r
461                 <div id="launcher_root" x-mojo-element="Scroller">\r
462                         <div id="pages_container"></div>\r
463                 </div>\r
464 diff --git a/usr/lib/luna/system/luna-applauncher/sources.json b/usr/lib/luna/system/luna-applauncher/sources.json
465 index bb94ae2..79c669d 100644
466 --- a/usr/lib/luna/system/luna-applauncher/sources.json
467 +++ b/usr/lib/luna/system/luna-applauncher/sources.json
468 @@ -27,6 +27,10 @@
469         {
470                 "source": "app\/models\/launcher-pages.js"
471         },
472 +
473 +    {
474 +        "source": "app\/controllers\/rename-page-assistant.js"
475 +    },
476         
477         {
478                 "source": "app\/models\/ApplicationService.js"
479 diff --git a/usr/lib/luna/system/luna-applauncher/stylesheets/launcher.css b/usr/lib/luna/system/luna-applauncher/stylesheets/launcher.css
480 index 45b6546..bbfc6a9 100644
481 --- a/usr/lib/luna/system/luna-applauncher/stylesheets/launcher.css
482 +++ b/usr/lib/luna/system/luna-applauncher/stylesheets/launcher.css
483 @@ -6,6 +6,10 @@ body.palm-default
484         background-image:url(../images/scrim.png);
485  }
486  
487 +#page-category {
488 +       opacity: 0.5;
489 +}
490 +
491  .root {
492         position:relative;
493         overflow:hidden;
494 @@ -59,7 +63,7 @@ body.palm-default
495         width: 100%;
496         z-index: 29;
497         height: 24px;
498 -       top: 1px;
499 +       top: 45px; /* Insert some space for the page selector (LMO) */
500         background: url(../images/fade-arrow-up.png) center center no-repeat;
501         -webkit-palm-mouse-target: ignore;
502  }
503 @@ -106,7 +110,7 @@ body.palm-default
504  }
505  
506  .page_scroller_container {
507 -       margin-top: 10px;
508 +       margin-top: 55px; /* Insert some space for the page selector (LMO) */
509         margin-bottom: -20px;
510  }
511