{"action":"created","comment":{"url":"https://api.github.com/repos/skatejs/skatejs/pulls/comments/40513459","id":40513459,"diff_hunk":"@@ -0,0 +1,164 @@\n+import dashCase from '../util/dash-case';\n+import data from '../util/data';\n+import emit from '../api/emit';\n+\n+// TODO Decouple boolean attributes from the Boolean function.\n+// TODO Split apart createNativePropertyDefinition function.\n+\n+function getLinkedAttribute (name, attr) {\n+  return attr === true ? dashCase(name) : attr;\n+}\n+\n+function createNativePropertyDefinition (name, opts) {\n+  let prop = {\n+    configurable: true,\n+    enumerable: true\n+  };\n+\n+  prop.created = function (elem, initialValue) {\n+    let info = data(elem, `api/property/${name}`);\n+    info.linkedAttribute = getLinkedAttribute(name, opts.attribute);\n+    info.removeAttribute = elem.removeAttribute;\n+    info.setAttribute = elem.setAttribute;\n+    info.updatingProperty = false;\n+\n+    // TODO Refactor\n+    if (info.linkedAttribute) {\n+      if (!info.attributeMap) {\n+        info.attributeMap = {};\n+\n+        elem.removeAttribute = function (attrName) {\n+          info.removeAttribute.call(this, attrName);\n+          if (attrName in info.attributeMap) {\n+            elem[info.attributeMap[attrName]] = undefined;\n+          }\n+        };\n+\n+        elem.setAttribute = function (attrName, attrValue) {\n+          info.setAttribute.call(this, attrName, attrValue);\n+          if (attrName in info.attributeMap) {\n+            // Could also call getAttribute() but this does the same thing.\n+            attrValue = String(attrValue);\n+            elem[info.attributeMap[attrName]] = opts.deserialize ? opts.deserialize(attrValue) : attrValue;\n+          }\n+        };\n+      }\n+\n+      info.attributeMap[info.linkedAttribute] = name;\n+    }\n+\n+    if (initialValue === undefined) {\n+      if (info.linkedAttribute && elem.hasAttribute(info.linkedAttribute)) {\n+        let attributeValue = elem.getAttribute(info.linkedAttribute);\n+        initialValue = opts.deserialize ? opts.deserialize(attributeValue) : attributeValue;\n+      } else if (typeof opts.default === 'function') {\n+        initialValue = opts.default();\n+      } else if (typeof opts.default !== 'undefined') {\n+        initialValue = opts.default;\n+      }\n+    }\n+\n+    info.internalValue = initialValue;\n+  };\n+\n+  prop.get = function () {\n+    let value = opts.get ? opts.get(this) : data(this, `api/property/${name}`).internalValue;\n+\n+    if (value === undefined && opts.default !== undefined) {\n+      if (typeof opts.default === 'function') {\n+        value = opts.default();\n+      } else {\n+        value = opts.default;\n+      }\n+    }\n+\n+    return value;\n+  };\n+\n+  prop.ready = function (elem, value) {\n+    if (opts.type) {\n+      opts.type(value);\n+    }\n+\n+    if (opts.set) {\n+      opts.set(elem, {\n+        name: name,\n+        newValue: value,\n+        oldValue: undefined\n+      });\n+    }\n+  };\n+\n+  prop.set = function (newValue) {\n+    let info = data(this, `api/property/${name}`);\n+\n+    if (info.updatingProperty) {\n+      return;\n+    }\n+\n+    info.updatingProperty = true;\n+    let oldValue = this[name];\n+\n+    if (!opts.get) {\n+      info.internalValue = newValue;\n+    }\n+\n+    if (newValue === oldValue) {\n+      info.updatingProperty = false;\n+      return;\n+    }\n+\n+    if (opts.type) {\n+      opts.type(newValue);\n+    }\n+\n+    if (info.linkedAttribute) {\n+      let serializedValue = opts.serialize ? opts.serialize(newValue) : newValue;\n+      if (serializedValue === undefined) {\n+        info.removeAttribute.call(this, info.linkedAttribute);\n+      } else {\n+        info.setAttribute.call(this, info.linkedAttribute, serializedValue);\n+      }\n+    }\n+\n+    let changeData = {\n+      name: name,\n+      newValue: newValue,\n+      oldValue: oldValue\n+    };\n+\n+    if (opts.set) {\n+      opts.set(this, changeData);","path":"src/lifecycle/property.js","position":131,"original_position":131,"commit_id":"7ce5b3561b12a95f40568f34de7c946d7d2c0c3d","original_commit_id":"7ce5b3561b12a95f40568f34de7c946d7d2c0c3d","user":{"login":"treshugart","id":136556,"avatar_url":"https://avatars.githubusercontent.com/u/136556?v=3","gravatar_id":"","url":"https://api.github.com/users/treshugart","html_url":"https://github.com/treshugart","followers_url":"https://api.github.com/users/treshugart/followers","following_url":"https://api.github.com/users/treshugart/following{/other_user}","gists_url":"https://api.github.com/users/treshugart/gists{/gist_id}","starred_url":"https://api.github.com/users/treshugart/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/treshugart/subscriptions","organizations_url":"https://api.github.com/users/treshugart/orgs","repos_url":"https://api.github.com/users/treshugart/repos","events_url":"https://api.github.com/users/treshugart/events{/privacy}","received_events_url":"https://api.github.com/users/treshugart/received_events","type":"User","site_admin":false},"body":"It shouldn't. Internally, Skate will just move the `Object.defineProperty()` call to the `prototype` rather than doing it on the element instance itself. The public definition remains the same.","created_at":"2015-09-28T01:33:13Z","updated_at":"2015-09-28T01:33:13Z","html_url":"https://github.com/skatejs/skatejs/pull/334#discussion_r40513459","pull_request_url":"https://api.github.com/repos/skatejs/skatejs/pulls/334","_links":{"self":{"href":"https://api.github.com/repos/skatejs/skatejs/pulls/comments/40513459"},"html":{"href":"https://github.com/skatejs/skatejs/pull/334#discussion_r40513459"},"pull_request":{"href":"https://api.github.com/repos/skatejs/skatejs/pulls/334"}}},"pull_request":{"url":"https://api.github.com/repos/skatejs/skatejs/pulls/334","id":45469607,"html_url":"https://github.com/skatejs/skatejs/pull/334","diff_url":"https://github.com/skatejs/skatejs/pull/334.diff","patch_url":"https://github.com/skatejs/skatejs/pull/334.patch","issue_url":"https://api.github.com/repos/skatejs/skatejs/issues/334","number":334,"state":"open","locked":false,"title":"#281 - Finalise property options.","user":{"login":"treshugart","id":136556,"avatar_url":"https://avatars.githubusercontent.com/u/136556?v=3","gravatar_id":"","url":"https://api.github.com/users/treshugart","html_url":"https://github.com/treshugart","followers_url":"https://api.github.com/users/treshugart/followers","following_url":"https://api.github.com/users/treshugart/following{/other_user}","gists_url":"https://api.github.com/users/treshugart/gists{/gist_id}","starred_url":"https://api.github.com/users/treshugart/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/treshugart/subscriptions","organizations_url":"https://api.github.com/users/treshugart/orgs","repos_url":"https://api.github.com/users/treshugart/repos","events_url":"https://api.github.com/users/treshugart/events{/privacy}","received_events_url":"https://api.github.com/users/treshugart/received_events","type":"User","site_admin":false},"body":"### Property Changes\r\n\r\nThe property API has been completely refactored to work with the current test suite, but so that specifying custom properties is done simply by specifying an object that is compatible with `Object.defineProperty()`:\r\n\r\n```js\r\nlet myPropDefinition1 = {\r\n  get () {},\r\n  set () {},\r\n  created () {},\r\n  ready () {}\r\n};\r\n\r\nlet myPropDefinition2 = function (opts) {\r\n  return {\r\n    get () {},\r\n    set () {},\r\n    created () {},\r\n    ready () {}\r\n  };\r\n}\r\n\r\nproperties: {\r\n  myProp1: myPropDefinition1,\r\n  myProp2: myPropDefinition2({})\r\n}\r\n```\r\n\r\n\\* *Currently the old property definition is still supported, but this is the proposed future.*\r\n\r\nIt supports a superset of options on top of the native options so that it works into the Skate lifecycle:\r\n\r\n- `created` called after the main `created` lifecycle to set up the property. Good for setting initial values if overriding an existing property without having to invoke the setter which may cause mutations to happen before the descendant tree is initialised.\r\n- `ready` called just before the `ready` callback. This is so that a property can wait until the descendant tree has been initialised before triggering anything that might mutate the DOM.\r\n\r\nThese property lifecycle callbacks are required in order to allow us to define properties separately from:\r\n\r\n- overriding of existing properties\r\n- setting up the property based on information from the element\r\n- the ability to delay the triggering of a callback when the property is set in case it has mutations and the descendant DOM must be initialised\r\n\r\nThese wouldn't be necessary if we were to define the property at initialisation time while passing in the element but this has performance and long-term API implications:\r\n\r\n- you end up running the property setup function for every single property of every single instance\r\n- it at least can run and return the definition that will be applied to every single property of every single instance, so it's saving a little bit of memory and cpu cycles\r\n- it sets us up to be able to define properties on the prototype once, instead of for every single instance once [this 5 year-old bug](https://bugs.webkit.org/show_bug.cgi?id=49739) is fixed and we support a version of Webkit that it lands in. Every other browser supports accessing of native property getters / setters\r\n- even if we decided to set aside the performance concerns, it would lock us into a property API that would prevent us from later using the prototype\r\n\r\n### Render Changes\r\n\r\nThe following has been done to help accommodate server-side rendering. It's recommended this be done with property finalisation because how we finalise properties will affect server-side rendering and vice-versa.\r\n\r\n- Moving responsibility of `render` to `renderer` that is responsible for rendering the \"shadow\" DOM.\r\n- Re-purpose `render` so that it's sole responsibility is to return a rendered \"shadow\" template.","created_at":"2015-09-19T04:17:15Z","updated_at":"2015-09-28T01:33:13Z","closed_at":null,"merged_at":null,"merge_commit_sha":"389b07339b29009f93cf1fb25e8557fd8b7195be","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/skatejs/skatejs/pulls/334/commits","review_comments_url":"https://api.github.com/repos/skatejs/skatejs/pulls/334/comments","review_comment_url":"https://api.github.com/repos/skatejs/skatejs/pulls/comments{/number}","comments_url":"https://api.github.com/repos/skatejs/skatejs/issues/334/comments","statuses_url":"https://api.github.com/repos/skatejs/skatejs/statuses/7ce5b3561b12a95f40568f34de7c946d7d2c0c3d","head":{"label":"skatejs:281","ref":"281","sha":"7ce5b3561b12a95f40568f34de7c946d7d2c0c3d","user":{"login":"skatejs","id":7636121,"avatar_url":"https://avatars.githubusercontent.com/u/7636121?v=3","gravatar_id":"","url":"https://api.github.com/users/skatejs","html_url":"https://github.com/skatejs","followers_url":"https://api.github.com/users/skatejs/followers","following_url":"https://api.github.com/users/skatejs/following{/other_user}","gists_url":"https://api.github.com/users/skatejs/gists{/gist_id}","starred_url":"https://api.github.com/users/skatejs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/skatejs/subscriptions","organizations_url":"https://api.github.com/users/skatejs/orgs","repos_url":"https://api.github.com/users/skatejs/repos","events_url":"https://api.github.com/users/skatejs/events{/privacy}","received_events_url":"https://api.github.com/users/skatejs/received_events","type":"Organization","site_admin":false},"repo":{"id":16425042,"name":"skatejs","full_name":"skatejs/skatejs","owner":{"login":"skatejs","id":7636121,"avatar_url":"https://avatars.githubusercontent.com/u/7636121?v=3","gravatar_id":"","url":"https://api.github.com/users/skatejs","html_url":"https://github.com/skatejs","followers_url":"https://api.github.com/users/skatejs/followers","following_url":"https://api.github.com/users/skatejs/following{/other_user}","gists_url":"https://api.github.com/users/skatejs/gists{/gist_id}","starred_url":"https://api.github.com/users/skatejs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/skatejs/subscriptions","organizations_url":"https://api.github.com/users/skatejs/orgs","repos_url":"https://api.github.com/users/skatejs/repos","events_url":"https://api.github.com/users/skatejs/events{/privacy}","received_events_url":"https://api.github.com/users/skatejs/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/skatejs/skatejs","description":"Skate is a web component library that provides an API to bind behaviour to DOM elements. It's based on the W3C specification for Custom Elements.","fork":false,"url":"https://api.github.com/repos/skatejs/skatejs","forks_url":"https://api.github.com/repos/skatejs/skatejs/forks","keys_url":"https://api.github.com/repos/skatejs/skatejs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/skatejs/skatejs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/skatejs/skatejs/teams","hooks_url":"https://api.github.com/repos/skatejs/skatejs/hooks","issue_events_url":"https://api.github.com/repos/skatejs/skatejs/issues/events{/number}","events_url":"https://api.github.com/repos/skatejs/skatejs/events","assignees_url":"https://api.github.com/repos/skatejs/skatejs/assignees{/user}","branches_url":"https://api.github.com/repos/skatejs/skatejs/branches{/branch}","tags_url":"https://api.github.com/repos/skatejs/skatejs/tags","blobs_url":"https://api.github.com/repos/skatejs/skatejs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/skatejs/skatejs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/skatejs/skatejs/git/refs{/sha}","trees_url":"https://api.github.com/repos/skatejs/skatejs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/skatejs/skatejs/statuses/{sha}","languages_url":"https://api.github.com/repos/skatejs/skatejs/languages","stargazers_url":"https://api.github.com/repos/skatejs/skatejs/stargazers","contributors_url":"https://api.github.com/repos/skatejs/skatejs/contributors","subscribers_url":"https://api.github.com/repos/skatejs/skatejs/subscribers","subscription_url":"https://api.github.com/repos/skatejs/skatejs/subscription","commits_url":"https://api.github.com/repos/skatejs/skatejs/commits{/sha}","git_commits_url":"https://api.github.com/repos/skatejs/skatejs/git/commits{/sha}","comments_url":"https://api.github.com/repos/skatejs/skatejs/comments{/number}","issue_comment_url":"https://api.github.com/repos/skatejs/skatejs/issues/comments{/number}","contents_url":"https://api.github.com/repos/skatejs/skatejs/contents/{+path}","compare_url":"https://api.github.com/repos/skatejs/skatejs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/skatejs/skatejs/merges","archive_url":"https://api.github.com/repos/skatejs/skatejs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/skatejs/skatejs/downloads","issues_url":"https://api.github.com/repos/skatejs/skatejs/issues{/number}","pulls_url":"https://api.github.com/repos/skatejs/skatejs/pulls{/number}","milestones_url":"https://api.github.com/repos/skatejs/skatejs/milestones{/number}","notifications_url":"https://api.github.com/repos/skatejs/skatejs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/skatejs/skatejs/labels{/name}","releases_url":"https://api.github.com/repos/skatejs/skatejs/releases{/id}","created_at":"2014-02-01T00:32:47Z","updated_at":"2015-09-24T12:21:40Z","pushed_at":"2015-09-25T23:47:03Z","git_url":"git://github.com/skatejs/skatejs.git","ssh_url":"git@github.com:skatejs/skatejs.git","clone_url":"https://github.com/skatejs/skatejs.git","svn_url":"https://github.com/skatejs/skatejs","homepage":"http://skate.js.org","size":6697,"stargazers_count":502,"watchers_count":502,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":22,"mirror_url":null,"open_issues_count":10,"forks":22,"open_issues":10,"watchers":502,"default_branch":"master"}},"base":{"label":"skatejs:master","ref":"master","sha":"27035de8be2a9ea88d0d7d8c76b9feecc59559dc","user":{"login":"skatejs","id":7636121,"avatar_url":"https://avatars.githubusercontent.com/u/7636121?v=3","gravatar_id":"","url":"https://api.github.com/users/skatejs","html_url":"https://github.com/skatejs","followers_url":"https://api.github.com/users/skatejs/followers","following_url":"https://api.github.com/users/skatejs/following{/other_user}","gists_url":"https://api.github.com/users/skatejs/gists{/gist_id}","starred_url":"https://api.github.com/users/skatejs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/skatejs/subscriptions","organizations_url":"https://api.github.com/users/skatejs/orgs","repos_url":"https://api.github.com/users/skatejs/repos","events_url":"https://api.github.com/users/skatejs/events{/privacy}","received_events_url":"https://api.github.com/users/skatejs/received_events","type":"Organization","site_admin":false},"repo":{"id":16425042,"name":"skatejs","full_name":"skatejs/skatejs","owner":{"login":"skatejs","id":7636121,"avatar_url":"https://avatars.githubusercontent.com/u/7636121?v=3","gravatar_id":"","url":"https://api.github.com/users/skatejs","html_url":"https://github.com/skatejs","followers_url":"https://api.github.com/users/skatejs/followers","following_url":"https://api.github.com/users/skatejs/following{/other_user}","gists_url":"https://api.github.com/users/skatejs/gists{/gist_id}","starred_url":"https://api.github.com/users/skatejs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/skatejs/subscriptions","organizations_url":"https://api.github.com/users/skatejs/orgs","repos_url":"https://api.github.com/users/skatejs/repos","events_url":"https://api.github.com/users/skatejs/events{/privacy}","received_events_url":"https://api.github.com/users/skatejs/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/skatejs/skatejs","description":"Skate is a web component library that provides an API to bind behaviour to DOM elements. It's based on the W3C specification for Custom Elements.","fork":false,"url":"https://api.github.com/repos/skatejs/skatejs","forks_url":"https://api.github.com/repos/skatejs/skatejs/forks","keys_url":"https://api.github.com/repos/skatejs/skatejs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/skatejs/skatejs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/skatejs/skatejs/teams","hooks_url":"https://api.github.com/repos/skatejs/skatejs/hooks","issue_events_url":"https://api.github.com/repos/skatejs/skatejs/issues/events{/number}","events_url":"https://api.github.com/repos/skatejs/skatejs/events","assignees_url":"https://api.github.com/repos/skatejs/skatejs/assignees{/user}","branches_url":"https://api.github.com/repos/skatejs/skatejs/branches{/branch}","tags_url":"https://api.github.com/repos/skatejs/skatejs/tags","blobs_url":"https://api.github.com/repos/skatejs/skatejs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/skatejs/skatejs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/skatejs/skatejs/git/refs{/sha}","trees_url":"https://api.github.com/repos/skatejs/skatejs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/skatejs/skatejs/statuses/{sha}","languages_url":"https://api.github.com/repos/skatejs/skatejs/languages","stargazers_url":"https://api.github.com/repos/skatejs/skatejs/stargazers","contributors_url":"https://api.github.com/repos/skatejs/skatejs/contributors","subscribers_url":"https://api.github.com/repos/skatejs/skatejs/subscribers","subscription_url":"https://api.github.com/repos/skatejs/skatejs/subscription","commits_url":"https://api.github.com/repos/skatejs/skatejs/commits{/sha}","git_commits_url":"https://api.github.com/repos/skatejs/skatejs/git/commits{/sha}","comments_url":"https://api.github.com/repos/skatejs/skatejs/comments{/number}","issue_comment_url":"https://api.github.com/repos/skatejs/skatejs/issues/comments{/number}","contents_url":"https://api.github.com/repos/skatejs/skatejs/contents/{+path}","compare_url":"https://api.github.com/repos/skatejs/skatejs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/skatejs/skatejs/merges","archive_url":"https://api.github.com/repos/skatejs/skatejs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/skatejs/skatejs/downloads","issues_url":"https://api.github.com/repos/skatejs/skatejs/issues{/number}","pulls_url":"https://api.github.com/repos/skatejs/skatejs/pulls{/number}","milestones_url":"https://api.github.com/repos/skatejs/skatejs/milestones{/number}","notifications_url":"https://api.github.com/repos/skatejs/skatejs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/skatejs/skatejs/labels{/name}","releases_url":"https://api.github.com/repos/skatejs/skatejs/releases{/id}","created_at":"2014-02-01T00:32:47Z","updated_at":"2015-09-24T12:21:40Z","pushed_at":"2015-09-25T23:47:03Z","git_url":"git://github.com/skatejs/skatejs.git","ssh_url":"git@github.com:skatejs/skatejs.git","clone_url":"https://github.com/skatejs/skatejs.git","svn_url":"https://github.com/skatejs/skatejs","homepage":"http://skate.js.org","size":6697,"stargazers_count":502,"watchers_count":502,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":22,"mirror_url":null,"open_issues_count":10,"forks":22,"open_issues":10,"watchers":502,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/skatejs/skatejs/pulls/334"},"html":{"href":"https://github.com/skatejs/skatejs/pull/334"},"issue":{"href":"https://api.github.com/repos/skatejs/skatejs/issues/334"},"comments":{"href":"https://api.github.com/repos/skatejs/skatejs/issues/334/comments"},"review_comments":{"href":"https://api.github.com/repos/skatejs/skatejs/pulls/334/comments"},"review_comment":{"href":"https://api.github.com/repos/skatejs/skatejs/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/skatejs/skatejs/pulls/334/commits"},"statuses":{"href":"https://api.github.com/repos/skatejs/skatejs/statuses/7ce5b3561b12a95f40568f34de7c946d7d2c0c3d"}}}}