├── .babelrc ├── .eslintignore ├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── codeql-analysis.yml ├── .gitignore ├── .nvmrc ├── .ruby-version ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── DATA_REFRESH.md ├── LICENSE ├── PIPELINE_CHANGELOG.md ├── README.md ├── __mocks__ ├── algoliasearch │ └── src │ │ └── browser │ │ └── builds │ │ └── algoliasearchLite.js └── autocomplete.js.js ├── autocompleteDataset.js ├── babel-css.js ├── demo.gif ├── docs ├── .gitignore ├── Gemfile ├── Gemfile.lock ├── config.rb └── source │ ├── api-clients.html │ ├── bootstrap.html │ ├── contact.html │ ├── documentation.html │ ├── examples.html │ ├── images │ ├── algoliaPlaces_demo_checkout.gif │ ├── algoliaPlaces_demo_map.gif │ ├── background_footer.svg │ ├── clippy.svg │ ├── favicon.png │ ├── hp-demo-autocompletejs.gif │ ├── inner-background_footer.svg │ ├── map-demo.gif │ ├── svg │ │ ├── advanced-icon.svg │ │ ├── algolia-community-badge.svg │ │ ├── algolia-community.svg │ │ ├── algolia-mark-white.svg │ │ ├── background_footer.svg │ │ ├── city-icon.svg │ │ ├── community-badge.svg │ │ ├── country-icon.svg │ │ ├── form-icon.svg │ │ ├── icon-arrow-pipe.svg │ │ ├── icon-github.svg │ │ ├── icon-heart-dark.svg │ │ ├── icon-heart-light.svg │ │ ├── icon-heart.svg │ │ ├── icon-hover-cursor-visible.svg │ │ ├── icon-hover-cursor.svg │ │ ├── icon-search-white.svg │ │ ├── iconsicon-heart.svg │ │ ├── illus-feat-autocomplete.svg │ │ ├── illus-feat-relevance.svg │ │ ├── illus-feat-rocket.svg │ │ ├── illus-feat-typo-tolerance.svg │ │ ├── logo-algolia-dark.svg │ │ ├── logo-algolia-light.svg │ │ ├── logo-community.svg │ │ ├── map-icon.svg │ │ ├── places-illustration.svg │ │ ├── search-everywhere-illu.svg │ │ ├── search-icon-2.svg │ │ └── search-icon.svg │ ├── visual-preview-places.png │ └── visual-preview-places_mobile.png │ ├── index.html │ ├── javascripts │ ├── activateClipboard.js │ ├── anchorableElements.js │ ├── autoPullCredentials.js │ ├── common.js │ ├── docsearch.js │ ├── documentation-layout.js │ ├── index.js │ ├── responsiveNavigation.js │ ├── sidebar.js │ └── support.js │ ├── layouts │ ├── bootstrap.erb │ ├── documentation.erb │ ├── landing.erb │ └── layout.erb │ ├── partials │ ├── examples │ │ ├── _autocomplete_dataset.html.erb │ │ ├── _city_search.html.erb │ │ ├── _complete_form.html.erb │ │ ├── _country_search.html.erb │ │ ├── _demo.html.erb │ │ ├── _disable_styling.html.erb │ │ ├── _dynamic_control.html.erb │ │ ├── _dynamic_search.html.erb │ │ ├── _instantsearch.html.erb │ │ ├── _map.html.erb │ │ ├── _map_paris.html.erb │ │ ├── _postcode_search.html.erb │ │ ├── _ranking_info.html.erb │ │ ├── _reverse_geocoding.html.erb │ │ ├── _simple_input.html.erb │ │ ├── _single_country_search.html.erb │ │ ├── _templates.html.erb │ │ ├── _visual-helper.html.haml │ │ └── reverse-city-search │ │ │ ├── _code.html.erb │ │ │ ├── _code_places.html.erb │ │ │ └── _demo_places.html.erb │ ├── footer.html.haml │ ├── hero.html.haml │ ├── marketing.html.erb │ ├── navigation.html.haml │ └── status │ │ ├── CHANGELOG.md.erb │ │ ├── DATA_REFRESH.md.erb │ │ └── PIPELINE_CHANGELOG.md.erb │ ├── pricing.html │ ├── rest.html │ ├── status.html │ ├── stylesheets │ ├── components │ │ ├── _buttons.scss │ │ ├── _clipboard.scss │ │ ├── _code-highlight.scss │ │ ├── _containers.scss │ │ ├── _documentation.scss │ │ ├── _examples-intro.scss │ │ ├── _examples.scss │ │ ├── _fonts.scss │ │ ├── _footer.scss │ │ ├── _icons.scss │ │ ├── _inputs.scss │ │ ├── _media.scss │ │ ├── _navigation.scss │ │ ├── _sidebar.scss │ │ ├── _visual-helper.scss │ │ └── docsearch │ │ │ ├── _docsearch.scss │ │ │ ├── _dropdown.scss │ │ │ └── _searchbox.scss │ ├── landing.css.scss │ ├── site.css.scss │ └── vendors │ │ ├── _animations.scss │ │ ├── _base.scss │ │ ├── _functions.scss │ │ ├── _helpers.scss │ │ ├── _mixins.scss │ │ ├── _normalize.scss │ │ └── _variables.scss │ └── support.html ├── header.png ├── index.js ├── instantsearchWidget.js ├── package.json ├── renovate.json ├── scripts ├── build-website.sh ├── build.sh ├── bump-package-version.js ├── clear-cdn-cache.sh ├── deploy-website.sh ├── dev.sh ├── finish-release.sh ├── release.sh └── test-ci.sh ├── src ├── configure │ └── index.js ├── createAutocompleteDataset.js ├── createAutocompleteDataset.test.js ├── createAutocompleteSource.js ├── createAutocompleteSource.test.js ├── createReverseGeocodingSource.js ├── createReverseGeocodingSource.test.js ├── defaultTemplates.js ├── errors.js ├── findCountryCode.js ├── findCountryCode.test.js ├── findType.js ├── findType.test.js ├── formatDropdownValue.js ├── formatDropdownValue.test.js ├── formatHit.js ├── formatHit.test.js ├── formatInputValue.js ├── formatInputValue.test.js ├── icons │ ├── address.svg │ ├── algolia.svg │ ├── bus.svg │ ├── city.svg │ ├── clear.svg │ ├── country.svg │ ├── osm.svg │ ├── plane.svg │ ├── townhall.svg │ └── train.svg ├── instantsearch │ ├── __snapshots__ │ │ └── widget.test.js.snap │ ├── widget.js │ └── widget.test.js ├── navigatorLanguage.js ├── places.css ├── places.js ├── places.test.js └── version.js ├── test ├── cdn-autocomplete-min │ └── index.html ├── cdn-autocomplete │ └── index.html ├── cdn-main-min │ └── index.html ├── cdn-main │ └── index.html ├── cdn-widget-min │ └── index.html ├── cdn-widget │ └── index.html ├── e2e.test.js ├── fileMock.js ├── npm-autocomplete │ ├── import.js │ └── index.html ├── npm-lib │ ├── import.js │ └── index.html └── npm-widget │ ├── import.js │ └── index.html ├── typings.d.ts ├── webpack.config.docs.js ├── webpack.config.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"], 3 | "env": { 4 | "npm": { 5 | "plugins": [ 6 | [ 7 | "babel-plugin-inline-import", 8 | { 9 | "extensions": [ 10 | ".svg", 11 | ".css" 12 | ] 13 | } 14 | ] 15 | ] 16 | } 17 | }, 18 | "plugins": [ 19 | "@babel/plugin-syntax-dynamic-import", 20 | "@babel/plugin-syntax-import-meta", 21 | "@babel/plugin-proposal-class-properties", 22 | "@babel/plugin-proposal-json-strings", 23 | [ 24 | "@babel/plugin-proposal-decorators", 25 | { 26 | "legacy": true 27 | } 28 | ], 29 | "@babel/plugin-proposal-function-sent", 30 | "@babel/plugin-proposal-export-namespace-from", 31 | "@babel/plugin-proposal-numeric-separator", 32 | "@babel/plugin-proposal-throw-expressions" 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | docs/build/ 3 | docs/vendor/ 4 | test/npm-lib/ 5 | test/npm-autocomplete/ 6 | test/npm-widget/ 7 | .eslintrc.js -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['algolia', 'algolia/jest'], 3 | settings: { 4 | jest: { 5 | version: 26 6 | } 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 7 | 8 | **Do you want to request a *feature* or report a *bug*?** 9 | 10 | **What is the current behavior?** 11 | 12 | **If the current behavior is a bug, please provide all the steps to reproduce and a minimal 13 | [JSFiddle](https://jsfiddle.net/) example or a repository on GitHub that we can `npm install` 14 | and `npm start`.** 15 | 16 | **What is the expected behavior?** 17 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | **Summary** 7 | 8 | 13 | 14 | **Result** 15 | 16 | 21 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "Code scanning - action" 2 | 3 | on: 4 | push: 5 | pull_request: 6 | schedule: 7 | - cron: '0 1 * * 3' 8 | 9 | jobs: 10 | CodeQL-Build: 11 | 12 | # CodeQL runs on ubuntu-latest and windows-latest 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v2 18 | with: 19 | # We must fetch at least the immediate parents so that if this is 20 | # a pull request then we can checkout the head. 21 | fetch-depth: 2 22 | 23 | # If this run was triggered by a pull request event, then checkout 24 | # the head of the pull request instead of the merge commit. 25 | - run: git checkout HEAD^2 26 | if: ${{ github.event_name == 'pull_request' }} 27 | 28 | # Initializes the CodeQL tools for scanning. 29 | - name: Initialize CodeQL 30 | uses: github/codeql-action/init@v1 31 | # Override language selection by uncommenting this and choosing your languages 32 | # with: 33 | # languages: go, javascript, csharp, python, cpp, java 34 | 35 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 36 | # If this step fails, then you should remove it and run the build manually (see below) 37 | - name: Autobuild 38 | uses: github/codeql-action/autobuild@v1 39 | 40 | # ℹ️ Command-line programs to run using the OS shell. 41 | # 📚 https://git.io/JvXDl 42 | 43 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 44 | # and modify them (or add more) to build your code if your project 45 | # uses a compiled language 46 | 47 | #- run: | 48 | # make bootstrap 49 | # make release 50 | 51 | - name: Perform CodeQL Analysis 52 | uses: github/codeql-action/analyze@v1 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | npm-debug.log 4 | docs/.sass-cache/ 5 | docs/.webpack/ 6 | .DS_Store 7 | .coverage/ 8 | .vscode/ 9 | test/npm-lib/places.js 10 | test/npm-widget/places.js 11 | test/npm-autocomplete/places.js 12 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 10.24.1 2 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.7.3 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: stable 3 | before_install: 4 | - git config --global user.email "algobot@users.noreply.github.com" 5 | - git config --global user.name "algobot" 6 | - rvm install 2.7.0 7 | - rvm use 2.7.0 8 | - "(cd docs && bundle install)" 9 | script: 10 | - npm run test:ci 11 | branches: 12 | only: 13 | - master 14 | notifications: 15 | slack: 16 | rooms: 17 | secure: ksGBanrJ0rmBUpMJT8TWCvjJ6F8Rlin8a9DQNPNOa1s+bCGswp87V1a1bSybz/166JflMqSutf6ES2/qBcp8uhXS3hfKdpj3wJwUPtiWQ+Q1GRAsL7ZiPlz/OgOkACihyrONipjzTANSKhAy7NiJSGOMbSn09yUaaun+wp5iy1KJ2qcC/GRbytkyyDkzzVYDKonNV96KINeTnv3WnM+cgt/1YEzvQ6lPLExS0S90m4m/JUn+pO4CNfw0uHc1NEd3whPQi7WDr1a43qNGea7/WFg9f8yDn1PFnkLujYku77rfFrn164s1UaerUuHusEX7Qff/0BZ3Fy29LPfmQIqZzrb5RGRnsYxv+nyZwMuWw1xP/Ag2fs+GuPw8JG2JJNE61aAKL+HgbC/g4XaSckvwMzA3T/5cvJVh7aIBQmptDuB8AWygp6srBKgKtTmZxqFnpZaHm1Pz5A2C/mERQNf6YQorv/QBtT7seek9CtS5DBqlaBxogHTRN1qJ+dNZ/t1S8Tk5QT4w8Wt8L3xS4fBEakH0eaFXtKAPDO8optNMQhHesvBGUfOJ+bjaT/2626BFK9FXJg3VTlgPMZlto8QSaax6zJocmC3PGxvHOevB4cjR3j44msvmRRtgkRXIuxTK1mXamCbH2UCXLN5aVgXWSQjZY9W5uG8sqwFjnao4VZg= 18 | cache: 19 | bundler: true 20 | yarn: true 21 | env: 22 | global: 23 | secure: o9jGb6EMsAv955rn+Mu1GPLX+3aA6j5POM5rjq3X3T+zRSV5eBEnP8TiRSmUqIz+aLXmvQMKsCJsFc4oI9udjotjwBUXKvl4Zq7Ph45iVunQLi06Bp+4DaB7pSrAn/qeY5R2P38jIonN5nitjDQSf/htgxsvurC8aX0QR1Bp4TdQNVQUuedaGjHfGitBDwgGIjU7LatHwPKguJA/NnKKg9qFZNJDrZ3Wb9O9//RJyWxcnYF4JEVKztgk7I+vGXkN7a7mpCsesUxS6qjs2MRTY7qjFRXHV3HrltLEwYs6z+0ijmTJl3e6W8KO1kKj3qfQCTpkZV1R6YWDtefKpQfzW0SBFgTX8rJ/pnt+o0DxLRFzHpnUCZBcAqvtjZOzwP2qJyqI3S9LGLZ6QZ2OpqTGamBm4DLrAUmeB84jImbgj2buiRDMStY0ut2z9RURdr2zWSUouVojjJmlhbBTWvwGk6x6ZbQy1P+SZGSzjXbKn25X9c14B6OJUjv5NFdDZf4zxWdYaMhX8tum+SMvnwZjoGC57R+WyrN0M27Xu0OAO30PyEFTBpe0y3JN7bdeL1AnZxqlSJ+gX2BfRZaoLnQzdTcUW+VUIRBwRsLJCFqGo6GAATe2kDbDDZshSKkP8sJnbmbty7BY9j5PTe1tXqDwCT0l7WZtq+K6WRxFVay44xU= 24 | -------------------------------------------------------------------------------- /DATA_REFRESH.md: -------------------------------------------------------------------------------- 1 | ### Dataset freshness 2 | - OSM Data from 2019-10-16 3 | - Geonames Data from 2019-09-30 4 | - BAN Data from 2018-09-17 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Algolia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PIPELINE_CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ### 2019-01-07 3 | 4 | 5 | #### Features 6 | 7 | * **admin-levels** 8 | * define administrative, county and city admin levels by country (#104) 9 | 10 | 11 | 12 | ### 2018-11-15 13 | 14 | 15 | #### Bug Fixes 16 | 17 | * **tests** 18 | * Update Andorra end-to-end test (#94) 19 | 20 | 21 | 22 | ### 2018-11-02 23 | 24 | 25 | #### Bug Fixes 26 | 27 | * **pt-housenumber** 28 | * put house number after streetname in Portugal (#89) 29 | 30 | 31 | 32 | ### 2018-10-31 33 | 34 | 35 | #### Bug Fixes 36 | 37 | * **district** 38 | * rank district lower than the city (#88) 39 | 40 | 41 | 42 | ### 2018-08-31 43 | 44 | 45 | #### Bug Fixes 46 | 47 | * **historic-geonames** 48 | * update alternateNames processing to handle newlines and new table format (#86) 49 | 50 | 51 | 52 | ### 2018-08-29 53 | 54 | 55 | #### Bug Fixes 56 | 57 | * **merge-geonames** 58 | * use postcodes from OSM if no postcodes in Geonames (#83) 59 | 60 | 61 | 62 | ### 2018-07-30 63 | 64 | 65 | #### Bug Fixes 66 | 67 | * **historic-geonames** 68 | * update alternateNames processing to handle newlines and new table format (#85) 69 | 70 | 71 | 72 | ### 2018-06-05 73 | 74 | 75 | #### Bug Fixes 76 | 77 | * **null-country** 78 | * use iso instead of country in PlanetOutput (#78) 79 | 80 | 81 | 82 | ### 2018-04-09 83 | 84 | 85 | #### Bug Fixes 86 | 87 | * **deploy** 88 | * remove useless dir creation which fails the rollback, data being in a wrong subdir (#74) 89 | 90 | 91 | 92 | ### 2018-01-30 93 | 94 | 95 | #### Features 96 | 97 | * **docs** 98 | * add troubleshooting for snap.rb (#60) 99 | 100 | 101 | 102 | ### 2018-01-26 103 | 104 | 105 | #### Features 106 | 107 | * **linked-places** 108 | * expose linked_place_id and linked_address in object (#44) 109 | 110 | 111 | #### Bug Fixes 112 | 113 | * **country-codes** 114 | * fix wrong country attributions (#41) 115 | 116 | 117 | 118 | ### 2018-01-02 119 | 120 | 121 | #### Features 122 | 123 | * **docs** 124 | * add a knowledge base to the repository 125 | 126 | 127 | #### Bug Fixes 128 | 129 | * **config** 130 | * add a config.example.json to use as a basis for config.json (#42) 131 | 132 | 133 | -------------------------------------------------------------------------------- /__mocks__/algoliasearch/src/browser/builds/algoliasearchLite.js: -------------------------------------------------------------------------------- 1 | const defaultSearchStub = jest.fn(() => Promise.resolve()); 2 | let searchStub = defaultSearchStub; 3 | const addAlgoliaAgent = jest.fn(); 4 | const search = jest.fn((...args) => searchStub(...args)); 5 | const reverse = jest.fn((...args) => searchStub(...args)); 6 | 7 | const algoliasearch = { 8 | initPlaces: jest.fn(() => ({ 9 | as: { 10 | addAlgoliaAgent, 11 | }, 12 | search, 13 | reverse, 14 | })), 15 | }; 16 | 17 | algoliasearch.__searchSpy = search; 18 | algoliasearch.__reverseSpy = reverse; 19 | algoliasearch.__addAlgoliaAgentSpy = addAlgoliaAgent; 20 | algoliasearch.__setSearchStub = (fn) => { 21 | searchStub = fn; 22 | }; 23 | algoliasearch.__clearSearchStub = () => { 24 | searchStub = defaultSearchStub; 25 | }; 26 | 27 | export default algoliasearch; 28 | -------------------------------------------------------------------------------- /__mocks__/autocomplete.js.js: -------------------------------------------------------------------------------- 1 | const autocomplete = jest.fn(() => { 2 | document.querySelector('input').classList.add('ap-input'); 3 | let query = 'query'; 4 | 5 | const instance = { 6 | on: jest.fn(), 7 | focus: jest.fn(), 8 | val: jest.fn(() => query), 9 | autocomplete: { 10 | setVal: jest.fn(), 11 | getVal: jest.fn(), 12 | open: jest.fn(), 13 | close: jest.fn(), 14 | destroy: jest.fn(), 15 | }, 16 | }; 17 | autocomplete.__instance = instance; 18 | autocomplete.__setQuery = (q) => { 19 | query = q; 20 | }; 21 | return instance; 22 | }); 23 | 24 | export default autocomplete; 25 | -------------------------------------------------------------------------------- /autocompleteDataset.js: -------------------------------------------------------------------------------- 1 | // we need to export using commonjs for ease of usage in all 2 | // JavaScript environments 3 | 4 | /* eslint-disable import/no-commonjs */ 5 | 6 | require('./src/navigatorLanguage'); 7 | const createAutocompleteDataset = require('./src/createAutocompleteDataset') 8 | .default; 9 | const css = require('./babel-css').default; 10 | const insertCss = require('insert-css'); 11 | insertCss(css, { prepend: true }); 12 | 13 | // must use module.exports to be commonJS compatible 14 | module.exports = createAutocompleteDataset; 15 | /* eslint-enable import/no-commonjs */ 16 | -------------------------------------------------------------------------------- /babel-css.js: -------------------------------------------------------------------------------- 1 | // this is proxy file so that babel inlines src/places.css into the css variable 2 | // since it is not a commonjs file 3 | import css from './src/places.css'; 4 | 5 | export default css; 6 | -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/places/e417a59765b86972a812ec28ad11ccd53f909bbb/demo.gif -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile ~/.gitignore_global 6 | 7 | # Ignore bundler config 8 | /.bundle 9 | 10 | # Ignore the build directory 11 | /build 12 | 13 | # Ignore cache 14 | /.sass-cache 15 | /.cache 16 | 17 | # Ignore .DS_store file 18 | .DS_Store 19 | -------------------------------------------------------------------------------- /docs/Gemfile: -------------------------------------------------------------------------------- 1 | # If you do not have OpenSSL installed, change 2 | # the following line to use 'http://' 3 | source 'https://rubygems.org' 4 | 5 | gem 'kramdown' 6 | gem 'kramdown-parser-gfm' 7 | 8 | # Middleman Gems 9 | gem 'middleman', '~> 4.4.0' 10 | gem 'middleman-livereload' 11 | gem 'middleman-minify-html' 12 | gem 'middleman-syntax' 13 | gem 'middleman-deploy', '~> 2.0.0-alpha' 14 | gem 'middleman-protect-emails' 15 | -------------------------------------------------------------------------------- /docs/source/api-clients.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | This page has been moved to https://www.algolia.com/ref/places 11 | 12 | -------------------------------------------------------------------------------- /docs/source/bootstrap.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | This page has been moved to https://www.algolia.com/ref/places 11 | 12 | -------------------------------------------------------------------------------- /docs/source/contact.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | This page has been moved to https://www.algolia.com/ref/places 11 | -------------------------------------------------------------------------------- /docs/source/documentation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | This page has been moved to https://www.algolia.com/ref/places 11 | 12 | -------------------------------------------------------------------------------- /docs/source/examples.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | This page has been moved to https://www.algolia.com/ref/places 11 | ` -------------------------------------------------------------------------------- /docs/source/images/algoliaPlaces_demo_checkout.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/places/e417a59765b86972a812ec28ad11ccd53f909bbb/docs/source/images/algoliaPlaces_demo_checkout.gif -------------------------------------------------------------------------------- /docs/source/images/algoliaPlaces_demo_map.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/places/e417a59765b86972a812ec28ad11ccd53f909bbb/docs/source/images/algoliaPlaces_demo_map.gif -------------------------------------------------------------------------------- /docs/source/images/clippy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/source/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/places/e417a59765b86972a812ec28ad11ccd53f909bbb/docs/source/images/favicon.png -------------------------------------------------------------------------------- /docs/source/images/hp-demo-autocompletejs.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/places/e417a59765b86972a812ec28ad11ccd53f909bbb/docs/source/images/hp-demo-autocompletejs.gif -------------------------------------------------------------------------------- /docs/source/images/inner-background_footer.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Rectangle 89 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /docs/source/images/map-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/places/e417a59765b86972a812ec28ad11ccd53f909bbb/docs/source/images/map-demo.gif -------------------------------------------------------------------------------- /docs/source/images/svg/advanced-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | advanced-icon 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/source/images/svg/algolia-mark-white.svg: -------------------------------------------------------------------------------- 1 | algolia-new-logo copy -------------------------------------------------------------------------------- /docs/source/images/svg/city-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | city-icon 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/source/images/svg/community-badge.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/source/images/svg/country-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | country-icon 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/source/images/svg/form-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | form-icon 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/source/images/svg/icon-arrow-pipe.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Shape 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/source/images/svg/icon-github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Shape 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/source/images/svg/icon-heart-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Shape 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/source/images/svg/icon-heart-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Shape 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/source/images/svg/icon-heart.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | icon-heart 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/source/images/svg/icon-hover-cursor-visible.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Shape 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/source/images/svg/icon-hover-cursor.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Shape 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/source/images/svg/icon-search-white.svg: -------------------------------------------------------------------------------- 1 | Icons/Search -------------------------------------------------------------------------------- /docs/source/images/svg/iconsicon-heart.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21FAE128-B409-439B-9A26-1A68EA5F2290 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/source/images/svg/illus-feat-autocomplete.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | feature-icons/illus-feat-autocomplete 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /docs/source/images/svg/illus-feat-typo-tolerance.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | feature-icons/illus-feat-typo-tolerance 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/source/images/svg/logo-community.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | logo/algolia-community/mark-sm 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/source/images/svg/map-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | map-icon 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/source/images/svg/places-illustration.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Geosearch 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /docs/source/images/svg/search-icon-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | search-icon 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/source/images/svg/search-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | search-icon copy 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/source/images/visual-preview-places.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/places/e417a59765b86972a812ec28ad11ccd53f909bbb/docs/source/images/visual-preview-places.png -------------------------------------------------------------------------------- /docs/source/images/visual-preview-places_mobile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/places/e417a59765b86972a812ec28ad11ccd53f909bbb/docs/source/images/visual-preview-places_mobile.png -------------------------------------------------------------------------------- /docs/source/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | This page has been moved to https://www.algolia.com/ref/places 11 | -------------------------------------------------------------------------------- /docs/source/javascripts/activateClipboard.js: -------------------------------------------------------------------------------- 1 | /* global clippyPath */ 2 | 3 | import ClipboardJS from 'clipboard'; 4 | 5 | export default function activateClipboard(codeSamples) { 6 | Array.from(codeSamples).forEach((codeSample) => { 7 | const copyToClipboard = document.createElement('button'); 8 | copyToClipboard.innerHTML = ``; 9 | copyToClipboard.classList.add('clipboard'); 10 | codeSample.appendChild(copyToClipboard); 11 | const clipboard = new ClipboardJS(copyToClipboard, { 12 | text: () => codeSample.textContent, 13 | }); 14 | 15 | copyToClipboard.addEventListener('mouseleave', () => { 16 | copyToClipboard.removeAttribute('aria-label'); 17 | copyToClipboard.classList.remove('hint--top'); 18 | }); 19 | clipboard.on('success', () => { 20 | copyToClipboard.classList.add('hint--top'); 21 | copyToClipboard.setAttribute('aria-label', 'Copied!'); 22 | }); 23 | // safari: https://clipboardjs.com/#browser-support 24 | clipboard.on('error', () => 25 | copyToClipboard.setAttribute('aria-label', 'Hit ⌘+C to copy') 26 | ); 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /docs/source/javascripts/anchorableElements.js: -------------------------------------------------------------------------------- 1 | export default function anchorableElements(elements) { 2 | Array.from(elements).forEach((element) => { 3 | // duplicate id in name to benefit from css :target 4 | element.setAttribute('name', element.getAttribute('id')); 5 | const anchor = document.createElement('a'); 6 | anchor.setAttribute('href', `#${element.id}`); 7 | anchor.classList.add('anchor'); 8 | anchor.textContent = '#'; 9 | element.appendChild(anchor); 10 | }); 11 | } 12 | -------------------------------------------------------------------------------- /docs/source/javascripts/autoPullCredentials.js: -------------------------------------------------------------------------------- 1 | function saveCredentialsForSession({ appId, apiKey }) { 2 | sessionStorage.setItem('placesAppId', appId); 3 | sessionStorage.setItem('placesApiKey', apiKey); 4 | } 5 | 6 | function getCredentialsFromSession() { 7 | const appId = sessionStorage.getItem('placesAppId'); 8 | const apiKey = sessionStorage.getItem('placesApiKey'); 9 | 10 | if (appId && apiKey) { 11 | return { appId, apiKey }; 12 | } 13 | 14 | return null; 15 | } 16 | 17 | function getCredentialsFromAlgolia() { 18 | return fetch('https://www.algolia.com/static/current_user', { 19 | credentials: 'include', 20 | headers: {}, 21 | referrer: 'https://www.algolia.com/', 22 | referrerPolicy: 'no-referrer-when-downgrade', 23 | body: null, 24 | method: 'GET', 25 | mode: 'cors', 26 | }) 27 | .then((x) => x.json()) 28 | .then((credentials) => { 29 | const { application_id: appId, search_api_key: apiKey } = credentials; 30 | if (appId && appId.startsWith('pl') && apiKey) { 31 | saveCredentialsForSession({ appId, apiKey }); 32 | return { appId, apiKey }; 33 | } 34 | 35 | return null; 36 | }) 37 | .catch(() => null); 38 | } 39 | 40 | function getCredentials() { 41 | return new Promise((resolve, reject) => { 42 | const sessionCredentials = getCredentialsFromSession(); 43 | if (!sessionCredentials) { 44 | getCredentialsFromAlgolia() 45 | .then((credentials) => { 46 | resolve(credentials || {}); 47 | }) 48 | .catch(reject); 49 | } else { 50 | resolve(sessionCredentials || {}); 51 | } 52 | }); 53 | } 54 | 55 | function updatePlaceholders({ appId, apiKey }) { 56 | document.querySelectorAll('.rouge-code > pre > span').forEach((elt) => { 57 | if (elt.textContent.match(/.*YOUR_PLACES_APP_ID.*/)) { 58 | if (elt.textContent.startsWith(`'`)) { 59 | // eslint-disable-next-line no-param-reassign 60 | elt.innerHTML = `'${appId}'`; 61 | } else { 62 | // eslint-disable-next-line no-param-reassign 63 | elt.innerHTML = `"${appId}"`; 64 | } 65 | } 66 | 67 | if (elt.textContent.match(/.*YOUR_PLACES_API_KEY.*/)) { 68 | if (elt.textContent.startsWith(`'`)) { 69 | // eslint-disable-next-line no-param-reassign 70 | elt.innerHTML = `'${apiKey}'`; 71 | } else { 72 | // eslint-disable-next-line no-param-reassign 73 | elt.innerHTML = `"${apiKey}"`; 74 | } 75 | } 76 | }); 77 | } 78 | 79 | function noop() {} 80 | 81 | export default function autoPullCredentials() { 82 | return getCredentials() 83 | .then(({ appId, apiKey }) => { 84 | if (appId && apiKey) { 85 | updatePlaceholders({ appId, apiKey }); 86 | } 87 | }) 88 | .catch(noop); 89 | } 90 | -------------------------------------------------------------------------------- /docs/source/javascripts/common.js: -------------------------------------------------------------------------------- 1 | import responsiveNavigation from './responsiveNavigation'; 2 | import autoPullCredentials from './autoPullCredentials'; 3 | import './docsearch'; 4 | responsiveNavigation(); 5 | autoPullCredentials(); 6 | -------------------------------------------------------------------------------- /docs/source/javascripts/docsearch.js: -------------------------------------------------------------------------------- 1 | import docsearch from 'docsearch.js'; 2 | 3 | const search = docsearch({ 4 | apiKey: '5718722ffb11e109821befd53a1d9fde', 5 | indexName: 'places', 6 | inputSelector: '#docsearch', 7 | }); 8 | 9 | const form = document.querySelector('#docsearch-form'); 10 | const docsearchInput = document.querySelector('#docsearch'); 11 | const reset = form.querySelector('[type="reset"]'); 12 | const searchbox = form.querySelector('.searchbox__input'); 13 | 14 | reset.addEventListener('click', () => { 15 | searchbox.focus(); 16 | reset.classList.add('hide'); 17 | search.autocomplete.autocomplete.setVal(''); 18 | }); 19 | 20 | docsearchInput.addEventListener('keyup', () => { 21 | if (searchbox.value.length === 0) { 22 | reset.classList.add('hide'); 23 | } else { 24 | reset.classList.remove('hide'); 25 | } 26 | }); 27 | 28 | docsearchInput.addEventListener('change', () => 29 | docsearchInput.classList.add('filled') 30 | ); 31 | 32 | docsearchInput.addEventListener('blur', () => { 33 | if (docsearchInput.value.length === 0) { 34 | docsearchInput.classList.remove('filled'); 35 | } 36 | }); 37 | 38 | search.autocomplete.on('autocomplete:selected', () => 39 | reset.classList.add('hide') 40 | ); 41 | -------------------------------------------------------------------------------- /docs/source/javascripts/documentation-layout.js: -------------------------------------------------------------------------------- 1 | import sidebar from './sidebar'; 2 | import activateClipboard from './activateClipboard'; 3 | import anchorableElements from './anchorableElements'; 4 | 5 | sidebar({ 6 | headersContainer: document.querySelector('.documentation-container'), 7 | sidebarContainer: document.querySelector('#sidebar'), 8 | headerStartLevel: 2, 9 | }); 10 | anchorableElements( 11 | document 12 | .querySelector('.documentation-container') 13 | .querySelectorAll('h2, h3, .api-entry') 14 | ); 15 | activateClipboard(document.querySelectorAll('.rouge-code')); 16 | -------------------------------------------------------------------------------- /docs/source/javascripts/index.js: -------------------------------------------------------------------------------- 1 | /* eslint no-console: 0 */ 2 | /* global places */ 3 | 4 | const $input = document.querySelector('#landing-demo'); 5 | const placesAutocomplete = places({ 6 | appId: 'plFMJJT5O9PC', 7 | apiKey: '8b126ce956636c64b6e74c8b3f3d0e5e', 8 | container: $input, 9 | }); 10 | $input.style.opacity = 1; // we initially hide the input to avoid size flickering 11 | 12 | if (process.env.NODE_ENV === 'development') { 13 | const events = ['change', 'suggestions', 'cursorchanged']; 14 | events.forEach((eventName) => 15 | placesAutocomplete.on(eventName, (eventData) => { 16 | console.log(`Algolia Places: received event **${eventName}**`); 17 | if (typeof console.table === 'function') { 18 | Object.keys(eventData).forEach((dataKeyName) => { 19 | console.log(`data: ${dataKeyName}`); 20 | const data = eventData[dataKeyName]; 21 | if (Array.isArray(data)) { 22 | console.table(data); 23 | } else { 24 | console.log(data); 25 | } 26 | }); 27 | } else { 28 | console.log('event data:', eventData); 29 | } 30 | }) 31 | ); 32 | } 33 | 34 | const processingTime = (time) => { 35 | switch (true) { 36 | case time < 26: 37 | return 'data-highlight-fast'; 38 | case time < 46: 39 | return 'data-highlight-medium'; 40 | case time < 66: 41 | return 'data-highlight-slow'; 42 | default: 43 | return 'data-highlight-fast'; 44 | } 45 | }; 46 | 47 | const $response = document.querySelector('#json-response'); 48 | const $responseText = document.querySelector('#json-response-text'); 49 | const $responseTiming = document.querySelector('#json-response-timing'); 50 | placesAutocomplete.on('change', (e) => { 51 | let postcodes = (e.suggestion.postcodes || []).slice(0, 3); 52 | if (postcodes.length !== (e.suggestion.postcodes || []).length) { 53 | postcodes = [...postcodes, '...']; 54 | } else if (postcodes.length === 0) { 55 | postcodes = undefined; 56 | } 57 | 58 | const content = { 59 | ...e, 60 | // hide advanced API event data in demo 61 | suggestion: { 62 | ...e.suggestion, 63 | hit: undefined, 64 | hitIndex: undefined, 65 | query: undefined, 66 | rawAnswer: undefined, 67 | postcodes, 68 | }, 69 | rawAnswer: undefined, 70 | suggestionIndex: undefined, 71 | }; 72 | const output = JSON.stringify(content, null, 2); 73 | 74 | const regex = { 75 | key: /"(.*)"/g, 76 | value: /"(.*)":/g, 77 | float: /([-]?\d+\.\d+)/g, 78 | highlight: /((.*)<\/em>)/g, 79 | default: /[:]/g, 80 | }; 81 | 82 | const codes = output 83 | .replace(regex.value, `"$1":`) 84 | .replace(regex.key, `"$1"`) 85 | .replace(regex.float, `$1`) 86 | .replace( 87 | regex.highlight, 88 | `<em>$1</em>` 89 | ) 90 | .replace(regex.default, `:`); 91 | 92 | $responseText.innerHTML = codes; 93 | $responseTiming.innerHTML = `Computed in ${e.rawAnswer.processingTimeMS}ms`; 96 | $response.classList.add('display'); 97 | }); 98 | placesAutocomplete.on('clear', () => { 99 | $responseText.textContent = ''; 100 | $response.classList.remove('display'); 101 | }); 102 | -------------------------------------------------------------------------------- /docs/source/javascripts/responsiveNavigation.js: -------------------------------------------------------------------------------- 1 | /* global currentPath */ 2 | // currentPath is computed by Middleman, inlined in layout.erb and contains 3 | // the source file name of the current page (index.html, documentation.html) 4 | 5 | export default function responsiveNavigation() { 6 | const navigation = document.querySelector('.ac-nav'); 7 | const links = navigation.querySelectorAll('a'); 8 | const navigationAsSelect = document.createElement('select'); 9 | 10 | if ( 11 | navigator.userAgent.match(/iPhone/i) || 12 | navigator.userAgent.match(/iPod/i) 13 | ) { 14 | navigationAsSelect.classList.add('display-on-small', 'device'); 15 | } else { 16 | navigationAsSelect.classList.add('display-on-small'); 17 | } 18 | 19 | Array.from(links).forEach((link) => { 20 | const option = document.createElement('option'); 21 | option.text = link.title; 22 | option.value = link.href; 23 | if (link.dataset.path === currentPath) { 24 | option.selected = true; 25 | } 26 | navigationAsSelect.appendChild(option); 27 | }); 28 | 29 | navigation.appendChild(navigationAsSelect); 30 | navigationAsSelect.addEventListener('change', (e) => { 31 | window.location = e.target.value; 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /docs/source/javascripts/support.js: -------------------------------------------------------------------------------- 1 | const defaultIp = 'Find it on https://api.ipify.org'; 2 | const defaultCoords = 'Find it on https://jsfiddle.net/qmjet97b/'; 3 | const link = document.querySelector('#support-google-form'); 4 | const getFormURL = (ip, coords) => 5 | `https://docs.google.com/forms/d/13r_7B72v6u6326atqzKZpv0fs_3OUOJFR-6QDipHl3Y/viewform?entry.1560244398&entry.1894094686&entry.1809496416&entry.2029760924&entry.1442423869&entry.1714224469&entry.1070945708=${encodeURIComponent( 6 | ip 7 | )}&entry.2019626860=${encodeURIComponent(coords)}`; 8 | link.setAttribute('href', getFormURL(defaultIp, defaultCoords)); 9 | link.addEventListener('click', (clickEvent) => { 10 | clickEvent.preventDefault(); 11 | try { 12 | navigator.geolocation.getCurrentPosition( 13 | ({ coords }) => { 14 | // success 15 | window.location.href = getFormURL( 16 | window.userip ? `${window.userip} (detected)` : defaultIp, 17 | `${coords.latitude},${coords.longitude} (detected)` 18 | ); 19 | }, 20 | () => { 21 | window.location.href = clickEvent.target.href; 22 | } // error 23 | ); 24 | } catch (geoNotAvailable) { 25 | window.location.href = clickEvent.target.href; 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /docs/source/layouts/bootstrap.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Algolia Places | No style test 18 | <%= javascript_include_tag config[:places_lib_url] %> 19 | 24 | 25 | 26 | 27 | <%= yield %> 28 | 29 | 30 | -------------------------------------------------------------------------------- /docs/source/layouts/documentation.erb: -------------------------------------------------------------------------------- 1 | <% wrap_layout :layout do %> 2 |
3 |
4 | 5 |
6 | <%= yield %> 7 |
8 |
9 |
10 | <%= javascript_include_tag 'documentation-layout' %> 11 | <% end %> 12 | -------------------------------------------------------------------------------- /docs/source/layouts/landing.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | Algolia Places <%= "| #{current_page.data.title}" if (current_page.path != 'index.html') %> 27 | 28 | 29 | 30 | <% if current_page.path == 'index.html' %> 31 | 32 | <% end %> 33 | <% if current_page.path == 'contact.html' %> 34 | 35 | <% end %> 36 | 37 | <%= stylesheet_link_tag(:landing) %> 38 | <%= auto_stylesheet_link_tag %> 39 | <%= javascript_include_tag config[:places_lib_url] %> 40 | 44 | 45 | 46 | 47 | <%= partial("/partials/navigation") %> 48 | <%= yield %> 49 | <%= partial("/partials/footer") %> 50 | <%= javascript_include_tag :common %> 51 | <%= auto_javascript_include_tag %> 52 | 53 | 54 | -------------------------------------------------------------------------------- /docs/source/layouts/layout.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | Algolia Places <%= "| #{current_page.data.title}" if (current_page.path != 'index.html') %> 27 | 28 | 29 | 30 | <% if current_page.path == 'index.html' %> 31 | 32 | <% end %> 33 | <% if current_page.path == 'contact.html' %> 34 | 35 | <% end %> 36 | 37 | <%= stylesheet_link_tag :site %> 38 | <%= auto_stylesheet_link_tag %> 39 | <%= javascript_include_tag config[:places_lib_url] %> 40 | 44 | 45 | 46 | 47 | <%= partial("/partials/navigation") %> 48 | <%= partial("/partials/hero") %> 49 | <%= yield %> 50 | <%= partial "/partials/footer" %> 51 | <%= javascript_include_tag :common %> 52 | <%= auto_javascript_include_tag %> 53 | 54 | 55 | -------------------------------------------------------------------------------- /docs/source/partials/examples/_autocomplete_dataset.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 47 | <%= javascript_include_tag config[:places_autocomplete_dataset_lib_url] %> 48 | -------------------------------------------------------------------------------- /docs/source/partials/examples/_city_search.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%= javascript_include_tag config[:places_lib_url] %> 4 | -------------------------------------------------------------------------------- /docs/source/partials/examples/_complete_form.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 |
6 |
7 | 8 | 9 |
10 |
11 | 12 | 13 |
14 |
15 | 16 | 17 |
18 |
19 | 20 | <%= javascript_include_tag config[:places_lib_url] %> 21 | -------------------------------------------------------------------------------- /docs/source/partials/examples/_country_search.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 | 7 | <%= javascript_include_tag config[:places_lib_url] %> 8 | -------------------------------------------------------------------------------- /docs/source/partials/examples/_demo.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%= javascript_include_tag config[:places_lib_url] %> 4 | -------------------------------------------------------------------------------- /docs/source/partials/examples/_disable_styling.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | <%= javascript_include_tag config[:places_lib_url] %> 6 | 44 | 45 | -------------------------------------------------------------------------------- /docs/source/partials/examples/_instantsearch.html.erb: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 7 | 8 | <%= javascript_include_tag config[:instantsearch_lib_url] %> 9 | <%= javascript_include_tag config[:places_instantsearch_widget_lib_url] %> 10 | <%= javascript_include_tag config[:google_maps_lib_url] %> 11 | -------------------------------------------------------------------------------- /docs/source/partials/examples/_map.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 7 | 8 | <%= javascript_include_tag config[:places_lib_url] %> 9 | -------------------------------------------------------------------------------- /docs/source/partials/examples/_map_paris.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 9 | 10 | <%= javascript_include_tag config[:places_lib_url] %> 11 | -------------------------------------------------------------------------------- /docs/source/partials/examples/_postcode_search.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%= javascript_include_tag config[:places_lib_url] %> 4 | -------------------------------------------------------------------------------- /docs/source/partials/examples/_reverse_geocoding.html.erb: -------------------------------------------------------------------------------- 1 | 9 |
10 | 11 |
12 | 13 |
14 |
15 | 16 | 17 |
18 |
19 | 20 | 21 |
22 |
23 | 24 |
25 |
26 | 27 |
28 |
29 | 30 | 31 |
32 |
33 | 34 | 35 |
36 |
37 | 38 | 39 |
40 |
41 | 42 | 43 | -------------------------------------------------------------------------------- /docs/source/partials/examples/_simple_input.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Selected: none

