{"id":20854370,"url":"https://github.com/w8r/leaflet.bookmarks","last_synced_at":"2025-05-12T05:31:52.111Z","repository":{"id":21568494,"uuid":"24888335","full_name":"w8r/Leaflet.Bookmarks","owner":"w8r","description":"Leaflet plugin for user-generated bookmarks","archived":false,"fork":false,"pushed_at":"2023-07-18T21:13:09.000Z","size":3208,"stargazers_count":59,"open_issues_count":7,"forks_count":17,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-04-15T09:18:20.642Z","etag":null,"topics":["bookmarks","leaflet","leaflet-plugin","localstorage"],"latest_commit_sha":null,"homepage":"http://w8r.github.io/Leaflet.Bookmarks/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/w8r.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-10-07T11:58:19.000Z","updated_at":"2024-09-15T07:15:44.000Z","dependencies_parsed_at":"2024-06-19T01:35:35.159Z","dependency_job_id":"8f5293d4-214c-4caf-8adc-e229cd755441","html_url":"https://github.com/w8r/Leaflet.Bookmarks","commit_stats":{"total_commits":67,"total_committers":5,"mean_commits":13.4,"dds":"0.26865671641791045","last_synced_commit":"a6604f2987cd3494ec302b6551b90aa142f7a6c3"},"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/w8r%2FLeaflet.Bookmarks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/w8r%2FLeaflet.Bookmarks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/w8r%2FLeaflet.Bookmarks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/w8r%2FLeaflet.Bookmarks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/w8r","download_url":"https://codeload.github.com/w8r/Leaflet.Bookmarks/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253682360,"owners_count":21946918,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bookmarks","leaflet","leaflet-plugin","localstorage"],"created_at":"2024-11-18T03:25:31.448Z","updated_at":"2025-05-12T05:31:51.471Z","avatar_url":"https://github.com/w8r.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"Leaflet.Bookmarks\n=================\n[![npm version](https://badge.fury.io/js/leaflet-bookmarks.svg)](http://badge.fury.io/js/leaflet-bookmarks)\n[![Bower version](https://badge.fury.io/bo/leaflet-bookmarks.svg)](http://badge.fury.io/bo/leaflet-bookmarks) [![CircleCI](https://circleci.com/gh/w8r/Leaflet.Bookmarks.svg?style=shield)](https://circleci.com/gh/w8r/Leaflet.Bookmarks)\n\nHighly customizable Leaflet plugin for user-generated bookmarks, stored locally or on the server.\n\nSee [demo and documentation](http://w8r.github.io/Leaflet.Bookmarks/)\n\n## Description\n\nThis is a highly customizable plugin for leaflet to allow users to drop bookmarks on your map and to store them locally or on server. It uses localstorage by default, but allows you to implement your own storage solution. You can also redefine the addition of bookmarks, their looks and fields.\n\nRight-click on the map, to add a new bookmark\n\n## Usage\n\nIncludes\n\n```html\n\u003cscript src=\"/path/to/leaflet.js\"\u003e\u003c/script\u003e\n\u003cscript src=\"/path/to/Leaflet.Bookmarks.min.js\"\u003e\u003c/script\u003e\n\u003clink type=\"text/css\" rel=\"stylesheet\" href=\"/path/to/leaflet.bookmarks.css\"\u003e\n```\n## Put control on the map\n\n```js\nvar map = new L.Map(...);\nvar control = new L.Control.Bookmarks().addTo(map);\n```\n\n## Adding a bookmark\n\nHow you trigger a bookmark addition is your own choice. For the demo I used the beautiful Leaflet.contextmenu plugin by @aratcliffe, but you are free to take any approach you want - it's based on the event bookmark:new dispatched by the map instance:\n\n```js\nmap.fire('bookmark:new', {\n    latlng: new L.LatLng(..., ...)\n});\n```\n\nIf you want you can omit the naming step and add a bookmark straight to the list using a bookmark:add event.\n\n```js\nmap.fire('bookmark:add', {\n  data: {\n    id: 'XXXX' // make sure it's unique,\n    name: 'Bookmark name',\n    latlng: [lat, lng] // important, we're dealing with JSON here,\n    your_key: 'your value'\n  }\n});\n```\n\n## Events\n\nTriggered on **map**:\n* `bookmark:removed` - Bookmark has been removed from storage and interface\n* `bookmark:show` - bookmark selected from list or just created\n\n## `GeoJSON` support\n\nThere are GeoJSON import/export methods provided for convinence and use within the storage methods of your choice\n\n* `.bookmarkToFeature(bookmark)`\nUse it on a single bookmark if you want to convert it into geoJSON `Feature` before send\n* `.toGeoJSON()`\nExports the whole list into GeoJSON, uses `.bookmarkToFeature`\n* `.fromGeoJSON(geojson)`\nUses properties as the bookmark contents, geometry as the location. GeoJSON `Point` expected, you can change it for a different type of geometry, if you want, then you'll have to take care of the centroid routines.\n\n## Customizing\n\n### localStorage or variable storage\n\nThe control uses localStorage by default. Your bookmarks will be stored in prefixed key-value pairs. You can customize the prefix if you want to\n\n```js\nvar control = new L.Control.Bookmarks({\n    name: 'your-storage-prefix', // defaults to 'leaflet-bookmarks'\n    localStorage: false // if you want to use local variable for storage\n});\n```\n\nP.S. You can access the storage directly through the control:\n\n```js\ncontrol._storage.getItem(key, callback);\ncontrol._storage.setItem(key, value, callback);\ncontrol._storage.removeItem(key, callback);\ncontrol._storage.getAllItems(callback);\n```\n\n### Custom storage(e.g AJAX)\n\nI intentionally didn't add an engine for anything else than localStorage and local variable storage, so you could use your own xhr functions. To do that, you have to pass the interface to your storage to the control like this:\n\n```js\nvar control = new L.Control.Bookmarks({\n    storage: {\n        getItem: function(id, callback){\n            $.ajax({\n                url: '/bookmarks/' + id,\n                type: 'GET',\n                dataType: 'json',\n                success: callback\n            });\n        },\n        setItem: function(id, value, callback){\n            $.ajax({\n                url: '/bookmarks/' + id,\n                type: 'PUT',\n                data: value,\n                dataType: 'json',\n                success: callback\n            });\n        },\n        removeItem: function(id, callback){\n            $.ajax({\n                url: '/bookmarks/' + id,\n                type: 'DELETE',\n                dataType: 'json',\n                success: callback\n            });\n        },\n        getAllItems: function(callback){\n            $.ajax({\n                url: '/bookmarks/',\n                type: 'GET',\n                dataType: 'json',\n                success: callback\n            });\n        }\n    }\n}).addTo(map);\n```\n\n### Custom templates\n\nPass those into the options if you want to customize the popup or list templates. Proceed with caution\n\n```js\n{\n       // list item MUST contain `data-id` attribute,\n       // or provide your own `options.getBookmarkFromListItem(listItem)` method\n       bookmarkTemplate: '\u003cli class=\"{{ itemClass }}\" data-id=\"{{ data.id }}\"\u003e' +\n            '\u003cspan class=\"{{ removeClass }}\"\u003e\u0026times;\u003c/span\u003e' +\n            '\u003cspan class=\"{{ nameClass }}\"\u003e{{ data.name }}\u003c/span\u003e' +\n            '\u003cspan class=\"{{ coordsClass }}\"\u003e{{ data.coords }}\u003c/span\u003e' +\n            '\u003c/li\u003e',\n\n        // format list item name\n        formatName: function(name){ ... },\n\n        // format coords\n        // again, you have access to the control here, so you can\n        // output projected coords for example\n        formatCoords: function(laltlng){\n            var projected = this._map.project(L.latLng(latlng[0], latlng[1]));\n            return 'X: ' + projected.x + 'm, Y: ' + projected.y + 'm';\n        },\n\n        // no bookmarks yet\n        emptyTemplate: '\u003cli class=\"{{ itemClass }} {{ emptyClass }}\"\u003e' +\n            '{{ data.emptyMessage }}\u003c/li\u003e',\n\n        // no bookmarks text\n        emptyMessage: \"Hell no, I forgot where I've been!\",\n\n        // you can change them, but then provide your own styling\n        bookmarkTemplateOptions: {\n            itemClass: 'bookmark-item',\n            nameClass: 'bookmark-name',\n            coordsClass: 'bookmark-coords',\n            removeClass: 'bookmark-remove',\n            emptyClass: 'bookmarks-empty'\n        },\n\n        // change that if you have custom fields in your bookmarks\n        popupTemplate: '\u003cdiv\u003e\u003ch3\u003e{{ name }}\u003c/h3\u003e\u003cp\u003e{{ latlng }}\u003c/p\u003e',\n\n        // here you extract them for the template.\n        // note - you have access to controls methods and fields here\n        getPopupContent: function(bookmark) {\n            return L.Util.template(this.options.popupTemplate, {\n                latlng: this.formatCoords(bookmark.latlng),\n                name: bookmark.name\n            });\n        },\n\n        // here you can filter bookmarks that you get from\n        // the storage or a user, make sure it returns an Array\n        filterBookmarks: function(bookmarks){ ... },\n}\n```\n\nYou can customize the bookmark add form too, pass that to the control options:\n\n```js\nformPopup: {\n        className: 'leaflet-bookmarks-form-popup',\n        templateOptions: {\n            formClass: 'leaflet-bookmarks-form',\n            inputClass: 'leaflet-bookmarks-form-input',\n            coordsClass: 'leaflet-bookmarks-form-coords',\n            submitClass: 'leaflet-bookmarks-form-submit',\n            inputPlaceholder: 'Bookmark name',\n            submitText: '+'\n        },\n        getBookmarkData: function(){\n            var input = this._contentNode.querySelector('.' +\n            this.options.templateOptions.inputClass);\n            ...\n            return {\n                id: 'YOUR_UNIQUE_ID',\n                name: 'Bookmark name',\n                your_custom_field: ... // get it from the form inputs\n                latlng: this._source.getLatLng() // get it from the marker\n            };\n        },\n        onRemove: function(bookmark, callback){\n          /* use that to add confirmation menus\n             when removing a bookmark */\n           },\n        generateNames: true, // generate unique name if it's not provided by the user\n        generateNamesPrefix: 'Bookmark ',\n        template: '\u003cform class=\"{{ formClass }}\"\u003e' +\n            '\u003cinput type=\"text\" name=\"bookmark-name\" ' +\n            'placeholder=\"{{ inputPlaceholder }}\" class=\"{{ inputClass }}\"\u003e' +\n            '\u003cinput type=\"submit\" value=\"{{ submitText }}\" ' +\n            'class=\"{{ submitClass }}\"\u003e' +\n            '\u003cdiv class=\"{{ coordsClass }}\"\u003e{{ coords }}\u003c/div\u003e' +\n            '\u003c/form\u003e',\n    }\n```\n\n### Editing\n\nYou can enable bookmarks editing/removal by putting a flag in the bookmark object\n\n```js\n{\n  name: '',\n  id: 'XXX',\n  latlng: [lat, lng],\n  editable: true,\n  removable: true\n}\n```\n\nThis will enable a menu on popup to remove or edit the bookmark.\nPresence of menu items will is defined by those params also\n\n![screenshot 2015-05-27 21 32 51](https://cloud.githubusercontent.com/assets/26884/7845663/987abcfa-04b8-11e5-867d-f4ea025b416e.png)\n\n### Removal\n\nYou can pass a custom confirm function to the control, so you could handle confirmation menus\n\n```\n  onRemove: function(bookmark, callback){\n    if(confirm('Are you really sure?')){\n      if(bookmark.name === 'Bamby') {\n        alert('Keep your hands away!');\n        callback(false); // won't be removed\n      } else {\n        callback(true);  // will be removed\n      }\n    } else {\n      callback(false);\n    }\n  }\n```\n\n### `L.Util._template`\n\nSmall template function used by this project. It's a simple implementation of @lodash templates, using mustache interpolation syntax. You get it as a souvenir.\n\n```js\nL.Util._template('Whereof one cannot {{ data.action }}, thereof one must keep {{ data.instead }}', { data: { action: 'speak', instead: 'silent' }});\n// -\u003e \"Whereof one cannot speak, thereof one must keep silent\"\n```\n## Authors and Contributors\n\nAlexander Milevski\n\n## License\n\nMIT\n\n## Changelog\n\n* **0.4.0**\n  * Leaflet 1.6 support\n* **0.3.0**\n  * Fixed some bugs\n  * Migrated to rollup build system and ESM modules\n* **0.2.0**\n  * Editing/removal funtionality\n  * \"Add new\" button\n  * Tests added\n* **0.1.5**\n  * GeoJSON support\n* **0.1.3**\n  * Different layout when in `topleft` position\n  * Scroll to bookmark on addition\n* **0.1.2**\n  * Remove marker when bookmark is removed\n* **0.1.0**\n  * npm \u0026 bower packages published\n* **0.0.2**\n  * Zoom level ztored and used by default\n  * Remove button flickering fixed\n  * Add bookmark UX: now you can show the newly created bookmark right away\n* **0.0.1**\n  * Initial release\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fw8r%2Fleaflet.bookmarks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fw8r%2Fleaflet.bookmarks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fw8r%2Fleaflet.bookmarks/lists"}