{ "id": "109043", "key": "TIMOB-12553", "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": [ { "id": "15703", "description": "2013 Sprint 22", "name": "2013 Sprint 22", "archived": true, "released": true, "releaseDate": "2013-11-01" }, { "id": "14982", "description": "Release 3.2.0", "name": "Release 3.2.0", "archived": false, "released": true, "releaseDate": "2013-12-19" } ], "resolution": { "id": "1", "description": "A fix for this issue is checked into the tree and tested.", "name": "Fixed" }, "resolutiondate": "2013-10-24T22:40:56.000+0000", "created": "2013-02-01T19:41:44.000+0000", "priority": { "name": "High", "id": "2" }, "labels": [ "qe-closed-3.2.0" ], "versions": [ { "id": "13505", "description": "Release 3.0.0", "name": "Release 3.0.0", "archived": true, "released": true, "releaseDate": "2012-12-14" } ], "issuelinks": [ { "id": "25429", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "outwardIssue": { "id": "81429", "key": "TIMOB-5744", "fields": { "summary": "Android: Titanium objects' toString method is not consistent", "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" } }, "priority": { "name": "Trivial", "id": "5" }, "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false } } } }, { "id": "29043", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "outwardIssue": { "id": "99986", "key": "ALOY-210", "fields": { "summary": "Support Dynamic Styling", "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" } }, "priority": { "name": "Critical", "id": "1" }, "issuetype": { "id": "2", "description": "A new feature of the product, which has yet to be developed.", "name": "New Feature", "subtask": false } } } }, { "id": "25513", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "inwardIssue": { "id": "109216", "key": "TIMOB-12595", "fields": { "summary": "TiAPI: Add support for constructors for controls", "status": { "description": "The issue is open and ready for the assignee to start work on it.", "name": "Open", "id": "1", "statusCategory": { "id": 2, "key": "new", "colorName": "blue-gray", "name": "To Do" } }, "priority": { "name": "High", "id": "2" }, "issuetype": { "id": "7", "description": "gh.issue.story.desc", "name": "Story", "subtask": false } } } }, { "id": "29539", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "inwardIssue": { "id": "115878", "key": "ALOY-706", "fields": { "summary": "Store \"classes\" and \"apiName\" on Alloy-created proxies", "status": { "description": "A resolution has been taken, and it is awaiting verification by reporter. From here issues are either reopened, or are closed.", "name": "Resolved", "id": "5", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "priority": { "name": "High", "id": "2" }, "issuetype": { "id": "2", "description": "A new feature of the product, which has yet to be developed.", "name": "New Feature", "subtask": false } } } } ], "assignee": { "name": "ingo", "key": "ingo", "displayName": "Ingo Muschenetz", "active": true, "timeZone": "America/Los_Angeles" }, "updated": "2013-12-11T23:52:49.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": "10224", "name": "TiAPI", "description": "This component is used for cross-platform API work. Specifications are most likely to use this component." } ], "description": "Currently there is no way to inspect an object's type reliably. typeof just returns \"object\" and toString() is notoriously unreliable, and parsing toString is considered a big no-no (similar to parsing user agents).\r\n\r\nAlloy needs this information to implement dynamic styles.", "attachment": [], "flagged": false, "summary": "TiAPI: Implement \"apiName\" property on proxies", "creator": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "subtasks": [ { "id": "114860", "key": "TIMOB-13968", "fields": { "summary": "Specification: Create \"apiName\" property specification", "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" } }, "priority": { "name": "High", "id": "2" }, "issuetype": { "id": "5", "description": "The sub-task of the issue", "name": "Sub-task", "subtask": true } } }, { "id": "115898", "key": "TIMOB-14217", "fields": { "summary": "iOS: Implement apiName constants", "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" } }, "priority": { "name": "Medium", "id": "3" }, "issuetype": { "id": "5", "description": "The sub-task of the issue", "name": "Sub-task", "subtask": true } } }, { "id": "115899", "key": "TIMOB-14218", "fields": { "summary": "Android: Implement apiName constants", "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" } }, "priority": { "name": "Medium", "id": "3" }, "issuetype": { "id": "5", "description": "The sub-task of the issue", "name": "Sub-task", "subtask": true } } }, { "id": "115900", "key": "TIMOB-14219", "fields": { "summary": "MobileWeb: Implement apiName constants", "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" } }, "priority": { "name": "Medium", "id": "3" }, "issuetype": { "id": "5", "description": "The sub-task of the issue", "name": "Sub-task", "subtask": true } } }, { "id": "115901", "key": "TIMOB-14220", "fields": { "summary": "BlackBerry: Implement apiName constants", "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" } }, "priority": { "name": "Medium", "id": "3" }, "issuetype": { "id": "5", "description": "The sub-task of the issue", "name": "Sub-task", "subtask": true } } }, { "id": "115902", "key": "TIMOB-14222", "fields": { "summary": "Tizen: Implement apiName constants", "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" } }, "priority": { "name": "Medium", "id": "3" }, "issuetype": { "id": "5", "description": "The sub-task of the issue", "name": "Sub-task", "subtask": true } } } ], "reporter": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "environment": null, "comment": { "comments": [ { "id": "236932", "author": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "body": "We may also want to consider the behavior of instanceof. i.e. it would be really useful if we could do:\r\n{code}\r\nvar label = Ti.UI.createLabel();\r\nconsole.log(label instanceof Ti.UI.Label); // logs \"true\"\r\n{code}\r\nThis works perfectly fine with pure JS objects", "updateAuthor": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-02-01T19:47:08.000+0000", "updated": "2013-02-01T19:47:49.000+0000" }, { "id": "237004", "author": { "name": "ivan.skugor", "key": "ivan.skugor", "displayName": "Ivan Skugor", "active": true, "timeZone": "Europe/Amsterdam" }, "body": "IMHO - \"typeof\" produces same result as it was called on native object so that should be fine. \"toString\" is inconsistent because it's made that way. Yes - it can produce anything for host objects in theory and it's not something that can be relied on - in DOM environment. But Titanium is a lot different, there are no X vendors with their own implementations of \"toString\", in Titanium environment \"toString\" can be made consistent in same manner as \"type\" property - there is really no difference in using property instead of method.\r\n\r\nActually, \"toString\" can use \"type\" property to produce consistent string (that's actually \"type\" wrapped with constant string - \"[object \" + object.type + \"]\").\r\n\r\n\r\n***\r\n\r\n\r\n\"instanceof\" would solve some problems. However, \"instanceof\" is used in prototype inheritance, which Titanium objects do not support. Not sure what ECMA specification says about \"instanceof\" and host objects, but I doubt that it permits partial implementation.", "updateAuthor": { "name": "ivan.skugor", "key": "ivan.skugor", "displayName": "Ivan Skugor", "active": true, "timeZone": "Europe/Amsterdam" }, "created": "2013-02-02T12:15:21.000+0000", "updated": "2013-02-02T12:15:21.000+0000" }, { "id": "237053", "author": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Remember Ivan that Mobile Web *is* in a DOM environment, so whatever restrictions there are in DOM-land apply to Titanium as well.\n\nThe other problem with toString is that, as you said, you get \"[object\" + type + \"]\", meaning that apps have to do some string manipulation to figure out the type, typically using a regex, and performance wise doing a direct string comparison will be a lot faster.\n\nTitanium objects do use prototypal inheritance on Mobile Web today, and my goal is that all platforms will one day", "updateAuthor": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-02-04T18:12:06.000+0000", "updated": "2013-02-04T18:12:06.000+0000" }, { "id": "237211", "author": { "name": "ivan.skugor", "key": "ivan.skugor", "displayName": "Ivan Skugor", "active": true, "timeZone": "Europe/Amsterdam" }, "body": "Bryan,\r\n\r\n\r\nyes, it is true that Mobile Web is implemented in DOM environment - however, that's is not so relevant. Let me explain. \"toString\" always produce same result for native objects. The only problem are host objects, that is - DOM objects (because, by specification, \"toString\" call on DOM objects can produce whatever). But in Mobile Web we won't use DOM directly, we'll use Titanium objects that can override \"toString\" method so it produces desired string. Right? :)\r\n\r\n\r\nI wouldn't use regex (although, I think they are quite fast for this particular case) because it's not necessary: var isButton = button.toString() == \"[object TiUIButton]\";\r\nThere is no need to extract \"Button\" from that string.\r\n\r\n\r\nPrototypal inheritance on all platforms would be really great. Then, we wouldn't have to use \"toString\" - var isButton = button instanceof Ti.UI.Button; (or something like that).\r\nI did develop technique that enables prototypal inheritance in Titanium by using native objects as wrappers (don't know if you saw it already): http://zenborgium.blogspot.com/2012/09/prototype-based-inheritance-in-titanium.html\r\nI'll open source whole solution next week - you may find some interesting ideas there.\r\n\r\n\r\n\r\nCheers.", "updateAuthor": { "name": "ivan.skugor", "key": "ivan.skugor", "displayName": "Ivan Skugor", "active": true, "timeZone": "Europe/Amsterdam" }, "created": "2013-02-05T13:22:47.000+0000", "updated": "2013-02-05T13:22:47.000+0000" }, { "id": "237236", "author": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "body": "We could override toString, but that takes a lot more code to override a function than a property, and size is the single most important performance factor in Mobile Web, so that's a non-starter. As for the name of the string itself, TiUIButton is a non-starter as well because it doesn't align with our long-term goals for the platform. Eventually, the only name you will care about is 'ti/ui/button' and any other permutation will not be visible in JavaScript land. We could do '[object ti/ui/button]', but that's a LOT of wasted characters (going back to size==performance).", "updateAuthor": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-02-05T18:07:24.000+0000", "updated": "2013-02-05T18:07:24.000+0000" }, { "id": "237415", "author": { "name": "ivan.skugor", "key": "ivan.skugor", "displayName": "Ivan Skugor", "active": true, "timeZone": "Europe/Amsterdam" }, "body": "I don't know Mobile Web architecture well, but isn't there some base \"class\" (prototype object) for all UI components? \"toString\" could be defined just there. Something like this:\r\n\r\nElement.prototype.toString = function() { return \"[object \" + this.type + \"]\" };\r\n\r\nand other objects that inherent from base \"class\"/object could just define \"type\" property.\r\n\"TiUIButton\" was just an example, you can put there whatever you want (as long as it's identical to what other platforms produce).\r\n\r\n\r\nOr, modify \"declare\" function: https://github.com/appcelerator/titanium_mobile/blob/master/mobileweb/titanium/Ti/_/declare.js\r\nThere, \"className\" could be used to define \"toString\" method. It could be optimal solution because you wouldn't have to define \"type\" property everywhere, just use \"className\" and a bit of string manipulation to get desired format.\r\n\r\nTrivial implementation (without string manipulation): definition.toString = function() { return \"[object \" + className + \"]\"; };\r\n\r\n\r\n\r\n\r\nSorry, but I just can't believe that \"toString\" implementation can be so complicated and can impact so much on framework size and performance. :D", "updateAuthor": { "name": "ivan.skugor", "key": "ivan.skugor", "displayName": "Ivan Skugor", "active": true, "timeZone": "Europe/Amsterdam" }, "created": "2013-02-06T10:52:45.000+0000", "updated": "2013-02-06T10:52:45.000+0000" }, { "id": "237441", "author": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Hmmm...that is a possibility. My question to you is why are you so insistent on toString() specifically? Just because something is possible doesn't make it a good idea. Function calls give more overhead and you get a string back that isn't very direct and has a lot of cruft in it's format. This mechanism would be a lot more elegant.", "updateAuthor": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-02-06T16:40:46.000+0000", "updated": "2013-02-06T16:40:46.000+0000" }, { "id": "237445", "author": { "name": "ivan.skugor", "key": "ivan.skugor", "displayName": "Ivan Skugor", "active": true, "timeZone": "Europe/Amsterdam" }, "body": "It's more standardised way of getting object's type/class and it's more common practice to use \"toString\" then \"type\". Also, \"toString\" is called automatically in some cases, while \"type\" property is not.\r\n\r\n\r\nWell, function calls are not overhead in modern JS engines because they'll optimise functions that are slow or used often. I doubt \"toString\" will cause any performance issue even without those optimisations because it's quite fast and it won't be called so much in the code.", "updateAuthor": { "name": "ivan.skugor", "key": "ivan.skugor", "displayName": "Ivan Skugor", "active": true, "timeZone": "Europe/Amsterdam" }, "created": "2013-02-06T16:55:42.000+0000", "updated": "2013-02-06T16:55:42.000+0000" }, { "id": "253701", "author": { "name": "tlukasavage", "key": "tlukasavage", "displayName": "Tony Lukasavage", "active": true, "timeZone": "America/Los_Angeles" }, "body": "We should probably use something other than \"classname\" to avoid confusion with [Ti.UI.TableViewRow.className|http://docs.appcelerator.com/titanium/latest/#!/api/Titanium.UI.TableViewRow-property-className]. Perhaps:\r\n* api\r\n* type\r\n* apiType\r\n* apiName", "updateAuthor": { "name": "tlukasavage", "key": "tlukasavage", "displayName": "Tony Lukasavage", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-05-23T19:10:21.000+0000", "updated": "2013-05-23T19:12:06.000+0000" }, { "id": "257669", "author": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "body": "why can't we just implement the instanceof? i'm with Bryan on this. also having \"classname\" and \"className\" are VERY BAD. i'd prefer \"instanceof\" or \"typeof\" property if we have to use a property.", "updateAuthor": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2013-06-13T18:08:51.000+0000", "updated": "2013-06-13T18:08:51.000+0000" }, { "id": "257710", "author": { "name": "rblalock", "key": "rblalock", "displayName": "Rick Blalock", "active": false, "timeZone": "America/Havana" }, "body": "I like instanceof. Not a super fan of typeof but would work too. What about Titanium.instanceof ? Keeps the standard JS instanceof / typeof clean that way.", "updateAuthor": { "name": "rblalock", "key": "rblalock", "displayName": "Rick Blalock", "active": false, "timeZone": "America/Havana" }, "created": "2013-06-13T19:04:01.000+0000", "updated": "2013-06-13T19:04:01.000+0000" }, { "id": "257711", "author": { "name": "rblalock", "key": "rblalock", "displayName": "Rick Blalock", "active": false, "timeZone": "America/Havana" }, "body": "errr. meant to type Titanium.instanceof(somethingHere)", "updateAuthor": { "name": "rblalock", "key": "rblalock", "displayName": "Rick Blalock", "active": false, "timeZone": "America/Havana" }, "created": "2013-06-13T19:05:36.000+0000", "updated": "2013-06-13T19:05:51.000+0000" }, { "id": "257742", "author": { "name": "cbarber", "key": "cbarber", "displayName": "Chris Barber", "active": true, "timeZone": "America/Chicago" }, "body": "Mobile Web already has this and it's called \"declaredClass\".\n\n{code}\nvar myview = Ti.UI.createView();\nconsole.log(myview.declaredClass); // 'Ti.UI.View'\nconsole.log(myview.toString()); // '[object TiUIView]'\n{code}\n\nOne caveat is that Mobile Web is not able to detect if a particular instance is an instanceof a deep base class. We collapse the hierarchy for speed. In other words, there's no way to know if a Ti.UI.Button is actually an instanceOf Ti.UI.View (even though we know it is).\n\nMy preference is to support \"declaredClass\". I'm not a huge fan of instanceOf(), but Mobile Web can at least be made to support it.\n", "updateAuthor": { "name": "cbarber", "key": "cbarber", "displayName": "Chris Barber", "active": true, "timeZone": "America/Chicago" }, "created": "2013-06-13T20:47:03.000+0000", "updated": "2013-06-13T20:47:03.000+0000" }, { "id": "257743", "author": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "body": "We can't really use declaredClass though. The format of the string is going to be \"Ti.UI.Button\", not \"Ti/UI/Button\", and I suspect changing the format of declared class would break the loader. FWIW the format has already been decided upon and can be viewed in the specification sub-task.", "updateAuthor": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-06-13T20:51:36.000+0000", "updated": "2013-06-13T20:52:27.000+0000" }, { "id": "257789", "author": { "name": "cbarber", "key": "cbarber", "displayName": "Chris Barber", "active": true, "timeZone": "America/Chicago" }, "body": "[~bhughes] How do you figure?\n\n!https://www.evernote.com/shard/s75/sh/43c65ffe-11c8-4691-bbaf-759a81520bbb/89c80289497405e30a692c55172f57cb/deep/0/Screenshot%206/13/13%203:57%20PM.jpg!", "updateAuthor": { "name": "cbarber", "key": "cbarber", "displayName": "Chris Barber", "active": true, "timeZone": "America/Chicago" }, "created": "2013-06-13T22:59:02.000+0000", "updated": "2013-06-13T22:59:02.000+0000" }, { "id": "257796", "author": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Oh, my bad. I thought that declared class was formatted with slashes, not dots. Either way, we already agreed on and approved the name \"apiName\". Should have attended the architecture meeting :)", "updateAuthor": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-06-13T23:13:53.000+0000", "updated": "2013-06-13T23:13:53.000+0000" }, { "id": "276697", "author": { "name": "pwang", "key": "pwang", "displayName": "Ping Wang", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Resolved the ticket since all the subtasks are done.", "updateAuthor": { "name": "pwang", "key": "pwang", "displayName": "Ping Wang", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-10-24T22:40:56.000+0000", "updated": "2013-10-24T22:40:56.000+0000" }, { "id": "283664", "author": { "name": "emerriman", "key": "emerriman", "displayName": "Eric Merriman ", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Is there any test guidance on this feature?", "updateAuthor": { "name": "emerriman", "key": "emerriman", "displayName": "Eric Merriman ", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-12-10T22:42:28.000+0000", "updated": "2013-12-10T22:42:28.000+0000" }, { "id": "283669", "author": { "name": "cbarber", "key": "cbarber", "displayName": "Chris Barber", "active": true, "timeZone": "America/Chicago" }, "body": "[~emerriman] Try this:\n\n{code}\nvar myview = Ti.UI.createView();\nconsole.log(myview.apiName);\n{code}", "updateAuthor": { "name": "cbarber", "key": "cbarber", "displayName": "Chris Barber", "active": true, "timeZone": "America/Chicago" }, "created": "2013-12-10T22:51:24.000+0000", "updated": "2013-12-10T22:51:24.000+0000" }, { "id": "283900", "author": { "name": "sdowse", "key": "sdowse", "displayName": "Samuel Dowse", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Tested on:\nMac OSX 10.9 Mavericks\nAppcelerator Studio, build: 3.2.0.201312101708\nTitanium SDK, build: 3.2.0.v20131210191510\nCLI: 3.2.0-cr\nAlloy: 1.3.0-cr\nMozilla Firefox: 26.0.0\n\nUsed test case provided by Chris Barber.\nOpened the project in browser and checked web console.\nOutcome displayed as expected.\nClosing.", "updateAuthor": { "name": "sdowse", "key": "sdowse", "displayName": "Samuel Dowse", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-12-11T23:52:36.000+0000", "updated": "2013-12-11T23:52:36.000+0000" } ], "maxResults": 20, "total": 20, "startAt": 0 } } }