{ "id": "81219", "key": "TIMOB-5466", "fields": { "issuetype": { "id": "2", "description": "A new feature of the product, which has yet to be developed.", "name": "New Feature", "subtask": false }, "project": { "id": "10153", "key": "TIMOB", "name": "Titanium SDK/CLI", "projectCategory": { "id": "10100", "description": "Titanium and related SDKs used in application development", "name": "Client" } }, "fixVersions": [], "resolution": { "id": "2", "description": "The problem described is an issue which will never be fixed.", "name": "Won't Fix" }, "resolutiondate": "2017-05-26T19:30:20.000+0000", "created": "2011-10-07T02:03:19.000+0000", "priority": { "name": "Low", "id": "4" }, "labels": [], "versions": [ { "id": "11331", "description": "", "name": "Release 1.8.0", "archived": true, "released": true, "releaseDate": "2011-10-31" } ], "issuelinks": [], "assignee": { "name": "ingo", "key": "ingo", "displayName": "Ingo Muschenetz", "active": true, "timeZone": "America/Los_Angeles" }, "updated": "2018-08-02T22:20:03.000+0000", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "components": [ { "id": "10206", "name": "iOS", "description": "iOS Platform" } ], "description": "h1. Feature\r\nExpose a currentWindow feature for a tab so that developers can access the visible window on the tab's stack.\r\n\r\nh2. Expected Behavior\r\nWhenever a window is opened on the tab, currentWindow would point to the newly opened window. The same applies to whenever you close a window: through clicking a back button, programmatically calling tab.close(someWindow), or tapping the tab's button.\r\n\r\nh2. Why This Is Necessary\r\nThe end goal of this is to be able to pop back to the root window of a tab group, cleaning up and closing each window along the way. By exposing currentWindow, we give developers access to data we have internally already.\r\n\r\nh2. Why Name It \"currentWindow\"?\r\nFor parity with Ti.UI.currentWindow.\r\n\r\nh2. Sample Implementation\r\n{code:title=TiUITabProxy.m}\r\n-(id)currentWindow\r\n{\r\n return [current window];\r\n}\r\n{code}\r\n\r\nh2. Sample Documentation\r\n{code:title=Tab.yml}\r\n...\r\n - name: window\r\n description: the root level tab window. all tabs must have at least one root level tab window.\r\n type: Titanium.UI.Window\r\n - name: currentWindow\r\n description: The currently visible window in the tab; the window that was last opened in this tab.\r\n type: Titanium.UI.Window\r\n permission: read-only\r\n...\r\n{code}\r\n\r\nh2. Sample Consuming Code\r\nDrop the following in an app.js. Touch \"S1: Touch Me\" and a series of windows will be popped on to the tab's stack. Then hit \"S2: Touch Me\", and the code will utilize the new currentWindow property to cascade back to the root window.\r\n\r\n{code:title=app.js}\r\nfunction openWindowOnStack(i) {\r\n var win = Ti.UI.createWindow({\r\n title: 'Window ' + i,\r\n rightNavButton: Ti.UI.createButton({ title: 'S2: Touch Me' })\r\n });\r\n win.rightNavButton.addEventListener('click', function() {\r\n popToRoot();\r\n });\r\n win.addEventListener('open', function() {\r\n Ti.API.info('Opened: ' + tab.currentWindow.title);\r\n if (i < 4) {\r\n openWindowOnStack(i + 1);\r\n }\r\n });\r\n win.addEventListener('close', function(evt) {\r\n Ti.API.info('Closed: ' + evt.source.title);\r\n if (evt.source.cascadeClose && !tab.currentWindow.rootWindow) {\r\n tab.currentWindow.cascadeClose = true;\r\n tab.close(tab.currentWindow, { animated: false });\r\n }\r\n });\r\n tab.open(win);\r\n}\r\n\r\nfunction popToRoot() {\r\n tab.currentWindow.cascadeClose = true;\r\n tab.close(tab.currentWindow, { animated: false });\r\n}\r\n\r\nvar outer = Ti.UI.createWindow({\r\n title: 'Root Window',\r\n rightNavButton: Ti.UI.createButton({ title: 'S1: Touch Me' }),\r\n rootWindow: true\r\n});\r\nouter.rightNavButton.addEventListener('click', function() {\r\n openWindowOnStack(0);\r\n});\r\n\r\nvar tabGroup = Ti.UI.createTabGroup();\r\nvar tab = Ti.UI.createTab({\r\n window: outer\r\n});\r\ntabGroup.addTab(tab);\r\ntabGroup.open();\r\n{code}", "attachment": [], "flagged": false, "summary": "iOS: Expose Current Window of Tab in Tab Group", "creator": { "name": "dtoth", "key": "dtoth", "displayName": "Dawson Toth", "active": true, "timeZone": "America/New_York" }, "subtasks": [], "reporter": { "name": "dtoth", "key": "dtoth", "displayName": "Dawson Toth", "active": true, "timeZone": "America/New_York" }, "environment": null, "closedSprints": [ { "id": 1058, "state": "closed", "name": "2018 Sprint 16 SDK", "startDate": "2018-07-29T22:26:06.486Z", "endDate": "2018-08-12T22:26:00.000Z", "completeDate": "2018-08-13T17:38:16.757Z", "originBoardId": 114 } ], "comment": { "comments": [ { "id": "168337", "author": { "name": "dthorp", "key": "dthorp", "displayName": "Don Thorp", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Ti.UI.currentWindow is immutable. It is injected into the JS context that the window was opened with.", "updateAuthor": { "name": "dthorp", "key": "dthorp", "displayName": "Don Thorp", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2011-10-07T12:18:46.000+0000", "updated": "2011-10-07T12:18:46.000+0000" }, { "id": "168342", "author": { "name": "dtoth", "key": "dtoth", "displayName": "Dawson Toth", "active": true, "timeZone": "America/New_York" }, "body": "I'm not asking for Ti.UI.currentWindow, but a new property on the tab itself. Ti.UI.createTab({}).currentWindow. Make sense?", "updateAuthor": { "name": "dtoth", "key": "dtoth", "displayName": "Dawson Toth", "active": true, "timeZone": "America/New_York" }, "created": "2011-10-07T12:23:07.000+0000", "updated": "2011-10-07T12:23:07.000+0000" }, { "id": "168512", "author": { "name": "blainhamon", "key": "blainhamon", "displayName": "Blain Hamon", "active": true, "timeZone": "America/Los_Angeles" }, "body": "At best, this is only going to add to confusion. CurrentWindow refers to the window which owns the context that is executing the javascript, NOT the visible window.\r\n\r\nAt this late in the game, I feel very uncomfortable adding an API without giving it deep thought, especially if we have to support it in later versions. If this functionality is needed, it should be with a better and more consistent metaphor in 1.9.", "updateAuthor": { "name": "blainhamon", "key": "blainhamon", "displayName": "Blain Hamon", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2011-10-09T23:26:36.000+0000", "updated": "2011-10-09T23:26:36.000+0000" }, { "id": "168516", "author": { "name": "dtoth", "key": "dtoth", "displayName": "Dawson Toth", "active": true, "timeZone": "America/New_York" }, "body": "I trust your judgement. I've updated the example with a full JavaScript workaround that will hold the tab group in a consistent state, so long as the three guidelines at the top of the JavaScript are followed:\r\n\r\n{code:title=app.js}\r\n/*\r\n To keep track of and clean up windows that have been opened on a specific tab, you must do the following:\r\n - Whenever you open a window, use the \"openInTab(tab, win)\" function.\r\n - On every window, listen for its \"close\" event and call the \"trackClosedWindow(tab, win)\" function.\r\n - Whenever you want to close all but the root window of a tab, call the \"closeAllInTab(tab)\" function.\r\n */\r\n\r\nfunction openWindowOnStack(i) {\r\n var win = Ti.UI.createWindow({\r\n title: 'Window ' + i,\r\n rightNavButton: Ti.UI.createButton({ title: 'S2: Touch Me' })\r\n });\r\n win.rightNavButton.addEventListener('click', function() {\r\n closeAllInTab(tab);\r\n });\r\n win.addEventListener('open', function(evt) {\r\n Ti.API.info('Opened: ' + evt.source.title);\r\n if (i < 4) {\r\n openWindowOnStack(i + 1);\r\n }\r\n });\r\n win.addEventListener('close', function(evt) {\r\n Ti.API.info('Closed: ' + evt.source.title);\r\n trackClosedWindow(tab, evt.source);\r\n });\r\n openInTab(tab, win);\r\n}\r\n\r\nvar outer = Ti.UI.createWindow({\r\n title: 'Root Window',\r\n rightNavButton: Ti.UI.createButton({ title: 'S1: Touch Me' })\r\n});\r\nouter.rightNavButton.addEventListener('click', function() {\r\n openWindowOnStack(0);\r\n});\r\n\r\nfunction trackClosedWindow(tab, window) {\r\n var windows = tab.windows || [];\r\n // Iterate through backwards because windows further down the tree are more likely to be removed.\r\n for (var w = windows.length - 1; w >= 0; w--) {\r\n if (windows[w] == window) {\r\n windows[w] = null;\r\n windows.splice(w, 1);\r\n break;\r\n }\r\n }\r\n tab.windows = windows;\r\n}\r\nfunction closeAllInTab(tab) {\r\n var windows = tab.windows || [];\r\n // Iterate through forwards because we want to close the most recent window last for a nice animation to the root.\r\n for (var w = 0; w < windows.length; w++) {\r\n windows[w].close();\r\n windows[w] = null;\r\n }\r\n tab.windows = windows = [];\r\n}\r\nfunction openInTab(tab, window) {\r\n var windows = tab.windows || [];\r\n windows.push(window);\r\n tab.open(window);\r\n tab.windows = windows;\r\n}\r\n\r\nvar tabGroup = Ti.UI.createTabGroup();\r\nvar tab = Ti.UI.createTab({\r\n window: outer\r\n});\r\ntabGroup.addTab(tab);\r\ntabGroup.open();\r\n{code}", "updateAuthor": { "name": "dtoth", "key": "dtoth", "displayName": "Dawson Toth", "active": true, "timeZone": "America/New_York" }, "created": "2011-10-10T03:28:17.000+0000", "updated": "2011-10-10T03:28:17.000+0000" }, { "id": "168625", "author": { "name": "blainhamon", "key": "blainhamon", "displayName": "Blain Hamon", "active": true, "timeZone": "America/Los_Angeles" }, "body": "While I agree that there is a need, I do want to think about this, especially for parity's sake.\r\n\r\nWe have the opportunity to have multiple classes to have the same design pattern. For iOS, the Root view, tab group, navGroup, and individual tabs (while they have navGroups built in on iOS) all have the same concept of having many windows, with only one visible at a time. On Android, there are some differences, so this should be addressed in planning.\r\n", "updateAuthor": { "name": "blainhamon", "key": "blainhamon", "displayName": "Blain Hamon", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2011-10-10T07:03:40.000+0000", "updated": "2011-10-10T07:03:40.000+0000" }, { "id": "420539", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "body": "Resolving as {{Won't Fix}}, since the {{Ti.UI.currentWindow}} went away in 6.0.0 as well when removing the {{Ti.UI.Window.url}} property.", "updateAuthor": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2017-05-26T19:30:20.000+0000", "updated": "2017-05-26T19:30:20.000+0000" }, { "id": "439724", "author": { "name": "emerriman", "key": "emerriman", "displayName": "Eric Merriman ", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Closing old \"Won't fix\" tickets. If you disagree, please reopen.", "updateAuthor": { "name": "emerriman", "key": "emerriman", "displayName": "Eric Merriman ", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2018-08-02T22:20:03.000+0000", "updated": "2018-08-02T22:20:03.000+0000" } ], "maxResults": 10, "total": 10, "startAt": 0 } } }