{"id":13343945,"url":"https://github.com/clseibold/ZeroFrame-Router","last_synced_at":"2025-03-12T06:30:43.963Z","repository":{"id":159557250,"uuid":"98695090","full_name":"clseibold/ZeroFrame-Router","owner":"clseibold","description":"A very simple ZeroFrame Router for the ZeroNet.","archived":false,"fork":false,"pushed_at":"2017-12-31T15:05:47.000Z","size":33,"stargazers_count":1,"open_issues_count":7,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-24T16:50:04.051Z","etag":null,"topics":["library","router","simple","zeroframe","zeronet"],"latest_commit_sha":null,"homepage":"http://127.0.0.1:43110/1K2myjtjoEVpRC2JMieRL73ES4V4iLP2Ev","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/clseibold.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-07-28T23:22:19.000Z","updated_at":"2024-08-15T00:20:21.000Z","dependencies_parsed_at":"2023-05-21T20:30:40.315Z","dependency_job_id":null,"html_url":"https://github.com/clseibold/ZeroFrame-Router","commit_stats":null,"previous_names":["clseibold/zeroframe-router"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clseibold%2FZeroFrame-Router","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clseibold%2FZeroFrame-Router/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clseibold%2FZeroFrame-Router/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clseibold%2FZeroFrame-Router/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/clseibold","download_url":"https://codeload.github.com/clseibold/ZeroFrame-Router/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243171450,"owners_count":20247876,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["library","router","simple","zeroframe","zeronet"],"created_at":"2024-07-29T19:32:07.372Z","updated_at":"2025-03-12T06:30:43.955Z","avatar_url":"https://github.com/clseibold.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ZeroFrame Router\r\nA *very* basic router that works with the ZeroFrame API.\u003cbr\u003e\r\nLicense: BSD 2-Clause\r\n\r\n## Example Usage\r\n```javascript\r\nRouter.add('about', function () {\r\n    console.log('about');\r\n}, { // Hooks for a specific route - the 'about' route\r\n    // This route-specific before function is called directly after the global before function (passed in with the Router.hooks function)\r\n    before: function(params) {\r\n        console.log(\"Route-specific before hook\");\r\n        return true; // Continue to resolving the route. If false, the route doesn't resolve.\r\n    },\r\n    after: function(params) {\r\n        console.log(\"Route-specific after hook\");\r\n    }\r\n}).add('tutorials', function() {\r\n    console.log('tutorials')\r\n}).add('products/:pid/edit/:eid', function(params) {\r\n    console.log('products', params.pid, params.eid);\r\n    // If you go to route: /products/21/edit/3\r\n    // It will log: products 21 3\r\n}).add('*/create', function() {\r\n    console.log('Wildcard example');\r\n}).add(function() {\r\n    console.log('home');\r\n});\r\n\r\nRouter.hooks({\r\n    // Called before every route resolves. currentRoute is the route that will be resolved (if you return true).\r\n    before: function(currentRoute, params) {\r\n        console.log(\"Global before hook\");\r\n        var refreshBtn = document.getElementById('refreshBtn');\r\n        if (currentRoute == 'tutorials') {\r\n            // Show refresh button on tutorials route\r\n            refreshBtn.style.display = 'inline';\r\n        } else {\r\n            // Hide refresh button for all other routes\r\n            refreshBtn.style.display = 'none';\r\n        }\r\n\r\n        return true; // Continue to resolving the route. If false, the route doesn't resolve.\r\n    },\r\n    // Called after every route resolves. currentRoute is the route that just resolved.\r\n    after: function(currentRoute, params) {\r\n        console.log(\"Global after hook\");\r\n    },\r\n    // Called when leaving a route, `route` is the route you are leaving.\r\n    leave: function(route) {\r\n        console.log('Leaving route: ' + route);\r\n        return true; // Continue navigating to route. Return false if you don't want to continue with leaving the route.\r\n    }\r\n});\r\n\r\nRouter.init();\r\n```\r\n\r\nTo navigate to a route, use the `Router.navigate('/route')` function. **You must also make sure your ZeroFrame instance is called `page`.** (you can get around this by doing something as simple as `page = zeroframe;`).\r\n\r\nThe order in which you add routes matters. The URL which is added earlier and matches will be the one that is called.\r\n\r\n*Note*: You must call `Router.listenForBack()` in the `OnRequest()` function of your ZeroFrame class in order to detect when the user hits the back button and navigate to the correct route.\r\n\r\n\r\n*Credit*: Library based on code from this tutorial: [http://krasimirtsonev.com/blog/article/A-modern-JavaScript-router-in-100-lines-history-api-pushState-hash-url](http://krasimirtsonev.com/blog/article/A-modern-JavaScript-router-in-100-lines-history-api-pushState-hash-url)\r\n\r\n## Sharing Variables Between A Route's Function And Its Hooks\r\nLet's say you want to set a variable in the `before` hook and access it in the route's main function. You can do this simply by setting the variable on `this`. Here's an example:\r\n\r\n```javascript\r\nRoute.add('about', function(params) {\r\n    console.log(this.testvariable, \" works in here!\"); // Use the variable here.\r\n}, {\r\n    before: function(params) {\r\n        this.testvariable = \"Test Variable\"; // Set the variable here!\r\n        return true;\r\n    },\r\n    after: function() {\r\n        console.log(this.testvariable, \" also works in here!\"); // Use the variable here also.\r\n    }\r\n});\r\n```\r\n\r\nIt should be noted that this also applies to global hooks.\r\n\r\n## What Happens When `navigate` Is Called?\r\nThis is exactly what happens when you call the `navigate` function:\r\n* Call Global `leave` hook\r\n* Push State to new route\r\n* Call Global `before` hook\r\n  - If returned false, push state to previous route and return (don't do anything else)\r\n* Call Route-specific `before` hook\r\n  - If returned false, push state to previous route and return (don't do anything else)\r\n* Set `currentRoute` to the route navigating to\r\n* Call Route's function\r\n* Call Route-specific `after` hook\r\n* Call Global `after` hook\r\n\r\n## Router Vue Plugin\r\nIf you wan't to be able to easily create links that navigate to a route without having to type out a call to a function, you can use the vue component that the vuejs plugin provides. Simply include the js file, after the vue js and initialize the plugin file AND `router.js` file, and use the component as such:\r\n\r\n```html\r\n\u003croute-link to=\"/\"\u003eHome\u003c/route-link\u003e\r\n```\r\n\r\n### Initializing ZeroFrame Router Vue Plugin\r\nYou must initialize the plugin before you can use it and the `route-link` component.\r\n\r\n```javascript\r\nVue.use(VueZeroFrameRouter.VueZeroFrameRouter);\r\n```\r\n\r\nIf you want to use Vue components for each route, you must add `currentView` to the data section of your root Vue instance. This is how the data for ZeroMedium's root Vue instance looks:\r\n\r\n```javascript\r\ndata: {\r\n    currentView: null,\r\n    siteInfo: null,\r\n    userInfo: null,\r\n    navbarShadow: false,\r\n    signin_modal_active: false\r\n},\r\n```\r\n\r\nIn order to show the route's component, you must put this into your template for the root Vue instance. This is how ZeroMedium does it:\r\n\r\n```javascript\r\ntemplate: `\r\n    \u003cdiv\u003e\r\n        \u003ccustom-nav v-on:show-signin-modal=\"showSigninModal()\" v-on:get-user-info=\"getUserInfo()\" v-bind:user-info=\"userInfo\" v-bind:shadow=\"navbarShadow\"\u003e\u003c/custom-nav\u003e\r\n        \u003ccomponent ref=\"view\" v-bind:is=\"currentView\" v-on:show-signin-modal=\"showSigninModal()\" v-on:navbar-shadow-on=\"navbarShadowOn()\" v-on:navbar-shadow-off=\"navbarShadowOff()\" v-on:get-user-info=\"getUserInfo()\" v-bind:user-info=\"userInfo\"\u003e\u003c/component\u003e\r\n    \u003c/div\u003e\r\n    `,\r\n```\r\n\r\nNotice that `currentView` is bound to `is` on the `component` tag. ZeroMedium also binds things to this component that will be accessed by *many* of the routes and is often global data, like the current user's information, for example.\r\n\r\nTo make sure the back button works properly, you must add this within your ZeroFrame class's `onRequest` function:\r\n\r\n```javascript\r\nRouter.listenForBack(cmd, message);\r\n```\r\n\r\n### Adding Routes with the Plugin\r\nThe Vue plugin has a different way of managing the routes. Also, your vuejs components' `mounted`, `beforeMount`, and `afterMount` should be used instead of the router's hooks (this is detailed more below.\r\n\r\nThis code comes directly from [ZeroMedium](https://github.com/krixano/ZeroMedium):\r\n\r\n```javascript\r\n// Router Pages\r\nvar Home = require(\"./router_pages/home.js\");\r\nvar Search = require(\"./router_pages/search.js\");\r\nvar TopicSlug = require(\"./router_pages/topic_slug.js\");\r\nvar TagSlug = require(\"./router_pages/tag_slug.js\");\r\nvar Newstory = require(\"./router_pages/newstory.js\");\r\nvar Profile = require(\"./router_pages/profile.js\");\r\nvar ProfileStory = require(\"./router_pages/profile_story.js\");\r\nvar MeStories = require(\"./router_pages/me_stories.js\");\r\nvar EditStory = require(\"./router_pages/edit_story.js\");\r\n\r\nVueZeroFrameRouter.VueZeroFrameRouter_Init(Router, app, [\r\n    { route: 'search', component: Search },\r\n    { route: 'topic/:slug', component: TopicSlug },\r\n    { route: 'tag/:slug', component: TagSlug },\r\n    { route: 'me/newstory', component: Newstory },\r\n    { route: 'me/stories/:slug/edit', component: EditStory },\r\n    { route: 'me/stories', component: MeStories },\r\n    { route: ':userauthaddress/:slug', component: ProfileStory },\r\n    { route: ':userauthaddress', component: Profile }, // TODO: Have tabs use '\u0026tab='\r\n    { route: '', component: Home }\r\n]);\r\n```\r\n\r\nNotice that each route has a component, which are `require`d from their own files. This keeps everything organized and seperate. You can also create components that are associated with a specific route within their files to keep everything related together. This is the code for the Home route, taken from ZeroMedium (a lot of the html, and any methods that correspond to that html, has been cut out so it's not so big):\r\n\r\n```javascript\r\nvar Vue = require(\"vue/dist/vue.min.js\");\r\nvar Router = require(\"../router.js\");\r\nvar moment = require('moment');\r\n\r\nvar Home = {\r\n    beforeMount: function() {\r\n        this.$emit(\"navbar-shadow-off\");\r\n        var that = this;\r\n        page.getTopics((topics) =\u003e {\r\n            that.topics = topics;\r\n        });\r\n        this.getStories();\r\n        // TODO: Do a sort based on number of likes/claps and maybe responses (only responses made during that day).\r\n    },\r\n    methods: {\r\n        showSigninModal: function() {\r\n            //this.signin_modal_visible = !this.signin_modal_visible;\r\n            this.$emit('show-signin-modal');\r\n        },\r\n        goto: function(to) {\r\n            Router.navigate(to);\r\n        },\r\n    },\r\n    data: function() {\r\n        return {\r\n            topics: []\r\n        }\r\n    },\r\n    template: `\r\n        \u003cdiv\u003e\r\n            \u003cdiv class=\"navbar is-transparent has-shadow\" style=\"border-top: 1px solid rgba(0,0,0,.05);\"\u003e\r\n                \u003cdiv class=\"container\"\u003e\r\n                    \u003cdiv class=\"navbar-brand\" style=\"overflow-x: hidden;\"\u003e\r\n                        \u003c!-- Categories --\u003e\r\n                        \u003ca class=\"navbar-item is-active\"\u003eHome\u003c/a\u003e\r\n                        \u003ca class=\"navbar-item\"\u003ePopular\u003c/a\u003e\r\n                        \u003c!--\u003ca class=\"navbar-item\"\u003eStaff Picks\u003c/a\u003e--\u003e\r\n                        \u003ca class=\"navbar-item\" v-for=\"topic in topics\" :key=\"topic.topic_id\" :href=\"'./?/topic/' + topic.slug\" v-on:click.prevent=\"topicClick(topic.slug)\"\u003e{{topic.name}}\u003c/a\u003e\r\n                    \u003c/div\u003e\r\n                \u003c/div\u003e\r\n            \u003c/div\u003e\r\n            \u003chome-hero v-on:show-signin-modal=\"showSigninModal()\"\u003e\u003c/home-hero\u003e\r\n            \u003csection class=\"section\"\u003e\r\n                \u003cdiv class=\"columns is-centered\"\u003e\r\n                    \u003cdiv class=\"column is-three-quarters-tablet is-three-quarters-desktop\"\u003e\r\n                        \u003c!-- This was cut out, along with its corresponding methods --\u003e\r\n                    \u003c/div\u003e\r\n                \u003c/div\u003e\r\n            \u003c/section\u003e\r\n        \u003c/div\u003e\r\n        `\r\n};\r\n\r\nVue.component('home-hero', {\r\n    methods: {\r\n        showSigninModal: function() {\r\n            this.$emit(\"show-signin-modal\");\r\n        }\r\n    },\r\n    template: `\r\n        \u003cdiv class=\"hero\"\u003e\r\n            \u003cdiv class=\"columns is-centered\"\u003e\r\n                \u003cdiv class=\"column is-three-quarters-tablet is-three-quarters-desktop\"\u003e\r\n                    \u003cdiv class=\"hero-body\"\u003e\r\n                        \u003cp class=\"title\"\u003eZeroMedium\u003c/p\u003e\r\n                        \u003cp\u003eBlogs on many different topics, from many different people.\u003c/p\u003e\r\n                        \u003cbr\u003e\r\n                        \u003ca class=\"button is-dark is-small\" v-on:click.prevent=\"showSigninModal()\"\u003eGet Started\u003c/a\u003e\r\n                        \u003ca class=\"button is-small\" href=\"bitcoin:1CVmbCKWtbskK2GAZLM6gnMuiL6Je25Yds?message=Donation to ZeroMedium\"\u003eDonate via Bitcoin\u003c/a\u003e\r\n                    \u003c/div\u003e\r\n                \u003c/div\u003e\r\n            \u003c/div\u003e\r\n        \u003c/div\u003e\r\n        `\r\n});\r\n\r\nmodule.exports = Home;\r\n```\r\n\r\nNotice how the `Home` route uses a component that is also created/defined within the same file (at the bottom). In order to be able to do this, we must `require` Vue.\r\n\r\nWe also `require` the Router because one of its functions are used within the `Home` route, `Router.navigate()`. This lets you have a link that calls this method, called `goto`, giving it only the route, which will call the Router's `navigate` function. We could also have just called `Router.navigate()` directly from the links that need it if we wanted to.\r\n\r\nHowever, sometimes you need to use a router function to get information passed in from the route. For example, if you have a route `blog/:slug`, you will be able to get what the `slug` was by calling `Router.currentParams[\"slug\"]`. This is typically done in the `beforeMount()` Vue function so you can get the information *before* the Vue component is mounted and shown. This is exactly how ZeroMedium does its profile route, `:userauthaddress`. The code for its `beforeMount` function is shown below:\r\n\r\n```javascript\r\nbeforeMount: function() {\r\n    this.$emit('navbar-shadow-off');\r\n    var that = this;\r\n    page.getUserProfileInfo(Router.currentParams[\"userauthaddress\"], true, true, (profileInfo) =\u003e {\r\n        that.profileInfo = profileInfo;\r\n        page.getUserClaps(Router.currentParams[\"userauthaddress\"], (claps) =\u003e {\r\n            that.claps = claps;\r\n        });\r\n    });\r\n},\r\n```\r\n\r\nZeroMedium gets the `userauthaddress` that was passed in within the `beforeMount` function so it can start getting the user's profile information (by calling `page.getUserProfileInfo()`) before the route's Vue component is mounted. Because a function is passed into `getUserProfileInfo`, it uses `var that = this` to be able to reference `this` as `that` from within the callback function. This callback function is called once the profile information has been gathered. The callback function then sets the Vue component's `profileInfo` data to that which was given to the function. *This is done this way because the `getUserProfileInfo` function is async.*\r\n\r\nYou can find an example of how this Router, Vue, and ZeroFrame are used together in a medium-sized project on [ZeroMedium's GitHub page](https://github.com/krixano/ZeroMedium).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclseibold%2FZeroFrame-Router","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fclseibold%2FZeroFrame-Router","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclseibold%2FZeroFrame-Router/lists"}