{"id":13630604,"url":"https://github.com/estrattonbailey/operator","last_synced_at":"2025-05-12T04:30:33.726Z","repository":{"id":11108182,"uuid":"67044856","full_name":"estrattonbailey/operator","owner":"estrattonbailey","description":" 1.8kb drop-in \"PJAX\" solution for fluid, smooth transitions between pages. ","archived":false,"fork":false,"pushed_at":"2023-01-06T01:32:49.000Z","size":908,"stargazers_count":91,"open_issues_count":14,"forks_count":11,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-05-07T23:06:36.270Z","etag":null,"topics":["ajax-library","ajaxify","pjax","spa"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/estrattonbailey.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-08-31T14:28:18.000Z","updated_at":"2024-10-24T23:52:33.000Z","dependencies_parsed_at":"2023-01-13T16:20:05.964Z","dependency_job_id":null,"html_url":"https://github.com/estrattonbailey/operator","commit_stats":null,"previous_names":["estrattonbailey/operator.js"],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/estrattonbailey%2Foperator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/estrattonbailey%2Foperator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/estrattonbailey%2Foperator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/estrattonbailey%2Foperator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/estrattonbailey","download_url":"https://codeload.github.com/estrattonbailey/operator/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253606578,"owners_count":21935200,"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":["ajax-library","ajaxify","pjax","spa"],"created_at":"2024-08-01T22:01:49.249Z","updated_at":"2025-05-12T04:30:33.394Z","avatar_url":"https://github.com/estrattonbailey.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# operator ![npm](https://img.shields.io/npm/v/operator) [![](https://badgen.net/bundlephobia/minzip/operator)](https://bundlephobia.com/result?p=operator)\n\n1.8kb drop-in \"PJAX\" solution for fluid, smooth transitions between pages. Zero stress.\n\n## Features\n1. Advanced routing via [matchit](https://github.com/lukeed/matchit)\n2. Client-side redirects\n3. Async-by-default, easy data loading between routes\n4. Pages are cached after initial visit\n5. Pre-fetch select pages, as needed\n\n## Install\n```bash\nnpm i operator --save\n```\n\n# Usage\nBasically zero config by default, just specify a root DOM node to attach to.\n```javascript\nimport operator from 'operator'\n\noperator('#root')\n```\n\n## Defining routes\nTo define custom handlers for a given route, pass an object with a `path`\nproperty and `handler` method.\n```javascript\noperator('#root', [\n  {\n    path: '/',\n    handler (state) {\n      console.log(state)\n    }\n  }\n])\n```\n\nRoutes handlers can also return `Promise`s, and they support params, optional\nparams, and wildcards.\n```javascript\noperator('#root', [\n  {\n    path: '/',\n    handler (state) {\n      console.log(state)\n    }\n  },\n  {\n    path: '/products',\n    handler (state) {\n      return getProducts() // Promise\n    }\n  },\n  {\n    path: '/products/:category/:slug?',\n    handler ({ params }) {\n      const reqs = [ getProductCategory(params.category) ]\n      if (params.slug) reqs.push(getProductBySlug(params.slug))\n      return Promise.all(reqs)\n    }\n  }\n])\n```\n\n### Route Caching\nRoutes are cached by default, so on subsequent visits, no data will be loaded.\nTo follow links to pages via AJAX, but fetch fresh content on each navigation\naction, set `cache` to `false`:\n```javascript\noperator('#root', [\n  {\n    'path': '/',\n    cache: false\n  }\n])\n```\n\n### Ignoring Routes\nSometimes you need to navigate to a page without AJAX, perhaps to load some sort\nof `iframe` content. To do so, set `ignore` to `true`:\n```javascript\noperator('#root', [\n  {\n    'path': '/',\n    ignore: true\n  }\n])\n```\n\n## Lifecycle\nAny function passed to the route config will be called on every route change,\nkind of like *middleware*.\n```javascript\nconst app = operator('#root', [\n  state =\u003e console.log(state)\n])\n```\n\nOperator also emits some helpful events.\n```javascript\napp.on('navigate', state =\u003e {}) // on valid link click\napp.on('before', state =\u003e {}) // before render\napp.on('after', state =\u003e {}) // after render\napp.on('hash', state =\u003e {}) // when the URL contains a hash\n```\n\n### History state\nOperator does not manage `History` or page title, for maximum flexibility to the\nuser. Most people should probably just use this snippet:\n```javascript\napp.on('after', ({ previousDocument, location }) =\u003e {\n  document.title = previousDocumnt.title\n  window.history.pushState({}, '', location)\n})\n```\n\nIf you want to ignore things like query strings or hashes, use `pathname`:\n```javascript\napp.on('after', ({ previousDocumnt, pathname }) =\u003e {\n  document.title = previousDocumnt.title\n  window.history.pushState({}, '', pathname)\n})\n```\n\n### Hash Anchors\nWhen a hash is encountered – whether on a `navigate` action between pages, or\nfor scroll-anchors on the same page - Operator will emit a `hash` event. *It's\n  up to you to handle scrolling.*\n\nFor most sites, this should work:\n```javascript\napp.on('hash', ({ hash }) =\u003e {\n  const target = document.getElementById(hash)\n\n  if (target) {\n    const scroll = target.getBoundingClientRect().top + window.pageYOffset\n    window.scrollTo(0, scroll)\n  }\n})\n```\n\nSmooth scrolling is also pretty easy:\n```javascript\nimport sscroll from 'sscroll'\n\napp.on('hash', ({ hash }) =\u003e {\n  const target = document.getElementById(hash)\n  target \u0026\u0026 sscroll(target, { duration: 500 })\n})\n```\n\n# API\n### go(path)\n```javascript\napp.go('/about')\n```\n\n### load(path)\nUse this for prefetching pages.\n```javascript\napp.load('/about')\n```\n\n### state (getter)\n```javascript\napp.state // =\u003e { previousDocument, pathname, location, params, hash, search, handler }\n```\n\n# Recipes\n### Redirects\n```javascript\napp.on('before', ({ pathname }) =\u003e {\n  if (/redirect/.test(pathname)) {\n    app.go('/') // redirect\n  }\n})\n```\n\n### Transition animation\n```javascript\nimport wait from 'w2t'\n\noperator('#root', [\n  state =\u003e {\n    return wait(600, [\n      const root = document.documentElement.classList\n      return new Promise(res =\u003e {\n        root.add('is-transitioning')\n        setTimeout(() =\u003e {\n          root.remove('is-transitioning')\n          res()\n        }, 600)\n      })\n    ])\n  }\n])\n```\n\n# Changelog\n### v1.8.0\nRemoved default scroll handling. This should be moved to user-space in the event\nthe user doesn't want the page to reset to the top.\n\n### v1.7.0\nAdded `previousDocument` (a complete cloned `document` object) to the `state`\nobject. Replaces `state.title` via `previousDocument.title`.\n\n### v1.6.0\n- Implemented `hash` event, see [docs](#hash-anchors)\n- Fix bad `mailto` and `tel` regex, thanks [@gabrielloeb](https://github.com/gabrielloeb)!\n\n### v1.2.0\nSlight update to the API, will require brief migration to new syntax for most\nusers.\n- Deprecated Array format for route configs in favor of more flexible Object\n  syntax\n- Add `ignore` and `cache` options\n\n## License\nMIT License © [Eric Bailey](https://estrattonbailey.com)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Festrattonbailey%2Foperator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Festrattonbailey%2Foperator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Festrattonbailey%2Foperator/lists"}