{"action":"closed","number":72,"pull_request":{"url":"https://api.github.com/repos/yoshuawuyts/vmd/pulls/72","id":55580448,"html_url":"https://github.com/yoshuawuyts/vmd/pull/72","diff_url":"https://github.com/yoshuawuyts/vmd/pull/72.diff","patch_url":"https://github.com/yoshuawuyts/vmd/pull/72.patch","issue_url":"https://api.github.com/repos/yoshuawuyts/vmd/issues/72","number":72,"state":"closed","locked":false,"title":"Shared state and dynamic menus, fixes #61","user":{"login":"maxkueng","id":168709,"avatar_url":"https://avatars.githubusercontent.com/u/168709?v=3","gravatar_id":"","url":"https://api.github.com/users/maxkueng","html_url":"https://github.com/maxkueng","followers_url":"https://api.github.com/users/maxkueng/followers","following_url":"https://api.github.com/users/maxkueng/following{/other_user}","gists_url":"https://api.github.com/users/maxkueng/gists{/gist_id}","starred_url":"https://api.github.com/users/maxkueng/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/maxkueng/subscriptions","organizations_url":"https://api.github.com/users/maxkueng/orgs","repos_url":"https://api.github.com/users/maxkueng/repos","events_url":"https://api.github.com/users/maxkueng/events{/privacy}","received_events_url":"https://api.github.com/users/maxkueng/received_events","type":"User","site_admin":false},"body":"This update introduces two new things in order to fix #61:\r\n\r\n### Shared state\r\n\r\nThere's a new singleton module `./shared-state.js` that represents a shared state between the main process (`server.js`) and the renderer processes (`client.js`). It allows both parts to make changes to the state and to subscribe to changes.\r\n\r\nIt uses Redux internally and exposes Redux' `getState()` and `subscribe()` functions, along with some action creators to make changes to the state. The client API (`api.js`) provides the shared state's API to the client.\r\n\r\nThe main process listens to changes to the shared state and updates the application menu accordingly. For example, the \"Edit\" -> \"Copy\" menu item should only be enabled if the currently focused window has some selected text.\r\n\r\nIt currently holds the following data:\r\n\r\n - `focusedWindow`: the ID of the currently focused window\r\n - `windows`: an array containing the state of each window\r\n   - `id`: window ID\r\n   - `selection`: the selected/highlighted text\r\n   - `history`\r\n     -  `canGoBack`: whether going back in the history is possible\r\n     -  `canGoForward`: whether going forward in the history is possible \r\n\r\n### createMenu()\r\n\r\nIn order to update (show/hide, enable/disable) menu items, there's a new module `./create-menu.js` that provides a function to create a `electron.Menu` based on a template object, and exposes a function to update each menu item's `visible` and `enabled` properties based on a model.\r\n\r\nThe difference to Electron's built-in menu template is that the `enabled` and `visible` item properties are functions that return a boolean - instead of being booleans themselves. The function receive a reference to the model as the first argument.\r\n\r\nThe `click` handlers also receive the model as the first argument. `click(model, menuItem, window)`.\r\n\r\nThis is a shortened version of how the context menu is created. The application menu works the same but uses `sharedState.getFocusedWindowState()` and its model.\r\n```js\r\nconst createMenu = require('./create-menu')\r\n\r\nvar template = [\r\n  {\r\n    label: 'Open folder',\r\n    click: function (model) {\r\n      return model.link && shell.openItem(model.link.path)\r\n    },\r\n    visible: function (model) {\r\n      return model.link && model.link.type === 'directory'\r\n    }\r\n  },\r\n  {\r\n    label: 'Open file',\r\n    click: function (model) {\r\n      if (model.link && model.link.type === 'file') {\r\n        return model.link && shell.openItem(model.link.path)\r\n      }\r\n\r\n      if (model.link && model.link.type === 'markdown-file') {\r\n        return navigateTo(hist.push({\r\n          filePath: model.link.path\r\n        }))\r\n      }\r\n    },\r\n    visible: function (model) {\r\n      return model.link && (model.link.type === 'file' || model.link.type === 'markdown-file')\r\n    }\r\n  },\r\n  ...\r\n]\r\n\r\nvar contextMenu = createMenu(template, {})\r\n\r\nwindow.addEventListener('contextmenu', function (ev) {\r\n  ev.preventDefault()\r\n  var el = document.elementFromPoint(ev.x, ev.y) || null\r\n  contextMenu.update({\r\n    link: getLinkType(findClosestLink(el)),\r\n    ...\r\n  })\r\n\r\n  contextMenu.getMenu().popup(currentWindow)\r\n}, false)\r\n```","created_at":"2016-01-11T01:20:42Z","updated_at":"2016-01-11T01:24:32Z","closed_at":"2016-01-11T01:24:32Z","merged_at":"2016-01-11T01:24:32Z","merge_commit_sha":"ea1dcdd28d08b6271f7b154195252336935c0609","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/yoshuawuyts/vmd/pulls/72/commits","review_comments_url":"https://api.github.com/repos/yoshuawuyts/vmd/pulls/72/comments","review_comment_url":"https://api.github.com/repos/yoshuawuyts/vmd/pulls/comments{/number}","comments_url":"https://api.github.com/repos/yoshuawuyts/vmd/issues/72/comments","statuses_url":"https://api.github.com/repos/yoshuawuyts/vmd/statuses/91c47d4049296c1925379bbe6a4bfe76e596899f","head":{"label":"yoshuawuyts:shared-state","ref":"shared-state","sha":"91c47d4049296c1925379bbe6a4bfe76e596899f","user":{"login":"yoshuawuyts","id":2467194,"avatar_url":"https://avatars.githubusercontent.com/u/2467194?v=3","gravatar_id":"","url":"https://api.github.com/users/yoshuawuyts","html_url":"https://github.com/yoshuawuyts","followers_url":"https://api.github.com/users/yoshuawuyts/followers","following_url":"https://api.github.com/users/yoshuawuyts/following{/other_user}","gists_url":"https://api.github.com/users/yoshuawuyts/gists{/gist_id}","starred_url":"https://api.github.com/users/yoshuawuyts/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yoshuawuyts/subscriptions","organizations_url":"https://api.github.com/users/yoshuawuyts/orgs","repos_url":"https://api.github.com/users/yoshuawuyts/repos","events_url":"https://api.github.com/users/yoshuawuyts/events{/privacy}","received_events_url":"https://api.github.com/users/yoshuawuyts/received_events","type":"User","site_admin":false},"repo":{"id":30476886,"name":"vmd","full_name":"yoshuawuyts/vmd","owner":{"login":"yoshuawuyts","id":2467194,"avatar_url":"https://avatars.githubusercontent.com/u/2467194?v=3","gravatar_id":"","url":"https://api.github.com/users/yoshuawuyts","html_url":"https://github.com/yoshuawuyts","followers_url":"https://api.github.com/users/yoshuawuyts/followers","following_url":"https://api.github.com/users/yoshuawuyts/following{/other_user}","gists_url":"https://api.github.com/users/yoshuawuyts/gists{/gist_id}","starred_url":"https://api.github.com/users/yoshuawuyts/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yoshuawuyts/subscriptions","organizations_url":"https://api.github.com/users/yoshuawuyts/orgs","repos_url":"https://api.github.com/users/yoshuawuyts/repos","events_url":"https://api.github.com/users/yoshuawuyts/events{/privacy}","received_events_url":"https://api.github.com/users/yoshuawuyts/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/yoshuawuyts/vmd","description":":pray: preview markdown files","fork":false,"url":"https://api.github.com/repos/yoshuawuyts/vmd","forks_url":"https://api.github.com/repos/yoshuawuyts/vmd/forks","keys_url":"https://api.github.com/repos/yoshuawuyts/vmd/keys{/key_id}","collaborators_url":"https://api.github.com/repos/yoshuawuyts/vmd/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/yoshuawuyts/vmd/teams","hooks_url":"https://api.github.com/repos/yoshuawuyts/vmd/hooks","issue_events_url":"https://api.github.com/repos/yoshuawuyts/vmd/issues/events{/number}","events_url":"https://api.github.com/repos/yoshuawuyts/vmd/events","assignees_url":"https://api.github.com/repos/yoshuawuyts/vmd/assignees{/user}","branches_url":"https://api.github.com/repos/yoshuawuyts/vmd/branches{/branch}","tags_url":"https://api.github.com/repos/yoshuawuyts/vmd/tags","blobs_url":"https://api.github.com/repos/yoshuawuyts/vmd/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/yoshuawuyts/vmd/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/yoshuawuyts/vmd/git/refs{/sha}","trees_url":"https://api.github.com/repos/yoshuawuyts/vmd/git/trees{/sha}","statuses_url":"https://api.github.com/repos/yoshuawuyts/vmd/statuses/{sha}","languages_url":"https://api.github.com/repos/yoshuawuyts/vmd/languages","stargazers_url":"https://api.github.com/repos/yoshuawuyts/vmd/stargazers","contributors_url":"https://api.github.com/repos/yoshuawuyts/vmd/contributors","subscribers_url":"https://api.github.com/repos/yoshuawuyts/vmd/subscribers","subscription_url":"https://api.github.com/repos/yoshuawuyts/vmd/subscription","commits_url":"https://api.github.com/repos/yoshuawuyts/vmd/commits{/sha}","git_commits_url":"https://api.github.com/repos/yoshuawuyts/vmd/git/commits{/sha}","comments_url":"https://api.github.com/repos/yoshuawuyts/vmd/comments{/number}","issue_comment_url":"https://api.github.com/repos/yoshuawuyts/vmd/issues/comments{/number}","contents_url":"https://api.github.com/repos/yoshuawuyts/vmd/contents/{+path}","compare_url":"https://api.github.com/repos/yoshuawuyts/vmd/compare/{base}...{head}","merges_url":"https://api.github.com/repos/yoshuawuyts/vmd/merges","archive_url":"https://api.github.com/repos/yoshuawuyts/vmd/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/yoshuawuyts/vmd/downloads","issues_url":"https://api.github.com/repos/yoshuawuyts/vmd/issues{/number}","pulls_url":"https://api.github.com/repos/yoshuawuyts/vmd/pulls{/number}","milestones_url":"https://api.github.com/repos/yoshuawuyts/vmd/milestones{/number}","notifications_url":"https://api.github.com/repos/yoshuawuyts/vmd/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/yoshuawuyts/vmd/labels{/name}","releases_url":"https://api.github.com/repos/yoshuawuyts/vmd/releases{/id}","created_at":"2015-02-08T01:28:58Z","updated_at":"2016-01-10T20:04:56Z","pushed_at":"2016-01-11T01:24:33Z","git_url":"git://github.com/yoshuawuyts/vmd.git","ssh_url":"git@github.com:yoshuawuyts/vmd.git","clone_url":"https://github.com/yoshuawuyts/vmd.git","svn_url":"https://github.com/yoshuawuyts/vmd","homepage":"","size":699,"stargazers_count":298,"watchers_count":298,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":25,"mirror_url":null,"open_issues_count":8,"forks":25,"open_issues":8,"watchers":298,"default_branch":"master"}},"base":{"label":"yoshuawuyts:master","ref":"master","sha":"739d53fcebc6c8950edc177e99bb2bcf3f37ac3e","user":{"login":"yoshuawuyts","id":2467194,"avatar_url":"https://avatars.githubusercontent.com/u/2467194?v=3","gravatar_id":"","url":"https://api.github.com/users/yoshuawuyts","html_url":"https://github.com/yoshuawuyts","followers_url":"https://api.github.com/users/yoshuawuyts/followers","following_url":"https://api.github.com/users/yoshuawuyts/following{/other_user}","gists_url":"https://api.github.com/users/yoshuawuyts/gists{/gist_id}","starred_url":"https://api.github.com/users/yoshuawuyts/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yoshuawuyts/subscriptions","organizations_url":"https://api.github.com/users/yoshuawuyts/orgs","repos_url":"https://api.github.com/users/yoshuawuyts/repos","events_url":"https://api.github.com/users/yoshuawuyts/events{/privacy}","received_events_url":"https://api.github.com/users/yoshuawuyts/received_events","type":"User","site_admin":false},"repo":{"id":30476886,"name":"vmd","full_name":"yoshuawuyts/vmd","owner":{"login":"yoshuawuyts","id":2467194,"avatar_url":"https://avatars.githubusercontent.com/u/2467194?v=3","gravatar_id":"","url":"https://api.github.com/users/yoshuawuyts","html_url":"https://github.com/yoshuawuyts","followers_url":"https://api.github.com/users/yoshuawuyts/followers","following_url":"https://api.github.com/users/yoshuawuyts/following{/other_user}","gists_url":"https://api.github.com/users/yoshuawuyts/gists{/gist_id}","starred_url":"https://api.github.com/users/yoshuawuyts/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yoshuawuyts/subscriptions","organizations_url":"https://api.github.com/users/yoshuawuyts/orgs","repos_url":"https://api.github.com/users/yoshuawuyts/repos","events_url":"https://api.github.com/users/yoshuawuyts/events{/privacy}","received_events_url":"https://api.github.com/users/yoshuawuyts/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/yoshuawuyts/vmd","description":":pray: preview markdown files","fork":false,"url":"https://api.github.com/repos/yoshuawuyts/vmd","forks_url":"https://api.github.com/repos/yoshuawuyts/vmd/forks","keys_url":"https://api.github.com/repos/yoshuawuyts/vmd/keys{/key_id}","collaborators_url":"https://api.github.com/repos/yoshuawuyts/vmd/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/yoshuawuyts/vmd/teams","hooks_url":"https://api.github.com/repos/yoshuawuyts/vmd/hooks","issue_events_url":"https://api.github.com/repos/yoshuawuyts/vmd/issues/events{/number}","events_url":"https://api.github.com/repos/yoshuawuyts/vmd/events","assignees_url":"https://api.github.com/repos/yoshuawuyts/vmd/assignees{/user}","branches_url":"https://api.github.com/repos/yoshuawuyts/vmd/branches{/branch}","tags_url":"https://api.github.com/repos/yoshuawuyts/vmd/tags","blobs_url":"https://api.github.com/repos/yoshuawuyts/vmd/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/yoshuawuyts/vmd/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/yoshuawuyts/vmd/git/refs{/sha}","trees_url":"https://api.github.com/repos/yoshuawuyts/vmd/git/trees{/sha}","statuses_url":"https://api.github.com/repos/yoshuawuyts/vmd/statuses/{sha}","languages_url":"https://api.github.com/repos/yoshuawuyts/vmd/languages","stargazers_url":"https://api.github.com/repos/yoshuawuyts/vmd/stargazers","contributors_url":"https://api.github.com/repos/yoshuawuyts/vmd/contributors","subscribers_url":"https://api.github.com/repos/yoshuawuyts/vmd/subscribers","subscription_url":"https://api.github.com/repos/yoshuawuyts/vmd/subscription","commits_url":"https://api.github.com/repos/yoshuawuyts/vmd/commits{/sha}","git_commits_url":"https://api.github.com/repos/yoshuawuyts/vmd/git/commits{/sha}","comments_url":"https://api.github.com/repos/yoshuawuyts/vmd/comments{/number}","issue_comment_url":"https://api.github.com/repos/yoshuawuyts/vmd/issues/comments{/number}","contents_url":"https://api.github.com/repos/yoshuawuyts/vmd/contents/{+path}","compare_url":"https://api.github.com/repos/yoshuawuyts/vmd/compare/{base}...{head}","merges_url":"https://api.github.com/repos/yoshuawuyts/vmd/merges","archive_url":"https://api.github.com/repos/yoshuawuyts/vmd/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/yoshuawuyts/vmd/downloads","issues_url":"https://api.github.com/repos/yoshuawuyts/vmd/issues{/number}","pulls_url":"https://api.github.com/repos/yoshuawuyts/vmd/pulls{/number}","milestones_url":"https://api.github.com/repos/yoshuawuyts/vmd/milestones{/number}","notifications_url":"https://api.github.com/repos/yoshuawuyts/vmd/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/yoshuawuyts/vmd/labels{/name}","releases_url":"https://api.github.com/repos/yoshuawuyts/vmd/releases{/id}","created_at":"2015-02-08T01:28:58Z","updated_at":"2016-01-10T20:04:56Z","pushed_at":"2016-01-11T01:24:33Z","git_url":"git://github.com/yoshuawuyts/vmd.git","ssh_url":"git@github.com:yoshuawuyts/vmd.git","clone_url":"https://github.com/yoshuawuyts/vmd.git","svn_url":"https://github.com/yoshuawuyts/vmd","homepage":"","size":699,"stargazers_count":298,"watchers_count":298,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":25,"mirror_url":null,"open_issues_count":8,"forks":25,"open_issues":8,"watchers":298,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/yoshuawuyts/vmd/pulls/72"},"html":{"href":"https://github.com/yoshuawuyts/vmd/pull/72"},"issue":{"href":"https://api.github.com/repos/yoshuawuyts/vmd/issues/72"},"comments":{"href":"https://api.github.com/repos/yoshuawuyts/vmd/issues/72/comments"},"review_comments":{"href":"https://api.github.com/repos/yoshuawuyts/vmd/pulls/72/comments"},"review_comment":{"href":"https://api.github.com/repos/yoshuawuyts/vmd/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/yoshuawuyts/vmd/pulls/72/commits"},"statuses":{"href":"https://api.github.com/repos/yoshuawuyts/vmd/statuses/91c47d4049296c1925379bbe6a4bfe76e596899f"}},"merged":true,"mergeable":null,"mergeable_state":"unknown","merged_by":{"login":"maxkueng","id":168709,"avatar_url":"https://avatars.githubusercontent.com/u/168709?v=3","gravatar_id":"","url":"https://api.github.com/users/maxkueng","html_url":"https://github.com/maxkueng","followers_url":"https://api.github.com/users/maxkueng/followers","following_url":"https://api.github.com/users/maxkueng/following{/other_user}","gists_url":"https://api.github.com/users/maxkueng/gists{/gist_id}","starred_url":"https://api.github.com/users/maxkueng/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/maxkueng/subscriptions","organizations_url":"https://api.github.com/users/maxkueng/orgs","repos_url":"https://api.github.com/users/maxkueng/repos","events_url":"https://api.github.com/users/maxkueng/events{/privacy}","received_events_url":"https://api.github.com/users/maxkueng/received_events","type":"User","site_admin":false},"comments":0,"review_comments":0,"commits":9,"additions":434,"deletions":231,"changed_files":8}}