4 | <%= javascript_include_tag config[:places_lib_url] %> 5 | -------------------------------------------------------------------------------- /docs/source/partials/examples/_single_country_search.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 3 | 7 |
8 | 9 | 10 | 11 |

Selected: none

12 | <%= javascript_include_tag config[:places_lib_url] %> 13 | -------------------------------------------------------------------------------- /docs/source/partials/examples/_templates.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%= javascript_include_tag config[:places_lib_url] %> 4 | -------------------------------------------------------------------------------- /docs/source/partials/examples/_visual-helper.html.haml: -------------------------------------------------------------------------------- 1 | %div.preview-holder.no-mobile 2 | %img{:src => "/images/visual-preview-places.png", :alt => "preview-places", :id => "visual-helper"}/ 3 | .overlay 4 | .ov-input{'data-mention' => '.ap-input'} 5 | .ov-cancel{'data-mention' => '.ap-icon-[clear/pin]'} 6 | .ov-suggestions{'data-mention' => '.ap-dropdown-menu'} 7 | .ov-suggestion-cursor{'data-mention' => '.ap-suggestion.ap-cursor (on hover)'} 8 | .ov-suggestion{'data-mention' => '.ap-suggestion'} 9 | .ov-icon{'data-mention' => '.ap-suggestion-icon'} 10 | .ov-name{'data-mention' => '.ap-name'} 11 | .ov-highlight{'data-mention' => ''} 12 | .ov-address{'data-mention' => '.ap-address'} 13 | 14 | %div.preview-holder.display-on-small 15 | %img{:src => "/images/visual-preview-places_mobile.png", :alt => "preview-places", :id => "visual-helper"}/ 16 | 17 | %table.api 18 | %thead 19 | %tr 20 | %th CSS Class 21 | %th Description 22 | %tbody 23 | %tr 24 | %td 25 | %div{:class => "css-class api-entry", :id => "css-class-ap-input"} 26 | .ap-input 27 | 28 | %td 29 | %p This class is the one use by the main places input 30 | 31 | %tr 32 | %td 33 | %div{:class => "css-class api-entry", :id => "css-class-ap-icon-pin"} 34 | .ap-icon-pin 35 | 36 | %td 37 | %p This is the class attached to the pin icon, which is visible when the input is on it's normal state 38 | 39 | %tr 40 | %td 41 | %div{:class => "css-class api-entry", :id => "css-class-ap-icon-clear"} 42 | .ap-icon-clear 43 | 44 | %td 45 | %p This is the class attached to the clear icon, which is visible when the input is filled, clicking it will empty the input 46 | 47 | %tr 48 | %td 49 | %div{:class => "css-class api-entry", :id => "css-class-ap-dropdown-menu"} 50 | .ap-dropdown-menu 51 | 52 | %td 53 | %p This class is the one that is on the whole suggestions wrapper 54 | 55 | %tr 56 | %td 57 | %div{:class => "css-class api-entry", :id => "css-class-ap-suggestion"} 58 | .ap-suggestion 59 | 60 | %td 61 | %p The .ap-suggestion class is the class of each dropdown suggestions 62 | 63 | %tr 64 | %td 65 | %div{:class => "css-class api-entry", :id => "css-class-ap-cursor"} 66 | .ap-cursor 67 | 68 | %td 69 | %p The .ap-cursor class is added to .ap-suggestion when the suggestion is hovered 70 | 71 | %tr 72 | %td 73 | %div{:class => "css-class api-entry", :id => "css-class-ap-suggestion-icon"} 74 | .ap-suggestion-icon 75 | 76 | %td 77 | %p The .ap-suggestion-icon is the class that is used on the left icon of each suggestions 78 | 79 | %tr 80 | %td 81 | %div{:class => "css-class api-entry", :id => "css-class-ap-name"} 82 | .ap-name 83 | 84 | %td 85 | %p The .ap-name class is the one used on the name of the place 86 | 87 | %tr 88 | %td 89 | %div{:class => "css-class api-entry", :id => "css-class-ap-address"} 90 | .ap-address 91 | 92 | %td 93 | %p The .ap-address class is the one used on the address of the place 94 | 95 | %tr 96 | %td 97 | %div{:class => "css-class api-entry", :id => "css-class-em"} 98 | <em> 99 | %td 100 | %p The <em> tag in the .ap-suggestion is the tag that is used to make an highlight on each names 101 | -------------------------------------------------------------------------------- /docs/source/partials/examples/reverse-city-search/_code.html.erb: -------------------------------------------------------------------------------- 1 |
2 | Searching around: 3 |
4 |
5 | 6 | 7 | -------------------------------------------------------------------------------- /docs/source/partials/examples/reverse-city-search/_code_places.html.erb: -------------------------------------------------------------------------------- 1 |
2 | Searching around: 3 |
4 | 5 | 6 | <%= javascript_include_tag config[:places_lib_url] %> 7 | -------------------------------------------------------------------------------- /docs/source/partials/examples/reverse-city-search/_demo_places.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

When constructing a search UI using InstantSearch, you may want to filter your dataset to only display some of your products based on the distance to the end user. This is usually done using the aroundLatLngViaIP filter, or aroundLatLng filter if you have access to precise geolocation information. However geographical filters are hard to interpret when displayed in raw format, as noone really knows where the coordinates 48.8566, 2.34287 are.

3 | 4 |

Using Places, you can do a query to find the city in which your user is located and display that city name instead of a geolocation.

5 |
6 | 7 |

Example:

8 | 9 |
10 | Searching around: 11 | 12 |
13 | 14 | <%= javascript_include_tag config[:places_lib_url] %> 15 | -------------------------------------------------------------------------------- /docs/source/partials/footer.html.haml: -------------------------------------------------------------------------------- 1 | %section.ac-footer 2 | 3 | .ac-footer-container 4 | %p.ac-footer-links 5 | Code licensed under 6 | %a.ac-footer-link-item{:href => "https://github.com/algolia/places/blob/master/LICENSE"} MIT 7 | %br/ 8 | %a.ac-footer-link-item{:href => "https://github.com/algolia/places/"} Github 9 | %a.ac-footer-link-item{:href => "https://github.com/algolia/places/issues"} Issues 10 | %a.ac-footer-link-item{:href => "https://www.algolia.com/policies/privacy"} Privacy policy 11 | 12 | .ac-footer-container.ac-footer-brand 13 | %p This project is part of 14 | %img.ac-footer-brand-icon{:src => "images/svg/community-badge.svg"}/ 15 | %figure 16 | %img.ac-footer-brand-logo{:src => "https://res.cloudinary.com/hilnmyskv/image/upload/v1484219849/algolia-community-logo-words-darkbg.svg"}/ 17 | %figcaption Algolia Community 18 | 19 | %a.ac-footer-btn.ac-footer-btn-cta{:href => "https://community.algolia.com/"} See More 20 | %span.ac-icon.ac-icon-love-dark 21 | 22 | %p.ac-footer-version Latest version: #{config[:places_lib_version]} 23 | 24 | .ac-footer-actions 25 | .footer-container 26 | %p Build unique search experiences with Algolia 27 | %a.ac-footer-btn.ac-footer-btn-ghost-grey{:href => "https://www.algolia.com/why?utm_medium=social-owned&utm_source=places%20website&utm_campaign=homepage&utm_term=why"} 28 | See Why 29 | %span.ac-icon-triangle 30 | = partial "/partials/marketing" 31 | -------------------------------------------------------------------------------- /docs/source/partials/hero.html.haml: -------------------------------------------------------------------------------- 1 | %section{:class => ["hero-section", ("shrink" if current_page.path != "index.html")]} 2 | .container 3 | %div.hero-container 4 | 5 | %div.fl-left 6 | %a{href: "https://www.algolia.com/?utm_medium=social-owned&utm_source=places%20website&utm_campaign=homepage", title:"Algolia built this"} 7 | %span{class: "icon icon-algolia-small no-mobile", id: "icon-algolia"} 8 | %span{class: "display-on-small small-illustration"} 9 | %img{src: "images/svg/places-illustration.svg"} 10 | %h1= current_page.data.title 11 | - if current_page.data.subtitle 12 | %h3= current_page.data.subtitle 13 | 14 | - if current_page.path == 'index.html' 15 | %div.fl-right 16 | = partial("/images/svg/places-illustration.svg") 17 | %input{type: "search", id: "landing-demo", class: "hero-searchbar form-control", autofocus: true, placeholder: "Search a city or address", style: 'opacity: 0'} 18 | 19 | %div.relative 20 | %div#json-response 21 | %div#json-response-text 22 | %div#json-response-timing 23 | 24 | - if current_page.path == 'examples.html' 25 | %div.examples-intro 26 | %div.items-holder 27 | %div{:class => "item"} 28 | %a{:href => '#simple-input'} 29 | %span{:class => "square input"} 30 | = partial("/images/svg/search-icon-2.svg") 31 | %span.name Simple Input 32 | 33 | %div{:class => "item"} 34 | %a{:href => '#complete-form'} 35 | %span{:class => "square form"} 36 | = partial("/images/svg/form-icon.svg") 37 | %span.name Complete Form 38 | 39 | %div{:class => "item"} 40 | %a{:href => '#city-search'} 41 | %span{:class => "square city"} 42 | = partial("/images/svg/city-icon.svg") 43 | %span.name City Search 44 | 45 | %div{:class => "item"} 46 | %a{:href => '#country-search'} 47 | %span{:class => "square country"} 48 | = partial("/images/svg/country-icon.svg") 49 | %span.name Country Search 50 | 51 | %div{:class => "item"} 52 | %a{:href => '#displaying-on-a-map'} 53 | %span{:class => "square map"} 54 | = partial("/images/svg/map-icon.svg") 55 | %span.name Link to a map 56 | 57 | %div{:class => "item"} 58 | %a{:href => '#advanced'} 59 | %span{:class => "square advanced"} 60 | = partial("/images/svg/advanced-icon.svg") 61 | %span.name Advanced 62 | -------------------------------------------------------------------------------- /docs/source/partials/marketing.html.erb: -------------------------------------------------------------------------------- 1 | <% if build? %> 2 | 3 | 5 | 10 | <% end %> 11 | -------------------------------------------------------------------------------- /docs/source/partials/status/DATA_REFRESH.md.erb: -------------------------------------------------------------------------------- 1 | ### Dataset freshness 2 | - OSM Data from 2019-10-16 3 | - Geonames Data from 2019-09-30 4 | - BAN Data from 2018-09-17 5 | -------------------------------------------------------------------------------- /docs/source/partials/status/PIPELINE_CHANGELOG.md.erb: -------------------------------------------------------------------------------- 1 | 2 | ### 2019-01-07 3 | 4 | 5 | ##### Features 6 | 7 | * **admin-levels** 8 | * define administrative, county and city admin levels by country (#104) 9 | 10 | 11 | 12 | ### 2018-11-15 13 | 14 | 15 | ##### Bug Fixes 16 | 17 | * **tests** 18 | * Update Andorra end-to-end test (#94) 19 | 20 | 21 | 22 | ### 2018-11-02 23 | 24 | 25 | ##### Bug Fixes 26 | 27 | * **pt-housenumber** 28 | * put house number after streetname in Portugal (#89) 29 | 30 | 31 | 32 | ### 2018-10-31 33 | 34 | 35 | ##### Bug Fixes 36 | 37 | * **district** 38 | * rank district lower than the city (#88) 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /docs/source/pricing.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | This page has been moved to https://www.algolia.com/ref/places 11 | 12 | -------------------------------------------------------------------------------- /docs/source/rest.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | This page has been moved to https://www.algolia.com/ref/places 11 | 12 | -------------------------------------------------------------------------------- /docs/source/status.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | This page has been moved to https://www.algolia.com/ref/places 11 | -------------------------------------------------------------------------------- /docs/source/stylesheets/components/_buttons.scss: -------------------------------------------------------------------------------- 1 | .btn { 2 | background: $darkish-pink; 3 | color: #fff; 4 | border: 1px solid $red-pink; 5 | height: 40px; 6 | max-width: 140px; 7 | line-height: 40px; 8 | padding: 0 1em; 9 | text-align: center; 10 | display: block; 11 | text-decoration: none; 12 | border-radius: 3px; 13 | text-transform: uppercase; 14 | font-weight: 600; 15 | font-size: 12px; 16 | box-shadow: 0 1px 10px rgba(0, 0, 0, 0.2), 0 2px 4px 0 rgba(0, 0, 0, 0.1); 17 | transition: background 0.1s ease; 18 | cursor: pointer; 19 | 20 | &:hover, 21 | &:active { 22 | background: $red-pink 23 | } 24 | 25 | &.btn-cta { 26 | max-width: 230px; 27 | margin: 32px auto; 28 | } 29 | 30 | &.btn-grey { 31 | background: $silver; 32 | border-color: $light-blue-grey; 33 | border-width: 2px; 34 | color: $grey-blue; 35 | box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1), 0 2px 4px 0 rgba(0, 0, 0, 0.1); 36 | } 37 | 38 | &.btn-black { 39 | background: $black; 40 | border-color: mix($black, #fff, 90%); 41 | } 42 | 43 | 44 | &-ghost { 45 | background: transparent; 46 | border-color: currentColor; 47 | font-weight: bold; 48 | max-width: inherit; 49 | padding: 0 32px; 50 | 51 | &-grey { 52 | color: $steel; 53 | 54 | &:hover { 55 | background: $steel; 56 | border-color: $steel; 57 | color: #fff; 58 | 59 | .ico-triangle { 60 | border-left-color: #fff 61 | } 62 | } 63 | } 64 | 65 | &-pink { 66 | color: $red-pink; 67 | 68 | &:hover { 69 | background: $red-pink; 70 | border-color: $red-pink; 71 | color: #fff; 72 | } 73 | } 74 | } 75 | 76 | } -------------------------------------------------------------------------------- /docs/source/stylesheets/components/_clipboard.scss: -------------------------------------------------------------------------------- 1 | .rouge-code { 2 | position:relative; 3 | 4 | .clipboard { 5 | position: absolute; 6 | top: 0; 7 | right: 0; 8 | width: 40px; 9 | height: 39px; 10 | background-color: #f4f4f4; 11 | border: none; 12 | display: flex; 13 | box-sizing: border-box; 14 | border-bottom-left-radius: 4px; 15 | justify-content: center; 16 | align-items: center; 17 | opacity: 0; 18 | transition: opacity 150ms; 19 | } 20 | 21 | &:hover { 22 | .clipboard { 23 | opacity: 1; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /docs/source/stylesheets/components/_examples-intro.scss: -------------------------------------------------------------------------------- 1 | // icon - degree - colorStart - colorEnd 2 | $square-map: ( 3 | (input,135, #13c4a5, #10a4b8), 4 | (form,138, #af84e3, #5071c7), 5 | (city,314, #ec4918, #e25d8d), 6 | (country,134, #fad961, #f76b1c), 7 | (map,135, #81bf30, #00bdbd), 8 | (advanced,135, #bfbfbf, #8a8a8a) 9 | ); 10 | 11 | .examples-intro { 12 | margin-top: 4em; 13 | margin-bottom: 6em; 14 | 15 | float: left; 16 | width: 100%; 17 | display: none; 18 | 19 | @include small-mq { 20 | margin-bottom: 1.5em; 21 | } 22 | 23 | body.examples &{ 24 | display: block; 25 | } 26 | 27 | .items-holder { 28 | margin: 2em auto 2em; 29 | display: block; 30 | max-width: 940px; 31 | padding: 0em; 32 | display: flex; 33 | flex-wrap: wrap; 34 | flex-direction: row; 35 | 36 | @include small-mq { 37 | align-items: center; 38 | margin-bottom: 0; 39 | } 40 | 41 | a { 42 | text-decoration: none; 43 | color: inherit; 44 | } 45 | 46 | .item { 47 | max-width: 120px; 48 | height: 120px; 49 | float: left; 50 | flex:1 1 auto; 51 | margin: 0 22px; 52 | text-align: center; 53 | 54 | &:first-of-type { 55 | margin-left: 0; 56 | } 57 | &:last-of-type { 58 | margin-right: 0; 59 | } 60 | 61 | @include small-mq { 62 | margin: auto auto 58px; 63 | width: 50%; 64 | 65 | &:first-of-type { 66 | margin-left: auto; 67 | } 68 | &:last-of-type { 69 | margin-right: auto; 70 | } 71 | } 72 | 73 | span.square { 74 | display: block; 75 | position: relative; 76 | max-width: 120px; 77 | height: 120px; 78 | border-radius: 16px; 79 | box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.3); 80 | transition: box-shadow 0.3s ease, transform 0.1s ease; 81 | 82 | @each $class,$degrees, $color-a, $color-b in $square-map { 83 | &.#{$class} { 84 | background: linear-gradient(#{$degrees}deg, #{$color-a} 0, #{$color-b} 100%); 85 | } 86 | } 87 | 88 | &:hover { 89 | box-shadow: none; 90 | transform: scale(1.05); 91 | 92 | &~ .name { 93 | opacity: 1; 94 | } 95 | } 96 | } 97 | 98 | svg { 99 | position: absolute; 100 | top: 50%; 101 | left: 50%; 102 | transform: translate(-50%, -50%); 103 | } 104 | 105 | .name { 106 | font-family: 'Open Sans', Helvetica Neue, helvetica, sans-serif; 107 | opacity: 0.8; 108 | font-size: 16px; 109 | font-weight: 300; 110 | line-height: 52px; 111 | transition: opacity 0.3s ease; 112 | } 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /docs/source/stylesheets/components/_examples.scss: -------------------------------------------------------------------------------- 1 | .form-control { 2 | width: 100%; 3 | box-sizing: border-box; 4 | padding-left: 16px; 5 | line-height: 40px; 6 | height: 40px; 7 | border: 1px solid #cccccc; 8 | border-radius: 3px; 9 | outline: none; 10 | } 11 | 12 | .form-group { 13 | margin-bottom: 1em; 14 | clear: both; 15 | 16 | label { 17 | display: block; 18 | font-weight: bold; 19 | font-size: .8em; 20 | } 21 | } 22 | 23 | #map-example-container, 24 | #map-example-container-paris { 25 | // trigger zindex value otherwise 26 | // map goes hover other elements (like header) 27 | position: relative; 28 | z-index: 0; 29 | } 30 | -------------------------------------------------------------------------------- /docs/source/stylesheets/components/_fonts.scss: -------------------------------------------------------------------------------- 1 | p a { 2 | color: #21A4D7; 3 | text-decoration: none; 4 | } 5 | 6 | /* heading settings 7 | =======================*/ 8 | h1,h2,h3,h4 { 9 | padding: 0; 10 | margin: 0; 11 | } 12 | 13 | h1 { 14 | font-size: 46px; 15 | } 16 | 17 | h3 { 18 | font-size: 20px; 19 | } 20 | 21 | h3 { 22 | font-size: 18px; 23 | } 24 | 25 | /* Paragraphs 26 | ======================*/ 27 | p { 28 | font-family: 'Open Sans', Helvetica Neue, helvetica, sans-serif; 29 | font-size: 20px; 30 | line-height: 32px; 31 | color: $charcoal-grey-75; 32 | 33 | @include small-mq { 34 | font-size: 16px; 35 | } 36 | 37 | &+ul, 38 | &+ol { 39 | font-size: 20px; 40 | line-height: 32px; 41 | color: $charcoal-grey-75; 42 | } 43 | } 44 | 45 | /* Big titles 46 | ======================*/ 47 | h2.title { 48 | text-align: center; 49 | width: 100%; 50 | font-size: 1.8em; 51 | color: $charcoal-grey; 52 | display: block; 53 | position: relative; 54 | margin-top: 120px; 55 | margin-bottom: 80px; 56 | 57 | &:after { 58 | content: ''; 59 | position: absolute; 60 | width: 50px; 61 | height: 3px; 62 | background: $red-pink; 63 | top: 2.8em; 64 | left: 0; 65 | right: 0; 66 | margin: auto; 67 | } 68 | 69 | ~ p { 70 | color: $charcoal-grey; 71 | font-size: 1.3em; 72 | text-align: center; 73 | 74 | @include small-mq { 75 | font-size: 16px; 76 | } 77 | } 78 | 79 | @include small-mq { 80 | margin-top: 60px; 81 | font-size: 22px; 82 | } 83 | } 84 | 85 | /* Small titles 86 | ======================*/ 87 | h3.title { 88 | font-size: 1.5em; 89 | color: $greyish-brown; 90 | font-weight: bold; 91 | margin: 0; 92 | padding: 0; 93 | line-height: 1.2em; 94 | 95 | ~ p { 96 | margin: 32px 0; 97 | padding: 8px 0 0; 98 | } 99 | } 100 | h4 { 101 | font-size: 18px; 102 | } 103 | 104 | /* Anchors / links 105 | ====================*/ 106 | .link { 107 | text-transform: uppercase; 108 | font-size: 16px; 109 | color: $red-pink; 110 | font-weight: 600; 111 | text-decoration: none; 112 | padding: 0 8px; 113 | } 114 | -------------------------------------------------------------------------------- /docs/source/stylesheets/components/_icons.scss: -------------------------------------------------------------------------------- 1 | .icon { 2 | text-indent: -99999px; 3 | color: transparent; 4 | transition: background 0.2s ease; 5 | 6 | &-love { 7 | background: url($icon-heart)no-repeat center center / contain 8 | } 9 | 10 | &-love-dark { 11 | background: url($icon-heart-dark)no-repeat center center / contain 12 | } 13 | 14 | &-algolia { 15 | background: url($icon-algolia-dark)no-repeat center center / contain 16 | } 17 | 18 | &-algolia-light { 19 | background: url($icon-algolia-light)no-repeat center bottom / contain; 20 | } 21 | 22 | &-mail { 23 | background: url($icon-mail)no-repeat 8px 7px / 70% 24 | } 25 | 26 | &-algolia-small { 27 | background: url('../images/svg/algolia-mark-white.svg')no-repeat center center / contain 28 | } 29 | } 30 | 31 | // Small css shape 32 | .ico-triangle { 33 | width: 0; 34 | height: 0; 35 | border-top: 5px solid transparent; 36 | border-bottom: 5px solid transparent; 37 | border-left: 5px solid $steel; 38 | position: relative; 39 | display: inline-block; 40 | margin-left: 8px; 41 | } -------------------------------------------------------------------------------- /docs/source/stylesheets/components/_inputs.scss: -------------------------------------------------------------------------------- 1 | input { 2 | outline: none; 3 | border-radius: 4px; 4 | 5 | &::-webkit-search-decoration, 6 | &::-webkit-search-cancel-button, 7 | &::-webkit-search-results-button, 8 | &::-webkit-search-results-decoration { 9 | display: none !important; 10 | } 11 | 12 | &:not([type="radio"]):not([type="checkbox"]){ 13 | @include appearance(none !important); 14 | } 15 | } 16 | 17 | 18 | // Style the input for the Demo page 19 | .hero-section { 20 | 21 | .algolia-places { 22 | top: 50px; 23 | font-family: 'Open Sans', helvetica Neue; 24 | 25 | &:before { 26 | content:'Try it!'; 27 | position: absolute; 28 | top: -44px; 29 | left: 2px; 30 | width: 100px; 31 | height: 44px; 32 | text-align: right; 33 | font-style: italic; 34 | font-weight: 600; 35 | line-height: 44px; 36 | color: $powder-blue; 37 | background: { 38 | image: url($icon-arrow); 39 | repeat: no-repeat; 40 | position: bottom 12px left 24px; 41 | size: 24px; 42 | } 43 | } 44 | 45 | .hero-searchbar { 46 | border: solid 1px rgba(255, 255, 255, 0.5); 47 | box-shadow: 0 1px 10px rgba(0, 0, 0, 0.2), 0 2px 4px 0 rgba(0, 0, 0, 0.1); 48 | color: #8f94ad; 49 | font-family: "Raleway", Helvetica Neue, helvetica; 50 | height: 56px; 51 | padding-left: 16px; 52 | padding-right: 48px; 53 | border-radius: 4px; 54 | 55 | @include appearance(none) 56 | } 57 | 58 | .ap-suggestion { 59 | color: #262626; 60 | text-align: left; 61 | } 62 | 63 | .ap-footer { 64 | color: #797979; 65 | } 66 | } 67 | } 68 | 69 | #form-message-success{ 70 | font-size: 1.2em; 71 | background-color: #D6EAC7; 72 | padding: 30px; 73 | text-align: center; 74 | border-radius: 4px; 75 | &.hide{ 76 | display: none; 77 | } 78 | } 79 | 80 | #form-contact { 81 | width: 800px; 82 | margin: 0 auto; 83 | 84 | &.hide{ 85 | display: none; 86 | } 87 | 88 | .control-label{ 89 | font-size: 1em; 90 | margin-bottom: 4px; 91 | 92 | &.required::after{ 93 | display: inline-block; 94 | content: '*'; 95 | margin-left: 4px; 96 | color: #E7486B; 97 | vertical-align: baseline;; 98 | } 99 | } 100 | 101 | textarea{ 102 | height: 264px; 103 | resize: none; 104 | } 105 | 106 | .btn-cta { 107 | margin-top: 40px; 108 | width: 150px; 109 | } 110 | 111 | .row{ 112 | width: 100%; 113 | } 114 | 115 | > .col-6{ 116 | width: 50%; 117 | float: left; 118 | 119 | &:first-child{ 120 | padding-right: 40px; 121 | } 122 | } 123 | 124 | .form-group{ 125 | &:after { 126 | content: ''; 127 | display: table; 128 | clear: both; 129 | } 130 | .col-6{ 131 | width: 50%; 132 | float: left; 133 | 134 | &:first-child{ 135 | padding-right: 8px; 136 | } 137 | } 138 | } 139 | 140 | @media (max-width: $bp-medium) { 141 | width: 100%; 142 | } 143 | 144 | @media (max-width: $bp-small) { 145 | > .col-6 , 146 | > .col-6:first-child { 147 | width: 100%; 148 | padding: 0; 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /docs/source/stylesheets/components/_media.scss: -------------------------------------------------------------------------------- 1 | .media-object { 2 | display: block; 3 | width: 100%; 4 | height: 100%; 5 | float: left; 6 | padding: 0; 7 | margin: 0; 8 | 9 | img { 10 | object: { 11 | fit: cover; 12 | position: center center; 13 | } 14 | display: block; 15 | padding: 4px; 16 | line-height: 1.42857143; 17 | background-color: #fff; 18 | border: 1px solid #ddd; 19 | border-radius: 4px; 20 | width: 100%; 21 | max-width: 400px; 22 | 23 | 24 | &.gif { 25 | display: block; 26 | max-width: 100%; 27 | height: auto; 28 | padding: 4px; 29 | line-height: 1.42857143; 30 | background-color: #fff; 31 | border: 1px solid #ddd; 32 | border-radius: 4px; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /docs/source/stylesheets/components/_sidebar.scss: -------------------------------------------------------------------------------- 1 | nav.sidebar { 2 | float: left; 3 | width: 100%; 4 | height: 100%; 5 | position: absolute; 6 | max-width: $sidebar-width; 7 | border-right: 1px solid #d8d8d8; 8 | padding-top: 120px; 9 | 10 | &.fixed { 11 | position: fixed; 12 | top: $navigation-height + 16px; 13 | z-index: 9; 14 | padding-top: 0; 15 | } 16 | 17 | li:hover ul { 18 | display: block; 19 | } 20 | 21 | a.active ~ ul { 22 | display: block; 23 | } 24 | 25 | ul { 26 | display: none; 27 | list-style: none; 28 | width: 100%; 29 | padding: 0; 30 | margin: 0; 31 | float: left; 32 | 33 | li { 34 | width: 100%; 35 | display: block; 36 | height: 32px; 37 | line-height: 32px; 38 | 39 | a { 40 | text-decoration: none; 41 | display: block; 42 | width: 100%; 43 | height: 100%; 44 | color: $charcoal-grey-75; 45 | font-weight: 400; 46 | 47 | 48 | &:focus, 49 | &:target { 50 | @extend %active-links; 51 | } 52 | &.active { 53 | @extend %active-links; 54 | } 55 | } 56 | } 57 | } 58 | 59 | @include small-mq { 60 | width: calc(100% + 16px); 61 | max-width: calc(100% + 16px); 62 | position: absolute; 63 | max-height: 46px; 64 | left: 0; 65 | top: 16px; 66 | border: none; 67 | padding-top: 0; 68 | display: none; 69 | 70 | select { 71 | width: calc(100% - 32px); 72 | margin: 8px 8px; 73 | visibility: hidden; 74 | } 75 | 76 | &.fixed { 77 | background: $brand-primary; 78 | color: #fff; 79 | top: 50px; 80 | display: block; 81 | 82 | select { 83 | visibility: visible; 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /docs/source/stylesheets/components/docsearch/_docsearch.scss: -------------------------------------------------------------------------------- 1 | // SEARCHBOX 2 | $searchbox-config: ( 3 | input-width: 200px, 4 | input-height: 36px, 5 | border-width: 2px, 6 | border-radius: 18px, 7 | input-border-color: rgba(#fff,.5), 8 | input-focus-border-color: rgba(#fff,.8), 9 | input-background: #000, 10 | font-size: 12px, 11 | placeholder-color: #777, 12 | icon-size: 18px, 13 | icon-position: left, 14 | icon-color: #fff, 15 | icon-background-opacity: 0, 16 | icon-clear-size: 12px 17 | ) !default; 18 | 19 | // DROPDOWN 20 | $dropdown-config: ( 21 | main-color: #458EE1, 22 | layout-type: normal, 23 | layout-alignment: right, 24 | layout-width: 800, 25 | background-color: #fff, 26 | border-radius: 4, 27 | border-width: 1, 28 | border-color: #d9d9d9, 29 | box-shadow: light, 30 | branding-position: bottom, 31 | spacing: normal, 32 | include-desc: yes, 33 | background-category-header: #ffffff, 34 | font-size: normal, 35 | header-color: #33363D, 36 | title-color: #02060C, 37 | subtitle-color: #A4A7AE, 38 | text-color: #63676D, 39 | highlight-color: #3881FF 40 | ) !default; 41 | -------------------------------------------------------------------------------- /docs/source/stylesheets/site.css.scss: -------------------------------------------------------------------------------- 1 | @import 'vendors/normalize', 2 | 'vendors/variables', 3 | 'vendors/functions', 4 | 'vendors/mixins', 5 | 'vendors/base'; 6 | 7 | @import 'components/code-highlight', 8 | 'components/icons', 9 | 'components/containers', 10 | 'components/navigation', 11 | 'components/buttons', 12 | 'components/media', 13 | 'components/inputs', 14 | 'components/fonts', 15 | 'components/sidebar', 16 | 'components/documentation', 17 | 'components/examples-intro', 18 | 'components/examples', 19 | 'components/footer', 20 | 'components/visual-helper', 21 | 'components/clipboard'; 22 | 23 | @import 'vendors/helpers', 24 | 'vendors/animations'; 25 | 26 | @import 'components/docsearch/docsearch'; 27 | @import 'components/docsearch/dropdown'; 28 | @import 'components/docsearch/searchbox'; 29 | 30 | @include searchbox($searchbox-config...); 31 | @include dropdown($dropdown-config...); 32 | 33 | -------------------------------------------------------------------------------- /docs/source/stylesheets/vendors/_animations.scss: -------------------------------------------------------------------------------- 1 | // Hero Illustration 2 | $timingFunction: 3s ease infinite; 3 | 4 | @mixin anim($name, $p1, $p2, $p3) { 5 | @keyframes #{$name}{ 6 | 0%, 20%, 80%, 100% { 7 | transform: #{$p1}; 8 | } 9 | 10%, 40%, 50% { 10 | transform: #{$p2}; 11 | } 12 | 60% { 13 | transform: #{$p3}; 14 | } 15 | } 16 | } 17 | @mixin animEllipse($name, $p1, $p2, $p3) { 18 | @keyframes #{$name}{ 19 | 0%, 20%, 80%, 100% { 20 | transform: #{$p1}; 21 | } 22 | 10%, 40%, 50% { 23 | transform: #{$p2}; 24 | opacity: 0.6; 25 | } 26 | 60% { 27 | transform: #{$p3}; 28 | opacity: 0.6; 29 | } 30 | } 31 | } 32 | 33 | #pin { 34 | animation: bounce $timingFunction; 35 | } 36 | ellipse { 37 | transform-origin: center center; 38 | -moz-transform-origin: 50% 40%; 39 | animation: bounceShadow $timingFunction; 40 | -moz-animation: mozBounceShadow $timingFunction; 41 | 42 | } 43 | // Fix svg in FF 44 | #plan-holder { 45 | -moz-transform: translateY(10px); 46 | } 47 | #plan { 48 | -moz-transform: scale(1.1); 49 | } 50 | 51 | @include anim('bounce', 'translateY(0)', 'translateY(-5px)', 'translateY(-5px)'); 52 | @include animEllipse('bounceShadow', 'scale(1) translateY(12px)', 'scale(0.75) translateY(12px) ', 'scale(0.75) translateY(12px) '); 53 | @include animEllipse('mozBounceShadow', 'scale(1) translateY(16px)', 'scale(0.75) translateY(16px) translateX(-8px) ', 'scale(0.75) translateY(16px) translateX(-8px) '); 54 | 55 | // Footer heartbeat 56 | @keyframes pulse{ 57 | 0% { 58 | box-shadow: 0 0 0 0 rgba($red-pink, 0.4); 59 | } 60 | 70% { 61 | 62 | box-shadow: 0 0 0 30px rgba($red-pink, 0); 63 | } 64 | 100% { 65 | 66 | box-shadow: 0 0 0 0 rgba($red-pink, 0); 67 | } 68 | } 69 | 70 | @keyframes pulseHeart{ 71 | 0% { 72 | transform: scale(1.3) 73 | } 74 | 70% { 75 | 76 | transform: scale(1.15) 77 | } 78 | 100% { 79 | 80 | transform: scale(1) 81 | } 82 | } 83 | 84 | .icon-love-dark { 85 | display: block; 86 | position: relative; 87 | 88 | &:before { 89 | content: ''; 90 | display: block; 91 | width: 8px; 92 | height: 8px; 93 | position: absolute; 94 | top: 45%; 95 | bottom: 0; 96 | left: 50%; 97 | transform: translate(-50%,-50%); 98 | right: 0; 99 | z-index: -1; 100 | border-radius: 100%; 101 | } 102 | } 103 | 104 | .inner-bloc:hover .icon-love-dark{ 105 | animation: pulseHeart 1s ease infinite; 106 | 107 | &:before { 108 | animation: pulse 1s ease infinite !important; 109 | } 110 | } 111 | 112 | 113 | // part of animate.css 114 | @keyframes fadeInDown { 115 | 0% { 116 | opacity: 0; 117 | transform: translate3d(0, -100%, 0); 118 | } 119 | 120 | 100% { 121 | opacity: 1; 122 | transform: none; 123 | } 124 | } 125 | 126 | -------------------------------------------------------------------------------- /docs/source/stylesheets/vendors/_base.scss: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Raleway:400,500,600,700|Open+Sans:400,600,700); 2 | 3 | * { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 14px; 9 | font-family: "Raleway", Helvetica Neue, helvetica; 10 | } 11 | 12 | figure { 13 | figcaption { 14 | text-indent: -9999px; 15 | color: transparent; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /docs/source/stylesheets/vendors/_functions.scss: -------------------------------------------------------------------------------- 1 | $browser-context: 16; // Default 2 | 3 | @function em($pixels, $context: $browser-context) { 4 | @return #{$pixels/$context}em; 5 | } -------------------------------------------------------------------------------- /docs/source/stylesheets/vendors/_helpers.scss: -------------------------------------------------------------------------------- 1 | $sizes: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10; 2 | 3 | [class*="bloc-"] { 4 | float: left; 5 | } 6 | @each $size in $sizes { 7 | .bloc-#{$size} { 8 | $size: $size*10%; 9 | width: $size; 10 | } 11 | } 12 | 13 | .relative { 14 | position: relative; 15 | overflow: hidden; 16 | } 17 | 18 | .center-text { 19 | text-align: center; 20 | } 21 | 22 | .fl-left { 23 | float: left; 24 | } 25 | 26 | .fl-right { 27 | float: right; 28 | } 29 | 30 | hr { 31 | border: none; 32 | float: left; 33 | clear: both; 34 | width: 100%; 35 | height: 1px; 36 | background: #e5e5e5; 37 | margin: 0; 38 | 39 | &:before, 40 | &:after { 41 | content: ''; 42 | display: table; 43 | clear: both; 44 | } 45 | } 46 | 47 | .pipe { 48 | width: 2px; 49 | height: 20px; 50 | background: $red-pink; 51 | display: inline-block; 52 | float: left; 53 | margin: 20px 16px 0; 54 | line-height: $navigation-height; 55 | 56 | &+ span { 57 | font-weight: bold; 58 | width: 0; 59 | float: left; 60 | } 61 | 62 | body.index &{ 63 | display: none; 64 | 65 | &+ span { 66 | display: none !important; 67 | } 68 | } 69 | } 70 | 71 | // The following helper classes 72 | // made responsive desing easy 73 | // - no-desktop : Only display on mobile 74 | // - no-mobile : Only display on desktop 75 | // - display-on-small : only display on smallish screen ( no mobile ) 76 | 77 | .no-desktop { 78 | @include hide(); 79 | @include small-mq { 80 | @include hide(); 81 | } 82 | 83 | @include mobile-mq { 84 | @include unhide(block); 85 | } 86 | 87 | 88 | &.community-badge { 89 | @include mobile-mq { 90 | @include unhide(inline); 91 | } 92 | } 93 | 94 | @media screen and (orientation: landscape) { 95 | @include hide(); 96 | } 97 | } 98 | 99 | .no-mobile { 100 | @include unhide(block); 101 | 102 | &.nav-icon { 103 | @include unhide(inline); 104 | 105 | @include small-mq { 106 | @include hide(); 107 | } 108 | } 109 | 110 | @include small-mq { 111 | @include hide(); 112 | } 113 | } 114 | 115 | .display-on-small { 116 | @include hide(); 117 | 118 | @media (max-width: 960px){ 119 | display: inline-block !important; 120 | visibility: visible; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /docs/source/stylesheets/vendors/_mixins.scss: -------------------------------------------------------------------------------- 1 | // Mixins 2 | @mixin placeholder { 3 | $placeholders: ":-webkit-input" ":-moz" "-moz" "-ms-input"; 4 | @each $placeholder in $placeholders { 5 | &:#{$placeholder}-placeholder { 6 | @content; 7 | } 8 | } 9 | } 10 | @mixin better-fonts() { 11 | h1,h2,h3,h4,h5,h6,span,div,p,pre,code,a,strong,em,i { 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | } 16 | 17 | @mixin footer-text{ 18 | color: #496f92; 19 | text-transform: uppercase; 20 | font-weight: bold; 21 | font-size: 12px; 22 | margin: 0; 23 | font-family: 'Raleway', helvetica, sans-serif; 24 | font-weight: 800; 25 | float: none; 26 | } 27 | 28 | @mixin hide() { 29 | display: none !important; 30 | visibility: hidden; 31 | } 32 | 33 | @mixin unhide($type) { 34 | display: $type !important; 35 | visibility: visible; 36 | } 37 | @mixin appearance ($value) { 38 | -webkit-appearance: $value; 39 | -moz-appearance: $value; 40 | appearance: $value; 41 | } 42 | 43 | // Responsive Breakpoints 44 | @mixin big-min-mq { 45 | @media (min-width: $bp-big){ 46 | @content 47 | } 48 | } 49 | @mixin huge-min-mq { 50 | @media (min-width: $bp-huge){ 51 | @content 52 | } 53 | } 54 | 55 | @mixin big-mq { 56 | @media (max-width: $bp-big){ 57 | @content 58 | } 59 | } 60 | @mixin medium-mq { 61 | @media (max-width: $bp-medium){ 62 | @content 63 | } 64 | } 65 | @mixin small-mq { 66 | @media (max-width: $bp-medium){ 67 | @content 68 | } 69 | } 70 | @mixin mobile-mq { 71 | @media (max-width: $bp-small){ 72 | @content 73 | } 74 | } 75 | @mixin tablet-mq-portrait { 76 | @media only screen 77 | and (min-device-width : 768px) 78 | and (max-device-width : 1024px) 79 | and (orientation : portrait) { 80 | @content 81 | } 82 | } 83 | @mixin tablet-mq-landscape { 84 | @media only screen 85 | and (min-device-width : 768px) 86 | and (max-device-width : 1024px) 87 | and (orientation : landscape) { 88 | @content 89 | } 90 | } 91 | 92 | // Placeholders 93 | 94 | 95 | %fadeInDown { 96 | animation-name: fadeInDown; 97 | } 98 | 99 | %animated { 100 | -webkit-animation-duration: 0.3s; 101 | animation-duration: 0.3s; 102 | -webkit-animation-fill-mode: both; 103 | animation-fill-mode: both; 104 | } 105 | 106 | %active-links { 107 | color: $red-pink; 108 | box-shadow: inset -2px 0 0 0 $red-pink; 109 | 110 | @include small-mq { 111 | font-weight: bold; 112 | box-shadow: none; 113 | color: #fff; 114 | border-bottom: 2px solid $red-pink; 115 | 116 | } 117 | } -------------------------------------------------------------------------------- /docs/source/support.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | This page has been moved to https://www.algolia.com/ref/places 11 | -------------------------------------------------------------------------------- /header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/places/e417a59765b86972a812ec28ad11ccd53f909bbb/header.png -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // we need to export using commonjs for ease of usage in all 2 | // JavaScript environments 3 | // We therefore need to import in commonjs too. see: 4 | // https://github.com/webpack/webpack/issues/4039 5 | 6 | /* eslint-disable import/no-commonjs */ 7 | 8 | const places = require('./src/places'); 9 | const version = require('./src/version'); 10 | 11 | // must use module.exports to be commonJS compatible 12 | module.exports = places.default; 13 | module.exports.version = version.default; 14 | /* eslint-enable import/no-commonjs */ 15 | -------------------------------------------------------------------------------- /instantsearchWidget.js: -------------------------------------------------------------------------------- 1 | // we need to export using commonjs for ease of usage in all 2 | // JavaScript environments 3 | // We therefore need to import in commonjs too. see: 4 | // https://github.com/webpack/webpack/issues/4039 5 | 6 | /* eslint-disable import/no-commonjs */ 7 | 8 | const widget = require('./src/instantsearch/widget'); 9 | module.exports = widget.default; 10 | /* eslint-enable import/no-commonjs */ 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "places.js", 3 | "version": "1.19.0", 4 | "description": "🌐 Turn any into an address autocomplete.", 5 | "main": "index.js", 6 | "types": "typings.d.ts", 7 | "jsdelivr": "dist/cdn/places.min.js", 8 | "scripts": { 9 | "build": "NODE_ENV=production ./scripts/build.sh", 10 | "dev": "./scripts/dev.sh", 11 | "docs:js:build": "webpack --mode production --config webpack.config.docs.js", 12 | "docs:js:watch": "webpack --mode production --config webpack.config.docs.js --watch", 13 | "docs:build": "./scripts/build-website.sh", 14 | "docs:deploy": "./scripts/deploy-website.sh", 15 | "doctoc": "doctoc --maxlevel 3 CONTRIBUTING.md", 16 | "js:build": "webpack --mode development", 17 | "js:watch": "webpack --mode development --watch", 18 | "lint": "eslint .", 19 | "lint:fix": "eslint . --fix", 20 | "release": "./scripts/release.sh", 21 | "test:unit": "jest --bail --no-cache --testPathIgnorePatterns=e2e", 22 | "test:watch": "jest --watch", 23 | "test:ci": "./scripts/test-ci.sh", 24 | "test:e2e": "jest e2e.test.js", 25 | "test": "npm run --scripts-prepend-node-path=auto test:unit && npm run --scripts-prepend-node-path=auto lint && npm run --scripts-prepend-node-path=auto build && npm run --scripts-prepend-node-path=auto test:e2e" 26 | }, 27 | "author": "Algolia (https://www.algolia.com)", 28 | "homepage": "https://community.algolia.com/places", 29 | "bugs": "https://github.com/algolia/places/issues", 30 | "repository": "https://github.com/algolia/places", 31 | "license": "MIT", 32 | "devDependencies": { 33 | "@babel/cli": "7.16.0", 34 | "@babel/core": "7.16.0", 35 | "@babel/node": "7.16.0", 36 | "@babel/plugin-proposal-class-properties": "7.16.0", 37 | "@babel/plugin-proposal-decorators": "7.16.0", 38 | "@babel/plugin-proposal-export-namespace-from": "7.16.0", 39 | "@babel/plugin-proposal-function-sent": "7.16.0", 40 | "@babel/plugin-proposal-json-strings": "7.16.0", 41 | "@babel/plugin-proposal-numeric-separator": "7.16.0", 42 | "@babel/plugin-proposal-throw-expressions": "7.16.0", 43 | "@babel/plugin-syntax-dynamic-import": "7.8.3", 44 | "@babel/plugin-syntax-import-meta": "7.10.4", 45 | "@babel/polyfill": "7.12.1", 46 | "@babel/preset-env": "7.16.0", 47 | "algolia-aerial": "1.5.3", 48 | "algoliasearch-helper": "2.28.1", 49 | "babel-core": "7.0.0-bridge.0", 50 | "babel-eslint": "10.1.0", 51 | "babel-jest": "26.6.3", 52 | "babel-loader": "8.2.3", 53 | "babel-plugin-inline-import": "3.0.0", 54 | "clipboard": "2.0.11", 55 | "conventional-changelog-cli": "2.1.1", 56 | "docsearch.js": "2.6.3", 57 | "doctoc": "1.4.0", 58 | "eslint": "7.32.0", 59 | "eslint-config-algolia": "16.0.0", 60 | "eslint-config-prettier": "6.15.0", 61 | "eslint-import-resolver-webpack": "0.13.2", 62 | "eslint-plugin-eslint-comments": "3.2.0", 63 | "eslint-plugin-import": "2.25.2", 64 | "eslint-plugin-jest": "24.7.0", 65 | "eslint-plugin-prettier": "3.4.1", 66 | "eslint-plugin-react": "7.26.1", 67 | "jest-cli": "26.6.3", 68 | "json": "10.0.0", 69 | "prettier": "2.4.1", 70 | "pretty-bytes-cli": "2.0.0", 71 | "puppeteer": "5.5.0", 72 | "raw-loader": "4.0.2", 73 | "replace-in-file": "6.3.5", 74 | "semver": "7.3.7", 75 | "uglify-js": "3.14.3", 76 | "webpack": "4.46.0", 77 | "webpack-cli": "3.3.12" 78 | }, 79 | "dependencies": { 80 | "algoliasearch": "^3.35.1", 81 | "autocomplete.js": "^0.38.0", 82 | "events": "^3.0.0", 83 | "insert-css": "^2.0.0", 84 | "pending-xhr-puppeteer": "1.0.17" 85 | }, 86 | "jest": { 87 | "testRegex": "\\.test\\.js$", 88 | "coverageDirectory": ".coverage/", 89 | "moduleNameMapper": { 90 | "^.+\\.(svg)$": "/test/fileMock.js" 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:js-lib", 4 | "algolia" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /scripts/build-website.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e # exit when error 4 | 5 | printf "\nBuilding website\n" 6 | 7 | VERSION=`json version < package.json` 8 | 9 | mkdir -p docs/source/partials/status/ 10 | 11 | # ensure DATA_REFRESH.md exists 12 | touch DATA_REFRESH.md 13 | cp DATA_REFRESH.md docs/source/partials/status/DATA_REFRESH.md.erb 14 | 15 | # ensure CHANGELOG.md exists 16 | touch CHANGELOG.md 17 | # cuts after the first 5 minor releases 18 | # changes the

into

and

into

19 | # so that the produced markdown is well formatted for display 20 | # and remove line starting with a link (not useful for display) 21 | cat CHANGELOG.md | \ 22 | awk 'BEGIN { counter=0 } /^# / {counter++} NR > 1 { print prev } { prev = $0 } counter==5 {exit}' | \ 23 | sed -E 's/^### /##### /' | \ 24 | sed -E 's/^# /### /' | \ 25 | sed -E 's/^ docs/source/partials/status/CHANGELOG.md.erb 27 | 28 | # ensure PIPELINE_CHANGELOG.md exists 29 | touch PIPELINE_CHANGELOG.md 30 | # cuts after the first 5 minor releases 31 | # changes the

into

32 | # so that the produced markdown is well formatted for display 33 | # and remove line starting with a link (not useful for display) 34 | cat PIPELINE_CHANGELOG.md | \ 35 | awk 'BEGIN { counter=0 } /^### / {counter++} NR > 1 { print prev } { prev = $0 } counter==5 {exit}' | \ 36 | sed -E 's/^#### /##### /' | \ 37 | sed -E 's/^ docs/source/partials/status/PIPELINE_CHANGELOG.md.erb 39 | 40 | cd docs 41 | VERSION=${VERSION} NODE_ENV=production bundle exec middleman build 42 | cd .. 43 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e # exit when error, no verbose 4 | 5 | printf "\nBuilding places.js library\n" 6 | 7 | bundles=( 'places' 'placesAutocompleteDataset' 'placesInstantsearchWidget' ) 8 | license="/*! ${NAME} ${VERSION:-UNRELEASED} | © Algolia | github.com/algolia/places */" 9 | dist_dir="dist" 10 | dist_dir_cdn="dist/cdn" 11 | 12 | # clean 13 | mkdir -p "$dist_dir_cdn" 14 | rm -rf "${dist_dir:?}"/* 15 | 16 | # CDN build 17 | webpack --mode production 18 | 19 | for bundle in "${bundles[@]}" 20 | do 21 | dist_file="$dist_dir_cdn/${bundle}.js" 22 | dist_file_min="$dist_dir_cdn/${bundle}.min.js" 23 | source_map="${bundle}.js.map" 24 | source_map_min="${bundle}.min.js.map" 25 | dist_file_sourcemap="$dist_dir_cdn/${source_map}" 26 | dist_file_sourcemap_min="$dist_dir_cdn/${source_map_min}" 27 | 28 | echo "$license" | cat - "${dist_file}" > /tmp/out && mv /tmp/out "${dist_file}" 29 | 30 | uglifyjs "${dist_file}" \ 31 | --source-map "content=${dist_file_sourcemap}" \ 32 | --source-map "base=${dist_file_sourcemap_min}" \ 33 | --source-map "url=${source_map_min}" \ 34 | -b beautify=false,preamble="\"$license\"" \ 35 | -c \ 36 | -m \ 37 | -o "${dist_file_min}" 38 | 39 | gzip_size=$(gzip -9 < "$dist_file_min" | wc -c | pretty-bytes) 40 | echo "=> $dist_file_min gzipped will weight $gzip_size" 41 | done 42 | 43 | # NPM build 44 | # We are gonna resolve webpack loaders and transpile every file into ES5 45 | # The goal is for the user to be able to require/import places without 46 | # having to import a complete build (dist/cdn), to avoid duplication of dependencies 47 | BABEL_DISABLE_CACHE=1 BABEL_ENV=npm babel index.js -o "$dist_dir/index.js" 48 | BABEL_DISABLE_CACHE=1 BABEL_ENV=npm babel babel-css.js -o "$dist_dir/babel-css.js" 49 | BABEL_DISABLE_CACHE=1 BABEL_ENV=npm babel autocompleteDataset.js -o "$dist_dir/autocompleteDataset.js" 50 | BABEL_DISABLE_CACHE=1 BABEL_ENV=npm babel instantsearchWidget.js -o "$dist_dir/instantsearchWidget.js" 51 | BABEL_DISABLE_CACHE=1 BABEL_ENV=npm babel src/ --out-dir "$dist_dir/src/" --ignore "src/**/*.test.js","src/**/__mocks__/*","src/**/__snapshots__/*" 52 | -------------------------------------------------------------------------------- /scripts/bump-package-version.js: -------------------------------------------------------------------------------- 1 | /* eslint no-console:0 max-len:0 */ 2 | import fs from 'fs'; 3 | import path from 'path'; 4 | 5 | import replace from 'replace-in-file'; 6 | import semver from 'semver'; 7 | import currentVersion from '../src/version'; 8 | 9 | if (!process.env.VERSION) { 10 | throw new Error( 11 | 'bump: Usage is VERSION=MAJOR.MINOR.PATCH scripts/bump-package-version.js' 12 | ); 13 | } 14 | const newVersion = process.env.VERSION; 15 | 16 | if (!semver.valid(newVersion)) { 17 | throw new Error( 18 | `bump: Provided new version ${newVersion} is not a valid version per semver` 19 | ); 20 | } 21 | 22 | if (semver.gte(currentVersion, newVersion)) { 23 | throw new Error( 24 | `bump: Provided new version is not higher than current version (${newVersion} <= ${currentVersion})` 25 | ); 26 | } 27 | 28 | console.log(`Bumping ${newVersion}`); 29 | 30 | console.log('..Updating src/version.js'); 31 | 32 | const versionFile = path.join(__dirname, '../src/version.js'); 33 | const newContent = `export default '${newVersion}';\n`; 34 | fs.writeFileSync(versionFile, newContent); 35 | 36 | console.log('..Updating package.json'); 37 | 38 | replace.sync({ 39 | files: [path.join(__dirname, '..', 'package.json')], 40 | from: `"version": "${currentVersion}"`, 41 | to: `"version": "${newVersion}"`, 42 | }); 43 | 44 | replace.sync({ 45 | files: [path.join(__dirname, '..', 'README.md')], 46 | from: `places.js@${currentVersion}`, 47 | to: `places.js@${newVersion}`, 48 | }); 49 | -------------------------------------------------------------------------------- /scripts/clear-cdn-cache.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e # exit when error 4 | 5 | printf "\nClear CDN cache\n" 6 | 7 | VERSION=`json version < package.json` 8 | CDN_URL="https://cdn.jsdelivr.net/npm/places.js@$VERSION" 9 | 10 | while true; do 11 | STATUS=$(curl -L -I $CDN_URL 2>/dev/null | head -n 1 | cut -d$' ' -f2); 12 | if [ $STATUS == '200' ]; then 13 | printf "%s is now available on CDN\n" "$VERSION" 14 | break; 15 | else 16 | printf "%s is not yet published on CDN, retrying in 30s (status was $STATUS)\n" "$VERSION" 17 | fi 18 | sleep 30 19 | done 20 | 21 | # No more needed to clear the CDN cache because we advise to use specific versions 22 | # curl --silent -L $CACHE_URL > /dev/null 23 | -------------------------------------------------------------------------------- /scripts/deploy-website.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | set -e # exit when error 4 | 5 | printf "\nDeploying website website to gh-pages\n" 6 | 7 | : ${GH_TOKEN?"You need a GH_TOKEN environment variable to deploy"} 8 | 9 | VERSION=`json version < package.json` 10 | 11 | cd docs 12 | VERSION=${VERSION} NODE_ENV=production bundle exec middleman deploy &>/dev/null # hide output, we do not want github tokens to leak in stdout 13 | if [ $? -eq 0 ] 14 | then 15 | echo "\nWebsite was updated\n" 16 | else 17 | echo "\nCould not update the website\n" 18 | exit 1 19 | fi 20 | -------------------------------------------------------------------------------- /scripts/dev.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e # exit when error 4 | 5 | printf "\nLaunching dev environment\n" 6 | 7 | yarn 8 | 9 | VERSION=$(json version < package.json)"-DEV" 10 | 11 | mkdir -p docs/source/partials/status/ 12 | 13 | # ensure DATA_REFRESH.md exists 14 | touch DATA_REFRESH.md 15 | cp DATA_REFRESH.md docs/source/partials/status/DATA_REFRESH.md.erb 16 | 17 | # ensure CHANGELOG.md exists 18 | touch CHANGELOG.md 19 | # cuts after the first 5 minor releases 20 | # changes the

into

and

into

21 | # so that the produced markdown is well formatted for display 22 | # and remove line starting with a link (not useful for display) 23 | cat CHANGELOG.md | \ 24 | awk 'BEGIN { counter=0 } /^# / {counter++} NR > 1 { print prev } { prev = $0 } counter==5 {exit}' | \ 25 | sed -E 's/^### /##### /' | \ 26 | sed -E 's/^# /### /' | \ 27 | sed -E 's/^ docs/source/partials/status/CHANGELOG.md.erb 29 | 30 | # ensure PIPELINE_CHANGELOG.md exists 31 | touch PIPELINE_CHANGELOG.md 32 | # cuts after the first 5 minor releases 33 | # changes the

into

34 | # so that the produced markdown is well formatted for display 35 | # and remove line starting with a link (not useful for display) 36 | cat PIPELINE_CHANGELOG.md | \ 37 | awk 'BEGIN { counter=0 } /^### / {counter++} NR > 1 { print prev } { prev = $0 } counter==5 {exit}' | \ 38 | sed -E 's/^#### /##### /' | \ 39 | sed -E 's/^ docs/source/partials/status/PIPELINE_CHANGELOG.md.erb 41 | 42 | cd docs && 43 | bundle install && 44 | NODE_ENV=development VERSION=$VERSION bundle exec middleman 45 | -------------------------------------------------------------------------------- /scripts/finish-release.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | set -e # exit when error 4 | 5 | printf "\nFinishing release\n" 6 | 7 | ./scripts/clear-cdn-cache.sh 8 | ./scripts/deploy-website.sh 9 | -------------------------------------------------------------------------------- /scripts/release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e # exit when error 4 | 5 | printf "\nReleasing\n" 6 | 7 | if [ "$(node -v)" != "v$(cat .nvmrc)" ] 8 | then 9 | printf "Release: Node version mismatch with .nvmrc (should be $(cat .nvmrc))\n" 10 | exit 1 11 | fi 12 | 13 | if ! npm owner ls | grep -q "$(npm whoami)" 14 | then 15 | printf "Release: Not an owner of the npm repo, ask a contributor for access\n" 16 | exit 1 17 | fi 18 | 19 | currentBranch=`git rev-parse --abbrev-ref HEAD` 20 | if [ $currentBranch != 'master' ]; then 21 | printf "Release: You must be on master\n" 22 | exit 1 23 | fi 24 | 25 | if [[ -n $(git status --porcelain) ]]; then 26 | printf "Release: Working tree is not clean (git status)\n" 27 | exit 1 28 | fi 29 | 30 | printf "\n\nRelease: update working tree" 31 | git pull origin master 32 | git fetch origin --tags 33 | 34 | printf "Release: install dependencies" 35 | yarn 36 | 37 | currentVersion=`cat package.json | json version` 38 | 39 | # header 40 | printf "\n\nRelease: current version is %s" $currentVersion 41 | printf "\nRelease: a changelog will be generated only if a fix/feat/performance/breaking token is found in git log" 42 | printf "\nRelease: you must choose a new ve.rs.ion (semver)" 43 | printf "\nRelease: press q to exit the next screen\n\n" 44 | 45 | # preview changelog 46 | read -p "=> Release: press [ENTER] to view changes since latest version.." 47 | 48 | conventional-changelog --preset angular --output-unreleased | less 49 | 50 | # choose and bump new version 51 | # printf "\n\nRelease: Please enter the new chosen version > " 52 | printf "\n=> Release: please type the new chosen version > " 53 | read -e newVersion 54 | VERSION=$newVersion babel-node ./scripts/bump-package-version.js 55 | 56 | # build new version 57 | NODE_ENV=production VERSION=$newVersion npm run build 58 | 59 | # update changelog 60 | printf "\n\nRelease: update changelog" 61 | conventional-changelog --preset angular --infile CHANGELOG.md --same-file 62 | 63 | # regenerate readme TOC 64 | printf "\n\nRelease: generate TOCS" 65 | npm run doctoc 66 | 67 | # git add and tag 68 | commitMessage="release v$newVersion 69 | 70 | See https://github.com/algolia/places/blob/master/CHANGELOG.md" 71 | 72 | printf "Release: update lock file" 73 | yarn 74 | 75 | git add src/version.js package.json CHANGELOG.md README.md CONTRIBUTING.md yarn.lock 76 | printf %s "$commitMessage" | git commit --file - 77 | git tag "v$newVersion" 78 | 79 | printf "\n\nRelease: almost done, check everything in another terminal tab.\n" 80 | read -p "=> Release: when ready, press [ENTER] to push to github and publish the package" 81 | 82 | printf "\n\nRelease: push to github, publish on npm\n" 83 | git push origin master 84 | git push origin --tags 85 | 86 | # We are gonna publish the package to npm, in a way 87 | # where only the dist cdn and npm are available 88 | cp package.json README.md LICENSE typings.d.ts dist/ 89 | # jsDelivr original structure for places.js 90 | # cannot be changed easily: https://github.com/jsdelivr/jsdelivr/issues/12282 91 | mkdir dist/dist 92 | mv dist/cdn dist/dist 93 | cd dist 94 | npm publish 95 | mv dist/cdn cdn 96 | rm -rf dist 97 | rm -f package.json README.md LICENSE 98 | cd .. 99 | 100 | printf " 101 | Release: 102 | Package was published to npm. 103 | A job on travis-ci will be automatically launched to finalize the release. 104 | " 105 | -------------------------------------------------------------------------------- /scripts/test-ci.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e # exit when error 4 | 5 | printf "\nTesting\n" 6 | 7 | # try to build the library 8 | NODE_ENV=production npm run build 9 | 10 | # run tests 11 | npm run test:unit 12 | npm run lint 13 | 14 | # try to build the libray 15 | npm run build 16 | 17 | # run end-to-end tests against the libraries that were built 18 | npm run test:e2e 19 | 20 | # try to build the website 21 | ./scripts/build-website.sh 22 | 23 | # Finish release (clear CDN cache, deploy website) when building on master 24 | if [ "$TRAVIS_PULL_REQUEST" == 'false' ] && [ "$TRAVIS_BRANCH" == 'master' ]; then 25 | ./scripts/finish-release.sh 26 | fi 27 | -------------------------------------------------------------------------------- /src/configure/index.js: -------------------------------------------------------------------------------- 1 | const extractParams = ({ 2 | hitsPerPage, 3 | postcodeSearch, 4 | aroundLatLng, 5 | aroundRadius, 6 | aroundLatLngViaIP, 7 | insideBoundingBox, 8 | insidePolygon, 9 | getRankingInfo, 10 | countries, 11 | language, 12 | type, 13 | }) => { 14 | const extracted = { 15 | countries, 16 | hitsPerPage: hitsPerPage || 5, 17 | language: language || navigator.language.split('-')[0], 18 | type, 19 | }; 20 | 21 | if (Array.isArray(countries)) { 22 | extracted.countries = extracted.countries.map((country) => 23 | country.toLowerCase() 24 | ); 25 | } 26 | 27 | if (typeof extracted.language === 'string') { 28 | extracted.language = extracted.language.toLowerCase(); 29 | } 30 | 31 | if (aroundLatLng) { 32 | extracted.aroundLatLng = aroundLatLng; 33 | } else if (aroundLatLngViaIP !== undefined) { 34 | extracted.aroundLatLngViaIP = aroundLatLngViaIP; 35 | } 36 | 37 | if (postcodeSearch) { 38 | extracted.restrictSearchableAttributes = 'postcode'; 39 | } 40 | 41 | return { 42 | ...extracted, 43 | aroundRadius, 44 | insideBoundingBox, 45 | insidePolygon, 46 | getRankingInfo, 47 | }; 48 | }; 49 | 50 | const extractControls = ({ 51 | useDeviceLocation = false, 52 | computeQueryParams = (params) => params, 53 | formatInputValue, 54 | onHits = () => {}, 55 | onError = (e) => { 56 | throw e; 57 | }, 58 | onRateLimitReached, 59 | onInvalidCredentials, 60 | }) => ({ 61 | useDeviceLocation, 62 | computeQueryParams, 63 | formatInputValue, 64 | onHits, 65 | onError, 66 | onRateLimitReached, 67 | onInvalidCredentials, 68 | }); 69 | 70 | let params = {}; 71 | let controls = {}; 72 | 73 | const configure = (configuration) => { 74 | params = extractParams({ ...params, ...configuration }); 75 | controls = extractControls({ ...controls, ...configuration }); 76 | 77 | return { params, controls }; 78 | }; 79 | 80 | export default configure; 81 | -------------------------------------------------------------------------------- /src/createAutocompleteDataset.js: -------------------------------------------------------------------------------- 1 | import createAutocompleteSource from './createAutocompleteSource'; 2 | import defaultTemplates from './defaultTemplates'; 3 | 4 | export default function createAutocompleteDataset(options) { 5 | const templates = { 6 | ...defaultTemplates, 7 | ...options.templates, 8 | }; 9 | 10 | const source = createAutocompleteSource({ 11 | ...options, 12 | formatInputValue: templates.value, 13 | templates: undefined, 14 | }); 15 | 16 | return { 17 | source, 18 | templates, 19 | displayKey: 'value', 20 | name: 'places', 21 | cache: false, 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /src/createAutocompleteDataset.test.js: -------------------------------------------------------------------------------- 1 | import createAutocompleteDataset from './createAutocompleteDataset'; 2 | import createAutocompleteSource from './createAutocompleteSource'; 3 | 4 | jest.mock('./defaultTemplates.js', () => ({ template: 'test', value: 'test' })); 5 | jest.mock('./createAutocompleteSource.js', () => jest.fn(() => 'source')); 6 | 7 | describe('createAutocompleteDataset', () => { 8 | let dataset; 9 | 10 | beforeEach(() => createAutocompleteSource.mockClear()); 11 | beforeEach(() => { 12 | dataset = createAutocompleteDataset({ 13 | templates: { option: 'test' }, 14 | option: 'test', 15 | }); 16 | }); 17 | 18 | it('returns an autocomplete.js dataset', () => { 19 | expect(dataset).toEqual({ 20 | source: 'source', 21 | templates: { template: 'test', value: 'test', option: 'test' }, 22 | displayKey: 'value', 23 | name: 'places', 24 | cache: false, 25 | }); 26 | }); 27 | 28 | it('calls createAutocompleteSource', () => { 29 | expect(createAutocompleteSource.mock.calls[0][0]).toEqual({ 30 | formatInputValue: 'test', 31 | option: 'test', 32 | }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /src/createAutocompleteSource.js: -------------------------------------------------------------------------------- 1 | import configure from './configure'; 2 | import formatHit from './formatHit'; 3 | import version from './version'; 4 | 5 | export default function createAutocompleteSource({ 6 | algoliasearch, 7 | clientOptions, 8 | apiKey, 9 | appId, 10 | hitsPerPage, 11 | postcodeSearch, 12 | aroundLatLng, 13 | aroundRadius, 14 | aroundLatLngViaIP, 15 | insideBoundingBox, 16 | insidePolygon, 17 | getRankingInfo, 18 | countries, 19 | formatInputValue, 20 | computeQueryParams = (params) => params, 21 | useDeviceLocation = false, 22 | language = navigator.language.split('-')[0], 23 | onHits = () => {}, 24 | onError = (e) => { 25 | throw e; 26 | }, 27 | onRateLimitReached, 28 | onInvalidCredentials, 29 | type, 30 | }) { 31 | const placesClient = algoliasearch.initPlaces(appId, apiKey, clientOptions); 32 | placesClient.as.addAlgoliaAgent(`Algolia Places ${version}`); 33 | 34 | const configuration = configure({ 35 | hitsPerPage, 36 | type, 37 | postcodeSearch, 38 | countries, 39 | language, 40 | aroundLatLng, 41 | aroundRadius, 42 | aroundLatLngViaIP, 43 | insideBoundingBox, 44 | insidePolygon, 45 | getRankingInfo, 46 | formatInputValue, 47 | computeQueryParams, 48 | useDeviceLocation, 49 | onHits, 50 | onError, 51 | onRateLimitReached, 52 | onInvalidCredentials, 53 | }); 54 | 55 | let params = configuration.params; 56 | let controls = configuration.controls; 57 | 58 | let userCoords; 59 | let tracker = null; 60 | 61 | if (controls.useDeviceLocation) { 62 | tracker = navigator.geolocation.watchPosition(({ coords }) => { 63 | userCoords = `${coords.latitude},${coords.longitude}`; 64 | }); 65 | } 66 | 67 | function searcher(query, cb) { 68 | const searchParams = { 69 | ...params, 70 | query, 71 | }; 72 | 73 | if (userCoords) { 74 | searchParams.aroundLatLng = userCoords; 75 | } 76 | 77 | return placesClient 78 | .search(controls.computeQueryParams(searchParams)) 79 | .then((content) => { 80 | const hits = content.hits.map((hit, hitIndex) => 81 | formatHit({ 82 | formatInputValue: controls.formatInputValue, 83 | hit, 84 | hitIndex, 85 | query, 86 | rawAnswer: content, 87 | }) 88 | ); 89 | 90 | controls.onHits({ 91 | hits, 92 | query, 93 | rawAnswer: content, 94 | }); 95 | 96 | return hits; 97 | }) 98 | .then(cb) 99 | .catch((e) => { 100 | if ( 101 | e.statusCode === 403 && 102 | e.message === 'Invalid Application-ID or API key' 103 | ) { 104 | controls.onInvalidCredentials(); 105 | return; 106 | } else if (e.statusCode === 429) { 107 | controls.onRateLimitReached(); 108 | return; 109 | } 110 | 111 | controls.onError(e); 112 | }); 113 | } 114 | 115 | searcher.configure = (partial) => { 116 | const updated = configure({ ...params, ...controls, ...partial }); 117 | 118 | params = updated.params; 119 | controls = updated.controls; 120 | 121 | if (controls.useDeviceLocation && tracker === null) { 122 | tracker = navigator.geolocation.watchPosition(({ coords }) => { 123 | userCoords = `${coords.latitude},${coords.longitude}`; 124 | }); 125 | } else if (!controls.useDeviceLocation && tracker !== null) { 126 | navigator.geolocation.clearWatch(tracker); 127 | tracker = null; 128 | userCoords = null; 129 | } 130 | }; 131 | return searcher; 132 | } 133 | -------------------------------------------------------------------------------- /src/createReverseGeocodingSource.js: -------------------------------------------------------------------------------- 1 | import configure from './configure'; 2 | import formatHit from './formatHit'; 3 | import version from './version'; 4 | import defaultTemplates from './defaultTemplates'; 5 | 6 | const filterApplicableParams = (params) => { 7 | const { hitsPerPage, aroundLatLng, getRankingInfo, language } = params; 8 | 9 | const filtered = {}; 10 | 11 | if (typeof hitsPerPage === 'number') { 12 | filtered.hitsPerPage = hitsPerPage; 13 | } 14 | 15 | if (typeof language === 'string') { 16 | filtered.language = language; 17 | } 18 | 19 | if (typeof getRankingInfo === 'boolean') { 20 | filtered.getRankingInfo = getRankingInfo; 21 | } 22 | if (typeof aroundLatLng === 'string') { 23 | filtered.aroundLatLng = aroundLatLng; 24 | } 25 | 26 | return filtered; 27 | }; 28 | 29 | const createReverseGeocodingSource = ({ 30 | algoliasearch, 31 | clientOptions, 32 | apiKey, 33 | appId, 34 | hitsPerPage, 35 | aroundLatLng, 36 | getRankingInfo, 37 | formatInputValue = defaultTemplates.value, 38 | language = navigator.language.split('-')[0], 39 | onHits = () => {}, 40 | onError = (e) => { 41 | throw e; 42 | }, 43 | onRateLimitReached, 44 | onInvalidCredentials, 45 | }) => { 46 | const placesClient = algoliasearch.initPlaces(appId, apiKey, clientOptions); 47 | placesClient.as.addAlgoliaAgent(`Algolia Places ${version}`); 48 | 49 | const configuration = configure({ 50 | apiKey, 51 | appId, 52 | hitsPerPage, 53 | aroundLatLng, 54 | getRankingInfo, 55 | language, 56 | formatInputValue, 57 | onHits, 58 | onError, 59 | onRateLimitReached, 60 | onInvalidCredentials, 61 | }); 62 | 63 | let params = filterApplicableParams(configuration.params); 64 | let controls = configuration.controls; 65 | 66 | const searcher = (queryAroundLatLng, cb) => { 67 | const finalAroundLatLng = queryAroundLatLng || params.aroundLatLng; 68 | 69 | if (!finalAroundLatLng) { 70 | const error = new Error( 71 | 'A location must be provided for reverse geocoding' 72 | ); 73 | return Promise.reject(error); 74 | } 75 | 76 | return placesClient 77 | .reverse({ ...params, aroundLatLng: finalAroundLatLng }) 78 | .then((content) => { 79 | const hits = content.hits.map((hit, hitIndex) => 80 | formatHit({ 81 | formatInputValue: controls.formatInputValue, 82 | hit, 83 | hitIndex, 84 | query: finalAroundLatLng, 85 | rawAnswer: content, 86 | }) 87 | ); 88 | 89 | controls.onHits({ 90 | hits, 91 | query: finalAroundLatLng, 92 | rawAnswer: content, 93 | }); 94 | 95 | return hits; 96 | }) 97 | .then(cb) 98 | .catch((e) => { 99 | if ( 100 | e.statusCode === 403 && 101 | e.message === 'Invalid Application-ID or API key' 102 | ) { 103 | controls.onInvalidCredentials(); 104 | return; 105 | } else if (e.statusCode === 429) { 106 | controls.onRateLimitReached(); 107 | return; 108 | } 109 | 110 | controls.onError(e); 111 | }); 112 | }; 113 | 114 | searcher.configure = (partial) => { 115 | const updated = configure({ ...params, ...controls, ...partial }); 116 | 117 | params = filterApplicableParams(updated.params); 118 | controls = updated.controls; 119 | 120 | return searcher; 121 | }; 122 | 123 | return searcher; 124 | }; 125 | 126 | export default createReverseGeocodingSource; 127 | -------------------------------------------------------------------------------- /src/defaultTemplates.js: -------------------------------------------------------------------------------- 1 | import value from './formatInputValue'; 2 | import suggestion from './formatDropdownValue'; 3 | import algoliaLogo from './icons/algolia.svg'; 4 | import osmLogo from './icons/osm.svg'; 5 | 6 | export default { 7 | footer: ``, 11 | value, 12 | suggestion, 13 | }; 14 | -------------------------------------------------------------------------------- /src/errors.js: -------------------------------------------------------------------------------- 1 | export default { 2 | multiContainers: `Algolia Places: 'container' must point to a single element. 3 | Example: instantiate the library twice if you want to bind two . 4 | 5 | See https://community.algolia.com/places/documentation.html#api-options-container`, 6 | badContainer: `Algolia Places: 'container' must point to an element. 7 | 8 | See https://community.algolia.com/places/documentation.html#api-options-container`, 9 | rateLimitReached: `Algolia Places: Current rate limit reached. 10 | 11 | Sign up for a free 100,000 queries/month account at 12 | https://www.algolia.com/users/sign_up/places. 13 | 14 | Or upgrade your 100,000 queries/month plan by contacting us at 15 | https://community.algolia.com/places/contact.html.`, 16 | invalidCredentials: `The APP ID or API key provided is invalid.`, 17 | invalidAppId: `Your APP ID is invalid. A Places APP ID starts with 'pl'. You must create a valid Places app first. 18 | 19 | Create a free Places app here: https://www.algolia.com/users/sign_up/places`, 20 | }; 21 | -------------------------------------------------------------------------------- /src/findCountryCode.js: -------------------------------------------------------------------------------- 1 | export default function findCountryCode(tags) { 2 | for (let tagIndex = 0; tagIndex < tags.length; tagIndex++) { 3 | const tag = tags[tagIndex]; 4 | const find = tag.match(/country\/(.*)?/); 5 | if (find) { 6 | return find[1]; 7 | } 8 | } 9 | 10 | return undefined; 11 | } 12 | -------------------------------------------------------------------------------- /src/findCountryCode.test.js: -------------------------------------------------------------------------------- 1 | import findCountryCode from './findCountryCode'; 2 | 3 | describe('findCountryCode', () => { 4 | const testCases = [ 5 | { 6 | name: 'empty array', 7 | input: [], 8 | expected: undefined, 9 | }, 10 | { 11 | name: 'match', 12 | input: ['country/us', 'country/fr'], 13 | expected: 'us', 14 | }, 15 | ]; 16 | 17 | testCases.forEach((testCase) => 18 | it(`${testCase.name} test case`, () => 19 | expect(findCountryCode(testCase.input)).toEqual(testCase.expected)) 20 | ); 21 | }); 22 | -------------------------------------------------------------------------------- /src/findType.js: -------------------------------------------------------------------------------- 1 | export default function findType(tags) { 2 | const types = { 3 | country: 'country', 4 | city: 'city', 5 | 'amenity/bus_station': 'busStop', 6 | 'amenity/townhall': 'townhall', 7 | 'railway/station': 'trainStation', 8 | 'aeroway/aerodrome': 'airport', 9 | 'aeroway/terminal': 'airport', 10 | 'aeroway/gate': 'airport', 11 | }; 12 | 13 | for (const t in types) { 14 | if (tags.indexOf(t) !== -1) { 15 | return types[t]; 16 | } 17 | } 18 | 19 | return 'address'; 20 | } 21 | -------------------------------------------------------------------------------- /src/findType.test.js: -------------------------------------------------------------------------------- 1 | import findType from './findType'; 2 | 3 | describe('findType', () => { 4 | const testCases = [ 5 | { 6 | name: 'empty array', 7 | input: [], 8 | expected: 'address', 9 | }, 10 | { 11 | name: 'unknown', 12 | input: ['foo', 'bar'], 13 | expected: 'address', 14 | }, 15 | { 16 | name: 'city', 17 | input: ['city', 'address'], 18 | expected: 'city', 19 | }, 20 | { 21 | name: 'country', 22 | input: ['country', 'city'], 23 | expected: 'country', 24 | }, 25 | { 26 | name: 'address', 27 | input: ['address'], 28 | expected: 'address', 29 | }, 30 | { 31 | name: 'an airport', 32 | input: ['address', 'aeroway/aerodrome'], 33 | expected: 'airport', 34 | }, 35 | { 36 | name: 'a bus stop', 37 | input: ['address', 'amenity/bus_station'], 38 | expected: 'busStop', 39 | }, 40 | { 41 | name: 'a train station', 42 | input: ['address', 'railway/station'], 43 | expected: 'trainStation', 44 | }, 45 | { 46 | name: 'a townhall', 47 | input: ['amenity/townhall', 'address'], 48 | expected: 'townhall', 49 | }, 50 | ]; 51 | 52 | testCases.forEach((testCase) => 53 | it(`${testCase.name} test case`, () => 54 | expect(findType(testCase.input)).toEqual(testCase.expected)) 55 | ); 56 | }); 57 | -------------------------------------------------------------------------------- /src/formatDropdownValue.js: -------------------------------------------------------------------------------- 1 | import addressIcon from './icons/address.svg'; 2 | import cityIcon from './icons/city.svg'; 3 | import countryIcon from './icons/country.svg'; 4 | import busIcon from './icons/bus.svg'; 5 | import trainIcon from './icons/train.svg'; 6 | import townhallIcon from './icons/townhall.svg'; 7 | import planeIcon from './icons/plane.svg'; 8 | 9 | const icons = { 10 | address: addressIcon, 11 | city: cityIcon, 12 | country: countryIcon, 13 | busStop: busIcon, 14 | trainStation: trainIcon, 15 | townhall: townhallIcon, 16 | airport: planeIcon, 17 | }; 18 | 19 | export default function formatDropdownValue({ type, highlight }) { 20 | const { name, administrative, city, country } = highlight; 21 | 22 | const out = `${icons[type].trim()} 23 | ${name} 24 | 25 | ${[city, administrative, country] 26 | .filter((token) => token !== undefined) 27 | .join(', ')}`.replace(/\s*\n\s*/g, ' '); 28 | 29 | return out; 30 | } 31 | -------------------------------------------------------------------------------- /src/formatDropdownValue.test.js: -------------------------------------------------------------------------------- 1 | import formatDropdownValue from './formatDropdownValue'; 2 | jest.mock('./icons/address.svg', () => 'address'); 3 | 4 | describe('formatDropdownValue', () => { 5 | it('formats the address', () => { 6 | expect( 7 | formatDropdownValue({ 8 | type: 'address', 9 | highlight: { 10 | name: 'Paris', 11 | administrative: 'Île-de-France', 12 | city: 'Paris', 13 | country: 'France', 14 | type: 'address', 15 | }, 16 | }) 17 | ).toEqual( 18 | 'address Paris Paris, Île-de-France, France' 19 | ); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/formatInputValue.js: -------------------------------------------------------------------------------- 1 | export default function formatInputValue({ 2 | administrative, 3 | city, 4 | country, 5 | name, 6 | type, 7 | }) { 8 | const out = `${name}${type !== 'country' && country !== undefined ? ',' : ''} 9 | ${city ? `${city},` : ''} 10 | ${administrative ? `${administrative},` : ''} 11 | ${country ? country : ''}` 12 | .replace(/\s*\n\s*/g, ' ') 13 | .trim(); 14 | return out; 15 | } 16 | -------------------------------------------------------------------------------- /src/formatInputValue.test.js: -------------------------------------------------------------------------------- 1 | import formatInputValue from './formatInputValue'; 2 | 3 | describe('formatInputValue', () => { 4 | const testCases = [ 5 | { 6 | name: 'simple', 7 | input: { 8 | administrative: 'Île-de-France', 9 | city: 'Paris', 10 | country: 'France', 11 | name: '88 rue de Rivoli', 12 | type: 'address', 13 | }, 14 | expected: '88 rue de Rivoli, Paris, Île-de-France, France', 15 | }, 16 | { 17 | name: 'country', 18 | input: { 19 | name: 'France', 20 | type: 'country', 21 | }, 22 | expected: 'France', 23 | }, 24 | { 25 | name: 'no city', 26 | input: { 27 | administrative: 'Île-de-France', 28 | country: 'France', 29 | name: '88 rue de Rivoli', 30 | type: 'address', 31 | }, 32 | expected: '88 rue de Rivoli, Île-de-France, France', 33 | }, 34 | { 35 | name: 'no administrative', 36 | input: { 37 | country: 'France', 38 | name: '88 rue de Rivoli', 39 | type: 'address', 40 | }, 41 | expected: '88 rue de Rivoli, France', 42 | }, 43 | { 44 | name: 'no country', 45 | input: { 46 | name: '88 rue de Rivoli', 47 | type: 'address', 48 | }, 49 | expected: '88 rue de Rivoli', 50 | }, 51 | ]; 52 | 53 | testCases.forEach((testCase) => 54 | it(`${testCase.name} test case`, () => 55 | expect(formatInputValue(testCase.input)).toEqual(testCase.expected)) 56 | ); 57 | }); 58 | -------------------------------------------------------------------------------- /src/icons/address.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/icons/bus.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/icons/city.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/icons/clear.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/icons/country.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/icons/osm.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/icons/plane.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/icons/townhall.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/icons/train.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/navigatorLanguage.js: -------------------------------------------------------------------------------- 1 | // polyfill for navigator.language (IE <= 10) 2 | // not polyfilled by https://cdn.polyfill.io/v2/docs/ 3 | 4 | // Defined: http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#navigatorlanguage 5 | // with allowable values at http://www.ietf.org/rfc/bcp/bcp47.txt 6 | // Note that the HTML spec suggests that anonymizing services return "en-US" by default for 7 | // user privacy (so your app may wish to provide a means of changing the locale) 8 | if (!('language' in navigator)) { 9 | navigator.language = 10 | // IE 10 in IE8 mode on Windows 7 uses upper-case in 11 | // navigator.userLanguage country codes but per 12 | // http://msdn.microsoft.com/en-us/library/ie/ms533052.aspx (via 13 | // http://msdn.microsoft.com/en-us/library/ie/ms534713.aspx), they 14 | // appear to be in lower case, so we bring them into harmony with navigator.language. 15 | (navigator.userLanguage && 16 | navigator.userLanguage.replace( 17 | /-[a-z]{2}$/, 18 | String.prototype.toUpperCase 19 | )) || 20 | 'en-US'; // Default for anonymizing services: http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#navigatorlanguage 21 | } 22 | -------------------------------------------------------------------------------- /src/places.css: -------------------------------------------------------------------------------- 1 | .algolia-places { 2 | width: 100%; 3 | } 4 | 5 | .ap-input, .ap-hint { 6 | width: 100%; 7 | padding-right: 35px; 8 | padding-left: 16px; 9 | line-height: 40px; 10 | height: 40px; 11 | border: 1px solid #CCC; 12 | border-radius: 3px; 13 | outline: none; 14 | font: inherit; 15 | appearance: none; 16 | -webkit-appearance: none; 17 | box-sizing: border-box; 18 | } 19 | 20 | .ap-input::-webkit-search-decoration { 21 | -webkit-appearance: none; 22 | } 23 | 24 | .ap-input::-ms-clear { 25 | display: none; 26 | } 27 | 28 | .ap-input:hover ~ .ap-input-icon svg, 29 | .ap-input:focus ~ .ap-input-icon svg, 30 | .ap-input-icon:hover svg { 31 | fill: #aaaaaa; 32 | } 33 | 34 | .ap-dropdown-menu { 35 | width: 100%; 36 | background: #ffffff; 37 | box-shadow: 0 1px 10px rgba(0, 0, 0, 0.2), 0 2px 4px 0 rgba(0, 0, 0, 0.1); 38 | border-radius: 3px; 39 | margin-top: 3px; 40 | overflow: hidden; 41 | } 42 | 43 | .ap-suggestion { 44 | cursor: pointer; 45 | height: 46px; 46 | line-height: 46px; 47 | padding-left: 18px; 48 | overflow: hidden; 49 | } 50 | 51 | .ap-suggestion em { 52 | font-weight: bold; 53 | font-style: normal; 54 | } 55 | 56 | .ap-address { 57 | font-size: smaller; 58 | margin-left: 12px; 59 | color: #aaaaaa; 60 | } 61 | 62 | .ap-suggestion-icon { 63 | margin-right: 10px; 64 | width: 14px; 65 | height: 20px; 66 | vertical-align: middle; 67 | } 68 | 69 | .ap-suggestion-icon svg { 70 | display: inherit; 71 | -webkit-transform: scale(0.9) translateY(2px); 72 | transform: scale(0.9) translateY(2px); 73 | fill: #cfcfcf; 74 | } 75 | 76 | .ap-input-icon { 77 | border: 0; 78 | background: transparent; 79 | position: absolute; 80 | top: 0; 81 | bottom: 0; 82 | right: 16px; 83 | outline: none; 84 | } 85 | 86 | .ap-input-icon.ap-icon-pin { 87 | cursor: pointer; 88 | } 89 | 90 | .ap-input-icon svg { 91 | fill: #cfcfcf; 92 | position: absolute; 93 | top: 50%; 94 | right: 0; 95 | -webkit-transform: translateY(-50%); 96 | transform: translateY(-50%); 97 | } 98 | 99 | .ap-cursor { 100 | background: #efefef; 101 | } 102 | 103 | .ap-cursor .ap-suggestion-icon svg { 104 | -webkit-transform: scale(1) translateY(2px); 105 | transform: scale(1) translateY(2px); 106 | fill: #aaaaaa; 107 | } 108 | 109 | .ap-footer { 110 | opacity: .8; 111 | text-align: right; 112 | padding: .5em 1em .5em 0; 113 | font-size: 12px; 114 | line-height: 12px; 115 | } 116 | 117 | .ap-footer a { 118 | color: inherit; 119 | text-decoration: none; 120 | } 121 | 122 | .ap-footer a svg { 123 | vertical-align: middle; 124 | } 125 | 126 | .ap-footer:hover { 127 | opacity: 1; 128 | } 129 | -------------------------------------------------------------------------------- /src/version.js: -------------------------------------------------------------------------------- 1 | export default '1.19.0'; 2 | -------------------------------------------------------------------------------- /test/cdn-autocomplete-min/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 98 | 99 | -------------------------------------------------------------------------------- /test/cdn-autocomplete/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 98 | 99 | -------------------------------------------------------------------------------- /test/cdn-main-min/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 17 | 18 | -------------------------------------------------------------------------------- /test/cdn-main/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 17 | 18 | -------------------------------------------------------------------------------- /test/cdn-widget-min/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 32 | 33 | -------------------------------------------------------------------------------- /test/cdn-widget/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 32 | 33 | -------------------------------------------------------------------------------- /test/fileMock.js: -------------------------------------------------------------------------------- 1 | export default 'file'; 2 | -------------------------------------------------------------------------------- /test/npm-autocomplete/import.js: -------------------------------------------------------------------------------- 1 | const placesAutocompleteDataset = require('../../dist/autocompleteDataset'); 2 | 3 | module.exports = { placesAutocompleteDataset }; 4 | -------------------------------------------------------------------------------- /test/npm-autocomplete/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 98 | 99 | -------------------------------------------------------------------------------- /test/npm-lib/import.js: -------------------------------------------------------------------------------- 1 | const places = require('../../dist/index'); 2 | 3 | module.exports = { places }; 4 | -------------------------------------------------------------------------------- /test/npm-lib/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 30 | 31 | -------------------------------------------------------------------------------- /test/npm-widget/import.js: -------------------------------------------------------------------------------- 1 | const placesInstantsearchWidget = require('../../dist/instantsearchWidget'); 2 | 3 | module.exports = { placesInstantsearchWidget }; 4 | -------------------------------------------------------------------------------- /test/npm-widget/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 32 | 33 | -------------------------------------------------------------------------------- /webpack.config.docs.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-commonjs */ 2 | const baseConfig = require('./webpack.config'); 3 | const { join } = require('path'); 4 | 5 | module.exports = { 6 | ...baseConfig, 7 | entry: `./docs/source/javascripts/${process.env.BUNDLE}.js`, 8 | output: { 9 | path: join(__dirname, 'docs/.webpack/js'), 10 | filename: `${process.env.BUNDLE}.js`, 11 | }, 12 | }; 13 | /* eslint-enable import/no-commonjs */ 14 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-commonjs */ 2 | const { join } = require('path'); 3 | 4 | module.exports = { 5 | entry: { 6 | places: './index.js', 7 | placesAutocompleteDataset: './autocompleteDataset.js', 8 | placesInstantsearchWidget: './instantsearchWidget.js', 9 | }, 10 | devtool: 'source-map', 11 | output: { 12 | path: join(__dirname, './dist/cdn'), 13 | filename: '[name].js', 14 | library: '[name]', 15 | libraryTarget: 'umd', 16 | }, 17 | module: { 18 | rules: [ 19 | { 20 | test: /\.js$/, 21 | exclude: /node_modules/, 22 | loader: 'babel-loader', 23 | }, 24 | { 25 | test: /\.(svg|css)$/, 26 | exclude: /node_modules/, 27 | loader: 'raw-loader', 28 | }, 29 | ], 30 | }, 31 | optimization: { 32 | minimize: false, 33 | }, 34 | }; 35 | /* eslint-enable import/no-commonjs */ 36 | --------------------------------------------------------------------------------